问题描述
有时,即使我正确使用并迭代了该引擎,也可以使用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)。结果如下图所示。该图表明,来自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/