added num module, implemented basic biguint functionality
This commit is contained in:
parent
b53ec32c7d
commit
067ad2217f
3 changed files with 211 additions and 0 deletions
|
@ -1,2 +1,3 @@
|
|||
pub mod expr;
|
||||
pub mod matrix;
|
||||
pub mod num;
|
||||
|
|
1
src/num.rs
Normal file
1
src/num.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod bigint;
|
209
src/num/bigint.rs
Normal file
209
src/num/bigint.rs
Normal file
|
@ -0,0 +1,209 @@
|
|||
use std::{mem, ops::{Add, AddAssign}};
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct BigUInt {
|
||||
digits: Vec<u8>
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct BigInt {
|
||||
sign: bool,
|
||||
num: BigUInt
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
pub struct ParseError;
|
||||
|
||||
impl BigUInt {
|
||||
pub fn new() -> Self {
|
||||
Self { digits: vec![0] }
|
||||
}
|
||||
|
||||
pub fn parse(str: impl Into<String>) -> Result<Self, ParseError> {
|
||||
let str = str.into();
|
||||
let str = str.trim();
|
||||
if str.is_empty() {
|
||||
return Ok(Self::new())
|
||||
}
|
||||
let mut digits = Vec::with_capacity(str.len());
|
||||
for b in str.bytes().rev() {
|
||||
if !b.is_ascii_digit() {
|
||||
return Err(ParseError)
|
||||
}
|
||||
digits.push(b - b'0');
|
||||
}
|
||||
Ok(Self { digits })
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> String {
|
||||
self.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for BigUInt {
|
||||
fn from(mut value: u128) -> Self {
|
||||
if value == 0 {
|
||||
return Self::new()
|
||||
}
|
||||
let mut digits = Vec::with_capacity(39);
|
||||
while value > 0 {
|
||||
digits.push((value % 10) as u8);
|
||||
value /= 10;
|
||||
}
|
||||
Self { digits }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for BigUInt {
|
||||
fn from(value: u64) -> Self {
|
||||
Self::from(value as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for BigUInt {
|
||||
fn from(value: u32) -> Self {
|
||||
Self::from(value as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for BigUInt {
|
||||
fn from(value: u16) -> Self {
|
||||
Self::from(value as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for BigUInt {
|
||||
fn from(value: u8) -> Self {
|
||||
Self::from(value as u128)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for BigUInt {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
BigUInt::parse(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for BigUInt {
|
||||
fn into(self) -> String {
|
||||
self.digits.into_iter().rev().map(|b|(b + b'0') as char).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BigUInt {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for BigUInt {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
let (small, mut big) = if self.digits.len() < rhs.digits.len() {
|
||||
(self, rhs)
|
||||
} else {
|
||||
(rhs, self)
|
||||
};
|
||||
big.digits.resize(big.digits.len() + 1, 0);
|
||||
for i in 0..small.digits.len() {
|
||||
let new_digit = small.digits[i] + big.digits[i];
|
||||
big.digits[i] = new_digit % 10;
|
||||
big.digits[i + 1] += new_digit / 10;
|
||||
}
|
||||
for i in small.digits.len()..big.digits.len() {
|
||||
if big.digits[i] < 10 {
|
||||
break;
|
||||
}
|
||||
big.digits[i] -= 10;
|
||||
big.digits[i + 1] += 1;
|
||||
}
|
||||
if big.digits.len() > 1 && big.digits[big.digits.len() - 1] == 0 {
|
||||
big.digits.pop();
|
||||
}
|
||||
big
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for BigUInt {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
*self = mem::take(self) + rhs;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn bigint(s: impl Into<String>) -> BigUInt {
|
||||
BigUInt::parse(s).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_num() {
|
||||
assert_eq!(BigUInt::new(), BigUInt { digits: vec![0] });
|
||||
assert_eq!(BigUInt::from(0u8), BigUInt { digits: vec![0] });
|
||||
assert_eq!(BigUInt::from(1234u16), BigUInt { digits: vec![4,3,2,1] });
|
||||
assert_eq!(BigUInt::from(12345678u32), BigUInt { digits: vec![8,7,6,5,4,3,2,1] });
|
||||
assert_eq!(
|
||||
BigUInt::from(1234567890123456u64),
|
||||
BigUInt { digits: vec![6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1] }
|
||||
);
|
||||
assert_eq!(
|
||||
BigUInt::from(12345678901234561234567890123456u128),
|
||||
BigUInt { digits: vec![6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1] }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_str() {
|
||||
assert_eq!(BigUInt::parse(""), Ok(BigUInt { digits: vec![0] }));
|
||||
assert_eq!(BigUInt::parse(" "), Ok(BigUInt { digits: vec![0] }));
|
||||
assert_eq!(BigUInt::parse("0"), Ok(BigUInt { digits: vec![0] }));
|
||||
assert_eq!(BigUInt::parse("1234"), Ok(BigUInt { digits: vec![4,3,2,1] }));
|
||||
assert_eq!(BigUInt::parse(" 1234 "), Ok(BigUInt { digits: vec![4,3,2,1] }));
|
||||
assert_eq!(
|
||||
BigUInt::parse("1234567890123456789012345678901234567890"),
|
||||
Ok(BigUInt { digits: vec![0,9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1] })
|
||||
);
|
||||
assert_eq!(BigUInt::parse("wawa"), Err(ParseError))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(BigUInt { digits: vec![0] }.as_str(), "0");
|
||||
assert_eq!(BigUInt { digits: vec![4,3,2,1] }.as_str(), "1234");
|
||||
assert_eq!(
|
||||
BigUInt { digits: vec![0,9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1,0,9,8,7,6,5,4,3,2,1] }.as_str(),
|
||||
"1234567890123456789012345678901234567890");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add() {
|
||||
assert_eq!(bigint("0") + bigint("0"), bigint("0"));
|
||||
assert_eq!(bigint("1234") + bigint("0"), bigint("1234"));
|
||||
assert_eq!(bigint("0") + bigint("1234"), bigint("1234"));
|
||||
assert_eq!(bigint("1234") + bigint("1234"), bigint("2468"));
|
||||
assert_eq!(bigint("123456") + bigint("123"), bigint("123579"));
|
||||
assert_eq!(bigint("123") + bigint("123456"), bigint("123579"));
|
||||
assert_eq!(bigint("9999999") + bigint("1"), bigint("10000000"));
|
||||
assert_eq!(bigint("1") + bigint("9999999"), bigint("10000000"));
|
||||
assert_eq!(bigint("9999801") + bigint("999999"), bigint("10999800"));
|
||||
assert_eq!(bigint("999") + bigint("999"), bigint("1998"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_assign() {
|
||||
let mut n = bigint("1732");
|
||||
n += bigint("1234");
|
||||
assert_eq!(n, bigint("2966"));
|
||||
n += bigint("746283");
|
||||
assert_eq!(n, bigint("749249"));
|
||||
n += bigint("9999");
|
||||
assert_eq!(n, bigint("759248"));
|
||||
n += bigint("0");
|
||||
assert_eq!(n, bigint("759248"));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue