Program to find all primes in a very large given range of integers
algorithm, java, primes, sieve-of-eratosthenes
Solution
You are given
1 <= m <= n <= 1000000000, n-m<=100000
these are very small numbers. To sieve a range with an upper bound of `n`, you need the primes to `√n`. Here you know `n <= 10^9`, so `√n < 31623`, so you need at worst the primes to 31621. There are 3401. You can generate them with a standard sieve in a few microseconds.
Then you can simply sieve the small range from `m` to `n` by marking the multiples of the primes you've sieved before, stopping when the prime exceeds `√n`. Some speedup can be gained by eliminating the multiples of some small primes from the sieve, but the logic becomes more complicated (you need to treat sieves with small `m` specially).
public int[] chunk(int m, int n) {
if (n < 2) return null;
if (m < 2) m = 2;
if (n < m) throw new IllegalArgumentException("Borked");
int root = (int)Math.sqrt((double)n);
boolean[] sieve = new boolean[n-m+1];
// primes is the global array of primes to 31621 populated earlier
// primeCount is the number of primes stored in primes, i.e. 3401
// We ignore even numbers, but keep them in the sieve to avoid index arithmetic.
// It would be very simple to omit them, though.
for(int i = 1, p = primes[1]; i < primeCount; ++i) {
if ((p = primes[i]) > root) break;
int mult;
if (p*p < m) {
mult = (m-1)/p+1;
if (mult % 2 == 0) ++mult;
mult = p*mult;
} else {
mult = p*p;
}
for(; mult <= n; mult += 2*p) {
sieve[mult-m] = true;
}
}
int count = m == 2 ? 1 : 0;
for(int i = 1 - m%2; i < n-m; i += 2) {
if (!sieve[i]) ++count;
}
int sievedPrimes[] = new int[count];
int pi = 0;
if (m == 2) {
sievedPrimes[0] = 2;
pi = 1;
}
for(int i = 1 - m%2; i < n-m; i += 2) {
if (!sieve[i]) {
sievedPrimes[pi++] = m+i;
}
}
return sievedPrimes;
}
Using a `BitSet` or any other type of packed flag-array would reduce the memory usage and thus may give a significant speed-up due to better cache-locality.
Problem
i came across this following question on a programming website : Peter wants to generate some prime numbers for his cryptosystem. Help him! Your task is to generate all prime numbers between two given numbers! Input The input begins with the number t of test cases in a single line (t<=10). In each of the next t lines there are two numbers m and n (1 <= m <= n <= 1000000000, n-m<=100000) separated by a space. I came up with the following solution : ``` import java.util.*; public class PRIME1 { static int numCases; static int left, right; static boolean[] initSieve = new boolean[32000]; static boolean[] answer; public static void main(String[] args) { Scanner sc = new Scanner(System.in); numCases = sc.nextInt(); initSieve[0] = true; initSieve[1] = true; Sieve(); for (int j = 0; j < numCases; j++) { String line = sc.next(); String line2 = sc.next(); left = Integer.parseInt(line); right = Integer.parseInt(line2); answer = new boolean[right - left + 1]; getAnswer(); for (int i = 0; i < answer.length; i++) { if (!answer[i]) { int ans = i + left; System.out.println(ans); } } System.out.println(); } } public static void Sieve() { for (int i = 2; i < 32000; i++) { if (!initSieve[i]) { for (int j = 2 * i; j < 32000; j += i) { initSieve[j] = true; } } if (i * i > 32000) break; } } public static void getAnswer() { for (int i = 2; i < 32000 && i <= right; i++) { if (!initSieve[i]) { int num = i; if (num * 2 >= left) { num *= 2; } else { num = (num * (left / num)); if (num < left) num += i; } for (int j = num; j >= left && j <= right; j += i) { answer[j - left] = true; } } } } } ``` I have edited my solution after reading some of the suggestions. I am still getting a time limit exceeded kind of error. Any more suggestions as how to further optimize this ? Am calculating all the primes upto 32000 and then using these to find the primes between n to m. Thanks, Rohit