@@ -489,6 +489,21 @@ impl f64 {
489489 #[ stable( feature = "assoc_int_consts" , since = "1.43.0" ) ]
490490 pub const NEG_INFINITY : f64 = -1.0_f64 / 0.0_f64 ;
491491
492+ /// Sign bit
493+ const SIGN_MASK : u64 = 0x8000_0000_0000_0000 ;
494+
495+ /// Exponent mask
496+ const EXP_MASK : u64 = 0x7ff0_0000_0000_0000 ;
497+
498+ /// Mantissa mask
499+ const MAN_MASK : u64 = 0x000f_ffff_ffff_ffff ;
500+
501+ /// Minimum representable positive value (min subnormal)
502+ const TINY_BITS : u64 = 0x1 ;
503+
504+ /// Minimum representable negative value (min negative subnormal)
505+ const NEG_TINY_BITS : u64 = Self :: TINY_BITS | Self :: SIGN_MASK ;
506+
492507 /// Returns `true` if this value is NaN.
493508 ///
494509 /// ```
@@ -514,9 +529,7 @@ impl f64 {
514529 #[ rustc_const_unstable( feature = "const_float_classify" , issue = "72505" ) ]
515530 pub ( crate ) const fn abs_private ( self ) -> f64 {
516531 // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
517- unsafe {
518- mem:: transmute :: < u64 , f64 > ( mem:: transmute :: < f64 , u64 > ( self ) & 0x7fff_ffff_ffff_ffff )
519- }
532+ unsafe { mem:: transmute :: < u64 , f64 > ( mem:: transmute :: < f64 , u64 > ( self ) & !Self :: SIGN_MASK ) }
520533 }
521534
522535 /// Returns `true` if this value is positive infinity or negative infinity, and
@@ -673,13 +686,10 @@ impl f64 {
673686 // and some normal floating point numbers truncated from an x87 FPU.
674687 #[ rustc_const_unstable( feature = "const_float_classify" , issue = "72505" ) ]
675688 const unsafe fn partial_classify ( self ) -> FpCategory {
676- const EXP_MASK : u64 = 0x7ff0000000000000 ;
677- const MAN_MASK : u64 = 0x000fffffffffffff ;
678-
679689 // SAFETY: The caller is not asking questions for which this will tell lies.
680690 let b = unsafe { mem:: transmute :: < f64 , u64 > ( self ) } ;
681- match ( b & MAN_MASK , b & EXP_MASK ) {
682- ( 0 , EXP_MASK ) => FpCategory :: Infinite ,
691+ match ( b & Self :: MAN_MASK , b & Self :: EXP_MASK ) {
692+ ( 0 , Self :: EXP_MASK ) => FpCategory :: Infinite ,
683693 ( 0 , 0 ) => FpCategory :: Zero ,
684694 ( _, 0 ) => FpCategory :: Subnormal ,
685695 _ => FpCategory :: Normal ,
@@ -691,12 +701,9 @@ impl f64 {
691701 // plus a transmute. We do not live in a just world, but we can make it more so.
692702 #[ rustc_const_unstable( feature = "const_float_classify" , issue = "72505" ) ]
693703 const fn classify_bits ( b : u64 ) -> FpCategory {
694- const EXP_MASK : u64 = 0x7ff0000000000000 ;
695- const MAN_MASK : u64 = 0x000fffffffffffff ;
696-
697- match ( b & MAN_MASK , b & EXP_MASK ) {
698- ( 0 , EXP_MASK ) => FpCategory :: Infinite ,
699- ( _, EXP_MASK ) => FpCategory :: Nan ,
704+ match ( b & Self :: MAN_MASK , b & Self :: EXP_MASK ) {
705+ ( 0 , Self :: EXP_MASK ) => FpCategory :: Infinite ,
706+ ( _, Self :: EXP_MASK ) => FpCategory :: Nan ,
700707 ( 0 , 0 ) => FpCategory :: Zero ,
701708 ( _, 0 ) => FpCategory :: Subnormal ,
702709 _ => FpCategory :: Normal ,
@@ -756,7 +763,7 @@ impl f64 {
756763 // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
757764 // applies to zeros and NaNs as well.
758765 // SAFETY: This is just transmuting to get the sign bit, it's fine.
759- unsafe { mem:: transmute :: < f64 , u64 > ( self ) & 0x8000_0000_0000_0000 != 0 }
766+ unsafe { mem:: transmute :: < f64 , u64 > ( self ) & Self :: SIGN_MASK != 0 }
760767 }
761768
762769 #[ must_use]
@@ -797,19 +804,17 @@ impl f64 {
797804 #[ unstable( feature = "float_next_up_down" , issue = "91399" ) ]
798805 #[ rustc_const_unstable( feature = "float_next_up_down" , issue = "91399" ) ]
799806 pub const fn next_up ( self ) -> Self {
800- // We must use strictly integer arithmetic to prevent denormals from
801- // flushing to zero after an arithmetic operation on some platforms.
802- const TINY_BITS : u64 = 0x1 ; // Smallest positive f64.
803- const CLEAR_SIGN_MASK : u64 = 0x7fff_ffff_ffff_ffff ;
804-
807+ // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
808+ // denormals to zero. This is in general unsound and unsupported, but here
809+ // we do our best to still produce the correct result on such targets.
805810 let bits = self . to_bits ( ) ;
806811 if self . is_nan ( ) || bits == Self :: INFINITY . to_bits ( ) {
807812 return self ;
808813 }
809814
810- let abs = bits & CLEAR_SIGN_MASK ;
815+ let abs = bits & ! Self :: SIGN_MASK ;
811816 let next_bits = if abs == 0 {
812- TINY_BITS
817+ Self :: TINY_BITS
813818 } else if bits == abs {
814819 bits + 1
815820 } else {
@@ -847,19 +852,17 @@ impl f64 {
847852 #[ unstable( feature = "float_next_up_down" , issue = "91399" ) ]
848853 #[ rustc_const_unstable( feature = "float_next_up_down" , issue = "91399" ) ]
849854 pub const fn next_down ( self ) -> Self {
850- // We must use strictly integer arithmetic to prevent denormals from
851- // flushing to zero after an arithmetic operation on some platforms.
852- const NEG_TINY_BITS : u64 = 0x8000_0000_0000_0001 ; // Smallest (in magnitude) negative f64.
853- const CLEAR_SIGN_MASK : u64 = 0x7fff_ffff_ffff_ffff ;
854-
855+ // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing
856+ // denormals to zero. This is in general unsound and unsupported, but here
857+ // we do our best to still produce the correct result on such targets.
855858 let bits = self . to_bits ( ) ;
856859 if self . is_nan ( ) || bits == Self :: NEG_INFINITY . to_bits ( ) {
857860 return self ;
858861 }
859862
860- let abs = bits & CLEAR_SIGN_MASK ;
863+ let abs = bits & ! Self :: SIGN_MASK ;
861864 let next_bits = if abs == 0 {
862- NEG_TINY_BITS
865+ Self :: NEG_TINY_BITS
863866 } else if bits == abs {
864867 bits - 1
865868 } else {
0 commit comments