当我意识到我的硬币翻转代码从未记录过连续超过15个头的任何条纹时,我正在研究St Petersburg Paradox的模拟。我运行模拟100,000,000次,这应该导致平均1526 头部 16 long 。
(0.5 ^ 16)x 100,000,000 = 1526
显然,出了点问题。#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(int argc, char const *argv[])
{
srand(time(0));
int i, lim = 100000000, streak = 0, maxstreak = 0;
for (i = 0; i < lim; ++i)
{
if (rand()%2) {
streak++;
if (streak > maxstreak) maxstreak = streak;
}
else streak = 0;
}
printf("Ran %d times, longest streak of %d\n", lim, maxstreak);
return 0;
}
每次都返回以下内容:
Ran 100000000 times, longest streak of 15
感谢您的帮助!
编辑:在Windows 7 x64上运行GCC 4.6.2版。一般来说,编程是新的。
编辑2:感谢大家的帮助!任何人都在坚持,我想知道目前的实施情况会限制15个头? rand()
函数如何被如此有趣地破解以产生这个问题?
答案 0 :(得分:4)
您的代码很好 - 这是您的C库的rand()
实现,显然低于标准。可能在输出的低位之间存在相关性,或者内部状态可能非常小(因此,您的100,000,000次试验实际上覆盖了发生器的整个输出序列多次)。
在第一种情况下(相关输出位),您可以将生成器的输出后处理为“白化”它,但在第二种情况下,您需要插入更好的实现,例如Mersenne Twister。
答案 1 :(得分:4)
尝试为随机数生成器选择不同的种子值。虽然rand()是一个非常好的随机数生成器,但它确实是一个伪随机数生成器。您可能希望阅读rand(man -s3 rand)的手册页,它明确指出您应该(对于某些实现)使用高阶位而不是低位位...
NOTES
The versions of rand() and srand() in the Linux C Library use the same
random number generator as random(3) and srandom(3), so the lower-order
bits should be as random as the higher-order bits. However, on older
rand() implementations, and on current implementations on different
systems, the lower-order bits are much less random than the higher-
order bits. Do not use this function in applications intended to be
portable when good randomness is needed. (Use random(3) instead.)
在不了解您正在运行程序的系统的更多信息的情况下,我们无法知道这是否是您的问题。但是尝试将代码更改为使用与2 ^ 0位不同的位。
运行你的版本对我有用,
/coinflipsim
Ran 100000000 times
head 50006650, streak 27
tail 49993350, streak 25
这是适用于我的代码,使用与位0不同的位,
int main(int argc, char const *argv[])
{
srand(time(0));
int i, lim = 100000000;
int head=0, tail=0;
int hstreak=0, tstreak=0;
int hstreakmax=0, tstreakmax=0;
for (i = 0; i < lim; ++i)
{
//if (rand()%2)
if( rand() & (1<<13) ) //pick a bit, try different bits
{
head++;
if( ++hstreak>hstreakmax) hstreakmax=hstreak;
tstreak=0;
}
else {
tail++;
if( ++tstreak>tstreakmax) tstreakmax=tstreak;
hstreak=0;
}
}
printf("Ran %d times\n",lim);
printf("head %d, streak %d\n",head,hstreakmax);
printf("tail %d, streak %d\n",tail,tstreakmax);
return 0;
}
将rand()%2行更改为此行并重新运行,
if( rand() & (1<<13) ) //pick a bit, try different bits
结果不同,
./coinflipsim
Ran 100000000 times
head 50001852, streak 25
tail 49998148, streak 28
答案 2 :(得分:2)
让X(i)成为第i个翻转头的事件。设E(i)= union {X(j)| i&lt; = j&lt; i + 16}是在i处开始连续16个头的事件。
您的分析假设事件E(i)是独立的。这是不正确的。如果E(i)没有发生,那么大大降低了直接在E(i-1),E(i-2)等之前发生的概率。
是正确的说E(i)和E(j)是独立的iff | i - j | &gt; = 16。
可能是你的随机数发生器不是很好。由于rand()
确实最终会产生确定性模式,因此随机生成器可能会产生一种模式,该模式永远不会为您提供16个偶数(或奇数)数字。