在Go中将值四舍五入到小数点后2位

时间:2018-10-09 03:31:22

标签: go rounding

在Go中使用math.Round()将正整数(例如:1.015)舍入为小数点后两位(小数点后两位):

fmt.Println(math.Round(1.015*100) / 100)

Go Playground

我得到了:1.02。没错。

但是当我使用一个函数来完成相同的工作时:

func RoundHalfUp(x float64) float64 {
    return math.Round(x*100) / 100
}

Go Playground

我得到了1.01

RoundHalfUp函数怎么了?

1 个答案:

答案 0 :(得分:1)

  

The Go Programming Language Specification

     

Constants

     

数值常数表示任意精度的精确值,并且   不溢出。

     

实施限制:尽管数字常量具有任意性   语言的精确度,编译器可以使用   内部表示,精度有限。也就是说,每个   实施必须:

     
      
  • 表示浮点常量,包括复数常量的部分,尾数至少为256位,并且带符号
      至少16位的二进制指数。
  •   
  • 如果由于精度限制而无法表示浮点或复数常量,则将其舍入到最接近的可表示常量。
  •   
     

这些要求既适用于文字常量也适用于结果   常数表达式的计算。

     

Constant expressions

     

常量表达式只能包含常量操作数,并且   在编译时评估。

     

常量表达式总是精确计算的;中间值   常量本身可能需要很高的精度   大于该语言中任何预先声明的类型所支持的大小。

     

实现限制:编译器可能在   计算无类型的浮点数或复杂的常量表达式;看到   常量部分中的实现限制。这个   舍入可能导致浮点常量表达式无效   在整数上下文中,即使在计算时将是整数   使用无限精度,反之亦然。


像Go编译器为RoundHalfUp一样实现math.Round(1.015*100) / 100函数。 1.015*100是一个无类型的浮点常量表达式。使用math/big包,至少要有256位精度。 float64(IEEE-754 64位浮点数)具有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"))
}

游乐场: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