Golang将float64转换为int错误

pat*_*oid 3 floating-point precision go

在将float转换为int时,如何避免浮点错误.例如,下面的代码打印出来:0.5499999999999972当我想要打印时0.55.

package main

import "fmt"

func main() {
    x := 100.55
    fmt.Println(x - float64(int(x)))    
}

Output:
0.5499999999999972
Run Code Online (Sandbox Code Playgroud)

icz*_*cza 6

你需要了解一些东西:100.55是十进制数(以十进制基数表示).100.55十进制是一个有限数,正是这样:100.55.

计算机通常以二进制表示形式存储数字.数字100.55不能用有限二进制数表示:100.55是二进制表示中的无穷数(同样的原因1/3不能用有限的十进制数表示,它是无穷无尽的序列:) 0.333333333.....

但Go(与任何其他语言一样)float64使用IEEE-754标准存储类型,IEEE-754标准是有限二进制表示.甲float64值使用64个比特在存储器来描述的53位被用于描述数字和11位被用于指数的数量,.

现在当你"说"这个:

x := 100.55
Run Code Online (Sandbox Code Playgroud)

它是一个简短的变量声明,它将创建一个名为的新变量,x并从右侧表达式推断其类型,这是一个浮点文字,因此Go规范x的类型将是float64.浮点文字必须被"转换"才能用64位表示(由指定的规则表示IEEE-754).并且由于100.55要求无限位以二进制基数精确表示,通过仅使用64位(数字为53),结果将不会(不能)完全100.55(但是最接近的IEEE-754格式的64位二进制数)它),这是:

x := 100.55
fmt.Printf("%.50f\n", x)

100.54999999999999715782905695959925651550292968750000
Run Code Online (Sandbox Code Playgroud)

所以你已经开始了一个不存在的数字100.55.

100从中减去(float64(int(x))确切地说100.0):

x = x - float64(int(x))
fmt.Printf("%.50f\n", x)

0.54999999999999715782905695959925651550292968750000
Run Code Online (Sandbox Code Playgroud)

你能为这个做什么?真的没什么.您期望的结果(0.55)在二进制表示中也是无限数字,因此您不能0.55在类型变量中具有精确数字float64.

您可以做的是正常使用数字,但是当您打印它时,将其四舍五入到您选择的小数位.最简单的方法是使用fmt.Printf(),并使用%f包含精度的动词指定格式字符串:

fmt.Printf("%.2f\n", x)
Run Code Online (Sandbox Code Playgroud)

结果:

0.55
Run Code Online (Sandbox Code Playgroud)

另一种选择是避免使用浮点数.例如,如果您要代表美元金额,您可以将所有值"乘以" 100并将金额表示为美分(1 $*100),这是一个整数.只有当您需要将结果打印为USD时,才能打印出类似的内容

cents := 10055
fmt.Printf("%d.%d $", cents/100, cents%100)
Run Code Online (Sandbox Code Playgroud)

输出:

100.55 $
Run Code Online (Sandbox Code Playgroud)