【问题标题】:C++ Random Number Check for Very Small ProbabilitiesC++ 随机数检查非常小的概率
【发布时间】:2015-04-23 01:54:21
【问题描述】:

我发生事件的概率非常小(顺序为 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_MAX是什么?
  • 你在某个时候打电话给srand()吗?
  • 使用 g++ 4.8,frac_success 即使对于 Prob = 1e-6 也是准确的

标签: c++ random probability


【解决方案1】:

这听起来你的RAND_MAX 值太小了。

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

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

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

【讨论】:

    【解决方案2】:

    rand() 是一个非常糟糕的 RNG,仅用于实现井字游戏就可以,但不适用于任何严肃的业务。

    如果您不能使用 C+11 random 模块,您仍然可以利用 Boost.Random,它也适用于 C++03。浏览generators page 并寻找最适合的西装。

    【讨论】:

    • 这是 OP 问题的原因吗?
    • @OliverCharlesworth,因为 OP 写了 “我怎样才能以如此小的概率准确检查成功?”,我想问题是 rand() 的偏度在测试如此小的值 (1e-4) 时变得相关,从而产生有偏差的结果。 OP 需要随机值的良好均匀分布。
    • 有很多情况(例如测试)随机数的质量并不重要,所以它可以用于“严肃的业务”。您只需确保获得所需的位数,可能需要多次调用rand
    【解决方案3】:

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

    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 &lt; 1/RAND_MAX 附近)。实际上我不知道这是否可以通过简单地除以 RAND_MAX+1 来解决,但 here 是一个视频,它很好地戏剧化并解释了 rand() 的问题。

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-04-10
        • 2020-07-13
        • 2017-11-26
        • 2013-12-18
        • 2017-05-16
        • 2018-01-09
        • 1970-01-01
        相关资源
        最近更新 更多