1//! Support for rounding directions and status flags as specified by IEEE 754.
2//!
3//! Rust does not support the floating point environment so rounding mode is passed as an argument
4//! and status flags are returned as part of the result. There is currently not much support for
5//! this; most existing ports from musl use a form of `force_eval!` to raise exceptions, but this
6//! has no side effects in Rust. Further, correct behavior relies on elementary operations making
7//! use of the correct rounding and raising relevant exceptions, which is not the case for Rust.
8//!
9//! This module exists so no functionality is lost when porting algorithms that respect floating
10//! point environment, and so that some functionality may be tested (that which does not rely on
11//! side effects from elementary operations). Full support would require wrappers around basic
12//! operations, but there is no plan to add this at the current time.
1314/// A value combined with a floating point status.
15pub struct FpResult<T> {
16pub val: T,
17#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))]
18pub status: Status,
19}
2021impl<T> FpResult<T> {
22pub fn new(val: T, status: Status) -> Self {
23Self { val, status }
24 }
2526/// Return `val` with `Status::OK`.
27pub fn ok(val: T) -> Self {
28Self {
29val,
30 status: Status::OK,
31 }
32 }
33}
3435/// IEEE 754 rounding mode, excluding the optional `roundTiesToAway` version of nearest.
36///
37/// Integer representation comes from what CORE-MATH uses for indexing.
38#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))]
39#[derive(#[automatically_derived]
#[allow(dead_code)]
impl ::core::clone::Clone for Round {
#[inline]
fn clone(&self) -> Round { *self }
}Clone, #[automatically_derived]
#[allow(dead_code)]
impl ::core::marker::Copy for Round { }Copy, #[automatically_derived]
#[allow(dead_code)]
impl ::core::fmt::Debug for Round {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
Round::Nearest => "Nearest",
Round::Negative => "Negative",
Round::Positive => "Positive",
Round::Zero => "Zero",
})
}
}Debug, #[automatically_derived]
#[allow(dead_code)]
impl ::core::cmp::PartialEq for Round {
#[inline]
fn eq(&self, other: &Round) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}PartialEq)]
40pub enum Round {
41/// IEEE 754 nearest, `roundTiesToEven`.
42Nearest = 0,
43/// IEEE 754 `roundTowardNegative`.
44Negative = 1,
45/// IEEE 754 `roundTowardPositive`.
46Positive = 2,
47/// IEEE 754 `roundTowardZero`.
48Zero = 3,
49}
5051/// IEEE 754 exception status flags.
52#[derive(#[automatically_derived]
impl ::core::clone::Clone for Status {
#[inline]
fn clone(&self) -> Status {
let _: ::core::clone::AssertParamIsClone<u8>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Status { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for Status {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Status",
&&self.0)
}
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for Status {
#[inline]
fn eq(&self, other: &Status) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Status {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<u8>;
}
}Eq)]
53pub struct Status(u8);
5455impl Status {
56/// Default status indicating no errors.
57pub const OK: Self = Self(0);
5859/// No definable result.
60 ///
61 /// Includes:
62 /// - Any ops on sNaN, with a few exceptions.
63 /// - `0 * inf`, `inf * 0`.
64 /// - `fma(0, inf, c)` or `fma(inf, 0, c)`, possibly excluding `c = qNaN`.
65 /// - `+inf + -inf` and similar (includes subtraction and fma).
66 /// - `0.0 / 0.0`, `inf / inf`
67 /// - `remainder(x, y)` if `y == 0.0` or `x == inf`, and neither is NaN.
68 /// - `sqrt(x)` with `x < 0.0`.
69pub const INVALID: Self = Self(1);
7071/// Division by zero.
72 ///
73 /// The default result for division is +/-inf based on operand sign. For `logB`, the default
74 /// result is -inf.
75 /// `x / y` when `x != 0.0` and `y == 0.0`,
76#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))]
77pub const DIVIDE_BY_ZERO: Self = Self(1 << 2);
7879/// The result exceeds the maximum finite value.
80 ///
81 /// The default result depends on rounding mode. `Nearest*` rounds to +/- infinity, sign based
82 /// on the intermediate result. `Zero` rounds to the signed maximum finite. `Positive` and
83 /// `Negative` round to signed maximum finite in one direction, signed infinity in the other.
84#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))]
85pub const OVERFLOW: Self = Self(1 << 3);
8687/// The result is subnormal and lost precision.
88pub const UNDERFLOW: Self = Self(1 << 4);
8990/// The finite-precision result does not match that of infinite precision, and the reason
91 /// is not represented by one of the other flags.
92pub const INEXACT: Self = Self(1 << 5);
9394/// True if `UNDERFLOW` is set.
95#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))]
96pub const fn underflow(self) -> bool {
97self.0 & Self::UNDERFLOW.0 != 0
98}
99100/// True if `OVERFLOW` is set.
101#[cfg_attr(not(feature = "unstable-public-internals"), allow(dead_code))]
102pub const fn overflow(self) -> bool {
103self.0 & Self::OVERFLOW.0 != 0
104}
105106pub fn set_underflow(&mut self, val: bool) {
107self.set_flag(val, Self::UNDERFLOW);
108 }
109110/// True if `INEXACT` is set.
111pub const fn inexact(self) -> bool {
112self.0 & Self::INEXACT.0 != 0
113}
114115pub fn set_inexact(&mut self, val: bool) {
116self.set_flag(val, Self::INEXACT);
117 }
118119fn set_flag(&mut self, val: bool, mask: Self) {
120if val {
121self.0 |= mask.0;
122 } else {
123self.0 &= !mask.0;
124 }
125 }
126127pub(crate) const fn with(self, rhs: Self) -> Self {
128Self(self.0 | rhs.0)
129 }
130}