127

For 6 years I've had a random number generator page on my website. For a long time, it was the first or second result on Google for "random number generator" and has been used to decide dozens, if not hundreds of contests and drawings on discussion forums and blogs (I know because I see the referrers in my web logs and usually go take a look).

Today, someone emailed me to tell me it may not be as random as I thought. She tried generating very large random numbers (e.g., between 1 and 10000000000000000000) and found that they were almost always the same number of digits. Indeed, I wrapped the function in a loop so I could generate thousands of numbers and sure enough, for very large numbers, the variation was only about 2 orders of magnitude.

Why?

Here is the looping version, so you can try it out for yourself:

http://andrew.hedges.name/experiments/random/randomness.html

It includes both a straightforward implementation taken from the Mozilla Developer Network and some code from 1997 that I swiped off a web page that no longer exists (Paul Houle's "Central Randomizer 1.3"). View source to see how each method works.

I've read here and elsewhere about Mersenne Twister. What I'm interested in is why there wouldn't be greater variation in the results from JavaScript's built-in Math.random function. Thanks!

Community
  • 1
  • 1
Andrew Hedges
  • 21,688
  • 16
  • 67
  • 79
  • 1
    "sarnath'd" as in, beaten to the punch, or in this case, the answer – maetl Jun 30 '09 at 11:29
  • 7
    If you're looking for the answer to the question in the title, see http://stackoverflow.com/questions/2344312/how-is-randomness-achieved-with-math-random-in-javascript – Andrew B. Jun 07 '12 at 23:53
  • From the title, I thought this question was about the distribution uniformity of the `Math.random()` method. But this… is unexpected, in a way. Frankly speaking, I can’t believe that there’s more than a hundred people who didn’t know the why for this. – Константин Ван Nov 18 '22 at 03:56

9 Answers9

197

Given numbers between 1 and 100.

  • 9 have 1 digit (1-9)
  • 90 have 2 digits (10-99)
  • 1 has 3 digits (100)

Given numbers between 1 and 1000.

  • 9 have 1 digit
  • 90 have 2 digits
  • 900 have 3 digits
  • 1 has 4 digits

and so on.

So if you select some at random, then that vast majority of selected numbers will have the same number of digits, because the vast majority of possible values have the same number of digits.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 13
    Your idea of randomness meaning perfectly and evenly distributed is intriguing... –  Jun 30 '09 at 10:34
  • 26
    @R.Pate - random number *generation* isn't much use unless it is evenly distributed on a long scale – annakata Jun 30 '09 at 10:56
  • 3
    Read again. @David is only stating what kind of numbers there are between the limits, not the result of selecting N random numbers. I do admit the titling is misleading. – nikc.org Jun 30 '09 at 10:57
  • Edited. I phrased my initial answer ambiguously. – Quentin Jun 30 '09 at 11:01
  • 3
    For the record, I voted up both this and @jwoolard's answers. I chose this one as the accepted answer because the examples make it clear as crystal why the distribution of numbers is skewed to numbers with more digits. – Andrew Hedges Jun 30 '09 at 11:13
  • 1
    @andrew-hedges quite right - this is the clearer answer, but thanks :) – jwoolard Jul 01 '09 at 09:04
59

Your results are actually expected. If the random numbers are uniformly distributed in a range 1 to 10^n, then you would expect about 9/10 of the numbers to have n digits, and a further 9/100 to have n-1 digits.

jwoolard
  • 6,024
  • 9
  • 37
  • 37
  • 8
    Exactly. The distribution of the number of digits is expectedly going to be skewed. The distribution of the log of the number of digits shoudl be uniform however. – Noldorin Jun 30 '09 at 10:34
48

There different types of randomness. Math.random gives you an uniform distribution of numbers.

If you want different orders of magnitude, I would suggest using an exponential function to create what's called a power law distribution:

function random_powerlaw(mini, maxi) {
    return Math.ceil(Math.exp(Math.random()*(Math.log(maxi)-Math.log(mini)))*mini)
}

This function should give you roughly the same number of 1-digit numbers as 2-digit numbers and as 3-digit numbers.

There are also other distributions for random numbers like the normal distribution (also called Gaussian distribution).

Christian
  • 25,249
  • 40
  • 134
  • 225
  • With this algorithm, I put the `minimum = 1` and the `maximum = 10` and would sometimes get 11 as a result. You probably meant to use `Math.floor` instead of `Math.round` – Sam Eaton Aug 03 '15 at 20:13
  • 1
    Why does it work? Does it transform uniform distribution to exponential distribution? – shinzou Apr 09 '17 at 11:39
  • @shinzou I asked on [math.stackexchange](https://math.stackexchange.com/a/2580824/2263) and got a slightly different formula as answer. I changed the code to reflect the mathematically derived formula from math.stackexchange. – Christian Dec 26 '17 at 15:28
  • Do you know the reason for the skewed in the results with this algorithm? When doing this from range 1 to 1,000,000. I average around 76,300 for results over several tests. Of course proper range randomizer should be around 500,000. – Timothy C. Quinn Nov 01 '22 at 20:24
26

Looks perfectly random to me! (Hint: It's browser dependent.)

Personally, I think my implementation would be better, although I stole it off from XKCD, who should ALWAYS be acknowledged:

function random() {
  return 4; // Chosen by a fair dice throw. Guaranteed to be random.
}
aleclarson
  • 18,087
  • 14
  • 64
  • 91
Arafangion
  • 11,517
  • 1
  • 40
  • 72
19

The following paper explains how math.random() in major Web browsers is (un)secure: "Temporary user tracking in major browsers and Cross-domain information leakage and attacks" by Amid Klein (2008). It's no stronger than typical Java or Windows built-in PRNG functions.

On the other hand, implementing SFMT of the period 2^19937-1 requires 2496 bytes of the internal state maintained for each PRNG sequence. Some people may consider this as unforgivable cost.

trlkly
  • 681
  • 7
  • 13
jj1bdx
  • 1,117
  • 1
  • 15
  • 32
6

If you use a number like 10000000000000000000 you're going beyond the accuracy of the datatype Javascript is using. Note that all the numbers generated end in "00".

Greg
  • 316,276
  • 54
  • 369
  • 333
  • 1
    That's not his problem in this case, though. – Joey Jun 30 '09 at 10:31
  • 3
    @Johannes - it's *one* of his problems :) – annakata Jun 30 '09 at 10:33
  • The distribution of IEE754 isn't even. Maybe you can represent 0 to 999 in increments of two and have enough precision for that so you notice an even distribution across that range if you pick number many times. 10% will be two digit and 90% three digit. When you start to hit really high numbers though, the increment will exceed 1. You might only be able to step from a trillion billion to a trillion billion one thousand and not a trillion billion and one. Though for small numbers / scales, this effect will be negligible to non-existent. The scale effect will have far more impact though. – jgmjgm May 30 '19 at 11:58
4

I tried JS pseudorandom number generator on Chaos Game.

My Sierpiński triangle says its pretty random: Fractal

zie1ony
  • 1,190
  • 2
  • 14
  • 33
3

Well, if you are generating numbers up to, say, 1e6, you will hopefully get all numbers with approximately equal probability. That also means that you only have a one in ten chance of getting a number with one digit less. A one in a hundred chance of getting two digits less, etc. I doubt you will see much difference when using another RNG, because you have a uniform distribution across the numbers, not their logarithm.

Joey
  • 344,408
  • 85
  • 689
  • 683
1

Non-random numbers uniformly distributed from 1 to N have the same property. Note that (in some sense) it's a matter of precision. A uniform distribution on 0-99 (as integers) does have 90% of its numbers having two digits. A uniform distribution on 0-999999 has 905 of its numbers having five digits.

Any set of numbers (under some not too restrictive conditions) has a density. When someone want to discuss "random" numbers, the density of these numbers should be specified (as noted above.) A common density is the uniform density. There are others: the exponential density, the normal density, etc. One must choose which density is relevant before proposing a random number generator. Also, numbers coming from one density can often be easily transformed to another density by carious means.

ttw
  • 111
  • 3