Skip to content

Instantly share code, notes, and snippets.

@lovasoa
Last active August 29, 2015 14:07
Show Gist options
  • Save lovasoa/deb8d4d5fb204def0bac to your computer and use it in GitHub Desktop.
Save lovasoa/deb8d4d5fb204def0bac to your computer and use it in GitHub Desktop.
Managing large numbers in rust
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