From ef5f658c66e3cff4b85202e17d22c39d54af1c9b Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 8 Jul 2017 23:06:41 +0200 Subject: Correct round --- round.go | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'round.go') diff --git a/round.go b/round.go index 345f7b0..1962ea6 100644 --- a/round.go +++ b/round.go @@ -6,9 +6,39 @@ import "math" // q = \sgn(y) \left\lfloor \left| y \right| + 0.5 \right\rfloor // = -\sgn(y) \left\lceil -\left| y \right| - 0.5 \right\rceil -// Round a float value to n decimal places -func Round(v float64, n int) float64 { +// RoundN a float value to n decimal places +func RoundN(x float64, n int) float64 { pow := math.Pow(10, float64(n)) - abs := math.Abs(v*pow) + 0.5 - return math.Copysign(math.Floor(abs)/pow, v) + return Round(x*pow) / pow +} + +// Round a float value +// https://www.cockroachlabs.com/blog/rounding-implementations-in-go/ +func Round(x float64) float64 { + const ( + mask = 0x7FF + shift = 64 - 11 - 1 + bias = 1023 + signMask = 1 << 63 + fracMask = (1 << shift) - 1 + halfMask = 1 << (shift - 1) + one = bias << shift + ) + + bits := math.Float64bits(x) + e := uint(bits>>shift) & mask + switch { + case e < bias: + // Round abs(x)<1 including denormals. + bits &= signMask // +-0 + if e == bias-1 { + bits |= one // +-1 + } + case e < bias+shift: + // Round any abs(x)>=1 containing a fractional component [0,1). + e -= bias + bits += halfMask >> e + bits &^= fracMask >> e + } + return math.Float64frombits(bits) } -- cgit v1.2.3