Compare commits
	
		
			12 Commits
		
	
	
		
			23a96d5bee
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8e297a3e84 | |||
| bfbdb6a20e | |||
| 87b4b49dad | |||
| e293fb90d3 | |||
| cc626a6d85 | |||
| 19b2434789 | |||
| 9f10cee3e0 | |||
| 1e0f6fd077 | |||
| cad2d2b910 | |||
| 50b2aa8932 | |||
| ed886762d0 | |||
| 2ec7e6c296 | 
| @@ -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()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,7 @@ pub struct Rational { | ||||
| } | ||||
|  | ||||
| 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")); | ||||
|         } | ||||
| @@ -33,6 +33,8 @@ impl Fraction { | ||||
|                 Sign::Negatif => Sign::Positif, | ||||
|             }, | ||||
|         }; | ||||
|         numerator.sign = Sign::Positif; | ||||
|         denominator.sign = Sign::Positif; | ||||
|         let mut f = Fraction { | ||||
|             numerator, | ||||
|             denominator, | ||||
|   | ||||
							
								
								
									
										244
									
								
								src/grid.rs
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								src/grid.rs
									
									
									
									
									
								
							| @@ -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()) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,3 +4,4 @@ pub mod grid; | ||||
| pub mod math; | ||||
| pub mod number; | ||||
| pub mod permutation; | ||||
| pub mod time; | ||||
|   | ||||
| @@ -15,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, | ||||
| } | ||||
|  | ||||
| @@ -26,9 +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) | ||||
|         (b as i8).wrapping_sub('0' as i8) | ||||
|     } | ||||
|  | ||||
|     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 { | ||||
|         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 { | ||||
| @@ -71,6 +75,13 @@ impl Number { | ||||
|  | ||||
|         last_two.0 | ||||
|     } | ||||
|  | ||||
|     pub fn abs(self) -> Self { | ||||
|         Number { | ||||
|             digits: self.digits, | ||||
|             sign: Sign::Positif, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Display for Number { | ||||
| @@ -107,4 +118,28 @@ mod number_tests { | ||||
|         assert_eq!(digit_4, 2); | ||||
|         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)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use std::{ | ||||
|     cmp::min, | ||||
|     cmp::{min, Ordering}, | ||||
|     iter::zip, | ||||
|     ops::{Add, AddAssign}, | ||||
| }; | ||||
| @@ -14,9 +14,10 @@ impl Add for Number { | ||||
|         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![0isize; difference]; | ||||
|             let pad = vec![0i8; difference]; | ||||
|             if min(self_len, rhs_len) == self_len { | ||||
|                 self_digits = [self.digits, pad].concat(); | ||||
|             } else { | ||||
| @@ -26,14 +27,24 @@ impl Add for Number { | ||||
|         let zipped = zip(self_digits.iter(), rhs_digits.iter()); | ||||
|         let mut carry = 0; | ||||
|         let mut digits = Vec::new(); | ||||
|         let mut sign = match (self.sign, rhs.sign) { | ||||
|             (Sign::Positif, Sign::Positif) => Sign::Positif, | ||||
|             (Sign::Negatif, Sign::Negatif) => Sign::Negatif, | ||||
|             (Sign::Positif, Sign::Negatif) | (Sign::Negatif, Sign::Positif) => Sign::Positif, | ||||
|         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) { | ||||
|                 (Sign::Positif, Sign::Positif) => { | ||||
|             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; | ||||
| @@ -42,43 +53,32 @@ impl Add for Number { | ||||
|                     } | ||||
|                     comb % 10 | ||||
|                 } | ||||
|                 (Sign::Positif, Sign::Negatif) => { | ||||
|                     let comb = a - b - carry; | ||||
|                     if comb > 0 && b > a { | ||||
|                 (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; | ||||
|                     } | ||||
|                     if b > a { | ||||
|                         sign = Sign::Negatif; | ||||
|                     } else { | ||||
|                         sign = Sign::Positif; | ||||
|                     } | ||||
|                         comb | ||||
|                     }; | ||||
|                     (comb % 10).abs() | ||||
|                 } | ||||
|                 (Sign::Negatif, Sign::Positif) => { | ||||
|                     let comb = -a + b - carry; | ||||
|                     if comb > 0 && a > b { | ||||
|                 (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; | ||||
|                     } | ||||
|                     if a > b { | ||||
|                         sign = Sign::Negatif; | ||||
|                     } else { | ||||
|                         sign = Sign::Positif; | ||||
|                     } | ||||
|                         comb | ||||
|                     }; | ||||
|                     (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); | ||||
|         } | ||||
| @@ -87,6 +87,13 @@ impl Add for Number { | ||||
|             digits.push(carry); | ||||
|         } | ||||
|  | ||||
|         for &digit in digits.clone().iter().rev() { | ||||
|             if digit != 0 || digits.len() == 1 { | ||||
|                 break; | ||||
|             } | ||||
|             digits.pop(); | ||||
|         } | ||||
|  | ||||
|         Self { digits, sign } | ||||
|     } | ||||
| } | ||||
| @@ -104,13 +111,21 @@ mod test_number_add { | ||||
|     use crate::number::Number; | ||||
|  | ||||
|     #[test] | ||||
|     fn add_positif() { | ||||
|     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); | ||||
| @@ -152,21 +167,36 @@ mod test_number_add { | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn add_larger_positif_to_negatif() { | ||||
|     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() { | ||||
|     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); | ||||
|   | ||||
| @@ -7,54 +7,93 @@ use std::{ | ||||
| use super::{Number, Sign}; | ||||
|  | ||||
| impl Number { | ||||
|     pub fn div_with_rem(n1: Number, n2: Number) -> Result<(Number, Number), Box<dyn Error>> { | ||||
|         if n2 == 0.into() { | ||||
|     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 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(), | ||||
|         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 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 { | ||||
|             while remainder < divisor && !dividend.digits.is_empty() { | ||||
|                 remainder.digits.insert(0, dividend.digits.pop().unwrap()); | ||||
|                 quotient.push(0); | ||||
|             } | ||||
|             let mut factor = 0; | ||||
|             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 { | ||||
|                     quotient.push(factor); | ||||
|                     break; | ||||
|                 } | ||||
|                 remainder = temp_remainder; | ||||
|                 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; | ||||
|             } | ||||
|             remainder.digits.push(n1.digits[n2_len + iteration - 1]); | ||||
|             iteration += 1; | ||||
|             remainder.digits.insert(0, dividend.digits.pop().unwrap()); | ||||
|         } | ||||
|         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, | ||||
|             sign: Sign::Positif, | ||||
|             sign, | ||||
|         }; | ||||
|         for digit in res.clone().digits { | ||||
|             if digit != 0 || res.digits.len() == 1 { | ||||
|                 break; | ||||
|             } | ||||
|             res.digits.remove(0); | ||||
|         } | ||||
|         for digit in remainder.clone().digits { | ||||
|         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.remove(0); | ||||
|             remainder.digits.pop(); | ||||
|         } | ||||
|         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()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ impl TryFrom<Number> for isize { | ||||
|     fn try_from(value: Number) -> Result<Self, Self::Error> { | ||||
|         let mut num = 0; | ||||
|         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() { | ||||
|                 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 mut digits = vec![]; | ||||
|         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); | ||||
|         } | ||||
|         let digits = digits.to_vec(); | ||||
|   | ||||
| @@ -7,42 +7,43 @@ impl Mul for Number { | ||||
|  | ||||
|     #[allow(clippy::suspicious_arithmetic_impl)] | ||||
|     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) { | ||||
|             (Sign::Positif, Sign::Positif) => Sign::Positif, | ||||
|             (Sign::Positif, Sign::Negatif) => Sign::Negatif, | ||||
|             (Sign::Negatif, Sign::Positif) => Sign::Negatif, | ||||
|             (Sign::Negatif, Sign::Negatif) => Sign::Positif, | ||||
|         }; | ||||
|         for (idx, rdigit) in rhs.digits.iter().enumerate() { | ||||
|             let rdigit = rdigit * 10_isize.pow(idx as u32); | ||||
|             let mult_vec: Vec<isize> = self.digits.iter().map(|ldigit| ldigit * rdigit).collect(); | ||||
|             let mut normalized_mult_vec = Vec::new(); | ||||
|             let mut carry = 0; | ||||
|             let mut add_zero = true; | ||||
|             mult_vec.into_iter().for_each(|digit| { | ||||
|                 let digit = digit + carry; | ||||
|                 if digit > 9 { | ||||
|                     carry = digit % 10; | ||||
|                     normalized_mult_vec.insert(0, digit / 10); | ||||
|         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 { | ||||
|                     normalized_mult_vec.insert(0, digit); | ||||
|                     carry = 0; | ||||
|                     add_zero = false; | ||||
|                     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; | ||||
|                 } | ||||
|             }); | ||||
|             if carry != 0 || add_zero { | ||||
|                 normalized_mult_vec.insert(0, carry); | ||||
|             } | ||||
|             mult_vecs.push(Number { | ||||
|                 digits: normalized_mult_vec, | ||||
|                 sign, | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         mult_vecs.into_iter().reduce(|acc, num| acc + num).unwrap() | ||||
|         Number { digits, sign } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -123,7 +124,23 @@ mod test_number_mul { | ||||
|     } | ||||
|  | ||||
|     #[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 b = Number::from("987654321"); | ||||
|         let res = Number::from("121932631112635269"); | ||||
|   | ||||
| @@ -25,7 +25,7 @@ impl Ord for Number { | ||||
|                 Sign::Negatif => Ordering::Less, | ||||
|             }, | ||||
|             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) { | ||||
|                         Ordering::Less => match self.sign { | ||||
|                             Sign::Positif => Ordering::Less, | ||||
| @@ -46,6 +46,8 @@ impl Ord for Number { | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod test_number_ord { | ||||
|     use std::cmp::Ordering; | ||||
|  | ||||
|     use crate::number::Number; | ||||
|  | ||||
|     #[test] | ||||
| @@ -53,6 +55,7 @@ mod test_number_ord { | ||||
|         let a = Number::from(1); | ||||
|         let b = Number::from(1); | ||||
|         assert_eq!(a, b); | ||||
|         assert_eq!(Ordering::Equal, a.cmp(&b)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -60,6 +63,7 @@ mod test_number_ord { | ||||
|         let a = Number::from(-1); | ||||
|         let b = Number::from(-1); | ||||
|         assert_eq!(a, b); | ||||
|         assert_eq!(Ordering::Equal, a.cmp(&b)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -67,6 +71,7 @@ mod test_number_ord { | ||||
|         let a = Number::from(1); | ||||
|         let b = Number::from(-1); | ||||
|         assert!(a > b); | ||||
|         assert_eq!(Ordering::Greater, a.cmp(&b)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -74,6 +79,7 @@ mod test_number_ord { | ||||
|         let a = Number::from(-1); | ||||
|         let b = Number::from(1); | ||||
|         assert!(a < b); | ||||
|         assert_eq!(Ordering::Less, a.cmp(&b)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -81,6 +87,7 @@ mod test_number_ord { | ||||
|         let a = Number::from(-1); | ||||
|         let b = Number::from(-10); | ||||
|         assert!(a > b); | ||||
|         assert_eq!(Ordering::Greater, a.cmp(&b)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -88,6 +95,7 @@ mod test_number_ord { | ||||
|         let a = Number::from(1); | ||||
|         let b = Number::from(10); | ||||
|         assert!(a < b); | ||||
|         assert_eq!(Ordering::Less, a.cmp(&b)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -95,6 +103,7 @@ mod test_number_ord { | ||||
|         let a = Number::from(-10); | ||||
|         let b = Number::from(-1); | ||||
|         assert!(a < b); | ||||
|         assert_eq!(Ordering::Less, a.cmp(&b)); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -102,5 +111,14 @@ mod test_number_ord { | ||||
|         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)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| use std::{ | ||||
|     cmp::min, | ||||
|     cmp::{min, Ordering}, | ||||
|     iter::zip, | ||||
|     ops::{Sub, SubAssign}, | ||||
| }; | ||||
| @@ -14,9 +14,10 @@ impl Sub for Number { | ||||
|         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![0isize; difference]; | ||||
|             let pad = vec![0i8; difference]; | ||||
|             if min(self_len, rhs_len) == self_len { | ||||
|                 self_digits = [self.digits, pad].concat(); | ||||
|             } else { | ||||
| @@ -26,28 +27,24 @@ impl Sub for Number { | ||||
|         let zipped = zip(self_digits.iter(), rhs_digits.iter()); | ||||
|         let mut carry = 0; | ||||
|         let mut digits = Vec::new(); | ||||
|         let mut sign = match (self.sign, rhs.sign) { | ||||
|             (Sign::Positif, Sign::Negatif) => Sign::Positif, | ||||
|             (Sign::Negatif, Sign::Positif) => Sign::Negatif, | ||||
|             (Sign::Positif, Sign::Positif) | (Sign::Negatif, Sign::Negatif) => Sign::Positif, | ||||
|         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) { | ||||
|                 (Sign::Positif, Sign::Positif) => { | ||||
|                     let comb = a - b - carry; | ||||
|                     if comb < 0 { | ||||
|                         carry = 1; | ||||
|                     } else { | ||||
|                         carry = 0; | ||||
|                     } | ||||
|                     if b > a { | ||||
|                         sign = Sign::Negatif; | ||||
|                     } else { | ||||
|                         sign = Sign::Positif; | ||||
|                     } | ||||
|                     (comb % 10).abs() | ||||
|             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::Positif, Sign::Negatif, _) | (Sign::Negatif, Sign::Positif, _) => { | ||||
|                     let comb = a + b + carry; | ||||
|                     if comb > 9 { | ||||
|                         carry = 1; | ||||
| @@ -56,36 +53,47 @@ impl Sub for Number { | ||||
|                     } | ||||
|                     comb % 10 | ||||
|                 } | ||||
|                 (Sign::Negatif, Sign::Positif) => { | ||||
|                     let comb = -a - b - carry; | ||||
|                     if comb < -9 { | ||||
|                 (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::Negatif, Sign::Negatif) => { | ||||
|                     let comb = -a + b + carry; | ||||
|                     if comb > 10 { | ||||
|                 (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; | ||||
|                     } | ||||
|                     if a > b { | ||||
|                         sign = Sign::Negatif; | ||||
|                     } else { | ||||
|                         sign = Sign::Positif; | ||||
|                     } | ||||
|                     comb % 10 | ||||
|                         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 } | ||||
|     } | ||||
| } | ||||
| @@ -150,6 +158,38 @@ mod test_number_sub { | ||||
|         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); | ||||
| @@ -165,4 +205,12 @@ mod test_number_sub { | ||||
|         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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										27
									
								
								src/time.rs
									
									
									
									
									
										Normal 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(" ") | ||||
| } | ||||
		Reference in New Issue
	
	Block a user