2023-01-21 15:34:25 +01:00
|
|
|
|
(* ************************************************************
|
|
|
|
|
Дополнительные алгоритмы генераторов какбыслучайных чисел.
|
|
|
|
|
Вадим Исаев, 2020
|
|
|
|
|
|
|
|
|
|
Additional generators of pseudorandom numbers.
|
|
|
|
|
Vadim Isaev, 2020
|
|
|
|
|
************************************************************ *)
|
|
|
|
|
|
|
|
|
|
MODULE RandExt;
|
|
|
|
|
|
|
|
|
|
IMPORT HOST, MathRound, MathBits;
|
|
|
|
|
|
|
|
|
|
CONST
|
|
|
|
|
(* Для алгоритма Мерсена-Твистера *)
|
|
|
|
|
N = 624;
|
|
|
|
|
M = 397;
|
|
|
|
|
MATRIX_A = 9908B0DFH; (* constant vector a *)
|
|
|
|
|
UPPER_MASK = 80000000H; (* most significant w-r bits *)
|
|
|
|
|
LOWER_MASK = 7FFFFFFFH; (* least significant r bits *)
|
|
|
|
|
INT_MAX = 4294967295;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TYPE
|
|
|
|
|
(* структура служебных данных, для алгоритма mrg32k3a *)
|
|
|
|
|
random_t = RECORD
|
|
|
|
|
mrg32k3a_seed : REAL;
|
|
|
|
|
mrg32k3a_x : ARRAY 3 OF REAL;
|
|
|
|
|
mrg32k3a_y : ARRAY 3 OF REAL
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
(* Для алгоритма Мерсена-Твистера *)
|
|
|
|
|
MTKeyArray = ARRAY N OF INTEGER;
|
|
|
|
|
|
|
|
|
|
VAR
|
|
|
|
|
(* Для алгоритма mrg32k3a *)
|
|
|
|
|
prndl: random_t;
|
|
|
|
|
(* Для алгоритма Мерсена-Твистера *)
|
|
|
|
|
mt : MTKeyArray; (* the array for the state vector *)
|
|
|
|
|
mti : INTEGER; (* mti == N+1 means mt[N] is not initialized *)
|
|
|
|
|
|
|
|
|
|
(* ---------------------------------------------------------------------------
|
|
|
|
|
Генератор какбыслучайных чисел в диапазоне [a,b].
|
|
|
|
|
Алгоритм 133б из книги "Агеев и др. - Бибилотека алгоритмов 101б-150б",
|
|
|
|
|
стр. 53.
|
|
|
|
|
Переделка из Algol на Oberon и доработка, Вадим Исаев, 2020
|
|
|
|
|
|
|
|
|
|
Generator pseudorandom numbers, algorithm 133b from
|
|
|
|
|
Comm ACM 5,10 (Oct 1962) 553.
|
|
|
|
|
Convert from Algol to Oberon Vadim Isaev, 2020.
|
|
|
|
|
|
|
|
|
|
Входные параметры:
|
|
|
|
|
a - начальное вычисляемое значение, тип REAL;
|
|
|
|
|
b - конечное вычисляемое значение, тип REAL;
|
|
|
|
|
seed - начальное значение для генерации случайного числа.
|
|
|
|
|
Должно быть в диапазоне от 10 000 000 000 до 34 359 738 368 (2^35),
|
|
|
|
|
нечётное.
|
|
|
|
|
--------------------------------------------------------------------------- *)
|
|
|
|
|
PROCEDURE alg133b* (a, b: REAL; VAR seed: INTEGER): REAL;
|
|
|
|
|
CONST
|
|
|
|
|
m35 = 34359738368;
|
|
|
|
|
m36 = 68719476736;
|
|
|
|
|
m37 = 137438953472;
|
|
|
|
|
|
|
|
|
|
VAR
|
|
|
|
|
x: INTEGER;
|
|
|
|
|
BEGIN
|
|
|
|
|
IF seed # 0 THEN
|
|
|
|
|
IF (seed MOD 2 = 0) THEN
|
|
|
|
|
seed := seed + 1
|
|
|
|
|
END;
|
|
|
|
|
x:=seed;
|
|
|
|
|
seed:=0;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
x:=5*x;
|
|
|
|
|
IF x>=m37 THEN
|
|
|
|
|
x:=x-m37
|
|
|
|
|
END;
|
|
|
|
|
IF x>=m36 THEN
|
|
|
|
|
x:=x-m36
|
|
|
|
|
END;
|
|
|
|
|
IF x>=m35 THEN
|
|
|
|
|
x:=x-m35
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
RETURN FLT(x) / FLT(m35) * (b - a) + a
|
|
|
|
|
END alg133b;
|
|
|
|
|
|
|
|
|
|
(* ----------------------------------------------------------
|
|
|
|
|
Генератор почти равномерно распределённых
|
|
|
|
|
какбыслучайных чисел mrg32k3a
|
|
|
|
|
(Combined Multiple Recursive Generator) от 0 до 1.
|
|
|
|
|
Период повторения последовательности = 2^127
|
|
|
|
|
|
|
|
|
|
Generator pseudorandom numbers,
|
|
|
|
|
algorithm mrg32k3a.
|
|
|
|
|
|
|
|
|
|
Переделка из FreePascal на Oberon, Вадим Исаев, 2020
|
|
|
|
|
Convert from FreePascal to Oberon, Vadim Isaev, 2020
|
|
|
|
|
---------------------------------------------------------- *)
|
|
|
|
|
(* Инициализация генератора.
|
|
|
|
|
|
|
|
|
|
Входные параметры:
|
|
|
|
|
seed - значение для инициализации. Любое. Если передать
|
|
|
|
|
ноль, то вместо ноля будет подставлено кол-во
|
|
|
|
|
процессорных тиков. *)
|
|
|
|
|
PROCEDURE mrg32k3a_init* (seed: REAL);
|
|
|
|
|
BEGIN
|
|
|
|
|
prndl.mrg32k3a_x[0] := 1.0;
|
|
|
|
|
prndl.mrg32k3a_x[1] := 1.0;
|
|
|
|
|
prndl.mrg32k3a_y[0] := 1.0;
|
|
|
|
|
prndl.mrg32k3a_y[1] := 1.0;
|
|
|
|
|
prndl.mrg32k3a_y[2] := 1.0;
|
|
|
|
|
|
|
|
|
|
IF seed # 0.0 THEN
|
|
|
|
|
prndl.mrg32k3a_x[2] := seed;
|
|
|
|
|
ELSE
|
|
|
|
|
prndl.mrg32k3a_x[2] := FLT(HOST.GetTickCount());
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
END mrg32k3a_init;
|
|
|
|
|
|
|
|
|
|
(* Генератор какбыслучайных чисел от 0.0 до 1.0. *)
|
|
|
|
|
PROCEDURE mrg32k3a* (): REAL;
|
|
|
|
|
|
|
|
|
|
CONST
|
|
|
|
|
(* random MRG32K3A algorithm constants *)
|
|
|
|
|
MRG32K3A_NORM = 2.328306549295728E-10;
|
|
|
|
|
MRG32K3A_M1 = 4294967087.0;
|
|
|
|
|
MRG32K3A_M2 = 4294944443.0;
|
|
|
|
|
MRG32K3A_A12 = 1403580.0;
|
|
|
|
|
MRG32K3A_A13 = 810728.0;
|
|
|
|
|
MRG32K3A_A21 = 527612.0;
|
|
|
|
|
MRG32K3A_A23 = 1370589.0;
|
|
|
|
|
RAND_BUFSIZE = 512;
|
|
|
|
|
|
|
|
|
|
VAR
|
|
|
|
|
|
|
|
|
|
xn, yn, result: REAL;
|
|
|
|
|
|
|
|
|
|
BEGIN
|
|
|
|
|
(* Часть 1 *)
|
|
|
|
|
xn := MRG32K3A_A12 * prndl.mrg32k3a_x[1] - MRG32K3A_A13 * prndl.mrg32k3a_x[2];
|
|
|
|
|
xn := xn - MathRound.trunc(xn / MRG32K3A_M1) * MRG32K3A_M1;
|
|
|
|
|
IF xn < 0.0 THEN
|
|
|
|
|
xn := xn + MRG32K3A_M1;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
prndl.mrg32k3a_x[2] := prndl.mrg32k3a_x[1];
|
|
|
|
|
prndl.mrg32k3a_x[1] := prndl.mrg32k3a_x[0];
|
|
|
|
|
prndl.mrg32k3a_x[0] := xn;
|
|
|
|
|
|
|
|
|
|
(* Часть 2 *)
|
|
|
|
|
yn := MRG32K3A_A21 * prndl.mrg32k3a_y[0] - MRG32K3A_A23 * prndl.mrg32k3a_y[2];
|
|
|
|
|
yn := yn - MathRound.trunc(yn / MRG32K3A_M2) * MRG32K3A_M2;
|
|
|
|
|
IF yn < 0.0 THEN
|
|
|
|
|
yn := yn + MRG32K3A_M2;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
prndl.mrg32k3a_y[2] := prndl.mrg32k3a_y[1];
|
|
|
|
|
prndl.mrg32k3a_y[1] := prndl.mrg32k3a_y[0];
|
|
|
|
|
prndl.mrg32k3a_y[0] := yn;
|
|
|
|
|
|
|
|
|
|
(* Смешение частей *)
|
|
|
|
|
IF xn <= yn THEN
|
|
|
|
|
result := ((xn - yn + MRG32K3A_M1) * MRG32K3A_NORM)
|
|
|
|
|
ELSE
|
|
|
|
|
result := (xn - yn) * MRG32K3A_NORM;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
RETURN result
|
|
|
|
|
END mrg32k3a;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(* -------------------------------------------------------------------
|
|
|
|
|
Генератор какбыслучайных чисел, алгоритм Мерсена-Твистера (MT19937).
|
|
|
|
|
Переделка из Delphi в Oberon Вадим Исаев, 2020.
|
|
|
|
|
|
|
|
|
|
Mersenne Twister Random Number Generator.
|
|
|
|
|
|
|
|
|
|
A C-program for MT19937, with initialization improved 2002/1/26.
|
|
|
|
|
Coded by Takuji Nishimura and Makoto Matsumoto.
|
|
|
|
|
|
|
|
|
|
Adapted for DMath by Jean Debord - Feb. 2007
|
|
|
|
|
Adapted for Oberon-07 by Vadim Isaev - May 2020
|
|
|
|
|
------------------------------------------------------------ *)
|
|
|
|
|
(* Initializes MT generator with a seed *)
|
|
|
|
|
PROCEDURE InitMT(Seed : INTEGER);
|
|
|
|
|
VAR
|
|
|
|
|
i : INTEGER;
|
|
|
|
|
BEGIN
|
|
|
|
|
mt[0] := MathBits.iand(Seed, INT_MAX);
|
|
|
|
|
FOR i := 1 TO N-1 DO
|
|
|
|
|
mt[i] := (1812433253 * MathBits.ixor(mt[i-1], LSR(mt[i-1], 30)) + i);
|
|
|
|
|
(* See Knuth TAOCP Vol2. 3rd Ed. P.106 For multiplier.
|
|
|
|
|
In the previous versions, MSBs of the seed affect
|
|
|
|
|
only MSBs of the array mt[].
|
|
|
|
|
2002/01/09 modified by Makoto Matsumoto *)
|
|
|
|
|
mt[i] := MathBits.iand(mt[i], INT_MAX);
|
|
|
|
|
(* For >32 Bit machines *)
|
|
|
|
|
END;
|
|
|
|
|
mti := N;
|
|
|
|
|
END InitMT;
|
|
|
|
|
|
|
|
|
|
(* Initialize MT generator with an array InitKey[0..(KeyLength - 1)] *)
|
|
|
|
|
PROCEDURE InitMTbyArray(InitKey : MTKeyArray; KeyLength : INTEGER);
|
|
|
|
|
VAR
|
|
|
|
|
i, j, k, k1 : INTEGER;
|
|
|
|
|
BEGIN
|
|
|
|
|
InitMT(19650218);
|
|
|
|
|
|
|
|
|
|
i := 1;
|
|
|
|
|
j := 0;
|
|
|
|
|
|
|
|
|
|
IF N > KeyLength THEN
|
|
|
|
|
k1 := N
|
|
|
|
|
ELSE
|
|
|
|
|
k1 := KeyLength;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
FOR k := k1 TO 1 BY -1 DO
|
|
|
|
|
(* non linear *)
|
|
|
|
|
mt[i] := MathBits.ixor(mt[i], (MathBits.ixor(mt[i-1], LSR(mt[i-1], 30)) * 1664525)) + InitKey[j] + j;
|
|
|
|
|
mt[i] := MathBits.iand(mt[i], INT_MAX); (* for WORDSIZE > 32 machines *)
|
|
|
|
|
INC(i);
|
|
|
|
|
INC(j);
|
|
|
|
|
IF i >= N THEN
|
|
|
|
|
mt[0] := mt[N-1];
|
|
|
|
|
i := 1;
|
|
|
|
|
END;
|
|
|
|
|
IF j >= KeyLength THEN
|
|
|
|
|
j := 0;
|
|
|
|
|
END;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
FOR k := N-1 TO 1 BY -1 DO
|
|
|
|
|
(* non linear *)
|
|
|
|
|
mt[i] := MathBits.ixor(mt[i], (MathBits.ixor(mt[i-1], LSR(mt[i-1], 30)) * 1566083941)) - i;
|
|
|
|
|
mt[i] := MathBits.iand(mt[i], INT_MAX); (* for WORDSIZE > 32 machines *)
|
|
|
|
|
INC(i);
|
|
|
|
|
IF i >= N THEN
|
|
|
|
|
mt[0] := mt[N-1];
|
|
|
|
|
i := 1;
|
|
|
|
|
END;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
mt[0] := UPPER_MASK; (* MSB is 1; assuring non-zero initial array *)
|
|
|
|
|
|
|
|
|
|
END InitMTbyArray;
|
|
|
|
|
|
|
|
|
|
(* Generates a integer Random number on [-2^31 .. 2^31 - 1] interval *)
|
|
|
|
|
PROCEDURE IRanMT(): INTEGER;
|
|
|
|
|
VAR
|
|
|
|
|
mag01 : ARRAY 2 OF INTEGER;
|
|
|
|
|
y,k : INTEGER;
|
|
|
|
|
BEGIN
|
|
|
|
|
IF mti >= N THEN (* generate N words at one Time *)
|
|
|
|
|
(* If IRanMT() has not been called, a default initial seed is used *)
|
|
|
|
|
IF mti = N + 1 THEN
|
|
|
|
|
InitMT(5489);
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
FOR k := 0 TO (N-M)-1 DO
|
|
|
|
|
y := MathBits.ior(MathBits.iand(mt[k], UPPER_MASK), MathBits.iand(mt[k+1], LOWER_MASK));
|
|
|
|
|
mt[k] := MathBits.ixor(MathBits.ixor(mt[k+M], LSR(y, 1)), mag01[MathBits.iand(y, 1H)]);
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
FOR k := (N-M) TO (N-2) DO
|
|
|
|
|
y := MathBits.ior(MathBits.iand(mt[k], UPPER_MASK), MathBits.iand(mt[k+1], LOWER_MASK));
|
|
|
|
|
mt[k] := MathBits.ixor(mt[k - (N - M)], MathBits.ixor(LSR(y, 1), mag01[MathBits.iand(y, 1H)]));
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
y := MathBits.ior(MathBits.iand(mt[N-1], UPPER_MASK), MathBits.iand(mt[0], LOWER_MASK));
|
|
|
|
|
mt[N-1] := MathBits.ixor(mt[M-1], MathBits.ixor(LSR(y, 1), mag01[MathBits.iand(y, 1H)]));
|
|
|
|
|
|
|
|
|
|
mti := 0;
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
|
|
y := mt[mti];
|
|
|
|
|
INC(mti);
|
|
|
|
|
|
|
|
|
|
(* Tempering *)
|
|
|
|
|
y := MathBits.ixor(y, LSR(y, 11));
|
|
|
|
|
y := MathBits.ixor(y, MathBits.iand(LSL(y, 7), 9D2C5680H));
|
|
|
|
|
y := MathBits.ixor(y, MathBits.iand(LSL(y, 15), 4022730752));
|
|
|
|
|
y := MathBits.ixor(y, LSR(y, 18));
|
|
|
|
|
|
|
|
|
|
RETURN y
|
|
|
|
|
END IRanMT;
|
|
|
|
|
|
|
|
|
|
(* Generates a real Random number on [0..1] interval *)
|
|
|
|
|
PROCEDURE RRanMT(): REAL;
|
|
|
|
|
BEGIN
|
|
|
|
|
RETURN FLT(IRanMT())/FLT(INT_MAX)
|
|
|
|
|
END RRanMT;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
END RandExt.
|