0

So I have created a program that finds the 10,001st prime number. Here is the main for that program:

int main(){

  int i;
  int j;
  int count=0;
  int currnumber=0;

  for(i=1; count < 10002; i++){

      if(isPrime(i)){

          count++;
          currnumber = i;

          if(count == 10002)
              printf("%i",currnumber);
      }


  }

}

And here is the code for the IsPrime function I built in a custom library:

long long isPrime(long long number){

    long long i = 2;

    if(number == 2)
        return 1;

    for(i=2;i<number;i++){

        if(number % i == 0)
            return 0;



    }
    if(i >= number && ((number % 1 == 0) && (number % number == 0)))
        return 1;
}

When I run the program, it works and gives me the correct answer(It's an Euler problem so I know i did it right :D), but it takes at least 6 seconds to process. So my questions are:

  1. Why is it taking that long? Is it something to do with how i've set my algorithm?
  2. How can I potentially improve my code to make it run faster?

Thanks in advance!

Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
  • 2
    Look up "prime sieve" and code up an easy one. Yours does a lot of unnecessary tests (e.g. once we've tested that a number isn't divisible by 2, why test any even number?). – U2EF1 Jul 22 '14 at 19:56
  • This question is better suited to http://codereview.stackexchange.com – McLovin Jul 22 '14 at 19:56
  • 1
    Instead of `for(i=2;i – Michael Parker Jul 22 '14 at 19:56
  • possible duplicate of [Fastest way to list all primes below N in python](http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python) – msw Jul 22 '14 at 20:19
  • He is not asking for the fastest way to find all primes below N but instead asking for the fastest way to find the N'th prime. This is different. – TheGreatContini Jul 24 '14 at 00:01

4 Answers4

1

Probably the first thing you can do is cache the prime number values you do create, and use the sieve of eratosthenes algorithm in order to not have to constantly recalculate prime number values once you've found them.

Jason
  • 30,174
  • 7
  • 55
  • 73
1

You are using two for loops

A faster way which comes to my mind and is also a great exercise is the algorithm called: Sieve of Eratosthenes

Igor
  • 3,423
  • 1
  • 9
  • 30
0

There's a lot of optimisations that can be done. A few people have mentioned the sieve of Eratosthenes, which is right, but let me give you some additional pointers.

Improving your code without changing algorithm: As Michael Parker mentioned, you do not need to deal with the even numbers because only one of them is prime (the number 2, which makes it the 'oddest' prime of all -- that's a pun). You can do a similar trick by avoiding multiples of three, which boils down to only dealing with integers i which are either 1 or 5 more than a multiple of 6. To turn that into code, first set count to 3 to account for primes 2, 3, and 5. Then start i at 6 and test both i+1 and i+5 (both within the for loop), and then increment i by 6 every time.

For isPrime() you could add similar improvements but you can also stop trial dividing once you reach the square root of the number. This is because a number has a divisor >= sqrt(number) if and only if it has a divisor <= sqrt(number). To prove this, the key is that if a divides number, then number/a is another divisor (you can fill in remaining details because you are smart).

Improving your code by using Sieve of Eratosthenes: As many have mentioned, the sieve of Eratosthenes is much better for solving this. In fact, it is super-duper fast. But the one issue often overlooked is how big to make your sieve length to be sure that you captured the prime you are after, without making it outrageously large? The Prime Number Theorem gives an estimate to how big it should be. But you will need an upper bound. Suggest using n * (ln n * ln ln n).

TheGreatContini
  • 5,791
  • 1
  • 18
  • 25
0

If I understand correctly, you are taking every number less than 1001 and checking if it has a common denominator. This is extremely slow. The complexity is actually increasing exponentially. What you should do is combine this method with a sieve. Take any primes you find with the common denominator method and and multiply them from from 1 to n until you have all their multiple between 1 and 10001. That way you will skip testing the common denominator method on multiples of all the prime numbers you have already found. For example, try this:

ArrayList<Integer> List = new ArrayList<Integer>();
ArrayList<Integer> Primes = new ArrayList<Integer>();
Primes.add(2);
Integer p=2;
Integer n=105000;
Integer i=1;

while(p < n) {
    i=1;
    while((p*i)<=n){
        List.add(p*i);
        i++;
    }
    while (p < n){
    p++;
    if(List.contains(p)){}
    else {Primes.add(p); break;}
    }
}

System.out.println(Primes.get(10000));
the_prole
  • 6,481
  • 11
  • 56
  • 120
  • List is not the best data structure to use. For one, it will include duplicates, which makes your space blow up -- O(n^2) memory. Set is closer to what you want, but when you evaluate the running time you need to think about the time for insertion into the set and checking for containment. Ultimately, the best data structure for a sieve is simply an array: it will be both time and memory efficient. – TheGreatContini Jul 24 '14 at 22:19
  • The reason I used an array list is because I would have to instantiate a new array to add an element to it. – the_prole Jul 25 '14 at 01:30