JavaScript 的 Math.random 有多随机?
Posted
技术标签:
【中文标题】JavaScript 的 Math.random 有多随机?【英文标题】:How random is JavaScript's Math.random? 【发布时间】:2010-11-06 23:13:28 【问题描述】:6 年来,我的网站上有一个random number generator 页面。长期以来,它是 Google 上“随机数生成器”的第一个或第二个结果,并且已被用于决定论坛和博客上的数十个(如果不是数百个)竞赛和绘图(我知道,因为我在我的网络日志,通常去看看)。
今天,有人给我发电子邮件告诉我它可能不像我想象的那样随机。她尝试生成非常大的随机数(例如,1 到 10000000000000000000 之间),发现它们几乎总是相同的位数。事实上,我将函数封装在一个循环中,这样我就可以生成数千个数字,而且果然,对于非常大的数字,变化只有大约 2 个数量级。
为什么?
这里是循环版,大家可以自己试一试:
http://andrew.hedges.name/experiments/random/randomness.html
它包括取自 Mozilla Developer Network 的简单实现和一些 1997 年的代码,这些代码是我从一个不再存在的网页上刷下来的(Paul Houle 的“Central Randomizer 1.3”)。查看源代码以了解每种方法的工作原理。
我读过here 和elsewhere 关于Mersenne Twister 的文章。 我感兴趣的是为什么javascript 的内置结果不会有更大的变化Math.random 函数。谢谢!
【问题讨论】:
如果您正在寻找标题中问题的答案,请参阅***.com/questions/2344312/… 【参考方案1】:给定 1 到 100 之间的数字。
9 有 1 个数字 (1-9) 90 有 2 位数字 (10-99) 1 有 3 个数字 (100)给定 1 到 1000 之间的数字。
9 有 1 位 90有2位 900有3位 1 有 4 个数字等等。
因此,如果您随机选择一些,那么绝大多数选定的数字将具有相同的位数,因为绝大多数可能的值具有相同的位数。
【讨论】:
你对随机性意味着完美和均匀分布的想法很有趣...... @R.Pate - 随机数 generation 没有多大用处,除非它在长尺度上均匀分布 再读一遍。 @David 只是说明限制之间有什么样的数字,而不是选择 N 个随机数的结果。我承认标题具有误导性。 为了记录,我对这个和@jwoolard 的答案都投了赞成票。我选择这个作为公认的答案,因为这些例子清楚地说明了为什么数字的分布偏向于具有更多数字的数字。 @andrew-hedges 非常正确 - 这是更清晰的答案,但谢谢 :)【参考方案2】:您的结果实际上是预期的。如果随机数均匀分布在 1 到 10^n 的范围内,那么您预计大约 9/10 的数字有 n 位,另外 9/100 有 n-1 位。
【讨论】:
没错。预计位数的分布会出现偏差。然而,位数的对数分布应该是统一的。【参考方案3】:有不同类型的随机性。 Math.random 为您提供统一的数字分布。
如果你想要不同的数量级,我建议使用指数函数来创建所谓的power law distribution:
function random_powerlaw(mini, maxi)
return Math.ceil(Math.exp(Math.random()*(Math.log(maxi)-Math.log(mini)))*mini)
此函数应为您提供与 2 位数字和 3 位数字大致相同数量的 1 位数字。
还有其他随机数分布,例如 normal distribution(也称为高斯分布)。
【讨论】:
使用这个算法,我把minimum = 1
和maximum = 10
放在一起,结果有时会得到11。您可能打算使用 Math.floor
而不是 Math.round
为什么有效?它是否将均匀分布转换为指数分布?
@shinzou 我在math.stackexchange 上提问,得到的答案略有不同。我更改了代码以反映从 math.stackexchange 得出的数学公式。【参考方案4】:
在我看来完全随机! (提示:这取决于浏览器。)
就我个人而言,我认为我的实现会更好,虽然我从XKCD 那里偷走了它,谁应该总是得到承认:
function random()
return 4; // Chosen by a fair dice throw. Guaranteed to be random.
【讨论】:
+1 表示它依赖于浏览器,-1 表示借用 xkcd 而不链接。 是否需要,因为它是 xkcd,它正在被归因。 :) OT:我很惊讶也很高兴“XKCD”是本周大学挑战问题的答案:D Bergi:直接链接还不够? 我认为他们的意思是没有正确引用这个笑话(“random = 4;”而不是“return 4;”)【参考方案5】:以下论文解释了主要 Web 浏览器中的 math.random() 是如何(不)安全的: "Temporary user tracking in major browsers and Cross-domain information leakage and attacks" by Amid Klein (2008)。它并不比典型的 Java 或 Windows 内置 PRNG 函数强。
另一方面,实现周期 2^19937-1 的 SFMT 需要为每个 PRNG 序列维护 2496 个字节的内部状态。有些人可能会认为这是不可原谅的代价。
【讨论】:
+1:提到的论文很棒,远远超出了最初的问题。【参考方案6】:如果您使用像 10000000000000000000 这样的数字,您将超出 Javascript 使用的数据类型的准确性。请注意,生成的所有数字都以“00”结尾。
【讨论】:
不过,在这种情况下,这不是他的问题。 @Johannes - 这是他的一个问题:) IEE754的分布不均。也许您可以以 2 为增量表示 0 到 999 并具有足够的精度,因此如果您多次选择数字,您会注意到该范围内的均匀分布。 10% 将是两位数,90% 将是三位数。但是,当您开始达到非常高的数字时,增量将超过 1。您可能只能从一万亿到一万亿一千,而不是一万亿零一。尽管对于小数字/规模,这种影响可以忽略不计甚至不存在。不过,规模效应会产生更大的影响。【参考方案7】:我在Chaos Game上尝试了JS伪随机数生成器。
我的Sierpiński triangle 说它很随机:
【讨论】:
您介意在此处分享三角代码和 jsfiddle/jsbin,以便我们可以轻松地在不同浏览器的实践中检查它吗? 好的,但是给我几天时间,因为我需要将代码翻译成英文。现在是波兰语-英语,我有很多工作。 @zie1ony 几天过去了。 usp :( work, work, work 链接:kubaplas.vot.pl/green/fractal 第一个参数是顶点的nr。第二个是线段的交点(从0到1)。只是实验。 链接失效 - 也许是 Github 存储库?【参考方案8】:好吧,如果您生成的数字达到 1e6,那么您希望得到所有数字的概率大致相等。这也意味着您只有十分之一的机会获得少一位数的数字。百分之一的机会减少两位数,等等。我怀疑使用另一个 RNG 时你会看到很大的不同,因为你在数字上是均匀分布的,而不是它们的对数。
【讨论】:
【参考方案9】:从 1 到 N 均匀分布的非随机数具有相同的性质。请注意,(在某种意义上)这是一个精度问题。 0-99(作为整数)的均匀分布确实有 90% 的数字有两位数。在 0-999999 上的均匀分布有 905 个五位数的数字。
任何一组数字(在一些不太严格的条件下)都有密度。当有人想讨论“随机”数字时,应指定这些数字的密度(如上所述)。常见的密度是均匀密度。还有其他:指数密度、正态密度等。在提出随机数生成器之前,必须选择哪个密度是相关的。此外,来自一个密度的数字通常可以很容易地通过龋齿手段转换为另一个密度。
【讨论】:
以上是关于JavaScript 的 Math.random 有多随机?的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript中Math.random()方法产生的随机数包括0和1吗?
JavaScript - Math.floor(Math.random()) - 重新定位元素