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

118
30 июня 2019, 02:00

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

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

Код на 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;
}

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

Answer 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. Это полученное значение мы умножаем на одно и то же выражение.

Answer 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) << " ";
}

Гистограмма, впрочем, такая же :)

Answer 3

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

Да, но практичней будет вычислять оба и второе значение использовать при последующих запросах к функции.

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

READ ALSO
Запрет ввода символов в Linux консоле на C++

Запрет ввода символов в Linux консоле на C++

как можно запретить ввод букв внутри терминала? Жмем клавишу, программа сразу отрабатывает, понимает, что это буква и ничего не происходитЖмем...

121
Internal error. MavenArchiver

Internal error. MavenArchiver

Получаю при интале вот такую ошибкукто знает как исправить?

113
Документация по наведению мыши

Документация по наведению мыши

Изучаю Spring на IDE IntelJIdeaХочу почитать что делает тот или иной метод, аннотация

133
Многомодульный проект

Многомодульный проект

Есть проект (веб + андроид приложение) со следующей структурой:

136