Compare commits
2 Commits
1f96d76c74
...
23a96d5bee
Author | SHA1 | Date | |
---|---|---|---|
23a96d5bee | |||
e0fce27917 |
@ -1,23 +1,42 @@
|
|||||||
use std::error::Error;
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
error::Error,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::number::Number;
|
use crate::number::{Number, Sign};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Fraction {
|
pub struct Fraction {
|
||||||
pub numerator: Number,
|
pub numerator: Number,
|
||||||
pub denominator: Number,
|
pub denominator: Number,
|
||||||
|
pub sign: Sign,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Rational {}
|
pub struct Rational {
|
||||||
|
pub decimal: Number,
|
||||||
|
pub mantissa: Number,
|
||||||
|
pub recurring: Number,
|
||||||
|
}
|
||||||
|
|
||||||
impl Fraction {
|
impl Fraction {
|
||||||
pub fn new(numerator: Number, denominator: Number) -> Result<Self, Box<dyn Error>> {
|
pub fn new(numerator: Number, denominator: Number) -> Result<Self, Box<dyn Error>> {
|
||||||
if denominator == 0.into() {
|
if denominator == 0.into() {
|
||||||
return Err(Box::from("Division by 0"));
|
return Err(Box::from("Division by 0"));
|
||||||
}
|
}
|
||||||
|
let sign = match numerator.sign {
|
||||||
|
Sign::Positif => match denominator.sign {
|
||||||
|
Sign::Positif => Sign::Positif,
|
||||||
|
Sign::Negatif => Sign::Negatif,
|
||||||
|
},
|
||||||
|
Sign::Negatif => match denominator.sign {
|
||||||
|
Sign::Positif => Sign::Negatif,
|
||||||
|
Sign::Negatif => Sign::Positif,
|
||||||
|
},
|
||||||
|
};
|
||||||
let mut f = Fraction {
|
let mut f = Fraction {
|
||||||
numerator,
|
numerator,
|
||||||
denominator,
|
denominator,
|
||||||
|
sign,
|
||||||
};
|
};
|
||||||
f.reduce();
|
f.reduce();
|
||||||
Ok(f)
|
Ok(f)
|
||||||
@ -31,10 +50,78 @@ impl Fraction {
|
|||||||
self.numerator = self.numerator.clone() / gcd.clone();
|
self.numerator = self.numerator.clone() / gcd.clone();
|
||||||
self.denominator = self.denominator.clone() / gcd.clone();
|
self.denominator = self.denominator.clone() / gcd.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_full_mantissa(fraction: &Fraction) -> Option<Number> {
|
||||||
|
let mut div_memory = HashMap::new();
|
||||||
|
let mut rem_memory = HashSet::new();
|
||||||
|
rem_memory.insert(1.into());
|
||||||
|
let mut div_with = fraction.numerator.clone();
|
||||||
|
let mut rational = Vec::new();
|
||||||
|
if div_with < fraction.denominator {
|
||||||
|
div_with = div_with * 10;
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
while div_with < fraction.denominator {
|
||||||
|
rational.push(0);
|
||||||
|
div_memory
|
||||||
|
.entry(0)
|
||||||
|
.and_modify(|value| *value += 1)
|
||||||
|
.or_insert(1);
|
||||||
|
div_with = div_with * 10;
|
||||||
|
rem_memory.insert(div_with.clone());
|
||||||
|
}
|
||||||
|
let (div, rem) =
|
||||||
|
Number::div_with_rem(div_with.clone(), fraction.denominator.clone()).unwrap();
|
||||||
|
if rem == 0.into() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let next_digit = div.digits[0];
|
||||||
|
if div_memory.contains_key(&next_digit) && rem_memory.contains(&rem) && next_digit != 0
|
||||||
|
{
|
||||||
|
let mut digits = vec![];
|
||||||
|
if div_memory.values().min() != div_memory.values().max() {
|
||||||
|
rational.push(div.digits[0]);
|
||||||
|
digits = rational;
|
||||||
|
let (l, r) = digits.split_at(digits.len() / 2);
|
||||||
|
if l == r {
|
||||||
|
digits = l.to_vec();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let idx = rational
|
||||||
|
.iter()
|
||||||
|
.position(|digit| digit == &div.digits[0])
|
||||||
|
.unwrap();
|
||||||
|
if idx == rational.len() - 1 {
|
||||||
|
digits.push(div.digits[0]);
|
||||||
|
} else {
|
||||||
|
for digit in &rational[idx..] {
|
||||||
|
if digits.contains(digit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
digits.push(*digit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some(Number {
|
||||||
|
digits,
|
||||||
|
sign: Sign::Positif,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
div_memory
|
||||||
|
.entry(next_digit)
|
||||||
|
.and_modify(|count| *count += 1)
|
||||||
|
.or_insert(1);
|
||||||
|
rem_memory.insert(rem.clone());
|
||||||
|
rational.push(div.digits[0]);
|
||||||
|
div_with = rem * 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use crate::number::Sign;
|
||||||
|
|
||||||
use super::Fraction;
|
use super::Fraction;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -44,7 +131,8 @@ mod test {
|
|||||||
f,
|
f,
|
||||||
Fraction {
|
Fraction {
|
||||||
numerator: 4.into(),
|
numerator: 4.into(),
|
||||||
denominator: 3.into()
|
denominator: 3.into(),
|
||||||
|
sign: Sign::Positif
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
471
src/number.rs
471
src/number.rs
@ -1,10 +1,13 @@
|
|||||||
use std::cmp::{min, Ordering};
|
mod add;
|
||||||
use std::error::Error;
|
mod div;
|
||||||
use std::fmt::{Display, Formatter};
|
mod from;
|
||||||
use std::iter::zip;
|
mod mul;
|
||||||
use std::ops::{Add, Div, Mul, Rem, Sub};
|
mod ord;
|
||||||
|
mod sub;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum Sign {
|
pub enum Sign {
|
||||||
Positif,
|
Positif,
|
||||||
Negatif,
|
Negatif,
|
||||||
@ -28,85 +31,6 @@ impl Number {
|
|||||||
(b as isize).wrapping_sub('0' as isize)
|
(b as isize).wrapping_sub('0' as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_overflows(&mut self) {
|
|
||||||
let new_digits = &mut self.digits;
|
|
||||||
let digits_len = new_digits.len();
|
|
||||||
let mut digits_idx = digits_len - 1;
|
|
||||||
loop {
|
|
||||||
let digit_or_num = new_digits[digits_idx];
|
|
||||||
let digit_len = if digit_or_num != 0 {
|
|
||||||
(digit_or_num.abs() as f64 + 1.0).log10().ceil() as usize
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
};
|
|
||||||
for i in 0..digit_len {
|
|
||||||
let new_digit = Self::get_digit(digit_or_num, i);
|
|
||||||
let (digit_idx, is_overflow) = digits_idx.overflowing_sub(i);
|
|
||||||
if is_overflow {
|
|
||||||
new_digits.insert(0, new_digit);
|
|
||||||
digits_idx += 1;
|
|
||||||
} else {
|
|
||||||
let digit = new_digits.get_mut(digit_idx).unwrap();
|
|
||||||
if i == 0 {
|
|
||||||
*digit = new_digit;
|
|
||||||
} else {
|
|
||||||
*digit += new_digit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if digits_idx == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
digits_idx -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_underflows(&mut self) {
|
|
||||||
let new_digits = &mut self.digits;
|
|
||||||
let mut digits_len = new_digits.len();
|
|
||||||
for digit in new_digits.clone() {
|
|
||||||
match digit.cmp(&0) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
if digits_len == 1 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
digits_len -= 1;
|
|
||||||
new_digits.remove(0);
|
|
||||||
}
|
|
||||||
Ordering::Less => {
|
|
||||||
self.sign = Sign::Negatif;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => break,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let mut digits_idx = digits_len - 1;
|
|
||||||
loop {
|
|
||||||
let digit = new_digits[digits_idx];
|
|
||||||
if self.sign == Sign::Positif && digit < 0 && digits_idx > 0 {
|
|
||||||
let mut_digit = new_digits.get_mut(digits_idx).unwrap();
|
|
||||||
*mut_digit = 10 - digit.abs();
|
|
||||||
let mut_digit = new_digits.get_mut(digits_idx - 1).unwrap();
|
|
||||||
*mut_digit -= 1;
|
|
||||||
} else {
|
|
||||||
let mut_digit = new_digits.get_mut(digits_idx).unwrap();
|
|
||||||
*mut_digit = digit.abs();
|
|
||||||
}
|
|
||||||
if digits_idx == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
digits_idx -= 1;
|
|
||||||
}
|
|
||||||
for digit in new_digits.clone() {
|
|
||||||
match digit.cmp(&0) {
|
|
||||||
Ordering::Equal => {
|
|
||||||
new_digits.remove(0);
|
|
||||||
}
|
|
||||||
_ => break,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pow(self, n: u32) -> Self {
|
pub fn pow(self, n: u32) -> Self {
|
||||||
let mut result = self.clone();
|
let mut result = self.clone();
|
||||||
if ((self.digits.len() * 8) as u32) < isize::BITS {
|
if ((self.digits.len() * 8) as u32) < isize::BITS {
|
||||||
@ -118,7 +42,7 @@ impl Number {
|
|||||||
} else {
|
} else {
|
||||||
let number = self.clone();
|
let number = self.clone();
|
||||||
for _i in 1..n {
|
for _i in 1..n {
|
||||||
result = result * number.clone();
|
result *= number.clone();
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -147,137 +71,6 @@ impl Number {
|
|||||||
|
|
||||||
last_two.0
|
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 {
|
impl Display for Number {
|
||||||
@ -285,6 +78,7 @@ impl Display for Number {
|
|||||||
let number_string = self
|
let number_string = self
|
||||||
.digits
|
.digits
|
||||||
.iter()
|
.iter()
|
||||||
|
.rev()
|
||||||
.map(|&digit| digit.to_string())
|
.map(|&digit| digit.to_string())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("");
|
.join("");
|
||||||
@ -295,194 +89,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)]
|
#[cfg(test)]
|
||||||
mod number_tests {
|
mod number_tests {
|
||||||
use crate::number::{Number, Sign};
|
use crate::number::Number;
|
||||||
|
|
||||||
#[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
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_digit() {
|
fn test_get_digit() {
|
||||||
@ -498,60 +107,4 @@ mod number_tests {
|
|||||||
assert_eq!(digit_4, 2);
|
assert_eq!(digit_4, 2);
|
||||||
assert_eq!(digit_5, 1);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
185
src/number/add.rs
Normal file
185
src/number/add.rs
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
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 = [self.digits, pad].concat();
|
||||||
|
} else {
|
||||||
|
rhs_digits = [rhs.digits, pad].concat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let zipped = zip(self_digits.iter(), rhs_digits.iter());
|
||||||
|
let mut carry = 0;
|
||||||
|
let mut digits = Vec::new();
|
||||||
|
let mut sign = match (self.sign, rhs.sign) {
|
||||||
|
(Sign::Positif, Sign::Positif) => Sign::Positif,
|
||||||
|
(Sign::Negatif, Sign::Negatif) => Sign::Negatif,
|
||||||
|
(Sign::Positif, Sign::Negatif) | (Sign::Negatif, Sign::Positif) => Sign::Positif,
|
||||||
|
};
|
||||||
|
for (a, b) in zipped {
|
||||||
|
let comb = match (self.sign, rhs.sign) {
|
||||||
|
(Sign::Positif, Sign::Positif) => {
|
||||||
|
let comb = a + b + carry;
|
||||||
|
if comb > 9 {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
comb % 10
|
||||||
|
}
|
||||||
|
(Sign::Positif, Sign::Negatif) => {
|
||||||
|
let comb = a - b - carry;
|
||||||
|
if comb > 0 && b > a {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
if b > a {
|
||||||
|
sign = Sign::Negatif;
|
||||||
|
} else {
|
||||||
|
sign = Sign::Positif;
|
||||||
|
}
|
||||||
|
(comb % 10).abs()
|
||||||
|
}
|
||||||
|
(Sign::Negatif, Sign::Positif) => {
|
||||||
|
let comb = -a + b - carry;
|
||||||
|
if comb > 0 && a > b {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
if a > b {
|
||||||
|
sign = Sign::Negatif;
|
||||||
|
} else {
|
||||||
|
sign = Sign::Positif;
|
||||||
|
}
|
||||||
|
(comb % 10).abs()
|
||||||
|
}
|
||||||
|
(Sign::Negatif, Sign::Negatif) => {
|
||||||
|
let comb = a + b + carry;
|
||||||
|
if comb > 9 {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
comb % 10
|
||||||
|
}
|
||||||
|
};
|
||||||
|
digits.push(comb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if carry != 0 {
|
||||||
|
digits.push(carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { digits, sign }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Number {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
let new = self.clone() + rhs;
|
||||||
|
self.digits = new.digits;
|
||||||
|
self.sign = new.sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_number_add {
|
||||||
|
use crate::number::Number;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_positif() {
|
||||||
|
let a = Number::from(1);
|
||||||
|
let b = 1.into();
|
||||||
|
let res = Number::from(2);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_large_positif() {
|
||||||
|
let a = Number::from(9);
|
||||||
|
let b = 9.into();
|
||||||
|
let res = Number::from(18);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_negatif() {
|
||||||
|
let a = Number::from(-1);
|
||||||
|
let b = (-1).into();
|
||||||
|
let res = Number::from(-2);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_large_negatif() {
|
||||||
|
let a = Number::from(-9);
|
||||||
|
let b = (-9).into();
|
||||||
|
let res = Number::from(-18);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_negatif_to_positif() {
|
||||||
|
let a = Number::from(1);
|
||||||
|
let b = (-1).into();
|
||||||
|
let res = Number::from(0);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_positif_to_negatif() {
|
||||||
|
let a = Number::from(-1);
|
||||||
|
let b = (1).into();
|
||||||
|
let res = Number::from(0);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_larger_positif_to_negatif() {
|
||||||
|
let a = Number::from(-1);
|
||||||
|
let b = (11).into();
|
||||||
|
let res = Number::from(10);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_larger_negatif_to_positif() {
|
||||||
|
let a = Number::from(1);
|
||||||
|
let b = (-11).into();
|
||||||
|
let res = Number::from(-10);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_positif_to_larger_negatif() {
|
||||||
|
let a = Number::from(-99);
|
||||||
|
let b = (11).into();
|
||||||
|
let res = Number::from(-88);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_negatif_to_larger_positif() {
|
||||||
|
let a = Number::from(99);
|
||||||
|
let b = (-11).into();
|
||||||
|
let res = Number::from(88);
|
||||||
|
assert_eq!(res, a + b);
|
||||||
|
}
|
||||||
|
}
|
112
src/number/div.rs
Normal file
112
src/number/div.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
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,
|
||||||
|
};
|
||||||
|
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}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
111
src/number/from.rs
Normal file
111
src/number/from.rs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
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().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()
|
||||||
|
.rev()
|
||||||
|
.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..].iter().rev() {
|
||||||
|
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.to_vec();
|
||||||
|
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![4, 3, 2, 1],
|
||||||
|
sign: Sign::Negatif
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_0isize() {
|
||||||
|
let number = Number::from(0);
|
||||||
|
assert_eq!(
|
||||||
|
number,
|
||||||
|
Number {
|
||||||
|
digits: vec![0],
|
||||||
|
sign: Sign::Positif
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_from_str() {
|
||||||
|
let number = Number::from("-1234");
|
||||||
|
assert_eq!(
|
||||||
|
number,
|
||||||
|
Number {
|
||||||
|
digits: vec![4, 3, 2, 1],
|
||||||
|
sign: Sign::Negatif
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
132
src/number/mul.rs
Normal file
132
src/number/mul.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use std::ops::{Mul, MulAssign};
|
||||||
|
|
||||||
|
use super::{Number, Sign};
|
||||||
|
|
||||||
|
impl Mul for Number {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
#[allow(clippy::suspicious_arithmetic_impl)]
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
println!("left {self:#?}");
|
||||||
|
println!("right {rhs:#?}");
|
||||||
|
let mut mult_vecs = Vec::new();
|
||||||
|
let sign = match (self.sign, rhs.sign) {
|
||||||
|
(Sign::Positif, Sign::Positif) => Sign::Positif,
|
||||||
|
(Sign::Positif, Sign::Negatif) => Sign::Negatif,
|
||||||
|
(Sign::Negatif, Sign::Positif) => Sign::Negatif,
|
||||||
|
(Sign::Negatif, Sign::Negatif) => Sign::Positif,
|
||||||
|
};
|
||||||
|
for (idx, rdigit) in rhs.digits.iter().enumerate() {
|
||||||
|
let rdigit = rdigit * 10_isize.pow(idx as u32);
|
||||||
|
let mult_vec: Vec<isize> = self.digits.iter().map(|ldigit| ldigit * rdigit).collect();
|
||||||
|
let mut normalized_mult_vec = Vec::new();
|
||||||
|
let mut carry = 0;
|
||||||
|
let mut add_zero = true;
|
||||||
|
mult_vec.into_iter().for_each(|digit| {
|
||||||
|
let digit = digit + carry;
|
||||||
|
if digit > 9 {
|
||||||
|
carry = digit % 10;
|
||||||
|
normalized_mult_vec.insert(0, digit / 10);
|
||||||
|
} else {
|
||||||
|
normalized_mult_vec.insert(0, digit);
|
||||||
|
carry = 0;
|
||||||
|
add_zero = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if carry != 0 || add_zero {
|
||||||
|
normalized_mult_vec.insert(0, carry);
|
||||||
|
}
|
||||||
|
mult_vecs.push(Number {
|
||||||
|
digits: normalized_mult_vec,
|
||||||
|
sign,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mult_vecs.into_iter().reduce(|acc, num| acc + num).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<Number> for isize {
|
||||||
|
type Output = Number;
|
||||||
|
|
||||||
|
fn mul(self, rhs: Number) -> Self::Output {
|
||||||
|
Number::from(self) * rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<isize> for Number {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: isize) -> Self::Output {
|
||||||
|
self * Number::from(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign for Number {
|
||||||
|
fn mul_assign(&mut self, rhs: Self) {
|
||||||
|
let new = self.clone() * rhs;
|
||||||
|
self.digits = new.digits;
|
||||||
|
self.sign = new.sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_number_mul {
|
||||||
|
use crate::number::Number;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_positif() {
|
||||||
|
let a = Number::from(9);
|
||||||
|
let b = Number::from(9);
|
||||||
|
let res = Number::from(81);
|
||||||
|
assert_eq!(res, a * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_negatif() {
|
||||||
|
let a = Number::from(-9);
|
||||||
|
let b = Number::from(-9);
|
||||||
|
let res = Number::from(81);
|
||||||
|
assert_eq!(res, a * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_positif_with_negatif() {
|
||||||
|
let a = Number::from(9);
|
||||||
|
let b = Number::from(-9);
|
||||||
|
let res = Number::from(-81);
|
||||||
|
assert_eq!(res, a * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_negatif_with_positif() {
|
||||||
|
let a = Number::from(-9);
|
||||||
|
let b = Number::from(9);
|
||||||
|
let res = Number::from(-81);
|
||||||
|
assert_eq!(res, a * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_eleven_x_ten() {
|
||||||
|
let a = Number::from(11);
|
||||||
|
let b = Number::from(10);
|
||||||
|
let res = Number::from(110);
|
||||||
|
assert_eq!(res, a * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_eleven_x_eleven() {
|
||||||
|
let a = Number::from(11);
|
||||||
|
let b = Number::from(11);
|
||||||
|
let res = Number::from(121);
|
||||||
|
assert_eq!(res, a * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mul_big() {
|
||||||
|
let a = Number::from("123456789");
|
||||||
|
let b = Number::from("987654321");
|
||||||
|
let res = Number::from("121932631112635269");
|
||||||
|
assert_eq!(res, a * b);
|
||||||
|
}
|
||||||
|
}
|
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);
|
||||||
|
}
|
||||||
|
}
|
168
src/number/sub.rs
Normal file
168
src/number/sub.rs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
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 = [self.digits, pad].concat();
|
||||||
|
} else {
|
||||||
|
rhs_digits = [rhs.digits, pad].concat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let zipped = zip(self_digits.iter(), rhs_digits.iter());
|
||||||
|
let mut carry = 0;
|
||||||
|
let mut digits = Vec::new();
|
||||||
|
let mut sign = match (self.sign, rhs.sign) {
|
||||||
|
(Sign::Positif, Sign::Negatif) => Sign::Positif,
|
||||||
|
(Sign::Negatif, Sign::Positif) => Sign::Negatif,
|
||||||
|
(Sign::Positif, Sign::Positif) | (Sign::Negatif, Sign::Negatif) => Sign::Positif,
|
||||||
|
};
|
||||||
|
for (a, b) in zipped {
|
||||||
|
let comb = match (self.sign, rhs.sign) {
|
||||||
|
(Sign::Positif, Sign::Positif) => {
|
||||||
|
let comb = a - b - carry;
|
||||||
|
if comb < 0 {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
if b > a {
|
||||||
|
sign = Sign::Negatif;
|
||||||
|
} else {
|
||||||
|
sign = Sign::Positif;
|
||||||
|
}
|
||||||
|
(comb % 10).abs()
|
||||||
|
}
|
||||||
|
(Sign::Positif, Sign::Negatif) => {
|
||||||
|
let comb = a + b + carry;
|
||||||
|
if comb > 9 {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
comb % 10
|
||||||
|
}
|
||||||
|
(Sign::Negatif, Sign::Positif) => {
|
||||||
|
let comb = -a - b - carry;
|
||||||
|
if comb < -9 {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
(comb % 10).abs()
|
||||||
|
}
|
||||||
|
(Sign::Negatif, Sign::Negatif) => {
|
||||||
|
let comb = -a + b + carry;
|
||||||
|
if comb > 10 {
|
||||||
|
carry = 1;
|
||||||
|
} else {
|
||||||
|
carry = 0;
|
||||||
|
}
|
||||||
|
if a > b {
|
||||||
|
sign = Sign::Negatif;
|
||||||
|
} else {
|
||||||
|
sign = Sign::Positif;
|
||||||
|
}
|
||||||
|
comb % 10
|
||||||
|
}
|
||||||
|
};
|
||||||
|
digits.push(comb);
|
||||||
|
}
|
||||||
|
if carry != 0 {
|
||||||
|
digits.push(carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { digits, sign }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Number {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
let new = self.clone() - rhs;
|
||||||
|
self.digits = new.digits;
|
||||||
|
self.sign = new.sign;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_number_sub {
|
||||||
|
use crate::number::Number;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_positif() {
|
||||||
|
let a = Number::from(1);
|
||||||
|
let b = 1.into();
|
||||||
|
let res = Number::from(0);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_negatif() {
|
||||||
|
let a = Number::from(-1);
|
||||||
|
let b = (-1).into();
|
||||||
|
let res = Number::from(0);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_negatif_from_positif() {
|
||||||
|
let a = Number::from(1);
|
||||||
|
let b = (-1).into();
|
||||||
|
let res = Number::from(2);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_positif_from_negatif() {
|
||||||
|
let a = Number::from(-1);
|
||||||
|
let b = (1).into();
|
||||||
|
let res = Number::from(-2);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_larger_positif_from_negatif() {
|
||||||
|
let a = Number::from(-1);
|
||||||
|
let b = (11).into();
|
||||||
|
let res = Number::from(-12);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_larger_negatif_from_positif() {
|
||||||
|
let a = Number::from(1);
|
||||||
|
let b = (-11).into();
|
||||||
|
let res = Number::from(12);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_positif_from_larger_negatif() {
|
||||||
|
let a = Number::from(-99);
|
||||||
|
let b = (11).into();
|
||||||
|
let res = Number::from(-110);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sub_negatif_from_larger_positif() {
|
||||||
|
let a = Number::from(99);
|
||||||
|
let b = (-11).into();
|
||||||
|
let res = Number::from(110);
|
||||||
|
assert_eq!(res, a - b);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user