(* ************************************
   Генератор какбыслучайных чисел,
   Линейный конгруэнтный метод,
   алгоритм Лемера.
   Вадим Исаев, 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;


(* Целые какбыслучайные числа до RAND_MAX *)
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 до l.
   Return a random number in a range 0 ... l *)
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)) + 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.