Handling Currency In Golang And Other Programming Language
Tags: go, currency, database, govalues
Published: 2024-06-28 20:37:56

Handling currency in programming languages is a critical aspect of software development, especially for applications dealing with financial transactions, e-commerce, banking, and accounting systems. Accurate representation and manipulation of currency values are essential to avoid errors that can lead to significant financial discrepancies. 

This article will explore best practices in handling currency with example in Go languages.

# Precision and Accuracy

One of the primary concerns when dealing with currency is precision. Unlike floating-point numbers, which can introduce rounding errors, currency values require precise representation. 

consider following code
```go
package main

import "fmt"

func main() {

	var a float64 = 1.1
	var b float64 = 1.2
	var c float64 = 1.3
	fmt.Println(a + b + c)

}

```
Above code would print
```text
3.5999999999999996
```
Since memory of computers is limited, most programming language including Go store floating point based on the [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754) standard using 32 or 64 bits, even using 64-bit precision it’s impossible to store an infinite number of digits, which means these numbers are rounded at some point, making them inherently imprecise, and the more calculation is performed the more they become imprecise.

There is many way to handle this problem like using 3rd party library or the programming language you use has a native support.  In Go, there are several libraries, including :
- [shopspring/decimal](https://github.com/govalues/decimal)
- [ericlagergren/decimal](https://github.com/govalues/decimal)
- [alpacahq/alpacadecimal](https://github.com/govalues/decimal)
- [govalues/decimal](https://github.com/govalues/decimal)

_credit to [kennfatt](https://dev.to/kennfatt) for curating this library list_

# Choosing Library
Choosing the right library for handling currency programming involves several considerations. Here's a guide to help you choose an appropriate decimal library for your needs

## 1. Accuracy and Precision
Ensure the library supports precision and accuracy suit your requirement. Look for arbitrary precision capabilities if dealing with very large numbers or very precise calculations.

## 2. Ease of Use
The library should have clear and comprehensive documentation. It should be easy to integrate with your existing codebase and workflows.

## 3. Performance
Consider the performance impact, especially if you are performing a large number of calculations or operating in a high-frequency trading environment.

## 4. Feature
Ensure the features suit with your needs, from basic arithmetic like rounding, addition, subtraction multiplication, division to more complex math operation.

## 5. Community and Support
A well-supported library with an active community can be crucial for getting help and finding solutions to problems.    Look for libraries that are actively maintained and updated.

## Using 3rd Party
This article will use 3rd party library ``govalues/decimal`` for code example, since doc simple and easy to read and suite the need for code demonstration 
```go
package main

import (
	"fmt"
	"github.com/govalues/decimal"
)

func main() {

	a, _ := decimal.Parse("1.1")
	b, _ := decimal.Parse("1.2")
	c, _ := decimal.Parse("1.3")

	a, _ = a.Add(b)
	a, _ = a.Add(c)
	fmt.Println(a.String())

}
```
Above code would print
```text
3.6
```
In above example has no precision loss, still since memory has a cost and not infinite, digit after the decimal point are still limited, controlling decimal digit is important, in this example you can set the size using ``decimal.ParseExact()``


# Storing And Retrieving

Storing in databases also requires careful consideration to maintain precision and consistency.

## Use Appropriate Column Types
Most relational databases have specific types for currency values, such as `DECIMAL` or `NUMERIC`.
## Avoid Floating-Point Storage
Just like in programming, avoid storing currency values as floating-point numbers in databases.

For example in MySQL
```mysql
CREATE TABLE `users` (
    `id` int,
    `balance` decimal(6, 2)
);
```


### Full MySQL Demonstration in go
```go
package main

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

func main() {

	db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
	if err != nil {
		panic(err)
	}

	_, err = db.Exec(`
		CREATE TABLE test (
			id int,
			balance_decimal decimal(16, 8),
			balance_float float(16, 8),
			PRIMARY KEY (id)
		);
	`)

	_, err = db.Exec("INSERT INTO test (id, balance_decimal, balance_float) VALUES (1, 1.1, 1.1)")
	_, err = db.Exec(`
		UPDATE test 
			SET 
			    balance_decimal = balance_decimal + 1.2 , 
			    balance_float   = balance_float + 1.2 
			WHERE id = 1;
	`)
}

```
Above code would produce

| id | balance_decimal | balance_float |
|----|-----------------|---------------|
| 1  | 2.30000000      | 2.29999995    |


# Data Transfer
Data transfer also requires careful consideration of precision. a correct format is required 

For example in JSON format, using type `string`  guaranteed precision across any programing language
```go
package main

import (
	"encoding/json"
	"log"
)

type Data struct {
	Decimal string  `json:"decimal"`
	Float   float64 `json:"float"`
}

func main() {

	payload := []byte(`{"decimal":"999.99999999999999","float":999.99999999999999}`)

	result := Data{}

	_ = json.Unmarshal(payload, &result)

	log.Print("Decimal: ", result.Decimal)
	log.Print("Float: ", result.Float)

}
```
Above code would print
```
Decimal: 999.99999999999999
Float: 1000
```


# Conclusion
Handling currency in programming languages requires careful attention to detail to ensure precision, accuracy, and consistency. By using appropriate data types, libraries, and best practices, developers can avoid common pitfalls and ensure their applications handle currency correctly. Proper handling of currency not only prevents financial errors but also enhances user trust and confidence in the application.

**There's no single best library for everyone. Each project has different needs. You should think about what's good and bad about each library based on what your project requires.**


# External Link
- [Full Code Example](https://github.com/dikac/currency-in-go)
- [govalues/decimal Repo](https://github.com/govalues/decimal)
- [shopspring/decimal Repo](https://github.com/govalues/decimal)
- [ericlagergren/decimal Repo](https://github.com/govalues/decimal)
- [alpacahq/alpacadecimal Repo](https://github.com/govalues/decimal)