Skip to content

Releases: AlexandrosKyriakakis/zerodecimal

v0.0.2

13 Jun 20:08
a9fad51

Choose a tag to compare

What's Changed

Full Changelog: v0.0.1...v0.0.2

v0.0.1

12 Jun 17:31

Choose a tag to compare

zerodecimal v0.0.1 — first release

Zero-allocation, panic-free, fixed-point decimals for latency-critical Go. No big.Int anywhere in the package, no GC pressure, and the fastest benchmark results of any Go decimal library we tested.

Highlights

  • Strictly zero heap allocations on every operation — parse, arithmetic, comparison, rounding, conversions, and every Unmarshal*/Scan path, on success and error paths. Enforced by exact testing.AllocsPerRun gates in the default test suite (alloc_test.go). String/Marshal* allocate exactly their one return value.
  • Fastest in class (Apple M1 Pro, benchstat over -count=10, committed in benchmarks/):
    • −35.0% time geomean vs quagmt/udecimal (15.50ns → 10.07ns) — faster on 89 of 90 op×shape cells, one statistical tie
    • −79.7% vs ericlagergren/decimal, −83.4% vs alpacadecimal, −89.6% vs shopspring/decimal
    • PGO adds a further −7.5% geomean — see the README's PGO guide and benchmarks/bench-pgo.txt
  • Reciprocal division: rescaling, rounding, formatting, and division never use the hardware divider for powers of ten — precomputed Granlund–Montgomery–Warren magics (64-bit) and Möller–Granlund 2-by-1 reciprocal steps (128/256-bit), with all table constants generated and re-proven against big.Int.
  • Panic-free error model: fallible operations return zero-allocation sentinel errors (errors.Is-able); Must* twins panic for call sites with proven bounds.

What's in the box

  • 24-byte value type: value = ±coef / 10^prec, 128-bit coefficient, 0–19 fractional digits; domain ±(2¹²⁸−1)/10^prec (~39 significant digits)
  • Arithmetic: Add, Sub, Mul, Div (adaptive precision — huge quotients degrade precision gracefully instead of failing), QuoRem, Mod, Sum, Avg, Min/Max
  • Rounding: Round (half away from zero), RoundBank, RoundUp, RoundDown, RoundCeil, RoundFloor, Truncate, Floor, Ceil — all infallible
  • Parsing: zero-alloc NewFromString/ParseBytes (+Trunc variants for lossy ingest), scientific notation, strict float constructors
  • Codecs: always-quoted JSON, text, compact binary (10/18 bytes), database/sql Scan/Value, NullDecimal; implements Go 1.24+ encoding.TextAppender/BinaryAppender for zero-alloc encoding
  • Small-value string cache: String()/Value() are 0-alloc for −1000.00..+1000.00 at ≤2dp (opt out: -tags zerodecimal_nostrcache)
  • Build tags zerodecimal_prec9 / zerodecimal_prec12 for reduced division precision (compile+vet verified; test suites assume the default 19)

How correctness is enforced

  • Deterministic differential cross-check vs shopspring/decimal: ~112k pairs every test run, including proofs that every returned ErrOverflow is genuine (crosscheck_test.go)
  • 23 differential fuzz targets vs shopspring and udecimal (-tags fuzz), soak-tested; garbage inputs cannot panic the library
  • 40M+ case verification of the 128/256-bit primitives and reciprocal tables against bits.Div64/big.Int
  • 98.6% coverage, race-clean, CI across Linux/macOS/Windows × two Go versions

Requirements & install

  • Go 1.26+, zero runtime dependencies
  • go get github.com/AlexandrosKyriakakis/zerodecimal (while the repo is private: set GOPRIVATE=github.com/AlexandrosKyriakakis/zerodecimal)

Known limitations (deliberate)

  • Not a drop-in shopspring replacement: arithmetic returns (Decimal, error), rounding places are uint8 (no negative places), "1."/".1" are rejected, Div truncates at adaptive precision rather than rounding at DivisionPrecision
  • No Pow, Sqrt, Ln, or trig yet — reserved for v2
  • Binary format is not wire-compatible with udecimal (documented layout, version-guarded)
  • == is representation equality; use Equal/Cmp for numeric comparison

Credits

Built standing on the shoulders of quagmt/udecimal (BSD-3-Clause — the 256÷128 division is adapted from it, with a latent-panic fix, and the fuzz corpus seeds it pioneered), ridiculousfish/libdivide, alpacadecimal (small-value cache design), shopspring/decimal (the correctness oracle), and Möller & Granlund / Granlund & Montgomery's division papers.

Full Changelog: https://github.com/AlexandrosKyriakakis/zerodecimal/commits/v0.0.1