C: Генерация случайных чисел - что (если что-нибудь) не так с этим - PullRequest
4 голосов
/ 06 апреля 2010

Для простого моделирования на C мне нужно сгенерировать экспоненциальные случайные величины.Я помню, как где-то читал (но сейчас не могу найти и не помню почему), что использование функции rand () для генерации случайных целых чисел в фиксированном диапазоне генерирует неравномерно распределенные целые числаИз-за этого мне интересно, может ли этот код иметь похожую проблему:

//generate u ~ U[0,1]
u = (   (double)rand() / ((double)(RAND_MAX));
//inverse of exponential CDF to get exponential random variable
expon = -log(1-u) * mean;

Спасибо!

Ответы [ 5 ]

5 голосов
/ 06 апреля 2010

Проблема со случайными числами в фиксированном диапазоне заключается в том, что многие люди делают это для чисел от 100 до 200, например:

100 + rand() % 100

Это не однородно. Но при этом это (или, по крайней мере, достаточно близко к униформе):

u = 100 + 100 * ((double)rand() / ((double)(RAND_MAX));

Поскольку это то, что вы делаете, вы должны быть в безопасности.

2 голосов
/ 06 апреля 2010

RAND_MAX обычно составляет 32 КБ, в то время как LCG rand () генерирует псевдослучайные 32-битные числа. Таким образом, отсутствие единообразия, а также низкая периодичность, как правило, останутся незамеченными.

Если вам требуются высококачественные псевдослучайные числа, вы можете попробовать CMWC4096 Джорджа Марсальи (Дополнительное умножение с переносом). Вероятно, это лучший генератор псевдослучайных чисел с чрезвычайной периодичностью и равномерным распределением (вам просто нужно выбрать хорошие семена для него). Кроме того, он пылает быстро (не так быстро, как LCG, но примерно в два раза быстрее, чем Mersenne Twister.

2 голосов
/ 06 апреля 2010

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

1 голос
/ 06 апреля 2010

Да и нет. Проблема, о которой вы думаете, возникает, когда вы зажимаете выходной сигнал из rand() в диапазон, который на меньше , чем RAND_MAX (т. Е. Имеется меньше возможных выходных сигналов, чем входных).

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

Что касается "обычно", всегда возможно, что у вас есть 64-битный генератор случайных чисел, где тип double имеет 53-битную мантиссу. В этом случае у вас может возникнуть та же проблема, что и при ограничении диапазона целыми числами.

0 голосов
/ 13 января 2011

Нет, ваш алгоритм будет работать;он использует функцию модуля, которая делает вещи неидеально.
Одна проблема состоит в том, что, поскольку он квантуется, время от времени он генерирует именно RAND_MAX, и вы будете запрашивать log(1-1).Я бы порекомендовал по крайней мере (rand() + 0.5)/(RAND_MAX+1), если не лучший источник, такой как drand48().

. Существуют гораздо более быстрые способы вычисления необходимых чисел, например, алгоритм Зиккурата . * 1009.*

...