diff --git a/src/pkg/math/Makefile b/src/pkg/math/Makefile index 0e89df7e79e..7892371ac02 100644 --- a/src/pkg/math/Makefile +++ b/src/pkg/math/Makefile @@ -12,6 +12,7 @@ OFILES_amd64=\ OFILES_386=\ asin_386.$O\ atan_386.$O\ + atan2_386.$O\ exp_386.$O\ fabs_386.$O\ floor_386.$O\ diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go index c0ac152ab40..184d045c995 100644 --- a/src/pkg/math/all_test.go +++ b/src/pkg/math/all_test.go @@ -100,6 +100,18 @@ var atanh = []float64{ 1.8459947964298794318714228e-01, -1.3273186910532645867272502e+00, } +var atan2 = []float64{ + 1.1088291730037004444527075e+00, + 9.1218183188715804018797795e-01, + 1.5984772603216203736068915e+00, + 2.0352918654092086637227327e+00, + 8.0391819139044720267356014e-01, + 1.2861075249894661588866752e+00, + 1.0889904479131695712182587e+00, + 1.3044821793397925293797357e+00, + 1.3902530903455392306872261e+00, + 2.2859857424479142655411058e+00, +} var ceil = []float64{ 5.0000000000000000e+00, 8.0000000000000000e+00, @@ -427,6 +439,64 @@ var atanhSC = []float64{ NaN(), NaN(), } +var vfatan2SC = [][2]float64{ + [2]float64{Inf(-1), Inf(-1)}, + [2]float64{Inf(-1), -Pi}, + [2]float64{Inf(-1), 0}, + [2]float64{Inf(-1), +Pi}, + [2]float64{Inf(-1), Inf(1)}, + [2]float64{Inf(-1), NaN()}, + [2]float64{-Pi, Inf(-1)}, + [2]float64{-Pi, 0}, + [2]float64{-Pi, Inf(1)}, + [2]float64{-Pi, NaN()}, + [2]float64{0, Inf(-1)}, + [2]float64{0, -Pi}, + [2]float64{0, 0}, + [2]float64{0, +Pi}, + [2]float64{0, Inf(1)}, + [2]float64{0, NaN()}, + [2]float64{+Pi, Inf(-1)}, + [2]float64{+Pi, 0}, + [2]float64{+Pi, Inf(1)}, + [2]float64{+Pi, NaN()}, + [2]float64{Inf(1), Inf(-1)}, + [2]float64{Inf(1), -Pi}, + [2]float64{Inf(1), 0}, + [2]float64{Inf(1), +Pi}, + [2]float64{Inf(1), Inf(1)}, + [2]float64{Inf(1), NaN()}, + [2]float64{NaN(), NaN()}, +} +var atan2SC = []float64{ + -3 * Pi / 4, + -Pi / 2, + -Pi / 2, + -Pi / 2, + -Pi / 4, + NaN(), + -Pi, + -Pi / 2, + -0, + NaN(), + Pi, + Pi, + 0, + 0, + 0, + NaN(), + Pi, + Pi / 2, + 0, + NaN(), + 3 * Pi / 4, + Pi / 2, + Pi / 2, + Pi / 2, + Pi / 4, + NaN(), + NaN(), +} var vfceilSC = []float64{ Inf(-1), @@ -851,6 +921,19 @@ func TestAtanh(t *testing.T) { } } +func TestAtan2(t *testing.T) { + for i := 0; i < len(vf); i++ { + if f := Atan2(10, vf[i]); !veryclose(atan2[i], f) { + t.Errorf("Atan2(10, %g) = %g, want %g\n", vf[i], f, atan2[i]) + } + } + for i := 0; i < len(vfatan2SC); i++ { + if f := Atan2(vfatan2SC[i][0], vfatan2SC[i][1]); !alike(atan2SC[i], f) { + t.Errorf("Atan2(%g, %g) = %g, want %g\n", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i]) + } + } +} + func TestCeil(t *testing.T) { for i := 0; i < len(vf); i++ { if f := Ceil(vf[i]); ceil[i] != f { @@ -1254,6 +1337,12 @@ func BenchmarkAtanh(b *testing.B) { } } +func BenchmarkAtan2(b *testing.B) { + for i := 0; i < b.N; i++ { + Atan2(.5, 1) + } +} + func BenchmarkCeil(b *testing.B) { for i := 0; i < b.N; i++ { Ceil(.5) diff --git a/src/pkg/math/atan2.go b/src/pkg/math/atan2.go index 80a28b15b1e..a738fbcc674 100644 --- a/src/pkg/math/atan2.go +++ b/src/pkg/math/atan2.go @@ -7,14 +7,69 @@ package math // Atan2 returns the arc tangent of y/x, using // the signs of the two to determine the quadrant // of the return value. +// +// Special cases are (in order): +// Atan2(y, NaN) = NaN +// Atan2(NaN, x) = NaN +// Atan2(0, x>=0) = 0 +// Atan2(0, x<0) = Pi +// Atan2(y>0, 0) = +Pi/2 +// Atan2(y<0, 0) = -Pi/2 +// Atan2(+Inf, +Inf) = +Pi/4 +// Atan2(-Inf, +Inf) = -Pi/4 +// Atan2(+Inf, -Inf) = 3Pi/4 +// Atan2(-Inf, -Inf) = -3Pi/4 +// Atan2(y, +Inf) = 0 +// Atan2(y>0, -Inf) = +Pi +// Atan2(y<0, -Inf) = -Pi +// Atan2(+Inf, x) = +Pi/2 +// Atan2(-Inf, x) = -Pi/2 func Atan2(y, x float64) float64 { - // Determine the quadrant and call atan. - if y+x == y { - if y >= 0 { + // TODO(rsc): Remove manual inlining of IsNaN, IsInf + // when compiler does it for us + // special cases + switch { + case y != y || x != x: // IsNaN(y) || IsNaN(x): + return NaN() + case y == 0: + if x >= 0 { + return 0 + } + return Pi + case x == 0: + if y > 0 { + return Pi / 2 + } + return -Pi / 2 + case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0): + if x > MaxFloat64 { // IsInf(x, 1) { + switch { + case y > MaxFloat64: // IsInf(y, 1): + return Pi / 4 + case y < -MaxFloat64: // IsInf(y, -1): + return -Pi / 4 + default: + return 0 + } + } + switch { + case y > MaxFloat64: //IsInf(y, 1): + return 3 * Pi / 4 + case y < -MaxFloat64: //IsInf(y, -1): + return -3 * Pi / 4 + case y > 0: + return Pi + default: + return -Pi + } + case y < -MaxFloat64 || y > MaxFloat64: //IsInf(y, 0): + if y > MaxFloat64 { // IsInf(y, 1) { return Pi / 2 } return -Pi / 2 } + + // Call atan and determine the quadrant. q := Atan(y / x) if x < 0 { if q <= 0 { diff --git a/src/pkg/math/atan2_386.s b/src/pkg/math/atan2_386.s new file mode 100755 index 00000000000..9a664926aba --- /dev/null +++ b/src/pkg/math/atan2_386.s @@ -0,0 +1,11 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// func Atan2(y, x float64) float64 // =atan(y/x) +TEXT ·Atan2(SB),7,$0 + FMOVD y+0(FP), F0 // F0=y + FMOVD x+8(FP), F0 // F0=x, F1=y + FPATAN // F0=atan(F1/F0) + FMOVDP F0, r+16(FP) + RET diff --git a/src/pkg/math/atan2_decl.go b/src/pkg/math/atan2_decl.go new file mode 100755 index 00000000000..3932ed6e4af --- /dev/null +++ b/src/pkg/math/atan2_decl.go @@ -0,0 +1,7 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package math + +func Atan2(y, x float64) float64