Skip to content

Commit 1e66395

Browse files
authored
Merge pull request #201 from cuviper/faster-add2-sub2, r=hauleth
bigint: simplify the add2/sub2 loops
2 parents f0bc559 + 609629d commit 1e66395

File tree

2 files changed

+42
-30
lines changed

2 files changed

+42
-30
lines changed

benches/bigint.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ fn fib_100(b: &mut Bencher) {
9090
b.iter(|| fib(100));
9191
}
9292

93+
#[bench]
94+
fn fib_1000(b: &mut Bencher) {
95+
b.iter(|| fib(1000));
96+
}
97+
98+
#[bench]
99+
fn fib_10000(b: &mut Bencher) {
100+
b.iter(|| fib(10000));
101+
}
102+
93103
#[bench]
94104
fn fac_to_string(b: &mut Bencher) {
95105
let fac = factorial(100);

bigint/src/lib.rs

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ use std::str::{self, FromStr};
9090
use std::fmt;
9191
#[cfg(test)]
9292
use std::hash;
93+
use std::cmp;
9394
use std::cmp::Ordering::{self, Less, Greater, Equal};
9495
use std::{f32, f64};
9596
use std::{u8, i64, u64};
@@ -173,12 +174,7 @@ fn sbb(a: BigDigit, b: BigDigit, borrow: &mut BigDigit) -> BigDigit {
173174
(*borrow as DoubleBigDigit));
174175
// hi * (base) + lo == 1*(base) + ai - bi - borrow
175176
// => ai - bi - borrow < 0 <=> hi == 0
176-
//
177-
*borrow = if hi == 0 {
178-
1
179-
} else {
180-
0
181-
};
177+
*borrow = (hi == 0) as BigDigit;
182178
lo
183179
}
184180

@@ -755,20 +751,22 @@ forward_all_binop_to_val_ref_commutative!(impl Add for BigUint, add);
755751
#[must_use]
756752
#[inline]
757753
fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
758-
let mut b_iter = b.iter();
754+
debug_assert!(a.len() >= b.len());
755+
759756
let mut carry = 0;
757+
let (a_lo, a_hi) = a.split_at_mut(b.len());
760758

761-
for ai in a.iter_mut() {
762-
if let Some(bi) = b_iter.next() {
763-
*ai = adc(*ai, *bi, &mut carry);
764-
} else if carry != 0 {
765-
*ai = adc(*ai, 0, &mut carry);
766-
} else {
767-
break;
759+
for (a, b) in a_lo.iter_mut().zip(b) {
760+
*a = adc(*a, *b, &mut carry);
761+
}
762+
763+
if carry != 0 {
764+
for a in a_hi {
765+
*a = adc(*a, 0, &mut carry);
766+
if carry == 0 { break }
768767
}
769768
}
770769

771-
debug_assert!(b_iter.next() == None);
772770
carry
773771
}
774772

@@ -832,21 +830,25 @@ impl<'a> Add<&'a BigUint> for BigUint {
832830
forward_all_binop_to_val_ref!(impl Sub for BigUint, sub);
833831

834832
fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
835-
let mut b_iter = b.iter();
836833
let mut borrow = 0;
837834

838-
for ai in a.iter_mut() {
839-
if let Some(bi) = b_iter.next() {
840-
*ai = sbb(*ai, *bi, &mut borrow);
841-
} else if borrow != 0 {
842-
*ai = sbb(*ai, 0, &mut borrow);
843-
} else {
844-
break;
835+
let len = cmp::min(a.len(), b.len());
836+
let (a_lo, a_hi) = a.split_at_mut(len);
837+
let (b_lo, b_hi) = b.split_at(len);
838+
839+
for (a, b) in a_lo.iter_mut().zip(b_lo) {
840+
*a = sbb(*a, *b, &mut borrow);
841+
}
842+
843+
if borrow != 0 {
844+
for a in a_hi {
845+
*a = sbb(*a, 0, &mut borrow);
846+
if borrow == 0 { break }
845847
}
846848
}
847849

848850
// note: we're _required_ to fail on underflow
849-
assert!(borrow == 0 && b_iter.all(|x| *x == 0),
851+
assert!(borrow == 0 && b_hi.iter().all(|x| *x == 0),
850852
"Cannot subtract b from a because b is larger than a.");
851853
}
852854

@@ -866,14 +868,14 @@ fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
866868

867869
match cmp_slice(a, b) {
868870
Greater => {
869-
let mut ret = BigUint::from_slice(a);
870-
sub2(&mut ret.data[..], b);
871-
BigInt::from_biguint(Plus, ret.normalize())
871+
let mut a = a.to_vec();
872+
sub2(&mut a, b);
873+
BigInt::new(Plus, a)
872874
}
873875
Less => {
874-
let mut ret = BigUint::from_slice(b);
875-
sub2(&mut ret.data[..], a);
876-
BigInt::from_biguint(Minus, ret.normalize())
876+
let mut b = b.to_vec();
877+
sub2(&mut b, a);
878+
BigInt::new(Minus, b)
877879
}
878880
_ => Zero::zero(),
879881
}

0 commit comments

Comments
 (0)