From 85a3c9141da71e63ca05983c2f0c125aadcb2d0d Mon Sep 17 00:00:00 2001 From: Chen-Pang He Date: Tue, 14 May 2024 14:34:44 +0800 Subject: [PATCH] Fix MAX_10_EXP --- src/lib.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- src/test.rs | 37 +++++++------------------------------ 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 13ef239..0cc6612 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -156,7 +156,13 @@ impl F8 /// The maximum exponent /// /// Normal numbers < 1 × 2`MAX_EXP`. - pub const MAX_EXP: i32 = (1 << E) - B - matches!(N, NanStyle::IEEE) as i32; + pub const MAX_EXP: i32 = (1 << E) + - B + - match N { + NanStyle::IEEE => 1, + NanStyle::FN => (M == 0) as i32, + NanStyle::FNUZ => 0, + }; /// One greater than the minimum normal exponent /// @@ -664,6 +670,26 @@ impl Neg for F16 { } } +#[allow(clippy::excessive_precision)] +const LOG2_SIGNIFICAND: [f64; 16] = [ + -2.0, + -1.0, + -4.150_374_992_788_438_13e-1, + -1.926_450_779_423_958_81e-1, + -9.310_940_439_148_146_51e-2, + -4.580_368_961_312_478_86e-2, + -2.272_007_650_008_352_89e-2, + -1.131_531_322_783_414_61e-2, + -5.646_563_141_142_062_72e-3, + -2.820_519_062_378_662_63e-3, + -1.409_570_254_671_353_63e-3, + -7.046_129_765_893_727_06e-4, + -3.522_634_716_290_213_85e-4, + -1.761_209_842_740_240_62e-4, + -8.805_780_458_002_638_34e-5, + -4.402_823_044_177_721_15e-5, +]; + /// Generic trait for minifloat types /// /// We are **not** going to implement [`num_traits::Float`][flt] because: @@ -698,7 +724,13 @@ pub trait Minifloat: Copy + PartialEq + PartialOrd + Neg { /// The maximum exponent /// /// Normal numbers < 1 × 2`MAX_EXP`. - const MAX_EXP: i32 = (1 << Self::E) - Self::B - matches!(Self::N, NanStyle::IEEE) as i32; + const MAX_EXP: i32 = (1 << Self::E) + - Self::B + - match Self::N { + NanStyle::IEEE => 1, + NanStyle::FN => (Self::M == 0) as i32, + NanStyle::FNUZ => 0, + }; /// One greater than the minimum normal exponent /// @@ -720,7 +752,12 @@ pub trait Minifloat: Copy + PartialEq + PartialOrd + Neg { /// /// Equal to floor(log10([`MAX`][Self::MAX])) #[allow(clippy::cast_possible_truncation)] - const MAX_10_EXP: i32 = (Self::MAX_EXP as f64 * LOG10_2) as i32; + const MAX_10_EXP: i32 = { + let exponent = (1 << Self::E) - Self::B - matches!(Self::N, NanStyle::IEEE) as i32; + let precision = Self::M + !matches!(Self::N, NanStyle::FN) as u32; + let log2_max = exponent as f64 + LOG2_SIGNIFICAND[precision as usize]; + (log2_max * LOG10_2) as i32 + }; /// Minimum x such that 10`x` is normal /// diff --git a/src/test.rs b/src/test.rs index 6d2b263..049f454 100644 --- a/src/test.rs +++ b/src/test.rs @@ -292,36 +292,13 @@ fn test_10_exp_generic() where f64: From, { - let assert_lt = |x: f64, y: f64, z: f64| { - assert!( - x < y, - "{}: {} < {} failed ({})", - core::any::type_name::(), - x, - y, - z, - ); - }; - assert_lt( - libm::exp10(T::MAX_10_EXP.into()), - T::MAX.into(), - f64::exp2(T::MAX_EXP.into()), - ); - assert_lt( - T::MAX.into(), - libm::exp10((T::MAX_10_EXP + 1).into()), - f64::exp2(T::MAX_EXP.into()), - ); - assert_lt( - T::MIN_POSITIVE.into(), - libm::exp10(T::MIN_10_EXP.into()), - f64::exp2(T::MIN_EXP.into()), - ); - assert_lt( - libm::exp10((T::MIN_10_EXP - 1).into()), - T::MIN_POSITIVE.into(), - f64::exp2(T::MIN_EXP.into()), - ); + fn exp10i(x: i32) -> f64 { + libm::exp10(x.into()) + } + assert!(exp10i(T::MAX_10_EXP) <= T::MAX.into()); + assert!(exp10i(T::MAX_10_EXP + 1) > T::MAX.into()); + assert!(exp10i(T::MIN_10_EXP) >= T::MIN_POSITIVE.into()); + assert!(exp10i(T::MIN_10_EXP - 1) < T::MIN_POSITIVE.into()); } #[test]