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

Листинг 6.9. Комбинирование генераторов type TtdCombinedPRNG = class (TtdBasePRNG) private FSeedl : longint;
FSeed2 : longint;
protected
procedure cpSetSeedl(aValue : longint);
procedure cpSetSeed2 (aValue : longint) ; public

constructor Create (aSeedl, aSeed2 : longint) ; function As Double : double;
override; property Seedl : longint read FSeedl write cpSetSeedl ; property Seed2 : longint read FSeed2 write cpSetSeed2 ;
end;
constructor TtdCombinedPRNG. Create (aSeedl, aSeed2 begin
inherited Create;
Seedl := aSeedl;
Seed2 := aSeed2;
end;
longint);

function TtdCombinedPRNG.AsDouble : double; const

al = 40014;
ml = 2147483563;
ql = 53668; {равно ml div al}
rl = 12211; {равно ml mod al}
a2 = 40692;
m2 = 2147483399;
q2 = 52774; {равно m2 div a2}
r2 = 3791; {равно m2 mod a2}
OneOverMl : double = 1.0 / 2147483563.0; var к : longint;
Z : longint;
begin
{получить случайное число с помощью первого генератора} к := FSeedl div ql;
FSeedl :== (al * (FSeedl - (k * ql))) - (k * rl);
if (FSeedl <= 0) then
inc(FSeedl, ml) ; {получить случайное число с помощью второго генератора} к := FSeed2 divq2;
FSeed2 := (а2 * (FSeed2 - (к * q2))) - (к * r2);
if (FSeed2 <= 0) then
inc(FSeed2, m2) ; {объединить два случайных числа} Z := FSeedl - FSeed2; if (Z <= 0) then
Z : = Z + ml - 1; Result := Z * OneOverMl;
end;
procedure TtdCombinedPRNG.cpSetSeedl(aValue : longint);
const
ml = 2147483563; begin
if (aValue > 0) then FSeedl : = aValue

else FSeedl := GetTimeAsLong; {убедиться, что случайное число находится в диапазоне от 1 до т-1

включительно} if (FSeedl >- ml-1) then
FSeedl := FSeedl - (ml-1) + 1;
end;
procedure TtdCombinedPRNG. cpSetSeed2 (aValue : longint) ; const
m2 = 2147483399;

begin if (aValue > 0) then FSeed2 : = aValue else FSeed2 := GetTimeAsLong; {убедиться, что случайное число находится в диапазоне от 1 до т-1

включительно} if (FSeed2 >=m2-l) then FSeed2 := FSeed2 - (m2 - 1) + 1;
end;

Как видите, код метода As Double в листинге 6.9 содержит два мультипликативных линейных конгруэнтных генератора: первый с параметрами {а, т} = {40014,2147483563} и второй с параметрами {а, т) = {40692, 2147483399}. Циклы обоих генераторов отличаются, но, тем не менее, близки к 231. Для преобразования промежуточного значения типа longint в значение типа double используется генератор с более длинным циклом.

Приведенный в листинге 6.9 генератор исключает двухмерную регулярность простого мультипликативного линейного конгруэнтного генератора, в чем можно убедиться с помощью программы тестирования. Можно показать, что длина цикла полученного комбинированного генератора составляет примерно 2 * 1018. (Для сравнения, длина цикла стандартного генератора Delphi примерно равна 4 * 109.) Последовательность, вычисляемая с помощью комбинированного генератора полностью, определяется двумя начальными числами - по одному для каждого внутреннего генератора, в то время как для простого мультипликативного генератора было достаточно одного числа.

Результаты выполнения тестов || Оглавление || Аддитивные генераторы


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



Новости за месяц

  • Август
    2019
  • Пн
  • Вт
  • Ср
  • Чт
  • Пт
  • Сб
  • Вс