Почему 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 был популярным выбором в прошлом, хотя малые генераторы, кажется, популярны в наши дни.

Другие вопросы по тегам