Implemented checked arithmetic for Big(U)Ints

This commit is contained in:
TorstenWeber 2014-03-03 19:20:21 +01:00
parent 3f3425a555
commit 47cff94ab9

View File

@ -21,6 +21,7 @@ use Integer;
use std::cmp;
use std::fmt;
use std::from_str::FromStr;
use std::num::CheckedDiv;
use std::num::{Bitwise, ToPrimitive, FromPrimitive};
use std::num::{Zero, One, ToStrRadix, FromStrRadix};
use std::rand::Rng;
@ -338,6 +339,40 @@ impl Neg<BigUint> for BigUint {
fn neg(&self) -> BigUint { fail!() }
}
impl CheckedAdd for BigUint {
#[inline]
fn checked_add(&self, v: &BigUint) -> Option<BigUint> {
return Some(self.add(v));
}
}
impl CheckedSub for BigUint {
#[inline]
fn checked_sub(&self, v: &BigUint) -> Option<BigUint> {
if *self < *v {
return None;
}
return Some(self.sub(v));
}
}
impl CheckedMul for BigUint {
#[inline]
fn checked_mul(&self, v: &BigUint) -> Option<BigUint> {
return Some(self.mul(v));
}
}
impl CheckedDiv for BigUint {
#[inline]
fn checked_div(&self, v: &BigUint) -> Option<BigUint> {
if v.is_zero() {
return None;
}
return Some(self.div(v));
}
}
impl Integer for BigUint {
#[inline]
fn div_rem(&self, other: &BigUint) -> (BigUint, BigUint) {
@ -1053,6 +1088,38 @@ impl Neg<BigInt> for BigInt {
}
}
impl CheckedAdd for BigInt {
#[inline]
fn checked_add(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.add(v));
}
}
impl CheckedSub for BigInt {
#[inline]
fn checked_sub(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.sub(v));
}
}
impl CheckedMul for BigInt {
#[inline]
fn checked_mul(&self, v: &BigInt) -> Option<BigInt> {
return Some(self.mul(v));
}
}
impl CheckedDiv for BigInt {
#[inline]
fn checked_div(&self, v: &BigInt) -> Option<BigInt> {
if v.is_zero() {
return None;
}
return Some(self.div(v));
}
}
impl Integer for BigInt {
#[inline]
fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) {
@ -1402,6 +1469,7 @@ mod biguint_tests {
use std::i64;
use std::num::{Zero, One, FromStrRadix, ToStrRadix};
use std::num::{ToPrimitive, FromPrimitive};
use std::num::CheckedDiv;
use std::rand::{task_rng};
use std::str;
use std::u64;
@ -1822,6 +1890,82 @@ mod biguint_tests {
}
}
#[test]
fn test_checked_add() {
for elm in sum_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigUint::from_slice(aVec);
let b = BigUint::from_slice(bVec);
let c = BigUint::from_slice(cVec);
assert!(a.checked_add(&b).unwrap() == c);
assert!(b.checked_add(&a).unwrap() == c);
}
}
#[test]
fn test_checked_sub() {
for elm in sum_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigUint::from_slice(aVec);
let b = BigUint::from_slice(bVec);
let c = BigUint::from_slice(cVec);
assert!(c.checked_sub(&a).unwrap() == b);
assert!(c.checked_sub(&b).unwrap() == a);
if a > c {
assert!(a.checked_sub(&c).is_none());
}
if b > c {
assert!(b.checked_sub(&c).is_none());
}
}
}
#[test]
fn test_checked_mul() {
for elm in mul_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigUint::from_slice(aVec);
let b = BigUint::from_slice(bVec);
let c = BigUint::from_slice(cVec);
assert!(a.checked_mul(&b).unwrap() == c);
assert!(b.checked_mul(&a).unwrap() == c);
}
for elm in div_rem_quadruples.iter() {
let (aVec, bVec, cVec, dVec) = *elm;
let a = BigUint::from_slice(aVec);
let b = BigUint::from_slice(bVec);
let c = BigUint::from_slice(cVec);
let d = BigUint::from_slice(dVec);
assert!(a == b.checked_mul(&c).unwrap() + d);
assert!(a == c.checked_mul(&b).unwrap() + d);
}
}
#[test]
fn test_checked_div() {
for elm in mul_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigUint::from_slice(aVec);
let b = BigUint::from_slice(bVec);
let c = BigUint::from_slice(cVec);
if !a.is_zero() {
assert!(c.checked_div(&a).unwrap() == b);
}
if !b.is_zero() {
assert!(c.checked_div(&b).unwrap() == a);
}
assert!(c.checked_div(&Zero::zero()).is_none());
}
}
#[test]
fn test_gcd() {
fn check(a: uint, b: uint, c: uint) {
@ -2058,6 +2202,7 @@ mod bigint_tests {
use std::cmp::{Less, Equal, Greater};
use std::i64;
use std::num::CheckedDiv;
use std::num::{Zero, One, FromStrRadix, ToStrRadix};
use std::num::{ToPrimitive, FromPrimitive};
use std::rand::{task_rng};
@ -2399,6 +2544,94 @@ mod bigint_tests {
}
}
#[test]
fn test_checked_add() {
for elm in sum_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigInt::from_slice(Plus, aVec);
let b = BigInt::from_slice(Plus, bVec);
let c = BigInt::from_slice(Plus, cVec);
assert!(a.checked_add(&b).unwrap() == c);
assert!(b.checked_add(&a).unwrap() == c);
assert!(c.checked_add(&(-a)).unwrap() == b);
assert!(c.checked_add(&(-b)).unwrap() == a);
assert!(a.checked_add(&(-c)).unwrap() == (-b));
assert!(b.checked_add(&(-c)).unwrap() == (-a));
assert!((-a).checked_add(&(-b)).unwrap() == (-c))
assert!(a.checked_add(&(-a)).unwrap() == Zero::zero());
}
}
#[test]
fn test_checked_sub() {
for elm in sum_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigInt::from_slice(Plus, aVec);
let b = BigInt::from_slice(Plus, bVec);
let c = BigInt::from_slice(Plus, cVec);
assert!(c.checked_sub(&a).unwrap() == b);
assert!(c.checked_sub(&b).unwrap() == a);
assert!((-b).checked_sub(&a).unwrap() == (-c))
assert!((-a).checked_sub(&b).unwrap() == (-c))
assert!(b.checked_sub(&(-a)).unwrap() == c);
assert!(a.checked_sub(&(-b)).unwrap() == c);
assert!((-c).checked_sub(&(-a)).unwrap() == (-b));
assert!(a.checked_sub(&a).unwrap() == Zero::zero());
}
}
#[test]
fn test_checked_mul() {
for elm in mul_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigInt::from_slice(Plus, aVec);
let b = BigInt::from_slice(Plus, bVec);
let c = BigInt::from_slice(Plus, cVec);
assert!(a.checked_mul(&b).unwrap() == c);
assert!(b.checked_mul(&a).unwrap() == c);
assert!((-a).checked_mul(&b).unwrap() == -c);
assert!((-b).checked_mul(&a).unwrap() == -c);
}
for elm in div_rem_quadruples.iter() {
let (aVec, bVec, cVec, dVec) = *elm;
let a = BigInt::from_slice(Plus, aVec);
let b = BigInt::from_slice(Plus, bVec);
let c = BigInt::from_slice(Plus, cVec);
let d = BigInt::from_slice(Plus, dVec);
assert!(a == b.checked_mul(&c).unwrap() + d);
assert!(a == c.checked_mul(&b).unwrap() + d);
}
}
#[test]
fn test_checked_div() {
for elm in mul_triples.iter() {
let (aVec, bVec, cVec) = *elm;
let a = BigInt::from_slice(Plus, aVec);
let b = BigInt::from_slice(Plus, bVec);
let c = BigInt::from_slice(Plus, cVec);
if !a.is_zero() {
assert!(c.checked_div(&a).unwrap() == b);
assert!((-c).checked_div(&(-a)).unwrap() == b);
assert!((-c).checked_div(&a).unwrap() == -b);
}
if !b.is_zero() {
assert!(c.checked_div(&b).unwrap() == a);
assert!((-c).checked_div(&(-b)).unwrap() == a);
assert!((-c).checked_div(&b).unwrap() == -a);
}
assert!(c.checked_div(&Zero::zero()).is_none());
assert!((-c).checked_div(&Zero::zero()).is_none());
}
}
#[test]
fn test_gcd() {
fn check(a: int, b: int, c: int) {