1use crate::buffer::{NaiveBuffer, PrimeBufferExt};
15use crate::factor::{one_line, pollard_rho, squfof, SQUFOF_MULTIPLIERS};
16use crate::mint::SmallMint;
17use crate::primality::{PrimalityBase, PrimalityRefBase};
18use crate::tables::{
19 MOEBIUS_ODD, SMALL_PRIMES, SMALL_PRIMES_NEXT, WHEEL_NEXT, WHEEL_PREV,
20 WHEEL_SIZE,
21};
22#[cfg(feature = "big-table")]
23use crate::tables::{SMALL_PRIMES_INV, ZETA_LOG_TABLE};
24use crate::traits::{FactorizationConfig, Primality, PrimalityTestConfig, PrimalityUtils};
25use crate::{BitTest, ExactRoots};
26use num_integer::Roots;
27#[cfg(feature = "num-bigint")]
28use num_modular::DivExact;
29use num_modular::{ModularCoreOps, ModularInteger, MontgomeryInt};
30use num_traits::{CheckedAdd, FromPrimitive, Num, RefNum, ToPrimitive};
31use rand::random;
32use std::collections::BTreeMap;
33use std::convert::TryFrom;
34
35#[cfg(feature = "big-table")]
36use crate::tables::{MILLER_RABIN_BASE64, MILLER_RABIN_BASE32};
37
38#[cfg(not(feature = "big-table"))]
42pub fn is_prime64(target: u64) -> bool {
43 if target < 2 {
45 return false;
46 }
47 if target & 1 == 0 {
48 return target == 2;
49 }
50 if let Ok(u) = u8::try_from(target) {
51 return SMALL_PRIMES.binary_search(&u).is_ok();
53 } else {
54 let pos = (target % WHEEL_SIZE as u64) as usize;
57 if pos == 0 || WHEEL_NEXT[pos] < WHEEL_NEXT[pos - 1] {
58 return false;
59 }
60 }
61
62 is_prime64_miller(target)
64}
65
66#[cfg(feature = "big-table")]
70pub fn is_prime64(target: u64) -> bool {
71 if target < 2 {
73 return false;
74 }
75 if target & 1 == 0 {
76 return target == 2;
77 }
78
79 if target < SMALL_PRIMES_NEXT {
81 return SMALL_PRIMES.binary_search(&(target as u16)).is_ok();
83 } else {
84 let pos = (target % WHEEL_SIZE as u64) as usize;
87 if pos == 0 || WHEEL_NEXT[pos] < WHEEL_NEXT[pos - 1] {
88 return false;
89 }
90 }
91
92 is_prime64_miller(target)
94}
95
96#[cfg(not(feature = "big-table"))]
99fn is_prime64_miller(target: u64) -> bool {
100 if let Ok(u) = u32::try_from(target) {
102 const WITNESS32: [u32; 3] = [2, 7, 61];
103 let u = SmallMint::from(u);
104 WITNESS32.iter().all(|&x| u.is_sprp(SmallMint::from(x)))
105 } else {
106 const WITNESS64: [u64; 7] = [2, 325, 9375, 28178, 450775, 9780504, 1795265022];
107 let u = SmallMint::from(target);
108 WITNESS64.iter().all(|&x| u.is_sprp(SmallMint::from(x)))
109 }
110}
111
112#[cfg(feature = "big-table")]
113fn is_prime32_miller(target: u32) -> bool {
114 let h = target as u64;
115 let h = ((h >> 16) ^ h).wrapping_mul(0x45d9f3b);
116 let h = ((h >> 16) ^ h).wrapping_mul(0x45d9f3b);
117 let h = ((h >> 16) ^ h) & 255;
118 let u = SmallMint::from(target);
119 return u.is_sprp(SmallMint::from(MILLER_RABIN_BASE32[h as usize] as u32));
120}
121
122#[cfg(feature = "big-table")]
125fn is_prime64_miller(target: u64) -> bool {
126 if let Ok(u) = u32::try_from(target) {
127 return is_prime32_miller(u);
128 }
129
130 let u = SmallMint::from(target);
131 if !u.is_sprp(2.into()) {
132 return false;
133 }
134
135 let h = target;
136 let h = ((h >> 32) ^ h).wrapping_mul(0x45d9f3b3335b369);
137 let h = ((h >> 32) ^ h).wrapping_mul(0x3335b36945d9f3b);
138 let h = ((h >> 32) ^ h) & 16383;
139 let b = MILLER_RABIN_BASE64[h as usize];
140 return u.is_sprp((b as u64 & 4095).into()) && u.is_sprp((b as u64 >> 12).into());
141}
142
143pub fn factorize64(target: u64) -> BTreeMap<u64, usize> {
149 let mut result = BTreeMap::new();
160
161 let f2 = target.trailing_zeros();
163 if f2 == 0 {
164 if is_prime64(target) {
165 result.insert(target, 1);
166 return result;
167 }
168 } else {
169 result.insert(2, f2 as usize);
170 }
171
172 let tsqrt = target.sqrt() + 1;
174
175 let mut residual = target >> f2;
176 let mut factored = false;
177
178 #[cfg(not(feature = "big-table"))]
179 for p in SMALL_PRIMES.iter().skip(1).map(|&v| v as u64) {
180 if p > tsqrt {
181 factored = true;
182 break;
183 }
184
185 while residual % p == 0 {
186 residual = residual / p;
187 *result.entry(p).or_insert(0) += 1;
188 }
189 if residual == 1 {
190 factored = true;
191 break;
192 }
193 }
194
195 #[cfg(feature = "big-table")]
196 for (p, &pinv) in SMALL_PRIMES
198 .iter()
199 .map(|&p| p as u64)
200 .zip(SMALL_PRIMES_INV.iter())
201 .skip(1)
202 {
203 if p > tsqrt {
205 factored = true;
206 break;
207 }
208
209 let mut exp: usize = 0;
210 while let Some(q) = residual.div_exact(p, &pinv) {
211 exp += 1;
212 residual = q;
213 }
214 if exp > 0 {
215 result.insert(p, exp);
216 }
217
218 if residual == 1 {
219 factored = true;
220 break;
221 }
222 }
223
224 if factored {
225 if residual != 1 {
226 result.insert(residual, 1);
227 }
228 return result;
229 }
230
231 for (p, exp) in factorize64_advanced(&[(residual, 1usize)]).into_iter() {
233 *result.entry(p).or_insert(0) += exp;
234 }
235 result
236}
237
238pub(crate) fn factorize64_advanced(cofactors: &[(u64, usize)]) -> Vec<(u64, usize)> {
240 let mut todo: Vec<_> = cofactors.iter().cloned().collect();
241 let mut factored: Vec<(u64, usize)> = Vec::new(); while let Some((target, exp)) = todo.pop() {
244 if is_prime64_miller(target) {
245 factored.push((target, exp));
246 continue;
247 }
248
249 if let Some(d) = target.sqrt_exact() {
253 todo.push((d, exp * 2));
254 continue;
255 }
256 if let Some(d) = target.cbrt_exact() {
257 todo.push((d, exp * 3));
258 continue;
259 }
260
261 let mut i = 0usize;
263 let mut max_iter_ratio = 1; let divisor = loop {
265 const NMETHODS: usize = 3;
267 match i % NMETHODS {
268 0 => {
269 let start = MontgomeryInt::new(random::<u64>(), &target);
271 let offset = start.convert(random::<u64>());
272 let max_iter = max_iter_ratio << (target.bits() / 6); if let (Some(p), _) = pollard_rho(
274 &SmallMint::from(target),
275 start.into(),
276 offset.into(),
277 max_iter,
278 ) {
279 break p.value();
280 }
281 }
282 1 => {
283 let mul_target = target.checked_mul(480).unwrap_or(target);
285 let max_iter = max_iter_ratio << (mul_target.bits() / 6); if let (Some(p), _) = one_line(&target, mul_target, max_iter) {
287 break p;
288 }
289 }
290 2 => {
291 let mut d = None;
293 for &k in SQUFOF_MULTIPLIERS.iter() {
294 if let Some(mul_target) = target.checked_mul(k as u64) {
295 let max_iter = max_iter_ratio * 2 * mul_target.sqrt().sqrt() as usize;
296 if let (Some(p), _) = squfof(&target, mul_target, max_iter) {
297 d = Some(p);
298 break;
299 }
300 }
301 }
302 if let Some(p) = d {
303 break p;
304 }
305 }
306 _ => unreachable!(),
307 }
308 i += 1;
309
310 if i % NMETHODS == 0 {
312 max_iter_ratio *= 2;
313 }
314 };
315 todo.push((divisor, exp));
316 todo.push((target / divisor, exp));
317 }
318 factored
319}
320
321pub fn factorize128(target: u128) -> BTreeMap<u128, usize> {
324 if target < (1u128 << 64) {
326 return factorize64(target as u64)
327 .into_iter()
328 .map(|(k, v)| (k as u128, v))
329 .collect();
330 }
331
332 let mut result = BTreeMap::new();
333
334 let f2 = target.trailing_zeros();
336 if f2 != 0 {
337 result.insert(2, f2 as usize);
338 }
339 let mut residual = target >> f2;
340
341 #[cfg(not(feature = "big-table"))]
344 for p in SMALL_PRIMES.iter().skip(1).map(|&v| v as u128) {
345 while residual % p == 0 {
346 residual = residual / p;
347 *result.entry(p).or_insert(0) += 1;
348 }
349 if residual == 1 {
350 return result;
351 }
352 }
353
354 #[cfg(feature = "big-table")]
355 for (p, &pinv) in SMALL_PRIMES
357 .iter()
358 .map(|&p| p as u64)
359 .zip(SMALL_PRIMES_INV.iter())
360 .skip(1)
361 {
362 let mut exp: usize = 0;
363 while let Some(q) = residual.div_exact(p, &pinv) {
364 exp += 1;
365 residual = q;
366 }
367 if exp > 0 {
368 result.insert(p as u128, exp);
369 }
370
371 if residual == 1 {
372 return result;
373 }
374 }
375
376 for (p, exp) in factorize128_advanced(&[(residual, 1usize)]).into_iter() {
378 *result.entry(p).or_insert(0) += exp;
379 }
380 result
381}
382
383pub(crate) fn factorize128_advanced(cofactors: &[(u128, usize)]) -> Vec<(u128, usize)> {
384 let (mut todo128, mut todo64) = (Vec::new(), Vec::new()); let mut factored: Vec<(u128, usize)> = Vec::new(); for &(co, e) in cofactors.iter() {
387 if let Ok(co64) = u64::try_from(co) {
388 todo64.push((co64, e));
389 } else {
390 todo128.push((co, e));
391 };
392 }
393
394 while let Some((target, exp)) = todo128.pop() {
395 if is_prime(&SmallMint::from(target), Some(PrimalityTestConfig::bpsw())).probably() {
396 factored.push((target, exp));
397 continue;
398 }
399
400 if let Some(d) = target.sqrt_exact() {
404 if let Ok(d64) = u64::try_from(d) {
405 todo64.push((d64, exp * 2));
406 } else {
407 todo128.push((d, exp * 2));
408 }
409 continue;
410 }
411 if let Some(d) = target.cbrt_exact() {
412 if let Ok(d64) = u64::try_from(d) {
413 todo64.push((d64, exp * 3));
414 } else {
415 todo128.push((d, exp * 3));
416 }
417 continue;
418 }
419 let mut i = 0usize;
423 let mut max_iter_ratio = 1;
424
425 let divisor = loop {
426 const NMETHODS: usize = 3;
428 match i % NMETHODS {
429 0 => {
430 let start = MontgomeryInt::new(random::<u128>(), &target);
432 let offset = start.convert(random::<u128>());
433 let max_iter = max_iter_ratio << (target.bits() / 6); if let (Some(p), _) = pollard_rho(
435 &SmallMint::from(target),
436 start.into(),
437 offset.into(),
438 max_iter,
439 ) {
440 break p.value();
441 }
442 }
443 1 => {
444 let mul_target = target.checked_mul(480).unwrap_or(target);
446 let max_iter = max_iter_ratio << (mul_target.bits() / 6); if let (Some(p), _) = one_line(&target, mul_target, max_iter) {
448 break p;
449 }
450 }
451 2 => {
452 let mut d = None;
454 for &k in SQUFOF_MULTIPLIERS.iter() {
455 if let Some(mul_target) = target.checked_mul(k as u128) {
456 let max_iter = max_iter_ratio * 2 * mul_target.sqrt().sqrt() as usize;
457 if let (Some(p), _) = squfof(&target, mul_target, max_iter) {
458 d = Some(p);
459 break;
460 }
461 }
462 }
463 if let Some(p) = d {
464 break p;
465 }
466 }
467 _ => unreachable!(),
468 }
469 i += 1;
470
471 if i % NMETHODS == 0 {
473 max_iter_ratio *= 2;
474 }
475 };
476
477 if let Ok(d64) = u64::try_from(divisor) {
478 todo64.push((d64, exp));
479 } else {
480 todo128.push((divisor, exp));
481 }
482 let co = target / divisor;
483 if let Ok(d64) = u64::try_from(co) {
484 todo64.push((d64, exp));
485 } else {
486 todo128.push((co, exp));
487 }
488 }
489
490 factored.extend(
492 factorize64_advanced(&todo64)
493 .into_iter()
494 .map(|(p, exp)| (p as u128, exp)),
495 );
496 factored
497}
498
499pub fn is_prime<T: PrimalityBase>(target: &T, config: Option<PrimalityTestConfig>) -> Primality
503where
504 for<'r> &'r T: PrimalityRefBase<T>,
505{
506 NaiveBuffer::new().is_prime(target, config)
507}
508
509pub fn factors<T: PrimalityBase>(
513 target: T,
514 config: Option<FactorizationConfig>,
515) -> (BTreeMap<T, usize>, Option<Vec<T>>)
516where
517 for<'r> &'r T: PrimalityRefBase<T>,
518{
519 NaiveBuffer::new().factors(target, config)
520}
521
522pub fn factorize<T: PrimalityBase>(target: T) -> BTreeMap<T, usize>
526where
527 for<'r> &'r T: PrimalityRefBase<T>,
528{
529 NaiveBuffer::new().factorize(target)
530}
531
532pub fn primes(limit: u64) -> Vec<u64> {
536 NaiveBuffer::new().into_primes(limit).collect()
537}
538
539pub fn nprimes(count: usize) -> Vec<u64> {
543 NaiveBuffer::new().into_nprimes(count).collect()
544}
545
546pub fn prime_pi(limit: u64) -> u64 {
550 NaiveBuffer::new().prime_pi(limit)
551}
552
553pub fn nth_prime(n: u64) -> u64 {
557 NaiveBuffer::new().nth_prime(n)
558}
559
560pub fn primorial<T: PrimalityBase + std::iter::Product>(n: usize) -> T {
562 NaiveBuffer::new()
563 .into_nprimes(n)
564 .map(|p| T::from_u64(p).unwrap())
565 .product()
566}
567
568pub fn moebius<T: PrimalityBase>(target: &T) -> i8
578where
579 for<'r> &'r T: PrimalityRefBase<T>,
580{
581 if target.is_even() {
583 let two = T::one() + T::one();
584 let four = &two + &two;
585 if (target % four).is_zero() {
586 return 0;
587 } else {
588 return -moebius(&(target / &two));
589 }
590 }
591
592 if let Some(v) = (target - T::one()).to_u8() {
594 let m = MOEBIUS_ODD[(v >> 6) as usize];
595 let m = m & (3 << (v & 63));
596 let m = m >> (v & 63);
597 return m as i8 - 1;
598 }
599
600 let three_sq = T::from_u8(9).unwrap();
602 let five_sq = T::from_u8(25).unwrap();
603 let seven_sq = T::from_u8(49).unwrap();
604 if (target % three_sq).is_zero()
605 || (target % five_sq).is_zero()
606 || (target % seven_sq).is_zero()
607 {
608 return 0;
609 }
610
611 moebius_factorized(&factorize(target.clone()))
613}
614
615pub fn moebius_factorized<T>(factors: &BTreeMap<T, usize>) -> i8 {
618 if factors.values().any(|exp| exp > &1) {
619 0
620 } else if factors.len() % 2 == 0 {
621 1
622 } else {
623 -1
624 }
625}
626
627pub fn is_square_free<T: PrimalityBase>(target: &T) -> bool
632where
633 for<'r> &'r T: PrimalityRefBase<T>,
634{
635 moebius(target) != 0
636}
637
638pub fn prime_pi_bounds<T: ToPrimitive + FromPrimitive>(target: &T) -> (T, T) {
647 if let Some(x) = target.to_u64() {
648 if x <= (*SMALL_PRIMES.last().unwrap()) as u64 {
650 #[cfg(not(feature = "big-table"))]
651 let pos = SMALL_PRIMES.binary_search(&(x as u8));
652 #[cfg(feature = "big-table")]
653 let pos = SMALL_PRIMES.binary_search(&(x as u16));
654
655 let n = match pos {
656 Ok(p) => p + 1,
657 Err(p) => p,
658 };
659 return (T::from_usize(n).unwrap(), T::from_usize(n).unwrap());
660 }
661
662 let n = x as f64;
664 let ln = n.ln();
665 let invln = ln.recip();
666
667 let lo = match () {
668 _ if x >= 468049 => n / (ln - 1. - invln),
670 _ if x >= 88789 => n * invln * (1. + invln * (1. + 2. * invln)),
672 _ if x >= 5393 => n / (ln - 1.),
674 _ if x >= 599 => n * invln * (1. + invln),
676 _ => n * invln,
678 };
679 let hi = match () {
680 _ if x >= 7398600000 => n * invln * (1. + invln * (1. + invln * (2. + invln * 7.59))),
682 _ if x >= 2953652287 => n * invln * (1. + invln * (1. + invln * 2.334)),
684 _ if x >= 467345 => n / (ln - 1. - 1.2311 * invln),
686 _ if x >= 29927 => n * invln * (1. + invln * (1. + invln * 2.53816)),
688 _ if x >= 5668 => n / (ln - 1.112),
690 _ if x >= 148 => n * invln * (1. + invln * 1.2762),
692 _ => 1.25506 * n * invln,
694 };
695 (T::from_f64(lo).unwrap(), T::from_f64(hi).unwrap())
696 } else {
697 let n = target.to_f64().unwrap();
698 let ln = n.ln();
699 let invln = ln.recip();
700
701 let lo = n / (ln - 1. - invln);
703 let hi = n * invln * (1. + invln * (1. + invln * (2. + invln * 7.59)));
704 (T::from_f64(lo).unwrap(), T::from_f64(hi).unwrap())
705 }
706}
707
708pub fn nth_prime_bounds<T: ToPrimitive + FromPrimitive>(target: &T) -> Option<(T, T)> {
726 if let Some(x) = target.to_usize() {
727 if x == 0 {
728 return Some((T::from_u8(0).unwrap(), T::from_u8(0).unwrap()));
729 }
730
731 if x <= SMALL_PRIMES.len() {
733 let p = SMALL_PRIMES[x - 1];
734
735 #[cfg(not(feature = "big-table"))]
736 return Some((T::from_u8(p).unwrap(), T::from_u8(p).unwrap()));
737
738 #[cfg(feature = "big-table")]
739 return Some((T::from_u16(p).unwrap(), T::from_u16(p).unwrap()));
740 }
741
742 let n = x as f64;
744 let ln = n.ln();
745 let lnln = ln.ln();
746
747 let lo = match () {
748 _ if x >= 317200 => {
750 n * (ln + lnln - 1. + (lnln - 2.) / ln
751 - (lnln * lnln - 6. * lnln + 11.321) / (2. * ln * ln))
752 }
753 _ if x >= 3520 => n * (ln + lnln - 1. + (lnln - 2.1) / ln),
755 _ => n * (ln + lnln - 1.),
757 };
758 let hi = match () {
759 _ if x >= 46254381 => {
761 n * (ln + lnln - 1. + (lnln - 2.) / ln
762 - (lnln * lnln - 6. * lnln + 10.667) / (2. * ln * ln))
763 }
764 _ if x >= 8009824 => {
766 n * (ln + lnln - 1. + (lnln - 2.) / ln
767 - (lnln * lnln - 6. * lnln + 10.273) / (2. * ln * ln))
768 }
769 _ if x >= 688383 => n * (ln + lnln - 1. + (lnln - 2.) / ln),
771 _ if x >= 178974 => n * (ln + lnln - 1. + (lnln - 1.95) / ln),
773 _ if x >= 39017 => n * (ln + lnln - 0.9484),
775 _ if x >= 27076 => n * (ln + lnln - 1. + (lnln - 1.8) / ln),
777 _ => n * (ln + lnln - 0.5),
779 };
780 Some((T::from_f64(lo)?, T::from_f64(hi)?))
781 } else {
782 let n = target.to_f64().unwrap();
783 let ln = n.ln();
784 let lnln = ln.ln();
785
786 let lo = n
788 * (ln + lnln - 1. + (lnln - 2.) / ln
789 - (lnln * lnln - 6. * lnln + 11.321) / (2. * ln * ln));
790 let hi = n
791 * (ln + lnln - 1. + (lnln - 2.) / ln
792 - (lnln * lnln - 6. * lnln + 10.667) / (2. * ln * ln));
793 Some((T::from_f64(lo)?, T::from_f64(hi)?))
794 }
795}
796
797pub fn is_safe_prime<T: PrimalityBase>(target: &T) -> Primality
800where
801 for<'r> &'r T: PrimalityRefBase<T>,
802{
803 let buf = NaiveBuffer::new();
804 let config = Some(PrimalityTestConfig::strict());
805
806 let sophie_p = buf.is_prime(&(target >> 1), config);
808 if matches!(sophie_p, Primality::No) {
809 return sophie_p;
810 }
811
812 let target_p = buf.is_prime(target, config);
814 target_p & sophie_p
815}
816
817#[cfg(not(feature = "big-table"))]
820pub fn next_prime<T: PrimalityBase + CheckedAdd>(
821 target: &T,
822 config: Option<PrimalityTestConfig>,
823) -> Option<T>
824where
825 for<'r> &'r T: PrimalityRefBase<T>,
826{
827 if let Some(x) = target.to_u8() {
829 return match SMALL_PRIMES.binary_search(&x) {
830 Ok(pos) => {
831 if pos + 1 == SMALL_PRIMES.len() {
832 T::from_u64(SMALL_PRIMES_NEXT)
833 } else {
834 T::from_u8(SMALL_PRIMES[pos + 1])
835 }
836 }
837 Err(pos) => T::from_u8(SMALL_PRIMES[pos]),
838 };
839 }
840
841 let mut i = (target % T::from_u8(WHEEL_SIZE).unwrap()).to_u8().unwrap();
843 let mut t = target.clone();
844 loop {
845 let offset = WHEEL_NEXT[i as usize];
846 t = t.checked_add(&T::from_u8(offset).unwrap())?;
847 i = i.addm(offset, &WHEEL_SIZE);
848 if is_prime(&t, config).probably() {
849 break Some(t);
850 }
851 }
852}
853
854#[cfg(feature = "big-table")]
857pub fn next_prime<T: PrimalityBase + CheckedAdd>(
858 target: &T,
859 config: Option<PrimalityTestConfig>,
860) -> Option<T>
861where
862 for<'r> &'r T: PrimalityRefBase<T>,
863{
864 if target <= &T::from_u8(255).unwrap() || target < &T::from_u16(*SMALL_PRIMES.last().unwrap()).unwrap()
867 {
868 let next = match SMALL_PRIMES.binary_search(&target.to_u16().unwrap()) {
869 Ok(pos) => SMALL_PRIMES[pos + 1],
870 Err(pos) => SMALL_PRIMES[pos],
871 };
872 return T::from_u16(next);
873 }
874
875 let mut i = (target % T::from_u16(WHEEL_SIZE).unwrap())
877 .to_u16()
878 .unwrap();
879 let mut t = target.clone();
880 loop {
881 let offset = WHEEL_NEXT[i as usize];
882 t = t.checked_add(&T::from_u8(offset).unwrap())?;
883 i = i.addm(offset as u16, &WHEEL_SIZE);
884 if is_prime(&t, config).probably() {
885 break Some(t);
886 }
887 }
888}
889
890#[cfg(not(feature = "big-table"))]
893pub fn prev_prime<T: PrimalityBase>(target: &T, config: Option<PrimalityTestConfig>) -> Option<T>
894where
895 for<'r> &'r T: PrimalityRefBase<T>,
896{
897 if target <= &(T::one() + T::one()) {
898 return None;
899 }
900
901 if let Some(x) = target.to_u8() {
903 let next = match SMALL_PRIMES.binary_search(&x) {
904 Ok(pos) => SMALL_PRIMES[pos - 1],
905 Err(pos) => SMALL_PRIMES[pos - 1],
906 };
907 return Some(T::from_u8(next).unwrap());
908 }
909
910 let mut i = (target % T::from_u8(WHEEL_SIZE).unwrap()).to_u8().unwrap();
912 let mut t = target.clone();
913 loop {
914 let offset = WHEEL_PREV[i as usize];
915 t = t - T::from_u8(offset).unwrap();
916 i = i.subm(offset, &WHEEL_SIZE);
917 if is_prime(&t, config).probably() {
918 break Some(t);
919 }
920 }
921}
922
923#[cfg(feature = "big-table")]
926pub fn prev_prime<T: PrimalityBase>(target: &T, config: Option<PrimalityTestConfig>) -> Option<T>
927where
928 for<'r> &'r T: PrimalityRefBase<T>,
929{
930 if target <= &(T::one() + T::one()) {
931 return None;
932 }
933
934 if target <= &T::from_u8(255).unwrap() || target < &T::from_u16(*SMALL_PRIMES.last().unwrap()).unwrap()
937 {
938 let next = match SMALL_PRIMES.binary_search(&target.to_u16().unwrap()) {
939 Ok(pos) => SMALL_PRIMES[pos - 1],
940 Err(pos) => SMALL_PRIMES[pos - 1],
941 };
942 return Some(T::from_u16(next).unwrap());
943 }
944
945 let mut i = (target % T::from_u16(WHEEL_SIZE).unwrap())
947 .to_u16()
948 .unwrap();
949 let mut t = target.clone();
950 loop {
951 let offset = WHEEL_PREV[i as usize];
952 t = t - T::from_u8(offset).unwrap();
953 i = i.subm(offset as u16, &WHEEL_SIZE);
954 if is_prime(&t, config).probably() {
955 break Some(t);
956 }
957 }
958}
959
960#[cfg(not(feature = "big-table"))]
962pub fn prime_pi_est<T: Num + ToPrimitive + FromPrimitive>(target: &T) -> T {
963 let (lo, hi) = prime_pi_bounds(target);
964 (lo + hi) / T::from_u8(2).unwrap()
965}
966
967#[cfg(feature = "big-table")]
972pub fn prime_pi_est<T: ToPrimitive + FromPrimitive>(target: &T) -> T {
973 if let Some(x) = target.to_u16() {
975 if x <= (*SMALL_PRIMES.last().unwrap()) as u16 {
976 let (lo, hi) = prime_pi_bounds(&x);
977 debug_assert_eq!(lo, hi);
978 return T::from_u16(lo).unwrap();
979 }
980 }
981
982 let lnln = target.to_f64().unwrap().ln().ln();
984 let mut total = 0f64;
985 let mut lnp = 0f64; let mut lnfac = 0f64; for k in 1usize..100 {
989 lnp += lnln;
990 let lnk = (k as f64).ln();
991 lnfac += lnk;
992 let lnzeta = if k > 64 { 0f64 } else { ZETA_LOG_TABLE[k - 1] };
993 let t = lnp - lnk - lnfac - lnzeta;
994 if t < -4. {
995 break;
997 }
998 total += t.exp();
999 }
1000 T::from_f64(total + 1f64).unwrap()
1001}
1002
1003pub fn nth_prime_est<T: ToPrimitive + FromPrimitive + Num + PartialOrd>(target: &T) -> Option<T>
1006where
1007 for<'r> &'r T: RefNum<T>,
1008{
1009 let (mut lo, mut hi) = nth_prime_bounds(target)?;
1010 if lo == hi {
1011 return Some(lo);
1012 }
1013
1014 while lo != &hi - T::from_u8(1).unwrap() {
1015 let x = (&lo + &hi) / T::from_u8(2).unwrap();
1016 let mid = prime_pi_est(&x);
1017 if &mid < target {
1018 lo = x
1019 } else if &mid > target {
1020 hi = x
1021 } else {
1022 return Some(x);
1023 }
1024 }
1025 return Some(lo);
1026}
1027
1028#[cfg(test)]
1037mod tests {
1038 use super::*;
1039 use rand::{prelude::SliceRandom, random};
1040 use std::iter::FromIterator;
1041
1042 #[test]
1043 fn is_prime64_test() {
1044 for x in 2..100 {
1046 assert_eq!(SMALL_PRIMES.contains(&x), is_prime64(x as u64));
1047 }
1048 assert!(is_prime64(677));
1049
1050 assert!(!is_prime64(9773));
1052 assert!(!is_prime64(13357));
1053 assert!(!is_prime64(18769));
1054
1055 assert!(is_prime64(6469693333));
1057 assert!(is_prime64(13756265695458089029));
1058 assert!(is_prime64(13496181268022124907));
1059 assert!(is_prime64(10953742525620032441));
1060 assert!(is_prime64(17908251027575790097));
1061
1062 assert!(is_prime64(480194653));
1064 assert!(!is_prime64(20074069));
1065 assert!(is_prime64(8718775377449));
1066 assert!(is_prime64(3315293452192821991));
1067 assert!(!is_prime64(8651776913431));
1068 assert!(!is_prime64(1152965996591997761));
1069
1070 assert!(!is_prime64(600437059821397));
1072 assert!(!is_prime64(3866032210719337));
1073 assert!(!is_prime64(4100599722623587));
1074
1075 let mut rng = rand::thread_rng();
1077 for _ in 0..100 {
1078 let x = random();
1079 if !is_prime64(x) {
1080 continue;
1081 }
1082 assert_ne!(x % (*SMALL_PRIMES.choose(&mut rng).unwrap() as u64), 0);
1083 }
1084
1085 for _ in 0..100 {
1087 let x = random::<u32>() as u64;
1088 let y = random::<u32>() as u64;
1089 assert!(!is_prime64(x * y));
1090 }
1091 }
1092
1093 #[test]
1094 fn factorize64_test() {
1095 let fac4095 = BTreeMap::from_iter([(3, 2), (5, 1), (7, 1), (13, 1)]);
1097 let fac = factorize64(4095);
1098 assert_eq!(fac, fac4095);
1099
1100 let fac123456789 = BTreeMap::from_iter([(3, 2), (3803, 1), (3607, 1)]);
1101 let fac = factorize64(123456789);
1102 assert_eq!(fac, fac123456789);
1103
1104 let fac1_17 = BTreeMap::from_iter([(2071723, 1), (5363222357, 1)]);
1105 let fac = factorize64(11111111111111111);
1106 assert_eq!(fac, fac1_17);
1107
1108 for exp in 2u32..5 {
1110 assert_eq!(
1111 factorize128(8167u128.pow(exp)),
1112 BTreeMap::from_iter([(8167, exp as usize)])
1113 );
1114 }
1115
1116 for _ in 0..100 {
1118 let x = random();
1119 let fac = factorize64(x);
1120 let mut prod = 1;
1121 for (p, exp) in fac {
1122 assert!(
1123 is_prime64(p),
1124 "factorization result should have prime factors! (get {})",
1125 p
1126 );
1127 prod *= p.pow(exp as u32);
1128 }
1129 assert_eq!(x, prod, "factorization check failed! ({} != {})", x, prod);
1130 }
1131 }
1132
1133 #[test]
1134 fn factorize128_test() {
1135 let fac_primorial19 =
1137 BTreeMap::from_iter(SMALL_PRIMES.iter().take(19).map(|&p| (p as u128, 1)));
1138 let fac = factorize128(7858321551080267055879090);
1139 assert_eq!(fac, fac_primorial19);
1140
1141 let fac_smallbig = BTreeMap::from_iter([(167, 1), (2417851639229258349412369, 1)]);
1142 let fac = factorize128(403781223751286144351865623);
1143 assert_eq!(fac, fac_smallbig);
1144
1145 for exp in 5u32..10 {
1147 assert_eq!(
1149 factorize128(8167u128.pow(exp)),
1150 BTreeMap::from_iter([(8167, exp as usize)])
1151 );
1152 }
1153
1154 for _ in 0..4 {
1156 let x = random::<u128>() >> 28; let fac = factorize128(x);
1158 let mut prod = 1;
1159 for (p, exp) in fac {
1160 assert!(
1161 is_prime(&p, None).probably(),
1162 "factorization result should have prime factors! (get {})",
1163 p
1164 );
1165 prod *= p.pow(exp as u32);
1166 }
1167 assert_eq!(x, prod, "factorization check failed! ({} != {})", x, prod);
1168 }
1169 }
1170
1171 #[test]
1172 fn is_safe_prime_test() {
1173 let safe_primes = [
1175 5u16, 7, 11, 23, 47, 59, 83, 107, 167, 179, 227, 263, 347, 359, 383, 467, 479, 503,
1176 563, 587, 719, 839, 863, 887, 983, 1019, 1187, 1283, 1307, 1319, 1367, 1439, 1487,
1177 1523, 1619, 1823, 1907,
1178 ];
1179 for p in SMALL_PRIMES {
1180 let p = p as u16;
1181 if p > 1500 {
1182 break;
1183 }
1184 assert_eq!(
1185 is_safe_prime(&p).probably(),
1186 safe_primes.iter().find(|&v| &p == v).is_some()
1187 );
1188 }
1189 }
1190
1191 #[test]
1192 fn moebius_test() {
1193 let mu20: [i8; 20] = [
1195 1, -1, -1, 0, -1, 1, -1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1, 0, -1, 0,
1196 ];
1197 for i in 0..20 {
1198 assert_eq!(moebius(&(i + 1)), mu20[i], "moebius on {}", i);
1199 }
1200
1201 assert_eq!(moebius(&1024u32), 0);
1203 assert_eq!(moebius(&(8081u32 * 8081)), 0);
1204
1205 let sphenic3: [u8; 20] = [
1207 30, 42, 66, 70, 78, 102, 105, 110, 114, 130, 138, 154, 165, 170, 174, 182, 186, 190,
1208 195, 222,
1209 ]; for i in 0..20 {
1211 assert_eq!(moebius(&sphenic3[i]), -1i8, "moebius on {}", sphenic3[i]);
1212 }
1213 let sphenic5: [u16; 23] = [
1214 2310, 2730, 3570, 3990, 4290, 4830, 5610, 6006, 6090, 6270, 6510, 6630, 7410, 7590,
1215 7770, 7854, 8610, 8778, 8970, 9030, 9282, 9570, 9690,
1216 ]; for i in 0..20 {
1218 assert_eq!(moebius(&sphenic5[i]), -1i8, "moebius on {}", sphenic5[i]);
1219 }
1220 }
1221
1222 #[test]
1223 fn prime_pi_bounds_test() {
1224 fn check(n: u64, pi: u64) {
1225 let (lo, hi) = prime_pi_bounds(&n);
1226 let est = prime_pi_est(&n);
1227 assert!(
1228 lo <= pi && pi <= hi,
1229 "fail to satisfy {} <= pi({}) = {} <= {}",
1230 lo,
1231 n,
1232 pi,
1233 hi
1234 );
1235 assert!(lo <= est && est <= hi);
1236 }
1237
1238 let mut pb = NaiveBuffer::new();
1240 let mut last = 0;
1241 for (i, p) in pb.primes(100000).cloned().enumerate() {
1242 for j in last..p {
1243 check(j, i as u64);
1244 }
1245 last = p;
1246 }
1247
1248 let pow10_values = [
1250 0,
1251 4,
1252 25,
1253 168,
1254 1229,
1255 9592,
1256 78498,
1257 664579,
1258 5761455,
1259 50847534,
1260 455052511,
1261 4118054813,
1262 37607912018,
1263 346065536839,
1264 3204941750802,
1265 29844570422669,
1266 279238341033925,
1267 2623557157654233,
1268 ];
1269 for (exponent, gt) in pow10_values.iter().enumerate() {
1270 let n = 10u64.pow(exponent as u32);
1271 check(n, *gt);
1272 }
1273 }
1274
1275 #[test]
1276 fn nth_prime_bounds_test() {
1277 fn check(n: u64, p: u64) {
1278 let (lo, hi) = super::nth_prime_bounds(&n).unwrap();
1279 assert!(
1280 lo <= p && p <= hi,
1281 "fail to satisfy: {} <= {}-th prime = {} <= {}",
1282 lo,
1283 n,
1284 p,
1285 hi
1286 );
1287 let est = super::nth_prime_est(&n).unwrap();
1288 assert!(lo <= est && est <= hi);
1289 }
1290
1291 let mut pb = NaiveBuffer::new();
1293 for (i, p) in pb.primes(100000).cloned().enumerate() {
1294 check(i as u64 + 1, p as u64);
1295 }
1296
1297 let pow10_values = [
1299 2,
1300 29,
1301 541,
1302 7919,
1303 104729,
1304 1299709,
1305 15485863,
1306 179424673,
1307 2038074743,
1308 22801763489,
1309 252097800623,
1310 2760727302517,
1311 29996224275833,
1312 323780508946331,
1313 3475385758524527,
1314 37124508045065437,
1315 ];
1316 for (exponent, nth_prime) in pow10_values.iter().enumerate() {
1317 let n = 10u64.pow(exponent as u32);
1318 check(n, *nth_prime);
1319 }
1320 }
1321
1322 #[test]
1323 fn prev_next_test() {
1324 assert_eq!(prev_prime(&2u32, None), None);
1325
1326 assert_eq!(prev_prime(&257u16, None), Some(251));
1328 assert_eq!(next_prime(&251u16, None), Some(257));
1329 assert_eq!(next_prime(&251u8, None), None);
1330 assert_eq!(prev_prime(&8167u16, None), Some(8161));
1331 assert_eq!(next_prime(&8161u16, None), Some(8167));
1332
1333 let twine_primes: [(u32, u32); 8] = [
1335 (2, 3), (3, 5),
1337 (5, 7),
1338 (11, 13),
1339 (17, 19),
1340 (29, 31),
1341 (41, 43),
1342 (617, 619),
1343 ];
1344 for (p1, p2) in twine_primes {
1345 assert_eq!(prev_prime(&p2, None).unwrap(), p1);
1346 assert_eq!(next_prime(&p1, None).unwrap(), p2);
1347 }
1348
1349 let adj10_primes: [(u32, u32); 7] = [
1350 (7, 11),
1351 (97, 101),
1352 (997, 1009),
1353 (9973, 10007),
1354 (99991, 100003),
1355 (999983, 1000003),
1356 (9999991, 10000019),
1357 ];
1358 for (i, (p1, p2)) in adj10_primes.iter().enumerate() {
1359 assert_eq!(prev_prime(p2, None).unwrap(), *p1);
1360 assert_eq!(next_prime(p1, None).unwrap(), *p2);
1361
1362 let pow = 10u32.pow((i + 1) as u32);
1363 assert_eq!(prev_prime(&pow, None).unwrap(), *p1);
1364 assert_eq!(next_prime(&pow, None).unwrap(), *p2);
1365 }
1366 }
1367}