генерация случайных чисел в 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.