FAQ der Newsgroup de.comp.lang.assembler (d.c.l.a.)

Wie dividiere ich mit großen Zahlen (zwei Register)?

Begriffe:  Dividend / Divisor = Quotient Rest

1. Fall: Der Dividend passt nicht in ein Register. Der Divisor und die Ergebnisse der Division (Quotient, Rest) passen jedoch vollständig in je ein Register. Da der Dividend bei DIV immer aus EDX:EAX gebildet wird, ergibt sich kein Problem:

Aufgabe:   353821814888 : 1000   = 353821814  Rest 888
         = 0x52616C7068 / 0x03E8 = 0x1516E476 Rest 0x378

Assembler:

        mov edx, 52h         ; Dividend: EDX:EAX
        mov eax, 616C7068h
        mov ebx, 1000        ; Divisor
        div ebx

Danach befinden sich in EAX der Quotient und in EDX der Rest

2. Fall: Der Quotient wird nicht in ein 32-Bit-Register passen:

Aufgabe:   353821814888 : 10   = 35382181488  Rest 8
         = 0x52616C7068 / 0x0A = 0x083CF13E70 Rest 0x08

Assembler:

        mov edx, 52h         ; Hi-Dividend:Lo-Dividend: EDX:EAX
        mov eax, 616C7068h
        mov ebx, 10          ; Divisor
        mov ecx, eax         ; Lo-Dividend sichern
        mov eax, edx         ; Hi-Dividend wird einziger Dividend
        xor edx, edx
        div ebx              ; Hi-Dividend / 100
        xchg eax, ecx        ; EAX wird Hi-Quotient, altes EAX zurück, EDX bleibt
        div ebx              ; Quotient wird Lo-Quotient, EDX: Rest

Danach befindet sich der Quotient in ECX:EAX und der Rest in EDX.

3. Fall: Divisor und/oder Rest passen nicht in ein Register

Aufgabe:   353821814888 : 10000000000 = 35    Rest 3821814888
         = 0x52616C0000 / 0x02540BE400 = 0x23 Rest 0xE3CC4468

Assembler:

            push ebp                   ; vorsichtshalber
            mov edx, 52h               ; Dividend: EDX:EAX
            mov eax, 616C7068h
            mov ebp, 02h               ; Divisor: EBP:EBX
            mov ebx, 540BE400h
            push 0                     ; Quotient: [esp]
            push 0
            xor esi, esi               ; Zahl: EDI:ESI
            xor edi, edi
            mov ecx, 64                ; 64 Schleifendurchgänge: for (cx=64; cx>0; cx--)
        Schleife:
            shl eax, 1                 ; linkes Bit von Dividend nach Zahl
            rcl edx, 1
            rcl esi, 1
            rcl edi, 1
            cmp ebp, edi               ; Divisor (EBP:EBX) und Zahl (EDI:ESI) vergleichen
            je  S1                     ; ebp = edi
            jc  S2                     ; ebp < edi
            jmp Sprungmarke            ; ebp > edi
        S1:
            cmp ebx, esi
            ja Sprungmarke             ; ebx > esi (CY=0 & ZF=0)
        S2:
            sub esi, ebx               ; Zahl = Zahl-Divisor, Carry setzen
            sbb edi, ebp
            stc
        Sprungmarke:
            rcl dword ptr [esp], 1     ; Carry (0 oder 1) an Quotienten kleben.
            rcl dword ptr [esp+4], 1
            loop Schleife
            pop eax
            pop edx
            pop ebp

Danach steht der Quotient in EDX:EAX und der Rest in EDI:ESI.

Die Vorgehensweise beim 3. Fall entspricht der "Division ohne DIV". Näheres beim entsprechenden FAQ-Artikel.

Ralph 'rkhb' Bauer Aug 2008