Last active
August 29, 2015 14:07
-
-
Save lovasoa/deb8d4d5fb204def0bac to your computer and use it in GitHub Desktop.
Managing large numbers in rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate time; | |
use std::fmt; | |
#[deriving(Clone)] | |
struct BigNum { | |
val: Vec<u8>, | |
base: u8, | |
} | |
impl BigNum { | |
fn new<T: Num+FromPrimitive+ToPrimitive>(n: T) -> BigNum { | |
let mut ret = BigNum{val: Vec::new(), base : 0}; | |
let zero = FromPrimitive::from_int(0).unwrap(); | |
let (mut curn, base) = match FromPrimitive::from_int(256) { | |
Some(base) => (n, base), | |
None => { | |
ret.val.push(n.to_u8().unwrap()); | |
return ret | |
} | |
}; | |
while curn != zero { | |
ret.val.push((curn % base).to_u8().unwrap()); | |
curn = curn/base; | |
} | |
ret | |
} | |
fn to_int(&self) -> int { | |
let (base, mut exponent) = (self.base() as int, 1i); | |
self.val.iter().fold(0i, |prev, &cur| { | |
let ret = prev + (cur as int)*exponent; | |
exponent *= base; | |
ret | |
}) | |
} | |
fn from_digits(base:u8, d: Vec<u8>) -> BigNum { BigNum{val: d, base: base,} } | |
fn base(&self) -> u16 {if self.base==0 {256} else {self.base as u16}} | |
fn add_in_place(&mut self, rhs:&BigNum) { | |
let base = self.base(); | |
let mut retain = 0u16; | |
let (rlen,slen) = (rhs.val.len(), self.val.len()); | |
self.val.grow( | |
if slen < rlen {(rlen-slen) as uint} else {0}, | |
0 | |
); | |
let mut rhsiter = rhs.val.iter(); | |
for selfval in self.val.iter_mut() { | |
let rhsval = match rhsiter.next() { | |
Some(n) => *n as u16, | |
None => 0u16 | |
}; | |
let cur = retain + rhsval + (*selfval as u16); | |
*selfval = (cur%base) as u8; | |
retain = cur / base; | |
} | |
if retain > 0 {self.val.push(retain as u8)}; | |
} | |
} | |
impl Add<BigNum, BigNum> for BigNum { | |
fn add(&self, rhs: &BigNum) -> BigNum { | |
let mut ret = self.clone(); | |
ret.add_in_place(rhs); | |
ret | |
} | |
} | |
impl Mul<BigNum, BigNum> for BigNum { | |
fn mul(&self, rhs: &BigNum) -> BigNum { | |
let base = self.base(); | |
let (a, b) = | |
if rhs.val.len() > self.val.len() { | |
(&rhs.val, &self.val) | |
} else { | |
(&self.val, &rhs.val) | |
}; | |
let mut rdigits : Vec<u8> = Vec::with_capacity(a.len()); | |
let mut cur : u16; | |
let mut retain : u16; | |
let mut idx : uint; | |
for (bindex,bdigit) in b.iter().enumerate() { | |
idx = bindex; | |
retain = 0; | |
for adigit in a.iter() { | |
cur = (*adigit as u16)*(*bdigit as u16) + retain; | |
if idx >= rdigits.len() { | |
debug_assert_eq!(idx, rdigits.len()); | |
rdigits.push((cur % base) as u8); | |
} else { | |
let old = rdigits.get_mut(idx); | |
cur += *old as u16; | |
*old = cur as u8; | |
}; | |
retain = cur / base; | |
idx += 1; | |
} | |
if retain > 0 { | |
if idx < rdigits.len() { | |
*rdigits.get_mut(idx) = retain as u8; | |
} else { | |
rdigits.push(retain as u8); | |
} | |
} | |
} | |
BigNum{val:rdigits, base: base as u8} | |
} | |
} | |
impl fmt::Show for BigNum { | |
fn fmt(&self, fm: &mut fmt::Formatter) -> | |
Result<(), fmt::FormatError> { | |
match fm.write_int(self.to_int()) { | |
Ok(_) => Ok(()), | |
Err(_) => Err(fmt::WriteError) | |
} | |
} | |
} | |
fn unit_test_op(f: |int,int| -> int, g: |BigNum,BigNum| -> BigNum) { | |
for n1 in range(0i,1000) { | |
for n2 in range(0i, 1000) { | |
let b1 = BigNum::new(n1); | |
let b2 = BigNum::new(n2); | |
assert_eq!(f(n1,n2), (g(b1,b2)).to_int()); | |
} | |
} | |
} | |
fn launch_tests () { | |
let t = time::get_time(); | |
unit_test_op(|x,y|x+y, |x,y|x+y); | |
println!("Addition test passed"); | |
unit_test_op(|x,y|x*y, |x,y|x*y); | |
println!("Multiplication test passed"); | |
println!("Test time: {:.2f} ms", | |
((time::get_time()-t).num_nanoseconds().unwrap() as f64)/1000000.0); | |
} | |
fn main() { | |
launch_tests(); | |
let a = BigNum::new(256i+255); | |
let b = BigNum::new(256i+2); | |
let c = a*b; | |
println!("{} * {} = {}", a.val, b.val, c.val); | |
println!("{} * {} = {}", a.to_int(), b.to_int(), c.to_int()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment