From e520bdad0d047d9f0fb7aad46f44faae9d45de9d Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Mon, 24 Oct 2016 07:41:59 +0100 Subject: [PATCH 01/24] Add scalar multiplication to BigUint, BigInt BigUint and BigInt can now be multiplied by a BigDigit, re-using the same buffer for the output, thereby reducing allocations and copying. --- bigint/src/algorithms.rs | 17 +++++++++++++++++ bigint/src/bigint.rs | 9 +++++++++ bigint/src/biguint.rs | 15 ++++++++++++++- bigint/src/tests/bigint.rs | 25 +++++++++++++++++++++++++ bigint/src/tests/biguint.rs | 20 ++++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) diff --git a/bigint/src/algorithms.rs b/bigint/src/algorithms.rs index 0afd6b1..3c1ac9f 100644 --- a/bigint/src/algorithms.rs +++ b/bigint/src/algorithms.rs @@ -85,6 +85,15 @@ pub fn mac_with_carry(a: BigDigit, b: BigDigit, c: BigDigit, carry: &mut BigDigi lo } +#[inline] +pub fn mul_with_carry(a: BigDigit, b: BigDigit, carry: &mut BigDigit) -> BigDigit { + let (hi, lo) = big_digit::from_doublebigdigit((a as DoubleBigDigit) * (b as DoubleBigDigit) + + (*carry as DoubleBigDigit)); + + *carry = hi; + lo +} + /// Divide a two digit numerator by a one digit divisor, returns quotient and remainder: /// /// Note: the caller must ensure that both the quotient and remainder will fit into a single digit. @@ -377,6 +386,14 @@ pub fn mul3(x: &[BigDigit], y: &[BigDigit]) -> BigUint { prod.normalize() } +pub fn scalar_mul(a: &mut [BigDigit], b: BigDigit) -> BigDigit { + let mut carry = 0; + for a in a.iter_mut() { + *a = mul_with_carry(*a, b, &mut carry); + } + carry +} + pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) { if d.is_zero() { panic!() diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index b86ca52..93f4ae7 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -436,6 +436,15 @@ impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { } } +impl Mul for BigInt { + type Output = BigInt; + + #[inline] + fn mul(self, other: BigDigit) -> BigInt { + BigInt::from_biguint(self.sign, self.data * other) + } +} + forward_all_binop_to_ref_ref!(impl Div for BigInt, div); impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 340aaae..a5b74d0 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -22,7 +22,7 @@ mod algorithms; pub use self::algorithms::big_digit; pub use self::big_digit::{BigDigit, DoubleBigDigit, ZERO_BIG_DIGIT}; -use self::algorithms::{mac_with_carry, mul3, div_rem, div_rem_digit}; +use self::algorithms::{mac_with_carry, mul3, scalar_mul, div_rem, div_rem_digit}; use self::algorithms::{__add2, add2, sub2, sub2rev}; use self::algorithms::{biguint_shl, biguint_shr}; use self::algorithms::{cmp_slice, fls, ilog2}; @@ -431,6 +431,19 @@ impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { } } +impl Mul for BigUint { + type Output = BigUint; + + #[inline] + fn mul(mut self, other: BigDigit) -> BigUint { + let carry = scalar_mul(&mut self.data[..], other); + if carry != 0 { + self.data.push(carry); + } + self + } +} + forward_all_binop_to_ref_ref!(impl Div for BigUint, div); impl<'a, 'b> Div<&'b BigUint> for &'a BigUint { diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index aa4319d..9e83373 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -637,6 +637,31 @@ fn test_mul() { } } +#[test] +fn test_scalar_mul() { + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let c = BigInt::from_slice(Plus, c_vec); + let nc = BigInt::from_slice(Minus, c_vec); + + if a_vec.len() == 1 { + let b = BigInt::from_slice(Plus, b_vec); + let nb = BigInt::from_slice(Minus, b_vec); + let a = a_vec[0]; + assert!(b * a == c); + assert!(nb * a == nc); + } + + if b_vec.len() == 1 { + let a = BigInt::from_slice(Plus, a_vec); + let na = BigInt::from_slice(Minus, a_vec); + let b = b_vec[0]; + assert!(a * b == c); + assert!(na * b == nc); + } + } +} + #[test] fn test_div_mod_floor() { fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) { diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index 7c5a423..ac95235 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -770,6 +770,26 @@ fn test_mul() { } } +#[test] +fn test_scalar_mul() { + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let c = BigUint::from_slice(c_vec); + + if a_vec.len() == 1 { + let b = BigUint::from_slice(b_vec); + let a = a_vec[0]; + assert!(b * a == c); + } + + if b_vec.len() == 1 { + let a = BigUint::from_slice(a_vec); + let b = b_vec[0]; + assert!(a * b == c); + } + } +} + #[test] fn test_div_rem() { for elm in MUL_TRIPLES.iter() { From a2a28c682e0c677e553723494e4428fa1e88c651 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Wed, 28 Jun 2017 15:38:48 +0100 Subject: [PATCH 02/24] Scalar addition of BigDigit to BigUint A BigDigit can be added to a BigUint - this is one of several operations being implemented to allow scalar operations on BigInt and BigUint across the board. --- bigint/src/biguint.rs | 17 +++++++++++++++++ bigint/src/tests/biguint.rs | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index a5b74d0..2f5f462 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -394,6 +394,23 @@ impl<'a> Add<&'a BigUint> for BigUint { } } +impl Add for BigUint { + type Output = BigUint; + + #[inline] + fn add(mut self, other: BigDigit) -> BigUint { + if self.data.len() == 0 { + self.data.push(0); + } + + let carry = __add2(&mut self.data, &[other]); + if carry != 0 { + self.data.push(carry); + } + self + } +} + forward_val_val_binop!(impl Sub for BigUint, sub); forward_ref_ref_binop!(impl Sub for BigUint, sub); diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index ac95235..31ac79b 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -690,6 +690,26 @@ fn test_add() { } } +#[test] +fn test_scalar_add() { + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let c = BigUint::from_slice(c_vec); + + if a_vec.len() == 1 { + let a = a_vec[0]; + let b = BigUint::from_slice(b_vec); + assert!(b + a == c); + } + + if b_vec.len() == 1 { + let a = BigUint::from_slice(a_vec); + let b = b_vec[0]; + assert!(a + b == c); + } + } +} + #[test] fn test_sub() { for elm in SUM_TRIPLES.iter() { From 7b7799eab7d1ee1888bf7ce1978a7c8675ab228e Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Wed, 28 Jun 2017 16:24:56 +0100 Subject: [PATCH 03/24] Scalar subtraction of a BigDigit from a BigUint A BigDigit can be subtracted from a BigUint - this is one of several operations being implemented to allow scalar operations on BigInt and BigUint across the board. --- bigint/src/biguint.rs | 10 ++++++++++ bigint/src/tests/biguint.rs | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 2f5f462..5d71465 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -437,6 +437,16 @@ impl<'a> Sub for &'a BigUint { } } +impl Sub for BigUint { + type Output = BigUint; + + #[inline] + fn sub(mut self, other: BigDigit) -> BigUint { + sub2(&mut self.data[..], &[other]); + self.normalize() + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigUint, mul); impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index 31ac79b..f5c226f 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -723,6 +723,27 @@ fn test_sub() { } } +#[test] +fn test_scalar_sub() { + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + + if a_vec.len() == 1 { + let a = a_vec[0]; + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); + assert!(c - a == b); + } + + if b_vec.len() == 1 { + let a = BigUint::from_slice(a_vec); + let b = b_vec[0]; + let c = BigUint::from_slice(c_vec); + assert!(c - b == a); + } + } +} + #[test] #[should_panic] fn test_sub_fail_on_underflow() { From 530e2f60225649e7a7f49982e9bcbd072939969b Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Wed, 28 Jun 2017 16:26:40 +0100 Subject: [PATCH 04/24] Fix typo in comment in division algorithm --- bigint/src/algorithms.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigint/src/algorithms.rs b/bigint/src/algorithms.rs index 3c1ac9f..604fee2 100644 --- a/bigint/src/algorithms.rs +++ b/bigint/src/algorithms.rs @@ -433,7 +433,7 @@ pub fn div_rem(u: &BigUint, d: &BigUint) -> (BigUint, BigUint) { // q0, our guess, is calculated by dividing the last few digits of a by the last digit of b // - this should give us a guess that is "close" to the actual quotient, but is possibly // greater than the actual quotient. If q0 * b > a, we simply use iterated subtraction - // until we have a guess such that q0 & b <= a. + // until we have a guess such that q0 * b <= a. // let bn = *b.data.last().unwrap(); From 784d26bbf8e24dd7ce1b6f7c8e4cd45a496aa11f Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Wed, 28 Jun 2017 16:59:35 +0100 Subject: [PATCH 05/24] Scalar division of a BigUint by a BigDigit A BigUint can be divided by a BigDigit - this is one of several operations being implemented to allow scalar operations on BigInt and BigUint across the board. --- bigint/src/biguint.rs | 24 ++++++++++++++++++++++-- bigint/src/tests/biguint.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 5d71465..9064490 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -479,7 +479,17 @@ impl<'a, 'b> Div<&'b BigUint> for &'a BigUint { #[inline] fn div(self, other: &BigUint) -> BigUint { let (q, _) = self.div_rem(other); - return q; + q + } +} + +impl Div for BigUint { + type Output = BigUint; + + #[inline] + fn div(self, other: BigDigit) -> BigUint { + let (q, _) = div_rem_digit(self, other); + q } } @@ -491,7 +501,17 @@ impl<'a, 'b> Rem<&'b BigUint> for &'a BigUint { #[inline] fn rem(self, other: &BigUint) -> BigUint { let (_, r) = self.div_rem(other); - return r; + r + } +} + +impl Rem for BigUint { + type Output = BigDigit; + + #[inline] + fn rem(self, other: BigDigit) -> BigDigit { + let (_, r) = div_rem_digit(self, other); + r } } diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index f5c226f..1c57d86 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -866,6 +866,41 @@ fn test_div_rem() { } } +#[test] +fn test_scalar_div_rem() { + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let c = BigUint::from_slice(c_vec); + + if a_vec.len() == 1 && a_vec[0] != 0 { + let a = a_vec[0]; + let b = BigUint::from_slice(b_vec); + assert!(c.clone() / a == b); + assert!(c.clone() % a == Zero::zero()); + } + + if b_vec.len() == 1 && b_vec[0] != 0 { + let a = BigUint::from_slice(a_vec); + let b = b_vec[0]; + assert!(c.clone() / b == a); + assert!(c.clone() % b == Zero::zero()); + } + } + + for elm in DIV_REM_QUADRUPLES.iter() { + let (a_vec, b_vec, c_vec, d_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let c = BigUint::from_slice(c_vec); + + if b_vec.len() == 1 && b_vec[0] != 0 { + let b = b_vec[0]; + let d = d_vec[0]; + assert!(a.clone() / b == c); + assert!(a.clone() % b == d); + } + } +} + #[test] fn test_checked_add() { for elm in SUM_TRIPLES.iter() { From e5ed5031414f7840ce4d71e6601dfff6678a7b65 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 08:41:46 +0100 Subject: [PATCH 06/24] Implement all variants of adding BigDigit to BigUint Allow the addition to occur with either operand order, and with any combination of owned and borrowed arguments. --- bigint/src/biguint.rs | 2 + bigint/src/macros.rs | 88 +++++++++++++++++++++++++++++++++++++ bigint/src/tests/biguint.rs | 6 ++- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 9064490..3063236 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -394,6 +394,8 @@ impl<'a> Add<&'a BigUint> for BigUint { } } +forward_all_scalar_binop_to_val_val!(impl Add for BigUint, add); + impl Add for BigUint { type Output = BigUint; diff --git a/bigint/src/macros.rs b/bigint/src/macros.rs index 39f45a4..c6ebf71 100644 --- a/bigint/src/macros.rs +++ b/bigint/src/macros.rs @@ -105,6 +105,85 @@ macro_rules! forward_ref_ref_binop_commutative { } } +macro_rules! forward_scalar_val_val_binop { + (impl $imp:ident<$scalar:ty> for $res:ty, $method: ident) => { + impl $imp<$res> for $scalar { + type Output = $res; + + #[inline] + fn $method(self, other: $res) -> $res { + $imp::$method(other, self) + } + } + } +} + +macro_rules! forward_scalar_val_ref_binop { + (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { + impl<'a> $imp<&'a $scalar> for $res { + type Output = $res; + + #[inline] + fn $method(self, other: &$scalar) -> $res { + $imp::$method(self, *other) + } + } + + impl<'a> $imp<$res> for &'a $scalar { + type Output = $res; + + #[inline] + fn $method(self, other: $res) -> $res { + $imp::$method(other, *self) + } + } + } +} + +macro_rules! forward_scalar_ref_val_binop { + (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { + impl<'a> $imp<$scalar> for &'a $res { + type Output = $res; + + #[inline] + fn $method(self, other: $scalar) -> $res { + $imp::$method(self.clone(), other) + } + } + + impl<'a> $imp<&'a $res> for $scalar { + type Output = $res; + + #[inline] + fn $method(self, other: &$res) -> $res { + $imp::$method(other.clone(), self) + } + } + } +} + +macro_rules! forward_scalar_ref_ref_binop { + (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { + impl<'a, 'b> $imp<&'b $scalar> for &'a $res { + type Output = $res; + + #[inline] + fn $method(self, other: &$scalar) -> $res { + $imp::$method(self.clone(), *other) + } + } + + impl<'a, 'b> $imp<&'a $res> for &'b $scalar { + type Output = $res; + + #[inline] + fn $method(self, other: &$res) -> $res { + $imp::$method(other.clone(), *self) + } + } + } +} + // Forward everything to ref-ref, when reusing storage is not helpful macro_rules! forward_all_binop_to_ref_ref { (impl $imp:ident for $res:ty, $method:ident) => { @@ -131,3 +210,12 @@ macro_rules! forward_all_binop_to_val_ref_commutative { forward_ref_ref_binop_commutative!(impl $imp for $res, $method); }; } + +macro_rules! forward_all_scalar_binop_to_val_val { + (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { + forward_scalar_val_val_binop!(impl $imp<$scalar> for $res, $method); + forward_scalar_val_ref_binop!(impl $imp<$scalar> for $res, $method); + forward_scalar_ref_val_binop!(impl $imp<$scalar> for $res, $method); + forward_scalar_ref_ref_binop!(impl $imp<$scalar> for $res, $method); + } +} diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index 1c57d86..f3627fa 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -699,13 +699,15 @@ fn test_scalar_add() { if a_vec.len() == 1 { let a = a_vec[0]; let b = BigUint::from_slice(b_vec); - assert!(b + a == c); + assert_op!(a + b == c); + assert_op!(b + a == c); } if b_vec.len() == 1 { let a = BigUint::from_slice(a_vec); let b = b_vec[0]; - assert!(a + b == c); + assert_op!(a + b == c); + assert_op!(b + a == c); } } } From fd2f516a5dae187ec37ec610249e5fa9c0b17018 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 09:56:15 +0100 Subject: [PATCH 07/24] All variants of multiplying BigUint by BigDigit Allow the multiplication to occur with either operand order and with any combination of owned and borrowed arguments. --- bigint/src/biguint.rs | 2 ++ bigint/src/tests/biguint.rs | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 3063236..ffe14e0 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -460,6 +460,8 @@ impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { } } +forward_all_scalar_binop_to_val_val!(impl Mul for BigUint, mul); + impl Mul for BigUint { type Output = BigUint; diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index f3627fa..da6c956 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -822,13 +822,15 @@ fn test_scalar_mul() { if a_vec.len() == 1 { let b = BigUint::from_slice(b_vec); let a = a_vec[0]; - assert!(b * a == c); + assert_op!(a * b == c); + assert_op!(b * a == c); } if b_vec.len() == 1 { let a = BigUint::from_slice(a_vec); let b = b_vec[0]; - assert!(a * b == c); + assert_op!(a * b == c); + assert_op!(b * a == c); } } } From 5738141b7ce089ad209497a32835a6a2751fd6e8 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 09:59:42 +0100 Subject: [PATCH 08/24] Distinction for commutative scalar ops --- bigint/src/biguint.rs | 4 ++-- bigint/src/macros.rs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index ffe14e0..b2e4492 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -394,7 +394,7 @@ impl<'a> Add<&'a BigUint> for BigUint { } } -forward_all_scalar_binop_to_val_val!(impl Add for BigUint, add); +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); impl Add for BigUint { type Output = BigUint; @@ -460,7 +460,7 @@ impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { } } -forward_all_scalar_binop_to_val_val!(impl Mul for BigUint, mul); +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); impl Mul for BigUint { type Output = BigUint; diff --git a/bigint/src/macros.rs b/bigint/src/macros.rs index c6ebf71..92041a9 100644 --- a/bigint/src/macros.rs +++ b/bigint/src/macros.rs @@ -105,7 +105,7 @@ macro_rules! forward_ref_ref_binop_commutative { } } -macro_rules! forward_scalar_val_val_binop { +macro_rules! forward_scalar_val_val_binop_commutative { (impl $imp:ident<$scalar:ty> for $res:ty, $method: ident) => { impl $imp<$res> for $scalar { type Output = $res; @@ -118,7 +118,7 @@ macro_rules! forward_scalar_val_val_binop { } } -macro_rules! forward_scalar_val_ref_binop { +macro_rules! forward_scalar_val_ref_binop_commutative { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { impl<'a> $imp<&'a $scalar> for $res { type Output = $res; @@ -140,7 +140,7 @@ macro_rules! forward_scalar_val_ref_binop { } } -macro_rules! forward_scalar_ref_val_binop { +macro_rules! forward_scalar_ref_val_binop_commutative { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { impl<'a> $imp<$scalar> for &'a $res { type Output = $res; @@ -162,7 +162,7 @@ macro_rules! forward_scalar_ref_val_binop { } } -macro_rules! forward_scalar_ref_ref_binop { +macro_rules! forward_scalar_ref_ref_binop_commutative { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { impl<'a, 'b> $imp<&'b $scalar> for &'a $res { type Output = $res; @@ -211,11 +211,11 @@ macro_rules! forward_all_binop_to_val_ref_commutative { }; } -macro_rules! forward_all_scalar_binop_to_val_val { +macro_rules! forward_all_scalar_binop_to_val_val_commutative { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { - forward_scalar_val_val_binop!(impl $imp<$scalar> for $res, $method); - forward_scalar_val_ref_binop!(impl $imp<$scalar> for $res, $method); - forward_scalar_ref_val_binop!(impl $imp<$scalar> for $res, $method); - forward_scalar_ref_ref_binop!(impl $imp<$scalar> for $res, $method); + forward_scalar_val_val_binop_commutative!(impl $imp<$scalar> for $res, $method); + forward_scalar_val_ref_binop_commutative!(impl $imp<$scalar> for $res, $method); + forward_scalar_ref_val_binop_commutative!(impl $imp<$scalar> for $res, $method); + forward_scalar_ref_ref_binop_commutative!(impl $imp<$scalar> for $res, $method); } } From 51408a9b3ba67513936e3074df3ed9ff6d7c5e75 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 10:12:53 +0100 Subject: [PATCH 09/24] All variants of subtracting BigDigit from BigUint Allow the subtraction to occur with either operand order and with any combination of owned and borrowed arguments. --- bigint/src/biguint.rs | 16 ++++++++++++++++ bigint/src/macros.rs | 26 ++++++++++++++++---------- bigint/src/tests/biguint.rs | 12 ++++++++++-- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index b2e4492..2949fb1 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -439,6 +439,8 @@ impl<'a> Sub for &'a BigUint { } } +forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); + impl Sub for BigUint { type Output = BigUint; @@ -449,6 +451,20 @@ impl Sub for BigUint { } } +impl Sub for BigDigit { + type Output = BigUint; + + #[inline] + fn sub(self, mut other: BigUint) -> BigUint { + if other.data.len() == 0 { + other.data.push(0); + } + + sub2rev(&[self], &mut other.data[..]); + other.normalize() + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigUint, mul); impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { diff --git a/bigint/src/macros.rs b/bigint/src/macros.rs index 92041a9..f81bd84 100644 --- a/bigint/src/macros.rs +++ b/bigint/src/macros.rs @@ -118,7 +118,7 @@ macro_rules! forward_scalar_val_val_binop_commutative { } } -macro_rules! forward_scalar_val_ref_binop_commutative { +macro_rules! forward_scalar_val_ref_binop { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { impl<'a> $imp<&'a $scalar> for $res { type Output = $res; @@ -134,13 +134,13 @@ macro_rules! forward_scalar_val_ref_binop_commutative { #[inline] fn $method(self, other: $res) -> $res { - $imp::$method(other, *self) + $imp::$method(*self, other) } } } } -macro_rules! forward_scalar_ref_val_binop_commutative { +macro_rules! forward_scalar_ref_val_binop { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { impl<'a> $imp<$scalar> for &'a $res { type Output = $res; @@ -156,13 +156,13 @@ macro_rules! forward_scalar_ref_val_binop_commutative { #[inline] fn $method(self, other: &$res) -> $res { - $imp::$method(other.clone(), self) + $imp::$method(self, other.clone()) } } } } -macro_rules! forward_scalar_ref_ref_binop_commutative { +macro_rules! forward_scalar_ref_ref_binop { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { impl<'a, 'b> $imp<&'b $scalar> for &'a $res { type Output = $res; @@ -178,7 +178,7 @@ macro_rules! forward_scalar_ref_ref_binop_commutative { #[inline] fn $method(self, other: &$res) -> $res { - $imp::$method(other.clone(), *self) + $imp::$method(*self, other.clone()) } } } @@ -211,11 +211,17 @@ macro_rules! forward_all_binop_to_val_ref_commutative { }; } +macro_rules! forward_all_scalar_binop_to_val_val { + (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { + forward_scalar_val_ref_binop!(impl $imp<$scalar> for $res, $method); + forward_scalar_ref_val_binop!(impl $imp<$scalar> for $res, $method); + forward_scalar_ref_ref_binop!(impl $imp<$scalar> for $res, $method); + } +} + macro_rules! forward_all_scalar_binop_to_val_val_commutative { (impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => { forward_scalar_val_val_binop_commutative!(impl $imp<$scalar> for $res, $method); - forward_scalar_val_ref_binop_commutative!(impl $imp<$scalar> for $res, $method); - forward_scalar_ref_val_binop_commutative!(impl $imp<$scalar> for $res, $method); - forward_scalar_ref_ref_binop_commutative!(impl $imp<$scalar> for $res, $method); + forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method); } -} +} \ No newline at end of file diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index da6c956..b62ab51 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -734,14 +734,22 @@ fn test_scalar_sub() { let a = a_vec[0]; let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); - assert!(c - a == b); + assert_op!(c - a == b); } if b_vec.len() == 1 { let a = BigUint::from_slice(a_vec); let b = b_vec[0]; let c = BigUint::from_slice(c_vec); - assert!(c - b == a); + assert_op!(c - b == a); + } + + if c_vec.len() == 1 { + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = c_vec[0]; + assert_op!(c - a == b); + assert_op!(c - b == a); } } } From d0bfb54eee684778003dc7346c0ce0a0c26ddcb6 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 13:38:00 +0100 Subject: [PATCH 10/24] All variants of dividing BigUint by BigDigit Allow the division to occur with either operand order and with any combination of owned and borrowed arguments. --- bigint/src/biguint.rs | 38 ++++++++++++++++-- bigint/src/tests/biguint.rs | 79 ++++++++++++++++++++++--------------- 2 files changed, 83 insertions(+), 34 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 2949fb1..b055b6a 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -503,6 +503,8 @@ impl<'a, 'b> Div<&'b BigUint> for &'a BigUint { } } +forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); + impl Div for BigUint { type Output = BigUint; @@ -513,6 +515,20 @@ impl Div for BigUint { } } +impl Div for BigDigit { + type Output = BigUint; + + #[inline] + fn div(self, mut other: BigUint) -> BigUint { + other = other.normalize(); + match other.data.len() { + 0 => panic!(), + 1 => From::from(self / other.data[0]), + _ => Zero::zero() + } + } +} + forward_all_binop_to_ref_ref!(impl Rem for BigUint, rem); impl<'a, 'b> Rem<&'b BigUint> for &'a BigUint { @@ -525,13 +541,29 @@ impl<'a, 'b> Rem<&'b BigUint> for &'a BigUint { } } +forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); + impl Rem for BigUint { - type Output = BigDigit; + type Output = BigUint; #[inline] - fn rem(self, other: BigDigit) -> BigDigit { + fn rem(self, other: BigDigit) -> BigUint { let (_, r) = div_rem_digit(self, other); - r + From::from(r) + } +} + +impl Rem for BigDigit { + type Output = BigUint; + + #[inline] + fn rem(self, mut other: BigUint) -> BigUint { + other = other.normalize(); + match other.data.len() { + 0 => panic!(), + 1 => From::from(self % other.data[0]), + _ => other + } } } diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index b62ab51..c39aa40 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -692,22 +692,22 @@ fn test_add() { #[test] fn test_scalar_add() { - for elm in SUM_TRIPLES.iter() { - let (a_vec, b_vec, c_vec) = *elm; - let c = BigUint::from_slice(c_vec); + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); - if a_vec.len() == 1 { - let a = a_vec[0]; - let b = BigUint::from_slice(b_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - } + if a_vec.len() == 1 { + let a = a_vec[0]; + assert_op!(a + b == c); + assert_op!(b + a == c); + } - if b_vec.len() == 1 { - let a = BigUint::from_slice(a_vec); - let b = b_vec[0]; - assert_op!(a + b == c); - assert_op!(b + a == c); + if b_vec.len() == 1 { + let b = b_vec[0]; + assert_op!(a + b == c); + assert_op!(b + a == c); } } } @@ -729,24 +729,21 @@ fn test_sub() { fn test_scalar_sub() { for elm in SUM_TRIPLES.iter() { let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); + let c = BigUint::from_slice(c_vec); if a_vec.len() == 1 { let a = a_vec[0]; - let b = BigUint::from_slice(b_vec); - let c = BigUint::from_slice(c_vec); assert_op!(c - a == b); } if b_vec.len() == 1 { - let a = BigUint::from_slice(a_vec); let b = b_vec[0]; - let c = BigUint::from_slice(c_vec); assert_op!(c - b == a); } if c_vec.len() == 1 { - let a = BigUint::from_slice(a_vec); - let b = BigUint::from_slice(b_vec); let c = c_vec[0]; assert_op!(c - a == b); assert_op!(c - b == a); @@ -792,6 +789,7 @@ const DIV_REM_QUADRUPLES: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[(&[1], &[2], &[], &[1]), + (&[3], &[2], &[1], &[1]), (&[1, 1], &[2], &[M / 2 + 1], &[1]), (&[1, 1, 1], &[2], &[M / 2 + 1, M / 2 + 1], &[1]), (&[0, 1], &[N1], &[1], &[1]), @@ -825,17 +823,17 @@ fn test_mul() { fn test_scalar_mul() { for elm in MUL_TRIPLES.iter() { let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); if a_vec.len() == 1 { - let b = BigUint::from_slice(b_vec); let a = a_vec[0]; assert_op!(a * b == c); assert_op!(b * a == c); } if b_vec.len() == 1 { - let a = BigUint::from_slice(a_vec); let b = b_vec[0]; assert_op!(a * b == c); assert_op!(b * a == c); @@ -882,33 +880,52 @@ fn test_div_rem() { fn test_scalar_div_rem() { for elm in MUL_TRIPLES.iter() { let (a_vec, b_vec, c_vec) = *elm; + let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); if a_vec.len() == 1 && a_vec[0] != 0 { let a = a_vec[0]; - let b = BigUint::from_slice(b_vec); - assert!(c.clone() / a == b); - assert!(c.clone() % a == Zero::zero()); + assert_op!(c / a == b); + assert_op!(c % a == Zero::zero()); } if b_vec.len() == 1 && b_vec[0] != 0 { - let a = BigUint::from_slice(a_vec); let b = b_vec[0]; - assert!(c.clone() / b == a); - assert!(c.clone() % b == Zero::zero()); + assert_op!(c / b == a); + assert_op!(c % b == Zero::zero()); + } + + if c_vec.len() == 1 { + let c = c_vec[0]; + if !a.is_zero() { + assert_op!(c / a == b); + assert_op!(c % a == Zero::zero()); + } + if !b.is_zero() { + assert_op!(c / b == a); + assert_op!(c % b == Zero::zero()); + } } } for elm in DIV_REM_QUADRUPLES.iter() { let (a_vec, b_vec, c_vec, d_vec) = *elm; let a = BigUint::from_slice(a_vec); + let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); + let d = BigUint::from_slice(d_vec); if b_vec.len() == 1 && b_vec[0] != 0 { let b = b_vec[0]; - let d = d_vec[0]; - assert!(a.clone() / b == c); - assert!(a.clone() % b == d); + assert_op!(a / b == c); + assert_op!(a % b == d); + } + + if a_vec.len() == 1 && !b.is_zero() { + let a = a_vec[0]; + assert_op!(a / b == c); + assert_op!(a % b == d); } } } From 1e26bdde8105ff267c15cf20bae8df1a414b9dce Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 13:53:08 +0100 Subject: [PATCH 11/24] Remove unnecessary normalization --- bigint/src/biguint.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index b055b6a..631686d 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -519,8 +519,7 @@ impl Div for BigDigit { type Output = BigUint; #[inline] - fn div(self, mut other: BigUint) -> BigUint { - other = other.normalize(); + fn div(self, other: BigUint) -> BigUint { match other.data.len() { 0 => panic!(), 1 => From::from(self / other.data[0]), @@ -557,8 +556,7 @@ impl Rem for BigDigit { type Output = BigUint; #[inline] - fn rem(self, mut other: BigUint) -> BigUint { - other = other.normalize(); + fn rem(self, other: BigUint) -> BigUint { match other.data.len() { 0 => panic!(), 1 => From::from(self % other.data[0]), From 80feea2722a76bf8d400e9bbd394914a4d1a200a Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 14:07:44 +0100 Subject: [PATCH 12/24] Also implement scalar addition for BigInt --- bigint/src/bigint.rs | 20 ++++++++++++++++++++ bigint/src/tests/bigint.rs | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index 93f4ae7..dba6a7a 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -362,6 +362,26 @@ impl Add for BigInt { } } +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); + +impl Add for BigInt { + type Output = BigInt; + + #[inline] + fn add(self, other: BigDigit) -> BigInt { + match self.sign { + NoSign => From::from(other), + Plus => BigInt::from_biguint(Plus, self.data + other), + Minus => + match self.data.cmp(&From::from(other)) { + Equal => Zero::zero(), + Less => BigInt::from_biguint(Plus, other - self.data), + Greater => BigInt::from_biguint(Minus, self.data - other), + } + } + } +} + // We want to forward to BigUint::sub, but it's not clear how that will go until // we compare both sign and magnitude. So we duplicate this body for every // val/ref combination, deferring that decision to BigUint's own forwarding. diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index 9e83373..4cdf616 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -552,6 +552,24 @@ fn test_add() { } } +#[test] +fn test_scalar_add() { + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let b = BigInt::from_slice(Plus, b_vec); + let c = BigInt::from_slice(Plus, c_vec); + let (nb, nc) = (-&b, -&c); + + if a_vec.len() == 1 { + let a = a_vec[0]; + assert_op!(a + b == c); + assert_op!(b + a == c); + assert_op!(a + nc == nb); + assert_op!(nc + a == nb); + } + } +} + #[test] fn test_sub() { for elm in SUM_TRIPLES.iter() { From 79448cbdf9c805a0bce2c5c6dded1d4aa2ad44bf Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 15:15:59 +0100 Subject: [PATCH 13/24] Add scalar subtraction to BigInt --- bigint/src/bigint.rs | 29 ++++++++++++++++++++++++ bigint/src/tests/bigint.rs | 46 +++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index dba6a7a..32af7ab 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -445,6 +445,35 @@ impl Sub for BigInt { } } +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); + +impl Sub for BigInt { + type Output = BigInt; + + #[inline] + fn sub(self, other: BigDigit) -> BigInt { + match self.sign { + NoSign => BigInt::from_biguint(Minus, From::from(other)), + Minus => BigInt::from_biguint(Minus, self.data + other), + Plus => + match self.data.cmp(&From::from(other)) { + Equal => Zero::zero(), + Greater => BigInt::from_biguint(Plus, self.data - other), + Less => BigInt::from_biguint(Minus, other - self.data), + } + } + } +} + +impl Sub for BigDigit { + type Output = BigInt; + + #[inline] + fn sub(self, other: BigInt) -> BigInt { + -(other - self) + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul); impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index 4cdf616..610dfa9 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -556,9 +556,10 @@ fn test_add() { fn test_scalar_add() { for elm in SUM_TRIPLES.iter() { let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); let b = BigInt::from_slice(Plus, b_vec); let c = BigInt::from_slice(Plus, c_vec); - let (nb, nc) = (-&b, -&c); + let (na, nb, nc) = (-&a, -&b, -&c); if a_vec.len() == 1 { let a = a_vec[0]; @@ -567,6 +568,14 @@ fn test_scalar_add() { assert_op!(a + nc == nb); assert_op!(nc + a == nb); } + + if b_vec.len() == 1 { + let b = b_vec[0]; + assert_op!(a + b == c); + assert_op!(b + a == c); + assert_op!(b + nc == na); + assert_op!(nc + b == na); + } } } @@ -590,6 +599,41 @@ fn test_sub() { } } +#[test] +fn test_scalar_sub() { + for elm in SUM_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let b = BigInt::from_slice(Plus, b_vec); + let c = BigInt::from_slice(Plus, c_vec); + let (na, nb, nc) = (-&a, -&b, -&c); + + if a_vec.len() == 1 { + let a = a_vec[0]; + assert_op!(c - a == b); + assert_op!(a - c == nb); + assert_op!(a - nb == c); + assert_op!(nb - a == nc); + } + + if b_vec.len() == 1 { + let b = b_vec[0]; + assert_op!(c - b == a); + assert_op!(b - c == na); + assert_op!(b - na == c); + assert_op!(na - b == nc); + } + + if c_vec.len() == 1 { + let c = c_vec[0]; + assert_op!(c - a == b); + assert_op!(a - c == nb); + assert_op!(c - b == a); + assert_op!(b - c == na); + } + } +} + const M: u32 = ::std::u32::MAX; static MUL_TRIPLES: &'static [(&'static [BigDigit], &'static [BigDigit], From 8b1288ea01d88dfe778a62ff19d1ec6bdab27872 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 15:46:07 +0100 Subject: [PATCH 14/24] Add scalar multiplication to BigInt --- bigint/src/bigint.rs | 2 ++ bigint/src/biguint.rs | 10 +++++++--- bigint/src/tests/bigint.rs | 20 +++++++++++--------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index 32af7ab..69937ad 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -485,6 +485,8 @@ impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { } } +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); + impl Mul for BigInt { type Output = BigInt; diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 631686d..28b6e73 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -483,9 +483,13 @@ impl Mul for BigUint { #[inline] fn mul(mut self, other: BigDigit) -> BigUint { - let carry = scalar_mul(&mut self.data[..], other); - if carry != 0 { - self.data.push(carry); + if other == 0 { + self.data.clear(); + } else { + let carry = scalar_mul(&mut self.data[..], other); + if carry != 0 { + self.data.push(carry); + } } self } diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index 610dfa9..a24cb3e 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -703,23 +703,25 @@ fn test_mul() { fn test_scalar_mul() { for elm in MUL_TRIPLES.iter() { let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let b = BigInt::from_slice(Plus, b_vec); let c = BigInt::from_slice(Plus, c_vec); - let nc = BigInt::from_slice(Minus, c_vec); + let (na, nb, nc) = (-&a, -&b, -&c); if a_vec.len() == 1 { - let b = BigInt::from_slice(Plus, b_vec); - let nb = BigInt::from_slice(Minus, b_vec); let a = a_vec[0]; - assert!(b * a == c); - assert!(nb * a == nc); + assert_op!(b * a == c); + assert_op!(a * b == c); + assert_op!(nb * a == nc); + assert_op!(a * nb == nc); } if b_vec.len() == 1 { - let a = BigInt::from_slice(Plus, a_vec); - let na = BigInt::from_slice(Minus, a_vec); let b = b_vec[0]; - assert!(a * b == c); - assert!(na * b == nc); + assert_op!(a * b == c); + assert_op!(b * a == c); + assert_op!(na * b == nc); + assert_op!(b * na == nc); } } } From 9b0392d2352fe9fd1f8dc4b0190a430eb17f0d4a Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 16:19:11 +0100 Subject: [PATCH 15/24] Add scalar division to BigInt --- bigint/src/bigint.rs | 40 ++++++++++++++++++++++++++++ bigint/src/tests/bigint.rs | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index 69937ad..858b977 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -508,6 +508,26 @@ impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { } } +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); + +impl Div for BigInt { + type Output = BigInt; + + #[inline] + fn div(self, other: BigDigit) -> BigInt { + BigInt::from_biguint(self.sign, self.data / other) + } +} + +impl Div for BigDigit { + type Output = BigInt; + + #[inline] + fn div(self, other: BigInt) -> BigInt { + BigInt::from_biguint(other.sign, self / other.data) + } +} + forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem); impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { @@ -520,6 +540,26 @@ impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { } } +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); + +impl Rem for BigInt { + type Output = BigInt; + + #[inline] + fn rem(self, other: BigDigit) -> BigInt { + BigInt::from_biguint(self.sign, self.data % other) + } +} + +impl Rem for BigDigit { + type Output = BigInt; + + #[inline] + fn rem(self, other: BigInt) -> BigInt { + BigInt::from_biguint(Plus, self % other.data) + } +} + impl Neg for BigInt { type Output = BigInt; diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index a24cb3e..b8a48dc 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -832,6 +832,59 @@ fn test_div_rem() { } } +#[test] +fn test_scalar_div_rem() { + fn check_sub(a: &BigInt, b: BigDigit, ans_q: &BigInt, ans_r: &BigInt) { + let (q, r) = (a / b, a % b); + if !r.is_zero() { + assert_eq!(r.sign, a.sign); + } + assert!(r.abs() <= From::from(b)); + assert!(*a == b * &q + &r); + assert!(q == *ans_q); + assert!(r == *ans_r); + + let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone()); + assert_op!(a / b == ans_q); + assert_op!(a % b == ans_r); + } + + fn check(a: &BigInt, b: BigDigit, q: &BigInt, r: &BigInt) { + check_sub(a, b, q, r); + check_sub(&a.neg(), b, &q.neg(), &r.neg()); + } + + for elm in MUL_TRIPLES.iter() { + let (a_vec, b_vec, c_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let b = BigInt::from_slice(Plus, b_vec); + let c = BigInt::from_slice(Plus, c_vec); + + if a_vec.len() == 1 && a_vec[0] != 0 { + let a = a_vec[0]; + check(&c, a, &b, &Zero::zero()); + } + + if b_vec.len() == 1 && b_vec[0] != 0 { + let b = b_vec[0]; + check(&c, b, &a, &Zero::zero()); + } + } + + for elm in DIV_REM_QUADRUPLES.iter() { + let (a_vec, b_vec, c_vec, d_vec) = *elm; + let a = BigInt::from_slice(Plus, a_vec); + let c = BigInt::from_slice(Plus, c_vec); + let d = BigInt::from_slice(Plus, d_vec); + + if b_vec.len() == 1 && b_vec[0] != 0 { + let b = b_vec[0]; + check(&a, b, &c, &d); + } + } + +} + #[test] fn test_checked_add() { for elm in SUM_TRIPLES.iter() { From 94d570697c26d65aa2047a8914cbe5073535074d Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 17:20:17 +0100 Subject: [PATCH 16/24] Add operations on i32 to BigInt --- bigint/src/bigint.rs | 122 +++++++++++++++++++++++++++++++++++++ bigint/src/tests/bigint.rs | 63 +++++++++++++++++++ 2 files changed, 185 insertions(+) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index 858b977..848eb09 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -299,6 +299,14 @@ impl Signed for BigInt { } } +// A convenience method for getting the absolute value of an i32 in a u32. +fn i32_abs_as_u32(a: i32) -> u32 { + match a.checked_abs() { + Some(x) => x as u32, + None => a as u32 + } +} + // We want to forward to BigUint::add, but it's not clear how that will go until // we compare both sign and magnitude. So we duplicate this body for every // val/ref combination, deferring that decision to BigUint's own forwarding. @@ -382,6 +390,21 @@ impl Add for BigInt { } } +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); + +impl Add for BigInt { + type Output = BigInt; + + #[inline] + fn add(self, other: i32) -> BigInt { + if other >= 0 { + self + other as u32 + } else { + self - i32_abs_as_u32(other) + } + } +} + // We want to forward to BigUint::sub, but it's not clear how that will go until // we compare both sign and magnitude. So we duplicate this body for every // val/ref combination, deferring that decision to BigUint's own forwarding. @@ -474,6 +497,34 @@ impl Sub for BigDigit { } } +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); + +impl Sub for BigInt { + type Output = BigInt; + + #[inline] + fn sub(self, other: i32) -> BigInt { + if other >= 0 { + self - other as u32 + } else { + self + i32_abs_as_u32(other) + } + } +} + +impl Sub for i32 { + type Output = BigInt; + + #[inline] + fn sub(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u32 - other + } else { + -other - i32_abs_as_u32(self) + } + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul); impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { @@ -496,6 +547,21 @@ impl Mul for BigInt { } } +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); + +impl Mul for BigInt { + type Output = BigInt; + + #[inline] + fn mul(self, other: i32) -> BigInt { + if other >= 0 { + self * other as u32 + } else { + -(self * i32_abs_as_u32(other)) + } + } +} + forward_all_binop_to_ref_ref!(impl Div for BigInt, div); impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { @@ -528,6 +594,34 @@ impl Div for BigDigit { } } +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); + +impl Div for BigInt { + type Output = BigInt; + + #[inline] + fn div(self, other: i32) -> BigInt { + if other >= 0 { + self / other as u32 + } else { + -(self / i32_abs_as_u32(other)) + } + } +} + +impl Div for i32 { + type Output = BigInt; + + #[inline] + fn div(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u32 / other + } else { + -(i32_abs_as_u32(self) / other) + } + } +} + forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem); impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { @@ -560,6 +654,34 @@ impl Rem for BigDigit { } } +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); + +impl Rem for BigInt { + type Output = BigInt; + + #[inline] + fn rem(self, other: i32) -> BigInt { + if other >= 0 { + self % other as u32 + } else { + self % i32_abs_as_u32(other) + } + } +} + +impl Rem for i32 { + type Output = BigInt; + + #[inline] + fn rem(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u32 % other + } else { + -(i32_abs_as_u32(self) % other) + } + } +} + impl Neg for BigInt { type Output = BigInt; diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index b8a48dc..ac3d543 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -567,6 +567,14 @@ fn test_scalar_add() { assert_op!(b + a == c); assert_op!(a + nc == nb); assert_op!(nc + a == nb); + + if a <= i32::max_value() as u32 { + let na = -(a as i32); + assert_op!(na + nb == nc); + assert_op!(nb + na == nc); + assert_op!(na + c == b); + assert_op!(c + na == b); + } } if b_vec.len() == 1 { @@ -575,6 +583,14 @@ fn test_scalar_add() { assert_op!(b + a == c); assert_op!(b + nc == na); assert_op!(nc + b == na); + + if b <= i32::max_value() as u32 { + let nb = -(b as i32); + assert_op!(na + nb == nc); + assert_op!(nb + na == nc); + assert_op!(nb + c == a); + assert_op!(c + nb == a); + } } } } @@ -614,6 +630,14 @@ fn test_scalar_sub() { assert_op!(a - c == nb); assert_op!(a - nb == c); assert_op!(nb - a == nc); + + if a <= i32::max_value() as u32 { + let na = -(a as i32); + assert_op!(nc - na == nb); + assert_op!(na - nc == b); + assert_op!(na - b == nc); + assert_op!(b - na == c); + } } if b_vec.len() == 1 { @@ -622,6 +646,14 @@ fn test_scalar_sub() { assert_op!(b - c == na); assert_op!(b - na == c); assert_op!(na - b == nc); + + if b <= i32::max_value() as u32 { + let nb = -(b as i32); + assert_op!(nc - nb == na); + assert_op!(nb - nc == a); + assert_op!(nb - a == nc); + assert_op!(a - nb == c); + } } if c_vec.len() == 1 { @@ -630,6 +662,14 @@ fn test_scalar_sub() { assert_op!(a - c == nb); assert_op!(c - b == a); assert_op!(b - c == na); + + if c <= i32::max_value() as u32 { + let nc = -(c as i32); + assert_op!(nc - na == nb); + assert_op!(na - nc == b); + assert_op!(nc - nb == na); + assert_op!(nb - nc == a); + } } } } @@ -665,6 +705,7 @@ static DIV_REM_QUADRUPLES: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] = &[(&[1], &[2], &[], &[1]), + (&[3], &[2], &[1], &[1]), (&[1, 1], &[2], &[M / 2 + 1], &[1]), (&[1, 1, 1], &[2], &[M / 2 + 1, M / 2 + 1], &[1]), (&[0, 1], &[N1], &[1], &[1]), @@ -714,6 +755,14 @@ fn test_scalar_mul() { assert_op!(a * b == c); assert_op!(nb * a == nc); assert_op!(a * nb == nc); + + if a <= i32::max_value() as u32 { + let na = -(a as i32); + assert_op!(nb * na == c); + assert_op!(na * nb == c); + assert_op!(b * na == nc); + assert_op!(na * b == nc); + } } if b_vec.len() == 1 { @@ -722,6 +771,14 @@ fn test_scalar_mul() { assert_op!(b * a == c); assert_op!(na * b == nc); assert_op!(b * na == nc); + + if b <= i32::max_value() as u32 { + let nb = -(b as i32); + assert_op!(na * nb == c); + assert_op!(nb * na == c); + assert_op!(a * nb == nc); + assert_op!(nb * a == nc); + } } } } @@ -847,6 +904,12 @@ fn test_scalar_div_rem() { let (a, b, ans_q, ans_r) = (a.clone(), b.clone(), ans_q.clone(), ans_r.clone()); assert_op!(a / b == ans_q); assert_op!(a % b == ans_r); + + if b <= i32::max_value() as u32 { + let nb = -(b as i32); + assert_op!(a / nb == -ans_q.clone()); + assert_op!(a % nb == ans_r); + } } fn check(a: &BigInt, b: BigDigit, q: &BigInt, r: &BigInt) { From 99873d06e53c0de622829cb0517757b4bd510327 Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 18:29:14 +0100 Subject: [PATCH 17/24] Scalar operations on integer types up to 32 bits --- bigint/src/bigint.rs | 5 ++++ bigint/src/biguint.rs | 5 ++++ bigint/src/macros.rs | 63 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index 848eb09..ff68886 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -370,6 +370,7 @@ impl Add for BigInt { } } +promote_all_scalars!(impl Add for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); impl Add for BigInt { @@ -468,6 +469,7 @@ impl Sub for BigInt { } } +promote_all_scalars!(impl Sub for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); impl Sub for BigInt { @@ -536,6 +538,7 @@ impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { } } +promote_all_scalars!(impl Mul for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); impl Mul for BigInt { @@ -574,6 +577,7 @@ impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { } } +promote_all_scalars!(impl Div for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); impl Div for BigInt { @@ -634,6 +638,7 @@ impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { } } +promote_all_scalars!(impl Rem for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); impl Rem for BigInt { diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 28b6e73..6a00cbf 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -394,6 +394,7 @@ impl<'a> Add<&'a BigUint> for BigUint { } } +promote_unsigned_scalars!(impl Add for BigUint, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); impl Add for BigUint { @@ -439,6 +440,7 @@ impl<'a> Sub for &'a BigUint { } } +promote_unsigned_scalars!(impl Sub for BigUint, sub); forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); impl Sub for BigUint { @@ -476,6 +478,7 @@ impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { } } +promote_unsigned_scalars!(impl Mul for BigUint, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); impl Mul for BigUint { @@ -507,6 +510,7 @@ impl<'a, 'b> Div<&'b BigUint> for &'a BigUint { } } +promote_unsigned_scalars!(impl Div for BigUint, div); forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); impl Div for BigUint { @@ -544,6 +548,7 @@ impl<'a, 'b> Rem<&'b BigUint> for &'a BigUint { } } +promote_unsigned_scalars!(impl Rem for BigUint, rem); forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); impl Rem for BigUint { diff --git a/bigint/src/macros.rs b/bigint/src/macros.rs index f81bd84..76d805e 100644 --- a/bigint/src/macros.rs +++ b/bigint/src/macros.rs @@ -184,6 +184,50 @@ macro_rules! forward_scalar_ref_ref_binop { } } +macro_rules! promote_scalars { + (impl $imp:ident<$promo:ty> for $res:ty, $method:ident, $( $scalar:ty ),*) => { + $( + forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method); + + impl $imp<$scalar> for $res { + type Output = $res; + + #[inline] + fn $method(self, other: $scalar) -> $res { + $imp::$method(self, other as $promo) + } + } + + impl $imp<$res> for $scalar { + type Output = $res; + + #[inline] + fn $method(self, other: $res) -> $res { + $imp::$method(self as $promo, other) + } + } + )* + } +} + +macro_rules! promote_unsigned_scalars_to_u32 { + (impl $imp:ident for $res:ty, $method:ident) => { + #[cfg(target_pointer_width = "32")] + promote_scalars!(impl $imp for $res, $method, u8, u16, usize); + #[cfg(target_pointer_width = "64")] + promote_scalars!(impl $imp for $res, $method, u8, u16); + } +} + +macro_rules! promote_signed_scalars_to_i32 { + (impl $imp:ident for $res:ty, $method:ident) => { + #[cfg(target_pointer_width = "32")] + promote_scalars!(impl $imp for $res, $method, i8, i16, isize); + #[cfg(target_pointer_width = "64")] + promote_scalars!(impl $imp for $res, $method, i8, i16); + } +} + // Forward everything to ref-ref, when reusing storage is not helpful macro_rules! forward_all_binop_to_ref_ref { (impl $imp:ident for $res:ty, $method:ident) => { @@ -224,4 +268,23 @@ macro_rules! forward_all_scalar_binop_to_val_val_commutative { forward_scalar_val_val_binop_commutative!(impl $imp<$scalar> for $res, $method); forward_all_scalar_binop_to_val_val!(impl $imp<$scalar> for $res, $method); } +} + +macro_rules! promote_unsigned_scalars { + (impl $imp:ident for $res:ty, $method:ident) => { + promote_unsigned_scalars_to_u32!(impl $imp for $res, $method); + } +} + +macro_rules! promote_signed_scalars { + (impl $imp:ident for $res:ty, $method:ident) => { + promote_signed_scalars_to_i32!(impl $imp for $res, $method); + } +} + +macro_rules! promote_all_scalars { + (impl $imp:ident for $res:ty, $method:ident) => { + promote_unsigned_scalars!(impl $imp for $res, $method); + promote_signed_scalars!(impl $imp for $res, $method); + } } \ No newline at end of file From fd87d87db345f1d694d246cdb5cfa1f4ff73b07d Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 20:40:54 +0100 Subject: [PATCH 18/24] Fix normalization in scalar addition --- bigint/src/biguint.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 6a00cbf..f341b85 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -402,7 +402,7 @@ impl Add for BigUint { #[inline] fn add(mut self, other: BigDigit) -> BigUint { - if self.data.len() == 0 { + if self.data.len() == 0 && other != 0 { self.data.push(0); } From 2a3cd4182015d91243c7051b2924e5ae800de0ea Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 22:18:54 +0100 Subject: [PATCH 19/24] Add scalar ops for all remaining integer types --- bigint/src/bigint.rs | 214 +++++++++++++++++++++++++++++++++++++++++- bigint/src/biguint.rs | 121 +++++++++++++++++++++++- bigint/src/macros.rs | 16 ++++ 3 files changed, 348 insertions(+), 3 deletions(-) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index ff68886..dfb69d4 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -23,7 +23,7 @@ use self::Sign::{Minus, NoSign, Plus}; use super::ParseBigIntError; use super::big_digit; -use super::big_digit::BigDigit; +use super::big_digit::{BigDigit, DoubleBigDigit}; use biguint; use biguint::to_str_radix_reversed; use biguint::BigUint; @@ -307,6 +307,14 @@ fn i32_abs_as_u32(a: i32) -> u32 { } } +// A convenience method for getting the absolute value of an i64 in a u64. +fn i64_abs_as_u64(a: i64) -> u64 { + match a.checked_abs() { + Some(x) => x as u64, + None => a as u64 + } +} + // We want to forward to BigUint::add, but it's not clear how that will go until // we compare both sign and magnitude. So we duplicate this body for every // val/ref combination, deferring that decision to BigUint's own forwarding. @@ -372,6 +380,7 @@ impl Add for BigInt { promote_all_scalars!(impl Add for BigInt, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); impl Add for BigInt { type Output = BigInt; @@ -391,7 +400,26 @@ impl Add for BigInt { } } +impl Add for BigInt { + type Output = BigInt; + + #[inline] + fn add(self, other: DoubleBigDigit) -> BigInt { + match self.sign { + NoSign => From::from(other), + Plus => BigInt::from_biguint(Plus, self.data + other), + Minus => + match self.data.cmp(&From::from(other)) { + Equal => Zero::zero(), + Less => BigInt::from_biguint(Plus, other - self.data), + Greater => BigInt::from_biguint(Minus, self.data - other), + } + } + } +} + forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigInt, add); impl Add for BigInt { type Output = BigInt; @@ -406,6 +434,19 @@ impl Add for BigInt { } } +impl Add for BigInt { + type Output = BigInt; + + #[inline] + fn add(self, other: i64) -> BigInt { + if other >= 0 { + self + other as u64 + } else { + self - i64_abs_as_u64(other) + } + } +} + // We want to forward to BigUint::sub, but it's not clear how that will go until // we compare both sign and magnitude. So we duplicate this body for every // val/ref combination, deferring that decision to BigUint's own forwarding. @@ -471,6 +512,7 @@ impl Sub for BigInt { promote_all_scalars!(impl Sub for BigInt, sub); forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); impl Sub for BigInt { type Output = BigInt; @@ -499,7 +541,35 @@ impl Sub for BigDigit { } } +impl Sub for BigInt { + type Output = BigInt; + + #[inline] + fn sub(self, other: DoubleBigDigit) -> BigInt { + match self.sign { + NoSign => BigInt::from_biguint(Minus, From::from(other)), + Minus => BigInt::from_biguint(Minus, self.data + other), + Plus => + match self.data.cmp(&From::from(other)) { + Equal => Zero::zero(), + Greater => BigInt::from_biguint(Plus, self.data - other), + Less => BigInt::from_biguint(Minus, other - self.data), + } + } + } +} + +impl Sub for DoubleBigDigit { + type Output = BigInt; + + #[inline] + fn sub(self, other: BigInt) -> BigInt { + -(other - self) + } +} + forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); +forward_all_scalar_binop_to_val_val!(impl Sub for BigInt, sub); impl Sub for BigInt { type Output = BigInt; @@ -527,6 +597,32 @@ impl Sub for i32 { } } +impl Sub for BigInt { + type Output = BigInt; + + #[inline] + fn sub(self, other: i64) -> BigInt { + if other >= 0 { + self - other as u64 + } else { + self + i64_abs_as_u64(other) + } + } +} + +impl Sub for i64 { + type Output = BigInt; + + #[inline] + fn sub(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u64 - other + } else { + -other - i64_abs_as_u64(self) + } + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul); impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { @@ -540,6 +636,7 @@ impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { promote_all_scalars!(impl Mul for BigInt, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); impl Mul for BigInt { type Output = BigInt; @@ -550,7 +647,17 @@ impl Mul for BigInt { } } +impl Mul for BigInt { + type Output = BigInt; + + #[inline] + fn mul(self, other: DoubleBigDigit) -> BigInt { + BigInt::from_biguint(self.sign, self.data * other) + } +} + forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigInt, mul); impl Mul for BigInt { type Output = BigInt; @@ -565,6 +672,19 @@ impl Mul for BigInt { } } +impl Mul for BigInt { + type Output = BigInt; + + #[inline] + fn mul(self, other: i64) -> BigInt { + if other >= 0 { + self * other as u64 + } else { + -(self * i64_abs_as_u64(other)) + } + } +} + forward_all_binop_to_ref_ref!(impl Div for BigInt, div); impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { @@ -579,6 +699,7 @@ impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { promote_all_scalars!(impl Div for BigInt, div); forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); impl Div for BigInt { type Output = BigInt; @@ -598,7 +719,26 @@ impl Div for BigDigit { } } +impl Div for BigInt { + type Output = BigInt; + + #[inline] + fn div(self, other: DoubleBigDigit) -> BigInt { + BigInt::from_biguint(self.sign, self.data / other) + } +} + +impl Div for DoubleBigDigit { + type Output = BigInt; + + #[inline] + fn div(self, other: BigInt) -> BigInt { + BigInt::from_biguint(other.sign, self / other.data) + } +} + forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); +forward_all_scalar_binop_to_val_val!(impl Div for BigInt, div); impl Div for BigInt { type Output = BigInt; @@ -626,6 +766,32 @@ impl Div for i32 { } } +impl Div for BigInt { + type Output = BigInt; + + #[inline] + fn div(self, other: i64) -> BigInt { + if other >= 0 { + self / other as u64 + } else { + -(self / i64_abs_as_u64(other)) + } + } +} + +impl Div for i64 { + type Output = BigInt; + + #[inline] + fn div(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u64 / other + } else { + -(i64_abs_as_u64(self) / other) + } + } +} + forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem); impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { @@ -640,6 +806,7 @@ impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { promote_all_scalars!(impl Rem for BigInt, rem); forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); impl Rem for BigInt { type Output = BigInt; @@ -659,7 +826,26 @@ impl Rem for BigDigit { } } +impl Rem for BigInt { + type Output = BigInt; + + #[inline] + fn rem(self, other: DoubleBigDigit) -> BigInt { + BigInt::from_biguint(self.sign, self.data % other) + } +} + +impl Rem for DoubleBigDigit { + type Output = BigInt; + + #[inline] + fn rem(self, other: BigInt) -> BigInt { + BigInt::from_biguint(Plus, self % other.data) + } +} + forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); +forward_all_scalar_binop_to_val_val!(impl Rem for BigInt, rem); impl Rem for BigInt { type Output = BigInt; @@ -687,6 +873,32 @@ impl Rem for i32 { } } +impl Rem for BigInt { + type Output = BigInt; + + #[inline] + fn rem(self, other: i64) -> BigInt { + if other >= 0 { + self % other as u64 + } else { + self % i64_abs_as_u64(other) + } + } +} + +impl Rem for i64 { + type Output = BigInt; + + #[inline] + fn rem(self, other: BigInt) -> BigInt { + if self >= 0 { + self as u64 % other + } else { + -(i64_abs_as_u64(self) % other) + } + } +} + impl Neg for BigInt { type Output = BigInt; diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index f341b85..7af2e71 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -396,6 +396,7 @@ impl<'a> Add<&'a BigUint> for BigUint { promote_unsigned_scalars!(impl Add for BigUint, add); forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); +forward_all_scalar_binop_to_val_val_commutative!(impl Add for BigUint, add); impl Add for BigUint { type Output = BigUint; @@ -414,6 +415,27 @@ impl Add for BigUint { } } +impl Add for BigUint { + type Output = BigUint; + + #[inline] + fn add(mut self, other: DoubleBigDigit) -> BigUint { + if self.data.len() == 0 && other != 0 { + self.data.push(0); + } + if self.data.len() == 1 && other > BigDigit::max_value() as DoubleBigDigit { + self.data.push(0); + } + + let (lo, hi) = big_digit::from_doublebigdigit(other); + let carry = __add2(&mut self.data, &[lo, hi]); + if carry != 0 { + self.data.push(carry); + } + self + } +} + forward_val_val_binop!(impl Sub for BigUint, sub); forward_ref_ref_binop!(impl Sub for BigUint, sub); @@ -442,6 +464,7 @@ impl<'a> Sub for &'a BigUint { promote_unsigned_scalars!(impl Sub for BigUint, sub); forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); +forward_all_scalar_binop_to_val_val!(impl Sub for BigUint, sub); impl Sub for BigUint { type Output = BigUint; @@ -467,6 +490,32 @@ impl Sub for BigDigit { } } +impl Sub for BigUint { + type Output = BigUint; + + #[inline] + fn sub(mut self, other: DoubleBigDigit) -> BigUint { + let (lo, hi) = big_digit::from_doublebigdigit(other); + sub2(&mut self.data[..], &[lo, hi]); + self.normalize() + } +} + +impl Sub for DoubleBigDigit { + type Output = BigUint; + + #[inline] + fn sub(self, mut other: BigUint) -> BigUint { + while other.data.len() < 2 { + other.data.push(0); + } + + let (lo, hi) = big_digit::from_doublebigdigit(self); + sub2rev(&[lo, hi], &mut other.data[..]); + other.normalize() + } +} + forward_all_binop_to_ref_ref!(impl Mul for BigUint, mul); impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { @@ -480,6 +529,7 @@ impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { promote_unsigned_scalars!(impl Mul for BigUint, mul); forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); +forward_all_scalar_binop_to_val_val_commutative!(impl Mul for BigUint, mul); impl Mul for BigUint { type Output = BigUint; @@ -498,6 +548,23 @@ impl Mul for BigUint { } } +impl Mul for BigUint { + type Output = BigUint; + + #[inline] + fn mul(mut self, other: DoubleBigDigit) -> BigUint { + if other == 0 { + self.data.clear(); + self + } else if other <= BigDigit::max_value() as DoubleBigDigit { + self * other as BigDigit + } else { + let (lo, hi) = big_digit::from_doublebigdigit(other); + mul3(&self.data[..], &[lo, hi]) + } + } +} + forward_all_binop_to_ref_ref!(impl Div for BigUint, div); impl<'a, 'b> Div<&'b BigUint> for &'a BigUint { @@ -512,6 +579,7 @@ impl<'a, 'b> Div<&'b BigUint> for &'a BigUint { promote_unsigned_scalars!(impl Div for BigUint, div); forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); +forward_all_scalar_binop_to_val_val!(impl Div for BigUint, div); impl Div for BigUint { type Output = BigUint; @@ -531,7 +599,31 @@ impl Div for BigDigit { match other.data.len() { 0 => panic!(), 1 => From::from(self / other.data[0]), - _ => Zero::zero() + _ => Zero::zero(), + } + } +} + +impl Div for BigUint { + type Output = BigUint; + + #[inline] + fn div(self, other: DoubleBigDigit) -> BigUint { + let (q, _) = self.div_rem(&From::from(other)); + q + } +} + +impl Div for DoubleBigDigit { + type Output = BigUint; + + #[inline] + fn div(self, other: BigUint) -> BigUint { + match other.data.len() { + 0 => panic!(), + 1 => From::from(self / other.data[0] as u64), + 2 => From::from(self / big_digit::to_doublebigdigit(other.data[0], other.data[1])), + _ => Zero::zero(), } } } @@ -550,6 +642,7 @@ impl<'a, 'b> Rem<&'b BigUint> for &'a BigUint { promote_unsigned_scalars!(impl Rem for BigUint, rem); forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); +forward_all_scalar_binop_to_val_val!(impl Rem for BigUint, rem); impl Rem for BigUint { type Output = BigUint; @@ -569,7 +662,31 @@ impl Rem for BigDigit { match other.data.len() { 0 => panic!(), 1 => From::from(self % other.data[0]), - _ => other + _ => From::from(self) + } + } +} + +impl Rem for BigUint { + type Output = BigUint; + + #[inline] + fn rem(self, other: DoubleBigDigit) -> BigUint { + let (_, r) = self.div_rem(&From::from(other)); + r + } +} + +impl Rem for DoubleBigDigit { + type Output = BigUint; + + #[inline] + fn rem(self, other: BigUint) -> BigUint { + match other.data.len() { + 0 => panic!(), + 1 => From::from(self % other.data[0] as u64), + 2 => From::from(self % big_digit::to_doublebigdigit(other.data[0], other.data[1])), + _ => From::from(self), } } } diff --git a/bigint/src/macros.rs b/bigint/src/macros.rs index 76d805e..a8143ad 100644 --- a/bigint/src/macros.rs +++ b/bigint/src/macros.rs @@ -219,6 +219,13 @@ macro_rules! promote_unsigned_scalars_to_u32 { } } +macro_rules! promote_unsigned_scalars_to_u64 { + (impl $imp:ident for $res:ty, $method:ident) => { + #[cfg(target_pointer_width = "64")] + promote_scalars!(impl $imp for $res, $method, usize); + } +} + macro_rules! promote_signed_scalars_to_i32 { (impl $imp:ident for $res:ty, $method:ident) => { #[cfg(target_pointer_width = "32")] @@ -228,6 +235,13 @@ macro_rules! promote_signed_scalars_to_i32 { } } +macro_rules! promote_signed_scalars_to_i64 { + (impl $imp:ident for $res:ty, $method:ident) => { + #[cfg(target_pointer_width = "64")] + promote_scalars!(impl $imp for $res, $method, isize); + } +} + // Forward everything to ref-ref, when reusing storage is not helpful macro_rules! forward_all_binop_to_ref_ref { (impl $imp:ident for $res:ty, $method:ident) => { @@ -273,12 +287,14 @@ macro_rules! forward_all_scalar_binop_to_val_val_commutative { macro_rules! promote_unsigned_scalars { (impl $imp:ident for $res:ty, $method:ident) => { promote_unsigned_scalars_to_u32!(impl $imp for $res, $method); + promote_unsigned_scalars_to_u64!(impl $imp for $res, $method); } } macro_rules! promote_signed_scalars { (impl $imp:ident for $res:ty, $method:ident) => { promote_signed_scalars_to_i32!(impl $imp for $res, $method); + promote_signed_scalars_to_i64!(impl $imp for $res, $method); } } From 1fb03ca18aa2ef6a9cc7bb706cd0fc604fcf270c Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Fri, 30 Jun 2017 00:39:37 +0100 Subject: [PATCH 20/24] Make new code work on rustc-1.8.0 - Don't apply attributes to statements (1.12.0) - Don't use checked_abs (1.13.0) --- bigint/src/bigint.rs | 17 +++++++++++------ bigint/src/biguint.rs | 2 ++ bigint/src/lib.rs | 10 ++++++++++ bigint/src/macros.rs | 40 ++++------------------------------------ 4 files changed, 27 insertions(+), 42 deletions(-) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index dfb69d4..ece48b2 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -28,6 +28,9 @@ use biguint; use biguint::to_str_radix_reversed; use biguint::BigUint; +use UsizePromotion; +use IsizePromotion; + #[cfg(test)] #[path = "tests/bigint.rs"] mod bigint_tests; @@ -301,17 +304,19 @@ impl Signed for BigInt { // A convenience method for getting the absolute value of an i32 in a u32. fn i32_abs_as_u32(a: i32) -> u32 { - match a.checked_abs() { - Some(x) => x as u32, - None => a as u32 + if a == i32::min_value() { + a as u32 + } else { + a.abs() as u32 } } // A convenience method for getting the absolute value of an i64 in a u64. fn i64_abs_as_u64(a: i64) -> u64 { - match a.checked_abs() { - Some(x) => x as u64, - None => a as u64 + if a == i64::min_value() { + a as u64 + } else { + a.abs() as u64 } } diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 7af2e71..38f7f29 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -27,6 +27,8 @@ use self::algorithms::{__add2, add2, sub2, sub2rev}; use self::algorithms::{biguint_shl, biguint_shr}; use self::algorithms::{cmp_slice, fls, ilog2}; +use UsizePromotion; + use ParseBigIntError; #[cfg(test)] diff --git a/bigint/src/lib.rs b/bigint/src/lib.rs index 586eeec..02b9992 100644 --- a/bigint/src/lib.rs +++ b/bigint/src/lib.rs @@ -88,6 +88,16 @@ use std::error::Error; use std::num::ParseIntError; use std::fmt; +#[cfg(target_pointer_width = "32")] +type UsizePromotion = u32; +#[cfg(target_pointer_width = "64")] +type UsizePromotion = u64; + +#[cfg(target_pointer_width = "32")] +type IsizePromotion = i32; +#[cfg(target_pointer_width = "64")] +type IsizePromotion = i64; + #[derive(Debug, PartialEq)] pub enum ParseBigIntError { ParseInt(ParseIntError), diff --git a/bigint/src/macros.rs b/bigint/src/macros.rs index a8143ad..7705f55 100644 --- a/bigint/src/macros.rs +++ b/bigint/src/macros.rs @@ -210,35 +210,17 @@ macro_rules! promote_scalars { } } -macro_rules! promote_unsigned_scalars_to_u32 { +macro_rules! promote_unsigned_scalars { (impl $imp:ident for $res:ty, $method:ident) => { - #[cfg(target_pointer_width = "32")] - promote_scalars!(impl $imp for $res, $method, u8, u16, usize); - #[cfg(target_pointer_width = "64")] promote_scalars!(impl $imp for $res, $method, u8, u16); + promote_scalars!(impl $imp for $res, $method, usize); } } -macro_rules! promote_unsigned_scalars_to_u64 { +macro_rules! promote_signed_scalars { (impl $imp:ident for $res:ty, $method:ident) => { - #[cfg(target_pointer_width = "64")] - promote_scalars!(impl $imp for $res, $method, usize); - } -} - -macro_rules! promote_signed_scalars_to_i32 { - (impl $imp:ident for $res:ty, $method:ident) => { - #[cfg(target_pointer_width = "32")] - promote_scalars!(impl $imp for $res, $method, i8, i16, isize); - #[cfg(target_pointer_width = "64")] promote_scalars!(impl $imp for $res, $method, i8, i16); - } -} - -macro_rules! promote_signed_scalars_to_i64 { - (impl $imp:ident for $res:ty, $method:ident) => { - #[cfg(target_pointer_width = "64")] - promote_scalars!(impl $imp for $res, $method, isize); + promote_scalars!(impl $imp for $res, $method, isize); } } @@ -284,20 +266,6 @@ macro_rules! forward_all_scalar_binop_to_val_val_commutative { } } -macro_rules! promote_unsigned_scalars { - (impl $imp:ident for $res:ty, $method:ident) => { - promote_unsigned_scalars_to_u32!(impl $imp for $res, $method); - promote_unsigned_scalars_to_u64!(impl $imp for $res, $method); - } -} - -macro_rules! promote_signed_scalars { - (impl $imp:ident for $res:ty, $method:ident) => { - promote_signed_scalars_to_i32!(impl $imp for $res, $method); - promote_signed_scalars_to_i64!(impl $imp for $res, $method); - } -} - macro_rules! promote_all_scalars { (impl $imp:ident for $res:ty, $method:ident) => { promote_unsigned_scalars!(impl $imp for $res, $method); From 18cc1902fb152b2b299c9c2aea3e6f27fbe28193 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 11 Jul 2017 17:01:15 -0700 Subject: [PATCH 21/24] inline i32_abs_as_u32 and i64_abs_as_u64 --- bigint/src/bigint.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bigint/src/bigint.rs b/bigint/src/bigint.rs index ece48b2..259f619 100644 --- a/bigint/src/bigint.rs +++ b/bigint/src/bigint.rs @@ -303,6 +303,7 @@ impl Signed for BigInt { } // A convenience method for getting the absolute value of an i32 in a u32. +#[inline] fn i32_abs_as_u32(a: i32) -> u32 { if a == i32::min_value() { a as u32 @@ -312,6 +313,7 @@ fn i32_abs_as_u32(a: i32) -> u32 { } // A convenience method for getting the absolute value of an i64 in a u64. +#[inline] fn i64_abs_as_u64(a: i64) -> u64 { if a == i64::min_value() { a as u64 From 18a5bfcd0b1a8b49102cb525662383383dfe00ec Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 11 Jul 2017 17:22:11 -0700 Subject: [PATCH 22/24] fix endianness of to/from_doublebigdigit calls --- bigint/src/biguint.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index 38f7f29..db00a72 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -429,7 +429,7 @@ impl Add for BigUint { self.data.push(0); } - let (lo, hi) = big_digit::from_doublebigdigit(other); + let (hi, lo) = big_digit::from_doublebigdigit(other); let carry = __add2(&mut self.data, &[lo, hi]); if carry != 0 { self.data.push(carry); @@ -497,7 +497,7 @@ impl Sub for BigUint { #[inline] fn sub(mut self, other: DoubleBigDigit) -> BigUint { - let (lo, hi) = big_digit::from_doublebigdigit(other); + let (hi, lo) = big_digit::from_doublebigdigit(other); sub2(&mut self.data[..], &[lo, hi]); self.normalize() } @@ -512,7 +512,7 @@ impl Sub for DoubleBigDigit { other.data.push(0); } - let (lo, hi) = big_digit::from_doublebigdigit(self); + let (hi, lo) = big_digit::from_doublebigdigit(self); sub2rev(&[lo, hi], &mut other.data[..]); other.normalize() } @@ -561,7 +561,7 @@ impl Mul for BigUint { } else if other <= BigDigit::max_value() as DoubleBigDigit { self * other as BigDigit } else { - let (lo, hi) = big_digit::from_doublebigdigit(other); + let (hi, lo) = big_digit::from_doublebigdigit(other); mul3(&self.data[..], &[lo, hi]) } } @@ -624,7 +624,7 @@ impl Div for DoubleBigDigit { match other.data.len() { 0 => panic!(), 1 => From::from(self / other.data[0] as u64), - 2 => From::from(self / big_digit::to_doublebigdigit(other.data[0], other.data[1])), + 2 => From::from(self / big_digit::to_doublebigdigit(other.data[1], other.data[0])), _ => Zero::zero(), } } From 6afac825d9dc0504667d5db2e54b9d377292330e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 11 Jul 2017 17:27:19 -0700 Subject: [PATCH 23/24] test and fix more scalar add cases --- bigint/src/biguint.rs | 37 ++++++++++++++------------ bigint/src/tests/bigint.rs | 52 +++++++++++++++++++++++++++++++++---- bigint/src/tests/biguint.rs | 32 +++++++++++++++++++---- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/bigint/src/biguint.rs b/bigint/src/biguint.rs index db00a72..2c2d046 100644 --- a/bigint/src/biguint.rs +++ b/bigint/src/biguint.rs @@ -405,13 +405,15 @@ impl Add for BigUint { #[inline] fn add(mut self, other: BigDigit) -> BigUint { - if self.data.len() == 0 && other != 0 { - self.data.push(0); - } + if other != 0 { + if self.data.len() == 0 { + self.data.push(0); + } - let carry = __add2(&mut self.data, &[other]); - if carry != 0 { - self.data.push(carry); + let carry = __add2(&mut self.data, &[other]); + if carry != 0 { + self.data.push(carry); + } } self } @@ -422,19 +424,20 @@ impl Add for BigUint { #[inline] fn add(mut self, other: DoubleBigDigit) -> BigUint { - if self.data.len() == 0 && other != 0 { - self.data.push(0); - } - if self.data.len() == 1 && other > BigDigit::max_value() as DoubleBigDigit { - self.data.push(0); - } - let (hi, lo) = big_digit::from_doublebigdigit(other); - let carry = __add2(&mut self.data, &[lo, hi]); - if carry != 0 { - self.data.push(carry); + if hi == 0 { + self + lo + } else { + while self.data.len() < 2 { + self.data.push(0); + } + + let carry = __add2(&mut self.data, &[lo, hi]); + if carry != 0 { + self.data.push(carry); + } + self } - self } } diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index ac3d543..14f86a1 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -1,4 +1,4 @@ -use {BigDigit, BigUint, big_digit}; +use {BigDigit, DoubleBigDigit, BigUint, big_digit}; use {Sign, BigInt, RandBigInt, ToBigInt}; use Sign::{Minus, NoSign, Plus}; @@ -532,6 +532,16 @@ const SUM_TRIPLES: &'static [(&'static [BigDigit], (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), (&[2, 2, 1], &[N1, N2], &[1, 1, 2])]; +fn get_scalar(vec: &[BigDigit]) -> BigDigit { + vec.get(0).map_or(0, BigDigit::clone) +} + +fn get_scalar_double(vec: &[BigDigit]) -> DoubleBigDigit { + let lo = vec.get(0).map_or(0, BigDigit::clone); + let hi = vec.get(1).map_or(0, BigDigit::clone); + big_digit::to_doublebigdigit(hi, lo) +} + #[test] fn test_add() { for elm in SUM_TRIPLES.iter() { @@ -561,8 +571,8 @@ fn test_scalar_add() { let c = BigInt::from_slice(Plus, c_vec); let (na, nb, nc) = (-&a, -&b, -&c); - if a_vec.len() == 1 { - let a = a_vec[0]; + if a_vec.len() <= 1 { + let a = get_scalar(a_vec); assert_op!(a + b == c); assert_op!(b + a == c); assert_op!(a + nc == nb); @@ -577,8 +587,24 @@ fn test_scalar_add() { } } - if b_vec.len() == 1 { - let b = b_vec[0]; + if a_vec.len() <= 2 { + let a = get_scalar_double(a_vec); + assert_op!(a + b == c); + assert_op!(b + a == c); + assert_op!(a + nc == nb); + assert_op!(nc + a == nb); + + if a <= i64::max_value() as u64 { + let na = -(a as i64); + assert_op!(na + nb == nc); + assert_op!(nb + na == nc); + assert_op!(na + c == b); + assert_op!(c + na == b); + } + } + + if b_vec.len() <= 1 { + let b = get_scalar(b_vec); assert_op!(a + b == c); assert_op!(b + a == c); assert_op!(b + nc == na); @@ -592,6 +618,22 @@ fn test_scalar_add() { assert_op!(c + nb == a); } } + + if b_vec.len() <= 2 { + let b = get_scalar_double(b_vec); + assert_op!(a + b == c); + assert_op!(b + a == c); + assert_op!(b + nc == na); + assert_op!(nc + b == na); + + if b <= i64::max_value() as u64 { + let nb = -(b as i64); + assert_op!(na + nb == nc); + assert_op!(nb + na == nc); + assert_op!(nb + c == a); + assert_op!(c + nb == a); + } + } } } diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index c39aa40..b8b3492 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -1,5 +1,5 @@ use integer::Integer; -use {BigDigit, BigUint, ToBigUint, big_digit}; +use {BigDigit, DoubleBigDigit, BigUint, ToBigUint, big_digit}; use {BigInt, RandBigInt, ToBigInt}; use Sign::Plus; @@ -677,6 +677,16 @@ const SUM_TRIPLES: &'static [(&'static [BigDigit], (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), (&[2, 2, 1], &[N1, N2], &[1, 1, 2])]; +fn get_scalar(vec: &[BigDigit]) -> BigDigit { + vec.get(0).map_or(0, BigDigit::clone) +} + +fn get_scalar_double(vec: &[BigDigit]) -> DoubleBigDigit { + let lo = vec.get(0).map_or(0, BigDigit::clone); + let hi = vec.get(1).map_or(0, BigDigit::clone); + big_digit::to_doublebigdigit(hi, lo) +} + #[test] fn test_add() { for elm in SUM_TRIPLES.iter() { @@ -698,14 +708,26 @@ fn test_scalar_add() { let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); - if a_vec.len() == 1 { - let a = a_vec[0]; + if a_vec.len() <= 1 { + let a = get_scalar(a_vec); assert_op!(a + b == c); assert_op!(b + a == c); } - if b_vec.len() == 1 { - let b = b_vec[0]; + if a_vec.len() <= 2 { + let a = get_scalar_double(a_vec); + assert_op!(a + b == c); + assert_op!(b + a == c); + } + + if b_vec.len() <= 1 { + let b = get_scalar(b_vec); + assert_op!(a + b == c); + assert_op!(b + a == c); + } + + if b_vec.len() <= 2 { + let b = get_scalar_double(b_vec); assert_op!(a + b == c); assert_op!(b + a == c); } From e5434dc6594ce15d5bab07431a8e07bd56f2f3a5 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 11 Jul 2017 21:59:10 -0700 Subject: [PATCH 24/24] Add assert_scalar_op! for DRYer testing --- bigint/src/tests/bigint.rs | 192 ++++++++---------------------------- bigint/src/tests/biguint.rs | 124 +++++++---------------- 2 files changed, 75 insertions(+), 241 deletions(-) diff --git a/bigint/src/tests/bigint.rs b/bigint/src/tests/bigint.rs index 14f86a1..9fbebb0 100644 --- a/bigint/src/tests/bigint.rs +++ b/bigint/src/tests/bigint.rs @@ -1,4 +1,4 @@ -use {BigDigit, DoubleBigDigit, BigUint, big_digit}; +use {BigDigit, BigUint, big_digit}; use {Sign, BigInt, RandBigInt, ToBigInt}; use Sign::{Minus, NoSign, Plus}; @@ -24,6 +24,25 @@ macro_rules! assert_op { }; } +/// Assert that an op works for scalar left or right +macro_rules! assert_scalar_op { + (($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => { + $( + if let Some(left) = $left.$to() { + assert_op!(left $op $right == $expected); + } + if let Some(right) = $right.$to() { + assert_op!($left $op right == $expected); + } + )* + }; + ($left:ident $op:tt $right:ident == $expected:expr) => { + assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize, + to_i8, to_i16, to_i32, to_i64, to_isize) + $left $op $right == $expected); + }; +} + #[test] fn test_from_biguint() { fn check(inp_s: Sign, inp_n: usize, ans_s: Sign, ans_n: usize) { @@ -532,16 +551,6 @@ const SUM_TRIPLES: &'static [(&'static [BigDigit], (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), (&[2, 2, 1], &[N1, N2], &[1, 1, 2])]; -fn get_scalar(vec: &[BigDigit]) -> BigDigit { - vec.get(0).map_or(0, BigDigit::clone) -} - -fn get_scalar_double(vec: &[BigDigit]) -> DoubleBigDigit { - let lo = vec.get(0).map_or(0, BigDigit::clone); - let hi = vec.get(1).map_or(0, BigDigit::clone); - big_digit::to_doublebigdigit(hi, lo) -} - #[test] fn test_add() { for elm in SUM_TRIPLES.iter() { @@ -571,69 +580,14 @@ fn test_scalar_add() { let c = BigInt::from_slice(Plus, c_vec); let (na, nb, nc) = (-&a, -&b, -&c); - if a_vec.len() <= 1 { - let a = get_scalar(a_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - assert_op!(a + nc == nb); - assert_op!(nc + a == nb); - - if a <= i32::max_value() as u32 { - let na = -(a as i32); - assert_op!(na + nb == nc); - assert_op!(nb + na == nc); - assert_op!(na + c == b); - assert_op!(c + na == b); - } - } - - if a_vec.len() <= 2 { - let a = get_scalar_double(a_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - assert_op!(a + nc == nb); - assert_op!(nc + a == nb); - - if a <= i64::max_value() as u64 { - let na = -(a as i64); - assert_op!(na + nb == nc); - assert_op!(nb + na == nc); - assert_op!(na + c == b); - assert_op!(c + na == b); - } - } - - if b_vec.len() <= 1 { - let b = get_scalar(b_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - assert_op!(b + nc == na); - assert_op!(nc + b == na); - - if b <= i32::max_value() as u32 { - let nb = -(b as i32); - assert_op!(na + nb == nc); - assert_op!(nb + na == nc); - assert_op!(nb + c == a); - assert_op!(c + nb == a); - } - } - - if b_vec.len() <= 2 { - let b = get_scalar_double(b_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - assert_op!(b + nc == na); - assert_op!(nc + b == na); - - if b <= i64::max_value() as u64 { - let nb = -(b as i64); - assert_op!(na + nb == nc); - assert_op!(nb + na == nc); - assert_op!(nb + c == a); - assert_op!(c + nb == a); - } - } + assert_scalar_op!(a + b == c); + assert_scalar_op!(b + a == c); + assert_scalar_op!(c + na == b); + assert_scalar_op!(c + nb == a); + assert_scalar_op!(a + nc == nb); + assert_scalar_op!(b + nc == na); + assert_scalar_op!(na + nb == nc); + assert_scalar_op!(a + na == Zero::zero()); } } @@ -666,53 +620,14 @@ fn test_scalar_sub() { let c = BigInt::from_slice(Plus, c_vec); let (na, nb, nc) = (-&a, -&b, -&c); - if a_vec.len() == 1 { - let a = a_vec[0]; - assert_op!(c - a == b); - assert_op!(a - c == nb); - assert_op!(a - nb == c); - assert_op!(nb - a == nc); - - if a <= i32::max_value() as u32 { - let na = -(a as i32); - assert_op!(nc - na == nb); - assert_op!(na - nc == b); - assert_op!(na - b == nc); - assert_op!(b - na == c); - } - } - - if b_vec.len() == 1 { - let b = b_vec[0]; - assert_op!(c - b == a); - assert_op!(b - c == na); - assert_op!(b - na == c); - assert_op!(na - b == nc); - - if b <= i32::max_value() as u32 { - let nb = -(b as i32); - assert_op!(nc - nb == na); - assert_op!(nb - nc == a); - assert_op!(nb - a == nc); - assert_op!(a - nb == c); - } - } - - if c_vec.len() == 1 { - let c = c_vec[0]; - assert_op!(c - a == b); - assert_op!(a - c == nb); - assert_op!(c - b == a); - assert_op!(b - c == na); - - if c <= i32::max_value() as u32 { - let nc = -(c as i32); - assert_op!(nc - na == nb); - assert_op!(na - nc == b); - assert_op!(nc - nb == na); - assert_op!(nb - nc == a); - } - } + assert_scalar_op!(c - a == b); + assert_scalar_op!(c - b == a); + assert_scalar_op!(nb - a == nc); + assert_scalar_op!(na - b == nc); + assert_scalar_op!(b - na == c); + assert_scalar_op!(a - nb == c); + assert_scalar_op!(nc - na == nb); + assert_scalar_op!(a - a == Zero::zero()); } } @@ -791,37 +706,12 @@ fn test_scalar_mul() { let c = BigInt::from_slice(Plus, c_vec); let (na, nb, nc) = (-&a, -&b, -&c); - if a_vec.len() == 1 { - let a = a_vec[0]; - assert_op!(b * a == c); - assert_op!(a * b == c); - assert_op!(nb * a == nc); - assert_op!(a * nb == nc); + assert_scalar_op!(a * b == c); + assert_scalar_op!(b * a == c); + assert_scalar_op!(na * nb == c); - if a <= i32::max_value() as u32 { - let na = -(a as i32); - assert_op!(nb * na == c); - assert_op!(na * nb == c); - assert_op!(b * na == nc); - assert_op!(na * b == nc); - } - } - - if b_vec.len() == 1 { - let b = b_vec[0]; - assert_op!(a * b == c); - assert_op!(b * a == c); - assert_op!(na * b == nc); - assert_op!(b * na == nc); - - if b <= i32::max_value() as u32 { - let nb = -(b as i32); - assert_op!(na * nb == c); - assert_op!(nb * na == c); - assert_op!(a * nb == nc); - assert_op!(nb * a == nc); - } - } + assert_scalar_op!(na * b == nc); + assert_scalar_op!(nb * a == nc); } } diff --git a/bigint/src/tests/biguint.rs b/bigint/src/tests/biguint.rs index b8b3492..0f3b743 100644 --- a/bigint/src/tests/biguint.rs +++ b/bigint/src/tests/biguint.rs @@ -1,5 +1,5 @@ use integer::Integer; -use {BigDigit, DoubleBigDigit, BigUint, ToBigUint, big_digit}; +use {BigDigit, BigUint, ToBigUint, big_digit}; use {BigInt, RandBigInt, ToBigInt}; use Sign::Plus; @@ -25,6 +25,24 @@ macro_rules! assert_op { }; } +/// Assert that an op works for scalar left or right +macro_rules! assert_scalar_op { + (($($to:ident),*) $left:ident $op:tt $right:ident == $expected:expr) => { + $( + if let Some(left) = $left.$to() { + assert_op!(left $op $right == $expected); + } + if let Some(right) = $right.$to() { + assert_op!($left $op right == $expected); + } + )* + }; + ($left:ident $op:tt $right:ident == $expected:expr) => { + assert_scalar_op!((to_u8, to_u16, to_u32, to_u64, to_usize) + $left $op $right == $expected); + }; +} + #[test] fn test_from_slice() { fn check(slice: &[BigDigit], data: &[BigDigit]) { @@ -677,16 +695,6 @@ const SUM_TRIPLES: &'static [(&'static [BigDigit], (&[1, 1, 1], &[N1, N1], &[0, 1, 2]), (&[2, 2, 1], &[N1, N2], &[1, 1, 2])]; -fn get_scalar(vec: &[BigDigit]) -> BigDigit { - vec.get(0).map_or(0, BigDigit::clone) -} - -fn get_scalar_double(vec: &[BigDigit]) -> DoubleBigDigit { - let lo = vec.get(0).map_or(0, BigDigit::clone); - let hi = vec.get(1).map_or(0, BigDigit::clone); - big_digit::to_doublebigdigit(hi, lo) -} - #[test] fn test_add() { for elm in SUM_TRIPLES.iter() { @@ -708,29 +716,8 @@ fn test_scalar_add() { let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); - if a_vec.len() <= 1 { - let a = get_scalar(a_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - } - - if a_vec.len() <= 2 { - let a = get_scalar_double(a_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - } - - if b_vec.len() <= 1 { - let b = get_scalar(b_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - } - - if b_vec.len() <= 2 { - let b = get_scalar_double(b_vec); - assert_op!(a + b == c); - assert_op!(b + a == c); - } + assert_scalar_op!(a + b == c); + assert_scalar_op!(b + a == c); } } @@ -755,21 +742,8 @@ fn test_scalar_sub() { let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); - if a_vec.len() == 1 { - let a = a_vec[0]; - assert_op!(c - a == b); - } - - if b_vec.len() == 1 { - let b = b_vec[0]; - assert_op!(c - b == a); - } - - if c_vec.len() == 1 { - let c = c_vec[0]; - assert_op!(c - a == b); - assert_op!(c - b == a); - } + assert_scalar_op!(c - a == b); + assert_scalar_op!(c - b == a); } } @@ -849,17 +823,8 @@ fn test_scalar_mul() { let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); - if a_vec.len() == 1 { - let a = a_vec[0]; - assert_op!(a * b == c); - assert_op!(b * a == c); - } - - if b_vec.len() == 1 { - let b = b_vec[0]; - assert_op!(a * b == c); - assert_op!(b * a == c); - } + assert_scalar_op!(a * b == c); + assert_scalar_op!(b * a == c); } } @@ -906,28 +871,14 @@ fn test_scalar_div_rem() { let b = BigUint::from_slice(b_vec); let c = BigUint::from_slice(c_vec); - if a_vec.len() == 1 && a_vec[0] != 0 { - let a = a_vec[0]; - assert_op!(c / a == b); - assert_op!(c % a == Zero::zero()); + if !a.is_zero() { + assert_scalar_op!(c / a == b); + assert_scalar_op!(c % a == Zero::zero()); } - if b_vec.len() == 1 && b_vec[0] != 0 { - let b = b_vec[0]; - assert_op!(c / b == a); - assert_op!(c % b == Zero::zero()); - } - - if c_vec.len() == 1 { - let c = c_vec[0]; - if !a.is_zero() { - assert_op!(c / a == b); - assert_op!(c % a == Zero::zero()); - } - if !b.is_zero() { - assert_op!(c / b == a); - assert_op!(c % b == Zero::zero()); - } + if !b.is_zero() { + assert_scalar_op!(c / b == a); + assert_scalar_op!(c % b == Zero::zero()); } } @@ -938,16 +889,9 @@ fn test_scalar_div_rem() { let c = BigUint::from_slice(c_vec); let d = BigUint::from_slice(d_vec); - if b_vec.len() == 1 && b_vec[0] != 0 { - let b = b_vec[0]; - assert_op!(a / b == c); - assert_op!(a % b == d); - } - - if a_vec.len() == 1 && !b.is_zero() { - let a = a_vec[0]; - assert_op!(a / b == c); - assert_op!(a % b == d); + if !b.is_zero() { + assert_scalar_op!(a / b == c); + assert_scalar_op!(a % b == d); } } }