Better random function in JavaScript - javascript

I'm currently making a Conway's Game of Life reproduction in JavaScript and I've noticed that the function Math.random() is always returning a certain pattern. Here's a sample of a randomized result in a 100x100 grid:
Does anyone knows how to get better randomized numbers?
ApplyRandom: function() {
var $this = Evolution;
var total = $this.Settings.grid_x * $this.Settings.grid_y;
var range = parseInt(total * ($this.Settings.randomPercentage / 100));
for(var i = 0; i < total; i++) {
$this.Infos.grid[i] = false;
}
for(var i = 0; i < range; i++) {
var random = Math.floor((Math.random() * total) + 1);
$this.Infos.grid[random] = true;
}
$this.PrintGrid();
},
[UPDATE]
I've created a jsFiddle here: http://jsfiddle.net/5Xrs7/1/
[UPDATE]
It seems that Math.random() was OK after all (thanks raina77ow). Sorry folks! :(. If you are interested by the result, here's an updated version of the game: http://jsfiddle.net/sAKFQ/
(But I think there's some bugs left...)

This line in your code...
var position = (y * 10) + x;
... is what's causing this 'non-randomness'. It really should be...
var position = (y * $this.Settings.grid_x) + x;
I suppose 10 was the original size of this grid, that's why it's here. But that's clearly wrong: you should choose your position based on the current size of the grid.
As a sidenote, no offence, but I still consider the algorithm given in #JayC answer to be superior to yours. And it's quite easy to implement, just change two loops in ApplyRandom function to a single one:
var bias = $this.Settings.randomPercentage / 100;
for (var i = 0; i < total; i++) {
$this.Infos.grid[i] = Math.random() < bias;
}
With this change, you will no longer suffer from the side effect of reusing the same numbers in var random = Math.floor((Math.random() * total) + 1); line, which lowered the actual cell fillrate in your original code.

Math.random is a pseudo random method, that's why you're getting those results. A by pass i often use is to catch the mouse cursor position in order to add some salt to the Math.random results :
Math.random=(function(rand) {
var salt=0;
document.addEventListener('mousemove',function(event) {
salt=event.pageX*event.pageY;
});
return function() { return (rand()+(1/(1+salt)))%1; };
})(Math.random);
It's not completly random, but a bit more ;)

A better solution is probably not to randomly pick points and paint them black, but to go through each and every point, decide what the odds are that it should be filled, and then fill accordingly. (That is, if you want it on average %20 percent chance of it being filled, generate your random number r and fill when r < 0.2 I've seen a Life simulator in WebGL and that's kinda what it does to initialize...IIRC.
Edit: Here's another reason to consider alternate methods of painting. While randomly selecting pixels might end up in less work and less invocation of your random number generator, which might be a good thing, depending upon what you want. As it is, you seem to have selected a way that, at most some percentage of your pixels will be filled. IF you had kept track of the pixels being filled, and chose to fill another pixel if one was already filled, essentially all your doing is shuffling an exact percentage of black pixels among your white pixels. Do it my way, and the percentage of pixels selected will follow a binomial distribution. Sometimes the percentage filled will be a little more, sometimes a little less. The set of all shufflings is a strict subset of the possibilities generated this kind of picking (which, also strictly speaking, contains all possibilities for painting the board, just with astronomically low odds of getting most of them). Simply put, randomly choosing for every pixel would allow more variance.
Then again, I could modify the shuffle algorithm to pick a percentage of pixels based upon numbers generated from a binomial probability distribution function with a defined expected/mean value instead of the expected/mean value itself, and I honestly don't know that it'd be any different--at least theoretically--than running the odds for every pixel with the expected/mean value itself. There's a lot that could be done.

console.log(window.crypto.getRandomValues(new Uint8Array(32))); //return 32 random bytes
This return a random bytes with crypto-strength: https://developer.mozilla.org/en/docs/Web/API/Crypto/getRandomValues

You can try
JavaScript Crypto Library (BSD license). It is supposed to have a good random number generator. See here an example of usage.
Stanford JavaScript Crypto Library (BSD or GPL license). See documentation for random numbers.
For a discussion of strength of Math.random(), see this question.

The implementation of Math.random probably is based on a linear congruential generator, one weakness of which is that a random number depends on the earlier value, producing predictable patterns like this, depending on the choice of the constants in the algorithm. A famous example of the effect of poor choice of constants can be seen in RANDU.
The Mersenne Twister random number generator does not have this weakness. You can find an implementation of MT in JavaScript for example here: https://gist.github.com/banksean/300494
Update: Seeing your code, you have a problem in the code that renders the grid. This line:
var position = (y * 10) + x;
Should be:
var position = (y * grid_x) + x;
With this fix there is no discernible pattern.

You can using the part of sha256 hash from timestamp including nanoseconds:
console.log(window.performance.now()); //return nanoseconds inside
This can be encoded as string,
then you can get hash, using this: http://geraintluff.github.io/sha256/
salt = parseInt(sha256(previous_salt_string).substring(0, 12), 16);
//48 bits number < 2^53-1
then, using function from #nfroidure,
write gen_salt function before, use sha256 hash there,
and write gen_salt call to eventListener.
You can use sha256(previous_salt) + mouse coordinate, as string to get randomized hash.

Related

Algorithm to get progressively closer to a number without ever reaching it

I need to have a number that gets updated progressively closer to the max (or min) value, without ever reaching it. I also would like each update to have a smooth transition, like a curve or something (I have never studied math or computer science so I don't know the correct terminology)
Here's what I got so far but it obviously doesn't work:
let numberToUpdate = 5 // this number will vary after each update
const numberToUpdateMin = 1
const numberToUpdateMax = 10
let someValueA = 100 // this number will change randomly between updates
let someValueB = 50 // this number will change randomly between updates
function updateNumber() {
let differenceBetweenValues = someValueA - someValueB
if (differenceBetweenValues > 0) {
// make numberToUpdate closer to numberToUpdateMax (without ever reaching it)
numberToUpdate += (numberToUpdateMax - numberToUpdate) * (someValueA / someValueB) // this doesn't work at all
}
else if (differenceBetweenValues < 0) {
// make numberToUpdate closer to numberToUpdateMin (without ever reaching it)
numberToUpdate -= (numberToUpdate - numberToUpdateMin) * (someValueB / someValueA) // this doesn't work at all
}
}
any help would be greatly appreciated, I have no clue what I'm doing or what terms I should be googling to arrive to a suitable result.
Edit: It doesn't have to work with infinitely small/big numbers, it could have a cap.
Here is a simple example of an asymptotic function:
function generateAsymptotic(step) {
return step / (step + 1);
}
As step gets bigger, generateAsymptotic will get closer and closer to 1, but never be 1.
On a computer, this is impossible, because the number of distinct values representable is finite, so in the end you will reach the forbidden number.

JS - How to check if 2 images (their hash) are similar

GOAL
Finding a good way to check if 2 image are similar compairing their hash profiles. The hash is a simple array containing 0 and 1 values.
INTRO
I have 2 images. They are the same image but with some little differences: one has a different brightness, rotation and shot.
What I want to do is create a Javascript method to compare the 2 images and calculate a percentage value that tells how much they are similar.
WHAT I'VE DONE
After uploading the 2 images into a html5 canvas to get their image data, I've used the pHash algorithm (www.phash.org) to obtain their hash rapresentation.
The hash is an array containing 0 and 1 values that recreates the image in a "simplified" form.
I've also created a JS script that generates a html table with black cells where the array contains 1.The result is the following screenshot (the image is a Van Gogh picture):
Screenshot
Now, what I should do is to compare the 2 arrays for obtaining a percentage value to know "how much" they are similar.
The most part of the hash Javascript algorithms I've found googling already have a compare algorithm: the hamming distance algorithm. It's very simple and fast, but not very precise. In fact, the hamming distance algorithm says that the 2 images in my screenshot have a 67% of similarity.
THE QUESTION
Starting with 2 simple arrays, with the same length, filled with 0 and 1 values: what could be a good algorithm to determine similarity more precisely?
NOTES
- Pure Javascript development, no third party plugins or framework.
- No need of a complex algorithm to find the right similarity when the 2 images are the same but they are very different (strong rotation, totaly different colors, etc.).
Thanx
PHASH CODE
// Size is the image size (for example 128px)
var pixels = [];
for (var i=0;i<imgData.data.length;i+=4){
var j = (i==0) ? 0 : i/4;
var y = Math.floor(j/size);
var x = j-(y*size);
var pixelPos = x + (y*size);
var r = imgData.data[i];
var g = imgData.data[i+1];
var b = imgData.data[i+2];
var gs = Math.floor((r*0.299)+(g*0.587)+(b*0.114));
pixels[pixelPos] = gs;
}
var avg = Math.floor( array_sum(pixels) / pixels.length );
var hash = [];
array.forEach(pixels, function(px,i){
if(px > avg){
hash[i] = 1;
} else{
hash[i] = 0;
}
});
return hash;
HAMMING DISTANCE CODE
// hash1 and hash2 are the arrays of the "coded" images.
var similarity = hash1.length;
array.forEach(hash1, function(val,key){
if(hash1[key] != hash2[key]){
similarity--;
}
});
var percentage = (similarity/hash1.length*100).toFixed(2);
NOTE: array.forEach is not pure javascript. Consider it as a replace of: for (var i = 0; i < array.length; i++).
I'm using blockhash, it seems pretty good so far, only false positives I get are when half the pictures are of the same background color, which is to be expected =/
http://blockhash.io/
BlockHash may be slower than yours but it should be more accurate.
What you do is just calculate the greyscale of EACH pixels, and just compare it to the average to create your hash.
What BlockHash does is split the picture in small rectangles of equal size and averages the sum of the RGB values of the pixels inside them and compares them to 4 horizontal medians.
So it is normal that it takes longer, but it is still pretty efficient and accurate.
I'm doing it with pictures of a good resolution, at minimum 1000x800, and use 16bits. This gives a 64 character long hexadecimal hash. When using the hamming distance provided by the same library, I see good results when using a 10 similarity threshold.
Your idea of using greyscale isn't bad at all. But you should average out portions of the image instead of comparing each pixels. That way you can compare a thumbnail version to its original, and get pretty much the same phash!
I don't know if this can do the trick, but you can just compare the 0 and 1 similarities between arrays :
const arr1 = [1,1,1,1,1,1,1,1,1,1],
arr2 = [0,0,0,0,0,0,0,0,0,0],
arr3 = [0,1,0,1,0,1,0,1,0,1],
arr4 = [1,1,1,0,1,1,1,0,1,1]
const howSimilar = (a1,a2) => {
let similarity = 0
a1.forEach( (elem,index) => {
if(a2[index]==elem) similarity++
})
let percentage = parseInt(similarity/arr1.length*100) + "%"
console.log(percentage)
}
howSimilar(arr1,arr2) // 0%
howSimilar(arr1,arr3) // 50%
howSimilar(arr1,arr4) // 80%

Maidenhead Grid Square Functions in SAS, PHP or JavaScript

Conceptually I understand what I need to do. But mathmatically I'm stumped.
I would like to create two functions preferably in SAS but PHP or JavaScript would work too. The first to convert a latitude/longitude into the Maidenhead Grid Square, the second finds the latitude and longitude for the center of the Maidenhead Grid Square given the grid square name (i.e. EM29qe78pq). I would like both to work with all 10 characters but still be flexable enough to only need 6 and 8 of them.
I've read and re-read the Wikipedia article https://en.wikipedia.org/wiki/Maidenhead_Locator_System but always come up with the wrong values. I've Googled quite literally more than 100 times looking for help, none I found does. I've come to the realization I just am not understanding the math part of this problem. And its simple math..I'm told.
This is the SAS macro I have converting grid square to lat/lon, but while close, its not correct. Would someone care to investigate this for me and perhaps give me the answer.
%macro grid2latlong(grid);
field = 'ABCDEFGHIJKLMNOPQRSTUVWX';
array sparts $ 1 var1-var10;
do i = 1 to length(&grid);
sparts{i} = substr(&grid,i,1);
lon1 = (find(field,var1)-1) * 20 - 180;
lat1 = (find(field,var2)-1) * 10 - 90;
lon2 = var3 * 2;
lat2 = var4 * 1;
lon3 = (find(field,var5)-1) * 5/60;
lat3 = (find(field,var6)-1) * 2.5/60;
lon4 = var7 * 0.0083333;
lat4 = var8 * 0.0041666;
lon5 = var9;
lat5 = var10;
lonx = sum(lon1,lon2,lon3,lon4);
latx = sum(lat1,lat2,lat3,lat4);
end;
drop i var1-var8 lon4 lat4 lon1-lon3 lat1-lat3;
%mend;
You're not calculating the centroid, you're calculating the lower left boundary of the square, as I understand it. To calculate the centroid, it looks like the standard Perl routine Wikipedia references appends "..55LL55LL" as needed (the first two obviously have to be present, but after that 55 or LL will be roughly the central point of the grid tile). I assume 55LL is the "standard" given its presence there; you could calculate it more precisely by taking the average of the left boundary and the right boundary (the next left boundary).
Here's a slightly simplified version of your code above that does this. I write it as a data step to simplify testing but of course making it a macro is trivial. If you have FCMP (9.2+, better 9.4+) you can write it as an actual function in that of course.
data have;
length grid $10;
input grid $;
datalines;
AB12CD34
AB12CD
AB12CD34EF
;;;;
run;
%let grid=grid;
data want;
set have;
*Initialize some variables;
latmult=10; *the amount to multiply latitude values by (starting out);
lonmult=20; *the amount to multiply longitude values by (starting out);
lon=-180; *the zero point for longitude in this system;
lat=-90; *the zero point for latitude in this system;
*append 5's and L's to the string if it is incomplete;
*If you leave this out, this still works, but returns the edge not the center;
initial_String='LL55LL55LL';
substr(initial_String,1,length(&grid.)) = trim(&grid.);
do i = 1 to length(initial_String) by 2;
if mod((i+1)/2,2)=1 then do; *letters;
if I>1 then do; *i=1 it is initialized properly already;
lonmult=lonmult/24;
latmult=latmult/24;
end;
*rank converts "A" to 65 and up through "Z" is 90.;
lon=sum(lon,lonmult*(rank(upcase(char(initial_String,i)))-65));
lat=sum(lat,latmult*(rank(upcase(char(initial_String,i+1)))-65));
end;
else do;
latmult=latmult/10;
lonmult=lonmult/10;
lon=sum(lon,lonmult*input(char(initial_String,i),1.));
lat=sum(lat,latmult*input(char(initial_String,i+1),1.));
end;
end;
run;

Generating a random number between a range with a weight/bias?

I am trying to generate a random number between 1 and a maximum. This I don't have a problem doing so and do so with the following:
var max = 200;
var randomNumber = Math.floor(Math.random() * max) + 1;
However in an ideal situation I would like to generate a number between 1 and my maximum however the lower numbers have a higher probability of occurring. I want the variable to be biased towards 1. However my maths skills aren't strong enough to work this out, it would be great if someone could point me in the right direction.
Thank you,
Josh
a simple way will be to just square the result of Math.random(). Since the result of the function is between 0 and 1 , the square will also be in the range [0, 1], but values , for example , 0.5 from it will be mapped to lower ones - 0.25 . You can experiment with powers above 1 until you find an acceptable function.
I got a code in java which does what you want.
You should choose your own probabilities for the int[] prob arrays.
I think it wont be that hard to translate this to js or build smth. equal.
int[] probs;
void initRandom(int n, int[] probabilities)
{
int i,j,begin=0,end=0,sum=0;
int[] probs;
// sum of all propabilitys must be 100%
for(i=0;i<probabilities.length;i++) sum+=probabilities[i];
probs=new int[sum];
// fills numbers from 0 till n-1 in regard to their probabilities
// to the probability array.
for(i=0;i<n;i++)
{
begin=end;
end+=probabilities[i];
for(j=begin;j<end;j++) probs[j]=i;
}
}
int genRandom()
{
return probs[smallRand(probs.length-1)];
}
This is a very general question. First consider this link here
http://en.wikipedia.org/wiki/List_of_probability_distributions#Supported_on_a_bounded_interval
It shows some probability functions which are bounded, which I believe is what you are looking for (since min=1 and max=max).
You can also chose a semi-infine interval, and just ignore all value above your maximum. I think, this could also be acceptable, depending on your application.
Next, chose one of those probabilty functions, that suits you best. For the sake of simplicity, I chose the triangular distribution
The distribution functions are (PDF and CDF)
f(x) = 2/(2*max-1-max^2)*(x-max)
F(x) = 2/(2*max-1-max^2)*(0.5*x^2-max*x-0.5+max)
so I can generate from a uniform distribution on 0-1 a biased distribution by inverting the CDF like
var urand = Math.random();
var a = 2/(2*max-1-max^2);
var randomNumber = max-Math.sqrt(max*max-2*(max-urand/a-0.5));
Cheers
R
The following function i made up gives you a near-one-biased random number
function rand(max) {
var r = Math.random();
r = 1/(101-100 * r);
return Math.floor(r * max) - 1;
}
It only uses simple arithmetics, thus, it should be quite fast.

What is the fastest way to generate a random integer in javascript?

Normally this is how you get a random number in javascript.
Math.random();
However, this method seems to be inefficient when it comes to generating random integers.
Firstly, the random function has to generate a random decimal, like 0.1036098338663578, then it has to be multiplied to a suitable range (10.464593220502138). Finally, the floor function subtracts the decimals to produce the result (which in this case, 10).
var random_integer = Math.floor(Math.random()*101);
Is there a faster way to generate random integers in javascript?
Edit1:
I am using this for creating a canvas HTML5 game. The FPS is about 50, and my code is pretty optimized, apart from generating a random number.
This code is faster... to type.
var random_integer = Math.random()*101|0;
It won't work right for huge numbers though.
(and it doesn't run any faster, at least not in chrome.)
You could achieve a much faster speed during the game if you generate the random numbers beforehand, though.
for (var i=1e6, lookupTable=[]; i--;) {
lookupTable.push(Math.random()*101|0);
}
function lookup() {
return ++i >= lookupTable.length ? lookupTable[i=0] : lookupTable[i];
}
lookup will rotate through an array with a million random integers. It is much faster than calling random and floor (of course, there is a "loading time" penalty up front from generating the lookup table).
If you want to avoid floating point calculation then you can do that by writing your own pseudo random number generator. Here is a list of well known pseudo random number generators (PRNG). Linear congruential generator is the easiest one to implement and probably most effective in terms of performance too. However, you will need to understand the theory behind PRNGs well enough to write an effective one. That might not be worth of effort though. The JS implementation should be effective enough. At the end there is a high possibility that you will find Math.random() is running faster than your code.
i mostly use
var a = Math.floor(Math.random((number you'd like to be minimum, (number you'd like to be maximum) * (number you'd like to be maximum);
No, there is no easier or shorter way. You can create a function if you need to do it multiple times, though.
const getRandomInt = (base = 10) => {
return Math.floor(Math.random() * base)
}
Heres what I use:
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
An example of how this would be used would be
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
if(getRandomInt(420) == 69){
console.log("nice")
}
Your way is the right way to retrive a random integer in javascript, don't worry about performance it will run fast.
This is the shortest one-liner Random Number Generator code
rnd=(a,b)=>~~(Math.random()*(b-a))+a
How To Use: rnd(min,max)
Example : rnd(10,100)

Categories

Resources