# Generate random numbers with Math.random()

## `Math.random()` on the AP CS A Exam

The AP CS A Exam features problems that require:

• generating numbers in a given range using `Math.random()`. This may be featured on the multiple choice section, the free response section, or both.
• determining the range of numbers generated by a given expression that uses `Math.random()`. This is typically featured on the multiple choice section.
• using `Math.random()` to make something happen with a given probability. This may be featured on either section.

Solutions must be exactly correct to earn the point. Off by 1 will not earn the point.

## Generate random numbers in a given range

### `Math.random()` technique

The statement
`double r = Math.random();`

results in `r` having a random value in the range
`0.0 <= r < 1.0`

There are 3 things you can do with the result returned by `Math.random()`.

1. Multiply
2. Cast to an `int`

Steps that do not apply can be skipped. Steps should not be reordered. The issue with reordering the steps isn’t that it doesn’t work, but that it makes it harder to check that the resulting range is exactly correct.

For example, the technique requires:
`double r = (int) (Math.random() * 10) + 1;`

`double r = (int) (Math.random() * 10 + 1);`

even though both generate values in the same range.

Write what you have, which always starts as the original range above. Write out what you want. Every time you update the `Math.random()` expression, update what you have.

When you’re done, you are either right and you know you’re right or you’re wrong and you know you’re wrong. If you’re wrong, start over. If you need to start over, look at your previous attempt to determine what needs to be changed. Do not simply modify your previous attempt. Modifying your previous attempt makes it harder to check that the range is exactly what you want.

### Example 1

#### Step 1

``````double r = Math.random();
have: 0.0 <= r < 1.0
want: 0.0 <= r < 5.0
``````

Step 1 is writing out the unaltered call to `Math.random()`, the original range returned by `Math.random()`, and the numeric range we want.

When we want a `double`, the upper end of the range is typically specified with `<`.

#### Step 2

``````double r = Math.random() * 5;
have: 0.0 <= r < 5.0
want: 0.0 <= r < 5.0
``````

Multiplying by `5` changes the high end of the range to `5.0` (and leaves the low end at `0.0` since `0.0 * 5` is `0.0`).

We have what we want, so we’re done and we know we’re right.

### Example 2

#### Step 1

``````double r = Math.random();
have: 0.0 <= r < 1.0
want: 7.0 <= r < 12.0
``````

#### Step 2

``````double r = Math.random() * 5;
have: 0.0 <= r < 5.0
want: 7.0 <= r < 12.0
``````

Multiplying by `5` changes the high end to `5.0`.

#### Step 3

``````double r = Math.random() * 5 + 7;
have: 7.0 <= r < 12.0
want: 7.0 <= r < 12.0
``````

Adding `7` changes both ends of the range.

We have what we want, so we’re done and we know we’re right.

### Example 3

#### Step 1

``````int r = Math.random();
have: 0.0 <= r < 1.0
want: 0 <= r <= 5
``````

When we want an `int`, the upper end of the range is typically specified with `<=`.

The original statement will not compile because `Math.random()` returns a `double`. This is fine because we don’t plan to keep the original statement.

#### Step 2

``````int r = Math.random() * 6;
have: 0.0 <= r < 6.0
want: 0 <= r <= 5
``````

Multiplying by `6` changes the high end of the range to `6.0`.

This statement will not compile either. This is still fine because we aren’t done.

#### Step 3

``````int r = (int) (Math.random() * 6);
have: 0 <= r <= 5
want: 0 <= r <= 5
``````

When casting to an `int`, it is the quantity `(Math.random() * 6)` that we want to cast. Without the parentheses, the cast would apply to the return value from `Math.random()`, which would always yield `0`.

Casting to an int changes the low end of the range to `0`.

The high end of the range is more interesting. When we take a number strictly less than `6.0` and cast it to an `int`, the largest number we will ever get is `5`. So the high end of the range becomes `<= 5`.

We have what we want, so we’re done and we know we’re right.

### Example 4

#### Step 1

``````int r = Math.random();
have: 0.0 <= r < 1.0
want: 10 <= r <= 25
``````

#### Step 2

``````int r = Math.random() * 16;
have: 0.0 <= r < 16.0
want: 10 <= r <= 25
``````

Multiplying changes only the high end.

#### Step 3

``````int r = (int) (Math.random() * 16);
have: 0 <= r <= 15
want: 10 <= r <= 25
``````

Casting to an int changes both ends. See Example 3 Step 3 for an explanation.

#### Step 4

``````int r = (int) (Math.random() * 16) + 10;
have: 10 <= r <= 25
want: 10 <= r <= 25
``````

We have what we want, so we’re done and we know we’re right.

### Example 4

We want a random valid index in `str`, a `String` that has been previously declared and initialized.

#### Step 1

``````int index = Math.random();
have: 0.0 <= index < 1.0
want: 0 <= index <= str.length() - 1
``````

In this case, Step 1 requires converting the description into a numeric range. As with all situations in which we want an `int`, we use `<=` for the high end. (It is possible to express the high end as `< str.length()`. Doing so would make it slightly more difficult to check our result.)

#### Step 2

``````int index = Math.random() * str.length();
have: 0.0 <= index < str.length()
want: 0 <= index <= str.length() - 1
``````

#### Step 3

``````int index = (int) (Math.random() * str.length());
have: 0 <= index <= str.length() - 1
want: 0 <= index <= str.length() - 1
``````

We have what we want, so we’re done and we know we’re right.

The same approach works for generating a valid random index in an array or in an `ArrayList`.

It is very common for students to multiply by a variation of `str.length()` such as `(str.length() - 1)`, not check the resulting range, and lose a point.

It is also common for students to add or subtract after casting, not check the resulting range, and lose a point.

## Determine the range generated

Questions on the multiple choice section may be phrased such that they effectively ask you to generate numbers in a given range. Use the technique above for these.

Other questions start with an existing expression based on `Math.random()` and ask what range it generates. To answer these questions:

1. Simplify or convert the expression such that it matches the format above. It might be necessary to break the expression into more than 1 expression, each of which simplifies to the format above.

2. Write the range for an unmodified call to `Math.random()`.

3. Apply the multiplication to the range. Then apply the cast. Then apply the addition (or subtraction). Skip any that aren’t present.

### Example

What is the range of values that could be stored in `value` as a result of the statement below?
`double value = 5 + Math.random() * 12;`

#### Step 1

The expression in the format above is
`double value = Math.random() * 12 + 5;`

The range generated by `Math.random()` is
`have: 0.0 <= value < 1.0`

#### Step 2

The range after multiplying by 12 is
`have: 0.0 <= value < 12.0`

#### Step 3

The range after adding 5 is
`have: 5.0 <= value < 17.0`

This is the final range.

## Simulate a given probability

The statement
`double r = Math.random();`

results in `r` having a random value in the range
`0.0 <= r < 1.0`

The value return by `Math.random()` is evenly distributed within that range. (Any value within the range is equally likely.)

Using `Math.random()` to simulate a given probability does not require manipulating the output. Instead, we simply check if the result is less than the desired probability.

### Example 1

Print `"player wins"` 35% of the time.

``````if(Math.random() < 0.35)
System.out.println("player wins");
``````

#### Example 2

Print `"yes"` 15% of the time, `"no"` 35% of the time, and `"maybe"` the other 50% of the time.

``````double r = Math.random();
if(r < 0.15)
System.out.println("yes");
else if(r < 0.5)
System.out.println("no");
else
System.out.println("maybe");
``````

We use only 1 random number, not 1 random number per possibility. We want the `else if` condition to be `true` 35% of the time. `0.15 + 0.35` is `0.5`.

## Exercises

### Exercise 1

`a` and `b` are of type `double` and
`a >= 0.0 && b > a`

Give code to declare `double r` and initialize it to a random value in the range
`a <= r < b`

### Exercise 2

`c` and `d` are of type `int` and
`c >= 0 && d > c`

Give code to declare `int r` and initialize it to a random value in the range
`c <= r <= d`

### Exercise 3

``````ArrayList<String> names = new ArrayList<String>();
/* code to add many more names to names */
``````

Give code to remove and print a randomly selected name from `names`. Each name must be equally likely to be selected.

### Exercise 4

The code below simulates rolling an 8 sided die.
`int roll = (int) (Math.random() * 8) + 1;`

The range of values generated is
`1 <= roll <= 8`

Which of the following correctly simulate(s) the result of rolling two 8 sided dice and adding the values together?

``````Case I:   int sum = (int) (Math.random() * 8) + 1 + (int) (Math.random() * 8) + 1;

Case II:  int sum = 2 + (int) (Math.random() * 8) + (int) (Math.random() * 8);

Case III: int sum = ((int) (Math.random() * 8) + 1) * 2;
``````

(A) `I` only
(B) `II` only
(C) `III` only
(D) `I` and `II` only
(E) `I`, `II`, and `III`