Task: Extensible prime generator


C++: #include <iostream>
#include <cstdint>
#include <queue>
#include <utility>
#include <vector>
#include <limits>

template<typename integer>
class prime_generator {
public:
    integer next_prime();
    integer count() const {
        return count_;
    }
private:
    struct queue_item {
        queue_item(integer prime, integer multiple, unsigned int wheel_index) :
            prime_(prime), multiple_(multiple), wheel_index_(wheel_index) {}
        integer prime_;
        integer multiple_;
        unsigned int wheel_index_;
    };
    struct cmp {
        bool operator()(const queue_item& a, const queue_item& b) const {
            return a.multiple_ > b.multiple_;
        }
    };
    static integer wheel_next(unsigned int& index) {
        integer offset = wheel_[index];
        ++index;
        if (index == std::size(wheel_))
            index = 0;
        return offset;
    }
    typedef std::priority_queue<queue_item, std::vector<queue_item>, cmp> queue;
    integer next_ = 11;
    integer count_ = 0;
    queue queue_;
    unsigned int wheel_index_ = 0;
    static const unsigned int wheel_[];
    static const integer primes_[];
};

template<typename integer>
const unsigned int prime_generator<integer>::wheel_[] = {
    2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2,
    6, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6,
    2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4, 2, 10, 2, 10
};

template<typename integer>
const integer prime_generator<integer>::primes_[] = {
    2, 3, 5, 7
};

template<typename integer>
integer prime_generator<integer>::next_prime() {
    if (count_ < std::size(primes_))
        return primes_[count_++];
    integer n = next_;
    integer prev = 0;
    while (!queue_.empty()) {
        queue_item item = queue_.top();
        if (prev != 0 && prev != item.multiple_)
            n += wheel_next(wheel_index_);
        if (item.multiple_ > n)
            break;
        else if (item.multiple_ == n) {
            queue_.pop();
            queue_item new_item(item);
            new_item.multiple_ += new_item.prime_ * wheel_next(new_item.wheel_index_);
            queue_.push(new_item);
        }
        else
            throw std::overflow_error("prime_generator: overflow!");
        prev = item.multiple_;
    }
    if (std::numeric_limits<integer>::max()/n > n)
        queue_.emplace(n, n * n, wheel_index_);
    next_ = n + wheel_next(wheel_index_);
    ++count_;
    return n;
}

int main() {
    typedef uint32_t integer;
    prime_generator<integer> pgen;
    std::cout << "First 20 primes:\n";
    for (int i = 0; i < 20; ++i) {
        integer p = pgen.next_prime();
        if (i != 0)
            std::cout << ", ";
        std::cout << p;
    }
    std::cout << "\nPrimes between 100 and 150:\n";
    for (int n = 0; ; ) {
        integer p = pgen.next_prime();
        if (p > 150)
            break;
        if (p >= 100) {
            if (n != 0)
                std::cout << ", ";
            std::cout << p;
            ++n;
        }
    }
    int count = 0;
    for (;;) {
        integer p = pgen.next_prime();
        if (p > 8000)
            break;
        if (p >= 7700)
            ++count;
    }
    std::cout << "\nNumber of primes between 7700 and 8000: " << count << '\n';

    for (integer n = 10000; n <= 10000000; n *= 10) {
        integer prime;
        while (pgen.count() != n)
            prime = pgen.next_prime();
        std::cout << n << "th prime: " << prime << '\n';
    }
    return 0;
}




Java: import java.util.*;

public class PrimeGenerator {
    private int limit_;
    private int index_ = 0;
    private int increment_;
    private int count_ = 0;
    private List<Integer> primes_ = new ArrayList<>();
    private BitSet sieve_ = new BitSet();
    private int sieveLimit_ = 0;

    public PrimeGenerator(int initialLimit, int increment) {
        limit_ = nextOddNumber(initialLimit);
        increment_ = increment;
        primes_.add(2);
        findPrimes(3);
    }

    public int nextPrime() {
        if (index_ == primes_.size()) {
            if (Integer.MAX_VALUE - increment_ < limit_)
                return 0;
            int start = limit_ + 2;
            limit_ = nextOddNumber(limit_ + increment_);
            primes_.clear();
            findPrimes(start);
        }
        ++count_;
        return primes_.get(index_++);
    }

    public int count() {
        return count_;
    }

    private void findPrimes(int start) {
        index_ = 0;
        int newLimit = sqrt(limit_);
        for (int p = 3; p * p <= newLimit; p += 2) {
            if (sieve_.get(p/2 - 1))
                continue;
            int q = p * Math.max(p, nextOddNumber((sieveLimit_ + p - 1)/p));
            for (; q <= newLimit; q += 2*p)
                sieve_.set(q/2 - 1, true);
        }
        sieveLimit_ = newLimit;
        int count = (limit_ - start)/2 + 1;
        BitSet composite = new BitSet(count);
        for (int p = 3; p <= newLimit; p += 2) {
            if (sieve_.get(p/2 - 1))
                continue;
            int q = p * Math.max(p, nextOddNumber((start + p - 1)/p)) - start;
            q /= 2;
            for (; q >= 0 && q < count; q += p)
                composite.set(q, true);
        }
        for (int p = 0; p < count; ++p) {
            if (!composite.get(p))
                primes_.add(p * 2 + start);
        }
    }

    private static int sqrt(int n) {
        return nextOddNumber((int)Math.sqrt(n));
    }

    private static int nextOddNumber(int n) {
        return 1 + 2 * (n/2);
    }

    public static void main(String[] args) {
        PrimeGenerator pgen = new PrimeGenerator(20, 200000);
        System.out.println("First 20 primes:");
        for (int i = 0; i < 20; ++i) {
            if (i > 0)
                System.out.print(", ");
            System.out.print(pgen.nextPrime());
        }
        System.out.println();
        System.out.println("Primes between 100 and 150:");
        for (int i = 0; ; ) {
            int prime = pgen.nextPrime();
            if (prime > 150)
                break;
            if (prime >= 100) {
                if (i++ != 0)
                    System.out.print(", ");
                System.out.print(prime);
            }
        }
        System.out.println();
        int count = 0;
        for (;;) {
            int prime = pgen.nextPrime();
            if (prime > 8000)
                break;
            if (prime >= 7700)
                ++count;
        }
        System.out.println("Number of primes between 7700 and 8000: " + count);
        int n = 10000;
        for (;;) {
            int prime = pgen.nextPrime();
            if (prime == 0) {
                System.out.println("Can't generate any more primes.");
                break;
            }
            if (pgen.count() == n) {
                System.out.println(n + "th prime: " + prime);
                n *= 10;
            }
        }
    }
}