Package decimal implements immutable decimal floating-point numbers for Go. This package is designed specifically for use in transactional financial systems.
- Optimized Performance - Utilizes uint64 for coefficients, reducing heap allocations and memory consumption.
- Immutability - Once a decimal is set, it remains unchanged. This immutability ensures safe concurrent access across goroutines.
- Banker's Rounding - Methods use half even rounding, also known as "banker's rounding", which minimizes cumulative rounding errors commonly seen in financial calculations.
- No Panics - All methods are designed to be panic-free. Instead of potentially crashing your application, they return errors for issues such as overflow or division by zero.
- Simple String Representation - Decimals are represented without the complexities of scientific or engineering notation.
- Correctness - Fuzz testing is used to cross-validate arithmetic operations against both the cockroachdb and shopspring decimal packages.
To add the decimal package to your Go workspace:
go get github.com/govalues/decimal
Create decimal values using one of the constructors. After creating a decimal value, various operations can be performed:
package main
import (
"fmt"
"github.com/govalues/decimal"
)
func main() {
// Constructors
d, _ := decimal.New(8, 0) // d = 8
e, _ := decimal.Parse("12.5") // e = 12.5
f, _ := decimal.NewFromFloat64(2.567) // f = 2.567
g, _ := decimal.NewFromInt64(7, 896, 3) // g = 7.896
// Operations
fmt.Println(d.Add(e)) // 8 + 12.5
fmt.Println(d.Sub(e)) // 8 - 12.5
fmt.Println(d.Mul(e)) // 8 * 12.5
fmt.Println(d.Quo(e)) // 8 / 12.5
fmt.Println(d.QuoRem(e)) // 8 div 12.5, 8 mod 12.5
fmt.Println(d.FMA(e, f)) // 8 * 12.5 + 2.567
fmt.Println(d.Pow(2)) // 8 ^ 2
fmt.Println(d.Inv()) // 1 / 8
// Rounding to 2 decimal places
fmt.Println(g.Round(2)) // 7.90
fmt.Println(g.Ceil(2)) // 7.90
fmt.Println(g.Floor(2)) // 7.89
fmt.Println(g.Trunc(2)) // 7.89
// Conversions
fmt.Println(f.Int64(9)) // 2 567000000
fmt.Println(f.Float64()) // 2.567
fmt.Println(f.String()) // 2.567
// Formatting
fmt.Printf("%.2f\n", f) // 2.57
fmt.Printf("%.2k\n", f) // 256.70%
}
For detailed documentation and additional examples, visit the package
documentation.
For examples related to financial calculations, see the money
package
documentation.
Comparison with other popular packages:
Feature | govalues | cockroachdb v3.2.1 | shopspring v1.3.1 |
---|---|---|---|
Speed | High | Medium | Low1 |
Mutability | Immutable | Mutable1 | Immutable |
Memory Footprint | Low | Medium | High |
Panic Free | Yes | Yes | No |
Precision | 19 digits | Arbitrary | Arbitrary |
Default Rounding | Half to even | Half up | Half away from 0 |
Context | Implicit | Explicit | Implicit |
goos: linux
goarch: amd64
pkg: github.com/govalues/decimal-tests
cpu: AMD Ryzen 7 3700C with Radeon Vega Mobile Gfx
Test Case | Expression | govalues | cockroachdb v3.2.1 | shopspring v1.3.1 | govalues vs cockroachdb | govalues vs shopspring |
---|---|---|---|---|---|---|
Add | 2 + 3 | 15.53n | 46.68n | 142.30n | +200.45% | +816.00% |
Mul | 2 * 3 | 15.64n | 52.83n | 137.35n | +237.76% | +778.20% |
QuoFinite | 2 / 4 | 51.65n | 179.60n | 619.40n | +247.76% | +1099.34% |
QuoInfinite | 2 / 3 | 568.80n | 935.20n | 2749.00n | +64.43% | +383.30% |
Pow | 1.1^60 | 1.28µ | 3.28µ | 16.03µ | +156.99% | +1156.09% |
Pow | 1.01^600 | 4.31µ | 10.43µ | 37.00µ | +142.15% | +758.69% |
Pow | 1.001^6000 | 7.54µ | 20.39µ | 651.51µ | +170.58% | +8544.78% |
Parse | 1 | 17.14n | 77.64n | 129.15n | +353.00% | +653.50% |
Parse | 123.456 | 36.15n | 201.85n | 235.25n | +458.37% | +550.76% |
Parse | 123456789.1234567890 | 98.90n | 210.95n | 475.05n | +113.30% | +380.33% |
String | 1 | 5.18n | 21.43n | 208.00n | +313.99% | +3918.16% |
String | 123.456 | 42.31n | 67.55n | 226.55n | +59.66% | +435.52% |
String | 123456789.1234567890 | 76.04n | 209.50n | 329.95n | +175.49% | +333.89% |
Telco | see specification | 134.00n | 947.60n | 3945.50n | +607.13% | +2844.40% |
The benchmark results shown in the table are provided for informational purposes only and may vary depending on your specific use case.
Interested in contributing? Here's how to get started:
- Fork and clone the repository.
- Implement your changes.
- Write tests to cover your changes.
- Ensure all tests pass with
go test
. - Commit and push to your fork.
- Open a pull request detailing your changes.
Note: If you're considering significant changes, please open an issue first to discuss with the maintainers. This ensures alignment with the project's objectives and roadmap.