govalues/decimal

repository·main·Indexed 42 days ago

https://github.com/govalues/decimal

A Go package implementing correctly rounded decimal floating-point numbers for transactional financial systems. It features high performance, zero heap allocations, and panic-free arithmetic. The package supports banker's rounding (half-to-even), transcendental functions, and provides direct compatibility with JSON, BSON, XML, and SQL. It includes specialized methods like MulExact and AddExact to prevent precision loss in monetary calculations.

Tokens
6.1K
Snippets
20
Records
43
Agent score
54%

What's inside govalues/decimal

  1. Compatibility with BSON, JSON, XML, and SQL

    main

    The decimal package implements the necessary interfaces for direct compatibility with common Go data handling packages:

    • mongo-driver/bson (BSON)
    • encoding/json (JSON)
    • encoding/xml (XML)
    • database/sql (SQL)
  2. Perform arithmetic operations with decimal

    main

    The decimal package provides a wide range of arithmetic operations, including basic math, compound operations, and transcendental functions. All operations are panic-free and return errors where appropriate (though the README examples show direct usage).

    // Basic Arithmetic
    d.Add(e)           // 8 + 12.5
    d.Sub(e)           // 8 - 12.5
    d.SubAbs(e)        // abs(8 - 12.5)
    d.Mul(e)           // 8 * 12.5
    d.PowInt(2)        // 8²
    
    // Compound Arithmetic
    d.AddMul(e, f)     // 8 + 12.5 * 2.567
    d.SubMul(e, f)     // 8 - 12.5 * 2.567
    d.AddQuo(e, f)     // 8 + 12.5 / 2.567
    
    // Division and Remainder
    d.Quo(e)           // 8 / 12.5
    d.QuoRem(e)        // 8 div 12.5, 8 mod 12.5
    d.Inv()            // 1 / 8
    
    // Package-level functions
    decimal.Sum(d, e, f)  // 8 + 12.5 + 2.567
    decimal.Mean(d, e, f) // (8 + 12.5 + 2.567) / 3
    decimal.Prod(d, e, f) // 8 * 12.5 * 2.567
    
    // Transcendental functions
    e.Sqrt()           // √12.5
    e.Exp()            // exp(12.5)
    e.Log()            // ln(12.5)
    e.Pow(d)           // 12.5⁸
  3. Round decimal values

    main

    You can round, ceil, floor, or truncate decimal values to a specific number of decimal places. The package uses half-to-even (banker's rounding) for all rounding operations.

    // Rounding to 2 decimal places
    g.Round(2) // 7.90
    g.Ceil(2)  // 7.90
    g.Floor(2) // 7.89
    g.Trunc(2) // 7.89
  4. Create decimal values using constructors

    main

    You can create decimal values using several constructor methods. Note that most constructors return both the value and an error, which should be handled to ensure safety (e.g., in case of parsing errors).

    // d = 8
    d, _ := decimal.New(8, 0)
    
    // e = 12.5
    e, _ := decimal.Parse("12.5")
    
    // f = 2.567
    f, _ := decimal.NewFromFloat64(2.567)
    
    // g = 7.896
    g, _ := decimal.NewFromInt64(7, 896, 3)
  5. Perform fused quotient-subtraction with SubQuo and SubQuoExact

    main

    The SubQuo and SubQuoExact methods compute the fused operation d - e / f using at least double precision during intermediate rounding.

    • SubQuo(e, f Decimal) (Decimal, error): Computes d - e / f with default rounding.
    • SubQuoExact(e, f Decimal, scale int) (Decimal, error): Computes d - e / f and requires that no significant digits are lost during rounding at the specified scale.

    Errors are returned if:

    • The divisor f is 0.
    • The integer part of the result exceeds MaxPrec digits.
    • In SubQuoExact, the provided scale is outside the allowed MinScale to MaxScale range, or significant digits are lost during rounding.
    // Example usage (conceptual)
    // result = d - (e / f)
    result, err := d.SubQuo(e, f)
    
    // result = d - (e / f) with specific scale
    result, err = d.SubQuoExact(e, f, 2)
  6. Calculate exponential with Exp and Expm1

    main

    Compute exponential functions:

    • Exp() (Decimal, error): Returns the (possibly rounded) exponential $e^d$.
    • Expm1() (Decimal, error): Returns the shifted exponential $e^d - 1$.

    Errors:

    • Both return an error if the integer part of the result exceeds MaxPrec digits.
  7. Convert Decimal to and from float64

    main

    Use NewFromFloat64(f) to create a Decimal from a float64. This method returns an error if the float is NaN or Inf.

    Use Float64() to convert a Decimal back to a float64. This uses banker's rounding (rounding half to even). Note that this conversion may lose precision because float64 has less precision than the Decimal type.

    d, err := decimal.NewFromFloat64(3.14159)
    f, ok := d.Float64()
  8. Clamp a decimal within a range

    main

    The Clamp(min, max Decimal) (Decimal, error) method constrains a decimal within the provided [min, max] range.

    • If d < min, it returns min.
    • If d > max, it returns max.
    • Otherwise, it returns d.

    Errors are returned if min is numerically greater than max.

    clamped, err := d.Clamp(min, max)
  9. Perform decimal scaling and rounding with fint

    main

    The fint type provides several methods to manipulate values as if they were decimal numbers by shifting the decimal point (scaling by powers of 10):

    • lsh(shift int): Left shift. Calculates $x \times 10^{shift}$. Returns ok=false on overflow.
    • rshHalfEven(shift int): Right shift with half-to-even rounding (banker's rounding). Calculates $round(x / 10^{shift})$.
    • rshUp(shift int): Right shift with rounding away from zero. Calculates $\lceil x / 10^{shift} \rceil$.
    • rshDown(shift int): Right shift with rounding towards zero. Calculates $\lfloor x / 10^{shift} \rfloor$.
    • fsa(shift int, b byte): Fused Shift and Addition. Calculates $(x \times 10^{shift}) + b$. Useful for parsing digits.
    x := fint(12345)
    
    // Rounding examples
    // rshHalfEven(2) -> 123
    // rshUp(2)       -> 124
    // rshDown(2)     -> 123