Binäre Zahlen dezimal anzeigen

Eine häufig auftretende, in der Regel recht aufwendig zu lösende Aufgabenstellung ist es, eine Zahl, die sich im Binärformat in einem Register befindet, dezimal auf dem Bildschirm auszugeben.

Ein gängiger Algorithmus dafür, den wir auch in ähnlicher Form im Kapitel »Zahlensysteme« erläutert haben, ist es, die Zahl wiederholt durch 10 zu dividieren, und jeweils den Rest dieser Division als Ziffer anzuzeigen. Die Zahl 123 beispielsweise ergibt nach der ersten Division 12; der Rest 3 stellt die letzte Ziffer der Zahl dar. Der nächste Schritt ermittelt nun die zweite Ziffer, 2, die der Rest der Division 12/10=1 ist. Übrig bleibt die erste Ziffer der Zahl: 1.

Dieser Algorithmus läßt sich leicht in einer Schleife formulieren. Sie besitzt allerdings den Nachteil, daß sie die Ziffern genau in der umgekehrten Reihenfolge ermittelt, in der sie eigentlich zur Anzeige auf dem Bildschirm benötigt werden. Daher ist es notwendig, die einzelnen Ziffern zwischenzuspeichern. Das folgende Demonstrationsprogramm lädt die anzuzeigende 8-Bit-Zahl 123 (7Bh) in das Register AL und zeigt sie auf dem Bildschirm an:

A
MOV AL,7B       ;100 Anzuzeigende Zahl: 123
MOV DI,120      ;102 Speicher für die Zahl
MOV BL,A        ;105 Divisor
MOV CX,3        ;107 Zahl auf 3 Stellen anzeigen
MOV AH,0        ;10A Start der Schleife: MSB löschen
DIV BL          ;10C Zahl/10 nach AL, Rest nach AH
ADD AH,30       ;10E Ziffer in ASCII umwandeln
MOV [DI],AH     ;111 und im Puffer abspeichern
DEC DI          ;113 vorhergehende Ziffer bearbeiten
LOOP 10A        ;114
MOV DX,11E      ;116 Ergebnis anzeigen
MOV AH,9        ;119 DOS-Funktion: Text anzeigen
INT 21          ;11B
RET             ;11D Programm beenden
DB "   $"

NDEMO1.COM
RCX
22
W
Q

Dieser Algorithmus ist nicht nur recht aufwendig — er zeigt die Zahl auch stets mit unschönen führenden Nullen an, wie Sie leicht feststellen können, indem Sie die zweite Zeile z.B. in »MOV AL,C« abändern. Bei genauerer Betrachtung der Routine kristallisiert sich als Hauptübel die notwendige Zwischenspeicherung heraus. Diese zu umgehen, ist aber nicht weiter schwer, wenn man auf das programmiertechnische Mittel der Rekursion zurückgreift. In Worten formuliert lautet der Algorithmus hierzu etwa so: »Dividiere die Zahl durch 10 und lege das Ergebnis auf dem Stapel ab. Rekursiere, bis alle Ziffern bearbeitet sind. Hole nun die Ziffer wieder vom Stapel und zeige sie an.« Unser so verändertes Demonstrationsprogramm sieht nun so aus:

A
MOV AL,7B       ;100 Anzuzeigende Zahl: 123
MOV BL,A        ;102 Divisor
MOV CX,3        ;104 Zahl auf 3 Stellen anzeigen
CALL 10C        ;107 Anzeigeroutine aufrufen
INT 20          ;10A Programm beenden
MOV AH,0        ;10C MSB löschen
DIV BL          ;10E Zahl/10 nach AL, Rest nach AH
PUSH AX         ;110 Ziffer auf dem Stapel ablegen
DEC CX          ;111 Alle Ziffern bearbeitet?
JZ 117          ;112
CALL 10C        ;114 Nein: Rekursion!
POP AX          ;117 Ziffer holen
ADD AH,30       ;118 Ziffer in ASCII umwandeln
MOV DL,AH       ;11B und anzeigen
MOV AH,2        ;11D DOS-Funktion: Zeichen anzeigen
INT 21H         ;11F
RET             ;121

NDEMO2.COM
RCX
22
W
Q

Berücksichtigt man noch die Überlegungen des vorhergehenden Abschnitts, so können die beiden Zeilen »CALL 10C« und »INT 20« ersatzlos entfallen — wobei freilich auf die Adressänderung der nachfolgenden Zeilen zu achten ist. Verzichtet man außerdem auf die formatierte dreistellige Ausgabe zugunsten einer anschaulicheren Zahl mit variabler Länge (ohne führende Nullen), läßt sich der Algorithmus noch weiter vereinfachen. Als Endebedingung für die Rekursion verwendet das nachstehend abgedruckte Listing nicht den stellenangebenden Schleifenzähler CX, sondern die zu bearbeitende Zahl selbst: Ist das Ergebnis der Division gleich Null, so erübrigt sich eine weitere Rekursion, weil alle Ziffern bereits bearbeitet wurden und nur noch führende Nullen folgen würden.

A
MOV AL,7B       ;100 Anzuzeigende Zahl: 123
MOV BL,A        ;102 Divisor
MOV AH,0        ;104 MSB löschen
DIV BL          ;106 Zahl/10 nach AL, Rest nach AH
PUSH AX         ;118 Ziffer auf dem Stapel ablegen
AND AL,AL       ;109 Alle Ziffern bearbeitet?
JZ 110          ;10B
CALL 104        ;10D Nein: Rekursion!
POP AX          ;110 Ziffer holen
ADD AH,30       ;111 Ziffer in ASCII umwandeln
MOV DL,AH       ;114 und anzeigen
MOV AH,2        ;116 DOS-Funktion: Zeichen anzeigen
INT 21H         ;118
RET             ;11A

NDEMO3.COM
RCX
1B
W
Q

Sogar die Zahl 0 selbst kann durch diese Methode richtig dargestellt werden. Probieren Sie ruhig verschiedene Werte anstelle der Zahl 123 aus — im Bereich von 0 bis 255 funktioniert der Algorithmus absolut zuverlässig. Reicht die von ihm verwendete Zahlengröße von 8 Bit allerdings nicht aus, kann er leicht auf 16 Bit erweitert werden. Dazu muß lediglich die 8-Bit-Division durch einen 16-Bit-Typ ausgetauscht werden. Zudem sind einige weitere kleine Änderungen erforderlich, um das Programm auf die anderen Register anzupassen. Dies können Sie bei Bedarf selbst vornehmen; selbstverständlich greifen auch einige unserer Tips auf diese Routinen zurück.

Solange Sie mit 8-Bit-Zahlen auskommen, können Sie den obigen Algorithmus sogar noch weiter vereinfachen! Denn der 8086 besitzt einige recht nützliche Spezialbefehle, die allesamt nur ein oder zwei Byte belegen, jedoch oft recht komplexe Aufgaben übernehmen können. Häufig wissen selbst Profis nichts von der Existenz dieser Befehle — oder sie verdrängen sie einfach, weil ihre Anwendung zu speziell ist. Dabei bieten sich gerade durch sie oft verblüffend kurze Lösungsmöglichkeiten an. Einer dieser Befehle, der uns hier zugute kommt, lautet »AAM«. Er dient dazu, gepackte Zahlen vor einer Multiplikation zu entpacken, um sie mit dem normalem Multiplikationsbefehl bearbeiten zu können. AAM (»ASCII Adjust for Multiplication«) dividiert den Inhalt des Registers AL durch 10, schreibt das Ergebnis in AH und beläßt den Rest in AL. Mit seiner Hilfe läßt sich unser Testprogramm so kurz gestalten (weshalb wir in vielen unserer Tips natürlich eine Routine wie diese verwenden):

A
MOV AL,7B       ;100 Anzuzeigende Zahl: 123
AAM             ;102 Zahl/10 nach AH, Rest nach AL
PUSH AX         ;104 Ziffer auf dem Stapel ablegen
AND AH,AH       ;105 Alle Ziffern bearbeitet?
JZ 10E          ;107
MOV AL,AH       ;109 Nein: Nächste Ziffer
CALL 102        ;10B Rekursion!
POP DX          ;10E Ziffer gleich nach DL
ADD DL,30       ;10F Ziffer in ASCII umwandeln
MOV AH,2        ;112 DOS-Funktion: Zeichen anzeigen
INT 21H         ;114
RET             ;116

NDEMO4.COM
RCX
17
W
Q

Quelle: 200 Utilities für PC-/MS-DOS von Gerhard Schild und Thomas Jannot