From 067ad2217fbf07bee1311a027b1421b72c230efe Mon Sep 17 00:00:00 2001 From: erius Date: Tue, 11 Jun 2024 11:55:38 +0300 Subject: [PATCH] added num module, implemented basic biguint functionality --- src/lib.rs | 1 + src/num.rs | 1 + src/num/bigint.rs | 209 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 src/num.rs create mode 100644 src/num/bigint.rs diff --git a/src/lib.rs b/src/lib.rs index c0db143..af34116 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod expr; pub mod matrix; +pub mod num; diff --git a/src/num.rs b/src/num.rs new file mode 100644 index 0000000..8f8d148 --- /dev/null +++ b/src/num.rs @@ -0,0 +1 @@ +pub mod bigint; diff --git a/src/num/bigint.rs b/src/num/bigint.rs new file mode 100644 index 0000000..4dae7d9 --- /dev/null +++ b/src/num/bigint.rs @@ -0,0 +1,209 @@ +use std::{mem, ops::{Add, AddAssign}}; + +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct BigUInt { + digits: Vec +} + +#[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) -> Result { + 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 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 for BigUInt { + fn from(value: u64) -> Self { + Self::from(value as u128) + } +} + +impl From for BigUInt { + fn from(value: u32) -> Self { + Self::from(value as u128) + } +} + +impl From for BigUInt { + fn from(value: u16) -> Self { + Self::from(value as u128) + } +} + +impl From for BigUInt { + fn from(value: u8) -> Self { + Self::from(value as u128) + } +} + +impl TryFrom for BigUInt { + type Error = ParseError; + + fn try_from(value: String) -> Result { + BigUInt::parse(value) + } +} + +impl Into 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) -> 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")); + } +}