]> Cypherpunks repositories - gostls13.git/commitdiff
math/cmplx: handle special cases
authorBrian Kessler <brian.m.kessler@gmail.com>
Sat, 2 Feb 2019 06:08:45 +0000 (23:08 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 7 Nov 2019 19:48:30 +0000 (19:48 +0000)
Implement special case handling and testing to ensure
conformance with the C99 standard annex G.6 Complex arithmetic.

Fixes #29320

Change-Id: Ieb0527191dd7fdea5b1aecb42b9e23aae3f74260
Reviewed-on: https://go-review.googlesource.com/c/go/+/169501
Run-TryBot: Brian Kessler <brian.m.kessler@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/math/cmplx/abs.go
src/math/cmplx/asin.go
src/math/cmplx/cmath_test.go
src/math/cmplx/exp.go
src/math/cmplx/log.go
src/math/cmplx/sin.go
src/math/cmplx/sqrt.go
src/math/cmplx/tan.go

index f3cd1073ed27a1991839c0216e1432921b7ca4c2..2f89d1bcfc721e9ce7d9647771c3cca929915f4f 100644 (file)
@@ -3,7 +3,8 @@
 // license that can be found in the LICENSE file.
 
 // Package cmplx provides basic constants and mathematical functions for
-// complex numbers.
+// complex numbers. Special case handling conforms to the C99 standard
+// Annex G IEC 60559-compatible complex arithmetic.
 package cmplx
 
 import "math"
index 062f324ce2cec423e0bdcf77fe4bde0d2786decd..54f41f44a69d789c25d82d908fa36d651a9a9ad8 100644 (file)
@@ -49,8 +49,31 @@ import "math"
 
 // Asin returns the inverse sine of x.
 func Asin(x complex128) complex128 {
-       if imag(x) == 0 && math.Abs(real(x)) <= 1 {
-               return complex(math.Asin(real(x)), imag(x))
+       switch re, im := real(x), imag(x); {
+       case im == 0 && math.Abs(re) <= 1:
+               return complex(math.Asin(re), im)
+       case re == 0 && math.Abs(im) <= 1:
+               return complex(re, math.Asinh(im))
+       case math.IsNaN(im):
+               switch {
+               case re == 0:
+                       return complex(re, math.NaN())
+               case math.IsInf(re, 0):
+                       return complex(math.NaN(), re)
+               default:
+                       return NaN()
+               }
+       case math.IsInf(im, 0):
+               switch {
+               case math.IsNaN(re):
+                       return x
+               case math.IsInf(re, 0):
+                       return complex(math.Copysign(math.Pi/4, re), im)
+               default:
+                       return complex(math.Copysign(0, re), im)
+               }
+       case math.IsInf(re, 0):
+               return complex(math.Copysign(math.Pi/2, re), math.Copysign(re, im))
        }
        ct := complex(-imag(x), real(x)) // i * x
        xx := x * x
@@ -62,8 +85,31 @@ func Asin(x complex128) complex128 {
 
 // Asinh returns the inverse hyperbolic sine of x.
 func Asinh(x complex128) complex128 {
-       if imag(x) == 0 && math.Abs(real(x)) <= 1 {
-               return complex(math.Asinh(real(x)), imag(x))
+       switch re, im := real(x), imag(x); {
+       case im == 0 && math.Abs(re) <= 1:
+               return complex(math.Asinh(re), im)
+       case re == 0 && math.Abs(im) <= 1:
+               return complex(re, math.Asin(im))
+       case math.IsInf(re, 0):
+               switch {
+               case math.IsInf(im, 0):
+                       return complex(re, math.Copysign(math.Pi/4, im))
+               case math.IsNaN(im):
+                       return x
+               default:
+                       return complex(re, math.Copysign(0.0, im))
+               }
+       case math.IsNaN(re):
+               switch {
+               case im == 0:
+                       return x
+               case math.IsInf(im, 0):
+                       return complex(im, re)
+               default:
+                       return NaN()
+               }
+       case math.IsInf(im, 0):
+               return complex(math.Copysign(im, re), math.Copysign(math.Pi/2, im))
        }
        xx := x * x
        x1 := complex(1+real(xx), imag(xx)) // 1 + x*x
@@ -91,6 +137,9 @@ func Acos(x complex128) complex128 {
 
 // Acosh returns the inverse hyperbolic cosine of x.
 func Acosh(x complex128) complex128 {
+       if x == 0 {
+               return complex(0, math.Copysign(math.Pi/2, imag(x)))
+       }
        w := Acos(x)
        if imag(w) <= 0 {
                return complex(-imag(w), real(w)) // i * w
@@ -133,6 +182,17 @@ func Acosh(x complex128) complex128 {
 
 // Atan returns the inverse tangent of x.
 func Atan(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case im == 0:
+               return complex(math.Atan(re), im)
+       case re == 0 && math.Abs(im) <= 1:
+               return complex(re, math.Atanh(im))
+       case math.IsInf(im, 0) || math.IsInf(re, 0):
+               if math.IsNaN(re) {
+                       return complex(math.NaN(), math.Copysign(0, im))
+               }
+               return complex(math.Copysign(math.Pi/2, re), math.Copysign(0, im))
+       }
        x2 := real(x) * real(x)
        a := 1 - x2 - imag(x)*imag(x)
        if a == 0 {
index 57ba76a76711934b1fe8507738bcb3ffe37600b7..d2301cacf59824998065f617237bc7318785f8e1 100644 (file)
@@ -291,48 +291,190 @@ var tanh = []complex128{
        (-1.0000000491604982429364892e+00 - 2.901873195374433112227349e-08i),
 }
 
-// special cases
+// special cases conform to C99 standard appendix G.6 Complex arithmetic
+var inf, nan = math.Inf(1), math.NaN()
+
 var vcAbsSC = []complex128{
        NaN(),
 }
 var absSC = []float64{
        math.NaN(),
 }
-var vcAcosSC = []complex128{
-       NaN(),
-}
-var acosSC = []complex128{
-       NaN(),
-}
-var vcAcoshSC = []complex128{
-       NaN(),
-}
-var acoshSC = []complex128{
-       NaN(),
-}
-var vcAsinSC = []complex128{
-       NaN(),
-}
-var asinSC = []complex128{
-       NaN(),
-}
-var vcAsinhSC = []complex128{
-       NaN(),
-}
-var asinhSC = []complex128{
-       NaN(),
-}
-var vcAtanSC = []complex128{
-       NaN(),
-}
-var atanSC = []complex128{
-       NaN(),
-}
-var vcAtanhSC = []complex128{
-       NaN(),
-}
-var atanhSC = []complex128{
-       NaN(),
+var acosSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.1.1
+       {complex(zero, zero),
+               complex(math.Pi/2, -zero)},
+       {complex(-zero, zero),
+               complex(math.Pi/2, -zero)},
+       {complex(zero, nan),
+               complex(math.Pi/2, nan)},
+       {complex(-zero, nan),
+               complex(math.Pi/2, nan)},
+       {complex(1.0, inf),
+               complex(math.Pi/2, -inf)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(-inf, 1.0),
+               complex(math.Pi, -inf)},
+       {complex(inf, 1.0),
+               complex(0.0, -inf)},
+       {complex(-inf, inf),
+               complex(3*math.Pi/4, -inf)},
+       {complex(inf, inf),
+               complex(math.Pi/4, -inf)},
+       {complex(inf, nan),
+               complex(nan, -inf)}, // imaginary sign unspecified
+       {complex(-inf, nan),
+               complex(nan, inf)}, // imaginary sign unspecified
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(nan, -inf)},
+       {NaN(),
+               NaN()},
+}
+var acoshSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.2.1
+       {complex(zero, zero),
+               complex(zero, math.Pi/2)},
+       {complex(-zero, zero),
+               complex(zero, math.Pi/2)},
+       {complex(1.0, inf),
+               complex(inf, math.Pi/2)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(-inf, 1.0),
+               complex(inf, math.Pi)},
+       {complex(inf, 1.0),
+               complex(inf, zero)},
+       {complex(-inf, inf),
+               complex(inf, 3*math.Pi/4)},
+       {complex(inf, inf),
+               complex(inf, math.Pi/4)},
+       {complex(inf, nan),
+               complex(inf, nan)},
+       {complex(-inf, nan),
+               complex(inf, nan)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(inf, nan)},
+       {NaN(),
+               NaN()},
+}
+var asinSC = []struct {
+       in,
+       want complex128
+}{
+       // Derived from Asin(z) = -i * Asinh(i * z), G.6 #7
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(1.0, inf),
+               complex(0, inf)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, 1),
+               complex(math.Pi/2, inf)},
+       {complex(inf, inf),
+               complex(math.Pi/4, inf)},
+       {complex(inf, nan),
+               complex(nan, inf)}, // imaginary sign unspecified
+       {complex(nan, zero),
+               NaN()},
+       {complex(nan, 1),
+               NaN()},
+       {complex(nan, inf),
+               complex(nan, inf)},
+       {NaN(),
+               NaN()},
+}
+var asinhSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.2.2
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(1.0, inf),
+               complex(inf, math.Pi/2)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, 1.0),
+               complex(inf, zero)},
+       {complex(inf, inf),
+               complex(inf, math.Pi/4)},
+       {complex(inf, nan),
+               complex(inf, nan)},
+       {complex(nan, zero),
+               complex(nan, zero)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(inf, nan)}, // sign of real part unspecified
+       {NaN(),
+               NaN()},
+}
+var atanSC = []struct {
+       in,
+       want complex128
+}{
+       // Derived from Atan(z) = -i * Atanh(i * z), G.6 #7
+       {complex(0, zero),
+               complex(0, zero)},
+       {complex(0, nan),
+               NaN()},
+       {complex(1.0, zero),
+               complex(math.Pi/4, zero)},
+       {complex(1.0, inf),
+               complex(math.Pi/2, zero)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, 1),
+               complex(math.Pi/2, zero)},
+       {complex(inf, inf),
+               complex(math.Pi/2, zero)},
+       {complex(inf, nan),
+               complex(math.Pi/2, zero)},
+       {complex(nan, 1),
+               NaN()},
+       {complex(nan, inf),
+               complex(nan, zero)},
+       {NaN(),
+               NaN()},
+}
+var atanhSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.2.3
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(zero, nan),
+               complex(zero, nan)},
+       {complex(1.0, zero),
+               complex(inf, zero)},
+       {complex(1.0, inf),
+               complex(0, math.Pi/2)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, 1.0),
+               complex(zero, math.Pi/2)},
+       {complex(inf, inf),
+               complex(zero, math.Pi/2)},
+       {complex(inf, nan),
+               complex(0, nan)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(zero, math.Pi/2)}, // sign of real part not specified.
+       {NaN(),
+               NaN()},
 }
 var vcConjSC = []complex128{
        NaN(),
@@ -340,23 +482,105 @@ var vcConjSC = []complex128{
 var conjSC = []complex128{
        NaN(),
 }
-var vcCosSC = []complex128{
-       NaN(),
-}
-var cosSC = []complex128{
-       NaN(),
-}
-var vcCoshSC = []complex128{
-       NaN(),
-}
-var coshSC = []complex128{
-       NaN(),
-}
-var vcExpSC = []complex128{
-       NaN(),
-}
-var expSC = []complex128{
-       NaN(),
+var cosSC = []struct {
+       in,
+       want complex128
+}{
+       // Derived from Cos(z) = Cosh(i * z), G.6 #7
+       {complex(zero, zero),
+               complex(1.0, -zero)},
+       {complex(zero, inf),
+               complex(inf, -zero)},
+       {complex(zero, nan),
+               complex(nan, zero)}, // imaginary sign unspecified
+       {complex(1.0, inf),
+               complex(inf, -inf)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, zero),
+               complex(nan, -zero)},
+       {complex(inf, 1.0),
+               NaN()},
+       {complex(inf, inf),
+               complex(inf, nan)}, // real sign unspecified
+       {complex(inf, nan),
+               NaN()},
+       {complex(nan, zero),
+               complex(nan, -zero)}, // imaginary sign unspecified
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(inf, nan)},
+       {NaN(),
+               NaN()},
+}
+var coshSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.2.4
+       {complex(zero, zero),
+               complex(1.0, zero)},
+       {complex(zero, inf),
+               complex(nan, zero)}, // imaginary sign unspecified
+       {complex(zero, nan),
+               complex(nan, zero)}, // imaginary sign unspecified
+       {complex(1.0, inf),
+               NaN()},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, zero),
+               complex(inf, zero)},
+       {complex(inf, 1.0),
+               complex(inf*math.Cos(1.0), inf*math.Sin(1.0))}, // +inf  cis(y)
+       {complex(inf, inf),
+               complex(inf, nan)}, // real sign unspecified
+       {complex(inf, nan),
+               complex(inf, nan)},
+       {complex(nan, zero),
+               complex(nan, zero)}, // imaginary sign unspecified
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               NaN()},
+       {NaN(),
+               NaN()},
+}
+var expSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.3.1
+       {complex(zero, zero),
+               complex(1.0, zero)},
+       {complex(-zero, zero),
+               complex(1.0, zero)},
+       {complex(1.0, inf),
+               NaN()},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, zero),
+               complex(inf, zero)},
+       {complex(-inf, 1.0),
+               complex(math.Copysign(0.0, math.Cos(1.0)), math.Copysign(0.0, math.Sin(1.0)))}, // +0 cis(y)
+       {complex(inf, 1.0),
+               complex(inf*math.Cos(1.0), inf*math.Sin(1.0))}, // +inf  cis(y)
+       {complex(-inf, inf),
+               complex(zero, zero)}, // real and imaginary sign unspecified
+       {complex(inf, inf),
+               complex(inf, nan)}, // real sign unspecified
+       {complex(-inf, nan),
+               complex(zero, zero)}, // real and imaginary sign unspecified
+       {complex(inf, nan),
+               complex(inf, nan)}, // real sign unspecified
+       {complex(nan, zero),
+               complex(nan, zero)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               NaN()},
+       {NaN(),
+               NaN()},
 }
 var vcIsNaNSC = []complex128{
        complex(math.Inf(-1), math.Inf(-1)),
@@ -380,17 +604,70 @@ var isNaNSC = []bool{
        false,
        true,
 }
-var vcLogSC = []complex128{
-       NaN(),
-}
-var logSC = []complex128{
-       NaN(),
-}
-var vcLog10SC = []complex128{
-       NaN(),
-}
-var log10SC = []complex128{
-       NaN(),
+
+var logSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.3.2
+       {complex(zero, zero),
+               complex(-inf, zero)},
+       {complex(-zero, zero),
+               complex(-inf, math.Pi)},
+       {complex(1.0, inf),
+               complex(inf, math.Pi/2)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(-inf, 1.0),
+               complex(inf, math.Pi)},
+       {complex(inf, 1.0),
+               complex(inf, 0.0)},
+       {complex(-inf, inf),
+               complex(inf, 3*math.Pi/4)},
+       {complex(inf, inf),
+               complex(inf, math.Pi/4)},
+       {complex(-inf, nan),
+               complex(inf, nan)},
+       {complex(inf, nan),
+               complex(inf, nan)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(inf, nan)},
+       {NaN(),
+               NaN()},
+}
+var log10SC = []struct {
+       in,
+       want complex128
+}{
+       // derived from Log special cases via Log10(x) = math.Log10E*Log(x)
+       {complex(zero, zero),
+               complex(-inf, zero)},
+       {complex(-zero, zero),
+               complex(-inf, float64(math.Log10E)*float64(math.Pi))},
+       {complex(1.0, inf),
+               complex(inf, float64(math.Log10E)*float64(math.Pi/2))},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(-inf, 1.0),
+               complex(inf, float64(math.Log10E)*float64(math.Pi))},
+       {complex(inf, 1.0),
+               complex(inf, 0.0)},
+       {complex(-inf, inf),
+               complex(inf, float64(math.Log10E)*float64(3*math.Pi/4))},
+       {complex(inf, inf),
+               complex(inf, float64(math.Log10E)*float64(math.Pi/4))},
+       {complex(-inf, nan),
+               complex(inf, nan)},
+       {complex(inf, nan),
+               complex(inf, nan)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(inf, nan)},
+       {NaN(),
+               NaN()},
 }
 var vcPolarSC = []complex128{
        NaN(),
@@ -406,35 +683,153 @@ var powSC = []complex128{
        NaN(),
        NaN(),
 }
-var vcSinSC = []complex128{
-       NaN(),
+var sinSC = []struct {
+       in,
+       want complex128
+}{
+       // Derived from Sin(z) = -i * Sinh(i * z), G.6 #7
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(zero, inf),
+               complex(zero, inf)},
+       {complex(zero, nan),
+               complex(zero, nan)},
+       {complex(1.0, inf),
+               complex(inf, inf)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, zero),
+               complex(nan, zero)},
+       {complex(inf, 1.0),
+               NaN()},
+       {complex(inf, inf),
+               complex(nan, inf)},
+       {complex(inf, nan),
+               NaN()},
+       {complex(nan, zero),
+               complex(nan, zero)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(nan, inf)},
+       {NaN(),
+               NaN()},
 }
-var sinSC = []complex128{
-       NaN(),
-}
-var vcSinhSC = []complex128{
-       NaN(),
-}
-var sinhSC = []complex128{
-       NaN(),
-}
-var vcSqrtSC = []complex128{
-       NaN(),
-}
-var sqrtSC = []complex128{
-       NaN(),
-}
-var vcTanSC = []complex128{
-       NaN(),
-}
-var tanSC = []complex128{
-       NaN(),
-}
-var vcTanhSC = []complex128{
-       NaN(),
+
+var sinhSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.2.5
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(zero, inf),
+               complex(zero, nan)}, // real sign unspecified
+       {complex(zero, nan),
+               complex(zero, nan)}, // real sign unspecified
+       {complex(1.0, inf),
+               NaN()},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, zero),
+               complex(inf, zero)},
+       {complex(inf, 1.0),
+               complex(inf*math.Cos(1.0), inf*math.Sin(1.0))}, // +inf  cis(y)
+       {complex(inf, inf),
+               complex(inf, nan)}, // real sign unspecified
+       {complex(inf, nan),
+               complex(inf, nan)}, // real sign unspecified
+       {complex(nan, zero),
+               complex(nan, zero)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               NaN()},
+       {NaN(),
+               NaN()},
 }
-var tanhSC = []complex128{
-       NaN(),
+
+var sqrtSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.4.2
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(-zero, zero),
+               complex(zero, zero)},
+       {complex(1.0, inf),
+               complex(inf, inf)},
+       {complex(nan, inf),
+               complex(inf, inf)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(-inf, 1.0),
+               complex(zero, inf)},
+       {complex(inf, 1.0),
+               complex(inf, zero)},
+       {complex(-inf, nan),
+               complex(nan, inf)}, // imaginary sign unspecified
+       {complex(inf, nan),
+               complex(inf, nan)},
+       {complex(nan, 1.0),
+               NaN()},
+       {NaN(),
+               NaN()},
+}
+var tanSC = []struct {
+       in,
+       want complex128
+}{
+       // Derived from Tan(z) = -i * Tanh(i * z), G.6 #7
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(zero, nan),
+               complex(zero, nan)},
+       {complex(1.0, inf),
+               complex(zero, 1.0)},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, 1.0),
+               NaN()},
+       {complex(inf, inf),
+               complex(zero, 1.0)},
+       {complex(inf, nan),
+               NaN()},
+       {complex(nan, zero),
+               NaN()},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               complex(zero, 1.0)},
+       {NaN(),
+               NaN()},
+}
+var tanhSC = []struct {
+       in,
+       want complex128
+}{
+       // G.6.2.6
+       {complex(zero, zero),
+               complex(zero, zero)},
+       {complex(1.0, inf),
+               NaN()},
+       {complex(1.0, nan),
+               NaN()},
+       {complex(inf, 1.0),
+               complex(1.0, math.Copysign(0.0, math.Sin(2*1.0)))}, // 1 + i 0 sin(2y)
+       {complex(inf, inf),
+               complex(1.0, zero)}, // imaginary sign unspecified
+       {complex(inf, nan),
+               complex(1.0, zero)}, // imaginary sign unspecified
+       {complex(nan, zero),
+               complex(nan, zero)},
+       {complex(nan, 1.0),
+               NaN()},
+       {complex(nan, inf),
+               NaN()},
+       {NaN(),
+               NaN()},
 }
 
 // branch cut continuity checks
@@ -496,13 +891,7 @@ func cTolerance(a, b complex128, e float64) bool {
 func cSoclose(a, b complex128, e float64) bool { return cTolerance(a, b, e) }
 func cVeryclose(a, b complex128) bool          { return cTolerance(a, b, 4e-16) }
 func cAlike(a, b complex128) bool {
-       switch {
-       case IsNaN(a) && IsNaN(b):
-               return true
-       case a == b:
-               return math.Signbit(real(a)) == math.Signbit(real(b)) && math.Signbit(imag(a)) == math.Signbit(imag(b))
-       }
-       return false
+       return alike(real(a), real(b)) && alike(imag(a), imag(b))
 }
 
 func TestAbs(t *testing.T) {
@@ -523,9 +912,13 @@ func TestAcos(t *testing.T) {
                        t.Errorf("Acos(%g) = %g, want %g", vc[i], f, acos[i])
                }
        }
-       for i := 0; i < len(vcAcosSC); i++ {
-               if f := Acos(vcAcosSC[i]); !cAlike(acosSC[i], f) {
-                       t.Errorf("Acos(%g) = %g, want %g", vcAcosSC[i], f, acosSC[i])
+       for _, v := range acosSC {
+               if f := Acos(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Acos(%g) = %g, want %g", v.in, f, v.want)
+               }
+               // Acos(Conj(z))  == Conj(Acos(z))
+               if f := Acos(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Acos(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
                }
        }
        for _, pt := range branchPoints {
@@ -540,10 +933,15 @@ func TestAcosh(t *testing.T) {
                        t.Errorf("Acosh(%g) = %g, want %g", vc[i], f, acosh[i])
                }
        }
-       for i := 0; i < len(vcAcoshSC); i++ {
-               if f := Acosh(vcAcoshSC[i]); !cAlike(acoshSC[i], f) {
-                       t.Errorf("Acosh(%g) = %g, want %g", vcAcoshSC[i], f, acoshSC[i])
+       for _, v := range acoshSC {
+               if f := Acosh(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Acosh(%g) = %g, want %g", v.in, f, v.want)
                }
+               // Acosh(Conj(z))  == Conj(Acosh(z))
+               if f := Acosh(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Acosh(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+
        }
        for _, pt := range branchPoints {
                if f0, f1 := Acosh(pt[0]), Acosh(pt[1]); !cVeryclose(f0, f1) {
@@ -557,9 +955,21 @@ func TestAsin(t *testing.T) {
                        t.Errorf("Asin(%g) = %g, want %g", vc[i], f, asin[i])
                }
        }
-       for i := 0; i < len(vcAsinSC); i++ {
-               if f := Asin(vcAsinSC[i]); !cAlike(asinSC[i], f) {
-                       t.Errorf("Asin(%g) = %g, want %g", vcAsinSC[i], f, asinSC[i])
+       for _, v := range asinSC {
+               if f := Asin(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Asin(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Asin(Conj(z))  == Asin(Sinh(z))
+               if f := Asin(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Asin(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Asin(-z)  == -Asin(z)
+               if f := Asin(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Asin(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
        for _, pt := range branchPoints {
@@ -574,9 +984,21 @@ func TestAsinh(t *testing.T) {
                        t.Errorf("Asinh(%g) = %g, want %g", vc[i], f, asinh[i])
                }
        }
-       for i := 0; i < len(vcAsinhSC); i++ {
-               if f := Asinh(vcAsinhSC[i]); !cAlike(asinhSC[i], f) {
-                       t.Errorf("Asinh(%g) = %g, want %g", vcAsinhSC[i], f, asinhSC[i])
+       for _, v := range asinhSC {
+               if f := Asinh(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Asinh(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Asinh(Conj(z))  == Asinh(Sinh(z))
+               if f := Asinh(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Asinh(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Asinh(-z)  == -Asinh(z)
+               if f := Asinh(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Asinh(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
        for _, pt := range branchPoints {
@@ -591,9 +1013,21 @@ func TestAtan(t *testing.T) {
                        t.Errorf("Atan(%g) = %g, want %g", vc[i], f, atan[i])
                }
        }
-       for i := 0; i < len(vcAtanSC); i++ {
-               if f := Atan(vcAtanSC[i]); !cAlike(atanSC[i], f) {
-                       t.Errorf("Atan(%g) = %g, want %g", vcAtanSC[i], f, atanSC[i])
+       for _, v := range atanSC {
+               if f := Atan(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Atan(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Atan(Conj(z))  == Conj(Atan(z))
+               if f := Atan(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Atan(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Atan(-z)  == -Atan(z)
+               if f := Atan(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Atan(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
        for _, pt := range branchPoints {
@@ -608,9 +1042,21 @@ func TestAtanh(t *testing.T) {
                        t.Errorf("Atanh(%g) = %g, want %g", vc[i], f, atanh[i])
                }
        }
-       for i := 0; i < len(vcAtanhSC); i++ {
-               if f := Atanh(vcAtanhSC[i]); !cAlike(atanhSC[i], f) {
-                       t.Errorf("Atanh(%g) = %g, want %g", vcAtanhSC[i], f, atanhSC[i])
+       for _, v := range atanhSC {
+               if f := Atanh(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Atanh(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Atanh(Conj(z))  == Conj(Atanh(z))
+               if f := Atanh(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Atanh(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Atanh(-z)  == -Atanh(z)
+               if f := Atanh(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Atanh(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
        for _, pt := range branchPoints {
@@ -637,9 +1083,21 @@ func TestCos(t *testing.T) {
                        t.Errorf("Cos(%g) = %g, want %g", vc[i], f, cos[i])
                }
        }
-       for i := 0; i < len(vcCosSC); i++ {
-               if f := Cos(vcCosSC[i]); !cAlike(cosSC[i], f) {
-                       t.Errorf("Cos(%g) = %g, want %g", vcCosSC[i], f, cosSC[i])
+       for _, v := range cosSC {
+               if f := Cos(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Cos(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Cos(Conj(z))  == Cos(Cosh(z))
+               if f := Cos(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Cos(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Cos(-z)  == Cos(z)
+               if f := Cos(-v.in); !cAlike(v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Cos(%g) = %g, want %g", -v.in, f, v.want)
                }
        }
 }
@@ -649,9 +1107,21 @@ func TestCosh(t *testing.T) {
                        t.Errorf("Cosh(%g) = %g, want %g", vc[i], f, cosh[i])
                }
        }
-       for i := 0; i < len(vcCoshSC); i++ {
-               if f := Cosh(vcCoshSC[i]); !cAlike(coshSC[i], f) {
-                       t.Errorf("Cosh(%g) = %g, want %g", vcCoshSC[i], f, coshSC[i])
+       for _, v := range coshSC {
+               if f := Cosh(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Cosh(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Cosh(Conj(z))  == Conj(Cosh(z))
+               if f := Cosh(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Cosh(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Cosh(-z)  == Cosh(z)
+               if f := Cosh(-v.in); !cAlike(v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Cosh(%g) = %g, want %g", -v.in, f, v.want)
                }
        }
 }
@@ -661,9 +1131,13 @@ func TestExp(t *testing.T) {
                        t.Errorf("Exp(%g) = %g, want %g", vc[i], f, exp[i])
                }
        }
-       for i := 0; i < len(vcExpSC); i++ {
-               if f := Exp(vcExpSC[i]); !cAlike(expSC[i], f) {
-                       t.Errorf("Exp(%g) = %g, want %g", vcExpSC[i], f, expSC[i])
+       for _, v := range expSC {
+               if f := Exp(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Exp(%g) = %g, want %g", v.in, f, v.want)
+               }
+               // Exp(Conj(z))  == Exp(Cosh(z))
+               if f := Exp(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Exp(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
                }
        }
 }
@@ -680,9 +1154,13 @@ func TestLog(t *testing.T) {
                        t.Errorf("Log(%g) = %g, want %g", vc[i], f, log[i])
                }
        }
-       for i := 0; i < len(vcLogSC); i++ {
-               if f := Log(vcLogSC[i]); !cAlike(logSC[i], f) {
-                       t.Errorf("Log(%g) = %g, want %g", vcLogSC[i], f, logSC[i])
+       for _, v := range logSC {
+               if f := Log(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Log(%g) = %g, want %g", v.in, f, v.want)
+               }
+               // Log(Conj(z))  == Conj(Log(z))
+               if f := Log(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Log(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
                }
        }
        for _, pt := range branchPoints {
@@ -697,9 +1175,13 @@ func TestLog10(t *testing.T) {
                        t.Errorf("Log10(%g) = %g, want %g", vc[i], f, log10[i])
                }
        }
-       for i := 0; i < len(vcLog10SC); i++ {
-               if f := Log10(vcLog10SC[i]); !cAlike(log10SC[i], f) {
-                       t.Errorf("Log10(%g) = %g, want %g", vcLog10SC[i], f, log10SC[i])
+       for _, v := range log10SC {
+               if f := Log10(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Log10(%g) = %g, want %g", v.in, f, v.want)
+               }
+               // Log10(Conj(z))  == Conj(Log10(z))
+               if f := Log10(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Log10(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
                }
        }
 }
@@ -764,9 +1246,22 @@ func TestSin(t *testing.T) {
                        t.Errorf("Sin(%g) = %g, want %g", vc[i], f, sin[i])
                }
        }
-       for i := 0; i < len(vcSinSC); i++ {
-               if f := Sin(vcSinSC[i]); !cAlike(sinSC[i], f) {
-                       t.Errorf("Sin(%g) = %g, want %g", vcSinSC[i], f, sinSC[i])
+       for _, v := range sinSC {
+               if f := Sin(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Sin(%g) = %g, want %g", v.in, f, v.want)
+               }
+
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Sin(Conj(z))  == Conj(Sin(z))
+               if f := Sin(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Sinh(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Sin(-z)  == -Sin(z)
+               if f := Sin(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Sinh(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
 }
@@ -776,9 +1271,21 @@ func TestSinh(t *testing.T) {
                        t.Errorf("Sinh(%g) = %g, want %g", vc[i], f, sinh[i])
                }
        }
-       for i := 0; i < len(vcSinhSC); i++ {
-               if f := Sinh(vcSinhSC[i]); !cAlike(sinhSC[i], f) {
-                       t.Errorf("Sinh(%g) = %g, want %g", vcSinhSC[i], f, sinhSC[i])
+       for _, v := range sinhSC {
+               if f := Sinh(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Sinh(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Sinh(Conj(z))  == Conj(Sinh(z))
+               if f := Sinh(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Sinh(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Sinh(-z)  == -Sinh(z)
+               if f := Sinh(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Sinh(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
 }
@@ -788,9 +1295,13 @@ func TestSqrt(t *testing.T) {
                        t.Errorf("Sqrt(%g) = %g, want %g", vc[i], f, sqrt[i])
                }
        }
-       for i := 0; i < len(vcSqrtSC); i++ {
-               if f := Sqrt(vcSqrtSC[i]); !cAlike(sqrtSC[i], f) {
-                       t.Errorf("Sqrt(%g) = %g, want %g", vcSqrtSC[i], f, sqrtSC[i])
+       for _, v := range sqrtSC {
+               if f := Sqrt(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Sqrt(%g) = %g, want %g", v.in, f, v.want)
+               }
+               // Sqrt(Conj(z)) == Conj(Sqrt(z))
+               if f := Sqrt(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Sqrt(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
                }
        }
        for _, pt := range branchPoints {
@@ -805,9 +1316,21 @@ func TestTan(t *testing.T) {
                        t.Errorf("Tan(%g) = %g, want %g", vc[i], f, tan[i])
                }
        }
-       for i := 0; i < len(vcTanSC); i++ {
-               if f := Tan(vcTanSC[i]); !cAlike(tanSC[i], f) {
-                       t.Errorf("Tan(%g) = %g, want %g", vcTanSC[i], f, tanSC[i])
+       for _, v := range tanSC {
+               if f := Tan(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Tan(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Tan(Conj(z))  == Conj(Tan(z))
+               if f := Tan(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Tan(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Tan(-z)  == -Tan(z)
+               if f := Tan(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Tan(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
 }
@@ -817,9 +1340,21 @@ func TestTanh(t *testing.T) {
                        t.Errorf("Tanh(%g) = %g, want %g", vc[i], f, tanh[i])
                }
        }
-       for i := 0; i < len(vcTanhSC); i++ {
-               if f := Tanh(vcTanhSC[i]); !cAlike(tanhSC[i], f) {
-                       t.Errorf("Tanh(%g) = %g, want %g", vcTanhSC[i], f, tanhSC[i])
+       for _, v := range tanhSC {
+               if f := Tanh(v.in); !cAlike(v.want, f) {
+                       t.Errorf("Tanh(%g) = %g, want %g", v.in, f, v.want)
+               }
+               if cAlike(-v.in, Conj(v.in)) && !cAlike(-v.want, Conj(v.want)) {
+                       // The following conditions can't simultaneously be satisfied for this input.
+                       continue
+               }
+               // Tanh(Conj(z))  == Conj(Tanh(z))
+               if f := Tanh(Conj(v.in)); !cAlike(Conj(v.want), f) && !cAlike(v.in, Conj(v.in)) {
+                       t.Errorf("Tanh(%g) = %g, want %g", Conj(v.in), f, Conj(v.want))
+               }
+               // Tanh(-z)  == -Tanh(z)
+               if f := Tanh(-v.in); !cAlike(-v.want, f) && !cAlike(v.in, -v.in) {
+                       t.Errorf("Tanh(%g) = %g, want %g", -v.in, f, -v.want)
                }
        }
 }
index 485ed2c78d9a56b605e210d3981c2c703ca28fc6..d5d0a5d470c05defe6c29fd690d69b9ac2df8526 100644 (file)
@@ -49,6 +49,23 @@ import "math"
 
 // Exp returns e**x, the base-e exponential of x.
 func Exp(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case math.IsInf(re, 0):
+               switch {
+               case re > 0 && im == 0:
+                       return x
+               case math.IsInf(im, 0) || math.IsNaN(im):
+                       if re < 0 {
+                               return complex(0, math.Copysign(0, im))
+                       } else {
+                               return complex(math.Inf(1.0), math.NaN())
+                       }
+               }
+       case math.IsNaN(re):
+               if im == 0 {
+                       return complex(math.NaN(), im)
+               }
+       }
        r := math.Exp(real(x))
        s, c := math.Sincos(imag(x))
        return complex(r*c, r*s)
index 881a064d8b8b1bf43bddfb5b1813bbd79aa67850..fd39c76cde10ee08963e3dac39e97b19ffa8e46e 100644 (file)
@@ -60,5 +60,6 @@ func Log(x complex128) complex128 {
 
 // Log10 returns the decimal logarithm of x.
 func Log10(x complex128) complex128 {
-       return math.Log10E * Log(x)
+       z := Log(x)
+       return complex(math.Log10E*real(z), math.Log10E*imag(z))
 }
index 2c57536edfc8312c7f10c635484a0496de0398f0..febac0e0bbdec63672ed910af6abf2b027dee27f 100644 (file)
@@ -51,6 +51,19 @@ import "math"
 
 // Sin returns the sine of x.
 func Sin(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case im == 0 && (math.IsInf(re, 0) || math.IsNaN(re)):
+               return complex(math.NaN(), im)
+       case math.IsInf(im, 0):
+               switch {
+               case re == 0:
+                       return x
+               case math.IsInf(re, 0) || math.IsNaN(re):
+                       return complex(math.NaN(), im)
+               }
+       case re == 0 && math.IsNaN(im):
+               return x
+       }
        s, c := math.Sincos(real(x))
        sh, ch := sinhcosh(imag(x))
        return complex(s*ch, c*sh)
@@ -71,6 +84,19 @@ func Sin(x complex128) complex128 {
 
 // Sinh returns the hyperbolic sine of x.
 func Sinh(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case re == 0 && (math.IsInf(im, 0) || math.IsNaN(im)):
+               return complex(re, math.NaN())
+       case math.IsInf(re, 0):
+               switch {
+               case im == 0:
+                       return complex(re, im)
+               case math.IsInf(im, 0) || math.IsNaN(im):
+                       return complex(re, math.NaN())
+               }
+       case im == 0 && math.IsNaN(re):
+               return complex(math.NaN(), im)
+       }
        s, c := math.Sincos(imag(x))
        sh, ch := sinhcosh(real(x))
        return complex(c*sh, s*ch)
@@ -96,6 +122,19 @@ func Sinh(x complex128) complex128 {
 
 // Cos returns the cosine of x.
 func Cos(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case im == 0 && (math.IsInf(re, 0) || math.IsNaN(re)):
+               return complex(math.NaN(), -im*math.Copysign(0, re))
+       case math.IsInf(im, 0):
+               switch {
+               case re == 0:
+                       return complex(math.Inf(1), -re*math.Copysign(0, im))
+               case math.IsInf(re, 0) || math.IsNaN(re):
+                       return complex(math.Inf(1), math.NaN())
+               }
+       case re == 0 && math.IsNaN(im):
+               return complex(math.NaN(), 0)
+       }
        s, c := math.Sincos(real(x))
        sh, ch := sinhcosh(imag(x))
        return complex(c*ch, -s*sh)
@@ -115,6 +154,19 @@ func Cos(x complex128) complex128 {
 
 // Cosh returns the hyperbolic cosine of x.
 func Cosh(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case re == 0 && (math.IsInf(im, 0) || math.IsNaN(im)):
+               return complex(math.NaN(), re*math.Copysign(0, im))
+       case math.IsInf(re, 0):
+               switch {
+               case im == 0:
+                       return complex(math.Inf(1), im*math.Copysign(0, re))
+               case math.IsInf(im, 0) || math.IsNaN(im):
+                       return complex(math.Inf(1), math.NaN())
+               }
+       case im == 0 && math.IsNaN(re):
+               return complex(math.NaN(), im)
+       }
        s, c := math.Sincos(imag(x))
        sh, ch := sinhcosh(real(x))
        return complex(c*ch, s*sh)
index 0fbdcdedd36cdd38584fe9883a9bd26a50323b4e..d817fe3976b413100b4bdab8952827985da00029 100644 (file)
@@ -65,6 +65,8 @@ func Sqrt(x complex128) complex128 {
                        return complex(0, math.Copysign(math.Sqrt(-real(x)), imag(x)))
                }
                return complex(math.Sqrt(real(x)), imag(x))
+       } else if math.IsInf(imag(x), 0) {
+               return complex(math.Inf(1.0), imag(x))
        }
        if real(x) == 0 {
                if imag(x) < 0 {
index 0243ea0417fbea54cf5c870b5ef62796941901d6..2da5d1d47bcef7672dd0977997710c5f6e5a940c 100644 (file)
@@ -57,6 +57,16 @@ import "math"
 
 // Tan returns the tangent of x.
 func Tan(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case math.IsInf(im, 0):
+               switch {
+               case math.IsInf(re, 0) || math.IsNaN(re):
+                       return complex(math.Copysign(0, re), math.Copysign(1, im))
+               }
+               return complex(math.Copysign(0, math.Sin(2*re)), math.Copysign(1, im))
+       case re == 0 && math.IsNaN(im):
+               return x
+       }
        d := math.Cos(2*real(x)) + math.Cosh(2*imag(x))
        if math.Abs(d) < 0.25 {
                d = tanSeries(x)
@@ -81,6 +91,16 @@ func Tan(x complex128) complex128 {
 
 // Tanh returns the hyperbolic tangent of x.
 func Tanh(x complex128) complex128 {
+       switch re, im := real(x), imag(x); {
+       case math.IsInf(re, 0):
+               switch {
+               case math.IsInf(im, 0) || math.IsNaN(im):
+                       return complex(math.Copysign(1, re), math.Copysign(0, im))
+               }
+               return complex(math.Copysign(1, re), math.Copysign(0, math.Sin(2*im)))
+       case im == 0 && math.IsNaN(re):
+               return x
+       }
        d := math.Cosh(2*real(x)) + math.Cos(2*imag(x))
        if d == 0 {
                return Inf()