@@ -796,6 +796,31 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
796
796
/// check(f64::NEG_INFINITY, 1 << 52, 972, -1);
797
797
/// ```
798
798
fn integer_decode ( self ) -> ( u64 , i16 , i8 ) ;
799
+
800
+ /// Rounds to the nearest integer, with ties biasing towards an even result.
801
+ fn round_ties_even ( self ) -> Self {
802
+ let half = ( Self :: one ( ) + Self :: one ( ) ) . recip ( ) ;
803
+
804
+ if self . fract ( ) . abs ( ) != half {
805
+ self . round ( )
806
+ } else {
807
+ let i = self . abs ( ) . trunc ( ) ;
808
+
809
+ let value = if ( i * half) . fract ( ) == half {
810
+ // -1.5, 1.5, 3.5, ...
811
+ self . abs ( ) + half
812
+ } else {
813
+ // -0.5, 0.5, 2.5, ...
814
+ self . abs ( ) - half
815
+ } ;
816
+
817
+ if self . signum ( ) != value. signum ( ) {
818
+ -value
819
+ } else {
820
+ value
821
+ }
822
+ }
823
+ }
799
824
}
800
825
801
826
impl FloatCore for f32 {
@@ -844,6 +869,11 @@ impl FloatCore for f32 {
844
869
Self :: powi( self , n: i32 ) -> Self ;
845
870
}
846
871
872
+ #[ cfg( all( feature = "std" , feature = "msrv_1_77" ) ) ]
873
+ forward ! {
874
+ Self :: round_ties_even( self ) -> Self ;
875
+ }
876
+
847
877
#[ cfg( all( not( feature = "std" ) , feature = "libm" ) ) ]
848
878
forward ! {
849
879
libm:: floorf as floor( self ) -> Self ;
@@ -906,6 +936,11 @@ impl FloatCore for f64 {
906
936
Self :: powi( self , n: i32 ) -> Self ;
907
937
}
908
938
939
+ #[ cfg( all( feature = "std" , feature = "msrv_1_77" ) ) ]
940
+ forward ! {
941
+ Self :: round_ties_even( self ) -> Self ;
942
+ }
943
+
909
944
#[ cfg( all( not( feature = "std" ) , feature = "libm" ) ) ]
910
945
forward ! {
911
946
libm:: floor as floor( self ) -> Self ;
@@ -2510,4 +2545,170 @@ mod tests {
2510
2545
check_lt ( f32:: INFINITY , f32:: NAN ) ;
2511
2546
check_gt ( f32:: NAN , 1.0_f32 ) ;
2512
2547
}
2548
+
2549
+ /// Compares the fallback implementation of [`round_ties_even`] to the one provided by `f32`.`
2550
+ ///
2551
+ /// [`round_ties_even`]: crate::float::FloatCore::round_ties_even
2552
+ #[ cfg( feature = "msrv_1_77" ) ]
2553
+ #[ test]
2554
+ fn round_ties_even ( ) {
2555
+ mod wrapped_f32 {
2556
+ use crate :: { float:: FloatCore , Num , NumCast , One , ToPrimitive , Zero } ;
2557
+ use core:: ops:: { Add , Div , Mul , Neg , Rem , Sub } ;
2558
+
2559
+ #[ derive( Clone , Copy , PartialEq , PartialOrd , Debug ) ]
2560
+ pub struct WrappedF32 ( pub f32 ) ;
2561
+
2562
+ impl ToPrimitive for WrappedF32 {
2563
+ fn to_i64 ( & self ) -> Option < i64 > {
2564
+ f32:: to_i64 ( & self . 0 )
2565
+ }
2566
+
2567
+ fn to_u64 ( & self ) -> Option < u64 > {
2568
+ f32:: to_u64 ( & self . 0 )
2569
+ }
2570
+ }
2571
+
2572
+ impl NumCast for WrappedF32 {
2573
+ fn from < T : crate :: ToPrimitive > ( n : T ) -> Option < Self > {
2574
+ Some ( Self ( <f32 as NumCast >:: from ( n) ?) )
2575
+ }
2576
+ }
2577
+
2578
+ impl Neg for WrappedF32 {
2579
+ type Output = Self ;
2580
+
2581
+ fn neg ( self ) -> Self :: Output {
2582
+ Self ( self . 0 . neg ( ) )
2583
+ }
2584
+ }
2585
+
2586
+ impl Mul for WrappedF32 {
2587
+ type Output = Self ;
2588
+
2589
+ fn mul ( self , rhs : Self ) -> Self :: Output {
2590
+ Self ( f32:: mul ( self . 0 , rhs. 0 ) )
2591
+ }
2592
+ }
2593
+
2594
+ impl Add for WrappedF32 {
2595
+ type Output = Self ;
2596
+
2597
+ fn add ( self , rhs : Self ) -> Self :: Output {
2598
+ Self ( f32:: add ( self . 0 , rhs. 0 ) )
2599
+ }
2600
+ }
2601
+
2602
+ impl Rem for WrappedF32 {
2603
+ type Output = Self ;
2604
+
2605
+ fn rem ( self , rhs : Self ) -> Self :: Output {
2606
+ Self ( f32:: rem ( self . 0 , rhs. 0 ) )
2607
+ }
2608
+ }
2609
+
2610
+ impl Div for WrappedF32 {
2611
+ type Output = Self ;
2612
+
2613
+ fn div ( self , rhs : Self ) -> Self :: Output {
2614
+ Self ( f32:: div ( self . 0 , rhs. 0 ) )
2615
+ }
2616
+ }
2617
+
2618
+ impl Sub for WrappedF32 {
2619
+ type Output = Self ;
2620
+
2621
+ fn sub ( self , rhs : Self ) -> Self :: Output {
2622
+ Self ( f32:: sub ( self . 0 , rhs. 0 ) )
2623
+ }
2624
+ }
2625
+
2626
+ impl One for WrappedF32 {
2627
+ fn one ( ) -> Self {
2628
+ Self ( f32:: one ( ) )
2629
+ }
2630
+ }
2631
+
2632
+ impl Zero for WrappedF32 {
2633
+ fn zero ( ) -> Self {
2634
+ Self ( f32:: zero ( ) )
2635
+ }
2636
+
2637
+ fn is_zero ( & self ) -> bool {
2638
+ self . 0 . is_zero ( )
2639
+ }
2640
+ }
2641
+
2642
+ impl Num for WrappedF32 {
2643
+ type FromStrRadixErr = <f32 as Num >:: FromStrRadixErr ;
2644
+
2645
+ fn from_str_radix ( str : & str , radix : u32 ) -> Result < Self , Self :: FromStrRadixErr > {
2646
+ Ok ( Self ( f32:: from_str_radix ( str, radix) ?) )
2647
+ }
2648
+ }
2649
+
2650
+ impl FloatCore for WrappedF32 {
2651
+ fn infinity ( ) -> Self {
2652
+ Self ( f32:: infinity ( ) )
2653
+ }
2654
+
2655
+ fn neg_infinity ( ) -> Self {
2656
+ Self ( f32:: neg_infinity ( ) )
2657
+ }
2658
+
2659
+ fn nan ( ) -> Self {
2660
+ Self ( f32:: nan ( ) )
2661
+ }
2662
+
2663
+ fn neg_zero ( ) -> Self {
2664
+ Self ( f32:: neg_zero ( ) )
2665
+ }
2666
+
2667
+ fn min_value ( ) -> Self {
2668
+ Self ( f32:: min_value ( ) )
2669
+ }
2670
+
2671
+ fn min_positive_value ( ) -> Self {
2672
+ Self ( f32:: min_positive_value ( ) )
2673
+ }
2674
+
2675
+ fn epsilon ( ) -> Self {
2676
+ Self ( f32:: epsilon ( ) )
2677
+ }
2678
+
2679
+ fn max_value ( ) -> Self {
2680
+ Self ( f32:: max_value ( ) )
2681
+ }
2682
+
2683
+ fn classify ( self ) -> core:: num:: FpCategory {
2684
+ f32:: classify ( self . 0 )
2685
+ }
2686
+
2687
+ fn to_degrees ( self ) -> Self {
2688
+ Self ( f32:: to_degrees ( self . 0 ) )
2689
+ }
2690
+
2691
+ fn to_radians ( self ) -> Self {
2692
+ Self ( f32:: to_radians ( self . 0 ) )
2693
+ }
2694
+
2695
+ fn integer_decode ( self ) -> ( u64 , i16 , i8 ) {
2696
+ f32:: integer_decode ( self . 0 )
2697
+ }
2698
+ }
2699
+ }
2700
+
2701
+ use crate :: float:: FloatCore ;
2702
+ use wrapped_f32:: WrappedF32 ;
2703
+
2704
+ for x in [
2705
+ -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 ,
2706
+ 2.5 , 3.0 , 3.5 , 4.0 , 4.5 , 5.0 ,
2707
+ ] {
2708
+ for dx in -250_000 ..=250_000 {
2709
+ let y = x + ( dx as f32 / 1_000_000.0 ) ;
2710
+ assert_eq ! ( WrappedF32 ( y) . round_ties_even( ) . 0 , y. round_ties_even( ) ) ;
2711
+ }
2712
+ }
2713
+ }
2513
2714
}
0 commit comments