RND

Aus C64-Wiki
Zur Navigation springenZur Suche springen
RND
Syntax: RND(<Zahl>)
Parameter
<Zahl>: bestimmt den Ausgangswert (Seed) für die Berechnung der Zufallszahl
Einordnung
Typ: numerische Funktion
Kontext: Arithmetik
Aufgabe: Erzeugen einer Pseudozufallszahl
Abkürzung: rN
Token: $bb (187)
Verwandte Befehle

Anmerkung: Dieser Artikel beschreibt die numerische BASIC-Funktion RND unter BASIC V2 des Commodore 64.


Die BASIC-Funktion RND() (Englisch: random[1]) dient zur Erzeugung von Zufallszahlen. Sie erzeugt eine pseudozufällige[2] 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.
    Dies dient üblicherweise dazu, einen Startpunkt einer Zufallszahlenfolge zu bestimmen, entweder um eine definierte, reproduzierbare Folge zu erhalten oder abhängig von einem Hardware-Parameter einen "zufälligen" Startpunkt zu wählen (ähnlich dem, was manche andere BASIC-Dialekte mit einer RAND- oder RANDOMIZE-Funktion anbieten).
  • > 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[3] und der Echtzeituhr[4] des CIA-Ein-/Ausgabe-Chips (siehe $E09E). 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.

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.

Das Laufzeitverhalten von RND(0) ist im Vergleich zu RND(1) deutlich besser und etwa 5 mal so schnell.

Verwendung[Bearbeiten | Quelltext bearbeiten]

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.

Implementierung[Bearbeiten | Quelltext bearbeiten]

Leider hat Commodore bei der Implementierung[5][6] (basierend auf einer Diskussion in comp.sys.cbm [7]) 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. Es ist sogar ein Konstellation möglich, wo der Generator nur einen einzigen (konstanten) Wert liefert (siehe Beispiel).


Andere Plattformen

Für RND(0) werden Hardware-Register herangezogen, damit in möglichst zufälliger Charakter entsteht.

Plattform BASIC-Version Hardware-Register Anmerkung
C64 BASIC V2 CIA 1 Timer A und RTC 1/10s- und 1s-Register Die RTC wird nicht automatisch gestartet, daher liefern diese Anteile keinen Beitrag.
VC 20 BASIC V2 VIA 1 Timer A und Timer B Beide Timer laufen ständig, was eine gute Zufallsgrundlage darstellt.
Anomalie z.B. bei VICE-Emulator (Version 2.4.20), wo der Timer-A-Wert langsam zwischen 0 und 255 hin und her spring, der im signifikanteren Teil der Mantisse verwendet wird, was dazu führt, dass der Wert ständig Nahe bei 1 oder 0 liegt.
PET
CBM 4000
CBM 8000
BASIC 4.0 VIA 1 Timer A und Timer B Beide Timer laufen ständig, was eine gute Zufallsgrundlage darstellt.
C264-Serie BASIC 3.5 TED Timer 1 und Timer 2 Beide Timer laufen ständig, was eine gute Zufallsgrundlage darstellt.
C128 BASIC 7.0 CIA 1 Timer A und Timer B Timer A ist nur beim Kassettenbetrieb in Verwendung und liefert sonst keinen Beitrag (0-Bits in der Mantisse).

Das BASIC 4.0+ der CBM-II-Serie hat keinen hardware-bezogenen Parameter für die RND-Funktion und der Parameter 0 wird wie sonst beim Fall >0 behandelt.

Trivia[Bearbeiten | Quelltext bearbeiten]

Diese Funktion kann als Easteregg-Generator "missbraucht" werden, was gelegentlich als Beleg dafür angenommen wird, Commodore habe seinerseits ab dem Zeitpunkt der Verwendung von BASIC V2 im VIC 20 mit einem Easteregg auf Microsofts BASIC-Easteregg gekontert. Tatsächlich ist dieser Ansatz - nämlich ausgehend von einem bestimmten Anfangswert geheime Botschaften in einem zufälligen Zahlenstrom zu finden - aber mehr oder weniger eine grundlegende Eigenschaft von Pseudozufallszahlengeneratoren. Es handelt sich bei diesem Effekt also lediglich um eine ungewollte Nebenwirkung.

Beispiele[Bearbeiten | Quelltext bearbeiten]

Siehe auch Beispielprogramme mit Zufallseffekten zum Thema Programmierung.

Einfache Beispiele[Bearbeiten | Quelltext bearbeiten]

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)

RND(0) mit Echtzeituhr[Bearbeiten | Quelltext bearbeiten]

Echtzeituhr für die Initialisierung verwenden:

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

RND(0) Anomalie und Vergleich zu RND(1)[Bearbeiten | Quelltext bearbeiten]

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.png Basic RND 1.png

Ein Beispiel[8], 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.

RND(1) mit konstantem Wert[Bearbeiten | Quelltext bearbeiten]

Das folgende Programm[9] initialisiert den Pseudozufallsgenerator mit einem Startwert, der die Generatorformel immer den gleichen Wert produzieren lässt und somit die RND(1)-Funktion unbrauchbar macht bzw. ein Beleg für die mangelnde Qualität der Implementierung darstellt.

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

8008/10371 entsteht bei der Kettenbruchentwicklung von 1658186197/2147483648 und ist bereits so genau genug, dass die beiden Zahlen für den C64 im Fließkommaformat gleich sind.[10]

Quellen / Anmerkungen[Bearbeiten | Quelltext bearbeiten]

Weblinks[Bearbeiten | Quelltext bearbeiten]

WP-W11.png Wikipedia: Pseudozufallszahl