为什么使用mingw gcc4.8.1的std :: random_device每次运行都得到相同的序列?


70

我使用以下代码来测试C ++<random>库。

为什么每次编译的可执行文件都会得到完全相同的序列?是rd()在编译时确定的?每次运行如何获得不同的输出?

Windows 7 64位上的GCC 4.8.1。使用http://nuwen.net/mingw.html中的MinGW分发。

编辑:我用Visual Studio测试了相同的代码。没有问题。输出是不确定的。这可能是我使用的mingw gcc 4.8.1中的错误。

#include <iostream>
#include <random>
using namespace std;

int main(){
 random_device rd;
 mt19937 mt(rd());
 uniform_int_distribution<int> dist(0,99);
 for (int i = 0; i< 16; ++i){
    cout<<dist(mt)<<" ";
 }
 cout <<endl;
}

5
请平台和编译器。即使使用,也绝对不会发生这种情况entropy() == 0。如果确实如此,那是一个错误。
Konrad Rudolph 2013年

9
@MM。不,那不是random_device工作原理。
Konrad Rudolph 2013年

5
您可以让编译器打印宏的内容_GLIBCXX_USE_RANDOM_TR1吗?如果为0,则使用带有固定种子的mt19937作为后备。
Konrad Rudolph 2013年

3
使用gcc 4.9.2
MM

4
是否有人尝试向GCC报告错误以便可以解决?还是问得太多?
乔纳森·威克利

Answers:


34

http://en.cppreference.com/w/cpp/numeric/random/random_device

注意,如果不确定源(例如,硬件设备)不可用于实现,则可以使用伪随机数引擎来实现std :: random_device。

我希望一个体面的实施至少可以为RNG注入种子。

编辑:我怀疑他们每次都故意选择传递相同的序列,以使流不像所承诺的那样随机这一事实显而易见。


10
我同意。stdlibc ++的后备实现使用常量种子,这不会让我感到那么聪明(并且没有解释)。
Konrad Rudolph 2013年

17
真正的失败是首先使这种伪随机回退。
ypnos 2014年

6
@ypnos:该标准必须做一些事情以涵盖确定性平台上C ++实现的情况。但是,在真实平台上进行操作是一个巨大的实现质量问题。另请参阅如何简洁,可移植和彻底播种mt19937 PRNG?
彼得·科德斯

26

从MSFT的STL得到了确认的答案:

与VC不同,GCC尚未在Windows上不确定地实现random_device。Boost具有,因此您可以使用Boost.Random。


1
我还没有找到合适的文档来指示gcc中需要哪些升压库-l和哪些顺序的升压-l来避免链接错误,并且还需要任何系统-l。仅添加-lboost-random-mgw48-mt-d-1_57会导致链接器抱怨没有boost :: random :: random_device(),也没有boost :: random ::〜random_device()
Brian Jack


3

这是GCC错误,已在GCC 9.2中修复。

如果遇到此问题,请更新编译器。(例如,您可以从MSYS2获得新的GCC。)


@northerner运行pacman -Syuu。发生了变化,它将关闭终端(和所有msys2程序)以继续进行;较旧的版本会要求您手动执行。如果发生任何此类情况,则必须重新启动MSYS2并再次运行相同的命令以完成更新。
HolyBlackCat

更新失败stackoverflow.com/questions/63201980/…另外,我已经拥有GCC 9.1,random_device但仍然无法正常工作。
北方人

@northerner嗯,正如我所说的,它在GCC 9.2中已修复,而您的版本比该版本更旧。尝试重新安装MSYS2。
HolyBlackCat

2
  1. GCC无法正确实现rd.entropy()-始终返回0(至少在Mac OS X上如此)。

  2. 不幸的是,似乎没有办法将额外的熵混合到random_device中,这很重要,因为它通常(通常是Linux的/ dev / random和/ dev / urandom,以及Intel RDRAND实现)实现了伪随机数生成器在引擎盖下。我希望能够通过注入我认为是随机的东西与它的熵源产生的任何东西混合来提高其输出。同样,由于此设备(或内核模块)在内部实现了一种加密算法来处理其获取的熵位以生成其输出,因此我希望能够通过注入我自己的数据与任何东西混合来“随机化”更多该过程设备选择的熵。例如,考虑Java SecureRandom()。它不允许您设置 种子(的确可以将其转换为PRNG),但它会愉快地将您提供的内容与所使用的内容进行更多地“随机化”。

  3. 我个人更喜欢RDRAND。具有紧凑C接口的小型汇编库。这里是参考:

    英特尔的David Johnson在Stackoverflow上解释了RDRAND

    Windows,Linux和Mac OS X的RDRAND库源的Stackoverflow指针

    RDRAND库上的英特尔博客以及下载链接


6
播种是没有意义的random_device。如果需要种子,则它应该是伪随机数生成器,而不是真正的随机数生成器random_device
克里斯·贝克

3
“种子”是一个不幸的名词。您不会“播种”“ true”的random_device。但是,由于Linux等随机设备(甚至是由固件实现的RDRAND)所提供的软件算法,其熵源与用户可用的输出之间都涉及软件算法,因此将其他来源的随机性/熵混合在一起不会损害结果,有时甚至可以改进它。如果您说实话,我认为您应该收回您的反对意见。
鼠标

2
我认为答案写得很混乱,如果您重写它,那么我可能会收回我的不赞成票。伪随机数生成随机性提取之间存在差异。从理论上讲,它的工作原理是这样的。给定一个弱随机源,例如其中可能只有1000位熵的1000位,首先要使用提取器来获得其中50位熵的〜50位。实际上,这使用加密哈希函数。然后,结果可以用作生成器的种子,生成器将50位扩展为更多的位,供您的应用程序使用。(数字组成。)
克里斯·贝克

3
真好 我不知道您可以写信/dev/random。现在我更了解:添加一个文件作为熵源为什么写到/ dev /随机...。将额外的熵与结果进行异或运算是一种好而有效的方法-缺点是过于明确。
鼠标

2
我认为Java模型是最好的,因为它允许所利用的程序的其余部分SecureRandom不了解所有这些细节和改进,而只是按原样使用标准类的标准接口。Java SecureRandom API的另一个优点是,它可以抵抗用户输入的“不良”随机性而导致的损坏。SecureRandom输出只能通过附加输入来改善(或保持相同的质量)。
鼠标
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.