Skip to content

Commit cc8abf7

Browse files
committed
Add round_ties_even to Float and Real
Also add example to `FloatCore::round_ties_even` documentation
1 parent 3c1e02a commit cc8abf7

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

src/float.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,24 @@ pub trait FloatCore: Num + NumCast + Neg<Output = Self> + PartialOrd + Copy {
798798
fn integer_decode(self) -> (u64, i16, i8);
799799

800800
/// Rounds to the nearest integer, with ties biasing towards an even result.
801+
///
802+
/// # Examples
803+
///
804+
/// ```
805+
/// use num_traits::float::FloatCore;
806+
///
807+
/// fn check<T: FloatCore>(x: T, rounded: T) {
808+
/// assert!(x.round_ties_even() == rounded);
809+
/// }
810+
///
811+
/// check(1.0f32, 1.0);
812+
/// check(1.25f32, 1.0);
813+
/// check(1.75f32, 2.0);
814+
/// check(1.5f32, 2.0);
815+
/// check(2.5f32, 2.0);
816+
/// check(3.5f32, 4.0);
817+
/// check(-3.5f32, -4.0);
818+
/// ```
801819
fn round_ties_even(self) -> Self {
802820
let half = (Self::one() + Self::one()).recip();
803821

@@ -1944,6 +1962,49 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
19441962
self.neg()
19451963
}
19461964
}
1965+
1966+
/// Rounds to the nearest integer, with ties biasing towards an even result.
1967+
///
1968+
/// # Examples
1969+
///
1970+
/// ```
1971+
/// use num_traits::Float;
1972+
///
1973+
/// fn check<T: Float>(x: T, rounded: T) {
1974+
/// assert!(x.round_ties_even() == rounded);
1975+
/// }
1976+
///
1977+
/// check(1.0f32, 1.0);
1978+
/// check(1.25f32, 1.0);
1979+
/// check(1.75f32, 2.0);
1980+
/// check(1.5f32, 2.0);
1981+
/// check(2.5f32, 2.0);
1982+
/// check(3.5f32, 4.0);
1983+
/// check(-3.5f32, -4.0);
1984+
/// ```
1985+
fn round_ties_even(self) -> Self {
1986+
let half = (Self::one() + Self::one()).recip();
1987+
1988+
if self.fract().abs() != half {
1989+
self.round()
1990+
} else {
1991+
let i = self.abs().trunc();
1992+
1993+
let value = if (i * half).fract() == half {
1994+
// -1.5, 1.5, 3.5, ...
1995+
self.abs() + half
1996+
} else {
1997+
// -0.5, 0.5, 2.5, ...
1998+
self.abs() - half
1999+
};
2000+
2001+
if self.signum() != value.signum() {
2002+
-value
2003+
} else {
2004+
value
2005+
}
2006+
}
2007+
}
19472008
}
19482009

19492010
#[cfg(feature = "std")]
@@ -2024,6 +2085,11 @@ macro_rules! float_impl_std {
20242085
Self::atanh(self) -> Self;
20252086
Self::copysign(self, sign: Self) -> Self;
20262087
}
2088+
2089+
#[cfg(has_round_ties_even)]
2090+
forward! {
2091+
Self::round_ties_even(self) -> Self;
2092+
}
20272093
}
20282094
};
20292095
}

src/real.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,49 @@ pub trait Real: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
777777
/// assert!(abs_difference < 1.0e-10);
778778
/// ```
779779
fn atanh(self) -> Self;
780+
781+
/// Rounds to the nearest integer, with ties biasing towards an even result.
782+
///
783+
/// # Examples
784+
///
785+
/// ```
786+
/// use num_traits::real::Real;
787+
///
788+
/// fn check<T: Real>(x: T, rounded: T) {
789+
/// assert!(x.round_ties_even() == rounded);
790+
/// }
791+
///
792+
/// check(1.0f32, 1.0);
793+
/// check(1.25f32, 1.0);
794+
/// check(1.75f32, 2.0);
795+
/// check(1.5f32, 2.0);
796+
/// check(2.5f32, 2.0);
797+
/// check(3.5f32, 4.0);
798+
/// check(-3.5f32, -4.0);
799+
/// ```
800+
fn round_ties_even(self) -> Self {
801+
let half = (Self::one() + Self::one()).recip();
802+
803+
if self.fract().abs() != half {
804+
self.round()
805+
} else {
806+
let i = self.abs().trunc();
807+
808+
let value = if (i * half).fract() == half {
809+
// -1.5, 1.5, 3.5, ...
810+
self.abs() + half
811+
} else {
812+
// -0.5, 0.5, 2.5, ...
813+
self.abs() - half
814+
};
815+
816+
if self.signum() != value.signum() {
817+
-value
818+
} else {
819+
value
820+
}
821+
}
822+
}
780823
}
781824

782825
impl<T: Float> Real for T {
@@ -830,5 +873,6 @@ impl<T: Float> Real for T {
830873
Float::asinh(self) -> Self;
831874
Float::acosh(self) -> Self;
832875
Float::atanh(self) -> Self;
876+
Float::round_ties_even(self) -> Self;
833877
}
834878
}

0 commit comments

Comments
 (0)