added float masks feature

This commit is contained in:
Apersoma
2026-04-24 23:06:04 +00:00
parent 0312931d8c
commit d5b941d163
5 changed files with 282 additions and 42 deletions
+73 -9
View File
@@ -339,14 +339,78 @@ impl f128 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
/// The mask of the bit used to encode the sign of an [`f128`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f128::is_sign_positive
/// [`is_sign_negative`]: f128::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f128)]
/// # #[cfg(target_has_reliable_f128)] {
/// let sign_mask = f128::SIGN_MASK;
/// let a = 1.6552f128;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f128::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f128).to_bits());
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
/// Exponent mask
pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
/// The mask of the bits used to encode the exponent of an [`f128`].
///
/// Note that the exponent is stored as a biased value, with a bias of 16383 for `f128`.
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f128)]
/// # #[cfg(target_has_reliable_f128)] {
/// fn get_exp(a: f128) -> i128 {
/// let bias = 16383;
/// let biased = a.to_bits() & f128::EXPONENT_MASK;
/// (biased >> (f128::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
/// Mantissa mask
pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
/// The mask of the bits used to encode the mantissa of an [`f128`].
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f128)]
/// # #[cfg(target_has_reliable_f128)] {
/// let mantissa_mask = f128::MANTISSA_MASK;
///
/// assert_eq!(0f128.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f128.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f128;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f128::MAX.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK);
/// assert_eq!(f128::MIN.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u128 = 0x1;
@@ -510,9 +574,9 @@ pub const fn is_normal(self) -> bool {
#[unstable(feature = "f128", issue = "116909")]
pub const fn classify(self) -> FpCategory {
let bits = self.to_bits();
match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (bits & Self::MANTISSA_MASK, bits & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+75 -9
View File
@@ -333,14 +333,80 @@ impl f16 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u16 = 0x8000;
/// The mask of the bit used to encode the sign of an [`f16`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f16::is_sign_positive
/// [`is_sign_negative`]: f16::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f16)]
/// # #[cfg(target_has_reliable_f16)] {
/// let sign_mask = f16::SIGN_MASK;
/// let a = 1.6552f16;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f16::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f16).to_bits());
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u16 = 0x8000;
/// Exponent mask
pub(crate) const EXP_MASK: u16 = 0x7c00;
/// The mask of the bits used to encode the exponent of an [`f16`].
///
/// Note that the exponent is stored as a biased value, with a bias of 15 for `f16`.
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f16)]
/// # #[cfg(target_has_reliable_f16)] {
/// let exponent_mask = f16::EXPONENT_MASK;
///
/// fn get_exp(a: f16) -> i16 {
/// let bias = 15;
/// let biased = a.to_bits() & f16::EXPONENT_MASK;
/// (biased >> (f16::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u16 = 0x7c00;
/// Mantissa mask
pub(crate) const MAN_MASK: u16 = 0x03ff;
/// The mask of the bits used to encode the mantissa of an [`f16`].
///
/// ```rust
/// #![feature(float_masks)]
/// #![feature(f16)]
/// # #[cfg(target_has_reliable_f16)] {
/// let mantissa_mask = f16::MANTISSA_MASK;
///
/// assert_eq!(0f16.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f16.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f16;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f16::MAX.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK);
/// assert_eq!(f16::MIN.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK);
/// # }
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u16 = 0x03ff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u16 = 0x1;
@@ -502,9 +568,9 @@ pub const fn is_normal(self) -> bool {
#[unstable(feature = "f16", issue = "116909")]
pub const fn classify(self) -> FpCategory {
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+64 -9
View File
@@ -572,14 +572,69 @@ impl f32 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u32 = 0x8000_0000;
/// The mask of the bit used to encode the sign of an [`f32`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f32::is_sign_positive
/// [`is_sign_negative`]: f32::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// let sign_mask = f32::SIGN_MASK;
/// let a = 1.6552f32;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f32::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f32).to_bits());
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u32 = 0x8000_0000;
/// Exponent mask
pub(crate) const EXP_MASK: u32 = 0x7f80_0000;
/// The mask of the bits used to encode the exponent of an [`f32`].
///
/// Note that the exponent is stored as a biased value, with a bias of 127 for `f32`.
///
/// ```rust
/// #![feature(float_masks)]
/// fn get_exp(a: f32) -> i32 {
/// let bias = 127;
/// let biased = a.to_bits() & f32::EXPONENT_MASK;
/// (biased >> (f32::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u32 = 0x7f80_0000;
/// Mantissa mask
pub(crate) const MAN_MASK: u32 = 0x007f_ffff;
/// The mask of the bits used to encode the mantissa of an [`f32`].
///
/// ```rust
/// #![feature(float_masks)]
/// let mantissa_mask = f32::MANTISSA_MASK;
///
/// assert_eq!(0f32.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f32.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f32;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f32::MAX.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK);
/// assert_eq!(f32::MIN.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u32 = 0x007f_ffff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u32 = 0x1;
@@ -730,9 +785,9 @@ pub const fn classify(self) -> FpCategory {
// of our tests is able to find any difference between the complicated and the naive
// version, so now we are back to the naive version.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+64 -9
View File
@@ -571,14 +571,69 @@ impl f64 {
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER;
/// Sign bit
pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
/// The mask of the bit used to encode the sign of an [`f64`].
///
/// This bit is set when the sign is negative and unset when the sign is
/// positive.
/// If you only need to check whether a value is positive or negative,
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
///
/// [`is_sign_positive`]: f64::is_sign_positive
/// [`is_sign_negative`]: f64::is_sign_negative
/// ```rust
/// #![feature(float_masks)]
/// let sign_mask = f64::SIGN_MASK;
/// let a = 1.6552f64;
/// let a_bits = a.to_bits();
///
/// assert_eq!(a_bits & sign_mask, 0x0);
/// assert_eq!(f64::from_bits(a_bits ^ sign_mask), -a);
/// assert_eq!(sign_mask, (-0.0f64).to_bits());
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
/// Exponent mask
pub(crate) const EXP_MASK: u64 = 0x7ff0_0000_0000_0000;
/// The mask of the bits used to encode the exponent of an [`f64`].
///
/// Note that the exponent is stored as a biased value, with a bias of 1024 for `f64`.
///
/// ```rust
/// #![feature(float_masks)]
/// fn get_exp(a: f64) -> i64 {
/// let bias = 1023;
/// let biased = a.to_bits() & f64::EXPONENT_MASK;
/// (biased >> (f64::MANTISSA_DIGITS - 1)).cast_signed() - bias
/// }
///
/// assert_eq!(get_exp(0.5), -1);
/// assert_eq!(get_exp(1.0), 0);
/// assert_eq!(get_exp(2.0), 1);
/// assert_eq!(get_exp(4.0), 2);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const EXPONENT_MASK: u64 = 0x7ff0_0000_0000_0000;
/// Mantissa mask
pub(crate) const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff;
/// The mask of the bits used to encode the mantissa of an [`f64`].
///
/// ```rust
/// #![feature(float_masks)]
/// let mantissa_mask = f64::MANTISSA_MASK;
///
/// assert_eq!(0f64.to_bits() & mantissa_mask, 0x0);
/// assert_eq!(1f64.to_bits() & mantissa_mask, 0x0);
///
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
/// // unless the result or initial value is not normal.
/// let a = 1.6552f64;
/// let b = 4.0 * a;
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
///
/// // The maximum and minimum values have a saturated significand
/// assert_eq!(f64::MAX.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK);
/// assert_eq!(f64::MIN.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK);
/// ```
#[unstable(feature = "float_masks", issue = "154064")]
pub const MANTISSA_MASK: u64 = 0x000f_ffff_ffff_ffff;
/// Minimum representable positive value (min subnormal)
const TINY_BITS: u64 = 0x1;
@@ -729,9 +784,9 @@ pub const fn classify(self) -> FpCategory {
// of our tests is able to find any difference between the complicated and the naive
// version, so now we are back to the naive version.
let b = self.to_bits();
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
(_, 0) => FpCategory::Subnormal,
_ => FpCategory::Normal,
+6 -6
View File
@@ -204,8 +204,8 @@ impl Float for f16 {
const BITS: u32 = 16;
const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS;
const EXP_MASK: Self::Int = Self::EXP_MASK;
const SIG_MASK: Self::Int = Self::MAN_MASK;
const EXP_MASK: Self::Int = Self::EXPONENT_MASK;
const SIG_MASK: Self::Int = Self::MANTISSA_MASK;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -22;
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 5;
@@ -238,8 +238,8 @@ impl Float for f32 {
const BITS: u32 = 32;
const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS;
const EXP_MASK: Self::Int = Self::EXP_MASK;
const SIG_MASK: Self::Int = Self::MAN_MASK;
const EXP_MASK: Self::Int = Self::EXPONENT_MASK;
const SIG_MASK: Self::Int = Self::MANTISSA_MASK;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17;
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10;
@@ -271,8 +271,8 @@ impl Float for f64 {
const BITS: u32 = 64;
const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS;
const EXP_MASK: Self::Int = Self::EXP_MASK;
const SIG_MASK: Self::Int = Self::MAN_MASK;
const EXP_MASK: Self::Int = Self::EXPONENT_MASK;
const SIG_MASK: Self::Int = Self::MANTISSA_MASK;
const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4;
const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23;