golang 在将 float32 转换为 float64 时丢失精度?

问题描述 投票:0回答:1

在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

怎样才能让它不变

go floating-point double
1个回答
13
投票
在二进制表示中,

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)更多
  • 因此,由于
  • 鸽子洞原理
  • ,多个不同的 float64 数字在转换过程中必须映射到相同的 float32 数字。 因此,由于信息丢失,转换是不可逆的。
  • 由于 float64 和 float32 格式的基本相似性,可以用 float32 精确表示的数字也可以用 float64 精确表示,并且它们可以在任一方向上转换而不会损失精度。问题是,只有满足某些条件,数字才能用这些二进制浮点格式精确表示:

数字必须是有理数(可以表示为整数的分数)
  • 该分数的分母必须是 2 的幂(1、2、4、8 等)
  • 分子和分母不得超过一定的大小限制,这取决于您使用的浮点标准。
  • 您可能会发现您正在处理的任何随机数满足这些条件的概率都很低。例如,如果将
-8888.95

表示为整数的分数,您将得到

-177779/20
。由于 20 不是 2 的幂,因此该数字无法用任何一种浮点格式精确表示,因此会出现准确性问题。
    

© www.soinside.com 2019 - 2024. All rights reserved.