Спецификация языка программирования Go
Константы
Числовые константы представляют собой точные значения произвольной точности и не переполняются.
Ограничение реализации: Хотя числовые константы имеют произвольную точность в языке, компилятор может реализовать их, используя внутреннее представление с ограниченной точностью.Тем не менее, каждая реализация должна:
- Представлять константы с плавающей точкой, включая части комплексной константы, с мантиссой не менее 256 бит и двоичным показателем
со знаком не менее 16биты. - Округление до ближайшей представимой константы, если невозможно представить числовую или комплексную константу из-за ограничений по точности.
Эти требования применяются как к литеральным константам, так и крезультат вычисления константных выражений.
константные выражения
константные выражения могут содержать только постоянные операнды и вычисляются во время компиляции.
Постоянные выражения всегда вычисляются точно;промежуточные значения и сами константы могут требовать точности, значительно превышающей поддерживаемую любым предварительно объявленным типом в языке.
Ограничение реализации: компилятор может использовать округление при вычислении нетипизированных выражений с плавающей точкой или сложных константных выражений;см. ограничение реализации в разделе о константах.Это округление может привести к тому, что константное выражение с плавающей точкой будет недопустимым в целочисленном контексте, даже если оно будет целочисленным при вычислении с бесконечной точностью, и наоборот.
Реализация RoundHalfUp
функция, подобная компилятору Go, для math.Round(1.015*100) / 100
.1.015*100
- нетипизированное выражение константы с плавающей точкой.Используйте пакет math/big
с точностью не менее 256 бит.Go float64
(64-битная IEEE-754 с плавающей запятой) имеет точность 53 бита.
Например, с 256 битами точности (постоянное выражение),
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
Вывод:
1.02
Если мы используем только 53 бита точности (float64
):
xf, _, err := big.ParseFloat(x, 10, 53, big.ToNearestEven)
Детская площадка: https://play.golang.org/p/ejz-wkuycaU
Выход:
1.01