Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does 0.1 + 0.2 get 0.3 in Google Go?

Tags:

precision

go

As long as floating point is used, 0.1 can not be represented exactly in memory, so we know that this value usually comes out to 0.10000000000000004.

But when using go to add 0.1 and 0.2. I'm getting 0.3.

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

Why is 0.3 coming out instead of 0.30000000000000004 ?

like image 503
Integral Avatar asked Feb 10 '17 07:02

Integral


Video Answer


1 Answers

It is because when you print it (e.g. with the fmt package), the printing function already rounds to a certain amount of fraction digits.

See this example:

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)

Output (try it on the Go Playground):

0.3
0.29999999999999998890
0.30000000000000004
0.30000000000000004441

First we used constants because that's different than using (non-constant) values of type float64. Numeric constants represent exact values of arbitrary precision and do not overflow.

But when printing the result of ca+cb, the constant value have to be converted to a non-constant, typed value to be able to be passed to fmt.Println(). This value will be of type float64, which cannot represent 0.3 exactly. But fmt.Println() will round it to like ~16 fraction digits, which will be 0.3. But when we explicitly state we want it displayed with 20 digits, we'll see it's not exact. Note that only 0.3 will be converted to float64, because the constant arithmetic 0.1+0.2 will be evaluated by the compiler (at compile time).

Next we started with variables of type float64, and to no surprise, output wasn't 0.3 exactly, but this time even with the default rounding we got a result different from 0.3. The reason for this is because in the first case (constants) it was 0.3 that was converted, but this time both 0.1 and 0.2 were converted to float64, none of which is exact, and adding them resulted in a number having bigger distance from 0.3, big enough to make a "visual appearance" with the default rounding of the fmt package.

Check out similar / relevant questions+answers to know more about the topic:

Why do these two float64s have different values?

How does Go perform arithmetic on constants?

Golang converting float64 to int error

Does go compiler's evaluation differ for constant expression and other expression

Why does adding 0.1 multiple times remain lossless?

Golang Round to Nearest 0.05

Go: Converting float64 to int with multiplier

like image 188
icza Avatar answered Oct 21 '22 12:10

icza