malachite_base/num/arithmetic/primorial.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{CheckedPrimorial, Primorial};
10use crate::num::basic::integers::USIZE_IS_U32;
11use crate::num::conversion::traits::WrappingFrom;
12
13const PRIMORIALS_U8: [u8; 5] = [1, 2, 6, 30, 210];
14const PRIMORIALS_U16: [u16; 7] = [1, 2, 6, 30, 210, 2310, 30030];
15const PRIMORIALS_U32: [u32; 10] = [1, 2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870];
16const PRIMORIALS_U64: [u64; 16] = [
17 1,
18 2,
19 6,
20 30,
21 210,
22 2310,
23 30030,
24 510510,
25 9699690,
26 223092870,
27 6469693230,
28 200560490130,
29 7420738134810,
30 304250263527210,
31 13082761331670030,
32 614889782588491410,
33];
34const PRIMORIALS_U128: [u128; 27] = [
35 1,
36 2,
37 6,
38 30,
39 210,
40 2310,
41 30030,
42 510510,
43 9699690,
44 223092870,
45 6469693230,
46 200560490130,
47 7420738134810,
48 304250263527210,
49 13082761331670030,
50 614889782588491410,
51 32589158477190044730,
52 1922760350154212639070,
53 117288381359406970983270,
54 7858321551080267055879090,
55 557940830126698960967415390,
56 40729680599249024150621323470,
57 3217644767340672907899084554130,
58 267064515689275851355624017992790,
59 23768741896345550770650537601358310,
60 2305567963945518424753102147331756070,
61 232862364358497360900063316880507363070,
62];
63
64const PRIMORIAL_PRIMES_U8: [u64; 5] = [2, 3, 5, 7, 11];
65
66const PRIMORIAL_PRIMES_U16: [u64; 7] = [2, 3, 5, 7, 11, 13, 17];
67
68const PRIMORIAL_PRIMES_U32: [u64; 10] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
69
70const PRIMORIAL_PRIMES_U64: [u64; 16] =
71 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53];
72
73const PRIMORIAL_PRIMES_U128: [u64; 27] = [
74 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
75 101, 103,
76];
77
78macro_rules! impl_primorials_a {
79 ($t:ident, $ps:ident, $pps:ident) => {
80 impl CheckedPrimorial for $t {
81 /// Computes the primorial of a number: the product of all primes less than or equal to
82 /// it.
83 ///
84 /// The
85 /// [`checked_product_of_first_n_primes`](CheckedPrimorial::checked_product_of_first_n_primes)
86 /// function is similar; it computes the primorial of the $n$th prime.
87 ///
88 /// If the input is too large, the function returns `None`.
89 ///
90 /// $$
91 /// f(n) = \\begin{cases}
92 /// \operatorname{Some}(n\\#) & \text{if} \\quad n\\# < 2^W, \\\\
93 /// \operatorname{None} & \text{if} \\quad n\\# \geq 2^W,
94 /// \\end{cases}
95 /// $$
96 /// where $W$ is `Self::WIDTH`.
97 ///
98 /// # Worst-case complexity
99 /// Constant time and additional memory.
100 ///
101 /// # Examples
102 /// See [here](super::primorial#checked_primorial).
103 #[inline]
104 fn checked_primorial(n: u64) -> Option<$t> {
105 let i = match $pps.binary_search(&n) {
106 Ok(i) => i + 1,
107 Err(i) => i,
108 };
109 $ps.get(i).copied()
110 }
111
112 /// Computes the product of the first $n$ primes.
113 ///
114 /// The [`checked_primorial`](CheckedPrimorial::checked_primorial) function is similar;
115 /// it computes the product of all primes less than or equal to $n$.
116 ///
117 /// If the input is too large, the function returns `None`.
118 ///
119 /// $$
120 /// f(n) = \\begin{cases}
121 /// \operatorname{Some}(p_n\\#) & \text{if} \\quad p_n\\# < 2^W, \\\\
122 /// \operatorname{None} & \text{if} \\quad p_n\\# \geq 2^W,
123 /// \\end{cases}
124 /// $$
125 /// where $W$ is `Self::WIDTH`.
126 ///
127 /// # Worst-case complexity
128 /// Constant time and additional memory.
129 ///
130 /// # Examples
131 /// See [here](super::primorial#checked_product_of_first_n_primes).
132 #[inline]
133 fn checked_product_of_first_n_primes(n: u64) -> Option<$t> {
134 $ps.get(usize::try_from(n).ok()?).copied()
135 }
136 }
137 };
138}
139impl_primorials_a!(u8, PRIMORIALS_U8, PRIMORIAL_PRIMES_U8);
140impl_primorials_a!(u16, PRIMORIALS_U16, PRIMORIAL_PRIMES_U16);
141impl_primorials_a!(u32, PRIMORIALS_U32, PRIMORIAL_PRIMES_U32);
142impl_primorials_a!(u64, PRIMORIALS_U64, PRIMORIAL_PRIMES_U64);
143impl_primorials_a!(u128, PRIMORIALS_U128, PRIMORIAL_PRIMES_U128);
144
145impl CheckedPrimorial for usize {
146 /// Computes the primorial of a [`usize`]: the product of all primes less than or equal to it.
147 ///
148 /// The
149 /// [`checked_product_of_first_n_primes`](CheckedPrimorial::checked_product_of_first_n_primes)
150 /// function is similar; it computes the primorial of the $n$th prime.
151 ///
152 /// If the input is too large, the function returns `None`.
153 ///
154 /// $$
155 /// f(n) = \\begin{cases}
156 /// \operatorname{Some}(n\\#) & \text{if} \\quad n\\# < 2^W, \\\\
157 /// \operatorname{None} & \text{if} \\quad n\\# \geq 2^W,
158 /// \\end{cases}
159 /// $$
160 /// where $W$ is `usize::WIDTH`.
161 ///
162 /// # Worst-case complexity
163 /// Constant time and additional memory.
164 ///
165 /// # Examples
166 /// See [here](super::primorial#checked_primorial).
167 #[inline]
168 fn checked_primorial(n: u64) -> Option<usize> {
169 if USIZE_IS_U32 {
170 u32::checked_primorial(n).map(usize::wrapping_from)
171 } else {
172 u64::checked_primorial(n).map(usize::wrapping_from)
173 }
174 }
175
176 /// Computes the product of the first $n$ primes.
177 ///
178 /// The [`checked_primorial`](CheckedPrimorial::checked_primorial) function is similar; it
179 /// computes the product of all primes less than or equal to $n$.
180 ///
181 /// If the input is too large, the function returns `None`.
182 ///
183 /// $$
184 /// f(n) = \\begin{cases}
185 /// \operatorname{Some}(p_n\\#) & \text{if} \\quad p_n\\# < 2^W, \\\\
186 /// \operatorname{None} & \text{if} \\quad p_n\\# \geq 2^W,
187 /// \\end{cases}
188 /// $$
189 /// where $W$ is `usize::WIDTH`.
190 ///
191 /// # Worst-case complexity
192 /// Constant time and additional memory.
193 ///
194 /// # Examples
195 /// See [here](super::primorial#checked_product_of_first_n_primes).
196 #[inline]
197 fn checked_product_of_first_n_primes(n: u64) -> Option<usize> {
198 if USIZE_IS_U32 {
199 u32::checked_product_of_first_n_primes(n).map(usize::wrapping_from)
200 } else {
201 u64::checked_product_of_first_n_primes(n).map(usize::wrapping_from)
202 }
203 }
204}
205
206macro_rules! impl_primorials_b {
207 ($t:ident) => {
208 impl Primorial for $t {
209 /// Computes the primorial of a number: the product of all primes less than or equal to
210 /// it.
211 ///
212 /// The [`product_of_first_n_primes`](Primorial::product_of_first_n_primes) function is
213 /// similar; it computes the primorial of the $n$th prime.
214 ///
215 /// If the input is too large, the function panics. For a function that returns `None`
216 /// instead, try [`checked_primorial`](CheckedPrimorial::checked_primorial).
217 ///
218 /// $$
219 /// f(n) = n\\# = \prod_{p \leq n \atop p \\ \\text {prime}} p.
220 /// $$
221 ///
222 /// $n\\# = O(e^{(1+o(1))n})$.
223 ///
224 /// # Worst-case complexity
225 /// Constant time and additional memory.
226 ///
227 /// # Panics
228 /// Panics if the output is too large to be represented.
229 ///
230 /// # Examples
231 /// See [here](super::primorial#primorial).
232 #[inline]
233 fn primorial(n: u64) -> $t {
234 $t::checked_primorial(n).unwrap()
235 }
236
237 /// Computes the product of the first $n$ primes.
238 ///
239 /// The [`primorial`](Primorial::primorial) function is similar; it computes the product
240 /// of all primes less than or equal to $n$.
241 ///
242 /// If the input is too large, the function panics. For a function that returns `None`
243 /// instead, try
244 /// [`checked_product_of_first_n_primes`](CheckedPrimorial::checked_product_of_first_n_primes).
245 ///
246 /// $$
247 /// f(n) = p_n\\# = \prod_{k=1}^n p_n,
248 /// $$
249 /// where $p_n$ is the $n$th prime number.
250 ///
251 /// $p_n\\# = O\left ( \left ( \frac{1}{e}k\log k\left ( \frac{\log k}{e^2}k \right
252 /// )^{1/\log k} \right )^k \omega(1)\right )$.
253 ///
254 /// This asymptotic approximation is due to [Bart
255 /// Michels](https://math.stackexchange.com/a/1594930).
256 ///
257 /// # Worst-case complexity
258 /// Constant time and additional memory.
259 ///
260 /// # Panics
261 /// Panics if the output is too large to be represented.
262 ///
263 /// # Examples
264 /// See [here](super::primorial#product_of_first_n_primes).
265 #[inline]
266 fn product_of_first_n_primes(n: u64) -> $t {
267 $t::checked_product_of_first_n_primes(n).unwrap()
268 }
269 }
270 };
271}
272apply_to_unsigneds!(impl_primorials_b);