Home | History | Annotate | Download | only in cmplx
      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 
      5 package cmplx
      6 
      7 import "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 //   moshier (a] na-net.ornl.gov
     30 
     31 // Complex square root
     32 //
     33 // DESCRIPTION:
     34 //
     35 // If z = x + iy,  r = |z|, then
     36 //
     37 //                       1/2
     38 // Re w  =  [ (r + x)/2 ]   ,
     39 //
     40 //                       1/2
     41 // Im w  =  [ (r - x)/2 ]   .
     42 //
     43 // Cancelation error in r-x or r+x is avoided by using the
     44 // identity  2 Re w Im w  =  y.
     45 //
     46 // Note that -w is also a square root of z. The root chosen
     47 // is always in the right half plane and Im w has the same sign as y.
     48 //
     49 // ACCURACY:
     50 //
     51 //                      Relative error:
     52 // arithmetic   domain     # trials      peak         rms
     53 //    DEC       -10,+10     25000       3.2e-17     9.6e-18
     54 //    IEEE      -10,+10   1,000,000     2.9e-16     6.1e-17
     55 
     56 // Sqrt returns the square root of x.
     57 // The result r is chosen so that real(r)  0 and imag(r) has the same sign as imag(x).
     58 func Sqrt(x complex128) complex128 {
     59 	if imag(x) == 0 {
     60 		if real(x) == 0 {
     61 			return complex(0, 0)
     62 		}
     63 		if real(x) < 0 {
     64 			return complex(0, math.Sqrt(-real(x)))
     65 		}
     66 		return complex(math.Sqrt(real(x)), 0)
     67 	}
     68 	if real(x) == 0 {
     69 		if imag(x) < 0 {
     70 			r := math.Sqrt(-0.5 * imag(x))
     71 			return complex(r, -r)
     72 		}
     73 		r := math.Sqrt(0.5 * imag(x))
     74 		return complex(r, r)
     75 	}
     76 	a := real(x)
     77 	b := imag(x)
     78 	var scale float64
     79 	// Rescale to avoid internal overflow or underflow.
     80 	if math.Abs(a) > 4 || math.Abs(b) > 4 {
     81 		a *= 0.25
     82 		b *= 0.25
     83 		scale = 2
     84 	} else {
     85 		a *= 1.8014398509481984e16 // 2**54
     86 		b *= 1.8014398509481984e16
     87 		scale = 7.450580596923828125e-9 // 2**-27
     88 	}
     89 	r := math.Hypot(a, b)
     90 	var t float64
     91 	if a > 0 {
     92 		t = math.Sqrt(0.5*r + 0.5*a)
     93 		r = scale * math.Abs((0.5*b)/t)
     94 		t *= scale
     95 	} else {
     96 		r = math.Sqrt(0.5*r - 0.5*a)
     97 		t = scale * math.Abs((0.5*b)/r)
     98 		r *= scale
     99 	}
    100 	if b < 0 {
    101 		return complex(t, -r)
    102 	}
    103 	return complex(t, r)
    104 }
    105