11use core:: { fmt, mem, ops} ;
22
3- use super :: int_traits:: { CastInto , Int , MinInt } ;
3+ use super :: int_traits:: { CastFrom , CastInto , Int , MinInt } ;
44
55/// Trait for some basic operations on floats
66#[ allow( dead_code) ]
@@ -73,11 +73,18 @@ pub trait Float:
7373 self . to_bits ( ) . signed ( )
7474 }
7575
76+ /// Check bitwise equality.
77+ fn biteq ( self , rhs : Self ) -> bool {
78+ self . to_bits ( ) == rhs. to_bits ( )
79+ }
80+
7681 /// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
77- /// represented in multiple different ways. This method returns `true` if two NaNs are
78- /// compared.
82+ /// represented in multiple different ways.
83+ ///
84+ /// This method returns `true` if two NaNs are compared. Use [`biteq`](Self::biteq) instead
85+ /// if `NaN` should not be treated separately.
7986 fn eq_repr ( self , rhs : Self ) -> bool {
80- if self . is_nan ( ) && rhs. is_nan ( ) { true } else { self . to_bits ( ) == rhs. to_bits ( ) }
87+ if self . is_nan ( ) && rhs. is_nan ( ) { true } else { self . biteq ( rhs) }
8188 }
8289
8390 /// Returns true if the value is NaN.
@@ -94,17 +101,22 @@ pub trait Float:
94101 ( self . to_bits ( ) & Self :: EXP_MASK ) == Self :: Int :: ZERO
95102 }
96103
97- /// Returns the exponent, not adjusting for bias.
104+ /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero .
98105 fn exp ( self ) -> i32 {
99106 ( ( self . to_bits ( ) & Self :: EXP_MASK ) >> Self :: SIG_BITS ) . cast ( )
100107 }
101108
109+ /// Extract the exponent and adjust it for bias, not accounting for subnormals or zero.
110+ fn exp_unbiased ( self ) -> i32 {
111+ self . exp ( ) - ( Self :: EXP_BIAS as i32 )
112+ }
113+
102114 /// Returns the significand with no implicit bit (or the "fractional" part)
103115 fn frac ( self ) -> Self :: Int {
104116 self . to_bits ( ) & Self :: SIG_MASK
105117 }
106118
107- /// Returns the significand with implicit bit
119+ /// Returns the significand with implicit bit.
108120 fn imp_frac ( self ) -> Self :: Int {
109121 self . frac ( ) | Self :: IMPLICIT_BIT
110122 }
@@ -113,11 +125,11 @@ pub trait Float:
113125 fn from_bits ( a : Self :: Int ) -> Self ;
114126
115127 /// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
116- fn from_parts ( negative : bool , exponent : Self :: Int , significand : Self :: Int ) -> Self {
128+ fn from_parts ( negative : bool , exponent : i32 , significand : Self :: Int ) -> Self {
117129 let sign = if negative { Self :: Int :: ONE } else { Self :: Int :: ZERO } ;
118130 Self :: from_bits (
119131 ( sign << ( Self :: BITS - 1 ) )
120- | ( ( exponent << Self :: SIG_BITS ) & Self :: EXP_MASK )
132+ | ( Self :: Int :: cast_from ( exponent as u32 & Self :: EXP_MAX ) << Self :: SIG_BITS )
121133 | ( significand & Self :: SIG_MASK ) ,
122134 )
123135 }
@@ -239,3 +251,100 @@ pub const fn f64_from_bits(bits: u64) -> f64 {
239251 // SAFETY: POD cast with no preconditions
240252 unsafe { mem:: transmute :: < u64 , f64 > ( bits) }
241253}
254+
255+ #[ cfg( test) ]
256+ mod tests {
257+ use super :: * ;
258+
259+ #[ test]
260+ #[ cfg( f16_enabled) ]
261+ fn check_f16 ( ) {
262+ // Constants
263+ assert_eq ! ( f16:: EXP_MAX , 0b11111 ) ;
264+ assert_eq ! ( f16:: EXP_BIAS , 15 ) ;
265+
266+ // `exp_unbiased`
267+ assert_eq ! ( f16:: FRAC_PI_2 . exp_unbiased( ) , 0 ) ;
268+ assert_eq ! ( ( 1.0f16 / 2.0 ) . exp_unbiased( ) , -1 ) ;
269+ assert_eq ! ( f16:: MAX . exp_unbiased( ) , 15 ) ;
270+ assert_eq ! ( f16:: MIN . exp_unbiased( ) , 15 ) ;
271+ assert_eq ! ( f16:: MIN_POSITIVE . exp_unbiased( ) , -14 ) ;
272+ // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
273+ // results for zero and subnormals.
274+ assert_eq ! ( f16:: ZERO . exp_unbiased( ) , -15 ) ;
275+ assert_eq ! ( f16:: from_bits( 0x1 ) . exp_unbiased( ) , -15 ) ;
276+
277+ // `from_parts`
278+ assert_biteq ! ( f16:: from_parts( true , f16:: EXP_BIAS as i32 , 0 ) , -1.0f16 ) ;
279+ assert_biteq ! ( f16:: from_parts( false , 0 , 1 ) , f16:: from_bits( 0x1 ) ) ;
280+ }
281+
282+ #[ test]
283+ fn check_f32 ( ) {
284+ // Constants
285+ assert_eq ! ( f32 :: EXP_MAX , 0b11111111 ) ;
286+ assert_eq ! ( f32 :: EXP_BIAS , 127 ) ;
287+
288+ // `exp_unbiased`
289+ assert_eq ! ( f32 :: FRAC_PI_2 . exp_unbiased( ) , 0 ) ;
290+ assert_eq ! ( ( 1.0f32 / 2.0 ) . exp_unbiased( ) , -1 ) ;
291+ assert_eq ! ( f32 :: MAX . exp_unbiased( ) , 127 ) ;
292+ assert_eq ! ( f32 :: MIN . exp_unbiased( ) , 127 ) ;
293+ assert_eq ! ( f32 :: MIN_POSITIVE . exp_unbiased( ) , -126 ) ;
294+ // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
295+ // results for zero and subnormals.
296+ assert_eq ! ( f32 :: ZERO . exp_unbiased( ) , -127 ) ;
297+ assert_eq ! ( f32 :: from_bits( 0x1 ) . exp_unbiased( ) , -127 ) ;
298+
299+ // `from_parts`
300+ assert_biteq ! ( f32 :: from_parts( true , f32 :: EXP_BIAS as i32 , 0 ) , -1.0f32 ) ;
301+ assert_biteq ! ( f32 :: from_parts( false , 10 + f32 :: EXP_BIAS as i32 , 0 ) , hf32!( "0x1p10" ) ) ;
302+ assert_biteq ! ( f32 :: from_parts( false , 0 , 1 ) , f32 :: from_bits( 0x1 ) ) ;
303+ }
304+
305+ #[ test]
306+ fn check_f64 ( ) {
307+ // Constants
308+ assert_eq ! ( f64 :: EXP_MAX , 0b11111111111 ) ;
309+ assert_eq ! ( f64 :: EXP_BIAS , 1023 ) ;
310+
311+ // `exp_unbiased`
312+ assert_eq ! ( f64 :: FRAC_PI_2 . exp_unbiased( ) , 0 ) ;
313+ assert_eq ! ( ( 1.0f64 / 2.0 ) . exp_unbiased( ) , -1 ) ;
314+ assert_eq ! ( f64 :: MAX . exp_unbiased( ) , 1023 ) ;
315+ assert_eq ! ( f64 :: MIN . exp_unbiased( ) , 1023 ) ;
316+ assert_eq ! ( f64 :: MIN_POSITIVE . exp_unbiased( ) , -1022 ) ;
317+ // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
318+ // results for zero and subnormals.
319+ assert_eq ! ( f64 :: ZERO . exp_unbiased( ) , -1023 ) ;
320+ assert_eq ! ( f64 :: from_bits( 0x1 ) . exp_unbiased( ) , -1023 ) ;
321+
322+ // `from_parts`
323+ assert_biteq ! ( f64 :: from_parts( true , f64 :: EXP_BIAS as i32 , 0 ) , -1.0f64 ) ;
324+ assert_biteq ! ( f64 :: from_parts( false , 10 + f64 :: EXP_BIAS as i32 , 0 ) , hf64!( "0x1p10" ) ) ;
325+ assert_biteq ! ( f64 :: from_parts( false , 0 , 1 ) , f64 :: from_bits( 0x1 ) ) ;
326+ }
327+
328+ #[ test]
329+ #[ cfg( f128_enabled) ]
330+ fn check_f128 ( ) {
331+ // Constants
332+ assert_eq ! ( f128:: EXP_MAX , 0b111111111111111 ) ;
333+ assert_eq ! ( f128:: EXP_BIAS , 16383 ) ;
334+
335+ // `exp_unbiased`
336+ assert_eq ! ( f128:: FRAC_PI_2 . exp_unbiased( ) , 0 ) ;
337+ assert_eq ! ( ( 1.0f128 / 2.0 ) . exp_unbiased( ) , -1 ) ;
338+ assert_eq ! ( f128:: MAX . exp_unbiased( ) , 16383 ) ;
339+ assert_eq ! ( f128:: MIN . exp_unbiased( ) , 16383 ) ;
340+ assert_eq ! ( f128:: MIN_POSITIVE . exp_unbiased( ) , -16382 ) ;
341+ // This is a convenience method and not ldexp, `exp_unbiased` does not return correct
342+ // results for zero and subnormals.
343+ assert_eq ! ( f128:: ZERO . exp_unbiased( ) , -16383 ) ;
344+ assert_eq ! ( f128:: from_bits( 0x1 ) . exp_unbiased( ) , -16383 ) ;
345+
346+ // `from_parts`
347+ assert_biteq ! ( f128:: from_parts( true , f128:: EXP_BIAS as i32 , 0 ) , -1.0f128 ) ;
348+ assert_biteq ! ( f128:: from_parts( false , 0 , 1 ) , f128:: from_bits( 0x1 ) ) ;
349+ }
350+ }
0 commit comments