генерация случайных чисел в C++ с использованием TR1/dev / random (устойчив к

Я хотел бы создать равномерные случайные числа в C++ между 0 и 1, таким образом, который не использует стандартный rand() и srand(time(NULL)) метод. Причина этого в том, что если я запускаю приложение более одного раза в течение одной и той же секунды моих часов, семя будет точно таким же и даст тот же результат.

Я не хочу полагаться на boost или специфику ОС/компилятора. x86 можно предположить.

кажется, что альтернативный способ сделать это-использовать TR1 (I не имеют C++11) и посева с /dev/random каким-то образом?

прямо сейчас у меня есть это, но он все еще использует time(NULL) как семя, которое не будет хорошо работать в течение 1 секунды работает:

#include <iostream> 
#include <tr1/random> 

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed(time(NULL)); 
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 

3 ответов


размещение по запросу OP:

Это все еще несколько специфично для компилятора, но все равно будет работать почти на всех компиляторах x86-targeting:

#ifdef _WIN32

//  Windows
#define rdtsc  __rdtsc

#else

//  For everything else
unsigned long long rdtsc(){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((unsigned long long)hi << 32) | lo;
}

#endif

int main() 
{ 
  std::tr1::mt19937 eng; 
  eng.seed( rdtsc() );    //  Seed with rdtsc.
  std::tr1::uniform_int<int> unif(1, RAND_MAX); 
  int u = unif(eng); 
  std::cout << (float)u/RAND_MAX << std::endl; 
} 

идея здесь состоит в том, чтобы семя генератора случайных чисел с rdtsc цикл-счетчик.

причина, почему это работает, потому что rdtsc счетчик циклов повторяется примерно с той же скоростью, что и частота процессора. Поэтому вероятность того, что два вызова к нему вернут одно и то же значение, чрезвычайно тонкий-тем самым, делая его отличным семенем для ГСЧ.


TR1 в [tr.ранд.устройства] указывает random_device класс, который генерирует неподписанные ints из источника, зависящего от реализации. Поэтому должно работать следующее, хотя я не скомпилировал его сам:

int main() {
  std::tr1::random_device dev_random;
  std::tr1::mt19937 eng(dev_random());
  ...

в TR1 передача dev_random напрямую без вызова работает и инициализирует состояние eng более случайным образом, но в C++11 Вам нужно обернуть аргументы seed в другой класс. Поскольку вызов аргумента работает в обеих библиотеках, я бы сделал это для ремонтопригодности, если у вас нет более требовательные потребности.


ваша проблема связана с тем, как вы инициализации генератора случайных чисел. Очевидно, что посев со временем (NULL) будет производить ту же последовательность PRNG в течение этой секунды при посеве. Это самый распространенный способ посева Ранда, но, к сожалению, плохая практика из-за этой самой проблемы. Мало того, я читал, что это может вызвать смещение в результатах.

отметим, что каждый PRNG будет производить тот же результат, если посеяны с теми же значениями. Так что твоя проблема не связано с генератором, больше с посевом.

Я задал вопрос о посеве здесь всего несколько недель назад и получил ссылку на следующую статью, которую вы также можете найти полезной. хорошая практика в (псевдо) генерации случайных чисел для приложений биоинформатики См. раздел о посеве или разогреве генератора.

rand () не лучший генератор случайных чисел, но подходит во многих случаях при условии, что он правильно посеян. Если вы хотите что-то лучше, где последовательность повторов очень велика, тогда есть некоторые из них в этой ссылке. Или используйте основанные на TR1. Лично я бы пошел с более портативным кодом на основе C++03 и держался подальше от TR1.

также считают умножить на carry как альтернативный алгоритм PRNG.