mirror of
https://github.com/uutils/num-prime.git
synced 2026-06-10 16:12:35 -07:00
fix clippy warnings:
Fixed with: ` cargo clippy --fix --allow-dirty -- -W clippy::pedantic `
This commit is contained in:
@@ -3,13 +3,13 @@ use num_prime::nt_funcs::factorize64;
|
||||
/// Return all divisors of the target
|
||||
fn divisors(target: u64) -> Vec<u64> {
|
||||
let factors = factorize64(target);
|
||||
let mut result = Vec::with_capacity(factors.iter().map(|(_, e)| e + 1).product());
|
||||
let mut result = Vec::with_capacity(factors.values().map(|e| e + 1).product());
|
||||
result.push(1);
|
||||
|
||||
for (p, e) in factors {
|
||||
// the new results contain all previous divisors multiplied by p, p^2, .., p^e
|
||||
let mut new_result = Vec::with_capacity(result.len() * e);
|
||||
for i in 1..(e as u32 + 1) {
|
||||
for i in 1..=(e as u32) {
|
||||
new_result.extend(result.iter().map(|f| f * p.pow(i)));
|
||||
}
|
||||
result.append(&mut new_result);
|
||||
@@ -17,7 +17,7 @@ fn divisors(target: u64) -> Vec<u64> {
|
||||
result
|
||||
}
|
||||
|
||||
/// Calculate the divisor sigma function σ_z(n) on the target
|
||||
/// Calculate the divisor sigma function `σ_z(n`) on the target
|
||||
/// Reference: <https://en.wikipedia.org/wiki/Divisor_function>
|
||||
fn divisor_sigma(target: u64, z: u32) -> u64 {
|
||||
divisors(target).into_iter().map(|d| d.pow(z)).sum()
|
||||
|
||||
@@ -11,6 +11,6 @@ fn list_mersenne() -> Vec<u64> {
|
||||
fn main() {
|
||||
println!("Mersenne primes under 2^128:");
|
||||
for p in list_mersenne() {
|
||||
println!("2^{} - 1", p);
|
||||
println!("2^{p} - 1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ fn prime_omega(target: u64) -> usize {
|
||||
/// Reference: <https://en.wikipedia.org/wiki/Prime_omega_function>
|
||||
#[allow(non_snake_case)]
|
||||
fn prime_Omega(target: u64) -> usize {
|
||||
factorize64(target).into_iter().map(|(_, e)| e).sum()
|
||||
factorize64(target).into_values().sum()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -8,7 +8,7 @@ use rand::random;
|
||||
|
||||
/// Collect the the iteration number of each factorization algorithm with different settings
|
||||
fn profile_n(n: u128) -> Vec<(String, usize)> {
|
||||
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.iter().take(10).cloned().collect();
|
||||
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.iter().take(10).copied().collect();
|
||||
let k_oneline: Vec<u16> = vec![1, 360, 480];
|
||||
const MAXITER: usize = 1 << 20;
|
||||
const POLLARD_REPEATS: usize = 2;
|
||||
@@ -25,8 +25,8 @@ fn profile_n(n: u128) -> Vec<(String, usize)> {
|
||||
|
||||
// squfof
|
||||
for &k in &k_squfof {
|
||||
let key = format!("squfof_k{}", k);
|
||||
if let Some(kn) = n.checked_mul(k as u128) {
|
||||
let key = format!("squfof_k{k}");
|
||||
if let Some(kn) = n.checked_mul(u128::from(k)) {
|
||||
let n = squfof(&n, kn, MAXITER).1;
|
||||
n_stats.push((key, n));
|
||||
} else {
|
||||
@@ -36,8 +36,8 @@ fn profile_n(n: u128) -> Vec<(String, usize)> {
|
||||
|
||||
// one line
|
||||
for &k in &k_oneline {
|
||||
let key = format!("one_line_k{}", k);
|
||||
if let Some(kn) = n.checked_mul(k as u128) {
|
||||
let key = format!("one_line_k{k}");
|
||||
if let Some(kn) = n.checked_mul(u128::from(k)) {
|
||||
let n = one_line(&n, kn, MAXITER).1;
|
||||
n_stats.push((key, n));
|
||||
} else {
|
||||
@@ -50,7 +50,7 @@ fn profile_n(n: u128) -> Vec<(String, usize)> {
|
||||
|
||||
/// Collect the best case of each factorization algorithm
|
||||
fn profile_n_min(n: u128) -> Vec<(String, usize)> {
|
||||
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.iter().cloned().collect();
|
||||
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.to_vec();
|
||||
let k_oneline: Vec<u16> = vec![1, 360, 480];
|
||||
const MAXITER: usize = 1 << 24;
|
||||
const POLLARD_REPEATS: usize = 4;
|
||||
@@ -72,7 +72,7 @@ fn profile_n_min(n: u128) -> Vec<(String, usize)> {
|
||||
// squfof
|
||||
let mut squfof_best = (MAXITER, u128::MAX);
|
||||
for &k in &k_squfof {
|
||||
if let Some(kn) = n.checked_mul(k as u128) {
|
||||
if let Some(kn) = n.checked_mul(u128::from(k)) {
|
||||
let tstart = Instant::now();
|
||||
let (result, iters) = squfof(&n, kn, squfof_best.0);
|
||||
if result.is_some() {
|
||||
@@ -86,7 +86,7 @@ fn profile_n_min(n: u128) -> Vec<(String, usize)> {
|
||||
// one line
|
||||
let mut oneline_best = (MAXITER, u128::MAX);
|
||||
for &k in &k_oneline {
|
||||
if let Some(kn) = n.checked_mul(k as u128) {
|
||||
if let Some(kn) = n.checked_mul(u128::from(k)) {
|
||||
let tstart = Instant::now();
|
||||
let (result, iters) = one_line(&n, kn, oneline_best.0);
|
||||
if result.is_some() {
|
||||
@@ -119,7 +119,7 @@ fn main() -> Result<(), Error> {
|
||||
|
||||
let n = p1 * p2;
|
||||
n_list.push((n, (n as f64).log2() as f32));
|
||||
println!("Semiprime ({}bits): {} = {} * {}", total_bits, n, p1, p2);
|
||||
println!("Semiprime ({total_bits}bits): {n} = {p1} * {p2}");
|
||||
// stats.push(profile_n(n));
|
||||
stats.push(profile_n_min(n));
|
||||
}
|
||||
|
||||
+46
-42
@@ -1,12 +1,12 @@
|
||||
//! Implementations and extensions for [PrimeBuffer], which represents a container of primes
|
||||
//! Implementations and extensions for [`PrimeBuffer`], which represents a container of primes
|
||||
//!
|
||||
//! In `num-prime`, there is no global instance to store primes, the user has to generate
|
||||
//! and store the primes themselves. The trait [PrimeBuffer] defines a unified interface
|
||||
//! and store the primes themselves. The trait [`PrimeBuffer`] defines a unified interface
|
||||
//! for a prime number container. Some methods that can take advantage of pre-generated
|
||||
//! primes will be implemented in the [PrimeBufferExt] trait.
|
||||
//! primes will be implemented in the [`PrimeBufferExt`] trait.
|
||||
//!
|
||||
//! We also provide [NaiveBuffer] as a simple implementation of [PrimeBuffer] without any
|
||||
//! external dependencies. The performance of the [NaiveBuffer] will not be extremely optimized,
|
||||
//! We also provide [`NaiveBuffer`] as a simple implementation of [`PrimeBuffer`] without any
|
||||
//! external dependencies. The performance of the [`NaiveBuffer`] will not be extremely optimized,
|
||||
//! but it will be efficient enough for most applications.
|
||||
//!
|
||||
|
||||
@@ -30,7 +30,7 @@ use std::num::NonZeroUsize;
|
||||
pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
|
||||
/// Test if an integer is a prime.
|
||||
///
|
||||
/// For targets smaller than 2^64, the deterministic [is_prime64] will be used, otherwise
|
||||
/// For targets smaller than 2^64, the deterministic [`is_prime64`] will be used, otherwise
|
||||
/// the primality test algorithms can be specified by the `config` argument.
|
||||
///
|
||||
/// The primality test can be either deterministic or probabilistic for large integers depending on the `config`.
|
||||
@@ -61,7 +61,7 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
|
||||
};
|
||||
}
|
||||
|
||||
let config = config.unwrap_or(PrimalityTestConfig::default());
|
||||
let config = config.unwrap_or_default();
|
||||
let mut probability = 1.;
|
||||
|
||||
// miller-rabin test
|
||||
@@ -74,7 +74,7 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
|
||||
for _ in 0..config.sprp_random_trials {
|
||||
// we have ensured target is larger than 2^64
|
||||
let mut w: u64 = rand::random();
|
||||
while witness_list.iter().find(|&x| x == &w).is_some() {
|
||||
while witness_list.iter().any(|x| x == &w) {
|
||||
w = rand::random();
|
||||
}
|
||||
witness_list.push(w);
|
||||
@@ -130,10 +130,10 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
|
||||
.collect();
|
||||
return (factors, None);
|
||||
}
|
||||
let config = config.unwrap_or(FactorizationConfig::default());
|
||||
let config = config.unwrap_or_default();
|
||||
|
||||
// test the existing primes
|
||||
let (result, factored) = trial_division(self.iter().cloned(), target, config.td_limit);
|
||||
let (result, factored) = trial_division(self.iter().copied(), target, config.td_limit);
|
||||
let mut result: BTreeMap<T, usize> = result
|
||||
.into_iter()
|
||||
.map(|(k, v)| (T::from_u64(k).unwrap(), v))
|
||||
@@ -159,13 +159,11 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
|
||||
.probably()
|
||||
{
|
||||
*result.entry(target).or_insert(0) += 1;
|
||||
} else if let Some(divisor) = self.divisor(&target, &mut config) {
|
||||
todo.push(divisor.clone());
|
||||
todo.push(target / divisor);
|
||||
} else {
|
||||
if let Some(divisor) = self.divisor(&target, &mut config) {
|
||||
todo.push(divisor.clone());
|
||||
todo.push(target / divisor);
|
||||
} else {
|
||||
failed.push(target);
|
||||
}
|
||||
failed.push(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,7 +240,7 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
|
||||
config.rho_trials -= 1;
|
||||
// TODO: change to a reasonable pollard rho limit
|
||||
// TODO: add other factorization methods
|
||||
if let (Some(p), _) = pollard_rho(target, start, offset, 1048576) {
|
||||
if let (Some(p), _) = pollard_rho(target, start, offset, 1_048_576) {
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
@@ -253,16 +251,22 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
|
||||
|
||||
impl<T> PrimeBufferExt for T where for<'a> T: PrimeBuffer<'a> {}
|
||||
|
||||
/// NaiveBuffer implements a very simple Sieve of Eratosthenes
|
||||
/// `NaiveBuffer` implements a very simple Sieve of Eratosthenes
|
||||
pub struct NaiveBuffer {
|
||||
list: Vec<u64>, // list of found prime numbers
|
||||
next: u64, // all primes smaller than this value has to be in the prime list, should be an odd number
|
||||
}
|
||||
|
||||
impl Default for NaiveBuffer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl NaiveBuffer {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
let list = SMALL_PRIMES.iter().map(|&p| p as u64).collect();
|
||||
#[must_use] pub fn new() -> Self {
|
||||
let list = SMALL_PRIMES.iter().map(|&p| u64::from(p)).collect();
|
||||
NaiveBuffer {
|
||||
list,
|
||||
next: SMALL_PRIMES_NEXT,
|
||||
@@ -355,14 +359,14 @@ impl NaiveBuffer {
|
||||
}
|
||||
|
||||
/// Returns all primes ≤ `limit` and takes ownership. The primes are sorted.
|
||||
pub fn into_primes(mut self, limit: u64) -> std::vec::IntoIter<u64> {
|
||||
#[must_use] pub fn into_primes(mut self, limit: u64) -> std::vec::IntoIter<u64> {
|
||||
self.reserve(limit);
|
||||
let position = match self.list.binary_search(&limit) {
|
||||
Ok(p) => p + 1,
|
||||
Err(p) => p,
|
||||
}; // into_ok_or_err()
|
||||
self.list.truncate(position);
|
||||
return self.list.into_iter();
|
||||
self.list.into_iter()
|
||||
}
|
||||
|
||||
/// Returns primes of certain amount counting from 2. The primes are sorted.
|
||||
@@ -375,13 +379,13 @@ impl NaiveBuffer {
|
||||
}
|
||||
|
||||
/// Returns primes of certain amount counting from 2 and takes ownership. The primes are sorted.
|
||||
pub fn into_nprimes(mut self, count: usize) -> std::vec::IntoIter<u64> {
|
||||
#[must_use] pub fn into_nprimes(mut self, count: usize) -> std::vec::IntoIter<u64> {
|
||||
let (_, bound) = nth_prime_bounds(&(count as u64))
|
||||
.expect("Estimated size of the largest prime will be larger than u64 limit");
|
||||
self.reserve(bound);
|
||||
debug_assert!(self.list.len() >= count);
|
||||
self.list.truncate(count);
|
||||
return self.list.into_iter();
|
||||
self.list.into_iter()
|
||||
}
|
||||
|
||||
/// Get the n-th prime (n counts from 1).
|
||||
@@ -414,7 +418,7 @@ impl NaiveBuffer {
|
||||
x
|
||||
}
|
||||
|
||||
/// Legendre's phi function, used as a helper function for [Self::prime_pi]
|
||||
/// Legendre's phi function, used as a helper function for [`Self::prime_pi`]
|
||||
pub fn prime_phi(&mut self, x: u64, a: usize, cache: &mut LruCache<(u64, usize), u64>) -> u64 {
|
||||
if a == 1 {
|
||||
return (x + 1) / 2;
|
||||
@@ -459,19 +463,19 @@ impl NaiveBuffer {
|
||||
let mut phi_cache = LruCache::new(cache_cap);
|
||||
let mut sum =
|
||||
self.prime_phi(limit, a as usize, &mut phi_cache) + (b + a - 2) * (b - a + 1) / 2;
|
||||
for i in a + 1..b + 1 {
|
||||
for i in (a + 1)..=b {
|
||||
let w = limit / self.nth_prime(i);
|
||||
sum -= self.prime_pi(w);
|
||||
if i <= c {
|
||||
let l = self.prime_pi(w.sqrt());
|
||||
sum += (l * (l - 1) - i * (i - 3)) / 2 - 1;
|
||||
for j in i..(l + 1) {
|
||||
for j in i..=l {
|
||||
let pj = self.nth_prime(j);
|
||||
sum -= self.prime_pi(w / pj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
sum
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,12 +500,12 @@ mod tests {
|
||||
];
|
||||
|
||||
let mut pb = NaiveBuffer::new();
|
||||
assert_eq!(pb.primes(50).cloned().collect::<Vec<_>>(), PRIME50);
|
||||
assert_eq!(pb.primes(300).cloned().collect::<Vec<_>>(), PRIME300);
|
||||
assert_eq!(pb.primes(50).copied().collect::<Vec<_>>(), PRIME50);
|
||||
assert_eq!(pb.primes(300).copied().collect::<Vec<_>>(), PRIME300);
|
||||
|
||||
// test when limit itself is a prime
|
||||
pb.clear();
|
||||
assert_eq!(pb.primes(293).cloned().collect::<Vec<_>>(), PRIME300);
|
||||
assert_eq!(pb.primes(293).copied().collect::<Vec<_>>(), PRIME300);
|
||||
pb = NaiveBuffer::new();
|
||||
assert_eq!(*pb.primes(257).last().unwrap(), 257); // boundary of small table
|
||||
pb = NaiveBuffer::new();
|
||||
@@ -511,15 +515,15 @@ mod tests {
|
||||
#[test]
|
||||
fn nth_prime_test() {
|
||||
let mut pb = NaiveBuffer::new();
|
||||
assert_eq!(pb.nth_prime(10000), 104729);
|
||||
assert_eq!(pb.nth_prime(20000), 224737);
|
||||
assert_eq!(pb.nth_prime(10000), 104729); // use existing primes
|
||||
assert_eq!(pb.nth_prime(10000), 104_729);
|
||||
assert_eq!(pb.nth_prime(20000), 224_737);
|
||||
assert_eq!(pb.nth_prime(10000), 104_729); // use existing primes
|
||||
|
||||
// Riemann zeta based, test on OEIS:A006988
|
||||
assert_eq!(pb.nth_prime(10u64.pow(4)), 104729);
|
||||
assert_eq!(pb.nth_prime(10u64.pow(5)), 1299709);
|
||||
assert_eq!(pb.nth_prime(10u64.pow(6)), 15485863);
|
||||
assert_eq!(pb.nth_prime(10u64.pow(7)), 179424673);
|
||||
assert_eq!(pb.nth_prime(10u64.pow(4)), 104_729);
|
||||
assert_eq!(pb.nth_prime(10u64.pow(5)), 1_299_709);
|
||||
assert_eq!(pb.nth_prime(10u64.pow(6)), 15_485_863);
|
||||
assert_eq!(pb.nth_prime(10u64.pow(7)), 179_424_673);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -539,8 +543,8 @@ mod tests {
|
||||
// Meissel–Lehmer algorithm, test on OEIS:A006880
|
||||
assert_eq!(pb.prime_pi(10u64.pow(5)), 9592);
|
||||
assert_eq!(pb.prime_pi(10u64.pow(6)), 78498);
|
||||
assert_eq!(pb.prime_pi(10u64.pow(7)), 664579);
|
||||
assert_eq!(pb.prime_pi(10u64.pow(8)), 5761455);
|
||||
assert_eq!(pb.prime_pi(10u64.pow(7)), 664_579);
|
||||
assert_eq!(pb.prime_pi(10u64.pow(8)), 5_761_455);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -573,7 +577,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// test large numbers
|
||||
const P: u128 = 18699199384836356663; // https://golang.org/issue/638
|
||||
const P: u128 = 18_699_199_384_836_356_663; // https://golang.org/issue/638
|
||||
assert!(matches!(pb.is_prime(&P, None), Primality::Probable(_)));
|
||||
assert!(matches!(
|
||||
pb.is_prime(&P, Some(PrimalityTestConfig::bpsw())),
|
||||
@@ -588,7 +592,7 @@ mod tests {
|
||||
Primality::Probable(_)
|
||||
));
|
||||
|
||||
const P2: u128 = 2019922777445599503530083;
|
||||
const P2: u128 = 2_019_922_777_445_599_503_530_083;
|
||||
assert!(matches!(pb.is_prime(&P2, None), Primality::Probable(_)));
|
||||
assert!(matches!(
|
||||
pb.is_prime(&P2, Some(PrimalityTestConfig::bpsw())),
|
||||
|
||||
+39
-39
@@ -19,7 +19,7 @@ use std::collections::BTreeMap;
|
||||
/// The parameter limit additionally sets the maximum of primes to be tried.
|
||||
/// The residual will be Ok(1) or Ok(p) if fully factored.
|
||||
///
|
||||
/// TODO: implement fast check for small primes with BigInts in the precomputed table, and skip them in this function
|
||||
/// TODO: implement fast check for small primes with `BigInts` in the precomputed table, and skip them in this function
|
||||
pub fn trial_division<
|
||||
I: Iterator<Item = u64>,
|
||||
T: Integer + Clone + Roots + NumRef + FromPrimitive,
|
||||
@@ -98,14 +98,14 @@ where
|
||||
|
||||
while i < max_iter {
|
||||
i += 1;
|
||||
a = a.sqm(&target).addm(&offset, &target);
|
||||
a = a.sqm(target).addm(&offset, target);
|
||||
if a == b {
|
||||
return (None, i);
|
||||
}
|
||||
|
||||
// FIXME: optimize abs_diff for montgomery form if we are going to use the abs_diff in the std lib
|
||||
let diff = if b > a { &b - &a } else { &a - &b }; // abs_diff
|
||||
z = z.mulm(&diff, &target);
|
||||
z = z.mulm(&diff, target);
|
||||
if z.is_zero() {
|
||||
// the factor is missed by a combined GCD, do backtracing
|
||||
if backtrace {
|
||||
@@ -145,7 +145,7 @@ where
|
||||
/// This function implements Shanks's square forms factorization (SQUFOF).
|
||||
///
|
||||
/// The input is usually multiplied by a multiplier, and the multiplied integer should be put in
|
||||
/// the `mul_target` argument. The multiplier can be choosen from SQUFOF_MULTIPLIERS, or other square-free odd numbers.
|
||||
/// the `mul_target` argument. The multiplier can be choosen from `SQUFOF_MULTIPLIERS`, or other square-free odd numbers.
|
||||
/// The returned values are the factor and the count of passed iterations.
|
||||
///
|
||||
/// The max iteration can be choosed as 2*n^(1/4), based on Theorem 4.22 from [1].
|
||||
@@ -163,7 +163,7 @@ where
|
||||
for<'r> &'r T: RefNum<T>,
|
||||
{
|
||||
assert!(
|
||||
&mul_target.is_multiple_of(&target),
|
||||
&mul_target.is_multiple_of(target),
|
||||
"mul_target should be multiples of target"
|
||||
);
|
||||
let rd = Roots::sqrt(&mul_target); // root of k*N
|
||||
@@ -210,7 +210,7 @@ where
|
||||
if new_u == u {
|
||||
break;
|
||||
} else {
|
||||
u = new_u
|
||||
u = new_u;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ pub const SQUFOF_MULTIPLIERS: [u16; 38] = [
|
||||
///
|
||||
///
|
||||
/// The one line factorization algorithm is especially good at factoring semiprimes with form pq,
|
||||
/// where p = next_prime(c^a+d1), p = next_prime(c^b+d2), a and b are close, and c, d1, d2 are small integers.
|
||||
/// where p = `next_prime(c^a+d1`), p = `next_prime(c^b+d2`), a and b are close, and c, d1, d2 are small integers.
|
||||
///
|
||||
/// Reference: Hart, W. B. (2012). A one line factoring algorithm. Journal of the Australian Mathematical Society, 92(1), 61-69. doi:10.1017/S1446788712000146
|
||||
// TODO: add multipliers preset for one_line method?
|
||||
@@ -290,7 +290,7 @@ where
|
||||
for<'r> &'r T: RefNum<T>,
|
||||
{
|
||||
assert!(
|
||||
&mul_target.is_multiple_of(&target),
|
||||
&mul_target.is_multiple_of(target),
|
||||
"mul_target should be multiples of target"
|
||||
);
|
||||
|
||||
@@ -306,13 +306,13 @@ where
|
||||
}
|
||||
|
||||
// prevent overflow
|
||||
ikn = if let Some(n) = (&ikn).checked_add(&mul_target) {
|
||||
ikn = if let Some(n) = ikn.checked_add(&mul_target) {
|
||||
n
|
||||
} else {
|
||||
return (None, i);
|
||||
}
|
||||
}
|
||||
return (None, max_iter);
|
||||
(None, max_iter)
|
||||
}
|
||||
|
||||
// TODO: ECM, (self initialize) Quadratic sieve, Lehman's Fermat(https://en.wikipedia.org/wiki/Fermat%27s_factorization_method, n_factor_lehman)
|
||||
@@ -335,7 +335,7 @@ mod tests {
|
||||
fn pollard_rho_test() {
|
||||
assert_eq!(pollard_rho(&8051u16, 2, 1, 100).0, Some(97));
|
||||
assert!(matches!(pollard_rho(&8051u16, random(), 1, 100).0, Some(i) if i == 97 || i == 83));
|
||||
assert_eq!(pollard_rho(&455459u32, 2, 1, 100).0, Some(743));
|
||||
assert_eq!(pollard_rho(&455_459_u32, 2, 1, 100).0, Some(743));
|
||||
|
||||
// Mint test
|
||||
for _ in 0..10 {
|
||||
@@ -365,34 +365,34 @@ mod tests {
|
||||
12851,
|
||||
13289,
|
||||
75301,
|
||||
120787,
|
||||
967009,
|
||||
997417,
|
||||
7091569,
|
||||
5214317,
|
||||
20834839,
|
||||
23515517,
|
||||
33409583,
|
||||
44524219,
|
||||
13290059,
|
||||
223553581,
|
||||
2027651281,
|
||||
11111111111,
|
||||
100895598169,
|
||||
60012462237239,
|
||||
287129523414791,
|
||||
9007199254740931,
|
||||
11111111111111111,
|
||||
314159265358979323,
|
||||
384307168202281507,
|
||||
419244183493398773,
|
||||
658812288346769681,
|
||||
922337203685477563,
|
||||
1000000000000000127,
|
||||
1152921505680588799,
|
||||
1537228672809128917,
|
||||
120_787,
|
||||
967_009,
|
||||
997_417,
|
||||
7_091_569,
|
||||
5_214_317,
|
||||
20_834_839,
|
||||
23_515_517,
|
||||
33_409_583,
|
||||
44_524_219,
|
||||
13_290_059,
|
||||
223_553_581,
|
||||
2_027_651_281,
|
||||
11_111_111_111,
|
||||
100_895_598_169,
|
||||
60_012_462_237_239,
|
||||
287_129_523_414_791,
|
||||
9_007_199_254_740_931,
|
||||
11_111_111_111_111_111,
|
||||
314_159_265_358_979_323,
|
||||
384_307_168_202_281_507,
|
||||
419_244_183_493_398_773,
|
||||
658_812_288_346_769_681,
|
||||
922_337_203_685_477_563,
|
||||
1_000_000_000_000_000_127,
|
||||
1_152_921_505_680_588_799,
|
||||
1_537_228_672_809_128_917,
|
||||
// this case should success at step 276, from https://rosettacode.org/wiki/Talk:Square_form_factorization
|
||||
4558849,
|
||||
4_558_849,
|
||||
];
|
||||
for n in cases {
|
||||
let d = squfof(&n, n, 40000)
|
||||
@@ -401,7 +401,7 @@ mod tests {
|
||||
.or(squfof(&n, 5 * n, 40000).0)
|
||||
.or(squfof(&n, 7 * n, 40000).0)
|
||||
.or(squfof(&n, 11 * n, 40000).0);
|
||||
assert!(matches!(d, Some(_)), "{}", n);
|
||||
assert!(d.is_some(), "{}", n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-11
@@ -1,7 +1,9 @@
|
||||
//! Backend implementations for integers
|
||||
|
||||
use crate::tables::{CUBIC_MODULI, CUBIC_RESIDUAL, QUAD_MODULI, QUAD_RESIDUAL};
|
||||
use crate::traits::{BitTest, ExactRoots};
|
||||
use crate::{
|
||||
tables::{CUBIC_MODULI, CUBIC_RESIDUAL, QUAD_MODULI, QUAD_RESIDUAL},
|
||||
traits::{BitTest, ExactRoots},
|
||||
};
|
||||
|
||||
#[cfg(feature = "num-bigint")]
|
||||
use num_bigint::{BigInt, BigUint, ToBigInt};
|
||||
@@ -155,19 +157,19 @@ impl ExactRoots for BigInt {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rand;
|
||||
|
||||
|
||||
#[test]
|
||||
fn exact_root_test() {
|
||||
// some simple tests
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&3u8), None));
|
||||
assert!(ExactRoots::sqrt_exact(&3u8).is_none());
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&4u8), Some(2)));
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&9u8), Some(3)));
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&18u8), None));
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&3i8), None));
|
||||
assert!(ExactRoots::sqrt_exact(&18u8).is_none());
|
||||
assert!(ExactRoots::sqrt_exact(&3i8).is_none());
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&4i8), Some(2)));
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&9i8), Some(3)));
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&18i8), None));
|
||||
assert!(ExactRoots::sqrt_exact(&18i8).is_none());
|
||||
|
||||
// test fast implementations of sqrt against nth_root
|
||||
for _ in 0..100 {
|
||||
@@ -188,15 +190,15 @@ mod tests {
|
||||
}
|
||||
// test perfect powers
|
||||
for _ in 0..100 {
|
||||
let x = rand::random::<u32>() as u64;
|
||||
let x = u64::from(rand::random::<u32>());
|
||||
assert!(matches!(ExactRoots::sqrt_exact(&(x * x)), Some(v) if v == x));
|
||||
let x = rand::random::<i16>() as i64;
|
||||
let x = i64::from(rand::random::<i16>());
|
||||
assert!(matches!(ExactRoots::cbrt_exact(&(x * x * x)), Some(v) if v == x));
|
||||
}
|
||||
// test non-perfect powers
|
||||
for _ in 0..100 {
|
||||
let x = rand::random::<u32>() as u64;
|
||||
let y = rand::random::<u32>() as u64;
|
||||
let x = u64::from(rand::random::<u32>());
|
||||
let y = u64::from(rand::random::<u32>());
|
||||
if x == y {
|
||||
continue;
|
||||
}
|
||||
|
||||
+4
-4
@@ -26,8 +26,8 @@
|
||||
//! - [Moebius function][nt_funcs::moebius]
|
||||
//!
|
||||
//! # Usage
|
||||
//! Most number theoretic functions can be found in [nt_funcs] module, while some
|
||||
//! of them are implemented as member function of [num_modular::ModularOps] or [PrimalityUtils].
|
||||
//! Most number theoretic functions can be found in [`nt_funcs`] module, while some
|
||||
//! of them are implemented as member function of [`num_modular::ModularOps`] or [`PrimalityUtils`].
|
||||
//!
|
||||
//! Example code for primality testing and integer factorization:
|
||||
//! ```rust
|
||||
@@ -52,9 +52,9 @@
|
||||
//! This crate is built with modular integer type and prime generation backends.
|
||||
//! Most functions support generic input types, and support for `num-bigint` is
|
||||
//! also available (it's an optional feature). To make a new integer type supported
|
||||
//! by this crate, the type has to implement [detail::PrimalityBase] and [detail::PrimalityRefBase].
|
||||
//! by this crate, the type has to implement [`detail::PrimalityBase`] and [`detail::PrimalityRefBase`].
|
||||
//! For prime generation, there's a builtin implementation (see [buffer] module),
|
||||
//! but you can also use other backends (such as `primal`) as long as it implements [PrimeBuffer].
|
||||
//! but you can also use other backends (such as `primal`) as long as it implements [`PrimeBuffer`].
|
||||
//!
|
||||
//! # Optional Features
|
||||
//! - `big-int` (default): Enable this feature to support `num-bigint::BigUint` as integer inputs.
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
//! Wrapper of integer to makes it efficient in modular arithmetics but still have the same
|
||||
//! API of normal integers.
|
||||
|
||||
use core::ops::*;
|
||||
use either::*;
|
||||
use core::ops::{Add, Div, Mul, Neg, Rem, Shr, Sub};
|
||||
use either::{Either, Left, Right};
|
||||
use num_integer::{Integer, Roots};
|
||||
use num_modular::{
|
||||
ModularCoreOps, ModularInteger, ModularPow, ModularSymbols, ModularUnaryOps, Montgomery,
|
||||
@@ -12,7 +12,7 @@ use num_traits::{FromPrimitive, Num, One, Pow, ToPrimitive, Zero};
|
||||
|
||||
use crate::{BitTest, ExactRoots};
|
||||
|
||||
/// Integer with fast modular arithmetics support, based on [MontgomeryInt] under the hood
|
||||
/// Integer with fast modular arithmetics support, based on [`MontgomeryInt`] under the hood
|
||||
///
|
||||
/// This struct only designed to be working with this crate. Most binary operators assume that
|
||||
/// the modulus of two operands (when in montgomery form) are the same, and most implicit conversions
|
||||
|
||||
+136
-136
File diff suppressed because it is too large
Load Diff
+26
-30
@@ -341,7 +341,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A dummy trait for integer type. All types that implements this and [PrimalityRefBase]
|
||||
/// A dummy trait for integer type. All types that implements this and [`PrimalityRefBase`]
|
||||
/// will be supported by most functions in `num-primes`
|
||||
pub trait PrimalityBase:
|
||||
Integer
|
||||
@@ -369,7 +369,7 @@ impl<
|
||||
{
|
||||
}
|
||||
|
||||
/// A dummy trait for integer reference type. All types that implements this and [PrimalityBase]
|
||||
/// A dummy trait for integer reference type. All types that implements this and [`PrimalityBase`]
|
||||
/// will be supported by most functions in `num-primes`
|
||||
pub trait PrimalityRefBase<Base>:
|
||||
RefNum<Base>
|
||||
@@ -441,26 +441,26 @@ mod tests {
|
||||
3927,
|
||||
12970,
|
||||
42837,
|
||||
141481,
|
||||
467280,
|
||||
1543321,
|
||||
5097243,
|
||||
16835050,
|
||||
55602393,
|
||||
183642229,
|
||||
606529080,
|
||||
2003229469,
|
||||
6616217487,
|
||||
21851881930,
|
||||
72171863277,
|
||||
238367471761,
|
||||
787274278560,
|
||||
2600190307441,
|
||||
141_481,
|
||||
467_280,
|
||||
1_543_321,
|
||||
5_097_243,
|
||||
16_835_050,
|
||||
55_602_393,
|
||||
183_642_229,
|
||||
606_529_080,
|
||||
2_003_229_469,
|
||||
6_616_217_487,
|
||||
21_851_881_930,
|
||||
72_171_863_277,
|
||||
238_367_471_761,
|
||||
787_274_278_560,
|
||||
2_600_190_307_441,
|
||||
];
|
||||
let m = random::<u16>();
|
||||
for n in 2..p3qm1.len() {
|
||||
let (uk, _) = LucasUtils::lucasm(3, -1, m as u64, n as u64);
|
||||
assert_eq!(uk, p3qm1[n] % (m as u64));
|
||||
let (uk, _) = LucasUtils::lucasm(3, -1, u64::from(m), n as u64);
|
||||
assert_eq!(uk, p3qm1[n] % u64::from(m));
|
||||
|
||||
#[cfg(feature = "num-bigint")]
|
||||
{
|
||||
@@ -491,18 +491,14 @@ mod tests {
|
||||
(u as u16, v as u16)
|
||||
}
|
||||
for _ in 0..10 {
|
||||
let n = random::<u8>() as u16;
|
||||
let n = u16::from(random::<u8>());
|
||||
let m = random::<u16>();
|
||||
let p = random::<u16>() as usize;
|
||||
let q = random::<i16>() as isize;
|
||||
assert_eq!(
|
||||
LucasUtils::lucasm(p, q, m, n),
|
||||
lucasm_naive(p, q, m, n),
|
||||
"failed with Lucas settings: p={}, q={}, m={}, n={}",
|
||||
p,
|
||||
q,
|
||||
m,
|
||||
n
|
||||
"failed with Lucas settings: p={p}, q={q}, m={m}, n={n}"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -519,7 +515,7 @@ mod tests {
|
||||
|
||||
// least lucas pseudo primes for Q=-1 and Jacobi(D/n) = -1 (from Wikipedia)
|
||||
let plimit: [u16; 5] = [323, 35, 119, 9, 9];
|
||||
for (i, l) in plimit.iter().cloned().enumerate() {
|
||||
for (i, l) in plimit.iter().copied().enumerate() {
|
||||
let p = i + 1;
|
||||
assert!(l.is_lprp(Some(p), Some(-1)));
|
||||
|
||||
@@ -544,7 +540,7 @@ mod tests {
|
||||
|
||||
// least strong lucas pseudoprimes for Q=-1 and Jacobi(D/n) = -1 (from Wikipedia)
|
||||
let plimit: [u16; 3] = [4181, 169, 119];
|
||||
for (i, l) in plimit.iter().cloned().enumerate() {
|
||||
for (i, l) in plimit.iter().copied().enumerate() {
|
||||
let p = i + 1;
|
||||
assert!(l.is_slprp(Some(p), Some(-1)));
|
||||
|
||||
@@ -581,7 +577,7 @@ mod tests {
|
||||
if n <= 3 || (n.is_sprp(2) && n.is_sprp(3)) {
|
||||
continue;
|
||||
} // skip real primes
|
||||
if lpsp.iter().find(|&x| x == &n).is_some() {
|
||||
if lpsp.iter().any(|x| x == &n) {
|
||||
continue;
|
||||
} // skip pseudoprimes
|
||||
assert!(!n.is_lprp(None, None), "lucas prp test on {}", n);
|
||||
@@ -601,7 +597,7 @@ mod tests {
|
||||
if n <= 3 || (n.is_sprp(2) && n.is_sprp(3)) {
|
||||
continue;
|
||||
} // skip real primes
|
||||
if slpsp.iter().find(|&x| x == &n).is_some() {
|
||||
if slpsp.iter().any(|x| x == &n) {
|
||||
continue;
|
||||
} // skip pseudoprimes
|
||||
assert!(!n.is_slprp(None, None), "strong lucas prp test on {}", n);
|
||||
@@ -621,7 +617,7 @@ mod tests {
|
||||
if n <= 3 || (n.is_sprp(2) && n.is_sprp(3)) {
|
||||
continue;
|
||||
} // skip real primes
|
||||
if eslpsp.iter().find(|&x| x == &n).is_some() {
|
||||
if eslpsp.iter().any(|x| x == &n) {
|
||||
continue;
|
||||
} // skip pseudoprimes
|
||||
assert!(!n.is_eslprp(None), "extra strong lucas prp test on {}", n);
|
||||
|
||||
+7
-11
@@ -83,9 +83,7 @@ impl_randprime_prim!(u8 u16 u32 u64);
|
||||
impl<R: Rng> RandPrime<u128> for R {
|
||||
#[inline]
|
||||
fn gen_prime(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> u128 {
|
||||
if bit_size > (u128::BITS as usize) {
|
||||
panic!("The given bit size limit exceeded the capacity of the integer type!")
|
||||
}
|
||||
assert!(bit_size <= (u128::BITS as usize), "The given bit size limit exceeded the capacity of the integer type!");
|
||||
|
||||
loop {
|
||||
let t: u128 = self.gen();
|
||||
@@ -101,9 +99,7 @@ impl<R: Rng> RandPrime<u128> for R {
|
||||
|
||||
#[inline]
|
||||
fn gen_prime_exact(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> u128 {
|
||||
if bit_size > (u128::BITS as usize) {
|
||||
panic!("The given bit size limit exceeded the capacity of the integer type!")
|
||||
}
|
||||
assert!(bit_size <= (u128::BITS as usize), "The given bit size limit exceeded the capacity of the integer type!");
|
||||
|
||||
loop {
|
||||
let t: u128 = self.gen();
|
||||
@@ -212,11 +208,11 @@ mod tests {
|
||||
|
||||
// test random prime generation for each size
|
||||
let p: u8 = rng.gen_prime(8, None);
|
||||
assert!(is_prime64(p as u64));
|
||||
assert!(is_prime64(u64::from(p)));
|
||||
let p: u16 = rng.gen_prime(16, None);
|
||||
assert!(is_prime64(p as u64));
|
||||
assert!(is_prime64(u64::from(p)));
|
||||
let p: u32 = rng.gen_prime(32, None);
|
||||
assert!(is_prime64(p as u64));
|
||||
assert!(is_prime64(u64::from(p)));
|
||||
let p: u64 = rng.gen_prime(64, None);
|
||||
assert!(is_prime64(p));
|
||||
let p: u128 = rng.gen_prime(128, None);
|
||||
@@ -251,10 +247,10 @@ mod tests {
|
||||
|
||||
// test exact size prime generation
|
||||
let p: u8 = rng.gen_prime_exact(8, None);
|
||||
assert!(is_prime64(p as u64));
|
||||
assert!(is_prime64(u64::from(p)));
|
||||
assert_eq!(p.leading_zeros(), 0);
|
||||
let p: u32 = rng.gen_prime_exact(32, None);
|
||||
assert!(is_prime64(p as u64));
|
||||
assert!(is_prime64(u64::from(p)));
|
||||
assert_eq!(p.leading_zeros(), 0);
|
||||
let p: u128 = rng.gen_prime_exact(128, None);
|
||||
assert!(is_prime(&p, None).probably());
|
||||
|
||||
+2930
-2930
File diff suppressed because it is too large
Load Diff
+13
-13
@@ -32,9 +32,9 @@ pub enum Primality {
|
||||
|
||||
impl Primality {
|
||||
/// Check whether the resule indicates that the number is
|
||||
/// (very) probably a prime. Return false only on [Primality::No]
|
||||
/// (very) probably a prime. Return false only on [`Primality::No`]
|
||||
#[inline(always)]
|
||||
pub fn probably(self) -> bool {
|
||||
#[must_use] pub fn probably(self) -> bool {
|
||||
match self {
|
||||
Primality::No => false,
|
||||
_ => true,
|
||||
@@ -112,14 +112,14 @@ impl PrimalityTestConfig {
|
||||
/// Create a configuration with a very strong primality check. It's based on
|
||||
/// the **strongest deterministic primality testing** and some SPRP tests with
|
||||
/// random bases.
|
||||
pub fn strict() -> Self {
|
||||
#[must_use] pub fn strict() -> Self {
|
||||
let mut config = Self::bpsw();
|
||||
config.sprp_random_trials = 1;
|
||||
config
|
||||
}
|
||||
|
||||
/// Create a configuration for Baillie-PSW test (base 2 SPRP test + SLPRP test)
|
||||
pub fn bpsw() -> Self {
|
||||
#[must_use] pub fn bpsw() -> Self {
|
||||
Self {
|
||||
sprp_trials: 1,
|
||||
sprp_random_trials: 0,
|
||||
@@ -172,7 +172,7 @@ impl Default for FactorizationConfig {
|
||||
|
||||
impl FactorizationConfig {
|
||||
/// Same as the default configuration but with strict primality check
|
||||
pub fn strict() -> Self {
|
||||
#[must_use] pub fn strict() -> Self {
|
||||
let mut config = Self::default();
|
||||
config.primality_config = PrimalityTestConfig::strict();
|
||||
config
|
||||
@@ -180,7 +180,7 @@ impl FactorizationConfig {
|
||||
}
|
||||
|
||||
// FIXME: backport to num_integer (see https://github.com/rust-num/num-traits/issues/233)
|
||||
/// Extension on [num_integer::Roots] to support perfect power check on integers
|
||||
/// Extension on [`num_integer::Roots`] to support perfect power check on integers
|
||||
pub trait ExactRoots: Roots + Pow<u32, Output = Self> + Clone {
|
||||
fn nth_root_exact(&self, n: u32) -> Option<Self> {
|
||||
let r = self.nth_root(n);
|
||||
@@ -230,7 +230,7 @@ pub trait PrimeBuffer<'a> {
|
||||
fn bound(&self) -> u64;
|
||||
|
||||
/// Test if the number is in the buffer. If a number is not in the buffer,
|
||||
/// then it's either a composite or large than [PrimeBuffer::bound()]
|
||||
/// then it's either a composite or large than [`PrimeBuffer::bound()`]
|
||||
fn contains(&self, num: u64) -> bool;
|
||||
|
||||
/// clear the prime buffer to save memory
|
||||
@@ -276,26 +276,26 @@ pub trait RandPrime<T> {
|
||||
/// Generate a random prime within the given bit size limit
|
||||
///
|
||||
/// # Panics
|
||||
/// if the bit_size is 0 or it's larger than the bit width of the integer
|
||||
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
|
||||
fn gen_prime(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> T;
|
||||
|
||||
/// Generate a random prime with **exact** the given bit size
|
||||
///
|
||||
/// # Panics
|
||||
/// if the bit_size is 0 or it's larger than the bit width of the integer
|
||||
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
|
||||
fn gen_prime_exact(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> T;
|
||||
|
||||
/// Generate a random (Sophie German) safe prime within the given bit size limit. The generated prime
|
||||
/// is guaranteed to pass the [is_safe_prime][crate::nt_funcs::is_safe_prime] test
|
||||
/// is guaranteed to pass the [`is_safe_prime`][crate::nt_funcs::is_safe_prime] test
|
||||
///
|
||||
/// # Panics
|
||||
/// if the bit_size is 0 or it's larger than the bit width of the integer
|
||||
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
|
||||
fn gen_safe_prime(&mut self, bit_size: usize) -> T;
|
||||
|
||||
/// Generate a random (Sophie German) safe prime with the **exact** given bit size. The generated prime
|
||||
/// is guaranteed to pass the [is_safe_prime][crate::nt_funcs::is_safe_prime] test
|
||||
/// is guaranteed to pass the [`is_safe_prime`][crate::nt_funcs::is_safe_prime] test
|
||||
///
|
||||
/// # Panics
|
||||
/// if the bit_size is 0 or it's larger than the bit width of the integer
|
||||
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
|
||||
fn gen_safe_prime_exact(&mut self, bit_size: usize) -> T;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user