Как показано в этом сообщение Есть несколько способов генерировать случайные числа с плавающей точкой в C ++. Но я не до конца понимаю третий вариант ответа:
float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));
Может кто-нибудь объяснить мне эту строку? Как здесь рассчитываются лимиты?
rand()
генерирует случайные числа из 0
в RAND_MAX
,
0 <= rand()/RAND_MAX <= 1
implies: 0 <= rand()/RAND_MAX*(HI-LO) <= HI-LO
implies: LO <= LO + rand()/RAND_MAX*(HI-LO) <= HI
Сейчас с RAND_MAX
а также HI-LO
целые числа, RAND_MAX/(HI-LO)
Типизировано float
,
rand()
возвращает что-то между 0
а также RAND_MAX
, Давайте назовем это r
,
r / (RAND_MAX/(HI-LO)) = r / RAND_MAX * (HI-LO)
так что это между 0
а также HI-LO
,
добавлять LO
и у вас есть значение между LO
а также HI
static_cast
s заставляет компилятор преобразовывать в float
иначе он будет придерживаться int
и запутать вычисления.
Г-н STL объяснил, почему это (и другие rand()
связанные конструкции) очень плохая идея в его презентации «rand () считается вредным».
Идея этого кода заключается в использовании числа с плавающей запятой для уменьшения потери энтропии случайного числа, зажатого операцией по модулю.
Как указывает Стивен, решение с плавающей запятой не имеет проблемы, которую представляет операция по модулю (в основном, существует интервал значений, которые имеют большую вероятность генерироваться, чем другие, благодаря модулю, нарушающему theorical однородность rand()
).
Но с плавающей точкой возникает новая проблема: округление, произведенное при окончательном преобразовании из типа с плавающей точкой в целочисленный тип, который ожидает пользователь, приводит к проблеме, которая одно и то же число генерируется много раз для разных входов, но несколько значений генерируются только одним. Итак, опять же, единообразие потеряно.
Конечно, это округление не является проблемой, если целью является генерация случайной плавающей запятой, как в вашем случае. Но выполненные округления и деления могут привести к нарушению равномерности распределения.
Вывод ко всему вышесказанному: Этот код пытается решить проблемы однородности классическим способом по модулю, но также приводит к (меньше? Я не уверен) проблемам однородности. Поэтому попробуйте заменить случайные средства C другими библиотеками (как в стандартной <random>
библиотека предоставлена начиная с C ++ 11).
Он пытается сгенерировать случайное число в диапазоне [LO, HI]
Лучший способ сделать это в C ++ 11 — использовать <random>
библиотека:
std::default_random_engine generator;
std::uniform_real_distribution<double> distribution(LO,HI);
double value = distribution(generator);