Почему drand48() и друзья устарели?
В конце концов, они кажутся лучше стандартного libc rand(). Я что-то пропустил?
(Я потратил некоторое время на поиск этого в Интернете, и единственный другой пример этого вопроса, который я мог найти, был в контексте предвзятости распределения и остался без ответа.)
Страницы руководства для rand () и drand48() также кажутся противоречивыми. Первый рекомендует второй, а второй заявляет, что он устарел, и следует использовать первый. (Хотя, если честно, многие люди, которые понимают математику, лежащую в основе PRNG, имеют проблемы с man-страницами для этих функций, потому что они плохо сформулированы, а в некоторых случаях просто ошибочны.)
Тем не менее, я не могу найти оправдания "устаревшему" статусу.
2 ответа
Страница man в моей системе (которая из проекта man-pages для Linux гласит:
Эти функции объявлены устаревшими SVID 3, в котором говорится, что
rand(3)
следует использовать вместо
SVID 3 был опубликован в 1989 году.
SVID 4 (ссылка на 720-страничный PDF), опубликованная в 1995 году, документы drand48
, erand48
, lrand48
, nrand48
, mrand48
, jrand48
, srand48
, seed48
, а также lcong48
и, как POSIX, ничего не говорит о том, что они устарели.
POSIX, по состоянию на 2013 год, ничего не говорит о том, что они устарели, устарели или устарели.
Я не нашел копию SVID 3, поэтому я не знаю, почему он объявил бы эти функции устаревшими, но, очевидно, это решение было пересмотрено позже. Заявление на странице руководства выглядит как устаревшая информация. Я бы не беспокоился об этом.
Что касается какой функции вы должны использовать, стандарт C rand()
функция является наиболее переносимой (если только вы не перекомпилируете другую версию из исходного кода). Немного rand()
реализации низкого качества, причем биты младшего разряда повторяются в очень регулярном порядке; другие немного лучше.
Если вам не нужны высококачественные псевдослучайные числа, вы также можете использовать rand()
(посеянный по телефону srand()
с разумным значением, например, srand(time(NULL))
,
Если вам нужны высококачественные псевдослучайные числа, скорее всего, ни одна из этих функций не достаточно хороша, я бы посоветовал не использовать какую-либо из них для криптографии, например. Ты можешь использовать /dev/urandom
или же /dev/random
если ваша система поддерживает это. Я слышал хорошие вещи о Мерсенном Твистере, но мне не хватает опыта, чтобы комментировать дальше.
(Кстати, если вы делаете поиск в Google по SVID, следите за Svið).
Примечание о стандартах:
rand()
является частью стандарта C, поэтому он должен быть предоставлен. Его реализация не определена, но в glibc он использует тот же алгоритм, что иrandom()
, От человека 3 ранда:Версии
rand()
а такжеsrand()
в библиотеке Linux C используйте тот же генератор случайных чисел, что иrandom(3)
а такжеsrandom(3)
,...drand48()
является частью стандарта POSIX. Кажется, что его алгоритм указан, он должен использовать 48-разрядный линейный конгруэнтный генератор со следующей формулой (согласно man 3 drand48):Xn+1 = (aXn + c) mod m, where n >= 0
random()
является частью стандарта POSIX. Он использует 31 слово состояния и неуказанный алгоритм, согласно man 3 random:Функция random() использует генератор случайных чисел с нелинейной аддитивной обратной связью, использующий таблицу по умолчанию длинных целых чисел размера 31, чтобы возвращать последовательные псевдослучайные числа в диапазоне от 0 до RAND_MAX. Период этого генератора случайных чисел очень большой, примерно 16 * ((2^31) - 1).
Итак, POSIX имеет эти три генератора случайных чисел. Лучший из них random()
или же rand()
, которые одинаковы в glibc (но, вероятно, не то же самое в других системах). drand48()
Генератор - это очень простой тип (линейный конгруэнтный) с относительно небольшим количеством состояний (48 бит), поэтому его следует избегать. Ни один из рассмотренных здесь генераторов случайных чисел не подходит, например, для моделирования Монте-Карло, но drand48()
вероятно намного хуже чем rand()
или же random()
,
Какой я должен использовать?
Я бы всегда избегал drand48()
потому что это крошечный линейный конгруэнтный генератор с небольшим состоянием, и он доступен только в системах POSIX. В системах POSIX, random()
обычно доступно, и лучше.
Я бы обычно избегал rand()
потому что во многих системах это плохой генератор, часто линейный конгруэнтный генератор, который даже меньше, чем drand48()
и его младшие значащие биты в некоторых системах являются циклическими. Если вам не нужны хорошие случайные числа, то rand()
Это хорошо.
я хотел бы использовать random()
в любой системе POSIX, если мне нужны случайные числа, но они не заботятся о том, как они генерируются.
Вы всегда можете использовать свой собственный генератор случайных чисел: если вам нужен хороший портативный генератор случайных чисел, это ваш единственный выбор. Mersenne Twister был популярным выбором в прошлом, хотя малые генераторы, кажется, популярны в наши дни.