🔒 Locked
Highly optimized code for distance
Advertisement
Original Post
Does somebody knows how to make a high optimized code to determine distance between 2 points (3d point -> x,y,z).
I though of using an inline function with assembly but applying a formula like this in assembly is hard to me (i''m not asm expert !):
for 2 points A(Ax,Ay,Az) & B(Bx,By,Bz)
distance² = (Ax+Bx)² + (Ay+By)² + (Az+Bz)²
and then we take the distance sqrt()
Thank you for any help...
Nope, that's as fast as you'll get it. Unless you can get it in SSE or something, but I question the value of doing that.
Instead of optimizing the distance formula, the usual trick is to work in "squares-of-distances". If you're only interested in relative distances, then instead of:
try:
See? The logic is the same, but it's a multiply instead of square root.
Edit: Not even a multiply if you're using a constant on the right
codeka.com - Just click it.
[edited by - Dean Harding on January 15, 2003 6:36:42 AM]
Instead of optimizing the distance formula, the usual trick is to work in "squares-of-distances". If you're only interested in relative distances, then instead of:
if( distance < 2 )
{
// do something
}try:
if( distance2 < 4 )
{
// do something
}See? The logic is the same, but it's a multiply instead of square root.
Edit: Not even a multiply if you're using a constant on the right
If I had my way, I'd have all of you shot!
codeka.com - Just click it.
[edited by - Dean Harding on January 15, 2003 6:36:42 AM]
Actually, it''s :
d^2 = (Ax - Bx)^2 + (Ay - By)^2 + (Az - Bz)^2
(note the - sign instead of +)
ASM won''t help you here. It would be even faster to use a C++ inline function since it may be easier for the compiler to interleave the generated opcodes with opcodes that are outside the function, which is more pipeline and super scalar friendly.
Just forget about ASM and use an inline function.
The only optimizations I can think of are these ones (remember the square root is the bottleneck here) :
- Use a custom sqrt() function. Some aproximations can be computed faster (Quake 2 code contains such a function, if memory deserves).
- Do not compute the square root. If you don''t need the actual distance and you just want to compare distances, you can use the squared distances (since A^2 > B^2 and A > 0 and B > 0 => A > B).
PS : since my english sucks and I''ve noticed you''re french, I can explain it in french if you want.
d^2 = (Ax - Bx)^2 + (Ay - By)^2 + (Az - Bz)^2
(note the - sign instead of +)
ASM won''t help you here. It would be even faster to use a C++ inline function since it may be easier for the compiler to interleave the generated opcodes with opcodes that are outside the function, which is more pipeline and super scalar friendly.
Just forget about ASM and use an inline function.
The only optimizations I can think of are these ones (remember the square root is the bottleneck here) :
- Use a custom sqrt() function. Some aproximations can be computed faster (Quake 2 code contains such a function, if memory deserves).
- Do not compute the square root. If you don''t need the actual distance and you just want to compare distances, you can use the squared distances (since A^2 > B^2 and A > 0 and B > 0 => A > B).
PS : since my english sucks and I''ve noticed you''re french, I can explain it in french if you want.
quote:
Original post by Prosper/LOADED
d^2 = (Ax - Bx)^2 + (Ay - By)^2 + (Az - Bz)^2
(note the - sign instead of +)
ASM won't help you here. It would be even faster to use a C++ inline function since it may be easier for the compiler to interleave the generated opcodes with opcodes that are outside the function, which is more pipeline and super scalar friendly.
Just forget about ASM and use an inline function.
The only optimizations I can think of are these ones (remember the square root is the bottleneck here) :
- Use a custom sqrt() function. Some aproximations can be computed faster (Quake 2 code contains such a function, if memory deserves).
- Do not compute the square root. If you don't need the actual distance and you just want to compare distances, you can use the squared distances (since A^2 > B^2 and A > 0 and B > 0 => A > B).
PS : since my english sucks and I've noticed you're french, I can explain it in french if you want.
he could use left shift for the ^2 to make it go faster
[edited by - xaxa on January 15, 2003 7:16:19 AM]
Left shift won''t help here. A left shift one step is multiplication by two. Although you can use the shift operator and addition multiple times to achieve a square, it will be WAY slower than a single multiplication. Also, if the datatypes in use are floatingpoint types, shifts won''t work at all.
quote:
Original post by xaxa
he could use left shift for the ^2 to make it go faster
Please explain how. Left shift is commonly used to multiply a number by a power of two but I fail to see how you can compute X^2 (ie. X*X) with it.
quote:
Original post by Prosper/LOADED
Please explain how. Left shift is commonly used to multiply a number by a power of two but I fail to see how you can compute X^2 (ie. X*X) with it.
Yes sorry, I was wrong. It only works for integer numbers power of two.
(256)^2 = (100000000)<<8 = 10000000000000000
So i guess it's useless in this case.
EDIT: I mean power (not multiple)
[edited by - xaxa on January 15, 2003 8:16:06 AM]
Does this need to be exact?
You can get an upper bound on the distance by summing the absolute difference between components (manhattan or taxicab distance).
> Unless you can get it in SSE or something, but I question the value of doing that.
> Just forget about ASM and use an inline function.
hehe...
VC7:
slapped together 3DNow! code:
a bit more than 2x as fast on my Athlon XP. Similar gains are possible with SSE, though it''s a bit more clumsy for lack of an accumulate instruction.
If you can''t avoid the sqrt, calculate it as x * rsqrt(x):
- on Athlons: pfrsqrt + pfmul (7 clock latency)
- otherwise, use a clever bit of code credited to Carmack:
What this does in a nutshell is approximate via one iteration of Newton''s method (the line with the magic number computes an initial guess, important for convergence).
HTH
Jan
500x2
You can get an upper bound on the distance by summing the absolute difference between components (manhattan or taxicab distance).
> Unless you can get it in SSE or something, but I question the value of doing that.
> Just forget about ASM and use an inline function.
hehe...
VC7:
fld DWORD PTR x1
fsub DWORD PTR x2
fld DWORD PTR y1
fsub DWORD PTR y2
fld DWORD PTR z1
fsub DWORD PTR z2
fld ST(0)
fmul ST(0), ST(1)
fld ST(2)
fmul ST(0), ST(3)
faddp ST(1), ST(0)
fld ST(3)
fmul ST(0), ST(4)
faddp ST(1), ST(0)
fstp ST(3)
fstp ST(0)
fstp ST(0)
slapped together 3DNow! code:
movq mm0, [x1] ; y1 x1
movq mm1, [x2] ; y2 x2
movq mm2, [z1] ; z2 z1
pfsub mm0, mm1 ; dy dx
pfnacc mm2, mm2 ; dz dz
pfmul mm0, mm0 ; dy^2 dx^2
pfmul mm2, mm2 ; dz^2 dz^2
pfacc mm0, mm0 ; dx^2+dy^2 dx^2+dy^2
pfadd mm0, mm2 ; dist^2 dist^2
a bit more than 2x as fast on my Athlon XP. Similar gains are possible with SSE, though it''s a bit more clumsy for lack of an accumulate instruction.
If you can''t avoid the sqrt, calculate it as x * rsqrt(x):
- on Athlons: pfrsqrt + pfmul (7 clock latency)
- otherwise, use a clever bit of code credited to Carmack:
float InvSqrt (float x)
{
float xhalf = 0.5f*x;
int i = *(int*)&x
i = 0x5f3759df - (i >> 1);
x = *(float*)&i
x = x*(1.5f - xhalf*x*x);
return x;
}
What this does in a nutshell is approximate via one iteration of Newton''s method (the line with the magic number computes an initial guess, important for convergence).
HTH
Jan
500x2
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement