码迷,mamicode.com
首页 > 其他好文 > 详细

sroHOBOorz来自HOBO的高精类

时间:2014-10-12 13:28:28      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:blog   io   os   ar   for   sp   div   on   log   

/*
 bigint()
 bigint(long long)
 bigint(bigint)
 bigint(char*)
 bigint(string)
 +, +=, ++
 -, -=, --
 *, *=
 /, /=
 <<, <<=
 ==, !=
 <, <=
 >, >=
 -
 !
 abs(bigint), bigint.abs()
 pow(bigint, unsigned), bigint.pow(unsigned)
 root(bigint, unsigned), bigint.root(unsigned)
 sqrt(bigint), bigint.sqrt()
 bigint.read(default = stdin)
 bigint.write(default = stdout)
 istream>>bigint
 ostream<<bigint
 enoughMemory() : optimize division and modulo
*/
#include <iostream>

#ifndef BIGINT
#define BIGINT 1

#include <istream>
#include <ostream>
#include <string>
#include <vector>
#include <complex>
#include <algorithm>
#include <utility>
#include <cstring>
#include <cstdio>
using namespace std;

static const unsigned base = 10000, length = 4;
static bool __enoughMemory = false;

typedef vector<int> vi;
typedef vector<int>::iterator viit;
typedef vector<int>::const_iterator vicit;
typedef vector<int>::reverse_iterator virit;
typedef vector<int>::const_reverse_iterator vicrit;
typedef complex<double> comp;
typedef vector<comp> vc;
typedef vector<comp>::iterator vcit;

class Bigint {
public :
    Bigint();
    template<typename _Tp> Bigint(_Tp);
    Bigint(const Bigint&);
    Bigint(const char*);
    Bigint(const string&);
    
    bool& neg();
    const bool& neg() const;
    vi& num();
    const vi& num() const;
    
    bool operator==(const Bigint&) const;
    bool operator!=(const Bigint&) const;
    bool operator<(const Bigint&) const;
    bool operator<=(const Bigint&) const;
    bool operator>(const Bigint&) const;
    bool operator>=(const Bigint&) const;
    
    Bigint& operator+=(const Bigint&);
    Bigint& operator-=(const Bigint&);
    Bigint& operator*=(const Bigint&);
    Bigint& operator/=(const Bigint&);
    Bigint& operator%=(const Bigint&);
    Bigint& operator<<=(const unsigned&);
    Bigint& operator>>=(const unsigned&);
    
    Bigint& operator++();
    Bigint& operator--();
    Bigint operator-() const;
    bool operator!() const;
    
    int compare(const Bigint&) const;
    bool equal(const Bigint&) const;
    bool less(const Bigint&) const;
    bool lessOrEqual(const Bigint&) const;
    bool greater(const Bigint&) const;
    bool greaterOrEqual(const Bigint&) const;
    
    Bigint& abs();
    Bigint& pow(unsigned);
    Bigint& root(const unsigned&);
    Bigint& sqrt();
    void multiply10(const unsigned&);
    void divide2();
    
    void add(const Bigint&);
    void subtract(const Bigint&);
    void multiply(const Bigint&);
    void multiplySlow(const Bigint&);
    void multiplyFast(const Bigint&, const int&, const int&);
    pair<vi, vi> divide(const Bigint&);
    
    Bigint& read(FILE*);
    const Bigint& write(FILE*) const;
    
private :
    bool _m_neg;
    vi _m_num;
    
    void adjust();
    comp exp(const double&);
    void bitrev(const vcit&, const int&, const int&, const int&, const int&);
    void fft(vc&, const int&, const int&, const bool&);
    
    void divideByZero();
    void imaginaryNumberUnsupported();
    void error(const string&);
};

//pre-declaration
Bigint abs(const Bigint&);
Bigint pow(const Bigint&, const unsigned&);
Bigint root(const Bigint&, const unsigned&);
Bigint sqrt(const Bigint&);
istream& operator>>(istream&, Bigint&);
ostream& operator<<(ostream&, const Bigint&);
void enoughMemory();

//operator
inline Bigint operator+(const Bigint& __x, const Bigint& __y) {
    return Bigint(__x) += __y;
}
inline Bigint operator-(const Bigint& __x, const Bigint& __y) {
    return Bigint(__x) -= __y;
}
inline Bigint operator*(const Bigint& __x, const Bigint& __y) {
    return Bigint(__x) *= __y;
}
inline Bigint operator/(const Bigint& __x, const Bigint& __y) {
    return Bigint(__x) /= __y;
}
inline Bigint operator%(const Bigint& __x, const Bigint& __y) {
    return Bigint(__x) %= __y;
}
template<typename _Tp> inline Bigint operator<<(const Bigint& __x, const _Tp& __y) {
    return Bigint(__x) <<= __y;
}
template<typename _Tp> inline Bigint operator>>(const Bigint& __x, const _Tp& __y) {
    return Bigint(__x) >>= __y;
}

//public

//constructor
inline Bigint::Bigint() {
    neg() = false;
    num().clear();
    num().push_back(0);
}
template<typename _Tp> inline Bigint::Bigint(_Tp __t) {
    if (__t < 0) neg() = true, __t = -__t;
    else neg() = false;
    num().clear();
    while (__t >= base) {
        num().push_back(__t % base);
        __t /= base;
    }
    num().push_back(__t);
}
inline Bigint::Bigint(const Bigint& __t) {
    *this = __t;
}
inline Bigint::Bigint(const char* __c) {
    while (*__c) {
        if (*__c == ‘-‘ || *__c == ‘+‘ || ‘0‘ <= *__c && *__c <= ‘9‘)
            break;
        ++__c;
    }
    if (*__c == ‘-‘) ++__c, neg() = true;
    else {
        neg() = false;
        if (*__c == ‘+‘) ++__c;
    }
    int __n = strlen(__c);
    num().clear();
    if (__n == 0) {
        neg() = false;
        num().push_back(0);
        return ;
    }
    const char* __t = __c + __n;
    while (__c + 1 != __t && *__c == ‘0‘) ++__c;
    int __x = 0, __y = 1, __z = 0;
    while (__t-- != __c) {
        if (__z == 4) {
            num().push_back(__x);
            __x = 0, __y = 1, __z = 0;
        }
        __x += (*__t - ‘0‘) * __y;
        __y = (__y << 3) + (__y << 1);
        ++__z;
    }
    num().push_back(__x);
}
inline Bigint::Bigint(const string& __s) {
    string::const_iterator i = __s.begin();
    string::const_iterator j = __s.end();
    while (i != j) {
        if (*i == ‘-‘ || *i == ‘+‘ || ‘0‘ <= *i && *i <= ‘9‘)
            break;
        ++i;
    }
    if (i != j) {
        if (*i == ‘-‘) ++i, neg() = true;
        else {
            neg() = false;
            if (*i == ‘+‘) ++i;
        }
    }
    int __n = j - i;
    if (__n == 0) {
        neg() = false;
        num().push_back(0);
        return ;
    }
    while (i + 1 != j && *i == ‘0‘) ++i;
    int __x = 0, __y = 1, __z = 0;
    while (j-- != i) {
        if (__z == 4) {
            num().push_back(__x);
            __x = 0, __y = 1, __z = 0;
        }
        __x += (*j - ‘0‘) * __y;
        __y = (__y << 3) + (__y << 1);
        ++__z;
    }
    num().push_back(__x);
}

inline bool& Bigint::neg() {
    return _m_neg;
}
inline const bool& Bigint::neg() const {
    return _m_neg;
}
inline vi& Bigint::num() {
    return _m_num;
}
inline const vi& Bigint::num() const {
    return _m_num;
}

//logical operator
inline bool Bigint::operator==(const Bigint& __t) const {
    return neg() == __t.neg() && equal(__t);
}
inline bool Bigint::operator!=(const Bigint& __t) const {
    return neg() != __t.neg() || !equal(__t);
}
inline bool Bigint::operator<(const Bigint& __t) const {
    if (neg() != __t.neg()) return neg();
    if (neg()) return greater(__t);
    return less(__t);
}
inline bool Bigint::operator<=(const Bigint& __t) const {
    if (neg() != __t.neg()) return neg();
    if (neg()) return greaterOrEqual(__t);
    return lessOrEqual(__t);
}
inline bool Bigint::operator>(const Bigint& __t) const {
    if (neg() != __t.neg()) return __t.neg();
    if (neg()) return less(__t);
    return greater(__t);
}
inline bool Bigint::operator>=(const Bigint& __t) const {
    if (neg() != __t.neg()) return __t.neg();
    if (neg()) return lessOrEqual(__t);
    return greaterOrEqual(__t);
}

//arithmetic operators
inline Bigint& Bigint::operator+=(const Bigint& __t) {
    if (neg() == __t.neg()) add(__t);
    else {
        int __x = compare(__t);
        if (__x == 0) *this = Bigint();
        else if (__x == -1) {
            Bigint __y = *this;
            *this = __t;
            subtract(__y);
        }
        else subtract(__t);
    }
    return *this;
}
inline Bigint& Bigint::operator-=(const Bigint& __t) {
    return *this += (-__t);
}
inline Bigint& Bigint::operator*=(const Bigint& __t) {
    if (*this != 0 && __t != 0) {
        neg() = neg() != __t.neg();
        multiply(__t);
    }
    else *this = Bigint();
    return *this;
}
inline Bigint& Bigint::operator/=(const Bigint& __t) {
    if (__t == 0) divideByZero();
    if (less(__t)) *this = Bigint();
    else {
        neg() = neg() != __t.neg();
        num() = divide(__t).first;
        adjust();
    }
    return *this;
}
inline Bigint& Bigint::operator%=(const Bigint& __t) {
    if (__t == 0) divideByZero();
    num() = divide(__t).second;
    adjust();
    if (num().size() == 1 && !*num().rbegin()) neg() = false;
    return *this;
}
inline Bigint& Bigint::operator<<=(const unsigned& __y) {
    return *this *= Bigint(2).pow(__y);
}
inline Bigint& Bigint::operator>>=(const unsigned& __y) {
    for (unsigned i = 0 ; i < __y ; ++i) divide2();
    return *this;
}

//self operator
inline Bigint& Bigint::operator++() {
    return *this += 1;
}
inline Bigint& Bigint::operator--() {
    return *this -= 1;
}
inline Bigint Bigint::operator-() const {
    Bigint __t = *this;
    if (__t != 0) __t.neg() ^= true;
    return __t;
}
inline bool Bigint::operator!() const {
    return *this == 0;
}

//comparator
inline int Bigint::compare(const Bigint& __t) const {
    if (num().size() < __t.num().size()) return -1;
    else if (num().size() > __t.num().size()) return 1;
    vicrit i = num().rbegin();
    vicrit j = __t.num().rbegin();
    while (i != num().rend()) {
        if (*i < *j) return -1;
        else if (*i > *j) return 1;
        ++i, ++j;
    }
    return 0;
}
inline bool Bigint::equal(const Bigint& __t) const {
    return compare(__t) == 0;
}
inline bool Bigint::less(const Bigint& __t) const {
    return compare(__t) == -1;
}
inline bool Bigint::lessOrEqual(const Bigint& __t) const {
    int __r = compare(__t);
    return __r == -1 || __r == 0;
}
inline bool Bigint::greater(const Bigint& __t) const {
    return compare(__t) == 1;
}
inline bool Bigint::greaterOrEqual(const Bigint& __t) const {
    int __r = compare(__t);
    return __r == 1 || __r == 0;
}

//math
inline Bigint& Bigint::abs() {
    if (neg()) neg() = false;
    return *this;
}
inline Bigint& Bigint::pow(unsigned __y) {
    Bigint __x = *this;
    *this = 1;
    while (__y) {
        if (__y & 1) *this *= __x;
        __x *= __x;
        __y >>= 1;
    }
    return *this;
}
inline Bigint& Bigint::root(const unsigned& __y = 2) {
    if (!__y) divideByZero();
    if (*this == 0 || __y == 1) return *this;
    bool __n = neg();
    if (__n)
        if (__y & 1) neg() = false;
        else imaginaryNumberUnsupported();
    const double log2_10 = 3.3219280948873623478703194294893901758648313930245806;
    size_t __s = num().size();
    if (double(__s << 2) * log2_10 < __y) return *this = 1;
    __s = __s / __y + (__s % __y ? 1 : 0);
    int __l, __r, __m;
    Bigint __a = *this, __b, __c;
    num().clear();
    for (int i = __s - 1 ; i >= 0 ; --i) {
        __l = 1, __r = base - 1;
        while (__l <= __r) {
            __m = __l + __r >> 1;
            __b = *this;
            __b.num().insert(__b.num().begin(), __m);
            __b.pow(__y);
            __b.multiply10(i * __y << 2);
            if (__b <= __a) __l = __m + 1;
            else __r = __m - 1;
        }
        num().insert(num().begin(), __r);
    }
    neg() = __n;
    return *this;
}
inline Bigint& Bigint::sqrt() {
    root();
    return *this;
}
inline void Bigint::multiply10(const unsigned& __t) {
    if (!__t) return ;
    size_t __s = num().size();
    size_t __r = (__t >> 2) + (__t & 3 ? 1 : 0);
    int __x = 0, __y, __z, __a, __b;
    if ((__t & 3) == 0) __a = 1, __b = 10000;
    else if ((__t & 3) == 1) __a = 1000, __b = 10;
    else if ((__t & 3) == 2) __a = 100, __b = 100;
    else if ((__t & 3) == 3) __a = 10, __b = 1000;
    num().resize(__s + __r);
    virit i = num().rbegin();
    virit j = i + __r;
    while (i != num().rbegin() + __s) {
        __y = *j++;
        __z = __y / __a;
        __x += __z;
        *i++ = __x;
        __x = (__y - __z * __a) * __b;
    }
    *i++ = __x;
    fill(i, num().rend(), 0);
    adjust();
}
inline void Bigint::divide2() {
    int __t = 0;
    for (virit i = num().rbegin() ; i != num().rend() ; ++i) {
        __t = (__t & 1 ? base : 0) + *i;
        *i = __t >> 1;
    }
    adjust();
}

//+, -, *, /
inline void Bigint::add(const Bigint& __t) {
    if (num().size() < __t.num().size())
        num().resize(__t.num().size());
    viit i = num().begin();
    vicit j = __t.num().begin();
    while (i != num().end() && j != __t.num().end())
        *i++ += *j++;
    for (i = num().begin() ; i + 1 != num().end() ; ++i)
        if (*i >= base) {
            *i -= base;
            ++*(i + 1);
        }
    if (*i >= base) {
        *i -= base;
        num().push_back(1);
    }
}
inline void Bigint::subtract(const Bigint& __t) {
    viit i = num().begin();
    vicit j = __t.num().begin();
    while (j != __t.num().end())
        *i++ -= *j++;
    for (i = num().begin() ; i + 1 != num().end() ; ++i)
        if (*i < 0) {
            *i += base;
            --*(i + 1);
        }
    adjust();
}
inline void Bigint::multiply(const Bigint& __t) {
    int __n = max(num().size(), __t.num().size());
    int __l = 0;
    while ((1 << __l) < __n) ++__l;
    __n = 1 << ++__l;
    if ((long long)num().size() * __t.num().size() <= (long long)__n * __l * 20)
        multiplySlow(__t);
    else
        multiplyFast(__t, __n, __l);
    adjust();
}
inline void Bigint::multiplySlow(const Bigint& __t) {
    int __n = num().size() + __t.num().size(), i, j, k;
    vi __x, __y;
    if (__t.num().size() * 4 < num().size())
        __x = __t.num(), __y = num();
    else
        __x = num(), __y = __t.num();
    num().clear();
    num().resize(__n);
    for (i = 0 ; i < __x.size() ; ++i) {
        k = __x[i];
        for (j = 0 ; j < __y.size() ; ++j)
            num()[i + j] += k * __y[j];
        k = i + 1 + __y.size();
        for (j = 0 ; j < k ; ++j) {
            num()[j + 1] += num()[j] / base;
            num()[j] %= base;
        }
    }
}
inline void Bigint::multiplyFast(const Bigint& __t, const int& __n, const int& __l) {
    vc a, b;
    a.reserve(__n);
    b.reserve(__n);
    for (viit i = num().begin() ; i != num().end() ; ++i)
        a.push_back(comp(*i, 0));
    for (vicit i = __t.num().begin() ; i != __t.num().end() ; ++i)
        b.push_back(comp(*i, 0));
    a.resize(__n);
    b.resize(__n);
    fft(a, __l, __n, true);
    fft(b, __l, __n, true);
    vcit i = a.begin(), j = b.begin();
    while (i != a.end()) *i++ *= *j++;
    fft(a, __l, __n, false);
    long long __x = 0;
    num().resize(__n);
    i = a.begin();
    viit k = num().begin();
    while (i != a.end()) {
        __x = (long long)(i++ ->real() / __n + 0.5) + __x / base;
        *k++ = __x % base;
    }
}
inline pair<vi, vi> Bigint::divide(const Bigint& __t) {
    int __l, __r, __m, __n = num().size() - __t.num().size() + 1;
    Bigint __x = *this, __y = __t, __z;
    vi __v;
    __v.resize(__n);
    if (__enoughMemory) {
        Bigint __p[10];
        for (__m = 0 ; __m < 10 ; ++__m) __p[__m] = __m * __y;
        for (int i = __n - 1 ; i >= 0 ; --i) {
            int k = 0;
            for (int j = 3 + (i << 2) ; j >= (i << 2) ; --j) {
                __l = 1, __r = 9;
                while (__l <= __r) {
                    __m = __l + __r >> 1;
                    __z = __p[__m];
                    __z.multiply10(j);
                    if (__z.greater(__x)) __r = __m - 1;
                    else __l = __m + 1;
                }
                k = (k << 3) + (k << 1) + __r;
                __z = __p[__r];
                __z.multiply10(j);
                __x.subtract(__z);
            }
            __v[i] = k;
        }
    }
    else {
        for (int i = __n - 1 ; i >= 0 ; --i) {
            __l = 1, __r = base - 1;
            while (__l <= __r) {
                __m = __l + __r >> 1;
                __z = __m * __y;
                __z.multiply10(i << 2);
                if (__z.greater(__x)) __r = __m - 1;
                else __l = __m + 1;
            }
            __v[i] = __r;
            __z = __r * __y;
            __z.multiply10(i << 2);
            __x.subtract(__z);
        }
    }
    return make_pair(__v, __x.num());
}

//io
inline Bigint& Bigint::read(FILE *in = stdin) {
    string __s = "";
    char __c = fgetc(in);
    while (true) {
        if (__c == ‘-‘ || __c == ‘+‘ || ‘0‘ <= __c && __c <= ‘9‘ || __c == EOF)
            break;
        __c = fgetc(in);
    }
    while (true) {
        __s += __c;
        __c = fgetc(in);
        if (__c < ‘0‘ || __c > ‘9‘) break;
    }
    return *this = Bigint(__s.c_str());
}
inline const Bigint& Bigint::write(FILE *out = stdout) const {
    vicrit i = num().rbegin();
    if (neg()) fprintf(out, "-");
    fprintf(out, "%d", *i++);
    while (i != num().rend()) fprintf(out, "%04d", *i++);
    return *this;
}

//private

//other
inline void Bigint::adjust() {
    virit i = num().rbegin();
    while (i + 1 != num().rend()) {
        if (*i) break;
        ++i;
    }
    num().erase(i.base(), num().end());
}
inline comp Bigint::exp(const double& u) {
    return comp(cos(u), sin(u));
}
inline void Bigint::bitrev(const vcit& i, const int& __l, const int& __p, const int& __x, const int& __y) {
    if (__p == 0) {
        if (__x < __y) swap(*(i + __x), *(i + __y));
        return ;
    }
    bitrev(i, __l, __p - 1, __x << 1, __y);
    bitrev(i, __l, __p - 1, __x << 1 | 1, __y | (1 << __l - __p));
}
inline void Bigint::fft(vc& __a, const int& __l, const int& __n, const bool& __r) {
    const double __p = 3.141592653589793238462643383279;
    bitrev(__a.begin(), __l, __l, 0, 0);
    for (int i = 1 ; i <= __l ; ++i) {
        int __m = 1 << i;
        comp wm = exp((__r ? -2 : 2) * __p / __m);
        for (int k = 0 ; k < __n ; k += __m) {
            comp w = 1;
            for (int j = 0 ; j < __m / 2 ; ++j) {
                comp t = w * __a[k + j + __m / 2];
                comp u = __a[k + j];
                __a[k + j] = u + t;
                __a[k + j + __m / 2] = u - t;
                w *= wm;
            }
        }
    }
}

//error
inline void Bigint::divideByZero() {
    error("divide by zero");
}
inline void Bigint::imaginaryNumberUnsupported() {
    error("imaginary number unsupported");
}
inline void Bigint::error(const string& __s) {
    fprintf(stderr, "%s\n", __s.c_str());
    cerr << __s << endl;
    abort();
}

//math
inline Bigint abs(const Bigint& __x) {
    return Bigint(__x).abs();
}
inline Bigint pow(const Bigint& __x, const unsigned& __y) {
    return Bigint(__x).pow(__y);
}
inline Bigint root(const Bigint& __x, const unsigned& __y = 2) {
    return Bigint(__x).root(__y);
}
inline Bigint sqrt(const Bigint& __x) {
    return Bigint(__x).sqrt();
}

//io
inline istream& operator>>(istream& __s, Bigint& __t) {
    string __r;
    __s >> __r;
    __t = Bigint(__r);
    return __s;
}
inline ostream& operator<<(ostream& __s, const Bigint& __t) {
    if (__t.neg()) __s << ‘-‘;
    vicrit i = __t.num().rbegin();
    __s << *i;
    while (++i != __t.num().rend()) {
        __s.width(length);
        __s.fill(‘0‘);
        __s << *i;
    }
    return __s;
}

//optimization
inline void enoughMemory() {
    __enoughMemory = true;
}

#endif

  

sroHOBOorz来自HOBO的高精类

标签:blog   io   os   ar   for   sp   div   on   log   

原文地址:http://www.cnblogs.com/JackSlowFuck/p/4020264.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!