summaryrefslogtreecommitdiff
path: root/round.go
diff options
context:
space:
mode:
Diffstat (limited to 'round.go')
-rw-r--r--round.go38
1 files changed, 34 insertions, 4 deletions
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)
}