| // Copyright ©2018 The Gonum Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package quat |
| |
| import ( |
| "math" |
| "testing" |
| ) |
| |
| var expTests = []struct { |
| q Number |
| want Number |
| }{ |
| {q: Number{}, want: Number{Real: 1}}, |
| // Expected velues below are from pyquaternion. |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, |
| want: Number{Real: -0.43643792124786496, Imag: 1.549040352371697, Jmag: 1.549040352371697, Kmag: 1.549040352371697}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.42389891174348104, Imag: 0, Jmag: 1.8986002490721081, Kmag: 1.8986002490721081}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, |
| want: Number{Real: 1.4686939399158851, Imag: 0, Jmag: 0, Kmag: 2.2873552871788423}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, |
| want: Number{Real: -0.16055653857469052, Imag: 0.569860099182514, Jmag: 0.569860099182514, Kmag: 0.569860099182514}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.15594369476537437, Imag: 0, Jmag: 0.6984559986366083, Kmag: 0.6984559986366083}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, |
| want: Number{Real: 0.5403023058681398, Imag: 0, Jmag: 0, Kmag: 0.8414709848078965}, |
| }, |
| } |
| |
| func TestExp(t *testing.T) { |
| t.Parallel() |
| const tol = 1e-14 |
| for _, test := range expTests { |
| got := Exp(test.q) |
| if !equalApprox(got, test.want, tol) { |
| t.Errorf("unexpected result for Exp(%v): got:%v want:%v", test.q, got, test.want) |
| } |
| } |
| } |
| |
| var logTests = []struct { |
| q Number |
| want Number |
| }{ |
| {q: Number{}, want: Number{Real: -inf}}, |
| // Expected velues below are from pyquaternion. |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.6931471805599453, Imag: 0.6045997880780728, Jmag: 0.6045997880780728, Kmag: 0.6045997880780728}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.5493061443340548, Imag: 0, Jmag: 0.6755108588560398, Kmag: 0.6755108588560398}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, |
| want: Number{Real: 0.3465735902799727, Imag: 0, Jmag: 0, Kmag: 0.7853981633974484}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.5493061443340548, Imag: 0.906899682117109, Jmag: 0.906899682117109, Kmag: 0.906899682117109}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.3465735902799727, Imag: 0, Jmag: 1.1107207345395915, Kmag: 1.1107207345395915}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, |
| want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1.5707963267948966}, |
| }, |
| } |
| |
| func TestLog(t *testing.T) { |
| t.Parallel() |
| const tol = 1e-14 |
| for _, test := range logTests { |
| got := Log(test.q) |
| if !equalApprox(got, test.want, tol) { |
| t.Errorf("unexpected result for Log(%v): got:%v want:%v", test.q, got, test.want) |
| } |
| } |
| } |
| |
| var powTests = []struct { |
| q, r Number |
| want Number |
| }{ |
| {q: Number{}, r: Number{}, want: Number{Real: 1}}, |
| // Expected velues below are from pyquaternion. |
| // pyquaternion does not support quaternion powers. |
| // TODO(kortschak): Add non-real r cases. |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, |
| want: Number{Real: -2, Imag: 2, Jmag: 2, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, |
| want: Number{Real: -1, Imag: 0, Jmag: 2, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 2}, |
| want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, |
| want: Number{Real: -3, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 2}, |
| want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 2}, |
| want: Number{Real: -1, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, |
| want: Number{Real: -8.728144138959564, Imag: -0.7527136547040768, Jmag: -0.7527136547040768, Kmag: -0.7527136547040768}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, |
| want: Number{Real: -5.561182514695044, Imag: 0, Jmag: 0.5556661490713818, Kmag: 0.5556661490713818}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: math.Pi}, |
| want: Number{Real: -2.320735561810013, Imag: 0, Jmag: 0, Kmag: 1.8544983901925216}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, |
| want: Number{Real: 1.2388947209955585, Imag: -3.162774128856231, Jmag: -3.162774128856231, Kmag: -3.162774128856231}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: math.Pi}, |
| want: Number{Real: 0.6552860151073727, Imag: 0, Jmag: -2.0488506614051922, Kmag: -2.0488506614051922}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: math.Pi}, |
| want: Number{Real: 0.22058404074969779, Imag: 0, Jmag: 0, Kmag: -0.9753679720836315}, |
| }, |
| |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, |
| want: Number{Real: -8, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, |
| want: Number{Real: -5, Imag: 0, Jmag: 1, Kmag: 1}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 3}, |
| want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, |
| want: Number{Real: 0, Imag: -3, Jmag: -3, Kmag: -3}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: Number{Real: 3}, |
| want: Number{Real: 0, Imag: 0, Jmag: -2, Kmag: -2}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: Number{Real: 3}, |
| want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: -1}, |
| }, |
| } |
| |
| func TestPow(t *testing.T) { |
| t.Parallel() |
| const tol = 1e-14 |
| for _, test := range powTests { |
| got := Pow(test.q, test.r) |
| if !equalApprox(got, test.want, tol) { |
| t.Errorf("unexpected result for Pow(%v, %v): got:%v want:%v", test.q, test.r, got, test.want) |
| } |
| } |
| } |
| |
| var powRealTests = []struct { |
| q Number |
| r float64 |
| want Number |
| }{ |
| {q: Number{}, r: 0, want: Number{Real: 1}}, |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: 2, |
| want: Number{Real: -2, Imag: 2, Jmag: 2, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: 2, |
| want: Number{Real: -1, Imag: 0, Jmag: 2, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: 2, |
| want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: 2, |
| want: Number{Real: -3, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: 2, |
| want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: 2, |
| want: Number{Real: -1, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: math.Pi, |
| want: Number{Real: -8.728144138959564, Imag: -0.7527136547040768, Jmag: -0.7527136547040768, Kmag: -0.7527136547040768}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: math.Pi, |
| want: Number{Real: -5.561182514695044, Imag: 0, Jmag: 0.5556661490713818, Kmag: 0.5556661490713818}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: math.Pi, |
| want: Number{Real: -2.320735561810013, Imag: 0, Jmag: 0, Kmag: 1.8544983901925216}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: math.Pi, |
| want: Number{Real: 1.2388947209955585, Imag: -3.162774128856231, Jmag: -3.162774128856231, Kmag: -3.162774128856231}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: math.Pi, |
| want: Number{Real: 0.6552860151073727, Imag: 0, Jmag: -2.0488506614051922, Kmag: -2.0488506614051922}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: math.Pi, |
| want: Number{Real: 0.22058404074969779, Imag: 0, Jmag: 0, Kmag: -0.9753679720836315}, |
| }, |
| |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, r: 3, |
| want: Number{Real: -8, Imag: 0, Jmag: 0, Kmag: 0}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, r: 3, |
| want: Number{Real: -5, Imag: 0, Jmag: 1, Kmag: 1}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, r: 3, |
| want: Number{Real: -2, Imag: 0, Jmag: 0, Kmag: 2}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, r: 3, |
| want: Number{Real: 0, Imag: -3, Jmag: -3, Kmag: -3}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, r: 3, |
| want: Number{Real: 0, Imag: 0, Jmag: -2, Kmag: -2}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, r: 3, |
| want: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: -1}, |
| }, |
| } |
| |
| func TestRealPow(t *testing.T) { |
| t.Parallel() |
| const tol = 1e-14 |
| for _, test := range powRealTests { |
| got := PowReal(test.q, test.r) |
| if !equalApprox(got, test.want, tol) { |
| t.Errorf("unexpected result for Pow(%v, %v): got:%v want:%v", test.q, test.r, got, test.want) |
| } |
| } |
| } |
| |
| var sqrtTests = []struct { |
| q Number |
| want Number |
| }{ |
| {q: Number{}, want: Number{}}, |
| // Expected velues below are from pyquaternion. |
| { |
| q: Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 1.2247448713915892, Imag: 0.4082482904638631, Jmag: 0.4082482904638631, Kmag: 0.4082482904638631}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 1.1687708944803676, Imag: 0, Jmag: 0.42779983858367593, Kmag: 0.42779983858367593}, |
| }, |
| { |
| q: Number{Real: 1, Imag: 0, Jmag: 0, Kmag: 1}, |
| want: Number{Real: 1.0986841134678098, Imag: 0, Jmag: 0, Kmag: 0.45508986056222733}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 1, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.9306048591020996, Imag: 0.5372849659117709, Jmag: 0.5372849659117709, Kmag: 0.5372849659117709}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 1, Kmag: 1}, |
| want: Number{Real: 0.8408964152537146, Imag: 0, Jmag: 0.5946035575013604, Kmag: 0.5946035575013604}, |
| }, |
| { |
| q: Number{Real: 0, Imag: 0, Jmag: 0, Kmag: 1}, |
| want: Number{Real: 0.7071067811865476, Imag: 0, Jmag: 0, Kmag: 0.7071067811865475}, |
| }, |
| } |
| |
| func TestSqrt(t *testing.T) { |
| t.Parallel() |
| const tol = 1e-14 |
| for _, test := range sqrtTests { |
| got := Sqrt(test.q) |
| if !equalApprox(got, test.want, tol) { |
| t.Errorf("unexpected result for Sqrt(%v): got:%v want:%v", test.q, got, test.want) |
| } |
| } |
| } |