Fast Distance Threshold Formula AS3, C++, Java, Python
Posted November 17, 2010 by Nick Vogt in Programming
Most game programmers are familiar with the distance (magnitude) equation and how inefficient it is. Using a square root is a costly function that usually can't be afforded many times per frame. Here is a much more efficient distance equation for situations in which you want to check the distance against a threshold (such as determining if two bounding spheres collide).
Here is the original distance formula:
Distance = Sqrt( (x2 - x1)² + (y2 - y1)² )
And here it is expanded into simple multiplication :
Distance * Distance = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
(For 3D be sure to add the z part of the formula)
Using simple multiplication results in extremely fast calculations. Here are some performance tests I ran in Actionscript 3. Other programming languages should be similar. I started with the traditional distance equation:
Looping the above code 10,000,000 iterations resulted in a total process time of 4387 milliseconds. Now here is the simple multiplication version:
The above only took 172 milliseconds!
Note: For both tests I initialized the required variables before any timing, to eliminate initialization time from the test.
I'm sure most game programmers have used the above formula or something similar before, but for those still struggling I hope it will help. Unfortunately it doesn't help as much when you need to use the distance to scale another value (such as using distance to determine how much splash damage to take), as you will be scaling it exponentially! (you can use threshold steps to work around this of course)
Here is the original distance formula:
Distance = Sqrt( (x2 - x1)² + (y2 - y1)² )
And here it is expanded into simple multiplication :
Distance * Distance = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
(For 3D be sure to add the z part of the formula)
Using simple multiplication results in extremely fast calculations. Here are some performance tests I ran in Actionscript 3. Other programming languages should be similar. I started with the traditional distance equation:
dist = Math.sqrt(Math.pow(x2 - x1,2) + Math.pow(y2 - y1,2));
if(dist < minDist)
{
// Perform action
}
if(dist < minDist)
{
// Perform action
}
Looping the above code 10,000,000 iterations resulted in a total process time of 4387 milliseconds. Now here is the simple multiplication version:
dist = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
if(dist < minDist * minDist)
{
// Perform action
}
if(dist < minDist * minDist)
{
// Perform action
}
The above only took 172 milliseconds!
Note: For both tests I initialized the required variables before any timing, to eliminate initialization time from the test.
I'm sure most game programmers have used the above formula or something similar before, but for those still struggling I hope it will help. Unfortunately it doesn't help as much when you need to use the distance to scale another value (such as using distance to determine how much splash damage to take), as you will be scaling it exponentially! (you can use threshold steps to work around this of course)
| Series | ActionScript 3 Tutorials |
|---|---|
| Tags | actionscript 3 tutorial |
Comment on this post
Legacy Comments (4)
futureResident | February 6, 2011 | 12:43 AM PST
a = X1 - X2;
b = Y1 - Y2;
sqNum = ((a * a) + (b * b)) + .208;
if (sqNum < 1) {
initVal = 1 / sqNum;
invVal = true;
} else {
initVal = sqNum;
invVal = false;
}
apprxInit = initVal;
if (apprxInit > 7) {
if (apprxInit < 32768) {
if (apprxInit < 128) {
if (apprxInit < 32) {
apprxInit >>= 2;
if (apprxInit < 4) apprxInit++;
} else {
apprxInit >>= 3;
}
} else {
if (apprxInit < 2048) {
if (apprxInit < 512) {
apprxInit >>= 4;
} else {
apprxInit >>= 5;
}
} else {
if (apprxInit < 8096) {
apprxInit >>= 6;
} else {
apprxInit >>= 7;
}
}
}
b = Y1 - Y2;
sqNum = ((a * a) + (b * b)) + .208;
if (sqNum < 1) {
initVal = 1 / sqNum;
invVal = true;
} else {
initVal = sqNum;
invVal = false;
}
apprxInit = initVal;
if (apprxInit > 7) {
if (apprxInit < 32768) {
if (apprxInit < 128) {
if (apprxInit < 32) {
apprxInit >>= 2;
if (apprxInit < 4) apprxInit++;
} else {
apprxInit >>= 3;
}
} else {
if (apprxInit < 2048) {
if (apprxInit < 512) {
apprxInit >>= 4;
} else {
apprxInit >>= 5;
}
} else {
if (apprxInit < 8096) {
apprxInit >>= 6;
} else {
apprxInit >>= 7;
}
}
}
futureResident | February 6, 2011 | 12:43 AM PST
} else {
if (apprxInit < 8388608) {
if (apprxInit < 524288) {
if (apprxInit < 131072) {
apprxInit >>= 8;
} else {
apprxInit >>= 9;
}
} else {
if (apprxInit < 2097152) {
apprxInit >>= 10;
} else {
apprxInit >>= 11;
}
}
} else {
if (apprxInit < 134217728) {
if (apprxInit < 33554432) {
apprxInit >>= 12;
} else {
apprxInit >>= 13;
}
} else {
apprxInit >>= 14;
}
}
}
apprxRoot = (apprxInit + initVal / apprxInit) * 0.5;
} else if (apprxInit < 2) apprxRoot = initVal * 0.5 + 0.5
else apprxRoot = initVal * 0.25 + 1;
if (invVal) { apprxRoot = 1 / apprxRoot; }
c = int(apprxRoot);
if (apprxInit < 8388608) {
if (apprxInit < 524288) {
if (apprxInit < 131072) {
apprxInit >>= 8;
} else {
apprxInit >>= 9;
}
} else {
if (apprxInit < 2097152) {
apprxInit >>= 10;
} else {
apprxInit >>= 11;
}
}
} else {
if (apprxInit < 134217728) {
if (apprxInit < 33554432) {
apprxInit >>= 12;
} else {
apprxInit >>= 13;
}
} else {
apprxInit >>= 14;
}
}
}
apprxRoot = (apprxInit + initVal / apprxInit) * 0.5;
} else if (apprxInit < 2) apprxRoot = initVal * 0.5 + 0.5
else apprxRoot = initVal * 0.25 + 1;
if (invVal) { apprxRoot = 1 / apprxRoot; }
c = int(apprxRoot);
futureResident | February 6, 2011 | 12:38 AM PST
Man.. damn... I saw this and plopped a few bricks.
I've been working on the exact same problem in AS3, and had thought about breaking the formula apart and looking for a better way, but was.. well, too lazy...
I plugged your code into my benchmark program and found it was 96% slower then the method I arrived at. I thought for sure this would be quicker, but there was 4% to be gained somewhere.
I was looking into using bitwise methods instead. Your code made for a very cool comparison. I want to see the function that puts either of these to shame.
I've been working on the exact same problem in AS3, and had thought about breaking the formula apart and looking for a better way, but was.. well, too lazy...
I plugged your code into my benchmark program and found it was 96% slower then the method I arrived at. I thought for sure this would be quicker, but there was 4% to be gained somewhere.
I was looking into using bitwise methods instead. Your code made for a very cool comparison. I want to see the function that puts either of these to shame.
Rydik | February 1, 2011 | 12:39 PM PST
Awesome! I have never really had to worry about performance until recently, and had never considered the iterations required for sqrt. I used this new equation and had a huge performance boost.
Also if the distance checking statement is in a loop it may save even more time to calculate minDist*minDist outside the loop rather than 10,000,000 times in the loop. Thanks!
Also if the distance checking statement is in a loop it may save even more time to calculate minDist*minDist outside the loop rather than 10,000,000 times in the loop. Thanks!
