2015-03-31 42 views
0

我正在从Objective C重写一个蒙特卡洛仿真,用于从VBA/Excel的DLL。计算中的“引擎”是创建一个介于0和10001之间的随机数,与5000-7000邻域中的变量进行比较。每次迭代使用4-800次,我使用100000次迭代。所以这是每次运行约50万次随机数。避免Monte Carlo模拟中的基本rand()偏差?

虽然在Objective C中测试显示没有偏见,但我对C代码有很大的问题。 Objective C是C的一个超集,所以95%的代码是复制粘贴并且很难搞砸。我昨天和今天整天都经历过很多次,而且我没有发现任何问题。

我留下了与使用srand()arc4random_uniform()和rand()之间的差异,尤其是因为偏向于更低的数字0到10000.我进行的测试与这种偏见一致对于低于大约5000的数字,0.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的可能性比5600-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

很简单的答案是,你不应该真的使用rand()进行严肃的蒙特卡洛模拟。 rand()是基于线性全等的,这很糟糕,你应该检查其他的RNG Mersenne Twister例如 – Jeanno 2015-03-31 14:06:39

回答

0

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均分。