mirror of
https://github.com/golang/go
synced 2024-11-11 18:01:47 -07:00
math: Add Round function (ties away from zero)
This function avoids subtle faults found in many ad-hoc implementations, and is simple enough to be inlined by the compiler. Fixes #20100 Change-Id: Ib320254e9b1f1f798c6ef906b116f63bc29e8d08 Reviewed-on: https://go-review.googlesource.com/43652 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
dbe3522c7f
commit
03c3bb5f84
@ -529,6 +529,18 @@ var remainder = []float64{
|
||||
8.734595415957246977711748e-01,
|
||||
1.314075231424398637614104e+00,
|
||||
}
|
||||
var round = []float64{
|
||||
5,
|
||||
8,
|
||||
Copysign(0, -1),
|
||||
-5,
|
||||
10,
|
||||
3,
|
||||
5,
|
||||
3,
|
||||
2,
|
||||
-9,
|
||||
}
|
||||
var signbit = []bool{
|
||||
false,
|
||||
false,
|
||||
@ -1755,6 +1767,20 @@ var pow10SC = []float64{
|
||||
Inf(1), // pow10(MaxInt32)
|
||||
}
|
||||
|
||||
var vfroundSC = [][2]float64{
|
||||
{0, 0},
|
||||
{1.390671161567e-309, 0}, // denormal
|
||||
{0.49999999999999994, 0}, // 0.5-epsilon
|
||||
{0.5, 1},
|
||||
{0.5000000000000001, 1}, // 0.5+epsilon
|
||||
{-1.5, -2},
|
||||
{NaN(), NaN()},
|
||||
{Inf(1), Inf(1)},
|
||||
{2251799813685249.5, 2251799813685250}, // 1 bit fraction
|
||||
{4503599627370495.5, 4503599627370496}, // 1 bit fraction, rounding to 0 bit fraction
|
||||
{4503599627370497, 4503599627370497}, // large integer
|
||||
}
|
||||
|
||||
var vfsignbitSC = []float64{
|
||||
Inf(-1),
|
||||
Copysign(0, -1),
|
||||
@ -2713,6 +2739,19 @@ func TestRemainder(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRound(t *testing.T) {
|
||||
for i := 0; i < len(vf); i++ {
|
||||
if f := Round(vf[i]); !alike(round[i], f) {
|
||||
t.Errorf("Round(%g) = %g, want %g", vf[i], f, round[i])
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(vfroundSC); i++ {
|
||||
if f := Round(vfroundSC[i][0]); !alike(vfroundSC[i][1], f) {
|
||||
t.Errorf("Round(%g) = %g, want %g", vfroundSC[i][0], f, vfroundSC[i][1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignbit(t *testing.T) {
|
||||
for i := 0; i < len(vf); i++ {
|
||||
if f := Signbit(vf[i]); signbit[i] != f {
|
||||
@ -3360,6 +3399,16 @@ func BenchmarkPow10Neg(b *testing.B) {
|
||||
GlobalF = x
|
||||
}
|
||||
|
||||
var roundNeg = float64(-2.5)
|
||||
|
||||
func BenchmarkRound(b *testing.B) {
|
||||
x := 0.0
|
||||
for i := 0; i < b.N; i++ {
|
||||
x = Round(roundNeg)
|
||||
}
|
||||
GlobalF = x
|
||||
}
|
||||
|
||||
func BenchmarkRemainder(b *testing.B) {
|
||||
x := 0.0
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2009-2010 The Go Authors. All rights reserved.
|
||||
// Copyright 2009 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.
|
||||
|
||||
@ -54,3 +54,46 @@ func trunc(x float64) float64 {
|
||||
d, _ := Modf(x)
|
||||
return d
|
||||
}
|
||||
|
||||
// Round returns the nearest integer, rounding half away from zero.
|
||||
//
|
||||
// Special cases are:
|
||||
// Round(±0) = ±0
|
||||
// Round(±Inf) = ±Inf
|
||||
// Round(NaN) = NaN
|
||||
func Round(x float64) float64 {
|
||||
// Round is a faster implementation of:
|
||||
//
|
||||
// func Round(x float64) float64 {
|
||||
// t := Trunc(x)
|
||||
// if Abs(x-t) >= 0.5 {
|
||||
// return t + Copysign(1, x)
|
||||
// }
|
||||
// return t
|
||||
// }
|
||||
const (
|
||||
signMask = 1 << 63
|
||||
fracMask = 1<<shift - 1
|
||||
half = 1 << (shift - 1)
|
||||
one = bias << shift
|
||||
)
|
||||
|
||||
bits := Float64bits(x)
|
||||
e := uint(bits>>shift) & mask
|
||||
if e < bias {
|
||||
// Round abs(x) < 1 including denormals.
|
||||
bits &= signMask // +-0
|
||||
if e == bias-1 {
|
||||
bits |= one // +-1
|
||||
}
|
||||
} else if e < bias+shift {
|
||||
// Round any abs(x) >= 1 containing a fractional component [0,1).
|
||||
//
|
||||
// Numbers with larger exponents are returned unchanged since they
|
||||
// must be either an integer, infinity, or NaN.
|
||||
e -= bias
|
||||
bits += half >> e
|
||||
bits &^= fracMask >> e
|
||||
}
|
||||
return Float64frombits(bits)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user