gonum.org/v1/gonum@v0.14.0/num/dualquat/dual_test.go (about) 1 // Copyright ©2018 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package dualquat 6 7 import ( 8 "fmt" 9 "math" 10 "testing" 11 12 "gonum.org/v1/gonum/floats/scalar" 13 "gonum.org/v1/gonum/num/quat" 14 ) 15 16 var formatTests = []struct { 17 d Number 18 format string 19 want string 20 }{ 21 {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%#v", want: "dualquat.Number{Real:quat.Number{Real:1.1, Imag:2.1, Jmag:3.1, Kmag:4.1}, Dual:quat.Number{Real:1.2, Imag:2.2, Jmag:3.2, Kmag:4.2}}"}, // Bootstrap test. 22 {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%#v", want: "dualquat.Number{Real:quat.Number{Real:-1.1, Imag:-2.1, Jmag:-3.1, Kmag:-4.1}, Dual:quat.Number{Real:-1.2, Imag:-2.2, Jmag:-3.2, Kmag:-4.2}}"}, // Bootstrap test. 23 {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%+v", want: "{Real:{Real:1.1, Imag:2.1, Jmag:3.1, Kmag:4.1}, Dual:{Real:1.2, Imag:2.2, Jmag:3.2, Kmag:4.2}}"}, 24 {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%+v", want: "{Real:{Real:-1.1, Imag:-2.1, Jmag:-3.1, Kmag:-4.1}, Dual:{Real:-1.2, Imag:-2.2, Jmag:-3.2, Kmag:-4.2}}"}, 25 {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%v", want: "((1.1+2.1i+3.1j+4.1k)+(+1.2+2.2i+3.2j+4.2k)ϵ)"}, 26 {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%v", want: "((-1.1-2.1i-3.1j-4.1k)+(-1.2-2.2i-3.2j-4.2k)ϵ)"}, 27 {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%g", want: "((1.1+2.1i+3.1j+4.1k)+(+1.2+2.2i+3.2j+4.2k)ϵ)"}, 28 {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%g", want: "((-1.1-2.1i-3.1j-4.1k)+(-1.2-2.2i-3.2j-4.2k)ϵ)"}, 29 {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%e", want: "((1.100000e+00+2.100000e+00i+3.100000e+00j+4.100000e+00k)+(+1.200000e+00+2.200000e+00i+3.200000e+00j+4.200000e+00k)ϵ)"}, 30 {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%e", want: "((-1.100000e+00-2.100000e+00i-3.100000e+00j-4.100000e+00k)+(-1.200000e+00-2.200000e+00i-3.200000e+00j-4.200000e+00k)ϵ)"}, 31 {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%E", want: "((1.100000E+00+2.100000E+00i+3.100000E+00j+4.100000E+00k)+(+1.200000E+00+2.200000E+00i+3.200000E+00j+4.200000E+00k)ϵ)"}, 32 {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%E", want: "((-1.100000E+00-2.100000E+00i-3.100000E+00j-4.100000E+00k)+(-1.200000E+00-2.200000E+00i-3.200000E+00j-4.200000E+00k)ϵ)"}, 33 {d: Number{quat.Number{Real: 1.1, Imag: 2.1, Jmag: 3.1, Kmag: 4.1}, quat.Number{Real: 1.2, Imag: 2.2, Jmag: 3.2, Kmag: 4.2}}, format: "%f", want: "((1.100000+2.100000i+3.100000j+4.100000k)+(+1.200000+2.200000i+3.200000j+4.200000k)ϵ)"}, 34 {d: Number{quat.Number{Real: -1.1, Imag: -2.1, Jmag: -3.1, Kmag: -4.1}, quat.Number{Real: -1.2, Imag: -2.2, Jmag: -3.2, Kmag: -4.2}}, format: "%f", want: "((-1.100000-2.100000i-3.100000j-4.100000k)+(-1.200000-2.200000i-3.200000j-4.200000k)ϵ)"}, 35 } 36 37 func TestFormat(t *testing.T) { 38 t.Parallel() 39 for _, test := range formatTests { 40 got := fmt.Sprintf(test.format, test.d) 41 if got != test.want { 42 t.Errorf("unexpected result for fmt.Sprintf(%q, %#v): got:%q, want:%q", test.format, test.d, got, test.want) 43 } 44 } 45 } 46 47 // First derivatives: 48 49 func dExp(x quat.Number) quat.Number { return quat.Exp(x) } 50 func dLog(x quat.Number) quat.Number { 51 switch { 52 case x == zeroQuat: 53 return quat.Inf() 54 case quat.IsInf(x): 55 return zeroQuat 56 } 57 return quat.Inv(x) 58 } 59 func dSqrt(x quat.Number) quat.Number { return quat.Scale(0.5, quat.Inv(quat.Sqrt(x))) } 60 func dInv(x quat.Number) quat.Number { return quat.Scale(-1, quat.Inv(quat.Mul(x, x))) } 61 62 var ( 63 negZero = math.Copysign(0, -1) 64 oneReal = quat.Number{Real: 1} 65 negZeroQuat = quat.Scale(-1, zeroQuat) 66 one = quat.Number{Real: 1, Imag: 1, Jmag: 1, Kmag: 1} 67 negOne = quat.Scale(-1, one) 68 half = quat.Scale(0.5, one) 69 negHalf = quat.Scale(-1, half) 70 two = quat.Scale(2, one) 71 negTwo = quat.Scale(-1, two) 72 three = quat.Scale(3, one) 73 negThree = quat.Scale(-1, three) 74 four = quat.Scale(4, one) 75 six = quat.Scale(6, one) 76 ) 77 78 var dualTests = []struct { 79 name string 80 x []quat.Number 81 fnDual func(x Number) Number 82 fn func(x quat.Number) quat.Number 83 dFn func(x quat.Number) quat.Number 84 }{ 85 { 86 name: "exp", 87 x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, 88 fnDual: Exp, 89 fn: quat.Exp, 90 dFn: dExp, 91 }, 92 { 93 name: "log", 94 x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, 95 fnDual: Log, 96 fn: quat.Log, 97 dFn: dLog, 98 }, 99 { 100 name: "inv", 101 x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, 102 fnDual: Inv, 103 fn: quat.Inv, 104 dFn: dInv, 105 }, 106 { 107 name: "sqrt", 108 x: []quat.Number{quat.NaN(), quat.Inf(), negThree, negTwo, negOne, negHalf, negZeroQuat, zeroQuat, half, one, two, three}, 109 fnDual: Sqrt, 110 fn: quat.Sqrt, 111 dFn: dSqrt, 112 }, 113 } 114 115 func TestNumber(t *testing.T) { 116 t.Parallel() 117 const tol = 1e-15 118 for _, test := range dualTests { 119 for _, x := range test.x { 120 fxDual := test.fnDual(Number{Real: x, Dual: oneReal}) 121 fx := test.fn(x) 122 dFx := test.dFn(x) 123 if !same(fxDual.Real, fx, tol) { 124 t.Errorf("unexpected %s(%v): got:%v want:%v", test.name, x, fxDual.Real, fx) 125 } 126 if !same(fxDual.Dual, dFx, tol) { 127 t.Errorf("unexpected %s'(%v): got:%v want:%v", test.name, x, fxDual.Dual, dFx) 128 } 129 } 130 } 131 } 132 133 var invTests = []Number{ 134 {Real: quat.Number{Real: 1}}, 135 {Real: quat.Number{Real: 1}, Dual: quat.Number{Real: 1}}, 136 {Real: quat.Number{Imag: 1}, Dual: quat.Number{Real: 1}}, 137 {Real: quat.Number{Real: 1}, Dual: quat.Number{Real: 1, Imag: 1}}, 138 {Real: quat.Number{Real: 1, Imag: 1}, Dual: quat.Number{Real: 1, Imag: 1}}, 139 {Real: quat.Number{Real: 1, Imag: 10}, Dual: quat.Number{Real: 1, Imag: 5}}, 140 {Real: quat.Number{Real: 10, Imag: 1}, Dual: quat.Number{Real: 5, Imag: 1}}, 141 {Real: quat.Number{Real: 1}, Dual: quat.Number{Real: 1, Imag: 1, Kmag: 1}}, 142 {Real: quat.Number{Real: 12, Imag: 1}, Dual: quat.Number{Real: 1, Imag: 1}}, 143 {Real: quat.Number{Real: 12, Imag: 1, Jmag: 3}}, 144 } 145 146 func TestInv(t *testing.T) { 147 t.Parallel() 148 const tol = 1e-15 149 for _, x := range invTests { 150 got := Mul(x, Inv(x)) 151 want := Number{Real: quat.Number{Real: 1}} 152 if !sameDual(got, want, tol) { 153 t.Errorf("unexpected Mul(%[1]v, Inv(%[1]v)): got:%v want:%v", x, got, want) 154 } 155 } 156 } 157 158 var powRealTests = []struct { 159 d Number 160 p float64 161 want Number 162 }{ 163 // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x 164 {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, 165 {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, 166 {d: Number{Real: quat.NaN(), Dual: one}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, 167 {d: Number{Real: quat.NaN(), Dual: two}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, 168 {d: Number{Real: quat.NaN(), Dual: three}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, 169 {d: Number{Real: quat.NaN(), Dual: one}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, 170 {d: Number{Real: quat.NaN(), Dual: two}, p: 0, want: Number{Real: oneReal, Dual: quat.NaN()}}, 171 {d: Number{Real: quat.NaN(), Dual: three}, p: negZero, want: Number{Real: oneReal, Dual: quat.NaN()}}, 172 173 // PowReal(x, ±0) = 1 for any x 174 {d: Number{Real: zeroQuat, Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, 175 {d: Number{Real: negZeroQuat, Dual: zeroQuat}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, 176 {d: Number{Real: quat.Inf(), Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, 177 {d: Number{Real: quat.Inf(), Dual: zeroQuat}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, 178 {d: Number{Real: zeroQuat, Dual: one}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, 179 {d: Number{Real: negZeroQuat, Dual: one}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, 180 {d: Number{Real: quat.Inf(), Dual: one}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, 181 {d: Number{Real: quat.Inf(), Dual: one}, p: negZero, want: Number{Real: oneReal, Dual: zeroQuat}}, 182 183 // PowReal(1+xϵ, y) = (1+xyϵ) for any y 184 {d: Number{Real: oneReal, Dual: zeroQuat}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, 185 {d: Number{Real: oneReal, Dual: zeroQuat}, p: 1, want: Number{Real: oneReal, Dual: zeroQuat}}, 186 {d: Number{Real: oneReal, Dual: zeroQuat}, p: 2, want: Number{Real: oneReal, Dual: zeroQuat}}, 187 {d: Number{Real: oneReal, Dual: zeroQuat}, p: 3, want: Number{Real: oneReal, Dual: zeroQuat}}, 188 {d: Number{Real: oneReal, Dual: one}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, 189 {d: Number{Real: oneReal, Dual: one}, p: 1, want: Number{Real: oneReal, Dual: one}}, 190 {d: Number{Real: oneReal, Dual: one}, p: 2, want: Number{Real: oneReal, Dual: two}}, 191 {d: Number{Real: oneReal, Dual: one}, p: 3, want: Number{Real: oneReal, Dual: three}}, 192 {d: Number{Real: oneReal, Dual: two}, p: 0, want: Number{Real: oneReal, Dual: zeroQuat}}, 193 {d: Number{Real: oneReal, Dual: two}, p: 1, want: Number{Real: oneReal, Dual: two}}, 194 {d: Number{Real: oneReal, Dual: two}, p: 2, want: Number{Real: oneReal, Dual: four}}, 195 {d: Number{Real: oneReal, Dual: two}, p: 3, want: Number{Real: oneReal, Dual: six}}, 196 197 // PowReal(x, 1) = x for any x 198 {d: Number{Real: zeroQuat, Dual: zeroQuat}, p: 1, want: Number{Real: zeroQuat, Dual: zeroQuat}}, 199 {d: Number{Real: negZeroQuat, Dual: zeroQuat}, p: 1, want: Number{Real: negZeroQuat, Dual: zeroQuat}}, 200 {d: Number{Real: zeroQuat, Dual: one}, p: 1, want: Number{Real: zeroQuat, Dual: one}}, 201 {d: Number{Real: negZeroQuat, Dual: one}, p: 1, want: Number{Real: negZeroQuat, Dual: one}}, 202 {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 1, want: Number{Real: quat.NaN(), Dual: zeroQuat}}, 203 {d: Number{Real: quat.NaN(), Dual: one}, p: 1, want: Number{Real: quat.NaN(), Dual: one}}, 204 {d: Number{Real: quat.NaN(), Dual: two}, p: 1, want: Number{Real: quat.NaN(), Dual: two}}, 205 206 // PowReal(NaN+xϵ, y) = NaN+NaNϵ 207 {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 2, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 208 {d: Number{Real: quat.NaN(), Dual: zeroQuat}, p: 3, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 209 {d: Number{Real: quat.NaN(), Dual: one}, p: 2, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 210 {d: Number{Real: quat.NaN(), Dual: one}, p: 3, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 211 {d: Number{Real: quat.NaN(), Dual: two}, p: 2, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 212 {d: Number{Real: quat.NaN(), Dual: two}, p: 3, want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 213 214 // PowReal(x, NaN) = NaN+NaNϵ 215 {d: Number{Real: zeroQuat, Dual: zeroQuat}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 216 {d: Number{Real: two, Dual: zeroQuat}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 217 {d: Number{Real: three, Dual: zeroQuat}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 218 {d: Number{Real: zeroQuat, Dual: one}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 219 {d: Number{Real: two, Dual: one}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 220 {d: Number{Real: three, Dual: one}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 221 {d: Number{Real: zeroQuat, Dual: two}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 222 {d: Number{Real: two, Dual: two}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 223 {d: Number{Real: three, Dual: two}, p: math.NaN(), want: Number{Real: quat.NaN(), Dual: quat.NaN()}}, 224 225 // Handled by quat.Pow tests: 226 // 227 // Pow(±0, y) = ±Inf for y an odd integer < 0 228 // Pow(±0, -Inf) = +Inf 229 // Pow(±0, +Inf) = +0 230 // Pow(±0, y) = +Inf for finite y < 0 and not an odd integer 231 // Pow(±0, y) = ±0 for y an odd integer > 0 232 // Pow(±0, y) = +0 for finite y > 0 and not an odd integer 233 // Pow(-1, ±Inf) = 1 234 235 // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 236 {d: Number{Real: two, Dual: zeroQuat}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, 237 {d: Number{Real: three, Dual: zeroQuat}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, 238 239 // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 240 {d: Number{Real: two, Dual: one}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 241 {d: Number{Real: three, Dual: one}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 242 {d: Number{Real: two, Dual: two}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 243 {d: Number{Real: three, Dual: two}, p: math.Inf(1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 244 245 // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 246 {d: Number{Real: two, Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 247 {d: Number{Real: three, Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 248 {d: Number{Real: two, Dual: one}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 249 {d: Number{Real: three, Dual: one}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 250 {d: Number{Real: two, Dual: two}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 251 {d: Number{Real: three, Dual: two}, p: math.Inf(-1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 252 253 // PowReal(x+yϵ, +Inf) = +0+NaNϵ for |x| < 1 254 {d: Number{Real: quat.Scale(0.1, one), Dual: zeroQuat}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 255 {d: Number{Real: quat.Scale(0.1, one), Dual: quat.Scale(0.1, one)}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 256 {d: Number{Real: quat.Scale(0.2, one), Dual: quat.Scale(0.2, one)}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 257 {d: Number{Real: quat.Scale(0.5, one), Dual: quat.Scale(0.5, one)}, p: math.Inf(1), want: Number{Real: zeroQuat, Dual: quat.NaN()}}, 258 259 // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 260 {d: Number{Real: quat.Scale(0.1, one), Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, 261 {d: Number{Real: quat.Scale(0.2, one), Dual: zeroQuat}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.NaN()}}, 262 263 // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 264 {d: Number{Real: quat.Scale(0.1, one), Dual: quat.Scale(0.1, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 265 {d: Number{Real: quat.Scale(0.2, one), Dual: quat.Scale(0.1, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 266 {d: Number{Real: quat.Scale(0.1, one), Dual: quat.Scale(0.2, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 267 {d: Number{Real: quat.Scale(0.2, one), Dual: quat.Scale(0.2, one)}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 268 {d: Number{Real: quat.Scale(0.1, one), Dual: one}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 269 {d: Number{Real: quat.Scale(0.2, one), Dual: one}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 270 {d: Number{Real: quat.Scale(0.1, one), Dual: two}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 271 {d: Number{Real: quat.Scale(0.2, one), Dual: two}, p: math.Inf(-1), want: Number{Real: quat.Inf(), Dual: quat.Inf()}}, 272 273 // Handled by quat.Pow tests: 274 // 275 // Pow(+Inf, y) = +Inf for y > 0 276 // Pow(+Inf, y) = +0 for y < 0 277 // Pow(-Inf, y) = Pow(-0, -y) 278 } 279 280 func TestPowReal(t *testing.T) { 281 t.Parallel() 282 const tol = 1e-15 283 for _, test := range powRealTests { 284 got := PowReal(test.d, test.p) 285 if !sameDual(got, test.want, tol) { 286 t.Errorf("unexpected PowReal(%v, %v): got:%v want:%v", test.d, test.p, got, test.want) 287 } 288 } 289 } 290 291 func sameDual(a, b Number, tol float64) bool { 292 return same(a.Real, b.Real, tol) && same(a.Dual, b.Dual, tol) 293 } 294 295 func same(a, b quat.Number, tol float64) bool { 296 return (quat.IsNaN(a) && quat.IsNaN(b)) || (quat.IsInf(a) && quat.IsInf(b)) || equalApprox(a, b, tol) 297 } 298 299 func equalApprox(a, b quat.Number, tol float64) bool { 300 return scalar.EqualWithinAbsOrRel(a.Real, b.Real, tol, tol) && 301 scalar.EqualWithinAbsOrRel(a.Imag, b.Imag, tol, tol) && 302 scalar.EqualWithinAbsOrRel(a.Jmag, b.Jmag, tol, tol) && 303 scalar.EqualWithinAbsOrRel(a.Kmag, b.Kmag, tol, tol) 304 }