For this assignment, you will extend your PRNG class from Assignment Two so that it generates floating-point (double) numbers in the range 0 to 1.0 instead of integers in the range 0 to modulus-1. Also, you will provide evaluation methods that test the randomness quality of you pseudorandom number generator.
Write a new class, UniformRandom, that extends your PRNG class from Assignment Two and implements the RandI interface. You should provide at least a default constructor for your UniformRandom class.
Next, override your next() method. This new version of the method should return a Double instead of whatever it was returning. As an aside, the observant coder will have already noticed that the next() method from the PRNG class was returning an instance of the Integer wrapper class. You might not have noticed this because Java kindly wraps an int in an Integer object when an Object is expected, and kindly unwraps the integer value from the Integer object when the simple value is needed. The same applies to all the other primitive types and their corresponding wrapper classes. However, because we want you to use the next() method of your super-class (PRNG) as override it for the UniformRandom class, you will be receiving an object, which must be cast in order to extract its value.
With that aside, you should override next() to return a double (Double) value between 0.0 (inclusive) and 1.0 (exclusive). You can accomplish the translation to the 0-1 range by dividing the newly generated number by your modulus using floating-point arithmetic. Because the number generated by your PRNG method from last week is the remainder of a division by the modulus, it will never be greater than or equal to the modulus. Therefore, when dividing by the modulus, the quotient will always be strictly less than 1.0. If one repeatedly calls this new method, it should generate a sequence of pseudorandom numbers in the range [0.0 .. 1.0).
This should be the only method that you will need to override from your previous class. However, if you need or want to make changes to your version of PRNG (from which UniformRandom is inheriting), feel free to do so. Be sure to include a copy of your PRNG class with your submission whether you alter it or not.
There are many applications of pseudorandom number generators. For some of those applications, the particular properties or characteristics of the distribution and sequence are of critical importance. There are a number of such characteristics, but for this assignment we will consider only two of them: the distribution of numbers and the pairwise relation between consecutive numbers in the sequence.
If we divide the range [0..1.0) into some number, say ten, of "bins" and assign each number in a large sample to the appropriate bin, we would hope that a good pseudorandom number generator would fill the ten bins roughly evenly. This test checks the distribution of numbers given ensuring each number in the range is as likely to be generated as the other numbers. This alone, however, is insufficient. The sequence of numbers 0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,.... perfectly distributes numbers into the ten bins but we would hardly call this a good pseudorandom sequence.
One additional check we can employ is to track the relationship between consecutive numbers. This test checks the sequence for regularities that would reflect non-randomness. If we keep track of the number of times 0 is followed by each of the ten digits (including 0), and do the same for 1, 2 and all the other numbers, we can identify evenly distributed but non-random sequences such as the one above.
Once your new class is generating numbers in the appropriate range, we want to be able to run experiments that evaluate the distribution and sequence of resulting numbers. Write another class, RandomChecker, that has at least two methods:
public int checkDistribution(RandI rng, int howManyBins, int testSize);that will perform tests on the given instance of a pseudorandom number generator that satisfies the RandI interface. Your checkDistribution method should return a one-dimensional array containing the counts of numbers that fell into the respective ranges or bins. Your checkSequence returns a two-dimensional array where a cell indexed by i and j contains the number of times that j followed i in the sequence. The parameters determine the number of bins to use and how many samples to generate.
public int checkSequence(RandI rng, int howManyBins, int testSize);
Because the purpose of these methods is to evaluate the ‘random’ quality of your generator, you should write your main driver method to consume three integer inputs for the multiplier, increment and modulus. Then you will be able to run tests with different values of these parameters and observe their impact on the distribution and sequence without recompiling.
Your main method should run checkDistribution and checkSequence on a given number of bins, say ten, over a large sample of generated random numbers, say one million. If using ten bins, you would divide the range [0..1) into ten smaller ranges: [0.. 0.1), [0.1 .. 0.2), ... [0.9 .. 1.0). Finally, print out your results in a manner such as shown in the screen shot.
Run your experiment several times with different values for the multiplier, increment, and modulus. A set of good choices for these will yield approximately 10% of the total in each range. A generator with this equal-interval behavior is called uniformly distributed. Try to find a set of values that produce a better distribution than the values recommended in Assignment 2. (Note, the initial seed value is not too important in this regard as long as you have a large sample. So don't worry too much about experimenting with that value.)
Write two additional classes. The first, PRNGLogistic should extend your Logistic class from a previous lab and should implement the RandI interface. Update 1: The logistic function, under certain values of r, will give rise to a chaotic (random) sequence of values. Thus it may (under certain conditions) serve as a pseudo-random number generator. Depending on the details of your Logistic implementation from the lab, you may need to refactor your code so that the logistic element (what we care about) is separated from the graphical elements (that are irrelevant for this assignment). Ideally, you will refactor your lab code so that it works as before but as separate classes but that is not part of the assignment. The second class, PRNGBuiltIn should extend java.util.Random and implement the RandI interface.
Finally, modify the main method in your RandomChecker class to compare three different types of pseudo-random number generators: an instance of UniformRandom with the best multiplier, increment and modulus that you can find, an instance of PRNGLogistic with the best value of r that you can come up with, and an instance of PRNGBuiltIn. In your documentation for RandomChecker, you should report which method you found to be the best generator of random numbers.
Make sure that you create a folder named with your Westmont email name followed by "HW3". For example, someone with email address "cjones" would create a folder called "cjonesHW3". Make sure that inside that folder you have: java source files as well as html documentation files resulting from javadoc. Finally, either tar or zip the folder so that when we extract it, the folder "<emailname>HW3" will be created. Submit the packaged file for assignment 3 on Eureka.