为什么 0.1 + 0.2 在 Google Go 中得到 0.3?

Why does 0.1 + 0.2 get 0.3 in Google Go?

只要是用浮点数,0.1在内存中是无法准确表示的,所以我们知道这个值通常出来是0.100000000000000004。

但是用go的时候要加上0.1和0.2。 我得到 0.3.

fmt.Println(0.1 + 0.2)
// Output : 0.3

为什么出来的是 0.3 而不是 0.30000000000000004?

这是因为当你打印它时(例如使用fmt包),打印功能已经舍入到一定数量的小数位。

看这个例子:

const ca, cb = 0.1, 0.2
fmt.Println(ca + cb)
fmt.Printf("%.20f\n", ca+cb)

var a, b float64 = 0.1, 0.2
fmt.Println(a + b)
fmt.Printf("%.20f\n", a+b)

输出(在 Go Playground 上尝试):

0.3
0.29999999999999998890
0.30000000000000004
0.30000000000000004441

首先我们使用 constants,因为这与使用 float64 类型的 (non-constant) 值不同。 数值常量表示任意精度的精确值,不会溢出。

但是当打印 ca+cb 的结果时,常量值必须转换为 non-constant,键入的值才能传递给 fmt.Println()。该值将是 float64 类型,不能准确表示 0.3。但是 fmt.Println() 会将其四舍五入为 ~16 位小数,即 0.3。但是当我们明确声明我们希望它以 20 位数字显示时,我们会发现它并不准确。请注意,只有 0.3 会被转换为 float64,因为常量运算 0.1+0.2 将由编译器计算(在编译时)。

接下来我们从 float64 类型的变量开始,毫不奇怪,输出不完全是 0.3,但这次即使使用默认舍入,我们得到的结果也不同于 0.3。之所以这样是因为第一种情况(常量)是0.3被转换了,但是这次0.10.2都被转换成了float64,none 其中是精确的,将它们相加会导致与 0.3 的距离更大,大到足以使 "visual appearance" 具有 fmt 包的默认舍入。

查看类似/相关问题+答案以了解有关该主题的更多信息:

Why does adding 0.1 multiple times remain lossless?