6

I have got one question to print one million prime numbers . I have written a java program for that .. It's currently taking 1.5 mins approx to calculate it .. I think my solution is not that efficient. I have used the below algo:

  • Adding 1 2 3 to the prime list initially
  • Calculating the last digit of the number to be checked
  • Checking if the digit is 0 , 2 or 4 or 6 or 8 then skipping the number
  • else calculating the square root of the number ..
  • Trying to Divide the number starting from 2 till the square root of the number
  • if number is divisible then skipping the number else adding it to the prime list

I have read several other solutions as well , but I didn't find a good answer. Please suggest ideally what should be approx minimum time to calculate this and what changes are required to make the algorithm more efficient.

PearsonArtPhoto
  • 35,989
  • 16
  • 107
  • 136
priyas
  • 395
  • 1
  • 6
  • 26

10 Answers10

15

If you added 1 to your list, your answer is wrong already :)

Anyway, Sieve of Erathosthenes is where you should begin, it's incredibly simple and quite efficient.

Once you're familiar with the idea of sieves and how they work, you can move on to Sieve of Atkin, which is a bit more complicated but obviously more efficient.

biziclop
  • 46,403
  • 12
  • 73
  • 97
  • 1
    no, not obviously more efficient, more like non-obviously but certainly *less* efficient and enormously more complicated and hard to code right, compared to the wheel-optimized SoE. i.e. never to be used. see [user:GordonBGood](https://stackoverflow.com/users/549617/gordonbgood)'s posts and comments. – Will Ness Apr 09 '19 at 08:51
5

Key things:

  1. Skip all even numbers. Start with 5, and just add two at a time.
  2. 1 isn't a prime number...
  3. Test a number by finding the mod of all prime numbers till the square root of the number. No need to test anything but primes.
PearsonArtPhoto
  • 35,989
  • 16
  • 107
  • 136
  • 1
    i have tried to find the mod of all prime numbers till the square root ...but it increased the execution time a little bit ... – priyas Nov 15 '12 at 19:26
  • 2
    Sounds like either your method of collecting the primes isn't working right, or your listing method. It should be quicker to go through a smaller list of numbers, always... – PearsonArtPhoto Nov 15 '12 at 19:49
3

You might want to implement Sieve of Eratosthenes algorithm to find prime numbers from 1 to n and iteratively increase the range while you are doing it if needed to. (i.e. did not find 1,000,000 primes yet)

amit
  • 166,614
  • 24
  • 210
  • 314
  • "... and iteratively increase the range" *without re-doing the already done parts*, i.e. do a *segmented* sieve of Eratosthenes. – Will Ness Apr 09 '19 at 08:55
3

A simple sieve of Eratosthenes runs like the clappers. This calculates the 1,000,000th prime in less than a second on my box:

class PrimeSieve
{
    public List<int> Primes;

    private BitArray Sieve;

    public PrimeSieve(int max)
    {
        Primes = new List<int> { 2, 3 }; // Must include at least 2, 3.
        Sieve = new BitArray(max + 1);
        foreach (var p in Primes)
            for (var i = p * p; i < Sieve.Length; i += p) Sieve[i] = true;
    }

    public int Extend()
    {
        var p = Primes.Last() + 2; // Skip the even numbers.
        while (Sieve[p]) p += 2;
        for (var i = p * p; i < Sieve.Length; i += p) Sieve[i] = true;
        Primes.Add(p);
        return p;
    }
}

EDIT: sieving optimally starts from p^2, not 2p, as Will Ness correctly points out (all compound numbers below p^2 will have been marked in earlier iterations).

Rafe
  • 5,047
  • 3
  • 20
  • 26
  • A bit vector is probably the way to go for performance. My streaming version with Ocaml is terribly slow! will give this a try sometime. Thanks! – Asiri Rathnayake Nov 16 '12 at 01:26
  • @AsiriRathnayake you can dramatically improve the speed of your code, by starting the filtering of each stream at the correct point in time: you need to filter by 3 only from 9; filter by 5 only from 25; etc. See http://stackoverflow.com/a/8871918/849891 . – Will Ness Nov 16 '12 at 07:36
  • @WillNess: That explained a lot! Gained about 200% speed increase, but not close to the bit-array based approaches. Will experiment with both the approaches. Thanks! – Asiri Rathnayake Nov 16 '12 at 10:38
  • @WillNess: you're quite right. I've amended my answer accordingly. – Rafe Nov 19 '12 at 22:26
3

First, 1 is not a prime number.

Second, the millionth prime is 15,485,863, so you need to be prepared for some large data-handling.

Third, you probably want to use the Sieve of Eratosthenes; here's a simple version:

function sieve(n)
    bits := makeArray(0..n, True)
    for p from 2 to n step 1
        if bits[p]
            output p
            for i from p*p to n step p
                bits[i] := False

That may not work for the size of array that you will need to calculate the first million primes. In that case, you will want to implement a Segmented Sieve of Eratosthenes.

I've done a lot of work with prime numbers at my blog, including an essay that provides an optimized Sieve of Eratosthenes, with implementations in five programming languages.

No matter what you do, with any programming language, you should be able to compute the first million primes in no more than a few seconds.

user448810
  • 16,364
  • 2
  • 31
  • 53
1

Here's an Ocaml program that implements the Trial division sieve (which is sort of the inverse of Eratosthenes as correctly pointed out by Will):

(* Creates a function for streaming integers from x onward *)
let stream x =
  let counter = ref (x) in
  fun () ->
    let _ = counter := !counter + 1 in
    !counter;;

(* Filter the given stream of any multiples of x *)
let filter s x = fun () ->
  let rec filter' () = match s () with
    n when n mod x = 0 ->
      filter' ()|
    n ->
      n in
  filter' ();;

(* Get next prime, apply a new filter by that prime to the remainder of the stream *)
let primes count =
  let rec primes' count' s = match count' with
    0 ->
      []|
    _ -> 
      let n = s () in
      n :: primes' (count' - 1) (filter s n) in
  primes' count (stream 1);;

It works on a stream of integers. Each time a new prime number is discovered, a filter is added to the stream so that the remainder of the stream gets filtered of any multiples of that prime number. This program can be altered to generate prime numbers on-demand as well.

It should be fairly easy to take the same approach in Java.

Hope this helps!

Asiri Rathnayake
  • 1,098
  • 1
  • 10
  • 26
  • 1
    that's trial division sieve, ***not*** the sieve of Eratosthenes! the SoE *generates* multiples for each found prime, not *tests* for them, filtering by `mod` as your code does. – Will Ness Nov 15 '12 at 21:52
  • 1
    Yuk! terrible mistake. I have mixed it all up. Thanks! :) – Asiri Rathnayake Nov 15 '12 at 22:20
1

Here's a javascript solution that uses recursion and iteration to reach the millionth prime. It's not as fast as the Sieve of Erathosthenes, but does not require one to know the value of the millionth prime (i.e., size of the required sieve) in advance:

function findPrimes(n, current, primes) {
    if (!n || current < 2) return []
    var isPrime = true
    for (var i = 0; i < primes.length; i++) {
        if (current % primes[i] == 0) {
            isPrime = false
            break
        }
    }
    if (isPrime) primes.push(current)
    if (primes.length < n) return findPrimes(n, current + 1, primes)
    else return primes
}

var primes = [2,3]
for (var i = 1; i <= 1000; i++) {
    primes = findPrimes(i*1000, primes[primes.length - 1]+1, primes)
    console.log(i*1000 + 'th prime: ' + primes[primes.length-1])
}
process.exit()

Output:

...
996000th prime: 15419293
997000th prime: 15435941
998000th prime: 15452873
999000th prime: 15469313
1000000th prime: 15485863

Process finished with exit code 0
1

As a fresher level I will try this one, so any improvement to make this more efficient and faster is appreciated

 public static void main(String ar[]) {
    ArrayList primeNumbers = new ArrayList();

    for(int i = 2; primeNumbers.size() < 1000000; i++) {//first 1 million prime number

       // for(int i = 2; i < 1000000; i++) {//prime numbers from 1 to 1 million

            boolean divisible = false;

        for(int j=2;j<i/2;j++){

            if((i % j) == 0) {
                divisible = true;
                break;
            }
        }

        if(divisible == false) {
            primeNumbers.add(i);
           // System.out.println(i + " ");
        }
    }
    System.out.println(primeNumbers);
}
MangduYogii
  • 773
  • 6
  • 22
1
  • Adding 1 2 3 to the prime list initially

Actually, just 2 is sufficient. Hard-coding 3 might save, at most, a millisecond. There's no need to harp on 1. I am convinced that including it was an honest mistake. You already knew, and working on this program would have helped confirm this.

  • Calculating the last digit of the number to be checked

The last digit? In what base? Base 10? I think this might be your problem.

  • Checking if the digit is 0, 2 or 4 or 6 or 8 then skipping the number else calculating the square root of the number

I think this is where the problem lies. Your program should simply skip even numbers, because, aside from −2 and 2, they're all composite. On the other hand, this won't halve running time because odd numbers like 91 and and 2209 might require more effort to be ruled out as not prime.

  • Trying to Divide the number starting from 2 till the square root of the number if number is divisible then skipping the number else adding it to the prime list

Does "2 till the square root of the number" include numbers like 4, 6 and 9? The only potential factors that need to be checked are numbers that have already been proven prime. If n is not divisible by 7, it won't be divisible by 49 either. If you're building up a list, you might as well use it to check potential primes.

Benchmarking Java's a little difficult because you're at the mercy of the runtime system. Still, a minute and a half, while it would have been considered miraculous by Mersenne, is too slow today. Five, ten seconds, that I'd find acceptable.

Maybe this is one of those cases where you should avoid the use of objects in favor of an array of primitives. My first draft took even longer than yours. Eventually I came up with this:

    static int[] fillWithPrimes(int quantity) {
        int[] primes = new int[quantity];
        primes[0] = 2;
        int currPi = 1;
        int currIndex = 0;
        int currNum = 3;
        int currPrime;
        boolean coPrimeFlag;
        double squareRoot;
        while (currPi < quantity) {
            squareRoot = Math.sqrt(currNum);
            do {
                currPrime = primes[currIndex];
                coPrimeFlag = (currNum % currPrime != 0);
                currIndex++;
            } while (coPrimeFlag && currPrime <= squareRoot);
            if (coPrimeFlag) {
                primes[currPi] = currNum;
                currPi++;
            }
            currNum += 2;
            currIndex = 0;
        }
        return primes;
    }

Then I wrote a main() that notes the time before calling fillWithPrimes() with a quantity parameter of 1,000,000, and reports on the results:

run:

Operation took 2378 milliseconds

10th prime is 29

100th prime is 541

1000th prime is 7919

10000th prime is 104729

100000th prime is 1299709

1000000th prime is 15485863

BUILD SUCCESSFUL (total time: 2 seconds)

I'm sure it can be optimized further. Me, personally, I'm satisfied with two and a half seconds.

Alonso del Arte
  • 920
  • 1
  • 5
  • 17
-1

Isn't everything after 5 ending in a five divisible by 5 as well, so you can skip things who's right(1,numb)<>"5" for example 987,985. I made one in Excel that will test a million numbers for primes and spit them in a column in about 15 seconds but it gets crazy around 15 million

jstiene
  • 21
  • 2
  • 1
    Use sieve of Eratosthenes as commented by others. This will calculate first million in less than a second. http://programmingpraxis.com/2009/02/19/sieve-of-eratosthenes/ – priyas Apr 20 '15 at 06:14