Skip to content

Commit 863518e

Browse files
authored
Unrolled build for #154372
Rollup merge of #154372 - Apersoma:float_masks, r=tgross35 Exposing Float Masks Tracking issue: #154064 ACP: rust-lang/libs-team#753
2 parents 0a4ee3f + d5b941d commit 863518e

5 files changed

Lines changed: 282 additions & 42 deletions

File tree

library/core/src/num/f128.rs

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -339,14 +339,78 @@ impl f128 {
339339
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
340340
pub const MIN_EXACT_INTEGER: i128 = -Self::MAX_EXACT_INTEGER;
341341

342-
/// Sign bit
343-
pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
342+
/// The mask of the bit used to encode the sign of an [`f128`].
343+
///
344+
/// This bit is set when the sign is negative and unset when the sign is
345+
/// positive.
346+
/// If you only need to check whether a value is positive or negative,
347+
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
348+
///
349+
/// [`is_sign_positive`]: f128::is_sign_positive
350+
/// [`is_sign_negative`]: f128::is_sign_negative
351+
/// ```rust
352+
/// #![feature(float_masks)]
353+
/// #![feature(f128)]
354+
/// # #[cfg(target_has_reliable_f128)] {
355+
/// let sign_mask = f128::SIGN_MASK;
356+
/// let a = 1.6552f128;
357+
/// let a_bits = a.to_bits();
358+
///
359+
/// assert_eq!(a_bits & sign_mask, 0x0);
360+
/// assert_eq!(f128::from_bits(a_bits ^ sign_mask), -a);
361+
/// assert_eq!(sign_mask, (-0.0f128).to_bits());
362+
/// # }
363+
/// ```
364+
#[unstable(feature = "float_masks", issue = "154064")]
365+
pub const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
344366

345-
/// Exponent mask
346-
pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
367+
/// The mask of the bits used to encode the exponent of an [`f128`].
368+
///
369+
/// Note that the exponent is stored as a biased value, with a bias of 16383 for `f128`.
370+
///
371+
/// ```rust
372+
/// #![feature(float_masks)]
373+
/// #![feature(f128)]
374+
/// # #[cfg(target_has_reliable_f128)] {
375+
/// fn get_exp(a: f128) -> i128 {
376+
/// let bias = 16383;
377+
/// let biased = a.to_bits() & f128::EXPONENT_MASK;
378+
/// (biased >> (f128::MANTISSA_DIGITS - 1)).cast_signed() - bias
379+
/// }
380+
///
381+
/// assert_eq!(get_exp(0.5), -1);
382+
/// assert_eq!(get_exp(1.0), 0);
383+
/// assert_eq!(get_exp(2.0), 1);
384+
/// assert_eq!(get_exp(4.0), 2);
385+
/// # }
386+
/// ```
387+
#[unstable(feature = "float_masks", issue = "154064")]
388+
pub const EXPONENT_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
347389

348-
/// Mantissa mask
349-
pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
390+
/// The mask of the bits used to encode the mantissa of an [`f128`].
391+
///
392+
/// ```rust
393+
/// #![feature(float_masks)]
394+
/// #![feature(f128)]
395+
/// # #[cfg(target_has_reliable_f128)] {
396+
/// let mantissa_mask = f128::MANTISSA_MASK;
397+
///
398+
/// assert_eq!(0f128.to_bits() & mantissa_mask, 0x0);
399+
/// assert_eq!(1f128.to_bits() & mantissa_mask, 0x0);
400+
///
401+
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
402+
/// // unless the result or initial value is not normal.
403+
/// let a = 1.6552f128;
404+
/// let b = 4.0 * a;
405+
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
406+
///
407+
/// // The maximum and minimum values have a saturated significand
408+
/// assert_eq!(f128::MAX.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK);
409+
/// assert_eq!(f128::MIN.to_bits() & f128::MANTISSA_MASK, f128::MANTISSA_MASK);
410+
/// # }
411+
/// ```
412+
#[unstable(feature = "float_masks", issue = "154064")]
413+
pub const MANTISSA_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
350414

351415
/// Minimum representable positive value (min subnormal)
352416
const TINY_BITS: u128 = 0x1;
@@ -511,9 +575,9 @@ impl f128 {
511575
#[must_use]
512576
pub const fn classify(self) -> FpCategory {
513577
let bits = self.to_bits();
514-
match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
515-
(0, Self::EXP_MASK) => FpCategory::Infinite,
516-
(_, Self::EXP_MASK) => FpCategory::Nan,
578+
match (bits & Self::MANTISSA_MASK, bits & Self::EXPONENT_MASK) {
579+
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
580+
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
517581
(0, 0) => FpCategory::Zero,
518582
(_, 0) => FpCategory::Subnormal,
519583
_ => FpCategory::Normal,

library/core/src/num/f16.rs

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -333,14 +333,80 @@ impl f16 {
333333
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
334334
pub const MIN_EXACT_INTEGER: i16 = -Self::MAX_EXACT_INTEGER;
335335

336-
/// Sign bit
337-
pub(crate) const SIGN_MASK: u16 = 0x8000;
336+
/// The mask of the bit used to encode the sign of an [`f16`].
337+
///
338+
/// This bit is set when the sign is negative and unset when the sign is
339+
/// positive.
340+
/// If you only need to check whether a value is positive or negative,
341+
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
342+
///
343+
/// [`is_sign_positive`]: f16::is_sign_positive
344+
/// [`is_sign_negative`]: f16::is_sign_negative
345+
/// ```rust
346+
/// #![feature(float_masks)]
347+
/// #![feature(f16)]
348+
/// # #[cfg(target_has_reliable_f16)] {
349+
/// let sign_mask = f16::SIGN_MASK;
350+
/// let a = 1.6552f16;
351+
/// let a_bits = a.to_bits();
352+
///
353+
/// assert_eq!(a_bits & sign_mask, 0x0);
354+
/// assert_eq!(f16::from_bits(a_bits ^ sign_mask), -a);
355+
/// assert_eq!(sign_mask, (-0.0f16).to_bits());
356+
/// # }
357+
/// ```
358+
#[unstable(feature = "float_masks", issue = "154064")]
359+
pub const SIGN_MASK: u16 = 0x8000;
338360

339-
/// Exponent mask
340-
pub(crate) const EXP_MASK: u16 = 0x7c00;
361+
/// The mask of the bits used to encode the exponent of an [`f16`].
362+
///
363+
/// Note that the exponent is stored as a biased value, with a bias of 15 for `f16`.
364+
///
365+
/// ```rust
366+
/// #![feature(float_masks)]
367+
/// #![feature(f16)]
368+
/// # #[cfg(target_has_reliable_f16)] {
369+
/// let exponent_mask = f16::EXPONENT_MASK;
370+
///
371+
/// fn get_exp(a: f16) -> i16 {
372+
/// let bias = 15;
373+
/// let biased = a.to_bits() & f16::EXPONENT_MASK;
374+
/// (biased >> (f16::MANTISSA_DIGITS - 1)).cast_signed() - bias
375+
/// }
376+
///
377+
/// assert_eq!(get_exp(0.5), -1);
378+
/// assert_eq!(get_exp(1.0), 0);
379+
/// assert_eq!(get_exp(2.0), 1);
380+
/// assert_eq!(get_exp(4.0), 2);
381+
/// # }
382+
/// ```
383+
#[unstable(feature = "float_masks", issue = "154064")]
384+
pub const EXPONENT_MASK: u16 = 0x7c00;
341385

342-
/// Mantissa mask
343-
pub(crate) const MAN_MASK: u16 = 0x03ff;
386+
/// The mask of the bits used to encode the mantissa of an [`f16`].
387+
///
388+
/// ```rust
389+
/// #![feature(float_masks)]
390+
/// #![feature(f16)]
391+
/// # #[cfg(target_has_reliable_f16)] {
392+
/// let mantissa_mask = f16::MANTISSA_MASK;
393+
///
394+
/// assert_eq!(0f16.to_bits() & mantissa_mask, 0x0);
395+
/// assert_eq!(1f16.to_bits() & mantissa_mask, 0x0);
396+
///
397+
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
398+
/// // unless the result or initial value is not normal.
399+
/// let a = 1.6552f16;
400+
/// let b = 4.0 * a;
401+
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
402+
///
403+
/// // The maximum and minimum values have a saturated significand
404+
/// assert_eq!(f16::MAX.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK);
405+
/// assert_eq!(f16::MIN.to_bits() & f16::MANTISSA_MASK, f16::MANTISSA_MASK);
406+
/// # }
407+
/// ```
408+
#[unstable(feature = "float_masks", issue = "154064")]
409+
pub const MANTISSA_MASK: u16 = 0x03ff;
344410

345411
/// Minimum representable positive value (min subnormal)
346412
const TINY_BITS: u16 = 0x1;
@@ -503,9 +569,9 @@ impl f16 {
503569
#[must_use]
504570
pub const fn classify(self) -> FpCategory {
505571
let b = self.to_bits();
506-
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
507-
(0, Self::EXP_MASK) => FpCategory::Infinite,
508-
(_, Self::EXP_MASK) => FpCategory::Nan,
572+
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
573+
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
574+
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
509575
(0, 0) => FpCategory::Zero,
510576
(_, 0) => FpCategory::Subnormal,
511577
_ => FpCategory::Normal,

library/core/src/num/f32.rs

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -572,14 +572,69 @@ impl f32 {
572572
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
573573
pub const MIN_EXACT_INTEGER: i32 = -Self::MAX_EXACT_INTEGER;
574574

575-
/// Sign bit
576-
pub(crate) const SIGN_MASK: u32 = 0x8000_0000;
575+
/// The mask of the bit used to encode the sign of an [`f32`].
576+
///
577+
/// This bit is set when the sign is negative and unset when the sign is
578+
/// positive.
579+
/// If you only need to check whether a value is positive or negative,
580+
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
581+
///
582+
/// [`is_sign_positive`]: f32::is_sign_positive
583+
/// [`is_sign_negative`]: f32::is_sign_negative
584+
/// ```rust
585+
/// #![feature(float_masks)]
586+
/// let sign_mask = f32::SIGN_MASK;
587+
/// let a = 1.6552f32;
588+
/// let a_bits = a.to_bits();
589+
///
590+
/// assert_eq!(a_bits & sign_mask, 0x0);
591+
/// assert_eq!(f32::from_bits(a_bits ^ sign_mask), -a);
592+
/// assert_eq!(sign_mask, (-0.0f32).to_bits());
593+
/// ```
594+
#[unstable(feature = "float_masks", issue = "154064")]
595+
pub const SIGN_MASK: u32 = 0x8000_0000;
577596

578-
/// Exponent mask
579-
pub(crate) const EXP_MASK: u32 = 0x7f80_0000;
597+
/// The mask of the bits used to encode the exponent of an [`f32`].
598+
///
599+
/// Note that the exponent is stored as a biased value, with a bias of 127 for `f32`.
600+
///
601+
/// ```rust
602+
/// #![feature(float_masks)]
603+
/// fn get_exp(a: f32) -> i32 {
604+
/// let bias = 127;
605+
/// let biased = a.to_bits() & f32::EXPONENT_MASK;
606+
/// (biased >> (f32::MANTISSA_DIGITS - 1)).cast_signed() - bias
607+
/// }
608+
///
609+
/// assert_eq!(get_exp(0.5), -1);
610+
/// assert_eq!(get_exp(1.0), 0);
611+
/// assert_eq!(get_exp(2.0), 1);
612+
/// assert_eq!(get_exp(4.0), 2);
613+
/// ```
614+
#[unstable(feature = "float_masks", issue = "154064")]
615+
pub const EXPONENT_MASK: u32 = 0x7f80_0000;
580616

581-
/// Mantissa mask
582-
pub(crate) const MAN_MASK: u32 = 0x007f_ffff;
617+
/// The mask of the bits used to encode the mantissa of an [`f32`].
618+
///
619+
/// ```rust
620+
/// #![feature(float_masks)]
621+
/// let mantissa_mask = f32::MANTISSA_MASK;
622+
///
623+
/// assert_eq!(0f32.to_bits() & mantissa_mask, 0x0);
624+
/// assert_eq!(1f32.to_bits() & mantissa_mask, 0x0);
625+
///
626+
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
627+
/// // unless the result or initial value is not normal.
628+
/// let a = 1.6552f32;
629+
/// let b = 4.0 * a;
630+
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
631+
///
632+
/// // The maximum and minimum values have a saturated significand
633+
/// assert_eq!(f32::MAX.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK);
634+
/// assert_eq!(f32::MIN.to_bits() & f32::MANTISSA_MASK, f32::MANTISSA_MASK);
635+
/// ```
636+
#[unstable(feature = "float_masks", issue = "154064")]
637+
pub const MANTISSA_MASK: u32 = 0x007f_ffff;
583638

584639
/// Minimum representable positive value (min subnormal)
585640
const TINY_BITS: u32 = 0x1;
@@ -731,9 +786,9 @@ impl f32 {
731786
// of our tests is able to find any difference between the complicated and the naive
732787
// version, so now we are back to the naive version.
733788
let b = self.to_bits();
734-
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
735-
(0, Self::EXP_MASK) => FpCategory::Infinite,
736-
(_, Self::EXP_MASK) => FpCategory::Nan,
789+
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
790+
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
791+
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
737792
(0, 0) => FpCategory::Zero,
738793
(_, 0) => FpCategory::Subnormal,
739794
_ => FpCategory::Normal,

library/core/src/num/f64.rs

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -571,14 +571,69 @@ impl f64 {
571571
#[unstable(feature = "float_exact_integer_constants", issue = "152466")]
572572
pub const MIN_EXACT_INTEGER: i64 = -Self::MAX_EXACT_INTEGER;
573573

574-
/// Sign bit
575-
pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
574+
/// The mask of the bit used to encode the sign of an [`f64`].
575+
///
576+
/// This bit is set when the sign is negative and unset when the sign is
577+
/// positive.
578+
/// If you only need to check whether a value is positive or negative,
579+
/// [`is_sign_positive`] or [`is_sign_negative`] can be used.
580+
///
581+
/// [`is_sign_positive`]: f64::is_sign_positive
582+
/// [`is_sign_negative`]: f64::is_sign_negative
583+
/// ```rust
584+
/// #![feature(float_masks)]
585+
/// let sign_mask = f64::SIGN_MASK;
586+
/// let a = 1.6552f64;
587+
/// let a_bits = a.to_bits();
588+
///
589+
/// assert_eq!(a_bits & sign_mask, 0x0);
590+
/// assert_eq!(f64::from_bits(a_bits ^ sign_mask), -a);
591+
/// assert_eq!(sign_mask, (-0.0f64).to_bits());
592+
/// ```
593+
#[unstable(feature = "float_masks", issue = "154064")]
594+
pub const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
576595

577-
/// Exponent mask
578-
pub(crate) const EXP_MASK: u64 = 0x7ff0_0000_0000_0000;
596+
/// The mask of the bits used to encode the exponent of an [`f64`].
597+
///
598+
/// Note that the exponent is stored as a biased value, with a bias of 1024 for `f64`.
599+
///
600+
/// ```rust
601+
/// #![feature(float_masks)]
602+
/// fn get_exp(a: f64) -> i64 {
603+
/// let bias = 1023;
604+
/// let biased = a.to_bits() & f64::EXPONENT_MASK;
605+
/// (biased >> (f64::MANTISSA_DIGITS - 1)).cast_signed() - bias
606+
/// }
607+
///
608+
/// assert_eq!(get_exp(0.5), -1);
609+
/// assert_eq!(get_exp(1.0), 0);
610+
/// assert_eq!(get_exp(2.0), 1);
611+
/// assert_eq!(get_exp(4.0), 2);
612+
/// ```
613+
#[unstable(feature = "float_masks", issue = "154064")]
614+
pub const EXPONENT_MASK: u64 = 0x7ff0_0000_0000_0000;
579615

580-
/// Mantissa mask
581-
pub(crate) const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff;
616+
/// The mask of the bits used to encode the mantissa of an [`f64`].
617+
///
618+
/// ```rust
619+
/// #![feature(float_masks)]
620+
/// let mantissa_mask = f64::MANTISSA_MASK;
621+
///
622+
/// assert_eq!(0f64.to_bits() & mantissa_mask, 0x0);
623+
/// assert_eq!(1f64.to_bits() & mantissa_mask, 0x0);
624+
///
625+
/// // multiplying a finite value by a power of 2 doesn't change its mantissa
626+
/// // unless the result or initial value is not normal.
627+
/// let a = 1.6552f64;
628+
/// let b = 4.0 * a;
629+
/// assert_eq!(a.to_bits() & mantissa_mask, b.to_bits() & mantissa_mask);
630+
///
631+
/// // The maximum and minimum values have a saturated significand
632+
/// assert_eq!(f64::MAX.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK);
633+
/// assert_eq!(f64::MIN.to_bits() & f64::MANTISSA_MASK, f64::MANTISSA_MASK);
634+
/// ```
635+
#[unstable(feature = "float_masks", issue = "154064")]
636+
pub const MANTISSA_MASK: u64 = 0x000f_ffff_ffff_ffff;
582637

583638
/// Minimum representable positive value (min subnormal)
584639
const TINY_BITS: u64 = 0x1;
@@ -730,9 +785,9 @@ impl f64 {
730785
// of our tests is able to find any difference between the complicated and the naive
731786
// version, so now we are back to the naive version.
732787
let b = self.to_bits();
733-
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
734-
(0, Self::EXP_MASK) => FpCategory::Infinite,
735-
(_, Self::EXP_MASK) => FpCategory::Nan,
788+
match (b & Self::MANTISSA_MASK, b & Self::EXPONENT_MASK) {
789+
(0, Self::EXPONENT_MASK) => FpCategory::Infinite,
790+
(_, Self::EXPONENT_MASK) => FpCategory::Nan,
736791
(0, 0) => FpCategory::Zero,
737792
(_, 0) => FpCategory::Subnormal,
738793
_ => FpCategory::Normal,

0 commit comments

Comments
 (0)