lib_rapid/math/
primes.rs

1//! Traits and functions for handling primes and primality.
2
3// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
4// | Original implementations by Forisek, Jancina & J.A. Sory (rust-cas.org). |
5// | Further modified and optimised by NervousNullPtr.                        |
6// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
7
8use super::general::*;
9use crate::math::constants;
10/// Trait for prime functions.
11pub trait Primality {
12    /// Determines whether a number is prime.
13    /// # Returns
14    /// `true` if the number is prime, otherwise `false`.
15    /// # Warning
16    /// There is currently no implementation for `u128`/`i128`, because we want our own BigInt-implementation.
17    /// # Examples
18    /// ```
19    /// use lib_rapid::math::primes::Primality;
20    /// 
21    /// assert_eq!(false, (-2).is_prime());
22    /// assert_eq!(true, 8191.is_prime());
23    /// assert_eq!(false, 1.is_prime());
24    /// assert_eq!(false, 0.is_prime());
25    /// ```
26    /// ```
27    /// use lib_rapid::math::primes::{Primality, generate_primes};
28    /// 
29    /// let _p: Vec<usize>  = generate_primes(1000);
30    /// let p:  Vec<u64>    = _p.into_iter().map(|x: usize| x as u64).collect::<Vec<u64>>();
31    /// let mut f: Vec<u64> = Vec::new();
32    /// for i in 0..1000 {
33    ///     if (i as u64).is_prime() { f.push(i as u64); }
34    /// }
35    /// 
36    /// assert_eq!(p, f);
37    /// ```
38    /// ```
39    /// use lib_rapid::math::primes::{Primality, generate_primes};
40    /// 
41    /// let _p: Vec<usize> = generate_primes(100);
42    /// let p:  Vec<u8>    = _p.into_iter().map(|x: usize| x as u8).collect::<Vec<u8>>();
43    /// let mut f: Vec<u8> = Vec::new();
44    /// for i in 0..100 {
45    ///     if (i as u8).is_prime() { f.push(i as u8); }
46    /// }
47    /// 
48    /// assert_eq!(p, f);
49    /// ```
50    /// ```
51    /// use lib_rapid::math::primes::{Primality, generate_primes};
52    /// 
53    /// let _p: Vec<usize>  = generate_primes(1000);
54    /// let p:  Vec<u16>    = _p.into_iter().map(|x: usize| x as u16).collect::<Vec<u16>>();
55    /// let mut f: Vec<u16> = Vec::new();
56    /// 
57    /// for i in 0..1000 {
58    ///     if (i as u16).is_prime() { f.push(i as u16); }
59    /// }
60    /// 
61    /// assert_eq!(p, f);
62    /// ```
63    /// ```
64    /// use lib_rapid::math::primes::{Primality, generate_primes};
65    /// 
66    /// let _p: Vec<usize>  = generate_primes(1000);
67    /// let p:  Vec<u32>    = _p.into_iter().map(|x: usize| x as u32).collect::<Vec<u32>>();
68    /// let mut f: Vec<u32> = Vec::new();
69    /// for i in 0..1000 {
70    ///     if (i as u32).is_prime() { f.push(i as u32); }
71    /// }
72    /// 
73    /// assert_eq!(p, f);
74    /// ```
75    /// ```
76    /// use lib_rapid::math::primes::{Primality, generate_primes};
77    /// 
78    /// let _p: Vec<usize>   = generate_primes(1000);
79    /// let p:  Vec<u128>    = _p.into_iter().map(|x: usize| x as u128).collect::<Vec<u128>>();
80    /// let mut f: Vec<u128> = Vec::new();
81    /// for i in 0..1000 {
82    ///     if (i as u128).is_prime() { f.push(i as u128); }
83    /// }
84    /// 
85    /// assert_eq!(p, f);
86    /// assert_eq!(true, 18446744073709551557u64.is_prime());
87    /// ```
88    #[must_use]
89    fn is_prime(&self) -> bool;
90}
91
92impl Primality for u8 {
93    #[inline]
94    fn is_prime(&self) -> bool {
95        if self < &2
96        { return false; }
97
98        for i in constants::PRIMELIST[..6].iter() {
99            if *self == *i as u8
100            { return true; }
101            if self % *i as u8 == 0
102            { return false; }
103        }
104        true
105    }
106}
107
108impl Primality for u16 {// Splits 
109   fn is_prime(&self) -> bool {
110        if *self <= u8::MAX as u16
111        { return (*self as u8).is_prime(); }
112
113        constants::PRIMELIST.binary_search(self).is_ok()
114    }
115}
116
117impl Primality for u32 { 
118    fn is_prime(&self) -> bool {
119        if *self <= u16::MAX as u32
120        { return (*self as u16).is_prime(); }
121          
122            for i in constants::PRIMELIST[..30].iter() {
123                if self % *i as u32 == 0
124                { return false; }
125            }
126        machine_word_prime_32(*self)  
127    }
128}
129
130impl Primality for i32 {
131    fn is_prime(&self) -> bool {
132        if self <= &0 { return false; }
133        (*self as u32).is_prime()
134    }
135}
136
137impl Primality for u64 {
138   fn is_prime(&self) -> bool {
139        if *self <= u32::MAX as u64
140        { return (*self as u32).is_prime(); }
141
142        for i in constants::PRIMELIST[..30].iter() {
143            if self % *i as u64 == 0
144            { return false; }
145        }
146
147        machine_word_prime_64(*self)  
148   }
149}
150
151impl Primality for i64 {
152   fn is_prime(&self) -> bool {
153        if self <= &0 { return false; }
154        (*self as u64).is_prime()
155    }
156}
157
158impl Primality for u128 {
159    fn is_prime(&self) -> bool {
160        if *self <= u64::MAX as u128
161        { return (*self as u64).is_prime(); }
162        unimplemented!("is_prime is currently not implemented for u128/i128 values bigger than 2^64 - 1.")
163    }
164}
165
166impl Primality for i128 {
167    fn is_prime(&self) -> bool {
168        if self <= &0 { return false; }
169        (*self as u128).is_prime()
170    }
171}
172
173/// Generate a list of prime numbers in the interval `[2;limit[`.
174/// # Arguments
175/// * `limit: usize` The limit up to which the function should search for primes.
176/// # Returns
177/// A `Vec<usize>` containing a list of primes.
178/// # Examples
179/// ```
180/// use lib_rapid::math::primes::generate_primes;
181/// let p: Vec<usize> = vec![2, 3, 5, 7, 11, 13];
182/// let f: Vec<usize> = generate_primes(15);
183/// assert_eq!(p, f);
184/// ```
185#[must_use]
186pub fn generate_primes(limit: usize) -> Vec<usize> {
187    match limit {
188        0 | 1 => { return Vec::new(); }
189        2     => { return vec![2]; }
190        3     => { return vec![2, 3]; }
191        _     => { }
192    }
193
194    let mut res: Vec<usize> = Vec::with_capacity(limit >> 2 + 2);
195    res.push(2);
196    res.push(3);
197    let mut n: usize;
198    let mut sieve: Vec<bool> = vec![false; limit];
199    
200    for x in (1..).take_while(|n| n.square() < limit) {
201        for y in (1..).take_while(|n| n.square() < limit) {
202
203            n = 4 * x.square() + y.square();
204            if n <= limit && (n % 12 == 1 || n % 12 == 5)
205            { sieve[n] ^= true; }
206
207            n = 3 * x.square() + y.square();
208            if n <= limit && n % 12 == 7
209            { sieve[n] ^= true; }
210
211            if x > y {
212                n = 3 * x.square() - y.square();
213                if n <= limit && n % 12 == 11
214                { sieve[n] ^= true; }
215            }
216        }
217    }
218    
219    for r in (5..).take_while(|n| n.square() < limit) {
220        if sieve[r] {
221            for i in (r.square()..limit).step_by(r.square()) {
222                sieve[i] = false;
223            }
224        }
225    }
226
227    for (i, val) in sieve.iter().enumerate() {
228        if *val { res.push(i); }
229    }
230    res
231}
232#[must_use]
233fn machine_word_prime_32(n: u32) -> bool {
234    let mut x: u64 = (((n >> 16) ^ n) as u128 * 0x45d9f3b) as u64;
235            x      = (((x >> 16) ^ x) as u128 * 0x45d9f3b) as u64;
236            x      =  ((x >> 16) ^ x) & 255;
237
238    sprp_32(n, constants::BASES_32[x as usize] as u32)
239}
240#[must_use]
241fn machine_word_prime_64(x: u64) -> bool {
242
243    if !sprp_64(x, 2)
244    { return false; }
245
246    let mut h = x;
247    h         = (((h >> 32) ^ h) as u128 * 0x45d9f3b3335b369) as u64;
248    h         = (((h >> 32) ^ h) as u128 * 0x3335b36945d9f3b) as u64;
249    h         =   (h >> 32) ^ h;
250    
251    let b: u32 = constants::BASES_64[(h & 16383) as usize];
252    sprp_64(x, (b & 4095) as u64) && sprp_64(x, (b >> 12) as u64)
253}
254#[must_use]
255fn sprp_32(p: u32, base: u32) -> bool { // if base^p = 1 mod p || base^(d * 2^n)= -1
256    let zeroes: u32 = (p - 1).trailing_zeros(); // d * 2^n -1
257    let d:      u32 = (p - 1) >> zeroes;
258    let mut x:  u32 = mod_pow_32(&base, &d, &p); // base^d mod p
259
260    if x == 1 || x == p - 1 // base^p = 1 mod p || base^(d * 2^n)= -1
261    { return true; }
262
263    for _ in 0..zeroes - 1 { // checks for all d * 2^zeroes.
264        x = ((x as u64).square() % p as u64) as u32;
265        if x == p - 1
266        { return true; }
267    }
268    false
269}
270#[must_use]
271fn sprp_64(p: u64, base: u64) -> bool {
272    let zeroes: u32 = (p - 1).trailing_zeros();
273    let d:      u64 = (p - 1) >> zeroes;
274    let mut x:  u64 = mod_pow_64(&base, &d, &p);
275
276    if x == 1 || x == p - 1
277    { return true; }
278
279    for _ in 0..zeroes - 1 {
280        x = (((x as u128).square()) % p as u128) as u64;
281        if x == p - 1
282        { return true; }
283    }
284    false
285}
286#[must_use]
287const fn mod_pow_64(c: &u64, p: &u64, modulus: &u64) -> u64 {  
288    if *modulus == 0
289    { return *modulus; }
290    if *p == 0 
291    { return 1; }
292    let mut z:    u128 = 1;
293    let mut base: u128 = *c as u128;
294    let n:        u128 = *modulus as u128;
295    let mut pow:  u64  = *p;
296
297    while pow > 1 {
298
299        if pow & 1 == 0 {
300            base = base * base % n;
301            pow  >>= 1;
302            continue;
303        }
304        z    = base * z % n;
305        base = base * base % n;
306        pow  = (pow - 1) >> 1;
307    }
308    (base * z % n) as u64
309}
310#[must_use]
311const fn mod_pow_32(c: &u32, p: &u32, modulus: &u32) -> u32 {  
312    if *modulus == 0
313    { return 0; }
314    if *p == 0 
315    { return 1; }
316    let mut z:    u64 = 1;
317    let mut base: u64 = *c as u64;
318    let n:        u64 = *modulus as u64;
319    let mut pow:  u32 = *p;
320
321    while pow > 1 {
322
323        if pow & 1 == 0 {
324            base = base * base % n;
325            pow  >>= 1;
326            continue;
327        }
328        z = base * z % n;
329        base = base * base % n;
330        pow = (pow - 1) >> 1;
331    }
332    (base * z % n) as u32
333}