C ++ 14: 2 случайных генератора - один работает, другой нет - PullRequest
0 голосов
/ 03 октября 2018

Я изучаю C ++, и в моем коде генов случайных чисел я всегда получаю одно и то же число

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

, но srand / rand () работает.

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

Я думаю, что это связано со временем ().Но как мне заставить работать первый код?

1 Ответ

0 голосов
/ 03 октября 2018

Предполагая, что ваша проблема связана с компилятором 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>

Это просто модифицированная для SO версия aзаголовок в библиотеке Wrapped stdlib .

Я бы порекомендовал использовать принудительное включение (опция командной строки) этого исправления или просто определить _GLIBCXX_USE_RANDOM_TR1 в командной строке.


Изучая исходный код моего MinGW g ++ 7.3.0, файлов <random.h> и random.cc, выясняется, что этот подход работает на большинстве ПК, поскольку (с этим компилятором) _GLIBCXX_USE_RANDOM_TR1 выбирает генерацию чисел с помощью rdrand инструкция, если она доступна, а также через устройство "/dev/urandom" * nix world, если доступно.

Итак, критерии для «работ»:

  • процессор поддерживает rdrand инструкция, или
  • fopen успешно открывается "/dev/urandom".

Согласно статье Википедии о rdrand

AMD добавила поддержку инструкции в июне 2015 года.

... поэтому такой подход может не работать на ПК с Windows (без "/dev/urandom") с процессором AMD, выпущенным до этого времени (без инструкции 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, что, в свою очередь, заставляет код генерации чисел использовать инструкцию rdrand.

И в противном случае этот код пытается открыть случайное * nixустройство, и если это не сработает, то оно и, следовательно, конструкция random_device не будет выполнена с исключением.

...