Генерируйте случайные числа после нормального распределения в C/C++

Как я могу легко генерировать случайные числа после нормального распределения в C или C++?

Я не хочу использования Повышения.

Я знаю, что Knuth говорит об этом подробно, но у меня нет его книг под рукой прямо сейчас.

112
задан MultiplyByZer0 29 December 2018 в 03:31
поделиться

4 ответа

побитовый оператор OR

-121--2593429-

Как уже отмечали другие, это невозможно. Среда выполнения .NET обрабатывает выделение кучи от имени приложения.

По моему опыту, приложения .NET обычно страдают от OOM, когда должно быть достаточно памяти (или, по крайней мере, так это кажется). Причиной этого обычно является использование огромных коллекций, таких как массивы, List (который использует массив для хранения своих данных) или тому подобное.

Проблема в том, что эти типы иногда создают пики в использовании памяти. Если эти пиковые запросы не могут быть обработаны, возникает исключение OOM. Например, когда List должен увеличить свою емкость, он делает это путем выделения нового массива с удвоенным текущим размером, а затем копирует все ссылки/значения из одного массива в другой. Аналогично операции, такие как ToArray, создают новую копию массива. Я также видел подобные проблемы в больших операциях LINQ.

Каждый массив хранится как непрерывная память, поэтому во избежание OOM среда выполнения должна иметь возможность получить один большой блок памяти. Поскольку адресное пространство процесса может быть фрагментировано как из-за загрузки DLL, так и из-за общего использования кучи, это не всегда возможно, и в этом случае возникает исключение OOM.

-121--2964700-

Существует множество способов создания распределенных по Гауссу номеров из обычного RNG .

Обычно используется преобразование Бокса-Мюллера . Он корректно выдает значения с нормальным распределением. Математика проста. Вы генерируете два (однородных) случайных числа, и применяя к ним формулу, вы получаете два обычно распределенных случайных числа. Верните один и сохраните другой для следующего запроса случайного числа.

91
ответ дан 24 November 2019 в 02:49
поделиться

Быстрый и простой метод просто суммировать количество равномерно распределенных случайных чисел и взять их среднее значение. См. Центральную предельную теорему для полного объяснения того, почему это работает.

31
ответ дан 24 November 2019 в 02:49
поделиться

Используйте std :: tr1 :: normal_distribution .

Пространство имен std :: tr1 не является частью boost. Это пространство имен, которое содержит дополнения к библиотеке из Технического отчета 1 C ++ и доступно в последних компиляторах Microsoft и gcc, независимо от boost.

12
ответ дан 24 November 2019 в 02:49
поделиться

C++11

C++11 предлагает std::normal_distribution, что является способом, который я бы выбрал сегодня.

C или более старый C++

Вот некоторые решения в порядке возрастания сложности:

  1. Добавьте 12 равномерных случайных чисел от 0 до 1 и вычтите 6. Это будет соответствовать среднему и стандартному отклонению нормальной переменной. Очевидным недостатком является то, что диапазон ограничен ±6 - в отличие от истинного нормального распределения.

  2. Преобразование Бокса-Мюллера. Оно приведено выше, и его относительно просто реализовать. Однако если вам нужны очень точные выборки, имейте в виду, что преобразование Бокса-Маллера в сочетании с некоторыми равномерными генераторами страдает от аномалии, называемой эффектом Нива1.

  3. Для достижения наилучшей точности я предлагаю строить равномерные выборки и применять обратное кумулятивное нормальное распределение для получения нормально распределенных переменных. Вот очень хороший алгоритм для обратного кумулятивного нормального распределения.

1. H. R. Neave, "On using the Box-Muller transformation with multiplicative congruential pseudorandom number generators," Applied Statistics, 22, 92-97, 1973

46
ответ дан 24 November 2019 в 02:49
поделиться