| FAQ der Newsgroup de.comp.lang.assembler (d.c.l.a.) | |||||||||||||||||||||||||||||||||||||||||||||||||
|
Wie wandle ich eine Dezimalzahl (String) in ein Integer (Byte, Word etc.) um? In einem Text befinden sich Zahlen als eine Aneinanderreihung von Buchstaben. Damit der Prozessor damit rechnen kann, müssen diese Buchstaben erst in ein vom Prozessor unterstütztes Format umgerechnet werden. Das Intel-Manual spricht hier allgemein von 'Integer', wobei die Größe und das Vorzeichen der Zahl keine Rolle spielen. Wenn man nur eine einzelne Dezimalziffer vor sich hat, ist es kein größeres Problem, sie von der Buchstabenform (ASCII) in die Integerform (binär) zu überführen: Man kappt das obere Nibble. Eine mehrstelige Dezimalzahl in das Integerformat zu überführen, ist allerdings etwas komplizierter, da der Prozessor binär zählt und mit dem Dezimalsystem nichts anfangen kann. Beispielstring: "29282" Beginnen wir mit der ersten Ziffer dieser Dezimalzahl, die als einzelner Buchstabe (8 Bit) vorliegt. Nun entspricht eine '2' als Buchstabe leider nicht einer 2 als Integer. Sie muss nach folgender Tabelle umgerechnet werden:
Wie man sieht, unterscheiden sich ASCII-Code und Integer nur im vorderen Nibble (4-Bit-Block). Es genügt also, das vordere Nibble des ASCII-Codes (0011) in 0000 umzutauschen, und schon hat man ein Integer. Man braucht noch nicht einmal umzutauschen, sondern kann die ersten 4 Bits einfach löschen: ; int(2) = chr(2) & 00001111 mov bl, 00110010b ; ASCII-Code für '2' and bl, 00001111b ; vorderes Nibble löschen, hinteres Nibble unverändert Vor der Umwandlung muss man allerdings nachprüfen, ob eine Zahl oder irgend etwas anderes vorliegt. "Davor" deshalb, weil danach auf jeden Fall ein Integer vorliegt, auch wenn das ursprüngliche Zeichen ein Doppelpunkt war. ; jmp if (bl < '0') || (bl > '9') cmp bl, '0' ; der Compiler soll das in 00110000b umrechnen jb Ausstieg ; jmp if bl < '0' cmp bl, '9' ; der Compiler soll das in 00111001b umrechnen ja Ausstieg ; jmp if bl > '0' Zum Dritten muss man sich vor Augen halten, dass die Ziffern einer Zahl eine gewisse Wertigkeit haben. So bedeutet die erste 2 in 29282 nicht nur 2, sondern 20000, die zweite 2 bedeutet 200, während die dritte 2 tatsächlich nur 2 bedeutet. Die Zahl 29282 ist also nur die Abkürzung für 2*10000 + 9*1000 + 2*100 + 8*10 + 2*1. Eine Schwierigkeit besteht darin, dass man normalerweise nicht weiß, wieviel Ziffern die Dezimalzahl hat, und deshalb die Wertigkeit der gerade zu behandelnden Ziffer unbekannt ist. Die Lösung dieses Problems nennt sich Horner-Schema und verläuft für die Zahl 29282 so:
Wie man sieht, unterscheiden sich Schritte 2 bis 4 nur darin, dass unterschiedliche Ziffern umgewandelt und addiert werden. Man kann diese Schritte für jede beliebige Anzahl von Ziffern wiederholen. Wenn man vor Schritt 1 noch AX mit Null initialisiert, so kann auch der erste Schritt nach diesem Schema gestaltet werden - und man hat die Grundlage für eine Schleife. In Assembler sieht das dann so aus: Danach steht die Zahl als Integer in EAX. Eine Fehlerprüfung, ob die Zahl zu groß ist, sprich: das Ergebnis die Grenzen der Register sprengt, kann man an die Stelle des 'jmp Schleife' einbauen, z. B.:
adc edx, 0 ; EDX ist der Übertrag der MUL-Operation
or edx, edx
jz Schleife
xor eax, eax
.Ausstieg: ; wie oben
Danach steht in EAX Null, wenn die Horner-Operation einen Überlauf verursacht hat. Eine verwegene Lösung, mit der man Eindruck schinden kann: Ralph 'rkhb' Bauer Aug 2008 | ||||||||||||||||||||||||||||||||||||||||||||||||