Compare commits

...

14 Commits

13 changed files with 1684 additions and 501 deletions

View File

@@ -53,7 +53,7 @@ pub fn nth_lex<T: Clone + Ord>(
#[derive(Clone)]
pub struct Combinator<T: Clone + Ord> {
pub current: Vec<T>,
pub elements: Vec<T>,
pub k: usize,
idx: usize,
}
@@ -64,7 +64,7 @@ impl<T: Clone + Ord> Combinator<T> {
return Err(Box::from("Out of bounds"));
}
Ok(Self {
current: elements,
elements,
k,
idx: 0,
})
@@ -75,7 +75,7 @@ impl<T: Clone + Ord> Iterator for Combinator<T> {
type Item = Vec<T>;
fn next(&mut self) -> Option<Self::Item> {
let num_elements = self.current.len();
let num_elements = self.elements.len();
let num_combinations = binomial(num_elements, self.k);
if self.idx == num_combinations {
return None;
@@ -83,7 +83,7 @@ impl<T: Clone + Ord> Iterator for Combinator<T> {
let mut i = 0;
let mut remaining_k = self.k;
let mut comb = Vec::new();
let mut remainder = self.idx - 1;
let mut remainder = self.idx;
while remaining_k > 0 {
// Count the number of combinations that start with elements[i]
// example with n = 5, k = 2
@@ -94,7 +94,7 @@ impl<T: Clone + Ord> Iterator for Combinator<T> {
let count = binomial(num_elements - i - 1, remaining_k - 1);
if remainder < count {
// If the nth combination is within the count, pick this element
comb.push(self.current[i].clone());
comb.push(self.elements[i].clone());
remaining_k -= 1;
} else {
remainder -= count;
@@ -102,7 +102,143 @@ impl<T: Clone + Ord> Iterator for Combinator<T> {
i += 1;
}
self.idx += 1;
self.current = comb;
Some(self.current.clone())
Some(comb)
}
}
#[cfg(test)]
mod test {
use crate::combination::{nth_lex, Combinator};
const SMALL: [i8; 5] = [1, 2, 3, 4, 5];
// Nth Lex
#[test]
fn nth_lex_zero_small() {
let small = SMALL.to_vec();
assert!(nth_lex(small, 0, 1).is_err());
}
#[test]
fn nth_lex_more_small() {
let small = SMALL.to_vec();
assert!(nth_lex(small, 6, 1).is_err());
}
#[test]
fn nth_lex_all_small() {
let small = SMALL.to_vec();
assert!(nth_lex(small.clone(), 5, 1).unwrap() == vec![1, 2, 3, 4, 5]);
assert!(nth_lex(small, 5, 2).is_err());
}
#[test]
fn nth_lex_some_small() {
let small = SMALL.to_vec();
assert_eq!(nth_lex(small.clone(), 2, 1).unwrap(), vec![1, 2]);
assert_eq!(nth_lex(small.clone(), 2, 2).unwrap(), vec![1, 3]);
assert_eq!(nth_lex(small.clone(), 2, 3).unwrap(), vec![1, 4]);
assert_eq!(nth_lex(small.clone(), 2, 4).unwrap(), vec![1, 5]);
assert_eq!(nth_lex(small.clone(), 2, 5).unwrap(), vec![2, 3]);
assert_eq!(nth_lex(small.clone(), 2, 6).unwrap(), vec![2, 4]);
assert_eq!(nth_lex(small.clone(), 2, 7).unwrap(), vec![2, 5]);
assert_eq!(nth_lex(small.clone(), 2, 8).unwrap(), vec![3, 4]);
assert_eq!(nth_lex(small.clone(), 2, 9).unwrap(), vec![3, 5]);
assert_eq!(nth_lex(small.clone(), 2, 10).unwrap(), vec![4, 5]);
assert!(nth_lex(small, 2, 11).is_err());
}
#[test]
fn nth_lex_one_small() {
let small = SMALL.to_vec();
assert_eq!(nth_lex(small.clone(), 1, 1).unwrap(), vec![1]);
assert_eq!(nth_lex(small.clone(), 1, 2).unwrap(), vec![2]);
assert_eq!(nth_lex(small.clone(), 1, 3).unwrap(), vec![3]);
assert_eq!(nth_lex(small.clone(), 1, 4).unwrap(), vec![4]);
assert_eq!(nth_lex(small.clone(), 1, 5).unwrap(), vec![5]);
assert!(nth_lex(small, 1, 6).is_err());
}
// Can't yet use too big values
//#[test]
//fn nth_lex_all_big() {
// let big: Vec<i32> = (0..100).collect();
// assert_eq!(
// nth_lex(big.clone(), 100, 1).unwrap(),
// (0..100).collect::<Vec<i32>>()
// );
// assert!(nth_lex(big, 100, 2).is_err());
//}
//#[test]
//fn nth_lex_some_big() {
// let big: Vec<i32> = (0..100).collect();
// assert_eq!(
// nth_lex(big.clone(), 50, 1).unwrap(),
// (0..50).collect::<Vec<i32>>()
// );
//}
//#[test]
//fn nth_lex_one_big() {
// let big: Vec<i32> = (0..100).collect();
// assert_eq!(nth_lex(big.clone(), 1, 1).unwrap(), vec![0]);
// assert_eq!(nth_lex(big.clone(), 1, 2).unwrap(), vec![1]);
// assert_eq!(nth_lex(big.clone(), 1, 3).unwrap(), vec![2]);
// assert_eq!(nth_lex(big.clone(), 1, 4).unwrap(), vec![3]);
//}
// Combinator
#[test]
fn comb_zero_small() {
let small = SMALL.to_vec();
let comb = Combinator::new(small, 0);
assert!(comb.is_err());
}
#[test]
fn comb_more_small() {
let small = SMALL.to_vec();
let comb = Combinator::new(small, 6);
assert!(comb.is_err());
}
#[test]
fn comb_all_small() {
let small = SMALL.to_vec();
let mut comb = Combinator::new(small, 5).unwrap();
assert!(comb.next() == Some(vec![1, 2, 3, 4, 5]));
assert!(comb.next().is_none());
}
#[test]
fn comb_some_small() {
let small = SMALL.to_vec();
let mut comb = Combinator::new(small, 2).unwrap();
assert_eq!(comb.next(), Some(vec![1, 2]));
assert_eq!(comb.next(), Some(vec![1, 3]));
assert_eq!(comb.next(), Some(vec![1, 4]));
assert_eq!(comb.next(), Some(vec![1, 5]));
assert_eq!(comb.next(), Some(vec![2, 3]));
assert_eq!(comb.next(), Some(vec![2, 4]));
assert_eq!(comb.next(), Some(vec![2, 5]));
assert_eq!(comb.next(), Some(vec![3, 4]));
assert_eq!(comb.next(), Some(vec![3, 5]));
assert_eq!(comb.next(), Some(vec![4, 5]));
assert!(comb.next().is_none());
}
#[test]
fn comb_one_small() {
let small = SMALL.to_vec();
let mut comb = Combinator::new(small, 1).unwrap();
assert_eq!(comb.next(), Some(vec![1]));
assert_eq!(comb.next(), Some(vec![2]));
assert_eq!(comb.next(), Some(vec![3]));
assert_eq!(comb.next(), Some(vec![4]));
assert_eq!(comb.next(), Some(vec![5]));
assert!(comb.next().is_none());
}
}

View File

@@ -1,23 +1,44 @@
use std::error::Error;
use std::{
collections::{HashMap, HashSet},
error::Error,
};
use crate::number::Number;
use crate::number::{Number, Sign};
#[derive(Debug, PartialEq, Eq)]
pub struct Fraction {
pub numerator: Number,
pub denominator: Number,
pub sign: Sign,
}
pub struct Rational {}
pub struct Rational {
pub decimal: Number,
pub mantissa: Number,
pub recurring: Number,
}
impl Fraction {
pub fn new(numerator: Number, denominator: Number) -> Result<Self, Box<dyn Error>> {
pub fn new(mut numerator: Number, mut denominator: Number) -> Result<Self, Box<dyn Error>> {
if denominator == 0.into() {
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,
},
};
numerator.sign = Sign::Positif;
denominator.sign = Sign::Positif;
let mut f = Fraction {
numerator,
denominator,
sign,
};
f.reduce();
Ok(f)
@@ -31,10 +52,78 @@ impl Fraction {
self.numerator = self.numerator.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)]
mod test {
use crate::number::Sign;
use super::Fraction;
#[test]
@@ -44,7 +133,8 @@ mod test {
f,
Fraction {
numerator: 4.into(),
denominator: 3.into()
denominator: 3.into(),
sign: Sign::Positif
}
);
}

View File

@@ -1,7 +1,11 @@
use core::panic;
use std::error::Error;
#[derive(Debug)]
pub struct Grid<T: Clone>(pub Vec<Vec<T>>);
#[derive(Debug, PartialEq, Eq)]
pub struct Grid<T: Clone> {
pub rows: Vec<Vec<T>>,
pub width: u32,
}
impl<T: Clone> Grid<T> {
pub fn new(grid: Vec<Vec<T>>) -> Result<Self, Box<dyn Error>> {
@@ -11,23 +15,245 @@ impl<T: Clone> Grid<T> {
return Err(Box::from("Rows need to all be equal in length"));
}
}
Ok(Grid(grid))
Ok(Grid {
rows: grid,
width: row_length as u32,
})
}
pub fn invert(&mut self) -> Self {
let height = self.0.len();
let width = self.0[0].len();
pub fn rotate_90(&mut self) -> Self {
let height = self.rows.len();
let width = self.rows[0].len();
let mut new_grid = Vec::with_capacity(width);
for col_idx in 0..width {
let mut new_row = Vec::with_capacity(height);
for row_idx in 0..height {
new_row.push(self.0[row_idx][col_idx].clone());
new_row.push(self.rows[row_idx][col_idx].clone());
}
new_grid.push(new_row);
}
self.0 = new_grid;
Grid(self.0.clone())
self.rows = new_grid;
self.width = height as u32;
Grid {
rows: self.rows.clone(),
width: height as u32,
}
}
pub fn get_diagonals_aigu(&self) -> Vec<Vec<T>> {
let mut diagonals = Vec::new();
// col_idx == starting column of this diagonal
for col_idx in 0..self.width {
diagonals.push(self.get_diagonal_aigu(col_idx, 0));
if col_idx == self.width - 1 {
// row_idx == starting row of this diagonal
for row_idx in 1..self.rows.len() as u32 {
diagonals.push(self.get_diagonal_aigu(col_idx, row_idx));
}
}
}
diagonals
}
fn get_diagonal_aigu(&self, starting_col: u32, starting_row: u32) -> Vec<T> {
if starting_col != self.width - 1 && starting_row != 0 {
panic!("Start of diagonal needs to be valid. Start at top row or rightmost column");
}
// col_idx == current col_idx of this diagonal
let mut col_idx = starting_col as usize;
// row_idx == current row_idx of this diagonal
let mut row_idx = starting_row as usize;
let mut diagonal = Vec::new();
while let Some(row) = self.rows.get(row_idx) {
if let Some(element) = row.get(col_idx) {
diagonal.push(element.clone());
if let Some(sub) = col_idx.checked_sub(1) {
col_idx = sub;
} else {
break;
}
row_idx += 1;
} else {
break;
}
}
diagonal.reverse();
diagonal
}
pub fn get_diagonals_grave(&self) -> Vec<Vec<T>> {
let mut diagonals = Vec::new();
// col_idx == starting column of this diagonal
for col_idx in (0..self.width).rev() {
diagonals.push(self.get_diagonal_grave(col_idx, 0));
if col_idx == 0 {
// row_idx == starting row of this diagonal
for row_idx in 1..self.rows.len() as u32 {
diagonals.push(self.get_diagonal_grave(col_idx, row_idx));
}
}
}
diagonals
}
fn get_diagonal_grave(&self, starting_col: u32, starting_row: u32) -> Vec<T> {
if starting_col != 0 && starting_row != 0 {
panic!("Start of diagonal needs to be valid. Start at top row or leftmost column");
}
// col_idx == current col_idx of this diagonal
let mut col_idx = starting_col as usize;
// row_idx == current row_idx of this diagonal
let mut row_idx = starting_row as usize;
let mut diagonal = Vec::new();
while let Some(row) = self.rows.get(row_idx) {
if let Some(element) = row.get(col_idx) {
diagonal.push(element.clone());
col_idx += 1;
row_idx += 1;
} else {
break;
}
}
diagonal
}
}
#[cfg(test)]
mod test {
use super::Grid;
#[test]
fn diag_aigu_4x4() {
let grid = Grid::new(vec![
vec!["a", "b", "c", "d"],
vec!["e", "f", "g", "h"],
vec!["i", "j", "k", "l"],
vec!["m", "n", "o", "p"],
])
.unwrap();
let res = vec![
vec!["a"],
vec!["e", "b"],
vec!["i", "f", "c"],
vec!["m", "j", "g", "d"],
vec!["n", "k", "h"],
vec!["o", "l"],
vec!["p"],
];
assert_eq!(res, grid.get_diagonals_aigu());
}
#[test]
fn diag_aigu_4x3() {
let grid = Grid::new(vec![
vec!["a", "b", "c", "d"],
vec!["e", "f", "g", "h"],
vec!["i", "j", "k", "l"],
])
.unwrap();
let res = vec![
vec!["a"],
vec!["e", "b"],
vec!["i", "f", "c"],
vec!["j", "g", "d"],
vec!["k", "h"],
vec!["l"],
];
assert_eq!(res, grid.get_diagonals_aigu());
}
#[test]
fn diag_aigu_3x4() {
let grid = Grid::new(vec![
vec!["a", "b", "c"],
vec!["d", "e", "f"],
vec!["g", "h", "i"],
vec!["j", "k", "l"],
])
.unwrap();
let res = vec![
vec!["a"],
vec!["d", "b"],
vec!["g", "e", "c"],
vec!["j", "h", "f"],
vec!["k", "i"],
vec!["l"],
];
assert_eq!(res, grid.get_diagonals_aigu());
}
#[test]
fn diag_grave_4x4() {
let grid = Grid::new(vec![
vec!["a", "b", "c", "d"],
vec!["e", "f", "g", "h"],
vec!["i", "j", "k", "l"],
vec!["m", "n", "o", "p"],
])
.unwrap();
let res = vec![
vec!["d"],
vec!["c", "h"],
vec!["b", "g", "l"],
vec!["a", "f", "k", "p"],
vec!["e", "j", "o"],
vec!["i", "n"],
vec!["m"],
];
assert_eq!(res, grid.get_diagonals_grave());
}
#[test]
fn diag_grave_4x3() {
let grid = Grid::new(vec![
vec!["a", "b", "c", "d"],
vec!["e", "f", "g", "h"],
vec!["i", "j", "k", "l"],
])
.unwrap();
let res = vec![
vec!["d"],
vec!["c", "h"],
vec!["b", "g", "l"],
vec!["a", "f", "k"],
vec!["e", "j"],
vec!["i"],
];
assert_eq!(res, grid.get_diagonals_grave());
}
#[test]
fn diag_grave_3x4() {
let grid = Grid::new(vec![
vec!["a", "b", "c"],
vec!["d", "e", "f"],
vec!["g", "h", "i"],
vec!["j", "k", "l"],
])
.unwrap();
let res = vec![
vec!["c"],
vec!["b", "f"],
vec!["a", "e", "i"],
vec!["d", "h", "l"],
vec!["g", "k"],
vec!["j"],
];
assert_eq!(res, grid.get_diagonals_grave());
}
#[test]
fn rotate() {
let mut grid = Grid::new(vec![vec!["a", "b"], vec!["c", "d"]]).unwrap();
let res = Grid::new(vec![vec!["a", "c"], vec!["b", "d"]]).unwrap();
assert_eq!(res, grid.rotate_90())
}
}

View File

@@ -4,3 +4,4 @@ pub mod grid;
pub mod math;
pub mod number;
pub mod permutation;
pub mod time;

View File

@@ -1,10 +1,13 @@
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};
mod add;
mod div;
mod from;
mod mul;
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 {
Positif,
Negatif,
@@ -12,7 +15,7 @@ pub enum Sign {
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Number {
pub digits: Vec<isize>,
pub digits: Vec<i8>,
pub sign: Sign,
}
@@ -23,88 +26,9 @@ impl Number {
(n % modulo) / divisor
}
pub const fn byte_to_digit(b: u8) -> isize {
pub const fn byte_to_digit(b: u8) -> i8 {
// 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,
};
}
(b as i8).wrapping_sub('0' as i8)
}
pub fn pow(self, n: u32) -> Self {
@@ -118,23 +42,27 @@ impl Number {
} else {
let number = self.clone();
for _i in 1..n {
result = result * number.clone();
result *= number.clone();
}
result
}
}
pub fn ten_pow(self, n: u32) -> Self {
Number {
digits: [vec![0; n as usize], self.digits].concat(),
sign: self.sign,
}
}
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")
let mut n = Number::from(1);
while n <= self {
fact *= n.clone();
n += 1.into();
}
fact
}
pub fn fib(n: u64) -> Self {
@@ -148,135 +76,11 @@ impl Number {
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(),
pub fn abs(self) -> Self {
Number {
digits: self.digits,
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 }
}
}
@@ -285,6 +89,7 @@ impl Display for Number {
let number_string = self
.digits
.iter()
.rev()
.map(|&digit| digit.to_string())
.collect::<Vec<String>>()
.join("");
@@ -295,194 +100,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)]
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
}
);
}
use crate::number::Number;
#[test]
fn test_get_digit() {
@@ -500,58 +120,26 @@ mod number_tests {
}
#[test]
fn test_cmp_eq_pos() {
let a = Number::from(1);
let b = Number::from(1);
assert_eq!(a, b);
fn test_pow() {
let num = Number::from(2);
assert_eq!(Number::from(16), num.pow(4));
}
#[test]
fn test_cmp_eq_neg() {
let a = Number::from(-1);
let b = Number::from(-1);
assert_eq!(a, b);
fn test_ten_pow_zero() {
let num = Number::from(2);
assert_eq!(Number::from(2), num.ten_pow(0));
}
#[test]
fn test_cmp_pos_neg() {
let a = Number::from(1);
let b = Number::from(-1);
assert!(a > b);
fn test_ten_pow_one() {
let num = Number::from(2);
assert_eq!(Number::from(20), num.ten_pow(1));
}
#[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);
fn test_ten_pow_two() {
let num = Number::from(2);
assert_eq!(Number::from(200), num.ten_pow(2));
}
}

215
src/number/add.rs Normal file
View File

@@ -0,0 +1,215 @@
use std::{
cmp::{min, Ordering},
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();
let ord = self.clone().abs().cmp(&rhs.clone().abs());
if self_len != rhs_len {
let difference = (self_len).abs_diff(rhs_len);
let pad = vec![0i8; 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 sign = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Positif, _) => Sign::Positif,
(Sign::Negatif, Sign::Negatif, _) => Sign::Negatif,
(Sign::Positif, Sign::Negatif, Ordering::Greater) => Sign::Positif,
(Sign::Positif, Sign::Negatif, Ordering::Less) => Sign::Negatif,
(Sign::Negatif, Sign::Positif, Ordering::Greater) => Sign::Negatif,
(Sign::Negatif, Sign::Positif, Ordering::Less) => Sign::Positif,
(Sign::Positif, Sign::Negatif, Ordering::Equal)
| (Sign::Negatif, Sign::Positif, Ordering::Equal) => Sign::Positif,
};
for (a, b) in zipped {
let comb = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Negatif, Ordering::Equal)
| (Sign::Negatif, Sign::Positif, Ordering::Equal) => {
digits.push(0);
break;
}
(Sign::Positif, Sign::Positif, _) | (Sign::Negatif, Sign::Negatif, _) => {
let comb = a + b + carry;
if comb > 9 {
carry = 1;
} else {
carry = 0;
}
comb % 10
}
(Sign::Positif, Sign::Negatif, Ordering::Greater)
| (Sign::Negatif, Sign::Positif, Ordering::Greater) => {
let comb = if b > &(a - carry) {
let comb = a + 10 - b - carry;
carry = 1;
comb
} else {
let comb = a - b - carry;
carry = 0;
comb
};
(comb % 10).abs()
}
(Sign::Positif, Sign::Negatif, Ordering::Less)
| (Sign::Negatif, Sign::Positif, Ordering::Less) => {
let comb = if a > &(b - carry) {
let comb = b + 10 - a - carry;
carry = 1;
comb
} else {
let comb = b - a - carry;
carry = 0;
comb
};
(comb % 10).abs()
}
};
digits.push(comb);
}
if carry != 0 {
digits.push(carry);
}
for &digit in digits.clone().iter().rev() {
if digit != 0 || digits.len() == 1 {
break;
}
digits.pop();
}
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_1() {
let a = Number::from(1);
let b = 1.into();
let res = Number::from(2);
assert_eq!(res, a + b);
}
#[test]
fn add_positif_2() {
let a = Number::from(9);
let b = 1.into();
let res = Number::from(10);
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_1() {
let a = Number::from(-1);
let b = (11).into();
let res = Number::from(10);
assert_eq!(res, a + b);
}
#[test]
fn add_larger_positif_to_negatif_2() {
let a = Number::from(-2);
let b = (11).into();
let res = Number::from(9);
assert_eq!(res, a + b);
}
#[test]
fn add_larger_negatif_to_positif_1() {
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_2() {
let a = Number::from(2);
let b = (-11).into();
let res = Number::from(-9);
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);
}
}

255
src/number/div.rs Normal file
View File

@@ -0,0 +1,255 @@
use core::panic;
use std::{
error::Error,
ops::{Div, DivAssign, Rem, RemAssign},
};
use super::{Number, Sign};
impl Number {
pub fn div_with_rem(
dividend: Number,
divisor: Number,
) -> Result<(Number, Number), Box<dyn Error>> {
if divisor == 0.into() {
return Err(Box::from("Division by 0"));
}
let dividend_len = dividend.digits.len();
let divisor_len = divisor.digits.len();
let sign = match (dividend.sign, divisor.sign) {
(Sign::Positif, Sign::Positif) | (Sign::Negatif, Sign::Negatif) => Sign::Positif,
(Sign::Positif, Sign::Negatif) | (Sign::Negatif, Sign::Positif) => Sign::Negatif,
};
let mut dividend = Number {
digits: dividend.digits,
sign: Sign::Positif,
};
let divisor = Number {
digits: divisor.digits,
sign: Sign::Positif,
};
match (sign, dividend.cmp(&divisor)) {
(_, std::cmp::Ordering::Less) => return Ok((Number::from(0), dividend)),
(Sign::Positif, std::cmp::Ordering::Equal) => {
return Ok((Number::from(1), Number::from(0)))
}
(Sign::Negatif, std::cmp::Ordering::Equal) => {
return Ok((Number::from(-1), Number::from(0)))
}
(_, std::cmp::Ordering::Greater) => (),
}
let mut quotient = vec![];
let mut remainder = Number {
digits: dividend
.digits
.drain((dividend_len - divisor_len)..)
.collect(),
sign: Sign::Positif,
};
loop {
while remainder < divisor && !dividend.digits.is_empty() {
remainder.digits.insert(0, dividend.digits.pop().unwrap());
quotient.push(0);
}
let mut factor = 0;
loop {
if remainder.digits.iter().max().unwrap() == &0 {
quotient.push(0);
break;
}
let temp_remainder = remainder.clone() - divisor.clone();
if temp_remainder.sign == Sign::Negatif {
quotient.push(factor);
break;
}
factor += 1;
if temp_remainder == 0.into() {
remainder = temp_remainder;
quotient.push(factor);
break;
}
remainder = temp_remainder;
}
if dividend.digits.is_empty() {
break;
}
remainder.digits.insert(0, dividend.digits.pop().unwrap());
}
for digit in quotient.clone() {
if digit != 0 || quotient.len() == 1 {
break;
}
quotient.remove(0);
}
quotient.reverse();
let res = Number {
digits: quotient,
sign,
};
let mut rem_digits = remainder.clone().digits;
rem_digits.reverse();
for digit in rem_digits {
if digit != 0 || remainder.digits.len() == 1 {
break;
}
remainder.digits.pop();
}
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}"),
}
}
}
#[cfg(test)]
mod test_number_div_rem {
use core::panic;
use crate::number::Number;
#[test]
fn zero_denominator() {
let a = Number::from(9);
let b = Number::from(0);
if Number::div_with_rem(a, b).is_ok() {
panic!("Division by 0 not allowed");
}
}
#[test]
fn div_rem_positif() {
let a = Number::from(9);
let b = Number::from(9);
let res = (Number::from(1), Number::from(0));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_negatif() {
let a = Number::from(-9);
let b = Number::from(-9);
let res = (Number::from(1), Number::from(0));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_positif_with_negatif() {
let a = Number::from(9);
let b = Number::from(-9);
let res = (Number::from(-1), Number::from(0));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_negatif_with_positif() {
let a = Number::from(-9);
let b = Number::from(9);
let res = (Number::from(-1), Number::from(0));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_eleven_x_ten() {
let a = Number::from(11);
let b = Number::from(10);
let res = (Number::from(1), Number::from(1));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_eleven_x_eleven() {
let a = Number::from(11);
let b = Number::from(11);
let res = (Number::from(1), Number::from(0));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_ten_x_eleven() {
let a = Number::from(10);
let b = Number::from(11);
let res = (Number::from(0), Number::from(10));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_big_1() {
let a = Number::from("123");
let b = Number::from("32");
let res = (Number::from(3), Number::from(27));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_big_2() {
let a = Number::from("123456789");
let b = Number::from("123");
let res = (Number::from(1003713), Number::from(90));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_big_3() {
let a = Number::from("1010101010");
let b = Number::from("1010");
let res = (Number::from(1000100), Number::from(10));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
#[test]
fn div_rem_small() {
let a = Number::from(10);
let b = Number::from(1);
let res = (Number::from(10), Number::from(0));
assert_eq!(res, Number::div_with_rem(a, b).unwrap());
}
}

111
src/number/from.rs Normal file
View 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 as isize).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) as i8;
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
}
);
}
}

149
src/number/mul.rs Normal file
View File

@@ -0,0 +1,149 @@
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 {
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,
};
let mut digits = Vec::new();
for (zeroes, rdigit) in rhs.digits.iter().enumerate() {
for (idx, ldigit) in self.digits.iter().enumerate() {
let mult = rdigit * ldigit;
let new = mult % 10;
let mut carry = mult / 10;
if let Some(old) = digits.get(zeroes + idx) {
let add = old + new;
digits[zeroes + idx] = add % 10;
carry += add / 10;
} else {
digits.push(new);
}
let mut carry_idx = 1;
loop {
if carry == 0 {
break;
}
if let Some(old) = digits.get(zeroes + idx + carry_idx) {
let add = old + carry;
digits[zeroes + idx + carry_idx] = add % 10;
carry = add / 10;
} else {
digits.push(carry % 10);
carry /= 10;
}
carry_idx += 1;
}
}
}
Number { digits, sign }
}
}
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_999_x_999() {
let a = Number::from(999);
let b = Number::from(999);
let res = Number::from(998001);
assert_eq!(res, a * b);
}
#[test]
fn mul_big_1() {
let a = Number::from("123");
let b = Number::from("321");
let res = Number::from("39483");
assert_eq!(res, a * b);
}
#[test]
fn mul_big_2() {
let a = Number::from("123456789");
let b = Number::from("987654321");
let res = Number::from("121932631112635269");
assert_eq!(res, a * b);
}
}

124
src/number/ord.rs Normal file
View File

@@ -0,0 +1,124 @@
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).rev() {
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 std::cmp::Ordering;
use crate::number::Number;
#[test]
fn test_cmp_eq_pos() {
let a = Number::from(1);
let b = Number::from(1);
assert_eq!(a, b);
assert_eq!(Ordering::Equal, a.cmp(&b));
}
#[test]
fn test_cmp_eq_neg() {
let a = Number::from(-1);
let b = Number::from(-1);
assert_eq!(a, b);
assert_eq!(Ordering::Equal, a.cmp(&b));
}
#[test]
fn test_cmp_pos_neg() {
let a = Number::from(1);
let b = Number::from(-1);
assert!(a > b);
assert_eq!(Ordering::Greater, a.cmp(&b));
}
#[test]
fn test_cmp_neg_pos() {
let a = Number::from(-1);
let b = Number::from(1);
assert!(a < b);
assert_eq!(Ordering::Less, a.cmp(&b));
}
#[test]
fn test_cmp_short_neg() {
let a = Number::from(-1);
let b = Number::from(-10);
assert!(a > b);
assert_eq!(Ordering::Greater, a.cmp(&b));
}
#[test]
fn test_cmp_short_pos() {
let a = Number::from(1);
let b = Number::from(10);
assert!(a < b);
assert_eq!(Ordering::Less, a.cmp(&b));
}
#[test]
fn test_cmp_long_neg() {
let a = Number::from(-10);
let b = Number::from(-1);
assert!(a < b);
assert_eq!(Ordering::Less, a.cmp(&b));
}
#[test]
fn test_cmp_long_pos() {
let a = Number::from(10);
let b = Number::from(1);
assert!(a > b);
assert_eq!(Ordering::Greater, a.cmp(&b));
}
#[test]
fn test_cmp_91_32() {
let a = Number::from(91);
let b = Number::from(32);
assert!(a > b);
assert_eq!(Ordering::Greater, a.cmp(&b));
}
}

216
src/number/sub.rs Normal file
View File

@@ -0,0 +1,216 @@
use std::{
cmp::{min, Ordering},
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();
let ord = self.clone().abs().cmp(&rhs.clone().abs());
if self_len != rhs_len {
let difference = (self_len).abs_diff(rhs_len);
let pad = vec![0i8; 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 sign = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Negatif, _) => Sign::Positif,
(Sign::Negatif, Sign::Positif, _) => Sign::Negatif,
(Sign::Positif, Sign::Positif, Ordering::Greater) => Sign::Positif,
(Sign::Positif, Sign::Positif, Ordering::Less) => Sign::Negatif,
(Sign::Negatif, Sign::Negatif, Ordering::Greater) => Sign::Negatif,
(Sign::Negatif, Sign::Negatif, Ordering::Less) => Sign::Positif,
(Sign::Positif, Sign::Positif, Ordering::Equal)
| (Sign::Negatif, Sign::Negatif, Ordering::Equal) => Sign::Positif,
};
for (a, b) in zipped {
let comb = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Positif, Ordering::Equal)
| (Sign::Negatif, Sign::Negatif, Ordering::Equal) => {
digits.push(0);
break;
}
(Sign::Positif, Sign::Negatif, _) | (Sign::Negatif, Sign::Positif, _) => {
let comb = a + b + carry;
if comb > 9 {
carry = 1;
} else {
carry = 0;
}
comb % 10
}
(Sign::Positif, Sign::Positif, Ordering::Greater)
| (Sign::Negatif, Sign::Negatif, Ordering::Greater) => {
let comb = if b > &(a - carry) {
let comb = a + 10 - b - carry;
carry = 1;
comb
} else {
let comb = a - b - carry;
carry = 0;
comb
};
(comb % 10).abs()
}
(Sign::Positif, Sign::Positif, Ordering::Less)
| (Sign::Negatif, Sign::Negatif, Ordering::Less) => {
let comb = if a > &(b - carry) {
let comb = b + 10 - a - carry;
carry = 1;
comb
} else {
let comb = b - a - carry;
carry = 0;
comb
};
(comb % 10).abs()
}
};
digits.push(comb);
}
if carry != 0 {
digits.push(carry);
}
for &digit in digits.clone().iter().rev() {
if digit != 0 || digits.len() == 1 {
break;
}
digits.pop();
}
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_larger_positif_from_positif_1() {
let a = Number::from(1);
let b = (11).into();
let res = Number::from(-10);
assert_eq!(res, a - b);
}
#[test]
fn sub_larger_positif_from_positif_2() {
let a = Number::from(2);
let b = (11).into();
let res = Number::from(-9);
assert_eq!(res, a - b);
}
#[test]
fn sub_positif_from_larger_positif_1() {
let a = Number::from(11);
let b = (1).into();
let res = Number::from(10);
assert_eq!(res, a - b);
}
#[test]
fn sub_positif_from_larger_positif_2() {
let a = Number::from(11);
let b = (2).into();
let res = Number::from(9);
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);
}
#[test]
fn sub_91_32() {
let a = Number::from(91);
let b = (32).into();
let res = Number::from(59);
assert_eq!(res, a - b);
}
}

View File

@@ -1,9 +1,11 @@
use std::error::Error;
fn factorial(num: usize) -> usize {
let mut fact = 1;
use crate::number::Number;
fn factorial(num: usize) -> Number {
let mut fact = Number::from(1);
for n in 1..=num {
fact *= n;
fact *= Number::from(n as isize);
}
fact
}
@@ -25,59 +27,102 @@ pub fn nth_lex<T: Clone + Ord>(mut digits: Vec<T>, nth: usize) -> Result<Vec<T>,
if nth == 1 {
return Ok(digits);
}
if nth > factorial(digits.len()) || nth == 0 {
let nth = Number::from(nth as isize);
if nth > factorial(digits.len()) || nth == Number::from(0) {
return Err(Box::from("Out of bounds"));
}
let mut perm = Vec::new();
let num_unique_digits = digits.len();
let mut remainder = nth - 1;
let mut remainder = nth - 1.into();
for idx in 1..=digits.len() {
let permutations = remainder / factorial(num_unique_digits - idx);
let permutations = remainder.clone() / factorial(num_unique_digits - idx);
remainder %= factorial(num_unique_digits - idx);
perm.push(digits[permutations].clone());
digits.remove(permutations);
let permutations: isize = permutations.try_into().unwrap();
perm.push(digits[permutations as usize].clone());
digits.remove(permutations as usize);
}
Ok(perm)
}
#[derive(Clone)]
pub struct Permutator<T: Clone + Ord> {
pub current: Vec<T>,
pub elements: Vec<T>,
idx: usize,
}
impl<T: Clone + Ord> Permutator<T> {
pub fn new(elements: Vec<T>) -> Self {
Self {
current: elements,
idx: 0,
}
Self { elements, idx: 0 }
}
}
impl<T: Clone + Ord> Iterator for Permutator<T> {
impl<T: Clone + Ord + std::fmt::Display> Iterator for Permutator<T> {
type Item = Vec<T>;
/// Returns the next permutation and changes the current permutation to it
/// This operation wraps around
fn next(&mut self) -> Option<Self::Item> {
if self.current.is_empty() {
if self.elements.is_empty() {
return None;
}
let mut digits = self.current.clone();
if self.idx == factorial(digits.len()) {
if self.idx == 0 {
self.idx += 1;
return Some(self.elements.clone());
}
let num_unique_elements = self.elements.len();
if Number::from(self.idx as isize) == factorial(num_unique_elements) {
return None;
}
let mut elements = self.elements.clone();
let mut perm = Vec::new();
let num_unique_digits = digits.len();
let mut remainder = 1;
for idx in 1..=digits.len() {
let permutations = remainder / factorial(num_unique_digits - idx);
remainder %= factorial(num_unique_digits - idx);
perm.push(digits[permutations].clone());
digits.remove(permutations);
let mut remainder = Number::from(self.idx as isize);
for idx in 1..=num_unique_elements {
let permutations = remainder.clone() / factorial(num_unique_elements - idx);
remainder %= factorial(num_unique_elements - idx);
let permutations: isize = permutations.try_into().unwrap();
perm.push(elements.remove(permutations as usize));
}
self.idx += 1;
self.current = digits;
Some(self.current.clone())
Some(perm)
}
}
#[cfg(test)]
mod test {
use crate::permutation::{nth_lex, Permutator};
const SMALL: [i8; 3] = [1, 2, 3];
// Nth Lex
#[test]
fn nth_lex_zero_small() {
let small = SMALL.to_vec();
assert!(nth_lex(small, 0).is_err());
}
#[test]
fn nth_lex_small() {
let small = SMALL.to_vec();
assert_eq!(nth_lex(small.clone(), 1).unwrap(), vec![1, 2, 3]);
assert_eq!(nth_lex(small.clone(), 2).unwrap(), vec![1, 3, 2]);
assert_eq!(nth_lex(small.clone(), 3).unwrap(), vec![2, 1, 3]);
assert_eq!(nth_lex(small.clone(), 4).unwrap(), vec![2, 3, 1]);
assert_eq!(nth_lex(small.clone(), 5).unwrap(), vec![3, 1, 2]);
assert_eq!(nth_lex(small.clone(), 6).unwrap(), vec![3, 2, 1]);
assert!(nth_lex(small.clone(), 7).is_err());
}
// Permutator
#[test]
fn perm_small() {
let small = SMALL.to_vec();
let mut comb = Permutator::new(small);
assert_eq!(comb.next(), Some(vec![1, 2, 3]));
assert_eq!(comb.next(), Some(vec![1, 3, 2]));
assert_eq!(comb.next(), Some(vec![2, 1, 3]));
assert_eq!(comb.next(), Some(vec![2, 3, 1]));
assert_eq!(comb.next(), Some(vec![3, 1, 2]));
assert_eq!(comb.next(), Some(vec![3, 2, 1]));
assert_eq!(comb.next(), None);
}
}

27
src/time.rs Normal file
View File

@@ -0,0 +1,27 @@
use std::time::Duration;
pub fn get_elapsed_string(duration: Duration) -> String {
let total_microseconds = duration.as_micros();
let total_milliseconds = duration.as_millis();
let seconds = duration.as_secs() % 60;
let minutes = (duration.as_secs() / 60) % 60;
let milliseconds = total_milliseconds % 1000;
let microseconds = total_microseconds % 1_000;
let mut parts = vec![];
if minutes > 0 {
parts.push(format!("{}m", minutes));
}
if seconds > 0 {
parts.push(format!("{}s", seconds));
}
if milliseconds > 0 {
parts.push(format!("{}ms", milliseconds));
}
if microseconds > 0 {
parts.push(format!("{}µs", microseconds));
}
parts.join(" ")
}