🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

fixedpoint multiply?

Started by
4 comments, last by Nazghul 24 years, 8 months ago
Ok, here's the general algorthm in C++. Please note: this is the general case so please optimize it for your personal needs before you use it.

// I am assuming something like this
typedef long FixedPoint;
// assuming long is 32 bits
#define FP_INTEGER_PRECISION 16
#define FP_DECIMAL_PRECISION 16
#define FP_INTEGER_MASK 0xFF00
#define FP_DECIMAL_MASK 0x00FF

FixedPoint operator*(FixedPoint op1,FixedPoint op2)
{
FixedPoint op2int = op2 > FP_DECIMAL_PRECISION;
FixedPoint op2dec = op2 & FP_DECIMAL_MASK;
FixedPoint product = 0;
product = op1 * op2dec;
product = product > FP_DECIMAL_PRECISION;
product += op1 * op2high;
return product;
}

I haven't had time to test this code...so please respond here or email me if it has any errors. Also, please note that the potential for overflow is enormous. It is no different than multiplying 2 integers, but it is easy to forget that the highest 32 bit fixed point number (if 16x16 format is assumed) is the same as a 16 bit number, so 300*254 doesn't fit.

[This message has been edited by Xai (edited October 17, 1999).]

Advertisement
ASM is the only way to reliably multiply and divide fixed point numbers, because you can span 2 registers to make sure no accuracy is lost. You would have to twist my arm to get me to do fixed point multiply/divide using C/C++ code. Note that I'm not some fixed point lunatic (I've used it twice) and I would use floats 99% of the time. Only fixed point when you have to convert to integer often (like screen coordinates)
First of all, I think the problem is that "SHRD"...in ASM, the instruction is "SHR"(shift right). So that's probably what is wrong, however...I have my own function here that you can try:

fixed FixedMul(fixed num1, fixed num2)
{
fixed result;
bool sign=0;
asm
{
//num1 = ebx = eax
//num2 = ecx = edx
FixedMul_top:
mov ebx, num1
mov ecx, num2
xor eax, eax
xor edx, edx
//Check for negative numbers...
cmp ebx, 0
jg FixedMul_next1
mov sign, 1
neg ebx
FixedMul_next1:
cmp ecx, 0
jg FixedMul_next2
xor sign, 1
neg ecx
FixedMul_next2:
//num1.high * num2.high
mov eax, ebx
mov edx, ecx
shr eax, 16
shr edx, 16
mul edx
shl eax, 16
mov result, eax
//num1.high * num2.low
mov eax, ebx
mov dx, cx
shr eax, 16
mul edx
add result, eax
//num2.high * num1.low
xor eax, eax
mov edx, ecx
mov ax, bx
shr edx, 16
mul edx
add result, eax
//num1.low * num2.low
xor eax, eax
xor edx, edx
mov ax, bx
mov dx, cx
mul edx
shr eax, 16
add result, eax
//If sign variable is true, negate result
cmp sign, 0
jz FixedMul_bottom
neg result
FixedMul_bottom:
}
return (result);
}

It takes 2 32-bit fixed numbers, and returns a 32-bit fixed product. The precision is 16 bits, that is, shift right 16 times to get the integer value(but I'm sure you knew that). Optimize it further if you can/want to...let me know how it works for you or if you have questions.

asmlock@aol.com

asmlock - first of all, your fixed multiply is shitty complicated. Also, SHRD instruction is right and should be used.

Nazghul - this routine was written for Watcom C, so it has this strainght syntax not compatible with VC. You can use this procedure anyway:

fixed FixedMul(fixed f1, fixed f2) {
fixed result;
asm {
mov eax, f1
mov edx, f2
imul edx
shrd eax,edx,16
adc eax,0
mov result,eax
}
return result;
}

There is fixed point math unit on my homepage (written for pascal, but all procedures in asm). You can look there for more fixed point functions (like division, rounding, square roots etc...)

------------------
FlyFire/CodeX
http://codexorg.webjump.com

Hello everybody!

I need to multiply two fixedpoint variables.
The following snippet is from a friend. But it does'nt work in MS-Visual C++ 5:

Fixedpoint FixedMul(long num1, long num2);
#pragma aux FixedMul = \
"imul edx" \
"add eax, 8000h" \
"adc edx, 0" \
"shrd eax, edx, 16" \
parm caller [eax] [edx] \
value [eax] \
modify [eax edx];

Can anybody help me by converting the above snippet into plain C/C++/Pascal/Delphi.
Or just ASM without the "shrd"-command.
The Debugger stops on that line with "unknown command"...

Thanks!
Nazghul

You're right, SHRD is what to use...I didn't even check into it. I feel like an idiot now because I didn't even consider looking it up(I haven't needed to use anything beyond 32-bit multiplys...so I forgot about double-precision).
Anyway, what my function did was F.O.I.L. the top and bottom 16 bits of both numbers to avoid overflow, sorry about the complicated nature of it.

This topic is closed to new replies.

Advertisement