Pfad: Home => AVR-Überblick => Programmiertechniken => Fließkommazahlen => Dezimal in bin    (This page in English: Flag EN) Logo

Programmiertechnik für Anfänger in AVR Assemblersprache

Fließkommazahlen in Assemblersprache

Umwandlung von Fließkommazahlen von Dezimal in Binär in Assemblersprache

Nachdem nun die Fließkommazahlen in ihrem Aufbau hier geklärt sind und die Umwandlung von binären Fließkommazahlen in dezimales Format hier gezeigt worden ist, fehlt nun noch das Gegenstück: die Umwandlung aus dezimalen Zahlenformaten in binäre Fließkommazahlen. Und das geht so.

Dezimale Zahlenformate

Es gibt ganz verschiedene dezimale Zahlenformate: Um alle diese verschiedenen Arten von Dezimalzahlen korrekt in das binäre Fließkommazahlenformat verwandeln zu können, muss die Software
  1. feststellen, ob die Dezimalzahl negativ ist (beginnt mit "-"),
  2. die vorzeichenlose dezimale Mantisse in das binäre Zahlenformat umwandeln,
  3. den dezimalen Exponenten ermitteln (Anzahl der Ziffern vor dem Dezimalkomma plus negativer oder positiver Exponent nach "E") und die binäre Mantisse um diese Anzahl mit 10 multiplizieren (Exponent größer Null) bzw. durch 10 teilen (Exponent kleiner als Null),
  4. die binäre Mantisse normalisieren (höchstes Mantissenbit = 1), und
  5. bei negativer Mantisse das Vorzeichenbit und die restliche Mantisse invertieren.

Assembler-Software für das Umwandeln

Im Assembler-Quellcode hier, fliesskomma40_d2b, ist die umzuwandelnde Zahl als Tabelle im ASCII-Zeichen-Format vorgegeben. Diese wird zuerst in das SRAM kopiert, damit beim weiteren Rechengang Doppelzugriffe auf zwei oder mehr Orte im Flash gleichzeitig vermieden werden können. Wer die Dezimalzahl schon im SRAM vorhanden hat, kann diese dorthin kopieren und mit einer binären Null abschließen (als null-terinierte Zeichenkette).

Die Software ist für binäre Mantissen bis 40 Bit Länge geschrieben und für 8 Bit breite Binär-Exponenten. Das entspricht 48-Bit-Binär-Zahlen. Wer weniger Genauigkeit braucht, kann die Software entsprechend um ein oder zwei Bytes kürzen und spart damit Verarbeitungszeit.
Negatives Vorzeichen feststellen
Der Zeiger X (XH:XL = R27:R26) zeigt auf den Beginn dieser Zeichenkette und liest das erste ASCII-Zeichen. Ist dies ein Minuszeichen, wird die Flagge bMneg gesetzt. Die Verarbeitung eines negativen Mantissen-Vorzeichens erfolgt dann später.
Dezimalmantisse einlesen und ins Binärformat umwandeln
Die Software beginnt dann das Einlesen der Mantisse. Das Dezimal-Trennzeichen (hier auf englisches Zahlenformat eingestellt: ".") werden dabei überlesen und erst im nächsten Arbeitsgang separat verarbeitet. Der Nullterminator 0x00 oder ein "E" beenden das Einlesen der Mantisse. Andere Zeichen als ASCII-Nullen bis ASCII-Neun führen dazu, dass die Software in die ErrorLoop-Schleife abtaucht. Das Register rmp (=R16) enthält dann ein ASCII-Zeichen, die den Grund dafür angeben: Die einzelnen gelesenen Digits werden, beginnend mit 10.000.000.000 (0x02540BE400), malgenommen (durch fortgesetztes Addieren der fünf Bytes) und danach jeweils die nächstniedrige Zehnerpotenz zugrunde gelegt. Das Einlesen der Zehnerpotenzen aus der Tabelle vermeidet das Teilen durch 10 und sorgt daher für eine sehr flotte Umwandlung in das Binärformat. Ist die Tabelle fertig ausgelesen (erstes führendes Byte nicht Null), wird das weitere Einlesen von Ziffern eingestellt.
Binärmantisse berechnen
Um aus dieser eingelesenen Binärzahl nun das binäre Mantissenmuster zu erzeugen, werden alle Mantissenbits des Ergebnisses Null gesetzt. Bis das letzte Bit (Bit 0 in rR0): dieses wird Eins gesetzt, um das Ende der Umwandlung zu bewirken.

Beginnend mit der Dezimalzahl 1.000.000.000.000 (0xE8D4A51000) wird diese jeweils durch zwei geteilt und geprüft, ob die eingegebene Zahl größer oder gleich ist. Ist dies der Fall, wird die Dezimalzahl abgezogen und eine Eins in die Ergebnisregister eingeschoben. Wenn nicht, wird nicht abgezogen und eine Null eingeschoben. Wenn nach dem Einschieben eine Null in das Carry rotiert ist, wird weiter dividiert und abgezogen. Wenn nicht, ist die binäre Mantisse fertig umgewandelt.
Exponenten ermitteln und umrechnen
Nun geht es an die dezimalen Exponenten. Zunächst wird die Stellung des Dezimaltrenners in der Mantisse ermittelt, indem diese gelesen wird, das Minuszeichen überlesen und für jede Dezimalziffer vor dem Trenner der dezimale Exponent rDExp um Eins erhöht wird. Wird die Ende-Null 0x00 erreicht, ist die Ermittlung des Dezimalexponenten fertig, wenn stattdessen "E" erreicht wird, beginnt das Einlesen des Dezimalexponenten.

Wird ein "-" erkannt, wird die Flagge bEneg gesetzt. Plus-Zeichen werden überlesen, das Null-Zeichen 0x00 schließt das Einlesen des Exponenten ab. Jede gelesene Ziffer wird auf 0..9 geprüft, schon eingelesene Ziffern mit zehn multipliziert und die nächste Ziffer von ASCII in binär gewandelt und hinzuaddiert. Erreicht oder überschreitet der Dezimalexponent 40, gibt es eine Verzeigung zur Fehlerschleife.

Zuletzt wird der eingelesene Exponent zu dem Exponenten aus der Mantissenauswertung hinzuaddiert. Ist der Dezimalexponent positiv, wird die Mantisse solange mit 10 multipliziert wie es der Exponent angibt. Die Multiplikation erfolgt in der Unterroutine Mult10. Zuerst wird geprüft, ob das oberste Register rR4 größer oder gleich 25 ist. Falls ja, wird die Mantisse solange durch zwei geteilt, bis dies der Fall ist. Dabei wird der Binär-Exponent um Eins erhöht, Überschreitungen von 127 werden durch Verzweigen in die Fehlerschleife abgefangen. Erst dann erfolgt das Multiplizieren mit 10 (Kopieren der Mantisse, Mantisse mal zwei, Mantisse mal zwei, Addieren der Kopie, Mantisse mal zwei).

Bei negativem Dezimalexponenten wird die Mantisse durch 10 geteilt. In der Software sind hierfür gleich zwei Routinen im Unterprogramm Div10 enthalten:
  1. die klassische Methode: 40-maliges Herausschieben eines Bits, Abziehen von 10, falls kein Carry: Einschieben einer Eins, falls Carry: Rücknahme des Abzugs, Einschieben einer Null ins Resultat.
  2. die beschleunigte Methode: die bisherige Mantisse wird kopiert, zum Aufrunden wird fünf zur Mantisse hinzuaddiert, dann wird die Kopie durch zwei geteilt und van der Mantisse abgezogen, in einer Schleife wird dann jeweils die Kopie duch zwei geteilt und zweimal wird die geteilte Kopie abgezogen und zweimal nicht abgezogen. Das wird solange wiederholt bis die Kopie Null geworden ist.
Die Verwendung der beschleunigten Methode lohnt sich, wenn viele Teilungen durch 10 erfolgen müssen. Statt 14 ms für einen Dezimalexponenten von 1E-30 braucht die klassische Methode 24,55 ms, also fast das Doppelte an Zeit.

Die beschleunigte Methode ist hier für beliebige Teiler und hier für das Teilen durch 10 näher beschrieben.
Normalisierung und Verarbeitung von negativen Mantissen
Abschließend wird die binäre Mantisse normalisiert. Diese wird entweder nach rechts geschoben (wenn Bit 39 gesetzt sein sollte) bzw. solange nach links geschoben, bis Bit 38 der Mantisse eins ist. Natürlich erfolgt beides unter Anpassung des Binärexponenten. Wer die Normalisierung so braucht, dass das oberste Bit der Mantisse Eins ist und verschwindet, kann hier noch ein weiteres Mal linksschieben.

War die Flagge rDneg gesetzt, dann wird noch das gesamte Fünferpack invertiert.

Nach allen diesen Operationen ist das Ergebnis (binäre Mantisse in rR4:rR3:rR2:rR1:rR0, binärer Exponent in rBExp) nun komplett.
Ergebnisse
Umwandlungszeiten für Dezimalzahlen in Fliesskomma Die Tabelle rechts zeigt die Ergebnisse solcher Umwandlungen von dezimal in binär in ausgewählten Fällen. Dargestellt ist die Ausgangszahl, das binäre Ergebnis (Mantisse und Exponent), die dezimale Entsprechung dieser Binärzahl sowie die Ausführungszeiten in Millisekunden bei einem Takt von 1 MHz. In allen Fällen wurde mit der beschleunigten Divisions-Variante gerechnet.

Man erkennt, dass die rückgerechneten Zahlen ab der füften bis sechsten Dezimalstelle von der Ausgangszahl abweichen. So ist 0,123456551 ab der zweiten 5 in der siebten Dezimalstelle unkorrekt, was beim Runden die sechste Dezimalstelle falsch werden ließe. Das entspricht der Erwartung, denn bei 40 Bits beträgt die Genauigkeit LOG2(40) ca. 5 1/2 Dezimalstellen.

Fazit

Wer den Herrn Professor mit extensiven Bitschieberen beschäftigen und vom Wesentlichen abweichen lassen will, nehme Fließkommazahlen. So eignet sich die Umwandlung von Dezimalzahlen in binäre Fließkommazahlen ganz hervorragend als Ersatz für Verzögerungsroutinen im Millisekunden-Bereich. Und das Schönste daran: keiner erkennt die eigentliche Primitivschleife dahinter. Besonders negative dezimale Exponenten wie 1E-36 sind bei abgeschaltetem Beschleunigungsschalter dankbare Objekte und sehr langzeitwirksam.

Viel Spaß beim Spielen mit der Software.

Zum Seitenanfang

©2021 by http://www.avr-asm-tutorial.net