【问题标题】:boost::random generates identical values too often from the same seed at different statesboost::random 经常从不同状态的相同种子生成相同的值
【发布时间】:2020-03-21 04:32:14
【问题描述】:

问题描述

有时我使用 Mersenne Twister 引擎从均匀分布中得到相同的随机数,即使我正确使用了引擎并对其进行了迭代。我知道引擎的可能状态的数量是有限的,可能生成的值的数量也是有限的,但现在情况并非如此。

使用boost的实现,在范围[0;上生成1e6个均匀分布的随机值; 1e7)。这意味着可能的值比所需的随机值数量要多。但是,我经常得到相同的值,有时在这个范围内超过 100 倍。怎么可能?

代码

提供了一个简单的代码来重现这种情况。在两个平台上我都遇到了同样的问题:

  • MSVS 2019 与 boost-random:x64-windows 1.71.0,和
  • g++ (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609 with libboost-dev 1.58.0.1ubuntu1
#include <iostream>
#include <chrono>

#include <boost/random/mersenne_twister.hpp>          // random number generator
#include <boost/random/uniform_real_distribution.hpp> // uniform distribution generator
using namespace std;

int main()
{
    size_t seed = static_cast<int> (std::chrono::system_clock::now().time_since_epoch().count());
    cout << "seed = " << seed << endl;
    
    boost::random::mt19937 engine(seed);                         // the random number generator engine
    boost::random::uniform_real_distribution<double> u(0, 1e7);  // uniformly distributed double values on the range [0; 1e7)
    cout.precision(20);
    vector<double> history;                                      // stores the generated values for comparison
    for (size_t i = 0; i < 1e6; ++i)
    {
        history.push_back(u(engine));
        for (size_t j = 0; j < i; ++j)
            if (history[i] == history[j])
                cout << "Equal values ("<< history[i] <<") at ID = " << i << " and " << j << endl;
    }
}

问题

代码中是否存在产生相同值的错误?还是boost中的一个bug?

对于我的任务,生成均匀分布的数字很重要。找到相同的值是最简单的测试之一,但还有更多,我确信我不想对像 Boost 这样的知名库进行质量分析。我不想使用标准库,因为不能保证两个不同的编译器会为相同的种子值提供相同的序列,但这是任务的要求。您能提出什么样的解决方案?

注意

如果将生成的值与std::random generates 进行比较,就会发现一种奇怪的行为。种子 4561565448989 的来自 random::boost 的值的示例是

1755586.0406719148159
3354420.976247638464   <--
3630764.0071026980877
3488445.2889673411846  <--
7920481.4555123448372
8773544.1024415194988  <--

当标准库生成时

3354420.9766563926823  <--
3488445.2898126943037  <--
8773544.1042856499553  <--
...

也就是说,boost 序列中每一秒生成的值都非常接近标准库实现中的对应值。当 boost-sequence 中的两个值相等时,standard-library-sequence 中的值不相等,而是彼此接近。 MSVS 和 g++ 编译器也有相似之处,它们有权为 Mersenne Twister 和发行版提供不同的实现。


更新

可怜的种子?

有人建议,可能是种子值差导致了这种现象,因为size_t 只能生成2^64 数量的不同初始状态。更糟糕的是,我们的生命很短暂,可能的时间价值更小。虽然这是真的,但它并不能解释为什么不同的状态会多次生成相同的数字。毕竟,引擎只启动一次,所以我从 64 位子集中选择了一个状态,它是所有可能状态的子集。

如果我多次启动引擎并且我在不同(但不够不同)启动的引擎的序列中发现相同的值,则可能是种子不佳的原因。

是分布生成器

如果使用标准的 MT 引擎,但使用 boost 的分布,问题仍然存在。但是如果引擎是boost的引擎并且分配是标准的,那么问题就消失了。问题是,正如Peter pointed out,统一分布取决于我使用 boost 的平台。

一些统计数据

我对分布做了一点分析。使用相同的boost::random::mt19937 engine,但使用boost 或std 的uniform_real_distribution&lt;double&gt; u(0, 1),我生成了值对并研究了它们的差异并绘制了它们的相关积分I(x),即两个值比 x 更接近的概率。作为U[0; 1) 是一维域,I(x) 以线性函数开始,用于小 x 值(并趋于 1)。结果如下图所示。 该图表明来自 boost 实现的分布不仅有偏差,而且只有 4 个可能的距离值,而众所周知 doubles 更密集,而 std 确实产生了更大的距离值谱。

bug还是不是bug?已删除的答案

一个已删除的答案建议改进种子值,但到目前为止,它证明这不是问题的根源。从那以后,我在boost's github too 上发布了这个问题,但仍然不清楚问题出在哪里。这可能是 boost 中的一个错误,但即使在这种情况下,此 SO 源也可以帮助其他人识别其分发生成器中的问题。

【问题讨论】:

  • 您是否从 boost.org 下载了最新版本的 boost 并尝试过?如果您确实需要提交错误报告,1.58 版太旧了,无法提供补丁。
  • @user14717 我已经在 Windows 上安装了 boost 1.71,它具有相同的行为。

标签: c++ random boost mersenne-twister uniform-distribution


【解决方案1】:

这不是 Boost 中的错误。问题是由于较旧的 32 位 MersenneTwister 提供的分辨率有限。您在累积分布上看到的步长等于 2-32 ~ 10-10。几年前,我意识到了一个代价高昂的现实世界模拟失败。解决方案是使用能够产生全精度双精度的 RNG,同时通过所有统计测试套件,例如 MersenneTwister64 或 MIXMAX,后者现在可以在 Boost 中使用

【讨论】:

    猜你喜欢
    • 2010-12-23
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 2014-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多