Package money implements immutable monetary amounts and exchange rates for Go.
- 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.
 
To add the money package to your Go workspace:
go get github.com/govalues/moneyCreate 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
}For detailed documentation and additional examples, visit the package documentation.
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 | 
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.