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
Function countPrimes(int strt,int end) returns the count of primes in range. Take the initial variable count as 0. Take each number i and check if it is prime using isprime(i). Function isprime(int num) returns 0 if the number is non prime and 1 if it is prime.
Identifying a Large Prime Number It is an even number which is easily divided by 2. Add the digits of the large number and then divide it by 3. If it is exactly divisible by 3 then the large number is not a prime number. If the result of the first two methods is false, take out the square root of the number.
Prime sieves are almost always faster. Prime sieving is the fastest known way to deterministically enumerate the primes.
Approach: The idea is to iterate from in the range [L, R] and check if any number in the given range is prime or not. If yes then print that number and check for the next number till we iterate all the numbers. Below the implementation of the above approach: C.
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.
Use a BitSet instead of an Array of Boolean.
public static BitSet primes (final int MAX)
{
BitSet primes = new BitSet (MAX);
// make only odd numbers candidates...
for (int i = 3; i < MAX; i+=2)
{
primes.set(i);
}
// ... except no. 2
primes.set (2, true);
for (int i = 3; i < MAX; i+=2)
{
/*
If a number z is already eliminated (like 9),
because it is itself a multiple of a prime
(example: 3), then all multiples of z (9) are
already eliminated.
*/
if (primes.get (i))
{
int j = 3 * i;
while (j < MAX)
{
if (primes.get (j))
primes.set (j, false);
j += (2 * i);
}
}
}
return primes;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With