有没有人怀疑过 rand()函数得到的随机数并不随机?

2017-05-30 21:20:33 +08:00
 tianxiacangshen
我下载了国外某权威抽奖网站的 300 万期开奖号码的数据,然后自己用 rand()根据开奖规则随机产生了一些号码作为开奖号码,也是 300 万期,分析某个数值比如 9 隔多长时间出现一次的概率,发现有较为明显的差别:

这是彩票网站统计的数据:
90--1--0.0004% (意思是隔 90 期才出现 1 次,概率 0.0004%)
89--0--0%
88--0--0%
87--1--0.0004%
86--2--0.0007%
85--0--0%
84--0--0%
83--0--0%
82--1--0.0004%
81--0--0%
80--0--0%
79--1--0.0004%
78--1--0.0004%
77--1--0.0004%
76--0--0%
75--1--0.0004%
74--1--0.0004%
73--3--0.0011%
72--7--0.0026%
71--2--0.0007%
70--2--0.0007%
69--3--0.0011%
68--11--0.0041%
67--2--0.0007%
66--9--0.0034%
65--8--0.003%
64--11--0.0041%
63--11--0.0041%
62--10--0.0037%
61--4--0.0015%
60--13--0.0049%
59--14--0.0052%
58--14--0.0052%
57--21--0.0078%
56--21--0.0078%
55--18--0.0067%
54--17--0.0064%
53--24--0.009%
52--41--0.0153%
51--42--0.0157%
50--38--0.0142%
49--57--0.0213%
48--76--0.0284%
47--86--0.0321%
46--86--0.0321%
45--100--0.0374%
44--116--0.0433%
43--130--0.0486%
42--144--0.0538%
41--153--0.0572%
40--168--0.0628%
39--227--0.0848%
38--227--0.0848%
37--284--0.1061%
36--347--0.1297%
35--353--0.1319%
34--431--0.1611%
33--491--0.1835%
32--523--0.1954%
31--596--0.2227%
30--704--0.2631%
29--802--0.2997%
28--931--0.3479%
27--962--0.3595%
26--1161--0.4338%
25--1321--0.4936%
24--1536--0.574%
23--1755--0.6558%
22--2009--0.7507%
21--2305--0.8613%
20--2769--1.0347%
19--3096--1.1569%
18--3465--1.2948%
17--3917--1.4637%
16--4508--1.6845%
15--5280--1.973%
14--5922--2.2129%
13--6769--2.5294%
12--7779--2.9068%
11--8770--3.2771%
10--10043--3.7528%
9--11553--4.317%
8--12872--4.8099%
7--15013--5.6099%
6--17385--6.4962%
5--19536--7.3%
4--22339--8.3474%
3--25558--9.5502%
2--29304--10.95%
1--33414--12.4858%

下面是我用 rand 生成的开奖号码中该数值的统计:
90--0--0%
89--0--0%
88--0--0%
87--0--0%
86--0--0%
85--0--0%
84--0--0%
83--0--0%
82--0--0%
81--0--0%
80--0--0%
79--0--0%
78--66--0.0247%(注意这里)
77--0--0%
76--0--0%
75--0--0%
74--0--0%
73--0--0%
72--0--0%
71--0--0%
70--0--0%
69--0--0%
68--0--0%
67--0--0%
66--0--0%
65--0--0%
64--0--0%
63--0--0%
62--0--0%
61--0--0%
60--0--0%
59--65--0.0243%(注意这里)
58--0--0%
57--0--0%
56--0--0%
55--131--0.049%(注意这里)
54--0--0%
53--0--0%
52--0--0%
51--0--0%
50--65--0.0243%(注意这里)
49--66--0.0247%(注意这里)
48--0--0%
47--0--0%
46--0--0%
45--131--0.049%
44--131--0.049%
43--66--0.0247%
42--65--0.0243%
41--261--0.0975%
40--0--0%
39--327--0.1222%
38--130--0.0486%
37--326--0.1218%
36--459--0.1715%
35--524--0.1958%
34--459--0.1715%
33--523--0.1954%
32--721--0.2694%
31--523--0.1954%
30--196--0.0732%
29--1044--0.3901%
28--918--0.343%
27--652--0.2436%
26--1376--0.5142%
25--1572--0.5874%
24--1437--0.537%
23--1568--0.5859%
22--2426--0.9065%
21--2229--0.8329%
20--2620--0.979%
19--3471--1.297%
18--3338--1.2473%
17--3666--1.3699%
16--3795--1.4181%
15--5760--2.1523%
14--5952--2.2241%
13--6550--2.4475%
12--8180--3.0566%
11--9493--3.5472%
10--10683--3.9919%
9--11662--4.3577%
8--13614--5.0871%
7--15721--5.8744%
6--14404--5.3823%
5--19586--7.3187%
4--22190--8.2917%
3--26386--9.8596%
2--28525--10.6589%
1--33564--12.5418%

这么大的差别,足以证明 rand 并不是很靠谱的随机函数吧

纯技术分析,别骂我闲得蛋疼.... /:哭笑
16105 次点击
所在节点    PHP
91 条回复
doctorlai
2017-05-31 01:55:11 +08:00
ryd994
2017-05-31 03:22:16 +08:00
@vibbow Linux 默认 /dev/random 就是从物理事件获得的随机熵 比如寻道时间,键盘鼠标事件
对于不要求完全随机的,还有 /dev/urandom,就是以 random 为种子,如果熵池不够的话就会用软件补齐
Intel 近年的 CPU 带热噪声随机数生成器
当你 Linux 还讨论过要不要用
现在是也一起混入熵池,反正全部是 xor 进去的
ryd994
2017-05-31 03:25:21 +08:00
@jininij 还有硬盘寻道和鼠标键盘事件
ynyounuo
2017-05-31 03:49:54 +08:00
@msg7086 滚一次骰子拿不到 42 这么大呀
phrack
2017-05-31 07:28:32 +08:00
知识不够 v2 来补


让你不好好学习基础
tianxiacangshen
2017-05-31 08:25:44 +08:00
@phrack 惭愧惭愧
andyhuzhill
2017-05-31 08:48:01 +08:00
@grimpil 我也想知道 随机数怎么能够预测?
Halry
2017-05-31 08:56:24 +08:00
部分可以调用芯片内的 trng,做到了比较真的随机数
intel 好像从 haswell 开始芯片里面就内置了 secure key 生成器,出来的随机数还算比较真吧
jeffersonpig
2017-05-31 08:57:38 +08:00
@ynyounuo 但它就是宇宙的终极答案
jeffersonpig
2017-05-31 09:00:35 +08:00
@yangff 2333 买过《具体数学》结果收到货了才发现是封面是中文内容是英文原版,从此供起在书架上再也没碰过
breeswish
2017-05-31 09:06:39 +08:00
rand() 当然不随机,不仅有线性性而且是可预测的。
好几次 CTF 都有过需要预测 PHP 随机数的题了。
breeswish
2017-05-31 09:08:11 +08:00
附链接,自己以前一个预测随机数的方案: https://breeswish.org/blog/2016/03/16/0ctf-2016-quals-rand-2-writeup/
coolypf
2017-05-31 09:16:25 +08:00
C++ 可以用 std::mt19937 和 std::mt19937_64 生成高质量伪随机数。
参见 http://www.cplusplus.com/reference/random/
blankme
2017-05-31 09:20:19 +08:00
@breeswish 伪随机的可预测性不影响随机性,这两个是不矛盾的。

只要随机序列满足一定的测试要求,就可以用于模拟计算,即使这个序列是已知的。

随机数产生器的很多应用场景并不要求“未知”,而是要求满足均匀分布的统计特性。
reus
2017-05-31 09:43:26 +08:00
linux 可以读 /dev/urandom 或者 /dev/random,这个是比较随机的,因为数据源是各种设备驱动的事件,例如你键盘的输入可以看作是随机的吧,鼠标的移动也是,硬盘的读写也会产生各种事件,还有网络那些。比纯算法产生的好得多。windows 也有类似的设施。
Canrz
2017-05-31 09:45:07 +08:00
@shoaly #17 之前网易的一元夺宝就是采用的这种方式
neighbads
2017-05-31 09:49:29 +08:00
热噪声。硬件产生的,国密局有随机数检测要求,,
caniuse
2017-05-31 09:51:15 +08:00
random_bytes
bk201
2017-05-31 09:59:03 +08:00
我就想知道你怎么知道这个不是随机数?你告诉我看分布?
Clarencep
2017-05-31 10:10:37 +08:00
一般各种语言的基本库里面的 rand()函数不都配对一个 srand()的设置随机数种子的函数吗? 相同的种子后面产生的随机数都是一样的, 那自然随机性不是那么的好。

linux 下的 /dev/random 是一个不错的选择。但是使用 linux 的 /dev/random 的时候要注意,很有可能会被阻塞住的:

参考 wikipedia:
> 发生器有一个容纳噪声数据的熵池,在读取时,/dev/random 设备会返回小于熵池噪声总数的随机字节。/dev/random 可生成高随机性的公钥或一次性密码本。若熵池空了,对 /dev/random 的读操作将会被阻塞,直到收集到了足够的环境噪声为止[3]。这样的设计使得 /dev/random 是真正的随机数发生器,提供了最大可能的随机数据熵,建议在需要生成高强度的密钥时使用。
> /dev/random 的一个副本是 /dev/urandom (“ unblocked ”,非阻塞的随机数发生器[4]),它会重复使用熵池中的数据以产生伪随机数据。这表示对 /dev/urandom 的读取操作不会产生阻塞,但其输出的熵可能小于 /dev/random 的。它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/364780

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX