This tutorial introduces generating random numbers using the Random class. Random numbers are useful in all sorts of situations including games, cryptography, and audio.
Level: Beginner
Platforms: Windows, macOS, Linux, iOS, Android
Classes: Random, Range, BigInteger, Colour
Download the demo project for this tutorial here: PIP | ZIP. Unzip the project and open the first header file in the Projucer.
If you need help with this step, see Tutorial: Projucer Part 1: Getting started with the Projucer.
The demo project sets up a simple text console where we can display the results of various operations. This allows us to demonstrate some of the features of the Random class in this tutorial.
In its default configuration, the demo project displays a series of 100 randomly-generated 32-bit integers. These values should be distributed roughly uniformly in the range -2,147,483,648 .. 2,147,483,647. Of course these values aren't truly random. Since they are generated by a computer, they are pseudorandom. For most purposes the Random object will be random enough, but you may need to use more sophisticated techniques for certain critical or specialist applications.
Throughout this tutorial we will modify parts of the demo project to demonstrate different features of the Random class. All of the code under discussion is in the MainComponent
class. In fact, many of the changes in the first instance will be to the runExample()
function.
Here we access a shared (global) Random object using the Random::getSystemRandom() function. We call the Random::nextInt() function with this system Random object to generate a random number. In most cases it is satisfactory to use this system random object for generating all of your random numbers. In some cases it is necessary to create your own instance of the Random class. This is usually where the values you are generating are being generated on another thread — see Tutorial: Build a white noise generator. If two (or more) threads try to access the system Random object then the sequence could get corrupted and may cause problems.
You will almost certainly want to limit the range of values generated by the Random class. While this can be done using simple arithmetic, the Random class makes it even easier.
To set the maximum value you simply pass the Random::nextInt() an integer like so:
This will set the maximum value to one less than the argument passed. In this case the values will be in the range 0 .. 5. It might be easier in this case to think of the argument as being the number of possible outcomes. Using 6 as the maximum value means there are 6 possible outcomes. This is just like rolling a die except the faces of the die are number 0 .. 5 rather than 1 .. 6!
Of course, to generate values in the range 1 .. 6 we could just add 1 like this:
But, the Random class can handle this for us by passing it a Range object
The maximum value still needs to be one larger than the maximum value we want the Random object to be able to generate. The minimum value is inclusive and the maximum value is exclusive.
In the examples above the values generated are all in the range of 32-bit integers. The Random class can generate 64-bit integer values and even arbitrarily large integers using the BigInteger class.
To generate 64-bit integers use the Random::nextInt64() function:
This generates an integer in the range −9,223,372,036,854,775,808 .. 9,223,372,036,854,775,807. To specify a smaller range for 64-bit integers you would need to perform the arithmetic yourself.
To generate arbitrarily large integers use the Random::nextLargeNumber() function. This returns a BigInteger object and takes a single BigInteger object as an argument to indicate the maximum value (again the maximum value is exclusive):
Here, we create a very large maximum value of 2256 by setting bit 256 in the maximumValue
BigInteger object. The output is some very large, randomly generated integers. For example:
The Random class can generate floating-point values too:
And it can generate double
values:
In both of these cases the values returned are in the range 0.0 .. 1.0. To generate a different range you will need to apply the arithmetic yourself (see Tutorial: Build a white noise generator for an example). You can use the jmap() function for this.
It can be useful to visualise the random values generated, rather than looking at long lists of numbers. This is especially useful if you need a set of random values with a distribution other than a uniform distribution. This can also create some interesting patterns.
Change the MainContentComponent
to the following simple code:
This should generate an image something like this:
Try resizing the window. You will notice that a new set of rectangles is generated each time the window is resized and the paint()
function is called.
To randomise the size of the rectangles we could do this:
To make this generate squares each time we could do this:
Colours can be randomised too, but to create colours that work well together using randomisation is a little trickier. For example, this generates a new random colour for each of the rectangles. But this colour could be any colour:
This should look something like this:
To limit the colours in a simple way we could randomise only one or two of the elements (red, green, or blue) and limit the range of values:
This produces colours in the pink and purple shades:
To be more specific, you could generate colours using hue, saturation, and brightness. For example, the oranges are at a hue of around 30° (or 0.083 in the 0 .. 1 range). If we generate random hues in the range 0.05 .. 0.15 these should all be different shades of orange.
You could choose randomly from a specific set of colours by using an array:
Here we store the items in an array. To select an item at random we generate a random value based on the array's size. Then we use this value as the index into the array.
All of the random numbers generated in this tutorial so far have been uniformly distributed between the minimum and maximum values. While this is not a tutorial on statistics, it can be useful to know some simple methods of making certain randomly-generated values more likely to occur than others. This has application in games, computer-generated art, and generative sound and music.
In the following code we generate 1,000 circles distributed uniformly across the window:
You can see from the image that the circles are roughly distributed uniformly.
A linear distribution is where values at one end of the range are more likely than others. Values across the range become less likely towards the other end of the range. The probability between these two points changes in a linear fashion. A simple way to implement this is to generate one random value based on the outcome of another random value. In the following example we generate linearly-distributed values for both the x and y coordinates of the circles.
Here you can see that we generate one random value then pass the result to the Random::nextInt() function to generate the final value.
The result should look something like this:
Since values towards zero are more likely, the circles appear to be focused around the top-left corner. To focus the circles around the centre we could change the code like so:
In some cases you may want to weight the probability of certain outcomes specifically. Let's take our earlier example where we chose randomly from three colours in an array. Let's say we want white to be the most likely, orange less likely, and green even less likely than orange. We could define probabilities as shown in the following table:
Colour | Probability |
---|---|
White | 70% |
Orange | 25% |
Green | 5% |
We could add an additional array of weights to our code where the indices of the weights correspond with the indices of the colours:
This works as follows:
colourAtQuantile()
function uses this value to find the colour.RandomTutorial_02.h
file of the demo project.The result is shown in the following screenshot:
In this tutorial we have introduced the Random class and generating random numbers in general. After reading this tutorial you should be able to: