Add scalar ops for all remaining integer types

This commit is contained in:
Sam Cappleman-Lynes 2017-06-29 22:18:54 +01:00
parent fd87d87db3
commit 2a3cd41820
3 changed files with 348 additions and 3 deletions

View File

@ -23,7 +23,7 @@ use self::Sign::{Minus, NoSign, Plus};
use super::ParseBigIntError; use super::ParseBigIntError;
use super::big_digit; use super::big_digit;
use super::big_digit::BigDigit; use super::big_digit::{BigDigit, DoubleBigDigit};
use biguint; use biguint;
use biguint::to_str_radix_reversed; use biguint::to_str_radix_reversed;
use biguint::BigUint; 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 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 // we compare both sign and magnitude. So we duplicate this body for every
// val/ref combination, deferring that decision to BigUint's own forwarding. // 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); 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<BigDigit> for BigInt, add);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigInt, add);
impl Add<BigDigit> for BigInt { impl Add<BigDigit> for BigInt {
type Output = 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<i32> for BigInt, add);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<i64> for BigInt, add);
impl Add<i32> for BigInt { impl Add<i32> for BigInt {
type Output = 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 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 // we compare both sign and magnitude. So we duplicate this body for every
// val/ref combination, deferring that decision to BigUint's own forwarding. // 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); 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<BigDigit> for BigInt, sub);
forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigInt, sub);
impl Sub<BigDigit> for BigInt { impl Sub<BigDigit> for BigInt {
type Output = 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<i32> for BigInt, sub);
forward_all_scalar_binop_to_val_val!(impl Sub<i64> for BigInt, sub);
impl Sub<i32> for BigInt { impl Sub<i32> for BigInt {
type Output = 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); forward_all_binop_to_ref_ref!(impl Mul for BigInt, mul);
impl<'a, 'b> Mul<&'b BigInt> for &'a BigInt { 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); 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<BigDigit> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigInt, mul);
impl Mul<BigDigit> for BigInt { impl Mul<BigDigit> for BigInt {
type Output = 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<i32> for BigInt, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<i64> for BigInt, mul);
impl Mul<i32> for BigInt { impl Mul<i32> for BigInt {
type Output = 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); forward_all_binop_to_ref_ref!(impl Div for BigInt, div);
impl<'a, 'b> Div<&'b BigInt> for &'a BigInt { 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); 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<BigDigit> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigInt, div);
impl Div<BigDigit> for BigInt { impl Div<BigDigit> for BigInt {
type Output = 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<i32> for BigInt, div);
forward_all_scalar_binop_to_val_val!(impl Div<i64> for BigInt, div);
impl Div<i32> for BigInt { impl Div<i32> for BigInt {
type Output = 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); forward_all_binop_to_ref_ref!(impl Rem for BigInt, rem);
impl<'a, 'b> Rem<&'b BigInt> for &'a BigInt { 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); 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<BigDigit> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigInt, rem);
impl Rem<BigDigit> for BigInt { impl Rem<BigDigit> for BigInt {
type Output = 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<i32> for BigInt, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<i64> for BigInt, rem);
impl Rem<i32> for BigInt { impl Rem<i32> for BigInt {
type Output = 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 { impl Neg for BigInt {
type Output = BigInt; type Output = BigInt;

View File

@ -396,6 +396,7 @@ impl<'a> Add<&'a BigUint> for BigUint {
promote_unsigned_scalars!(impl Add for BigUint, add); 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<BigDigit> for BigUint, add);
forward_all_scalar_binop_to_val_val_commutative!(impl Add<DoubleBigDigit> for BigUint, add);
impl Add<BigDigit> for BigUint { impl Add<BigDigit> for BigUint {
type Output = 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_val_val_binop!(impl Sub for BigUint, sub);
forward_ref_ref_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); 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<BigDigit> for BigUint, sub);
forward_all_scalar_binop_to_val_val!(impl Sub<DoubleBigDigit> for BigUint, sub);
impl Sub<BigDigit> for BigUint { impl Sub<BigDigit> for BigUint {
type Output = 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); forward_all_binop_to_ref_ref!(impl Mul for BigUint, mul);
impl<'a, 'b> Mul<&'b BigUint> for &'a BigUint { 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); 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<BigDigit> for BigUint, mul);
forward_all_scalar_binop_to_val_val_commutative!(impl Mul<DoubleBigDigit> for BigUint, mul);
impl Mul<BigDigit> for BigUint { impl Mul<BigDigit> for BigUint {
type Output = 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); forward_all_binop_to_ref_ref!(impl Div for BigUint, div);
impl<'a, 'b> Div<&'b BigUint> for &'a BigUint { 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); 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<BigDigit> for BigUint, div);
forward_all_scalar_binop_to_val_val!(impl Div<DoubleBigDigit> for BigUint, div);
impl Div<BigDigit> for BigUint { impl Div<BigDigit> for BigUint {
type Output = BigUint; type Output = BigUint;
@ -531,7 +599,31 @@ impl Div<BigUint> for BigDigit {
match other.data.len() { match other.data.len() {
0 => panic!(), 0 => panic!(),
1 => From::from(self / other.data[0]), 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); 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<BigDigit> for BigUint, rem);
forward_all_scalar_binop_to_val_val!(impl Rem<DoubleBigDigit> for BigUint, rem);
impl Rem<BigDigit> for BigUint { impl Rem<BigDigit> for BigUint {
type Output = BigUint; type Output = BigUint;
@ -569,7 +662,31 @@ impl Rem<BigUint> for BigDigit {
match other.data.len() { match other.data.len() {
0 => panic!(), 0 => panic!(),
1 => From::from(self % other.data[0]), 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),
} }
} }
} }

View File

@ -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 { macro_rules! promote_signed_scalars_to_i32 {
(impl $imp:ident for $res:ty, $method:ident) => { (impl $imp:ident for $res:ty, $method:ident) => {
#[cfg(target_pointer_width = "32")] #[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 // Forward everything to ref-ref, when reusing storage is not helpful
macro_rules! forward_all_binop_to_ref_ref { macro_rules! forward_all_binop_to_ref_ref {
(impl $imp:ident for $res:ty, $method:ident) => { (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 { macro_rules! promote_unsigned_scalars {
(impl $imp:ident for $res:ty, $method:ident) => { (impl $imp:ident for $res:ty, $method:ident) => {
promote_unsigned_scalars_to_u32!(impl $imp for $res, $method); 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 { macro_rules! promote_signed_scalars {
(impl $imp:ident for $res:ty, $method:ident) => { (impl $imp:ident for $res:ty, $method:ident) => {
promote_signed_scalars_to_i32!(impl $imp for $res, $method); promote_signed_scalars_to_i32!(impl $imp for $res, $method);
promote_signed_scalars_to_i64!(impl $imp for $res, $method);
} }
} }