Just going back to this again :+)
The algorithm I described is significantly more efficient than what the OP has in the first post, at least enough to solve the problem quickly. |
Yes it is, and it does, and it seems OK for small numbers, but it is not as good as Eratosthenes. That can be seen from
JLBorges' code. In comparison, using cpp.sh, at N = 600'000 the time taken was 3225ms, at 650'000 it seemed to time out?.
(1) This is a primality test problem, not a sieving problem. In sieving, the algorithm gives you all primes numbers up to N. Here we want the Nth prime number. So this doesn't work here, because you dont know how large your list needs to be. |
But your code isn't really a primality "test": it still works out all the primes (on line 46, n is prime), just they are not being displayed or stored. As an example, my idea of a test is something like the remainder theorem for polynomials. If one plugs a number N into the polynomial formula, and the result is 0, then (x-N) is a factor. If one were to try all the integers from -10 to 10, then that becomes an algorithm that uses a test repeatedly.
Your code is similar to Eratosthenes Sieve in a lot of ways: the limit of sqrt(N), only doing odd numbers, some short circuiting when a factor is found. On the face of it, it might even look similar in performance, but it isn't really. It's worth noting that the sqrt of the 10'001 prime is only 323, so we are dealing with small numbers here.
However your code is still a type of trial division:
if(n%i==0)return false;
. This is
almost the same as setting values to false in a std::bitset. Where it differs is that yours tests multiples of 3 when 3 isn't a factor. For example, for a sufficiently large number that isn't a multiple of 3, it stills tests whether 9, 15, 21 .... are factors. These tests are repeated for successive primes. This is different to Eratosthenes because, in that, multiples are removed once.
This leads to Eratosthenes, or more specifically Euler's Sieve. One can use a std::bitset and the subscript as the number, then set positions in the to false if it isn't prime.
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
An advantage of using std::bitset is that addition is used with the subscript, there is no modulus operation.
JLBorges's code does that too.
(2) Sieve of Eratosthenes is spatially inefficient unlike the algorithm I described |
There are segmented versions of Eratosthenes that use much less memory. Yours doesn't use memory because it doesn't store anything :+)
One might as well store the primes, then it is much cheaper on successive occasions to do a lookup. For example if one found the N'th prime, then wanted something less than the N'th prime, do a lookup.
Regards :+)