Golang converting float64 to int error

You need to understand something: 100.55 is a decimal number (presented in decimal radix). 100.55 in decimal is a finite number and is exactly this: 100.55.

Computers in general store numbers in binary representation. The number 100.55 cannot be represented with a finite binary number: 100.55 is an infinite number in binary representation (same reason why 1/3 cannot be represented with a finite decimal number, it is an endless sequence: 0.333333333....).

But Go (like any other language) stores float64 types using the IEEE-754 standard, which is a finite binary representation. A float64 value uses 64 bits in memory to describe the number, of which 53 bits are used to describe the digits and 11 bits are used for the exponent.

Now when you “say” this:

x := 100.55

It is a short variable declaration which will create a new variable named x and infer its type from the right hand side expression which is a floating point literal, so by the Go spec x‘s type will be float64. The floating point literal will have to be “converted” in order to be represented using 64 bits (by rules specified by IEEE-754). And since 100.55 would require infinite bits to be represented precisely in binary radix, by using only 64 bits (53 for the digits) the result will not (cannot) be exactly 100.55 (but a 64-bit binary number in IEEE-754 format that is closest to it), which is:

x := 100.55
fmt.Printf("%.50f\n", x)

100.54999999999999715782905695959925651550292968750000

So you are already starting off with a number not being 100.55.

You subtract 100 from it (float64(int(x)) will be exactly 100.0):

x = x - float64(int(x))
fmt.Printf("%.50f\n", x)

0.54999999999999715782905695959925651550292968750000

What can you do about it? Nothing really. The result you expect (0.55) is also an infinite number in binary representation, so you can’t have an exact number of 0.55 in a variable of type float64.

What you can do is work with the number as normal, but when you print it, round it to decimal places of your choice. The easiest is to use fmt.Printf(), and specify a format string using the verb %f including the precision:

fmt.Printf("%.2f\n", x)

Result:

0.55

Another option is to avoid using floating point numbers. E.g. if you were to represent USD amounts, you could “multiply” all your values by 100 and represent amounts as cents (1$*100) which is an integer. Only if you need to print the result as USD, you could print something like

cents := 10055
fmt.Printf("%d.%d $", cents/100, cents%100)

Output:

100.55 $

Leave a Comment