Base implementation of signed numbers and EGCD, with tests.
This commit is contained in:
113
src/signed/add.rs
Normal file
113
src/signed/add.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
macro_rules! add_impls
|
||||
{
|
||||
($name: ident, $bigger: ident, $ubigger: ident) => {
|
||||
impl AddAssign<$name> for $name {
|
||||
fn add_assign(&mut self, rhs: $name) {
|
||||
self.add_assign(&rhs);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a $name> for $name {
|
||||
fn add_assign(&mut self, rhs: &$name) {
|
||||
if self.negative == rhs.negative {
|
||||
unsafe_addition(&mut self.value.value, &rhs.value.value, true);
|
||||
} else {
|
||||
if self.value > rhs.value {
|
||||
self.value -= rhs.value.clone();
|
||||
} else {
|
||||
self.value = rhs.value.clone() - self.value.clone();
|
||||
self.negative = rhs.negative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<$name> for $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: $name) -> $bigger
|
||||
{
|
||||
&self + &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a $name> for $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: &$name) -> $bigger
|
||||
{
|
||||
&self + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<$name> for &'a $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: $name) -> $bigger
|
||||
{
|
||||
self + &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> Add<&'a $name> for &'b $name {
|
||||
type Output = $bigger;
|
||||
|
||||
fn add(self, rhs: &$name) -> $bigger
|
||||
{
|
||||
if self.negative == rhs.negative {
|
||||
$bigger{
|
||||
negative: self.negative,
|
||||
value: &self.value + &rhs.value
|
||||
}
|
||||
} else {
|
||||
if self.value > rhs.value {
|
||||
$bigger {
|
||||
negative: self.negative,
|
||||
value: $ubigger::from(&self.value - &rhs.value)
|
||||
}
|
||||
} else {
|
||||
$bigger {
|
||||
negative: rhs.negative,
|
||||
value: $ubigger::from(&rhs.value - &self.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
macro_rules! generate_sigadd_tests {
|
||||
($sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
#[test]
|
||||
fn $lname() {
|
||||
generate_sigadd_tests!(body$sname, $name, $lname, $bigger, $ubigger);
|
||||
}
|
||||
};
|
||||
(ignore $sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn $lname() {
|
||||
generate_sigadd_tests!(body $sname, $name, $lname, $bigger, $ubigger);
|
||||
}
|
||||
};
|
||||
(body $sname: ident, $name: ident, $lname: ident, $bigger: ident, $ubigger: ident) => {
|
||||
let fname = format!("testdata/sigadd/{}.tests", stringify!($sname));
|
||||
run_test(fname.to_string(), 3, |case| {
|
||||
let (nega, abytes) = case.get("a").unwrap();
|
||||
let (negb, bbytes) = case.get("b").unwrap();
|
||||
let (negc, cbytes) = case.get("c").unwrap();
|
||||
|
||||
let mut a = $sname::new(*nega, $name::from_bytes(abytes));
|
||||
let b = $sname::new(*negb, $name::from_bytes(bbytes));
|
||||
let c = $bigger::new(*negc, $ubigger::from_bytes(cbytes));
|
||||
assert_eq!(c, &a + &b, "base addition");
|
||||
|
||||
if c.value.value[c.value.value.len()-1] == 0 {
|
||||
a += b;
|
||||
assert_eq!($sname::from(c), a, "mutating addition");
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user