Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
8097 maxcodehac 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.