Hacking

2 Error-Free Options for Decimal handling in Golang

Author profile picture

@vijaysavanthVijay Savanth

Lead Engineer. Based in Tāmaki Makaurau, Aotearoa (Auckland, New Zealand).

Motivation

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

Option 2 – Use a database

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);

Gotchas for Option 1

  • You will need to spend a couple of hours learning the library.
  • I haven’t figured out a way to easily and accurately specify
    (precision,scale)

    like you would in DB. I have asked the authors for guidance and I am waiting for their response.

Gotchas for Option 2

  • A network hop is involved if decimal operations cannot be performed directly on data in the DB. It may pay to spend some time to measure this delay and then assess if option 2 fits your needs for data not already in the DB.
  • The network hop results in a less performant solution when compared to Option 1.
  • Setting up a DB to perform decimal operations will increase cost and complexity if your app does not need a DB.

Summary

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.

Trivia

Did you know that the co-founder and current CEO of CockroachDB was one of the original authors of the popular tool Gimp?

Disclaimer

I am not an employee of CockroachDB.

Author profile picture

Read my stories

Lead Engineer. Based in Tāmaki Makaurau, Aotearoa (Auckland, New Zealand).

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to top button

Adblock Detected

Please consider supporting us by disabling your ad blocker