How to generate random numbers in a very large range via javascript?
Asked Answered
O

3

8

I was using this function for a long time and was happy with it. You probably saw it millions of times. It is even in the example section of the MDN documentation for Math.random()!

function random(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min
};

However when I called it on really large range it performed really poorly. Here are some results:

for(var i=0;i<100;i++) { console.log(random(0, 34359738368)) }

34064924616
6800671568
30945277424
2591785504
16404206304
29609031808
14821448928
10712020504
26471102024
21454653384
33180253592
28189739360
27189739528
1159593656
24058421888
13727549496
21995862272
20907450968
28767901872
8055552544
2856286816
28137132160
22775692392
21141911808
16418994064
28151646560
19928528408
11100796192
24022825648
17873139800
10310184976
7425284936
27043756016
2521657024
2864339728
8080550424
8812058632
8867252312
18571554760
19600873680
33687248280
14707542936
28864740112
26338252144
7877957776
28207487968
2268429496
14461565136
28062983608
5637084472
29651319832
31910601904
19776200528
16996597392
2478335752
4751145704
24803500872
21899551216
23144535632
19854787112
8490486080
14932659320
8625736560
11379900040
32357265704
33852039680
2826278800
4648275784
27363699728
14164020752
22279817656
25238815424
16569505656
30065335928
9904863008
26944796040
23179908064
19887944032
27944730648
16242926184
6518696400
25727832240
7496221976
19014687568
5685988776
34324757344
12538943128
21639530152
9532790800
25800487608
34329978920
10871183016
23748271688
23826614456
11774681408
667541072
1316689640
4539806456
2323113432
7782744448

Hardly random at all. All numbers are even.

My question is this: What is the CANONICAL way (if any) to overcome this problem? I have the impression that the above random function is the go-to function for random numbers in range. Thanks in advance.

Orator answered 23/3, 2014 at 10:37 Comment(7)
See #1528303.Basie
Not exactly an answer, but try using an odd number for the top limit.Richmound
@user1929959: The answers to that question simply say to use the above function. They don't explain the results of the above test or say anything about handling the effects.Thecla
Maybe it's just sleep deprivation talking, but it seems to me like Math.random() should have more than enough precision to produce odd numbers here.Thecla
It seems almost like it's returning random 32-bit floats, rather than 64-bit.Thecla
I think this is a browser bug. It works fine on Firefox, but Chrome gives shitty precision.Thecla
Works in (old 12.16) Opera as well.Mckinzie
M
2

The answer in general is don't use Math.random. It gets the job done, but it's not especially good. On top of that, any number in Javascript greater than 0xffffffffUL isn't represented by integer values--it's an IEEE 754 value with a behavior noted on the MDN site: "Note that as numbers in JavaScript are IEEE 754 floating point numbers with round-to-nearest-even behavior...."

And that's what you're seeing.

If you want larger random numbers, then you'll probably have to get something like Mersenne Twister or Blum-Blum-Shub 32-bit random integer values and multiply them. That will eliminate the rounding-off problem.

Metametabel answered 23/3, 2014 at 13:15 Comment(3)
Hi. I long ago accepted your answer, but what @user3363398 said doesn't give me peace. As I understood correctly it was a precision issue, right? How we can explain the fact that if we use a number that is not a power of 2 (but still greater than 2**35), we still get odd numbers as results? Thanks in advance and sorry for bothering you again. :)Orator
No matter what we might try, JavaScript in its current form just doesn't have 64-bit integers. At some point the numbers generated will exceed the integer bits available in the format, and the math engine will do its rounding trick. I looked at the ES6 specification, and even the typed arrays aren't going to handle better than 32-bit unsigned numbers. I think the question here is whether or not you can use numbers that live within the 32-bit limitations. What user3363398 sees is probably just the vagaries of the specific algorithm used by the math engine.Metametabel
The random() function provided isn't really all that good, either--not much different than that found in the C standard library. If you can use 32-bits of actual unsigned integers, you will get better results by picking a better PRNG algorithm. Not faster--but better.Metametabel
H
4

The WebCrypto API (supported in draft by all the major browsers) provides cryptographically random numbers....

/* assuming that window.crypto.getRandomValues is available */

var array = new Uint32Array(10);
window.crypto.getRandomValues(array);

console.log("Your lucky numbers:");
for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
}

W3C standard https://www.w3.org/TR/WebCryptoAPI/

Example from here. https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues

Hickory answered 30/10, 2016 at 6:51 Comment(0)
M
2

The answer in general is don't use Math.random. It gets the job done, but it's not especially good. On top of that, any number in Javascript greater than 0xffffffffUL isn't represented by integer values--it's an IEEE 754 value with a behavior noted on the MDN site: "Note that as numbers in JavaScript are IEEE 754 floating point numbers with round-to-nearest-even behavior...."

And that's what you're seeing.

If you want larger random numbers, then you'll probably have to get something like Mersenne Twister or Blum-Blum-Shub 32-bit random integer values and multiply them. That will eliminate the rounding-off problem.

Metametabel answered 23/3, 2014 at 13:15 Comment(3)
Hi. I long ago accepted your answer, but what @user3363398 said doesn't give me peace. As I understood correctly it was a precision issue, right? How we can explain the fact that if we use a number that is not a power of 2 (but still greater than 2**35), we still get odd numbers as results? Thanks in advance and sorry for bothering you again. :)Orator
No matter what we might try, JavaScript in its current form just doesn't have 64-bit integers. At some point the numbers generated will exceed the integer bits available in the format, and the math engine will do its rounding trick. I looked at the ES6 specification, and even the typed arrays aren't going to handle better than 32-bit unsigned numbers. I think the question here is whether or not you can use numbers that live within the 32-bit limitations. What user3363398 sees is probably just the vagaries of the specific algorithm used by the math engine.Metametabel
The random() function provided isn't really all that good, either--not much different than that found in the C standard library. If you can use 32-bits of actual unsigned integers, you will get better results by picking a better PRNG algorithm. Not faster--but better.Metametabel
P
1

Thats wierd! Well you know there is no such thing as truly random when in comes to computers. There is always an algorithm used. So you found a number that causes even's for this particular algorithm. I tried it out, it isn't necessarily caused by large numbers. More likely some kind of factorization of the number instead. Just try another number, even larger if you like and you should get output that isn't all even. Ex. 134359738368 which is even larger doesn't out all odd or even numbers.

Panzer answered 23/3, 2014 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.