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

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 好的同学可以试试可视化的库。

5091 次点击
所在节点    程序员
79 条回复
eastpiger
2018-01-04 14:23:31 +08:00
不可能

存在偏差的原因很复杂,OS 底层上看到的,或许有进程调度问题,有 IO 请求的延迟等待,有可能遇到内存页 miss,有可能即将执行的指令被 CPU 尝试预测到了等等。尽管看起来很复杂,但是这些大部分在系统层面都是可预测的可重现的。而且分布不可预测。目测并不会有很均匀的随机效果

> 假设系统(或 runtime )稳定的话
如何定义一个系统是“稳定”的呢。扣字眼一点的话,只有正常运转与不正常运转之分。压力大与小只要没有崩溃,这个系统都是稳定正确的呢。

一般情况下也不是很需要真随机数的吧。真的特别需要的话,https://www.random.org/ 是个好选择。
begeekmyfriend
2018-01-04 14:37:55 +08:00
@eastpiger 分布不均匀的话,还能否等同于随机?或者说随机数生成器必须是均匀分布的?
eastpiger
2018-01-04 14:45:05 +08:00
> Randomness is the lack of pattern or predictability in events.[1] A random sequence of events, symbols or steps has no order and does not follow an intelligible pattern or combination. Individual random events are by definition unpredictable, but in many cases the frequency of different outcomes over a large number of events (or "trials") is predictable. For example, when throwing two dice, the outcome of any particular roll is unpredictable, but a sum of 7 will occur twice as often as 4. In this view, randomness is a measure of uncertainty of an outcome, rather than haphazardness, and applies to concepts of chance, probability, and information entropy.

来自 wikipedia 词条 Randomness

个人理解,随机与分布没有相关性。随机的定义是围绕在数据不可预测和无规律上。而分布究竟如何,并不是一个限制条件,只是不同类型的随机分布的 feature 罢了。
begeekmyfriend
2018-01-04 14:50:12 +08:00
@eastpiger 既然满足不可预测和无规律这个条件就可以定义为“随机”的话,我觉得貌似存在一些参数,或一些技巧,可以将程序设计成运行时间“不可预测和无规律”的,比如我现在的随机值是 ms,那我可以用 ns 然后取余行不行?
JKeita
2018-01-04 14:52:55 +08:00
只要是代码生成的都是假随机数吧。
begeekmyfriend
2018-01-04 14:54:31 +08:00
@JKeita 如何证伪?
fcten
2018-01-04 15:06:28 +08:00
结果确实是随机数,但是随机性不好,缺少实用价值
顺便,这个随机数算法的性能太差了
begeekmyfriend
2018-01-04 15:23:22 +08:00
@fcten 性能其实不是问题,总是可以优化的,你甚至可以用底层语言去实现一个。至于随机性,我说过用 ns 取余等技巧。问题是如果是真·随机,那么已经证明纯代码是可以生成真·随机数的。
akira
2018-01-04 15:25:05 +08:00
真·随机数 是否存在是个哲学问题。
纯代码生成随机数,因为机器的状态是有限的,最终在数学上是可以证明有规律的。也就是公认的伪随机数了。

目前常见的号称 真·随机数的做法,都是依赖外部物理输入来产生的。
begeekmyfriend
2018-01-04 15:26:55 +08:00
@akira 宇宙的粒子数目也是有限的,那么状态也是有限的,难道这证明宇宙不存在随机?
eastpiger
2018-01-04 15:30:45 +08:00
这里看你的真随机数定义是怎么样了。

目前常见理解里,最为严格的定义观点来看,这个世界上只有一种真随机:取量子观测数据。

而目前比较广泛接受的稍微弱化一些的定义,一般认为来自物理学环境观测的数据属于真随机。常见用于各种硬件随机数生成器,比如热噪声或者光噪声采集卡。这种数据本身弱于量子观测数据,但是对于当前人类技术而言也还算可以、

至于程序生成的各种算法上。除了民用日用的并不严格的领域以外,基本上也没人承认过其能达到真随机的地步。
MonoLogueChi
2018-01-04 15:32:24 +08:00
按分布密度来说,现在能找到的随机数生成放到应该都能生成分布密度符合要求的随机数,但是从定义上来说,这些随机数都不是真随机数。想要验证可以把生成的随机数保存成日志,然后分析这些随机数的分布概率密度
begeekmyfriend
2018-01-04 15:34:44 +08:00
@MonoLogueChi 也存在无法分析概率密度的随机值
eastpiger
2018-01-04 15:34:47 +08:00
> 宇宙的粒子数目也是有限的,那么状态也是有限的,难道这证明宇宙不存在随机?

有限数据与随机性并无直接关联。有限数据是可以构成不可预测的随机序列的。

况且量子观测数据的理论重点在于其在观测前,叠加态无法预测

CPU 的运转这种相比之下已经很宏观的事情,还没有这个底气跟量子力学比试比试,甚至就连比比物理噪声都差得远
begeekmyfriend
2018-01-04 15:35:45 +08:00
@eastpiger 谁说 CPU 运行就没有物理噪声了?
fcten
2018-01-04 15:39:25 +08:00
@begeekmyfriend
1、O(n)的算法再怎么优化也不可能实现 O(1)的性能
2、这不是代码产生的随机数,代码产生的随机数应当与硬件无关,而 CPU 运算时间是一个与硬件有关的数据
3、依赖硬件产生真随机数的方法有很多
eastpiger
2018-01-04 15:41:53 +08:00
当然可以认为 everything 都受到物理噪声的影响。但是 CPU 并不是噪声发生器,其本身信号数据的信噪比非常高(不然我们的电脑还怎么运转呢)。你给出的方法更大程度上取决于 OS 层级的调度,CPU 层级的优化和实现,时钟信号和外部重点数据 IO,噪声在内部根本就是忽略不计的量级。

所以说啊,不能因为 CPU 本身有噪声,就认为 CPU 拿到的数据就是噪声影响的。实际上很可能那点噪声的影响根本都不到一个最小观测单位呢。

楼主小心走向啊民科啊 [逃
begeekmyfriend
2018-01-04 15:44:09 +08:00
@fcten
1、O(1)也是可以的,实际上 OJ 刷题是就碰到过用 hashmap 的题目 benchmark 在区间跳跃的,这些都是技巧实现细节的问题
2、样本就是 benchmark,这不是代码生成还是什么生成的?
3、纯代码生成真·随机的不知还有啥方法?
nigelvon
2018-01-04 15:45:39 +08:00
和粒子数有啥关系,0 和 1 两种状态就够了啊。
begeekmyfriend
2018-01-04 15:46:47 +08:00
@eastpiger 我不是民科,我是炼丹,就跟机器学习一样,真炼出来就“科学”了。另外,就算很大程度上依赖于 OS 调度,CPU 时钟等,那就说明真·随机数生成器本身是可以被设计的。

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

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

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

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

© 2021 V2EX