decimal-scaled 0.5.0

Const-generic base-10 fixed-point decimals (D18/D38/D76/D153/D307 and the half-width tiers up to D1232) with integer-only transcendentals correctly rounded to within 0.5 ULP — exact at the type's last representable place. Deterministic across every platform; no_std-friendly.
Documentation

decimal-scaled

crates.io docs.rs MSRV License site OpenSSF Best Practices OpenSSF Scorecard cargo-audit CodeQL

DocsPerformanceComparisonsAlgorithmsRoadmapAPI reference

A fast, precise, decimal library.

  • Decimal storage — unlike floating point, 1.1 is exactly 1.1.
  • Multiple rounding modes — six in total, HalfToEven by default.
  • Up to 4 Kb numbers — twelve widths, D18 to D1232.
  • Choose your precision at compile time — from 0 to one less than the width. i.e. D1232 can carry a precision of 1231 digits.
  • no_std friendly — the strict, integer-only path needs no std.
  • Validated by 71,469,918 value tests — every width × scale × rounding mode.

Install

[dependencies]
decimal-scaled = { version = "0.5", features = ["macros"] }

First use

use decimal_scaled::{d38, D38s12};

// The most common way to make a value: a literal, scale inferred from
// its digits.
let x = d38!(1.564232);                        // D38<6>
assert_eq!(x.to_string(), "1.564232");

let price: D38s12 = "19.99".parse().unwrap();
let qty = D38s12::try_from(3i64).unwrap();     // integer, scaled by 10^SCALE (fallible)
let total = price * qty;                       // 59.97 exactly

assert_eq!(total.to_string(), "59.97");
assert_eq!(total, d38!(59.97, scale 12));

// Transcendentals are correctly rounded to <= 0.5 ULP, integer-only,
// and bit-identical across platforms.
let sqrt2 = d38!(2, scale 12).sqrt_strict();

Why decimal-scaled

You need… decimal-scaled gives you…
Decimal arithmetic that doesn't drift (0.1 + 0.2 == 0.3) Base-10 storage; exact + - %, correctly-rounded * /.
Bit-identical results across Linux / macOS / Windows / ARM / x86 *_strict transcendentals — integer-only, no platform libm.
Compile-time-fixed precision with zero per-value scale byte Const-generic D38<19>, D76<35> etc. — scale is in the type.
no_std (or no_std + alloc) Builds under no_std + alloc with default-features = false; the strict, integer-only path needs no libm.
Correctly-rounded ln / exp / sin / cos / tan / sqrt / atan and friends — by default Within 0.5 ULP, HalfToEven by default; switch per call via *_with(mode) or crate-wide via the rounding-* features.

Documentation

Full docs: https://mootable.github.io/decimal-scaled/.

API reference: https://docs.rs/decimal-scaled/.


License

Licensed under either of:

at your option.

Copyright 2026 John Moxley. Third-party code attributions are listed in LICENSE-THIRD-PARTY.