mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-12-19 07:00:35 +08:00
feat: add sieve of atkin algorithm (#6709)
* feat: add sieve of atkin algorithm * fix: add full test coverage * refactor: if condition braces --------- Co-authored-by: a <alexanderklmn@gmail.com>
This commit is contained in:
143
src/main/java/com/thealgorithms/maths/SieveOfAtkin.java
Normal file
143
src/main/java/com/thealgorithms/maths/SieveOfAtkin.java
Normal file
@@ -0,0 +1,143 @@
|
||||
package com.thealgorithms.maths;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Implementation of the Sieve of Atkin, an optimized algorithm to generate
|
||||
* all prime numbers up to a given limit.
|
||||
*
|
||||
* The Sieve of Atkin uses quadratic forms and modular arithmetic to identify
|
||||
* prime candidates, then eliminates multiples of squares. It is more efficient
|
||||
* than the Sieve of Eratosthenes for large limits.
|
||||
*/
|
||||
public final class SieveOfAtkin {
|
||||
|
||||
private SieveOfAtkin() {
|
||||
// Utlity class; prevent instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list of all prime numbers up to the specified limit
|
||||
* using the Sieve of Atkin algorithm.
|
||||
*
|
||||
* @param limit the upper bound up to which primes are generated; must be zero or positive
|
||||
* @return a list of prime numbers up to the limit; empty if the limit is less than 2
|
||||
*/
|
||||
public static List<Integer> generatePrimes(int limit) {
|
||||
if (limit < 1) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
boolean[] sieve = new boolean[limit + 1];
|
||||
int sqrtLimit = (int) Math.sqrt(limit);
|
||||
|
||||
markQuadraticResidues(limit, sqrtLimit, sieve);
|
||||
eliminateMultiplesOfSquares(limit, sqrtLimit, sieve);
|
||||
|
||||
List<Integer> primes = new ArrayList<>();
|
||||
if (limit >= 2) {
|
||||
primes.add(2);
|
||||
}
|
||||
if (limit >= 3) {
|
||||
primes.add(3);
|
||||
}
|
||||
|
||||
for (int i = 5; i <= limit; i++) {
|
||||
if (sieve[i]) {
|
||||
primes.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
return primes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks numbers in the sieve as prime candidates based on quadratic residues.
|
||||
*
|
||||
* This method iterates over all x and y up to sqrt(limit) and applies
|
||||
* the three quadratic forms used in the Sieve of Atkin. Numbers satisfying
|
||||
* the modulo conditions are toggled in the sieve array.
|
||||
*
|
||||
* @param limit the upper bound for primes
|
||||
* @param sqrtLimit square root of the limit
|
||||
* @param sieve boolean array representing potential primes
|
||||
*/
|
||||
private static void markQuadraticResidues(int limit, int sqrtLimit, boolean[] sieve) {
|
||||
for (int x = 1; x <= sqrtLimit; x++) {
|
||||
for (int y = 1; y <= sqrtLimit; y++) {
|
||||
applyQuadraticForm(4 * x * x + y * y, limit, sieve, 1, 5);
|
||||
applyQuadraticForm(3 * x * x + y * y, limit, sieve, 7);
|
||||
applyQuadraticForm(3 * x * x - y * y, limit, sieve, 11, x > y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the sieve entry for a number if it satisfies one modulo condition.
|
||||
*
|
||||
* @param n the number to check
|
||||
* @param limit upper bound of primes
|
||||
* @param sieve boolean array representing potential primes
|
||||
* @param modulo the modulo condition number to check
|
||||
*/
|
||||
private static void applyQuadraticForm(int n, int limit, boolean[] sieve, int modulo) {
|
||||
if (n <= limit && n % 12 == modulo) {
|
||||
sieve[n] ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the sieve entry for a number if it satisfies either of two modulo conditions.
|
||||
*
|
||||
* @param n the number to check
|
||||
* @param limit upper bound of primes
|
||||
* @param sieve boolean array representing potential primes
|
||||
* @param modulo1 first modulo condition number to check
|
||||
* @param modulo2 second modulo condition number to check
|
||||
*/
|
||||
private static void applyQuadraticForm(int n, int limit, boolean[] sieve, int modulo1, int modulo2) {
|
||||
if (n <= limit && (n % 12 == modulo1 || n % 12 == modulo2)) {
|
||||
sieve[n] ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the sieve entry for a number if it satisfies the modulo condition and an additional boolean condition.
|
||||
*
|
||||
* This version is used for the quadratic form 3*x*x - y*y, which requires x > y.
|
||||
*
|
||||
* @param n the number to check
|
||||
* @param limit upper bound of primes
|
||||
* @param sieve boolean array representing potential primes
|
||||
* @param modulo the modulo condition number to check
|
||||
* @param condition an additional boolean condition that must be true
|
||||
*/
|
||||
private static void applyQuadraticForm(int n, int limit, boolean[] sieve, int modulo, boolean condition) {
|
||||
if (condition && n <= limit && n % 12 == modulo) {
|
||||
sieve[n] ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminates numbers that are multiples of squares from the sieve.
|
||||
*
|
||||
* All numbers that are multiples of i*i (where i is marked as prime) are
|
||||
* marked non-prime to finalize the sieve. This ensures only actual primes remain.
|
||||
*
|
||||
* @param limit the upper bound for primes
|
||||
* @param sqrtLimit square root of the limit
|
||||
* @param sieve boolean array representing potential primes
|
||||
*/
|
||||
private static void eliminateMultiplesOfSquares(int limit, int sqrtLimit, boolean[] sieve) {
|
||||
for (int i = 5; i <= sqrtLimit; i++) {
|
||||
if (!sieve[i]) {
|
||||
continue;
|
||||
}
|
||||
int square = i * i;
|
||||
for (int j = square; j <= limit; j += square) {
|
||||
sieve[j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java
Normal file
47
src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package com.thealgorithms.maths;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@code SieveOfAtkin} class.
|
||||
*/
|
||||
class SieveOfAtkinTest {
|
||||
|
||||
@Test
|
||||
void testGeneratePrimesLimit10() {
|
||||
List<Integer> primes = SieveOfAtkin.generatePrimes(10);
|
||||
// Assert the full expected list of primes
|
||||
List<Integer> expected = List.of(2, 3, 5, 7);
|
||||
assertEquals(expected, primes, "Primes up to 10 should match expected list");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGeneratePrimesLimit2() {
|
||||
List<Integer> primes = SieveOfAtkin.generatePrimes(2);
|
||||
List<Integer> expected = List.of(2);
|
||||
assertEquals(expected, primes, "Primes up to 2 should include 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGeneratePrimesLimit1() {
|
||||
List<Integer> primes = SieveOfAtkin.generatePrimes(1);
|
||||
assertTrue(primes.isEmpty(), "Primes list should be empty when limit < 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGeneratePrimesLimit50() {
|
||||
List<Integer> primes = SieveOfAtkin.generatePrimes(50);
|
||||
List<Integer> expected = List.of(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47);
|
||||
assertEquals(expected, primes, "Primes up to 50 should match expected list");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGeneratePrimesNegativeLimit() {
|
||||
List<Integer> primes = SieveOfAtkin.generatePrimes(-10);
|
||||
assertTrue(primes.isEmpty(), "Primes list should be empty for negative limit");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user