JavaScript的Math.random()如何生成随机数?

打开开发工具(Mac:cmd +选项+ i / Windows:ctrl + shift + i),转到控制台,键入Math.random() ,然后按回车键。

am 您得到一个随机数。

我得到了0.6199322557631561。

我一直想知道这些数字来自何处。 而且,更重要的是,它们如何可能是随机的? 毕竟,难道计算机不只是接受一些输入,用一些数学方法旋转它,然后将其吐出来吗? 似乎是一个可预测的过程。 那么当您想生成一个“随机”数字时会发生什么呢? 甚至如何工作以及幕后发生了什么?

对于初学者来说,这并不是随机的

令人惊讶的是,答案是Math.random()并未真正生成随机数。 不完全是。 它只是在模拟随机性方面做得非常好。

本质上,算法随机数生成不能完全是随机的。 这就是为什么将它们更恰当地称为伪随机数生成器(PRNG)的原因。 如果您使用数学和公式来创建一个数字序列,尽管看起来可能是随机的,但这些数字最终会重复出现并显示出非随机模式。

但是有些PRNG比其他的要好。 PRNG的质量取决于许多因素,一个非常重要的因素是所谓的周期 。 PRNG开始重复自身之前经过的迭代次数。 不仅具有长周期的PRNG 似乎更随意我们人类,但它也更难(即资源较多)对计算机的裂缝/预测; 即使没有人应该使用Math.random()进行加密,这也会带来安全隐患,但是无论如何都会发生。

所以现在的问题是: JavaScript使用什么PRNG?

答案:没有。

这取决于浏览器

JavaScript不会决定Math.random()的实现方式,而浏览器会确定。 JavaScript没有附带硬编码的PRNG算法。 相反,创建浏览器的工程师决定使用符合ECMAScript规范的算法,如下所示:

[Math.random]使用依赖于实现的算法或策略,返回一个具有正号的Number值,该值大于或等于0但小于1,在该范围内以近似均匀的分布随机或伪随机选择。 此函数不带参数。
为不同代码领域创建的每个Math.random函数必须从连续调用中产生不同的值序列。

这些就是说明,由浏览器决定如何遵循它们。 直到最近,不同的浏览器才使用略有不同的方法来实现此目的。 他们使用的算法名称很性感,例如Marsenne-Twister带进位乘线性同 余生成 器。 不过,请放心,了解所有这些内容的含义对您来说并不重要(尽管您确实对我印象深刻)。

了解所有这些重要的事情是(1)浏览器决定他们要使用哪种算法来计算Math.random() ,(2)在2015年几乎每个浏览器(至少是主要的浏览器)都放弃了旧的PRNG算法现在它们都使用相同的名称: xorshift128 +

事实证明,xorshift128 +在伪装随机性方面比旧算法做得更好。 加上重量极轻且计算速度快。 因此,它几乎被广泛采用,当您考虑到以前对此事有很多不同意见时,就充分说明了它的有效性。

但是它到底如何工作?

尽管每个浏览器实现算法的方式略有不同,但我们可以查看其“原始”版本以了解其工作原理。

一些有趣的数学

首先,我将向您展示该算法,以便您可以将其全部浸泡(如C所示),然后我们将仔细研究一下:

 uint64_t state0 = 1;
uint64_t state1 = 2;
 uint64_t xorshift128plus() {
uint64_t s1 = state0;
uint64_t s0 = state1;
state0 = s0;
s1 ^= s1 << 23;
s1 ^= s1 >> 17;
s1 ^= s0;
s1 ^= s0 >> 26;
state1 = s1;
return state0 + state1;
}

如果您像我一样(具有前端背景并且没有计算机科学学位),请看一下它,然后思考“好吧,变量赋值,变量赋值,函数……足够简单……”,但是您会得出s1 ^= s1 << 23; 并说“该死的是什么?”

这些是按位运算符。 它们以位级别(1和0)操作数据,并且构成了我们正在研究的算法的核心和灵魂。 它们也是普通的Web开发人员很少(如果有的话)可以使用的机会。 因此,为了解释该算法的作用,我将快速介绍上面显示的三个按位运算符以及它们如何工作。

第一个运算符<<称为左移。 这是一个示例: 12 << 4 。 在此示例中,您将采用数字12的二进制表示形式,并将其向左移动4个位置。 因此向左移动。 运作方式如下:

与此相反的函数称为right shift >> ,其作用相同,但右移而不是左移。

第二个运算符=^是xor赋值运算符。 Xor( exclusive或的缩写)比较两个数字的二进制表示形式,并在对应位匹配的地方输出0,在对应位不同的地方输出1。 您可以将xor视为“一个另一个,但不能同时存在 ”。 这是一个随机xor 53^18的可视化效果(xor没有分配)

既然您知道所有运算符都在做什么,那么您就可以开始理解上面的xorshift算法了。 我刚才提到的令人困惑的位( s1 ^= s1 << 23; )只是将s1左移23位,然后将结果与s1异或,从而得出s1的新分配值。 或者,换句话说,这是异或。

因此,为了完全简化,该算法采用了两个种子值,将它们切换过来,对它们的位值进行混洗,将它们的位值通过逻辑门放置,重复几次,然后将它们加在一起,然后…

am 您会得到一个“随机”数字。

结论(tl; dr)

为了将所有内容整齐打包,这里有一个概述。

问题: JavaScript的Math.random()如何生成随机数?

回答:

  • JS不会执行任何操作,这取决于浏览器
  • 截至2015年,大多数浏览器都使用称为xorshift128 +的算法
  • xorshift128 +生成的数字并不是真正随机的,序列需要很长时间才能重复,并且在期望的值范围内相对均匀地分布。

因此,事实证明,我们在这里真正要做的就是获取一些输入,并通过一些数学运算将其旋转,然后吐出一个结果。 一个完全可预测的非随机过程。 但是,对于我们来说,随机性足以使它达到其目的的目的是使我们JavaScript混乱不堪。

对于感兴趣的任何人,我都可以在GitHub上获得xorshift128 +的JS实现(在下面链接),它使您可以直观地看到算法的“随机性”,并可以处理 种子 移位 值。 谢谢阅读!

翻译自: https://hackernoon.com/how-does-javascripts-math-random-generate-random-numbers-ef0de6a20131

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值