bigint: simplify the add2/sub2 loops
This splits the main arithmetic loops from the final carry/borrow propagation, and also normalizes the slice lengths before iteration. This lets the optimizer generate better code for these functions.
This commit is contained in:
parent
f0bc5596af
commit
609629d34d
|
@ -90,6 +90,16 @@ fn fib_100(b: &mut Bencher) {
|
||||||
b.iter(|| fib(100));
|
b.iter(|| fib(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn fib_1000(b: &mut Bencher) {
|
||||||
|
b.iter(|| fib(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn fib_10000(b: &mut Bencher) {
|
||||||
|
b.iter(|| fib(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);
|
||||||
|
|
|
@ -90,6 +90,7 @@ use std::str::{self, FromStr};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::hash;
|
use std::hash;
|
||||||
|
use std::cmp;
|
||||||
use std::cmp::Ordering::{self, Less, Greater, Equal};
|
use std::cmp::Ordering::{self, Less, Greater, Equal};
|
||||||
use std::{f32, f64};
|
use std::{f32, f64};
|
||||||
use std::{u8, i64, u64};
|
use std::{u8, i64, u64};
|
||||||
|
@ -173,12 +174,7 @@ fn sbb(a: BigDigit, b: BigDigit, borrow: &mut BigDigit) -> BigDigit {
|
||||||
(*borrow as DoubleBigDigit));
|
(*borrow as DoubleBigDigit));
|
||||||
// hi * (base) + lo == 1*(base) + ai - bi - borrow
|
// hi * (base) + lo == 1*(base) + ai - bi - borrow
|
||||||
// => ai - bi - borrow < 0 <=> hi == 0
|
// => ai - bi - borrow < 0 <=> hi == 0
|
||||||
//
|
*borrow = (hi == 0) as BigDigit;
|
||||||
*borrow = if hi == 0 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
lo
|
lo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,20 +751,22 @@ forward_all_binop_to_val_ref_commutative!(impl Add for BigUint, add);
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
|
fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
|
||||||
let mut b_iter = b.iter();
|
debug_assert!(a.len() >= b.len());
|
||||||
|
|
||||||
let mut carry = 0;
|
let mut carry = 0;
|
||||||
|
let (a_lo, a_hi) = a.split_at_mut(b.len());
|
||||||
|
|
||||||
for ai in a.iter_mut() {
|
for (a, b) in a_lo.iter_mut().zip(b) {
|
||||||
if let Some(bi) = b_iter.next() {
|
*a = adc(*a, *b, &mut carry);
|
||||||
*ai = adc(*ai, *bi, &mut carry);
|
}
|
||||||
} else if carry != 0 {
|
|
||||||
*ai = adc(*ai, 0, &mut carry);
|
if carry != 0 {
|
||||||
} else {
|
for a in a_hi {
|
||||||
break;
|
*a = adc(*a, 0, &mut carry);
|
||||||
|
if carry == 0 { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(b_iter.next() == None);
|
|
||||||
carry
|
carry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,21 +830,25 @@ impl<'a> Add<&'a BigUint> for BigUint {
|
||||||
forward_all_binop_to_val_ref!(impl Sub for BigUint, sub);
|
forward_all_binop_to_val_ref!(impl Sub for BigUint, sub);
|
||||||
|
|
||||||
fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
|
||||||
let mut b_iter = b.iter();
|
|
||||||
let mut borrow = 0;
|
let mut borrow = 0;
|
||||||
|
|
||||||
for ai in a.iter_mut() {
|
let len = cmp::min(a.len(), b.len());
|
||||||
if let Some(bi) = b_iter.next() {
|
let (a_lo, a_hi) = a.split_at_mut(len);
|
||||||
*ai = sbb(*ai, *bi, &mut borrow);
|
let (b_lo, b_hi) = b.split_at(len);
|
||||||
} else if borrow != 0 {
|
|
||||||
*ai = sbb(*ai, 0, &mut borrow);
|
for (a, b) in a_lo.iter_mut().zip(b_lo) {
|
||||||
} else {
|
*a = sbb(*a, *b, &mut borrow);
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
if borrow != 0 {
|
||||||
|
for a in a_hi {
|
||||||
|
*a = sbb(*a, 0, &mut borrow);
|
||||||
|
if borrow == 0 { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// note: we're _required_ to fail on underflow
|
// note: we're _required_ to fail on underflow
|
||||||
assert!(borrow == 0 && b_iter.all(|x| *x == 0),
|
assert!(borrow == 0 && b_hi.iter().all(|x| *x == 0),
|
||||||
"Cannot subtract b from a because b is larger than a.");
|
"Cannot subtract b from a because b is larger than a.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,14 +868,14 @@ fn sub_sign(a: &[BigDigit], b: &[BigDigit]) -> BigInt {
|
||||||
|
|
||||||
match cmp_slice(a, b) {
|
match cmp_slice(a, b) {
|
||||||
Greater => {
|
Greater => {
|
||||||
let mut ret = BigUint::from_slice(a);
|
let mut a = a.to_vec();
|
||||||
sub2(&mut ret.data[..], b);
|
sub2(&mut a, b);
|
||||||
BigInt::from_biguint(Plus, ret.normalize())
|
BigInt::new(Plus, a)
|
||||||
}
|
}
|
||||||
Less => {
|
Less => {
|
||||||
let mut ret = BigUint::from_slice(b);
|
let mut b = b.to_vec();
|
||||||
sub2(&mut ret.data[..], a);
|
sub2(&mut b, a);
|
||||||
BigInt::from_biguint(Minus, ret.normalize())
|
BigInt::new(Minus, b)
|
||||||
}
|
}
|
||||||
_ => Zero::zero(),
|
_ => Zero::zero(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue