# How can I compare two quaternions for logical equality?

I'm trying to write some unit tests and realize I don't know how to compare quaternions. I need to know if two quaternions represent the same orientation (the object would be facing the same way). With a vector like position I'd simply compare the parts and check they are close enough, but for quaternions the values can be very different.

How can I compare two quaternions?

• I'm not sure if it is standard practice, but in e.g. Java and Unity the quaternions are stored as four float values. Simply compare these to eachother as outlined in these posts: answers.unity3d.com/questions/288338/… stackoverflow.com/questions/5803627/quaternion-comparision May 15, 2014 at 7:19
• @Tholle the user is also concerned with the impact of applying the quaternion to transform/rotate a 3D entity (i.e. pose-wise). Two different quaternions can achieve the same rotation (e.g. q and -q). The naive (computationally-wise) way would be to apply both quaternions to the same vector and see if their vector results are different.. May 15, 2014 at 7:52

If your two quaternions are q1 and q2, they represent the same rotation if either of these two conditions hold:

1. q1 is component wise approximately equal to q2 OR
2. q1 is component wise approximately equal to -q2

Knowing this, you can write a fairly simplistic equality tester that suits your goal.

• +1, one nitpick though, q and -q represent the same orientation (which was being asked for), but not the same rotation. This is crucial when interpolating. May 15, 2014 at 8:04
• @falstro, I think I understand what you mean: the rotation axes are inversed, but the argument angle is also negated between q and -q when represented as an angle-axis rotation operator. So, indeed, technically the effect of these rotations is the same, although the operators are not. And, yes, when SLERPING, one has to make sure q1 and q2 lie on the same hemisphere of the S3 hypersphere in order for the slerp to take the shortest path. May 15, 2014 at 9:30
• Exactly, when you execute either rotation, you'll end up with the same orientation, but interpolate it (whether you lerp or slerp or some other fancy interpolation), you'll see it is turning different ways. And yes, the angle argument is negated, but that's the same as 2pi-angle, so it's turning the long way around the negated axes. Sometimes this is what you want though; it's just something to be aware of, q1 dot q2 > 0 results in the short turn, q1 dot q2 < 0 takes the long turn. May 15, 2014 at 9:58
• is -q1 componentwise negation of q1?
– IC_
Dec 9, 2021 at 15:37
• @IC_ yes that's right. -q is { -q.x, -q.y, -q.z, -q.w } Aug 8, 2022 at 13:36

Just because it hasn't been mentioned. Since quaternions used for spatial orientation are always unit length (or should be), the following will also work.

$$\lvert q_1 \cdot q_2 \rvert > 1 - \epsilon$$

where $$\\epsilon\$$ (epsilon) is some fudge factor to allow for small errors due to limited floating point precision. If (and only if) both quaternions represent the same orientation then $$\q_1 = \pm q_2\$$, and thus $$\q_1 \cdot q_2 = \pm 1\$$. If you want to make sure they're the same rotation (rather than just orientation), then remove the absolute value.

• @bogglez true. Was hidden in the tl;dr text. :) May 15, 2014 at 16:46
• +1, pretty elegant and, perhaps even more numerically efficient than my answer (provided SIMD operations are used :) ). May 16, 2014 at 13:25
• What's the mathematical justification for this? Feb 8, 2016 at 15:37
• "Mathematical" (in quotes cause i m not a mathematician :) ) justification: Two unit length vectors have dot product (a.k.a. inner product) that is 0 if they are vertical to each other, 1*1=1 if they are pointing exactly the same direction, and 1*1*cos(phi) in the general case, with phi their angle...
– ntg
Sep 12, 2016 at 13:26
• this has the effect of throwing away all the sign information. im not sure that is accurate. q = |q| is not always true. Sep 2 at 18:16

Quaternions are stored as 4 floats or doubles, often called x, y, z and w, where the first three represent an axis and w the degree of rotation around that axis.

A naive approach would be to just compare those numbers of two quaternions for equality. However, because floating point calculations involve an error, you should at least use an error, often called eps (for epsilon) and compare each component like

    double const eps = 1e-12; // some error threshold
abs(quat1_x - quat2_x) < eps // similar enough?
// repeat for other values..


A better test would be to calculate the dot product of the two quaternions and test whether it is close to 1.0. You should look up the equation of quaternions with sin and cos and just dot two quaternions, then you should readily see why this works.

• i dont think this is 100% true. see teodron's answer. This allows the signs to be randomly flipped and still be equal. quaternions come in equiv pairs only. This method allows some false equivalents . Sep 1 at 20:05

Based on all the suggestions to use Dot and eps I found that using (in unity):

Mathf.Approximately(Mathf.Abs(Quaternion.Dot(transform.rotation, to)), 1.0f)


worked well without me having to make a decision for the size of eps.