Random.Mod 4.3 KB

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