From 78523ef63f6c766d193aad67a91ded12db199a8b Mon Sep 17 00:00:00 2001 From: saahilmahato Date: Wed, 8 Oct 2025 22:13:31 +0545 Subject: [PATCH 1/3] feat: add sieve of atkin algorithm --- .../com/thealgorithms/maths/SieveOfAtkin.java | 135 ++++++++++++++++++ .../thealgorithms/maths/SieveOfAtkinTest.java | 63 ++++++++ 2 files changed, 198 insertions(+) create mode 100644 src/main/java/com/thealgorithms/maths/SieveOfAtkin.java create mode 100644 src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java diff --git a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java new file mode 100644 index 000000000000..f8fa5ed44321 --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java @@ -0,0 +1,135 @@ +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 generatePrimes(int limit) { + if (limit < 2) { + return List.of(); + } + + boolean[] sieve = new boolean[limit + 1]; + int sqrtLimit = (int) Math.sqrt(limit); + + markQuadraticResidues(limit, sqrtLimit, sieve); + eliminateMultiplesOfSquares(limit, sqrtLimit, sieve); + + List 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; + } + } + } +} diff --git a/src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java b/src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java new file mode 100644 index 000000000000..f023989d2f16 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java @@ -0,0 +1,63 @@ +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 { + + /** + * Tests prime generation for a small limit of 10. + * Expected primes are 2, 3, 5, 7. + */ + @Test + void testGeneratePrimesLimit10() { + List primes = SieveOfAtkin.generatePrimes(10); + assertEquals(List.of(2, 3, 5, 7), primes); + } + + /** + * Tests prime generation when limit is 2. + * Expected result is a single prime number 2. + */ + @Test + void testGeneratePrimesLimit2() { + List primes = SieveOfAtkin.generatePrimes(2); + assertEquals(List.of(2), primes); + } + + /** + * Tests prime generation when limit is less than 2. + * Expected result is an empty list. + */ + @Test + void testGeneratePrimesLimit1() { + List primes = SieveOfAtkin.generatePrimes(1); + assertTrue(primes.isEmpty()); + } + + /** + * Tests prime generation for a moderate limit of 50. + * Verifies that the list contains all correct primes up to 50. + */ + @Test + void testGeneratePrimesLimit50() { + List primes = SieveOfAtkin.generatePrimes(50); + assertEquals(List.of(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47), primes); + } + + /** + * Tests prime generation when limit is negative. + * Expected result is an empty list. + */ + @Test + void testGeneratePrimesNegativeLimit() { + List primes = SieveOfAtkin.generatePrimes(-10); + assertTrue(primes.isEmpty()); + } +} From ce3d4f74a138b882d623be0552f01325c96580b6 Mon Sep 17 00:00:00 2001 From: saahilmahato Date: Wed, 8 Oct 2025 22:19:37 +0545 Subject: [PATCH 2/3] fix: add full test coverage --- .../com/thealgorithms/maths/SieveOfAtkin.java | 2 +- .../thealgorithms/maths/SieveOfAtkinTest.java | 34 +++++-------------- 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java index f8fa5ed44321..485b8f5f7dbf 100644 --- a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java +++ b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java @@ -25,7 +25,7 @@ private SieveOfAtkin() { * @return a list of prime numbers up to the limit; empty if the limit is less than 2 */ public static List generatePrimes(int limit) { - if (limit < 2) { + if (limit < 1) { return List.of(); } diff --git a/src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java b/src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java index f023989d2f16..8eca45c9abb8 100644 --- a/src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java +++ b/src/test/java/com/thealgorithms/maths/SieveOfAtkinTest.java @@ -11,53 +11,37 @@ */ class SieveOfAtkinTest { - /** - * Tests prime generation for a small limit of 10. - * Expected primes are 2, 3, 5, 7. - */ @Test void testGeneratePrimesLimit10() { List primes = SieveOfAtkin.generatePrimes(10); - assertEquals(List.of(2, 3, 5, 7), primes); + // Assert the full expected list of primes + List expected = List.of(2, 3, 5, 7); + assertEquals(expected, primes, "Primes up to 10 should match expected list"); } - /** - * Tests prime generation when limit is 2. - * Expected result is a single prime number 2. - */ @Test void testGeneratePrimesLimit2() { List primes = SieveOfAtkin.generatePrimes(2); - assertEquals(List.of(2), primes); + List expected = List.of(2); + assertEquals(expected, primes, "Primes up to 2 should include 2"); } - /** - * Tests prime generation when limit is less than 2. - * Expected result is an empty list. - */ @Test void testGeneratePrimesLimit1() { List primes = SieveOfAtkin.generatePrimes(1); - assertTrue(primes.isEmpty()); + assertTrue(primes.isEmpty(), "Primes list should be empty when limit < 2"); } - /** - * Tests prime generation for a moderate limit of 50. - * Verifies that the list contains all correct primes up to 50. - */ @Test void testGeneratePrimesLimit50() { List primes = SieveOfAtkin.generatePrimes(50); - assertEquals(List.of(2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47), primes); + List 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"); } - /** - * Tests prime generation when limit is negative. - * Expected result is an empty list. - */ @Test void testGeneratePrimesNegativeLimit() { List primes = SieveOfAtkin.generatePrimes(-10); - assertTrue(primes.isEmpty()); + assertTrue(primes.isEmpty(), "Primes list should be empty for negative limit"); } } From 5e43bae2eca9f9fe30b23b7206a3ea3b7eca478b Mon Sep 17 00:00:00 2001 From: saahilmahato Date: Wed, 8 Oct 2025 22:25:18 +0545 Subject: [PATCH 3/3] refactor: if condition braces --- .../com/thealgorithms/maths/SieveOfAtkin.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java index 485b8f5f7dbf..ee59d0784ec4 100644 --- a/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java +++ b/src/main/java/com/thealgorithms/maths/SieveOfAtkin.java @@ -36,11 +36,17 @@ public static List generatePrimes(int limit) { eliminateMultiplesOfSquares(limit, sqrtLimit, sieve); List primes = new ArrayList<>(); - if (limit >= 2) primes.add(2); - if (limit >= 3) primes.add(3); + 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); + if (sieve[i]) { + primes.add(i); + } } return primes; @@ -125,7 +131,9 @@ private static void applyQuadraticForm(int n, int limit, boolean[] sieve, int mo */ private static void eliminateMultiplesOfSquares(int limit, int sqrtLimit, boolean[] sieve) { for (int i = 5; i <= sqrtLimit; i++) { - if (!sieve[i]) continue; + if (!sieve[i]) { + continue; + } int square = i * i; for (int j = square; j <= limit; j += square) { sieve[j] = false;