To find all primes up to n, don't test each number on its own. Cross out multiples instead:
- assume every number from 2 to n is prime
- for each
pstill marked prime, cross outp², p² + p, p² + 2p, … - whatever remains unmarked is prime
Start at p² because smaller multiples of p were already crossed out by smaller primes. The total work is O(n log log n), practically linear.
Trading memory (a boolean array) for time like this is one of the most common optimization patterns.