// 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 }