RepoPilotOpen in app →

shopspring/decimal

Arbitrary-precision fixed-point decimal numbers in Go

Mixed

Mixed signals — read the receipts

weakest axis
Use as dependencyConcerns

non-standard license (Other); no tests detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 8w ago
  • 50+ active contributors
  • Distributed ownership (top contributor 34% of recent commits)
Show all 7 evidence items →
  • Other licensed
  • CI configured
  • Non-standard license (Other) — review terms
  • No test directory detected
What would change the summary?
  • Use as dependency ConcernsMixed if: clarify license terms

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/shopspring/decimal?axis=fork)](https://repopilot.app/r/shopspring/decimal)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/shopspring/decimal on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: shopspring/decimal

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/shopspring/decimal shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Mixed signals — read the receipts

  • Last commit 8w ago
  • 50+ active contributors
  • Distributed ownership (top contributor 34% of recent commits)
  • Other licensed
  • CI configured
  • ⚠ Non-standard license (Other) — review terms
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live shopspring/decimal repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/shopspring/decimal.

What it runs against: a local clone of shopspring/decimal — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in shopspring/decimal | Confirms the artifact applies here, not a fork | | 2 | License is still Other | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 83 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>shopspring/decimal</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of shopspring/decimal. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/shopspring/decimal.git
#   cd decimal
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of shopspring/decimal and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "shopspring/decimal(\\.git)?\\b" \\
  && ok "origin remote is shopspring/decimal" \\
  || miss "origin remote is not shopspring/decimal (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "decimal.go" \\
  && ok "decimal.go" \\
  || miss "missing critical file: decimal.go"
test -f "const.go" \\
  && ok "const.go" \\
  || miss "missing critical file: const.go"
test -f "rounding.go" \\
  && ok "rounding.go" \\
  || miss "missing critical file: rounding.go"
test -f "decimal_test.go" \\
  && ok "decimal_test.go" \\
  || miss "missing critical file: decimal_test.go"
test -f "decimal-go.go" \\
  && ok "decimal-go.go" \\
  || miss "missing critical file: decimal-go.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 83 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~53d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/shopspring/decimal"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

shopspring/decimal is a Go library providing arbitrary-precision fixed-point decimal arithmetic with no loss of precision for addition, subtraction, and multiplication. It solves the binary floating-point representation problem (e.g., float64 cannot accurately represent 0.1) by implementing a decimal type backed by big.Int, making it essential for financial calculations, pricing systems, and any domain requiring exact decimal math. Single-package monolith: core Decimal type defined in decimal.go with supporting files for constants (const.go), rounding rules (rounding.go), and Go 1.24+ compatibility shims (decimal_go124_test.go). Tests are colocated (*_test.go files) alongside implementation. Entry point is decimal-go.go for module initialization.

👥Who it's for

Backend engineers and fintech developers building payment systems, billing platforms, and e-commerce applications in Go who need to perform precise decimal calculations without rounding errors. Database teams integrating decimal serialization/deserialization with SQL and JSON APIs.

🌱Maturity & risk

Production-ready and actively maintained. The codebase has comprehensive test coverage (decimal_test.go, decimal_bench_test.go, const_test.go), CI/CD via GitHub Actions (.github/workflows/ci.yml), and supports Go 1.10+. The library is widely used in production (evident from the README listing it as the canonical choice for e-commerce), though commit recency data isn't visible here.

Low risk: minimal external dependencies (only stdlib, see go.mod), no breaking API changes since v1, and a single-maintainer model typical of stable Go libraries. The main limitation is documented in the README (max 2^31 digits after decimal point) rather than a hidden trap. No large open issue backlog is evident from the repo structure.

Active areas of work

No recent activity metrics are visible from the provided data, but the presence of decimal_go124_test.go suggests ongoing maintenance for newer Go versions. The CHANGELOG.md exists but isn't shown, indicating version history is tracked.

🚀Get running

Clone the repo, no build step required: git clone https://github.com/shopspring/decimal.git && cd decimal && go test ./... to verify the test suite. Requires Go >= 1.10 (set in go.mod).

Daily commands: Not a runnable service—it's a library. Run the test suite with go test ./... or benchmark with go test -bench=. ./... (uses decimal_bench_test.go). To use in a project: go get github.com/shopspring/decimal then import and call functions like decimal.NewFromString() (see README example).

🗺️Map of the codebase

  • decimal.go — Core Decimal type definition and primary API methods (Add, Sub, Mul, Div, etc.); this is the load-bearing struct and every contributor must understand its fields and contracts.
  • const.go — Defines package-level constants and helper functions for internal representation; essential for understanding precision limits and the 2^31-digit constraint.
  • rounding.go — Implements all rounding modes and strategy logic; critical for correct arithmetic results and a common area of extension.
  • decimal_test.go — Comprehensive test suite covering all public APIs and edge cases; defines expected behavior and regressions to avoid.
  • decimal-go.go — Go 1.10+ compatibility layer and main entry point; handles version-specific features and serialization/deserialization entry points.
  • decimal_bench_test.go — Performance benchmarks for arithmetic operations; guides optimization decisions and prevents performance regressions.

🧩Components & responsibilities

  • Decimal struct (Go struct, big.Int) — Encapsulates a fixed-point decimal number with big.Int mantissa and int32 exponent; validates and maintains invariants
    • Failure mode: Invalid exponent range (> 2^31) causes panic; should be caught during construction or at operation boundaries
  • Rounding module (RoundingMode enum, big.Int manipulation) — Applies banker's rounding, ceiling, floor, and truncation strategies to reduce precision without information loss
    • Failure mode: Incorrect rounding mode selection leads to subtle precision loss; mitigated by explicit API requiring mode selection
  • Serialization layer (encoding/json, encoding/xml, database/sql/driver, strconv) — Converts Decimal to/from JSON, XML, SQL, and string formats; ensures round-trip fidelity
    • Failure mode: Malformed input (e.g., invalid JSON) returns error; caller must handle gracefully
  • Arithmetic engine (big.Int methods (Add, Sub, Mul, Div, Mod), scale/exponent logic) — Implements Add, Sub, Mul, Div using big.Int operations and scale adjustment; preserves precision throughout
    • Failure mode: Division by zero returns error; scale overflow (> 2^31) causes panic during construction

🔀Data flow

  • User input (string or number)undefined — undefined

🛠️How to make changes

Add a new Decimal method for custom arithmetic operation

  1. Define the method signature in decimal.go following naming conventions (e.g., Pow, Sqrt, etc.); use receiver Decimal and return (Decimal, error) for fallible ops (decimal.go)
  2. Implement the core logic using existing helpers from const.go (e.g., setExponent, cmp); leverage big.Int internally for precision (decimal.go)
  3. For operations requiring precision control, accept a context or scale parameter and apply rounding via rounding.go strategies (rounding.go)
  4. Add comprehensive tests in decimal_test.go covering edge cases (negative, zero, large scales) and verify roundtrip with string parsing (decimal_test.go)
  5. Add optional benchmark in decimal_bench_test.go to track performance impact (decimal_bench_test.go)

Support a new serialization format (e.g., Protocol Buffers or custom binary)

  1. Extend decimal-go.go with a new marshaling method (e.g., MarshalProto, MarshalBinary) that encodes the internal big.Int and exponent (decimal-go.go)
  2. Implement the corresponding unmarshaling method (UnmarshalProto, UnmarshalBinary) that reconstructs the Decimal from encoded bytes (decimal-go.go)
  3. Add test cases in decimal_test.go to validate round-trip encoding/decoding for various Decimal values (decimal_test.go)

Add a new rounding mode

  1. Define a new RoundingMode constant in const.go if the mode is fundamentally different from existing ones (const.go)
  2. Implement the rounding logic in rounding.go following the pattern of existing modes; include helper to round a big.Int at a given scale (rounding.go)
  3. Integrate the new mode into Decimal methods that accept rounding parameters (e.g., Div, Round); ensure consistent behavior across all uses (decimal.go)
  4. Test the new mode exhaustively in decimal_test.go with positive, negative, and boundary cases (decimal_test.go)

Fix a precision or rounding bug

  1. Write a failing test case in decimal_test.go that reproduces the bug with minimal input (decimal_test.go)
  2. Identify the root cause in decimal.go or rounding.go by tracing the arithmetic operation and scale management (decimal.go)
  3. Fix the issue, ensuring no overflow of the internal big.Int and correct exponent tracking; verify const.go helpers are used correctly (const.go)
  4. Run full test suite and benchmarks to confirm the fix does not regress other operations (decimal_bench_test.go)

🔧Why these technologies

  • Go's math/big package — Provides arbitrary-precision integer arithmetic without overflow; essential for preserving all significant digits during decimal operations
  • Fixed-point representation (big.Int + exponent) — Avoids floating-point rounding errors and allows exact decimal representation required for financial and precision-critical applications
  • Rounding modes enum — Allows caller to control precision loss at division boundaries; critical for compliance with financial regulations and business rules
  • SQL driver interfaces (database/sql/driver) — Enables seamless integration with Go's database ecosystem; decouples decimal type from specific database drivers

⚖️Trade-offs already made

  • Fixed-point with exponent instead of variable-length byte representation

    • Why: Simpler arithmetic and faster operations; leverages Go's big.Int which is highly optimized
    • Consequence: Maximum 2^31 digits after decimal point; loses some flexibility in extreme precision scenarios but gains performance and simplicity
  • Zero-value is safe (equals 0) without explicit initialization

    • Why: Improves ergonomics and reduces nil-pointer errors; aligns with Go idioms
    • Consequence: Requires careful default handling of uninitialized Decimal fields; slightly more overhead in type definition
  • Explicit precision parameter in Div() rather than automatic inference

    • Why: Prevents surprising precision loss; makes rounding decision explicit and auditable
    • Consequence: More verbose API; caller must decide precision upfront, but ensures predictable behavior
  • No operator overloading support (Go limitation)

    • Why: Go does not support operator overloading; method-based API is the only option
    • Consequence: More verbose syntax (d1.Add(d2) vs d1 + d2) but consistent with Go conventions and avoids implicit precision surprises

🚫Non-goals (don't propose these)

  • Real-time or streaming decimal computation; designed for discrete arithmetic operations
  • Automatic currency conversion or exchange-rate handling; strictly arithmetic
  • Hardware acceleration or SIMD optimization; pure software big-integer math
  • Locale-aware formatting; numeric formatting is culture-agnostic

🪤Traps & gotchas

No environment variables or external services required. The main non-obvious constraint: NewFromFloat uses base-10 string conversion internally to avoid binary float precision issues, so NewFromFloat(0.1) is not a direct pass-through. Division requires explicit precision parameter (e.g., Div(divisor, places)) to avoid unbounded results—no default rounding mode. The exponent is limited to int32, capping decimal scale at ±2^31 as noted in README.

🏗️Architecture

💡Concepts to learn

  • Arbitrary-precision arithmetic — Understanding how shopspring/decimal achieves precision beyond native types by using big.Int and a custom exponent is fundamental to using and extending the library
  • Fixed-point vs. floating-point representation — The library's core design choice—storing a fixed decimal point position rather than dynamic exponent—determines its accuracy for financial math and why it solves float64 problems
  • Rounding modes (ROUND_HALF_UP, ROUND_DOWN, etc.) — shopspring/decimal implements multiple rounding strategies in rounding.go; choosing the correct mode is critical for regulatory compliance in financial systems
  • Immutable value types — Decimal is designed as an immutable type where all operations return new instances; this pattern affects API design, memory usage, and concurrency safety in the library
  • Scanner/Valuer interfaces (database/sql) — shopspring/decimal implements Go's database/sql marshaling interfaces, making direct integration with SQL databases seamless; understanding these is necessary for database operations
  • Scale and precision (decimal numeral system) — The library tracks both the mantissa (via big.Int) and scale (exponent) separately; understanding this split is essential for comprehending how operations preserve or change precision
  • cockroachdb/apd — Direct alternative for arbitrary-precision decimals in Go with a mutable API and richer feature set; explicitly mentioned in README as more performant for complex use cases
  • alpacahq/alpacadecimal — Drop-in compatible alternative optimized for high performance with fixed 12-digit precision; recommended when precision is bounded and speed is critical
  • govalues/decimal — Zero-allocation high-performance decimal for Go with 19-digit precision; useful for latency-sensitive financial systems where lower precision is acceptable
  • golang/go — Core Go standard library, particularly math/big which shopspring/decimal depends on for arbitrary-precision integer arithmetic
  • greatcloak/decimal — Fork of shopspring/decimal tailored for billing and e-commerce, adds BSON marshaling and domain-specific conveniences on top of this base

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive benchmarks for division operations in decimal_bench_test.go

The repo has decimal_bench_test.go but division is a complex operation that deserves dedicated performance benchmarks. Since division requires specified precision (unlike addition/multiplication which have 'no loss of precision'), performance regression testing is critical. This helps contributors understand performance characteristics and catch regressions when optimizing the division algorithm in rounding.go.

  • [ ] Add BenchmarkDivide with various precision levels (0, 2, 10, 100 decimal places)
  • [ ] Add BenchmarkDivideWithRounding comparing different rounding modes from rounding.go
  • [ ] Add BenchmarkDivideByZero to ensure error handling doesn't impact fast path
  • [ ] Run benchmarks locally and document baseline results in CHANGELOG.md

Add Go 1.24+ specific tests and verify compatibility in decimal_go124_test.go

The file decimal_go124_test.go exists but its purpose and coverage are unclear from the file structure. Given that go.mod specifies Go 1.10 as minimum but this file targets 1.24, there's likely a feature or optimization specific to newer Go versions. This PR should document what 1.24+ features are being tested and ensure the test file has comprehensive coverage of version-specific behavior.

  • [ ] Review decimal_go124_test.go and document which Go 1.24+ features it tests (e.g., range iteration, new math functions)
  • [ ] Add comments explaining version-specific optimizations or behavior changes
  • [ ] Ensure tests cover both happy path and edge cases for 1.24+ specific code
  • [ ] Update CI workflow in .github/workflows/ci.yml to explicitly test Go 1.24 if not already present

Add missing serialization/deserialization tests in decimal_test.go

The README advertises 'Database/sql serialization/deserialization' and 'JSON and XML serialization/deserialization' as key features, but these complex operations warrant dedicated test coverage. Current test file likely has basic tests but should include edge cases like null values, precision preservation, and format validation across different database drivers and encoding formats.

  • [ ] Add test cases for database/sql Scan() and Value() methods with NULL, zero, and very large precision decimals
  • [ ] Add JSON marshaling/unmarshaling tests covering scientific notation, precision loss scenarios, and invalid JSON inputs
  • [ ] Add XML marshaling/unmarshaling tests with namespace handling and nested structures
  • [ ] Add round-trip tests ensuring Decimal -> JSON -> Decimal maintains exact precision

🌿Good first issues

  • Add benchmarks for database/sql Scan and Value operations in decimal_bench_test.go—currently only arithmetic operations are benchmarked, making it hard to optimize serialization paths.
  • Expand decimal_test.go with tests for edge cases in JSON/XML marshaling (nil pointers, very large exponents near int32 limits, NaN-like values) which are mentioned in features but lack explicit test coverage.
  • Create a helper function or document best practices for safely parsing user-supplied decimal strings in README, since NewFromString can fail silently and the error handling pattern isn't shown in the main example.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 400829b — chore: rename AvoidScientificNotation to UseScientificNotation (#416) (mwoss)
  • 6540310 — Add support for omitzero struct tag (#415) (mwoss)
  • 9620fb7 — Add Spanner support for Encode and Decode (#395) (jtwatson)
  • e1e92bf — TrimTrailingZeros and AvoidScientificNotation bool variables (#389) (JohnAD)
  • 08afb35UnmarshalJSON, Scan and NewFromString performance improvements (#403) (PauliusLozys)
  • 01bb203 — Allow CI jobs on PR creation and sync (mwoss)
  • a1bdfc3 — Release version 1.4.0 (#365) (mwoss)
  • 275e48e — Add docs section with alternative libraries (#363) (mwoss)
  • dd603cb — Support scanning uint64 (#364) (serprex)
  • 80ec940 — Add NewFromUint64 constructor (#352) (agmt)

🔒Security observations

The shopspring/decimal repository demonstrates good security practices overall. It is a pure mathematical library with no external dependencies, which significantly reduces the attack surface. No hardcoded secrets, injection vulnerabilities, or infrastructure misconfigurations were identified. The primary concern is the outdated minimum Go version requirement, which should be modernized to receive current security patches and bug fixes. The codebase uses CI/CD pipelines (GitHub Actions) and maintains active development with changelog tracking. Given the library's focused purpose (decimal arithmetic), the attack surface is minimal.

  • Low · Outdated Go Version Requirement — go.mod. The module specifies Go 1.10 as the minimum version. Go 1.10 was released in February 2018 and is no longer supported. This version is vulnerable to multiple known security vulnerabilities that have been patched in newer Go versions. Fix: Update the minimum Go version requirement to at least Go 1.21 or the latest stable version. Update go.mod to reflect: 'go 1.21' or newer.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · shopspring/decimal — RepoPilot