Why do these two float64s have different values?

2020-02-11 02:47发布

问题:

Consider these two cases:

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

(Go Playground link)

The second one prints 9.120000000000001, which is actually fine, I understand why that is happening.

However, why does the first line print 9.12, without the …01 at the end? Does Go multiply the two untyped constants and simply replace them with a 9.12 literal when compiling?

回答1:

As per spec:

Constant expressions are always evaluated exactly; intermediate values and the constants themselves may require precision significantly larger than supported by any predeclared type in the language.

Since

912 * 0.01

is a constant expression, it is evaluated exactly. Thus, writing fmt.Println(912 * 0.01) has the same effect as writing fmt.Println(9.12). When you pin 912 to float64, the other operand of the floating-point multiplication is implicitly pinned to float64, too. Thus, the expression float64(912) * 0.01 behaves like float64(912) * float64(0.01). 0.01 is not exactly representable in a float64, thus precision is lost in a different place than in the expression float64(912 * 0.01) which arises in the argument of fmt.Println() in your first example, explaining the different results.



回答2:

The reason for the different output is that in the first case 912 * 0.01 is the multiplication of 2 untyped constant values which is of arbitrary precision, and only the result is converted to float64 when the value is passed to Println(). (See Constant expressions section of the Language specification for details.)

In the second case float64(912) * 0.01 first 912 is converted to float64, then the untyped constant 0.01 is converted to float64 and these two values having float64 are multiplied which is not an arbitrary precision, and will not give exact result.

Note:

In the first case the result will be converted to float64 when passed to the Println():

fmt.Printf("%T %v\n", 912 * 0.01, 912 * 0.01)

Output:

float64 9.12

Test it on Go Playground