| Crates.io | fixed-num |
| lib.rs | fixed-num |
| version | 0.1.1 |
| created_at | 2025-04-21 23:54:15.96165+00 |
| updated_at | 2025-04-22 00:03:21.117825+00 |
| description | A high-precision, high-performance fixed-point decimal type. |
| homepage | |
| repository | https://github.com/wdanilo/fixed-num |
| max_upload_size | |
| id | 1643377 |
| size | 128,887 |
Dec19x19 is a high-precision, high-performance fixed-point decimal type for Rust.
It is designed for environments where accuracy, determinism, and raw speed are non-negotiable: financial systems, trading engines, technical analysis, backtesting, and anywhere floating-point drift or arbitrary-precision overhead are unacceptable.
Internally, values are stored as i128 integers with the last 19 digits interpreted as the
fractional part. This allows all operations to perform without rounding or approximations within
the full range of exactly 19 fractional and 19 integer digits:
±9_999_999_999_999_999_999.999_999_999_999_999_999_9
The actual representable bounds are wider:
+17_014_118_346_046_923_173.168_730_371_588_410_572_7−17_014_118_346_046_923_173.168_730_371_588_410_572_8Overflow is safely handled via checked_* and saturating_* variants.
Dec19x19Dec19x19 is built for applications where exact decimal precision, deterministic behavior, and
high performance are essential. This includes financial software, trading platforms,
simulations, and systems where rounding errors are unacceptable.
In many domains—especially finance and crypto—values are represented using fixed decimal
precision. For example, most cryptocurrencies (including Ethereum) define token values using 18
decimal places, meaning the smallest unit is 10^-18. Floating-point numbers (f64, f32)
can't accurately represent these values without precision loss, and results can vary across
architectures due to non-deterministic behavior.
Unlike floating-point types, Dec19x19 guarantees:
i128 arithmetic
with zero allocations.Use Dec19x19 when:
Dec19x19!(1) as 1 millisecond,
it covers the range of 100 million years with precision down to the zeptosecond (travel time
of a photon across a hydrogen molecule = 247 zeptoseconds).In short, Dec19x19 provides the precision of big-decimal, performance close to primitive
types, and the reliability that floating-point types can't offer.
🔬 Exact Decimal Precision
Fixed 19 integer + 19 fractional digits. No approximations.
🛡️ Safety by Default
Checked and saturating arithmetic built in. No panics, no surprises.
🚀 High Performance
Lean i128 math optimized for speed. Compiles to minimal instructions.
🧪 Proven Correctness
Verified via extensive tests, fuzzing, and comparison with other crates.
🧱 Clean and simple implementation
Internally just a scaled i128. Easy to audit, maintain, and extend.
Construct values via:
Dec19x19!(...) macro to parse a decimal literal at compile time,Dec19x19::from_str(...) method to parse a decimal literal at runtime,Dec19x19::from(...) method to convert from other narrower types,Dec19x19::try_from(...) method to convert from other wider types.use fixed_num::Dec19x19 as Dec;
use std::str::FromStr;
let price = Dec::from(123_u8) + Dec!(0.456);
let fee = Dec!(1e-3);
let total = price + fee;
assert_eq!(Ok(total), Dec::from_str("123.457"));
assert_eq!(format!("{total}"), "123.457");
You can print Dec19x19 values using the Display trait with all the usual formatting options:
use fixed_num::Dec19x19 as Dec;
let dec = Dec!(7_654_321.123_456_7);
assert_eq!(&format!("{dec}"), "7654321.1234567");
// Human-readable form.
assert_eq!(&format!("{dec:#}"), "7_654_321.123_456_7");
// Precision rounding.
assert_eq!(&format!("{dec:.0}"), "7654321");
assert_eq!(&format!("{dec:.1}"), "7654321.1");
assert_eq!(&format!("{dec:.2}"), "7654321.12");
assert_eq!(&format!("{dec:.3}"), "7654321.123");
assert_eq!(&format!("{dec:.4}"), "7654321.1235");
assert_eq!(&format!("{dec:#.0}"), "7_654_321");
assert_eq!(&format!("{dec:#.4}"), "7_654_321.123_5");
assert_eq!(&format!("{dec:#.19}"), "7_654_321.123_456_700_000_000_000_0");
// Padding and alignment.
assert_eq!(&format!("{dec:#24}"), " 7_654_321.123_456_7");
assert_eq!(&format!("{dec:<#24}"), " 7_654_321.123_456_7");
assert_eq!(&format!("{dec:>#24}"), "7_654_321.123_456_7 ");
assert_eq!(&format!("{dec:^#24}"), " 7_654_321.123_456_7 ");
assert_eq!(&format!("{dec:^#24.4}"), " 7_654_321.123_5 ");
assert_eq!(&format!("{dec:_^#24.4}"), "____7_654_321.123_5_____");
// Explicit + sign display.
assert_eq!(&format!("{dec:^+#24.4}"), " +7_654_321.123_5 ");
We highly recommend setting overflow-checks = true in your Cargo.toml, especially when
developing financial or precision-critical libraries. This option introduces minimal overhead in
release builds, but it can be invaluable for catching arithmetic bugs during development. For best
results, we suggest the following configuration:
# Cargo.toml
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
panic = "abort"
overflow-checks = true
strip = true
# .cargo/config.toml
[build]
rustflags = ["-C", "target-cpu=native"]
Dec19x19 implements most standard arithmetic operations. The list of supported operations can be found here. Operations that never panic are marked with the ✅ symbol.
fixed_num |
rust_decimal |
bigdecimal |
decimal |
decimal_rs |
fixed |
fastnum |
|
|---|---|---|---|---|---|---|---|
| 100% Rust | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| Size (bits) | 128 | 128 | dynamic | 128 | 160 | Configurable | 64/128/256/512/.. |
| Underlying repr | i128 |
4 x u32 |
Vec<u64> |
[u8; 16] |
(u128, i16, bool, u8) |
Configurable | Configurable |
| Arbitrary precision | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ⚠️ (chosen during compilation) |
| Decimal fixed-point precision | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Precision | 38 digits, 19 before and 19 after dot | 28 digits, dot anywhere | Infinite | 34 digits, dot anywhere. More digits with round-off errors. | 38 digits, dot anywhere. | Configurable decimal and fractional bit count. | Infinite (chosen during compilation) |
| Copyable | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| Const exprs | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
No round-off errors (e.g. 0.1 + 0.2 ≠ 0.3) |
✅ | ✅ | ✅ | ✅ Up to 34 digits. | ✅ Up to 38 digits. | ❌ | ✅ |
±0, ±Infinity, NaN |
❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ |
Decimal represents a 128 bit
representation of a fixed-precision decimal number. The finite set of values of type Decimal are
of the form m / 10^e, where m is an integer such that -2^96 < m < 2^96, and e is an
integer between 0 and 28 inclusive. So, m is in range
-79_228_162_514_264_337_593_543_950_336 to 79_228_162_514_264_337_593_543_950_336, which gives
28 full digits and the dot can be placed anywhere in the number.Benchmarks measure normalized throughput. 1.00 = Dec19x19 baseline.
1.25 means 25% faster0.50 means 2× slower⚠️ indicates unsupported or panicking behavior| f64 | fixed_num | rust_decimal | bigdecimal | decimal | decimal_rs | fastnum | |
|---|---|---|---|---|---|---|---|
| eq | 0.82 | 1.00 | 0.10 | 0.01 | 0.02 | 0.15 | 0.09 |
| ord | 1.48 | 1.00 | 0.12 | 0.02 | 0.02 | 0.20 | 0.09 |
| signum | 1.40 | 1.00 | 0.39 | 0.03 | ⚠️ | ⚠️ | 0.50 |
| neg | 1.59 | 1.00 | 0.83 | 0.03 | 0.05 | 0.66 | 1.10 |
| abs | 2.01 | 1.00 | 1.10 | 0.03 | 0.06 | 0.82 | 0.98 |
| rem | 0.42 | 1.00 | 0.67 | 0.04 | 0.02 | 0.74 | 0.24 |
| add | 1.24 | 1.00 | 0.05 | 0.00 | 0.01 | 0.02 | 0.02 |
| sub | 1.19 | 1.00 | 0.05 | 0.00 | 0.01 | 0.02 | 0.02 |
| mul_fxf | 63.30 | 1.00 | 1.07 | 0.29 | 0.44 | 0.28 | 0.31 |
| mul_fxi | 15.72 | 1.00 | 1.32 | 0.08 | 0.12 | 0.24 | 0.34 |
| mul_ixi | 15.94 | 1.00 | 2.71 | 0.09 | 0.17 | 2.76 | 0.34 |
| div | 61.03 | 1.00 | 0.93 | 0.01 | 0.19 | 0.20 | 0.04 |
| checked_add | 1.05 | 1.00 | 0.05 | 0.00 | ⚠️ | 0.02 | ⚠️ |
| checked_sub | 1.01 | 1.00 | 0.05 | 0.00 | ⚠️ | 0.02 | ⚠️ |
| checked_mul_fxf | 51.52 | 1.00 | 1.15 | 0.30 | ⚠️ | 0.28 | ⚠️ |
| checked_mul_fxi | 14.29 | 1.00 | 2.46 | 0.08 | ⚠️ | 0.27 | ⚠️ |
| checked_mul_ixi | 14.25 | 1.00 | 3.69 | 0.10 | ⚠️ | 3.15 | ⚠️ |
| checked_div | 46.74 | 1.00 | 1.42 | 0.01 | ⚠️ | 0.24 | ⚠️ |
| trunc | 19.19 | 1.00 | 0.43 | ⚠️ | ⚠️ | 1.54 | ⚠️ |
| floor | 23.40 | 1.00 | 0.29 | ⚠️ | ⚠️ | 1.67 | 0.14 |
| ceil | 23.20 | 1.00 | 0.28 | ⚠️ | ⚠️ | 1.57 | 0.13 |
| round | 60.69 | 1.00 | 0.16 | ⚠️ | ⚠️ | 4.26 | 1.19 |
| powi | 3260.83 | 1.00 | 0.59 | ⚠️ | 0.21 | 0.36 | 0.99 |
| sqrt | 245.36 | 1.00 | 0.05 | 0.05 | ⚠️ | 0.03 | 0.00 |
| ln | 361.46 | 1.00 | 0.14 | ⚠️ | 0.01 | 0.18 | ⚠️ |
| log10_floor | 0.75 | 1.00 | 0.00 | ⚠️ | 0.00 | ⚠️ | 0.00 |
| rolling_window | 15.51 | 1.00 | 0.46 | 0.10 | ⚠️ | 0.18 | 0.38 |
⚠️ Note: The fixed crate was excluded due to frequent panics during arithmetic operations
in benchmarks.