@@ -4,21 +4,40 @@ use core::fmt;
4
4
5
5
use crate :: isqrt;
6
6
7
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
8
+ pub ( crate ) struct SegmentedSieveError ;
9
+
10
+ impl fmt:: Display for SegmentedSieveError {
11
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
12
+ write ! ( f, "the upper limit was smaller than `N`" )
13
+ }
14
+ }
15
+
16
+ #[ cfg( feature = "std" ) ]
17
+ impl std:: error:: Error for SegmentedSieveError { }
18
+
7
19
/// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
8
20
/// Assumes that the base sieve contains the prime status of the `N` fist integers. The output is only meaningful
9
- /// for the numbers below `N^2`. Fails to compile if `N` is 0.
21
+ /// for the numbers below `N^2`.
22
+ ///
23
+ /// # Errors
24
+ ///
25
+ /// Returns an error if `upper_limit` < `N`
10
26
#[ must_use = "the function only returns a new value and does not modify its inputs" ]
11
27
pub ( crate ) const fn sieve_segment < const N : usize > (
12
28
base_sieve : & [ bool ; N ] ,
13
29
upper_limit : u64 ,
14
- ) -> [ bool ; N ] {
30
+ ) -> Result < [ bool ; N ] , SegmentedSieveError > {
15
31
let mut segment_sieve = [ true ; N ] ;
16
32
17
- let lower_limit = upper_limit - N as u64 ;
33
+ let lower_limit = match upper_limit. checked_sub ( N as u64 ) {
34
+ Some ( diff) => diff,
35
+ None => return Err ( SegmentedSieveError ) ,
36
+ } ;
18
37
19
38
if lower_limit == 0 && N > 1 {
20
39
// If the lower limit is 0 we can just return the base sieve.
21
- return * base_sieve;
40
+ return Ok ( * base_sieve) ;
22
41
} else if lower_limit == 1 && N > 0 {
23
42
// In case 1 is included in the upper sieve we need to treat it as a special case
24
43
// since it's not a multiple of any prime in `base_sieve` even though it's not prime.
@@ -48,7 +67,7 @@ pub(crate) const fn sieve_segment<const N: usize>(
48
67
i += 1 ;
49
68
}
50
69
51
- segment_sieve
70
+ Ok ( segment_sieve)
52
71
}
53
72
54
73
/// Returns an array of size `N` that indicates which of the `N` largest integers smaller than `upper_limit` are prime.
@@ -152,12 +171,16 @@ pub const fn sieve_lt<const N: usize, const MEM: usize>(
152
171
let base_sieve: [ bool ; MEM ] = sieve ( ) ;
153
172
154
173
// Use the result to sieve the higher range.
155
- let upper_sieve = sieve_segment ( & base_sieve, upper_limit) ;
174
+ let ( offset, upper_sieve) = match sieve_segment ( & base_sieve, upper_limit) {
175
+ Ok ( res) => ( 0 , res) ,
176
+ // The sieve contained more entries than there are non-negative numbers below the upper limit.
177
+ Err ( _) => ( ( MEM as u64 - upper_limit) as usize , base_sieve) ,
178
+ } ;
156
179
157
- let mut ans = [ false ; N ] ;
158
180
let mut i = 0 ;
181
+ let mut ans = [ false ; N ] ;
159
182
while i < N {
160
- ans[ N - 1 - i] = upper_sieve[ MEM - 1 - i] ;
183
+ ans[ N - 1 - i] = upper_sieve[ MEM - 1 - i - offset ] ;
161
184
i += 1 ;
162
185
}
163
186
Ok ( ans)
@@ -331,7 +354,10 @@ pub const fn sieve_geq<const N: usize, const MEM: usize>(
331
354
332
355
let base_sieve: [ bool ; MEM ] = sieve ( ) ;
333
356
334
- let upper_sieve = sieve_segment ( & base_sieve, upper_limit) ;
357
+ let upper_sieve = match sieve_segment ( & base_sieve, upper_limit) {
358
+ Ok ( res) => res,
359
+ Err ( _) => panic ! ( "this is already checked above" ) ,
360
+ } ;
335
361
336
362
let mut ans = [ false ; N ] ;
337
363
let mut i = 0 ;
@@ -397,13 +423,25 @@ macro_rules! sieve_segment {
397
423
398
424
#[ cfg( test) ]
399
425
mod test {
426
+ use crate :: sieve:: SegmentedSieveError ;
427
+
400
428
use super :: { sieve, sieve_segment} ;
401
429
402
430
#[ test]
403
431
fn test_consistency_of_sieve_segment ( ) {
404
- const P : [ bool ; 10 ] = sieve_segment ( & sieve ( ) , 10 ) ;
405
- const PP : [ bool ; 10 ] = sieve_segment ( & sieve ( ) , 11 ) ;
432
+ const P : [ bool ; 10 ] = match sieve_segment ( & sieve ( ) , 10 ) {
433
+ Ok ( s) => s,
434
+ Err ( _) => panic ! ( ) ,
435
+ } ;
436
+ const PP : [ bool ; 10 ] = match sieve_segment ( & sieve ( ) , 11 ) {
437
+ Ok ( s) => s,
438
+ Err ( _) => panic ! ( ) ,
439
+ } ;
406
440
assert_eq ! ( P , sieve( ) ) ;
407
441
assert_eq ! ( PP , sieve:: <11 >( ) [ 1 ..] ) ;
442
+ assert_eq ! (
443
+ sieve_segment:: <5 >( & [ false , false , true , true , false ] , 4 ) ,
444
+ Err ( SegmentedSieveError )
445
+ ) ;
408
446
}
409
447
}
0 commit comments