From a9035ede1b7f705f7cd73c7de51d54f6119b123b Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 11 Jun 2014 09:09:37 -0700 Subject: [PATCH] math: implement Nextafter32 Provide Nextafter64 as alias to Nextafter. For submission after the 1.3 release. Fixes #8117. LGTM=adonovan R=adonovan CC=golang-codereviews https://golang.org/cl/101750048 --- src/pkg/math/all_test.go | 79 +++++++++++++++++++++++++++++++++------ src/pkg/math/nextafter.go | 40 ++++++++++++++++---- 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go index 0d8b10f67f..8b00ef1d6c 100644 --- a/src/pkg/math/all_test.go +++ b/src/pkg/math/all_test.go @@ -456,7 +456,19 @@ var modf = [][2]float64{ {1.0000000000000000e+00, 8.2530809168085506044576505e-01}, {-8.0000000000000000e+00, -6.8592476857560136238589621e-01}, } -var nextafter = []float64{ +var nextafter32 = []float32{ + 4.979012489318848e+00, + 7.738873004913330e+00, + -2.768800258636475e-01, + -5.010602951049805e+00, + 9.636294364929199e+00, + 2.926377534866333e+00, + 5.229084014892578e+00, + 2.727940082550049e+00, + 1.825308203697205e+00, + -8.685923576354980e+00, +} +var nextafter64 = []float64{ 4.97901192488367438926388786e+00, 7.73887247457810545370193722e+00, -2.7688005719200153853520874e-01, @@ -1331,7 +1343,32 @@ var modfSC = [][2]float64{ {NaN(), NaN()}, } -var vfnextafterSC = [][2]float64{ +var vfnextafter32SC = [][2]float32{ + {0, 0}, + {0, float32(Copysign(0, -1))}, + {0, -1}, + {0, float32(NaN())}, + {float32(Copysign(0, -1)), 1}, + {float32(Copysign(0, -1)), 0}, + {float32(Copysign(0, -1)), float32(Copysign(0, -1))}, + {float32(Copysign(0, -1)), -1}, + {float32(NaN()), 0}, + {float32(NaN()), float32(NaN())}, +} +var nextafter32SC = []float32{ + 0, + 0, + -1.401298464e-45, // Float32frombits(0x80000001) + float32(NaN()), + 1.401298464e-45, // Float32frombits(0x00000001) + float32(Copysign(0, -1)), + float32(Copysign(0, -1)), + -1.401298464e-45, // Float32frombits(0x80000001) + float32(NaN()), + float32(NaN()), +} + +var vfnextafter64SC = [][2]float64{ {0, 0}, {0, Copysign(0, -1)}, {0, -1}, @@ -1343,7 +1380,7 @@ var vfnextafterSC = [][2]float64{ {NaN(), 0}, {NaN(), NaN()}, } -var nextafterSC = []float64{ +var nextafter64SC = []float64{ 0, 0, -4.9406564584124654418e-324, // Float64frombits(0x8000000000000001) @@ -2303,15 +2340,29 @@ func TestModf(t *testing.T) { } } -func TestNextafter(t *testing.T) { +func TestNextafter32(t *testing.T) { + for i := 0; i < len(vf); i++ { + vfi := float32(vf[i]) + if f := Nextafter32(vfi, 10); nextafter32[i] != f { + t.Errorf("Nextafter32(%g, %g) = %g want %g", vfi, 10.0, f, nextafter32[i]) + } + } + for i := 0; i < len(vfnextafter32SC); i++ { + if f := Nextafter32(vfnextafter32SC[i][0], vfnextafter32SC[i][1]); !alike(float64(nextafter32SC[i]), float64(f)) { + t.Errorf("Nextafter32(%g, %g) = %g want %g", vfnextafter32SC[i][0], vfnextafter32SC[i][1], f, nextafter32SC[i]) + } + } +} + +func TestNextafter64(t *testing.T) { for i := 0; i < len(vf); i++ { - if f := Nextafter(vf[i], 10); nextafter[i] != f { - t.Errorf("Nextafter(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter[i]) + if f := Nextafter64(vf[i], 10); nextafter64[i] != f { + t.Errorf("Nextafter64(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter64[i]) } } - for i := 0; i < len(vfnextafterSC); i++ { - if f := Nextafter(vfnextafterSC[i][0], vfnextafterSC[i][1]); !alike(nextafterSC[i], f) { - t.Errorf("Nextafter(%g, %g) = %g want %g", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i]) + for i := 0; i < len(vfnextafter64SC); i++ { + if f := Nextafter64(vfnextafter64SC[i][0], vfnextafter64SC[i][1]); !alike(nextafter64SC[i], f) { + t.Errorf("Nextafter64(%g, %g) = %g want %g", vfnextafter64SC[i][0], vfnextafter64SC[i][1], f, nextafter64SC[i]) } } } @@ -2827,9 +2878,15 @@ func BenchmarkModf(b *testing.B) { } } -func BenchmarkNextafter(b *testing.B) { +func BenchmarkNextafter32(b *testing.B) { + for i := 0; i < b.N; i++ { + Nextafter32(.5, 1) + } +} + +func BenchmarkNextafter64(b *testing.B) { for i := 0; i < b.N; i++ { - Nextafter(.5, 1) + Nextafter64(.5, 1) } } diff --git a/src/pkg/math/nextafter.go b/src/pkg/math/nextafter.go index 7c4b5bcdfe..fab1ad267e 100644 --- a/src/pkg/math/nextafter.go +++ b/src/pkg/math/nextafter.go @@ -4,13 +4,33 @@ package math -// Nextafter returns the next representable value after x towards y. -// If x == y, then x is returned. -// -// Special cases are: -// Nextafter(NaN, y) = NaN -// Nextafter(x, NaN) = NaN -func Nextafter(x, y float64) (r float64) { +// Nextafter32 returns the next representable float32 value after x towards y. +// Special cases: +// Nextafter32(x, x) = x +// Nextafter32(NaN, y) = NaN +// Nextafter32(x, NaN) = NaN +func Nextafter32(x, y float32) (r float32) { + switch { + case IsNaN(float64(x)) || IsNaN(float64(y)): // special case + r = float32(NaN()) + case x == y: + r = x + case x == 0: + r = float32(Copysign(float64(Float32frombits(1)), float64(y))) + case (y > x) == (x > 0): + r = Float32frombits(Float32bits(x) + 1) + default: + r = Float32frombits(Float32bits(x) - 1) + } + return +} + +// Nextafter64 returns the next representable float64 value after x towards y. +// Special cases: +// Nextafter64(x, x) = x +// Nextafter64(NaN, y) = NaN +// Nextafter64(x, NaN) = NaN +func Nextafter64(x, y float64) (r float64) { switch { case IsNaN(x) || IsNaN(y): // special case r = NaN() @@ -25,3 +45,9 @@ func Nextafter(x, y float64) (r float64) { } return } + +// Nextafter is the same as Nextafter64. +// It is provided for backward-compatibility only. +func Nextafter(x, y float64) float64 { + return Nextafter64(x, y) +} -- 2.48.1