diff --git a/src/unsigned/div.rs b/src/unsigned/div.rs index 47f248f..d1c080f 100644 --- a/src/unsigned/div.rs +++ b/src/unsigned/div.rs @@ -151,6 +151,20 @@ macro_rules! div_impls (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 { 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 { type Output = $name; @@ -255,6 +282,12 @@ macro_rules! generate_div_tests { let (myq, myr) = a.divmod(&b); assert_eq!(q, myq); 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); }); }; } \ No newline at end of file diff --git a/src/unsigned/mod.rs b/src/unsigned/mod.rs index 14790b1..2f36637 100644 --- a/src/unsigned/mod.rs +++ b/src/unsigned/mod.rs @@ -70,7 +70,7 @@ use self::cmp::compare; use self::codec::raw_decoder; use self::div::get_number_size; use self::formatter::tochar; -use self::mul::multiply; +use self::mul::{multiply,multiply_small}; use self::primes::SMALL_PRIMES; use self::shifts::{shiftl,shiftr}; use self::sub::subtract; @@ -78,7 +78,9 @@ use std::cmp::{Ordering,min}; use std::fmt; use std::fmt::Write; 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::{Sub,SubAssign}; diff --git a/src/unsigned/mul.rs b/src/unsigned/mul.rs index 94c1436..e96d791 100644 --- a/src/unsigned/mul.rs +++ b/src/unsigned/mul.rs @@ -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 { ($name: ident, $dbl: ident) => { impl Mul<$name> for $name { @@ -61,6 +86,20 @@ macro_rules! multiply_impls { res } } + + impl MulAssign for $name { + fn mul_assign(&mut self, rhs: $name) { + let copy = self.value.clone(); + multiply_small(&mut self.value, ©, &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, ©, &rhs.value); + } + } }; } @@ -88,10 +127,12 @@ macro_rules! generate_mul_tests let (neg2, cbytes) = case.get("c").unwrap(); assert!(!neg0 && !neg1 && !neg2); - let a = $name::from_bytes(abytes); + let mut a = $name::from_bytes(abytes); let b = $name::from_bytes(bbytes); 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); }); }; } \ No newline at end of file