fix clippy warnings:

Fixed with:
`
cargo clippy --fix --allow-dirty  -- -W clippy::pedantic
`
This commit is contained in:
Sylvestre Ledru
2024-11-03 13:46:42 +01:00
parent dad684c95f
commit 48c099b7bb
14 changed files with 3231 additions and 3233 deletions
+3 -3
View File
@@ -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()
+1 -1
View File
@@ -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");
}
}
+1 -1
View File
@@ -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() {
+9 -9
View File
@@ -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
View File
@@ -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 {
// MeisselLehmer 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+26 -30
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+13 -13
View File
@@ -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;
}