我最近想出了如何通过谷歌获取一个随机数,它让我思考如何Math.random()工作.所以我在这里,我无法弄清楚他们是如何做Math.random()除非他们使用时间之类的东西有没有人知道JavaScript的Math.random()工作原理或等效的?
Nic*_*ick 26
Math.random()返回一个带有正号的Number值,大于或等于0但小于1,使用依赖于实现的算法或策略随机或伪随机选择,在该范围内具有近似均匀的分布.
这是V8的实现:
uint32_t V8::Random() {
// Random number generator using George Marsaglia's MWC algorithm.
static uint32_t hi = 0;
static uint32_t lo = 0;
// Initialize seed using the system random(). If one of the seeds
// should ever become zero again, or if random() returns zero, we
// avoid getting stuck with zero bits in hi or lo by reinitializing
// them on demand.
if (hi == 0) hi = random();
if (lo == 0) lo = random();
// Mix the bits.
hi = 36969 * (hi & 0xFFFF) + (hi >> 16);
lo = 18273 * (lo & 0xFFFF) + (lo >> 16);
return (hi << 16) + (lo & 0xFFFF);
}
Run Code Online (Sandbox Code Playgroud)
来源:http://dl.packetstormsecurity.net/papers/general/Google_Chrome_3.0_Beta_Math.random_vulnerability.pdf
以下是StackOverflow上的几个相关线程:
请参阅:有 Math.random(),然后有 Math.random()
直到最近(直到版本 4.9.40),V8 对 PRNG 的选择还是 MWC1616(乘以进位,结合两个 16 位部分)。它使用 64 位内部状态,大致如下所示:
uint32_t state0 = 1;
uint32_t state1 = 2;
uint32_t mwc1616() {
state0 = 18030 * (state0 & 0xffff) + (state0 >> 16);
state1 = 30903 * (state1 & 0xffff) + (state1 >> 16);
return state0 << 16 + (state1 & 0xffff);
Run Code Online (Sandbox Code Playgroud)
然后根据规范将 32 位值转换为介于 0 和 1 之间的浮点数。
MWC1616 使用很少的内存并且计算速度非常快,但不幸的是提供低于标准的质量:
已经向我们指出了这一点,并且了解了问题并经过一些研究后,我们决定基于称为 xorshift128+ 的算法重新实现 Math.random。它使用 128 位内部状态,周期长度为 2^128 - 1,并通过了 TestU01 套件的所有测试。
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;
}
Run Code Online (Sandbox Code Playgroud)
在我们意识到这个问题的几天内,新的实现就登陆 V8 4.9.41.0。它将在 Chrome 49 中可用。Firefox 和 Safari 也都切换到 xorshift128+。
他们使用“类似时间的东西”是正确的。伪随机生成器通常使用系统时钟作为种子,因为这是一个不总是相同的数字的良好来源。
一旦随机生成器被植入一个数字,它将生成一系列数字,这些数字都取决于初始值,但它们看起来是随机的。
一个简单的随机生成器(之前在编程语言中实际使用过)是在这样的算法中使用素数:
rnd = (rnd * 7919 + 1) & 0xffff;
Run Code Online (Sandbox Code Playgroud)
这将产生一系列来回跳跃的数字,看似随机。例如:
seed = 1337
36408
22089
7208
63833
14360
11881
41480
13689
6648
Run Code Online (Sandbox Code Playgroud)
Javascript 中的随机生成器稍微复杂一些(以提供更好的分布)并使用更大的数字(因为它必须生成一个大约 60 位而不是 16 位的数字),但它遵循相同的基本原则。
| 归档时间: |
|
| 查看次数: |
18206 次 |
| 最近记录: |