What is the fastest way to generate a random integer in javascript? - 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)

Related

Efficient way to compute the median of an array of canvas in JavaScript

I have an array of N HTMLCanvasElements that come from N frames of a video, and I want to compute the "median canvas" in the sense that every component (r, g, b, opacity) of every pixel is the median of the corresponding component in all the canvases.
The video frames are 1280x720, so that the pixels data for every canvas (obtained with canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data) is a Uint8ClampedArray of length 3.686.400.
The naive way to compute the median is to:
prepare a result Uint8ClampedArray of length 3.686.400
prepare a temporary Uint8ClampedArray of length N
loop from 0 to 3.686.399
a) loop over the N canvases to fill the array
b) compute the median of the array
c) store the median to the result array
But it's very slow, even for 4 canvases.
Is there an efficient way (or existing code) to do that? My question is very similar to Find median of list of images, but I need to to this in JavaScript, not Python.
Note: for b), I use d3.median() which doesn't work on typed arrays, as far as I understand, so that it implies converting to numbers, then converting back to Uint8Clamped.
Note 2: I don't know much of GLSL shaders, but maybe using the GPU would be a way to get faster results. It would require to pass data from the CPU to the GPU though, which takes time if done repeatedly.
Note 3: the naive solution is there: https://observablehq.com/#severo/compute-the-approximate-median-image-of-a-video
You wrote
I use d3.median() which doesn't work on typed arrays…
Although that is not exactly true it leads into the right direction. Internally d3.median() uses the d3.quantile() method which starts off like this:
export default function quantile(values, p, valueof) {
values = Float64Array.from(numbers(values, valueof));
As you can see, this in fact does make use of typed arrays, it is just not your Uint8ClampedArray but a Float64Array instead. Because floating-point arithmetic is much more computation-intensive than its integer counterpart (including the conversion itself) this has a dramatic effect on the performance of your code. Doing this some 3 million times in a tight loop kills the efficiency of your solution.
Since you are retrieving all your pixel values from a Uint8ClampedArray you can be sure that you are always dealing with integers, though. That said, it is fairly easy to build a custom function median(values) derived from d3.median() and d3.quantile():
function median(values) {
// No conversion to floating point values needed.
if (!(n = values.length)) return;
if (n < 2) return d3.min(values);
var n,
i = (n - 1) * 0.5,
i0 = Math.floor(i),
value0 = d3.max(d3.quickselect(values, i0).subarray(0, i0 + 1)),
value1 = d3.min(values.subarray(i0 + 1));
return value0 + (value1 - value0) * (i - i0);
}
On top of getting rid of the problematic conversion on the first line this implementation additionally applies some more micro-optimizations because in your case you are always looking for the 2-quantile (i.e. the median). That might not seem much at first, but doing this multiple million times in a loop it does make a difference.
With minimal changes to your own code you can call it like this:
// medianImageData.data[i] = d3.median(arr); Instead of this use line below.
medianImageData.data[i] = median(arr);
Have a look at my working fork of your Observable notebook.

Attempting to improve Math.random() in browser

Looking for a little expert advice on this one, my knowledge of cryptography is cursory at best.
I'm wondering if this is a viable solution for generating cryptographically secure random numbers. More specifically I'm wondering if using Math.abs() or Math.sin() to clamp the number will reduce the randomness of the number I get from crypto.getRandomValues so much that it is no longer useful for encryption.
if(window.crypto && window.crypto.getRandomValues) {
Math.random = () => {
var array = new Uint32Array(1)
window.crypto.getRandomValues(array)
return Math.abs(Math.sin(array[0]))
}
}
console.log(Math.random())
jsfiddle: https://jsfiddle.net/mg7ftm7w/
note: I've only tested this snippet in Chrome. I don't think the window.crypto object is present in IE.

Comparing big numbers in Javascript

I've got two numbers that I want to compare. The numbers in the following example are the result of 26^26 computed in two different systems. One of which is my javascript code.
However, when comparing the two numbers I end up with something like this:
AssertionError [ERR_ASSERTION]: 4.0329146112660565e+26 == 4.0329146112661e+26
They're obviously not equal, but theoretically they should.
What's the proper way to perform equality on big numbers in javascript (even if it's an approximation)?
If what you're trying to do is determine if two numbers are practically equivalent you'll have to come up with your margin of error. One way to do this is to compute the difference between the numbers and then determine if that difference is significant or not.
So, taking your numbers from before, we could evaluate the difference between these numbers through subtraction. Since we don't really care about the sign of this difference, I'll go ahead and get the absolute value of the difference.
Math.abs(4.0329146112660565e+26 - 4.0329146112661e+26) === 4329327034368
(Sidenote: Now is not the time to explain why, but the == operator in JavaScript has confusing and error-prone behavior, use === when you want to compare values.)
That difference is a HUGE number, but related to how big our numbers are in the first place, it's rather insignificant. Intuitively, I'm tempted to divide the difference by the smallest of our original numbers like so:
4329327034368 / 4.0329146112660565e+26 === 1.0734983136696987e-14
That looks like a pretty small number. Repeat that same operation with a bunch of values and you should be able to determine what you want your margin of error to be. Then, all you'll have to do is perform the same operations with arbitrary numbers and see if that "difference ratio" is small enough for you.
function similar(a, b) {
let diff = Math.abs(a - b);
let smallest = Math.min(Math.abs(a), Math.abs(b));
let ratio = diff / smallest;
return ratio < MARGIN_OF_ERROR;
}
Now I just came up with that way of determining the importance of the difference between two numbers. It might not be a very smart way to compute it, it might be appropriate to some situations and not to others. But the general idea is that you'll have to make a function that determines if two values are close enough with your own definition of "close".
Be aware though, JavaScript is one of the worst languages you can be doing math in. Integers become imprecise when they go beyond Number.MAX_SAFE_INT (which seems to be 9007199254740991 according to Chrome, not sure if it varies between browsers or if that's a standardized constant).
Update: If your target engine is es2020 or above, you can use the new BigInt javascript primitive, for numbers higher than Number.MAX_SAFE_INTEGER
BigInt(4.0329146112660565e+26) === BigInt(4.0329146112661e+26)
//false
See more information in MDN
var a = 4.0329146112660565e+26;
var b = 4.0329146112661e+26;
a = Math.round(a/10e+20)*10e+20
b = Math.round(b/10e+20)*10e+20
a == b;
I would suggest to use one of big numbers library:
big.js (https://www.npmjs.com/package/big.js)
Example:
var x = new Big('4.0329146112660565e+26');
var y = new Big('4.0329146112661e+26');
// Should print false
console.log('Comparision result' + x.eq(y));
big-numbers (https://www.npmjs.com/package/big-numbers)
Example:
var x = bn.of('4.0329146112660565e+26');
var y = bn.of('4.0329146112661e+26');
// Should print false
console.log('Comparision result' + x.equals(y));

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.

Better random function in 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.

Categories

Resources