1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
//! Making floating-point behave: ordering, equivalence, hashing, and
//! constraints for floating-point types.
//!
//! Decorum provides traits that describe types using floating-point
//! representations and provides proxy types that wrap primitive floating-point
//! types. Proxy types implement a total ordering and constraints on the classes
//! of values that they may represent.
//!
//! # Floating-Point Classes
//!
//! Traits, proxy types, and constraints are based on three classes or subsets
//! of floating-point values:
//!
//! | Class | Trait |
//! |--------------|------------|
//! | real number | `Real` |
//! | infinity | `Infinite` |
//! | not-a-number | `Nan` |
//!
//! Primitive floating-point values directly expose IEEE-754 and therefore the
//! complete set of values (and traits). Proxy types implement traits that are
//! compatible with their constraints, so types that disallow `NaN`s do not
//! implement the `Nan` trait, for example.
//!
//! # Proxy Types
//!
//! Proxy types wrap primitive floating-point types and constrain the classes of
//! values that they can represent:
//!
//! | Type | Aliases | Trait Implementations | Disallowed Values |
//! |----------|--------------|--------------------------------------------|-----------------------|
//! | `Total` | | `Encoding + Real + Infinite + Nan + Float` | |
//! | `NotNan` | `N32`, `N64` | `Encoding + Real + Infinite` | `NaN` |
//! | `Finite` | `R32`, `R64` | `Encoding + Real` | `NaN`, `-INF`, `+INF` |
//!
//! The `NotNan` and `Finite` types disallow values that represent `NaN`,
//! $\infin$, and $-\infin$. **Operations that emit values that violate these
//! constraints will panic**. The `Total` type applies no constraints and
//! exposes all classes of floating-point values.
//!
//! # Total Ordering
//!
//! The following total ordering is implemented by all proxy types and is
//! provided by traits in the `cmp` module:
//!
//! $$-\infin<\cdots<0<\cdots<\infin<\text{NaN}$$
//!
//! Note that all zero and `NaN` representations are considered equivalent. See
//! the `cmp` module documentation for more details.
//!
//! # Equivalence
//!
//! Floating-point `NaN`s have numerous representations and are incomparable.
//! Decorum considers all `NaN` representations equal to all other `NaN`
//! representations and any and all `NaN` representations are unequal to
//! non-`NaN` values.
//!
//! See the `cmp` module documentation for more details.
#![doc(
html_favicon_url = "https://raw.githubusercontent.com/olson-sean-k/decorum/master/doc/decorum-favicon.ico"
)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/olson-sean-k/decorum/master/doc/decorum.svg?sanitize=true"
)]
#![no_std]
#[cfg(feature = "std")]
extern crate std;
use core::num::FpCategory;
use core::ops::Neg;
#[allow(unused_imports)]
use num_traits::{Num, NumCast, Signed};
#[cfg(not(feature = "std"))]
pub(in crate) use num_traits::float::FloatCore as ForeignFloat;
#[cfg(feature = "std")]
pub(in crate) use num_traits::real::Real as ForeignReal;
#[cfg(feature = "std")]
pub(in crate) use num_traits::Float as ForeignFloat;
mod canonical;
pub mod cmp;
mod constraint;
pub mod hash;
mod primitive;
mod proxy;
use crate::cmp::IntrinsicOrd;
use crate::constraint::{FiniteConstraint, NotNanConstraint, UnitConstraint};
pub use crate::canonical::ToCanonicalBits;
pub use crate::primitive::Primitive;
pub use crate::proxy::ConstrainedFloat;
/// Floating-point representation with total ordering.
pub type Total<T> = ConstrainedFloat<T, UnitConstraint<T>>;
/// Floating-point representation that cannot be `NaN`.
///
/// If an operation emits `NaN`, then a panic will occur. Like `Total`, this
/// type implements a total ordering.
pub type NotNan<T> = ConstrainedFloat<T, NotNanConstraint<T>>;
/// 32-bit floating-point representation that cannot be `NaN`.
pub type N32 = NotNan<f32>;
/// 64-bit floating-point representation that cannot be `NaN`.
pub type N64 = NotNan<f64>;
/// Floating-point representation that must be a real number.
///
/// If an operation emits `NaN` or infinities, then a panic will occur. Like
/// `Total`, this type implements a total ordering.
pub type Finite<T> = ConstrainedFloat<T, FiniteConstraint<T>>;
/// 32-bit floating-point representation that must be a real number.
///
/// The prefix "R" for _real_ is used instead of "F" for _finite_, because if
/// "F" were used, then this name would be very similar to `f32`.
pub type R32 = Finite<f32>;
/// 64-bit floating-point representation that must be a real number.
///
/// The prefix "R" for _real_ is used instead of "F" for _finite_, because if
/// "F" were used, then this name would be very similar to `f64`.
pub type R64 = Finite<f64>;
/// Floating-point representations that expose infinities.
pub trait Infinite: Encoding {
const INFINITY: Self;
const NEG_INFINITY: Self;
fn is_infinite(self) -> bool;
fn is_finite(self) -> bool;
}
/// Floating-point representations that expose `NaN`s.
pub trait Nan: Encoding {
/// A representation of `NaN`.
///
/// For primitive floating-point types, `NaN` is incomparable. Therefore,
/// prefer the `is_nan` predicate over direct comparisons with `NaN`.
const NAN: Self;
fn is_nan(self) -> bool;
}
/// Floating-point encoding.
///
/// Provides values and operations that describe the encoding of an IEEE-754
/// floating-point value. Infinities and `NaN`s are described by the `Infinite`
/// and `NaN` sub-traits.
pub trait Encoding: Copy {
const MAX: Self;
const MIN: Self;
const MIN_POSITIVE: Self;
const EPSILON: Self;
fn classify(self) -> FpCategory;
fn is_normal(self) -> bool;
fn is_sign_positive(self) -> bool;
fn is_sign_negative(self) -> bool;
fn integer_decode(self) -> (u64, i16, i8);
}
/// Types that can represent real numbers.
///
/// Provides values and operations that generally apply to real numbers. As
/// such, this trait is implemented by types using floating-point
/// representations, but this trait is a general numeric trait and can be
/// implemented by other numeric types as well.
///
/// Some members of this trait depend on the standard library and the `std`
/// feature.
pub trait Real: Copy + Neg<Output = Self> + Num + PartialOrd + Signed {
const E: Self;
const PI: Self;
const FRAC_1_PI: Self;
const FRAC_2_PI: Self;
const FRAC_2_SQRT_PI: Self;
const FRAC_PI_2: Self;
const FRAC_PI_3: Self;
const FRAC_PI_4: Self;
const FRAC_PI_6: Self;
const FRAC_PI_8: Self;
const SQRT_2: Self;
const FRAC_1_SQRT_2: Self;
const LN_2: Self;
const LN_10: Self;
const LOG2_E: Self;
const LOG10_E: Self;
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn round(self) -> Self;
fn trunc(self) -> Self;
fn fract(self) -> Self;
fn recip(self) -> Self;
#[cfg(feature = "std")]
fn mul_add(self, a: Self, b: Self) -> Self;
#[cfg(feature = "std")]
fn powi(self, n: i32) -> Self;
#[cfg(feature = "std")]
fn powf(self, n: Self) -> Self;
#[cfg(feature = "std")]
fn sqrt(self) -> Self;
#[cfg(feature = "std")]
fn cbrt(self) -> Self;
#[cfg(feature = "std")]
fn exp(self) -> Self;
#[cfg(feature = "std")]
fn exp2(self) -> Self;
#[cfg(feature = "std")]
fn exp_m1(self) -> Self;
#[cfg(feature = "std")]
fn log(self, base: Self) -> Self;
#[cfg(feature = "std")]
fn ln(self) -> Self;
#[cfg(feature = "std")]
fn log2(self) -> Self;
#[cfg(feature = "std")]
fn log10(self) -> Self;
#[cfg(feature = "std")]
fn ln_1p(self) -> Self;
#[cfg(feature = "std")]
fn hypot(self, other: Self) -> Self;
#[cfg(feature = "std")]
fn sin(self) -> Self;
#[cfg(feature = "std")]
fn cos(self) -> Self;
#[cfg(feature = "std")]
fn tan(self) -> Self;
#[cfg(feature = "std")]
fn asin(self) -> Self;
#[cfg(feature = "std")]
fn acos(self) -> Self;
#[cfg(feature = "std")]
fn atan(self) -> Self;
#[cfg(feature = "std")]
fn atan2(self, other: Self) -> Self;
#[cfg(feature = "std")]
fn sin_cos(self) -> (Self, Self);
#[cfg(feature = "std")]
fn sinh(self) -> Self;
#[cfg(feature = "std")]
fn cosh(self) -> Self;
#[cfg(feature = "std")]
fn tanh(self) -> Self;
#[cfg(feature = "std")]
fn asinh(self) -> Self;
#[cfg(feature = "std")]
fn acosh(self) -> Self;
#[cfg(feature = "std")]
fn atanh(self) -> Self;
}
/// Floating-point representations.
///
/// Types that implement this trait are represented using IEEE-754 encoding and
/// expose the details of that encoding, including infinities, `NaN`, and
/// operations on real numbers. This trait is implemented by primitive
/// floating-point types and the `Total` proxy type.
pub trait Float: Encoding + Infinite + IntrinsicOrd + Nan + Real {}
impl<T> Float for T where T: Encoding + Infinite + IntrinsicOrd + Nan + Real {}