Skip to content

Commit df4503c

Browse files
committed
Ensure no rounds on even divides
1 parent 9a51c7c commit df4503c

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

packages/std/src/math/fraction.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ macro_rules! impl_mul_fraction {
5656
self,
5757
rhs: F,
5858
) -> Result<Self, CheckedMultiplyFractionError> {
59-
let numerator = rhs.numerator().into();
60-
let denominator = rhs.denominator().into();
59+
let divisor = rhs.denominator().into();
60+
let remainder = self
61+
.full_mul(rhs.numerator().into())
62+
.checked_rem(divisor.into())?;
6163
let floor_result = self.checked_mul_floored(rhs)?;
62-
if !numerator.checked_rem(denominator)?.is_zero() {
64+
if !remainder.is_zero() {
6365
Ok($Uint::one().checked_add(floor_result)?)
6466
} else {
6567
Ok(floor_result)

packages/std/src/math/uint128.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,13 @@ mod tests {
10671067
assert_eq!(Uint128::new(47030), res)
10681068
}
10691069

1070+
#[test]
1071+
fn mul_floored_does_not_round_on_even_divide() {
1072+
let fraction = (2u128, 5u128);
1073+
let res = Uint128::new(25).mul_floored(fraction);
1074+
assert_eq!(Uint128::new(10), res)
1075+
}
1076+
10701077
#[test]
10711078
fn mul_floored_works_when_operation_temporarily_takes_above_max() {
10721079
let fraction = (8u128, 21u128);
@@ -1143,6 +1150,13 @@ mod tests {
11431150
assert_eq!(Uint128::new(47031), res)
11441151
}
11451152

1153+
#[test]
1154+
fn mul_ceil_does_not_round_on_even_divide() {
1155+
let fraction = (2u128, 5u128);
1156+
let res = Uint128::new(25).mul_ceil(fraction);
1157+
assert_eq!(Uint128::new(10), res)
1158+
}
1159+
11461160
#[test]
11471161
fn mul_ceil_works_when_operation_temporarily_takes_above_max() {
11481162
let fraction = (8u128, 21u128);

packages/std/src/math/uint256.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,6 +1689,13 @@ mod tests {
16891689
assert_eq!(Uint256::from(47030u32), res)
16901690
}
16911691

1692+
#[test]
1693+
fn mul_floored_does_not_round_on_even_divide() {
1694+
let fraction = (2u128, 5u128);
1695+
let res = Uint256::from(25u32).mul_floored(fraction);
1696+
assert_eq!(Uint256::from(10u32), res)
1697+
}
1698+
16921699
#[test]
16931700
fn mul_floored_works_when_operation_temporarily_takes_above_max() {
16941701
let fraction = (8u128, 21u128);
@@ -1777,6 +1784,13 @@ mod tests {
17771784
assert_eq!(Uint256::from(47031u32), res)
17781785
}
17791786

1787+
#[test]
1788+
fn mul_ceil_does_not_round_on_even_divide() {
1789+
let fraction = (2u128, 5u128);
1790+
let res = Uint256::from(25u32).mul_ceil(fraction);
1791+
assert_eq!(Uint256::from(10u32), res)
1792+
}
1793+
17801794
#[test]
17811795
fn mul_ceil_works_when_operation_temporarily_takes_above_max() {
17821796
let fraction = (8u128, 21u128);

packages/std/src/math/uint64.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,13 @@ mod tests {
981981
assert_eq!(Uint64::new(47030), res)
982982
}
983983

984+
#[test]
985+
fn mul_floored_does_not_round_on_even_divide() {
986+
let fraction = (2u64, 5u64);
987+
let res = Uint64::new(25).mul_floored(fraction);
988+
assert_eq!(Uint64::new(10), res)
989+
}
990+
984991
#[test]
985992
fn mul_floored_works_when_operation_temporarily_takes_above_max() {
986993
let fraction = (8u64, 21u64);
@@ -1047,6 +1054,13 @@ mod tests {
10471054
assert_eq!(Uint64::new(47031), res)
10481055
}
10491056

1057+
#[test]
1058+
fn mul_ceil_does_not_round_on_even_divide() {
1059+
let fraction = (2u64, 5u64);
1060+
let res = Uint64::new(25).mul_ceil(fraction);
1061+
assert_eq!(Uint64::new(10), res)
1062+
}
1063+
10501064
#[test]
10511065
fn mul_ceil_works_when_operation_temporarily_takes_above_max() {
10521066
let fraction = (8u64, 21u64);

0 commit comments

Comments
 (0)