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
|
f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute Fibonacci numbers
|
||||||
fn fib(n: usize) -> BigUint {
|
fn fib(n: usize) -> BigUint {
|
||||||
let mut f0: BigUint = Zero::zero();
|
let mut f0: BigUint = Zero::zero();
|
||||||
let mut f1: BigUint = One::one();
|
let mut f1: BigUint = One::one();
|
||||||
|
@ -50,6 +51,18 @@ fn fib(n: usize) -> BigUint {
|
||||||
f0
|
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]
|
#[bench]
|
||||||
fn multiply_0(b: &mut Bencher) {
|
fn multiply_0(b: &mut Bencher) {
|
||||||
multiply_bench(b, 1 << 8, 1 << 8);
|
multiply_bench(b, 1 << 8, 1 << 8);
|
||||||
|
@ -100,6 +113,21 @@ fn fib_10000(b: &mut Bencher) {
|
||||||
b.iter(|| fib(10000));
|
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]
|
#[bench]
|
||||||
fn fac_to_string(b: &mut Bencher) {
|
fn fac_to_string(b: &mut Bencher) {
|
||||||
let fac = factorial(100);
|
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]) {
|
fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
||||||
let mut borrow = 0;
|
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 {
|
fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
|
||||||
// Normalize:
|
// Normalize:
|
||||||
let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
|
||||||
|
|
Loading…
Reference in New Issue