/* * 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 <vector> #include <string> #include <iostream> #include <sstream> #include <algorithm> 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() { 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() { 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() { return heap.front().eliminates(); } // Insert a new prime eliminator into the collection. void insert(int i) { heap.push_back(Eliminator(i)); push_heap(heap.begin(), heap.end()); } // Move on to the next elimination target. void advance() { // Get the current eliminee. int you_die = eliminates(); // Get rid of all the nodes which eliminate this same number. vector<Eliminator>::iterator heap_end = heap.end(); while(heap_end != heap.begin() && heap.front().eliminates() == you_die) { pop_heap(heap.begin(), heap_end); --heap_end; heap_end->advance(); } // Return them, now advanced, to the heap. do { ++heap_end; push_heap(heap.begin(), heap_end); } while(heap_end != heap.end()); } // Get 'em out. void dump() { vector<Eliminator>::iterator scan = heap.begin(); while(scan != heap.end()) { scan->print(); cout << endl; ++scan; } } private: // This holds the heap data structure. vector<Eliminator> heap; }; /* * Output with appropriate line breaking. */ void outprime(int n) { static int outlen = 0; // Output line width. // Get the string for n. ostringstream os; os << n; string strint = os.str(); // Do any needed wrap. if(outlen + strint.length() + 1 > 75) { cout << endl; outlen = 0; } else { cout << " "; outlen++; } cout << strint; 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. */ main() { outprime(2); EliminatorCollection ec; ec.insert(2); for(int m=3; 1; m++) { if(m == ec.eliminates()) ec.advance(); else { //cout << m << endl; outprime(m); ec.insert(m); } } cout << endl; }