Does anybody know how we can retrieve the fraction part of a division of two whole numbers using fixed point mathematics? I thought of a formula and it goes like this:

1. Divide dividend by the divisor. The quotient will be the whole part of the division.
2. (If there is a remainder) Divide the divisor by the remainder. Keep the quotient and the remainder.
3. (If there was a remainder) Divide 10 by the quotient of the division in the above stage.
4. The quotient of the second stage subtracted from the quotient of the above division will be the first digit of the fraction.

For example, divide 45 by 6:

1. 45 divided by 6 will yield the quotient 7. Keep this number.
2. The remainder of 45/6 = 3. Divide the divisor in the above stage (6) by 3 = 2, remainder = 0.
3. Divide 10 by the quotient of the above stage.10/2 = 5.
4. Subtract the remainder of the second stage from the quotient of the above stage 5-0 = 5.

So the result will be 7 (from the first stage) and with the fraction of .5 (from the 4th stage).


Or let?s say 68 divided by 14:

1. 68 divided by 14 yields the quotient of 4. Keep this number.
2. The remainder of 68/14 = 12. Divide the divisor of the above stage by 12. 14/12 yields the quotient of 1 and the remainder of 2.
3. Divide 10 by the quotient of the above stage which yields 10.
4. Subtract the remainder of the second stage from the quotient of the above stage which will yield 10-2=8.

Therefore the result will be 4 (from the first stage) and the fraction of 8 (from the 4th stage) = 4.8

However, the formula that I invented is not always accurate. There are some pitfalls to avoid and it won?t always yield the correct result. I was wondering if anybody knows of a better way to do this.

Here is the code that I have written for it:


  MOV    EAX , Dividend
  XOR    EDX , EDX
  MOV    EBX , Divisor
  DIV    EBX
  MOV    Quotient , EAX

  XOR    EAX , EAX
  TEST    EDX , EDX
  JZ      @NoFraction

  MOV    EAX , Divisor
  MOV    EBX , EDX
  XOR    EDX , EDX
  DIV    EBX

  MOV    ECX , EDX
  CMP    ECX , 1
  JNE    @NotOne
  XOR    ECX , ECX
  @NotOne:

  MOV    EBX , EAX
  MOV    EAX , 10
  XOR    EDX , EDX
  DIV    EBX

  SUB    EAX , ECX
  @NoFraction:
  MOV    Fraction , EAX
Posted on 2007-04-14 04:14:08 by XCHG
You should simply simulate what you have learned in grade school. Just continue dividing the remainder multiplied by 10 by the initial divisor until the remainder is either 0 or you have the required number of decimal places.

However, the result will definitely not be in a format which could easily be reused for other math operations. You may gain an additional perspective on the subject of fixed point math from the following:

http://www.ray.masmcode.com/fixmath.html

Raymond
Posted on 2007-04-14 20:23:09 by Raymond

pdec proto buf:DWORD,lo32:DWORD,hi32:DWORD,commas:DWORD,ljust:DWORD

power10 proc public uses ebx ecx n:dword
    mov eax,1
    mov ebx,n
    mov ecx,10
    or ebx,ebx
    jz done
  next:
    mul ecx
    sub ebx,1
    jnz next
  done:
    ret
power10 endp

pflt proc public uses ebx ecx edx esi buf:DWORD,num:DWORD,divisor:DWORD,commas:DWORD,ljust:DWORD,dig:DWORD
    local whole:dword,frac:dword
    mov eax,num
    sub edx,edx
    mov esi,buf
    div divisor
    mov ebx,edx
    INVOKE pdec,esi,eax,0,commas,ljust ;prints the "whole" part
    lstrlen esi
    lea esi,
    invoke power10,dig
    mul ebx
    div divisor
    mov edx,dig
    mov word ptr ,'.'  ;decimal point
    or dl,80h
    INVOKE pdec,esi,eax,0,0,edx  ;print the decimal part
    ret
pflt endp


Haven't used it much but seems to work OK.
Posted on 2007-04-15 02:39:26 by sinsi
Thank you Raymond. It is such a shame I had forgotten about that. Thank you sinsi.

I coded this function that returns the quotient of the division in EDX and the fraction part of the division in EAX just like a normal integer. For example, 654/32 = 20.4375. So EDX = 20 and EAX = 4375.

; ??????????????????????????????????????????????????
  __FixedDivision:
    ; QWORD __FixedDivision (DWORD Dividend, DWORD Divisor); StdCall;
    ; QWORD.DWORD#0 = Fraction
    ; QWORD.DWORD#1 = Quotient
    PUSH    EBX                                      ; Push the base index onto the stack
    PUSH    ECX                                      ; Push the count register onto the stack
    PUSH    ESI                                      ; Push the source index onto the stack
    PUSH    EDI                                      ; Push the destination index onto the stack
    PUSH    EBP                                      ; Push the base pointer onto the stack
    MOV    EBP , ESP                                ; Move the stack pointer to the base pointer
    SUB    ESP , 0x00000008                          ; Allocate 8 bytes of the stack space
    XOR    EAX , EAX                                ; Clear the accumulator to put into the stack space
    MOV    DWORD PTR , EAX              ; * = Quotient = 0
    MOV    DWORD PTR , EAX              ; * = Fraction = 0 (We have 0.0 for now)
    MOV    ESI , DWORD PTR               ; *ESI = The parameter
    TEST    ESI , ESI                                ; We can't go on with a dividend equal to zero
    JZ      .EP                                      ; Jump to the end of the procedure if Dividend is zero
    MOV    EDI , DWORD PTR ; Divisor    ; *EDI = The parameter
    TEST    EDI , EDI                                ; We can not divide by zero
    JZ      .EP                                      ; Jump to the end of the procedcure if Divisor is zero
    MOV    ECX , 0x00000009                          ; We can only have 9 digits of fraction in the result
    MOV    EAX , ESI                                ; Get the Dividend in EAX
    XOR    EDX , EDX                                ; Set the High Order DWORD of the Dividend to zero
    DIV    EDI                                      ; Divide the Dividend by the Divisor
    MOV    DWORD PTR , EAX              ; Get the Quotient in
    TEST    EDX , EDX                                ; See if there is a remainder
    JZ      .EP                                      ; Jump to the end of the procedure if there are no fractions
    LEA    ESI ,                         ; *ESI = Pointer to the Fraction part in the stack
    .GetFraction:                                    ; Here we should get the fraction (EDX*10/Divisor)
      LEA    EAX ,                       ; EAX = Remainder, Multiply EAX by 10, Step 1
      LEA    EAX ,                 ; Multiply the remainder by 10, Step 2
      XOR    EDX , EDX                              ; Clear the High Order DWORD of the Dividend
      DIV    EDI                                    ; EAX = The next digit of the fraction part of the division
      TEST    EAX , EAX                              ; See if the fraction part is zero
      JZ      .EP                                    ; Jump to the end of the procedure if yes (We don't want zeros)
      MOV    EBX , DWORD PTR                   ; Get the previous fraction in EBX
      ADD    EBX , EBX                              ; Multiply the previous fraction by 10, Step 1
      LEA    EBX ,                 ; Multiply the previous fraction by 10, Step 2
      ADD    EBX , EAX                              ; Put the new fraction in the previous fraction part
      MOV    DWORD PTR , EBX                  ; Put the new fraction in the stack
      DEC    ECX                                    ; Decrement the number of fraction digits we should get
      JNZ    .GetFraction                            ; Keep extracting the fraction part while ECX > 0
    .EP:                                              ; End of the procedure
      MOV    EDX , DWORD PTR             ; *EDX holds the quotient now
      MOV    EAX , DWORD PTR             ; *EAX holds the fraction part now
      ADD    ESP , 0x00000008                        ; Deallocate 8 bytes of the stack space
      POP    EBP                                    ; Restore the base pointer
      POP    EDI                                    ; Restore the destination index
      POP    ESI                                    ; Restore the source index
      POP    ECX                                    ; Restore the count register
      POP    EBX                                    ; Restore the base index
    RET    0x08                                      ; Return to the calling procedure
                                                      ; And sweep 2 parameters off the stack
; ??????????????????????????????????????????????????
Posted on 2007-04-16 01:41:10 by XCHG
XCHG

Sorry for the delay. I've been on the road for the past few days (migrating back up north).

In your .GetFraction: section, testing the content of EAX is the wrong thing to do (i.e. try it with 12/11 as an example). Instead, you should be testing the content of EDX (the remainder) after you have updated the fraction part and just before you decrement the counter for the number of decimal places.

Raymond
Posted on 2007-04-19 13:22:33 by Raymond