RND

Die BASIC-Funktion RND() (Englisch: random) dient zur Erzeugung von Zufallszahlen. Sie erzeugt eine pseudozufällige Gleitpunktzahl im Bereich zwischen 0.0 (inklusive) und 1.0 (exklusive). Das Hilfsargument Zahl darf positiv, negativ oder Null sein:

  • < 0
    Bei einem negativen Wert wird dieser direkt für die Berechnung der Zufallszahl verwendet. Die Funktion RND() liefert für ein bestimmtes negatives Argument Zahl immer das gleiche Ergebnis zurück. Zum Beispiel ergibt RND(-42) immer 3.92374204e-08.
  • > 0
    Bei positivem Argument dient die jeweils letzte Zufallszahl als Ausgangswert für die Berechnung der nächsten Zufallszahl. Wenn man also die Funktion mit einem festen negativen Wert und danach immer mit positiven Werten aufruft, erhält man bei jedem dieser Programmläufe immer wieder die gleiche Zahlenfolge.
  • = 0
    Mit Null als Argument erzeugt der Commodore 64 die Zufallszahl direkt aus den Werten des Timers und der Echtzeituhr des CIA-Ein-/Ausgabe-Chips. Die Verteilung der Werte ist unter gewissen Umständen (z.B. schnelle aufeinander folgende Abfragen) nicht ganz so zufällig. Dieser Parameter sollte nur zur Initialisierung einer Zufallsreihe verwendet werden und entspricht etwa dem, was manche andere BASIC-Dialekte mit einer RAND- oder RANDOMIZE-Funktion abdecken.

In Programmen sieht man oft, dass am Programmanfang RND() mit der negativen Zeit aus der Variable TI und im weiteren Programmverlauf mit einer positiven Zahl, meistens 1, aufgerufen wird, um bei jedem Programmlauf eine andere Zahlenfolge zu erhalten.
Eine ähnliche Wirkung (mit anderen Werten) erzielt man auch durch den einmaligen Aufruf mittels RND(0), um die Zufallsfolge zu initialisieren und gefolgt von RND()-Aufrufen mit einem positiven Argument im weiteren Programmverlauf.

Leider hat Commodore bei der Implementierung des Zahlenfolge-Algorithmus einen Fehler eingebaut: Trotz eines 32-Bit-Seeds (also eines Wertebereichs von über 4 Milliarden verschiedener Zahlen) kann die Zufallszahlenfolge in Zyklen mit einer Länge von gerade einmal 723 Elementen hineinlaufen, so dass dann also nur noch 723 verschiedene Zahlen erzeugt werden und sich diese Sequenz ständig wiederholt.

Wird RND() nicht mit einem numerischen Argument aufgerufen, wird die BASIC-Fehlermeldung ?TYPE MISMATCH ERROR ausgegeben. Fehlt das numerische Argument oder sind zu viele Argumente gegeben, bricht der Interpreter mit ?SYNTAX ERROR ab.

Beispiele

Siehe auch Beispielprogramme mit Zufallseffekten zum Thema Programmierung.

X=RND(-TI)             : REM Startwert setzen
PRINT INT(RND(1)*100)  : REM Wiedergabe von ganzen Zufallszahlen von 0 bis 99
PRINT INT(RND(1)*6)+1  : REM Wiedergabe von ganzen Zufallszahlen von 1 bis 6 (für Würfelsimulationen)
PRINT INT(RND(1)*49)+1 : REM Wiedergabe von ganzen Zufallszahlen von 1 bis 49 (für Lottosimulationen)
PRINT RND(0)*101+100   : REM Wiedergabe von zufälligen Gleitpunktzahlen von 100 bis 201 (exklusive)

Echtzeituhr für die Initialisierung verwenden:

POKE 56328,0    : REM Echtzeituhur 1/10s schreiben -> Uhr läuft ($DC08)
PRINT RND(0)    : REM Zufahlszahl abhängig von Timer und Echtzeituhr

Ein Beispiel, welches zeigt, warum RND(0), obwohl schneller als RND(1), keine gute Wahl ist:

  10 rem das programm zeigt den
  20 rem unterschied zwischen rnd(0)
  30 rem und rnd(1).
  40 rem es werden jeweils 1000 sterne
  50 rem zufaellig gesetzt und dann
  60 rem auf einen tastendruck gewartet.
  70 rem
  80 for i=0 to 1:print "{clr}";:poke 53280,7
  90 for j=1 to 1000:poke 1024+int(rnd(i)*1000),42:next
 100 print "{wht}rnd(";i;"{left} ){lt blue}":poke 53280,14:wait 198,1:get a$:next
 110 print "{clr}"

Bei RND(0) ist deutlich ein Muster zu erkennen, da die Funktion nur 256 verschiedene Werte liefert und damit nicht alle 1000 Zeichen auf dem Bildschirm erreicht werden können.

basic_rnd_0

basic_rnd_1

Ein Beispiel, welches den Fehler in RND(>0) demonstriert, wenn mit einem „schlechten“ Seed wie z.B. -7621 begonnen wird:

 1 print "{clr}";: x = rnd(-7621)
 2 for t = 1 to 100000: x = rnd(1): next: rem am Anfang ok, dann beginnt der Zyklus:
 3 x = int(rnd(1) * 40)
 4 y = int(rnd(1) * 25)
 5 poke 1024 + 40 * y + x, 160
 6 goto 3

Eigentlich müsste der Bildschirm immer mehr gefüllt werden, aber die für eine komplette Füllung nötigen 1000 verschiedenen Positionen werden nie erreicht.