JavaScript的Math.random是多么随机?

时间:2021-02-07 13:31:46

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).

6年来,我的网站上有一个随机数生成器页面。很长一段时间,它是Google上“随机数生成器”的第一个或第二个结果,并且已用于在论坛和博客上决定数十个(如果不是数百个)竞赛和绘图(我知道因为我看到了我的推荐人)网络日志,通常去看看)。

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.

今天有人给我发了电子邮件,告诉我它可能不像我想的那么随机。她尝试生成非常大的随机数(例如,在1到10000000000000000000之间)并发现它们几乎总是相同的位数。实际上,我将函数包装在一个循环中,因此我可以生成数千个数字,当然,对于非常大的数字,变化只有大约2个数量级。

Why?

为什么?

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

这是循环版本,所以你可以自己试试:

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

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.

它既包括Mozilla开发者网络的简单实现,也包括1997年我从一个不再存在的网页中删除的一些代码(Paul Houle的“Central Randomizer 1.3”)。查看源以查看每种方法的工作原理。

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!

我在这里和其他地方读过有关Mersenne Twister的文章。我感兴趣的是为什么JavaScript的内置Math.random函数的结果没有更大的变化。谢谢!

9 个解决方案

#1


156  

Given numbers between 1 and 100.

给定1到100之间的数字。

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

Given numbers between 1 and 1000.

给定1到1000之间的数字。

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

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.

因此,如果您随机选择一些,那么绝大多数所选数字将具有相同的位数,因为绝大多数可能的值具有相同的位数。

#2


50  

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.

您的结果实际上是预期的。如果随机数均匀分布在1到10 ^ n的范围内,那么您可能希望大约9/10的数字具有n个数字,并且另外9/100的数字具有n-1个数字。

#3


37  

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

有不同类型的随机性。 Math.random为您提供统一的数字分布。

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.

此功能应该为您提供与2位数字和3位数字大致相同的1位数字。

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

随机数也有其他分布,如正态分布(也称为高斯分布)。

#4


17  

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.

下面的文章解释了主要Web浏览器中的math.random()是如何(不)安全的:“主要浏览器中的临时用户跟踪以及跨域信息泄漏和攻击”,Amid Klein(2008)。它并不比典型的Java或Windows内置PRNG功能更强大。

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.

另一方面,实现时段2 ^ 19937-1的SFMT需要为每个PRNG序列维持2496字节的内部状态。有些人可能认为这是不可原谅的代价。

#5


14  

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:

就我个人而言,我认为我的实施会更好,尽管我从XKCD中偷走了它,而XKCD应该始终得到承认:

random = 4; // Chosen by a fair dice throw. Guaranteed to be random.

#6


5  

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".

如果您使用10000000000000000000之类的数字,那么您将超出Javascript使用的数据类型的准确性。请注意,生成的所有数字都以“00”结尾。

#7


4  

I tried JS pseudorandom number generator on Chaos Game.

我在Chaos Game上尝试了JS伪随机数生成器。

My Sierpiński triangle says its pretty random: JavaScript的Math.random是多么随机?

我的Sierpiński三角形说它非常随意:

#8


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.

好吧,如果您生成的数字高达1e6,那么您希望所有数字的概率大致相等。这也意味着你只有十分之一的机会得到一个数字少一个数字。百分之一的机会减少两位数等等。我怀疑你在使用另一个RNG时会看到很多不同,因为你在数字上有一个统一的分布,而不是它们的对数。

#9


0  

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.

从1到N均匀分布的非随机数具有相同的属性。请注意(在某种意义上)这是一个精确的问题。在0-99(作为整数)上的均匀分布确实有90%的数字具有两个数字。在0-999999上的均匀分布有905个数字有五位数。

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.

任何一组数字(在一些不太严格的条件下)都有密度。当有人想讨论“随机”数字时,应指定这些数字的密度(如上所述)。常见密度是均匀密度。还有其他:指数密度,正常密度等。在提出随机数发生器之前,必须选择哪个密度是相关的。而且,来自一个密度的数字通常可以通过龋齿手段容易地转换为另一个密度。

#1


156  

Given numbers between 1 and 100.

给定1到100之间的数字。

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

Given numbers between 1 and 1000.

给定1到1000之间的数字。

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

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.

因此,如果您随机选择一些,那么绝大多数所选数字将具有相同的位数,因为绝大多数可能的值具有相同的位数。

#2


50  

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.

您的结果实际上是预期的。如果随机数均匀分布在1到10 ^ n的范围内,那么您可能希望大约9/10的数字具有n个数字,并且另外9/100的数字具有n-1个数字。

#3


37  

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

有不同类型的随机性。 Math.random为您提供统一的数字分布。

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.

此功能应该为您提供与2位数字和3位数字大致相同的1位数字。

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

随机数也有其他分布,如正态分布(也称为高斯分布)。

#4


17  

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.

下面的文章解释了主要Web浏览器中的math.random()是如何(不)安全的:“主要浏览器中的临时用户跟踪以及跨域信息泄漏和攻击”,Amid Klein(2008)。它并不比典型的Java或Windows内置PRNG功能更强大。

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.

另一方面,实现时段2 ^ 19937-1的SFMT需要为每个PRNG序列维持2496字节的内部状态。有些人可能认为这是不可原谅的代价。

#5


14  

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:

就我个人而言,我认为我的实施会更好,尽管我从XKCD中偷走了它,而XKCD应该始终得到承认:

random = 4; // Chosen by a fair dice throw. Guaranteed to be random.

#6


5  

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".

如果您使用10000000000000000000之类的数字,那么您将超出Javascript使用的数据类型的准确性。请注意,生成的所有数字都以“00”结尾。

#7


4  

I tried JS pseudorandom number generator on Chaos Game.

我在Chaos Game上尝试了JS伪随机数生成器。

My Sierpiński triangle says its pretty random: JavaScript的Math.random是多么随机?

我的Sierpiński三角形说它非常随意:

#8


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.

好吧,如果您生成的数字高达1e6,那么您希望所有数字的概率大致相等。这也意味着你只有十分之一的机会得到一个数字少一个数字。百分之一的机会减少两位数等等。我怀疑你在使用另一个RNG时会看到很多不同,因为你在数字上有一个统一的分布,而不是它们的对数。

#9


0  

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.

从1到N均匀分布的非随机数具有相同的属性。请注意(在某种意义上)这是一个精确的问题。在0-99(作为整数)上的均匀分布确实有90%的数字具有两个数字。在0-999999上的均匀分布有905个数字有五位数。

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.

任何一组数字(在一些不太严格的条件下)都有密度。当有人想讨论“随机”数字时,应指定这些数字的密度(如上所述)。常见密度是均匀密度。还有其他:指数密度,正常密度等。在提出随机数发生器之前,必须选择哪个密度是相关的。而且,来自一个密度的数字通常可以通过龋齿手段容易地转换为另一个密度。