pub trait Ieee754:
Copy
+ PartialEq
+ PartialOrd {
type Bits: Bits;
type Exponent;
type RawExponent;
type Significand;
Show 16 methods
// Required methods
fn upto(self, lim: Self) -> Iter<Self> ⓘ;
fn next(self) -> Self;
fn prev(self) -> Self;
fn ulp(self) -> Option<Self>;
fn bits(self) -> Self::Bits;
fn from_bits(x: Self::Bits) -> Self;
fn exponent_bias() -> Self::Exponent;
fn decompose_raw(self) -> (bool, Self::RawExponent, Self::Significand);
fn recompose_raw(
sign: bool,
expn: Self::RawExponent,
signif: Self::Significand,
) -> Self;
fn decompose(self) -> (bool, Self::Exponent, Self::Significand);
fn recompose(
sign: bool,
expn: Self::Exponent,
signif: Self::Significand,
) -> Self;
fn total_cmp(&self, other: &Self) -> Ordering;
fn abs(self) -> Self;
fn copy_sign(self, sign: Self) -> Self;
fn sign(self) -> Self;
fn rel_error(self, exact: Self) -> Self;
}
Expand description
Types that are IEEE754 floating point numbers.
Required Associated Types§
Sourcetype RawExponent
type RawExponent
A type large enough to store the raw exponent (i.e. with the bias).
Sourcetype Significand
type Significand
A type large enough to store the significand of Self
.
Required Methods§
Sourcefn upto(self, lim: Self) -> Iter<Self> ⓘ
fn upto(self, lim: Self) -> Iter<Self> ⓘ
Iterate over each value of Self
in [self, lim]
.
The returned iterator will include subnormal numbers, and will
only include one of -0.0
and 0.0
.
§Panics
Panics if self > lim
, or if either are NaN.
§Examples
use ieee754::Ieee754;
// there are 840 single-precision floats in between 1.0 and 1.0001
// (inclusive).
assert_eq!(1_f32.upto(1.0001).count(), 840);
Sourcefn next(self) -> Self
fn next(self) -> Self
Return the next value after self
.
Calling this on NaN or positive infinity will yield nonsense.
§Examples
use ieee754::Ieee754;
let x: f32 = 1.0;
assert_eq!(x.next(), 1.000000119209);
Sourcefn prev(self) -> Self
fn prev(self) -> Self
Return the previous value before self
.
Calling this on NaN or negative infinity will yield nonsense.
§Examples
use ieee754::Ieee754;
let x: f32 = 1.0;
assert_eq!(x.prev(), 0.99999995);
Sourcefn ulp(self) -> Option<Self>
fn ulp(self) -> Option<Self>
Return the unit-in-the-last-place ulp of self
. That is,
x.abs().next() - x.abs()
, but handling overflow properly.
Returns None
if self
is not finite.
§Examples
Single precision:
use std::f32;
use ieee754::Ieee754;
assert_eq!(0_f32.ulp(), Some(1.4e-45));
assert_eq!(1_f32.ulp(), Some(1.1920928955078125e-07));
assert_eq!((-1_f32).ulp(), Some(1.1920928955078125e-07));
// 2^23
assert_eq!(8_388_608_f32.ulp(), Some(1.0));
// 2^24 - 1, the largest f32 with ULP 1
assert_eq!(16_777_215_f32.ulp(), Some(1.0));
// 2^24
assert_eq!(16_777_216_f32.ulp(), Some(2.0));
// non-finite
assert_eq!(f32::INFINITY.ulp(), None);
assert_eq!(f32::NAN.ulp(), None);
Double precision:
use std::f64;
use ieee754::Ieee754;
assert_eq!(0_f64.ulp(), Some(4.9e-324));
assert_eq!(1_f64.ulp(), Some(2.220446049250313e-16));
assert_eq!((-1_f64).ulp(), Some(2.220446049250313e-16));
// 2^52
assert_eq!(4_503_599_627_370_496_f64.ulp(), Some(1.0));
// 2^53 - 1, the largest f64 with ULP 1
assert_eq!(9_007_199_254_740_991_f64.ulp(), Some(1.0));
// 2^53
assert_eq!(9_007_199_254_740_992_f64.ulp(), Some(2.0));
// non-finite
assert_eq!(f64::INFINITY.ulp(), None);
assert_eq!(f64::NAN.ulp(), None);
Sourcefn bits(self) -> Self::Bits
fn bits(self) -> Self::Bits
View self
as a collection of bits.
§Examples
use ieee754::Ieee754;
let x: f32 = 1.0;
assert_eq!(x.bits(), 0x3f80_0000);
Sourcefn from_bits(x: Self::Bits) -> Self
fn from_bits(x: Self::Bits) -> Self
View a collections of bits as a floating point number.
§Examples
use ieee754::Ieee754;
let float: f32 = Ieee754::from_bits(0xbf80_0000);
assert_eq!(float, -1.0);
Sourcefn exponent_bias() -> Self::Exponent
fn exponent_bias() -> Self::Exponent
Get the bias of the stored exponent.
§Examples
use ieee754::Ieee754;
assert_eq!(f32::exponent_bias(), 127);
assert_eq!(f64::exponent_bias(), 1023);
Sourcefn decompose_raw(self) -> (bool, Self::RawExponent, Self::Significand)
fn decompose_raw(self) -> (bool, Self::RawExponent, Self::Significand)
Break self
into the three constituent parts of an IEEE754 float.
The exponent returned is the raw bits, use exponent_bias
to
compute the offset required or use decompose
to obtain this
in precomputed form.
§Examples
Single precision:
use ieee754::Ieee754;
assert_eq!(1_f32.decompose_raw(), (false, 127, 0));
assert_eq!(1234.567_f32.decompose_raw(), (false, 137, 0x1a5225));
assert_eq!((-0.525_f32).decompose_raw(), (true, 126, 0x66666));
assert_eq!(std::f32::INFINITY.decompose_raw(), (false, 255, 0));
let (sign, expn, signif) = std::f32::NAN.decompose_raw();
assert_eq!((sign, expn), (false, 255));
assert!(signif != 0);
Double precision:
use ieee754::Ieee754;
assert_eq!(1_f64.decompose_raw(), (false, 1023, 0));
assert_eq!(1234.567_f64.decompose_raw(), (false, 1033, 0x34a449ba5e354));
assert_eq!((-0.525_f64).decompose_raw(), (true, 1022, 0xcccc_cccc_cccd));
assert_eq!(std::f64::INFINITY.decompose_raw(), (false, 2047, 0));
let (sign, expn, signif) = std::f64::NAN.decompose_raw();
assert_eq!((sign, expn), (false, 2047));
assert!(signif != 0);
Sourcefn recompose_raw(
sign: bool,
expn: Self::RawExponent,
signif: Self::Significand,
) -> Self
fn recompose_raw( sign: bool, expn: Self::RawExponent, signif: Self::Significand, ) -> Self
Create a Self
out of the three constituent parts of an IEEE754 float.
This returns (-1)sign
×
1.signif
× 2expn
- bias, where
sign
is treated as iftrue
==1
(meaningtrue
is negative),- 1.
signif
refers to placing the bits ofsignif
as the fractional part of a number between 1 and 2, and - bias is the exponent bias for this float (see [
exponent_bias
]).
The exponent should be the raw bits: use exponent_bias
to
compute the offset required, or use recompose
to feed in an
unbiased exponent.
§Examples
Single precision:
use ieee754::Ieee754;
assert_eq!(f32::recompose_raw(false, 127, 0), 1.0);
assert_eq!(f32::recompose_raw(false, 137, 0x1a5225), 1234.567);
assert_eq!(f32::recompose_raw(true, 126, 0x66666), -0.525);
assert_eq!(f32::recompose_raw(false, 255, 0), std::f32::INFINITY);
assert!(f32::recompose_raw(false, 255, 1).is_nan());
Double precision:
use ieee754::Ieee754;
assert_eq!(f64::recompose_raw(false, 1023, 0), 1.0);
assert_eq!(f64::recompose_raw(false, 1033, 0x34a449ba5e354), 1234.567);
assert_eq!(f64::recompose_raw(true, 1022, 0xcccc_cccc_cccd), -0.525);
assert_eq!(f64::recompose_raw(false, 2047, 0), std::f64::INFINITY);
assert!(f64::recompose_raw(false, 2047, 1).is_nan());
Sourcefn decompose(self) -> (bool, Self::Exponent, Self::Significand)
fn decompose(self) -> (bool, Self::Exponent, Self::Significand)
Break self
into the three constituent parts of an IEEE754 float.
The exponent returned is the true exponent, after accounting for the bias it is stored with. The significand does not include the implicit highest bit (if it exists), e.g. the 24-bit for single precision.
§Examples
Single precision:
use ieee754::Ieee754;
assert_eq!(1_f32.decompose(), (false, 0, 0));
assert_eq!(1234.567_f32.decompose(), (false, 10, 0x1a5225));
assert_eq!((-0.525_f32).decompose(), (true, -1, 0x66666));
assert_eq!(std::f32::INFINITY.decompose(), (false, 128, 0));
let (sign, expn, signif) = std::f32::NAN.decompose();
assert_eq!((sign, expn), (false, 128));
assert!(signif != 0);
Double precision:
use ieee754::Ieee754;
assert_eq!(1_f64.decompose(), (false, 0, 0));
assert_eq!(1234.567_f64.decompose(), (false, 10, 0x34a449ba5e354));
assert_eq!((-0.525_f64).decompose(), (true, -1, 0xcccc_cccc_cccd));
assert_eq!(std::f64::INFINITY.decompose(), (false, 1024, 0));
let (sign, expn, signif) = std::f64::NAN.decompose();
assert_eq!((sign, expn), (false, 1024));
assert!(signif != 0);
Sourcefn recompose(
sign: bool,
expn: Self::Exponent,
signif: Self::Significand,
) -> Self
fn recompose( sign: bool, expn: Self::Exponent, signif: Self::Significand, ) -> Self
Create a Self
out of the three constituent parts of an IEEE754 float.
This returns (-1)sign
×
1.signif
× 2expn
, where
sign
is treated as iftrue
==1
(meaningtrue
is negative), and- 1.
signif
refers to placing the bits ofsignif
as the fractional part of a number between 1 and 2.
The exponent should be the true exponent, not accounting for any bias. The significand should not include the implicit highest bit (if it exists), e.g. the 24-th bit for single precision.
§Examples
Single precision:
use ieee754::Ieee754;
// normal numbers
assert_eq!(f32::recompose(false, 0, 0), 1.0);
assert_eq!(f32::recompose(false, 10, 0x1a5225), 1234.567);
assert_eq!(f32::recompose(true, -1, 0x66666), -0.525);
// infinity
assert_eq!(f32::recompose(false, 128, 0), std::f32::INFINITY);
// NaN
assert!(f32::recompose(false, 128, 1).is_nan());
Double precision:
use ieee754::Ieee754;
// normal numbers
assert_eq!(f64::recompose(false, 0, 0), 1.0);
assert_eq!(f64::recompose(false, 10, 0x34a449ba5e354), 1234.567);
assert_eq!(f64::recompose(true, -1, 0xcccc_cccc_cccd), -0.525);
// infinity
assert_eq!(f64::recompose(false, 1024, 0), std::f64::INFINITY);
// NaN
assert!(f64::recompose(false, 1024, 1).is_nan());
Sourcefn total_cmp(&self, other: &Self) -> Ordering
fn total_cmp(&self, other: &Self) -> Ordering
Compare x
and y
using the IEEE-754 totalOrder
predicate
(Section 5.10).
This orders NaNs before or after all non-NaN floats, depending on the sign bit. Using -qNaN to represent a quiet NaN with negative sign bit and similarly for a signalling NaN (sNaN), the order is:
-qNaN < -sNaN < -∞ < -12.34 < -0.0 < +0.0 < +12.34 < +∞ < +sNaN < +qNaN
(NaNs are ordered according to their payload.)
§Examples
Sorting:
use std::f32;
use ieee754::Ieee754;
let mut data = vec![0.0, f32::NEG_INFINITY, -1.0, f32::INFINITY,
f32::NAN, -0.0, 12.34e5, -f32::NAN];
data.sort_by(|a, b| a.total_cmp(b));
assert_eq!(format!("{:.0?}", data),
"[NaN, -inf, -1, -0, 0, 1234000, inf, NaN]");
Single precision:
use std::cmp::Ordering;
use std::f32;
use ieee754::Ieee754;
// normal comparison
assert_eq!(0_f32.total_cmp(&0_f32), Ordering::Equal);
assert_eq!(0_f32.total_cmp(&1_f32), Ordering::Less);
assert_eq!(1e10_f32.total_cmp(&f32::NEG_INFINITY), Ordering::Greater);
// signed zero
assert_eq!(0_f32.total_cmp(&-0_f32), Ordering::Greater);
// NaNs
assert_eq!(f32::NAN.total_cmp(&0_f32), Ordering::Greater);
assert_eq!(f32::NAN.total_cmp(&f32::INFINITY), Ordering::Greater);
assert_eq!((-f32::NAN).total_cmp(&f32::NEG_INFINITY), Ordering::Less);
Double precision:
use std::cmp::Ordering;
use std::f64;
use ieee754::Ieee754;
// normal comparison
assert_eq!(0_f64.total_cmp(&0_f64), Ordering::Equal);
assert_eq!(0_f64.total_cmp(&1_f64), Ordering::Less);
assert_eq!(1e10_f64.total_cmp(&f64::NEG_INFINITY), Ordering::Greater);
// signed zero
assert_eq!(0_f64.total_cmp(&-0_f64), Ordering::Greater);
// NaNs
assert_eq!(f64::NAN.total_cmp(&0_f64), Ordering::Greater);
assert_eq!(f64::NAN.total_cmp(&f64::INFINITY), Ordering::Greater);
assert_eq!((-f64::NAN).total_cmp(&f64::NEG_INFINITY), Ordering::Less);
Sourcefn abs(self) -> Self
fn abs(self) -> Self
Return the absolute value of x
.
This provides a no_std/core-only version of the built-in abs
in
std
, until
#50145 is
addressed.
§Examples
Single precision:
#![no_std]
use core::f32;
use ieee754::Ieee754;
assert_eq!((0_f32).abs(), 0.0);
assert_eq!((12.34_f32).abs(), 12.34);
assert_eq!((-12.34_f32).abs(), 12.34);
assert_eq!(f32::INFINITY.abs(), f32::INFINITY);
assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY);
assert!(f32::NAN.abs().is_nan());
Double precision:
#![no_std]
use core::f64;
use ieee754::Ieee754;
assert_eq!((0_f64).abs(), 0.0);
assert_eq!((12.34_f64).abs(), 12.34);
assert_eq!((-12.34_f64).abs(), 12.34);
assert_eq!(f64::INFINITY.abs(), f64::INFINITY);
assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY);
assert!(f64::NAN.abs().is_nan());
Sourcefn copy_sign(self, sign: Self) -> Self
fn copy_sign(self, sign: Self) -> Self
Return a float with the magnitude of self
but the sign of
sign
.
If sign
is NaN, this still uses its sign bit, and does not
(necessarily) return NaN.
§Examples
Single precision:
use std::f32;
use ieee754::Ieee754;
// normal numbers
assert_eq!(1_f32.copy_sign(1.0), 1.0);
assert_eq!(2_f32.copy_sign(-1.0), -2.0);
assert_eq!((-3_f32).copy_sign(1.0), 3.0);
assert_eq!((-4_f32).copy_sign(-1.0), -4.0);
// infinities
assert_eq!(5_f32.copy_sign(f32::NEG_INFINITY), -5.0);
assert_eq!(f32::NEG_INFINITY.copy_sign(1.0), f32::INFINITY);
// signs of zeros matter
assert_eq!((-6_f32).copy_sign(0.0), 6.0);
assert_eq!(7_f32.copy_sign(-0.0), -7.0);
// NaNs only propagate on the self argument
assert!(f32::NAN.copy_sign(1.0).is_nan());
assert_eq!(8_f32.copy_sign(-f32::NAN), -8.0);
Double precision:
use std::f64;
use ieee754::Ieee754;
// normal numbers
assert_eq!(1_f64.copy_sign(1.0), 1.0);
assert_eq!(2_f64.copy_sign(-1.0), -2.0);
assert_eq!((-3_f64).copy_sign(1.0), 3.0);
assert_eq!((-4_f64).copy_sign(-1.0), -4.0);
// infinities
assert_eq!(5_f64.copy_sign(f64::NEG_INFINITY), -5.0);
assert_eq!(f64::NEG_INFINITY.copy_sign(1.0), f64::INFINITY);
// signs of zeros matter
assert_eq!((-6_f64).copy_sign(0.0), 6.0);
assert_eq!(7_f64.copy_sign(-0.0), -7.0);
// NaNs only propagate on the self argument
assert!(f64::NAN.copy_sign(1.0).is_nan());
assert_eq!(8_f64.copy_sign(-f64::NAN), -8.0);
Sourcefn sign(self) -> Self
fn sign(self) -> Self
Return the sign of x
.
This provides a no_std/core-only function similar to the
built-in signum
in std
(until
#50145 is
addressed). This sign
function differs at two values; it
matches the mathematical definitions when self == 0.0
:
x | x.signum() (std ) | x.sign() (ieee754 ) |
---|---|---|
< 0.0 | −1.0 | −1.0 |
−0.0 | −1.0 | −0.0 |
+0.0 | +1.0 | +0.0 |
> 0.0 | +1.0 | +1.0 |
NaN | NaN | NaN |
§Examples
Single precision:
use std::f32;
use std::cmp::Ordering;
use ieee754::Ieee754;
// zeros
assert_eq!(0_f32.sign().total_cmp(&0.0), Ordering::Equal);
assert_eq!((-0_f32).sign().total_cmp(&-0.0), Ordering::Equal);
// normal numbers
assert_eq!((12.34_f32).sign(), 1.0);
assert_eq!((-12.34_f32).sign(), -1.0);
// extremes
assert_eq!(f32::INFINITY.sign(), 1.0);
assert_eq!(f32::NEG_INFINITY.sign(), -1.0);
assert!(f32::NAN.sign().is_nan());
Double precision:
use std::f64;
use std::cmp::Ordering;
use ieee754::Ieee754;
// zeros
assert_eq!(0_f64.sign().total_cmp(&0.0), Ordering::Equal);
assert_eq!((-0_f64).sign().total_cmp(&-0.0), Ordering::Equal);
// normal numbers
assert_eq!((12.34_f64).sign(), 1.0);
assert_eq!((-12.34_f64).sign(), -1.0);
// extremes
assert_eq!(f64::INFINITY.sign(), 1.0);
assert_eq!(f64::NEG_INFINITY.sign(), -1.0);
assert!(f64::NAN.sign().is_nan());
Sourcefn rel_error(self, exact: Self) -> Self
fn rel_error(self, exact: Self) -> Self
Compute the (generalized) signed relative error of self
as an approximation to exact
.
This computes the signed value: positive indicates self
in
the opposite direction to 0 from exact
; negative indicates
self
is in the same direction as 0 from exact
. Use
x.rel_error(exact).abs()
to get the non-signed relative
error.
The “generalized” refers to exact
being 0 or ±∞ the handling
of which is designed to indicate a “failure” (infinite error),
if self
doesn’t precisely equal exact
. This behaviour is
designed for checking output of algorithms on floats when it
is often desirable to match 0.0 and ±∞ perfectly.
The values of this function are:
exact | x | x.rel_error(exact) |
---|---|---|
NaN | any value | NaN |
any value | NaN | NaN |
0 | equal to exact | 0 |
0 | not equal to exact | signum(x ) × ∞ |
±∞ | equal to exact | 0 |
±∞ | not equal to exact | -∞ |
any other value | any value | (x - exact) / exact |
The sign of a zero-valued argument has no effect on the result of this function.
§Examples
Single precision:
use std::f32;
use ieee754::Ieee754;
assert_eq!(4_f32.rel_error(4.0), 0.0);
assert_eq!(3_f32.rel_error(4.0), -0.25);
assert_eq!(5_f32.rel_error(4.0), 0.25);
// zero
assert_eq!(0_f32.rel_error(0.0), 0.0);
assert_eq!(1_f32.rel_error(0.0), f32::INFINITY);
assert_eq!((-1_f32).rel_error(0.0), f32::NEG_INFINITY);
// infinities
assert_eq!(f32::INFINITY.rel_error(f32::INFINITY), 0.0);
assert_eq!(0_f32.rel_error(f32::INFINITY), f32::NEG_INFINITY);
assert_eq!(f32::NEG_INFINITY.rel_error(f32::NEG_INFINITY), 0.0);
assert_eq!(0_f32.rel_error(f32::NEG_INFINITY), f32::NEG_INFINITY);
// NaNs
assert!(f32::NAN.rel_error(4.0).is_nan());
assert!(4_f32.rel_error(f32::NAN).is_nan());
Double precision:
use std::f64;
use ieee754::Ieee754;
assert_eq!(4_f64.rel_error(4.0), 0.0);
assert_eq!(3_f64.rel_error(4.0), -0.25);
assert_eq!(5_f64.rel_error(4.0), 0.25);
// zero
assert_eq!(0_f64.rel_error(0.0), 0.0);
assert_eq!(1_f64.rel_error(0.0), f64::INFINITY);
assert_eq!((-1_f64).rel_error(0.0), f64::NEG_INFINITY);
// infinities
assert_eq!(f64::INFINITY.rel_error(f64::INFINITY), 0.0);
assert_eq!(0_f64.rel_error(f64::INFINITY), f64::NEG_INFINITY);
assert_eq!(f64::NEG_INFINITY.rel_error(f64::NEG_INFINITY), 0.0);
assert_eq!(0_f64.rel_error(f64::NEG_INFINITY), f64::NEG_INFINITY);
// NaNs
assert!(f64::NAN.rel_error(4.0).is_nan());
assert!(4_f64.rel_error(f64::NAN).is_nan());
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.