你需要明白一点: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的类型将是@ 987654336@。浮点文字必须“转换”才能使用 64 位表示(由 IEEE-754 指定的规则)。由于100.55 需要无限位以二进制基数精确表示,因此仅使用 64 位(53 位表示数字)结果将不会(不能)完全是 100.55(但 IEEE 中的 64 位二进制数-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) 在二进制表示中也是一个无限数,因此您不能在 float64 类型的变量中拥有确切数量的 0.55。
您可以照常使用该数字,但在打印时,请将其四舍五入到您选择的小数位。最简单的方法是使用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 $