Consider these two cases:
fmt.Println(912 * 0.01)
fmt.Println(float64(912) * 0.01)
(Go Playground link)
The second one prints 9.120
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.
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