bigint: allow `Sub` to work in-place on the RHS
A new Fibonacci benchmark demonstrates the improvement by using both addition and subtraction in each iteration of the loop, like #200. Before: test fib2_100 ... bench: 4,558 ns/iter (+/- 3,357) test fib2_1000 ... bench: 62,575 ns/iter (+/- 5,200) test fib2_10000 ... bench: 2,898,425 ns/iter (+/- 207,973) After: test fib2_100 ... bench: 1,973 ns/iter (+/- 102) test fib2_1000 ... bench: 41,203 ns/iter (+/- 947) test fib2_10000 ... bench: 2,544,272 ns/iter (+/- 45,183)
This commit is contained in:
parent
a7ac5e4299
commit
388a3132b8
|
@ -40,6 +40,7 @@ fn factorial(n: usize) -> BigUint {
|
|||
f
|
||||
}
|
||||
|
||||
/// Compute Fibonacci numbers
|
||||
fn fib(n: usize) -> BigUint {
|
||||
let mut f0: BigUint = Zero::zero();
|
||||
let mut f1: BigUint = One::one();
|
||||
|
@ -50,6 +51,18 @@ fn fib(n: usize) -> BigUint {
|
|||
f0
|
||||
}
|
||||
|
||||
/// Compute Fibonacci numbers with two ops per iteration
|
||||
/// (add and subtract, like issue #200)
|
||||
fn fib2(n: usize) -> BigUint {
|
||||
let mut f0: BigUint = Zero::zero();
|
||||
let mut f1: BigUint = One::one();
|
||||
for _ in 0..n {
|
||||
f1 = f1 + &f0;
|
||||
f0 = &f1 - f0;
|
||||
}
|
||||
f0
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn multiply_0(b: &mut Bencher) {
|
||||
multiply_bench(b, 1 << 8, 1 << 8);
|
||||
|
@ -100,6 +113,21 @@ fn fib_10000(b: &mut Bencher) {
|
|||
b.iter(|| fib(10000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib2_100(b: &mut Bencher) {
|
||||
b.iter(|| fib2(100));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib2_1000(b: &mut Bencher) {
|
||||
b.iter(|| fib2(1000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fib2_10000(b: &mut Bencher) {
|
||||
b.iter(|| fib2(10000));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fac_to_string(b: &mut Bencher) {
|
||||
let fac = factorial(100);
|
||||
|
|
|
@ -827,7 +827,8 @@ impl<'a> Add<&'a BigUint> for BigUint {
|
|||
}
|
||||
}
|
||||
|
||||
forward_all_binop_to_val_ref!(impl Sub for BigUint, sub);
|
||||
forward_val_val_binop!(impl Sub for BigUint, sub);
|
||||
forward_ref_ref_binop!(impl Sub for BigUint, sub);
|
||||
|
||||
fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
||||
let mut borrow = 0;
|
||||
|
@ -861,6 +862,40 @@ impl<'a> Sub<&'a BigUint> for BigUint {
|
|||
}
|
||||
}
|
||||
|
||||
fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
|
||||
debug_assert!(b.len() >= a.len());
|
||||
|
||||
let mut borrow = 0;
|
||||
|
||||
let len = cmp::min(a.len(), b.len());
|
||||
let (a_lo, a_hi) = a.split_at(len);
|
||||
let (b_lo, b_hi) = b.split_at_mut(len);
|
||||
|
||||
for (a, b) in a_lo.iter().zip(b_lo) {
|
||||
*b = sbb(*a, *b, &mut borrow);
|
||||
}
|
||||
|
||||
assert!(a_hi.is_empty());
|
||||
|
||||
// note: we're _required_ to fail on underflow
|
||||
assert!(borrow == 0 && b_hi.iter().all(|x| *x == 0),
|
||||
"Cannot subtract b from a because b is larger than a.");
|
||||
}
|
||||
|
||||
impl<'a> Sub<BigUint> for &'a BigUint {
|
||||
type Output = BigUint;
|
||||
|
||||
fn sub(self, mut other: BigUint) -> BigUint {
|
||||
if other.data.len() < self.data.len() {
|
||||
let extra = self.data.len() - other.data.len();
|
||||
other.data.extend(repeat(0).take(extra));
|
||||
}
|
||||
|
||||
sub2rev(&self.data[..], &mut other.data[..]);
|
||||
other.normalize()
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
|
||||
// Normalize:
|
||||
let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
||||
|
|
Loading…
Reference in New Issue