dword dezimal ausgeben
dword dezimal ausgeben
Wenn ich bei einer 16bit CPU mit x86 Syntax ein dword dezimal ausgeben will, wie mache ich das am besten? Also in Assembler.
Das größte Problem ist es, finde ich, dass es nunmal nie in ein register Past. Daran scheiter ich gerade. Aber ihr wisst doch bestimmt wie das geht
Das größte Problem ist es, finde ich, dass es nunmal nie in ein register Past. Daran scheiter ich gerade. Aber ihr wisst doch bestimmt wie das geht
Re: dword dezimal ausgeben
Der grösste 32 Bit Wert ist gleich dezimal 4.294.967.295 mit zehn Ziffern. Mit 32 Bit-Registern teilen wir diesen Wert durch 1.000.000.000, um die erste Ziffer zu bekommen. Siehe dazu auch meine HEX2DEZ-Routine für 32 Bit-Register: http://www.dosforum.de/viewtopic.php?f=15&t=6021oDOSseus hat geschrieben:Wenn ich bei einer 16bit CPU mit x86 Syntax ein dword dezimal ausgeben will, wie mache ich das am besten? Also in Assembler.
Das größte Problem ist es, finde ich, dass es nunmal nie in ein register Past. Daran scheiter ich gerade. Aber ihr wisst doch bestimmt wie das geht
Mit 16 Bit-Register können wir diesen 32 Bit Wert zwar auch nach DX und AX schreiben, doch eine sofortige Teilung durch 1.000.000.000 geht leider mit 16 Bit und dem DIV-Befehl so nicht und so können wir damit zunächst maximal nur durch 10.000 teilen und unmittelbar danach diesen Vorgang erneut wiederholen. Danach teilen wir durch 10. (Zu den jeweiligen Ziffern aus diesen Berechnungen addieren wir 30h, um dann diese ASCIIs in eine Speicherstelle für die Ausgabe zu speichern.)
Alternativ könnte man für die Teilung sonst auch die FPU verwenden.
Dirk
Re: dword dezimal ausgeben
Auf meiner Webseite finden sich auch Unterprogramme zur Wandlung von Zahlen, da sich Fragen danach immer mal wieder in Foren ergaben:
http://www.imperial-games.de/html/dosd2.htm
http://www.imperial-games.de/html/dosd2.htm
Re: dword dezimal ausgeben
@Dosferatu:
Leider ist der source Code bei dir auf der Webseite auch für 32bit. Ich benötige ihn jedoch für 16bit.
@freecrac:
Das Teilen durch Zehnerpotenzen hatte ich auch vor, jedoch weiß ich nciht was ich tun soll, nachdem ich das untere Word durch 10,100 und 1000 geteilt habe, denn irgendwann überschneiden sich die Zahlen im Dezimalsystem.
Wenn ich jetzt hätte
1000000
wären das hexadezimal
0x000F 4240
Da kann ich ja nicht erst
15 (higher word) und dann 16960 (lower word) ausgeben
Leider ist der source Code bei dir auf der Webseite auch für 32bit. Ich benötige ihn jedoch für 16bit.
@freecrac:
Das Teilen durch Zehnerpotenzen hatte ich auch vor, jedoch weiß ich nciht was ich tun soll, nachdem ich das untere Word durch 10,100 und 1000 geteilt habe, denn irgendwann überschneiden sich die Zahlen im Dezimalsystem.
Wenn ich jetzt hätte
1000000
wären das hexadezimal
0x000F 4240
Da kann ich ja nicht erst
15 (higher word) und dann 16960 (lower word) ausgeben
Re: dword dezimal ausgeben
Man muss schon den ganzen 32 Biz-Wert teilen, den man dafür in das DX-Register(high word) und in das AX-Register(low word) einladen muss.oDOSseus hat geschrieben:@Dosferatu:
Leider ist der source Code bei dir auf der Webseite auch für 32bit. Ich benötige ihn jedoch für 16bit.
@freecrac:
Das Teilen durch Zehnerpotenzen hatte ich auch vor, jedoch weiß ich nciht was ich tun soll, nachdem ich das untere Word durch 10,100 und 1000 geteilt habe, denn irgendwann überschneiden sich die Zahlen im Dezimalsystem.
Wenn ich jetzt hätte
1000000
wären das hexadezimal
0x000F 4240
Da kann ich ja nicht erst
15 (higher word) und dann 16960 (lower word) ausgeben
Bei einer 16 Bit-Integer-Division befindet sich der Dividend immer in = DX:AX, aber man kann diesen Wert nur durch einen 16 Bit-Divisor teilen.
(Ich vermute hierbei gab es ein kleines Verständnissproblem wie der DIV-Befehl zu verwenden ist bei einer 16 Bit-Integer-Division.)
Für eine Berechnung einer dezimalen 32 Bit Zahl die wir ausgeben wollen können wir daher pro Divison nur durch max 10.000 teilen, da in 16 Bit maximal ein Wert von 65536 hineinpasst und wir für die Division dann eben nur 10.000 nehmen können.
Weil wir aber den 32 Bit-Wert eigentlich durch 1.000.000.000 teilen wollen, um die höchste Ziffer davon zu bekommen, deswegen müssen wir die Division aufsplitten, dh. zunächst einen kleineren Divisor nehmen durch den wir den gesamten 32 Bit-Wert teilen.
Mit einer erneuten Division des Resultats mit 10.000 und einer weitere Division dieses Resultats durch 10 bekommen wir nun eine zerstückelte Division durch 1.000.000.000 und erhalten so die erste Ziffer.
Für alle anderen übrig gebliebenen Werte die größer als 99.999 sind müssen wir auf ähnliche Weise die Division aufsplitten auf mehrere kleine Divisionen, um die jeweilige höchste Ziffer aus diesem Wert zu bekommen.
Ich hoffe ich habe mich nun verständlich genug ausgedrückt, denn mit Mathe habe ich ja immer selber genug Probleme und wenn Zahlen mit ins Spiel kommen, dann bekomme ich meistens sehr schnell so etwas wie Denkblockaden. (Ich hoffe ich hatte jetzt kein Denkfehler.)
Es kann schon sein dass es auch noch andere Methoden gibt die noch effizienter die Berechnungen durchführen. Aber ich glaube du möchtest nur irgendeinen leicht verständlichen Weg finden, um dieses Problem überhaupt mit 16 Bit bewältigen zu können.
...
Edit: Ich selber habe so eine Berechnung auch noch gar nicht in Assembler geschrieben, weil ich auch nur für sehr kurze Zeit ein 80286er hatte und danach immer nur noch 32Bit-Register verwendet habe für solche Berechnungen.
Mit einem fertigen Code kann ich selber also auch noch gar nicht dienen. Wenn du deinen Code funktionstüchtig hinbekommen hast, dann würde ich mich freuen wenn du ihn hier auch mal posten könntest.
Dirk
Re: dword dezimal ausgeben
Leider doch, denn das Ergebniss passt leider nicht in das Zielregister. Daher muss man wohl doch einen anderen Weg wählen. Grrrr.freecrac hat geschrieben:Ich hoffe ich hatte jetzt kein Denkfehler.
Mit der FPU würde es auf jeden Fall gehen. Für eine Integer-Berechnung muss ich erst noch einmal darüber nachdenken. Sorry.
Division mit der FPU:
Code: Alles auswählen
finit
fild [DIVIDEND] ; Lade Integer
fidiv [DIVISOR] ; Division durch Integer
fistp [QUOTIENT] ; Schreibe Integer und pop
DIVIDEND DW 0FFFFh, 0FFFFh ; kow, high (maximaler 32 Bit-Wert)
DIVISOR DW 9680h, 98h ; low, high = 1.000.000.000 dezimal
QUOTIENT DB ?
Re: dword dezimal ausgeben
Nachdem ich nun in der Newsgroup "de.comp.lang.assembler" diese Frage stellte bekam ich auch prompt schon eine Antwort von Heiko Nokon.
Heute bin ich aber schon zu müde um die Antwort vollständig nachzuvollziehen. Morgen werde ich es mir noch einmal durch den Kopf gehen lassen.
Es läuft quasi darauf hinaus anstelle der Division mehrere Subtraktionen zu machen und in seinem Beispiel geschiet dieses auf Binär-Ebene.
Hier nun Heiko Nokons Antwort hinter bzw. zwischen meiner Frage:
Dirk Wolfgang Glomp wrote:
>ich möchte auf einem 80286 mit 16 Bit-Integer-Registern/Befehlen einen 32
>Bit-Wert als ASCIIs am Bildschirm ausgeben.
>
>Auf einem 80386 mit 32 Bit-Registern kann man beispielsweise den Wert von
>4.294.967.295 mit einem 32 Bit-Divisor von 1.000.000.000 teilen, um die
>höchste Ziffer (in diesem Fall eine 4) daraus zu bekommen.
>
>Wie stelle ich es aber mit 16 Bit-Register an, denn wenn ich den 32 Bit
>Wert von 4.294.967.295 in DX:AX durch einen 16 Bit-Divisor von 10.0000
>zu teilen versuchen würde, dann dürfte das Ergebnis davon ja nicht in das
>Zielregister passen.
>
>Kann jemand einen einfachen Lösungsweg mit der Verwendung von 16
>Bit-Registern aufzeigen?
Schriftliche Division kannst du doch sicherlich? Also aus der Schule und
im Dezimalsystem.
Nun, genau dasselbe Prinzip verwendet man auch zum dividieren im
Binärsystem. Da ergeben sich sogar einige Vereinfachungen, denn im
Dezimalsystem muß man überlegen, wie oft der Divisor in der aktuellen
Verschiebungsposition in den Dividenden paßt. Das ist im Binärsystem
nicht nötig, denn da gibt nur zwei Möglichkeiten: Entweder er paßt ein
mal oder null mal.
>Ich selber habe dafür bisher immer nur 32 Bit-Register verwendet
>und so brauchte ich mir darüber bisher nie Gedanken machen, wie es denn
>eigentlich nur mit 16 Bit-Register/Befehle funktionieren könnte.
Das Prinzip funktioniert sogar noch, wenn man nur eine Maschine mit nur
einem Bit Wortbreite hat. Nur die Zahl der nötigen Instruktionen ist
dann natürlich entsprechend höher.
Das Prinzip in Pseudocode für 32 Bit breite Register/Werte geht so:
Startwert Endwert
R0: Dividend Rest
R1: Divisor (unwichtig)
R2: 1 1
R3: 0 Quotient
linksausrichten:
Oberstes Bit von R1 gesetzt oder R1>=R0?
Ja:
goto dividieren
Nein:
schiebe R1 und R2 je ein Bit nach links
goto linksausrichten
dividieren:
R0=R0-R1
Unterlauf dabei passiert?
Ja:
R0=R0+R1
goto testfertig
Nein:
R3=R3+R2
goto testfertig
testfertig:
R2=1?
Ja:
goto fertig
Nein:
Schiebe R1 und R2 je ein Bit nach rechts
goto dividieren
fertig:
...
Soweit das Prinzip. Wenn man nur 16Bit-Register hat, muß man halt je
zwei verwenden (insgesamt braucht man dann also 8) und die
entsprechenden Additionen, Subtraktionen und Verschiebungen aus je zwei
Teilbefehlen zusammensetzen, wobei üblicherweise der Übertrag via
Carry-Flag passiert. Schieben nach links für Register R1, bestehend aus
den 16-Bit-Registern R1a (hiword) und R1b (loword), würde also z.B. so
umgesetzt werden: SchiebeLinks R1b (rausgeschobenes Bit landet im
Carryflag), Rotierelinks"through carry" R1a (Bit aus carry landet im
untersten Bit von R1a).
Schieben nach rechts funktioniert analog, man muß bloß mit dem hiword
beginnen. Also: SchiebeRechts R1a, dann RotiereRechts"through carry"
R1b.
Auch Addition und Subtraktion setzen jeweils bei Über/Unterlauf das
Carryflag und es gibt jeweils Varianten der Befehle, die den Zustand des
Carryflags in das Ergebnis einbeziehen. Im Unterschied zu den
Verschiebungen fängt man bei Addition/Subtraktion aber immer mit dem
loword an zu rechnen. Also z.B.: Addiere R0 (R0a:R0b) und R1 (R1a:R1b)
geht so: Addiere R0b=R0b+R1b (eventueller Überlauf landet im Carryflag),
dann AdddiereMitCarry R0a=R0a+R1a (wird dann hier in Rechenergebnis mit
einbezogen, es werden also eigentlich drei Zahlen addiert)
Bei noch schmaleren Registern muß man dann die Sache analog weiter
untersetzen, bei 8Bit-Registern besteht also so eine Verschiebung oder
Addition bereits aus vier Instruktionen.
Der Punkt ist: Das Prinzip ist immer das Gleiche. Genau dasselbe wie
beim aus der Schule bekannten "schriftlichen Dividieren", was eigentlich
nichts anderes ist als wiederholtes Subtrahieren. Sieht man im
Pseudocode auch sehr schön, direkt die erste Instruktion nach dem
"dividieren:"-Label ist die Subtraktionsoperation, die den Kern der
Sache darstellt.
Dirk
Heute bin ich aber schon zu müde um die Antwort vollständig nachzuvollziehen. Morgen werde ich es mir noch einmal durch den Kopf gehen lassen.
Es läuft quasi darauf hinaus anstelle der Division mehrere Subtraktionen zu machen und in seinem Beispiel geschiet dieses auf Binär-Ebene.
Hier nun Heiko Nokons Antwort hinter bzw. zwischen meiner Frage:
Dirk Wolfgang Glomp wrote:
>ich möchte auf einem 80286 mit 16 Bit-Integer-Registern/Befehlen einen 32
>Bit-Wert als ASCIIs am Bildschirm ausgeben.
>
>Auf einem 80386 mit 32 Bit-Registern kann man beispielsweise den Wert von
>4.294.967.295 mit einem 32 Bit-Divisor von 1.000.000.000 teilen, um die
>höchste Ziffer (in diesem Fall eine 4) daraus zu bekommen.
>
>Wie stelle ich es aber mit 16 Bit-Register an, denn wenn ich den 32 Bit
>Wert von 4.294.967.295 in DX:AX durch einen 16 Bit-Divisor von 10.0000
>zu teilen versuchen würde, dann dürfte das Ergebnis davon ja nicht in das
>Zielregister passen.
>
>Kann jemand einen einfachen Lösungsweg mit der Verwendung von 16
>Bit-Registern aufzeigen?
Schriftliche Division kannst du doch sicherlich? Also aus der Schule und
im Dezimalsystem.
Nun, genau dasselbe Prinzip verwendet man auch zum dividieren im
Binärsystem. Da ergeben sich sogar einige Vereinfachungen, denn im
Dezimalsystem muß man überlegen, wie oft der Divisor in der aktuellen
Verschiebungsposition in den Dividenden paßt. Das ist im Binärsystem
nicht nötig, denn da gibt nur zwei Möglichkeiten: Entweder er paßt ein
mal oder null mal.
>Ich selber habe dafür bisher immer nur 32 Bit-Register verwendet
>und so brauchte ich mir darüber bisher nie Gedanken machen, wie es denn
>eigentlich nur mit 16 Bit-Register/Befehle funktionieren könnte.
Das Prinzip funktioniert sogar noch, wenn man nur eine Maschine mit nur
einem Bit Wortbreite hat. Nur die Zahl der nötigen Instruktionen ist
dann natürlich entsprechend höher.
Das Prinzip in Pseudocode für 32 Bit breite Register/Werte geht so:
Startwert Endwert
R0: Dividend Rest
R1: Divisor (unwichtig)
R2: 1 1
R3: 0 Quotient
linksausrichten:
Oberstes Bit von R1 gesetzt oder R1>=R0?
Ja:
goto dividieren
Nein:
schiebe R1 und R2 je ein Bit nach links
goto linksausrichten
dividieren:
R0=R0-R1
Unterlauf dabei passiert?
Ja:
R0=R0+R1
goto testfertig
Nein:
R3=R3+R2
goto testfertig
testfertig:
R2=1?
Ja:
goto fertig
Nein:
Schiebe R1 und R2 je ein Bit nach rechts
goto dividieren
fertig:
...
Soweit das Prinzip. Wenn man nur 16Bit-Register hat, muß man halt je
zwei verwenden (insgesamt braucht man dann also 8) und die
entsprechenden Additionen, Subtraktionen und Verschiebungen aus je zwei
Teilbefehlen zusammensetzen, wobei üblicherweise der Übertrag via
Carry-Flag passiert. Schieben nach links für Register R1, bestehend aus
den 16-Bit-Registern R1a (hiword) und R1b (loword), würde also z.B. so
umgesetzt werden: SchiebeLinks R1b (rausgeschobenes Bit landet im
Carryflag), Rotierelinks"through carry" R1a (Bit aus carry landet im
untersten Bit von R1a).
Schieben nach rechts funktioniert analog, man muß bloß mit dem hiword
beginnen. Also: SchiebeRechts R1a, dann RotiereRechts"through carry"
R1b.
Auch Addition und Subtraktion setzen jeweils bei Über/Unterlauf das
Carryflag und es gibt jeweils Varianten der Befehle, die den Zustand des
Carryflags in das Ergebnis einbeziehen. Im Unterschied zu den
Verschiebungen fängt man bei Addition/Subtraktion aber immer mit dem
loword an zu rechnen. Also z.B.: Addiere R0 (R0a:R0b) und R1 (R1a:R1b)
geht so: Addiere R0b=R0b+R1b (eventueller Überlauf landet im Carryflag),
dann AdddiereMitCarry R0a=R0a+R1a (wird dann hier in Rechenergebnis mit
einbezogen, es werden also eigentlich drei Zahlen addiert)
Bei noch schmaleren Registern muß man dann die Sache analog weiter
untersetzen, bei 8Bit-Registern besteht also so eine Verschiebung oder
Addition bereits aus vier Instruktionen.
Der Punkt ist: Das Prinzip ist immer das Gleiche. Genau dasselbe wie
beim aus der Schule bekannten "schriftlichen Dividieren", was eigentlich
nichts anderes ist als wiederholtes Subtrahieren. Sieht man im
Pseudocode auch sehr schön, direkt die erste Instruktion nach dem
"dividieren:"-Label ist die Subtraktionsoperation, die den Kern der
Sache darstellt.
Dirk
Re: dword dezimal ausgeben
Nun hat auch " Markus Wichmann" auf meine Anfrage geantwortet:
DirkAlso, der normale Algorithmus ist ja:
char *target;
char *otarget;
int i;
otarget = target = as_you_like_it();
do {
*target++ = i % 10 + '0';
i /= 10;
} while (i);
target[1] = 0;
while (otarget < target) {
char c = *otarget;
*otarget++ = *target;
*target-- = c;
}
Der schwierige Schritt ist ofensichtlich "i /= 10". Den können wir
natürlich so hier lösen:
j = i / 10 -->
j = 0;
while (i > 10) j++, i -= 10;
In asm also: (*Ungetestet*)
ten: dw 10
; di = target
; dx:ax = i
; benutzt ax, bx, cx, dx, di, si
; erhält sp, bp, cs, ds, es, fs, gs, ss
; und die ganze FPU und MMX und SSE
func:
mov si, di ; otarget = target
l1: ; do {
mov cx, dx ; save i
mov bx, ax
div word [ten] ; dx = i % 10
add dx, '0'
mov ax, dx
stosb ; *target++ = dx
; i /= 10
xor dx, dx ; j = 0
xor ax, ax
l2: ; while(i > 10)
or bx, bx ; i == cx:bx --> i > 10 <-> cx > 10 || bx > 0
jnz l2b
cmp cx, 10
ja l2e
l2b:
inc dx ; ++j
adc ax, 0
sub cx, 10 ; i -= 10
sbb bx, 0
jmp l2
l2e: ; } while(i)
or ax, ax ; if ax == 0, we can simplify this a bit
jz simplified
jmp l1
; this means, that dx doesn't come into it here
simplified: ; now the number is down to one limb, namely dx.
; which means we don't have to do this crap with the
; software division any longer
; there already has been at least one digit output
; that's why the control block moves up:
; while (i) {
mov ax, dx
xor dx, dx ; prepare for div below. dword / word, because ax could
; still be too large for word / byte
or ax, ax
jz simplified_e
div word [ten] ; dx = i % 10
; ax = i / 10
xchg ax, dx
stosb ; *target++ = dl
jmp simplified
simplified_e:
;reversal loop
;while (si < di)
cmp si, di
jae rev_e
mov al, [si]
mov bl, [di]
mov [di], al
mov [si], bl
inc si
dec di
jmp simplified_e
rev_e:
ret
Re: dword dezimal ausgeben
Ich habe es nun so umgesetzt, doch es funktioniert nicht und ich weiß nicht wieso:
Kann mir das jemand erklären?
Code: Alles auswählen
;----------------------------------------------------------
;Teilt ein dword durch ein anderes. Der Divisor ist AX:BX (AX ist das höhere
;word) und der Dividend in CX:DX (CX ist das höhere word). Das Ergebnis ist in
;CX:DX und der Rest in AX:BX
div_dword:
;Speichern in den Buffern. Buffer1 = Divisor, Buffer2 = Dividend
mov [div_buff_1], bx
mov [div_buff_1+2], ax
mov [div_buff_2], dx
mov [div_buff_2+2], cx
;Zähler nullen
xor dx, dx
xor cx, cx
div_dword_sub:
mov ax, [div_buff_2]
sub [div_buff_1], ax
mov ax, [div_buff_2+2]
sbb [div_buff_1+2], ax
jc div_dword_end
add dx, 1
adc cx, 0
jmp div_dword_sub
div_dword_end:
;Wiederaddieren des zu großen Wertes
mov ax, [div_buff_2]
add [div_buff_1], ax
mov ax, [div_buff_2+2]
adc [div_buff_1+2], ax
;setzen der Register
mov bx, [div_buff_1]
mov ax, [div_buff_1+2]
;mov cx, Ist schon gesetzt
;mov dx, Ist schon gesetzt
ret
Re: dword dezimal ausgeben
Ich sehe den Fehler auch beim zweiten Anschauen leider immer noch nicht.oDOSseus hat geschrieben:Ich habe es nun so umgesetzt, doch es funktioniert nicht und ich weiß nicht wieso:Kann mir das jemand erklären?Code: Alles auswählen
;---------------------------------------------------------- ;Teilt ein dword durch ein anderes. Der Divisor ist AX:BX (AX ist das höhere ;word) und der Dividend in CX:DX (CX ist das höhere word). Das Ergebnis ist in ;CX:DX und der Rest in AX:BX div_dword: ;Speichern in den Buffern. Buffer1 = Divisor, Buffer2 = Dividend mov [div_buff_1], bx mov [div_buff_1+2], ax mov [div_buff_2], dx mov [div_buff_2+2], cx ;Zähler nullen xor dx, dx xor cx, cx div_dword_sub: mov ax, [div_buff_2] sub [div_buff_1], ax mov ax, [div_buff_2+2] sbb [div_buff_1+2], ax jc div_dword_end add dx, 1 adc cx, 0 jmp div_dword_sub div_dword_end: ;Wiederaddieren des zu großen Wertes mov ax, [div_buff_2] add [div_buff_1], ax mov ax, [div_buff_2+2] adc [div_buff_1+2], ax ;setzen der Register mov bx, [div_buff_1] mov ax, [div_buff_1+2] ;mov cx, Ist schon gesetzt ;mov dx, Ist schon gesetzt ret
..
Nun hat aber auch Ralph 'rkhb' Bauer geantwortet und auf die FAQ hingewiesen: http://dcla.rkhb.de/div64.html
(Die Vorgehensweise bei 16-Bit-Registern ist identisch.)
Und Jan Seiffert hat auch geantwortet und diese Seite empfohlen:
http://www.cs.uiowa.edu/~jones/bcd/deci ... l#division
Dirk
Re: dword dezimal ausgeben
ich hab das mal schnell in Pascal als Prinziproutine "hingerotzt" - das dürfte sich jedoch ohne größere Probleme auf assembler übertragen lassen.
Die Ausgabe erfolgt über die Variable Rest am Schleifenende (da steht auch das write) in umgekehrter Reihenfolge (wozu durch 10000, 1000,100,10 teilen wenn /10 reicht?).
Und arbeitet nach dem Guten alten Schulprinzip:
Bleistift:
dabei wird das eingangsdoppelwort in 3 Wörter zerlegt (jeweils um 1byte verschoben) und der Rest als übertrag genommen, also passt das ganze bequem in 16bit Register
werde das ganze mal bei gelegenheit komplettieren (in asm) aber die Prinziproutine steht schonmal.
Edit:
in dem Fall ist es ja doch rel. einfach, jedoch muss man wirklich von oben nach unten Arbeiten um überläufe zu vermeiden
Die Ausgabe erfolgt über die Variable Rest am Schleifenende (da steht auch das write) in umgekehrter Reihenfolge (wozu durch 10000, 1000,100,10 teilen wenn /10 reicht?).
Und arbeitet nach dem Guten alten Schulprinzip:
Bleistift:
Code: Alles auswählen
178950/10=17895
17 /10=1 Rest7
78 /10=7 Rest8
89 /10=8 Rest9
95 /10=9 Rest5
50/10=5 Rest0
heißt in diesem Fall:
FFFF FFFF /A wird zu
FFFF /A
= 1999
Rest 5
5 FF /A
= 99
Rest 5
5FF /A
= 99
Rest 5
-> 1999 9999 Rest 5
Der Rest (also die 5) Landet in der Ausgabe (als letzte Ziffer) und mit dem Ergebnis (1999 9999) wird das ganze wiederholt.
werde das ganze mal bei gelegenheit komplettieren (in asm) aber die Prinziproutine steht schonmal.
Code: Alles auswählen
function DwordToStr(Int:Longint):String;
var inta: array[0..3] of byte absolute int;var intw:array [0..1] of word absolute int;
var Rest:byte; {Rest halt}
var ber:word;var bera:array[0..1] of byte absolute ber;
var i:byte;
begin
writeln(inta[0],' ',inta[1],' ',inta[2],' ',inta[3]);
{speicherung 0 hibyte loword 1 lobyte loword, 2 hibyte hiword, 3 lobyte hiword}
for i:=0 to 10 do
begin
{wort1}
ber:=intw[1]; {hiwort von eingang auf berechnungsvariable}
Rest:=ber mod 10;
intw[1]:=ber div 10;
{wort2}
bera[1]:=Rest; {Rest als übertrag auf hibyte der weiteren berechnung}
bera[0]:=inta[1]; {auf das lobyte kommt das nächste byte vom eingang}
Rest:=ber mod 10;
inta[1]:=ber div 10;
{wort3}
bera[1]:=Rest; {Rest als übertrag}
bera[0]:=inta[0];
Rest:=ber mod 10; {Rest ist hier das ergebnis}
inta[0]:=ber div 10;
writeln(' Rest: ',rest); {für speicherung in String käme noch ein +$30 dazu}
end;
end;
Argh, das hatte ich ja ganz vergessen, man hat ja gleich 32 bit zur verfügungBei einer 16 Bit-Integer-Division befindet sich der Dividend immer in = DX:AX
in dem Fall ist es ja doch rel. einfach, jedoch muss man wirklich von oben nach unten Arbeiten um überläufe zu vermeiden
Re: dword dezimal ausgeben
Ich habs jetzt. Der Code:
Funktioniert top. Nur ich Depp habe die Variablen aus einem word raus geholt. Nicht aus einem doubleword. -.- Da hätte ich die Routine ja ewig durchsuchen können. aber bei dem Befehl "var dw 13" kann man das dw ja ganz schnell als double word interpretieren -.- Naja jetzt gehts weiter =) Was für eine Genugtuung
Code: Alles auswählen
;----------------------------------------------------------
;Teilt ein dword durch ein anderes. Der Divisor ist AX:BX (AX ist das höhere
;word) und der Dividend in CX:DX (CX ist das höhere word). Das Ergebnis ist in
;CX:DX und der Rest in AX:BX
div_dword:
push si
push di
xor si, si
xor di, di
clc
div_dword_sub:
sub bx, dx
sbb ax, cx
jc div_dword_too_far
add si, 0x01
adc di, 0x00
jmp div_dword_sub
div_dword_too_far:
clc
add bx, dx
adc ax, cx
mov dx, si
mov cx, di
pop di
pop si
ret
Re: dword dezimal ausgeben
Oh ja, solche Fehler sind schwer zu finden. Prima das es nun funtioniert.oDOSseus hat geschrieben:Ich habs jetzt. Der Code:Funktioniert top. Nur ich Depp habe die Variablen aus einem word raus geholt. Nicht aus einem doubleword. -.- Da hätte ich die Routine ja ewig durchsuchen können. aber bei dem Befehl "var dw 13" kann man das dw ja ganz schnell als double word interpretieren -.- Naja jetzt gehts weiter =) Was für eine GenugtuungCode: Alles auswählen
;---------------------------------------------------------- ;Teilt ein dword durch ein anderes. Der Divisor ist AX:BX (AX ist das höhere ;word) und der Dividend in CX:DX (CX ist das höhere word). Das Ergebnis ist in ;CX:DX und der Rest in AX:BX div_dword: push si push di xor si, si xor di, di clc div_dword_sub: sub bx, dx sbb ax, cx jc div_dword_too_far add si, 0x01 adc di, 0x00 jmp div_dword_sub div_dword_too_far: clc add bx, dx adc ax, cx mov dx, si mov cx, di pop di pop si ret
Dirk
Re: dword dezimal ausgeben
Folgender Code funktioniert jetzt zum dividieren richtig:
Aber er ist leider viiiiiiiieeeeel zu langsam. Die routine mit dem bitshift habe ich nicht verstanden und die war auch schlecht erklärt auf den Seiten finde ich. Könnte die jemand nochmal gut erklären? Das würde mir sehr weiterhelfen
Code: Alles auswählen
div_dword:
push si
push di
xor si, si
xor di, di
clc
div_dword_sub:
sub bx, dx
sbb ax, cx
jc div_dword_too_far
add si, 0x01
adc di, 0x00
jmp div_dword_sub
div_dword_too_far:
clc
add bx, dx
adc ax, cx
mov dx, si
mov cx, di
pop di
pop si
ret
Re: dword dezimal ausgeben
Ups, ich muss gestehen das ich mich in diese Variante immer noch nicht eingelesen habe. Ich vermute aber das es damit auch nicht schneller geht.oDOSseus hat geschrieben:Aber er ist leider viiiiiiiieeeeel zu langsam. Die routine mit dem bitshift habe ich nicht verstanden und die war auch schlecht erklärt auf den Seiten finde ich. Könnte die jemand nochmal gut erklären? Das würde mir sehr weiterhelfen
Ansprechpartner wäre dafür wohl Heiko Nokon(<Heiko.Nocon@gmx.net>) in der Newsgroup "de.comp.lang.assembler" im Thread: "32 Bit-Wert mit 16 Bit-Register als dezimale ASCIIs ausgeben?"
Leider hat google-groups die Reorganisation, bzw. die Zusammenlegung von den Gruppen "de.comp.lang.assembler.x86" und "de.comp.lang.assembler.misc" zu einer neuen Gruppe mit dem Namen "de.comp.lang.assembler" immer noch nicht berücksichtigt.
Ich hoffe dein Provider stellt dir auch eine Verbindung zum Usenet kostenlos zur Verfügung. Hansenet-Kunden brauchen dafür nichts extra zu bezahlen. Host= news.hansenet.de, Benutzername= ... , Passwort=.... (Wird ähnlich konfiguriert wie bei einem Mailclient.)
Dirk