在Golang中,似乎当float64 var首先转换为float32然后再转换float64时,它的值会改变。
a := -8888.95
fmt.Println(a) // -8888.95
fmt.Println(float32(a)) // -8888.95
fmt.Println(float64(float32(a))) // -8888.9501953125
怎样才能让它不变
float64
的精度明显高于 float32
。你的例子展示了 Go 如何在格式化中反映这个想法:默认情况下打印 float64 将比打印的 float32 显示更多的十进制数字(即更高的精度)。如果强制程序将所有值格式化为高精度,您将看到到底发生了什么:
a := -8888.95
fmt.Printf("%.20f\n", a)
fmt.Printf("%.20f\n", float32(a))
fmt.Printf("%.20f\n", float64(float32(a)))
输出:
-8888.95000000000072759576 // original 64-bit value
-8888.95019531250000000000 // converted to 32-bit
-8888.95019531250000000000 // re-converted to 64-bit
在这里您可以看到原始值非常接近(但不等于)
a
的字面值。转换为 32 位会使精度增加 8 到 9 个数量级。重新转换为 64 位没有添加任何变化。
总而言之:转换为 float32 时,您会损失二进制值的准确性。然后,在转换为 float64 时,您会遇到打印值的精度损失,因为 Go 更喜欢以更高的精度格式化 float64 值。请注意此处准确度和精确度的区别。 通常不可能在不损失精度的情况下从 float64 转换为 float32。这是一个简单的论据来解释为什么会这样:
可能的 float64 数字(~2^64)比 float32 数字(~2^32)更多
数字必须是有理数(可以表示为整数的分数)
-8888.95
表示为整数的分数,您将得到
-177779/20
。由于 20 不是 2 的幂,因此该数字无法用任何一种浮点格式精确表示,因此会出现准确性问题。