Будет ли работать этот случайный двойной генератор? - PullRequest
2 голосов
/ 14 ноября 2011

Интуитивно можно написать случайный двойной генератор следующим образом:

double randDouble(double lowerBound, double upperBound)
{
    double range = upperBound - lowerBound;
    return lowerBound + range * rand();
}

Предположим, мы предполагаем, что rand() возвращает равномерно распределенный псевдослучайный дубль на интервале [0, 1).

Гарантируется ли этот метод случайным двойным значением в пределах [lowerBound, upperBound) с равномерным распределением вероятности?Меня особенно интересует, может ли природа вычислений с плавающей запятой вызывать пики или провалы в окончательном распределении для некоторых диапазонов.

Ответы [ 3 ]

2 голосов
/ 14 ноября 2011

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

Во-вторых, как сказал Оли Чарлсворт, многие реализации rand возвращают число от 0 до RAND_MAX, где RAND_MAX - это наибольшее возможное значение, которое он может принять. В этих случаях вы можете получить значение в [0, 1) с помощью

double r = rand()/((double)RAND_MAX+1);

есть +1, поэтому r не может быть 1.

В других языках есть rand, который возвращает значение от 0 до 1, в этом случае вам не нужно делать вышеупомянутое деление. В любом случае, получается, что ваша функция возвращает достойное приближение случайного распределения. Для получения более подробной информации см. Следующую ссылку: http://www.thinkage.ca/english/gcos/expl/c/lib/rand.html Обратите внимание, что эта ссылка дает вам немного отличающиеся функции, которые, как они утверждают, работают немного лучше, но та, которая у вас, вероятно, работает достаточно хорошо.

2 голосов
/ 14 ноября 2011

Если ваши верхняя и нижняя границы являются смежными степенями двух, то полученное вами распределение будет таким же, как и полученное из rand(), так как вы фактически просто изменяете показатель того, что дает rand(), без изменения мантиссы.

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

Если вы используете метод в более общем диапазоне (например, мантисса изменяется при вычислении), то вы также сталкиваетесь с той же неоднородностью, которую получаете при попытке преобразовать случайное целое число в случайное целое число по модулю n без использования выборки отклонения.

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

1 голос
/ 14 ноября 2011

Ну нет. rand() возвращает число от 0 до RAND_MAX; это квантование оставит большие дыры в вашем распределении; фактически, почти все значения с плавающей запятой между lowerBound и upperBound никогда не будут выбраны.

...