1// Copyright 2010 The Go 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 cmplx 6 7import "math" 8 9// The original C code, the long comment, and the constants 10// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c. 11// The go code is a simplified version of the original C. 12// 13// Cephes Math Library Release 2.8: June, 2000 14// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier 15// 16// The readme file at http://netlib.sandia.gov/cephes/ says: 17// Some software in this archive may be from the book _Methods and 18// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster 19// International, 1989) or from the Cephes Mathematical Library, a 20// commercial product. In either event, it is copyrighted by the author. 21// What you see here may be used freely but it comes with no support or 22// guarantee. 23// 24// The two known misprints in the book are repaired here in the 25// source listings for the gamma function and the incomplete beta 26// integral. 27// 28// Stephen L. Moshier 29// [email protected] 30 31// Complex circular arc sine 32// 33// DESCRIPTION: 34// 35// Inverse complex sine: 36// 2 37// w = -i clog( iz + csqrt( 1 - z ) ). 38// 39// casin(z) = -i casinh(iz) 40// 41// ACCURACY: 42// 43// Relative error: 44// arithmetic domain # trials peak rms 45// DEC -10,+10 10100 2.1e-15 3.4e-16 46// IEEE -10,+10 30000 2.2e-14 2.7e-15 47// Larger relative error can be observed for z near zero. 48// Also tested by csin(casin(z)) = z. 49 50// Asin returns the inverse sine of x. 51func Asin(x complex128) complex128 { 52 switch re, im := real(x), imag(x); { 53 case im == 0 && math.Abs(re) <= 1: 54 return complex(math.Asin(re), im) 55 case re == 0 && math.Abs(im) <= 1: 56 return complex(re, math.Asinh(im)) 57 case math.IsNaN(im): 58 switch { 59 case re == 0: 60 return complex(re, math.NaN()) 61 case math.IsInf(re, 0): 62 return complex(math.NaN(), re) 63 default: 64 return NaN() 65 } 66 case math.IsInf(im, 0): 67 switch { 68 case math.IsNaN(re): 69 return x 70 case math.IsInf(re, 0): 71 return complex(math.Copysign(math.Pi/4, re), im) 72 default: 73 return complex(math.Copysign(0, re), im) 74 } 75 case math.IsInf(re, 0): 76 return complex(math.Copysign(math.Pi/2, re), math.Copysign(re, im)) 77 } 78 ct := complex(-imag(x), real(x)) // i * x 79 xx := x * x 80 x1 := complex(1-real(xx), -imag(xx)) // 1 - x*x 81 x2 := Sqrt(x1) // x2 = sqrt(1 - x*x) 82 w := Log(ct + x2) 83 return complex(imag(w), -real(w)) // -i * w 84} 85 86// Asinh returns the inverse hyperbolic sine of x. 87func Asinh(x complex128) complex128 { 88 switch re, im := real(x), imag(x); { 89 case im == 0 && math.Abs(re) <= 1: 90 return complex(math.Asinh(re), im) 91 case re == 0 && math.Abs(im) <= 1: 92 return complex(re, math.Asin(im)) 93 case math.IsInf(re, 0): 94 switch { 95 case math.IsInf(im, 0): 96 return complex(re, math.Copysign(math.Pi/4, im)) 97 case math.IsNaN(im): 98 return x 99 default: 100 return complex(re, math.Copysign(0.0, im)) 101 } 102 case math.IsNaN(re): 103 switch { 104 case im == 0: 105 return x 106 case math.IsInf(im, 0): 107 return complex(im, re) 108 default: 109 return NaN() 110 } 111 case math.IsInf(im, 0): 112 return complex(math.Copysign(im, re), math.Copysign(math.Pi/2, im)) 113 } 114 xx := x * x 115 x1 := complex(1+real(xx), imag(xx)) // 1 + x*x 116 return Log(x + Sqrt(x1)) // log(x + sqrt(1 + x*x)) 117} 118 119// Complex circular arc cosine 120// 121// DESCRIPTION: 122// 123// w = arccos z = PI/2 - arcsin z. 124// 125// ACCURACY: 126// 127// Relative error: 128// arithmetic domain # trials peak rms 129// DEC -10,+10 5200 1.6e-15 2.8e-16 130// IEEE -10,+10 30000 1.8e-14 2.2e-15 131 132// Acos returns the inverse cosine of x. 133func Acos(x complex128) complex128 { 134 w := Asin(x) 135 return complex(math.Pi/2-real(w), -imag(w)) 136} 137 138// Acosh returns the inverse hyperbolic cosine of x. 139func Acosh(x complex128) complex128 { 140 if x == 0 { 141 return complex(0, math.Copysign(math.Pi/2, imag(x))) 142 } 143 w := Acos(x) 144 if imag(w) <= 0 { 145 return complex(-imag(w), real(w)) // i * w 146 } 147 return complex(imag(w), -real(w)) // -i * w 148} 149 150// Complex circular arc tangent 151// 152// DESCRIPTION: 153// 154// If 155// z = x + iy, 156// 157// then 158// 1 ( 2x ) 159// Re w = - arctan(-----------) + k PI 160// 2 ( 2 2) 161// (1 - x - y ) 162// 163// ( 2 2) 164// 1 (x + (y+1) ) 165// Im w = - log(------------) 166// 4 ( 2 2) 167// (x + (y-1) ) 168// 169// Where k is an arbitrary integer. 170// 171// catan(z) = -i catanh(iz). 172// 173// ACCURACY: 174// 175// Relative error: 176// arithmetic domain # trials peak rms 177// DEC -10,+10 5900 1.3e-16 7.8e-18 178// IEEE -10,+10 30000 2.3e-15 8.5e-17 179// The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, 180// had peak relative error 1.5e-16, rms relative error 181// 2.9e-17. See also clog(). 182 183// Atan returns the inverse tangent of x. 184func Atan(x complex128) complex128 { 185 switch re, im := real(x), imag(x); { 186 case im == 0: 187 return complex(math.Atan(re), im) 188 case re == 0 && math.Abs(im) <= 1: 189 return complex(re, math.Atanh(im)) 190 case math.IsInf(im, 0) || math.IsInf(re, 0): 191 if math.IsNaN(re) { 192 return complex(math.NaN(), math.Copysign(0, im)) 193 } 194 return complex(math.Copysign(math.Pi/2, re), math.Copysign(0, im)) 195 case math.IsNaN(re) || math.IsNaN(im): 196 return NaN() 197 } 198 x2 := real(x) * real(x) 199 a := 1 - x2 - imag(x)*imag(x) 200 if a == 0 { 201 return NaN() 202 } 203 t := 0.5 * math.Atan2(2*real(x), a) 204 w := reducePi(t) 205 206 t = imag(x) - 1 207 b := x2 + t*t 208 if b == 0 { 209 return NaN() 210 } 211 t = imag(x) + 1 212 c := (x2 + t*t) / b 213 return complex(w, 0.25*math.Log(c)) 214} 215 216// Atanh returns the inverse hyperbolic tangent of x. 217func Atanh(x complex128) complex128 { 218 z := complex(-imag(x), real(x)) // z = i * x 219 z = Atan(z) 220 return complex(imag(z), -real(z)) // z = -i * z 221} 222