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