#floats #non-zero #nan #no-std

no-std typed_floats

Types for handling floats with type checking at compile time

1 unstable release

0.7.3 Nov 29, 2023
0.6.0 Nov 15, 2023
0.1.23 Jul 31, 2023

#138 in Math

Download history 32/week @ 2023-08-15 1/week @ 2023-08-22 27/week @ 2023-08-29 7/week @ 2023-09-05 3/week @ 2023-09-12 49/week @ 2023-09-19 5/week @ 2023-09-26 18/week @ 2023-10-03 1/week @ 2023-10-10 28/week @ 2023-10-17 1/week @ 2023-10-24 135/week @ 2023-10-31 40/week @ 2023-11-07 67/week @ 2023-11-14 110/week @ 2023-11-21 156/week @ 2023-11-28

376 downloads per month


3.5K SLoC

Build Status Tests on GitHub CI Version Documentation License dependency status Minimum Supported Rust Version

This crate helps you to ensure the kind of floats you are using, without panic! (except if the unsafe function is used in an unsound way).

zero overhead: everything is checked at compile time. (only try_from adds a little overhead at runtime)

NaN is rejected by all types.

The 12 types provided by this crate are:

And their positive and negative counterparts:

(Negatives types reject +0.0 and positives types reject -0.0)

Type -∞ ]-∞; -0.0[ -0.0 +0.0 ]+0.0; +∞[ +∞ NaN
NonNaN ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
NonNaNFinite ✔️ ✔️ ✔️ ✔️
NonZeroNonNaN ✔️ ✔️ ✔️ ✔️
NonZeroNonNaNFinite ✔️ ✔️
Positive ✔️ ✔️ ✔️
PositiveFinite ✔️ ✔️
StrictlyPositive ✔️ ✔️
StrictlyPositiveFinite ✔️
Negative ✔️ ✔️ ✔️
NegativeFinite ✔️ ✔️
StrictlyNegative ✔️ ✔️
StrictlyNegativeFinite ✔️

To avoid specifying the kind of float (e.g. like Positive<f32>), you can use the modules tf64 and tf32 which expose aliases.

The following conversions are implemented:

(The trait From or TryFrom is implemented depending on the situation. Impossible conversions - for example between Positive and Negative - are not implemented.)

When to use it

When handling floats

When you handle floats, this crate can help you to ensure that you are not using NaN or Infinity by mistake. Methods and functions implemented returns a type as strict as possible, so you know when you really have to check for NaN or Infinity.

When writing a library

Using one of the type provided by this crate in your public API can help your users to avoid mistakes and limits the checks your functions have to do.

It also helps to make API simpler as you don't have to handle and document all the possible cases with NaN and Infinity for example.

E.g. the following function:

fn fast_inv_sqrt(x: StrictlyPositiveFinite) -> StrictlyPositive;


  • For the person implementing the API: the parameter x is neither NaN nor Infinity, and is strictly positive
  • For the user: the result is not NaN and is strictly positive but may be Infinity

It that example:

  • the person implementing the API doesn't have to check for NaN, Infinity, or <= 0 for the parameter x
  • the user only have to check the result for Infinity if they want to handle it differently and can't call the function with an invalid parameter.


Most methods and traits available on the underlying type are available on the types of this crate.

Most constants are also available, with the most appropriate TypedFloat type (except NAN for obvious reasons) in the tf64 and tf32 modules (in tf64::consts and tf32::consts respectively when the constant comes from core::f64::consts or core::f32::consts). Those modules are named that way to avoid conflicts or confusion with the primitives f32 and f64.

⚠️ Like for primitives f32 and f64,-0.0 == +0.0 is true for all types of this crate. To facilitate comparisons, the methods is_positive_zero and is_negative_zero are added.

Traits implemented

As none of the types of this crate can be NaN, the following traits are implemented on all 12 types:

Note: for Hash on NonNaN and NonNaNFinite there is a (small) overhead because they both accept 0.0 and -0.0, which are equal so they mush hash to the same value.

Methods implemented

All 12 types implement the methods available on f32 and f64 except:

  • deprecated and nightly-only methods
  • total_cmp(&self, other: &f64) -> Ordering
  • sin_cos(self) -> (f64, f64)
  • mul_add(self, a: f64, b: f64) -> f64
  • clamp(self, min: f64, max: f64) -> f64
  • LowerExp
  • UpperExp
  • Product
  • Sum
  • to_int_unchecked
  • to*_bits
  • from*_bits


The only method that can panic! is the unsafe method new_unchecked when used in an invalid way.

A panic! triggered in any other way is considered a security bug and should be reported.

Minimal overhead

This crate is designed to have a minimal overhead at runtime, in terms of memory, speed and binary size.

It may even be faster than using primitives f32 and f64 directly, as it may avoids some checks by using compiler hints.

The only methods that adds a little overhead are try_from because of the checks they do at runtime, compared to the unsafe method new_unchecked.

In debug mode, a little overhead is present, both to check the validity of the values and because inline may not be respected.

Any other overhead is considered a bug and should be reported.


  • std: enabled by default, gives all f32 and f64 methods.
  • serde: implements Serialize and Deserialize for all NonNaN types.
  • libm: use the Float trait from num-traits and libm to implement the missing methods when the std feature is disabled. Side effect: f32 and f64 will implement Float from num-traits. When both std and libm features are enabled, the std implementation is used.

How it works

For each operation, at compile time crate determine the most strict type possible for the result.

For example, if you multiply a PositiveFinite and a StrictlyNegativeFinite, the result will be a Negative.

Methods that takes another float as parameter will also return the most strict type possible depending on the both types. For the methods where a trait is not available to specify the return type depending on the parameter type, a new trait is created: Hypot, Min, Max, Copysign, DivEuclid and Atan2.

Main limitations

  • Doesn't fix the floating point quirks such as 0.0 == -0.0
  • Doesn't fix the odd methods such as:
    • sqrt(-0.0) returning -0.0 instead of NaN
    • min(-0.0, 0.0) returning -0.0 instead of 0.0 (same for max)
    • frac(-0.0) returning 0.0 instead of -0.0

Because that would introduce a runtime overhead and may introduce some incompatibilities with existing code.

Rust version

This crate is tested when a new version is release with:

  • Rust beta
  • Rust stable
  • Rust 1.70.0

Also, tests on nightly, beta and stable are run weekly on GitHub actions.

The minimum supported Rust version is 1.70.0 because of the use of dep: in Cargo.toml and the usage of clap.


Tests are run on different architectures on GitHub actions and CircleCI.

To run all tests:

git clone https://github.com/tdelmas/typed_floats
cd typed_floats

# generate the published documentation, including some tests
cargo xtask pre-build

cargo test --all

Similar crates

  • checked-float A crate for making invariant-enforcing floating point wrappers
  • decorum Decorum is a Rust library that provides total ordering, equivalence, hashing, and constraints for floating-point representations. Decorum does not require std.
  • eq-float Float wrappers with a total order (by setting NAN == NAN).
  • fix_float Fixed floating types that allows useful trait implementations and datastructures on float numbers
  • float-derive A crate that allows deriving Eq and Hash for types that contain floating points.
  • float-ord A total ordering for floating-point numbers.
  • nanbox NaN boxing implementation.
  • noisy_float Contains floating point types that panic if they are set to an illegal value, such as NaN.
  • num-order Numerically consistent Eq, Ord and Hash implementations for various num types (u32, f64, num_bigint::BigInt, etc.)
  • ordered-float Provides several wrapper types for Ord and Eq implementations on f64 and friends.
  • partial-min-max min and max functions that work with PartialOrd.
  • real_float Floating point types that check for correctness and implement total ordering.
  • result_float Floating point type that cannot store NaN.
  • totally-ordered No dependency, no-std totally ordered f32/f64
  • unsigned-f64 A wrapper around f64 that guarantees that the value is always non-negative on the type level.

Features provided/checked by those crates:

✔️: provided, ❌: not provided, ❓: unknown

(you may need to scroll to the right to see all the columns: "Production ready", "Avoid panic!", "Minimal overhead", "Eq/Ord", "Hash", "NaN", "Inf", "Zero", "Positive", "Negative")

Crates Production ready Avoid panic! Minimal overhead Eq/Ord Hash NaN Inf Zero Positive Negative
typed_floats ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
checked-float ✔️ ✔️ ✔️ ✔️¹ ✔️¹ ✔️¹ ✔️¹ ✔️¹
decorum ✔️ ✔️¹ ✔️¹ ✔️¹ ✔️¹ ✔️¹
eq-float ✔️ ✔️ ✔️
fix_float ✔️ ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
float-derive ✔️ ✔️
float-ord ✔️ ✔️ ✔️
nanbox ✔️
noisy_float ✔️ ✔️ ✔️
num-order ✔️ ✔️ ✔️ ✔️
ordered-float ✔️ ✔️ ✔️
partial-min-max ✔️ ✔️
real_float ✔️ ✔️ ✔️ ✔️ ✔️
result_float ✔️ ✔️ ✔️ ✔️
totally-ordered ✔️ ✔️ ✔️ ✔️
unsigned-f64 ✔️ ✔️ ✔️

(N.B. "Production ready" is a subjective measure)

¹: Can be manually checked

Full documentation

Is on docs.rs.


~23K SLoC