0

On a IA-32 architecture how can i divide a signed number by 3 (e.g.) a value stored in 2 registers, edx:eax (a 64-bit value). I want to divide the whole value (64-bits) by 3, not only 32-bits, and store it in 2 registers.

I'm assuming this can only be done using shifts operations since imul only works for multiplying 32-bits numbers. But only found solutions for dividing by 2^n numbers.

How can i achieve this?

Diogo Soares
  • 130
  • 2
  • 8

1 Answers1

3

You can divide any length number by a 32 bit number with successive divides, using the remainder of the prior divide as the most significant 32 bits of the dividend for the next divide, similar to long hand division

Note I need to fix this code to handle negative divisors, but it should work with positive divisors and signed dividend.

Note this code rounds towards negative infinity: -10/3 : quotient = -4, remainder = +2. To handle negative divisors, the code could negate both divisor and dividend, then negate the remainder after.

        mov     ecx,000000003h  ;ecx = signed dvsr (must be positive)
        mov     edi,0fedcba98h  ;edi:esi = signed dvnd
        mov     esi,076543210h
        ;; inputs

        mov     eax,edi         ;eax = upper 32 bits dvnd
        cdq                     ; sign-extend that into EDX:EAX

        idiv    ecx
        test    edx,edx         ;br if sign rmdr == sign dvsr
        jns     short div0
        dec     eax             ;dec quot
        add     edx,ecx         ;rem += dvsr

div0:   mov     edi,eax         ;edi = upper 32 bits quot
        mov     eax,esi         ;eax = lower 32 bits dvnd
        div     ecx           
        mov     esi,eax         ;esi = lower 32 bits quot
;                               ;edx = remainder
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • But this doesnt seem to work, imagine u are doing a -20306/3... doing the same, but for simplification, ill do it with 16bit(representing 64-bit value): 10110000 10101110 ---> -20306 10110000 / 00000011 ---> -26 = 11100110 and 10101110 / 00000011 --> -27 = 11100101 so the resulting value will be 11100110 11100101 and 1110010110001111 its the value of 6768 wich is the correct result – Diogo Soares Oct 20 '18 at 16:45
  • 1
    Only the first divide is idiv, all the rest have to be udiv. – Aki Suihkonen Oct 20 '18 at 17:03
  • @DiogoSoares - I missed the signed part. I updated my answer that handles positive divisor and signed dividend. – rcgldr Oct 20 '18 at 22:38
  • @rcgldr thats pretty usefull actually, thank you. The code works pretty well, but i cant understand why this line make sense: `add edx, ecx` right after the `dec eax`. can you please enlighten me one more time – Diogo Soares Oct 20 '18 at 23:51
  • @DiogoSoares - The signed division instruction on an X86 rounds towards zero (the remainder is zero or has the same sign as the dividend), this creates problems in some cases, such as this one. The workaround adjusts the results so that the rounding is done towards negative infinity (the remainder is either zero or has the same sign as the divisor). For this example, the divisor is +3, and if the remainder is -1 or -2, rounding towards zero occurred, so the negative quotient is decremented, and the divisor is added to the remainder so that the remainder is positive. – rcgldr Oct 21 '18 at 09:31
  • 1
    @DiogoSoares - using the example in my answer, consider the case -10 / 3. The X86 idiv instruction will return quotient = -3, remainder = -1, since it rounded the quotient towards zero. However what is needed in this case is to round towards negative infinity, so -10/3 has a quotient of -4 with remainder +2, to get this result, the quotient of -3 is decremented to -4 and the remainder of -1 has 3 added to it to get a remainder of +2. – rcgldr Oct 21 '18 at 09:37