Support in-place division, multiplication, and modulos.
This commit is contained in:
@@ -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);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -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};
|
||||||
|
|
||||||
|
|||||||
@@ -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, ©, &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();
|
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);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user