22 March, 2008

Random Numbers in Java

Java has a rich toolkit for generating random numbers, in a class named "Random".
This document is a quick guide to using Random. Random can generate many kinds
of random number, not all of which I discuss here.

The best way to think of class Random is that its instances are random number
generator objects -- objects that go around spitting out random numbers of various
sorts in response to messages from their clients.

Gaining Access to Random

Random is defined in the "java.util" library package, so any Java
source file that uses Random must begin with a line of the form

    import java.util.Random;


    import java.util.*;

Creating Random Number Generators

The easiest way to initialize a random number generator is to use the parameterless
constructor, for example

    Random generator = new Random();

However, beware of one thing when you use this constructor: Algorithmic random
number generators are not truly random, they are really algorithms that generate
a fixed but random-looking sequence of numbers. When you create a random number
generator, it initializes its sequence from a value called its "seed".
The parameterless constructor for Random uses the current time as a seed, which
is usually as good a seed as any other. However, the time is only measured to
a resolution of 1 millisecond, so if you create two random number generators
within one millisecond of each other, they will both generate exactly the same
sequence of numbers.

If you prefer, there is also a constructor for Random that allows you to provide
your own seed. You can use any long integer as a seed with this constructor.
Note that there is no magic way of picking "good" seeds. For example,
the following creates a random number generator with seed 19580427:

    Random generator2 = new Random( 19580427 );

Generating Random Integers

To generate a random integer from a Random object, send the object a "nextInt"
message. This message takes no parameters, and returns the next integer in the
generator's random sequence. Any Java integer, positive or negative, may be
returned. Integers returned by this message are uniformly distributed over the
range of Java integers. Here is an example, assuming that "generator"
is an instance of Random:

    int r = generator.nextInt();

Often, programmers want to generate random integers between 0 and some upper
bound. For example, perhaps you want to randomly pick an index into an array
of n elements. Indices to this array, in Java, range from 0 to n-1.
There is a variation on the "nextInt" message that makes it easy to
do this: If you provide an integer parameter to "nextInt", it will
return an integer from a uniform distribution between 0 and one less than the
parameter. For example, here is how you could use a random number generator
object to generate the random array index suggested a minute ago:

    int randomIndex = generator.nextInt( n );

Generating Random Real Numbers

Random number generators can also generate real numbers. There are several
ways to do so, depending on what probablity distribution you want the numbers
drawn from.

To generate a random real number uniformly distributed between 0 and 1, use
the "nextDouble" message. This message takes no parameters. For example...

    double r = generator.nextDouble();

To generate a random number from a normal distribution, use "nextGaussian".
This message takes no parameters and returns a random number from a normal distribution
with mean 0 and standard deviation 1. In layman's terms, this means that the
results may be either positive or negative, with both being equally likely;
the numbers will almost always have small absolute values (about 70% will lie
between -1 and 1, about 95% between -2 and 2). For example...

    double r = generator.nextGaussian();

Translating and Scaling Random Numbers

Random number generators often return numbers in some limited range, typically
0 to b for some upper bound b. Sometimes you need your
random numbers to lie in a different range. You can make random numbers lie
in a longer or shorter range by multiplying them by a scale factor (scaling).
You can make random numbers lie in a range that is shifted to higher or lower
numbers than the original by adding (or subtracting) an offset from the random
numbers (translating).

Here are some examples of these operations:

  • Suppose you are writing a game program that simulates throwing dice, and
    so need a random integer in the range 1 to 6. "nextInt" can give
    you one in the range 0 to 5, and you can translate this to the range you need:

    int throw = generator.nextInt(6) + 1;

  • In drawing a pattern made up of random lines, you want to pick a random
    angle between 0 and 360 degrees at which to draw a line. The angle can be
    any real number. The "nextDouble" message will give you a random
    real number, but between 0 and 1. You can use scaling to turn this into a
    real number between 0 and 360:

    double angle = generator.nextDouble() * 360.0;

  • Suppose the same pattern-drawing program also needs to pick random lengths
    for the lines, but that the lines should never be shorter than 10 units, nor
    longer than 50. Line lengths can be any real number between these limits.
    Thus you need random lengths from a 40-unit range starting at 10. You can
    use scaling and translation together to generate these numbers from "nextDouble":

    double length = generator.nextDouble() * 40.0 + 10.0;