mirror of
https://github.com/golang/go
synced 2024-11-26 15:27:04 -07:00
a5c44f3e3f
Rounding ties to even is statistically useful for some applications. This implementation completes IEEE float64 rounding mode support (in addition to Round, Ceil, Floor, Trunc). This function avoids subtle faults found in ad-hoc implementations, and is simple enough to be inlined by the compiler. Fixes #21748 Change-Id: I09415df2e42435f9e7dabe3bdc0148e9b9ebd609 Reviewed-on: https://go-review.googlesource.com/61211 Reviewed-by: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
132 lines
3.1 KiB
Go
132 lines
3.1 KiB
Go
// 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.
|
|
|
|
package math
|
|
|
|
// Floor returns the greatest integer value less than or equal to x.
|
|
//
|
|
// Special cases are:
|
|
// Floor(±0) = ±0
|
|
// Floor(±Inf) = ±Inf
|
|
// Floor(NaN) = NaN
|
|
func Floor(x float64) float64
|
|
|
|
func floor(x float64) float64 {
|
|
if x == 0 || IsNaN(x) || IsInf(x, 0) {
|
|
return x
|
|
}
|
|
if x < 0 {
|
|
d, fract := Modf(-x)
|
|
if fract != 0.0 {
|
|
d = d + 1
|
|
}
|
|
return -d
|
|
}
|
|
d, _ := Modf(x)
|
|
return d
|
|
}
|
|
|
|
// Ceil returns the least integer value greater than or equal to x.
|
|
//
|
|
// Special cases are:
|
|
// Ceil(±0) = ±0
|
|
// Ceil(±Inf) = ±Inf
|
|
// Ceil(NaN) = NaN
|
|
func Ceil(x float64) float64
|
|
|
|
func ceil(x float64) float64 {
|
|
return -Floor(-x)
|
|
}
|
|
|
|
// Trunc returns the integer value of x.
|
|
//
|
|
// Special cases are:
|
|
// Trunc(±0) = ±0
|
|
// Trunc(±Inf) = ±Inf
|
|
// Trunc(NaN) = NaN
|
|
func Trunc(x float64) float64
|
|
|
|
func trunc(x float64) float64 {
|
|
if x == 0 || IsNaN(x) || IsInf(x, 0) {
|
|
return x
|
|
}
|
|
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
|
|
// }
|
|
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 |= uvone // +-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.
|
|
const half = 1 << (shift - 1)
|
|
e -= bias
|
|
bits += half >> e
|
|
bits &^= fracMask >> e
|
|
}
|
|
return Float64frombits(bits)
|
|
}
|
|
|
|
// RoundToEven returns the nearest integer, rounding ties to even.
|
|
//
|
|
// Special cases are:
|
|
// RoundToEven(±0) = ±0
|
|
// RoundToEven(±Inf) = ±Inf
|
|
// RoundToEven(NaN) = NaN
|
|
func RoundToEven(x float64) float64 {
|
|
// RoundToEven is a faster implementation of:
|
|
//
|
|
// func RoundToEven(x float64) float64 {
|
|
// t := math.Trunc(x)
|
|
// odd := math.Remainder(t, 2) != 0
|
|
// if d := math.Abs(x - t); d > 0.5 || (d == 0.5 && odd) {
|
|
// return t + math.Copysign(1, x)
|
|
// }
|
|
// return t
|
|
// }
|
|
bits := Float64bits(x)
|
|
e := uint(bits>>shift) & mask
|
|
if e >= bias {
|
|
// Round abs(x) >= 1.
|
|
// - Large numbers without fractional components, infinity, and NaN are unchanged.
|
|
// - Add 0.499.. or 0.5 before truncating depending on whether the truncated
|
|
// number is even or odd (respectively).
|
|
const halfMinusULP = (1 << (shift - 1)) - 1
|
|
e -= bias
|
|
bits += (halfMinusULP + (bits>>(shift-e))&1) >> e
|
|
bits &^= fracMask >> e
|
|
} else if e == bias-1 && bits&fracMask != 0 {
|
|
// Round 0.5 < abs(x) < 1.
|
|
bits = bits&signMask | uvone // +-1
|
|
} else {
|
|
// Round abs(x) <= 0.5 including denormals.
|
|
bits &= signMask // +-0
|
|
}
|
|
return Float64frombits(bits)
|
|
}
|