Browse Source

Add scalar ops for all remaining integer types

Sam Cappleman-Lynes 7 years ago
parent
commit
2a3cd41820
3 changed files with 348 additions and 3 deletions
  1. 213 1
      bigint/src/bigint.rs
  2. 119 2
      bigint/src/biguint.rs
  3. 16 0
      bigint/src/macros.rs

+ 213 - 1
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<BigInt> for BigInt {
 
 promote_all_scalars!(impl Add for BigInt, add);
 forward_all_scalar_binop_to_val_val_commutative!(impl Add<BigDigit> for BigInt, add);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigInt, add);
 
 impl Add<BigDigit> for BigInt {
     type Output = BigInt;
@@ -391,7 +400,26 @@ impl Add<BigDigit> for BigInt {
     }
 }
 
+impl Add<DoubleBigDigit> 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<i32> for BigInt, add);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<i64> for BigInt, add);
 
 impl Add<i32> for BigInt {
     type Output = BigInt;
@@ -406,6 +434,19 @@ impl Add<i32> for BigInt {
     }
 }
 
+impl Add<i64> 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<BigInt> for BigInt {
 
 promote_all_scalars!(impl Sub for BigInt, sub);
 forward_all_scalar_binop_to_val_val!(impl Sub<BigDigit> for BigInt, sub);
+forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigInt, sub);
 
 impl Sub<BigDigit> for BigInt {
     type Output = BigInt;
@@ -499,7 +541,35 @@ impl Sub<BigInt> for BigDigit {
     }
 }
 
+impl Sub<DoubleBigDigit> 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<BigInt> for DoubleBigDigit {
+    type Output = BigInt;
+
+    #[inline]
+    fn sub(self, other: BigInt) -> BigInt {
+        -(other - self)
+    }
+}
+
 forward_all_scalar_binop_to_val_val!(impl Sub<i32> for BigInt, sub);
+forward_all_scalar_binop_to_val_val!(impl Sub<i64> for BigInt, sub);
 
 impl Sub<i32> for BigInt {
     type Output = BigInt;
@@ -527,6 +597,32 @@ impl Sub<BigInt> for i32 {
     }
 }
 
+impl Sub<i64> 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<BigInt> 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<BigDigit> for BigInt, mul);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigInt, mul);
 
 impl Mul<BigDigit> for BigInt {
     type Output = BigInt;
@@ -550,7 +647,17 @@ impl Mul<BigDigit> for BigInt {
     }
 }
 
+impl Mul<DoubleBigDigit> 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<i32> for BigInt, mul);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i64> for BigInt, mul);
 
 impl Mul<i32> for BigInt {
     type Output = BigInt;
@@ -565,6 +672,19 @@ impl Mul<i32> for BigInt {
     }
 }
 
+impl Mul<i64> 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<BigDigit> for BigInt, div);
+forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigInt, div);
 
 impl Div<BigDigit> for BigInt {
     type Output = BigInt;
@@ -598,7 +719,26 @@ impl Div<BigInt> for BigDigit {
     }
 }
 
+impl Div<DoubleBigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn div(self, other: DoubleBigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data / other)
+    }
+}
+
+impl Div<BigInt> 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<i32> for BigInt, div);
+forward_all_scalar_binop_to_val_val!(impl Div<i64> for BigInt, div);
 
 impl Div<i32> for BigInt {
     type Output = BigInt;
@@ -626,6 +766,32 @@ impl Div<BigInt> for i32 {
     }
 }
 
+impl Div<i64> 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<BigInt> 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<BigDigit> for BigInt, rem);
+forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigInt, rem);
 
 impl Rem<BigDigit> for BigInt {
     type Output = BigInt;
@@ -659,7 +826,26 @@ impl Rem<BigInt> for BigDigit {
     }
 }
 
+impl Rem<DoubleBigDigit> for BigInt {
+    type Output = BigInt;
+
+    #[inline]
+    fn rem(self, other: DoubleBigDigit) -> BigInt {
+        BigInt::from_biguint(self.sign, self.data % other)
+    }
+}
+
+impl Rem<BigInt> 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<i32> for BigInt, rem);
+forward_all_scalar_binop_to_val_val!(impl Rem<i64> for BigInt, rem);
 
 impl Rem<i32> for BigInt {
     type Output = BigInt;
@@ -687,6 +873,32 @@ impl Rem<BigInt> for i32 {
     }
 }
 
+impl Rem<i64> 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<BigInt> 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;
 

+ 119 - 2
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<BigDigit> for BigUint, add);
+forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigUint, add);
 
 impl Add<BigDigit> for BigUint {
     type Output = BigUint;
@@ -414,6 +415,27 @@ impl Add<BigDigit> for BigUint {
     }
 }
 
+impl Add<DoubleBigDigit> 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<BigUint> for &'a BigUint {
 
 promote_unsigned_scalars!(impl Sub for BigUint, sub);
 forward_all_scalar_binop_to_val_val!(impl Sub<BigDigit> for BigUint, sub);
+forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigUint, sub);
 
 impl Sub<BigDigit> for BigUint {
     type Output = BigUint;
@@ -467,6 +490,32 @@ impl Sub<BigUint> for BigDigit {
     }
 }
 
+impl Sub<DoubleBigDigit> 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<BigUint> 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<BigDigit> for BigUint, mul);
+forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigUint, mul);
 
 impl Mul<BigDigit> for BigUint {
     type Output = BigUint;
@@ -498,6 +548,23 @@ impl Mul<BigDigit> for BigUint {
     }
 }
 
+impl Mul<DoubleBigDigit> 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<BigDigit> for BigUint, div);
+forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigUint, div);
 
 impl Div<BigDigit> for BigUint {
     type Output = BigUint;
@@ -531,7 +599,31 @@ impl Div<BigUint> for BigDigit {
         match other.data.len() {
             0 => panic!(),
             1 => From::from(self / other.data[0]),
-            _ => Zero::zero()
+            _ => Zero::zero(),
+        }
+    }
+}
+
+impl Div<DoubleBigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn div(self, other: DoubleBigDigit) -> BigUint {
+        let (q, _) = self.div_rem(&From::from(other));
+        q
+    }
+}
+
+impl Div<BigUint> 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<BigDigit> for BigUint, rem);
+forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigUint, rem);
 
 impl Rem<BigDigit> for BigUint {
     type Output = BigUint;
@@ -569,7 +662,31 @@ impl Rem<BigUint> for BigDigit {
         match other.data.len() {
             0 => panic!(),
             1 => From::from(self % other.data[0]),
-            _ => other
+            _ => From::from(self)
+        }
+    }
+}
+
+impl Rem<DoubleBigDigit> for BigUint {
+    type Output = BigUint;
+
+    #[inline]
+    fn rem(self, other: DoubleBigDigit) -> BigUint {
+        let (_, r) = self.div_rem(&From::from(other));
+        r
+    }
+}
+
+impl Rem<BigUint> 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),
         }
     }
 }

+ 16 - 0
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<u64> 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<i64> 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);
     }
 }