Ответ 1
Это генераторы псевдослучайных чисел, а не действительно случайные. Это часто хорошо, так как позволяет вам легче воспроизводить ошибки, когда речь идет о "случайных" числах.
Вы можете получить генераторы случайных чисел, такие как чтение /dev/random
в Linux, но обычные генераторы, которые поставляются с библиотеками C, обычно не работают.
Самый простой - линейные конгруэнтные генераторы, где:
n(x+1) = n(x) * A + C modulo M
с подходящим образом выбранными значениями A
, C
и M
На странице Википедии о LCG приведены примеры значений, используемых различными реализациями. Например, перечисленный здесь glibc
имеет a = 1103515245, c = 12345, m = 2^31
так что это простая вещь, такая как:
static unsigned int seed = 1;
void srand (int newseed) {
seed = (unsigned)newseed & 0x7fffffffU;
}
int rand (void) {
seed = (seed * 1103515245U + 12345U) & 0x7fffffffU;
return (int)seed;
}
Кроме того: в реализации glibc по-прежнему есть этот генератор (называемый генератором типа 0), но также есть и более удобный триномиальный генератор, который (предположительно) лучше.
Есть и более сложные (такие как твистер Мерсенна), которые имеют гораздо большее время цикла (время до начала повторения).
Любой действительно случайный генератор должен использовать действительно случайный входной источник, поэтому /dev/random
иногда будет блокировать ("ожидание энтропии"), а /dev/urandom
- нет.
"Истинно" случайные источники могут зависеть от времени между нажатиями клавиш, данных, вводимых пользователями, содержимого сетевых пакетов, шаблонов дискового ввода-вывода, времени, необходимого для ответа ICMP, чтобы вернуться по сети, и всех других удивительных, главным образом недетерминированные вещи.
Если вы не сильно разбираетесь в криптографии, обычные генераторы случайных чисел будут в порядке.