【发布时间】:2016-06-15 17:43:18
【问题描述】:
为什么下面的 C 代码在我的桌面和服务器上给出不同的结果,两者都运行类似的 Linux 版本?
它在 18 万亿次抛硬币中找到连续序列中最长的同一边。 [参见 Iain M. Banks 的科幻小说考虑 Phlebas。]
在服务器上,经过 15.7 万亿次硬币抛掷(它仍在运行),到目前为止,行序列中最长的同侧序列只有 29 个。由于2^44 = 17,592,186,044,416,我希望最长的同侧序列在某处40 年代中期到 40 年代中期,在 18 万亿美元全部完成后可能是 44 年代。
在桌面上仅抛了 47 亿次硬币之后,最长的序列已经是 31,因为2^31 = 2,147,483,648,这听起来很正确。
那么为什么我在抛硬币 15.7 万亿次后在服务器上只有 29 个序列,而在我的桌面上只在 47 亿次后得到了 31 个序列?
模数偏差是我的第一个想法。 RAND_MAX 在桌面和服务器上都是相同的,2,147,483,647(32 位有符号长)。所以rand() 函数会给我一个数字0 <= rand() <= 2,147,483,647。 0 是偶数,2,147,483,647 是奇数,所以除非我错了,否则我的int rand_num = (rand() % 2); 代码行没有引入模偏差。
我知道 C 标准库的伪随机数生成器不适合加密。当然,在生成零和一的序列时,这肯定不是一个因素,诚然确实相当长。可以吗?
来源:
在两台机器上编译使用:gcc -O3 -o 18TCT 18TrillionCoinTosses.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char* argv[])
{
srand(time(NULL));
int current_seq = 0;
int longest_seq = 0;
int prev_rand_num = -1;
long long i = 0;
long long total = 18000000000000;
// To serve as a rudimentary progress indicator.
long billion_counter = 0;
long billion = 1000000000;
while (i < total)
{
int rand_num = (rand() % 2);
if (rand_num == prev_rand_num)
{
current_seq++;
if (current_seq >= longest_seq)
{
longest_seq = current_seq;
printf("Longest sequence so far: %d (on iteration %lli)\n", longest_seq, i);
}
}
else
current_seq = 1;
if (billion_counter == billion)
{
billion_counter = 0;
printf("Progress report, current iteration: %lli\n", i);
}
prev_rand_num = rand_num;
i++;
billion_counter++;
}
printf("\nTotal coins tossed: %lli\n", i);
printf("Longest sequence: %d\n", longest_seq);
}
【问题讨论】:
-
TL;博士。不要写小说。见How to Ask。
-
看起来问题是“为什么服务器和笔记本电脑之间的输出不同?”其余的 99% 都是绒毛。
-
老实说,我喜欢阅读。
-
我也很喜欢它,如果您花时间理解它,那不是“为什么服务器和笔记本电脑之间的输出不同?”。
-
rand()没有定义的实现规范,因此实现无处不在。许多实现是低性能线性同余生成器。使用rand()几乎肯定是个问题,我建议尝试使用更好的生成器,例如Mersenne Twister 或WELL