bigint: avoid new allocations for small shifts
Before: test shl ... bench: 7,312 ns/iter (+/- 218) test shr ... bench: 5,282 ns/iter (+/- 243) After: test shl ... bench: 4,946 ns/iter (+/- 88) test shr ... bench: 4,121 ns/iter (+/- 52)
This commit is contained in:
parent
1ebcc77513
commit
b454a14bc4
124
src/bigint.rs
124
src/bigint.rs
|
@ -66,6 +66,7 @@
|
||||||
|
|
||||||
use Integer;
|
use Integer;
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
|
@ -590,11 +591,43 @@ impl<'a> BitXor<&'a BigUint> for BigUint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn biguint_shl(n: Cow<BigUint>, bits: usize) -> BigUint {
|
||||||
|
let n_unit = bits / big_digit::BITS;
|
||||||
|
let mut data = match n_unit {
|
||||||
|
0 => n.into_owned().data,
|
||||||
|
_ => {
|
||||||
|
let len = n_unit + n.data.len() + 1;
|
||||||
|
let mut data = Vec::with_capacity(len);
|
||||||
|
data.extend(repeat(0).take(n_unit));
|
||||||
|
data.extend(n.data.iter().cloned());
|
||||||
|
data
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let n_bits = bits % big_digit::BITS;
|
||||||
|
if n_bits > 0 {
|
||||||
|
let mut carry = 0;
|
||||||
|
for elem in data[n_unit..].iter_mut() {
|
||||||
|
let new_carry = *elem >> (big_digit::BITS - n_bits);
|
||||||
|
*elem = (*elem << n_bits) | carry;
|
||||||
|
carry = new_carry;
|
||||||
|
}
|
||||||
|
if carry != 0 {
|
||||||
|
data.push(carry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BigUint::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
impl Shl<usize> for BigUint {
|
impl Shl<usize> for BigUint {
|
||||||
type Output = BigUint;
|
type Output = BigUint;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn shl(self, rhs: usize) -> BigUint { (&self) << rhs }
|
fn shl(self, rhs: usize) -> BigUint {
|
||||||
|
biguint_shl(Cow::Owned(self), rhs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Shl<usize> for &'a BigUint {
|
impl<'a> Shl<usize> for &'a BigUint {
|
||||||
|
@ -602,17 +635,39 @@ impl<'a> Shl<usize> for &'a BigUint {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn shl(self, rhs: usize) -> BigUint {
|
fn shl(self, rhs: usize) -> BigUint {
|
||||||
let n_unit = rhs / big_digit::BITS;
|
biguint_shl(Cow::Borrowed(self), rhs)
|
||||||
let n_bits = rhs % big_digit::BITS;
|
|
||||||
self.shl_unit(n_unit).shl_bits(n_bits)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn biguint_shr(n: Cow<BigUint>, bits: usize) -> BigUint {
|
||||||
|
let n_unit = bits / big_digit::BITS;
|
||||||
|
if n_unit >= n.data.len() { return Zero::zero(); }
|
||||||
|
let mut data = match n_unit {
|
||||||
|
0 => n.into_owned().data,
|
||||||
|
_ => n.data[n_unit..].to_vec(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let n_bits = bits % big_digit::BITS;
|
||||||
|
if n_bits > 0 {
|
||||||
|
let mut borrow = 0;
|
||||||
|
for elem in data.iter_mut().rev() {
|
||||||
|
let new_borrow = *elem << (big_digit::BITS - n_bits);
|
||||||
|
*elem = (*elem >> n_bits) | borrow;
|
||||||
|
borrow = new_borrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BigUint::new(data)
|
||||||
|
}
|
||||||
|
|
||||||
impl Shr<usize> for BigUint {
|
impl Shr<usize> for BigUint {
|
||||||
type Output = BigUint;
|
type Output = BigUint;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn shr(self, rhs: usize) -> BigUint { (&self) >> rhs }
|
fn shr(self, rhs: usize) -> BigUint {
|
||||||
|
biguint_shr(Cow::Owned(self), rhs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Shr<usize> for &'a BigUint {
|
impl<'a> Shr<usize> for &'a BigUint {
|
||||||
|
@ -620,9 +675,7 @@ impl<'a> Shr<usize> for &'a BigUint {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn shr(self, rhs: usize) -> BigUint {
|
fn shr(self, rhs: usize) -> BigUint {
|
||||||
let n_unit = rhs / big_digit::BITS;
|
biguint_shr(Cow::Borrowed(self), rhs)
|
||||||
let n_bits = rhs % big_digit::BITS;
|
|
||||||
self.shr_unit(n_unit).shr_bits(n_bits)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1646,57 +1699,6 @@ impl BigUint {
|
||||||
str::from_utf8(buf).ok().and_then(|s| BigUint::from_str_radix(s, radix).ok())
|
str::from_utf8(buf).ok().and_then(|s| BigUint::from_str_radix(s, radix).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shl_unit(&self, n_unit: usize) -> BigUint {
|
|
||||||
if n_unit == 0 || self.is_zero() { return self.clone(); }
|
|
||||||
|
|
||||||
let mut v = vec![0; n_unit];
|
|
||||||
v.extend(self.data.iter().cloned());
|
|
||||||
BigUint::new(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shl_bits(self, n_bits: usize) -> BigUint {
|
|
||||||
if n_bits == 0 || self.is_zero() { return self; }
|
|
||||||
|
|
||||||
assert!(n_bits < big_digit::BITS);
|
|
||||||
|
|
||||||
let mut carry = 0;
|
|
||||||
let mut shifted = self.data;
|
|
||||||
for elem in shifted.iter_mut() {
|
|
||||||
let new_carry = *elem >> (big_digit::BITS - n_bits);
|
|
||||||
*elem = (*elem << n_bits) | carry;
|
|
||||||
carry = new_carry;
|
|
||||||
}
|
|
||||||
if carry != 0 {
|
|
||||||
shifted.push(carry);
|
|
||||||
}
|
|
||||||
BigUint::new(shifted)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shr_unit(&self, n_unit: usize) -> BigUint {
|
|
||||||
if n_unit == 0 { return self.clone(); }
|
|
||||||
if self.data.len() < n_unit { return Zero::zero(); }
|
|
||||||
BigUint::from_slice(&self.data[n_unit ..])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn shr_bits(self, n_bits: usize) -> BigUint {
|
|
||||||
if n_bits == 0 || self.data.is_empty() { return self; }
|
|
||||||
|
|
||||||
assert!(n_bits < big_digit::BITS);
|
|
||||||
|
|
||||||
let mut borrow = 0;
|
|
||||||
let mut shifted = self.data;
|
|
||||||
for elem in shifted.iter_mut().rev() {
|
|
||||||
let new_borrow = *elem << (big_digit::BITS - n_bits);
|
|
||||||
*elem = (*elem >> n_bits) | borrow;
|
|
||||||
borrow = new_borrow;
|
|
||||||
}
|
|
||||||
BigUint::new(shifted)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determines the fewest bits necessary to express the `BigUint`.
|
/// Determines the fewest bits necessary to express the `BigUint`.
|
||||||
pub fn bits(&self) -> usize {
|
pub fn bits(&self) -> usize {
|
||||||
if self.is_zero() { return 0; }
|
if self.is_zero() { return 0; }
|
||||||
|
@ -1915,7 +1917,9 @@ impl Shr<usize> for BigInt {
|
||||||
type Output = BigInt;
|
type Output = BigInt;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn shr(self, rhs: usize) -> BigInt { (&self) >> rhs }
|
fn shr(self, rhs: usize) -> BigInt {
|
||||||
|
BigInt::from_biguint(self.sign, self.data >> rhs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Shr<usize> for &'a BigInt {
|
impl<'a> Shr<usize> for &'a BigInt {
|
||||||
|
|
Loading…
Reference in New Issue