| 1 | module 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 | |
| 48 | const morebits = 6.123233995736765886130e-17 |
| 49 | const tan3pio8 = 2.41421356237309504880 |
| 50 | |
| 51 | // xatan evaluates a series valid in the range [0, 0.66]. |
| 52 | @[inline] |
| 53 | fn 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] |
| 74 | fn 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 |
| 89 | pub 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 |
| 121 | pub 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 | /* |
| 162 | Floating-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 |
| 173 | pub 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] |
| 203 | pub 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 | |