将float转换为int时,如何避免浮点错误。
例如,以下代码打印:0.5499999999999972
当我受伤时,希望它打印0.55
。
package main
import "fmt"
func main() {
x := 100.55
fmt.Println(x - float64(int(x)))
}
Output:
0.5499999999999972
答案 0 :(得分:6)
您需要了解一些事情:100.55
是一个十进制数字(以十进制基数表示)。十进制中的100.55
是一个有限数字,正是这样:100.55
。
计算机一般以二进制表示形式存储数字。数字100.55
不能用有限的二进制数表示:100.55
是二进制表示中的无限数字(同样的原因1/3
无法用有限的数字表示十进制数,它是一个无穷无尽的序列:0.333333333....
)。
但Go(与任何其他语言一样)使用IEEE-754标准存储float64
类型,这是一种有限的二进制表示。 float64
值使用内存中的64位来描述数字,其中53位用于描述数字,11位用于指数。
现在当你"说"这样:
x := 100.55
它是一个short variable declaration,它将创建一个名为x
的新变量,并从右侧表达式推断其类型,这是一个浮点文字,所以Go规范x
'类型将是float64
。浮点字面值必须进行转换"为了用64位表示(由IEEE-754
指定的规则)。并且由于100.55
要求无限位以二进制基数精确表示,因此仅使用64位(数字为53),结果将不会(不能)正好100.55
(但是64位)最接近它的IEEE-754格式的二进制数,即:
x := 100.55
fmt.Printf("%.50f\n", x)
100.54999999999999715782905695959925651550292968750000
所以你已经开始使用的数字不是100.55
。
您从中减去100
(float64(int(x))
将完全100.0
):
x = x - float64(int(x))
fmt.Printf("%.50f\n", x)
0.54999999999999715782905695959925651550292968750000
你能做些什么?真的没什么。您期望的结果(0.55
)在二进制表示中也是无限数字,因此您不能在0.55
类型的变量中具有确切数量的float64
。
您可以做的是正常使用数字,但是当您打印它时,将其四舍五入到您选择的小数位。最简单的方法是使用fmt.Printf()
,并使用动词%f
指定格式字符串,包括精度:
fmt.Printf("%.2f\n", x)
结果:
0.55
另一种选择是避免使用浮点数。例如。如果你要代表美元金额,你可以"乘以"所有值均由100
表示,并表示为美分(1 $ * 100),这是一个整数。只有当您需要将结果打印为USD时,才能打印类似
cents := 10055
fmt.Printf("%d.%d $", cents/100, cents%100)
输出:
100.55 $