2010-04-14 4 views
6

Я пытаюсь создать хорошее случайное семя для генератора псевдо-случайных чисел. Я думал, что найду мнения эксперта. сообщите мне, если это плохой способ сделать это или если есть гораздо лучшие способы.C++ генерировать хорошее случайное семя для генераторов случайных чисел psudo

#include <iostream> 
#include <cstdlib> 
#include <fstream> 
#include <ctime> 

unsigned int good_seed() 
{ 
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/random", std::ios::binary); 
    if (file.is_open()) 
    { 
     char * memblock; 
     int size = sizeof(int); 
     memblock = new char [size]; 
     file.read (memblock, size); 
     file.close(); 
     random_seed_a = int(memblock); 
     delete[] memblock; 
    }// end if 
    else 
    { 
     random_seed_a = 0; 
    } 
    random_seed_b = std::time(0); 
    random_seed = random_seed_a xor random_seed_b; 
    return random_seed; 
} // end good_seed() 
+0

не забудьте бросить кости и XOR с ним;) – Andrey

+2

Что произойдет, если ваш процесс запускается из дескрипторов файлов и не может открыть '/ DEV/random'? –

ответ

0

Определить хорошо. :-)

Важно ли быстро находить семена или чтобы семена были как можно более случайными, независимо от того, сколько времени потребуется, чтобы собрать их вместе?

Для баланса - определенно не самый случайный, безусловно, не самый быстрый ...

  • Когда это первый называется, принять системное время в миллисекундах.
  • Запустите это через функцию хэша, например SHA-1.
  • Используйте результат как семя.

Это должно дать вам в основном случайные 160 бит, что составляет 10 50 или около того изменчивости. Хеш займет секундную секунду, чтобы работать, поэтому это не молниеносно, но для меня это был хороший баланс.

+0

Я хотел бы иметь как можно более случайное для моего приложения, но меня тоже интересовало бы быстрое решение. – posop

+3

@DeanJ Хэш лишний. Просто семена с системным временем напрямую. То, что вы пытаетесь выполнить с помощью хэша, - это то, что (хороший) генератор псевдослучайных чисел уже * делает * (лучше). –

+0

Jon-Eric на 100% прав; с другой стороны, я привык работать с плохими генераторами случайных чисел, не мог отличить хороший от плохого, и, как правило, придерживаюсь (быстрого) переполнения. –

1

Традиционно мы использовали первый или второй пользовательский ввод, чтобы засеять наши значения, поскольку количество (от тика до миллисекунды) времени, которое требуется для их ответа, довольно изменчиво.

5

Код, который читает из/dev/random, кажется неправильным: вы C-стиль кастинг адрес вашего символьного буфера в random_seed_a (плагин для C++ приведения здесь) и игнорирование всего, что вы действительно читали из/dev/random (попробуйте *reinterpret_cast<int*>(memblock)

/dev/random должен быть уже хорошим источником энтропии, поэтому, если он доступен, он не может испортить значение с любыми другими данными и просто использовать его как семя напрямую. Если данных недостаточно, in/dev/random Я бы просто отступил на время и использовал это сам по себе, а не разбирался в чем-то.

+1

, согласно моим исследованиям, недетерминированная случайная величина «dev/urandom» xor-ed с не столь случайным временем переменной (0) по-прежнему будет недетерминированной случайной величиной. – posop

2

Хорошие генераторы псевдослучайных чисел не нуждаются в «хорошем» семени, это отличается от запустить для запуска) работает одинаково хорошо.

Использование системного времени напрямую - это нормально (и обычно). Использование /dev/random также прекрасное.

Если ваш генератор псевдослучайных чисел не подходит, даже выбор «хорошего» семени не поможет. Замените его, если сможете.

Предложения: Mersenne twister - очень хорошо. Here's Предшественник, который будет работать даже на самых ограниченных системах.

+3

В зависимости от цели генератору псевдослучайных чисел может потребоваться непредсказуемое семя. Была онлайн-игра в покер, которая подводила время к тому, что могло быть приличным PRNG, а это означало, что, наблюдая за некоторыми картами, можно было выяснить, где начинается PRNG, и, следовательно, знать всю колоду. –

+1

Если это * вообще * важно для пользователей, чтобы они не могли предсказать последовательность случайных чисел, тогда вам нужен криптографически безопасный генератор, а не псевдослучайный генератор. (Вы сумасшедший, если вы основываете азартные игры на реальные деньги на псевдослучайном генераторе.) –

+0

Просто FYI, с Mersenne twister, вам нужно наблюдать 624 последовательных карт (12 колод), прежде чем вы узнаете все будущие карты. –

0

Возможно, вам следует предпочесть /dev/urandom/ над /dev/random. Последний блокируется в Linux, если доступной энтропии недостаточно, что легко произойдет, если программа работает на машине без взаимодействия с пользователем. Если вы не можете открыть /dev/urandom, вы можете создать исключение вместо использования резервной копии.

1

«Хорошие» генераторы «Плохие генераторы» это ничего не значит. «Любой, кто рассматривает арифметические методы производства случайных цифр, конечно, находится в состоянии греха». - Джон фон Нейман. Каждый такой генератор - всего лишь детерминированный алгоритм. Это очень важно иметь начальные состояния (семя), которые приносят достаточно энтропии. В зависимости от того, что вам нужно, вы должны проверить качество вашего генератора. Метод Монте-Карло является очень хорошей оценкой генератора псевдослучайных чисел.

2

Хорошо, вот изменения, которые я внес после рассмотрения вашего ввода. Спасибо за все, кстати!

unsigned int good_seed() 
{ 
    unsigned int random_seed, random_seed_a, random_seed_b; 
    std::ifstream file ("/dev/urandom", std::ios::binary); 
    if (file.is_open()) 
    { 
     char * memblock; 
     int size = sizeof(int); 
     memblock = new char [size]; 
     file.read (memblock, size); 
     file.close(); 
     random_seed_a = *reinterpret_cast<int*>(memblock); 
     delete[] memblock; 
    }// end if 
    else 
    { 
     random_seed_a = 0; 
    } 
    random_seed_b = std::time(0); 
    random_seed = random_seed_a xor random_seed_b; 
    std::cout << "random_seed_a = " << random_seed_a << std::endl; 
    std::cout << "random_seed_b = " << random_seed_b << std::endl; 
    std::cout << " random_seed = " << random_seed << std::endl; 
    return random_seed; 
} // end good_seed() 
Смежные вопросы