| Crates.io | typed_floats |
| lib.rs | typed_floats |
| version | 1.0.7 |
| created_at | 2023-06-18 20:44:37.658878+00 |
| updated_at | 2025-09-22 18:33:18.111631+00 |
| description | Types for handling floats with type checking at compile time. |
| homepage | |
| repository | https://github.com/tdelmas/typed_floats |
| max_upload_size | |
| id | 893633 |
| size | 322,525 |
This crate helps you to ensure the kind of floats you are using, without panic! (except if the unsafe function new_unchecked is used in an unsound way).
zero overhead: everything is checked at compile time.
(only new and try_from adds a little overhead at runtime)
NaN is rejected by all types.
This crate is for you if:
If you want to know at compile time if a float can be negative, positive, zero, finite and ensure it is not NaN, without panic!.
If you need core::cmp::Ord, core::cmp::Eq or core::hash::Hash on (non-NaN) floats.
And their positive and negative counterparts:
Positive,PositiveFinite, StrictlyPositive, StrictlyPositiveFiniteNegative,NegativeFinite, StrictlyNegative, StrictlyNegativeFinite| 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.
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.
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;
It ensures:
x is neither NaN nor Infinity, and is strictly positiveNaN and is strictly positive but may be InfinityIn that example:
NaN, Infinity, or <= 0 for the parameter xInfinity 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 typed float 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.
core::convert::From / core::convert::TryFromf32 or f64)f32 and f64u128 and i128)NonZero* (core::num::NonZeroU8, core::num::NonZeroU16, core::num::NonZeroU32, core::num::NonZeroU64, core::num::NonZeroI8, core::num::NonZeroI16, core::num::NonZeroI32, core::num::NonZeroI64)(The traits From and TryFrom are implemented depending on the situation)
core::cmp::PartialOrd and core::cmp::PartialEq| 🗘 | f32/f64 |
NonNaN |
NonNaNFinite |
NonZeroNonNaN |
NonZeroNonNaNFinite |
Positive |
PositiveFinite |
StrictlyPositive |
StrictlyPositiveFinite |
Negative |
NegativeFinite |
StrictlyNegative |
StrictlyNegativeFinite |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
f32/f64 |
N/A | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
NonNaN |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
NonNaNFinite |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
NonZeroNonNaN |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
NonZeroNonNaNFinite |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
Positive |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
PositiveFinite |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
StrictlyPositive |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
StrictlyPositiveFinite |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
Negative |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
NegativeFinite |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
StrictlyNegative |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
StrictlyNegativeFinite |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Trait | NonNaN |
NonNaNFinite |
NonZeroNonNaN |
NonZeroNonNaNFinite |
Positive |
PositiveFinite |
StrictlyPositive |
StrictlyPositiveFinite |
Negative |
NegativeFinite |
StrictlyNegative |
StrictlyNegativeFinite |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
core::cmp::Eq |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
core::cmp::Ord |
✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
core::hash::Hash |
✔️¹ | ✔️¹ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
core::default::Default |
0.0 |
0.0 |
❌ | ❌ | 0.0 |
0.0 |
❌ | ❌ | -0.0 |
-0.0 |
❌ | ❌ |
¹: there is a (small) overhead because they accept 0.0 and -0.0 (which are equal) so they must core::hash::Hash to the same value.
All 12 types implement the methods available on f32 and f64 except:
total_cmp(&self, other: &f64) -> Orderingsin_cos(self) -> (f64, f64)mul_add(self, a: f64, b: f64) -> f64clamp(self, min: f64, max: f64) -> f64LowerExpUpperExpProductSumto_int_uncheckedto*_bitsfrom*_bitsThe 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.
This crate is designed to have a minimal overhead at runtime, in terms of memory, speed and binary size.
It can even be faster than using primitives f32 and f64 directly, as it may avoids some checks by using compiler hints and can use some faster implementations in some cases.
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.
The compiler hints are enabled by default to enable compiler optimization when possible.
Also, some methods are faster than the default implementation. For example:
Eq is implemented by comparing the bits of the two floats instead of the slower default implementation, that had special cases for NaN (to handle NaN != NaN) and -0.0 (to handle -0.0 == 0.0). (8% faster)Ord is implemented by directly comparing the bits of the two floats instead of the slower default implementation for negatives and positives types. (4% faster)signum doesn't needs to check for NaN. (35% faster)NonNaN and NonNaNFinite use a faster implementation of Eq, opening the door to Jump Threading optimisations.std: enabled by default, gives all f32 and f64 methods.
serde: implements Serialize and Deserialize for all 12 types.
libm: use the Float trait from num-traits and libm to implement the missing methods when the std feature is disabled. When both std and libm features are enabled, the std implementation is used.
compiler_hints: enabled by default, will add core::hint::unreachable_unchecked after all debug_assert.
ensure_no_undefined_behavior: Will panic! in release mode instead of risking undefined behavior. This will override the compiler_hints feature, and adds a little overhead to new_unchecked. This feature can be enabled by any parent crate to ensure no undefined behavior.
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.
0.0 == -0.0sqrt(-0.0) returning -0.0 instead of NaNmin(-0.0, 0.0) possibly returning 0.0 instead of -0.0 (same for max)frac(-0.0) returning 0.0 instead of -0.0Because that would introduce a runtime overhead and may introduce some incompatibilities with existing code.
This crate is tested when a new version is release with:
Also, tests on nightly, beta and stable are run monthly on GitHub actions.
The minimum supported Rust version (MSRV) is 1.70.0 because of the use of dep: in Cargo.toml.
A change in the MSRV will be treated as a breaking change.
Tests are run on different architectures on GitHub actions and CircleCI.
core::cmp::Eq, core::cmp::Ord and core::hash::Hash implementations for various num types (u32, f64, num_bigint::BigInt, etc.)min and max functions that work with PartialOrd.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
Is on docs.rs.