float-traits 0.0.3

Abstraction for general floating point numbers.
Documentation
use core;
use core::ops::Neg;
use core::cmp::PartialOrd;
use core::clone::Clone;
use num_traits::{Num, Bounded};
use num_integer::Integer;

pub trait Abs {
    type Output: Num;
    fn abs(&self) -> Self::Output;
    fn sign(&self) -> Self::Output;
}

macro_rules! impl_abs {
    ($($num:ty)*) => ($(
        impl Abs for $num {
            type Output = $num;
            #[inline]
            fn abs(&self) -> $num {
                self.clone().abs()
            }
            fn sign(&self) -> $num {
                self.signum()
            }
        }
        impl<'a> Abs for &'a $num {
            type Output = $num;
            #[inline]
            fn abs(&self) -> $num {
                self.clone().abs()
            }
            fn sign(&self) -> $num {
                self.clone().signum()
            }
        }
    )*)
}

impl_abs!(f32 f64);

pub trait Sqrt {
    type Output: Num;
    fn sqrt(self) -> Self::Output;
}

macro_rules! impl_sqrt {
    ($($num:ty)*) => ($(
        impl Sqrt for $num {
            type Output = $num;
            #[inline]
            fn sqrt(self) -> Self {
                self.sqrt()
            }
        }
        impl<'a> Sqrt for &'a $num {
            type Output = $num;
            #[inline]
            fn sqrt(self) -> $num {
                self.clone().sqrt()
            }
        }
    )*)
}

impl_sqrt!(f32 f64);

pub trait GeneralFloat: Num + PartialOrd {
    type Exponent: Integer;
    fn radix() -> Self;
    fn bit_size() -> Self::Exponent;
    fn epsilon() -> Self;
    fn radix_powi(p: Self::Exponent) -> Self;
}

pub trait BinaryFloat: Num + PartialOrd {
    type Expo: Integer;
    fn bits() -> Self::Expo;
    fn eps() -> Self;
    fn two_powi(p: Self::Expo) -> Self;
}

impl<T: BinaryFloat> GeneralFloat for T {
    type Exponent = T::Expo;
    #[inline]
    fn radix() -> T {
        T::one() + T::one()
    }
    #[inline]
    fn bit_size() -> T::Expo {
        T::bits()
    }
    #[inline]
    fn epsilon() -> T {
        T::eps()
    }
    #[inline]
    fn radix_powi(p: T::Expo) -> T {
        T::two_powi(p)
    }
}

pub trait BoundedFloat: Bounded + GeneralFloat {
    fn max_exponent() -> Self::Exponent;
    fn min_exponent() -> Self::Exponent;
}

pub trait Overflow: Num + PartialOrd {
    fn overflow() -> Self;
    fn neg_overflow() -> Self;
}

pub trait Infinite: Num + PartialOrd {
    fn infinity() -> Self;
    fn neg_infinity() -> Self;
    fn is_infinite(&self) -> bool;
}

impl<T: Infinite> Overflow for T {
    #[inline]
    fn overflow() -> Self {
        T::infinity()
    }
    #[inline]
    fn neg_overflow() -> Self {
        T::neg_infinity()
    }
}

pub trait Underflow: Num {
    fn min_positive() -> Self;
    fn unit_underflow() -> Self;
}

pub trait IEEE754Float
    : Abs<Output=Self> + Sqrt<Output = Self> + Neg<Output = Self> +
    BinaryFloat + BoundedFloat + Infinite + Underflow
    {
    fn nan() -> Self;
}

macro_rules! impl_fxx {
    ($fxx:ident, $expo:ty, [$emin:expr,$emax:expr], $bits:expr) => (
        impl BinaryFloat for $fxx {
            type Expo = $expo;
            #[inline]
            fn bits() -> Self::Expo{
                $bits
            }
            #[inline]
            fn eps() -> Self{
                core::$fxx::EPSILON
            }
            #[inline]
            fn two_powi(p: Self::Expo) -> Self{
                $fxx::radix().powi(p)
            }
        }
        impl BoundedFloat for $fxx {
            #[inline]
            fn max_exponent() -> Self::Exponent{
                $emax
            }
            #[inline]
            fn min_exponent() -> Self::Exponent{
                $emin
            }
        }
        impl Infinite for $fxx {
            #[inline]
            fn infinity() -> Self{
                core::$fxx::INFINITY
            }
            #[inline]
            fn neg_infinity() -> Self{
                core::$fxx::NEG_INFINITY
            }
            #[inline]
            fn is_infinite(&self) -> bool{
                $fxx::is_infinite(*self)
            }
        }
        impl Underflow for $fxx {
            #[inline]
            fn min_positive() -> Self{
                core::$fxx::MIN_POSITIVE
            }
            #[inline]
            fn unit_underflow() -> Self{
                core::$fxx::MIN_POSITIVE * core::$fxx::EPSILON
            }
        }
        impl IEEE754Float for $fxx {
            #[inline]
            fn nan() -> Self {
                core::$fxx::NAN
            }
        }
    )
}

impl_fxx!(f32, i32, [-126, 127], 24);
impl_fxx!(f64, i32, [-1022, 1023], 53);

mod tests {
    #[test]
    fn f64abs() {
        use super::{Abs,IEEE754Float};
        assert!((-1.0).abs() == <f64 as Abs>::abs(&-1.0f64));
        assert!(f64::nan().is_nan());
    }
}