gpt4 book ai didi

javascript - 随机数位数的分布

转载 作者:太空狗 更新时间:2023-10-29 17:07:39 25 4
gpt4 key购买 nike

我在尝试用 JavaScript 实现 UUID 生成器时遇到了这种奇怪的现象。

基本上,在 JavaScript 中,如果我在 Node 4.2.2 上使用内置的 Math.random() 生成大量随机数:

var records = {};
var l;
for (var i=0; i < 1e6; i += 1) {
l = String(Math.random()).length;
if (records[l]) {
records[l] += 1;
} else {
records[l] = 1;
}
}
console.log(records);

数字的数量有一个奇怪的模式:

{ '12': 1,
'13': 11,
'14': 65,
'15': 663,
'16': 6619,
'17': 66378,
'18': 611441,
'19': 281175,
'20': 30379,
'21': 2939,
'22': 282,
'23': 44,
'24': 3 }

我认为这是 V8 随机数生成器的一个怪癖,但类似的模式出现在 Python 3.4.3 中:

12 : 2
13 : 5
14 : 64
15 : 672
16 : 6736
17 : 66861
18 : 610907
19 : 280945
20 : 30455
21 : 3129
22 : 224

Python代码如下:

import random
random.seed()
records = {}
for i in range(0, 1000000):
n = random.random()
l = len(str(n))
try:
records[l] += 1
except KeyError:
records[l] = 1;

for i in sorted(records):
print(i, ':', records[i])

从 18 到以下的模式是预期的:假设随机数应该有 20 位,那么如果数字的最后一位是 0,它实际上只有 19 位。如果随机数生成器很好,发生这种情况的概率大约是 1/10。

但为什么 19 岁及以后的模式是相反的?

我猜这与 float 的二进制表示有关,但我无法弄清楚原因。

最佳答案

原因确实与浮点表示法有关。 float 表示具有它可以表示的最大(二进制)位数,以及有限的指数值范围。现在,当您不使用科学记数法打印出来时,在某些情况下,您可能需要在小数点后的有效数字开始之前有一些零。

您可以通过打印那些在转换为 string 时具有最长长度的随机数来可视化这种效果:

var records = {};
var l, r;
for (var i=0; i < 1e6; i += 1) {
r = Math.random();
l = String(r).length;
if (l === 23) {
console.log(r);
}
if (records[l]) {
records[l] += 1;
} else {
records[l] = 1;
}
}

这仅打印 23 长的字符串,您将得到如下数字:

0.000007411070483631654
0.000053944830052166104
0.000018188989763578967
0.000029525788901141325
0.000009613635131744402
0.000005937417234758158
0.000021099748521158368

注意第一个非零数字之前的零。这些实际上并不存储在浮点表示的数字部分中,而是由其指数部分隐含。

如果你要去掉前导零,然后进行计数:

var records = {};
var l, r, s;
for (var i=0; i < 1e6; i += 1) {
r = Math.random();
s = String(r).replace(/^[0\.]+/, '');
l = s.length;

if (records[l]) {
records[l] += 1;
} else {
records[l] = 1;
}
}

...你会得到不那么奇怪的结果。

但是,由于 javascript 将小数字转换为 string 的方式,您会看到一些不规则现象:当它们变得太小时,将在 中使用科学记数法code>string 表示。您可以通过以下脚本看到这一点(不确定是否每个浏览器都有相同的断点,所以您可能需要玩一下数字):

var i = 0.00000123456789012345678;
console.log(String(i), String(i/10));

这给了我以下输出:

0.0000012345678901234567 1.2345678901234568e-7

因此,非常小的数字将获得更固定的 string 长度,通常为 22 个字符,而在非科学记数法中,长度通常为 23。这也会影响我提供的第二个脚本,长度为 22 的点击率将高于 23。

需要注意的是,javascript在转换为二进制表示的string时不会切换为科学计数法:

var i = 0.1234567890123456789e-120;
console.log(i.toString(2));

以上将打印超过 450 个二进制数字的字符串!

关于javascript - 随机数位数的分布,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33582576/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com