gonum.org/v1/gonum@v0.14.0/num/dualcmplx/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 dualcmplx 6 7 import ( 8 "fmt" 9 "math" 10 "math/cmplx" 11 "testing" 12 13 "gonum.org/v1/gonum/floats/scalar" 14 ) 15 16 var formatTests = []struct { 17 d Number 18 format string 19 want string 20 }{ 21 {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%#v", want: "dualcmplx.Number{Real:(1.1+2.1i), Dual:(1.2+2.2i)}"}, // Bootstrap test. 22 {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%#v", want: "dualcmplx.Number{Real:(-1.1-2.1i), Dual:(-1.2-2.2i)}"}, // Bootstrap test. 23 {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%+v", want: "{Real:(1.1+2.1i), Dual:(1.2+2.2i)}"}, 24 {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%+v", want: "{Real:(-1.1-2.1i), Dual:(-1.2-2.2i)}"}, 25 {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%v", want: "((1.1+2.1i)+(+1.2+2.2i)ϵ)"}, 26 {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%v", want: "((-1.1-2.1i)+(-1.2-2.2i)ϵ)"}, 27 {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%g", want: "((1.1+2.1i)+(+1.2+2.2i)ϵ)"}, 28 {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%g", want: "((-1.1-2.1i)+(-1.2-2.2i)ϵ)"}, 29 {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%e", want: "((1.100000e+00+2.100000e+00i)+(+1.200000e+00+2.200000e+00i)ϵ)"}, 30 {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%e", want: "((-1.100000e+00-2.100000e+00i)+(-1.200000e+00-2.200000e+00i)ϵ)"}, 31 {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%E", want: "((1.100000E+00+2.100000E+00i)+(+1.200000E+00+2.200000E+00i)ϵ)"}, 32 {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%E", want: "((-1.100000E+00-2.100000E+00i)+(-1.200000E+00-2.200000E+00i)ϵ)"}, 33 {d: Number{1.1 + 2.1i, 1.2 + 2.2i}, format: "%f", want: "((1.100000+2.100000i)+(+1.200000+2.200000i)ϵ)"}, 34 {d: Number{-1.1 - 2.1i, -1.2 - 2.2i}, format: "%f", want: "((-1.100000-2.100000i)+(-1.200000-2.200000i)ϵ)"}, 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 // FIXME(kortschak): See golang/go#29320. 48 49 func sqrt(x complex128) complex128 { 50 switch { 51 case math.IsInf(imag(x), 1): 52 return cmplx.Inf() 53 case math.IsNaN(imag(x)): 54 return cmplx.NaN() 55 case math.IsInf(real(x), -1): 56 if imag(x) >= 0 && !math.IsInf(imag(x), 1) { 57 return complex(0, math.NaN()) 58 } 59 if math.IsNaN(imag(x)) { 60 return complex(math.NaN(), math.Inf(1)) 61 } 62 case math.IsInf(real(x), 1): 63 if imag(x) >= 0 && !math.IsInf(imag(x), 1) { 64 return complex(math.Inf(1), 0) 65 } 66 if math.IsNaN(imag(x)) { 67 return complex(math.Inf(1), math.NaN()) 68 } 69 case math.IsInf(real(x), -1): 70 return complex(0, math.Inf(1)) 71 case math.IsNaN(real(x)): 72 if math.IsNaN(imag(x)) || math.IsInf(imag(x), 0) { 73 return cmplx.NaN() 74 } 75 } 76 return cmplx.Sqrt(x) 77 } 78 79 // First derivatives: 80 81 func dExp(x complex128) complex128 { 82 if imag(x) == 0 { 83 return cmplx.Exp(x) 84 } 85 return (cmplx.Exp(x) - cmplx.Exp(cmplx.Conj(x))) / (x - cmplx.Conj(x)) 86 } 87 func dLog(x complex128) complex128 { 88 if cmplx.IsInf(x) { 89 return 0 90 } 91 if x == 0 { 92 if math.Copysign(1, real(x)) < 0 { 93 return complex(math.Inf(-1), math.NaN()) 94 } 95 return complex(math.Inf(1), math.NaN()) 96 } 97 return (cmplx.Log(x) - cmplx.Log(cmplx.Conj(x))) / (x - cmplx.Conj(x)) 98 } 99 func dInv(x complex128) complex128 { return -1 / (x * cmplx.Conj(x)) } 100 101 var ( 102 negZero = math.Copysign(0, -1) 103 zeroCmplx = 0 + 0i 104 negZeroCmplx = -1 * zeroCmplx 105 one = 1 + 1i 106 negOne = -1 - 1i 107 half = one / 2 108 negHalf = negOne / 2 109 two = 2 + 2i 110 negTwo = -2 - 2i 111 three = 3 + 3i 112 negThree = -3 + 3i 113 ) 114 115 var dualTests = []struct { 116 name string 117 x []complex128 118 fnDual func(x Number) Number 119 fn func(x complex128) complex128 120 dFn func(x complex128) complex128 121 }{ 122 { 123 name: "exp", 124 x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, 125 fnDual: Exp, 126 fn: cmplx.Exp, 127 dFn: dExp, 128 }, 129 { 130 name: "log", 131 x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, 132 fnDual: Log, 133 fn: cmplx.Log, 134 dFn: dLog, 135 }, 136 { 137 name: "inv", 138 x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, 139 fnDual: Inv, 140 fn: func(x complex128) complex128 { return 1 / x }, 141 dFn: dInv, 142 }, 143 { 144 name: "sqrt", 145 x: []complex128{cmplx.NaN(), cmplx.Inf(), negThree, negTwo, negOne, negHalf, negZeroCmplx, zeroCmplx, half, one, two, three}, 146 fnDual: Sqrt, 147 fn: sqrt, 148 // TODO(kortschak): Find a concise dSqrt. 149 }, 150 } 151 152 func TestNumber(t *testing.T) { 153 t.Parallel() 154 const tol = 1e-15 155 for _, test := range dualTests { 156 for _, x := range test.x { 157 fxDual := test.fnDual(Number{Real: x, Dual: 1}) 158 fx := test.fn(x) 159 if !same(fxDual.Real, fx, tol) { 160 t.Errorf("unexpected %s(%v): got:%v want:%v", test.name, x, fxDual.Real, fx) 161 } 162 if test.dFn == nil { 163 continue 164 } 165 dFx := test.dFn(x) 166 if !same(fxDual.Dual, dFx, tol) { 167 t.Errorf("unexpected %s'(%v): got:%v want:%v", test.name, x, fxDual.Dual, dFx) 168 } 169 } 170 } 171 } 172 173 var invTests = []Number{ 174 {Real: 1, Dual: 0}, 175 {Real: 1, Dual: 1}, 176 {Real: 1i, Dual: 1}, 177 {Real: 1, Dual: 1 + 1i}, 178 {Real: 1 + 1i, Dual: 1 + 1i}, 179 {Real: 1 + 10i, Dual: 1 + 5i}, 180 {Real: 10 + 1i, Dual: 5 + 1i}, 181 } 182 183 func TestInv(t *testing.T) { 184 t.Parallel() 185 const tol = 1e-15 186 for _, x := range invTests { 187 got := Mul(x, Inv(x)) 188 want := Number{Real: 1} 189 if !sameDual(got, want, tol) { 190 t.Errorf("unexpected Mul(%[1]v, Inv(%[1]v)): got:%v want:%v", x, got, want) 191 } 192 } 193 } 194 195 var expLogTests = []Number{ 196 {Real: 1i, Dual: 1i}, 197 {Real: 1 + 1i, Dual: 1 + 1i}, 198 {Real: 1 + 1e-1i, Dual: 1 + 1i}, 199 {Real: 1 + 1e-2i, Dual: 1 + 1i}, 200 {Real: 1 + 1e-4i, Dual: 1 + 1i}, 201 {Real: 1 + 1e-6i, Dual: 1 + 1i}, 202 {Real: 1 + 1e-8i, Dual: 1 + 1i}, 203 {Real: 1 + 1e-10i, Dual: 1 + 1i}, 204 {Real: 1 + 1e-12i, Dual: 1 + 1i}, 205 {Real: 1 + 1e-14i, Dual: 1 + 1i}, 206 {Dual: 1 + 1i}, 207 {Dual: 1 + 2i}, 208 {Dual: 2 + 1i}, 209 {Dual: 2 + 2i}, 210 {Dual: 1 + 1i}, 211 {Dual: 1 + 5i}, 212 {Dual: 5 + 1i}, 213 {Real: 1 + 0i, Dual: 1 + 1i}, 214 {Real: 1 + 0i, Dual: 1 + 2i}, 215 {Real: 1 + 0i, Dual: 2 + 1i}, 216 {Real: 1 + 0i, Dual: 2 + 2i}, 217 {Real: 1 + 1i, Dual: 1 + 1i}, 218 {Real: 1 + 3i, Dual: 1 + 5i}, 219 {Real: 2 + 1i, Dual: 5 + 1i}, 220 } 221 222 func TestExpLog(t *testing.T) { 223 t.Parallel() 224 const tol = 1e-15 225 for _, x := range expLogTests { 226 got := Log(Exp(x)) 227 want := x 228 if !sameDual(got, want, tol) { 229 t.Errorf("unexpected Log(Exp(%v)): got:%v want:%v", x, got, want) 230 } 231 } 232 } 233 234 func TestLogExp(t *testing.T) { 235 t.Parallel() 236 const tol = 1e-15 237 for _, x := range expLogTests { 238 if x.Real == 0 { 239 continue 240 } 241 got := Exp(Log(x)) 242 want := x 243 if !sameDual(got, want, tol) { 244 t.Errorf("unexpected Log(Exp(%v)): got:%v want:%v", x, got, want) 245 } 246 } 247 } 248 249 var powRealSpecialTests = []struct { 250 d Number 251 p float64 252 want Number 253 }{ 254 // PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x 255 {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, 256 {d: Number{Real: cmplx.NaN(), Dual: 0}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, 257 {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, 258 {d: Number{Real: cmplx.NaN(), Dual: 2}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, 259 {d: Number{Real: cmplx.NaN(), Dual: 3}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, 260 {d: Number{Real: cmplx.NaN(), Dual: 1}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, 261 {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 0, want: Number{Real: 1, Dual: cmplx.NaN()}}, 262 {d: Number{Real: cmplx.NaN(), Dual: 3}, p: negZero, want: Number{Real: 1, Dual: cmplx.NaN()}}, 263 264 // Pow(0+xϵ, y) = 0+Infϵ for all y < 1. 265 {d: Number{Real: 0}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, 266 {d: Number{Real: 0}, p: -1, want: Number{Dual: cmplx.Inf()}}, 267 {d: Number{Dual: 1}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, 268 {d: Number{Dual: 1}, p: -1, want: Number{Dual: cmplx.Inf()}}, 269 {d: Number{Dual: 1 + 1i}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, 270 {d: Number{Dual: 1 + 1i}, p: -1, want: Number{Dual: cmplx.Inf()}}, 271 {d: Number{Dual: 1i}, p: 0.1, want: Number{Dual: cmplx.Inf()}}, 272 {d: Number{Dual: 1i}, p: -1, want: Number{Dual: cmplx.Inf()}}, 273 // Pow(0+xϵ, y) = 0 for all y > 1. 274 {d: Number{Real: 0}, p: 1.1, want: Number{Real: 0}}, 275 {d: Number{Real: 0}, p: 2, want: Number{Real: 0}}, 276 {d: Number{Dual: 1}, p: 1.1, want: Number{Real: 0}}, 277 {d: Number{Dual: 1}, p: 2, want: Number{Real: 0}}, 278 {d: Number{Dual: 1 + 1i}, p: 1.1, want: Number{Real: 0}}, 279 {d: Number{Dual: 1 + 1i}, p: 2, want: Number{Real: 0}}, 280 {d: Number{Dual: 1i}, p: 1.1, want: Number{Real: 0}}, 281 {d: Number{Dual: 1i}, p: 2, want: Number{Real: 0}}, 282 283 // PowReal(x, ±0) = 1 for any x 284 {d: Number{Real: 0, Dual: 0}, p: 0, want: Number{Real: 1, Dual: 0}}, 285 {d: Number{Real: negZeroCmplx, Dual: 0}, p: negZero, want: Number{Real: 1, Dual: 0}}, 286 {d: Number{Real: cmplx.Inf(), Dual: 0}, p: 0, want: Number{Real: 1, Dual: 0}}, 287 {d: Number{Real: cmplx.Inf(), Dual: 0}, p: negZero, want: Number{Real: 1, Dual: 0}}, 288 {d: Number{Real: 0, Dual: 1}, p: 0, want: Number{Real: 1, Dual: 0}}, 289 {d: Number{Real: negZeroCmplx, Dual: 1}, p: negZero, want: Number{Real: 1, Dual: 0}}, 290 {d: Number{Real: cmplx.Inf(), Dual: 1}, p: 0, want: Number{Real: 1, Dual: 0}}, 291 {d: Number{Real: cmplx.Inf(), Dual: 1}, p: negZero, want: Number{Real: 1, Dual: 0}}, 292 293 // PowReal(1+xϵ, y) = (1+xyϵ) for any y 294 {d: Number{Real: 1, Dual: 0}, p: 0, want: Number{Real: 1, Dual: 0}}, 295 {d: Number{Real: 1, Dual: 0}, p: 1, want: Number{Real: 1, Dual: 0}}, 296 {d: Number{Real: 1, Dual: 0}, p: 2, want: Number{Real: 1, Dual: 0}}, 297 {d: Number{Real: 1, Dual: 0}, p: 3, want: Number{Real: 1, Dual: 0}}, 298 {d: Number{Real: 1, Dual: 1}, p: 0, want: Number{Real: 1, Dual: 0}}, 299 {d: Number{Real: 1, Dual: 1}, p: 1, want: Number{Real: 1, Dual: 1}}, 300 {d: Number{Real: 1, Dual: 1}, p: 2, want: Number{Real: 1, Dual: 2}}, 301 {d: Number{Real: 1, Dual: 1}, p: 3, want: Number{Real: 1, Dual: 3}}, 302 {d: Number{Real: 1, Dual: 2}, p: 0, want: Number{Real: 1, Dual: 0}}, 303 {d: Number{Real: 1, Dual: 2}, p: 1, want: Number{Real: 1, Dual: 2}}, 304 {d: Number{Real: 1, Dual: 2}, p: 2, want: Number{Real: 1, Dual: 4}}, 305 {d: Number{Real: 1, Dual: 2}, p: 3, want: Number{Real: 1, Dual: 6}}, 306 307 // Pow(Inf, y) = +Inf+NaNϵ for y > 0 308 {d: Number{Real: cmplx.Inf()}, p: 0.5, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 309 {d: Number{Real: cmplx.Inf()}, p: 1, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 310 {d: Number{Real: cmplx.Inf()}, p: 1.1, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 311 {d: Number{Real: cmplx.Inf()}, p: 2, want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 312 // Pow(Inf, y) = +0+NaNϵ for y < 0 313 {d: Number{Real: cmplx.Inf()}, p: -0.5, want: Number{Real: 0, Dual: cmplx.NaN()}}, 314 {d: Number{Real: cmplx.Inf()}, p: -1, want: Number{Real: 0, Dual: cmplx.NaN()}}, 315 {d: Number{Real: cmplx.Inf()}, p: -1.1, want: Number{Real: 0, Dual: cmplx.NaN()}}, 316 {d: Number{Real: cmplx.Inf()}, p: -2, want: Number{Real: 0, Dual: cmplx.NaN()}}, 317 318 // PowReal(x, 1) = x for any x 319 {d: Number{Real: 0, Dual: 0}, p: 1, want: Number{Real: 0, Dual: 0}}, 320 {d: Number{Real: negZeroCmplx, Dual: 0}, p: 1, want: Number{Real: negZeroCmplx, Dual: 0}}, 321 {d: Number{Real: 0, Dual: 1}, p: 1, want: Number{Real: 0, Dual: 1}}, 322 {d: Number{Real: negZeroCmplx, Dual: 1}, p: 1, want: Number{Real: negZeroCmplx, Dual: 1}}, 323 {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 1, want: Number{Real: cmplx.NaN(), Dual: 0}}, 324 {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 1, want: Number{Real: cmplx.NaN(), Dual: 1}}, 325 {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 1, want: Number{Real: cmplx.NaN(), Dual: 2}}, 326 327 // PowReal(NaN+xϵ, y) = NaN+NaNϵ 328 {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 2, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 329 {d: Number{Real: cmplx.NaN(), Dual: 0}, p: 3, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 330 {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 2, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 331 {d: Number{Real: cmplx.NaN(), Dual: 1}, p: 3, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 332 {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 2, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 333 {d: Number{Real: cmplx.NaN(), Dual: 2}, p: 3, want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 334 335 // PowReal(x, NaN) = NaN+NaNϵ 336 {d: Number{Real: 0, Dual: 0}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 337 {d: Number{Real: 2, Dual: 0}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 338 {d: Number{Real: 3, Dual: 0}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 339 {d: Number{Real: 0, Dual: 1}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 340 {d: Number{Real: 2, Dual: 1}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 341 {d: Number{Real: 3, Dual: 1}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 342 {d: Number{Real: 0, Dual: 2}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 343 {d: Number{Real: 2, Dual: 2}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 344 {d: Number{Real: 3, Dual: 2}, p: math.NaN(), want: Number{Real: cmplx.NaN(), Dual: cmplx.NaN()}}, 345 346 // Pow(-1, ±Inf) = 1 347 {d: Number{Real: -1}, p: math.Inf(-1), want: Number{Real: 1, Dual: cmplx.NaN()}}, 348 {d: Number{Real: -1}, p: math.Inf(1), want: Number{Real: 1, Dual: cmplx.NaN()}}, 349 350 // The following tests described for cmplx.Pow ar enot valid for this type and 351 // are handled by the special cases Pow(0+xϵ, y) above. 352 // Pow(±0, y) = ±Inf for y an odd integer < 0 353 // Pow(±0, -Inf) = +Inf 354 // Pow(±0, +Inf) = +0 355 // Pow(±0, y) = +Inf for finite y < 0 and not an odd integer 356 // Pow(±0, y) = ±0 for y an odd integer > 0 357 // Pow(±0, y) = +0 for finite y > 0 and not an odd integer 358 359 // PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1 360 {d: Number{Real: 2, Dual: 0}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 361 {d: Number{Real: 3, Dual: 0}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 362 363 // PowReal(x+yϵ, +Inf) = +Inf for |x| > 1 364 {d: Number{Real: 2, Dual: 1}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 365 {d: Number{Real: 3, Dual: 1}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 366 {d: Number{Real: 2, Dual: 2}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 367 {d: Number{Real: 3, Dual: 2}, p: math.Inf(1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 368 369 // PowReal(x, -Inf) = +0+NaNϵ for |x| > 1 370 {d: Number{Real: 2, Dual: 0}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 371 {d: Number{Real: 3, Dual: 0}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 372 {d: Number{Real: 2, Dual: 1}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 373 {d: Number{Real: 3, Dual: 1}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 374 {d: Number{Real: 2, Dual: 2}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 375 {d: Number{Real: 3, Dual: 2}, p: math.Inf(-1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 376 377 // PowReal(x+yϵ, +Inf) = +0+NaNϵ for |x| < 1 378 {d: Number{Real: 0.1, Dual: 0}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 379 {d: Number{Real: 0.1, Dual: 0.1}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 380 {d: Number{Real: 0.2, Dual: 0.2}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 381 {d: Number{Real: 0.5, Dual: 0.5}, p: math.Inf(1), want: Number{Real: 0, Dual: cmplx.NaN()}}, 382 383 // PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1 384 {d: Number{Real: 0.1, Dual: 0}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 385 {d: Number{Real: 0.2, Dual: 0}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.NaN()}}, 386 387 // PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1 388 {d: Number{Real: 0.1, Dual: 0.1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 389 {d: Number{Real: 0.2, Dual: 0.1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 390 {d: Number{Real: 0.1, Dual: 0.2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 391 {d: Number{Real: 0.2, Dual: 0.2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 392 {d: Number{Real: 0.1, Dual: 1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 393 {d: Number{Real: 0.2, Dual: 1}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 394 {d: Number{Real: 0.1, Dual: 2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 395 {d: Number{Real: 0.2, Dual: 2}, p: math.Inf(-1), want: Number{Real: cmplx.Inf(), Dual: cmplx.Inf()}}, 396 } 397 398 func TestPowRealSpecial(t *testing.T) { 399 t.Parallel() 400 const tol = 1e-15 401 for _, test := range powRealSpecialTests { 402 got := PowReal(test.d, test.p) 403 if !sameDual(got, test.want, tol) { 404 t.Errorf("unexpected PowReal(%v, %v): got:%v want:%v", test.d, test.p, got, test.want) 405 } 406 } 407 } 408 409 var powRealTests = []struct { 410 d Number 411 p float64 412 }{ 413 {d: Number{Real: 1e-1, Dual: 2 + 2i}, p: 0.2}, 414 {d: Number{Real: 1e-1, Dual: 2 + 2i}, p: 5}, 415 {d: Number{Real: 1e-2, Dual: 2 + 2i}, p: 0.2}, 416 {d: Number{Real: 1e-2, Dual: 2 + 2i}, p: 5}, 417 {d: Number{Real: 1e-3, Dual: 2 + 2i}, p: 0.2}, 418 {d: Number{Real: 1e-3, Dual: 2 + 2i}, p: 5}, 419 {d: Number{Real: 1e-4, Dual: 2 + 2i}, p: 0.2}, 420 {d: Number{Real: 1e-4, Dual: 2 + 2i}, p: 5}, 421 {d: Number{Real: 2, Dual: 0}, p: 0.5}, 422 {d: Number{Real: 2, Dual: 0}, p: 2}, 423 {d: Number{Real: 4, Dual: 0}, p: 0.5}, 424 {d: Number{Real: 4, Dual: 0}, p: 2}, 425 {d: Number{Real: 8, Dual: 0}, p: 1.0 / 3}, 426 {d: Number{Real: 8, Dual: 0}, p: 3}, 427 } 428 429 func TestPowReal(t *testing.T) { 430 t.Parallel() 431 const tol = 1e-14 432 for _, test := range powRealTests { 433 got := PowReal(PowReal(test.d, test.p), 1/test.p) 434 if !sameDual(got, test.d, tol) { 435 t.Errorf("unexpected PowReal(PowReal(%v, %v), 1/%[2]v): got:%v want:%[1]v", test.d, test.p, got) 436 } 437 if test.p != math.Floor(test.p) { 438 continue 439 } 440 root := PowReal(test.d, 1/test.p) 441 got = Number{Real: 1} 442 for i := 0; i < int(test.p); i++ { 443 got = Mul(got, root) 444 } 445 if !sameDual(got, test.d, tol) { 446 t.Errorf("unexpected PowReal(%v, 1/%v)^%[2]v: got:%v want:%[1]v", test.d, test.p, got) 447 } 448 } 449 } 450 451 func sameDual(a, b Number, tol float64) bool { 452 return same(a.Real, b.Real, tol) && same(a.Dual, b.Dual, tol) 453 } 454 455 func same(a, b complex128, tol float64) bool { 456 return ((math.IsNaN(real(a)) && (math.IsNaN(real(b)))) || scalar.EqualWithinAbsOrRel(real(a), real(b), tol, tol)) && 457 ((math.IsNaN(imag(a)) && (math.IsNaN(imag(b)))) || scalar.EqualWithinAbsOrRel(imag(a), imag(b), tol, tol)) 458 }