The purpose of this assignment [4,5] was to create a linear congruential method (LCM) random number generator (RNG) that offers a wide variety of return types (boolean, range of integers, reals, etc.). Further, we were to measure the equidistributivity of the numbers we generate using the chi-square method in order to ensure that our RNG is not biased. Finally, we were to focus on one aspect of our RNG and discuss it at length on a website.
After showing that equidistributivity for my RNG was within acceptable chi-square ranges, I decided to compare my RNG to Java's built-in RNG by conducting a Monte Carlo approximation of Pi with each one. Imagine a circle of diameter x drawn within a square of width x. A Monte Carlo approximation of Pi is calculated by first generating a random point and determining if it is inside the circle n times. We know that the area of the circle has the below relationship to the area of the square, so counting the hits and misses, we can look at the proportion of circle area to square area and multiply (p) by 4, thereby approximating Pi. If my RNG does not generate random reals uniformly, then the approximation can be expected to be incorrect because we will either get a lot more misses or a lot more hits than we should.

The following values were used for LCM in this experiment:
m = 275604541 // the 15 millionth prime number
c = 256203161 // the 14 millionth prime number
a = 86028121 // the 5 millionth prime number
Below are several tables with the approximated values of Pi and the percent error from the actual value for my LCM RNG and for Java's built-in Random class. The first table shows my RNGs approximations using a circle of diameter 10,000, which I realized is unnecessary for the level of precision we are achieving. Therefore, I used a circle of diameter 1 for the other trials. Randomly generated points were of the form (0<=x<=1,0<=y<=1) and type (double,double). Real numbers were used as coordinates because otherwise there would be a finite number of points to choose from and the edge cases (rounding) would make precision an elusive goal.
| # of Points (n) | Circle Diameter (d) | Approximated Pi | Percent Error |
|---|---|---|---|
| 10,000 | 10,000 | 3.1624 | 0.6623 |
| 100,000 | 10,000 | 3.13896 | 0.0838 |
| 1,000,000 | 10,000 | 3.140984 | 0.0194 |
| 10,000,000 | 10,000 | 3.1407564 | 0.0266 |
| 100,000,000 | 10,000 | 3.14105524 | 0.0171 |
| 1,000,000,000 | 10,000 | 3.141054348 | 0.0171 |
| # of Points (n) | Circle Diameter (d) | Approximated Pi | Percent Error |
|---|---|---|---|
| 10,000 | 1 | 3.148485151 | 0.219395 |
| 100,000 | 1 | 3.148688513 | 0.2258682 |
| 1,000,000 | 1 | 3.141032859 | 0.0178188 |
| 10,000,000 | 1 | 3.141790886 | 0.00630993 |
| 100,000,000 | 1 | 3.141680569 | 0.00279842 |
| 1,000,000,000 | 1 | 3.141578341 | 0.00045559 |
| # of Points (n) | Circle Diameter (d) | Approximated Pi | Percent Error |
|---|---|---|---|
| 10,000 | 1 | 3.118888111 | 0.722708 |
| 100,000 | 1 | 3.140448596 | 0.0364165 |
| 1,000,000 | 1 | 3.141024859 | 0.0180735 |
| 10,000,000 | 1 | 3.140732086 | 0.0273927 |
| 100,000,000 | 1 | 3.140743649 | 0.0270247 |
| 1,000,000,000 | 1 | 3.140744693 | 0.0269914 |
My RNG has a greater percent error almost of at least an order of magnitude almost across the board. This seems to indicate that my RNG does not uniformly scatter random points across the [0,1] interval. On the other hand, the percent error is not horrible, and it does seem to be getting smaller as n increases. My feeling is that Java's Random class is superior. It may be related to my chosen values of m, a, and c, or Java may just use a better method than LCM.
My experiment would benefit from repeated approximations with even higher n (100 billion or more). Running the approximation some hundred or thousand times would be ideal, and then measuring the variability. Right now, there's no guarantee that the values I measured are within the usual range of approximated values because I only ran each n one time. (For n=1,000,000,000 it took my 867MHz, 640MB RAM PowerBook G4 ~20 minutes to yield a single approximation.)
Furthermore, there are a whole slew of further tests that can be performed to gauge the randomness of my random number generator. I considered and began implementing two test: Random Excursions and Sequence Distribution. Random Excursions is a test that measures what states an RNG favors (if it does) if you consider a random sequence of binary values to be walking up and down the integral number line. You will find a method in RanMain.java that is the start of an implementation. The Sequence Distribution test generates n sequences of size x that consist, in turn, of coin flips (random binary values). If you count and plot the number of sequences with 0 through x ones in it, you should get a normal distribution if your RNG is random. (There is only one way to make a sequence with x ones in it, and one way to make a sequence with 0 ones in it. The most commonly generated sequence has x/2 ones in it.) Below is a graph of data from a method included in RanMain.java. Data should be compared to the normal curve to determine randomness of the RNG. These tests and more can be found at the NIST's site.
