The Go Programming Language
Specification
Constants
Numeric constants represent exact values of arbitrary precision and do
not overflow.
Implementation restriction: Although numeric constants have arbitrary
precision in the language, a compiler may implement them using an
internal representation with limited precision. That said, every
implementation must:
- Represent floating-point constants, including the parts of a complex constant, with a mantissa of at least 256 bits and a signed
binary exponent of at least 16 bits.
- Round to the nearest representable constant if unable to represent a floating-point or complex constant due to limits on precision.
These requirements apply both to literal constants and to the result
of evaluating constant expressions.
Constant expressions
Constant expressions may contain only constant operands and are
evaluated at compile time.
Constant expressions are always evaluated exactly; intermediate values
and the constants themselves may require precision significantly
larger than supported by any predeclared type in the language.
Implementation restriction: A compiler may use rounding while
computing untyped floating-point or complex constant expressions; see
the implementation restriction in the section on constants. This
rounding may cause a floating-point constant expression to be invalid
in an integer context, even if it would be integral when calculated
using infinite precision, and vice versa.
Implement the RoundHalfUp
function like the Go compiler does for math.Round(1.015*100) / 100
. 1.015*100
is a untyped floating-point constant expression. Use the math/big
package with at least 256 bits of precision. Go float64
(IEEE-754 64-bit floating-point) has 53 bits of precision.
For example, with 256 bits of precision (constant expression),
package main
import (
"fmt"
"math"
"math/big"
)
func RoundHalfUp(x string) float64 {
// math.Round(x*100) / 100
xf, _, err := big.ParseFloat(x, 10, 256, big.ToNearestEven)
if err != nil {
panic(err)
}
xf100, _ := new(big.Float).Mul(xf, big.NewFloat(100)).Float64()
return math.Round(xf100) / float64(100)
}
func main() {
fmt.Println(RoundHalfUp("1.015"))
}
Playground: https://play.golang.org/p/uqtYwP4o22B
Output:
1.02
If we only use 53 bits of precision (float64
):
xf, _, err := big.ParseFloat(x, 10, 53, big.ToNearestEven)
Playground: https://play.golang.org/p/ejz-wkuycaU
Output:
1.01