Я создал C ++ проект с открытым исходным кодом для нормально распределенного теста генерации случайных чисел .
Сравнивает несколько алгоритмов, включая
- Метод центральной предельной теоремы
- преобразование Бокса-Мюллера
- Марсалья полярный метод
- алгоритм Зиккурата
- Метод выборки с обратным преобразованием.
cpp11random
использует C ++ 11 std::normal_distribution
с std::minstd_rand
(на самом деле это преобразование Бокса-Мюллера в clang).
Результаты версии с одинарной точностью (float
) на iMac Corei5-3330S@2.70GHz, clang 6.1, 64-bit:
![normaldistf](https://i.stack.imgur.com/5HTKJ.png)
Для корректности программа проверяет среднее значение, стандартное отклонение, асимметрию и эксцесс образцов. Было обнаружено, что метод CLT путем суммирования 4, 8 или 16 равномерных чисел не имеет хорошего эксцесс, как другие методы.
Алгоритм Ziggurat имеет лучшую производительность, чем другие. Тем не менее, он не подходит для SIMD-параллелизма, так как требует поиска таблицы и ответвлений. Box-Muller с набором инструкций SSE2 / AVX намного быстрее (x1,79, x2,99), чем неигровая версия алгоритма зиккурата.
Поэтому я предложу использовать Box-Muller для архитектуры с наборами команд SIMD, и в противном случае может быть ziggurat.
P.S. В эталонном тесте используется простейший PRGG LCG для генерации равномерно распределенных случайных чисел. Так что это может быть недостаточно для некоторых приложений. Но сравнение производительности должно быть справедливым, потому что во всех реализациях используется один и тот же PRNG, поэтому тест в основном тестирует производительность преобразования.