mod add; mod div; mod from; mod mul; mod ord; mod sub; use std::cmp::Ordering; use std::fmt::{Display, Formatter}; #[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::try_from(self).unwrap(); for _i in 1..n { result = result * number; } result } else { let number = self.clone(); for _i in 1..n { 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::try_from(self).unwrap(); 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 } } 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}"), } } } #[cfg(test)] mod number_tests { use crate::number::Number; #[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); } }