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