/* * This program generates prime numbers fairly quickly using a sieve. * It prints prime numbers until the first of * o You get tired and kill it. * o It runs out of memory and crashes. * o The integers start to overflow, in which case you have a computer * with a whole lot of memory. */ #include #include #include #include using namespace std; /* * Prime eliminator. It is essentially a pair of numbers, the first prime * and the second a multiple of the first. The program keeps a collection * of these in a heap to eliminate candidate primes. */ class Eliminator { public: // Create at a prime, ready to eliminate the first multiple thereof. Eliminator(int p): base(p), target(2*p) { } // See what number is eliminated next. int eliminates() const { return target; } // Advance to the next elimination. void advance() { target += base; } // Compare Eliminators according to their eliminated value. bool operator<(const Eliminator &e) const { return target > e.target; // Note: Inverted sense } bool operator==(const Eliminator &e) const { return target == e.target; } void print() const { cout << "(" << base << ", " << target << ")"; } private: // The base is a prime number, and the target is the next multiple // which it has not yet eliminated. int base, target; }; // This is a collection of Eliminators organized as a heap, so the next largest // one can be found quickly. class EliminatorCollection { public: // What does the heap eliminate just now? int eliminates() const { return heap.top().eliminates(); } // Insert a new prime eliminator into the collection. void insert(int i) { heap.push(Eliminator(i)); } // Move on to the next elimination target. void advance() { // Get the current eliminee. int you_die = eliminates(); // Remove that and any other which eliminate the same thing, // advance it, and stick it back on. while(!heap.empty() && heap.top().eliminates() == you_die) { Eliminator e = heap.top(); heap.pop(); e.advance(); heap.push(e); } } private: // This holds the heap data structure. priority_queue heap; }; /* * Trivial class to output each number with appropriate line breaking. */ class OutLiner { private: int m_outlen; // Current output line length const int m_linemax; // Maximum output line length. public: OutLiner(int linemax): m_linemax(linemax), m_outlen(0) { } void outprime(int n) { // Convert the number to string, so we know how long // it will be. Then see if it fits on the line. string strint = to_string(n); if(m_outlen + strint.length() + 1 > m_linemax) { // Nope. End the line has zero on it. cout << endl; m_outlen = 0; } else { // Yep. Add a space and count it. cout << " "; m_outlen++; } // Print it, and update the count. cout << strint; m_outlen += strint.length(); } }; /* * Generate primes until you get tired of it (or run out of * ints). This uses a form of the seive method which * eliminates non-prime candidate primes by checking if they are a * multiple of any previous prime found. This is done efficiently by * keeping the set of multiples of previously-found primes in a heap. * A heap is a data structure which can quickly find the smallest * number it contains. */ int main() { OutLiner lpr(75); lpr.outprime(2); EliminatorCollection ec; ec.insert(2); for(int m=3; 1; m++) { if(m == ec.eliminates()) ec.advance(); else { //cout << m << endl; lpr.outprime(m); ec.insert(m); } } cout << endl; }