Dividing 64-bit unsigned integersAssembler/80386

Here is a division routine for dividing two 64-bit unsigned integers. I derived it by modifying some old 16-bit code for dividing 32-bit integers that I did several years ago for a Turbo-Pascal replacement library. If a 64-bit signed integer division is needed, appropriate shell code for this routine can easily be written.

;
; _ulldiv divides two unsigned long long numbers, the dividend and the divisor
; resulting in a quotient and a remainder.
;
; input:
;   edx:eax = dividend
;   ecx:ebx = divisor
;
; output:
;   edx:eax = quotient of division of dividend by divisor
;   ecx:ebx = remainder of division of dividend by divisor
;
; destroys:
;   eflags
;

PROC    _ulldiv NEAR

             test    ecx, ecx           ; divisor > 2^32-1 ?
             jnz     $big_divisor       ; yes, divisor > 32^32-1
             cmp     edx, ebx           ; only one division needed ? (ecx = 0)
             jb      $one_div           ; yes, one division sufficient
             mov     ecx, eax           ; save dividend-lo in ecx
             mov     eax, edx           ; get dividend-hi
             xor     edx, edx           ; zero extend it into edx:eax
             div     ebx                ; quotient-hi in eax
             xchg    eax, ecx           ; ecx = quotient-hi, eax =dividend-lo
$one_div:    div     ebx                ; eax = quotient-lo
             mov     ebx, edx           ; ebx = remainder-lo
             mov     edx, ecx           ; edx = quotient-hi(quotient in edx:eax)
             xor     ecx, ecx           ; ecx = remainder-hi (rem. in ecx:ebx)
             ret
$big_divisor:push    esi                ; save temp
             push    edi                ;  variables
             push    edx                ; save
             push    eax                ;  dividend
             mov     esi, ebx           ; divisor now in
             mov     edi, ecx           ;  edi:ebx and ecx:esi
             shr     edx, 1             ; shift both
             rcr     eax, 1             ;  divisor and
             ror     edi, 1             ;   and dividend
             rcr     ebx, 1             ;    right by 1 bit
             bsr     ecx, ecx           ; ecx = number of remaining shifts
             shrd    ebx, edi, CL       ; scale down divisor and
             shrd    eax, edx, CL       ;   dividend such that divisor
             shr     edx, CL            ;    less than 2^32 (i.e. fits in ebx)
             rol     edi, 1             ; restore original divisor (edi:esi)
             div     ebx                ; compute quotient
             pop     ebx                ; get dividend lo-word
             mov     ecx, eax           ; save quotient
             imul    edi, eax           ; quotient * divisor hi-word (low only)
             mul     esi                ; quotient * divisor lo-word
             add     edx, edi           ; edx:eax = quotient * divisor
             sub     ebx, eax           ; dividend-lo - (quot.*divisor)-lo
             mov     eax, ecx           ; get quotient
             pop     ecx                ; restore dividend hi-word
             sbb     ecx, edx           ; subtract divisor * quot. from dividend
             sbb     edx, edx           ; 0 if remainder > 0, else FFFFFFFFh
             and     esi, edx           ; nothing to add
             and     edi, edx           ;  back if remainder positive
             add     ebx, esi           ; correct remaider
             adc     ecx, edi           ;  and quotient if
             add     eax, edx           ;   necessary
             xor     edx, edx           ; clear hi-word of quot (eax<=FFFFFFFFh)
             pop     edi                ; restore temp
             pop     esi                ;  variables
             ret

ENDP    _ulldiv
Gem writer: Norbert Juffa
last updated: 1998-03-16