money
Immutable monetary amounts and exchange rates with panic-free arithmetic
About money
money
Package money implements immutable monetary amounts and exchange rates for Go.
Key Features
- Immutability - Once set, an amount or exchange rate remains constant, ensuring safe concurrent access across goroutines.
- Banker's Rounding - Uses half-to-even rounding, also known as "banker's rounding", to minimize cumulative rounding errors commonly seen in financial calculations.
- No Panics - All methods are panic-free, returning errors instead of crashing your application in cases such as overflow, division by zero, or currency mismatch.
- Zero Heap Allocation - Optimized to avoid heap allocations, reducing garbage collector impact during arithmetic operations.
- High Precision - Supports up to 19 digits of precision, representing amounts from -99,999,999,999,999,999.99 to 99,999,999,999,999,999.99 inclusive.
- Correctness - Arithmetic operations are cross-validated against the cockroachdb/apd and shopspring/decimal packages through extensive fuzz testing.
Getting Started
Installation
To add the money package to your Go workspace:
go get github.com/govalues/money
Basic Usage
Create an amount using one of the constructors. After creating an amount, you can perform various operations as shown below:
package main
import (
"fmt"
"github.com/govalues/decimal"
"github.com/govalues/money"
)
func main() {
// Constructors
a, _ := money.NewAmount("USD", 8, 0) // a = $8.00
b, _ := money.ParseAmount("USD", "12.5") // b = $12.50
c, _ := money.NewAmountFromFloat64("USD", 2.567) // c = $2.567
d, _ := money.NewAmountFromInt64("USD", 7, 896, 3) // d = $7.896
r, _ := money.NewExchRate("USD", "EUR", 9, 1) // r = $/€ 0.9
x, _ := decimal.New(2, 0) // x = 2
// Operations
fmt.Println(a.Add(b)) // $8.00 + $12.50
fmt.Println(a.Sub(b)) // $8.00 - $12.50
fmt.Println(a.SubAbs(b)) // abs($8.00 - $12.50)
fmt.Println(a.Mul(x)) // $8.00 * 2
fmt.Println(a.AddMul(b, x)) // $8.00 + $12.50 * 2
fmt.Println(a.SubMul(b, x)) // $8.00 - $12.50 * 2
fmt.Println(r.Conv(a)) // $8.00 * $/€ 0.9
fmt.Println(a.Quo(x)) // $8.00 / 2
fmt.Println(a.AddQuo(b, x)) // $8.00 + $12.50 / 2
fmt.Println(a.SubQuo(b, x)) // $8.00 - $12.50 / 2
fmt.Println(a.QuoRem(x)) // $8.00 div 2, $8.00 mod 2
fmt.Println(a.Rat(b)) // $8.00 / $12.50
fmt.Println(a.Split(3)) // $8.00 into 3 parts
// Rounding to 2 decimal places
fmt.Println(c.RoundToCurr()) // 2.57
fmt.Println(c.CeilToCurr()) // 2.57
fmt.Println(c.FloorToCurr()) // 2.56
fmt.Println(c.TruncToCurr()) // 2.56
// Conversions
fmt.Println(d.Int64(9)) // 7 896000000
fmt.Println(d.Float64()) // 7.896
fmt.Println(d.String()) // USD 7.896
// Formatting
fmt.Printf("%v", d) // USD 7.896
fmt.Printf("%[1]f %[1]c", d) // 7.896 USD
fmt.Printf("%f", d) // 7.896
fmt.Printf("%c", d) // USD
fmt.Printf("%d", d) // 790
}
Documentation
For detailed documentation and additional examples, visit the package documentation.
Comparison
Comparison with other popular packages:
| Feature | govalues | rhymond v1.0.10 | bojanz v1.2.1 |
|---|---|---|---|
| Speed | High | Medium | Medium |
| Numeric Representation | Floating Point | Fixed Point | Floating Point |
| Precision | 19 digits | 18 digits | 39 digits |
| Default Rounding | Half to even | Not supported | Half up |
| Overflow Control | Yes | No1 | Yes |
| Support for Division | Yes | No | Yes |
| Support for Currency Conversion | Yes | No | Yes |
Benchmarks
goos: linux
goarch: amd64
pkg: github.com/govalues/money-tests
cpu: AMD Ryzen 7 3700C with Radeon Vega Mobile Gfx
| Test Case | Expression | govalues | rhymond v1.0.10 | bojanz v1.2.1 | govalues vs rhymond | govalues vs bojanz |
|---|---|---|---|---|---|---|
| Add | $2.00 + $3.00 | 22.95n | 218.30n | 144.10n | +851.41% | +528.02% |
| Mul | $2.00 * 3 | 21.80n | 133.40n | 239.60n | +511.79% | +998.83% |
| Quo (exact) | $2.00 / 4 | 80.12n | n/a | 468.05n | n/a | +484.19% |
| Quo (inexact) | $2.00 / 3 | 602.1n | n/a | 512.4n | n/a | -14.91% |
| Split | $2.00 into 10 parts | 374.9n | 897.0n | n/a | +139.28% | n/a |
| Conv | $2.00 to € | 30.88n | n/a | 348.50n | n/a | +1028.38% |
| Parse | $1 | 44.99n | 139.50n | 99.09n | +210.07% | +120.26% |
| Parse | $123.456 | 61.45n | 148.60n | 240.90n | +141.82% | +292.03% |
| Parse | $123456789.1234567890 | 131.2n | 204.4n | 253.0n | +55.85% | +92.87% |
| String | $1 | 38.48n | 200.70n | 89.92n | +421.50% | +133.65% |
| String | $123.456 | 56.34n | 229.90n | 127.05n | +308.02% | +125.49% |
| String | $123456789.1234567890 | 84.73n | 383.30n | 277.55n | +352.38% | +227.57% |
| Telco | see specification | 224.2n | n/a | 1944.0n | n/a | +766.89% |
The benchmark results shown in the table are provided for informational purposes only and may vary depending on your specific use case.
Footnotes
Frequently Asked Questions
What is money?
money is a Financial library for the Go programming language. Immutable monetary amounts and exchange rates with panic-free arithmetic
How do I install money?
Install money with the Go module system using `go get govalues/money`. Check the repository for the current installation instructions.
What category does money belong to?
money is listed under Financial, specifically Financial.