diff --git a/src/bigint.rs b/src/bigint.rs index b41da436..1fc53547 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -180,6 +180,22 @@ impl fmt::UpperHex for BigInt { } } +// Negation in two's complement. +// acc must be initialized as 1 for least-significant digit. +// +// When negating, a carry (acc == 1) means that all the digits +// considered to this point were zero. This means that if all the +// digits of a negative BigInt have been considered, carry must be +// zero as we cannot have negative zero. +// +// 01 -> ...f ff +// ff -> ...f 01 +// 01 00 -> ...f ff 00 +// 01 01 -> ...f fe ff +// 01 ff -> ...f fe 01 +// ff 00 -> ...f 01 00 +// ff 01 -> ...f 00 ff +// ff ff -> ...f 00 01 #[inline] fn negate_carry(a: BigDigit, acc: &mut DoubleBigDigit) -> BigDigit { *acc += (!a) as DoubleBigDigit; @@ -195,10 +211,10 @@ fn normalize(i: &mut BigInt) { } } -// ! 0 = !...0000 = ...ffff - ...0000 = ...ffff = -1 -// !+1 = !...0001 = ...ffff - ...0001 = ...fffe = -2 -// !-2 = !...fffe = ...ffff - ...fffe = ...0001 = +1 -// !-1 = !...ffff = ...ffff - ...ffff = ...0000 = 0 +// !-2 = !...f fe = ...0 01 = +1 +// !-1 = !...f ff = ...0 00 = 0 +// ! 0 = !...0 00 = ...f ff = -1 +// !+1 = !...0 01 = ...f fe = -2 impl Not for BigInt { type Output = BigInt; @@ -221,74 +237,77 @@ impl Not for BigInt { } } -// +1 & +ff = ...0001 & ...00ff = 0001 = +1 -// +ff & +1 = ...00ff & ...0001 = 0001 = +1 +// +1 & +ff = ...0 01 & ...0 ff = 01 = +1 +// +ff & +1 = ...0 ff & ...0 01 = 01 = +1 // answer is pos, has length of shortest fn bitand_pos_pos(a: &mut Vec, b: &Vec) { for (ai, &bi) in a.iter_mut().zip(b.iter()) { *ai &= bi; } - a.truncate(b.len()); + if a.len() > b.len() { + a.truncate(b.len()); + } } -// +1 & -ff = ...0001 & ...ff01 = ...0001 = +1 -// +ff & -1 = ...00ff & ...ffff = ...00ff = +ff +// + 1 & -ff = ...0 01 & ...f 01 = ...0 01 = + 1 +// +ff & - 1 = ...0 ff & ...f ff = ...0 ff = +ff // answer is pos, has length of a fn bitand_pos_neg(a: &mut Vec, b: &Vec) { let mut carry_b = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_b = negate_carry(bi, &mut carry_b); - *ai &= abs_b; - } - if a.len() > b.len() { - debug_assert!(carry_b == 0); + let twos_b = negate_carry(bi, &mut carry_b); + *ai &= twos_b; } + debug_assert!(b.len() > a.len() || carry_b == 0); } -// -1 & +ff = ...ffff & ...00ff = ...00ff = +ff -// -ff & +1 = ...ff01 & ...0001 = ...0001 = +1 +// - 1 & +ff = ...f ff & ...0 ff = ...0 ff = +ff +// -ff & + 1 = ...f 01 & ...0 01 = ...0 01 = + 1 // answer is pos, has length of b fn bitand_neg_pos(a: &mut Vec, b: &Vec) { let mut carry_a = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_a = negate_carry(*ai, &mut carry_a); - *ai = abs_a & bi; + let twos_a = negate_carry(*ai, &mut carry_a); + *ai = twos_a & bi; } - if b.len() > a.len() { - debug_assert!(carry_a == 0); + debug_assert!(a.len() > b.len() || carry_a == 0); + if a.len() > b.len() { + a.truncate(b.len()); + } else if b.len() > a.len() { let extra = &b[a.len()..]; a.extend(extra.iter().cloned()); - } else { - a.truncate(b.len()); } } -// -1 & -ff = ...ffff & ...ff01 = ...ff01 = -ff -// -ff & -1 = ...ff01 & ...ffff = ...ff01 = -ff -// -ff & -fe = ...ff01 & ...ff02 = ...ff00 = -100 -// answer is neg, has length of longest with possible carry +// - 1 & -ff = ...f ff & ...f 01 = ...f 01 = - ff +// -ff & - 1 = ...f 01 & ...f ff = ...f 01 = - ff +// -ff & -fe = ...f 01 & ...f 02 = ...f 00 = -100 +// answer is neg, has length of longest with a possible carry fn bitand_neg_neg(a: &mut Vec, b: &Vec) { let mut carry_a = 1; let mut carry_b = 1; let mut carry_and = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_a = negate_carry(*ai, &mut carry_a); - let abs_b = negate_carry(bi, &mut carry_b); - *ai = negate_carry(abs_a & abs_b, &mut carry_and); + let twos_a = negate_carry(*ai, &mut carry_a); + let twos_b = negate_carry(bi, &mut carry_b); + *ai = negate_carry(twos_a & twos_b, &mut carry_and); } - if b.len() > a.len() { + debug_assert!(a.len() > b.len() || carry_a == 0); + debug_assert!(b.len() > a.len() || carry_b == 0); + if a.len() > b.len() { + for ai in a[b.len()..].iter_mut() { + let twos_a = negate_carry(*ai, &mut carry_a); + *ai = negate_carry(twos_a, &mut carry_and); + } + debug_assert!(carry_a == 0); + } else if b.len() > a.len() { let extra = &b[a.len()..]; a.extend(extra.iter().map(|&bi| { - let abs_b = negate_carry(bi, &mut carry_b); - negate_carry(abs_b, &mut carry_and) + let twos_b = negate_carry(bi, &mut carry_b); + negate_carry(twos_b, &mut carry_and) })); - } else { - for ai in a[b.len()..].iter_mut() { - let abs_a = negate_carry(*ai, &mut carry_a); - *ai = negate_carry(abs_a, &mut carry_and); - } + debug_assert!(carry_b == 0); } - debug_assert!(carry_a == 0 && carry_b == 0); if carry_and != 0 { a.push(1); } @@ -306,36 +325,40 @@ impl<'a> BitAnd<&'a BigInt> for BigInt { impl<'a> BitAndAssign<&'a BigInt> for BigInt { fn bitand_assign(&mut self, other: &BigInt) { match (self.sign, other.sign) { - (Sign::NoSign, Sign::NoSign) => { - // do nothing + (Sign::NoSign, _) => { + return; } - (Sign::Minus, Sign::Minus) => { - bitand_neg_neg(biguint::digits_mut(&mut self.data), + (_, Sign::NoSign) => { + self.assign_from_slice(Sign::NoSign, &[]); + return; + } + (Sign::Plus, Sign::Plus) => { + bitand_pos_pos(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); - self.sign = Sign::Minus; + self.sign = Sign::Plus; } - (_, Sign::Minus) => { + (Sign::Plus, Sign::Minus) => { bitand_pos_neg(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Plus; } - (Sign::Minus, _) => { + (Sign::Minus, Sign::Plus) => { bitand_neg_pos(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Plus; } - (_, _) => { - bitand_pos_pos(biguint::digits_mut(&mut self.data), + (Sign::Minus, Sign::Minus) => { + bitand_neg_neg(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); - self.sign = Sign::Plus; + self.sign = Sign::Minus; } } normalize(self); } } -// +1 | +ff = ...0001 | ...00ff = 00ff = +ff -// +ff | +1 = ...00ff | ...0001 = 00ff = +ff +// + 1 | +ff = ...0 01 | ...0 ff = ...0 ff = +ff +// +ff | + 1 = ...0 ff | ...0 01 = ...0 ff = +ff // answer is pos, has length of longest fn bitor_pos_pos(a: &mut Vec, b: &Vec) { for (ai, &bi) in a.iter_mut().zip(b.iter()) { @@ -347,71 +370,71 @@ fn bitor_pos_pos(a: &mut Vec, b: &Vec) { } } -// +1 | -ff = ...0001 | ...ff01 = ...ff01 = -ff -// +ff | -1 = ...00ff | ...ffff = ...ffff = -1 +// + 1 | -ff = ...0 01 | ...f 01 = ...f 01 = -ff +// +ff | - 1 = ...0 ff | ...f ff = ...f ff = - 1 // answer is neg, has length of b fn bitor_pos_neg(a: &mut Vec, b: &Vec) { let mut carry_b = 1; let mut carry_or = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_b = negate_carry(bi, &mut carry_b); - *ai = negate_carry(*ai | abs_b, &mut carry_or); + let twos_b = negate_carry(bi, &mut carry_b); + *ai = negate_carry(*ai | twos_b, &mut carry_or); } - if b.len() > a.len() { + debug_assert!(b.len() > a.len() || carry_b == 0); + if a.len() > b.len() { + a.truncate(b.len()); + } else if b.len() > a.len() { let extra = &b[a.len()..]; a.extend(extra.iter().map(|&bi| { - let abs_b = negate_carry(bi, &mut carry_b); - negate_carry(abs_b, &mut carry_or) + let twos_b = negate_carry(bi, &mut carry_b); + negate_carry(twos_b, &mut carry_or) })); - } else { - a.truncate(b.len()); - } - debug_assert!(carry_b == 0); - if carry_or != 0 { - a.push(1); + debug_assert!(carry_b == 0); } + // for carry_or to be non-zero, we would need twos_b == 0 + debug_assert!(carry_or == 0); } -// -1 | +ff = ...ffff | ...00ff = ...ffff = -1 -// -ff | +1 = ...ff01 | ...0001 = ...ff01 = -ff +// - 1 | +ff = ...f ff | ...0 ff = ...f ff = - 1 +// -ff | + 1 = ...f 01 | ...0 01 = ...f 01 = -ff // answer is neg, has length of a fn bitor_neg_pos(a: &mut Vec, b: &Vec) { let mut carry_a = 1; let mut carry_or = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_a = negate_carry(*ai, &mut carry_a); - *ai = negate_carry(abs_a | bi, &mut carry_or); + let twos_a = negate_carry(*ai, &mut carry_a); + *ai = negate_carry(twos_a | bi, &mut carry_or); } + debug_assert!(a.len() > b.len() || carry_a == 0); if a.len() > b.len() { for ai in a[b.len()..].iter_mut() { - let abs_a = negate_carry(*ai, &mut carry_a); - *ai = negate_carry(abs_a, &mut carry_or); + let twos_a = negate_carry(*ai, &mut carry_a); + *ai = negate_carry(twos_a, &mut carry_or); } + debug_assert!(carry_a == 0); } - debug_assert!(carry_a == 0); - if carry_or != 0 { - a.push(1); - } + // for carry_or to be non-zero, we would need twos_a == 0 + debug_assert!(carry_or == 0); } -// -1 | -ff = ...ffff | ...ff01 = ...ffff = -1 -// -ff | -1 = ...ff01 | ...ffff = ...ffff = -1 +// - 1 | -ff = ...f ff | ...f 01 = ...f ff = -1 +// -ff | - 1 = ...f 01 | ...f ff = ...f ff = -1 // answer is neg, has length of shortest fn bitor_neg_neg(a: &mut Vec, b: &Vec) { let mut carry_a = 1; let mut carry_b = 1; let mut carry_or = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_a = negate_carry(*ai, &mut carry_a); - let abs_b = negate_carry(bi, &mut carry_b); - *ai = negate_carry(abs_a | abs_b, &mut carry_or); + let twos_a = negate_carry(*ai, &mut carry_a); + let twos_b = negate_carry(bi, &mut carry_b); + *ai = negate_carry(twos_a | twos_b, &mut carry_or); } - if b.len() > a.len() { - debug_assert!(carry_a == 0); - } else { - debug_assert!(carry_b == 0); + debug_assert!(a.len() > b.len() || carry_a == 0); + debug_assert!(b.len() > a.len() || carry_b == 0); + if a.len() > b.len() { + a.truncate(b.len()); } - a.truncate(b.len()); + // for carry_or to be non-zero, we would need twos_a == 0 or twos_b == 0 debug_assert!(carry_or == 0); } @@ -427,36 +450,40 @@ impl<'a> BitOr<&'a BigInt> for BigInt { impl<'a> BitOrAssign<&'a BigInt> for BigInt { fn bitor_assign(&mut self, other: &BigInt) { match (self.sign, other.sign) { - (Sign::NoSign, Sign::NoSign) => { - // do nothing + (_, Sign::NoSign) => { + return; } - (Sign::Minus, Sign::Minus) => { - bitor_neg_neg(biguint::digits_mut(&mut self.data), + (Sign::NoSign, _) => { + self.assign_from_slice(other.sign, biguint::digits(&other.data)); + return; + } + (Sign::Plus, Sign::Plus) => { + bitor_pos_pos(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); - self.sign = Sign::Minus; + self.sign = Sign::Plus; } - (_, Sign::Minus) => { + (Sign::Plus, Sign::Minus) => { bitor_pos_neg(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Minus; } - (Sign::Minus, _) => { + (Sign::Minus, Sign::Plus) => { bitor_neg_pos(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Minus; } - (_, _) => { - bitor_pos_pos(biguint::digits_mut(&mut self.data), + (Sign::Minus, Sign::Minus) => { + bitor_neg_neg(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); - self.sign = Sign::Plus; + self.sign = Sign::Minus; } } normalize(self); } } -// +1 ^ +ff = ...0001 ^ ...00ff = 00fe = +fe -// +ff ^ +1 = ...00ff ^ ...0001 = 00fe = +fe +// + 1 ^ +ff = ...0 01 ^ ...0 ff = 0 fe = +fe +// +ff ^ + 1 = ...0 ff ^ ...0 01 = 0 fe = +fe // answer is pos, has length of longest fn bitxor_pos_pos(a: &mut Vec, b: &Vec) { for (ai, &bi) in a.iter_mut().zip(b.iter()) { @@ -468,88 +495,93 @@ fn bitxor_pos_pos(a: &mut Vec, b: &Vec) { } } -// +1 ^ -ff = ...0001 ^ ...ff01 = ...ff00 = -100 -// +ff ^ -1 = ...00ff ^ ...ffff = ...ff00 = -100 +// + 1 ^ -ff = ...0 01 ^ ...f 01 = ...f 00 = -100 +// +ff ^ - 1 = ...0 ff ^ ...f ff = ...f 00 = -100 // answer is neg, has length of longest with a possible carry fn bitxor_pos_neg(a: &mut Vec, b: &Vec) { let mut carry_b = 1; let mut carry_xor = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_b = negate_carry(bi, &mut carry_b); - *ai = negate_carry(*ai ^ abs_b, &mut carry_xor); + let twos_b = negate_carry(bi, &mut carry_b); + *ai = negate_carry(*ai ^ twos_b, &mut carry_xor); } - if b.len() > a.len() { + debug_assert!(b.len() > a.len() || carry_b == 0); + if a.len() > b.len() { + for ai in a[b.len()..].iter_mut() { + let twos_b = !0; + *ai = negate_carry(*ai ^ twos_b, &mut carry_xor); + } + } else if b.len() > a.len() { let extra = &b[a.len()..]; a.extend(extra.iter().map(|&bi| { - let abs_b = negate_carry(bi, &mut carry_b); - negate_carry(abs_b, &mut carry_xor) + let twos_b = negate_carry(bi, &mut carry_b); + negate_carry(twos_b, &mut carry_xor) })); - } else { - for ai in a[b.len()..].iter_mut() { - let abs_b = negate_carry(0, &mut carry_b); - *ai = negate_carry(*ai ^ abs_b, &mut carry_xor); - } + debug_assert!(carry_b == 0); } - debug_assert!(carry_b == 0); if carry_xor != 0 { a.push(1); } } -// -1 ^ +ff = ...ffff ^ ...00ff = ...ff00 = -100 -// -ff ^ +1 = ...ff01 ^ ...0001 = ...ff00 = -100 +// - 1 ^ +ff = ...f ff ^ ...0 ff = ...f 00 = -100 +// -ff ^ + 1 = ...f 01 ^ ...0 01 = ...f 00 = -100 // answer is neg, has length of longest with a possible carry fn bitxor_neg_pos(a: &mut Vec, b: &Vec) { let mut carry_a = 1; let mut carry_xor = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_a = negate_carry(*ai, &mut carry_a); - *ai = negate_carry(abs_a ^ bi, &mut carry_xor); + let twos_a = negate_carry(*ai, &mut carry_a); + *ai = negate_carry(twos_a ^ bi, &mut carry_xor); } - if b.len() > a.len() { + debug_assert!(a.len() > b.len() || carry_a == 0); + if a.len() > b.len() { + for ai in a[b.len()..].iter_mut() { + let twos_a = negate_carry(*ai, &mut carry_a); + *ai = negate_carry(twos_a, &mut carry_xor); + } + debug_assert!(carry_a == 0); + } else if b.len() > a.len() { let extra = &b[a.len()..]; a.extend(extra.iter().map(|&bi| { - let abs_a = negate_carry(0, &mut carry_a); - negate_carry(abs_a ^ bi, &mut carry_xor) + let twos_a = !0; + negate_carry(twos_a ^ bi, &mut carry_xor) })); - } else { - for ai in a[b.len()..].iter_mut() { - let abs_a = negate_carry(*ai, &mut carry_a); - *ai = negate_carry(abs_a, &mut carry_xor); - } } - debug_assert!(carry_a == 0); if carry_xor != 0 { a.push(1); } } -// -1 ^ -ff = ...ffff ^ ...ff01 = ...00fe = +fe -// -ff & -1 = ...ff01 ^ ...ffff = ...00fe = +fe +// - 1 ^ -ff = ...f ff ^ ...f 01 = ...0 fe = +fe +// -ff & - 1 = ...f 01 ^ ...f ff = ...0 fe = +fe // answer is pos, has length of longest fn bitxor_neg_neg(a: &mut Vec, b: &Vec) { let mut carry_a = 1; let mut carry_b = 1; for (ai, &bi) in a.iter_mut().zip(b.iter()) { - let abs_a = negate_carry(*ai, &mut carry_a); - let abs_b = negate_carry(bi, &mut carry_b); - *ai = abs_a ^ abs_b; + let twos_a = negate_carry(*ai, &mut carry_a); + let twos_b = negate_carry(bi, &mut carry_b); + *ai = twos_a ^ twos_b; } - if b.len() > a.len() { + debug_assert!(a.len() > b.len() || carry_a == 0); + debug_assert!(b.len() > a.len() || carry_b == 0); + if a.len() > b.len() { + for ai in a[b.len()..].iter_mut() { + let twos_a = negate_carry(*ai, &mut carry_a); + let twos_b = !0; + *ai = twos_a ^ twos_b; + } + debug_assert!(carry_a == 0); + } else if b.len() > a.len() { let extra = &b[a.len()..]; a.extend(extra.iter().map(|&bi| { - let abs_a = negate_carry(0, &mut carry_a); - let abs_b = negate_carry(bi, &mut carry_b); - abs_a ^ abs_b + let twos_a = !0; + let twos_b = negate_carry(bi, &mut carry_b); + twos_a ^ twos_b })); - } else { - for ai in a[b.len()..].iter_mut() { - let abs_a = negate_carry(*ai, &mut carry_a); - let abs_b = negate_carry(0, &mut carry_b); - *ai = abs_a ^ abs_b; - } + debug_assert!(carry_b == 0); } - debug_assert!(carry_a == 0 && carry_b == 0); } impl<'a> BitXor<&'a BigInt> for BigInt { @@ -564,26 +596,30 @@ impl<'a> BitXor<&'a BigInt> for BigInt { impl<'a> BitXorAssign<&'a BigInt> for BigInt { fn bitxor_assign(&mut self, other: &BigInt) { match (self.sign, other.sign) { - (Sign::NoSign, Sign::NoSign) => { - // do nothing + (_, Sign::NoSign) => { + return; } - (Sign::Minus, Sign::Minus) => { - bitxor_neg_neg(biguint::digits_mut(&mut self.data), + (Sign::NoSign, _) => { + self.assign_from_slice(other.sign, biguint::digits(&other.data)); + return; + } + (Sign::Plus, Sign::Plus) => { + bitxor_pos_pos(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Plus; } - (_, Sign::Minus) => { + (Sign::Plus, Sign::Minus) => { bitxor_pos_neg(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Minus; } - (Sign::Minus, _) => { + (Sign::Minus, Sign::Plus) => { bitxor_neg_pos(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Minus; } - (_, _) => { - bitxor_pos_pos(biguint::digits_mut(&mut self.data), + (Sign::Minus, Sign::Minus) => { + bitxor_neg_neg(biguint::digits_mut(&mut self.data), biguint::digits(&other.data)); self.sign = Sign::Plus; } diff --git a/src/biguint.rs b/src/biguint.rs index 3eb26b0e..40417206 100644 --- a/src/biguint.rs +++ b/src/biguint.rs @@ -22,7 +22,7 @@ use traits::{ToPrimitive, FromPrimitive, Float, Num, Unsigned, CheckedAdd, Check CheckedDiv, Zero, One}; #[path = "algorithms.rs"] -pub mod algorithms; +mod algorithms; #[path = "monty.rs"] mod monty; pub use self::algorithms::big_digit;