diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 38fc09fc..81554b74 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,9 +14,11 @@ license = "GPL-3.0" chrono = "0.4.38" itertools = "0.13.0" num-traits = "0.2.19" -rstest = "0.21.0" seq-macro = "0.3.5" +[dev-dependencies] +rstest = "0.21.0" + [target.'cfg(any(target_arch="wasm32",target_arch="wasm64"))'.dependencies] js-sys = "0.3" wasm-bindgen = "0.2" diff --git a/rust/src/include/factors.rs b/rust/src/include/factors.rs index b322d3ba..6896ec5e 100644 --- a/rust/src/include/factors.rs +++ b/rust/src/include/factors.rs @@ -8,6 +8,7 @@ use itertools::Itertools; use crate::include::primes::prime_factors; +#[derive(Clone, Debug)] pub struct ProperDivisors { seen: HashSet, diff --git a/rust/src/include/fibonacci.rs b/rust/src/include/fibonacci.rs index 0bdba578..5a033013 100644 --- a/rust/src/include/fibonacci.rs +++ b/rust/src/include/fibonacci.rs @@ -12,6 +12,7 @@ pub fn fib_by_3() -> impl Iterator where I: Copy + Zero + One + Add return cache_iterator(FibonacciBy3::::new()); } +#[derive(Clone, Copy, Debug, Hash)] pub struct Fibonacci { a: I, b: I, @@ -44,6 +45,7 @@ impl Iterator for Fibonacci where I: Zero + One + Add + Copy { } } +#[derive(Clone, Copy, Debug, Hash)] pub struct FibonacciBy3 { a: I, b: I, diff --git a/rust/src/include/iter_cache.rs b/rust/src/include/iter_cache.rs index c1c8d74c..75418726 100644 --- a/rust/src/include/iter_cache.rs +++ b/rust/src/include/iter_cache.rs @@ -14,6 +14,7 @@ where return CachingIterator::new(iterator); } +#[derive(Clone, Copy, Debug, Hash)] pub struct CachingIterator where I: Iterator + 'static, diff --git a/rust/src/include/math.rs b/rust/src/include/math.rs index 8e085cf2..e3a2c84a 100644 --- a/rust/src/include/math.rs +++ b/rust/src/include/math.rs @@ -1,8 +1,10 @@ use std::cmp::PartialOrd; +use std::fmt::Debug; use std::mem::size_of; use num_traits::NumAssign; use num_traits::one; +use num_traits::CheckedMul; const MAX_FACTORIAL: [u8; 16] = [ 5, // u8 @@ -23,7 +25,7 @@ where I: NumAssign + From } pub fn n_choose_r(n: usize, r: usize) -> I -where I: Copy + From + From + NumAssign + PartialOrd +where I: Copy + From + From + NumAssign + PartialOrd + CheckedMul + Debug { if n < r { panic!("Out of function's bounds"); @@ -33,7 +35,6 @@ where I: Copy + From + From + NumAssign + PartialOrd } // slow path for larger numbers let mut answer: I = one(); - let mut tmp: I; let mut factors: Vec = vec![1; n + 1]; factors[0] = 0; factors[1] = 0; @@ -59,17 +60,17 @@ where I: Copy + From + From + NumAssign + PartialOrd let mut j: usize = 2; while i <= n { while factors[i] > 0 { - tmp = answer; - answer *= (i as u64).into(); - while answer < tmp && j <= n { + let mut result = answer.checked_mul(&(i as u64).into()); + while result.is_none() && j <= n { while factors[j] < 0 { - tmp /= (j as u64).into(); + answer /= (j as u64).into(); factors[j] += 1; } j += 1; - answer = tmp * (i as u64).into(); + result = answer.checked_mul(&(i as u64).into()); } factors[i] -= 1; + answer = result.unwrap_or_else(|| panic!("nCr overflow: {:?} * {}", answer, i)); } i += 1; } diff --git a/rust/src/include/primes.rs b/rust/src/include/primes.rs index aae3bd49..03b1ff6d 100644 --- a/rust/src/include/primes.rs +++ b/rust/src/include/primes.rs @@ -7,6 +7,7 @@ use num_traits::{one,zero,One,Zero}; use crate::include::iter_cache::cache_iterator; +#[derive(Clone, Debug)] pub struct Eratosthenes where I: Hash { sieve: HashMap>, prime: I, @@ -68,6 +69,7 @@ pub fn primes_until(x: I) -> impl Iterator where I: Hash + One + Ze return primes::().take_while(move |n| *n < x); } +#[derive(Clone, Copy, Debug, Hash)] pub struct PrimeFactors { number: I } diff --git a/rust/src/main.rs b/rust/src/main.rs index e1de2135..7b83149b 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -15,6 +15,8 @@ use itertools::Itertools; pub mod include; use include::primes; use include::factors; +#[cfg(test)] +use include::math; #[cfg(not(test))] use include::problems::generate_supported_problems; use include::problems::get_problem; @@ -150,3 +152,14 @@ fn test_proper_divisors() -> Result<(), String> { } Ok(()) } + +#[cfg(test)] +#[test] +fn test_n_choose_r() -> Result<(), String> { + for i in 0..68usize { + for j in 0..i { + assert_eq!((0..i).combinations(j).count() as u128, math::n_choose_r::(i, j)); + } + } + Ok(()) +} diff --git a/rust/src/p0053.rs b/rust/src/p0053.rs index 5b889496..fce64a5a 100644 --- a/rust/src/p0053.rs +++ b/rust/src/p0053.rs @@ -31,7 +31,7 @@ pub fn p0053() -> Answer { let mut answer: u64 = 0; for n in 1..101 { for r in 2..(n-1) { - if n_choose_r::(n, r) > 1_000_000 { + if n_choose_r::(n, r) > 1_000_000 { answer += 1; } }