52704.fb2 Фундаментальные алгоритмы и структуры данных в Delphi - читать онлайн бесплатно полную версию книги . Страница 86

Фундаментальные алгоритмы и структуры данных в Delphi - читать онлайн бесплатно полную версию книги . Страница 86

procedure TtdMinStandardPRNG.msSetSeed(aValue : longint);

const

m = 2147483647;

begin

if (aValue > 0) then

FSeed := aValue

else

FSeed := GetTimeAsLong;

{убедиться, что значение начального числа находится в переделах от 0 до m-1 включительно}

if (FSeed >=m-1) then

FSeed := FSeed - (m - 1) + 1;

end;

Как несложно заметить в коде метода AsDouble, метод Шрейга выглядит гораздо сложнее, нежели простая формула X(_n+1_) = aX(_n_) mod m со значениями а = 16807 и m = 2(^31^) - 1. Тем не менее, используя достаточно сложные математические выкладки, можно доказать его равенство приведенной формуле.

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

Создадим класс случайных чисел, который будет использовать системный генератор случайных чисел - функцию Random. В листинге 6.4 показан код метода AsDouble для такого класса.

Листинг 6.4. Использование в классе системной функции Random

function TtdSystemPRNG.AsDouble : double;

var

OldSeed : longint;

begin

OldSeed := System.RandSeed;

System.RandSeed := Seed;

Result := System.Random;

Seed := System.RandSeed;

System.RandSeed := OldSeed;

end;

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

Тестирование

В основе всех тестов будут лежать одни и те же принципы. Мы будем генерировать большое количество случайных чисел из диапазона от 0.0 (включительно) до 1.0 (исключительно). Получаемые в результате работы генераторов значения будут разбиваться на несколько категорий, будет подсчитываться количество значений в каждой категории, а затем вероятность попадания значения в каждую категорию. На основе результатов вычислений будет определяться значение функции хи-квадрат, на основе которого будет прогоняться тест по критерию хи-квадрат. При этом количество степеней свободы будет на единицу меньше, чем количество категорий значений. Это было всего лишь краткое введение, но через несколько минут мы приступим к собственно тестированию.

Тест на однородность

Первый тест самый простой - проверка на однородность. О нем мы уже говорили. Фактически случайные числа будут проверяться на равномерность распределения по диапазону от 0.0 до 1.0. Разобьем весь диапазон на 100 поддиапазонов, сформируем набор из 1000000 случайных чисел и вычислим количество значений, попавших в каждый поддиапазон. В поддиапазоне 0 будут находиться значения от 0.00 до 0.01, в поддиапазоне 1 - значения от 0.01 до 0.02 и т.д. Вероятность попадания случайного числа в любой поддиапазон составляет 0.01. Для полученного распределения вычислим значение параметра хи-квадрат и сравним его с данными для стандартного распределения хи-квадрат, находящимися в строке, для 99 степеней свободы.

Листинг 6.5. Тест на однородность

procedure UnifomityTest(RandGen : TtdBasePRNG;

var ChiSquare : double; var DegsFreedo : integer);

var

BucketNumber, i : integer;

Expected, ChiSqVal : double;

Bucket : array [0..pred(Uniformitylntervals) ] of integer;

begin

{вычислить количество чисел в каждом поддиапазоне}

FillChar(Bucket, sizeof(Bucket), 0);

for i := 0 to pred(UniformityCount) do

begin

BucketNumber := trunc(RandGen.AsDouble * Uniformitylntervals);

inc (Bucket [BucketNumber]);

end;

{вычислить значение параметра xu-квадрат}

Expected := UniformityCount / Uniformitylntervals;

ChiSqVal := 0.0;

for i := 0 to pred(Uniformitylntervals) do

ChiSqVal := ChiSqVal + (Sqr (Expected - Bucket [i]) / Expected);

{вернуть значения}