microfloat 0.1.2

8-bit and sub-byte floating point types
Documentation
#![cfg(feature = "num-traits")]

use microfloat::*;
use num_traits::{FromPrimitive, Num, NumCast, One, Signed, ToPrimitive, Zero, float::FloatCore};

macro_rules! common_num_traits_tests {
    ($($module:ident: $type:ty;)*) => {
        $(
            mod $module {
                use super::*;

                #[test]
                fn bounded() {
                    assert_eq!(<$type as num_traits::Bounded>::min_value(), <$type>::MIN);
                    assert_eq!(<$type as num_traits::Bounded>::max_value(), <$type>::MAX);
                }
            }
        )*
    };
}

common_num_traits_tests! {
    float8_e3m4: f8e3m4;
    float8_e4m3: f8e4m3;
    float8_e4m3b11fnuz: f8e4m3b11fnuz;
    float8_e4m3fn: f8e4m3fn;
    float8_e4m3fnuz: f8e4m3fnuz;
    float8_e5m2: f8e5m2;
    float8_e5m2fnuz: f8e5m2fnuz;
    float8_e8m0fnu: f8e8m0fnu;
    float4_e2m1fn: f4e2m1fn;
    float6_e2m3fn: f6e2m3fn;
    float6_e3m2fn: f6e3m2fn;
}

macro_rules! float_core_constant_tests {
    ($($module:ident: $type:ty;)*) => {
        $(
            mod $module {
                use super::*;

                #[test]
                fn special_constants() {
                    assert_eq!(<$type as FloatCore>::nan().to_bits(), <$type>::NAN.to_bits());
                    assert_eq!(
                        <$type as FloatCore>::infinity().to_bits(),
                        <$type>::INFINITY.to_bits()
                    );
                    assert_eq!(
                        <$type as FloatCore>::neg_infinity().to_bits(),
                        <$type>::NEG_INFINITY.to_bits()
                    );
                    assert_eq!(
                        <$type as FloatCore>::neg_zero().to_bits(),
                        <$type>::NEG_ZERO.to_bits()
                    );
                }
            }
        )*
    };
}

float_core_constant_tests! {
    float_core_float8_e3m4: f8e3m4;
    float_core_float8_e4m3: f8e4m3;
    float_core_float8_e4m3b11fnuz: f8e4m3b11fnuz;
    float_core_float8_e4m3fn: f8e4m3fn;
    float_core_float8_e4m3fnuz: f8e4m3fnuz;
    float_core_float8_e5m2: f8e5m2;
    float_core_float8_e5m2fnuz: f8e5m2fnuz;
    float_core_float4_e2m1fn: f4e2m1fn;
    float_core_float6_e2m3fn: f6e2m3fn;
    float_core_float6_e3m2fn: f6e3m2fn;
}

#[test]
fn conversions_and_methods() {
    let value = f8e4m3::from_f32(2.0);

    assert_eq!(value.to_i64(), Some(2));
    assert_eq!(value.to_u64(), Some(2));
    assert_eq!(ToPrimitive::to_f32(&value), Some(2.0));
    assert_eq!(ToPrimitive::to_f64(&value), Some(2.0));

    assert_eq!(f8e4m3::from_i64(2), Some(value));
    assert_eq!(f8e4m3::from_u64(2), Some(value));
    assert_eq!(<f8e4m3 as FromPrimitive>::from_f32(2.0), Some(value));
    assert_eq!(<f8e4m3 as FromPrimitive>::from_f64(2.0), Some(value));
    assert_eq!(<f8e4m3 as NumCast>::from(2.0f32), Some(value));

    assert_eq!(f8e4m3::zero(), f8e4m3::ZERO);
    assert!(f8e4m3::ZERO.is_zero());
    assert!(!value.is_zero());
    assert_eq!(f8e4m3::one(), f8e4m3::ONE);
    assert_eq!(<f8e4m3 as Num>::from_str_radix("2", 10).unwrap(), value);

    assert_eq!(Signed::abs(&f8e4m3::from_f32(-2.0)), value);
    assert_eq!(value.abs_sub(&f8e4m3::ONE), f8e4m3::ONE);
    assert_eq!(f8e4m3::ONE.abs_sub(&value), f8e4m3::ZERO);
    assert_eq!(Signed::signum(&f8e4m3::from_f32(-2.0)), f8e4m3::NEG_ONE);
    assert!(value.is_positive());
    assert!(!f8e4m3::ZERO.is_positive());
    assert!(f8e4m3::from_f32(-2.0).is_negative());
    assert!(!f8e4m3::ZERO.is_negative());

    assert_eq!(<f8e4m3 as FloatCore>::min_value(), f8e4m3::MIN);
    assert_eq!(
        <f8e4m3 as FloatCore>::min_positive_value(),
        f8e4m3::MIN_POSITIVE
    );
    assert_eq!(<f8e4m3 as FloatCore>::epsilon(), f8e4m3::EPSILON);
    assert_eq!(<f8e4m3 as FloatCore>::max_value(), f8e4m3::MAX);
    assert!(FloatCore::is_nan(f8e4m3::NAN));
    assert!(FloatCore::is_infinite(f8e4m3::INFINITY));
    assert!(FloatCore::is_finite(value));
    assert!(FloatCore::is_normal(value));
    assert_eq!(FloatCore::classify(value), core::num::FpCategory::Normal);
    assert_eq!(value.to_degrees(), f8e4m3::from_f32(2.0f32.to_degrees()));
    assert_eq!(value.to_radians(), f8e4m3::from_f32(2.0f32.to_radians()));
    assert_eq!(
        value.integer_decode(),
        <f32 as FloatCore>::integer_decode(2.0)
    );
}