Refactoring
This commit is contained in:
parent
1f96d76c74
commit
e0fce27917
388
src/number.rs
388
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<dyn Error>> {
|
||||
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<Number> for isize {
|
||||
type Error = Box<dyn Error>;
|
||||
|
||||
fn try_from(value: Number) -> Result<Self, Self::Error> {
|
||||
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<Number> for String {
|
||||
fn from(value: Number) -> Self {
|
||||
let string_vec: Vec<String> = 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<isize> 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<Number> 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<isize> 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<Ordering> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
45
src/number/add.rs
Normal file
45
src/number/add.rs
Normal file
@ -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;
|
||||
}
|
||||
}
|
113
src/number/div.rs
Normal file
113
src/number/div.rs
Normal file
@ -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<dyn Error>> {
|
||||
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}"),
|
||||
}
|
||||
}
|
||||
}
|
99
src/number/from.rs
Normal file
99
src/number/from.rs
Normal file
@ -0,0 +1,99 @@
|
||||
use std::error::Error;
|
||||
|
||||
use super::{Number, Sign};
|
||||
|
||||
impl TryFrom<Number> for isize {
|
||||
type Error = Box<dyn Error>;
|
||||
|
||||
fn try_from(value: Number) -> Result<Self, Self::Error> {
|
||||
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<Number> for String {
|
||||
fn from(value: Number) -> Self {
|
||||
let string_vec: Vec<String> = 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<isize> 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
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
54
src/number/mul.rs
Normal file
54
src/number/mul.rs
Normal file
@ -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<Number> 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<isize> 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;
|
||||
}
|
||||
}
|
106
src/number/ord.rs
Normal file
106
src/number/ord.rs
Normal file
@ -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<Ordering> {
|
||||
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);
|
||||
}
|
||||
}
|
45
src/number/sub.rs
Normal file
45
src/number/sub.rs
Normal file
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user