18万亿投掷硬币,我哪里出错了?

mat*_*tst 3 c random

为什么以下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个序列?

Modulo偏见是我的第一个想法.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);
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*mit 6

您的随机数生成器可能在2 ^ 32 = 4294967296次调用后重复,因此您并未真正模拟18万亿次试验.您需要一个更好的RNG,一个保持超过32位内部状态的RNG.在许多系统上,只需调用random()而不是,就可以访问更好的RNG rand().(在我的系统上,man random说"随机 - 更好的随机数发生器"和"这个随机数发生器的周期非常大,约为16*((2**31)-1)".虽然那是"仅"34,359,738,352,这还不到18万亿.)

另外,作为一个侧点,rand() % 2是有风险的,虽然现在大多数RNG都没有会把你烧到那里的问题(如果你确实有这个问题,你就会知道,因为除此之外你还会得到0连续不管什么).


附录:您可以在C FAQ列表的问题13.15中找到对其他一些更好的随机数生成器的引用:http://c-faq.com/lib/rand.html.