Skip to content

Commit 7fcd5f7

Browse files
committed
Auto merge of #205 - cuviper:bigint-sub, r=hauleth
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)
2 parents a7ac5e4 + 388a313 commit 7fcd5f7

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

benches/bigint.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ fn factorial(n: usize) -> BigUint {
4040
f
4141
}
4242

43+
/// Compute Fibonacci numbers
4344
fn fib(n: usize) -> BigUint {
4445
let mut f0: BigUint = Zero::zero();
4546
let mut f1: BigUint = One::one();
@@ -50,6 +51,18 @@ fn fib(n: usize) -> BigUint {
5051
f0
5152
}
5253

54+
/// Compute Fibonacci numbers with two ops per iteration
55+
/// (add and subtract, like issue #200)
56+
fn fib2(n: usize) -> BigUint {
57+
let mut f0: BigUint = Zero::zero();
58+
let mut f1: BigUint = One::one();
59+
for _ in 0..n {
60+
f1 = f1 + &f0;
61+
f0 = &f1 - f0;
62+
}
63+
f0
64+
}
65+
5366
#[bench]
5467
fn multiply_0(b: &mut Bencher) {
5568
multiply_bench(b, 1 << 8, 1 << 8);
@@ -100,6 +113,21 @@ fn fib_10000(b: &mut Bencher) {
100113
b.iter(|| fib(10000));
101114
}
102115

116+
#[bench]
117+
fn fib2_100(b: &mut Bencher) {
118+
b.iter(|| fib2(100));
119+
}
120+
121+
#[bench]
122+
fn fib2_1000(b: &mut Bencher) {
123+
b.iter(|| fib2(1000));
124+
}
125+
126+
#[bench]
127+
fn fib2_10000(b: &mut Bencher) {
128+
b.iter(|| fib2(10000));
129+
}
130+
103131
#[bench]
104132
fn fac_to_string(b: &mut Bencher) {
105133
let fac = factorial(100);

bigint/src/lib.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,8 @@ impl<'a> Add<&'a BigUint> for BigUint {
827827
}
828828
}
829829

830-
forward_all_binop_to_val_ref!(impl Sub for BigUint, sub);
830+
forward_val_val_binop!(impl Sub for BigUint, sub);
831+
forward_ref_ref_binop!(impl Sub for BigUint, sub);
831832

832833
fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
833834
let mut borrow = 0;
@@ -861,6 +862,40 @@ impl<'a> Sub<&'a BigUint> for BigUint {
861862
}
862863
}
863864

865+
fn sub2rev(a: &[BigDigit], b: &mut [BigDigit]) {
866+
debug_assert!(b.len() >= a.len());
867+
868+
let mut borrow = 0;
869+
870+
let len = cmp::min(a.len(), b.len());
871+
let (a_lo, a_hi) = a.split_at(len);
872+
let (b_lo, b_hi) = b.split_at_mut(len);
873+
874+
for (a, b) in a_lo.iter().zip(b_lo) {
875+
*b = sbb(*a, *b, &mut borrow);
876+
}
877+
878+
assert!(a_hi.is_empty());
879+
880+
// note: we're _required_ to fail on underflow
881+
assert!(borrow == 0 && b_hi.iter().all(|x| *x == 0),
882+
"Cannot subtract b from a because b is larger than a.");
883+
}
884+
885+
impl<'a> Sub<BigUint> for &'a BigUint {
886+
type Output = BigUint;
887+
888+
fn sub(self, mut other: BigUint) -> BigUint {
889+
if other.data.len() < self.data.len() {
890+
let extra = self.data.len() - other.data.len();
891+
other.data.extend(repeat(0).take(extra));
892+
}
893+
894+
sub2rev(&self.data[..], &mut other.data[..]);
895+
other.normalize()
896+
}
897+
}
898+
864899
fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
865900
// Normalize:
866901
let a = &a[..a.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];

0 commit comments

Comments
 (0)