From 2a3cd4182015d91243c7051b2924e5ae800de0ea Mon Sep 17 00:00:00 2001 From: Sam Cappleman-Lynes Date: Thu, 29 Jun 2017 22:18:54 +0100 Subject: [PATCH] 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); } }