//! Wrappers for total order on Floats. See the [`OrderedFloat`] and [`NotNan`] docs for details.
#[cfg(feature = "std")] externcrate std; #[cfg(feature = "std")] use std::error::Error;
use core::borrow::Borrow; use core::cmp::Ordering; use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::hint::unreachable_unchecked; use core::iter::{Product, Sum}; use core::num::FpCategory; use core::ops::{
Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub,
SubAssign,
}; use core::str::FromStr;
#[cfg(not(feature = "std"))] use num_traits::float::FloatCore as Float; #[cfg(feature = "std")] pubuse num_traits::Float; use num_traits::{
AsPrimitive, Bounded, FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero,
};
// masks for the parts of the IEEE 754 float const SIGN_MASK: u64 = 0x8000000000000000u64; const EXP_MASK: u64 = 0x7ff0000000000000u64; const MAN_MASK: u64 = 0x000fffffffffffffu64;
// canonical raw bit patterns (for hashing) const CANONICAL_NAN_BITS: u64 = 0x7ff8000000000000u64; const CANONICAL_ZERO_BITS: u64 = 0x0u64;
/// A wrapper around floats providing implementations of `Eq`, `Ord`, and `Hash`. /// /// NaN is sorted as *greater* than all other values and *equal* /// to itself, in contradiction with the IEEE standard. /// /// ``` /// use ordered_float::OrderedFloat; /// use std::f32::NAN; /// /// let mut v = [OrderedFloat(NAN), OrderedFloat(2.0), OrderedFloat(1.0)]; /// v.sort(); /// assert_eq!(v, [OrderedFloat(1.0), OrderedFloat(2.0), OrderedFloat(NAN)]); /// ``` /// /// Because `OrderedFloat` implements `Ord` and `Eq`, it can be used as a key in a `HashSet`, /// `HashMap`, `BTreeMap`, or `BTreeSet` (unlike the primitive `f32` or `f64` types): /// /// ``` /// # use ordered_float::OrderedFloat; /// # use std::collections::HashSet; /// # use std::f32::NAN; /// /// let mut s: HashSet<OrderedFloat<f32>> = HashSet::new(); /// s.insert(OrderedFloat(NAN)); /// assert!(s.contains(&OrderedFloat(NAN))); /// ``` #[derive(Debug, Default, Clone, Copy)] #[repr(transparent)] pubstruct OrderedFloat<T>(pub T);
impl<T: Float> OrderedFloat<T> { /// Get the value out. #[inline] pubfn into_inner(self) -> T { self.0
}
}
impl<T: Float> AsMut<T> for OrderedFloat<T> { #[inline] fn as_mut(&mutself) -> &mut T {
&mutself.0
}
}
impl<'a, T: Float> From<&'a T> for &'a OrderedFloat<T> { #[inline] fn from(t: &'a T) -> &'a OrderedFloat<T> { // Safety: OrderedFloat is #[repr(transparent)] and has no invalid values. unsafe { &*(t as *const T as *const OrderedFloat<T>) }
}
}
impl<'a, T: Float> From<&'a mut T> for &'a mut OrderedFloat<T> { #[inline] fn from(t: &'a mut T) -> &'a mut OrderedFloat<T> { // Safety: OrderedFloat is #[repr(transparent)] and has no invalid values. unsafe { &mut *(t as *mut T as *mut OrderedFloat<T>) }
}
}
impl<T: Float + Num> Num for OrderedFloat<T> { type FromStrRadixErr = T::FromStrRadixErr; fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
T::from_str_radix(str, radix).map(OrderedFloat)
}
}
/// A wrapper around floats providing an implementation of `Eq`, `Ord` and `Hash`. /// /// A NaN value cannot be stored in this type. /// /// ``` /// use ordered_float::NotNan; /// /// let mut v = [ /// NotNan::new(2.0).unwrap(), /// NotNan::new(1.0).unwrap(), /// ]; /// v.sort(); /// assert_eq!(v, [1.0, 2.0]); /// ``` /// /// Because `NotNan` implements `Ord` and `Eq`, it can be used as a key in a `HashSet`, /// `HashMap`, `BTreeMap`, or `BTreeSet` (unlike the primitive `f32` or `f64` types): /// /// ``` /// # use ordered_float::NotNan; /// # use std::collections::HashSet; /// /// let mut s: HashSet<NotNan<f32>> = HashSet::new(); /// let key = NotNan::new(1.0).unwrap(); /// s.insert(key); /// assert!(s.contains(&key)); /// ``` /// /// Arithmetic on NotNan values will panic if it produces a NaN value: /// /// ```should_panic /// # use ordered_float::NotNan; /// let a = NotNan::new(std::f32::INFINITY).unwrap(); /// let b = NotNan::new(std::f32::NEG_INFINITY).unwrap(); /// /// // This will panic: /// let c = a + b; /// ``` #[derive(PartialOrd, PartialEq, Debug, Default, Clone, Copy)] #[repr(transparent)] pubstruct NotNan<T>(T);
impl<T: Float> NotNan<T> { /// Create a `NotNan` value. /// /// Returns `Err` if `val` is NaN pubfn new(val: T) -> Result<Self, FloatIsNan> { match val { ref val if val.is_nan() => Err(FloatIsNan),
val => Ok(NotNan(val)),
}
}
}
impl<T> NotNan<T> { /// Get the value out. #[inline] pubfn into_inner(self) -> T { self.0
}
/// Create a `NotNan` value from a value that is guaranteed to not be NaN /// /// # Safety /// /// Behaviour is undefined if `val` is NaN #[inline] pubconstunsafefn new_unchecked(val: T) -> Self {
NotNan(val)
}
/// Create a `NotNan` value from a value that is guaranteed to not be NaN /// /// # Safety /// /// Behaviour is undefined if `val` is NaN #[deprecated(
since = "2.5.0",
note = "Please use the new_unchecked function instead."
)] #[inline] pubconstunsafefn unchecked_new(val: T) -> Self { Self::new_unchecked(val)
}
}
impl NotNan<f64> { /// Converts this [`NotNan`]`<`[`f64`]`>` to a [`NotNan`]`<`[`f32`]`>` while giving up on /// precision, [using `roundTiesToEven` as rounding mode, yielding `Infinity` on /// overflow](https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics). pubfn as_f32(self) -> NotNan<f32> { // This is not destroying invariants, as it is a pure rounding operation. The only two special // cases are where f32 would be overflowing, then the operation yields Infinity, or where // the input is already NaN, in which case the invariant is already broken elsewhere.
NotNan(self.0as f32)
}
}
impl TryFrom<f32> for NotNan<f32> { type Error = FloatIsNan; #[inline] fn try_from(v: f32) -> Result<Self, Self::Error> {
NotNan::new(v)
}
}
impl TryFrom<f64> for NotNan<f64> { type Error = FloatIsNan; #[inline] fn try_from(v: f64) -> Result<Self, Self::Error> {
NotNan::new(v)
}
}
macro_rules! impl_from_int_primitive {
($primitive:ty, $inner:ty) => { impl From<$primitive> for NotNan<$inner> { fn from(source: $primitive) -> Self { // the primitives with which this macro will be called cannot hold a value that // f64::from would convert to NaN, so this does not hurt invariants
NotNan(<$inner as From<$primitive>>::from(source))
}
}
};
}
/// Adds a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN impl<T: Float> Add<T> for NotNan<T> { type Output = Self;
/// Adds a float directly. /// /// Panics if the provided value is NaN. impl<T: Float + Sum> Sum for NotNan<T> { fn sum<I: Iterator<Item = NotNan<T>>>(iter: I) -> Self {
NotNan::new(iter.map(|v| v.0).sum()).expect("Sum resulted in NaN")
}
}
/// Subtracts a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN impl<T: Float> Sub<T> for NotNan<T> { type Output = Self;
/// Multiplies a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN impl<T: Float> Mul<T> for NotNan<T> { type Output = Self;
/// Divides a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN impl<T: Float> Div<T> for NotNan<T> { type Output = Self;
/// Calculates `%` with a float directly. /// /// Panics if the provided value is NaN or the computation results in NaN impl<T: Float> Rem<T> for NotNan<T> { type Output = Self;
impl<T: Float + FromStr> FromStr for NotNan<T> { type Err = ParseNotNanError<T::Err>;
/// Convert a &str to `NotNan`. Returns an error if the string fails to parse, /// or if the resulting value is NaN /// /// ``` /// use ordered_float::NotNan; /// /// assert!("-10".parse::<NotNan<f32>>().is_ok()); /// assert!("abc".parse::<NotNan<f32>>().is_err()); /// assert!("NaN".parse::<NotNan<f32>>().is_err()); /// ``` fn from_str(src: &str) -> Result<Self, Self::Err> {
src.parse()
.map_err(ParseNotNanError::ParseFloatError)
.and_then(|f| NotNan::new(f).map_err(|_| ParseNotNanError::IsNaN))
}
}
/// An error indicating a parse error from a string for `NotNan`. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pubenum ParseNotNanError<E> { /// A plain parse error from the underlying float type.
ParseFloatError(E), /// The parsed float value resulted in a NaN.
IsNaN,
}
#[cfg(feature = "std")] impl<E: fmt::Debug + Error + 'static> Error for ParseNotNanError<E> { fn description(&self) -> &str { "Error parsing a not-NaN floating point value"
}
#[test] fn test_fail_on_nan() {
assert_de_tokens_error::<NotNan<f64>>(
&[Token::F64(f64::NAN)], "invalid value: floating point `NaN`, expected float (but not NaN)",
);
}
}
#[cfg(feature = "rkyv")] mod impl_rkyv { usesuper::{NotNan, OrderedFloat}; #[cfg(not(feature = "std"))] use num_traits::float::FloatCore as Float; #[cfg(feature = "std")] use num_traits::Float; #[cfg(test)] use rkyv::{archived_root, ser::Serializer}; use rkyv::{from_archived, Archive, Deserialize, Fallible, Serialize};
#[cfg(test)] type DefaultSerializer = rkyv::ser::serializers::CoreSerializer<16, 16>; #[cfg(test)] type DefaultDeserializer = rkyv::Infallible;
impl<T: Float + Archive> Archive for OrderedFloat<T> { type Archived = OrderedFloat<T>;
#[cfg(feature = "rand")] mod impl_rand { usesuper::{NotNan, OrderedFloat}; use rand::distributions::uniform::*; use rand::distributions::{Distribution, Open01, OpenClosed01, Standard}; use rand::Rng;
macro_rules! impl_distribution {
($dist:ident, $($f:ty),+) => {
$( impl Distribution<NotNan<$f>> for $dist { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> NotNan<$f> { // 'rand' never generates NaN values in the Standard, Open01, or // OpenClosed01 distributions. Using 'new_unchecked' is therefore // safe. unsafe { NotNan::new_unchecked(self.sample(rng)) }
}
}
#[test] #[should_panic] fn uniform_sampling_panic_on_infinity_notnan() { let (low, high) = (
NotNan::new(0f64).unwrap(),
NotNan::new(core::f64::INFINITY).unwrap(),
); let uniform = Uniform::new(low, high); let _ = uniform.sample(&mut rand::thread_rng());
}
#[test] #[should_panic] fn uniform_sampling_panic_on_infinity_ordered() { let (low, high) = (OrderedFloat(0f64), OrderedFloat(core::f64::INFINITY)); let uniform = Uniform::new(low, high); let _ = uniform.sample(&mut rand::thread_rng());
}
#[test] #[should_panic] fn uniform_sampling_panic_on_nan_ordered() { let (low, high) = (OrderedFloat(0f64), OrderedFloat(core::f64::NAN)); let uniform = Uniform::new(low, high); let _ = uniform.sample(&mut rand::thread_rng());
}
}
}
#[cfg(feature = "proptest")] mod impl_proptest { usesuper::{NotNan, OrderedFloat}; use proptest::arbitrary::{Arbitrary, StrategyFor}; use proptest::num::{f32, f64}; use proptest::strategy::{FilterMap, Map, Strategy}; use std::convert::TryFrom;
macro_rules! impl_arbitrary {
($($f:ident),+) => {
$( impl Arbitrary for NotNan<$f> { type Strategy = FilterMap<StrategyFor<$f>, fn(_: $f) -> Option<NotNan<$f>>>; type Parameters = <$f as Arbitrary>::Parameters; fn arbitrary_with(params: Self::Parameters) -> Self::Strategy {
<$f>::arbitrary_with(params)
.prop_filter_map("filter nan values", |f| NotNan::try_from(f).ok())
}
}
impl Arbitrary for OrderedFloat<$f> { type Strategy = Map<StrategyFor<$f>, fn(_: $f) -> OrderedFloat<$f>>; type Parameters = <$f as Arbitrary>::Parameters; fn arbitrary_with(params: Self::Parameters) -> Self::Strategy {
<$f>::arbitrary_with(params).prop_map(|f| OrderedFloat::from(f))
}
}
)*
}
}
impl_arbitrary! { f32, f64 }
}
#[cfg(feature = "arbitrary")] mod impl_arbitrary { usesuper::{FloatIsNan, NotNan, OrderedFloat}; use arbitrary::{Arbitrary, Unstructured}; use num_traits::FromPrimitive;
macro_rules! impl_arbitrary {
($($f:ident),+) => {
$( impl<'a> Arbitrary<'a> for NotNan<$f> { fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { let float: $f = u.arbitrary()?; match NotNan::new(float) {
Ok(notnan_value) => Ok(notnan_value),
Err(FloatIsNan) => { // If our arbitrary float input was a NaN (encoded by exponent = max // value), then replace it with a finite float, reusing the mantissa // bits. // // This means the output is not uniformly distributed among all // possible float values, but Arbitrary makes no promise that that // is true. // // An alternative implementation would be to return an // `arbitrary::Error`, but that is not as useful since it forces the // caller to retry with new random/fuzzed data; and the precendent of // `arbitrary`'s built-in implementations is to prefer the approach of // mangling the input bits to fit.
let (mantissa, _exponent, sign) =
num_traits::Float::integer_decode(float); let revised_float = <$f>::from_i64(
i64::from(sign) * mantissa as i64
).unwrap();
// If this unwrap() fails, then there is a bug in the above code.
Ok(NotNan::new(revised_float).unwrap())
}
}
}
#[cfg(feature = "bytemuck")] mod impl_bytemuck { usesuper::{Float, NotNan, OrderedFloat}; use bytemuck::{AnyBitPattern, CheckedBitPattern, NoUninit, Pod, Zeroable};
unsafeimpl<T: Zeroable> Zeroable for OrderedFloat<T> {}
// The zero bit pattern is indeed not a NaN bit pattern. unsafeimpl<T: Zeroable> Zeroable for NotNan<T> {}
unsafeimpl<T: Pod> Pod for OrderedFloat<T> {}
// `NotNan<T>` can only implement `NoUninit` and not `Pod`, since not every bit pattern is // valid (NaN bit patterns are invalid). `NoUninit` guarantees that we can read any bit pattern // from the value, which is fine in this case. unsafeimpl<T: NoUninit> NoUninit for NotNan<T> {}
unsafeimpl<T: Float + AnyBitPattern> CheckedBitPattern for NotNan<T> { type Bits = T;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.