(* ************************************
   Генератор какбыслучайных чисел,
   Линейный конгруэнтный метод,
   алгоритм Лемера.
   Вадим Исаев, 2020
   -------------------------------
   Generator pseudorandom numbers,
   Linear congruential generator,
   Algorithm by D. H. Lehmer.
   Vadim Isaev, 2020
*************************************** *)

MODULE Rand;

IMPORT HOST, Math;


CONST

    RAND_MAX = 2147483647;


VAR
    seed: INTEGER;


PROCEDURE Randomize*;
BEGIN
    seed := HOST.GetTickCount()
END Randomize;


(* Целые какбыслучайные числа 0..RAND_MAX-1 *)
PROCEDURE RandomI* (): INTEGER;
CONST
    a = 630360016;

BEGIN
    seed := (a * seed) MOD RAND_MAX
    RETURN seed
END RandomI;


(* Какбыслучайные числа с плавающей запятой [0, 1) *)
PROCEDURE RandomR* (): REAL;
    RETURN FLT(RandomI()) / FLT(RAND_MAX)
END RandomR;


(* Какбыслучайное число в диапазоне 0..aTo-1
   Return a random number in a range 0..aTo-1 *)
PROCEDURE RandomITo* (aTo: INTEGER): INTEGER;
    RETURN FLOOR(RandomR() * FLT(aTo))
END RandomITo;


(* Какбыслучайное число в диапазоне.
   Return a random number in a range *)
PROCEDURE RandomIRange* (aFrom, aTo: INTEGER): INTEGER;
    RETURN FLOOR(RandomR() * FLT(aTo - aFrom + 1)) + aFrom
END RandomIRange;


(* Какбыслучайное число. Распределение Гаусса *)
PROCEDURE RandG* (mean, stddev: REAL): REAL;
VAR
    U, S: REAL;

BEGIN
    REPEAT
        U := 2.0 * RandomR() - 1.0;
        S := Math.sqrr(U) + Math.sqrr(2.0 * RandomR() - 1.0)
    UNTIL (1.0E-20 < S) & (S <= 1.0)

    RETURN Math.sqrt(-2.0 * Math.ln(S) / S) * U * stddev + mean
END RandG;


BEGIN
    seed := 654321
END Rand.