I'm reading pbrt and trying to better understanding the return value of Dot(). The Dot() function takes two quaternions and returns their inner product. Also note, internally, when it comes to the inner product, a quaternion is treated as a 4D vector. I know when two vectors, or in this case the two quaternions, are parallel, then their inner product is equal to 1.0.

Things get little confusing for me when I read the implementation of Slerp()

Quaternion Slerp(float t, const Quaternion &q1,
                 const Quaternion &q2) {
    float cosTheta = Dot(q1, q2);
    if (cosTheta > .9995){
        return Normalize((1.f - t) * q1 + t * q2);
    } else {
      // ...

I don't quite understand the if(cosTheta > .9995) part. If two quaternions are parallel, then their inner product is 1.0, correct? The only reason I can think of for having a greater-than operator is because Slerp() is meant to work with quaternions and unit quaternions. Is that right?

My ultimate goal is to replace if(cosTheta > .9995) with something more accurate, such as:

if( approxEqual(cosTheta, 1.0) or cosTheta > 1.0 ){ ... }

approxEqual computes whether the two arguments are ap­prox­i­mately equal based on their relative difference.

Would my new if statement be mathematically correct?

In the book Slerp() is described as:

$$ slerp(q1,q2,t) = \frac{ q1 \sin((1-t) \theta) + q2 \sin(t\theta) }{ \sin \theta } $$

...given the quaternions to interpolate between, $q1$ and $q2$, denote by \theta the angle between them. Then, given a parameter value t ∈[0,1], we'd like to find the intermediate quaternion $q'$ that makes angle $\theta' = \theta t$ between it and $q1$, along the path from $q1$ to $q2$. --page 95

The implementation of the Slerp() function checks to see if the two quaternions are nearly parallel, in which case it uses regular linear interpolation of quaternion components in order to avoid numerical instability. Otherwise, ...

  • $\begingroup$ When two vectors are parallel, their inner product is equal to the product of their lengths. Perhaps you're thinking of unit vectors? Also, what is Slerp supposed to compute? And what is $f$? Offhand my guess is that the if statement has to do with numerical stability, but I don't have enough information to know for sure. $\endgroup$ Dec 23, 2011 at 2:14
  • $\begingroup$ @QiaochuYuan f is nothing. It just means that the number is float. I removed it. $\endgroup$
    – Arlen
    Dec 23, 2011 at 2:39
  • $\begingroup$ @QiaochuYuan As far as the inner product, yes I was thinking of unit vector, but I'm not sure if pbrt makes the same assumption. I also added the definition of slerp from the book. $\endgroup$
    – Arlen
    Dec 23, 2011 at 2:41
  • 3
    $\begingroup$ Looks like the explanation is right there in the book: if the quaternions are nearly parallel, the algorithm uses linear interpolation to avoid numerical instability. $\endgroup$ Dec 23, 2011 at 3:07
  • $\begingroup$ @QiaochuYuan so you're saying my if statement would work too? As far as I can tell mine is better than using the magic number 0.9995. $\endgroup$
    – Arlen
    Dec 23, 2011 at 3:21

1 Answer 1


The numerical instability the code is meant to avoid is not one that occurs only if $\cos\theta$ is calculated to be greater than $1$ due to rounding; it occurs already if $\cos\theta$ is close to $1$, since the exact formula uses division by $\sin\theta=\sqrt{1-\cos^2\theta}$. So the answer is, no, you shouldn't replace that line; it's there for a good reason. You can experiment with increasing the bound to see whether it's been optimally chosen, but you shouldn't replace it by $1$.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .