Generating Random Numbers
by Bob Currie
(c) 1990 R.A. Currie


SECTION 1

Anyone wanting to write, say, a guess-the-number game, will need some way of generating a number that is not predictable. Fortunately, SmartBASIC has a command called "RND(x)" which returns a random number or a series of random numbers and these numbers are not predictable - the first time around. If one "runs" the program a second time, one gets exactly the same set of numbers.

For example, type in and run the following short program:

10 FOR i=1 TO 5
20 a=RND(1)
30 PRINT a
40 NEXT i
50 END

The set of numbers generated are:

.732004777
.425420012
.0831831896
.705190617
.69693043

Every time that we "run" this program, we will get exactly the same set of numbers shown above, even if we change the 1 in line 20 to a 12 or any other positive integer value. This is because RND(x) does not generate true random numbers. RND(x) uses a mathematical formula which is built into basic and this formula uses the same seed (or starting number) every time a basic program using it is "run".

SmartBASIC does provide a way to get a different set of numbers when we run this program. Add this line to our program:

5 x=-1:a=RND(x)

"RUN" the program now and you will get:

.0966934073
.805508261
.897540095
.327457077
.120182341

Ah! A different set of numbers. But wait. If we "RUN" the program again, we get:

.0966934073
.805508261
.897540095
.327457077
.120182341

Yup, the same set of numbers as the last time we ran the program. If we change line 5 to read:

5 x=-2:a=RND(x)

and "run" the program again, we will get a different set of numbers than when we had a -1 in line 5. But every time that we run the program with -2 in the RND(x) statement, we will always get the same set of numbers generated. The negative number is called a seed number and SmartBASIC allows a range from -1 to about -1.7E+38. Each of the numbers in this range will produce a different random number. Therefore, if a way can be found to produce a seed number in an unpredictable manner, the RND(x) function can produce a number or set of numbers which are always different than the last time the program was run.

One way of doing this is to have the program ask the user to input a number, any number. This can work, but if he/she inputs a number that was used before then the same set of random numbers will be generated as for the last time that seed number was used.

Another way to generate a bit more unpredictable seed number is to set up a FOR-NEXT or a GOTO loop that looks for a keyboard or a fire-button activation. For example, the LOTO 649 program on the E.A.U.G. Basic Utilities tape tests for when the right fire button has been pressed and uses the counter number at that point in time as the seed for the random number generator.

If you would like to try this out, add the following lines to our little program:

5 GOSUB
1000: a=RND(x)
1000 HOME: PRINT: PRINT
1100 PRINT "Press right fire button to": PRINT "begin"
1200 FOR i = 1 TO 500000
1300 IF PDL(9)=1 THEN x=-i : REM make a note of the loop counter at which the button was pressed and convert it to a negative number for the RND(x) function.
1400 IF x=-i THEN i=500001 :REM to ensure that we close the for-next loop before returning from the gosub.
1500 NEXT i : PRINT: RETURN

The above routine checks for when the right fire button on joystick #1 has been pressed. If you would rather monitor the keyboard for a keypress, then add lines 5 and 1000 as above and the following lines which illustrate the use of a GOTO loop:

1100 PRINT "Press any key to begin"
1200 q = 16150: r = peek(q) : POKE q, 255 : REM disable SmartBASIC poke limitation
1300 POKE 64885,0: REM clear the keyboard status indicator
1400 POKE q,r : REM restore the poke limitation
1500 IF PEEK(64885) -0 then x=x-1 : GOTO 1500: REM keep looking at the keyboard status indicator until a result other than zero tells us that a key was pressed
1600 RETURN: REM we've got our seed number, now let's go back

Both of last two techniques go a long way towards giving a truly unpredictable or random number. However, they are not foolproof. With a little practice, it is possible to type in "run" and hit "return" and "any key" (or "fire button") and get the same set of numbers two or three times in a row. Next issue, I will describe a technique that should improve on the "randomness" of the number even more. At the sametime, I will clean up a few loose ends about the RND(x) function.

SECTION 2

In the first section of this article on generating random numbers, I introduced two ways of making the numbers more random than if one just used the RND(x) function as is. However, if one gets the timing just right, it is possible to generate the same set of numbers several times in a row.

What we need is a way of getting a number that does not depend on human input. For example, if we could get the computer itself to find a number that does not depend only on human timing, then our generated numbers would be much more random.

If we scan all of the accessible memory locations in the ADAM, we find that there are three addresses at which one does not always get the same number. At 17003(dec) we get a zero seven times out of ten and a one three times out of ten. At 65220(dec) we get a 4 seven times out of ten and a 140 three times out of ten. At 17011(dec) we get the numbers from 1 to 12 with a pretty much even chance of getting any one of them.

If you recall, our program for generating a random number by reading the right fire button was:

5 GOSUB 1000 : a=RND(x)
10 FOR i=1 TO 5
20 a=RND(1)
30 PRINT a
40 NEXT i
50 END
1000 HOME: PRINT: PRINT
1100 PRINT "Press right fire button to": PRINT "begin"
1200 FOR 1 = 1 TO 500000
1300 IF PDL(9)=1 THEN x=-i : REM make a note of the loop counter at which the button was pressed and convert it to a negative number for the RND(x) function.
1400 IF x=-i THEN i=500001 :REM to ensure that we close the for-next loop before returning from the gosub.
1500 NEXT i : PRINT: RETURN:rem Now that we have a seed number, let's go back

Add these lines to the above program:

1150 GOSUB 2000
1200 FOR i = x TO 500000 : REM This line replaces the original line 1200 and provides an offset to the counter
2000 x = PEEK(17003) + PEEK(17011) + PEEK(65220) : REM pick a number from each location and add them together
2200 RETURN: REM Now go back to line 1150

By letting the computer choose the starting point of the For-Next loop counter, we have added an extra dimension of uncertainty to the number that will be used for the seed number in the RND(x) function. In other words, our random number is now a little more unpredictable OR random.

If these locations are accessed twice to generate offset numbers we can get a somewhat more random number. This could be done as in the following example for the keyboard program discussed in part 1 of this article.

As you may recall this program was:

5 GOSUB 1000 : a=RND(x)
10 FOR i=1 TO 5
20 a=RND(1)
30 PRINT a
40 NEXT i
50 END 1000 HOME: PRINT: PRINT
1100 PRINT "Press any key to begin"
1200 q = 16150 : r = peek(q) : POKE q,255 : REM disable SmartBASIC poke limitation 1300 POKE 64885,0 : REM clear the keyboard status indicator
1400 POKE q,r : REM restore the poke limitation
1500 IF PEEK(64885) -0 then x=x-1 : GOTO 1500: REM keep looking at the keyboard status indicator until a result other than zero tells us that a key was pressed
1600 RETURN: REM we've got our seed number, now let's go back

Add these lines:

1250 GOSUB 2000: x = -zz : REM the first offset to the counter.
1550 GOSUB 2000 : x = x -zz : REM the second offset to the counter
2000 zz = PEEK(17003) + PEEK(17011) + PEEK(65220) : REM pick a number from each location and add them together.
2200 RETURN : REM Now go back to line 1250 or line 1550.

I hope than you find the foregoing information useful in your programming endeavours. In summary, the RND(x) function can have three arguments:

1) x can have the value of zero, in which case it always returns the same number, even when re-used from within the program.

2) x can have a positive integer value and returns the same number (or set of numbers from within a loop) each time the program is 'run'.

3) x can have a negative integer value and returns a different random number for each value of x. For a given value of x, the same random number will always be generated.

Back to Top