172 lines
3.4 KiB
Go
172 lines
3.4 KiB
Go
// 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.
|
||
|
||
// Copyright 2017 The Go 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"
|
||
|
||
// Sin returns the sine of q.
|
||
func Sin(q Number) Number {
|
||
w, uv := split(q)
|
||
if uv == zero {
|
||
return lift(math.Sin(w))
|
||
}
|
||
v := Abs(uv)
|
||
s, c := math.Sincos(w)
|
||
sh, ch := sinhcosh(v)
|
||
return join(s*ch, Scale(c*sh/v, uv))
|
||
}
|
||
|
||
// Sinh returns the hyperbolic sine of q.
|
||
func Sinh(q Number) Number {
|
||
w, uv := split(q)
|
||
if uv == zero {
|
||
return lift(math.Sinh(w))
|
||
}
|
||
v := Abs(uv)
|
||
s, c := math.Sincos(v)
|
||
sh, ch := sinhcosh(w)
|
||
return join(c*sh, scale(s*ch/v, uv))
|
||
}
|
||
|
||
// Cos returns the cosine of q.
|
||
func Cos(q Number) Number {
|
||
w, uv := split(q)
|
||
if uv == zero {
|
||
return lift(math.Cos(w))
|
||
}
|
||
v := Abs(uv)
|
||
s, c := math.Sincos(w)
|
||
sh, ch := sinhcosh(v)
|
||
return join(c*ch, Scale(-s*sh/v, uv))
|
||
}
|
||
|
||
// Cosh returns the hyperbolic cosine of q.
|
||
func Cosh(q Number) Number {
|
||
w, uv := split(q)
|
||
if uv == zero {
|
||
return lift(math.Cosh(w))
|
||
}
|
||
v := Abs(uv)
|
||
s, c := math.Sincos(v)
|
||
sh, ch := sinhcosh(w)
|
||
return join(c*ch, scale(s*sh/v, uv))
|
||
}
|
||
|
||
// Tan returns the tangent of q.
|
||
func Tan(q Number) Number {
|
||
d := Cos(q)
|
||
if d == zero {
|
||
return Inf()
|
||
}
|
||
return Mul(Sin(q), Inv(d))
|
||
}
|
||
|
||
// Tanh returns the hyperbolic tangent of q.
|
||
func Tanh(q Number) Number {
|
||
if math.IsInf(q.Real, 1) {
|
||
r := Number{Real: 1}
|
||
// Change signs dependent on imaginary parts.
|
||
r.Imag *= math.Sin(2 * q.Imag)
|
||
r.Jmag *= math.Sin(2 * q.Jmag)
|
||
r.Kmag *= math.Sin(2 * q.Kmag)
|
||
return r
|
||
}
|
||
d := Cosh(q)
|
||
if d == zero {
|
||
return Inf()
|
||
}
|
||
return Mul(Sinh(q), Inv(d))
|
||
}
|
||
|
||
// Asin returns the inverse sine of q.
|
||
func Asin(q Number) Number {
|
||
_, uv := split(q)
|
||
if uv == zero {
|
||
return lift(math.Asin(q.Real))
|
||
}
|
||
u := unit(uv)
|
||
return Mul(Scale(-1, u), Log(Add(Mul(u, q), Sqrt(Sub(Number{Real: 1}, Mul(q, q))))))
|
||
}
|
||
|
||
// Asinh returns the inverse hyperbolic sine of q.
|
||
func Asinh(q Number) Number {
|
||
return Log(Add(q, Sqrt(Add(Number{Real: 1}, Mul(q, q)))))
|
||
}
|
||
|
||
// Acos returns the inverse cosine of q.
|
||
func Acos(q Number) Number {
|
||
w, uv := split(Asin(q))
|
||
return join(math.Pi/2-w, Scale(-1, uv))
|
||
}
|
||
|
||
// Acosh returns the inverse hyperbolic cosine of q.
|
||
func Acosh(q Number) Number {
|
||
w := Acos(q)
|
||
_, uv := split(w)
|
||
if uv == zero {
|
||
return w
|
||
}
|
||
w = Mul(w, unit(uv))
|
||
if w.Real < 0 {
|
||
w = Scale(-1, w)
|
||
}
|
||
return w
|
||
}
|
||
|
||
// Atan returns the inverse tangent of q.
|
||
func Atan(q Number) Number {
|
||
w, uv := split(q)
|
||
if uv == zero {
|
||
return lift(math.Atan(w))
|
||
}
|
||
u := unit(uv)
|
||
return Mul(Mul(lift(0.5), u), Log(Mul(Add(u, q), Inv(Sub(u, q)))))
|
||
}
|
||
|
||
// Atanh returns the inverse hyperbolic tangent of q.
|
||
func Atanh(q Number) Number {
|
||
w, uv := split(q)
|
||
if uv == zero {
|
||
return lift(math.Atanh(w))
|
||
}
|
||
u := unit(uv)
|
||
return Mul(Scale(-1, u), Atan(Mul(u, q)))
|
||
}
|
||
|
||
// calculate sinh and cosh
|
||
func sinhcosh(x float64) (sh, ch float64) {
|
||
if math.Abs(x) <= 0.5 {
|
||
return math.Sinh(x), math.Cosh(x)
|
||
}
|
||
e := math.Exp(x)
|
||
ei := 0.5 / e
|
||
e *= 0.5
|
||
return e - ei, e + ei
|
||
}
|
||
|
||
// scale returns q scaled by f, except that inf×0 is 0.
|
||
func scale(f float64, q Number) Number {
|
||
if f == 0 {
|
||
return Number{}
|
||
}
|
||
if q.Real != 0 {
|
||
q.Real *= f
|
||
}
|
||
if q.Imag != 0 {
|
||
q.Imag *= f
|
||
}
|
||
if q.Jmag != 0 {
|
||
q.Jmag *= f
|
||
}
|
||
if q.Kmag != 0 {
|
||
q.Kmag *= f
|
||
}
|
||
return q
|
||
}
|