@@ -401,6 +401,29 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
401401 }
402402 }
403403
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+
404427 /// Return the integer part of a number.
405428 ///
406429 /// # Examples
@@ -844,6 +867,11 @@ impl FloatCore for f32 {
844867 Self :: powi( self , n: i32 ) -> Self ;
845868 }
846869
870+ #[ cfg( all( feature = "std" , has_round_ties_even) ) ]
871+ forward ! {
872+ Self :: round_ties_even( self ) -> Self ;
873+ }
874+
847875 #[ cfg( all( not( feature = "std" ) , feature = "libm" ) ) ]
848876 forward ! {
849877 libm:: floorf as floor( self ) -> Self ;
@@ -906,6 +934,11 @@ impl FloatCore for f64 {
906934 Self :: powi( self , n: i32 ) -> Self ;
907935 }
908936
937+ #[ cfg( all( feature = "std" , has_round_ties_even) ) ]
938+ forward ! {
939+ Self :: round_ties_even( self ) -> Self ;
940+ }
941+
909942 #[ cfg( all( not( feature = "std" ) , feature = "libm" ) ) ]
910943 forward ! {
911944 libm:: floor as floor( self ) -> Self ;
@@ -1195,6 +1228,29 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
11951228 /// ```
11961229 fn round ( self ) -> Self ;
11971230
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+
11981254 /// Return the integer part of a number.
11991255 ///
12001256 /// ```
@@ -1989,6 +2045,11 @@ macro_rules! float_impl_std {
19892045 Self :: atanh( self ) -> Self ;
19902046 Self :: copysign( self , sign: Self ) -> Self ;
19912047 }
2048+
2049+ #[ cfg( has_round_ties_even) ]
2050+ forward! {
2051+ Self :: round_ties_even( self ) -> Self ;
2052+ }
19922053 }
19932054 } ;
19942055}
@@ -2510,4 +2571,170 @@ mod tests {
25102571 check_lt ( f32:: INFINITY , f32:: NAN ) ;
25112572 check_gt ( f32:: NAN , 1.0_f32 ) ;
25122573 }
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+ }
25132740}
0 commit comments