<!-- PDF page 64 -->

## Chapter 10 – Random Numbers

### RANDOMIZE, RND and % RND

This chapter deals with the functions **RND**, **RND ()** and **% RND** and the keyword **RANDOMIZE**. They are all used in connection with random numbers, so you must be careful not to get them mixed up.

As far as normal functions go, **RND** is quite unusual: although it does calculations and produces a result, it does not need an argument.

Each time you use it, its result is a new *random floating point number* Sbetween **0** and **1**. (Sometimes it can take the value **0**, but never **1**.)

Try:

```
10 PRINT RND
20 GO TO 10
```

to see how the answer varies. Can you detect any pattern? You shouldn't be able to; *random* means that there is no pattern[^p64-1].

**% RND**, which is – as seen on *Chapter 8* – the version of **RND** available in integer expressions, behaves slightly differently. It takes a single argument (e.g. *n*) and returns a random integer in the range **0** to **n-1**. For example, **%RND 10** will return a random integer between **0** and **9**.

While **RND** returns, as discussed above, a random number between **0** and **1**, you can easily get random numbers in other ranges. For instance, **5\*RND** is between **0** and **5**, and **1.3+0.7\*RND** is between **1.3** and **2**. For cases where we need to be in the standard expression evaluator, there is yet another version of **RND**, which is not an integer expression only function:

**RND** (*n*)

which returns a random integer between **0** and **n-1** like **%RND n**. This is recommended over using the standard fractional floating-point function **RND** since it doesn't suffer from the biasing inherent in converting a fractional random number to an integer with multiply and truncation steps.

To get whole numbers with **RND** use **INT** (remembering that **INT** always rounds down) as in **1+INT (RND\*6)**. If however your desired random values can stay within the range of **0** to **65535,** it is better to use **% RND or RND()** which avoid the unnecessary conversions – and rather slow – floating point calculations involved.

To illustrate better what all version can do, let's use all three of them in a program to simulate dice throwing. **RND\*6** is in the range **0** to **6**, but since it never actually reaches **6, INT (RND\*6)** is 0,1,**2**,**3**,4 or **5**.

Here is the dice throwing program:

```
10 REM dice throwing program
20 CLS
30 FOR n=1 TO 2
40 PRINT 1+INT (RND*6);" ";
50 NEXT n
60 INPUT a$: GO TO 20
```

[^p64-1]: *Actually, RND is not truly random, because it follows a fixed sequence of 65536 numbers. However, these are so thoroughly jumbled up that there are at least no obvious patterns so we say that RND is pseudo-random.*

<!-- PDF page 65 -->

Press **ENTER** each time you want to throw the dice. To use **% RND** instead, change line 40 to read:

```
40 PRINT %1+ RND 6;" ";
```

and to use **RND ()** you need to write line 40 as:

```
40 PRINT 1+ RND (6);" ";
```

Aren't the latter two more readable?

The **RANDOMIZE** statement, is used to make **RND** and **% RND** start off at a definite place in its sequence of numbers, as you can see with this program:

```
10 RANDOMIZE 1
20 FOR n=1 TO 5: PRINT % RND
   100,: NEXT n
30 PRINT: GO TO 10
```

After each execution of **RANDOMIZE 1**, the **% RND** sequence starts off again with **97** and if you use **RND** instead of **% RND 100**, you'll get **0.0022735596**. You can use other numbers between **1** and **65535** in the **RANDOMIZE** statement to start the **RND** sequence off at different places.

If you had a program with **RND, RND() or %RND** in it and it also had some mistakes that you had not found, then it would help to use **RANDOMIZE** like this so that the program behaved the same way each time you ran it.

**RANDOMIZE** on its own (and **RANDOMIZE 0** has the same effect) is different, because it really does randomise **RND**, **RND()** and **% RND** – you can see this in the next program:

```
10 RANDOMIZE
20 PRINT % RND 65535: GO TO 10
```

The sequence you get here is not very random, because **RANDOMIZE** uses the time since the computer was switched on. Since this has gone up by the same amount each time **RANDOMIZE** is executed, the next **% RND** does more or less the same. You would get better randomness by replacing **GO TO 10** by **GO TO 20**. Here is a program to toss coins and count the numbers of heads and tails.

```
10 heads,tails=0
20 coin=% RND 2
30 ON coin: heads+=1:tails+=1
40 PRINT heads;",";tails,
50 IF tails<>0 THEN PRINT
   heads/tails;
60 PRINT: GO TO 20
```

The ratio of heads to tails should become approximately **1** if you go on long enough, because in the long run you expect approximately equal numbers of heads and tails.

Note that **RANDOMIZE** can also be written in short as **RAND** and it will expand to **RANDOMIZE**!

<!-- PDF page 66 -->

### Exercises

1. *(For mathematicians only.)*

   Let *p* be a (large) prime, and let *a* be a primitive root ***modulo*** *p*.

   Then if *b*ᵢ is the residue of *a*ᵢ ***modulo*** *p* (1 ≤ *b*ᵢ ≤ *p*-1 ), the sequence:

   <u>*b*ᵢ-1</u>\
   *p*-1

   is a cyclical sequence of *p*-1 distinct numbers in the range **0** to **1** (excluding **1**). By choosing *a* suitably, these can be made to look fairly random.

   **65537** is a Fermat prime, **2¹⁶+1**. Because the multiplicative group of non-zero residues ***modulo*** **65537** has a power of **2** as its order, a residue is a primitive root if and only if it is not a quadratic residue. Use Gauss' law of quadratic reciprocity to show that **75** is a primitive root ***modulo*** **65537** .

   The *ZX Spectrum Next* uses *p*=**65537** and *a*=**75**, and stores some *b*ᵢ-1 in memory. **RND** entails replacing *b*ᵢ-1 in memory by *b*ᵢ₊₁-1, and yielding the result (*b*ᵢ₊₁-1) / (*p*-1).

   **RANDOMIZE n** (with **1** ≤ **n** ≤ **65535**) makes *b*ᵢ equal to *n*+1.

   **RND** is approximately uniformly distributed over the range **0** to **1**.

