gonum.org/v1/gonum@v0.14.0/num/quat/quat.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 quat 6 7 import ( 8 "fmt" 9 "strconv" 10 "strings" 11 ) 12 13 var zero Number 14 15 // Number is a float64 precision quaternion. 16 type Number struct { 17 Real, Imag, Jmag, Kmag float64 18 } 19 20 // Format implements fmt.Formatter. 21 func (q Number) Format(fs fmt.State, c rune) { 22 prec, pOk := fs.Precision() 23 if !pOk { 24 prec = -1 25 } 26 width, wOk := fs.Width() 27 if !wOk { 28 width = -1 29 } 30 switch c { 31 case 'v': 32 if fs.Flag('#') { 33 fmt.Fprintf(fs, "%T{Real:%#v, Imag:%#v, Jmag:%#v, Kmag:%#v}", q, q.Real, q.Imag, q.Jmag, q.Kmag) 34 return 35 } 36 if fs.Flag('+') { 37 fmt.Fprintf(fs, "{Real:%+v, Imag:%+v, Jmag:%+v, Kmag:%+v}", q.Real, q.Imag, q.Jmag, q.Kmag) 38 return 39 } 40 c = 'g' 41 prec = -1 42 fallthrough 43 case 'e', 'E', 'f', 'F', 'g', 'G': 44 fre := fmtString(fs, c, prec, width, false) 45 fim := fmtString(fs, c, prec, width, true) 46 fmt.Fprintf(fs, fmt.Sprintf("(%s%[2]si%[2]sj%[2]sk)", fre, fim), q.Real, q.Imag, q.Jmag, q.Kmag) 47 default: 48 fmt.Fprintf(fs, "%%!%c(%T=%[2]v)", c, q) 49 return 50 } 51 } 52 53 // This is horrible, but it's what we have. 54 func fmtString(fs fmt.State, c rune, prec, width int, wantPlus bool) string { 55 var b strings.Builder 56 b.WriteByte('%') 57 for _, f := range "0+- " { 58 if fs.Flag(int(f)) || (f == '+' && wantPlus) { 59 b.WriteByte(byte(f)) 60 } 61 } 62 if width >= 0 { 63 fmt.Fprint(&b, width) 64 } 65 if prec >= 0 { 66 b.WriteByte('.') 67 if prec > 0 { 68 fmt.Fprint(&b, prec) 69 } 70 } 71 b.WriteRune(c) 72 return b.String() 73 } 74 75 // Add returns the sum of x and y. 76 func Add(x, y Number) Number { 77 return Number{ 78 Real: x.Real + y.Real, 79 Imag: x.Imag + y.Imag, 80 Jmag: x.Jmag + y.Jmag, 81 Kmag: x.Kmag + y.Kmag, 82 } 83 } 84 85 // Sub returns the difference of x and y, x-y. 86 func Sub(x, y Number) Number { 87 return Number{ 88 Real: x.Real - y.Real, 89 Imag: x.Imag - y.Imag, 90 Jmag: x.Jmag - y.Jmag, 91 Kmag: x.Kmag - y.Kmag, 92 } 93 } 94 95 // Mul returns the Hamiltonian product of x and y. 96 func Mul(x, y Number) Number { 97 return Number{ 98 Real: x.Real*y.Real - x.Imag*y.Imag - x.Jmag*y.Jmag - x.Kmag*y.Kmag, 99 Imag: x.Real*y.Imag + x.Imag*y.Real + x.Jmag*y.Kmag - x.Kmag*y.Jmag, 100 Jmag: x.Real*y.Jmag - x.Imag*y.Kmag + x.Jmag*y.Real + x.Kmag*y.Imag, 101 Kmag: x.Real*y.Kmag + x.Imag*y.Jmag - x.Jmag*y.Imag + x.Kmag*y.Real, 102 } 103 } 104 105 // Scale returns q scaled by f. 106 func Scale(f float64, q Number) Number { 107 return Number{Real: f * q.Real, Imag: f * q.Imag, Jmag: f * q.Jmag, Kmag: f * q.Kmag} 108 } 109 110 // Parse converts the string s to a Number. The string may be parenthesized and 111 // has the format [±]N±Ni±Nj±Nk. The order of the components is not strict. 112 func Parse(s string) (Number, error) { 113 if len(s) == 0 { 114 return Number{}, parseError{state: -1} 115 } 116 orig := s 117 118 wantClose := s[0] == '(' 119 if wantClose { 120 if s[len(s)-1] != ')' { 121 return Number{}, parseError{string: orig, state: -1} 122 } 123 s = s[1 : len(s)-1] 124 } 125 if len(s) == 0 { 126 return Number{}, parseError{string: orig, state: -1} 127 } 128 switch s[0] { 129 case 'n', 'N': 130 if strings.ToLower(s) == "nan" { 131 return NaN(), nil 132 } 133 case 'i', 'I': 134 if strings.ToLower(s) == "inf" { 135 return Inf(), nil 136 } 137 } 138 139 var q Number 140 var parts byte 141 for i := 0; i < 4; i++ { 142 beg, end, p, err := floatPart(s) 143 if err != nil { 144 return q, parseError{string: orig, state: -1} 145 } 146 if parts&(1<<p) != 0 { 147 return q, parseError{string: orig, state: -1} 148 } 149 parts |= 1 << p 150 var v float64 151 switch s[:end] { 152 case "-": 153 if len(s[end:]) == 0 { 154 return q, parseError{string: orig, state: -1} 155 } 156 v = -1 157 case "+": 158 if len(s[end:]) == 0 { 159 return q, parseError{string: orig, state: -1} 160 } 161 v = 1 162 default: 163 v, err = strconv.ParseFloat(s[beg:end], 64) 164 if err != nil { 165 return q, err 166 } 167 } 168 s = s[end:] 169 switch p { 170 case 0: 171 q.Real = v 172 case 1: 173 q.Imag = v 174 s = s[1:] 175 case 2: 176 q.Jmag = v 177 s = s[1:] 178 case 3: 179 q.Kmag = v 180 s = s[1:] 181 } 182 if len(s) == 0 { 183 return q, nil 184 } 185 if !isSign(rune(s[0])) { 186 return q, parseError{string: orig, state: -1} 187 } 188 } 189 190 return q, parseError{string: orig, state: -1} 191 } 192 193 func floatPart(s string) (beg, end int, part uint, err error) { 194 const ( 195 wantMantSign = iota 196 wantMantIntInit 197 wantMantInt 198 wantMantFrac 199 wantExpSign 200 wantExpInt 201 202 wantInfN 203 wantInfF 204 wantCloseInf 205 206 wantNaNA 207 wantNaNN 208 wantCloseNaN 209 ) 210 var i, state int 211 var r rune 212 for i, r = range s { 213 switch state { 214 case wantMantSign: 215 switch { 216 default: 217 return 0, i, 0, parseError{string: s, state: state, rune: r} 218 case isSign(r): 219 state = wantMantIntInit 220 case isDigit(r): 221 state = wantMantInt 222 case isDot(r): 223 state = wantMantFrac 224 case r == 'i', r == 'I': 225 state = wantInfN 226 case r == 'n', r == 'N': 227 state = wantNaNA 228 } 229 230 case wantMantIntInit: 231 switch { 232 default: 233 return 0, i, 0, parseError{string: s, state: state, rune: r} 234 case isDigit(r): 235 state = wantMantInt 236 case isDot(r): 237 state = wantMantFrac 238 case r == 'i': 239 // We need to sneak a look-ahead here. 240 if i == len(s)-1 || s[i+1] == '-' || s[i+1] == '+' { 241 return 0, i, 1, nil 242 } 243 fallthrough 244 case r == 'I': 245 state = wantInfN 246 case r == 'n', r == 'N': 247 state = wantNaNA 248 } 249 250 case wantMantInt: 251 switch { 252 default: 253 return 0, i, 0, parseError{string: s, state: state, rune: r} 254 case isDigit(r): 255 // Do nothing 256 case isDot(r): 257 state = wantMantFrac 258 case isExponent(r): 259 state = wantExpSign 260 case isSign(r): 261 return 0, i, 0, nil 262 case r == 'i': 263 return 0, i, 1, nil 264 case r == 'j': 265 return 0, i, 2, nil 266 case r == 'k': 267 return 0, i, 3, nil 268 } 269 270 case wantMantFrac: 271 switch { 272 default: 273 return 0, i, 0, parseError{string: s, state: state, rune: r} 274 case isDigit(r): 275 // Do nothing 276 case isExponent(r): 277 state = wantExpSign 278 case isSign(r): 279 return 0, i, 0, nil 280 case r == 'i': 281 return 0, i, 1, nil 282 case r == 'j': 283 return 0, i, 2, nil 284 case r == 'k': 285 return 0, i, 3, nil 286 } 287 288 case wantExpSign: 289 switch { 290 default: 291 return 0, i, 0, parseError{string: s, state: state, rune: r} 292 case isSign(r) || isDigit(r): 293 state = wantExpInt 294 } 295 296 case wantExpInt: 297 switch { 298 default: 299 return 0, i, 0, parseError{string: s, state: state, rune: r} 300 case isDigit(r): 301 // Do nothing 302 case isSign(r): 303 return 0, i, 0, nil 304 case r == 'i': 305 return 0, i, 1, nil 306 case r == 'j': 307 return 0, i, 2, nil 308 case r == 'k': 309 return 0, i, 3, nil 310 } 311 312 case wantInfN: 313 if r != 'n' && r != 'N' { 314 return 0, i, 0, parseError{string: s, state: state, rune: r} 315 } 316 state = wantInfF 317 case wantInfF: 318 if r != 'f' && r != 'F' { 319 return 0, i, 0, parseError{string: s, state: state, rune: r} 320 } 321 state = wantCloseInf 322 case wantCloseInf: 323 switch { 324 default: 325 return 0, i, 0, parseError{string: s, state: state, rune: r} 326 case isSign(r): 327 return 0, i, 0, nil 328 case r == 'i': 329 return 0, i, 1, nil 330 case r == 'j': 331 return 0, i, 2, nil 332 case r == 'k': 333 return 0, i, 3, nil 334 } 335 336 case wantNaNA: 337 if r != 'a' && r != 'A' { 338 return 0, i, 0, parseError{string: s, state: state, rune: r} 339 } 340 state = wantNaNN 341 case wantNaNN: 342 if r != 'n' && r != 'N' { 343 return 0, i, 0, parseError{string: s, state: state, rune: r} 344 } 345 state = wantCloseNaN 346 case wantCloseNaN: 347 if isSign(rune(s[0])) { 348 beg = 1 349 } 350 switch { 351 default: 352 return beg, i, 0, parseError{string: s, state: state, rune: r} 353 case isSign(r): 354 return beg, i, 0, nil 355 case r == 'i': 356 return beg, i, 1, nil 357 case r == 'j': 358 return beg, i, 2, nil 359 case r == 'k': 360 return beg, i, 3, nil 361 } 362 } 363 } 364 switch state { 365 case wantMantSign, wantExpSign, wantExpInt: 366 if state == wantExpInt && isDigit(r) { 367 break 368 } 369 return 0, i, 0, parseError{string: s, state: state, rune: r} 370 } 371 return 0, len(s), 0, nil 372 } 373 374 func isSign(r rune) bool { 375 return r == '+' || r == '-' 376 } 377 378 func isDigit(r rune) bool { 379 return '0' <= r && r <= '9' 380 } 381 382 func isExponent(r rune) bool { 383 return r == 'e' || r == 'E' 384 } 385 386 func isDot(r rune) bool { 387 return r == '.' 388 } 389 390 type parseError struct { 391 string string 392 state int 393 rune rune 394 } 395 396 func (e parseError) Error() string { 397 if e.state < 0 { 398 return fmt.Sprintf("quat: failed to parse: %q", e.string) 399 } 400 return fmt.Sprintf("quat: failed to parse in state %d with %q: %q", e.state, e.rune, e.string) 401 }