@@ -401,6 +401,29 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
401
401
}
402
402
}
403
403
404
+ /// Rounds to the nearest integer, with ties biasing towards an even result.
405
+ ///
406
+ /// # Examples
407
+ ///
408
+ /// ```
409
+ /// use num_traits::float::FloatCore;
410
+ ///
411
+ /// fn check<T: FloatCore>(x: T, rounded: T) {
412
+ /// assert!(x.round_ties_even() == rounded);
413
+ /// }
414
+ ///
415
+ /// check(1.0f32, 1.0);
416
+ /// check(1.25f32, 1.0);
417
+ /// check(1.75f32, 2.0);
418
+ /// check(1.5f32, 2.0);
419
+ /// check(2.5f32, 2.0);
420
+ /// check(3.5f32, 4.0);
421
+ /// check(-3.5f32, -4.0);
422
+ /// ```
423
+ fn round_ties_even ( self ) -> Self {
424
+ round_ties_even_impl ! ( self )
425
+ }
426
+
404
427
/// Return the integer part of a number.
405
428
///
406
429
/// # Examples
@@ -844,6 +867,11 @@ impl FloatCore for f32 {
844
867
Self :: powi( self , n: i32 ) -> Self ;
845
868
}
846
869
870
+ #[ cfg( all( feature = "std" , has_round_ties_even) ) ]
871
+ forward ! {
872
+ Self :: round_ties_even( self ) -> Self ;
873
+ }
874
+
847
875
#[ cfg( all( not( feature = "std" ) , feature = "libm" ) ) ]
848
876
forward ! {
849
877
libm:: floorf as floor( self ) -> Self ;
@@ -906,6 +934,11 @@ impl FloatCore for f64 {
906
934
Self :: powi( self , n: i32 ) -> Self ;
907
935
}
908
936
937
+ #[ cfg( all( feature = "std" , has_round_ties_even) ) ]
938
+ forward ! {
939
+ Self :: round_ties_even( self ) -> Self ;
940
+ }
941
+
909
942
#[ cfg( all( not( feature = "std" ) , feature = "libm" ) ) ]
910
943
forward ! {
911
944
libm:: floor as floor( self ) -> Self ;
@@ -1195,6 +1228,29 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
1195
1228
/// ```
1196
1229
fn round ( self ) -> Self ;
1197
1230
1231
+ /// Rounds to the nearest integer, with ties biasing towards an even result.
1232
+ ///
1233
+ /// # Examples
1234
+ ///
1235
+ /// ```
1236
+ /// use num_traits::Float;
1237
+ ///
1238
+ /// fn check<T: Float>(x: T, rounded: T) {
1239
+ /// assert!(x.round_ties_even() == rounded);
1240
+ /// }
1241
+ ///
1242
+ /// check(1.0f32, 1.0);
1243
+ /// check(1.25f32, 1.0);
1244
+ /// check(1.75f32, 2.0);
1245
+ /// check(1.5f32, 2.0);
1246
+ /// check(2.5f32, 2.0);
1247
+ /// check(3.5f32, 4.0);
1248
+ /// check(-3.5f32, -4.0);
1249
+ /// ```
1250
+ fn round_ties_even ( self ) -> Self {
1251
+ round_ties_even_impl ! ( self )
1252
+ }
1253
+
1198
1254
/// Return the integer part of a number.
1199
1255
///
1200
1256
/// ```
@@ -1989,6 +2045,11 @@ macro_rules! float_impl_std {
1989
2045
Self :: atanh( self ) -> Self ;
1990
2046
Self :: copysign( self , sign: Self ) -> Self ;
1991
2047
}
2048
+
2049
+ #[ cfg( has_round_ties_even) ]
2050
+ forward! {
2051
+ Self :: round_ties_even( self ) -> Self ;
2052
+ }
1992
2053
}
1993
2054
} ;
1994
2055
}
@@ -2510,4 +2571,170 @@ mod tests {
2510
2571
check_lt ( f32:: INFINITY , f32:: NAN ) ;
2511
2572
check_gt ( f32:: NAN , 1.0_f32 ) ;
2512
2573
}
2574
+
2575
+ /// Compares the fallback implementation of [`round_ties_even`] to the one provided by `f32`.`
2576
+ ///
2577
+ /// [`round_ties_even`]: crate::float::FloatCore::round_ties_even
2578
+ #[ cfg( has_round_ties_even) ]
2579
+ #[ test]
2580
+ fn round_ties_even ( ) {
2581
+ mod wrapped_f32 {
2582
+ use crate :: { float:: FloatCore , Num , NumCast , One , ToPrimitive , Zero } ;
2583
+ use core:: ops:: { Add , Div , Mul , Neg , Rem , Sub } ;
2584
+
2585
+ #[ derive( Clone , Copy , PartialEq , PartialOrd , Debug ) ]
2586
+ pub struct WrappedF32 ( pub f32 ) ;
2587
+
2588
+ impl ToPrimitive for WrappedF32 {
2589
+ fn to_i64 ( & self ) -> Option < i64 > {
2590
+ f32:: to_i64 ( & self . 0 )
2591
+ }
2592
+
2593
+ fn to_u64 ( & self ) -> Option < u64 > {
2594
+ f32:: to_u64 ( & self . 0 )
2595
+ }
2596
+ }
2597
+
2598
+ impl NumCast for WrappedF32 {
2599
+ fn from < T : crate :: ToPrimitive > ( n : T ) -> Option < Self > {
2600
+ Some ( Self ( <f32 as NumCast >:: from ( n) ?) )
2601
+ }
2602
+ }
2603
+
2604
+ impl Neg for WrappedF32 {
2605
+ type Output = Self ;
2606
+
2607
+ fn neg ( self ) -> Self :: Output {
2608
+ Self ( self . 0 . neg ( ) )
2609
+ }
2610
+ }
2611
+
2612
+ impl Mul for WrappedF32 {
2613
+ type Output = Self ;
2614
+
2615
+ fn mul ( self , rhs : Self ) -> Self :: Output {
2616
+ Self ( f32:: mul ( self . 0 , rhs. 0 ) )
2617
+ }
2618
+ }
2619
+
2620
+ impl Add for WrappedF32 {
2621
+ type Output = Self ;
2622
+
2623
+ fn add ( self , rhs : Self ) -> Self :: Output {
2624
+ Self ( f32:: add ( self . 0 , rhs. 0 ) )
2625
+ }
2626
+ }
2627
+
2628
+ impl Rem for WrappedF32 {
2629
+ type Output = Self ;
2630
+
2631
+ fn rem ( self , rhs : Self ) -> Self :: Output {
2632
+ Self ( f32:: rem ( self . 0 , rhs. 0 ) )
2633
+ }
2634
+ }
2635
+
2636
+ impl Div for WrappedF32 {
2637
+ type Output = Self ;
2638
+
2639
+ fn div ( self , rhs : Self ) -> Self :: Output {
2640
+ Self ( f32:: div ( self . 0 , rhs. 0 ) )
2641
+ }
2642
+ }
2643
+
2644
+ impl Sub for WrappedF32 {
2645
+ type Output = Self ;
2646
+
2647
+ fn sub ( self , rhs : Self ) -> Self :: Output {
2648
+ Self ( f32:: sub ( self . 0 , rhs. 0 ) )
2649
+ }
2650
+ }
2651
+
2652
+ impl One for WrappedF32 {
2653
+ fn one ( ) -> Self {
2654
+ Self ( f32:: one ( ) )
2655
+ }
2656
+ }
2657
+
2658
+ impl Zero for WrappedF32 {
2659
+ fn zero ( ) -> Self {
2660
+ Self ( f32:: zero ( ) )
2661
+ }
2662
+
2663
+ fn is_zero ( & self ) -> bool {
2664
+ self . 0 . is_zero ( )
2665
+ }
2666
+ }
2667
+
2668
+ impl Num for WrappedF32 {
2669
+ type FromStrRadixErr = <f32 as Num >:: FromStrRadixErr ;
2670
+
2671
+ fn from_str_radix ( str : & str , radix : u32 ) -> Result < Self , Self :: FromStrRadixErr > {
2672
+ Ok ( Self ( f32:: from_str_radix ( str, radix) ?) )
2673
+ }
2674
+ }
2675
+
2676
+ impl FloatCore for WrappedF32 {
2677
+ fn infinity ( ) -> Self {
2678
+ Self ( f32:: infinity ( ) )
2679
+ }
2680
+
2681
+ fn neg_infinity ( ) -> Self {
2682
+ Self ( f32:: neg_infinity ( ) )
2683
+ }
2684
+
2685
+ fn nan ( ) -> Self {
2686
+ Self ( f32:: nan ( ) )
2687
+ }
2688
+
2689
+ fn neg_zero ( ) -> Self {
2690
+ Self ( f32:: neg_zero ( ) )
2691
+ }
2692
+
2693
+ fn min_value ( ) -> Self {
2694
+ Self ( f32:: min_value ( ) )
2695
+ }
2696
+
2697
+ fn min_positive_value ( ) -> Self {
2698
+ Self ( f32:: min_positive_value ( ) )
2699
+ }
2700
+
2701
+ fn epsilon ( ) -> Self {
2702
+ Self ( f32:: epsilon ( ) )
2703
+ }
2704
+
2705
+ fn max_value ( ) -> Self {
2706
+ Self ( f32:: max_value ( ) )
2707
+ }
2708
+
2709
+ fn classify ( self ) -> core:: num:: FpCategory {
2710
+ f32:: classify ( self . 0 )
2711
+ }
2712
+
2713
+ fn to_degrees ( self ) -> Self {
2714
+ Self ( f32:: to_degrees ( self . 0 ) )
2715
+ }
2716
+
2717
+ fn to_radians ( self ) -> Self {
2718
+ Self ( f32:: to_radians ( self . 0 ) )
2719
+ }
2720
+
2721
+ fn integer_decode ( self ) -> ( u64 , i16 , i8 ) {
2722
+ f32:: integer_decode ( self . 0 )
2723
+ }
2724
+ }
2725
+ }
2726
+
2727
+ use crate :: float:: FloatCore ;
2728
+ use wrapped_f32:: WrappedF32 ;
2729
+
2730
+ for x in [
2731
+ -5.0 , -4.5 , -4.0 , -3.5 , -3.0 , -2.5 , -2.0 , -1.5 , -1.0 , -0.5 , 0.0 , 0.5 , 1.0 , 1.5 , 2.0 ,
2732
+ 2.5 , 3.0 , 3.5 , 4.0 , 4.5 , 5.0 ,
2733
+ ] {
2734
+ for dx in -250_000 ..=250_000 {
2735
+ let y = x + ( dx as f32 / 1_000_000.0 ) ;
2736
+ assert_eq ! ( WrappedF32 ( y) . round_ties_even( ) . 0 , y. round_ties_even( ) ) ;
2737
+ }
2738
+ }
2739
+ }
2513
2740
}
0 commit comments