You're here: Snippet Directory » Microsoft .NET » C# (33)
Language:

A Good 31 bit Random Number Generator Class

Language: English
Programming Language: C#
Published by: jill-eskimo-com [not registered]
Last Update: 5/15/2006
Views: 1085

License: Artistic License

Description

Miller and Parks late 80's ACM article revisited in C# with MFC exception throws. <sigh>I find it hard to believe that after all these years this is not part of a standard library </sigh>

Code

1 using System; 2 3 namespace Barsoom 4 { 5 /// <summary> 6 /// Good 31-bit Random Number Generator, returns Uint. 7 /// </summary> 8 /// <remarks> 9 /// 10 /// LICENSE : PUBLIC DOMAIN 11 /// 12 /// This is the base class for double and other statistical 13 /// random number distribution classes 14 /// 15 /// Throws exception if initial seed is out of range. 16 /// 17 /// Stephen K. Park and Keith W. Miller. RANDOM NUMBER GENERATORS: 18 /// GOOD ONES ARE HARD TO FIND. Communications of the ACM, 19 /// New York, NY.,October 1988 p.1192 20 /// 21 /// Throws exception if initial seed is out of range 22 /// This program is public domain and was written by Jill England 23 /// (Oct 1988). 24 /// 25 /// Modifications; 26 /// 27 /// Converted to C# from C++ and hacked heavily. One major cool thing done 28 /// here is to be able to SET the seed or get the next LCG value. 29 /// 3/4/2002 JAE Jill@eskimo.com 30 /// 31 /// Imported into Visual Studio .net, 3/1/2002 JAE jill@eskimo.com 32 /// 33 /// To build the generator with the original ACM 34 /// article's numbers use -DACM_ORIGINAL_NUMBERS when compiling. 35 /// 36 /// Original_numbers are those published m and q in the 37 /// original ACM article. John Burton, a Miller/Park, associate 38 /// has furnished numbers for a reportedly better generator. The 39 /// new numbers are now used in this program by default. 40 /// 41 /// F(z) = (az)%m 42 /// = az-m(az/m) 43 /// 44 /// F(z) = G(z) + mT(z) 45 /// G(z) = a(z%q) - r(z/q) 46 /// T(z) = (z/q) - (az/m) 47 /// 48 /// F(z) = a(z%q)- rz/q+ m((z/q) - a(z/m)) 49 /// = a(z%q)- rz/q+ m(z/q) - az 50 /// 51 /// NOTE JAE: I could easily extend this class to a C# 63 bit LCG but, 52 /// don't really see the point for most applications I have. 53 /// Besides 2**63 -1 is 9,223,372,036,854,775,807 that's 19 54 /// digits of precision. A double only has 15- 16 digits 55 /// of precision. Since my typical use is a double that's 56 /// at least 3 digits of precision I could never use. (of 57 /// course 2**31 -1 is only 10 digits of precision so that's 58 /// five less than I could use ...) 59 /// 60 /// Advantages of a 64 bit generator would be the insanely 61 /// long cycle until it repeats. Disadvantages would be 62 /// the implementation complexities of picking correct/good 63 /// m and q values, then testing it. I'll probabaly create 64 /// the class but will be unable to successfully test the numbers 65 /// for it. Besides I know the current values work great so 66 /// number I picked, without months of testing, would almost 67 /// certainly not be better. 68 /// 69 /// Of course, the other thing I could do, since this is C#, 70 /// is to not use Miller and Park's algorithm at all but still 71 /// use their values because the math module in C# is good 72 /// enough to not make 32 bit math mistakes. I've left it this way 73 /// however because it makes the implementation almost bullet 74 /// proof. 75 /// 76 /// Always be sure to test your implementation, 77 /// you never can tell when intel or someone else will sneak 78 /// a bad floating point unit into your machine. If the tests 79 /// pass you are probaly ok. 80 /// 81 /// <borg-joke> 82 /// "I am Pentium of Borg, 83 /// Division is Futile, 84 /// You will be approximated!" 85 /// </borg-joke> 86 /// </remarks> 87 public class RNDuint 88 { 89 protected uint seed; 90 91 #if(ACM_ORIGINAL_NUMBERS) 92 ///<remarks> This version uses the original ACM m and q. 93 ///</remarks> 94 static protected uint m = 2147483647; 95 static protected uint q = 127773; 96 static protected ushort a = 16807; 97 static protected ushort r = 2836; 98 static protected uint successfulltest = 1043618065; 99 #else 100 ///<remarks> 101 /// 1992 -- This version contains NEW numbers provided by John Burton 102 /// that improve the distribution over the originally published 103 /// numbers in the ACM. JAE jill@eskimo.com 104 /// </remarks> 105 /// <summary>modulus 2**31 -1</summary> 106 static protected uint m = 2147483647; 107 static protected uint q = 44488; 108 static protected ushort a = 48271; 109 static protected ushort r = 3399; 110 static protected uint successfulltest = 399268537; 111 #endif 112 113 protected void uintCheckSeed(uint initialseed) 114 { 115 if ( initialseed >= m ) 116 { 117 throw(new ArgumentOutOfRangeException( 118 "initialSeed", 119 initialseed, 120 "Invalid seed: Must be between 0 and 2,147,483,647") 121 ); 122 } 123 seed = initialseed; 124 } 125 126 127 public RNDuint() 128 { 129 seed = 1; 130 } 131 132 /// <summary> 133 /// Accepts inter seed from0 to 2**31 -1. 134 /// </summary> 135 /// <param name="initialseed">Value between 0 and 2,147,438,647.</param> 136 public RNDuint( uint initialseed ) 137 { 138 uintCheckSeed(initialseed); 139 } 140 141 /// <summary> 142 /// Get next value or set seed. Range uint 0 to 2**31-1. 143 /// </summary> 144 public uint n 145 { 146 get 147 { 148 int lo, hi, test; 149 150 hi = (int)(seed/q); 151 lo = (int)(seed%q); 152 153 test = a*lo - r*hi; 154 155 if (test > 0) 156 seed = (uint)test; 157 else 158 seed = (uint)test+ m; 159 160 return seed; 161 } 162 163 set 164 { 165 uintCheckSeed(value); 166 } 167 } 168 169 /// <summary> 170 /// Tests this class for correct compiler implementation. 171 /// </summary> 172 /// <returns>False means DO NOT USE this generator.</returns> 173 public bool test() 174 { 175 // First test the LCG it's self. This loop should 176 // exercise any math errors. 177 RNDuint t = new RNDuint(); 178 uint y; 179 180 for( int i = 1; i <= 9999; i++) 181 y = t.n; 182 183 if( t.n != successfulltest ) 184 return false; 185 186 // Error throw testing 187 try 188 { 189 t.n = m; // This MUST fail 190 } 191 catch( ArgumentOutOfRangeException e) 192 { 193 // So K 194 return true; 195 } 196 catch 197 { 198 // Not So K 199 return false; 200 } 201 202 return false; // if try did NOT generate an error 203 // then error detection is broken 204 } 205 206 } 207 } 208

No comments avaiable

Add a comment

Name *  

Email (won't be displayed) *    

Website  

Comment *  

Sicherheitscode Security Code *    

RSS