Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. (* ************************************************************
  2.    Дополнительные алгоритмы генераторов какбыслучайных чисел.
  3.    Вадим Исаев, 2020
  4.  
  5.    Additional generators of pseudorandom numbers.
  6.    Vadim Isaev, 2020
  7.    ************************************************************ *)
  8.  
  9. MODULE RandExt;
  10.  
  11. IMPORT HOST, MathRound, MathBits;
  12.  
  13. CONST
  14.   (* Для алгоритма Мерсена-Твистера *)
  15.   N          = 624;
  16.   M          = 397;
  17.   MATRIX_A   = 9908B0DFH;  (* constant vector a *)
  18.   UPPER_MASK = 80000000H;  (* most significant w-r bits *)
  19.   LOWER_MASK = 7FFFFFFFH;  (* least significant r bits *)
  20.   INT_MAX    = 4294967295;
  21.  
  22.  
  23. TYPE
  24. (* структура служебных данных, для алгоритма mrg32k3a *)
  25.   random_t = RECORD
  26.     mrg32k3a_seed       : REAL;
  27.     mrg32k3a_x          : ARRAY 3 OF REAL;
  28.     mrg32k3a_y          : ARRAY 3 OF REAL
  29.   END;
  30.  
  31.   (* Для алгоритма Мерсена-Твистера *)
  32.   MTKeyArray = ARRAY N OF INTEGER;
  33.  
  34. VAR
  35.   (* Для алгоритма mrg32k3a *)
  36.   prndl: random_t;
  37.   (* Для алгоритма Мерсена-Твистера *)
  38.   mt  : MTKeyArray;  (* the array for the state vector *)
  39.   mti : INTEGER;     (* mti == N+1 means mt[N] is not initialized *)
  40.  
  41. (* ---------------------------------------------------------------------------
  42.    Генератор какбыслучайных чисел в диапазоне [a,b].
  43.    Алгоритм 133б из книги "Агеев и др. - Бибилотека алгоритмов 101б-150б",
  44.    стр. 53.
  45.    Переделка из Algol на Oberon и доработка, Вадим Исаев, 2020
  46.  
  47.    Generator pseudorandom numbers, algorithm 133b from
  48.    Comm ACM 5,10 (Oct 1962) 553.
  49.    Convert from Algol to Oberon Vadim Isaev, 2020.
  50.  
  51.    Входные параметры:
  52.      a - начальное вычисляемое значение, тип REAL;
  53.      b - конечное вычисляемое значение, тип REAL;
  54.      seed - начальное значение для генерации случайного числа.
  55.             Должно быть в диапазоне от 10 000 000 000 до 34 359 738 368 (2^35),
  56.             нечётное.
  57.    --------------------------------------------------------------------------- *)
  58. PROCEDURE alg133b* (a, b: REAL; VAR seed: INTEGER): REAL;
  59. CONST
  60.   m35 = 34359738368;
  61.   m36 = 68719476736;
  62.   m37 = 137438953472;
  63.  
  64. VAR
  65.   x: INTEGER;
  66. BEGIN
  67.   IF seed # 0 THEN
  68.     IF  (seed MOD 2 = 0) THEN
  69.       seed := seed + 1
  70.     END;
  71.     x:=seed;
  72.     seed:=0;
  73.   END;
  74.  
  75.   x:=5*x;
  76.   IF x>=m37 THEN
  77.     x:=x-m37
  78.   END;
  79.   IF x>=m36 THEN
  80.     x:=x-m36
  81.   END;
  82.   IF x>=m35 THEN
  83.     x:=x-m35
  84.   END;
  85.  
  86.   RETURN FLT(x) / FLT(m35) * (b - a) + a
  87. END alg133b;
  88.  
  89. (* ----------------------------------------------------------
  90.    Генератор почти равномерно распределённых
  91.    какбыслучайных чисел mrg32k3a
  92.    (Combined Multiple Recursive Generator) от 0 до 1.
  93.    Период повторения последовательности = 2^127
  94.  
  95.    Generator pseudorandom numbers,
  96.    algorithm mrg32k3a.
  97.  
  98.    Переделка из FreePascal на Oberon, Вадим Исаев, 2020
  99.    Convert from FreePascal to Oberon, Vadim Isaev, 2020
  100.    ---------------------------------------------------------- *)
  101. (* Инициализация генератора.
  102.  
  103.    Входные параметры:
  104.      seed  - значение для инициализации. Любое. Если передать
  105.              ноль, то вместо ноля будет подставлено кол-во
  106.              процессорных тиков. *)
  107. PROCEDURE mrg32k3a_init* (seed: REAL);
  108. BEGIN
  109.   prndl.mrg32k3a_x[0] := 1.0;
  110.   prndl.mrg32k3a_x[1] := 1.0;
  111.   prndl.mrg32k3a_y[0] := 1.0;
  112.   prndl.mrg32k3a_y[1] := 1.0;
  113.   prndl.mrg32k3a_y[2] := 1.0;
  114.  
  115.   IF seed # 0.0 THEN
  116.     prndl.mrg32k3a_x[2] := seed;
  117.   ELSE
  118.     prndl.mrg32k3a_x[2] := FLT(HOST.GetTickCount());
  119.   END;
  120.  
  121. END mrg32k3a_init;
  122.  
  123. (* Генератор какбыслучайных чисел от 0.0 до 1.0. *)
  124. PROCEDURE mrg32k3a* (): REAL;
  125.  
  126. CONST
  127.   (* random MRG32K3A algorithm constants *)
  128.   MRG32K3A_NORM = 2.328306549295728E-10;
  129.   MRG32K3A_M1   = 4294967087.0;
  130.   MRG32K3A_M2   = 4294944443.0;
  131.   MRG32K3A_A12  = 1403580.0;
  132.   MRG32K3A_A13  = 810728.0;
  133.   MRG32K3A_A21  = 527612.0;
  134.   MRG32K3A_A23  = 1370589.0;
  135.   RAND_BUFSIZE  = 512;
  136.  
  137. VAR
  138.  
  139.   xn, yn, result: REAL;
  140.  
  141. BEGIN
  142.   (* Часть 1 *)
  143.   xn := MRG32K3A_A12 * prndl.mrg32k3a_x[1] - MRG32K3A_A13 * prndl.mrg32k3a_x[2];
  144.   xn := xn - MathRound.trunc(xn / MRG32K3A_M1) * MRG32K3A_M1;
  145.   IF xn < 0.0 THEN
  146.     xn := xn + MRG32K3A_M1;
  147.   END;
  148.  
  149.   prndl.mrg32k3a_x[2] := prndl.mrg32k3a_x[1];
  150.   prndl.mrg32k3a_x[1] := prndl.mrg32k3a_x[0];
  151.   prndl.mrg32k3a_x[0] := xn;
  152.  
  153.   (* Часть 2 *)
  154.   yn := MRG32K3A_A21 * prndl.mrg32k3a_y[0] - MRG32K3A_A23 * prndl.mrg32k3a_y[2];
  155.   yn := yn - MathRound.trunc(yn / MRG32K3A_M2) * MRG32K3A_M2;
  156.   IF yn < 0.0 THEN
  157.     yn := yn + MRG32K3A_M2;
  158.   END;
  159.  
  160.   prndl.mrg32k3a_y[2] := prndl.mrg32k3a_y[1];
  161.   prndl.mrg32k3a_y[1] := prndl.mrg32k3a_y[0];
  162.   prndl.mrg32k3a_y[0] := yn;
  163.  
  164.   (* Смешение частей *)
  165.   IF xn <= yn THEN
  166.     result := ((xn - yn + MRG32K3A_M1) * MRG32K3A_NORM)
  167.   ELSE
  168.     result := (xn - yn) * MRG32K3A_NORM;
  169.   END;
  170.  
  171.   RETURN result
  172. END mrg32k3a;
  173.  
  174.  
  175. (* -------------------------------------------------------------------
  176.     Генератор какбыслучайных чисел, алгоритм Мерсена-Твистера (MT19937).
  177.     Переделка из Delphi в Oberon Вадим Исаев, 2020.
  178.  
  179.     Mersenne Twister Random Number Generator.
  180.  
  181.     A C-program for MT19937, with initialization improved 2002/1/26.
  182.     Coded by Takuji Nishimura and Makoto Matsumoto.
  183.  
  184.     Adapted for DMath by Jean Debord - Feb. 2007
  185.     Adapted for Oberon-07 by Vadim Isaev - May 2020
  186.   ------------------------------------------------------------ *)
  187. (* Initializes MT generator with a seed *)
  188. PROCEDURE InitMT(Seed : INTEGER);
  189. VAR
  190.   i : INTEGER;
  191. BEGIN
  192.   mt[0] := MathBits.iand(Seed, INT_MAX);
  193.   FOR i := 1 TO N-1 DO
  194.       mt[i] := (1812433253 * MathBits.ixor(mt[i-1], LSR(mt[i-1], 30)) + i);
  195.         (* See Knuth TAOCP Vol2. 3rd Ed. P.106 For multiplier.
  196.           In the previous versions, MSBs of the seed affect
  197.           only MSBs of the array mt[].
  198.           2002/01/09 modified by Makoto Matsumoto *)
  199.       mt[i] := MathBits.iand(mt[i], INT_MAX);
  200.         (* For >32 Bit machines *)
  201.   END;
  202.   mti := N;
  203. END InitMT;
  204.  
  205. (* Initialize MT generator with an array InitKey[0..(KeyLength - 1)] *)
  206. PROCEDURE InitMTbyArray(InitKey : MTKeyArray; KeyLength : INTEGER);
  207. VAR
  208.   i, j, k, k1 : INTEGER;
  209. BEGIN
  210.   InitMT(19650218);
  211.  
  212.   i := 1;
  213.   j := 0;
  214.  
  215.   IF N > KeyLength THEN
  216.     k1 := N
  217.   ELSE
  218.     k1 := KeyLength;
  219.   END;
  220.  
  221.   FOR k := k1 TO 1 BY -1 DO
  222.     (* non linear *)
  223.     mt[i] := MathBits.ixor(mt[i], (MathBits.ixor(mt[i-1], LSR(mt[i-1], 30)) * 1664525)) + InitKey[j] + j;
  224.     mt[i] := MathBits.iand(mt[i], INT_MAX); (* for WORDSIZE > 32 machines *)
  225.     INC(i);
  226.     INC(j);
  227.     IF i >= N THEN
  228.       mt[0] := mt[N-1];
  229.       i := 1;
  230.     END;
  231.     IF j >= KeyLength THEN
  232.       j := 0;
  233.     END;
  234.   END;
  235.  
  236.   FOR k := N-1 TO 1 BY -1 DO
  237.     (* non linear *)
  238.     mt[i] := MathBits.ixor(mt[i], (MathBits.ixor(mt[i-1], LSR(mt[i-1], 30)) * 1566083941)) - i;
  239.     mt[i] := MathBits.iand(mt[i], INT_MAX); (* for WORDSIZE > 32 machines *)
  240.     INC(i);
  241.     IF i >= N THEN
  242.       mt[0] := mt[N-1];
  243.       i := 1;
  244.     END;
  245.   END;
  246.  
  247.   mt[0] := UPPER_MASK; (* MSB is 1; assuring non-zero initial array *)
  248.  
  249. END InitMTbyArray;
  250.  
  251. (* Generates a integer Random number on [-2^31 .. 2^31 - 1] interval *)
  252. PROCEDURE IRanMT(): INTEGER;
  253. VAR
  254.   mag01 : ARRAY 2 OF INTEGER;
  255.   y,k   : INTEGER;
  256. BEGIN
  257.   IF mti >= N THEN  (* generate N words at one Time *)
  258.     (* If IRanMT() has not been called, a default initial seed is used *)
  259.     IF mti = N + 1 THEN
  260.       InitMT(5489);
  261.     END;
  262.  
  263.     FOR k := 0 TO (N-M)-1 DO
  264.       y := MathBits.ior(MathBits.iand(mt[k], UPPER_MASK), MathBits.iand(mt[k+1], LOWER_MASK));
  265.       mt[k] := MathBits.ixor(MathBits.ixor(mt[k+M], LSR(y, 1)), mag01[MathBits.iand(y, 1H)]);
  266.     END;
  267.  
  268.     FOR k := (N-M) TO (N-2) DO
  269.       y := MathBits.ior(MathBits.iand(mt[k], UPPER_MASK), MathBits.iand(mt[k+1], LOWER_MASK));
  270.       mt[k] := MathBits.ixor(mt[k - (N - M)], MathBits.ixor(LSR(y, 1), mag01[MathBits.iand(y, 1H)]));
  271.     END;
  272.  
  273.     y := MathBits.ior(MathBits.iand(mt[N-1], UPPER_MASK), MathBits.iand(mt[0], LOWER_MASK));
  274.     mt[N-1] := MathBits.ixor(mt[M-1], MathBits.ixor(LSR(y, 1), mag01[MathBits.iand(y, 1H)]));
  275.  
  276.     mti := 0;
  277.   END;
  278.  
  279.   y := mt[mti];
  280.   INC(mti);
  281.  
  282.   (* Tempering *)
  283.   y := MathBits.ixor(y, LSR(y, 11));
  284.   y := MathBits.ixor(y, MathBits.iand(LSL(y,  7), 9D2C5680H));
  285.   y := MathBits.ixor(y, MathBits.iand(LSL(y, 15), 4022730752));
  286.   y := MathBits.ixor(y, LSR(y, 18));
  287.  
  288.   RETURN y
  289. END IRanMT;
  290.  
  291. (* Generates a real Random number on [0..1] interval *)
  292. PROCEDURE RRanMT(): REAL;
  293. BEGIN
  294.   RETURN FLT(IRanMT())/FLT(INT_MAX)
  295. END RRanMT;
  296.  
  297.  
  298. END RandExt.
  299.