Страницы

Поиск по вопросам

среда, 1 января 2020 г.

Преобразование Бокса — Мюллера

#cpp #c #алгоритм #математика #теория_вероятностей


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

Метод может сгенерировать два псевдослучайных числа, но мне нужно только одно. Могу
ли я использовать только одну из этих формул (только с синусом или только с косинусом)?
Будет ли распределение столь же нормальным, как если использовать их обе?

Код на C++:

const float pi = 3.1415926535;

float RandomFloat()
{
    return (float) rand() / RAND_MAX;
}

float normalRand()
{
    float z = RandomFloat();
    float f = RandomFloat();

    float r = cos(2 * pi * f) * sqrt(-2 * log(z));

    return r;
}


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


Ответы

Ответ 1



1) Из прикреплённой Вами же ссылки можно сделать вывод, что можно использовать и одно число: Тогда z 0 и z 1 будут независимы и распределены нормально с математическим ожиданием 0 и дисперсией 1. При реализации на компьютере обычно быстрее не вычислять обе тригонометрические функции — cos ⁡ и sin ⁡— а рассчитать одну из них через другую. Основное тригонометрическое тождество: sin^2(x) + cos^2(x) = 1; Выведите из него одно или пару случайных чисел. 2) Используйте srand от времени на Вашем компьютере, так возвращаемые значения rand() будут всегда разные. Пример: srand( time( 0 ) ); // автоматическая рандомизация cout << "rand_value = " << 1 + rand() % 10 << endl; // rand()%10 - возвращает значения от 0 до 9. UPD1: Подозреваю, что Преобразование Бокса — Мюллера здесь не зря используется и Вам нужно 2 величины. На всякий случай оставлю ссылку на небольшую статейку: тык. UPD2: Пояснение почему можно использовать любую из двух формул для просто случайного числа с "нормальным" распределением: Формулы отличаются лишь косинусом и синусом. И косинус, и синус принимают значения от -1 до 1. Это полученное значение мы умножаем на одно и то же выражение.

Ответ 2



Экспериментируем... 10000 пар чисел и 20000 первых чисел загоняем в Wolfram Mathematica и просим построить две гистограммы. Похоже на то, что вполне можно использовать только одно число. Можно и детальнее, разницы нет. Рекомендуемый вариант - int main() { random_device rd{}; mt19937 gen{rd()}; normal_distribution<> d{0,1}; for(int i = 0; i < 20000; ++i) cout << d(gen) << " "; } Гистограмма, впрочем, такая же :)

Ответ 3



Могу ли я использовать только одну из этих формул (только с синусом или только с косинусом)? Будет ли распределение столь же нормальным, как если использовать их обе? Да, но практичней будет вычислять оба и второе значение использовать при последующих запросах к функции. Но следует иметь ввиду, что это не очень хороший генератор (как и все наивные варианты использования rand()) — для типового размера RAND_MAX в 32768 этот алгоритм не будет выдавать результаты ≥4.57... да и у меньших значений статистика наверняка испортится.

Комментариев нет:

Отправить комментарий