2024-11-25 10:39:52 +01:00
|
|
|
mod add;
|
|
|
|
mod div;
|
|
|
|
mod from;
|
|
|
|
mod mul;
|
|
|
|
mod ord;
|
|
|
|
mod sub;
|
|
|
|
|
|
|
|
use std::cmp::Ordering;
|
2024-11-18 10:59:04 +01:00
|
|
|
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<isize>,
|
|
|
|
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 {
|
2024-11-20 12:34:05 +01:00
|
|
|
let number = isize::try_from(self).unwrap();
|
2024-11-18 10:59:04 +01:00
|
|
|
for _i in 1..n {
|
|
|
|
result = result * number;
|
|
|
|
}
|
|
|
|
result
|
|
|
|
} else {
|
|
|
|
let number = self.clone();
|
|
|
|
for _i in 1..n {
|
2024-11-25 10:39:52 +01:00
|
|
|
result *= number.clone();
|
2024-11-18 10:59:04 +01:00
|
|
|
}
|
|
|
|
result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fact(self) -> Self {
|
|
|
|
let mut fact = Number::from(1);
|
|
|
|
if ((self.digits.len() * 8) as u32) < isize::BITS {
|
2024-11-20 12:34:05 +01:00
|
|
|
let max = isize::try_from(self).unwrap();
|
2024-11-18 10:59:04 +01:00
|
|
|
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::<Vec<String>>()
|
|
|
|
.join("");
|
|
|
|
match self.sign {
|
|
|
|
Sign::Positif => write!(f, "{number_string}"),
|
|
|
|
Sign::Negatif => write!(f, "-{number_string}"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod number_tests {
|
2024-11-25 10:39:52 +01:00
|
|
|
use crate::number::Number;
|
2024-11-18 16:02:19 +01:00
|
|
|
|
2024-11-18 10:59:04 +01:00
|
|
|
#[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);
|
|
|
|
}
|
|
|
|
}
|