非常小概率的 C++ 随机数检查

C++ Random Number Check for Very Small Probabilities

我有一个事件发生的概率非常小(顺序为 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 代码的更改,但令人高兴的是,更改比我预期的要少)。

rand()是一个非常糟糕的随机数生成器,只用于井字游戏还可以,但不适合任何严肃的业务。

如果你不能使用 C+11 random 模块,你仍然可以利用 Boost.Random, which works with C++03 too. Browse the generators page 并寻找最合适的。

如果您怀疑您的随机数生成器有偏差,您可以通过 运行 多次检查并生成频率分布来检查它。

尝试使用不同的种子,看看偏差是否成立。

如果它确实有稳定的偏差,记录分布并用它来克服偏差。

听起来您的 RAND_MAX 值太小了。

考虑 rand() returns 一个介于 0RAND_MAX 之间的整数这一事实。如果你用这个数除以RAND_MAX,那么除了0,你能得到的最小数是1.0/RAND_MAX.

RAND_MAX32767时,最小值为3e-5。然而,在我的机器上,RAND_MAX2147483647,所以最小值是 4e-10

或者,查看 Stefano 关于使用 C++ 特定库的回答。

首先,您必须考虑到您的估算器存在一定的误差。没找到好的link,总之就是:

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() 问题的视频。