use std::cmp::{min, Ordering}; use std::error::Error; 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 { Positif, Negatif, } #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct Number { pub digits: Vec, pub sign: Sign, } impl Number { pub fn get_digit(n: isize, pos: usize) -> isize { let modulo = 10isize.pow(pos as u32 + 1); let divisor = modulo / 10; (n % modulo) / divisor } pub const fn byte_to_digit(b: u8) -> isize { // wrapping_sub('0' as u32) same as - 48 but less magical (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 { let mut result = self.clone(); if ((self.digits.len() * 8) as u32) < isize::BITS { let number = isize::from(self); for _i in 1..n { result = result * number; } result } else { let number = self.clone(); for _i in 1..n { result = result * number.clone(); } result } } pub fn fact(self) -> Self { let mut fact = Number::from(1); if ((self.digits.len() * 8) as u32) < isize::BITS { let max = isize::from(self); for n in 1..=max { fact = fact * n; } fact } else { panic!("starting number too big") } } pub fn fib(n: u64) -> Self { let mut last_two = (Self::from(1), Self::from(1)); let mut iteration = 1; while iteration < n { last_two = (last_two.1.clone(), last_two.0 + last_two.1); iteration += 1; } 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 From for isize { fn from(value: Number) -> Self { let mut num = 0; for (pos, &digit) in value.digits.iter().rev().enumerate() { num += digit * 10isize.pow(pos as u32); } 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 { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let number_string = self .digits .iter() .map(|&digit| digit.to_string()) .collect::>() .join(""); match self.sign { Sign::Positif => write!(f, "{number_string}"), Sign::Negatif => write!(f, "-{number_string}"), } } } 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 } } #[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 } ); } #[test] fn test_get_digit() { let num = 12345; let digit_1 = Number::get_digit(num, 0); let digit_2 = Number::get_digit(num, 1); let digit_3 = Number::get_digit(num, 2); let digit_4 = Number::get_digit(num, 3); let digit_5 = Number::get_digit(num, 4); assert_eq!(digit_1, 5); assert_eq!(digit_2, 4); assert_eq!(digit_3, 3); assert_eq!(digit_4, 2); assert_eq!(digit_5, 1); } }