Fließkommaarithmetik

Aus C64-Wiki
(Weitergeleitet von Fließkomma)
Wechseln zu: Navigation, Suche

Fließkommaarithmetik ist eine Methode zur Darstellung und Handhabung eines weiten Bereichs von Realzahlen in binärer Form. Der eingebaute BASIC-Interpreter des C64 enthält eine Reihe von Unterprogrammen für die verschiedensten Berechnungen mit Fließkommazahlen (auch Gleitkomma- oder Gleitpunktzahlen genannt). Diese Routinen können auch aus vom Benutzer erstellten Maschinenspracheprogrammen heraus aufgerufen werden, um Berechnungen mit Realzahlen im Bereich von ±2.93873588·10−39 bis ±1.70141183·1038 durchzuführen.

Funktionsweise[Bearbeiten]

Eine Realzahl T im Fließkommaformat besteht aus einer Mantisse m und einem Exponenten E, welche so "ausgewählt" werden, dass T = m · 2E entspricht.

Die Mantisse ist normalisiert, d.h. eine Festkommabinärzahl im Bereich von 0,5 bis 1, so dass 0,5 ≤ m < 1 gilt, d.h. unmittelbar nach dem Komma steht stets eine 1, dahinter folgen mehrere (31 im Falle des vom C64-BASIC verwendeten Formats) binäre Nachkommastellen.

Der vorzeichenbehaftete Exponent ist eine 8-Bit-Ganzzahl in Exzesscodierung, um negative Exponenten darstellen zu können, die für Fließkommazahlen mit einem Betrag < 0,5 oder >= 1 benötigt werden. Der Wert 128 (entspricht dem Exzess bzw. engl. bias) entspricht dabei einem Exponenten von 0, größere Werte stellen einen entsprechend großen positiven und kleinere einen negativen Exponenten dar. Der Vorteil davon liegt in der einfachen Vergleichbarkeit zweier Werte, ohne eine Subtraktion durchführen zu müssen, auch wenn beim Rechnen mit Exponenten mitunter Korrekturen nötig sind.

Wert Bedeutung als Exponent Fließkommawert
$00 --- 0
$01 -127 2↑(-127) * Mantisse
. . .
$80 0 2↑0 * Mantisse
. . .
$FF +127 2↑127 * Mantisse

Ein separates Vorzeichenbit zeigt an, ob die aus Mantisse und Exponent resultierende Fließkommazahl positiv oder negativ ist. Damit wird der gesamte oben genannte Wertebereich abgedeckt, bis auf die 0: Da sich diese aufgrund der Wertebereichseinschränkungen der Mantisse mit o.g. Formel nicht darstellen lässt, signalisiert stattdessen ein Exponent mit dem Wert 0 (entspräche Exponent −128), dass der gesamte Fließkommaausdruck dem Wert 0 entspricht, unabhängig von der zugehörigen Mantisse.

Fließkommadarstellung auf dem C64[Bearbeiten]

Grundsätzlich werden die Fließkommazahlen in 2 unterschiedlichen Formen abgelegt:

  1. In einer für Berechnungen praktikableren Form als Register bestehend aus 6 oder 7 Bytes.
  2. In Variablen in einer kompakten 5 Bytes umfassenden Form.

Registerdarstellung[Bearbeiten]

Zwei Bereiche in der Zeropage sind für das Rechnen mit Fließkommazahlen reserviert:

  1. Der erste ist der sogenannte FAC (Floating Point ACcumulator), gelegentlich auch als FAC1 bezeichnet:
    • Adresse 97/$61 enthält den Exponenten,
    • Adressen 98–101/$62–$65 enthalten die vier Bytes (32 Bit) der Mantisse,
    • Adresse 102/$66 enthält das Vorzeichen im Most Significant Bit: 0 für positive und $FF (-1) für negative Zahlen.
    • Adresse 112/$70 enthält Rundungsbits der Mantisse bei Zwischenberechnungen.
  2. Der zweite ist das sogenannte ARG (Floating Point ARGument), gelegentlich auch FAC2 genannt. Er ist im Wesentlichen wie der FAC bzw. FAC1 angelegt:
    • Adresse 105/$69 enthält den Exponenten,
    • Adressen 106–109/$6A–$6D werden von der Mantisse belegt,
    • Adresse 110/$6E enthält das Vorzeichen im MSB: 0 für positive und $FF (-1) für negative Zahlen.

Eine Fließkommazahl im FAC belegt 7 und im ARG belegt 6 Bytes.

Variablendarstellung[Bearbeiten]

Um den Speicherverbrauch zu reduzieren, werden Fließkommazahlen im restlichem Arbeitsspeicher auf 5 Bytes komprimiert: Da wegen der Normalisierung der Mantisse das führende Bit stets 1 ist, wird das dafür benötigte Bit von den ROM-Routinen, welche Zahlen aus FAC oder ARG in den Arbeitsspeicher kopieren, durch das Vorzeichenbit ersetzt. Die Routinen, welche in umgekehrter Richtung kopieren, lagern das Vorzeichenbit wieder aus und fügen das führende 1-Bit der Mantisse wieder hinzu.

Bezeichnung: exp sign/ma4 ma3 ma2 ma1
Byte: 0 1 2 3 4
Bit: 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
E E E E E E E E S M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M

Typische Werte in der Variablendarstellung:

Exponent
(hex.)
Mantisse
(hex.)
Wert
(dez.)
00 xx xx xx xx 0
(Mantisse egal)
01 00 00 00 00 2.93873588E-39
(betragsmäßig kleinster Wert)
80 00 00 00 00 0.5
81 00 00 00 00 1
81 80 00 00 00 -1
FF 7F FF FF FF 1.70141183e+38
(betragsmäßig größter positiver Wert)
FF FF FF FF FF -1.70141183e+38
(betragsmäßig größter negativer Wert)


Umrechnungsbeispiel[Bearbeiten]

  • Exponent: exp-128
  • Mantisse: (m4 >= 128 ? -1 : +1) * ((m4 | 0x80) >> 8 + m3 >> 16 + m2 >> 24 + m1 >> 32)
    als Ausdruck in der Syntax der Programmiersprache C, wobei "x >> y" as x*2↑(-y) zu verstehen ist (Bit-Schiebeoperation nach rechts).
     exp       m4       m3       m2       m1
      98       35       44       7A       00      - Hexadezimaldarstellung
     152       53       68      122        0      - Dezimaldarstellung
10011000 00110101 01000100 01111010 00000000      - Binärdarstellung
         ^sign bit

In diesem Fall:
Exponent = 152 - 128 = 24                                      ; dez
Mantisse = 0.10110101010001000111101000000000                  ; bin
Mantisse = +1 * (53 >> 8 + 68 >> 16 + 122 >> 24 + 0 >> 32)     ; dez
         = 1 * 2^-1 + 0 * 2^-2 + 1 * 2^-3 + 1 * 2^-4 + 0 * 2^-5 + ...
         = 0.70807611942291259765

Die Zahl ist also
0.70807611942291259765 * 2^24 = 11879546.0


Verwendung in Basic[Bearbeiten]

In sämtlichen CBM-Basic-Varianten werden Ausdrücke grundsätzlich in Fließkommaarithmetik durchgeführt, selbst dann, wenn nur einfachere Datentypen, wie etwa Ganzzahlvariablen beteiligt sind.

Abgesehen von den üblichen Operatoren gibt es folgende besondere Funktionen in Bezug auf Fließkommazahlen bzw. deren Eigenschaften:

  • ABS - den Betrag einer Fließkommazahl ermitteln (etwaiges negatives Vorzeichen entfernen)
  • INT - die nächstkleinere Ganzzahl ermitteln (Nachkommastellen entfernen).
  • SGN - das Vorzeichen ermitteln
  • STR$ - eine Fließkommazahl in eine Zeichenkette verwandeln
  • VAL - eine Zeichenkette in eine Fließkommazahl wandeln

Nutzung von Fließkommaroutinen[Bearbeiten]

So wie praktisch alle arithmetischen Maschinensprachebefehle den Akkumulator der CPU nutzen, stellen FAC und ARG die Dreh- und Angelpunkte für Fließkommaberechnungen dar: Die zu verarbeitenden Zahlen werden in FAC oder ARG kopiert und von den per JSR aufrufbaren Fließkommaroutinen im ROM gemäß deren Funktion manipuliert. Das Ergebnis der Operation steht anschließend im FAC bereit.

Falls Fließkommazahlen im Arbeitsspeicher für die Operation herangezogen oder aus FAC oder ARG dorthin kopiert werden, ist deren Adresse an die ROM-Routinen per A-, X- und/oder Y-Register zu übergeben, wobei die genaue Verwendung der Register je nach Funktion variiert. Auch muss man bei den meisten Rechenoperationen damit rechnen, dass FAC und ARG überschrieben werden.

Verschiebe-/Kopierroutinen[Bearbeiten]

Name Adresse
dez.
Adresse
hex.
Beschreibung
CONUPK 47756 BA8C ARG mit Zahl aus dem Speicher füllen (A=Adr.LB, Y=Adr.HB)
MOVEF 48143 BBFC Zahl in ARG nach FAC kopieren
MOVFA 48124 BC0F Zahl in FAC nach ARG kopieren
MOVFM 48034 BBA2 FAC mit Zahl aus dem Speicher füllen (A=Adr.LB, Y=Adr.HB)
MOVMF 48084 BBD4 Zahl aus FAC im Speicher ablegen (X=Adr.LB, Y=Adr.HB)

Formatumwandlungen[Bearbeiten]

Name Adresse
dez.
Adresse
hex.
Beschreibung
FACINX 45482 B1AA Zahl in FAC zu 16-Bit-Ganzzahl mit Vorzeichen wandeln (Y=LB, A=HB).
FIN 48371 BCF3 Nullterminierten PETSCII-String zu Fließkommazahl in FAC wandeln (Stringadresse in $7A/$7B). Erwartet erstes Zeichen im Akku und gelöschtes Carry-Flag, z.B. durch Aufruf von CHRGOT (JSR $0079).
STRVAL 47029 B7B5 PETSCII-String zu Fließkommazahl in FAC wandeln (Stringadresse in $22/$23, Stringlänge im Akku).
FOUT 48605 BDDD Zahl in FAC zu nullterminiertem PETSCII-String wandeln (ab $0100 ff., Adresse auch in A, Y). Direkte Ausgabe des FAC-Inhalts als String ist auch über $AABC/43708 möglich.
GIVAYF 45969 B391 16-Bit-Ganzzahl mit Vorzeichen zu Fließkommazahl in FAC wandeln (Y=LB, A=HB).
QINT 48283 BC9B Zahl in FAC in 32-Bit-Ganzzahl mit Vorzeichen wandeln ($62-$65, Big-Endian-Reihenfolge).

Rechenroutinen[Bearbeiten]

Name Adresse
dez.
Adresse
hex.
Beschreibung
ABS (ROM-Routine) 48216 BC58 Funktion ABS auf FAC anwenden
ATN (ROM-Routine) 58126 E30E Funktion ATN auf FAC anwenden
COS (ROM-Routine) 57956 E264 Funktion COS auf FAC anwenden
MUL10 47842 BAE2 Zahl in FAC mit 10 multiplizieren
DIV10 47870 BAFE Zahl in FAC durch 10 teilen. Vorzeichen wird ignoriert, das Ergebnis ist stets positiv.
EXP (ROM-Routine) 49133 BFED Funktion EXP auf FAC anwenden
FADD 47207 B867 Addiert Zahl in RAM zu FAC (A=Adr.LB, Y=Adr.HB)
FADDT 47210 B86A Addiert ARG zu FAC
FDIV 47887 BB0F Teilt Zahl in RAM durch FAC (A=Adr.LB, Y=Adr.HB)
FDIVT 47890 BB12 Teilt ARG durch FAC, Vorzeichen von FAC wird ignoriert und stets als positiv angenommen.
FMULT 47656 BA28 Multipliziert FAC und Zahl im RAM (A=Adr.LB, Y=Adr.HB)
FPWR 49016 BF78 Potenziert ARG mit Zahl aus RAM (A=Adr.LB, Y=Adr.HB)
FPWRT 49019 BF7B Potenziert ARG mit FAC
FSUB 47184 B850 Subtrahiert FAC von Zahl in RAM (A=Adr.LB, Y=Adr.HB)
FSUBT 47187 B853 Subtrahiert FAC von ARG
INT (ROM-Routine) 48332 BCCC Funktion INT auf FAC anwenden
LOG (ROM-Routine) 47594 B9EA Funktion LOG auf FAC anwenden
NEGOP 49076 BFB4 Ändert das Vorzeichen einer Zahl !=0 in FAC
POLY 57411 E043 Polynomauswertung für FAC.
POLY2 57433 E059 Polynomauswertung nur mit ungraden Exponenten für FAC
SIN (ROM-Routine) 57963 E26B Funktion SIN auf FAC anwenden
SGN (ROM-Routine) 48185 BC39 Funktion SGN auf FAC anwenden
SQR (ROM-Routine) 49009 BF71 Funktion SQR auf FAC anwenden
TAN (ROM-Routine) 58036 E2B4 Funktion TAN auf FAC anwenden

Vergleichsoperationen[Bearbeiten]

Name Adresse
dez.
Adresse
hex.
Beschreibung
FCOMP 48219 BC5B Vergleicht FAC mit Zahl im Speicher (A=Adr.LB, Y=Adr.HB). Ergebnis in Statusregister und Akku:
A=0: FAC=RAM,
A=1: FAC>RAM,
A=-1(255): FAC<RAM
SIGN 48171 BC2B Setzt Negativ- und Zero-Flags im Statusregister entsprechend dem Vorzeichen und Betrag der Zahl in FAC

Links[Bearbeiten]

WP-W11.png Wikipedia: Gleitkommazahl
WP-W11.png Wikipedia: Exzesscode