Classic Computer Magazine Archive COMPUTE! ISSUE 43 / DECEMBER 1983 / PAGE 44

THE BEGINNER'S PAGE

Richard Mansfield, Senior Editor

Zones Of Unpredictability

Part 2

The RND command is a necessary part of most computer games or computerized simulations of real events. That's because life (as far as we know) has a random quality. Perhaps it's our limited viewpoint, but some things do seem to be accidental. When you play Poker, or if you write a Poker game on your computer, you'll see randomness in action. When cards are shuffled and dealt, something accidental, something unpredictable is supposed to happen — no one knows what order the cards are in when they are passed around.

Last month we explored some of the general rules for working with the RND command in BASIC. However, since it is one of the less transportable of the BASIC instructions, we need to go into some of the specific differences in the ways that each particular computer handles RND. Transportable means the ease with which a program written in one computer's BASIC will run on another's BASIC. There are always a few adjustments to make, but some programs are so machine specific (especially graphics programs) that they're very hard to translate and are, therefore, not very transportable. Different computer brands tend to have specific peculiarities in their use of RND.

But before looking into the particular use and syntax of RND on your computer, let's run a brief test of the randomness of your RND. RND on any computer is an effort to cause accidental, unpredictable results. The more unpredictable, the better. One simple way that we can test your RND is to see if it favors one number over another. If we limit the test to the numbers 1 through 10, will it hit, say, 3 more often than 7?

Type in the program and RUN it. You'll see the statistics on how often each number is turning up. Ideally, you'll end up with 10 percent for each number. At first, of course, the percentages will be off, but if you let the program run for a while, you should get pretty close to even distribution.

There are a few general programming techniques to notice here. If you add up the percents, you won't get precisely 100 percent. That's because we're using the INT command to round off the numbers printed on the screen. The computer is working with extended decimal fractions, but for neatness, we're not printing everything out. Take off the INT to see how messy things get. Also look at line 40. Here 1 is added to X each time we get a random number. That's so we'll have numbers 1-10 instead of 0 - 9. Remember that an array (a collection of numbered variables) will start with zero. That is, A(0) is the first "cell" in an A() array. To make it easier for us to keep straight, we can just ignore the A(0) cell and work with the cells from 1 on up.

Can you tell why line 100 is necessary? At the start of our test, some numbers won't come up at all. They, will leave a zero in their A() array variable cell. The computer won't allow you to divide by zero. So, we need to put in a special test for zero and then skip over line 110 where the division would normally occur.

Special Seeding

There's an important aspect of randomness which is not tested by this program: order of arrival. A computer which gave the numbers 1 through 10 in order, each cycle through the test, would look perfect on the test. The distribution would be exactly 10 percent, but it certainly wouldn't be a good randomness generator. There are two aspects to the randomness of the order of arrival of numbers. First, you don't want the same sequence of random numbers each time you turn on the computer. We'll call this the start-up sequence. With a repeating start-up sequence, each time you played Poker the first hand of the evening would be identical to the last night's first hand. And the second hand would match last night's second hand. And so on.

The second aspect is repeating sequences within a program. You don't want to have a short sequence of random numbers that starts repeating itself (1534215342...). Last month we dealt with both of these issues and discovered that, in fact, the order on several computers is not random unless you take a special step to mix things up.

The special step is called seeding and it means using something random as a starting place. Computers are relentlessly logical. It's not easy for them to do things accidentally, to create randomness. So, they use a special algorithm (a method) to try to mix things up. The RND command takes a number (the seed), turns it inside out (by "rotating" it in its binary form), multiplies it by itself, rounds it off, and so forth. All this twisting and turning is designed to come up with an unexpected number. However, if the starting place is the same, the result will be the same. The same algorithm is used each time. That's where random seeding comes in.

It's Fast. You're Not.

If you give RND a seed from the computer's ultra-fast, realtime clock, you won't get the same seed twice. (Realtime means time which passes as humans use it: 60 minutes to an hour, etc. All computers have internal timers, but not all have clocks that keep realtime.) That's the method used by all of our computers except the Apple; it has no realtime clock. Why don't you ever get the same seed when it comes from the clock? Because this clock is terrifically fast and you're not. The time it takes you to turn on the computer, type RUN, and hit RETURN is never exactly the same. Consequently, the start-up time for a game will depend on you and that's plenty random by computer standards: if you bat an eyelash, the computer clock has registered hundreds of time cycles. In any case, you'll need to know how to work with your particular RND, and it will help you translate programs from alien BASICs if you also have some idea of how the other computers use RND. Here are some notes on how to use RND on several popular computers:

• Commodore Computers. You can first seed the RND with (TI), the special variable which holds the current value of the clock. To do this, you would write a line early in your program like this:

10A = RND(-TI)

This will cause the computer to provide a different sequence each time the computer is turned on. That is, the seed will depend on the clock and it will be called upon when you type RUN to start the program. To insure that calls to RND later in the program are also highly random, use RND (0).

• Atari. There are no special requirements for the Atari. It seeds the RND generator itself. Whenever you call upon RND, you'll get bQth randomized as well as different start-up sequences each time the computer is turned on. The syntax is the same as Commodore: A = RND (X). It doesn't matter what X is.

• TRS-80 Color Computer. Same syntax, but use RND (0) to achieve both randomized sequences and random start-ups.

• TI-99/4A. Using RND alone will result in identical sequences. To avoid that, you should use the additional command RANDOMIZE early in a program:

10 RANDOMIZE
100 A = RND

Further, our TI columnist, C. Regena, suggests using RANDOMIZE before each call to RND to insure total randomness.

• Timex/Sinclair. To call the clock for a seed, you should put the following line early in a program:

10 RAND 0

and then call RND the same way the TI does (no argument in parentheses):

100 A = RND

RND, when it follows RAND 1 - 65535 (any of these numbers), will result in a repeating sequence of "random numbers" which is the same each time power is turned on (if you use the same number after RAND). The computer generates 65536 numbers to use for its random numbers. The number following RND determines the entry point into this sequence of numbers. However, when you use zero after RAND, the entry point into the list of numbers is determined by how long the TV has been turned on. This is essentially the same solution that the Commodore computers use.

• Apple. Because the Apple doesn't contain a clock, the best way to seed the RND is to ask the user to hit a key, within a loop:

10 PRINT "Press RETURN when ready to start"
20 IF PEEK (-16384) < 128 THEN A = RND(l):
   GOTO 20

This will give you a random seed to prevent start-up sequence repetitions. The value in address —16384 will remain below 128 until a key is pressed. Thus, you'll keep reading off numbers via the RND, but will have reached an unpredictable position in the list by the time you hit RETURN. Following that, use RND (1) for the best randomness. There is a bug, however, in the Apple's BASIC which causes the sequences to start repeating themselves rather quickly. There's no cure for it.

One final note about RND. If you're writing a game, one way to test it is to deliberately violate the randomizing rules we've mentioned above. There are cases when you will want to have a repeating, nonrandom sequence of numbers to check things within the program. If that's what you're after, you can leave out the randomizing seeds and test things against the resulting known, predictable patterns.

Randomness Test

10 GOSUB 500
20 FOR I = 1 TO 100
30 T = T + 1
40 X = INT (RND (1) * 10):X=X+l
50 A(X)=A(X)+1
60 NEXT I
70 GOSUB 500
80 FORI=lTO10
90 PRINT I;
100 IFA(I)=0THENPRINT"— 0%":GOTO120
110 PRINT"—";INT(T/A(I));"%"
120 :NEXT I
130 GOTO 20
500 PRINT"{CLR}": REM CLEAR THE SCREEN
510 RETURN