避免蒙特卡罗模拟中的基本rand()偏差?

我正在用C语言重写C中的蒙特卡罗模拟,以便在VBA / Excel的dll中使用。 计算中的“引擎”是创建0到10001之间的随机数,并与5000-7000邻域中的变量进行比较。 每次迭代使用4-800次,我使用100000次迭代。 因此,每次运行大约有50.000.000代随机数。

在Objective C中,测试表明没有偏见,我对C代码有很大的问题。 Objective C是C的超集,因此95%的代码都是复制粘贴,很难搞砸。 我昨天和今天整天经历了很多次,我没有发现任何问题。

我使用srand()留下了arc4random_uniform()和rand()之间的区别,特别是因为偏向0到10000的较低数字。我所进行的测试与.5的偏差是一致的。对于大约5000以下的数字,2%。任何其他解释是我的代码避免重复,我想它不会。

代码非常简单(“spiller1evne”和“spiller2evne”是5500到6500之间的数字):

srand((unsigned)time(NULL)); for (j=0;j<antala;++j){ [..] for (i=1;i<450;i++){ chance = (rand() % 10001); [..] if (grey==1) { if (chance < spiller1evnea) vinder = 1; else vinder = 2; } else{ if (chance < spiller2evnea) vinder = 2; else vinder = 1; } 

现在我不需要真正的随机性,伪随机性非常好。 我只需要在累积的基础上近似均匀分布(如果5555的可能性是5556的两倍并不重要。如果5500-5599的可能性为5600-5699并且可能性为5如果有明显的0.5-2%偏向0-4000而不是6000-9999。

首先,rand()是我的问题听起来有道理吗?是否有一个简单的实现满足我的低需求?

编辑:如果我的怀疑是合理的,我可以使用任何一个:

http://www.azillionmonkeys.com/qed/random.html

我是否可以将其作为替代品复制粘贴(我在C中编写并使用Visual Studio,真的是新手)?:

 #include  #define RS_SCALE (1.0 / (1.0 + RAND_MAX)) double drand (void) { double d; do { d = (((rand () * RS_SCALE) + rand ()) * RS_SCALE + rand ()) * RS_SCALE; } while (d >= 1); /* Round off */ return d; } #define irand(x) ((unsigned int) ((x) * drand ())) 

编辑2:很明显上面的代码没有相同的偏见,所以我建议任何拥有相同“中间路线”的人 – 如上所述。 它确实带来了惩罚,因为它调用rand()三次。 所以我仍然在寻找更快的解决方案。

rand()函数生成范围为[0, RAND_MAX ]的int 。 如果通过模数运算符( % )将其转换为不同的范围,就像原始代码那样,那么除非目标范围的大小恰好分为RAND_MAX + 1否则会引入非均匀性。 这听起来就像你看到的那样。

你有多种选择,但如果你想坚持使用基于rand()东西,那么我建议你采用原始方法的这种变化:

 /* * Returns a pseudo-random int selected from the uniform distribution * over the half-open interval [0, limit), provided that limit does not * exceed RAND_MAX. */ int range_rand(int limit) { int rand_bound = (RAND_MAX / limit) * limit; int r; while ((r = rand()) >= rand_bound) { /* empty */ } return r % limit; } 

虽然原则上每次调用该函数的rand()调用次数都是无限制的,但实际上,对于相对较小的limit值,平均调用次数仅略大于1,并且每个limit值的平均值小于2 。 它通过从[0, RAND_MAX ]的子集中选择初始随机数来消除前面描述的非均匀性,其中大小均匀地除以limit