c++ - boost::random经常在不同状态下从同一种子生成相同值

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

问题描述

有时,即使我正确使用并迭代了该引擎,也可以使用Mersenne Twister引擎从均匀分布中获得相同的随机数。我知道引擎的可能状态数量是有限的,可能生成的值的数量也是有限的,但是现在不是这种情况。

使用boost的实现,在范围[0; 0; 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与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这样的著名库进行质量分析。我不想使用标准库,因为不能保证两个不同的编译器为相同的种子值提供相同的序列,但这是任务的要求。您可以提出什么样的解决方案?

注意

如果将生成的值与一个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序列中的两个值相等时,标准库序列中的值不相等,而是彼此接近。 MSVS和g ++编译器也具有相似性,它们有权对Mersenne Twister和发行版使用不同的实现。



更新资料

可怜的种子?

有人提出,可能是由于种子值不佳导致了这种现象,因为使用size_t只能生成2^64多个不同的初始状态。更糟糕的是,我们的生命很短暂,可能的时间价值甚至更少。尽管这是事实,但并不能解释为什么从不同的状态多次生成相同的数字。毕竟,引擎仅启动一次,因此我从64位子集中选择了一个状态,这是所有可能状态的子集。

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

它是分布生成器

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

一些统计

我对分布进行了一些分析。使用相同的boost::random::mt19937 engine,但使用boost或std的uniform_real_distribution<double> u(0, 1),我生成了值对并研究了它们之间的差异并绘制了它们的相关积分I(x),即两个值比x更近的概率。为U [0; 1)是一维域,I(x)从x值小的线性函数开始(并趋于1)。结果如下图所示。
A plot showing the correlation integral for std and boost along with the expected value
该图表明,来自boost实现的分布不仅具有偏差,而且仅存在4个可能的距离值,而已知double更加密集,并且std实际上产生了更大的距离值谱。

错误还是没有错误?删除的答案

一个已经删除的答案建议提高种子值,但到目前为止,事实并非这是问题的根源。从那时起,我将此问题发布在boost's github too上,但仍然不清楚问题出在哪里。这可能是提升的一个漏洞,但是即使在那种情况下,此SO源也可以帮助其他人识别其分布生成器中的问题。

最佳答案

这不是Boost中的错误。问题是由于较旧的32位MersenneTwister提供的分辨率有限。您在累积分布上看到的步骤等于$ 1/2 ^ {32} \ approx 10 ^ {-10} $。几年前,我意识到这种模拟导致了代价高昂的现实失败。解决方案是使用RNG,该RNG能够通过所有统计测试套件(例如MersenneTwister64或MIXMAX),并产生全精度的双精度。

关于c++ - boost::random经常在不同状态下从同一种子生成相同值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59039358/

相关文章:

java - 使用SAST工具时,为什么编译语言(例如C/C++)必须使用 "build wrapper"?

c++ - boost::iostreams::counter 似乎不起作用

c++ - 一个 QWebEnginePage 用于两个或多个 QWebEngineView

c++ - 在 C++ 中找出随机数生成器的种子

javascript - 图像的随机位置

kotlin 从数组中获取随机字符串

c++ - Boost Log 清除日志文件

c++ - Boost::Log 使用具有多个接收器的相同后端的安全性

c++ - 标准化之前多长时间 `string` 可用?

c++ - 安装 OpenGL AUX 库