1

This code works fine to count prime number till n. The problem is when n value is large like 1000000 or more, then it takes long time to execute and print the output (more than 30 secs.). I want to fix this issue. Any help would be great. Below is the code:

public class PrimeNotillN {

        public static void main(String[] args) {

            int n = 1000;
            int count = 0;

            for (int i = 2; i < n; i++) {
                boolean res = checkprime(i);
                if (res == true)
                    count++;
            }
            System.out.println("total prime number till " + n + " is " + count);
        }

        private static boolean checkprime(int n) {
            if (n == 1)
                return false;
            else {
                for (int i = 2; i <= n / 2; i++) {
                    if (n % i == 0) {

                        return false;
                    }
                }

                return true;
            }
        }
    }
Ujjwal
  • 346
  • 4
  • 11
  • 4
    This is not fixable without fundamentally rewriting. e.g. changing algorithms. you're using one of the slowest possible methods... – Marc B Jun 15 '15 at 16:41
  • 4
    You might want to research the [Sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes). – Don Roby Jun 15 '15 at 16:44
  • One quick and easy way to reduce your execution time would be to change your `for` loop to increment `i` by 2 each time (to skip checking even numbers). Note that this would require starting at 3 instead of 2, with `count = 1;` initially. – River Jun 15 '15 at 16:45
  • Not related to your question since it has already been correctly addressed, but inside your for loop you could just use if(checkprime(i)) count++; saves some space, gets rid of unnecessary variables, looks nice – Galax Jun 15 '15 at 16:48
  • Nope Nope Nope! this takes alotttttttttttt of time. `Sieve` is the key to do this. – Uma Kanth Jun 15 '15 at 16:50
  • just replace `i <= n / 2` with `i <= n / i`. will probably run for under a second instead of 30, which is still slow, but not _so_ terribly slow. – Will Ness Jun 16 '15 at 20:53

5 Answers5

2

The easiest change to make is to end the for loop in checkprime after i has reached the square root of n. The reason is that if you have found a factor greater than the square root of n, that implies that there was a factor less than the square root of n that should have been found already.

for (int i = 2; i <= Math.sqrt(n); i++) {

Additionally, if you need more speed, the best algorithm for printing all prime numbers up to a limit is the Sieve of Eratosthenes. That involves replacing what you have. You'll need an array in which you'll mark which numbers are composite. Starting with 2, you will mark all multiples of 2 as composite. Moving through the array, if you find a number that isn't marked composite, it's prime and you can print it. With each prime you encounter, you will mark all of that prime's multiples as composite as well.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • I*d use `i*i <= n` instead of `i <=Math.sqrt(n)` just from an intuition that squaring is faster than taking the square root (probably does not matter much on today's CPUs, though). Also keep in mind that with the Sieve of Eratosthenes, you will trade speed for memory usage (especially if the number is large). – mihi Jun 15 '15 at 16:49
  • This optimization combined with skipping even numbers will result in an algorithm with acceptable performance in my opinion. No it's not terribly fast, but it will be better the twice as fast as it would be without the optimizations as you are removing more than half of the numbers you check that will fail. – JustWannaFly Jun 15 '15 at 17:04
2

Sieve of Eratosthenes is a very famous and efficient algorithm to generate all small prime numbers up to around 1-10 million. This is an ancient algorithm given by a Greek mathematician named Eratosthenes.

 public class CountPrimes {

  public static void main(String[] args) {
    System.out.println(countPrimes(1000000));
  }

  public static int countPrimes(int n) {
    boolean[] primes = new boolean[n +1];

    for(int i = 0 ; i <= n ; i++) {
        primes[i] = true;
    }

    primes[0] = false;
    primes[1] = false;

    for(int i = 2 ; i * i <= n ; i++) {
        if(primes[i]) {
            for(int j = i ; i * j <= n ; j++) {
                primes[j * i ] = false;
            }
        }   
    }

    int primeCounts = 0;
    for(int i = 2 ; i <= n ; i++) {
        if(primes[i]) {
            primeCounts++;
        }
    }

    return primeCounts;
  }

}
Girish Rathi
  • 129
  • 1
  • 4
1

Primes, other than 2, are never even. Primes are only divisible by 1 and iteslef.

Also you can check up to it's sqrt. If you find nothing by then then it's a prime.

        public bool IsPrime(double num)
    {
        bool isprime = true;
        double limit = Math.Sqrt(num);

        if (num % 2 == 0)
            return num == 2;

        if (num == 3 || num == 5 || num == 7)
            return true;

        for (int i = 3; i < limit; i++)
            if (num % 1 == 0)
                return false;

        return isprime;
    }
rossum
  • 15,344
  • 1
  • 24
  • 38
GaidenFocus
  • 353
  • 4
  • 12
  • `i < limit` is wrong. `num % 1 == 0` is **always** true. using `double`s to represent primes is not good. – Will Ness Jun 16 '15 at 21:18
0

You can store found primes into list and make further checks only against them (Sieve of Eratosphenes):

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

public class PrimeNotillN {
    public static void main(String[] args) {
        int n = 1000000;
        int count = 0;
        List<Integer> primes = new ArrayList<>();

        for (int i = 2; i < n; i++) {
            boolean res = checkprime(primes, i);
            if (res) {
                count++;
                primes.add(i);
            }
        }
        System.out.println("total prime number till " + n + " is " + count);
    }

    private static boolean checkprime(List<Integer> primes, int n) {
        int fence = (int) Math.sqrt(n);
        for (int prime : primes) {
            if (n % prime == 0) {
                return false;
            }
            if (prime >= fence)
                break;
        }

        return true;
    }
}
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
  • no algorithm which makes checks (i.e. tries to divide) by whatever numbers is Sieve of Eratosthenes. the whole point to it is that *no checks* need be made. composites are generated by repeated addition, and what's left are *automatically* primes. if you test divide, complexity significantly worsens. – Will Ness Jun 16 '15 at 21:23
0

Using the sieve of eratoshtenes approach and maintaining the cache of all prime numbers found

    public int countPrimes(int n) {
    if(n==0){
        return 0;
    }else{
        boolean[] isPrime=new boolean[n];
        for(int i=2;i<n;i++){
            isPrime[i]=true;
        }

        for(int i=2;i*i<n;i++){
           if(!isPrime[i]){
               continue;
           }
            for(int j=i*i;j<n;j+=i){
                isPrime[j]=false;
            }
        }

        int counter=0;
        for(int i=2;i<n;i++){
            if(isPrime[i]){
                counter++;
            }
        }

        return counter;

    }
}
Mad Scientist
  • 340
  • 4
  • 14