Skip to content

Commit 125fbbd

Browse files
bors[bot]cuviper
andauthored
Merge #199
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 <cuviper@gmail.com>
2 parents cbfe665 + dce75e1 commit 125fbbd

File tree

7 files changed

+207
-102
lines changed

7 files changed

+207
-102
lines changed

benches/bigint.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn factorial(n: usize) -> BigUint {
3939
let mut f: BigUint = One::one();
4040
for i in 1..=n {
4141
let bu: BigUint = FromPrimitive::from_usize(i).unwrap();
42-
f += bu;
42+
f *= bu;
4343
}
4444
f
4545
}
@@ -351,6 +351,21 @@ fn pow_bench_bigexp(b: &mut Bencher) {
351351
});
352352
}
353353

354+
#[bench]
355+
fn pow_bench_1e1000(b: &mut Bencher) {
356+
b.iter(|| BigUint::from(10u32).pow(1_000));
357+
}
358+
359+
#[bench]
360+
fn pow_bench_1e10000(b: &mut Bencher) {
361+
b.iter(|| BigUint::from(10u32).pow(10_000));
362+
}
363+
364+
#[bench]
365+
fn pow_bench_1e100000(b: &mut Bencher) {
366+
b.iter(|| BigUint::from(10u32).pow(100_000));
367+
}
368+
354369
/// This modulus is the prime from the 2048-bit MODP DH group:
355370
/// https://tools.ietf.org/html/rfc3526#section-3
356371
const RFC3526_2048BIT_MODP_GROUP: &str = "\

src/bigint/multiplication.rs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,49 @@ impl Mul<Sign> for Sign {
2121
}
2222
}
2323

24-
forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul);
25-
26-
impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt {
27-
type Output = BigInt;
28-
29-
#[inline]
30-
fn mul(self, other: &BigInt) -> BigInt {
31-
BigInt::from_biguint(self.sign * other.sign, &self.data * &other.data)
32-
}
24+
macro_rules! impl_mul {
25+
($(impl<$($a:lifetime),*> Mul<$Other:ty> for $Self:ty;)*) => {$(
26+
impl<$($a),*> Mul<$Other> for $Self {
27+
type Output = BigInt;
28+
29+
#[inline]
30+
fn mul(self, other: $Other) -> BigInt {
31+
// automatically match value/ref
32+
let BigInt { data: x, .. } = self;
33+
let BigInt { data: y, .. } = other;
34+
BigInt::from_biguint(self.sign * other.sign, x * y)
35+
}
36+
}
37+
)*}
38+
}
39+
impl_mul! {
40+
impl<> Mul<BigInt> for BigInt;
41+
impl<'b> Mul<&'b BigInt> for BigInt;
42+
impl<'a> Mul<BigInt> for &'a BigInt;
43+
impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt;
44+
}
45+
46+
macro_rules! impl_mul_assign {
47+
($(impl<$($a:lifetime),*> MulAssign<$Other:ty> for BigInt;)*) => {$(
48+
impl<$($a),*> MulAssign<$Other> for BigInt {
49+
#[inline]
50+
fn mul_assign(&mut self, other: $Other) {
51+
// automatically match value/ref
52+
let BigInt { data: y, .. } = other;
53+
self.data *= y;
54+
if self.data.is_zero() {
55+
self.sign = NoSign;
56+
} else {
57+
self.sign = self.sign * other.sign;
58+
}
59+
}
60+
}
61+
)*}
3362
}
34-
35-
impl<'a> MulAssign<&'a BigInt> for BigInt {
36-
#[inline]
37-
fn mul_assign(&mut self, other: &BigInt) {
38-
*self = &*self * other;
39-
}
63+
impl_mul_assign! {
64+
impl<> MulAssign<BigInt> for BigInt;
65+
impl<'a> MulAssign<&'a BigInt> for BigInt;
4066
}
41-
forward_val_assign!(impl MulAssign for BigInt, mul_assign);
4267

4368
promote_all_scalars!(impl Mul for BigInt, mul);
4469
promote_all_scalars_assign!(impl MulAssign for BigInt, mul_assign);

src/biguint.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,8 +846,9 @@ impl BigUint {
846846
/// be nonzero.
847847
#[inline]
848848
fn normalize(&mut self) {
849-
while let Some(&0) = self.data.last() {
850-
self.data.pop();
849+
if let Some(&0) = self.data.last() {
850+
let len = self.data.iter().rposition(|&d| d != 0).map_or(0, |i| i + 1);
851+
self.data.truncate(len);
851852
}
852853
if self.data.len() < self.data.capacity() / 4 {
853854
self.data.shrink_to_fit();

0 commit comments

Comments
 (0)