primes.h

素数素因数分解に関するライブラリ。VC10β2で先取りしたC++0xの機能を用いている。
破壊的な変更がされる場合は別にエントリーを立てる。

//
// primes.h
// by M.Inamori
// written 3/25/10
// revised 4/16/10

#pragma once
#include "itertools.h"

namespace primes {
    std::vector<int>    primes(1, 2);
    
    class genPrimes {
        int k;
        static const int    N = 20000;
        
    public:
        genPrimes(int k = 0) : k(k) { init_primes(); }
        int next();
        bool exists_next() { return true; }
        
    private:
        void init_primes() {
            if((int)primes.size() > 2)
                return;
            
            // ふるいには範囲の上端の平方根までの素数が必要
            for(int n = 3; n <= int(sqrt((double)N)) * 2 + 1; n += 2) {
                if(is_prime(n))
                    primes.push_back(n);
            }
        }
        int sieve_size() const {
            int n = primes.back();
            return ((int)sqrt((double)n) / N + 1) * N;
        }
        bool is_prime(int n) const {
            for(int k = 0; ; k++) {
                int p = primes[k];
                if(p * p > n)
                    return true;
                else if(n % p == 0)
                    return false;
            }
        }
    };
    
    int genPrimes::next() {
        if(k >= (int)primes.size()) {
            int s = sieve_size();
            int *a = new int[s/2];
            for(int i = 0; i < s / 2; i++)
                a[i] = true;
            int offs = primes.back() + 2;
            int max_n = offs + s - 2;
            int limit = (int)sqrt((double)max_n);
            for(int k = 1; primes[k] <= limit; k++) {
                int p = primes[k];
                int init = ((offs + p) / 2 + p - 1) / p * p - (offs + p) / 2;
                for(int k = init; k < s / 2; k += p)
                    a[k] = false;
            }
            
            for(int k = 0; k < s / 2; k++) {
                if(a[k])
                    primes.push_back(offs + k * 2);
            }
            delete [] a;
        }
        
        if(k < (int)primes.size()) {
            k++;
            return primes[k-1];
        }
        else {
            return next();
        }
    }
    
    bool is_prime(int n) {
        using namespace itertools;
        if(n < 2) return false;
        return all([n] (int p) { return n % p != 0; },
                    takewhile([n] (int p) { return p * p <= n; },
                    genPrimes()));
    }
    
    typedef std::tuple<int,int> Fact;
    typedef std::vector<Fact>   Facts;
    
    std::ostream& operator<<(std::ostream& os, const Fact& f) {
        int     p = itertools::fst(f);
        int     e = itertools::snd(f);
        os << p;
        if(e > 1)
            os << "^" << e;
        return os;
    }
    
    std::ostream& operator<<(std::ostream& os, const Facts& f) {
        if(f.size() > 0) {
            for(int k = 0; k < (int)f.size() - 1; k++) {
                os << f[k] << " * ";
            }
            os << f.back();
        }
        else {
            os << 1;
        }
        return os;
    }
    
    class factorize {
        int     n;
        Fact    f;
        factorize   *fs;
        bool    first;
        
    public:
        factorize(int n, genPrimes *pg = nullptr) : n(n), first(true) {
            if(pg == nullptr)
                pg = new genPrimes();
            
            int k = 0;
            int p = pg->next();
            while(p * p <= n) {
                k++;
                int e = 0;
                while(n % p == 0) {
                    n /= p;
                    e++;
                }
                if(e > 0) {
                    f = Fact(p, e);
                    if(n > 1)
                        fs = new factorize(n, new genPrimes(k));
                    else
                        fs = nullptr;
                    delete pg;
                    return;
                }
                p = pg->next();
            }
            f = Fact(n, 1);
            fs = nullptr;
            delete pg;
        }
        ~factorize() {
            if(fs != nullptr)
                delete fs;
        }
        
        Fact next() {
            if(first) {
                first = false;
                return f;
            }
            else {
                if(fs == nullptr)
                    throw("error : no more elements in factorize.");
                return fs->next();
            }
        }
        bool exists_next() {
            if(first)
                return true;
            else if(fs == nullptr)
                return false;
            else
                return fs->exists_next();
        }
    };
    
    class divisors {
        Facts::iterator begin;
        Facts::iterator end;
        divisors    *g;
        int         p, e;
        int         e_max;
        std::tuple<Facts,Facts>     f;
        
    public:
        divisors() { }
        divisors(Facts::iterator b, Facts::iterator e) : begin(b), end(e) {
            if(begin == end) {
                g = nullptr;
            }
            else {
                g = new divisors(begin + 1, end);
                p = std::get<0>(*begin);
                e_max = std::get<1>(*begin);
            }
            this->e = 0;
        }
        
        std::tuple<Facts,Facts> next() {
            using namespace std;
            
            if(g == nullptr) {
                if(e == 0) {
                    e++;
                    return make_tuple(Facts(),Facts());
                }
                else {
                    throw("error : no more elements in divisors.");
                }
            }
            else {
                if(e == 0)
                    f = g->next();
                else if(e == 1)
                    get<0>(f).insert(get<0>(f).begin(), Fact(p, 1));
                else
                    get<1>(get<0>(f).front()) = e;
                
                if(e == 0)
                    get<1>(f).insert(get<1>(f).begin(), Fact(p, e_max));
                else if(e == e_max)
                    get<1>(f).erase(get<1>(f).begin());
                else
                    get<1>(get<1>(f).front()) = e_max - e;
                
                if(e == e_max)
                    e = 0;
                else
                    e++;
                
                return f;
            }
        }
        bool exists_next() {
            if(g == nullptr)
                return e == 0;
            else if(e == 0)
                return g->exists_next();
            else
                return true;
        }
    };
    
    int value_f(const Facts& f) {
        int     v = 1;
        for(int i = 0; i < (int)f.size(); i++) {
            int p = std::get<0>(f[i]);
            int e_max = std::get<1>(f[i]);
            for(int e = 0; e < e_max; e++)
                v *= p;
        }
        return v;
    }
    
    Facts mul_f(const Facts& f1, const Facts& f2) {
        Facts   f;
        int     k1 = 0;
        int     k2 = 0;
        while(true) {
            if(k1 < (int)f1.size()) {
                int p1 = itertools::fst(f1[k1]);
                int e1 = itertools::snd(f1[k1]);
                if(k2 < (int)f2.size()) {
                    int p2 = itertools::fst(f2[k2]);
                    int e2 = itertools::snd(f2[k2]);
                    if(p1 == p2) {
                        f.push_back(Fact(p1, e1 + e2));
                        k1++;
                        k2++;
                    }
                    else if(p1 < p2) {
                        f.push_back(f1[k1]);
                        k1++;
                    }
                    else {
                        f.push_back(f2[k2]);
                        k2++;
                    }
                }
                else {
                    f.push_back(f1[k1]);
                    k1++;
                }
            }
            else {
                if(k2 < (int)f2.size()) {
                    f.push_back(f2[k2]);
                    k2++;
                }
                else {
                    break;
                }
            }
        }
        return f;
    }
    
    // 割り算の結果は自然数となる仮定で
    Facts div_f(const Facts& f1, const Facts& f2) {
        Facts   f;
        int     k2 = 0;
        for(int k1 = 0; k1 < (int)f1.size(); k1++) {
            int p1 = itertools::fst(f1[k1]);
            int e1 = itertools::snd(f1[k1]);
            if(k2 < (int)f2.size()) {
                int p2 = itertools::fst(f2[k2]);
                int e2 = itertools::snd(f2[k2]);
                if(p1 == p2) {
                    if(e1 > e2)
                        f.push_back(Fact(p1, e1 - e2));
                    k2++;
                }
                else {
                    f.push_back(f1[k1]);
                }
            }
            else {
                f.push_back(f1[k1]);
            }
        }
        return f;
    }
}