Saturday, August 7, 2021

Optimization trick: avoid division and square root

It is well known that division and square root is usually slower than add and multiply (usually sqrt is much slower than multiply). Therefore, we should avoid square root whenever we can. 

Collision detection performance is important in many games where it needs to be computed a lot. This post discusses how to detect collision between two circles. 

The distance between two points is given by the following algorithm (source: https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection):

var circle1 = {radius: 20, x: 5, y: 5};
var circle2 = {radius: 12, x: 10, y: 5};

var dx = circle1.x - circle2.x;
var dy = circle1.y - circle2.y;
var distance = Math.sqrt(dx * dx + dy * dy);

if (distance < circle1.radius + circle2.radius) {
    // collision detected!
}

However, for the purposes of collision detection, the Math.sqrt operation is in fact unnecessary, because we can just compare the squares instead of the actual values, like this (source: https://stackoverflow.com/questions/697188/fast-circle-collision-detection):

private static boolean isCollision(Point2D.Double p1, double r1, Point2D.Double p2, double r2)
{
    final double a = r1 + r2;
    final double dx = p1.x - p2.x;
    final double dy = p1.y - p2.y;
    return a * a > (dx * dx + dy * dy);
}

As you can see, the calculation of dx * dx and dy * dy is the same, but instead of square rooting it and then comparing it to the threshold, we instead square the threshold and compare it to that. 

This effectively trades a sqrt operation for a multiply operation which is usually much faster.