Random.Mod 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE Random; (** AUTHOR "ecarter/bsm/pjm"; PURPOSE "Pseudo-random number generator"; *)
  3. (* Based on the ADA version by Everett F. Carter Jr., ported to Aos by Ben Smith-Mannschott. *)
  4. IMPORT SYSTEM, Math;
  5. CONST
  6. max = 2147483647;
  7. msbit = 40000000H;
  8. allbits = 7FFFFFFFH;
  9. halfrange = 20000000H;
  10. step = 7;
  11. TYPE
  12. (** A pseudo-random number generator. This object is not reentrant. *)
  13. Generator* = OBJECT
  14. VAR
  15. buffer: ARRAY 250 OF SET;
  16. index: LONGINT;
  17. Z: LONGINT; (* seed for Rand() *)
  18. PROCEDURE Rand(): LONGINT;
  19. (* for Init. Same as used by RandomNumbers *)
  20. CONST a = 16807; q = 127773; r = 2836;
  21. VAR t: LONGINT;
  22. BEGIN
  23. t := a * (Z MOD q) - r * (Z DIV q);
  24. IF t > 0 THEN Z := t ELSE Z := t + max END;
  25. RETURN Z;
  26. END Rand;
  27. (** Set the seed. *)
  28. PROCEDURE InitSeed*(seed: LONGINT);
  29. VAR
  30. k, i: LONGINT;
  31. mask, msb: LONGINT;
  32. BEGIN
  33. Z := seed; index := 0;
  34. FOR i := 0 TO 249 DO
  35. buffer[i] := SYSTEM.VAL(SET, Rand())
  36. END;
  37. FOR i := 0 TO 249 DO
  38. IF Rand() > halfrange THEN
  39. buffer[i] := buffer[i] + SYSTEM.VAL(SET,msbit);
  40. END;
  41. END;
  42. msb := msbit; mask := allbits;
  43. FOR i := 0 TO 30 DO
  44. k := step * i + 3;
  45. buffer[k] := buffer[k] * SYSTEM.VAL(SET,mask);
  46. buffer[k] := buffer[k] + SYSTEM.VAL(SET, msb);
  47. msb := msb DIV 2;
  48. mask := mask DIV 2;
  49. END;
  50. END InitSeed;
  51. (** The default seed is 1. *)
  52. PROCEDURE & Init*;
  53. BEGIN
  54. InitSeed(1)
  55. END Init;
  56. (** Return a pseudo-random 32-bit integer. *)
  57. PROCEDURE Integer*(): LONGINT;
  58. VAR newRand, j: LONGINT;
  59. BEGIN
  60. IF index >= 147 THEN j := index - 147 ELSE j := index + 103 END;
  61. buffer[index] := buffer[index] / buffer[j];
  62. newRand := SYSTEM.VAL(LONGINT, buffer[index]);
  63. IF index >= 249 THEN index := 0 ELSE INC(index) END;
  64. RETURN newRand
  65. END Integer;
  66. (** Return a pseudo-random number from 0..sides-1. *)
  67. PROCEDURE Dice*(sides: LONGINT): LONGINT;
  68. BEGIN
  69. RETURN Integer() MOD sides;
  70. END Dice;
  71. (** Return a pseudo-random real number, uniformly distributed. *)
  72. PROCEDURE Uniform*(): REAL;
  73. BEGIN
  74. RETURN Integer() / allbits;
  75. END Uniform;
  76. (** Return a pseudo-random real number, exponentially distributed. *)
  77. PROCEDURE Exp*(mu: REAL): REAL;
  78. BEGIN
  79. RETURN -Math.ln(Uniform())/mu
  80. END Exp;
  81. PROCEDURE Gaussian*(): REAL; (*generates a normal distribution with mean 0, variance 1 using the Box-Muller Transform*)
  82. VAR
  83. x1,x2,w,y1: REAL;
  84. BEGIN
  85. REPEAT
  86. x1:=2.0*Uniform()-1;
  87. x2:=2.0*Uniform()-1;
  88. w:=x1*x1+x2*x2;
  89. UNTIL w<1;
  90. w:=Math.sqrt( (-2.0* Math.ln(w) ) /w);
  91. y1:=x1*w;
  92. (*y2:=x2*w*)
  93. RETURN y1;
  94. END Gaussian;
  95. END Generator;
  96. TYPE
  97. (** This is a protected wrapper for the Generator object. It synchronizes concurrent calls and is therefore slower. *)
  98. Sequence* = OBJECT
  99. VAR r: Generator;
  100. PROCEDURE InitSeed*(seed: LONGINT);
  101. BEGIN {EXCLUSIVE}
  102. r.InitSeed(seed)
  103. END InitSeed;
  104. PROCEDURE &Init*;
  105. BEGIN
  106. NEW(r)
  107. END Init;
  108. PROCEDURE Integer*(): LONGINT;
  109. BEGIN {EXCLUSIVE}
  110. RETURN r.Integer()
  111. END Integer;
  112. PROCEDURE Dice*(sides: LONGINT): LONGINT;
  113. BEGIN {EXCLUSIVE}
  114. RETURN r.Dice(sides)
  115. END Dice;
  116. PROCEDURE Uniform*(): REAL;
  117. BEGIN {EXCLUSIVE}
  118. RETURN r.Uniform()
  119. END Uniform;
  120. PROCEDURE Exp*(mu: REAL): REAL;
  121. BEGIN {EXCLUSIVE}
  122. RETURN r.Exp(mu)
  123. END Exp;
  124. PROCEDURE Gaussian*(): REAL; (*generates a normal distribution with mean 0, variance 1 using the Box-Muller Transform*)
  125. VAR
  126. x1,x2,w,y1: REAL;
  127. BEGIN {EXCLUSIVE}
  128. REPEAT
  129. x1:=2.0*Uniform()-1;
  130. x2:=2.0*Uniform()-1;
  131. w:=x1*x1+x2*x2;
  132. UNTIL w<1;
  133. w:=Math.sqrt( (-2.0* Math.ln(w) ) /w);
  134. y1:=x1*w;
  135. (*y2:=x2*w*)
  136. RETURN y1;
  137. END Gaussian;
  138. END Sequence;
  139. END Random.
  140. (*
  141. from the ADA version:
  142. (c) Copyright 1997 Everett F. Carter Jr. Permission is
  143. granted by the author to use this software for any
  144. application provided this copyright notice is preserved.
  145. The algorithm was originally described by
  146. Kirkpatrick, S., and E. Stoll, 1981;
  147. A Very Fast Shift-Register Sequence Random Number Generator,
  148. Journal of Computational Physics, V. 40. pp. 517-526
  149. Performance:
  150. Its period is 2^249. This implementation is about 25% faster than
  151. RandomNumbers.Uniform(). It also offers direct generation of
  152. integers which is even faster (2x on PowerPC) and especially
  153. good for FPU-challenged machines like the Shark NCs.
  154. *)