Skip to content

Commit 78523ef

Browse files
committed
feat: add sieve of atkin algorithm
1 parent b031a0b commit 78523ef

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package com.thealgorithms.maths;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Implementation of the Sieve of Atkin, an optimized algorithm to generate
8+
* all prime numbers up to a given limit.
9+
*
10+
* The Sieve of Atkin uses quadratic forms and modular arithmetic to identify
11+
* prime candidates, then eliminates multiples of squares. It is more efficient
12+
* than the Sieve of Eratosthenes for large limits.
13+
*/
14+
public final class SieveOfAtkin {
15+
16+
private SieveOfAtkin() {
17+
// Utlity class; prevent instantiation
18+
}
19+
20+
/**
21+
* Generates a list of all prime numbers up to the specified limit
22+
* using the Sieve of Atkin algorithm.
23+
*
24+
* @param limit the upper bound up to which primes are generated; must be zero or positive
25+
* @return a list of prime numbers up to the limit; empty if the limit is less than 2
26+
*/
27+
public static List<Integer> generatePrimes(int limit) {
28+
if (limit < 2) {
29+
return List.of();
30+
}
31+
32+
boolean[] sieve = new boolean[limit + 1];
33+
int sqrtLimit = (int) Math.sqrt(limit);
34+
35+
markQuadraticResidues(limit, sqrtLimit, sieve);
36+
eliminateMultiplesOfSquares(limit, sqrtLimit, sieve);
37+
38+
List<Integer> primes = new ArrayList<>();
39+
if (limit >= 2) primes.add(2);
40+
if (limit >= 3) primes.add(3);
41+
42+
for (int i = 5; i <= limit; i++) {
43+
if (sieve[i]) primes.add(i);
44+
}
45+
46+
return primes;
47+
}
48+
49+
/**
50+
* Marks numbers in the sieve as prime candidates based on quadratic residues.
51+
*
52+
* This method iterates over all x and y up to sqrt(limit) and applies
53+
* the three quadratic forms used in the Sieve of Atkin. Numbers satisfying
54+
* the modulo conditions are toggled in the sieve array.
55+
*
56+
* @param limit the upper bound for primes
57+
* @param sqrtLimit square root of the limit
58+
* @param sieve boolean array representing potential primes
59+
*/
60+
private static void markQuadraticResidues(int limit, int sqrtLimit, boolean[] sieve) {
61+
for (int x = 1; x <= sqrtLimit; x++) {
62+
for (int y = 1; y <= sqrtLimit; y++) {
63+
applyQuadraticForm(4 * x * x + y * y, limit, sieve, 1, 5);
64+
applyQuadraticForm(3 * x * x + y * y, limit, sieve, 7);
65+
applyQuadraticForm(3 * x * x - y * y, limit, sieve, 11, x > y);
66+
}
67+
}
68+
}
69+
70+
/**
71+
* Toggles the sieve entry for a number if it satisfies one modulo condition.
72+
*
73+
* @param n the number to check
74+
* @param limit upper bound of primes
75+
* @param sieve boolean array representing potential primes
76+
* @param modulo the modulo condition number to check
77+
*/
78+
private static void applyQuadraticForm(int n, int limit, boolean[] sieve, int modulo) {
79+
if (n <= limit && n % 12 == modulo) {
80+
sieve[n] ^= true;
81+
}
82+
}
83+
84+
/**
85+
* Toggles the sieve entry for a number if it satisfies either of two modulo conditions.
86+
*
87+
* @param n the number to check
88+
* @param limit upper bound of primes
89+
* @param sieve boolean array representing potential primes
90+
* @param modulo1 first modulo condition number to check
91+
* @param modulo2 second modulo condition number to check
92+
*/
93+
private static void applyQuadraticForm(int n, int limit, boolean[] sieve, int modulo1, int modulo2) {
94+
if (n <= limit && (n % 12 == modulo1 || n % 12 == modulo2)) {
95+
sieve[n] ^= true;
96+
}
97+
}
98+
99+
/**
100+
* Toggles the sieve entry for a number if it satisfies the modulo condition and an additional boolean condition.
101+
*
102+
* This version is used for the quadratic form 3*x*x - y*y, which requires x > y.
103+
*
104+
* @param n the number to check
105+
* @param limit upper bound of primes
106+
* @param sieve boolean array representing potential primes
107+
* @param modulo the modulo condition number to check
108+
* @param condition an additional boolean condition that must be true
109+
*/
110+
private static void applyQuadraticForm(int n, int limit, boolean[] sieve, int modulo, boolean condition) {
111+
if (condition && n <= limit && n % 12 == modulo) {
112+
sieve[n] ^= true;
113+
}
114+
}
115+
116+
/**
117+
* Eliminates numbers that are multiples of squares from the sieve.
118+
*
119+
* All numbers that are multiples of i*i (where i is marked as prime) are
120+
* marked non-prime to finalize the sieve. This ensures only actual primes remain.
121+
*
122+
* @param limit the upper bound for primes
123+
* @param sqrtLimit square root of the limit
124+
* @param sieve boolean array representing potential primes
125+
*/
126+
private static void eliminateMultiplesOfSquares(int limit, int sqrtLimit, boolean[] sieve) {
127+
for (int i = 5; i <= sqrtLimit; i++) {
128+
if (!sieve[i]) continue;
129+
int square = i * i;
130+
for (int j = square; j <= limit; j += square) {
131+
sieve[j] = false;
132+
}
133+
}
134+
}
135+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.thealgorithms.maths;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
5+
6+
import java.util.List;
7+
import org.junit.jupiter.api.Test;
8+
9+
/**
10+
* Unit tests for the {@code SieveOfAtkin} class.
11+
*/
12+
class SieveOfAtkinTest {
13+
14+
/**
15+
* Tests prime generation for a small limit of 10.
16+
* Expected primes are 2, 3, 5, 7.
17+
*/
18+
@Test
19+
void testGeneratePrimesLimit10() {
20+
List<Integer> primes = SieveOfAtkin.generatePrimes(10);
21+
assertEquals(List.of(2, 3, 5, 7), primes);
22+
}
23+
24+
/**
25+
* Tests prime generation when limit is 2.
26+
* Expected result is a single prime number 2.
27+
*/
28+
@Test
29+
void testGeneratePrimesLimit2() {
30+
List<Integer> primes = SieveOfAtkin.generatePrimes(2);
31+
assertEquals(List.of(2), primes);
32+
}
33+
34+
/**
35+
* Tests prime generation when limit is less than 2.
36+
* Expected result is an empty list.
37+
*/
38+
@Test
39+
void testGeneratePrimesLimit1() {
40+
List<Integer> primes = SieveOfAtkin.generatePrimes(1);
41+
assertTrue(primes.isEmpty());
42+
}
43+
44+
/**
45+
* Tests prime generation for a moderate limit of 50.
46+
* Verifies that the list contains all correct primes up to 50.
47+
*/
48+
@Test
49+
void testGeneratePrimesLimit50() {
50+
List<Integer> primes = SieveOfAtkin.generatePrimes(50);
51+
assertEquals(List.of(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47), primes);
52+
}
53+
54+
/**
55+
* Tests prime generation when limit is negative.
56+
* Expected result is an empty list.
57+
*/
58+
@Test
59+
void testGeneratePrimesNegativeLimit() {
60+
List<Integer> primes = SieveOfAtkin.generatePrimes(-10);
61+
assertTrue(primes.isEmpty());
62+
}
63+
}

0 commit comments

Comments
 (0)