Optimizing and simplifying add and shl

This commit is contained in:
Tomasz Drwięga 2016-03-07 17:06:08 +01:00
parent 4717be07d6
commit cc0adf5442

View File

@ -71,29 +71,19 @@ macro_rules! uint_overflowing_add_reg {
($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({ ($name:ident, $n_words:expr, $self_expr: expr, $other: expr) => ({
let $name(ref me) = $self_expr; let $name(ref me) = $self_expr;
let $name(ref you) = $other; let $name(ref you) = $other;
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
let mut carry = [0u64; $n_words]; let mut carry = [0u64; $n_words + 1];
let mut b_carry = false;
let mut overflow = false;
for i in 0..$n_words { for i in 0..$n_words {
ret[i] = me[i].wrapping_add(you[i]); let (res1, overflow1) = me[i].overflowing_add(you[i]);
let (res2, overflow2) = res1.overflowing_add(carry[i]);
if ret[i] < me[i] { ret[i] = res2;
if i < $n_words - 1 { carry[i+1] = overflow1 as u64 + overflow2 as u64;
carry[i + 1] = 1;
b_carry = true;
} else {
overflow = true;
}
}
}
if b_carry {
let ret = overflowing!($name(ret).overflowing_add($name(carry)), overflow);
(ret, overflow)
} else {
($name(ret), overflow)
} }
($name(ret), carry[$n_words] > 0)
}) })
} }
@ -673,37 +663,10 @@ macro_rules! construct_uint {
} }
fn overflowing_shl(self, shift32: u32) -> ($name, bool) { fn overflowing_shl(self, shift32: u32) -> ($name, bool) {
let $name(ref original) = self;
let mut ret = [0u64; $n_words];
let shift = shift32 as usize; let shift = shift32 as usize;
let word_shift = shift / 64;
let bit_shift = shift % 64;
for i in 0..$n_words {
// Shift
if i + word_shift < $n_words {
ret[i + word_shift] += original[i] << bit_shift;
}
// Carry
if bit_shift > 0 && i + word_shift + 1 < $n_words {
ret[i + word_shift + 1] += original[i] >> (64 - bit_shift);
}
}
// Detecting overflow
let last = $n_words - word_shift - if bit_shift > 0 { 1 } else { 0 };
let overflow = if bit_shift > 0 {
(original[last] >> (64 - bit_shift)) > 0
} else if word_shift > 0 {
original[last] > 0
} else {
false
};
for i in last+1..$n_words-1 { let res = self << shift;
if original[i] > 0 { (res, self != (res >> shift))
return ($name(ret), true);
}
}
($name(ret), overflow)
} }
} }
@ -987,14 +950,15 @@ macro_rules! construct_uint {
let mut ret = [0u64; $n_words]; let mut ret = [0u64; $n_words];
let word_shift = shift / 64; let word_shift = shift / 64;
let bit_shift = shift % 64; let bit_shift = shift % 64;
for i in 0..$n_words {
// Shift // shift
if i + word_shift < $n_words { for i in word_shift..$n_words {
ret[i + word_shift] += original[i] << bit_shift; ret[i] += original[i - word_shift] << bit_shift;
} }
// Carry // carry
if bit_shift > 0 && i + word_shift + 1 < $n_words { if bit_shift > 0 {
ret[i + word_shift + 1] += original[i] >> (64 - bit_shift); for i in word_shift+1..$n_words {
ret[i] += original[i - 1 - word_shift] >> (64 - bit_shift);
} }
} }
$name(ret) $name(ret)
@ -1672,6 +1636,11 @@ mod tests {
#[test] #[test]
pub fn uint256_shl_overflow() { pub fn uint256_shl_overflow() {
assert_eq!(
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
<< 4,
U256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0").unwrap()
);
assert_eq!( assert_eq!(
U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() U256::from_str("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
.overflowing_shl(4), .overflowing_shl(4),
@ -1681,6 +1650,16 @@ mod tests {
#[test] #[test]
pub fn uint256_shl_overflow_words() { pub fn uint256_shl_overflow_words() {
assert_eq!(
U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
<< 64,
U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap()
);
assert_eq!(
U256::from_str("0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
<< 64,
U256::from_str("ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000").unwrap()
);
assert_eq!( assert_eq!(
U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap() U256::from_str("0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()
.overflowing_shl(64), .overflowing_shl(64),