我发生事件的概率非常小(1e-5阶)并且我试图使用统一的随机数来测试成功。当概率下降到大约1e-4时,成功的分数不再与下面的测试代码中的概率相匹配。
如何以如此小的概率准确检查成功?我尝试使用其他随机数生成器,但我找到的所有建议都是针对C ++ 11的,我没有使用。非常感谢提前!
#include <cstlib>
#include <iostream>
#include <cmath>
double Prob, rand_num, frac_success;
int num_success, num_tries;
Prob = 1e-4;
num_tries = 1e8;
num_success = 0;
for (int i=0; i<num_tries; i++) {
rand_num = (double) rand() / RAND_MAX; // random number between 0 and 1
if (rand_num < Prob) {
num_success ++; // Record success
}
}
frac_success = double(num_success) / double(num_tries);
cout << Prob << endl << frac_success << endl;
当Prob = 1e-3时,成功的比例大致等于Prob,但对于Prob = 1e-4,它总是大于1.2e-4。差异越大,概率越低,似乎不会通过增加尝试次数来解决。
编辑:
正如DiJuMx和Stefano Sanfilippo所说,似乎rand()根本不是一个足够好的发电机。我决定改用C ++ 11,所以我可以使用uniform_real_distribution来解决这个问题(这意味着对其他非C ++ 11代码进行了更改,但是很快就没有比我想象的更改了。)
答案 0 :(得分:2)
这听起来像RAND_MAX
的价值太小了。
考虑rand()
返回0
和RAND_MAX
之间的整数这一事实。如果您将此数字除以RAND_MAX
,那么除了0
之外,您可以获得的最小数字是1.0/RAND_MAX
。
当RAND_MAX
为32767
时,最小值为3e-5
。在我的计算机上,RAND_MAX
为2147483647
,因此最小值为4e-10
。
或者,看看Stefano关于使用C ++特定库的答案。
答案 1 :(得分:0)
rand()
是一个非常糟糕的RNG,它只适用于实施tic-tac-toe,但不适用于任何严肃的业务。
如果你不能使用C + 11 random
模块,你仍然可以利用Boost.Random
,它也适用于C ++ 03。浏览generators page并寻找最佳套装。
答案 2 :(得分:0)
首先,您必须考虑您的估算工具有一定的错误。我没有找到一个好的链接,简而言之就是:
H = success / trials // your estimator
E(H) = p // the expectation value is the real probability
Var(H) = p(1-p)/n // variance of your estimator
仅此一点就表明,对于较小的概率,您应该获得更好的结果。
但是,正如其他答案所示,您应该使用适当的随机数生成器。
rng应该以相同的概率产生每种可能的结果(如果它是均匀的)。让我们暂时说RAND_MAX=3
。如果我们经常运行它,每个可能的值将以相同的频率发生,并且我们得到相同的结果,就好像我们仅使用每个值一次。现在考虑
for (int i=0;i<4;i++){std::cout << (double)i/3 << std::endl;}
这将产生
0
0.333333
0.666667
1
对于不太小的概率,这将给出合理的结果(例如,当试图找到p=0.5
时,您可以找到确切的值)。但是,当你试图找到一个小概率时,结果会太大。
RAND_MAX=32767
时效果相同,它只显示较小的概率(约p < 1/RAND_MAX
附近)。实际上我不知道是否可以通过简单地除以RAND_MAX+1
来解决这个问题,但是here是一个非常好地戏剧化的视频,并解释了rand()的问题。
答案 3 :(得分:-1)
如果您怀疑随机数生成器存在偏差,可以通过大量运行并生成频率分布来检查它。
尝试使用不同的种子,看看偏见是否成立。
如果它确实存在稳定偏差,请记录分布并使用它来克服偏差。