Commodore‎ > ‎BASIC‎ > ‎Keywords‎ > ‎

### RND

 Keyword Abbreviation Token (hex) Version(s) Classification RND R{Shift+N} BB 1.0+ Function

RND value )

 Parameters Type Legal Value(s) Note(s) value Numeric any

 Returns Type Value(s) Note(s) result Floating-point 0 to 1 up to, but not including, 1

 Purpose
Calculate a psudo-random number.

 Remarks
The RND function is primarily used to generate a psudo-random number.  Psudo-random means the value is difficult predict, but not truly random.  CBM BASIC provides two ways to get a "random" number.  One way is to supply a value of zero to RND; in this case RND will generate a "random" number based on hardware timers and also update a Secret Variable called the seed.  The second way is to supply any positive value to RND; in this case it will generate a "random" number based on the current seed (and update the seed in the process).  I prefer to combine the methods: use a zero value at the start of the program to set a "random" seed based on the hardware timers and then use a positive value in the main loop of the program to generate a "random sequence".  I do this to avoid potential skewing of the results based on the periodic nature of the hardware timers.

Another, rarely used option, is to pass a negative value to RND which will set a specific seed.  This may be useful for testing as it will result in the same sequence of "random" numbers if you only use RND(1) in the future (i.e., in any positive value).

The result will be a floating-point number from zero up to, but not including, one.  To get an an integer number between min and max (inclusive), use the forumla:
R = min + INT( (max - min +1) * RND(1) )

For example, to get a random number from 1 to 6 to simulate the roll of a die, the forumula would work out as R = 1 + INT(6*RND(1)).

There has been some controversy around the RND function.  Mainly this involves the "quality" (or lack thereof) of the random values generated.  From my research, the poor quality seems to be a more serious issue in other (non-CBM) versions of BASIC.  This is probably due to a combination of poor algorithm along with limited precision (CBM features 32-bit floats, while most other 8-bits use only 24-bit floats).  In CBM BASIC, it seems many programs are using a 0 value which may reduce quality based on the peiodic nature of the hardware timers (as explained above).  There are several statical measures that can be applied to a sequence of numbers, and which ones are important tends to vary upon the intended use of the random numbers; hence another reason for debate.  My limited experiments (using my preferred/combined method) show that usually all values in 1-d or 2-d sense will eventually occur, and most of them with roughly the same frequency.  In a 3-d and 4-d sense the "random" numbers often will hit all possible combinations, but in a few cases (an "unlucky seed") some combinations never occur.  I think this could be avoided (but haven't verified) if you call RND(0) to re-seed the sequence on rare occassions (like maybe 1 in 5000, or even less often).

Another thing to consider is that the quality of the results may depend on how often / when you call RND.  If you call it routinely in a programmed loop (for example to draw a field of "stars" on a bitmap) the RND function will get called at a fairly predictible rate so that RND(0), which bases its results on the hardware timers, may be heavily skewed.  On the other hand, if you only occassionaly or "randomly" call RND(0) (for example, when the user performs a certain task) it may give "better" results than RND(1); the reason being that the user (if human) will generally not do things on a very precise time schedule (thus the hardware timers will tend to be "randomly out of sync" relative to the last time they were checked).  Anyway, I think using RND(0) to initialize the seed and RND(1) in loops is a good strategy.

If you don't trust BASIC (or my experimental results), some CBM machines have a SID chip which can be programmed to generate "random" numbers too; I haven't compared the quality of the two methods, but POKEing and PEEKing seems like it would be slower than using RND.

BASIC sets the seed to a constant value stored in ROM on power-up.  Thus, if you use RND(1) without initializing the seed your program will generate the same set of "random" numbers if you run it after power-up.  The BASIC versions are not consistant about the initial value returned by RND(1) or how they update the seed when given a negative value.  Thus on a single machine, you can set a specific seed (with either a negative value or the power-up method) and get a reliable sequence of numbers; but running the same program on a different machine may give different results... compare and contrast the examples.

If the value is omitted or not a valid expression, SYNTAX ERROR is generated.  If the value is not numeric, a TYPE MISMATCH ERROR occurs.

I almost forgot!  Some other BASICs use the value supplied to RND to determine the range of the result.  As explained above, CBM BASIC always returns a result in the range of 0 to 1 (the value is only used to specify a method used to generate the result or possibly set an initial seed).

Examples (Plus/4 or C128):
 ```PRINT RND(1) : REM result after power-up 1.07870447E-03 READY. PRINT RND(1) : REM the next number in the "random" sequence .793262171 READY. PRINT RND(-1) : REM set a specific seed 2.99196472E-08 READY. PRINT RND(1) : REM the next number in the "random" sequence .328780872 READY. PRINT RND(0) : REM this will be "random" unless you have very precise timing... .252642419 READY. ```

Examples (C64):
 ```PRINT RND(1) : REM result after power-up .185564016 READY. PRINT RND(1) : REM the next number in the "random" sequence .0468986348 READY. PRINT RND(-1) : REM set a specific seed 2.99196472E-08 READY. PRINT RND(1) : REM the next number in the "random" sequence .328780872 READY. PRINT RND(0) : REM this will be "random" unless you have very precise timing... .601563811 READY. ```

 Compare With

 Contrast With

© H2Obsession, 2014
Comments