RND

From C64-Wiki
Jump to navigationJump to search
BASIC keyword
Keyword: RND
Abbreviation: R, Shift+N
Type: Function
Token code: 187/$BB
Handling routine
in BASIC ROM:
57495–57592
$E097–E0F8
List of all BASIC keywords


Remark: This article describes the BASIC command RND in BASIC V2 on the Commodore 64.

Typ: Function 
General Programming Syntax: RND(<Number>)

The function RND generates pseudo random[1] floating point numbers in the range of 0.0 (inclusive) to 1.0 (exclusive). The argument <number> can be positive, negative or zero.

  • By using RND(<positive number>) gives a different random number each time from a predetermined sequence (the sequence number is stored internally).
  • Using RND(<negative number>) jumps to a point in the sequence determined by the particular negative number used. Repeatedly calling RND with the same negative number results in the same result; typical use is to call RND(<negative number>) once and then repeatedly call RND(<positive number>).
  • With RND(0) the C64 generates the random number from the internal timer[2] and real-time clock[3], though the possible values are limited as long the RTC isn't running to only 16 bit for the 32 bit wide floating point mantissa.

When using a invalid numeric value, the BASIC error ?TYPE MISMATCH ERROR appears. When the numeric argument is absent, it appears as ?SYNTAX ERROR.

The runtime performance of RND(0) is much better compared to RND(1) and up to 5 times faster.

Implementation[edit | edit source]

Commodore's implementation [4][5] (referring to the original discussion on newsgroup comp.sys.cbm [6]) has a severe error in producing the number sequence: Despite the 32 bit seed value (would give a possible range of 4 billions values) the random sequence could shrink to 723 values without repetition. In the worst case the sequence interval could break down to 1, just stuck in generating a single constant value (see example).


Other platforms

RND(0) might use specific hardware registers to improve the randomness of the generated values.

Platform BASIC version Hardware register Note
C64 BASIC V2 CIA 1 timer A and RTC's 1/10s- and 1s register Caveat: The RTC is not automatically started, so their registers do no contribute to it.
VC 20 BASIC V2 VIA 1 timer A and timer B Both timers are always running which are mixing up to well-suited random numbers.
Some anomaly arises in emulator environments, e.g. for the VICE emulator (version 2.4.20) the timer A value flips back and forth between the 0 and 255, resulting in a significant loss of shuffling the floating point mantissa and finally leads to values which are near 1 or 0.
PET
CBM 4000
CBM 8000
BASIC 4.0 VIA 1 timer A and timer B Both timers are always running which are mixing up to well-suited random numbers.
Commodore-264 series BASIC 3.5 TED timer 1 and timer 2 Both timers are always running which are mixing up to well-suited random numbers.
C128 BASIC 7.0 CIA 1 timer A and timer B Timer A is used only during Datasette operation and otherwise contributes only 0 bits in the mantissa.

The implementation in BASIC 4.0+ found in CBM B series uses no hardware related source for the RND function and parameter value 0 leads to the same behavior as for >0.

Examples[edit | edit source]

Typical usage[edit | edit source]

X = RND(-TI)           : REM Initialising
PRINT INT(RND(1)*100)  : REM Integer random numbers from 0 to 99
PRINT INT(RND(1)*6)+1  : REM Integer random numbers from 1 to 6 (for dice simulation)
PRINT INT(RND(1)*49)+1 : REM Integer random number from 1 to 49 (for lotto simulation, for example famous German lotto 6 out 49)
PRINT (RND(0)*101)+100 : REM Random numbers from 100 to 201

RND(0) including RTC values[edit | edit source]

Let the real-time clock contribute to the RND function.

POKE 56328,0    : REM real-time clock activate with 1/10s -> clock runs ($DC08)
PRINT RND(0)    : REM Random number addicted by timer and real-time clock

RND(0) anomalie in comparison to RND(1)[edit | edit source]

This example shows why the command RND(0) isn't very good, when compared to the command RND(1):

10 REM THIS PROGRAM SHOWS THE DIFFERENCE BETWEEN RND(0) AND RND(1).
20 REM 1000 ASTERISKS WILL BE GENERATED FOR RND(0), 
30 REM AFTER THIS HAS FINISHED PRESS ANY KEY TO START RND(1).
40 FOR I=0 TO 1
50 PRINT CHR$(147): REM CLEARS SCREEN
60 POKE 53280,0: REM SETS BORDER COLOUR
70 FOR J=1 TO 1000
80 POKE 1024+INT(RND(I)*1000),42: NEXT
90 PRINT "{WHITE}{HOME}RND(";I;"){LT. BLUE}": REM {LT. BLUE}=LIGHT BLUE
100 POKE 53280,14: REM "RESETS" BORDER COLOUR
110 WAIT 198,1: REM WAITS UNTIL A KEY IS PRESSED
120 GET A$: NEXT
130 PRINT CHR$(147)

With RND(0) you see a pattern. This is because RND(0) can only generate 256 numbers. For filling out the screen with asterisks (*) you need 1000 characters, but do note that this code does not look whether a spot is filled with an asterisk or not, so it may write an asterisk where there was already one, making it look like fewer asterisks were written.

Basic RND 0.png Basic RND 1.png

RND(1) giving a constant value[edit | edit source]

The following program[7] initializes the PRNG with a start value where the generator formula produces the same value which renders the RND(1) function pretty useless. This could be seen as strong evidence for the lack in quality of the implementation.

1 X=RND(-8008/10371)
2 PRINTRND(1):GOTO2
.166823086
.166823086
.166823086
.166823086
...

We get 8008/10371 from the continued fraction expansion of 1658186197/2147483648 and is precise enough that the floating point value on a C64 values stays the same.[8]


References[edit | edit source]

  1. WP-W11.png Wikipedia: Pseudorandomness
  2. CIA 1 timer A which provides the IRQ timing for the KERNAL.
  3. The RTC is not activated on system startup and without explicit setup it won't contribute to the randomness.
  4. Disassembly $E097/57495: Evaluate <rnd> on All_About_Your_64-Online
  5. listing and discussion about RND's implementation on codebase64.org
  6. USENET-Newsgroup comp.sys.cbm: C64 Random Generator?
  7. Thread: R.I.P. RND(1) on Forum64.de Language German
  8. Thread: R.I.P. RND(1) (Nachtrag) on Forum64.de Language German


BASIC V2.0 (second release) Commands

ABS | AND | ASC | ATN | CHR$ | CLOSE | CLR | CMD | CONT | COS | DATA | DEF | DIM | END | EXP | FN | FOR | FRE | GET | GET# | GOSUB | GOTO | IF | INPUT | INPUT# | INT | LEFT$ | LEN | LET | LIST | LOAD | LOG | MID$ | NEW | NEXT | NOT | ON | OPEN | OR | PEEK | π | POKE | POS | PRINT | PRINT# | READ | REM | RESTORE | RETURN | RIGHT$ | RND | RUN | SAVE | SGN | SIN | SPC | SQR | STATUS/ST | STEP | STOP | STR$ | SYS | TAB | TAN | THEN | TIME/TI | TIME$/TI$ | TO | USR | VAL | VERIFY | WAIT