为什么这两个float64具有不同的值?

时间:2015-01-07 12:04:36

标签: go floating-point floating-accuracy

考虑以下两种情况:

fmt.Println(912 * 0.01)
fmt.Println(float64(912) * 0.01)

Go Playground link

第二个打印9.120000000000001,实际上很好,I understand why that is happening

但是,为什么第一行打印9.12,最后没有... 01? Go是否将两个无类型常量相乘,并在编译时简单地用9.12文字替换它们?

2 个答案:

答案 0 :(得分:14)

根据spec

  

始终精确计算常量表达式;中间值和常量本身可能要求精度明显大于语言中任何预先声明的类型所支持的精度。

由于

912 * 0.01

是一个常量表达式,它是精确计算的。因此,写fmt.Println(912 * 0.01)与写fmt.Println(9.12)具有相同的效果。当您将912固定到float64时,浮点乘法的另一个操作数也会隐式固定到float64。因此,表达式float64(912) * 0.01的行为类似于float64(912) * float64(0.01)。 0.01在float64中不能完全表示,因此在第一个示例中float64(912 * 0.01)的参数中出现的表达式fmt.Println()中,精度会丢失在不同的位置,从而解释了不同的结果

答案 1 :(得分:6)

输出不同的原因是在第一种情况下912 * 0.01是2个无类型常量值的乘法,它具有任意精度,只有当值为float64时才将结果转换为Println()传递给float64(912) * 0.01。 (有关详细信息,请参阅语言规范的Constant expressions部分。)

在第二种情况下,912首先将float64转换为0.01,然后将无类型常量float64转换为float64,这两个值为float64 {1}}乘以不是任意精度,并且不会给出精确的结果。

注意:

在第一种情况下,当传递给Println()时,结果将转换为fmt.Printf("%T %v\n", 912 * 0.01, 912 * 0.01)

float64 9.12

输出:

{{1}}

Test it on Go Playground