1
1
use core:: { fmt, mem, ops} ;
2
2
3
- use super :: int_traits:: { CastInto , Int , MinInt } ;
3
+ use super :: int_traits:: { CastFrom , CastInto , Int , MinInt } ;
4
4
5
5
/// Trait for some basic operations on floats
6
6
#[ allow( dead_code) ]
@@ -73,11 +73,18 @@ pub trait Float:
73
73
self . to_bits ( ) . signed ( )
74
74
}
75
75
76
+ /// Check bitwise equality.
77
+ fn biteq ( self , rhs : Self ) -> bool {
78
+ self . to_bits ( ) == rhs. to_bits ( )
79
+ }
80
+
76
81
/// 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.
79
86
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) }
81
88
}
82
89
83
90
/// Returns true if the value is NaN.
@@ -94,17 +101,22 @@ pub trait Float:
94
101
( self . to_bits ( ) & Self :: EXP_MASK ) == Self :: Int :: ZERO
95
102
}
96
103
97
- /// Returns the exponent, not adjusting for bias.
104
+ /// Returns the exponent, not adjusting for bias, not accounting for subnormals or zero .
98
105
fn exp ( self ) -> i32 {
99
106
( ( self . to_bits ( ) & Self :: EXP_MASK ) >> Self :: SIG_BITS ) . cast ( )
100
107
}
101
108
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
+
102
114
/// Returns the significand with no implicit bit (or the "fractional" part)
103
115
fn frac ( self ) -> Self :: Int {
104
116
self . to_bits ( ) & Self :: SIG_MASK
105
117
}
106
118
107
- /// Returns the significand with implicit bit
119
+ /// Returns the significand with implicit bit.
108
120
fn imp_frac ( self ) -> Self :: Int {
109
121
self . frac ( ) | Self :: IMPLICIT_BIT
110
122
}
@@ -113,11 +125,11 @@ pub trait Float:
113
125
fn from_bits ( a : Self :: Int ) -> Self ;
114
126
115
127
/// 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 {
117
129
let sign = if negative { Self :: Int :: ONE } else { Self :: Int :: ZERO } ;
118
130
Self :: from_bits (
119
131
( 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 )
121
133
| ( significand & Self :: SIG_MASK ) ,
122
134
)
123
135
}
@@ -239,3 +251,100 @@ pub const fn f64_from_bits(bits: u64) -> f64 {
239
251
// SAFETY: POD cast with no preconditions
240
252
unsafe { mem:: transmute :: < u64 , f64 > ( bits) }
241
253
}
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