use cfg_if::cfg_if;
use ieee754::Ieee754;
use num_traits::{Float, PrimInt, ToPrimitive, Zero};
pub trait TwoSum<F>: Clone {
fn two_sum(a: F, b: F) -> (F, F);
}
pub trait Split: Float {
fn split_factor() -> Self;
#[inline]
fn split(self) -> (Self, Self) {
let x = self;
let c = Self::split_factor() * x;
let h = c - (c - x);
let t = x - h;
(h, t)
}
}
impl Split for f32 {
#[inline]
fn split_factor() -> Self {
4097.0
}
}
impl Split for f64 {
#[inline]
fn split_factor() -> Self {
134_217_729.0
}
}
cfg_if! {
if #[cfg(feature = "fma")] {
pub trait TwoProduct: Float { }
impl<F> TwoProduct for F where F: Float { }
} else {
pub trait TwoProduct: Float + Split { }
impl<F> TwoProduct for F where F: Float + Split { }
}
}
pub trait HalfUlp {
fn has_half_ulp_form(self) -> bool;
fn half_ulp(self) -> Self;
}
impl<F> HalfUlp for F
where
F: Float + Ieee754,
F::Significand: Zero + Eq,
{
#[inline]
fn has_half_ulp_form(self) -> bool {
self != F::zero() && self.decompose_raw().2 == F::Significand::zero()
}
#[inline]
fn half_ulp(self) -> Self {
self.ulp().unwrap_or_else(Self::zero) / F::one().exp2()
}
}
pub trait Round3: Float + Ieee754 + HalfUlp {}
impl<F> Round3 for F where F: Float + Ieee754 + HalfUlp {}
pub trait FloatFormat {
fn base() -> u32;
fn significand_digits() -> u32;
fn exponent_digits() -> u32;
#[inline]
fn base_pow_exponent_digits() -> usize {
Self::base()
.to_usize()
.expect("floating-point base cannot be converted to usize")
.pow(Self::exponent_digits())
}
#[inline]
fn base_pow_significand_digits_half() -> usize {
Self::base()
.to_usize()
.expect("floating-point base cannot be converted to usize")
.pow(Self::significand_digits() / 2)
}
}
impl FloatFormat for f32 {
#[inline]
fn base() -> u32 {
2
}
#[inline]
fn significand_digits() -> u32 {
24
}
#[inline]
fn exponent_digits() -> u32 {
8
}
#[inline]
fn base_pow_exponent_digits() -> usize {
256
}
#[inline]
fn base_pow_significand_digits_half() -> usize {
4096
}
}
impl FloatFormat for f64 {
#[inline]
fn base() -> u32 {
2
}
#[inline]
fn significand_digits() -> u32 {
53
}
#[inline]
fn exponent_digits() -> u32 {
11
}
#[inline]
fn base_pow_exponent_digits() -> usize {
2048
}
#[inline]
fn base_pow_significand_digits_half() -> usize {
67_108_864
}
}
pub trait RawExponent {
fn raw_exponent(self) -> usize;
}
impl<F> RawExponent for F
where
F: Ieee754,
F::RawExponent: PrimInt,
{
#[inline]
fn raw_exponent(self) -> usize {
self.decompose_raw()
.1
.to_usize()
.expect("exponent does not fit in a usize.")
}
}