Week2

Random numbers

Randomness

In order to make encryption algorithms, machine learning, computer games and econometric simulations less predictable, we require randomness. It is hard to realize randomness on a computer, since a computer can't make decisions on its own: a computer works deterministically. But, we can model randomness using pseudo random numbers. In Java, the most-used Pseudo Random Number (PRN) generator is a Linear Congruential Generator, following the recurrence relation of

Xn+1 = (a Xn + c) mod m

Where Java uses the constants multiplier a = 11, increment c = 25214903917 and modulus m = 248. The starting number X0 of a sequence is called a seed. The choices of a, c and m are made with the idea to have very long periods, so it takes a long time for the series to repeat itself. Also, it is meant to prevent the same sequence to occur twice, unless you pick the same seed. You can set a seed fixed, which will of course always generate the same sequence of numbers that appears to be randomly distributed. If you do not choose a seed, the seed will be based on some other source of randomness and a different sequence of numbers will be used every time you run your program.

This PRN works well enough for this course, but suffers from serial correlation so that it is not the best PRN one could imagine. You will learn more on pseudo random numbers in the Simulation course (FEB22013(X)).

Random class

Java offers the ready-made Random class for creating random numbers, which follows the linear congruential formula mentioned above. An instance of the Random class can be used as follows:

import java.util.Random;

public class Raffle {
    public static void main(String[] args) {
        // Create Random object ladyLuck without a fixed seed
        Random ladyLuck = new Random();

        for (int i = 0; i < 10; i++) {
            // Draw and print a random number
            int randomNumber = ladyLuck.nextInt(10);
            System.out.println(randomNumber);
        }
    }
}

Above we create an instance of the Random class. It has nextInt method, which gets an integer as a parameter. The method returns a random number from the range [0, integer). Please notice that the upper bound is not included.

The program output is not always the same. The constructor Random() with zero arguments picks a seed based on a non-deterministic source (e.g. the current time in milliseconds), so typically the sequence of random numbers generated by the Random object is different from program run to program. If we would have created the Random ladyLuck using a seed, by Random ladyLuck = new Random(233), the Random object is always initialized with 233 being the seed and the sequence of random numbers is different from run to run. As we did not set a seed in the example, one possible output is the following:

Sample output

2 2 4 3 4 5 6 0 7 8

We can use the nextInt method to create diverse randomness. For example, we might need a program to give us a temperature between [-30,50]. We can do this by first creating a random number between 0 and 80 and then subtracting 30 from it.

Random weatherMan = new Random();
int temperature = weatherMan.nextInt(81) - 30;
System.out.println(temperature);

Random events

A Random object can also be used to create random doubles, using the nextDouble method of the Random class. For example, this allows us to generate a random variable that is uniformly distributed over the half-open interval [0, 1) (the upper bound is not included). Such a random variable can be used to simulate random events, as follows

Suppose that

  • There is a 0.1 probability it rains (10%)
  • There is a 0.3 probability it snows (30%)
  • There is a 0.6 probability the sun shines (60%)

Let's create a weather forecast using these probabilities.

import java.util.ArrayList;
import java.util.Random;

public class WeatherMan {
    private Random random;

    public WeatherMan() {
        this.random = new Random();
    }

    public String forecast() {
        // This gives a uniform random number in [0,1)
        double probability = this.random.nextDouble();

        // 0.1 is the 10% probability threshold
        if (probability <= 0.1) {
            return "It rains";
        // Using else if, 0.4 (0.1+0.3) gives the 30% probability threshold
        // based on the assumption that the uniform draw was above 0.1
        } else if (probability <= 0.4) {
            return "It snows";
        // The else gives us the 1-0.4 = 60% probability threshold
        } else {
            return "The sun shines";
        }
    }

    public int makeAForecast() {
        return (int) (4 * this.random.nextGaussian() - 3);
    }
}

The makeAForecast method is interesting in many ways. The this.random.nextGaussian() call is a regular method call. However, what is interesting is that this method of the Random class returns a value drawn from the normal distribution. If you are curious about other random methods in Java, take a look at the methods of the Random class, using Java Documentation! In this method, we use explicit type casting to convert doubles to integers (int). We can equally convert integers to doubles with (double) integer.

Let's now add a main which uses the WeatherMan class.

// imports

public class Program {

    public static void main(String[] args) {
        WeatherMan forecaster = new WeatherMan();

        // save days of the week to a list
        ArrayList<String> days = new ArrayList<>();
        days.add("Mon");
        days.add("Tue");
        days.add("Wed");
        days.add("Thu");
        days.add("Fri");
        days.add("Sat");
        days.add("Sun");

        System.out.println("Next week's weather forecast:");

        for (String day : days) {
            String weatherForecast = forecaster.forecast();
            int temperatureForecast = forecaster.makeAForecast();

            System.out.println(day + ": " + weatherForecast + " "
                              + temperatureForecast + " degrees.");
        }
    }
}

The program output could be:

Sample output

Next week's weather forecast:

Mon: It snows 1 degrees.

Tue: It snows 1 degrees.

Wed: The sun shines -2 degrees.

Thu: The sun shines 0 degrees.

Fri: It snows -3 degrees.

Sat: It snows -3 degrees.

Sun: The sun shines -5 degrees

Note that while the standard Random object of Java is good enough for this course, we will discuss how you can use pseudo random number generators with better statistical property at the end of the course, when we discuss the use of external libraries.

Exercise

Test your knowledge

Assume a colleague has defined a static final int SEED with a value you do not know exactly. Determine which behavior would describe the following piece of code best.

Also, determine how you would have to adjust the code to obtain the alternative behaviors.

Random ran = new Random(SEED);
System.out.println(ran.nextInt(3));
ran = new Random(SEED);
System.out.println(ran.nextInt(3));

The potential outcomes are:

  1. It prints two random numbers from the set {0,1,2,3}
  2. It prints two random numbers from the set {0,1,2}
  3. It prints two random numbers from the set {1,2,3}

If we rerun the program multiple times:

  1. The two numbers printed can be different from run to run
  2. The two number printed will be equal from run to run

Within a single run of the program:

  1. The two numbers printed can be different or can be the same
  2. The two numbers printed are always different
  3. The two numbers printed are always the same
You have reached the end of this section! Continue to the next section: