36
36
/// ### Customization
37
37
///
38
38
/// This sieve offers multiple customization options, which may improve performance.
39
- /// Here's an example that's suitable for numbers up to a billion on a machine where
40
- /// the CPU's L1 data cache is 128 KiB:
39
+ /// Here's an example that's suitable for numbers up to a billion on a 64-bit machine
40
+ /// where the CPU's L1 data cache is 128 KiB:
41
41
///
42
42
/// ```swift
43
- /// NBKPrimeSieve(cache: .KiB(128), wheel: .x11, culls: .x31 , capacity: 50863957)
43
+ /// NBKPrimeSieve(cache: .KiB(128), wheel: .x11, culls: .x67 , capacity: 50863957)
44
44
/// ```
45
45
///
46
46
/// - Note: The size of the cache determines the size of each increment.
47
47
///
48
48
public final class NBKPrimeSieve : CustomStringConvertible {
49
49
50
+ /// A collection of all the primes that fit in one byte.
51
+ ///
52
+ /// - Note: It contains `54` elements.
53
+ ///
54
+ @usableFromInline static let primes = [
55
+ 0002 , 0003 , 0005 , 0007 , 0011 , 0013 , 0017 , 0019 ,
56
+ 0023 , 0029 , 0031 , 0037 , 0041 , 0043 , 0047 , 0053 ,
57
+ 0059 , 0061 , 0067 , 0071 , 0073 , 0079 , 0083 , 0089 ,
58
+ 0097 , 0101 , 0103 , 0107 , 0109 , 0113 , 0127 , 0131 ,
59
+ 0137 , 0139 , 0149 , 0151 , 0157 , 0163 , 0167 , 0173 ,
60
+ 0179 , 0181 , 0191 , 0193 , 0197 , 0199 , 0211 , 0223 ,
61
+ 0227 , 0229 , 0233 , 0239 , 0241 , 0251 ] as [ UInt8 ]
62
+
50
63
//=------------------------------------------------------------------------=
51
64
// MARK: State
52
65
//=------------------------------------------------------------------------=
@@ -77,6 +90,14 @@ public final class NBKPrimeSieve: CustomStringConvertible {
77
90
// MARK: Initializers
78
91
//=------------------------------------------------------------------------=
79
92
93
+ /// Creates a new instance and sieves the first page.
94
+ ///
95
+ /// - Note: It uses the default arguments of the main initialization method.
96
+ ///
97
+ @inlinable public convenience init ( ) {
98
+ self . init ( ) !
99
+ }
100
+
80
101
/// Creates a new instance and sieves the first page.
81
102
///
82
103
/// - Parameter cache: A collection of bits used to mark composite numbers.
@@ -87,11 +108,16 @@ public final class NBKPrimeSieve: CustomStringConvertible {
87
108
///
88
109
/// - Parameter capacity: The prime buffer's minimum capacity.
89
110
///
111
+ /// - Requires: Each element in `wheel` must exist in `culls`.
112
+ ///
90
113
/// - Note: A page contains `1` odd number per bit in `cache`.
91
114
///
92
115
/// - Note: The defaults strike a balance between size and performance.
93
116
///
94
- public init ( cache: Cache = . KiB( 32 ) , wheel: Wheel = . x07, culls: Culls = . x11, capacity: Int ? = nil ) {
117
+ public init ? ( cache: Cache = . KiB( 4 ) , wheel: Wheel = . x07, culls: Culls = . x11, capacity: Int ? = nil ) {
118
+ //=--------------------------------------=
119
+ guard wheel. primes. last! <= culls. primes. last! else { return nil }
120
+ //=--------------------------------------=
95
121
self . cache = cache
96
122
self . wheel = wheel
97
123
self . culls = culls
@@ -147,12 +173,7 @@ extension NBKPrimeSieve {
147
173
// mark composites not hit by the wheel
148
174
//=--------------------------------------=
149
175
let iteration = 1 &+ NBK . PBI. quotient ( dividing: NBK . ZeroOrMore ( self . limit &>> 1 as UInt ) , by: NBK . PowerOf2 ( bitWidth: UInt . self) )
150
-
151
- for pattern in self . culls. patterns {
152
- var pattern = NBK . CyclicIterator ( pattern) !
153
- pattern. formIteration ( iteration)
154
- self . cache. sieve ( pattern: pattern)
155
- }
176
+ self . cache. sieve ( patterns: self . culls. patterns, iteration: iteration)
156
177
//=--------------------------------------=
157
178
// mark composites using prime elements
158
179
//=--------------------------------------=
@@ -172,8 +193,8 @@ extension NBKPrimeSieve {
172
193
guard product. partialValue <= limit, !product. overflow else { continue }
173
194
Swift . assert ( start <= product. partialValue)
174
195
175
- inner. setIndex ( unchecked: Int ( bitPattern: self . wheel. indices [ Int ( bitPattern: multiple % self . wheel. circumference) ] ) )
176
- cache. sieve ( from: ( product. partialValue &- start) &>> 1 as UInt , stride: { prime &* inner. next ( ) &>> 1 as UInt } ) // OK
196
+ inner. setIndex ( unchecked: Int ( bitPattern: self . wheel. indices [ Int ( bitPattern: multiple % self . wheel. circumference) ] ) )
197
+ self . cache. sieve ( from: ( product. partialValue &- start) &>> 1 as UInt , stride: { prime &* inner. next ( ) &>> 1 as UInt } ) // OK
177
198
}
178
199
//=--------------------------------------=
179
200
Self . commit ( & self . cache, to: & self . state)
@@ -198,15 +219,15 @@ extension NBKPrimeSieve {
198
219
state. elements. append ( position)
199
220
}
200
221
201
- cache. base [ index] = chunk . onesComplement ( )
222
+ cache. base [ index] = UInt . max
202
223
state. limit &+= UInt ( bitPattern: UInt . bitWidth) &<< 1 as UInt
203
224
}
204
225
}
205
226
206
227
@inline ( never) @inlinable static func makeInitialState( _ cache: inout Cache , _ wheel: Wheel , _ culls: Culls , _ capacity: Int ? ) -> State {
207
228
Swift . assert ( wheel. primes. first == 00000000000000002 )
208
229
Swift . assert ( culls. primes. first != 00000000000000002 )
209
- precondition ( wheel. primes. last! <= culls. primes. last!, " must cull multiples of each element in wheel " )
230
+ Swift . assert ( wheel. primes. last! <= culls. primes. last!, " must cull multiples of each element in wheel " )
210
231
Swift . assert ( wheel. primes [ 1 ... ] . allSatisfy ( culls. primes. contains) )
211
232
Swift . assert ( cache. base. allSatisfy { $0. onesComplement ( ) . isZero } )
212
233
//=--------------------------------------=
@@ -222,10 +243,7 @@ extension NBKPrimeSieve {
222
243
// mark each number in: 1, culls
223
244
//=--------------------------------------=
224
245
cache. base [ cache. base. startIndex] = ~ 1
225
-
226
- for pattern in culls. patterns {
227
- cache. sieve ( pattern: NBK . CyclicIterator ( pattern) !)
228
- }
246
+ cache. sieve ( patterns: culls. patterns)
229
247
//=--------------------------------------=
230
248
// mark each number in: composites
231
249
//=--------------------------------------=
@@ -366,28 +384,37 @@ extension NBKPrimeSieve {
366
384
// MARK: Transformations
367
385
//=--------------------------------------------------------------------=
368
386
369
- /// Sieves the `marks` with the given pattern `cycle`.
370
- @inlinable mutating func sieve( pattern cycle: NBK . CyclicIterator < [ UInt ] > ) {
371
- var cycle = cycle; for index in self . base. indices { self . base [ index] &= cycle. next ( ) }
387
+ /// Sieves this instance using cyclical bit `patterns` from `iteration`.
388
+ @inlinable mutating func sieve( patterns: [ [ UInt ] ] , iteration: UInt = 0 ) {
389
+ self . base. withUnsafeMutableBufferPointer { base in
390
+ for var pattern in patterns. lazy. map ( { NBK . CyclicIterator ( $0) ! } ) {
391
+ pattern. formIteration ( iteration)
392
+ for index in base. indices {
393
+ base [ index] &= pattern. next ( )
394
+ }
395
+ }
396
+ }
372
397
}
373
398
374
- /// Sieves the `marks` from `start` with strides of `increment`.
399
+ /// Sieves this instance from `start` with strides of `increment`.
375
400
///
376
401
/// - Requires: `increment() <= UInt.max - UInt.bitWidth + 1`
377
402
///
378
403
@inlinable mutating func sieve( from start: UInt , stride increment: ( ) -> UInt ) {
379
- var index = NBK . PBI. dividing ( NBK . ZeroOrMore ( start) , by: NBK . PowerOf2 ( bitWidth: UInt . self) )
380
- while index. quotient < UInt ( bitPattern: self . base. count) {
381
- var chunk = UInt . zero
382
-
383
- while index. remainder < UInt . bitWidth {
384
- chunk &+= 1 &<< index. remainder
385
- index. remainder &+= increment ( )
404
+ self . base. withUnsafeMutableBufferPointer { base in
405
+ var ( ( index) ) : QR < UInt , UInt > = NBK . PBI. dividing ( NBK . ZeroOrMore ( start) , by: NBK . PowerOf2 ( bitWidth: UInt . self) )
406
+ while index. quotient < UInt ( bitPattern: base. count) {
407
+ var chunk = UInt . zero
408
+
409
+ while index. remainder < UInt ( bitPattern: UInt . bitWidth) {
410
+ chunk &+= 1 &<< index. remainder
411
+ index. remainder &+= increment ( )
412
+ }
413
+
414
+ base [ Int ( bitPattern: index. quotient) ] &= chunk. onesComplement ( )
415
+ index. quotient &+= NBK . PBI . quotient ( dividing: NBK . ZeroOrMore ( index. remainder) , by: NBK . PowerOf2 ( bitWidth: UInt . self) )
416
+ index. remainder = NBK . PBI. remainder ( dividing: NBK . ZeroOrMore ( index. remainder) , by: NBK . PowerOf2 ( bitWidth: UInt . self) )
386
417
}
387
-
388
- self . base [ Int ( bitPattern: index. quotient) ] &= chunk. onesComplement ( )
389
- index. quotient &+= NBK . PBI . quotient ( dividing: NBK . ZeroOrMore ( index. remainder) , by: NBK . PowerOf2 ( bitWidth: UInt . self) )
390
- index. remainder = NBK . PBI. remainder ( dividing: NBK . ZeroOrMore ( index. remainder) , by: NBK . PowerOf2 ( bitWidth: UInt . self) )
391
418
}
392
419
}
393
420
}
@@ -406,29 +433,44 @@ extension NBKPrimeSieve {
406
433
/// A cyclical pattern used to skip small prime multiples.
407
434
@frozen public struct Wheel {
408
435
409
- /// A wheel formed by the sequence: 2.
436
+ /// A wheel formed by the sequence: `2`.
437
+ ///
438
+ /// - Note: It covers `2` elements in `1` increment.
439
+ ///
410
440
@inlinable public static var x02 : Self {
411
- Self ( primes: [ 2 ] )
441
+ Self ( primes: NBKPrimeSieve . primes [ ... 0 ] )
412
442
}
413
443
414
- /// A wheel formed by the sequence: 2, 3.
444
+ /// A wheel formed by the sequence: `2`, `3`.
445
+ ///
446
+ /// - Note: It covers `6` elements in `2` increments.
447
+ ///
415
448
@inlinable public static var x03 : Self {
416
- Self ( primes: [ 2 , 3 ] )
449
+ Self ( primes: NBKPrimeSieve . primes [ ... 1 ] )
417
450
}
418
451
419
- /// A wheel formed by the sequence: 2, 3, 5.
452
+ /// A wheel formed by the sequence: `2`, `3`, `5`.
453
+ ///
454
+ /// - Note: It covers `30` elements in `8` increments.
455
+ ///
420
456
@inlinable public static var x05 : Self {
421
- Self ( primes: [ 2 , 3 , 5 ] )
457
+ Self ( primes: NBKPrimeSieve . primes [ ... 2 ] )
422
458
}
423
459
424
- /// A wheel formed by the sequence: 2, 3, 5, 7.
460
+ /// A wheel formed by the sequence: `2`, `3`, `5`, `7`.
461
+ ///
462
+ /// - Note: It covers `210` elements in `48` increments.
463
+ ///
425
464
@inlinable public static var x07 : Self {
426
- Self ( primes: [ 2 , 3 , 5 , 7 ] )
465
+ Self ( primes: NBKPrimeSieve . primes [ ... 3 ] )
427
466
}
428
467
429
- /// A wheel formed by the sequence: 2, 3, 5, 7, 11.
468
+ /// A wheel formed by the sequence: `2`, `3`, `5`, `7`, `11`.
469
+ ///
470
+ /// - Note: It covers `2310` elements in `480` increments.
471
+ ///
430
472
@inlinable public static var x11 : Self {
431
- Self ( primes: [ 2 , 3 , 5 , 7 , 11 ] )
473
+ Self ( primes: NBKPrimeSieve . primes [ ... 4 ] )
432
474
}
433
475
434
476
//=--------------------------------------------------------------------=
@@ -490,6 +532,10 @@ extension NBKPrimeSieve {
490
532
// MARK: Initializers
491
533
//=--------------------------------------------------------------------=
492
534
535
+ @inlinable init ( primes: [ UInt8 ] . SubSequence) {
536
+ self . init ( primes: primes. map ( UInt . init ( truncatingIfNeeded: ) ) )
537
+ }
538
+
493
539
@usableFromInline init ( primes: [ UInt ] ) {
494
540
//=----------------------------------=
495
541
Swift . assert ( primes. allSatisfy ( { $0 >= 2 } ) )
@@ -508,7 +554,11 @@ extension NBKPrimeSieve {
508
554
let count = Int ( bitPattern: 1 + value) - self . values. count
509
555
self . values . append ( contentsOf: repeatElement ( value, count: count) )
510
556
self . indices. append ( contentsOf: repeatElement ( self . increments. count, count: count) )
511
- } ; self . increments. append ( self . circumference - self . values. last! + self . values. first!)
557
+ }
558
+
559
+ let last = self . values. last! // default to zero if empty is allowed
560
+ let first = self . values. first! // default to zero if empty is allowed
561
+ self . increments. append ( self . circumference - last + first)
512
562
}
513
563
}
514
564
}
@@ -524,41 +574,81 @@ extension NBKPrimeSieve {
524
574
//*========================================================================*
525
575
526
576
/// A collection of cyclical patterns used to cull multiples of small primes.
577
+ ///
578
+ /// - Note: Even numbers are culled by omission, not by bit pattern.
579
+ ///
527
580
@frozen public struct Culls {
528
581
529
- /// Cyclical bit patterns for multiples of: 3, 5, 7, 11.
530
- @inlinable public static var x11 : Self {
531
- Self ( primes: [ 3 , 5 , 7 , 11 ] )
582
+ /// Cyclical bit patterns for multiples of primes from `3` through `5`.
583
+ ///
584
+ /// - Note: It stores `15` elements and culls `2` primes in `1` loop.
585
+ ///
586
+ @inlinable public static var x05 : Self {
587
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 02 ] )
532
588
}
533
589
534
- /// Cyclical bit patterns for multiples of: 3, 5, 7, 11, 13.
535
- @inlinable public static var x13 : Self {
536
- Self ( primes: [ 3 , 5 , 7 , 11 , 13 ] )
590
+ /// Cyclical bit patterns for multiples of primes from `3` through `11`.
591
+ ///
592
+ /// - Note: It stores `68` elements and culls `4` primes in `2` loops.
593
+ ///
594
+ @inlinable public static var x11 : Self {
595
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 04 ] )
537
596
}
538
597
539
- /// Cyclical bit patterns for multiples of: 3, 5, 7, 11, 13, 17.
598
+ /// Cyclical bit patterns for multiples of primes from `3` through `17`.
599
+ ///
600
+ /// - Note: It stores `193` elements and culls `6` primes in `3` loops.
601
+ ///
540
602
@inlinable public static var x17 : Self {
541
- Self ( primes: [ 3 , 5 , 7 , 11 , 13 , 17 ] )
603
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 06 ] )
542
604
}
543
605
544
- /// Cyclical bit patterns for multiples of: 3, 5, 7, 11, 13, 17, 19.
545
- @inlinable public static var x19 : Self {
546
- Self ( primes: [ 3 , 5 , 7 , 11 , 13 , 17 , 19 ] )
606
+ /// Cyclical bit patterns for multiples of primes from `3` through `23`.
607
+ ///
608
+ /// - Note: It stores `426` elements and culls `8` primes in `4` loops.
609
+ ///
610
+ @inlinable public static var x23 : Self {
611
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 08 ] )
547
612
}
548
613
549
- /// Cyclical bit patterns for multiples of: 3, 5, 7, 11, 13, 17, 19, 23.
550
- @inlinable public static var x23 : Self {
551
- Self ( primes: [ 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 ] )
614
+ /// Cyclical bit patterns for multiples of primes from `3` through `31`.
615
+ ///
616
+ /// - Note: It stores `829` elements and culls `10` primes in `5` loops.
617
+ ///
618
+ @inlinable public static var x31 : Self {
619
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 10 ] )
552
620
}
553
621
554
- /// Cyclical bit patterns for multiples of: 3, 5, 7, 11, 13, 17, 19, 23, 29.
555
- @inlinable public static var x29 : Self {
556
- Self ( primes: [ 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 ] )
622
+ /// Cyclical bit patterns for multiples of primes from `3` through `41`.
623
+ ///
624
+ /// - Note: It stores `1466` elements and culls `12` primes in `6` loops.
625
+ ///
626
+ @inlinable public static var x41 : Self {
627
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 12 ] )
557
628
}
558
629
559
- /// Cyclical bit patterns for multiples of: 3, 5, 7, 11, 13, 17, 19, 23, 29, 31.
560
- @inlinable public static var x31 : Self {
561
- Self ( primes: [ 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 , 31 ] )
630
+ /// Cyclical bit patterns for multiples of primes from `3` through `47`.
631
+ ///
632
+ /// - Note: It stores `2383` elements and culls `14` primes in `7` loops.
633
+ ///
634
+ @inlinable public static var x47 : Self {
635
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 14 ] )
636
+ }
637
+
638
+ /// Cyclical bit patterns for multiples of primes from `3` through `59`.
639
+ ///
640
+ /// - Note: It stores `3662` elements and culls `16` primes in `8` loops.
641
+ ///
642
+ @inlinable public static var x59 : Self {
643
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 16 ] )
644
+ }
645
+
646
+ /// Cyclical bit patterns for multiples of primes from `3` through `67`.
647
+ ///
648
+ /// - Note: It stores `5373` elements and culls `18` primes in `9` loops.
649
+ ///
650
+ @inlinable public static var x67 : Self {
651
+ Self ( primes: NBKPrimeSieve . primes [ 1 ... 18 ] )
562
652
}
563
653
564
654
//=--------------------------------------------------------------------=
@@ -580,6 +670,10 @@ extension NBKPrimeSieve {
580
670
// MARK: Initializers
581
671
//=--------------------------------------------------------------------=
582
672
673
+ @inlinable init ( primes: [ UInt8 ] . SubSequence) {
674
+ self . init ( primes: primes. map ( UInt . init ( truncatingIfNeeded: ) ) )
675
+ }
676
+
583
677
@inlinable init ( primes: [ UInt ] ) {
584
678
self . primes = primes
585
679
self . patterns = Culls . patterns ( primes: self . primes)
@@ -591,9 +685,13 @@ extension NBKPrimeSieve {
591
685
592
686
/// Patterns grow multiplicatively, so chunking reduces memory cost.
593
687
///
594
- /// g([3, 5, 7, 11, 13]) -> [f([3, 13]), f([5, 11]), f([7])]
688
+ /// g([3, 5, 7, 11]) -> [f([3, 11]), f([5, 7])]
689
+ ///
690
+ /// - Requires: The number of primes should be even for performance reasons.
595
691
///
596
692
@usableFromInline static func patterns( primes: [ UInt ] ) -> [ [ UInt ] ] {
693
+ Swift . assert ( primes. count. isEven)
694
+
597
695
var patterns = [ [ UInt] ] ( )
598
696
var lhsIndex = primes. startIndex
599
697
var rhsIndex = primes. index ( before: primes. endIndex)
@@ -604,10 +702,6 @@ extension NBKPrimeSieve {
604
702
patterns. formIndex ( before: & rhsIndex)
605
703
}
606
704
607
- if lhsIndex == rhsIndex {
608
- patterns. append ( self . pattern ( primes: [ primes [ lhsIndex] ] ) )
609
- }
610
-
611
705
return patterns as [ [ UInt ] ]
612
706
}
613
707
0 commit comments