【问题标题】:Random numbers generated using uniform real distribution in C++ are not really uniformly distributed在 C++ 中使用均匀实数分布生成的随机数并不是真正均匀分布的
【发布时间】:2015-08-14 04:22:41
【问题描述】:

我写了一个小代码来确保我可以从一个非常广泛的范围内获得随机数,例如。 [0, 10^36) 因为我稍后会使用这些宽范围。

我的代码如下:

#include <iostream>
#include <cmath>
#include <random>
#include <chrono>

int main()
{   unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    double expo = pow(10,36);
    std::uniform_real_distribution<double> dist(0,expo);
    std::mt19937_64 rng(seed);
    for (int i=0; i<10; i++)
        std::cout << dist(rng) << std::endl;
    return 0;
}   

以下是输出示例:

6.75507e+035
4.01129e+035
6.85525e+035
8.85896e+035
3.1455e+035
3.04962e+035
5.48817e+035
3.54502e+035
2.24337e+035
2.23367e+035

如您所见,随机数都非常接近给定区间的上端点。我尝试运行该程序很多次,也将 10 个数字增加到 100,但随机数总是接近区间的上端点(指数为 35,有时为 34)。

由于我使用了std::uniform_real_distribution,因此我希望也有一些数字,例如,有时会有 [0, 1000] 范围内的数字。我不认为这是一个均匀分布。这对我来说很重要,因为随机数不仅靠近上端点,因为我稍后将在 if 语句中使用随机数:

if (random_number == 0)
    //do some operations

而上端点实际上将用作发生某事的速率。但似乎随机数有时不可能为零。

我不知道为什么会发生这种情况,非常感谢任何想法或帮助。

(Eclipse 4.4.1,Windows 7)

【问题讨论】:

  • 如果std::uniform_real_distribution&lt;double&gt; dist(0,1000)(rng) 返回(精确)1000.0,那么您的实现中存在错误并且应该报告,因为间隔应该是半封闭的:[0, 1000)。返回 0 是可能的,但概率很小,可能小于千万亿分之一。

标签: c++ random


【解决方案1】:

如果你看一下情况的数学,一个数字更有可能有指数10^35,因为每个范围内都有可能的数字:

  • [1*10^35,1*10^36)范围内有9*10^34不同的数字
  • [1*10^34,1*10^35)范围内有9*10^33不同的数字
  • [1,1000]范围内有1000不同的数字

因此您可以看到,一个数字具有指数 10^35 的可能性比 10^3410 倍,而具有指数 10^35 的数字比 9*10^32 高在[1,1000] 范围内。

【讨论】:

    【解决方案2】:

    Benjamin Lindley 的回答很好。我想补充一点,您可能正在寻找一种不同的分布而不是均匀分布。你可以这样写:

    #include <iostream>
    #include <cmath>
    #include <random>
    #include <chrono>
    
    int main()
    {
        unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
        std::uniform_real_distribution<double> dist(0, 36);
        std::mt19937_64 rng(seed);
        for (int i = 0; i < 20; i++)
        {
            std::cout << pow(10, dist(rng)) << std::endl;
        }
        return 0;
    }
    

    该程序给了我以下输出:

    7.26972e+027
    5.97e+010
    3.50003e+034
    3.42446e+021
    2.93422e+035
    111.724
    2.73858e+019
    55641.4
    4.18253e+019
    7.47441e+007
    9.2706
    7.45588e+009
    3.26219e+007
    5.6794e+027
    4.67289e+026
    4.24672e+014
    3.97334e+010
    14.7511
    2.65037e+022
    85279.3
    

    【讨论】:

    • 这是个好主意,但正如我前面提到的,我以后应该使用上端点作为速率,所以我不允许更改它。 :/ 不过还是谢谢!
    • 我没有更改上端点,仍然是 10^36。我不小心将下端点从 0 更改为 1。
    • 你是对的。但是我的代码中的速率的意思是,例如对于 random_number=1,生成这个随机数的概率是 1/10^36。您的代码中的这种概率是 1/35 * 1/10^dist(rng) 。因为实际上概率是我的目的,而不是随机数本身,所以我不能使用你的代码,尽管我相信如果我没有考虑概率的限制,这是一个有趣的想法。
    【解决方案3】:

    如您所见,随机数都非常接近上限 给定区间的端点。

    不,他们不是。比如这个:

    2.23367e+035
    

    请注意,在[0, 1e36] 范围内,子范围[1e35, 1e36] 是子范围[0, 1e35] 的 9 倍,因此在均匀分布的情况下,您可以期望看到这些数字的频率是 9 倍.您会时不时地看到指数为 34 的数字,但任何更低的指数都极为罕见。

    【讨论】:

    • 没错!我没想到...所以这意味着它实际上是一个均匀分布。谢谢本杰明!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2020-04-04
    • 1970-01-01
    • 2012-09-18
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多