aboutsummaryrefslogtreecommitdiff
path: root/src/math
diff options
context:
space:
mode:
authorBrian Kessler <brian.m.kessler@gmail.com>2019-02-01 23:08:45 -0700
committerRobert Griesemer <gri@golang.org>2020-05-01 03:16:37 +0000
commit4209a9f65a461cfb184548e50ddb62fedd9f9e21 (patch)
treeb47e198c507fda726a3dbed82624e6904207165d /src/math
parentda382a3978d3db2380c7e9a69207545562dfd727 (diff)
downloadgo-4209a9f65a461cfb184548e50ddb62fedd9f9e21.tar.gz
go-4209a9f65a461cfb184548e50ddb62fedd9f9e21.zip
math/cmplx: handle special cases
Implement special case handling and testing to ensure conformance with the C99 standard annex G.6 Complex arithmetic. Fixes #29320 Change-Id: Id72eb4c5a35d5a54b4b8690d2f7176ab11028f1b Reviewed-on: https://go-review.googlesource.com/c/go/+/220689 Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/math')
-rw-r--r--src/math/cmplx/abs.go3
-rw-r--r--src/math/cmplx/asin.go70
-rw-r--r--src/math/cmplx/cmath_test.go908
-rw-r--r--src/math/cmplx/exp.go17
-rw-r--r--src/math/cmplx/log.go3
-rw-r--r--src/math/cmplx/sin.go52
-rw-r--r--src/math/cmplx/sqrt.go2
-rw-r--r--src/math/cmplx/tan.go20
8 files changed, 923 insertions, 152 deletions
diff --git a/src/math/cmplx/abs.go b/src/math/cmplx/abs.go
index f3cd1073ed..2f89d1bcfc 100644
--- a/src/math/cmplx/abs.go
+++ b/src/math/cmplx/abs.go
@@ -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"
diff --git a/src/math/cmplx/asin.go b/src/math/cmplx/asin.go
index 062f324ce2..30d019e9d4 100644
--- a/src/math/cmplx/asin.go
+++ b/src/math/cmplx/asin.go
@@ -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,19 @@ 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))
+ case math.IsNaN(re) || math.IsNaN(im):
+ return NaN()
+ }
x2 := real(x) * real(x)
a := 1 - x2 - imag(x)*imag(x)
if a == 0 {
diff --git a/src/math/cmplx/cmath_test.go b/src/math/cmplx/cmath_test.go
index d934ba5e57..3011e8327d 100644
--- a/src/math/cmplx/cmath_test.go
+++ b/src/math/cmplx/cmath_test.go
@@ -320,48 +320,190 @@ var tanHuge = []complex128{
-0.76417695016604922,
}
-// 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(),
@@ -369,23 +511,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)),
@@ -409,17 +633,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(),
@@ -435,35 +712,153 @@ var powSC = []complex128{
NaN(),
NaN(),
}
-var vcSinSC = []complex128{
- NaN(),
-}
-var sinSC = []complex128{
- NaN(),
-}
-var vcSinhSC = []complex128{
- NaN(),
-}
-var sinhSC = []complex128{
- NaN(),
-}
-var vcSqrtSC = []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 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
@@ -525,13 +920,25 @@ 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
+ var realAlike, imagAlike bool
+ if isExact(real(b)) {
+ realAlike = alike(real(a), real(b))
+ } else {
+ // Allow non-exact special cases to have errors in ULP.
+ realAlike = veryclose(real(a), real(b))
+ }
+ if isExact(imag(b)) {
+ imagAlike = alike(imag(a), imag(b))
+ } else {
+ // Allow non-exact special cases to have errors in ULP.
+ imagAlike = veryclose(imag(a), imag(b))
+ }
+ return realAlike && imagAlike
+}
+func isExact(x float64) bool {
+ // Special cases that should match exactly. Other cases are multiples
+ // of Pi that may not be last bit identical on all platforms.
+ return math.IsNaN(x) || math.IsInf(x, 0) || x == 0 || x == 1 || x == -1
}
func TestAbs(t *testing.T) {
@@ -552,9 +959,17 @@ 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)
+ }
+ if math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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 {
@@ -569,10 +984,19 @@ 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)
+ }
+ if math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
}
+ // 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) {
@@ -586,9 +1010,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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 {
@@ -603,9 +1043,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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 {
@@ -620,9 +1076,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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 {
@@ -637,9 +1109,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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 {
@@ -666,9 +1154,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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)
}
}
}
@@ -678,9 +1182,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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)
}
}
}
@@ -690,9 +1210,17 @@ 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)
+ }
+ if math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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))
}
}
}
@@ -709,9 +1237,17 @@ 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)
+ }
+ if math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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 {
@@ -726,9 +1262,17 @@ 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)
+ }
+ if math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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))
}
}
}
@@ -793,9 +1337,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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)
}
}
}
@@ -805,9 +1365,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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)
}
}
}
@@ -817,9 +1393,17 @@ 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)
+ }
+ if math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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 {
@@ -834,9 +1418,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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)
}
}
}
@@ -846,9 +1446,25 @@ 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 math.IsNaN(imag(v.in)) || math.IsNaN(imag(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ 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))
+ }
+ if math.IsNaN(real(v.in)) || math.IsNaN(real(v.want)) {
+ // Negating NaN is undefined with regard to the sign bit produced.
+ continue
+ }
+ // 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)
}
}
}
diff --git a/src/math/cmplx/exp.go b/src/math/cmplx/exp.go
index 485ed2c78d..d5d0a5d470 100644
--- a/src/math/cmplx/exp.go
+++ b/src/math/cmplx/exp.go
@@ -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)
diff --git a/src/math/cmplx/log.go b/src/math/cmplx/log.go
index 881a064d8b..fd39c76cde 100644
--- a/src/math/cmplx/log.go
+++ b/src/math/cmplx/log.go
@@ -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))
}
diff --git a/src/math/cmplx/sin.go b/src/math/cmplx/sin.go
index 2c57536edf..febac0e0bb 100644
--- a/src/math/cmplx/sin.go
+++ b/src/math/cmplx/sin.go
@@ -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)
diff --git a/src/math/cmplx/sqrt.go b/src/math/cmplx/sqrt.go
index 741e5a8865..eddce2fdfb 100644
--- a/src/math/cmplx/sqrt.go
+++ b/src/math/cmplx/sqrt.go
@@ -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 {
diff --git a/src/math/cmplx/tan.go b/src/math/cmplx/tan.go
index 714fb8c45b..67a1133a6f 100644
--- a/src/math/cmplx/tan.go
+++ b/src/math/cmplx/tan.go
@@ -60,6 +60,16 @@ import (
// 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)
@@ -84,6 +94,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()