PuzzleUtils/src/number.rs

111 lines
2.7 KiB
Rust
Raw Normal View History

2024-11-25 10:39:52 +01:00
mod add;
mod div;
mod from;
mod mul;
mod ord;
mod sub;
use std::fmt::{Display, Formatter};
#[derive(Copy, 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)
}
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 {
2024-11-25 10:39:52 +01:00
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()
.rev()
.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;
#[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);
}
}