dword dezimal ausgeben

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Benutzeravatar
oDOSseus
LAN Manager
Beiträge: 239
Registriert: Di 10. Aug 2010, 15:21

dword dezimal ausgeben

Beitrag von oDOSseus »

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
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

oDOSseus 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
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=6021

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
DOSferatu
DOS-Übermensch
Beiträge: 1220
Registriert: Di 25. Sep 2007, 12:05
Kontaktdaten:

Re: dword dezimal ausgeben

Beitrag von DOSferatu »

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
Benutzeravatar
oDOSseus
LAN Manager
Beiträge: 239
Registriert: Di 10. Aug 2010, 15:21

Re: dword dezimal ausgeben

Beitrag von oDOSseus »

@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
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

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
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.
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
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

freecrac hat geschrieben:Ich hoffe ich hatte jetzt kein Denkfehler.
Leider doch, denn das Ergebniss passt leider nicht in das Zielregister. Daher muss man wohl doch einen anderen Weg wählen. Grrrr.
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 ?
Dirk
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

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
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

Nun hat auch " Markus Wichmann" auf meine Anfrage geantwortet:
Also, 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
Dirk
Benutzeravatar
oDOSseus
LAN Manager
Beiträge: 239
Registriert: Di 10. Aug 2010, 15:21

Re: dword dezimal ausgeben

Beitrag von oDOSseus »

Ich habe es nun so umgesetzt, doch es funktioniert nicht und ich weiß nicht wieso:

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
Kann mir das jemand erklären?
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

oDOSseus hat geschrieben:Ich habe es nun so umgesetzt, doch es funktioniert nicht und ich weiß nicht wieso:

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
Kann mir das jemand erklären?
Ich sehe den Fehler auch beim zweiten Anschauen leider immer noch nicht.
..

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
Benutzeravatar
Dosenware
DOS-Gott
Beiträge: 3745
Registriert: Mi 24. Mai 2006, 20:29

Re: dword dezimal ausgeben

Beitrag von Dosenware »

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:

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.
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.

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;
Edit:
Bei einer 16 Bit-Integer-Division befindet sich der Dividend immer in = DX:AX
Argh, das hatte ich ja ganz vergessen, man hat ja gleich 32 bit zur verfügung
in dem Fall ist es ja doch rel. einfach, jedoch muss man wirklich von oben nach unten Arbeiten um überläufe zu vermeiden
Benutzeravatar
oDOSseus
LAN Manager
Beiträge: 239
Registriert: Di 10. Aug 2010, 15:21

Re: dword dezimal ausgeben

Beitrag von oDOSseus »

Ich habs jetzt. Der Code:

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
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
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

oDOSseus hat geschrieben:Ich habs jetzt. Der Code:

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
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
Oh ja, solche Fehler sind schwer zu finden. Prima das es nun funtioniert.

Dirk
Benutzeravatar
oDOSseus
LAN Manager
Beiträge: 239
Registriert: Di 10. Aug 2010, 15:21

Re: dword dezimal ausgeben

Beitrag von oDOSseus »

Folgender Code funktioniert jetzt zum dividieren richtig:

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
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
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: dword dezimal ausgeben

Beitrag von freecrac »

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
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.

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
Antworten