primal_estimate/lib.rs
1//! Estimate upper and lower bounds for the *n*-th prime, and π(*n*),
2//! the number of primes less than or equal to *n*.
3//!
4//! This is designed to be used via the `primal` crate.
5
6#[allow(dead_code)]
7mod tables;
8
9/// Returns estimated bounds for π(*n*), the number of primes less
10/// than or equal to `n`.
11///
12/// That is, if (*a*, *b*) = `estimate_prime_pi(n)`, *a* ≤ π(*n*) ≤
13/// *b*. The bounds used are proved in \[1], \[2, Théorème 1.10]
14/// (both summarised in \[2, pp. 14–15]), and \[3, Section 6.2].
15///
16/// \[1]: Barkley Rosser. "Explicit Bounds for Some Functions of Prime
17/// Numbers". American Journal of Mathematics 63 (1):
18/// 211–232. 1941. doi:[10.2307/2371291](http://dx.doi.org/10.2307/2371291).
19///
20/// \[2]: Dusart, Pierre. ["Autour de la fonction qui compte le nombre
21/// de nombres premiers."][pdf] PhD diss., Université de Limoges,
22/// 1998\.
23///
24/// [pdf]: http://www.unilim.fr/laco/theses/1998/T1998_01.html
25///
26/// \[3]: Dusart, Pierre. "Estimates of Some Functions Over Primes
27/// without R.H."
28/// ArXiv:[1002.0442](http://arxiv.org/abs/1002.0442). 2010.
29///
30/// # Examples
31///
32/// ```rust
33/// // the number of primes below 1e9
34/// let count_billion = 50_847_534;
35///
36/// let (low, high) = primal::estimate_prime_pi(1_000_000_000);
37/// // check the bounds are satisfied
38/// assert!(low <= count_billion && count_billion <= high);
39/// ```
40pub fn prime_pi(n: u64) -> (u64, u64) {
41 if n < tables::SMALL_PRIME_PI.len() as u64 {
42 let x = tables::SMALL_PRIME_PI[n as usize] as u64;
43 (x, x)
44 } else {
45 let n_ = n as f64;
46 let lg = n_.ln();
47 let inv_lg = 1.0 / lg;
48 let n_inv_lg = n_ * inv_lg;
49
50 let lo = match () {
51 // [3] Theorem 6.9 (6.7)
52 _ if n >= 88783_u64 => n_inv_lg * (1.0 + inv_lg * (1.0 + 2.0 * inv_lg)),
53 // [2] Theorem 1.10 (6.)
54 _ if n >= 32299_u64 => n_inv_lg * (1.0 + inv_lg * (1.0 + 1.8 * inv_lg)),
55 // [2] Theorem 1.10 (5.)
56 _ if n >= 5393_u64 => n_ / (lg - 1.0),
57 // [2] Theorem 1.10 (1.)
58 _ if n >= 599_u64 => n_inv_lg * (1.0 + inv_lg),
59 // [1]
60 _ => n_ / (lg + 2.0),
61 };
62
63 let hi = match () {
64 // [3] Theorem 6.9 (6.7)
65 _ if n >= 16537307828_u64 => n_inv_lg * (1.0 + inv_lg * (1.0 + 2.334 * inv_lg)),
66 // [2] Theorem 1.10 (3.)
67 _ if n >= 13220000000_u64 => n_inv_lg * (1.0 + 1.0992 * inv_lg),
68 // [3] Theorem 6.9 (6.7)
69 _ if n >= 2953652287_u64 => n_inv_lg * (1.0 + inv_lg * (1.0 + 2.334 * inv_lg)),
70 // [2] Theorem 1.10 (3.)
71 _ if n >= 355991_u64 => n_inv_lg * (1.0 + inv_lg * (1.0 + 2.51 * inv_lg)),
72 // [2] Theorem 1.10 (4.)
73 _ if n >= 60184_u64 => n_ / (lg - 1.1),
74 // [2] Theorem 1.10 (2.)
75 _ => n_inv_lg * (1.0 + 1.2762 * inv_lg),
76 };
77
78 (lo as u64, hi as u64)
79 }
80}
81
82/// Gives estimated bounds for *p<sub>n</sub>*, the `n`th prime number,
83/// 1-indexed (i.e. *p<sub>1</sub>* = 2, *p<sub>2</sub>* = 3).
84///
85/// That is, if (<i>a</i>,<i>b</i>) = `estimate_nth_prime(n)`, *a* ≤
86/// *p<sub>n</sub>* ≤ *b*. The bounds used are proved in \[1], \[2,
87/// Théorèmes 1.6–1.8] (both summarised in \[2, pp. 14–15]) and \[3,
88/// Section 6.1.2].
89///
90/// \[1]: Massias, Jean-Pierre; Robin, Guy. ["Bornes effectives pour
91/// certaines fonctions concernant les nombres
92/// premiers."](http://eudml.org/doc/247826) Journal de théorie des
93/// nombres de Bordeaux 8.1 (1996): 215-242.
94///
95/// \[2]: Dusart, Pierre. ["Autour de la fonction qui compte le nombre
96/// de nombres premiers."][pdf] PhD diss., Université de Limoges,
97/// 1998\.
98///
99/// [pdf]: http://www.unilim.fr/laco/theses/1998/T1998_01.html
100///
101/// \[3]: Dusart, Pierre. "Estimates of Some Functions Over Primes
102/// without R.H."
103/// ArXiv:[1002.0442](http://arxiv.org/abs/1002.0442). 2010.
104///
105/// # Examples
106///
107/// ```rust
108/// // the 1e9-th prime
109/// let billionth = 22_801_763_489;
110///
111/// let (low, high) = primal::estimate_nth_prime(1_000_000_000);
112/// // check the bounds are satisfied
113/// assert!(low <= billionth && billionth <= high);
114/// ```
115pub fn nth_prime(n: u64) -> (u64, u64) {
116 const MAX_VALID_INPUT: u64 = 425281711831682432;
117 assert!(n <= MAX_VALID_INPUT, "nth_prime({}) overflows a u64", n);
118
119 if n == 0 {
120 (0, 0)
121 } else if n <= tables::SMALL_PRIMES.len() as u64 {
122 // table is 0-indexed, n is 1-indexed, need to adjust.
123 let x = tables::SMALL_PRIMES[n as usize - 1] as u64;
124 (x, x)
125 } else {
126 let n_ = n as f64;
127 let lg = n_.ln();
128 let lglg = lg.ln();
129
130 let lo = match () {
131 // [2] Theorem 1.6
132 _ if n >= 3520_u64 => n_ * (lg + lglg - 1.0 + (lglg - 2.1) / lg),
133 // [1] Theorem A (ii)
134 _ => n_ * (lg + lglg - 1.0),
135 };
136
137 let hi = match () {
138 // [3] Proposition 6.6
139 _ if n >= 688383_u64 => n_ * (lg + lglg - 1.0 + (lglg - 2.0) / lg),
140 // [3] Lemma 6.5
141 _ if n >= 178974_u64 => n_ * (lg + lglg - 1.0 + (lglg - 1.95) / lg),
142 // [2] Theorem 1.8
143 _ if n >= 39017_u64 => n_ * (lg + lglg - 0.9484),
144 // [2] Theorem 1.7
145 _ if n >= 27076_u64 => n_ * (lg + lglg - 1.0 + (lglg - 1.8) / lg),
146 // [1] Theorem A (v)
147 _ if n >= 15985_u64 => n_ * (lg + lglg - 0.9427),
148 // [1] Theorem A (v)
149 _ if n >= 13_u64 => n_ * (lg + lglg - 1.0 + 1.8 * lglg / lg),
150 // [1] Theorem A (iv)
151 _ => n_ * (lg + lglg),
152 };
153 (lo as u64, hi as u64)
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use primal::Sieve;
160
161 #[test]
162 fn prime_pi() {
163 fn check(n: u64, pi: u64) {
164 let (lo, hi) = super::prime_pi(n);
165 assert!(lo <= pi && pi <= hi,
166 "found failing estimate at {}, should satisfy: {} <= {} <= {}",
167 n, lo, pi, hi)
168 }
169 let primes = Sieve::new(1_000_000);
170
171 let mut last = 0;
172 for (i, p) in primes.primes_from(0).enumerate() {
173 for j in last..p {
174 check(j as u64, i as u64);
175 }
176 last = p;
177 }
178
179 let sporadic = [
180 (1, 4),
181 (2, 25),
182 (3, 168),
183 (4, 1229),
184 (5, 9592),
185 (6, 78498),
186 (7, 664579),
187 (8, 5761455),
188 (9, 50847534),
189 (10, 455052511),
190 (11, 4118054813),
191 (12, 37607912018),
192 (13, 346065536839),
193 (14, 3204941750802),
194 (15, 29844570422669),
195 (16, 279238341033925),
196 (17, 2623557157654233),
197 ];
198 for &(exponent, real) in sporadic.iter() {
199 let n = 10u64.pow(exponent);
200 check(n, real);
201 }
202 }
203
204 #[test]
205 fn nth_prime() {
206 fn check(n: u64, p: u64) {
207 let (lo, hi) = super::nth_prime(n);
208 assert!(lo <= p && p <= hi,
209 "found failing estimate at {}, should satisfy: {} <= {} <= {}",
210 n, lo, p, hi);
211 }
212 let sieve = Sieve::new(1_000_000);
213
214 for (i, p) in sieve.primes_from(0).enumerate() {
215 let n = i as u64 + 1;
216 check(n, p as u64);
217 }
218
219 let sporadic = [
220 (0, 2),
221 (1, 29),
222 (2, 541),
223 (3, 7919),
224 (4, 104729),
225 (5, 1299709),
226 (6, 15485863),
227 (7, 179424673),
228 (8, 2038074743),
229 (9, 22801763489),
230 (10, 252097800623),
231 (11, 2760727302517),
232 (12, 29996224275833),
233 (13, 323780508946331),
234 (14, 3475385758524527),
235 (15, 37124508045065437),
236 ];
237
238 for &(exponent, nth_prime) in sporadic.iter() {
239 let n = 10u64.pow(exponent);
240 check(n, nth_prime);
241 }
242 }
243}