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
5package hyperdual
6
7import "math"
8
9// Sinh returns the hyperbolic sine of d.
10//
11// Special cases are:
12//	Sinh(±0) = (±0+Nϵ₁+Nϵ₂±0ϵ₁ϵ₂)
13//	Sinh(±Inf) = ±Inf
14//	Sinh(NaN) = NaN
15func Sinh(d Number) Number {
16	if d.Real == 0 {
17		return Number{
18			Real:    d.Real,
19			E1mag:   d.E1mag,
20			E2mag:   d.E1mag,
21			E1E2mag: d.Real,
22		}
23	}
24	if math.IsInf(d.Real, 0) {
25		return Number{
26			Real:    d.Real,
27			E1mag:   math.Inf(1),
28			E2mag:   math.Inf(1),
29			E1E2mag: d.Real,
30		}
31	}
32	fn := math.Sinh(d.Real)
33	deriv := math.Cosh(d.Real)
34	return Number{
35		Real:    fn,
36		E1mag:   deriv * d.E1mag,
37		E2mag:   deriv * d.E2mag,
38		E1E2mag: deriv*d.E1E2mag + fn*d.E1mag*d.E2mag,
39	}
40}
41
42// Cosh returns the hyperbolic cosine of d.
43//
44// Special cases are:
45//	Cosh(±0) = 1
46//	Cosh(±Inf) = +Inf
47//	Cosh(NaN) = NaN
48func Cosh(d Number) Number {
49	if math.IsInf(d.Real, 0) {
50		return Number{
51			Real:    math.Inf(1),
52			E1mag:   d.Real,
53			E2mag:   d.Real,
54			E1E2mag: math.Inf(1),
55		}
56	}
57	fn := math.Cosh(d.Real)
58	deriv := math.Sinh(d.Real)
59	return Number{
60		Real:    fn,
61		E1mag:   deriv * d.E1mag,
62		E2mag:   deriv * d.E2mag,
63		E1E2mag: deriv*d.E1E2mag + fn*d.E1mag*d.E2mag,
64	}
65}
66
67// Tanh returns the hyperbolic tangent of d.
68//
69// Special cases are:
70//	Tanh(±0) = (±0+Nϵ₁+Nϵ₂∓0ϵ₁ϵ₂)
71//	Tanh(±Inf) = (±1+0ϵ₁+0ϵ₂∓0ϵ₁ϵ₂)
72//	Tanh(NaN) = NaN
73func Tanh(d Number) Number {
74	switch d.Real {
75	case 0:
76		return Number{
77			Real:    d.Real,
78			E1mag:   d.E1mag,
79			E2mag:   d.E2mag,
80			E1E2mag: -d.Real,
81		}
82	case math.Inf(1):
83		return Number{
84			Real:    1,
85			E1mag:   0,
86			E2mag:   0,
87			E1E2mag: negZero,
88		}
89	case math.Inf(-1):
90		return Number{
91			Real:    -1,
92			E1mag:   0,
93			E2mag:   0,
94			E1E2mag: 0,
95		}
96	}
97	fn := math.Tanh(d.Real)
98	deriv := 1 - fn*fn
99	return Number{
100		Real:    fn,
101		E1mag:   deriv * d.E1mag,
102		E2mag:   deriv * d.E2mag,
103		E1E2mag: deriv*d.E1E2mag - d.E1mag*d.E2mag*(2*fn*deriv),
104	}
105}
106
107// Asinh returns the inverse hyperbolic sine of d.
108//
109// Special cases are:
110//	Asinh(±0) = (±0+Nϵ₁+Nϵ₂∓0ϵ₁ϵ₂)
111//	Asinh(±Inf) = ±Inf
112//	Asinh(NaN) = NaN
113func Asinh(d Number) Number {
114	if d.Real == 0 {
115		return Number{
116			Real:    d.Real,
117			E1mag:   d.E1mag,
118			E2mag:   d.E2mag,
119			E1E2mag: -d.Real,
120		}
121	}
122	fn := math.Asinh(d.Real)
123	deriv1 := d.Real*d.Real + 1
124	deriv := 1 / math.Sqrt(deriv1)
125	return Number{
126		Real:    fn,
127		E1mag:   deriv * d.E1mag,
128		E2mag:   deriv * d.E2mag,
129		E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(-d.Real*(deriv/deriv1)),
130	}
131}
132
133// Acosh returns the inverse hyperbolic cosine of d.
134//
135// Special cases are:
136//	Acosh(+Inf) = +Inf
137//	Acosh(1) = (0+Infϵ₁+Infϵ₂-Infϵ₁ϵ₂)
138//	Acosh(x) = NaN if x < 1
139//	Acosh(NaN) = NaN
140func Acosh(d Number) Number {
141	if d.Real <= 1 {
142		if d.Real == 1 {
143			return Number{
144				Real:    0,
145				E1mag:   math.Inf(1),
146				E2mag:   math.Inf(1),
147				E1E2mag: math.Inf(-1),
148			}
149		}
150		return Number{
151			Real:    math.NaN(),
152			E1mag:   math.NaN(),
153			E2mag:   math.NaN(),
154			E1E2mag: math.NaN(),
155		}
156	}
157	fn := math.Acosh(d.Real)
158	deriv1 := d.Real*d.Real - 1
159	deriv := 1 / math.Sqrt(deriv1)
160	return Number{
161		Real:    fn,
162		E1mag:   deriv * d.E1mag,
163		E2mag:   deriv * d.E2mag,
164		E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(-d.Real*(deriv/deriv1)),
165	}
166}
167
168// Atanh returns the inverse hyperbolic tangent of d.
169//
170// Special cases are:
171//	Atanh(1) = +Inf
172//	Atanh(±0) = (±0+Nϵ₁+Nϵ₂±0ϵ₁ϵ₂)
173//	Atanh(-1) = -Inf
174//	Atanh(x) = NaN if x < -1 or x > 1
175//	Atanh(NaN) = NaN
176func Atanh(d Number) Number {
177	if d.Real == 0 {
178		return Number{
179			Real:    d.Real,
180			E1mag:   d.E1mag,
181			E2mag:   d.E2mag,
182			E1E2mag: d.Real,
183		}
184	}
185	if math.Abs(d.Real) == 1 {
186		return Number{
187			Real:    math.Inf(int(d.Real)),
188			E1mag:   math.NaN(),
189			E2mag:   math.NaN(),
190			E1E2mag: math.Inf(int(d.Real)),
191		}
192	}
193	fn := math.Atanh(d.Real)
194	deriv1 := 1 - d.Real*d.Real
195	deriv := 1 / deriv1
196	return Number{
197		Real:    fn,
198		E1mag:   deriv * d.E1mag,
199		E2mag:   deriv * d.E2mag,
200		E1E2mag: deriv*d.E1E2mag + d.E1mag*d.E2mag*(2*d.Real/(deriv1*deriv1)),
201	}
202}
203