Implement assign_from_slice

This commit is contained in:
Nicolas Kirchner 2017-08-02 16:12:04 +02:00
parent 54fe41f305
commit 9b56d6667c
5 changed files with 94 additions and 15 deletions

View File

@ -118,7 +118,7 @@ pub fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit) {
rem = r;
}
(a.normalize(), rem)
(a.normalized(), rem)
}
// Only for the Add impl:
@ -339,7 +339,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
mac3(&mut p.data[..], x1, y1);
// Not required, but the adds go faster if we drop any unneeded 0s from the end:
p = p.normalize();
p.normalize();
add2(&mut acc[b..], &p.data[..]);
add2(&mut acc[b * 2..], &p.data[..]);
@ -350,7 +350,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
// p0 = x0 * y0
mac3(&mut p.data[..], x0, y0);
p = p.normalize();
p.normalize();
add2(&mut acc[..], &p.data[..]);
add2(&mut acc[b..], &p.data[..]);
@ -366,7 +366,7 @@ fn mac3(acc: &mut [BigDigit], b: &[BigDigit], c: &[BigDigit]) {
p.data.extend(repeat(0).take(len));
mac3(&mut p.data[..], &j0.data[..], &j1.data[..]);
p = p.normalize();
p.normalize();
sub2(&mut acc[b..], &p.data[..]);
},
@ -383,7 +383,7 @@ pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint {
let mut prod = BigUint { data: vec![0; len] };
mac3(&mut prod.data[..], x, y);
prod.normalize()
prod.normalized()
}
pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit {
@ -480,14 +480,14 @@ pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) {
add2(&mut q.data[j..], &q0.data[..]);
sub2(&mut a.data[j..], &prod.data[..]);
a = a.normalize();
a.normalize();
tmp = q0;
}
debug_assert!(a < b);
(q.normalize(), a >> shift)
(q.normalized(), a >> shift)
}
/// Find last set bit

View File

@ -1395,6 +1395,21 @@ impl BigInt {
BigInt::from_biguint(sign, BigUint::from_slice(slice))
}
/// Reinitializes a `BigInt`.
#[inline]
pub fn assign_from_slice(&mut self, sign: Sign, slice: &[BigDigit]) {
// Normalize:
let slice = &slice[..slice.iter().rposition(|&x| x != 0).map_or(0, |i| i + 1)];
if sign == NoSign || slice.len() == 0 {
self.sign = NoSign;
self.data = Zero::zero();
} else {
self.sign = sign;
self.data.assign_from_slice(slice);
}
}
/// Creates and initializes a `BigInt`.
///
/// The bytes are in big-endian byte order.

View File

@ -449,7 +449,7 @@ impl<'a> Sub<&'a BigUint> for BigUint {
fn sub(mut self, other: &BigUint) -> BigUint {
sub2(&mut self.data[..], &other.data[..]);
self.normalize()
self.normalized()
}
}
@ -463,7 +463,7 @@ impl<'a> Sub<BigUint> for &'a BigUint {
}
sub2rev(&self.data[..], &mut other.data[..]);
other.normalize()
other.normalized()
}
}
@ -477,7 +477,7 @@ impl Sub<BigDigit> for BigUint {
#[inline]
fn sub(mut self, other: BigDigit) -> BigUint {
sub2(&mut self.data[..], &[other]);
self.normalize()
self.normalized()
}
}
@ -491,7 +491,7 @@ impl Sub<BigUint> for BigDigit {
}
sub2rev(&[self], &mut other.data[..]);
other.normalize()
other.normalized()
}
}
@ -502,7 +502,7 @@ impl Sub<DoubleBigDigit> for BigUint {
fn sub(mut self, other: DoubleBigDigit) -> BigUint {
let (hi, lo) = big_digit::from_doublebigdigit(other);
sub2(&mut self.data[..], &[lo, hi]);
self.normalize()
self.normalized()
}
}
@ -517,7 +517,7 @@ impl Sub<BigUint> for DoubleBigDigit {
let (hi, lo) = big_digit::from_doublebigdigit(self);
sub2rev(&[lo, hi], &mut other.data[..]);
other.normalize()
other.normalized()
}
}
@ -1175,7 +1175,7 @@ impl BigUint {
/// The digits are in little-endian base 2^32.
#[inline]
pub fn new(digits: Vec<BigDigit>) -> BigUint {
BigUint { data: digits }.normalize()
BigUint { data: digits }.normalized()
}
/// Creates and initializes a `BigUint`.
@ -1186,6 +1186,16 @@ impl BigUint {
BigUint::new(slice.to_vec())
}
/// Assign a value to a `BigUint`.
///
/// The digits are in little-endian base 2^32.
#[inline]
pub fn assign_from_slice(&mut self, slice: &[BigDigit]) {
self.data.resize(slice.len(), 0);
self.data.copy_from_slice(slice);
self.normalize();
}
/// Creates and initializes a `BigUint`.
///
/// The bytes are in big-endian byte order.
@ -1436,10 +1446,16 @@ impl BigUint {
/// Strips off trailing zero bigdigits - comparisons require the last element in the vector to
/// be nonzero.
#[inline]
fn normalize(mut self) -> BigUint {
fn normalize(&mut self) {
while let Some(&0) = self.data.last() {
self.data.pop();
}
}
/// Returns a normalized `BigUint`.
#[inline]
fn normalized(mut self) -> BigUint {
self.normalize();
self
}
}

View File

@ -59,6 +59,39 @@ fn test_from_biguint() {
check(NoSign, 1, NoSign, 0);
}
#[test]
fn test_from_slice() {
fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) {
let inp = BigInt::from_slice(inp_s, &[inp_n]);
let ans = BigInt {
sign: ans_s,
data: FromPrimitive::from_u32(ans_n).unwrap(),
};
assert_eq!(inp, ans);
}
check(Plus, 1, Plus, 1);
check(Plus, 0, NoSign, 0);
check(Minus, 1, Minus, 1);
check(NoSign, 1, NoSign, 0);
}
#[test]
fn test_assign_from_slice() {
fn check(inp_s: Sign, inp_n: u32, ans_s: Sign, ans_n: u32) {
let mut inp = BigInt::from_slice(Minus, &[2627_u32, 0_u32, 9182_u32, 42_u32]);
inp.assign_from_slice(inp_s, &[inp_n]);
let ans = BigInt {
sign: ans_s,
data: FromPrimitive::from_u32(ans_n).unwrap(),
};
assert_eq!(inp, ans);
}
check(Plus, 1, Plus, 1);
check(Plus, 0, NoSign, 0);
check(Minus, 1, Minus, 1);
check(NoSign, 1, NoSign, 0);
}
#[test]
fn test_from_bytes_be() {
fn check(s: &str, result: &str) {

View File

@ -56,6 +56,21 @@ fn test_from_slice() {
check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]);
}
#[test]
fn test_assign_from_slice() {
fn check(slice: &[BigDigit], data: &[BigDigit]) {
let mut p = BigUint::from_slice(&[2627_u32, 0_u32, 9182_u32, 42_u32]);
p.assign_from_slice(slice);
assert!(p.data == data);
}
check(&[1], &[1]);
check(&[0, 0, 0], &[]);
check(&[1, 2, 0, 0], &[1, 2]);
check(&[0, 0, 1, 2], &[0, 0, 1, 2]);
check(&[0, 0, 1, 2, 0, 0], &[0, 0, 1, 2]);
check(&[-1i32 as BigDigit], &[-1i32 as BigDigit]);
}
#[test]
fn test_from_bytes_be() {
fn check(s: &str, result: &str) {