#![doc = include_str!("../README.truncated.md")]
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(all(test, not(feature = "std")))]
#[macro_use]
extern crate alloc;
mod macros;
mod traits;
mod types;
#[cfg(feature = "serde")]
mod serde;
pub use traits::*;
pub use types::*;
typed_floats_macros::generate_docs!(
pub mod conversions_rules {}
);
pub mod tf64 {
use const_fn::const_fn;
pub type NonNaN = crate::NonNaN<f64>;
pub type NonNaNFinite = crate::NonNaNFinite<f64>;
pub type NonZeroNonNaN = crate::NonZeroNonNaN<f64>;
pub type NonZeroNonNaNFinite = crate::NonZeroNonNaNFinite<f64>;
pub type StrictlyPositive = crate::StrictlyPositive<f64>;
pub type StrictlyNegative = crate::StrictlyNegative<f64>;
pub type Positive = crate::Positive<f64>;
pub type Negative = crate::Negative<f64>;
pub type StrictlyPositiveFinite = crate::StrictlyPositiveFinite<f64>;
pub type StrictlyNegativeFinite = crate::StrictlyNegativeFinite<f64>;
pub type PositiveFinite = crate::PositiveFinite<f64>;
pub type NegativeFinite = crate::NegativeFinite<f64>;
#[inline]
#[must_use]
#[const_fn("1.83")]
pub const fn is_positive_zero(x: f64) -> bool {
x == 0.0 && x.is_sign_positive()
}
#[inline]
#[must_use]
#[const_fn("1.83")]
pub const fn is_negative_zero(x: f64) -> bool {
x == 0.0 && x.is_sign_negative()
}
const fn from_bits(bits: u64) -> f64 {
unsafe {
#[allow(unnecessary_transmutes)]
core::mem::transmute::<u64, f64>(bits)
}
}
crate::generate_const!(
INFINITY,
StrictlyPositive,
f64,
f64::INFINITY,
"Infinity (∞)."
);
crate::generate_const!(
NEG_INFINITY,
StrictlyNegative,
f64,
f64::NEG_INFINITY,
"Negative infinity (−∞)."
);
crate::generate_const!(ZERO, PositiveFinite, f64, 0.0f64, "Positive zero (+0.0).");
crate::generate_const!(
NEG_ZERO,
NegativeFinite,
f64,
-0.0f64,
"Negative zero (-0.0)."
);
crate::generate_const!(
MAX,
StrictlyPositiveFinite,
f64,
f64::MAX,
"Largest finite `f64` value."
);
crate::generate_const!(
MIN,
StrictlyNegativeFinite,
f64,
f64::MIN,
"Smallest finite `f64` value."
);
crate::generate_const!(
MIN_POSITIVE,
StrictlyPositiveFinite,
f64,
f64::MIN_POSITIVE,
"Smallest positive normal `f64` value."
);
crate::generate_const!(
MIN_SUBNORMAL_POSITIVE,
StrictlyPositiveFinite,
f64,
from_bits(0x0000_0000_0000_0001),
"Smallest subnormal positive `f64` value."
);
crate::generate_const!(
MAX_SUBNORMAL_POSITIVE,
StrictlyPositiveFinite,
f64,
from_bits(0x000F_FFFF_FFFF_FFFF),
"Largest subnormal positive `f64` value."
);
crate::generate_const!(
MIN_SUBNORMAL_NEGATIVE,
StrictlyNegativeFinite,
f64,
from_bits(0x8000_0000_0000_0001),
"Smallest subnormal negative `f64` value."
);
crate::generate_const!(
MAX_SUBNORMAL_NEGATIVE,
StrictlyNegativeFinite,
f64,
from_bits(0x800F_FFFF_FFFF_FFFF),
"Largest subnormal negative `f64` value."
);
pub mod consts {
crate::generate_const!(
PI,
StrictlyPositiveFinite,
f64,
core::f64::consts::PI,
"Archimedes' constant (Ï€)"
);
crate::generate_const!(
TAU,
StrictlyPositiveFinite,
f64,
core::f64::consts::TAU,
"The full circle constant (Ï„). Equal to 2Ï€."
);
crate::generate_const!(
FRAC_PI_2,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_PI_2,
"Ï€/2"
);
crate::generate_const!(
FRAC_PI_3,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_PI_3,
"Ï€/3"
);
crate::generate_const!(
FRAC_PI_4,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_PI_4,
"Ï€/4"
);
crate::generate_const!(
FRAC_PI_6,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_PI_6,
"Ï€/6"
);
crate::generate_const!(
FRAC_PI_8,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_PI_8,
"Ï€/8"
);
crate::generate_const!(
FRAC_1_PI,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_1_PI,
"1/Ï€"
);
crate::generate_const!(
FRAC_2_PI,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_2_PI,
"2/Ï€"
);
crate::generate_const!(
FRAC_2_SQRT_PI,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_2_SQRT_PI,
"2/sqrt(Ï€)"
);
crate::generate_const!(
SQRT_2,
StrictlyPositiveFinite,
f64,
core::f64::consts::SQRT_2,
"sqrt(2)"
);
crate::generate_const!(
FRAC_1_SQRT_2,
StrictlyPositiveFinite,
f64,
core::f64::consts::FRAC_1_SQRT_2,
"1/sqrt(2)"
);
crate::generate_const!(
E,
StrictlyPositiveFinite,
f64,
core::f64::consts::E,
"Euler's number (e)"
);
crate::generate_const!(
LOG2_10,
StrictlyPositiveFinite,
f64,
core::f64::consts::LOG2_10,
"log<sub>2</sub>(10)"
);
crate::generate_const!(
LOG2_E,
StrictlyPositiveFinite,
f64,
core::f64::consts::LOG2_E,
"log<sub>2</sub>(e)"
);
crate::generate_const!(
LOG10_2,
StrictlyPositiveFinite,
f64,
core::f64::consts::LOG10_2,
"log<sub>10</sub>(2)"
);
crate::generate_const!(
LOG10_E,
StrictlyPositiveFinite,
f64,
core::f64::consts::LOG10_E,
"log<sub>10</sub>(e)"
);
crate::generate_const!(
LN_2,
StrictlyPositiveFinite,
f64,
core::f64::consts::LN_2,
"ln(2)"
);
crate::generate_const!(
LN_10,
StrictlyPositiveFinite,
f64,
core::f64::consts::LN_10,
"ln(10)"
);
}
#[doc(hidden)]
#[must_use]
pub fn get_test_values() -> [f64; 25] {
[
f64::NAN,
f64::NEG_INFINITY,
f64::MIN,
-core::f64::consts::PI,
-core::f64::consts::E,
-2.0,
-core::f64::consts::FRAC_PI_2,
-1.0,
-f64::MIN_POSITIVE,
crate::tf64::MAX_SUBNORMAL_NEGATIVE.get(),
-1.0e-308,
crate::tf64::MIN_SUBNORMAL_NEGATIVE.get(),
-0.0,
0.0,
crate::tf64::MIN_SUBNORMAL_POSITIVE.get(),
1.0e-308,
crate::tf64::MAX_SUBNORMAL_POSITIVE.get(),
f64::MIN_POSITIVE,
1.0,
core::f64::consts::FRAC_PI_2,
2.0,
core::f64::consts::E,
core::f64::consts::PI,
f64::MAX,
f64::INFINITY,
]
}
}
pub mod tf32 {
use const_fn::const_fn;
pub type NonNaN = crate::NonNaN<f32>;
pub type NonNaNFinite = crate::NonNaNFinite<f32>;
pub type NonZeroNonNaN = crate::NonZeroNonNaN<f32>;
pub type NonZeroNonNaNFinite = crate::NonZeroNonNaNFinite<f32>;
pub type StrictlyPositive = crate::StrictlyPositive<f32>;
pub type StrictlyNegative = crate::StrictlyNegative<f32>;
pub type Positive = crate::Positive<f32>;
pub type Negative = crate::Negative<f32>;
pub type StrictlyPositiveFinite = crate::StrictlyPositiveFinite<f32>;
pub type StrictlyNegativeFinite = crate::StrictlyNegativeFinite<f32>;
pub type PositiveFinite = crate::PositiveFinite<f32>;
pub type NegativeFinite = crate::NegativeFinite<f32>;
#[inline]
#[must_use]
#[const_fn("1.83")]
pub const fn is_positive_zero(x: f32) -> bool {
x == 0.0 && x.is_sign_positive()
}
const fn from_bits(bits: u32) -> f32 {
unsafe {
#[allow(unnecessary_transmutes)]
core::mem::transmute::<u32, f32>(bits)
}
}
#[inline]
#[must_use]
#[const_fn("1.83")]
pub const fn is_negative_zero(x: f32) -> bool {
x == 0.0 && x.is_sign_negative()
}
crate::generate_const!(
INFINITY,
StrictlyPositive,
f32,
f32::INFINITY,
"Infinity (∞)."
);
crate::generate_const!(
NEG_INFINITY,
StrictlyNegative,
f32,
f32::NEG_INFINITY,
"Negative infinity (−∞)."
);
crate::generate_const!(ZERO, PositiveFinite, f32, 0.0f32, "Positive zero (+0.0).");
crate::generate_const!(
NEG_ZERO,
NegativeFinite,
f32,
-0.0f32,
"Negative zero (-0.0)."
);
crate::generate_const!(
MAX,
StrictlyPositiveFinite,
f32,
f32::MAX,
"Largest finite `f32` value."
);
crate::generate_const!(
MIN,
StrictlyNegativeFinite,
f32,
f32::MIN,
"Smallest finite `f32` value."
);
crate::generate_const!(
MIN_POSITIVE,
StrictlyPositiveFinite,
f32,
f32::MIN_POSITIVE,
"Smallest positive normal `f32` value."
);
crate::generate_const!(
MIN_SUBNORMAL_POSITIVE,
StrictlyPositiveFinite,
f32,
from_bits(0b0_00000000_00000000000000000000001),
"Smallest subnormal positive `f32` value."
);
crate::generate_const!(
MAX_SUBNORMAL_POSITIVE,
StrictlyPositiveFinite,
f32,
from_bits(0b0_00000000_11111111111111111111111),
"Largest subnormal positive `f32` value."
);
crate::generate_const!(
MIN_SUBNORMAL_NEGATIVE,
StrictlyNegativeFinite,
f32,
from_bits(0b1_00000000_00000000000000000000001),
"Smallest subnormal negative `f32` value."
);
crate::generate_const!(
MAX_SUBNORMAL_NEGATIVE,
StrictlyNegativeFinite,
f32,
from_bits(0b1_00000000_11111111111111111111111),
"Largest subnormal negative `f32` value."
);
pub mod consts {
crate::generate_const!(
PI,
StrictlyPositiveFinite,
f32,
core::f32::consts::PI,
"Archimedes' constant (Ï€)"
);
crate::generate_const!(
TAU,
StrictlyPositiveFinite,
f32,
core::f32::consts::TAU,
"The full circle constant (Ï„). Equal to 2Ï€."
);
crate::generate_const!(
FRAC_PI_2,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_PI_2,
"Ï€/2"
);
crate::generate_const!(
FRAC_PI_3,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_PI_3,
"Ï€/3"
);
crate::generate_const!(
FRAC_PI_4,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_PI_4,
"Ï€/4"
);
crate::generate_const!(
FRAC_PI_6,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_PI_6,
"Ï€/6"
);
crate::generate_const!(
FRAC_PI_8,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_PI_8,
"Ï€/8"
);
crate::generate_const!(
FRAC_1_PI,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_1_PI,
"1/Ï€"
);
crate::generate_const!(
FRAC_2_PI,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_2_PI,
"2/Ï€"
);
crate::generate_const!(
FRAC_2_SQRT_PI,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_2_SQRT_PI,
"2/sqrt(Ï€)"
);
crate::generate_const!(
SQRT_2,
StrictlyPositiveFinite,
f32,
core::f32::consts::SQRT_2,
"sqrt(2)"
);
crate::generate_const!(
FRAC_1_SQRT_2,
StrictlyPositiveFinite,
f32,
core::f32::consts::FRAC_1_SQRT_2,
"1/sqrt(2)"
);
crate::generate_const!(
E,
StrictlyPositiveFinite,
f32,
core::f32::consts::E,
"Euler's number (e)"
);
crate::generate_const!(
LOG2_10,
StrictlyPositiveFinite,
f32,
core::f32::consts::LOG2_10,
"log<sub>2</sub>(10)"
);
crate::generate_const!(
LOG2_E,
StrictlyPositiveFinite,
f32,
core::f32::consts::LOG2_E,
"log<sub>2</sub>(e)"
);
crate::generate_const!(
LOG10_2,
StrictlyPositiveFinite,
f32,
core::f32::consts::LOG10_2,
"log<sub>10</sub>(2)"
);
crate::generate_const!(
LOG10_E,
StrictlyPositiveFinite,
f32,
core::f32::consts::LOG10_E,
"log<sub>10</sub>(e)"
);
crate::generate_const!(
LN_2,
StrictlyPositiveFinite,
f32,
core::f32::consts::LN_2,
"ln(2)"
);
crate::generate_const!(
LN_10,
StrictlyPositiveFinite,
f32,
core::f32::consts::LN_10,
"ln(10)"
);
}
#[doc(hidden)]
#[must_use]
pub fn get_test_values() -> [f32; 25] {
[
f32::NAN,
f32::NEG_INFINITY,
f32::MIN,
-core::f32::consts::PI,
-core::f32::consts::E,
-2.0,
-core::f32::consts::FRAC_PI_2,
-1.0,
-f32::MIN_POSITIVE,
crate::tf32::MAX_SUBNORMAL_NEGATIVE.get(),
-1.0e-40,
crate::tf32::MIN_SUBNORMAL_NEGATIVE.get(),
-0.0,
0.0,
crate::tf32::MIN_SUBNORMAL_POSITIVE.get(),
1.0e-40,
crate::tf32::MAX_SUBNORMAL_POSITIVE.get(),
f32::MIN_POSITIVE,
1.0,
core::f32::consts::FRAC_PI_2,
2.0,
core::f32::consts::E,
core::f32::consts::PI,
f32::MAX,
f32::INFINITY,
]
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_sorted<T: PartialEq + PartialOrd + core::fmt::Debug>(values: &[T], zero: T) {
assert!(values.len() >= 2);
for i in 1..values.len() {
let a = &values[i - 1];
let b = &values[i];
if a != &zero || b != &zero {
assert!(a < b, "{a:?} < {b:?} should be true");
}
}
}
#[test]
fn test_f32() {
let mut values = tf32::get_test_values().to_vec();
let first = values.remove(0);
assert!(first.is_nan());
let others = values.as_slice();
assert_sorted(others, 0.0);
let mut count_inf = 0;
let mut count_zero = 0;
let mut count_subnormal = 0;
for value in others {
if value.is_infinite() {
count_inf += 1;
}
if value == &0.0 {
count_zero += 1;
}
if value.is_subnormal() {
count_subnormal += 1;
}
}
assert_eq!(count_inf, 2);
assert_eq!(count_zero, 2);
assert!(count_subnormal >= 3);
}
#[test]
fn test_f64() {
let mut values = tf64::get_test_values().to_vec();
let first = values.remove(0);
assert!(first.is_nan());
let others = values.as_slice();
assert_sorted(others, 0.0);
let mut count_inf = 0;
let mut count_zero = 0;
let mut count_subnormal = 0;
for value in others {
if value.is_infinite() {
count_inf += 1;
}
if value == &0.0 {
count_zero += 1;
}
if value.is_subnormal() {
count_subnormal += 1;
}
}
assert_eq!(count_inf, 2);
assert_eq!(count_zero, 2);
assert!(count_subnormal >= 3);
}
#[test]
fn test_subnormals() {
const SUBNORMALS_F64: [f64; 4] = [
tf64::MAX_SUBNORMAL_NEGATIVE.get(),
tf64::MIN_SUBNORMAL_NEGATIVE.get(),
tf64::MIN_SUBNORMAL_POSITIVE.get(),
tf64::MAX_SUBNORMAL_POSITIVE.get(),
];
const SUBNORMALS_F32: [f32; 4] = [
tf32::MAX_SUBNORMAL_NEGATIVE.get(),
tf32::MIN_SUBNORMAL_NEGATIVE.get(),
tf32::MIN_SUBNORMAL_POSITIVE.get(),
tf32::MAX_SUBNORMAL_POSITIVE.get(),
];
assert_sorted(&SUBNORMALS_F64, 0.0);
assert_sorted(&SUBNORMALS_F32, 0.0);
for value in SUBNORMALS_F64 {
assert!(value.is_subnormal());
}
for value in SUBNORMALS_F32 {
assert!(value.is_subnormal());
}
}
}