繁体中文
设为首页
加入收藏
当前位置:.Net技术首页 >> Asp.Net开发 >> A Good 31 bit Random Number Generator Class

A Good 31 bit Random Number Generator Class

2007-07-15 08:00:00  作者:  来源:互联网  浏览次数:0  文字大小:【】【】【
简介:Latest Snippet Version: 1.0 using System; namespace Barsoom { /// /// Good 31-bit Random Number Generator, returns Uint. /// /// /// /// LICENSE : PUBLIC DOMAIN /// /// This is the base class f...

Latest Snippet Version: 1.0

using System;

namespace Barsoom

{

///

/// Good 31-bit Random Number Generator, returns Uint.

///

///

///

/// LICENSE : PUBLIC DOMAIN

///

/// This is the base class for double and other statistical

/// random number distribution classes

///

/// Throws exception if initial seed is out of range.

///

/// Stephen K. Park and Keith W. Miller. RANDOM NUMBER GENERATORS:

/// GOOD ONES ARE HARD TO FIND. Communications of the ACM,

/// New York, NY.,October 1988 p.1192

///

/// Throws exception if initial seed is out of range

/// This program is public domain and was written by Jill England

/// (Oct 1988).

///

/// Modifications;

///

/// Converted to C# from C++ and hacked heavily. One major cool thing done

/// here is to be able to SET the seed or get the next LCG value.

/// 3/4/2002 JAE Jill@eskimo.com

///

/// Imported into Visual Studio .net, 3/1/2002 JAE jill@eskimo.com

///

/// To build the generator with the original ACM

/// article's numbers use -DACM_ORIGINAL_NUMBERS when compiling.

///

/// Original_numbers are those published m and q in the

/// original ACM article. John Burton, a Miller/Park, associate

/// has furnished numbers for a reportedly better generator. The

/// new numbers are now used in this program by default.

///

/// F(z) = (az)%m

/// = az-m(az/m)

///

/// F(z) = G(z) + mT(z)

/// G(z) = a(z%q) - r(z/q)

/// T(z) = (z/q) - (az/m)

///

/// F(z) = a(z%q)- rz/q+ m((z/q) - a(z/m))

/// = a(z%q)- rz/q+ m(z/q) - az

///

/// NOTE JAE: I could easily extend this class to a C# 63 bit LCG but,

/// don't really see the point for most applications I have.

/// Besides 2**63 -1 is 9,223,372,036,854,775,807 that's 19

/// digits of precision. A double only has 15- 16 digits

/// of precision. Since my typical use is a double that's

/// at least 3 digits of precision I could never use. (of

/// course 2**31 -1 is only 10 digits of precision so that's

/// five less than I could use ...)

///

/// Advantages of a 64 bit generator would be the insanely

/// long cycle until it repeats. Disadvantages would be

/// the implementation complexities of picking correct/good

/// m and q values, then testing it. I'll probabaly create

/// the class but will be unable to successfully test the numbers

/// for it. Besides I know the current values work great so

/// number I picked, without months of testing, would almost

/// certainly not be better.

///

/// Of course, the other thing I could do, since this is C#,

/// is to not use Miller and Park's algorithm at all but still

/// use their values because the math module in C# is good

/// enough to not make 32 bit math mistakes. I've left it this way

/// however because it makes the implementation almost bullet

/// proof.

///

/// Always be sure to test your implementation,

/// you never can tell when intel or someone else will sneak

/// a bad floating point unit into your machine. If the tests

/// pass you are probaly ok.

///

///

/// "I am Pentium of Borg,

/// Division is Futile,

/// You will be approximated!"

///

///

public class RNDuint

{

protected uint seed;

#if(ACM_ORIGINAL_NUMBERS)

/// This version uses the original ACM m and q.

///

static protected uint m = 2147483647;

static protected uint q = 127773;

static protected ushort a = 16807;

static protected ushort r = 2836;

static protected uint successfulltest = 1043618065;

#else

///

/// 1992 -- This version contains NEW numbers provided by John Burton

/// that improve the distribution over the originally published

/// numbers in the ACM. JAE jill@eskimo.com

///

///

modulus 2**31 -1

static protected uint m = 2147483647;

static protected uint q = 44488;

static protected ushort a = 48271;

static protected ushort r = 3399;

static protected uint successfulltest = 399268537;

#endif

protected void uintCheckSeed(uint initialseed)

{

if ( initialseed >= m )

{

throw(new ArgumentOutOfRangeException(

"initialSeed",

initialseed,

"Invalid seed: Must be between 0 and 2,147,483,647")

);

}

seed = initialseed;

}

public RNDuint()

{

seed = 1;

}

///

/// Accepts inter seed from0 to 2**31 -1.

///

/// Value between 0 and 2,147,438,647.

public RNDuint( uint initialseed )

{

uintCheckSeed(initialseed);

}

///

/// Get next value or set seed. Range uint 0 to 2**31-1.

///

public uint n

{

get

{

int lo, hi, test;

hi = (int)(seed/q);

lo = (int)(seed%q);

test = a*lo - r*hi;

if (test > 0)

seed = (uint)test;

else

seed = (uint)test+ m;

return seed;

}

set

{

uintCheckSeed(value);

}

}

///

/// Tests this class for correct compiler implementation.

///

/// False means DO NOT USE this generator.

public bool test()

{

// First test the LCG it's self. This loop should

// exercise any math errors.

RNDuint t = new RNDuint();

uint y;

for( int i = 1; i <= 9999; i++)

y = t.n;

if( t.n != successfulltest )

return false;

// Error throw testing

try

{

t.n = m; // This MUST fail

}

catch( ArgumentOutOfRangeException e)

{

// So K

return true;

}

catch

{

// Not So K

return false;

}

return false; // if try did NOT generate an error

// then error detection is broken

}

}

}

责任编辑:admin
相关文章