diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aebcf7..0f3def8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- `classify_bits`, `is_infinity_bits` are now `const` +- Make the following methods `const` on all float types: + - `abs()` + - `classify()` + - `classify_bits()` + - `copysign()` + - `is_finite()` + - `is_infinite()` + - `is_infinity_bits()` + - `is_nan()` + - `is_normal()` + - `signum()` ## [0.1.2](https://github.com/LDeakin/microfloat/releases/tag/v0.1.2) - 2026-04-29 diff --git a/src/formats.rs b/src/formats.rs index 4a6e4b6..2310364 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -315,27 +315,27 @@ macro_rules! define_format { } /// Returns `true` if this value is NaN. - pub fn is_nan(self) -> bool { + pub const fn is_nan(self) -> bool { self.0.is_nan() } /// Returns `true` if this value is positive or negative infinity. - pub fn is_infinite(self) -> bool { + pub const fn is_infinite(self) -> bool { self.0.is_infinite() } /// Returns `true` if this value is neither infinite nor NaN. - pub fn is_finite(self) -> bool { + pub const fn is_finite(self) -> bool { self.0.is_finite() } /// Returns `true` if this value is finite, nonzero, and not subnormal. - pub fn is_normal(self) -> bool { + pub const fn is_normal(self) -> bool { self.0.is_normal() } /// Returns the floating point category of this value. - pub fn classify(self) -> core::num::FpCategory { + pub const fn classify(self) -> core::num::FpCategory { self.0.classify() } @@ -354,19 +354,19 @@ macro_rules! define_format { } /// Returns a value with the magnitude of `self` and the sign of `sign`. - pub fn copysign(self, sign: Self) -> Self { + pub const fn copysign(self, sign: Self) -> Self { Self(self.0.copysign(sign.0)) } /// Returns a number representing the sign of `self`. /// /// NaN and zero values are returned unchanged. - pub fn signum(self) -> Self { + pub const fn signum(self) -> Self { Self(self.0.signum()) } /// Returns the absolute value of `self`. - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { Self(self.0.abs()) } diff --git a/src/micro.rs b/src/micro.rs index e153e44..344e1ad 100644 --- a/src/micro.rs +++ b/src/micro.rs @@ -78,23 +78,24 @@ impl MicroFloat { f64::from(self.to_f32()) } - pub fn is_nan(self) -> bool { + pub const fn is_nan(self) -> bool { classify_bits::(self.bits).is_nan } - pub fn is_infinite(self) -> bool { + pub const fn is_infinite(self) -> bool { classify_bits::(self.bits).is_infinite } - pub fn is_finite(self) -> bool { + pub const fn is_finite(self) -> bool { !self.is_nan() && !self.is_infinite() } - pub fn is_normal(self) -> bool { - matches!(self.classify(), FpCategory::Normal) + pub const fn is_normal(self) -> bool { + let class = classify_bits::(self.bits); + !class.is_nan && !class.is_infinite && !class.is_zero && !class.is_subnormal } - pub fn classify(self) -> FpCategory { + pub const fn classify(self) -> FpCategory { let class = classify_bits::(self.bits); if class.is_nan { FpCategory::Nan @@ -126,11 +127,11 @@ impl MicroFloat { } } - pub fn copysign(self, sign: Self) -> Self { + pub const fn copysign(self, sign: Self) -> Self { if matches!(F::NAN, NanEncoding::Single(_)) && self.is_nan() { return self; } - if F::SIGN == SignMode::Unsigned { + if matches!(F::SIGN, SignMode::Unsigned) { self } else if sign.is_sign_negative() { Self::from_bits(abs_bits::(self.bits) | F::SIGN_BIT) @@ -139,8 +140,8 @@ impl MicroFloat { } } - pub fn signum(self) -> Self { - if self.is_nan() || self.classify() == FpCategory::Zero { + pub const fn signum(self) -> Self { + if self.is_nan() || matches!(self.classify(), FpCategory::Zero) { self } else if self.is_sign_negative() { Self::NEG_ONE @@ -149,7 +150,7 @@ impl MicroFloat { } } - pub fn abs(self) -> Self { + pub const fn abs(self) -> Self { if matches!(F::NAN, NanEncoding::Single(_)) && self.is_nan() { return self; } diff --git a/tests/const_methods.rs b/tests/const_methods.rs new file mode 100644 index 0000000..437e396 --- /dev/null +++ b/tests/const_methods.rs @@ -0,0 +1,54 @@ +use microfloat::{ + f4e2m1fn, f6e2m3fn, f6e3m2fn, f8e3m4, f8e4m3, f8e4m3b11fnuz, f8e4m3fn, f8e4m3fnuz, f8e5m2, + f8e5m2fnuz, f8e8m0fnu, +}; + +macro_rules! assert_const_methods_compile { + ($($type:ty),* $(,)?) => { + $( + const _: () = { + let value = <$type>::from_bits(0x01); + let sign = <$type>::NEG_ONE; + let bits = value.to_bits(); + let _ = <$type>::from_le_bytes([bits]); + let _ = <$type>::from_be_bytes([bits]); + let _ = <$type>::from_ne_bytes([bits]); + let _ = value.to_le_bytes(); + let _ = value.to_be_bytes(); + let _ = value.to_ne_bytes(); + let _ = <$type>::has_inf(); + let _ = <$type>::has_nan(); + let _ = <$type>::is_finite_only(); + let _ = value.is_nan(); + let _ = value.is_infinite(); + let _ = value.is_finite(); + let _ = value.is_normal(); + let _ = value.classify(); + let _ = value.is_sign_positive(); + let _ = value.is_sign_negative(); + let _ = value.copysign(sign); + let _ = value.signum(); + let _ = value.abs(); + let _ = value.next_up(); + let _ = value.next_down(); + }; + )* + }; +} + +assert_const_methods_compile!( + f8e3m4, + f8e4m3, + f8e4m3b11fnuz, + f8e4m3fn, + f8e4m3fnuz, + f8e5m2, + f8e5m2fnuz, + f8e8m0fnu, + f4e2m1fn, + f6e2m3fn, + f6e3m2fn, +); + +#[test] +fn const_methods_compile() {}