// CS 1538 Fall 2009 // This is a mixed linear congruetial generator taken from an old // CS 0445 textbook (Data Structures in C++ by Ford and Topp -- I // changed some things to make it work in Java but it is essentially the // same as the generator presented in the Ford and Topp textbook). // Note that value returned by this generator is only 16 bits, giving // it a maximum range of 2^16. This was common with older C++ compilers in // which a long int was only 32 bits (and in fact many implementations of // the rand() function in C/C++ still have a range of 2^16). It is well-known // that the lower-order bits in a linear congruential generator with a modulus // of 2^b do not have a very good "random" distribution. However, a modulus // of 2^b is easier and faster to calculate than other moduli, so it is // frequently used. Thus, most linear congruential generators of this type // will shift out the lower order bits so that the "usable" range of results // is actually smaller than the entire range of the generator. // If you examine m, a and c, you will see that they meet the criteria for a // full-period generator. The shortcomings of the smaller range can be seen // when the desired subrange of values is a significant (but not divisible) // part of the overall range. In this case, assuming that the original value // generated is uniform, when it is "mapped" onto the desired subrange the // probabilities will no longer be uniform. See notes on board for more // details. // Also note the last method, bogusInt. This uses all of the 32 bits // generated and will likely have very poor results, due to the lack of // "randomness" of those lower order bits. However, note that this poor // behavior may not necessarily be detected by a uniformity test such // as Chi-Square. We need to also test for independence. public class Rand1 { private final long mask = (1L << 32) - 1; // this is "m" = 2^32 private final long multiplier = 1194211693L; // this is "a" private final long adder = 12345L; // this is "c" private long randSeed; public Rand1() { randSeed = System.currentTimeMillis(); } public Rand1(long s) { randSeed = s; } public int nextShort(int n) { randSeed = (multiplier * randSeed + adder) & mask; int shortAns = Math.abs((int) randSeed >> 16); return (shortAns % n); } public int bogusInt(int n) { randSeed = (multiplier * randSeed + adder) & mask; int intAns = Math.abs((int)randSeed); return (intAns % n); } }