我正在用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的较低数字。我所进行的测试与这样的偏差是一致的。对于大约5000以下的数字,.5到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的可能性为5500-5699并且可能性为5如果对0-4000有明显的0.5-2%偏差而不是6000-9999。
首先,rand()是我的问题听起来似乎有道理吗?是否有一个简单的实现满足我的低需求?
编辑:如果我的怀疑是合理的,我可以使用任何一个:http://www.azillionmonkeys.com/qed/random.html
我是否可以将其作为替代品复制粘贴(我在C中编写并使用Visual Studio,真的是新手)?:
#include <stdlib.h>
#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 ()))
EDIT2:很明显上面的代码在没有相同偏见的情况下工作,所以我建议任何拥有与上述相同的“中间路线”的人。它确实带来了惩罚,因为它调用rand()三次。所以我仍然在寻找更快的解决方案。
答案 0 :(得分:0)
rand()
函数会在[0,int
]范围内生成RAND_MAX
。如果通过模数运算符(%
)将其转换为不同的范围,就像原始代码那样,那么除非目标范围的大小恰好均分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
。