@@ -2210,6 +2210,74 @@ float_const_impl! {
2210
2210
SQRT_2 ,
2211
2211
}
2212
2212
2213
+ /// Trait for floating point numbers that provide an implementation
2214
+ /// of the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
2215
+ /// floating point standard.
2216
+ pub trait TotalOrder {
2217
+ /// Return the ordering between `self` and `other`.
2218
+ ///
2219
+ /// Unlike the standard partial comparison between floating point numbers,
2220
+ /// this comparison always produces an ordering in accordance to
2221
+ /// the `totalOrder` predicate as defined in the IEEE 754 (2008 revision)
2222
+ /// floating point standard. The values are ordered in the following sequence:
2223
+ ///
2224
+ /// - negative quiet NaN
2225
+ /// - negative signaling NaN
2226
+ /// - negative infinity
2227
+ /// - negative numbers
2228
+ /// - negative subnormal numbers
2229
+ /// - negative zero
2230
+ /// - positive zero
2231
+ /// - positive subnormal numbers
2232
+ /// - positive numbers
2233
+ /// - positive infinity
2234
+ /// - positive signaling NaN
2235
+ /// - positive quiet NaN.
2236
+ ///
2237
+ /// The ordering established by this function does not always agree with the
2238
+ /// [`PartialOrd`] and [`PartialEq`] implementations. For example,
2239
+ /// they consider negative and positive zero equal, while `total_cmp`
2240
+ /// doesn't.
2241
+ ///
2242
+ /// The interpretation of the signaling NaN bit follows the definition in
2243
+ /// the IEEE 754 standard, which may not match the interpretation by some of
2244
+ /// the older, non-conformant (e.g. MIPS) hardware implementations.
2245
+ ///
2246
+ /// # Examples
2247
+ /// ```
2248
+ /// use num_traits::float::TotalOrder;
2249
+ /// use std::{f32, f64};
2250
+ ///
2251
+ /// fn check_eq<T: TotalOrder>(x: T, y: T) {
2252
+ /// assert_eq!(x.total_cmp(&y), std::cmp::Ordering::Equal);
2253
+ /// }
2254
+ ///
2255
+ /// check_eq(f64::NAN, f64::NAN);
2256
+ /// check_eq(f32::NAN, f32::NAN);
2257
+ ///
2258
+ /// fn check_lt<T: TotalOrder>(x: T, y: T) {
2259
+ /// assert_eq!(x.total_cmp(&y), std::cmp::Ordering::Less);
2260
+ /// }
2261
+ ///
2262
+ /// check_lt(-f64::NAN, f64::NAN);
2263
+ /// check_lt(f64::INFINITY, f64::NAN);
2264
+ /// check_lt(-0.0_f64, 0.0_f64);
2265
+ /// ```
2266
+ fn total_cmp ( & self , other : & Self ) -> std:: cmp:: Ordering ;
2267
+ }
2268
+ macro_rules! totalorder_impl {
2269
+ ( $T: ident) => {
2270
+ impl TotalOrder for $T {
2271
+ #[ inline]
2272
+ fn total_cmp( & self , other: & Self ) -> std:: cmp:: Ordering {
2273
+ Self :: total_cmp( & self , other)
2274
+ }
2275
+ }
2276
+ } ;
2277
+ }
2278
+ totalorder_impl ! ( f64 ) ;
2279
+ totalorder_impl ! ( f32 ) ;
2280
+
2213
2281
#[ cfg( test) ]
2214
2282
mod tests {
2215
2283
use core:: f64:: consts;
@@ -2341,4 +2409,50 @@ mod tests {
2341
2409
test_subnormal :: < f64 > ( ) ;
2342
2410
test_subnormal :: < f32 > ( ) ;
2343
2411
}
2412
+
2413
+ #[ test]
2414
+ fn total_cmp ( ) {
2415
+ use crate :: float:: { Float , TotalOrder } ;
2416
+ fn check_eq < T : Float + TotalOrder > ( x : T , y : T ) {
2417
+ assert_eq ! ( x. total_cmp( & y) , std:: cmp:: Ordering :: Equal ) ;
2418
+ }
2419
+ fn check_lt < T : Float + TotalOrder > ( x : T , y : T ) {
2420
+ assert_eq ! ( x. total_cmp( & y) , std:: cmp:: Ordering :: Less ) ;
2421
+ }
2422
+ fn check_gt < T : Float + TotalOrder > ( x : T , y : T ) {
2423
+ assert_eq ! ( x. total_cmp( & y) , std:: cmp:: Ordering :: Greater ) ;
2424
+ }
2425
+
2426
+ check_eq ( f64:: NAN , f64:: NAN ) ;
2427
+ check_eq ( f32:: NAN , f32:: NAN ) ;
2428
+
2429
+ check_lt ( -0.0_f64 , 0.0_f64 ) ;
2430
+ check_lt ( -0.0_f32 , 0.0_f32 ) ;
2431
+
2432
+ let s_nan = unsafe { std:: mem:: transmute :: < u64 , f64 > ( 0x7ff4000000000000 ) } ;
2433
+ let q_nan = unsafe { std:: mem:: transmute :: < u64 , f64 > ( 0x7ff8000000000000 ) } ;
2434
+ check_lt ( s_nan, q_nan) ;
2435
+
2436
+ let neg_s_nan = unsafe { std:: mem:: transmute :: < u64 , f64 > ( 0xfff4000000000000 ) } ;
2437
+ let neg_q_nan = unsafe { std:: mem:: transmute :: < u64 , f64 > ( 0xfff8000000000000 ) } ;
2438
+ check_lt ( neg_q_nan, neg_s_nan) ;
2439
+
2440
+ let s_nan = unsafe { std:: mem:: transmute :: < u32 , f32 > ( 0x7fa00000 ) } ;
2441
+ let q_nan = unsafe { std:: mem:: transmute :: < u32 , f32 > ( 0x7fc00000 ) } ;
2442
+ check_lt ( s_nan, q_nan) ;
2443
+
2444
+ let neg_s_nan = unsafe { std:: mem:: transmute :: < u32 , f32 > ( 0xffa00000 ) } ;
2445
+ let neg_q_nan = unsafe { std:: mem:: transmute :: < u32 , f32 > ( 0xffc00000 ) } ;
2446
+ check_lt ( neg_q_nan, neg_s_nan) ;
2447
+
2448
+ check_lt ( -f64:: NAN , f64:: NEG_INFINITY ) ;
2449
+ check_gt ( 1.0_f64 , -f64:: NAN ) ;
2450
+ check_lt ( f64:: INFINITY , f64:: NAN ) ;
2451
+ check_gt ( f64:: NAN , 1.0_f64 ) ;
2452
+
2453
+ check_lt ( -f32:: NAN , f32:: NEG_INFINITY ) ;
2454
+ check_gt ( 1.0_f32 , -f32:: NAN ) ;
2455
+ check_lt ( f32:: INFINITY , f32:: NAN ) ;
2456
+ check_gt ( f32:: NAN , 1.0_f32 ) ;
2457
+ }
2344
2458
}
0 commit comments