C ++ 14:2个随机生成器-一个起作用,另一个不起作用

时间:2018-10-03 10:44:26

标签: c++ c++14

我正在学习C ++,在我的随机数gen代码中,我总是得到相同的数字

random_device rd;
mt19937 x{rd()};
uniform_int_distribution<int> ran{1, 100};
cout << ran(x);

但是srand / rand()起作用。

srand (time(0));
cout << rand()%100;

我认为这与time()有关。但是如何获得第一个有效的代码?

1 个答案:

答案 0 :(得分:7)

假设问题出在MinGW g ++编译器上,则可以定义一个包装<random>的标头,如下所示:

#pragma once

#ifndef MY_NO_FIX_OF_RANDOM_DEVICE
#   ifdef __GNUC__
#       undef   _GLIBCXX_USE_RANDOM_TR1
#       define  _GLIBCXX_USE_RANDOM_TR1
#   endif
#endif
#include <random>

那只是a header in the Wrapped stdlib library的SO修改版。

我建议使用此修补程序的强制包含(命令行选项),或仅在命令行中定义_GLIBCXX_USE_RANDOM_TR1


通过检查我的MinGW g ++ 7.3.0的源代码,文件<random.h>random.cc,看来该方法适用于大多数PC,因为(使用该编译器)_GLIBCXX_USE_RANDOM_TR1选择了通过rdrand指令(如果有)生成数字,或者通过"/dev/urandom" * nix world设备(如果有)生成数字。

因此,“有效”的条件:

  • 处理器支持rdrand指令
  • fopen成功打开了"/dev/urandom"

根据Wikipedia article about rdrand

  

AMD在2015年6月增加了对该指令的支持。

...因此,这种方法可能在之前装有AMD处理器(没有"/dev/urandom"指令)的Windows PC(没有rdrand)上运行。


技术细节:

使用_GLIBCXX_USE_RANDOM_TR1定义的random_device默认构造函数,使用参数"default"调用以下函数:

  void
  random_device::_M_init(const std::string& token)
  {
    const char *fname = token.c_str();

    if (token == "default")
      {
#if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND
    unsigned int eax, ebx, ecx, edx;
    // Check availability of cpuid and, for now at least, also the
    // CPU signature for Intel's
    if (__get_cpuid_max(0, &ebx) > 0 && ebx == signature_INTEL_ebx)
      {
        __cpuid(1, eax, ebx, ecx, edx);
        if (ecx & bit_RDRND)
          {
        _M_file = nullptr;
        return;
          }
      }
#endif

    fname = "/dev/urandom";
      }
    else if (token != "/dev/urandom" && token != "/dev/random")
    fail:
      std::__throw_runtime_error(__N("random_device::"
                     "random_device(const std::string&)"));

    _M_file = static_cast<void*>(std::fopen(fname, "rb"));
    if (!_M_file)
      goto fail;
  }

如果__cpuid报告处理器支持rdrand指令,那么这将导致_M_file成员被清零,这反过来又导致数字生成代码使用{{1} }指令。

否则,此代码将尝试打开* nix随机设备,如果该设备失败,则它将打开,因此rdrand构造会失败,并出现异常。