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:
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
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
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
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.
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.
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
; ??????????????????????????????????????????????????
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
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