SoFunction
Updated on 2025-03-05

How to avoid floating point accuracy issues when calculating go currency

In the initial stage of development, we often encounter problems such as "floating point accuracy" and "money value representation".

So, how to deal with money, how to store and pass them.

Why is the problem

Standard floating point types in Go have some precision (like any other language) and you can't use them in currency operations. Here is the simplest example:

var v1, v2 = 0.1, 0.2
(v1 + v2)
// Output: 0.30000000000000000004

You can calculate how many times you need to add one value to another to get extra money on your account! But the other way around is the same — in this case, you just lose your money.

This is not only problematic when doing maths on your money, but also when passing data between different systems or services.

Next question — Pass your money

Every time you marshal your money from / to float, you will encounter the same problem as above, as well as other issues related to the marshal implementation - json, xml, text, etc...

Another problem is rounding. If you are dealing with currency, you will always face rounding. How should you round your currency value? For example, 0.345 yuan, usually we will round to 0.35 yuan?

What is our choice

There are some special types that can be used for the representation and calculation of currency.

Go standard library hasType (frommath/bigpackage, representing a floating point number of arbitrary precision). andfloat32andfloat64Differently, they have fixed size and precision,Allows you to set arbitrary precision for numbers and calculations.

Another good option isdecimalLibrary/shopspring/decimal

About rounding:

  • 1.234 => 1.23
  • 1.235 => 1.24
  • 1.236 => 1.24

For example,shopspring/decimalProvides a method to round values ​​appropriately.

Another good option to consider is to use currency units. This way, you move from the floating point problem to the integer and calculate everything as an integer. The only place to use rounding here: pass the result value.

Now let's discuss the choices when passing currency.

  • Using currency units — we pass everything as integers, there is no floating point problem here. Just control the limit of the value and it's OK.
  • Pass a floating point number as a string. It's usually a good choice too - when you pass a floating point number as a string, you're safe when the other party reads this string value and converts it back to a floating point number.

Simple example

You canGo PlaygroundTry it up.

package main

import (
    "fmt"
    "/shopspring/decimal"
)

func main() {
    a := 0.1
    b := 0.2
    c := (a)
    d := (b)
    (a, b, (), ()) 
    (a + b) 
    ((d).String()) 
}

The output is:

0.1 0.2 0.1 0.2
0.30000000000000004
0.3

in conclusion

When processing currency — usemath/bigOr some currency-related library, such asshopspring/decimal, or just use currency units, don't use floating point numbers here. Pass the currency as a string, or in the currency unit, do not use floating point numbers here.

In fact, there is another trick: for these values, we can use:xxx * 10000so that we can retain its accuracy.10000This value can be negotiated within the team.

This is the article about how to avoid floating point accuracy problems when GO currency calculation. For more related content on floating point accuracy problems, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!