

Lead Engineer. Based in Tāmaki Makaurau, Aotearoa (Auckland, New Zealand).
Early on in my Go journey, I was building a billing engine. I needed to handle decimal calculations accurately. Unfortunately, Go does not have a native decimal type. After about an hour of research I found 2 error free solutions.
Fast forward to Jan 2021 and a Google search for
decimal handling in golang
retrieves the following results:In my view, most people who contribute to open source projects are amazing and brave. It takes a lot of courage to put your work and ideas out there. My intention here is not to criticise their work. At the time this post was penned, the library mentioned in the first search result is a poor choice if you want accurate results.
There are numerous open issues clearly indicating incorrect results. The second search result has an open issue for incorrect results with very large values. All the other search results are discussing various options to handle decimal operations.
The motivation for this post is to discuss 2 error free options with the hope that this post reaches more gophers.
CockroachDB is a popular open source DB written in Go. I use it for most of my projects. I was using it for the billing engine I was building and my investigation led me to the library they were maintaining.
Here is some example code for decimal division. Note: make sure you are using the latest version of the library -
v2
at the time of this post.package main
import (
"fmt"
"log"
"github.com/cockroachdb/apd/v2"
)
func main() {
// Division needs a rounding specified.
// Precision here is the total number of digits
// to the left and right of the decimal place.
context := apd.BaseContext.WithPrecision(10)
// x = 1.234
xDecimal, _, err := apd.NewFromString("1.234")
if err != nil {
log.Fatalln(err)
}
// y = 3
yDecimal := apd.New(3, 0)
result := apd.New(0, 0)
_, err = context.Quo(result, xDecimal, yDecimal)
if err != nil {
log.Fatalln(err)
}
fmt.Println(result)
}
Produces the following result:
0.4113333333
Most popular databases have native support for decimal type. If your app involves the use of a database and you need to perform decimal operations on values which are already stored in the DB, then it may be convenient to use SQL to perform decimal operations instead of having to retrieve data and then perform decimal operations in Go.
In the event data is not already in the DB, you can construct a SQL statement to perform decimal operations with the understanding that there is a network hop.
Example SQL:
// PostgreSQL
SELECT ('1.234'::numeric/'3'::numeric)::numeric(20,10);
// CockroachDB
SELECT ('1.234'::decimal/'3'::decimal)::decimal(20,10);
(precision,scale)
like you would in DB. I have asked the authors for guidance and I am waiting for their response.2 error free options for handling decimal types in Go have been presented. Always prototype new options to measure and understand if they can fit your needs.
I mostly use Option 1. I use Option 2 only when I need to control rounding to the right of the decimal place OR if the data already exists in the DB.
Did you know that the co-founder and current CEO of CockroachDB was one of the original authors of the popular tool Gimp?
I am not an employee of CockroachDB.
Create your free account to unlock your custom reading experience.