fastnum

June 11, 2026 · View on GitHub

GitHub Crates.io Crates.io doc.rs MSRV

Fixed-size decimal numbers implemented in pure Rust. Suitable for financial, crypto and any other fixed-precision calculations.

API Docs

Overview

This crate is inspired by num_bigint and bigdecimal – amazing crates that allow you to store big integers and arbitrary precision fixed-point decimal numbers almost any precision.

BigInt internally uses a Vec of decimal digits the size of which is theoretically limited only by the usize max value or memory capacity.

Under the hood BigDecimal uses a BigInt object, paired with a 64-bit integer which determines the position of the decimal point. Therefore, the precision is not actually arbitrary, but limited to 2 63 decimal places.

Despite the seemingly undeniable advantages at first glance, this approach also has a number of fundamental disadvantages:

  • Non-copyable types for both integers and fixed point numbers.
  • Dynamic allocation to store even tiny numbers, for example, 0 or 1.
  • Extra dynamic allocation for almost any operation (mathematical operations, parsing, converting, etc.).
  • Constant calculations are not available.
  • Potentially uncontrolled growth of memory consumption and the need to artificially limit it.

Because most practical problems requiring the use of fixed-point numbers do not require so much limit on the number of digits, such as usize, but as a rule it is limited:

UnitPrecisionDecimal digits
United States Dollar (USD)0.012
United States Dollar, stock (USD)0.00014
Bitcoin (BTC)10-88
Ethereum (ETH)10-1818

Then most real numbers for financial and other systems requiring accuracy can use 256-bit or even 128-bit integer to store decimal digits.

So In this library, a different approach was chosen.

Decimals

fastnum provides signed and unsigned exact precision decimal numbers suitable for financial calculations that require significant integral and fractional digits with no round-off errors (such as 0.1 + 0.2 ≠ 0.3).

Any fastnum decimal type consists of an N-bit big unsigned integer, paired with a 64-bit signaling block which contains a 16-bit scaling factor determines the position of the decimal point, sign, special and signaling flags. Trailing zeros are preserved and may be exposed when in string form.

Thus, fixed-point numbers are trivially copyable and don't require any dynamic allocation. This allows you to get additional performance gains by eliminating not only dynamic allocation, like such, but also will get rid of one indirect addressing, which improves cache-friendliness and reduces the CPU load.

Why fastnum?

  • Strictly exact precision: no round-off errors (such as 0.1 + 0.2 ≠ 0.3).
  • Special values: fastnum support ±0, ±Infinity and NaN special values with IEEE 754 semantic.
  • Blazing fast: fastnum numerics are as fast as native types, well almost :).
  • Trivially copyable types: all fastnum numerics are trivially copyable (both integer and decimal, ether signed and unsigned) and can be stored on the stack, as they're fixed size.
  • No dynamic allocation: no expensive sys-call's, no indirect addressing, cache-friendly.
  • Compile-time integer and decimal parsing: all the from_* methods on fastnum integers and decimals are const, which allows parsing of integers and numerics from string slices and floats at compile time. Additionally, the string to be parsed does not have to be a literal: it could, for example, be obtained via include_str!, or env!.
  • Const-evaluated in compile time macro-helpers: any type has its own macro helper which can be used for definitions of constants or variables whose value is known in advance. This allows you to perform all the necessary checks at the compile time.
  • Short dependencies list by default: fastnum depends only upon bnum by default. All other dependencies are optional. Support for crates such as rand and serde can be enabled with crate features.
  • no-std compatible: fastnum can be used in no_std environments.
  • wasm compatible: fastnum is fully compatible with WebAssembly.
  • const evaluation: nearly all methods defined on fastnum integers and decimals are const, which allows complex compile-time calculations and checks.
  • Full range of advanced mathematical functions: exponential, roots, power, logarithmic, and trigonometric functions for working with exact precision decimals. And yes, they're all const too.

Installation

To install and use fastnum, simply add the following line to your Cargo.toml file in the [dependencies] section:

fastnum = "0.7"

Or, to enable various fastnum features as well, add, for example, this line instead:

fastnum = { version = "0.7", features = ["serde"] } # enables the "serde" feature

Example Usage

use fastnum::*;

fn main() {
    const ZERO: UD256 = udec256!(0);
    const ONE: UD256 = udec256!(1.0);

    let a = udec256!(12345);

    println!("a = {a}");
}

Features

Generic numeric num_traits trait implementations

The numtraits feature includes implementations of traits from the num_traits crate, e.g. AsPrimitive, Signed, etc.

Random Number Generation

The rand feature allows creation of random fastnum decimals via the rand crate.

Serialization and Deserialization

The serde feature enables serialization and deserialization of fastnum decimals via the serde crate. More details about serialization and deserialization you can found in API Docs.

Zeroize

The zeroize feature enables the Zeroize trait from the zeroize crate.

Database ORM's support

The diesel feature enables serialization and deserialization of fastnum decimals for diesel crate.

The sqlx feature enables serialization and deserialization of fastnum decimals for sqlx crate.

The tokio-postgres feature enables serialization and deserialization of fastnum decimals for tokio-postgres crate.

Autodocs crates support

The utoipa feature enables support of fastnum decimals for autogenerated OpenAPI documentation via the utoipa crate.

Competition & benchmarks

f64fastnumbigdecimalrust_decimaldecimal_rs
Size, bits64(52)64/128/256/512/...any128(96)64
Max precision, decimal digitsarbitrary*arbitrary2819
Exact precision
Trivially copyable / No dynamic allocation
Exceptional conditions such as inexact, subnormal, round, etc.
±0, ±Infinity and NaN special values
Compile-time calculations
Performance🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀
no-std

* Precision is arbitrary but fixed.

Benchmarks

fastnum is blazing fast. As much as possible given the overhead of arbitrary precision support.

Some benchmark reports are shown below:

Parse from string

Decimal digitsf64fastnumbigdecimal
412.782 ns11.810 ns86.252 ns
1112.759 ns17.175 ns92.105 ns
2013.426 ns27.096 ns115.91 ns
2238.531 ns30.746 ns127.37 ns
3338.102 ns42.282 ns143.59 ns
3938.295 ns48.973 ns151.37 ns
5242.090 ns83.334 ns178.53 ns
7242.856 ns112.30 ns215.94 ns

Allocation

Allocate vec![] with N elements.

Nf64fastnum(D128)bigdecimal
10062.099 ns59.355 ns1.7866 µs
50063.436 ns209.75 ns8.7757 µs
1000102.07 ns396.30 ns17.402 µs
10000769.01 ns4.2774 µs178.33 µs
10000010.777 µs43.982 µs1.8032 ms
1000000108.94 µs448.66 µs18.395 ms

Addition

Perform a + b.

Decimal digitsf64fastnumbigdecimal
2582.68 ps28.809 ns86.501 ns
24536.08 ps10.890 ns51.743 ns
39574.84 ps20.899 ns89.070 ns
40562.10 ps32.838 ns137.64 ns
100562.10 ps83.700 ns119.52 ns

Subtraction

Perform a - b.

Decimal digitsf64fastnumbigdecimal
2654.78 ps21.761 ns89.013 ns
12622.80 ps21.815 ns89.317 ns
24526.57 ps12.354 ns51.006 ns
39574.51 ps20.839 ns90.768 ns
40557.47 ps32.524 ns132.43 ns
76534.51 ps33.343 ns89.778 ns
154622.19 ps83.844 ns159.80 ns

Multiplication

Perform a × b.

Decimal digitsf64fastnumbigdecimal
3512.51 ps8.8683 ns57.996 ns
30529.00 ps8.7431 ns56.618 ns
44609.04 ps9.0473 ns106.84 ns
88617.74 ps74.798 ns463.48 ns

Division

Perform a ÷ b.

Decimal digitsf64fastnumbigdecimal
1554.17 ps12.181 ns96.252 ns
13607.92 ps84.582 ns175.94 ns
77592.75 ps1.8675 µs270.37 µs
154572.60 ps13.297 µs269.63 µs

To f64 conversion

Convert D64/D128 decimals into f64 floating point.

Decimal digitsrust_decimalfastnum 64fastnum 128bigdecimal*
13.4253 ns1.9320 ns3.1301 ns3.0061 ns
313.245 ns1.9915 ns3.1521 ns95.600 ns
411.196 ns2.0431 ns3.2573 ns97.964 ns
514.461 ns2.0424 ns3.2584 ns94.742 ns
714.623 ns1.9586 ns3.1418 ns114.97 ns
815.449 ns1.9537 ns3.1375 ns95.565 ns
1116.038 ns2.0434 ns3.2548 ns111.85 ns
1716.724 ns1.9541 ns3.1384 ns117.51 ns
2017.735 ns4.7775 ns5.7826 ns133.63 ns
2117.765 ns4.8360 ns5.9063 ns136.35 ns
33105.09 ns-18.460 ns271.66 ns
36104.97 ns-18.954 ns271.89 ns
41--36.271 ns368.55 ns

* bigdecimal to float conversion is not pretty accurate.

You can run benchmark tests with Criterion.rs tool:

cd benchmark
cargo criterion

Testing

This crate is tested as well as with specific edge cases.

cargo test --all-features

Minimum Supported Rust Version

The current Minimum Supported Rust Version (MSRV) is 1.94.

Documentation

API Docs

NB: fastnum is currently pre-1.0.0. As per the Semantic Versioning guidelines, the public API may contain breaking changes while it is in this stage. However, as the API is designed to be as similar as possible to the API of Rust's primitive types, it is unlikely that there will be a large number of breaking changes.

Compile-Time Configuration

You can set a few default parameters at compile-time via environment variables:

Environment VariableDefault
RUST_FASTNUM_DEFAULT_ROUNDING_MODEHalfUp
RUST_FASTNUM_FMT_EXPONENTIAL_LOWER_THRESHOLD5
RUST_FASTNUM_FMT_EXPONENTIAL_UPPER_THRESHOLD15
RUST_FASTNUM_FMT_MAX_INTEGER_PADDING1000
RUST_FASTNUM_SERDE_DESERIALIZE_MODEStrict

Future Work

There are several areas for further work:

  • Micro-optimization of big integer types using vector extensions (SSE2, SSE4.2, AVX2, AVX512F, etc.).
  • Const trait implementations once they're stabilized in Rust. (https://github.com/rust-lang/rust/issues/67792)
  • Integration with a large number of crates (ORM's, auto-docs crates, etc.).

Licensing

This code is dual-licensed under the permissive MIT & Apache 2.0 licenses.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Changelog

view changelog