Книга: Фундаментальные алгоритмы и структуры данных в Delphi

Другие распределения случайных чисел

Другие распределения случайных чисел

Если случайные числа используются для моделирования некоторого процесса, то вы можете обнаружить, что все рассмотренные выше генераторы случайных чисел не позволяют решить поставленную задачу. Это вызвано равномерным распределением генерируемых ими случайных чисел, т.е. вероятность возникновения одного случайного числа равна вероятности возникновения любого другого числа. При проведении моделирования бывают необходимы случайные числа, распределенные не по равномерному закону. Тем не менее, для вычисления последовательностей с другими распределениями можно использовать уже изученные нами генераторы случайных чисел.

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

Для нормально распределенного набора случайных чисел необходимо знать среднее значение и среднеквадратическое отклонение. Если эти параметры известны, генерация последовательности случайных чисел не представит особого труда. Для генерации мы будем использовать преобразование Бокса-Мюллера. Сами математические выкладки в этой книге не приводятся. Преобразование на своем входе требует два равномерно распределенных случайных числа, а на выходе генерирует два нормально распределенных случайных числа. Это не совсем удобно, поскольку нам, как правило, нужно только одно число за один раз. Однако второе число можно записать и выдать в качестве выходного значения при следующем вызове функции. Обратите внимание, что для многопоточных приложений предложенное решение приведет к тому, что функция не будет независимой от потоков, поскольку неиспользуемое значение придется хранить в глобальной переменной. Указанного недостатка можно избежать, если инкапсулировать вычисление случайных чисел в классе.

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

Листинг 6.12. Случайные числа с нормальным распределением

var

NRGNextNumber : double;

NRGNextlsSet : boolean;

function NormalRandomNumber(aPRNG : TtdBasePRNG;

aMean : double;

aStdDev : double): double;

var

Rl, R2 : double;

RadiusSqrd : double;

Factor : double;

begin

if NRGNextlsSet then begin

Result := NRGNextNumber;

NRGNextlsSet := false;

end

else begin

{получить два числа, которые определяют точку внутри окружности единичного радиуса}

repeat

Rl := (2.0 * aPRNG.AsDouble) -1.0;

R2 := (2.0 * aPRNG.AsDouble) - 1.0;

RadiusSqrd := sqr(Rl) + sqr(R2);

until (RadiusSqrd < 1.0) and (RadiusSqrd > 0.0);

{применить преобразование Бокса-Мюллера}

Factor := sqrt(-2.0 * In(RadiusSqrd) / RadiusSqrd);

Result := Rl * Factor;

NRGNextNumber :=R2 * Factor;

NRGNextlsSet :=true;

end;

Result := (Result * aStdDev) + aMean;

end;

Еще одним важным распределением является экспоненциальное. Случайные числа, распределенные по этому закону, используются для моделирования ситуаций "времени прибытия", например, времени прибытия покупателей к кассе в супермаркете. Если в среднем покупатели подходят к кассе каждые x секунд, то время прибытия будет распределено по экспоненциальному закону со средним значением х.

Генерировать случайные числа, распределенные по экспоненциальному закону, достаточно просто. Не вдаваясь в математические подробности можно сказать, что если u - случайное число, распределенное по равномерному закону в диапазоне от 0.0 до 1.0, то e, которое равно

e = -x ln(u)

будет случайном числом, распределенным по экспоненциальному закону со средним значением х.

Листинг 6.13. Случайные числа, распределенные по экспоненциальному закону

function ExponentialRandomNumber( aPRNG : TtdBasePRNG;

aMeart : double): double;

var

R : double;

begin

repeat

R := aPRNG.AsDouble;

until (R <> );

Result := -aMean * ln(R);

end;

И снова обратите внимание, что исключается редкий случай, когда значение равномерно распределенного случайного числа равно 0, поскольку от него будет браться натуральный логарифм.

Оглавление книги


Генерация: 1.153. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз