Reputation: 1896
I'm writing this Java program that finds all the prime numbers between a given range. Because I'm dealing with really big numbers my code seems to be not fast enough and gives me a time error. Here is my code, does anyone know to make it faster? Thanks.
import java.util.*;
public class primes2
{
private static Scanner streamReader = new Scanner(System.in);
public static void main(String[] args)
{
int xrange = streamReader.nextInt();
int zrange = streamReader.nextInt();
for (int checks = xrange; checks <= zrange; checks++)
{
boolean[] checkForPrime = Primes(1000000);
if (checkForPrime[checks])
{
System.out.println(checks);
}
}
}
public static boolean[] Primes(int n)
{
boolean[] isPrime = new boolean[n + 1];
if (n >= 2)
isPrime[2] = true;
for (int i = 3; i <= n; i += 2)
isPrime[i] = true;
for (int i = 3, end = sqrt(n); i <= end; i += 2)
{
if (isPrime[i])
{
for (int j = i * 3; j <= n; j += i << 1)
isPrime[j] = false;
}
}
return isPrime;
}
public static int sqrt(int x)
{
int y = 0;
for (int i = 15; i >= 0; i--)
{
y |= 1 << i;
if (y > 46340 || y * y > x)
y ^= 1 << i;
}
return y;
}
}
Upvotes: 0
Views: 7994
Reputation: 71065
You can start your inner loop from i*i
, i.e. instead of for (int j = i * 3; j <= n; j += i << 1)
you can write for (int j = i * i; j <= n; j += i << 1)
for a minor speed-up.
Also, you have to be sure that your zrange
is not greater than 1000000
.
If xrange
is much greater than sqrt(zrange)
, you can also split your sieve array in two, for an offset sieve scheme. The lower array will span from 2 to sqrt(zrange)
. The upper one will span from xrange
to zrange
. As you sieve your lower array, as each new prime becomes identified by it, inside your inner loop, in addition to marking the lower array up to its end also sieve the upper array. You will have to calcuate the starting offset for each prime i
, and use the same step of 2*i
as you do for the lower half. If your range is wider than a few primes, you will get speed advantage (otherwise just trial division by odds will suffice).
Another thing to try is, if evens > 2
are not primes anyway, why represent them in the array and waste half of the space? You can treat each i
as representing an odd number, 2*i+1
, thus compressing your array in half.
Last simple trick is to eliminate the multiples of 3 in advance as well, by marking ON
not just odds
(i.e. coprimes with 2
), by { ... i+=2; ...}
, but only coprimes with 2
and 3
, by { ... i+=2; ... i+=4; ... }
instead. Also, when marking OFF
multiples of primes > 3
, use { ... j+=2*i; ... j+=4i; ...}
too. E.g., in 5*5, 5*7, 5*9, 5*11, ...
you don't need to mark OFF
5*9
, if no multiple of 3
was marked ON
in the first place.
Upvotes: 0
Reputation: 1157
The obvious problem is that you're computing the primes up to 1000000 many time (zrange - xrange times). Another is that you dont need to compute the primes up to 1000000, you just need to check to primes up to zrange, so you're wasting time when zrange < 1000000, and getting a buffer overflow when zrange > 1000000.
Upvotes: 0
Reputation: 183321
You'll get an enormous improvement just by changing this:
for (int checks = xrange; checks <= zrange; checks++)
{
boolean[] checkForPrime = Primes(1000000);
to this:
boolean[] checkForPrime = Primes(1000000);
for (int checks = xrange; checks <= zrange; checks++)
{
Your current code regenerates the sieve zrange - xrange + 1
times, but you actually only need to generate it once.
Upvotes: 7