Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 57 additions & 41 deletions src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java
Original file line number Diff line number Diff line change
@@ -1,66 +1,82 @@
package com.thealgorithms.maths;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;

/**
* @brief utility class implementing <a href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes">Sieve of Eratosthenes</a>
* Sieve of Eratosthenes Algorithm
* An efficient algorithm to find all prime numbers up to a given limit.
*
* Algorithm:
* 1. Create a boolean array of size n+1, initially all true
* 2. Mark 0 and 1 as not prime
* 3. For each number i from 2 to sqrt(n):
* - If i is still marked as prime
* - Mark all multiples of i (starting from i²) as not prime
* 4. Collect all numbers still marked as prime
*
* Time Complexity: O(n log log n)
* Space Complexity: O(n)
*
* @author Navadeep0007
* @see <a href="https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes">Sieve of Eratosthenes</a>
*/
public final class SieveOfEratosthenes {

private SieveOfEratosthenes() {
// Utility class, prevent instantiation
}

private static void checkInput(int n) {
if (n <= 0) {
throw new IllegalArgumentException("n must be positive.");
/**
* Finds all prime numbers up to n using the Sieve of Eratosthenes algorithm
*
* @param n the upper limit (inclusive)
* @return a list of all prime numbers from 2 to n
* @throws IllegalArgumentException if n is negative
*/
public static List<Integer> findPrimes(int n) {
if (n < 0) {
throw new IllegalArgumentException("Input must be non-negative");
}
}

private static Type[] sievePrimesTill(int n) {
checkInput(n);
Type[] isPrimeArray = new Type[n + 1];
Arrays.fill(isPrimeArray, Type.PRIME);
isPrimeArray[0] = Type.NOT_PRIME;
isPrimeArray[1] = Type.NOT_PRIME;
if (n < 2) {
return new ArrayList<>();
}

// Create boolean array, initially all true
boolean[] isPrime = new boolean[n + 1];
for (int i = 2; i <= n; i++) {
isPrime[i] = true;
}

double cap = Math.sqrt(n);
for (int i = 2; i <= cap; i++) {
if (isPrimeArray[i] == Type.PRIME) {
for (int j = 2; i * j <= n; j++) {
isPrimeArray[i * j] = Type.NOT_PRIME;
// Sieve process
for (int i = 2; i * i <= n; i++) {
if (isPrime[i]) {
// Mark all multiples of i as not prime
for (int j = i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}
return isPrimeArray;
}

private static int countPrimes(Type[] isPrimeArray) {
return (int) Arrays.stream(isPrimeArray).filter(element -> element == Type.PRIME).count();
}

private static int[] extractPrimes(Type[] isPrimeArray) {
int numberOfPrimes = countPrimes(isPrimeArray);
int[] primes = new int[numberOfPrimes];
int primeIndex = 0;
for (int curNumber = 0; curNumber < isPrimeArray.length; ++curNumber) {
if (isPrimeArray[curNumber] == Type.PRIME) {
primes[primeIndex++] = curNumber;
// Collect all prime numbers
List<Integer> primes = new ArrayList<>();
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
primes.add(i);
}
}

return primes;
}

/**
* @brief finds all of the prime numbers up to the given upper (inclusive) limit
* @param n upper (inclusive) limit
* @exception IllegalArgumentException n is non-positive
* @return the array of all primes up to the given number (inclusive)
* Counts the number of prime numbers up to n
*
* @param n the upper limit (inclusive)
* @return count of prime numbers from 2 to n
*/
public static int[] findPrimesTill(int n) {
return extractPrimes(sievePrimesTill(n));
}

private enum Type {
PRIME,
NOT_PRIME,
public static int countPrimes(int n) {
return findPrimes(n).size();
}
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,64 @@
package com.thealgorithms.maths;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;

/**
* Test cases for Sieve of Eratosthenes algorithm
*
* @author Navadeep0007
*/
class SieveOfEratosthenesTest {

@Test
void testPrimesUpTo10() {
List<Integer> expected = Arrays.asList(2, 3, 5, 7);
assertEquals(expected, SieveOfEratosthenes.findPrimes(10));
}

@Test
void testPrimesUpTo30() {
List<Integer> expected = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
assertEquals(expected, SieveOfEratosthenes.findPrimes(30));
}

@Test
public void testfFindPrimesTill1() {
assertArrayEquals(new int[] {}, SieveOfEratosthenes.findPrimesTill(1));
void testPrimesUpTo2() {
List<Integer> expected = Arrays.asList(2);
assertEquals(expected, SieveOfEratosthenes.findPrimes(2));
}

@Test
public void testfFindPrimesTill2() {
assertArrayEquals(new int[] {2}, SieveOfEratosthenes.findPrimesTill(2));
void testPrimesUpTo1() {
assertTrue(SieveOfEratosthenes.findPrimes(1).isEmpty());
}

@Test
public void testfFindPrimesTill4() {
var primesTill4 = new int[] {2, 3};
assertArrayEquals(primesTill4, SieveOfEratosthenes.findPrimesTill(3));
assertArrayEquals(primesTill4, SieveOfEratosthenes.findPrimesTill(4));
void testPrimesUpTo0() {
assertTrue(SieveOfEratosthenes.findPrimes(0).isEmpty());
}

@Test
public void testfFindPrimesTill40() {
var primesTill40 = new int[] {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(37));
assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(38));
assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(39));
assertArrayEquals(primesTill40, SieveOfEratosthenes.findPrimesTill(40));
void testNegativeInput() {
assertThrows(IllegalArgumentException.class, () -> { SieveOfEratosthenes.findPrimes(-1); });
}

@Test
public void testfFindPrimesTill240() {
var primesTill240 = new int[] {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239};
assertArrayEquals(primesTill240, SieveOfEratosthenes.findPrimesTill(239));
assertArrayEquals(primesTill240, SieveOfEratosthenes.findPrimesTill(240));
void testCountPrimes() {
assertEquals(4, SieveOfEratosthenes.countPrimes(10));
assertEquals(25, SieveOfEratosthenes.countPrimes(100));
}

@Test
public void testFindPrimesTillThrowsExceptionForNonPositiveInput() {
assertThrows(IllegalArgumentException.class, () -> SieveOfEratosthenes.findPrimesTill(0));
void testLargeNumber() {
List<Integer> primes = SieveOfEratosthenes.findPrimes(1000);
assertEquals(168, primes.size()); // There are 168 primes up to 1000
assertEquals(2, primes.get(0)); // First prime
assertEquals(997, primes.get(primes.size() - 1)); // Last prime up to 1000
}
}