Commit a9035ede authored by Robert Griesemer's avatar Robert Griesemer

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
parent 775ab8ee
......@@ -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)
}
}
......
......@@ -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)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment