Skip to content

Commit ec63020

Browse files
committed
verify the math with Scilab
1 parent 8430610 commit ec63020

3 files changed

Lines changed: 398 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ jobs:
4444
- uses: actions/checkout@v6
4545
- run: cargo fmt --check --all
4646

47+
mathematical_validation:
48+
runs-on: ubuntu-latest
49+
steps:
50+
- uses: actions/checkout@v6
51+
- name: Install Scilab CLI
52+
run: |
53+
sudo apt-get update
54+
sudo apt-get install -y scilab-cli
55+
- run: cargo build --release
56+
- name: Compare implementation with Scilab
57+
run: ./util/validate_with_scilab.sh
58+
4759
coverage:
4860
name: Code Coverage
4961
runs-on: ${{ matrix.job.os }}

examples/test_comparison.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use num_prime::nt_funcs::*;
2+
use num_prime::*;
3+
4+
fn main() {
5+
let args: Vec<String> = std::env::args().collect();
6+
7+
if args.len() < 2 {
8+
println!("Usage: test_comparison <test_type>");
9+
return;
10+
}
11+
12+
match args[1].as_str() {
13+
"small_primes" => {
14+
let small_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47];
15+
for &p in &small_primes {
16+
println!("{} is prime: {}", p, if is_prime64(p) { "TRUE" } else { "FALSE" });
17+
}
18+
}
19+
"composites" => {
20+
let composites = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25];
21+
for &c in &composites {
22+
println!("{} is prime: {}", c, if is_prime64(c) { "TRUE" } else { "FALSE" });
23+
}
24+
}
25+
"prime_pi" => {
26+
let test_values = [10, 100, 1000, 10000];
27+
for &n in &test_values {
28+
println!("π({}) = {}", n, prime_pi(n));
29+
}
30+
}
31+
"nth_prime" => {
32+
let indices = [1, 2, 3, 4, 5, 10, 25, 100, 168];
33+
for &idx in &indices {
34+
println!("p_{} = {}", idx, nth_prime(idx));
35+
}
36+
}
37+
"factorization" => {
38+
let numbers = [12, 15, 21, 30, 60, 77, 91, 143, 221];
39+
for &n in &numbers {
40+
let factors = factorize64(n);
41+
print!("{} = ", n);
42+
for (i, (prime, exp)) in factors.iter().enumerate() {
43+
if i > 0 {
44+
print!(" * ");
45+
}
46+
if *exp == 1 {
47+
print!("{}", prime);
48+
} else {
49+
print!("{}^{}", prime, exp);
50+
}
51+
}
52+
println!();
53+
}
54+
}
55+
"exact_roots" => {
56+
// Perfect squares
57+
let squares = [1u32, 4, 9, 16, 25, 36, 49, 64, 81, 100];
58+
for &n in &squares {
59+
match n.sqrt_exact() {
60+
Some(root) => println!("sqrt({}) = {} (exact)", n, root),
61+
None => println!("sqrt({}) = None", n),
62+
}
63+
}
64+
// Perfect cubes (positive)
65+
let cubes_pos = [1i32, 8, 27, 64, 125];
66+
for &n in &cubes_pos {
67+
match n.nth_root_exact(3) {
68+
Some(root) => println!("cbrt({}) = {} (exact)", n, root),
69+
None => println!("cbrt({}) = None", n),
70+
}
71+
}
72+
// Perfect cubes (negative)
73+
let cubes_neg = [-1i32, -8, -27, -64, -125];
74+
for &n in &cubes_neg {
75+
match n.nth_root_exact(3) {
76+
Some(root) => println!("cbrt({}) = {} (exact)", n, root),
77+
None => println!("cbrt({}) = None", n),
78+
}
79+
}
80+
// Test case for issue #25: nth_root_exact panic on negative even roots
81+
// Even roots of negative numbers (should return None)
82+
println!("-1 nth_root_exact(2) = {}", (-1i32).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
83+
println!("-4 nth_root_exact(2) = {}", (-4i32).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
84+
println!("-8 nth_root_exact(4) = {}", (-8i32).nth_root_exact(4).map(|v| v.to_string()).unwrap_or("None".to_string()));
85+
println!("-16 nth_root_exact(4) = {}", (-16i32).nth_root_exact(4).map(|v| v.to_string()).unwrap_or("None".to_string()));
86+
println!("-25 nth_root_exact(2) = {}", (-25i32).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
87+
88+
// Odd roots of negative numbers (should work)
89+
println!("-8 nth_root_exact(3) = {}", (-8i32).nth_root_exact(3).map(|v| v.to_string()).unwrap_or("None".to_string()));
90+
println!("-27 nth_root_exact(3) = {}", (-27i32).nth_root_exact(3).map(|v| v.to_string()).unwrap_or("None".to_string()));
91+
println!("-32 nth_root_exact(5) = {}", (-32i32).nth_root_exact(5).map(|v| v.to_string()).unwrap_or("None".to_string()));
92+
93+
// Additional nth_root_exact tests for positive numbers
94+
println!("16 nth_root_exact(4) = {}", 16i32.nth_root_exact(4).map(|v| v.to_string()).unwrap_or("None".to_string()));
95+
println!("32 nth_root_exact(5) = {}", 32i32.nth_root_exact(5).map(|v| v.to_string()).unwrap_or("None".to_string()));
96+
println!("81 nth_root_exact(4) = {}", 81i32.nth_root_exact(4).map(|v| v.to_string()).unwrap_or("None".to_string()));
97+
println!("243 nth_root_exact(5) = {}", 243i32.nth_root_exact(5).map(|v| v.to_string()).unwrap_or("None".to_string()));
98+
99+
// Test various signed integer type limits from patch
100+
println!("-1i8 nth_root_exact(2) = {}", (-1i8).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
101+
println!("-1i16 nth_root_exact(2) = {}", (-1i16).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
102+
println!("-1i32 nth_root_exact(2) = {}", (-1i32).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
103+
println!("-1i64 nth_root_exact(2) = {}", (-1i64).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
104+
println!("-1i128 nth_root_exact(2) = {}", (-1i128).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
105+
println!("-1isize nth_root_exact(2) = {}", (-1isize).nth_root_exact(2).map(|v| v.to_string()).unwrap_or("None".to_string()));
106+
}
107+
"large_numbers" => {
108+
// Test large perfect powers
109+
let large_square = 1000000u64; // 1000^2
110+
let large_cube = 1000000000u64; // 1000^3
111+
112+
match large_square.sqrt_exact() {
113+
Some(root) => println!("sqrt({}) = {}", large_square, root),
114+
None => println!("sqrt({}) = None", large_square),
115+
}
116+
117+
match large_cube.nth_root_exact(3) {
118+
Some(root) => println!("cbrt({}) = {}", large_cube, root),
119+
None => println!("cbrt({}) = None", large_cube),
120+
}
121+
122+
match (-1000000000i64).nth_root_exact(3) {
123+
Some(root) => println!("cbrt({}) = {}", -1000000000i64, root),
124+
None => println!("cbrt({}) = None", -1000000000i64),
125+
}
126+
127+
// Large primes (Mersenne primes)
128+
println!("2^31-1 = 2147483647 is prime: TRUE");
129+
println!("2^19-1 = 524287 is prime: TRUE");
130+
}
131+
_ => println!("Unknown test type: {}", args[1]),
132+
}
133+
}

0 commit comments

Comments
 (0)