这段代码是否生成真·随机数

2018-01-04 14:12:42 +08:00
 begeekmyfriend

在 OJ 平台上刷题注意到一个现象,有的题用同一份代码,测试 benchmark 落点很稳定,有的在一个时间区间范围内跳跃,不太稳定。用方差描述的话叫做,benchmark 稳定方差小,不稳定方差大。

这就让我突发奇想,能否用一段代码的 benchmark 作为随机数?如果是真·随机数,那么这段代码岂不是可以用来作为随机数生成器了?

如何检验随机性?我考虑可以用 benchmark 落点概率分布来衡量。我设计了一套简陋的代码,其中调用了一些库函数 /系统函数,包括 random、usleep、malloc、free,还有 clock_gettime 用做 benchmark。循环 N 次,统计 benchmark 的所有落点,在终端输出,能够观测概率分布。代码在gist上。翻墙不便的直接贴出来

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int main(void)
{
        int i, j, k;
        int dim = 11;
        int num = 1024 * 1024;
        int loop = 1000;
        struct timespec start, end;
        size_t stat[200] = { 0 };

        for (k = 0; k < loop; k++) {
                usleep(50000);
                srandom(time(NULL));
                clock_gettime(CLOCK_MONOTONIC, &start);
                for (i = 0; i < num; i++) {
                        double *vector = malloc(dim * sizeof(double));
                        for (j = 0; j < dim; j++) {
                                vector[j] = (double) random() / RAND_MAX * 20 - 10;
                        }
                        free(vector);
                }
                clock_gettime(CLOCK_MONOTONIC, &end);
                size_t rand_ms = (end.tv_sec - start.tv_sec)*1000 + (end.tv_nsec - start.tv_nsec)/1000000;
                stat[rand_ms]++;
        }

        for (i = 0; i < sizeof(stat)/sizeof(*stat); i++) {
                printf("[%d](%f\%):", i, 100.0 * stat[i] / loop);
                for (j = 0; j < stat[i]; j++) {
                        putchar('-');
                }
                putchar('\n');
        }

        return 0;
}

目前循环次数为 1000,运行时间大约 4~5 分钟(机器好可以缩短到 3~4 分钟),我曾经设成 10W 次迭代跑了一个晚上。 原先预想的是,假设系统(或 runtime )稳定的话,benchmark 落点应该近似于正态分布。遗憾的是从终端输出上看,并没有达到随机的效果,但又不是收敛到一个稳定值上,分布比较离散化。

我的几点疑问:

由于仅凭终端输出,这段 C 代码在可视化上有局限,特别当样本量很大的话。Python 好的同学可以试试可视化的库。

5092 次点击
所在节点    程序员
79 条回复
facetest
2018-01-04 21:16:12 +08:00
不要以为代码行数多,看起来复杂就是真随机,之前听说过有些真随机数是用地球实时大气数据来生成的。
teloti
2018-01-04 21:30:31 +08:00
Valyrian
2018-01-04 21:43:05 +08:00
clock_gettime usleep 这些都是实实在在的方程,没有任何随机性。里面会像内核发 system call,然后内核会运行一些明确定义的代码。代码会在明确定义的 cpu 速度下运行,没有随机性
jason2017
2018-01-04 22:16:11 +08:00
真随机,目前只存在量子力学中。
而且,未来可能证实量子力学也未必是真随机。
alvinbone88
2018-01-04 23:10:17 +08:00
hjuj91
2018-01-04 23:19:21 +08:00
确定状态机怎么搞也搞不出真随机的
ipwx
2018-01-04 23:32:10 +08:00
读得太少,想得太多。

首先,随机数生成器得尽量减少相邻输出的关联性。这个 @alvinbone88 提到了。如果一个随机数生成器的相邻相关性太强,恭喜你,依赖这个随机数生成器的系统是存在安全漏洞,可以被攻击的。另外基于采样的各种蒙特卡洛算法在随机数生成器有相邻相关性的情况下都会 BOOOOOOOOOOOM。比如通过样本均值求期望(一种数值积分常用方法),相关性的存在会使得计算结果的方差上升,然后你的程序就跪了。

除了相关性,我觉得你的脑洞最糟糕的问题在于,你根本不知道这个“随机数生成器”生成的分布是什么。所以你既不能用它算东西(比如算积分),也不能用它产生别的分布(比如接受 /拒绝方法,借助一个均匀分布为代理来采别的分布的样本。一般用于别的分布非常难以采样,但是容易计算概率密度的情况)。根本不能拿来计算,那你这个随机数生成器到底有啥用?
kanex
2018-01-05 00:55:21 +08:00
lz 需要补习一些密码学基础知识,这样的代码是不可能生成真随机数的,生成的结果必定会存在一些概率(等等)模型上的 pattern
lepig
2018-01-05 09:09:32 +08:00
感觉楼上在神仙打架 我看不懂
arzterk
2018-01-05 09:28:21 +08:00
楼主的算法跟从一个内存里面随机位置读个数没啥区别啊
bramblex
2018-01-05 09:31:16 +08:00
楼主,你心里有民科的种子呀。
xAx
2018-01-05 09:50:27 +08:00
请搜索伪随机,向楼上说的,这是民科
zzNucker
2018-01-05 10:34:56 +08:00
楼主可能是语文学的不好,一个输入和纯代码的问题给他说了好几楼了都没转过来
youxiachai
2018-01-05 10:52:39 +08:00
土法炼随机数.....
反正这种时候...lz 开心就好了...
我们点头是是是就好了..
eurokingbai2
2018-01-05 11:11:21 +08:00
确实伪随机。你这段代码放到一个嵌入式芯片的单进程系统上跑,近乎于等值输出。
realpg
2018-01-05 13:10:08 +08:00
连真随机数是啥都不知道的就可以写真随机算法了……
我觉得还是别用什么 benchmark 了还得写代码,直接读一下风扇转速当随机数就行
LeoNG
2018-01-05 13:47:40 +08:00
@eastpiger #30 哥们你这 Blog 头像怎么都没改 - -
fantasua
2018-01-05 14:50:50 +08:00
不是说真正的随机数只存在现实世界中的物理现象中么,比如高斯白噪声什么的
860670496
2018-01-05 14:51:05 +08:00
@begeekmyfriend #10 单纯针对这楼发表一下意见,应该修正为“可观测宇宙”的“原子”数量是有限的,大约为 10^79,粒子数量暂时无法估计(拼图拼完了没有都还模糊着呢
另外我也觉的真随机数的定义就极难用实践方法证明
GeruzoniAnsasu
2018-01-05 15:06:13 +08:00
随机不等于均匀
随机数的分布更不一定是正态分布

真随机数的生成其实很简单,引入随机用户输入即可,benchmark 结果的随机也是由于系统各种运行环境影响产生的,而环境因素与过去历史用户操作密切相关,你其实就是期望通过引入系统运行不稳定性来制造随机

然而系统稳定性是可控的,我们完全可预测可计算 bechmark 什么时候结束,对于你这个算法来说,实际上期望结果是稳定的,完全不随机。

既然期望都是不随机的,你怎么还会想用它来制造随机数???

就算误差无法避免,这个算法中也没有过程来放大误差,假设误差时间在 1ms 到 10ms 之间,那随机数种子就只有 1 到 10 这么点结果,随机性能好到哪里去???

如果想靠计时误差来产生非可预测随机,首先记时精度一定要够高,并且,需要多次记时并引入混沌过程放大误差结果并消除可逆性,这样才能使种子足够“无法预测”

但无法预测是不是等于随机,抱歉,仍不知道

产生一个不可预测数后,返回固定分布的数很简单,筛子就行

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

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

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

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

© 2021 V2EX