Normalize Vectors Before Performing Dot Product?

Viewed 1597

I have a classic exercise which asks me to check if a character was attacked from the back (backstab or projectile). I know I can use the dot product for this, I was just wondering if I had to normalize the vectors first or if it didn't matter.

My reasoning was if the vector coordinates were huge numbers, if it would cause my dot product to overflow or underflow.

float dotProd(Vector3& P, Vector3& Q)
{
     return P.x * Q.x + P.y * Q.y + P.z * Q.z;
}

bool sneakAttack(Vector3& proj, Vector3& player)
{
    if(dotProd(proj, player) > 0)
        return true;
    else
        return false;
}
2 Answers

You are right that in principle, some coordinates could be so large that the dot product computation overflows.

However, the representable range of finite 32-bit floats is enormous, with a maximum of roughly 3 × 10^38 (Wikipedia). For instance supposing your vectors are in units of centimeters, that's enough to compute dot products of vectors stretching from Pluto to the Sun (distance of about 6 × 10^14 cm) and still not get close to overflowing. By the "You aren't gonna need it" (YAGNI) principle, it is not worth writing the routine to handle inputs larger than that, unless it is specifically known that some inputs actually have interstellar magnitudes. Also, normalizing adds runtime cost, so I'd say it is preferable to not do it unless practically necessary.

Broadly, just about any software that does arithmetic on floats or ints could have overflows in extreme cases. It would be a heavy burden if overflow error handling had to be considered around every operation. Instead, it is typical that software is developed considering inputs to stay within some reasonable range, without formally proving what the supported range is or handling out-of-range inputs, unless the application requires it.

Normalization could make your code more likely to overflow.

Suppose vector P has length A and Q has length B. To normalize the first vector, the usual approach divides each coordinate by A, which is obtained by first calculating A2, which happens to equal P·P. There is the problem. If A >= B, then P·P >= |P·Q|. So if P·Q overflows, then P·P overflows. Before overflow becomes an issue for your dot product, it has already become an issue for normalization.

There is another danger to watch out for, potentially another reason to discover the range of values you need to handle. Consider the case where

  • P.x = 1024,
  • P.y = 0.2,
  • P.z = 1024,

  • Q.x = 1024,
  • Q.y = 0.2, and
  • Q.z = -1024.

Mathematically, the dot product in this case is P.y * Q.y. However (using ^ to denote exponentiation) your dot product is calculated as (2^20 + 0.04) - 2^20. The difference in order of magnitude of 2^20 and 0.04 is too much for a 23-bit mantissa. So their sum evaluates to 2^20. Subtracting 2^20 leaves no indication of what the sign of P.y * Q.y was. Normalization does not help here, as it only shifts the problem to lower powers of 2. Solving this problem potentially could solve the overflow threat as a side-effect.

Related