Support in-place division, multiplication, and modulos.

This commit is contained in:
2018-12-23 20:23:36 -08:00
parent 364b0d168b
commit b52dd4d355
3 changed files with 80 additions and 4 deletions

View File

@@ -151,6 +151,20 @@ macro_rules! div_impls
(resq, r) (resq, r)
} }
} }
impl DivAssign for $name {
fn div_assign(&mut self, rhs: $name) {
self.div_assign(&rhs);
}
}
impl<'a> DivAssign<&'a $name> for $name {
fn div_assign(&mut self, rhs: &$name) {
let (res, _) = self.divmod(&rhs);
self.value.copy_from_slice(&res.value);
}
}
impl Div for $name { impl Div for $name {
type Output = $name; type Output = $name;
@@ -186,6 +200,19 @@ macro_rules! div_impls
} }
} }
impl RemAssign for $name {
fn rem_assign(&mut self, rhs: $name) {
self.rem_assign(&rhs);
}
}
impl<'a> RemAssign<&'a $name> for $name {
fn rem_assign(&mut self, rhs: &$name) {
let (_, res) = self.divmod(rhs);
self.value.copy_from_slice(&res.value);
}
}
impl Rem for $name { impl Rem for $name {
type Output = $name; type Output = $name;
@@ -255,6 +282,12 @@ macro_rules! generate_div_tests {
let (myq, myr) = a.divmod(&b); let (myq, myr) = a.divmod(&b);
assert_eq!(q, myq); assert_eq!(q, myq);
assert_eq!(r, myr); assert_eq!(r, myr);
let mut a2 = a.clone();
a2 /= &b;
assert_eq!(a2, q);
let mut a3 = a.clone();
a3 %= &b;
assert_eq!(a3, r);
}); });
}; };
} }

View File

@@ -70,7 +70,7 @@ use self::cmp::compare;
use self::codec::raw_decoder; use self::codec::raw_decoder;
use self::div::get_number_size; use self::div::get_number_size;
use self::formatter::tochar; use self::formatter::tochar;
use self::mul::multiply; use self::mul::{multiply,multiply_small};
use self::primes::SMALL_PRIMES; use self::primes::SMALL_PRIMES;
use self::shifts::{shiftl,shiftr}; use self::shifts::{shiftl,shiftr};
use self::sub::subtract; use self::sub::subtract;
@@ -78,7 +78,9 @@ use std::cmp::{Ordering,min};
use std::fmt; use std::fmt;
use std::fmt::Write; use std::fmt::Write;
use std::ops::{Add,AddAssign}; use std::ops::{Add,AddAssign};
use std::ops::{Div,Mul,Rem}; use std::ops::{Mul,MulAssign};
use std::ops::{Div,DivAssign};
use std::ops::{Rem,RemAssign};
use std::ops::{Shl,ShlAssign,Shr,ShrAssign}; use std::ops::{Shl,ShlAssign,Shr,ShrAssign};
use std::ops::{Sub,SubAssign}; use std::ops::{Sub,SubAssign};

View File

@@ -20,6 +20,31 @@ pub fn multiply(dest: &mut [u64], left: &[u64], right: &[u64])
} }
} }
pub fn multiply_small(dest: &mut [u64], left: &[u64], right: &[u64])
{
let len = right.len();
assert_eq!(dest.len(), len);
assert_eq!(left.len(), len);
for i in 0..len { dest[i] = 0; }
for i in 0..len {
let mut carry = 0;
for j in 0..len {
if i+j >= len {
carry = 0;
continue;
}
let old = dest[i+j] as u128;
let l128 = left[j] as u128;
let r128 = right[i] as u128;
let uv = old + (l128 * r128) + carry;
dest[i+j] = uv as u64;
carry = uv >> 64;
}
}
}
macro_rules! multiply_impls { macro_rules! multiply_impls {
($name: ident, $dbl: ident) => { ($name: ident, $dbl: ident) => {
impl Mul<$name> for $name { impl Mul<$name> for $name {
@@ -61,6 +86,20 @@ macro_rules! multiply_impls {
res res
} }
} }
impl MulAssign for $name {
fn mul_assign(&mut self, rhs: $name) {
let copy = self.value.clone();
multiply_small(&mut self.value, &copy, &rhs.value);
}
}
impl<'a> MulAssign<&'a $name> for $name {
fn mul_assign(&mut self, rhs: &$name) {
let copy = self.value.clone();
multiply_small(&mut self.value, &copy, &rhs.value);
}
}
}; };
} }
@@ -88,10 +127,12 @@ macro_rules! generate_mul_tests
let (neg2, cbytes) = case.get("c").unwrap(); let (neg2, cbytes) = case.get("c").unwrap();
assert!(!neg0 && !neg1 && !neg2); assert!(!neg0 && !neg1 && !neg2);
let a = $name::from_bytes(abytes); let mut a = $name::from_bytes(abytes);
let b = $name::from_bytes(bbytes); let b = $name::from_bytes(bbytes);
let c = $dbl::from_bytes(cbytes); let c = $dbl::from_bytes(cbytes);
assert_eq!(c, &a * &b); assert_eq!(c, &a * &b, "standard multiplication");
a *= b;
assert_eq!($name::from(c), a);
}); });
}; };
} }