diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 68c87b48de94..24ed84dcb0dc 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -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, diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 3412e49c49cd..d0cc9580765c 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -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, diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index e33cb098e4e8..0a80e19f51a5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -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, diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 872f567efafd..4d57f1dab852 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -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, diff --git a/library/core/src/num/imp/traits.rs b/library/core/src/num/imp/traits.rs index 7b84f7a4a5aa..3a7ea23f73f3 100644 --- a/library/core/src/num/imp/traits.rs +++ b/library/core/src/num/imp/traits.rs @@ -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;