Compare commits

...

12 Commits

13 changed files with 912 additions and 184 deletions

View File

@@ -53,7 +53,7 @@ pub fn nth_lex<T: Clone + Ord>(
#[derive(Clone)] #[derive(Clone)]
pub struct Combinator<T: Clone + Ord> { pub struct Combinator<T: Clone + Ord> {
pub current: Vec<T>, pub elements: Vec<T>,
pub k: usize, pub k: usize,
idx: usize, idx: usize,
} }
@@ -64,7 +64,7 @@ impl<T: Clone + Ord> Combinator<T> {
return Err(Box::from("Out of bounds")); return Err(Box::from("Out of bounds"));
} }
Ok(Self { Ok(Self {
current: elements, elements,
k, k,
idx: 0, idx: 0,
}) })
@@ -75,7 +75,7 @@ impl<T: Clone + Ord> Iterator for Combinator<T> {
type Item = Vec<T>; type Item = Vec<T>;
fn next(&mut self) -> Option<Self::Item> { 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); let num_combinations = binomial(num_elements, self.k);
if self.idx == num_combinations { if self.idx == num_combinations {
return None; return None;
@@ -83,7 +83,7 @@ impl<T: Clone + Ord> Iterator for Combinator<T> {
let mut i = 0; let mut i = 0;
let mut remaining_k = self.k; let mut remaining_k = self.k;
let mut comb = Vec::new(); let mut comb = Vec::new();
let mut remainder = self.idx - 1; let mut remainder = self.idx;
while remaining_k > 0 { while remaining_k > 0 {
// Count the number of combinations that start with elements[i] // Count the number of combinations that start with elements[i]
// example with n = 5, k = 2 // 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); let count = binomial(num_elements - i - 1, remaining_k - 1);
if remainder < count { if remainder < count {
// If the nth combination is within the count, pick this element // 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; remaining_k -= 1;
} else { } else {
remainder -= count; remainder -= count;
@@ -102,7 +102,143 @@ impl<T: Clone + Ord> Iterator for Combinator<T> {
i += 1; i += 1;
} }
self.idx += 1; self.idx += 1;
self.current = comb; Some(comb)
Some(self.current.clone()) }
}
#[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

@@ -19,7 +19,7 @@ pub struct Rational {
} }
impl Fraction { 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() { if denominator == 0.into() {
return Err(Box::from("Division by 0")); return Err(Box::from("Division by 0"));
} }
@@ -33,6 +33,8 @@ impl Fraction {
Sign::Negatif => Sign::Positif, Sign::Negatif => Sign::Positif,
}, },
}; };
numerator.sign = Sign::Positif;
denominator.sign = Sign::Positif;
let mut f = Fraction { let mut f = Fraction {
numerator, numerator,
denominator, denominator,

View File

@@ -1,7 +1,11 @@
use core::panic;
use std::error::Error; use std::error::Error;
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub struct Grid<T: Clone>(pub Vec<Vec<T>>); pub struct Grid<T: Clone> {
pub rows: Vec<Vec<T>>,
pub width: u32,
}
impl<T: Clone> Grid<T> { impl<T: Clone> Grid<T> {
pub fn new(grid: Vec<Vec<T>>) -> Result<Self, Box<dyn Error>> { 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")); 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 { pub fn rotate_90(&mut self) -> Self {
let height = self.0.len(); let height = self.rows.len();
let width = self.0[0].len(); let width = self.rows[0].len();
let mut new_grid = Vec::with_capacity(width); let mut new_grid = Vec::with_capacity(width);
for col_idx in 0..width { for col_idx in 0..width {
let mut new_row = Vec::with_capacity(height); let mut new_row = Vec::with_capacity(height);
for row_idx in 0..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); new_grid.push(new_row);
} }
self.0 = new_grid; self.rows = new_grid;
Grid(self.0.clone()) 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 math;
pub mod number; pub mod number;
pub mod permutation; pub mod permutation;
pub mod time;

View File

@@ -15,7 +15,7 @@ pub enum Sign {
#[derive(Clone, Debug, Eq, PartialEq, Hash)] #[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Number { pub struct Number {
pub digits: Vec<isize>, pub digits: Vec<i8>,
pub sign: Sign, pub sign: Sign,
} }
@@ -26,9 +26,9 @@ impl Number {
(n % modulo) / divisor (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 // wrapping_sub('0' as u32) same as - 48 but less magical
(b as isize).wrapping_sub('0' as isize) (b as i8).wrapping_sub('0' as i8)
} }
pub fn pow(self, n: u32) -> Self { pub fn pow(self, n: u32) -> Self {
@@ -48,17 +48,21 @@ impl Number {
} }
} }
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 { pub fn fact(self) -> Self {
let mut fact = Number::from(1); let mut fact = Number::from(1);
if ((self.digits.len() * 8) as u32) < isize::BITS { let mut n = Number::from(1);
let max = isize::try_from(self).unwrap(); while n <= self {
for n in 1..=max { fact *= n.clone();
fact = fact * n; n += 1.into();
}
fact
} else {
panic!("starting number too big")
} }
fact
} }
pub fn fib(n: u64) -> Self { pub fn fib(n: u64) -> Self {
@@ -71,6 +75,13 @@ impl Number {
last_two.0 last_two.0
} }
pub fn abs(self) -> Self {
Number {
digits: self.digits,
sign: Sign::Positif,
}
}
} }
impl Display for Number { impl Display for Number {
@@ -107,4 +118,28 @@ mod number_tests {
assert_eq!(digit_4, 2); assert_eq!(digit_4, 2);
assert_eq!(digit_5, 1); assert_eq!(digit_5, 1);
} }
#[test]
fn test_pow() {
let num = Number::from(2);
assert_eq!(Number::from(16), num.pow(4));
}
#[test]
fn test_ten_pow_zero() {
let num = Number::from(2);
assert_eq!(Number::from(2), num.ten_pow(0));
}
#[test]
fn test_ten_pow_one() {
let num = Number::from(2);
assert_eq!(Number::from(20), num.ten_pow(1));
}
#[test]
fn test_ten_pow_two() {
let num = Number::from(2);
assert_eq!(Number::from(200), num.ten_pow(2));
}
} }

View File

@@ -1,5 +1,5 @@
use std::{ use std::{
cmp::min, cmp::{min, Ordering},
iter::zip, iter::zip,
ops::{Add, AddAssign}, ops::{Add, AddAssign},
}; };
@@ -14,9 +14,10 @@ impl Add for Number {
let rhs_len = rhs.digits.len(); let rhs_len = rhs.digits.len();
let mut self_digits = self.digits.clone(); let mut self_digits = self.digits.clone();
let mut rhs_digits = rhs.digits.clone(); let mut rhs_digits = rhs.digits.clone();
let ord = self.clone().abs().cmp(&rhs.clone().abs());
if self_len != rhs_len { if self_len != rhs_len {
let difference = (self_len).abs_diff(rhs_len); let difference = (self_len).abs_diff(rhs_len);
let pad = vec![0isize; difference]; let pad = vec![0i8; difference];
if min(self_len, rhs_len) == self_len { if min(self_len, rhs_len) == self_len {
self_digits = [self.digits, pad].concat(); self_digits = [self.digits, pad].concat();
} else { } else {
@@ -26,14 +27,24 @@ impl Add for Number {
let zipped = zip(self_digits.iter(), rhs_digits.iter()); let zipped = zip(self_digits.iter(), rhs_digits.iter());
let mut carry = 0; let mut carry = 0;
let mut digits = Vec::new(); let mut digits = Vec::new();
let mut sign = match (self.sign, rhs.sign) { let sign = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Positif) => Sign::Positif, (Sign::Positif, Sign::Positif, _) => Sign::Positif,
(Sign::Negatif, Sign::Negatif) => Sign::Negatif, (Sign::Negatif, Sign::Negatif, _) => Sign::Negatif,
(Sign::Positif, Sign::Negatif) | (Sign::Negatif, Sign::Positif) => Sign::Positif, (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 { for (a, b) in zipped {
let comb = match (self.sign, rhs.sign) { let comb = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Positif) => { (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; let comb = a + b + carry;
if comb > 9 { if comb > 9 {
carry = 1; carry = 1;
@@ -42,43 +53,32 @@ impl Add for Number {
} }
comb % 10 comb % 10
} }
(Sign::Positif, Sign::Negatif) => { (Sign::Positif, Sign::Negatif, Ordering::Greater)
let comb = a - b - carry; | (Sign::Negatif, Sign::Positif, Ordering::Greater) => {
if comb > 0 && b > a { let comb = if b > &(a - carry) {
let comb = a + 10 - b - carry;
carry = 1; carry = 1;
comb
} else { } else {
let comb = a - b - carry;
carry = 0; carry = 0;
} comb
if b > a { };
sign = Sign::Negatif;
} else {
sign = Sign::Positif;
}
(comb % 10).abs() (comb % 10).abs()
} }
(Sign::Negatif, Sign::Positif) => { (Sign::Positif, Sign::Negatif, Ordering::Less)
let comb = -a + b - carry; | (Sign::Negatif, Sign::Positif, Ordering::Less) => {
if comb > 0 && a > b { let comb = if a > &(b - carry) {
let comb = b + 10 - a - carry;
carry = 1; carry = 1;
comb
} else { } else {
let comb = b - a - carry;
carry = 0; carry = 0;
} comb
if a > b { };
sign = Sign::Negatif;
} else {
sign = Sign::Positif;
}
(comb % 10).abs() (comb % 10).abs()
} }
(Sign::Negatif, Sign::Negatif) => {
let comb = a + b + carry;
if comb > 9 {
carry = 1;
} else {
carry = 0;
}
comb % 10
}
}; };
digits.push(comb); digits.push(comb);
} }
@@ -87,6 +87,13 @@ impl Add for Number {
digits.push(carry); digits.push(carry);
} }
for &digit in digits.clone().iter().rev() {
if digit != 0 || digits.len() == 1 {
break;
}
digits.pop();
}
Self { digits, sign } Self { digits, sign }
} }
} }
@@ -104,13 +111,21 @@ mod test_number_add {
use crate::number::Number; use crate::number::Number;
#[test] #[test]
fn add_positif() { fn add_positif_1() {
let a = Number::from(1); let a = Number::from(1);
let b = 1.into(); let b = 1.into();
let res = Number::from(2); let res = Number::from(2);
assert_eq!(res, a + b); 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] #[test]
fn add_large_positif() { fn add_large_positif() {
let a = Number::from(9); let a = Number::from(9);
@@ -152,21 +167,36 @@ mod test_number_add {
} }
#[test] #[test]
fn add_larger_positif_to_negatif() { fn add_larger_positif_to_negatif_1() {
let a = Number::from(-1); let a = Number::from(-1);
let b = (11).into(); let b = (11).into();
let res = Number::from(10); let res = Number::from(10);
assert_eq!(res, a + b); 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] #[test]
fn add_larger_negatif_to_positif() { fn add_larger_negatif_to_positif_1() {
let a = Number::from(1); let a = Number::from(1);
let b = (-11).into(); let b = (-11).into();
let res = Number::from(-10); let res = Number::from(-10);
assert_eq!(res, a + b); 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] #[test]
fn add_positif_to_larger_negatif() { fn add_positif_to_larger_negatif() {
let a = Number::from(-99); let a = Number::from(-99);

View File

@@ -7,54 +7,93 @@ use std::{
use super::{Number, Sign}; use super::{Number, Sign};
impl Number { impl Number {
pub fn div_with_rem(n1: Number, n2: Number) -> Result<(Number, Number), Box<dyn Error>> { pub fn div_with_rem(
if n2 == 0.into() { dividend: Number,
divisor: Number,
) -> Result<(Number, Number), Box<dyn Error>> {
if divisor == 0.into() {
return Err(Box::from("Division by 0")); return Err(Box::from("Division by 0"));
} }
let n1_len = n1.digits.len(); let dividend_len = dividend.digits.len();
let n2_len = n2.digits.len(); let divisor_len = divisor.digits.len();
if n2_len > n1_len { let sign = match (dividend.sign, divisor.sign) {
return Ok((Number::from(0), n2)); (Sign::Positif, Sign::Positif) | (Sign::Negatif, Sign::Negatif) => Sign::Positif,
} (Sign::Positif, Sign::Negatif) | (Sign::Negatif, Sign::Positif) => Sign::Negatif,
let dividend = n1.digits[..n2_len].to_vec(); };
let mut quotient = vec![]; let mut dividend = Number {
let mut remainder = Number { digits: dividend.digits,
digits: dividend.clone(),
sign: Sign::Positif, sign: Sign::Positif,
}; };
let mut iteration = 1; 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 { loop {
while remainder < divisor && !dividend.digits.is_empty() {
remainder.digits.insert(0, dividend.digits.pop().unwrap());
quotient.push(0);
}
let mut factor = 0; let mut factor = 0;
loop { loop {
let temp_remainder = remainder.clone() - n2.clone(); if remainder.digits.iter().max().unwrap() == &0 {
quotient.push(0);
break;
}
let temp_remainder = remainder.clone() - divisor.clone();
if temp_remainder.sign == Sign::Negatif { if temp_remainder.sign == Sign::Negatif {
quotient.push(factor); quotient.push(factor);
break; break;
} }
remainder = temp_remainder;
factor += 1; factor += 1;
if temp_remainder == 0.into() {
remainder = temp_remainder;
quotient.push(factor);
break;
}
remainder = temp_remainder;
} }
if n1_len == n2_len + iteration - 1 { if dividend.digits.is_empty() {
break; break;
} }
remainder.digits.push(n1.digits[n2_len + iteration - 1]); remainder.digits.insert(0, dividend.digits.pop().unwrap());
iteration += 1;
} }
let mut res = Number { for digit in quotient.clone() {
if digit != 0 || quotient.len() == 1 {
break;
}
quotient.remove(0);
}
quotient.reverse();
let res = Number {
digits: quotient, digits: quotient,
sign: Sign::Positif, sign,
}; };
for digit in res.clone().digits { let mut rem_digits = remainder.clone().digits;
if digit != 0 || res.digits.len() == 1 { rem_digits.reverse();
break; for digit in rem_digits {
}
res.digits.remove(0);
}
for digit in remainder.clone().digits {
if digit != 0 || remainder.digits.len() == 1 { if digit != 0 || remainder.digits.len() == 1 {
break; break;
} }
remainder.digits.remove(0); remainder.digits.pop();
} }
Ok((res, remainder)) Ok((res, remainder))
} }
@@ -110,3 +149,107 @@ impl RemAssign for Number {
} }
} }
} }
#[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());
}
}

View File

@@ -8,7 +8,7 @@ impl TryFrom<Number> for isize {
fn try_from(value: Number) -> Result<Self, Self::Error> { fn try_from(value: Number) -> Result<Self, Self::Error> {
let mut num = 0; let mut num = 0;
for (pos, &digit) in value.digits.iter().enumerate() { for (pos, &digit) in value.digits.iter().enumerate() {
let mul = digit.checked_mul(10isize.pow(pos as u32)); let mul = (digit as isize).checked_mul(10isize.pow(pos as u32));
if mul.is_none() { if mul.is_none() {
return Err(Box::from("Cannot convert Number to isize. Too big.")); return Err(Box::from("Cannot convert Number to isize. Too big."));
} }
@@ -62,7 +62,7 @@ impl From<isize> for Number {
let num_len = (value as f64 + 1.0).log10().ceil() as usize; let num_len = (value as f64 + 1.0).log10().ceil() as usize;
let mut digits = vec![]; let mut digits = vec![];
for digit_idx in 0..num_len { for digit_idx in 0..num_len {
let digit = Self::get_digit(value, digit_idx); let digit = Self::get_digit(value, digit_idx) as i8;
digits.push(digit); digits.push(digit);
} }
let digits = digits.to_vec(); let digits = digits.to_vec();

View File

@@ -7,42 +7,43 @@ impl Mul for Number {
#[allow(clippy::suspicious_arithmetic_impl)] #[allow(clippy::suspicious_arithmetic_impl)]
fn mul(self, rhs: Self) -> Self::Output { fn mul(self, rhs: Self) -> Self::Output {
println!("left {self:#?}");
println!("right {rhs:#?}");
let mut mult_vecs = Vec::new();
let sign = match (self.sign, rhs.sign) { let sign = match (self.sign, rhs.sign) {
(Sign::Positif, Sign::Positif) => Sign::Positif, (Sign::Positif, Sign::Positif) => Sign::Positif,
(Sign::Positif, Sign::Negatif) => Sign::Negatif, (Sign::Positif, Sign::Negatif) => Sign::Negatif,
(Sign::Negatif, Sign::Positif) => Sign::Negatif, (Sign::Negatif, Sign::Positif) => Sign::Negatif,
(Sign::Negatif, Sign::Negatif) => Sign::Positif, (Sign::Negatif, Sign::Negatif) => Sign::Positif,
}; };
for (idx, rdigit) in rhs.digits.iter().enumerate() { let mut digits = Vec::new();
let rdigit = rdigit * 10_isize.pow(idx as u32); for (zeroes, rdigit) in rhs.digits.iter().enumerate() {
let mult_vec: Vec<isize> = self.digits.iter().map(|ldigit| ldigit * rdigit).collect(); for (idx, ldigit) in self.digits.iter().enumerate() {
let mut normalized_mult_vec = Vec::new(); let mult = rdigit * ldigit;
let mut carry = 0; let new = mult % 10;
let mut add_zero = true; let mut carry = mult / 10;
mult_vec.into_iter().for_each(|digit| { if let Some(old) = digits.get(zeroes + idx) {
let digit = digit + carry; let add = old + new;
if digit > 9 { digits[zeroes + idx] = add % 10;
carry = digit % 10; carry += add / 10;
normalized_mult_vec.insert(0, digit / 10);
} else { } else {
normalized_mult_vec.insert(0, digit); digits.push(new);
carry = 0; }
add_zero = false; 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;
} }
});
if carry != 0 || add_zero {
normalized_mult_vec.insert(0, carry);
} }
mult_vecs.push(Number {
digits: normalized_mult_vec,
sign,
});
} }
Number { digits, sign }
mult_vecs.into_iter().reduce(|acc, num| acc + num).unwrap()
} }
} }
@@ -123,7 +124,23 @@ mod test_number_mul {
} }
#[test] #[test]
fn mul_big() { 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 a = Number::from("123456789");
let b = Number::from("987654321"); let b = Number::from("987654321");
let res = Number::from("121932631112635269"); let res = Number::from("121932631112635269");

View File

@@ -25,7 +25,7 @@ impl Ord for Number {
Sign::Negatif => Ordering::Less, Sign::Negatif => Ordering::Less,
}, },
Ordering::Equal => { Ordering::Equal => {
for pair in zip(&self.digits, &other.digits) { for pair in zip(&self.digits, &other.digits).rev() {
return match pair.0.cmp(pair.1) { return match pair.0.cmp(pair.1) {
Ordering::Less => match self.sign { Ordering::Less => match self.sign {
Sign::Positif => Ordering::Less, Sign::Positif => Ordering::Less,
@@ -46,6 +46,8 @@ impl Ord for Number {
#[cfg(test)] #[cfg(test)]
mod test_number_ord { mod test_number_ord {
use std::cmp::Ordering;
use crate::number::Number; use crate::number::Number;
#[test] #[test]
@@ -53,6 +55,7 @@ mod test_number_ord {
let a = Number::from(1); let a = Number::from(1);
let b = Number::from(1); let b = Number::from(1);
assert_eq!(a, b); assert_eq!(a, b);
assert_eq!(Ordering::Equal, a.cmp(&b));
} }
#[test] #[test]
@@ -60,6 +63,7 @@ mod test_number_ord {
let a = Number::from(-1); let a = Number::from(-1);
let b = Number::from(-1); let b = Number::from(-1);
assert_eq!(a, b); assert_eq!(a, b);
assert_eq!(Ordering::Equal, a.cmp(&b));
} }
#[test] #[test]
@@ -67,6 +71,7 @@ mod test_number_ord {
let a = Number::from(1); let a = Number::from(1);
let b = Number::from(-1); let b = Number::from(-1);
assert!(a > b); assert!(a > b);
assert_eq!(Ordering::Greater, a.cmp(&b));
} }
#[test] #[test]
@@ -74,6 +79,7 @@ mod test_number_ord {
let a = Number::from(-1); let a = Number::from(-1);
let b = Number::from(1); let b = Number::from(1);
assert!(a < b); assert!(a < b);
assert_eq!(Ordering::Less, a.cmp(&b));
} }
#[test] #[test]
@@ -81,6 +87,7 @@ mod test_number_ord {
let a = Number::from(-1); let a = Number::from(-1);
let b = Number::from(-10); let b = Number::from(-10);
assert!(a > b); assert!(a > b);
assert_eq!(Ordering::Greater, a.cmp(&b));
} }
#[test] #[test]
@@ -88,6 +95,7 @@ mod test_number_ord {
let a = Number::from(1); let a = Number::from(1);
let b = Number::from(10); let b = Number::from(10);
assert!(a < b); assert!(a < b);
assert_eq!(Ordering::Less, a.cmp(&b));
} }
#[test] #[test]
@@ -95,6 +103,7 @@ mod test_number_ord {
let a = Number::from(-10); let a = Number::from(-10);
let b = Number::from(-1); let b = Number::from(-1);
assert!(a < b); assert!(a < b);
assert_eq!(Ordering::Less, a.cmp(&b));
} }
#[test] #[test]
@@ -102,5 +111,14 @@ mod test_number_ord {
let a = Number::from(10); let a = Number::from(10);
let b = Number::from(1); let b = Number::from(1);
assert!(a > b); 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));
} }
} }

View File

@@ -1,5 +1,5 @@
use std::{ use std::{
cmp::min, cmp::{min, Ordering},
iter::zip, iter::zip,
ops::{Sub, SubAssign}, ops::{Sub, SubAssign},
}; };
@@ -14,9 +14,10 @@ impl Sub for Number {
let rhs_len = rhs.digits.len(); let rhs_len = rhs.digits.len();
let mut self_digits = self.digits.clone(); let mut self_digits = self.digits.clone();
let mut rhs_digits = rhs.digits.clone(); let mut rhs_digits = rhs.digits.clone();
let ord = self.clone().abs().cmp(&rhs.clone().abs());
if self_len != rhs_len { if self_len != rhs_len {
let difference = (self_len).abs_diff(rhs_len); let difference = (self_len).abs_diff(rhs_len);
let pad = vec![0isize; difference]; let pad = vec![0i8; difference];
if min(self_len, rhs_len) == self_len { if min(self_len, rhs_len) == self_len {
self_digits = [self.digits, pad].concat(); self_digits = [self.digits, pad].concat();
} else { } else {
@@ -26,28 +27,24 @@ impl Sub for Number {
let zipped = zip(self_digits.iter(), rhs_digits.iter()); let zipped = zip(self_digits.iter(), rhs_digits.iter());
let mut carry = 0; let mut carry = 0;
let mut digits = Vec::new(); let mut digits = Vec::new();
let mut sign = match (self.sign, rhs.sign) { let sign = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Negatif) => Sign::Positif, (Sign::Positif, Sign::Negatif, _) => Sign::Positif,
(Sign::Negatif, Sign::Positif) => Sign::Negatif, (Sign::Negatif, Sign::Positif, _) => Sign::Negatif,
(Sign::Positif, Sign::Positif) | (Sign::Negatif, Sign::Negatif) => Sign::Positif, (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 { for (a, b) in zipped {
let comb = match (self.sign, rhs.sign) { let comb = match (self.sign, rhs.sign, ord) {
(Sign::Positif, Sign::Positif) => { (Sign::Positif, Sign::Positif, Ordering::Equal)
let comb = a - b - carry; | (Sign::Negatif, Sign::Negatif, Ordering::Equal) => {
if comb < 0 { digits.push(0);
carry = 1; break;
} else {
carry = 0;
}
if b > a {
sign = Sign::Negatif;
} else {
sign = Sign::Positif;
}
(comb % 10).abs()
} }
(Sign::Positif, Sign::Negatif) => { (Sign::Positif, Sign::Negatif, _) | (Sign::Negatif, Sign::Positif, _) => {
let comb = a + b + carry; let comb = a + b + carry;
if comb > 9 { if comb > 9 {
carry = 1; carry = 1;
@@ -56,36 +53,47 @@ impl Sub for Number {
} }
comb % 10 comb % 10
} }
(Sign::Negatif, Sign::Positif) => { (Sign::Positif, Sign::Positif, Ordering::Greater)
let comb = -a - b - carry; | (Sign::Negatif, Sign::Negatif, Ordering::Greater) => {
if comb < -9 { let comb = if b > &(a - carry) {
let comb = a + 10 - b - carry;
carry = 1; carry = 1;
comb
} else { } else {
let comb = a - b - carry;
carry = 0; carry = 0;
} comb
};
(comb % 10).abs() (comb % 10).abs()
} }
(Sign::Negatif, Sign::Negatif) => { (Sign::Positif, Sign::Positif, Ordering::Less)
let comb = -a + b + carry; | (Sign::Negatif, Sign::Negatif, Ordering::Less) => {
if comb > 10 { let comb = if a > &(b - carry) {
let comb = b + 10 - a - carry;
carry = 1; carry = 1;
comb
} else { } else {
let comb = b - a - carry;
carry = 0; carry = 0;
} comb
if a > b { };
sign = Sign::Negatif; (comb % 10).abs()
} else {
sign = Sign::Positif;
}
comb % 10
} }
}; };
digits.push(comb); digits.push(comb);
} }
if carry != 0 { if carry != 0 {
digits.push(carry); digits.push(carry);
} }
for &digit in digits.clone().iter().rev() {
if digit != 0 || digits.len() == 1 {
break;
}
digits.pop();
}
Self { digits, sign } Self { digits, sign }
} }
} }
@@ -150,6 +158,38 @@ mod test_number_sub {
assert_eq!(res, a - b); 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] #[test]
fn sub_positif_from_larger_negatif() { fn sub_positif_from_larger_negatif() {
let a = Number::from(-99); let a = Number::from(-99);
@@ -165,4 +205,12 @@ mod test_number_sub {
let res = Number::from(110); let res = Number::from(110);
assert_eq!(res, a - b); 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; use std::error::Error;
fn factorial(num: usize) -> usize { use crate::number::Number;
let mut fact = 1;
fn factorial(num: usize) -> Number {
let mut fact = Number::from(1);
for n in 1..=num { for n in 1..=num {
fact *= n; fact *= Number::from(n as isize);
} }
fact fact
} }
@@ -25,59 +27,102 @@ pub fn nth_lex<T: Clone + Ord>(mut digits: Vec<T>, nth: usize) -> Result<Vec<T>,
if nth == 1 { if nth == 1 {
return Ok(digits); 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")); return Err(Box::from("Out of bounds"));
} }
let mut perm = Vec::new(); let mut perm = Vec::new();
let num_unique_digits = digits.len(); let num_unique_digits = digits.len();
let mut remainder = nth - 1; let mut remainder = nth - 1.into();
for idx in 1..=digits.len() { 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); remainder %= factorial(num_unique_digits - idx);
perm.push(digits[permutations].clone()); let permutations: isize = permutations.try_into().unwrap();
digits.remove(permutations); perm.push(digits[permutations as usize].clone());
digits.remove(permutations as usize);
} }
Ok(perm) Ok(perm)
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Permutator<T: Clone + Ord> { pub struct Permutator<T: Clone + Ord> {
pub current: Vec<T>, pub elements: Vec<T>,
idx: usize, idx: usize,
} }
impl<T: Clone + Ord> Permutator<T> { impl<T: Clone + Ord> Permutator<T> {
pub fn new(elements: Vec<T>) -> Self { pub fn new(elements: Vec<T>) -> Self {
Self { Self { elements, idx: 0 }
current: 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>; type Item = Vec<T>;
/// Returns the next permutation and changes the current permutation to it /// Returns the next permutation and changes the current permutation to it
/// This operation wraps around /// This operation wraps around
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.current.is_empty() { if self.elements.is_empty() {
return None; return None;
} }
let mut digits = self.current.clone(); if self.idx == 0 {
if self.idx == factorial(digits.len()) { 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; return None;
} }
let mut elements = self.elements.clone();
let mut perm = Vec::new(); let mut perm = Vec::new();
let num_unique_digits = digits.len(); let mut remainder = Number::from(self.idx as isize);
let mut remainder = 1; for idx in 1..=num_unique_elements {
for idx in 1..=digits.len() { let permutations = remainder.clone() / factorial(num_unique_elements - idx);
let permutations = remainder / factorial(num_unique_digits - idx); remainder %= factorial(num_unique_elements - idx);
remainder %= factorial(num_unique_digits - idx); let permutations: isize = permutations.try_into().unwrap();
perm.push(digits[permutations].clone()); perm.push(elements.remove(permutations as usize));
digits.remove(permutations);
} }
self.idx += 1; self.idx += 1;
self.current = digits; Some(perm)
Some(self.current.clone()) }
}
#[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(" ")
}