diff --git a/src/number.rs b/src/number.rs index 8f12f43..07dd308 100644 --- a/src/number.rs +++ b/src/number.rs @@ -1,8 +1,12 @@ -use std::cmp::{min, Ordering}; -use std::error::Error; +mod add; +mod div; +mod from; +mod mul; +mod ord; +mod sub; + +use std::cmp::Ordering; use std::fmt::{Display, Formatter}; -use std::iter::zip; -use std::ops::{Add, Div, Mul, Rem, Sub}; #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub enum Sign { @@ -118,7 +122,7 @@ impl Number { } else { let number = self.clone(); for _i in 1..n { - result = result * number.clone(); + result *= number.clone(); } result } @@ -147,137 +151,6 @@ impl Number { last_two.0 } - - pub fn div_with_rem(n1: Number, n2: Number) -> Result<(Number, Number), Box> { - if n2 == 0.into() { - return Err(Box::from("Division by 0")); - } - let n1_len = n1.digits.len(); - let n2_len = n2.digits.len(); - if n2_len > n1_len { - return Ok((Number::from(0), n2)); - } - let dividend = n1.digits[..n2_len].to_vec(); - let mut quotient = vec![]; - let mut remainder = Number { - digits: dividend.clone(), - sign: Sign::Positif, - }; - let mut iteration = 1; - loop { - let mut factor = 0; - loop { - let temp_remainder = remainder.clone() - n2.clone(); - if temp_remainder.sign == Sign::Negatif { - quotient.push(factor); - break; - } - remainder = temp_remainder; - factor += 1; - } - if n1_len == n2_len + iteration - 1 { - break; - } - remainder.digits.push(n1.digits[n2_len + iteration - 1]); - iteration += 1; - } - let mut res = Number { - digits: quotient, - sign: Sign::Positif, - }; - res.handle_overflows(); - for digit in res.clone().digits { - if digit != 0 || res.digits.len() == 1 { - break; - } - res.digits.remove(0); - } - for digit in remainder.clone().digits { - if digit != 0 || remainder.digits.len() == 1 { - break; - } - remainder.digits.remove(0); - } - Ok((res, remainder)) - } - - pub fn gcd(mut a: Number, mut b: Number) -> Number { - loop { - let t = b.clone(); - b = a % b; - a = t; - if b == Number::from(0) { - return a; - } - } - } -} - -impl TryFrom for isize { - type Error = Box; - - fn try_from(value: Number) -> Result { - let mut num = 0; - for (pos, &digit) in value.digits.iter().rev().enumerate() { - let mul = digit.checked_mul(10isize.pow(pos as u32)); - if mul.is_none() { - return Err(Box::from("Cannot convert Number to isize. Too big.")); - } - num += mul.unwrap(); - } - Ok(num) - } -} - -impl From for String { - fn from(value: Number) -> Self { - let string_vec: Vec = value - .digits - .iter() - .map(|&digit| digit.to_string()) - .collect(); - string_vec.concat() - } -} - -impl From<&str> for Number { - fn from(value: &str) -> Self { - let bytes = value.as_bytes(); - let (sign, idx_start) = match bytes[0] { - b'-' => (Sign::Negatif, 1), - _ => (Sign::Positif, 0), - }; - let mut digits = vec![]; - for &byte in &bytes[idx_start..] { - let digit = Self::byte_to_digit(byte); - digits.push(digit); - } - Self { digits, sign } - } -} - -impl From for Number { - fn from(mut value: isize) -> Self { - let mut sign = Sign::Positif; - if value < 0 { - sign = Sign::Negatif; - value *= -1; - } - if value == 0 { - return Self { - digits: vec![0], - sign: Sign::Positif, - }; - } - let num_len = (value as f64 + 1.0).log10().ceil() as usize; - let mut digits = vec![]; - for digit_idx in 0..num_len { - let digit = Self::get_digit(value, digit_idx); - digits.push(digit); - } - let digits = digits.iter().rev().copied().collect(); - Self { digits, sign } - } } impl Display for Number { @@ -295,194 +168,9 @@ impl Display for Number { } } -impl Add for Number { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - let self_len = self.digits.len(); - let rhs_len = rhs.digits.len(); - let mut self_digits = self.digits.clone(); - let mut rhs_digits = rhs.digits.clone(); - if self_len != rhs_len { - let difference = (self_len).abs_diff(rhs_len); - let pad = vec![0isize; difference]; - if min(self_len, rhs_len) == self_len { - self_digits = [pad, self.digits].concat(); - } else { - rhs_digits = [pad, rhs.digits].concat(); - } - } - let zipped = zip(self_digits.iter(), rhs_digits.iter()); - let added = zipped - .map(|(self_digit, rhs_digit)| self_digit + rhs_digit) - .collect(); - let mut overflown_number = Self { - digits: added, - sign: Sign::Positif, - }; - overflown_number.handle_overflows(); - overflown_number - } -} - -impl Sub for Number { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - let self_len = self.digits.len(); - let rhs_len = rhs.digits.len(); - let mut self_digits = self.digits.clone(); - let mut rhs_digits = rhs.digits.clone(); - if self_len != rhs_len { - let difference = (self_len).abs_diff(rhs_len); - let pad = vec![0isize; difference]; - if min(self_len, rhs_len) == self_len { - self_digits = [pad, self.digits].concat(); - } else { - rhs_digits = [pad, rhs.digits].concat(); - } - } - let zipped = zip(self_digits.iter(), rhs_digits.iter()); - let added = zipped - .map(|(self_digit, rhs_digit)| self_digit - rhs_digit) - .collect(); - let mut underflown_number = Self { - digits: added, - sign: Sign::Positif, - }; - underflown_number.handle_underflows(); - underflown_number - } -} - -impl Mul for Number { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - let multiplied = self.digits.iter().rev().enumerate().map(|(pos, &digit)| { - let mut mult = digit * rhs.clone(); - mult.digits = [mult.digits, vec![0; pos]].concat(); - mult - }); - let mut overflown_number = multiplied.reduce(|acc, num| acc + num).unwrap(); - overflown_number.handle_overflows(); - overflown_number - } -} - -impl Mul for isize { - type Output = Number; - - fn mul(self, rhs: Number) -> Self::Output { - let multiplied = rhs.digits.iter().map(|digit| digit * self).collect(); - let mut overflown_number = Number { - digits: multiplied, - sign: Sign::Positif, - }; - overflown_number.handle_overflows(); - overflown_number - } -} - -impl Mul for Number { - type Output = Self; - - fn mul(self, rhs: isize) -> Self::Output { - let multiplied = self.digits.iter().map(|digit| digit * rhs).collect(); - let mut overflown_number = Self { - digits: multiplied, - sign: Sign::Positif, - }; - overflown_number.handle_overflows(); - overflown_number - } -} - -impl Div for Number { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - Self::div_with_rem(self, rhs).unwrap().0 - } -} - -impl Rem for Number { - type Output = Self; - - fn rem(self, rhs: Self) -> Self::Output { - Self::div_with_rem(self, rhs).unwrap().1 - } -} - -impl PartialOrd for Number { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Number { - fn cmp(&self, other: &Self) -> Ordering { - if self.sign == Sign::Negatif && other.sign == Sign::Positif { - return Ordering::Less; - } else if self.sign == Sign::Positif && other.sign == Sign::Negatif { - return Ordering::Greater; - } - match self.digits.len().cmp(&other.digits.len()) { - Ordering::Less => match self.sign { - Sign::Positif => Ordering::Less, - Sign::Negatif => Ordering::Greater, - }, - Ordering::Greater => match self.sign { - Sign::Positif => Ordering::Greater, - Sign::Negatif => Ordering::Less, - }, - Ordering::Equal => { - for pair in zip(&self.digits, &other.digits) { - return match pair.0.cmp(pair.1) { - Ordering::Less => match self.sign { - Sign::Positif => Ordering::Less, - Sign::Negatif => Ordering::Greater, - }, - Ordering::Greater => match self.sign { - Sign::Positif => Ordering::Greater, - Sign::Negatif => Ordering::Less, - }, - Ordering::Equal => continue, - }; - } - Ordering::Equal - } - } - } -} - #[cfg(test)] mod number_tests { - use crate::number::{Number, Sign}; - - #[test] - fn test_from_isize() { - let number = Number::from(-1234); - assert_eq!( - number, - Number { - digits: vec![1, 2, 3, 4], - sign: Sign::Negatif - } - ); - } - - #[test] - fn test_from_0isize() { - let number = Number::from(0); - assert_eq!( - number, - Number { - digits: vec![0], - sign: Sign::Positif - } - ); - } + use crate::number::Number; #[test] fn test_get_digit() { @@ -498,60 +186,4 @@ mod number_tests { assert_eq!(digit_4, 2); assert_eq!(digit_5, 1); } - - #[test] - fn test_cmp_eq_pos() { - let a = Number::from(1); - let b = Number::from(1); - assert_eq!(a, b); - } - - #[test] - fn test_cmp_eq_neg() { - let a = Number::from(-1); - let b = Number::from(-1); - assert_eq!(a, b); - } - - #[test] - fn test_cmp_pos_neg() { - let a = Number::from(1); - let b = Number::from(-1); - assert!(a > b); - } - - #[test] - fn test_cmp_neg_pos() { - let a = Number::from(-1); - let b = Number::from(1); - assert!(a < b); - } - - #[test] - fn test_cmp_short_neg() { - let a = Number::from(-1); - let b = Number::from(-10); - assert!(a > b); - } - - #[test] - fn test_cmp_short_pos() { - let a = Number::from(1); - let b = Number::from(10); - assert!(a < b); - } - - #[test] - fn test_cmp_long_neg() { - let a = Number::from(-10); - let b = Number::from(-1); - assert!(a < b); - } - - #[test] - fn test_cmp_long_pos() { - let a = Number::from(10); - let b = Number::from(1); - assert!(a > b); - } } diff --git a/src/number/add.rs b/src/number/add.rs new file mode 100644 index 0000000..311b1c3 --- /dev/null +++ b/src/number/add.rs @@ -0,0 +1,45 @@ +use std::{ + cmp::min, + iter::zip, + ops::{Add, AddAssign}, +}; + +use super::{Number, Sign}; + +impl Add for Number { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + let self_len = self.digits.len(); + let rhs_len = rhs.digits.len(); + let mut self_digits = self.digits.clone(); + let mut rhs_digits = rhs.digits.clone(); + if self_len != rhs_len { + let difference = (self_len).abs_diff(rhs_len); + let pad = vec![0isize; difference]; + if min(self_len, rhs_len) == self_len { + self_digits = [pad, self.digits].concat(); + } else { + rhs_digits = [pad, rhs.digits].concat(); + } + } + let zipped = zip(self_digits.iter(), rhs_digits.iter()); + let added = zipped + .map(|(self_digit, rhs_digit)| self_digit + rhs_digit) + .collect(); + let mut overflown_number = Self { + digits: added, + sign: Sign::Positif, + }; + overflown_number.handle_overflows(); + overflown_number + } +} + +impl AddAssign for Number { + fn add_assign(&mut self, rhs: Self) { + let new = self.clone() + rhs; + self.digits = new.digits; + self.sign = new.sign; + } +} diff --git a/src/number/div.rs b/src/number/div.rs new file mode 100644 index 0000000..d6d6c31 --- /dev/null +++ b/src/number/div.rs @@ -0,0 +1,113 @@ +use core::panic; +use std::{ + error::Error, + ops::{Div, DivAssign, Rem, RemAssign}, +}; + +use super::{Number, Sign}; + +impl Number { + pub fn div_with_rem(n1: Number, n2: Number) -> Result<(Number, Number), Box> { + if n2 == 0.into() { + return Err(Box::from("Division by 0")); + } + let n1_len = n1.digits.len(); + let n2_len = n2.digits.len(); + if n2_len > n1_len { + return Ok((Number::from(0), n2)); + } + let dividend = n1.digits[..n2_len].to_vec(); + let mut quotient = vec![]; + let mut remainder = Number { + digits: dividend.clone(), + sign: Sign::Positif, + }; + let mut iteration = 1; + loop { + let mut factor = 0; + loop { + let temp_remainder = remainder.clone() - n2.clone(); + if temp_remainder.sign == Sign::Negatif { + quotient.push(factor); + break; + } + remainder = temp_remainder; + factor += 1; + } + if n1_len == n2_len + iteration - 1 { + break; + } + remainder.digits.push(n1.digits[n2_len + iteration - 1]); + iteration += 1; + } + let mut res = Number { + digits: quotient, + sign: Sign::Positif, + }; + res.handle_overflows(); + for digit in res.clone().digits { + if digit != 0 || res.digits.len() == 1 { + break; + } + res.digits.remove(0); + } + for digit in remainder.clone().digits { + if digit != 0 || remainder.digits.len() == 1 { + break; + } + remainder.digits.remove(0); + } + Ok((res, remainder)) + } + + pub fn gcd(mut a: Number, mut b: Number) -> Number { + loop { + let t = b.clone(); + b = a % b; + a = t; + if b == Number::from(0) { + return a; + } + } + } +} + +impl Div for Number { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + Self::div_with_rem(self, rhs).unwrap().0 + } +} + +impl DivAssign for Number { + fn div_assign(&mut self, rhs: Self) { + match Self::div_with_rem(self.clone(), rhs) { + Ok((new, _)) => { + self.digits = new.digits; + self.sign = new.sign; + } + Err(e) => panic!("{e}"), + } + } +} + +impl Rem for Number { + type Output = Self; + + fn rem(self, rhs: Self) -> Self::Output { + Self::div_with_rem(self, rhs).unwrap().1 + } +} + +impl RemAssign for Number { + fn rem_assign(&mut self, rhs: Self) { + match Self::div_with_rem(self.clone(), rhs) { + Ok((_, new)) => { + self.digits = new.digits; + self.sign = new.sign; + } + Err(e) => panic!("{e}"), + } + } +} diff --git a/src/number/from.rs b/src/number/from.rs new file mode 100644 index 0000000..db95ef7 --- /dev/null +++ b/src/number/from.rs @@ -0,0 +1,99 @@ +use std::error::Error; + +use super::{Number, Sign}; + +impl TryFrom for isize { + type Error = Box; + + fn try_from(value: Number) -> Result { + let mut num = 0; + for (pos, &digit) in value.digits.iter().rev().enumerate() { + let mul = digit.checked_mul(10isize.pow(pos as u32)); + if mul.is_none() { + return Err(Box::from("Cannot convert Number to isize. Too big.")); + } + num += mul.unwrap(); + } + Ok(num) + } +} + +impl From for String { + fn from(value: Number) -> Self { + let string_vec: Vec = value + .digits + .iter() + .map(|&digit| digit.to_string()) + .collect(); + string_vec.concat() + } +} + +impl From<&str> for Number { + fn from(value: &str) -> Self { + let bytes = value.as_bytes(); + let (sign, idx_start) = match bytes[0] { + b'-' => (Sign::Negatif, 1), + _ => (Sign::Positif, 0), + }; + let mut digits = vec![]; + for &byte in &bytes[idx_start..] { + let digit = Self::byte_to_digit(byte); + digits.push(digit); + } + Self { digits, sign } + } +} + +impl From for Number { + fn from(mut value: isize) -> Self { + let mut sign = Sign::Positif; + if value < 0 { + sign = Sign::Negatif; + value *= -1; + } + if value == 0 { + return Self { + digits: vec![0], + sign: Sign::Positif, + }; + } + let num_len = (value as f64 + 1.0).log10().ceil() as usize; + let mut digits = vec![]; + for digit_idx in 0..num_len { + let digit = Self::get_digit(value, digit_idx); + digits.push(digit); + } + let digits = digits.iter().rev().copied().collect(); + Self { digits, sign } + } +} + +#[cfg(test)] +mod test_number_from { + use crate::number::{Number, Sign}; + + #[test] + fn test_from_isize() { + let number = Number::from(-1234); + assert_eq!( + number, + Number { + digits: vec![1, 2, 3, 4], + sign: Sign::Negatif + } + ); + } + + #[test] + fn test_from_0isize() { + let number = Number::from(0); + assert_eq!( + number, + Number { + digits: vec![0], + sign: Sign::Positif + } + ); + } +} diff --git a/src/number/mul.rs b/src/number/mul.rs new file mode 100644 index 0000000..08bb400 --- /dev/null +++ b/src/number/mul.rs @@ -0,0 +1,54 @@ +use std::ops::{Mul, MulAssign}; + +use super::{Number, Sign}; + +impl Mul for Number { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + let multiplied = self.digits.iter().rev().enumerate().map(|(pos, &digit)| { + let mut mult = digit * rhs.clone(); + mult.digits = [mult.digits, vec![0; pos]].concat(); + mult + }); + let mut overflown_number = multiplied.reduce(|acc, num| acc + num).unwrap(); + overflown_number.handle_overflows(); + overflown_number + } +} + +impl Mul for isize { + type Output = Number; + + fn mul(self, rhs: Number) -> Self::Output { + let multiplied = rhs.digits.iter().map(|digit| digit * self).collect(); + let mut overflown_number = Number { + digits: multiplied, + sign: Sign::Positif, + }; + overflown_number.handle_overflows(); + overflown_number + } +} + +impl Mul for Number { + type Output = Self; + + fn mul(self, rhs: isize) -> Self::Output { + let multiplied = self.digits.iter().map(|digit| digit * rhs).collect(); + let mut overflown_number = Self { + digits: multiplied, + sign: Sign::Positif, + }; + overflown_number.handle_overflows(); + overflown_number + } +} + +impl MulAssign for Number { + fn mul_assign(&mut self, rhs: Self) { + let new = self.clone() * rhs; + self.digits = new.digits; + self.sign = new.sign; + } +} diff --git a/src/number/ord.rs b/src/number/ord.rs new file mode 100644 index 0000000..c7fef3e --- /dev/null +++ b/src/number/ord.rs @@ -0,0 +1,106 @@ +use std::{cmp::Ordering, iter::zip}; + +use super::{Number, Sign}; + +impl PartialOrd for Number { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Number { + fn cmp(&self, other: &Self) -> Ordering { + if self.sign == Sign::Negatif && other.sign == Sign::Positif { + return Ordering::Less; + } else if self.sign == Sign::Positif && other.sign == Sign::Negatif { + return Ordering::Greater; + } + match self.digits.len().cmp(&other.digits.len()) { + Ordering::Less => match self.sign { + Sign::Positif => Ordering::Less, + Sign::Negatif => Ordering::Greater, + }, + Ordering::Greater => match self.sign { + Sign::Positif => Ordering::Greater, + Sign::Negatif => Ordering::Less, + }, + Ordering::Equal => { + for pair in zip(&self.digits, &other.digits) { + return match pair.0.cmp(pair.1) { + Ordering::Less => match self.sign { + Sign::Positif => Ordering::Less, + Sign::Negatif => Ordering::Greater, + }, + Ordering::Greater => match self.sign { + Sign::Positif => Ordering::Greater, + Sign::Negatif => Ordering::Less, + }, + Ordering::Equal => continue, + }; + } + Ordering::Equal + } + } + } +} + +#[cfg(test)] +mod test_number_ord { + use crate::number::Number; + + #[test] + fn test_cmp_eq_pos() { + let a = Number::from(1); + let b = Number::from(1); + assert_eq!(a, b); + } + + #[test] + fn test_cmp_eq_neg() { + let a = Number::from(-1); + let b = Number::from(-1); + assert_eq!(a, b); + } + + #[test] + fn test_cmp_pos_neg() { + let a = Number::from(1); + let b = Number::from(-1); + assert!(a > b); + } + + #[test] + fn test_cmp_neg_pos() { + let a = Number::from(-1); + let b = Number::from(1); + assert!(a < b); + } + + #[test] + fn test_cmp_short_neg() { + let a = Number::from(-1); + let b = Number::from(-10); + assert!(a > b); + } + + #[test] + fn test_cmp_short_pos() { + let a = Number::from(1); + let b = Number::from(10); + assert!(a < b); + } + + #[test] + fn test_cmp_long_neg() { + let a = Number::from(-10); + let b = Number::from(-1); + assert!(a < b); + } + + #[test] + fn test_cmp_long_pos() { + let a = Number::from(10); + let b = Number::from(1); + assert!(a > b); + } +} diff --git a/src/number/sub.rs b/src/number/sub.rs new file mode 100644 index 0000000..970e7ca --- /dev/null +++ b/src/number/sub.rs @@ -0,0 +1,45 @@ +use std::{ + cmp::min, + iter::zip, + ops::{Sub, SubAssign}, +}; + +use super::{Number, Sign}; + +impl Sub for Number { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + let self_len = self.digits.len(); + let rhs_len = rhs.digits.len(); + let mut self_digits = self.digits.clone(); + let mut rhs_digits = rhs.digits.clone(); + if self_len != rhs_len { + let difference = (self_len).abs_diff(rhs_len); + let pad = vec![0isize; difference]; + if min(self_len, rhs_len) == self_len { + self_digits = [pad, self.digits].concat(); + } else { + rhs_digits = [pad, rhs.digits].concat(); + } + } + let zipped = zip(self_digits.iter(), rhs_digits.iter()); + let added = zipped + .map(|(self_digit, rhs_digit)| self_digit - rhs_digit) + .collect(); + let mut underflown_number = Self { + digits: added, + sign: Sign::Positif, + }; + underflown_number.handle_underflows(); + underflown_number + } +} + +impl SubAssign for Number { + fn sub_assign(&mut self, rhs: Self) { + let new = self.clone() - rhs; + self.digits = new.digits; + self.sign = new.sign; + } +}