v / vlib / math / invtrig.v
214 lines · 204 sloc · 5.03 KB · 390efe46a1f46f302ae98c803b8ffbbb333fdb28
Raw
1module math
2
3// The original C code, the long comment, and the constants below were
4// from http://netlib.sandia.gov/cephes/cmath/atan.c, available from
5// http://www.netlib.org/cephes/ctgz.
6// The go code is a version of the original C.
7//
8// atan.c
9// Inverse circular tangent (arctangent)
10//
11// SYNOPSIS:
12// double x, y, atan()
13// y = atan( x )
14//
15// DESCRIPTION:
16// Returns radian angle between -pi/2.0 and +pi/2.0 whose tangent is x.
17//
18// Range reduction is from three intervals into the interval from zero to 0.66.
19// The approximant uses a rational function of degree 4/5 of the form
20// x + x**3 P(x)/Q(x).
21//
22// ACCURACY:
23// Relative error:
24// arithmetic domain # trials peak rms
25// DEC -10, 10 50000 2.4e-17 8.3e-18
26// IEEE -10, 10 10^6 1.8e-16 5.0e-17
27//
28// Cephes Math Library Release 2.8: June, 2000
29// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
30//
31// The readme file at http://netlib.sandia.gov/cephes/ says:
32// Some software in this archive may be from the book _Methods and
33// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
34// International, 1989) or from the Cephes Mathematical Library, a
35// commercial product. In either event, it is copyrighted by the author.
36// What you see here may be used freely but it comes with no support or
37// guarantee.
38//
39// The two known misprints in the book are repaired here in the
40// source listings for the gamma function and the incomplete beta
41// integral.
42//
43// Stephen L. Moshier
44// [email protected]
45// pi/2.0 = PIO2 + morebits
46// tan3pio8 = tan(3*pi/8)
47
48const morebits = 6.123233995736765886130e-17
49const tan3pio8 = 2.41421356237309504880
50
51// xatan evaluates a series valid in the range [0, 0.66].
52@[inline]
53fn xatan(x f64) f64 {
54 xatan_p0 := -8.750608600031904122785e-01
55 xatan_p1 := -1.615753718733365076637e+01
56 xatan_p2 := -7.500855792314704667340e+01
57 xatan_p3 := -1.228866684490136173410e+02
58 xatan_p4 := -6.485021904942025371773e+01
59 xatan_q0 := 2.485846490142306297962e+01
60 xatan_q1 := 1.650270098316988542046e+02
61 xatan_q2 := 4.328810604912902668951e+02
62 xatan_q3 := 4.853903996359136964868e+02
63 xatan_q4 := 1.945506571482613964425e+02
64 mut z := x * x
65 z = z * ((((xatan_p0 * z + xatan_p1) * z + xatan_p2) * z + xatan_p3) * z + xatan_p4) / (
66 ((((z + xatan_q0) * z + xatan_q1) * z + xatan_q2) * z + xatan_q3) * z + xatan_q4)
67 z = x * z + x
68 return z
69}
70
71// satan reduces its argument (known to be positive)
72// to the range [0, 0.66] and calls xatan.
73@[inline]
74fn satan(x f64) f64 {
75 if x <= 0.66 {
76 return xatan(x)
77 }
78 if x > tan3pio8 {
79 return pi / 2.0 - xatan(1.0 / x) + f64(morebits)
80 }
81 return pi / 4 + xatan((x - 1.0) / (x + 1.0)) + 0.5 * f64(morebits)
82}
83
84// atan returns the arctangent, in radians, of x.
85//
86// special cases are:
87// atan(±0) = ±0
88// atan(±inf) = ±pi/2.0
89pub fn atan(x f64) f64 {
90 if x == 0 {
91 return x
92 }
93 if x > 0 {
94 return satan(x)
95 }
96 return -satan(-x)
97}
98
99// atan2 returns the arc tangent of y/x, using
100// the signs of the two to determine the quadrant
101// of the return value.
102//
103// special cases are (in order):
104// atan2(y, nan) = nan
105// atan2(nan, x) = nan
106// atan2(+0, x>=0) = +0
107// atan2(-0, x>=0) = -0
108// atan2(+0, x<=-0) = +pi
109// atan2(-0, x<=-0) = -pi
110// atan2(y>0, 0) = +pi/2.0
111// atan2(y<0, 0) = -pi/2.0
112// atan2(+inf, +inf) = +pi/4
113// atan2(-inf, +inf) = -pi/4
114// atan2(+inf, -inf) = 3pi/4
115// atan2(-inf, -inf) = -3pi/4
116// atan2(y, +inf) = 0
117// atan2(y>0, -inf) = +pi
118// atan2(y<0, -inf) = -pi
119// atan2(+inf, x) = +pi/2.0
120// atan2(-inf, x) = -pi/2.0
121pub fn atan2(y f64, x f64) f64 {
122 // special cases
123 if is_nan(y) || is_nan(x) {
124 return nan()
125 }
126 if y == 0.0 {
127 if x >= 0 && !signbit(x) {
128 return copysign(0, y)
129 }
130 return copysign(pi, y)
131 }
132 if x == 0.0 {
133 return copysign(pi / 2.0, y)
134 }
135 if is_inf(x, 0) {
136 if is_inf(x, 1) {
137 if is_inf(y, 0) {
138 return copysign(pi / 4, y)
139 }
140 return copysign(0, y)
141 }
142 if is_inf(y, 0) {
143 return copysign(3.0 * pi / 4.0, y)
144 }
145 return copysign(pi, y)
146 }
147 if is_inf(y, 0) {
148 return copysign(pi / 2.0, y)
149 }
150 // Call atan and determine the quadrant.
151 q := atan(y / x)
152 if x < 0 {
153 if q <= 0 {
154 return q + pi
155 }
156 return q - pi
157 }
158 return q
159}
160
161/*
162Floating-point arcsine and arccosine.
163
164 They are implemented by computing the arctangent
165 after appropriate range reduction.
166*/
167
168// asin returns the arcsine, in radians, of x.
169//
170// special cases are:
171// asin(±0) = ±0
172// asin(x) = nan if x < -1 or x > 1
173pub fn asin(x_ f64) f64 {
174 mut x := x_
175 if x == 0.0 {
176 return x // special case
177 }
178 mut neg := false
179 if x < 0.0 {
180 x = -x
181 neg = true
182 }
183 if x > 1.0 {
184 return nan() // special case
185 }
186 mut temp := sqrt(1.0 - x * x)
187 if x > 0.7 {
188 temp = pi / 2.0 - satan(temp / x)
189 } else {
190 temp = satan(x / temp)
191 }
192 if neg {
193 temp = -temp
194 }
195 return temp
196}
197
198// acos returns the arccosine, in radians, of x.
199//
200// special case is:
201// acos(x) = nan if x < -1 or x > 1
202@[inline]
203pub fn acos(x f64) f64 {
204 if x < -1.0 || x > 1.0 {
205 return nan()
206 }
207 if x > 0.5 {
208 return f64(2.0) * asin(sqrt(0.5 - 0.5 * x))
209 }
210 mut z := pi / f64(4.0) - asin(x)
211 z = z + morebits
212 z = z + pi / f64(4.0)
213 return z
214}
215