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}