Skip to content

Commit

Permalink
Merge rust-num#199
Browse files Browse the repository at this point in the history
199: Optimizations for multiplication r=cuviper a=cuviper

Relevant benchmarks:

```
 factorial_100          5,137                 2,663                      -2,474  -48.16%   x 1.93
 factorial_div_biguint  791,253               773,134                   -18,119   -2.29%   x 1.02
 factorial_div_u32      766,341               748,398                   -17,943   -2.34%   x 1.02
 factorial_mul_biguint  113,269               58,480                    -54,789  -48.37%   x 1.94
 factorial_mul_u32      35,062                37,848                      2,786    7.95%   x 0.93
 multiply_0             39                    40                              1    2.56%   x 0.98
 multiply_1             3,693                 3,708                          15    0.41%   x 1.00
 multiply_2             309,911               215,371                   -94,540  -30.51%   x 1.44
 multiply_3             662,091               494,419                  -167,672  -25.32%   x 1.34
 pow_bench              2,550,050             2,144,069                -405,981  -15.92%   x 1.19
 pow_bench_1e1000       1,332                 1,071                        -261  -19.59%   x 1.24
 pow_bench_1e10000      62,234                36,109                    -26,125  -41.98%   x 1.72
 pow_bench_1e100000     2,530,757             1,134,613              -1,396,144  -55.17%   x 2.23
 pow_bench_bigexp       2,630,660             2,155,688                -474,972  -18.06%   x 1.22
```

Co-authored-by: Josh Stone <[email protected]>
  • Loading branch information
bors[bot] and cuviper authored Mar 14, 2021
2 parents cbfe665 + dce75e1 commit 125fbbd
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 102 deletions.
17 changes: 16 additions & 1 deletion benches/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn factorial(n: usize) -> BigUint {
let mut f: BigUint = One::one();
for i in 1..=n {
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
f += bu;
f *= bu;
}
f
}
Expand Down Expand Up @@ -351,6 +351,21 @@ fn pow_bench_bigexp(b: &mut Bencher) {
});
}

#[bench]
fn pow_bench_1e1000(b: &mut Bencher) {
b.iter(|| BigUint::from(10u32).pow(1_000));
}

#[bench]
fn pow_bench_1e10000(b: &mut Bencher) {
b.iter(|| BigUint::from(10u32).pow(10_000));
}

#[bench]
fn pow_bench_1e100000(b: &mut Bencher) {
b.iter(|| BigUint::from(10u32).pow(100_000));
}

/// This modulus is the prime from the 2048-bit MODP DH group:
/// https://tools.ietf.org/html/rfc3526#section-3
const RFC3526_2048BIT_MODP_GROUP: &str = "\
Expand Down
57 changes: 41 additions & 16 deletions src/bigint/multiplication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,49 @@ impl Mul<Sign> for Sign {
}
}

forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul);

impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt {
type Output = BigInt;

#[inline]
fn mul(self, other: &BigInt) -> BigInt {
BigInt::from_biguint(self.sign * other.sign, &self.data * &other.data)
}
macro_rules! impl_mul {
($(impl<$($a:lifetime),*> Mul<$Other:ty> for $Self:ty;)*) => {$(
impl<$($a),*> Mul<$Other> for $Self {
type Output = BigInt;

#[inline]
fn mul(self, other: $Other) -> BigInt {
// automatically match value/ref
let BigInt { data: x, .. } = self;
let BigInt { data: y, .. } = other;
BigInt::from_biguint(self.sign * other.sign, x * y)
}
}
)*}
}
impl_mul! {
impl<> Mul<BigInt> for BigInt;
impl<'b> Mul<&'b BigInt> for BigInt;
impl<'a> Mul<BigInt> for &'a BigInt;
impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt;
}

macro_rules! impl_mul_assign {
($(impl<$($a:lifetime),*> MulAssign<$Other:ty> for BigInt;)*) => {$(
impl<$($a),*> MulAssign<$Other> for BigInt {
#[inline]
fn mul_assign(&mut self, other: $Other) {
// automatically match value/ref
let BigInt { data: y, .. } = other;
self.data *= y;
if self.data.is_zero() {
self.sign = NoSign;
} else {
self.sign = self.sign * other.sign;
}
}
}
)*}
}

impl<'a> MulAssign<&'a BigInt> for BigInt {
#[inline]
fn mul_assign(&mut self, other: &BigInt) {
*self = &*self * other;
}
impl_mul_assign! {
impl<> MulAssign<BigInt> for BigInt;
impl<'a> MulAssign<&'a BigInt> for BigInt;
}
forward_val_assign!(impl MulAssign for BigInt, mul_assign);

promote_all_scalars!(impl Mul for BigInt, mul);
promote_all_scalars_assign!(impl MulAssign for BigInt, mul_assign);
Expand Down
5 changes: 3 additions & 2 deletions src/biguint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -846,8 +846,9 @@ impl BigUint {
/// be nonzero.
#[inline]
fn normalize(&mut self) {
while let Some(&0) = self.data.last() {
self.data.pop();
if let Some(&0) = self.data.last() {
let len = self.data.iter().rposition(|&d| d != 0).map_or(0, |i| i + 1);
self.data.truncate(len);
}
if self.data.len() < self.data.capacity() / 4 {
self.data.shrink_to_fit();
Expand Down
Loading

0 comments on commit 125fbbd

Please sign in to comment.