Skip to content

Commit 687db5d

Browse files
committed
Fix issue #15826.
The implemented fix rounds half-way cases away from zero as described in the original comments. This rounding algorithm is sometimes called arithmetic rounding. It is described further here: http://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero I also added several new tests to prevent regressions.
1 parent b516532 commit 687db5d

File tree

1 file changed

+29
-6
lines changed

1 file changed

+29
-6
lines changed

src/libnum/rational.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,14 @@ impl<T: Clone + Integer + PartialOrd>
137137
}
138138

139139
/// Rounds to the nearest integer. Rounds half-way cases away from zero.
140-
///
141-
/// Note: This function is currently broken and always rounds away from zero.
142140
#[inline]
143141
pub fn round(&self) -> Ratio<T> {
144-
// FIXME(#15826)
145142
if *self < Zero::zero() {
146-
Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom)
143+
// a/b - 1/2 = (2*a - b)/(2*b)
144+
Ratio::from_integer((self.numer + self.numer - self.denom) / (self.denom + self.denom))
147145
} else {
148-
Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom)
146+
// a/b + 1/2 = (2*a + b)/(2*b)
147+
Ratio::from_integer((self.numer + self.numer + self.denom) / (self.denom + self.denom))
149148
}
150149
}
151150

@@ -388,7 +387,11 @@ mod test {
388387
pub static _2: Rational = Ratio { numer: 2, denom: 1};
389388
pub static _1_2: Rational = Ratio { numer: 1, denom: 2};
390389
pub static _3_2: Rational = Ratio { numer: 3, denom: 2};
391-
pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
390+
pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2};
391+
pub static _1_3: Rational = Ratio { numer: 1, denom: 3};
392+
pub static _neg1_3: Rational = Ratio { numer: -1, denom: 3};
393+
pub static _2_3: Rational = Ratio { numer: 2, denom: 3};
394+
pub static _neg2_3: Rational = Ratio { numer: -2, denom: 3};
392395

393396
pub fn to_big(n: Rational) -> BigRational {
394397
Ratio::new(
@@ -578,6 +581,26 @@ mod test {
578581

579582
#[test]
580583
fn test_round() {
584+
assert_eq!(_1_3.ceil(), _1);
585+
assert_eq!(_1_3.floor(), _0);
586+
assert_eq!(_1_3.round(), _0);
587+
assert_eq!(_1_3.trunc(), _0);
588+
589+
assert_eq!(_neg1_3.ceil(), _0);
590+
assert_eq!(_neg1_3.floor(), -_1);
591+
assert_eq!(_neg1_3.round(), _0);
592+
assert_eq!(_neg1_3.trunc(), _0);
593+
594+
assert_eq!(_2_3.ceil(), _1);
595+
assert_eq!(_2_3.floor(), _0);
596+
assert_eq!(_2_3.round(), _1);
597+
assert_eq!(_2_3.trunc(), _0);
598+
599+
assert_eq!(_neg2_3.ceil(), _0);
600+
assert_eq!(_neg2_3.floor(), -_1);
601+
assert_eq!(_neg2_3.round(), -_1);
602+
assert_eq!(_neg2_3.trunc(), _0);
603+
581604
assert_eq!(_1_2.ceil(), _1);
582605
assert_eq!(_1_2.floor(), _0);
583606
assert_eq!(_1_2.round(), _1);

0 commit comments

Comments
 (0)