Какой из <случайных> механизмов случайных чисел следует использовать на практике? станд :: mt19937?

21

Предположим, вы хотите использовать средства C ++ <random>в практической программе (для некоторого определения «практический» - ограничения здесь являются частью этого вопроса). У вас есть код примерно так:

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}

У меня вопрос, какой тип вы должны использовать ENGINE?

  • Раньше я всегда говорил, std::mt19937потому что это было быстро печатать и узнавать имя. Но в наши дни кажется, что все говорят, что Mersenne Twister очень тяжелый и кеша и даже не проходит все статистические тесты, которые делают другие.

  • Я хотел бы сказать, std::default_random_engineпотому что это очевидный «дефолт». Но я не знаю, меняется ли он от платформы к платформе, и я не знаю, статистически ли это хорошо.

  • Поскольку в наши дни все работают на 64-битной платформе, следует ли нам хотя бы использовать std::mt19937_64over std::mt19937?

  • Я хотел бы сказать, pcg64или xoroshiro128потому что они кажутся уважаемыми и легкими, но они вообще не существуют <random>.

  • Я ничего не знаю minstd_rand, minstd_rand0, ranlux24, knuth_bконечно , они должны быть хорошо для чего - то - и т.д.?

Очевидно, здесь есть некоторые конкурирующие ограничения.

  • Сила двигателя. ( <random>не имеет криптографически сильных PRNG, но все же некоторые из стандартизированных «слабее» других, верно?)

  • sizeof двигатель.

  • Скорость его operator().

  • Легкость высева. mt19937общеизвестно, что правильно посеять правильно, потому что у него так много состояний для инициализации.

  • Переносимость между поставщиками библиотек. Если один поставщик foo_engineпроизводит разные номера от другого foo_engine, это не подходит для некоторых приложений. (Надеюсь, это не исключает ничего, кроме, может быть default_random_engine.)

Взвесив все эти ограничения как можно лучше, что бы вы назвали окончательным ответом «наилучшая практика - оставаться в пределах стандартной библиотеки»? Должен ли я просто продолжать использовать std::mt19937, или как?

Quuxplusone
источник
2
К вашему последнему пункту, все стандартные адаптеры движка заданы так, чтобы возвращать определенное значение при конкретном последовательном вызове созданного по умолчанию значения, поэтому они должны быть переносимыми.
1201ProgramAlarm

Ответы:

15

Справочник C ++ перечисляет все случайные механизмы, в настоящее время предоставляемые C ++. Тем не менее, выбор двигателей оставляет желать лучшего (например, см. Мой список высококачественных генераторов случайных чисел ). Например:

  • default_random_engine определяется реализацией, поэтому неизвестно, есть ли у движка статистические недостатки, о которых может заботиться приложение.
  • linear_congruential_engineреализует линейные конгруэнтные генераторы. Однако они имеют тенденцию иметь низкое качество, если модуль не является простым и очень большим (не менее 64 бит). Кроме того, они не могут допустить больше семян, чем их модуль.
  • minstd_rand0и minstd_randдопускают только около 2 ^ 31 семян. knuth_bоборачивает minstd_rand0и делает перемешивание Бэйса-Дарема.
  • mt19937и mt19937_64может допускать намного больше std::seed_seqначальных значений random_device, если их лучше инициализировать (например, путем инициализации с несколькими выходами , а не только с одним), но они используют около 2500 байтов состояния.
  • ranlux24и ranlux48использовать около 577 бит состояния, но они медленные (они работают, сохраняя одни и отбрасывая другие псевдослучайные выходные данные).

Однако в C ++ также есть два движка, которые обертывают другой движок, чтобы потенциально улучшить его свойства случайности:

  • discard_block_engine отбрасывает некоторые из выходов данного случайного двигателя.
  • shuffle_order_engine реализует перемешивание Бэйса – Дарема для данного случайного движка.

Например, можно, например, иметь Отсеки-Durham перетасовка mt19937, ranlux24или обычая linear_congruential_engineс shuffle_order_engine. Возможно, завернутый двигатель лучше по качеству, чем оригинальный. Однако трудно предсказать статистическое качество нового движка без его тестирования .

Таким образом, в ожидании таких тестов кажется, что mt19937это самый практичный движок в стандарте C ++ на данный момент. Однако мне известно, по крайней мере, одно предложение добавить еще один механизм случайных чисел в будущие версии C ++ (см. Документ C ++ P2075 ).

Питер О.
источник
1

По ссылке C ++ , default_random_engine:

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

Таким образом , для легкого использования вы не должны беспокоиться о чем - либо, семена default_random_engineс , Epoch Time (time(0))и что было бы хорошо достаточно;)

Фарбод Ахмадиан
источник
Я считаю, что проблема здесь в мобильности. Хотя по умолчанию может быть механизм, который работает хорошо, он не может быть воспроизведен на другой платформе.
bremen_matt
@bremen_matt Хм ... Ну, а зачем нам воспроизводить "случайное" число?
Фарбод Ахмадиан
2
Тестирование. Для тестирования вам нужны воспроизводимые входные данные. В то же время, вы можете хотеть или нуждаться, чтобы эти входы были случайными. Например, большинство алгоритмов машинного обучения предполагают, что параметры инициализируются случайным образом. Ransac, CNN, DNN, ... многие алгоритмы требуют случайных параметров.
bremen_matt