mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
Merge pull request #1549 from nbraud/factor/strong-pseudoprime-bug
factor: Fix very-rare bug in ρ
This commit is contained in:
commit
f33ffc73eb
3 changed files with 20 additions and 6 deletions
|
@ -156,4 +156,17 @@ mod tests {
|
||||||
.map(|i| 2 * i + 2u64.pow(32) + 1)
|
.map(|i| 2 * i + 2u64.pow(32) + 1)
|
||||||
.all(|i| factor(i).product() == i));
|
.all(|i| factor(i).product() == i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn factor_recombines_strong_pseudoprime() {
|
||||||
|
// This is a strong pseudoprime (wrt. miller_rabin::BASIS)
|
||||||
|
// and triggered a bug in rho::factor's codepath handling
|
||||||
|
// miller_rabbin::Result::Composite
|
||||||
|
let pseudoprime = 17179869183;
|
||||||
|
for _ in 0..20 {
|
||||||
|
// Repeat the test 20 times, as it only fails some fraction
|
||||||
|
// of the time.
|
||||||
|
assert!(factor(pseudoprime).product() == pseudoprime);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,7 +175,7 @@ impl Arithmetic for Montgomery {
|
||||||
// extended Euclid algorithm
|
// extended Euclid algorithm
|
||||||
// precondition: a is odd
|
// precondition: a is odd
|
||||||
pub(crate) fn inv_mod_u64(a: u64) -> u64 {
|
pub(crate) fn inv_mod_u64(a: u64) -> u64 {
|
||||||
assert!(a % 2 == 1);
|
assert!(a % 2 == 1, "{} is not odd", a);
|
||||||
let mut t = 0u64;
|
let mut t = 0u64;
|
||||||
let mut newt = 1u64;
|
let mut newt = 1u64;
|
||||||
let mut r = 0u64;
|
let mut r = 0u64;
|
||||||
|
|
|
@ -48,7 +48,7 @@ fn find_divisor<A: Arithmetic>(n: A) -> u64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _factor<A: Arithmetic>(mut num: u64) -> Factors {
|
fn _factor<A: Arithmetic>(num: u64) -> Factors {
|
||||||
// Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
|
// Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
|
||||||
let _factor = |n| {
|
let _factor = |n| {
|
||||||
// TODO: Optimise with 32 and 64b versions
|
// TODO: Optimise with 32 and 64b versions
|
||||||
|
@ -61,6 +61,7 @@ fn _factor<A: Arithmetic>(mut num: u64) -> Factors {
|
||||||
}
|
}
|
||||||
|
|
||||||
let n = A::new(num);
|
let n = A::new(num);
|
||||||
|
let divisor;
|
||||||
match miller_rabin::test::<A>(n) {
|
match miller_rabin::test::<A>(n) {
|
||||||
Prime => {
|
Prime => {
|
||||||
factors.push(num);
|
factors.push(num);
|
||||||
|
@ -68,14 +69,14 @@ fn _factor<A: Arithmetic>(mut num: u64) -> Factors {
|
||||||
}
|
}
|
||||||
|
|
||||||
Composite(d) => {
|
Composite(d) => {
|
||||||
num /= d;
|
divisor = d;
|
||||||
factors *= _factor(d)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pseudoprime => {}
|
Pseudoprime => {
|
||||||
|
divisor = find_divisor::<A>(n);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let divisor = find_divisor::<A>(n);
|
|
||||||
factors *= _factor(divisor);
|
factors *= _factor(divisor);
|
||||||
factors *= _factor(num / divisor);
|
factors *= _factor(num / divisor);
|
||||||
factors
|
factors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue