C++ 实现BigInteger 类

说明

  该文件旨在使 BigInteger 类在 C++ 中能够像基本数据类型一样使用。由于该类是在 vector< int > 类的基础上做计算,所以其计算速度不如 int,但也因此获得了更高的精度。


已重载的运算符

运算符类型 运算符
双目运算符 +(加), -(减), *(乘), /(整除), %(取模)
关系运算符 ==(等于), !=(不等于), <(小于), >(大于), <=(小于等于), >=(大于等于)
逻辑运算符 ||(逻辑或), &&(逻辑与), !(逻辑非)
单目运算符 +(正), -(负)
自增自减运算符 ++(自增), –(自减)
赋值运算符 =, +=, -=, *=, /=, %=
位运算符 >>(右移运算符,与输入流关联), <<(左移运算符,与输出流关联)

支持的其他函数

函数声明 函数功能
size_t size() const 返回 BigInteger 对象的位数
BigInteger e(size_t n) const 返回 BigInteger 对象 × 10n 后的值
BigInteger abs() const 返回 BigInteger 对象的绝对值


  更多函数请使用者在已有代码基础上自行编写。


计算耗时比( tBigIntegertint/longlong )

运算符 int long long
ostream& operator<<(ostream&, const T&) 1.087 1.097
istream& operator>>(istream&, T&) 1.355 1.211
abs() 1.407 1.273
比较运算符 1.490 1.506
T operator+(const T&, const T&) 3.180 3.063
T operator-(const T&, const T&) 3.140 3.014
T operator*(const T&, const T&) 1.938 2.121
T operator/(const T&, const T&) 8.698 19.616
T operator%(const T&, const T&) 11.038 20.656


  检验结果准确性与运行时间代码,在 test.cpp 文件内,可将三个文件添加到工程中运行检测。默认将 BigInteger 类的计算时间与 int 类型数据计算时间比较,若要与 long long 类型计算时间进行比较,可将程序第 11 行

typedef int Type

  改为

typedef long long Type
此为第二版本,修复初版以下问题:
1. 缺少 const BigInteger& operator=(int n) 赋值函数导致的程序二义性问题
2. 对于常量 LONG_LONG_MIN abs 为负值的修正
3. 添加输入与构造函数的 const char* 格式检查,格式不符时,当前输入失效,不改变变量值,构造函数则默认构造 BigInteger(0)

该类的局限性:
1. 可以与 bool, int, long long 数据类型做隐式类型转换(只能从低精度往高精度),但不能与浮点数做隐式类型转换
2. 构造函数不支持 long int 类型
3. 对除以 0 错误不做处理

biginteger.h 头文件:

#ifndef BIGINTEGER_H_
#define BIGINTEGER_H_

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

class BigInteger {
private:
    static const int BASE = 100000000;
    static const int WIDTH = 8;
    bool sign;
    size_t length;
    vector<int> num;

    void cutLeadingZero();
    void setLength();

public:
    BigInteger(int n = 0);
    BigInteger(long long n);
    BigInteger(const char *n);
    BigInteger(const BigInteger &n);

    const BigInteger& operator=(int n);
    const BigInteger& operator=(long long n);
    const BigInteger& operator=(const char *n);
    const BigInteger& operator=(const BigInteger &n);

    size_t size() const;
    BigInteger e(size_t n) const;
    BigInteger abs() const;

    const BigInteger& operator+() const;
    friend BigInteger operator+(const BigInteger &a, const BigInteger &b);
    const BigInteger& operator+=(const BigInteger &n);
    const BigInteger& operator++();
    BigInteger operator++(int);

    BigInteger operator-() const;
    friend BigInteger operator-(const BigInteger &a, const BigInteger &b);
    const BigInteger& operator-=(const BigInteger &n);
    const BigInteger& operator--();
    BigInteger operator--(int);

    friend BigInteger operator*(const BigInteger &a, const BigInteger &b);
    const BigInteger& operator*=(const BigInteger &n);

    friend BigInteger operator/(const BigInteger &a, const BigInteger &b);
    const BigInteger& operator/=(const BigInteger &n);

    friend BigInteger operator%(const BigInteger &a, const BigInteger &b);
    const BigInteger& operator%=(const BigInteger &n);

    friend bool operator<(const BigInteger &a, const BigInteger &b);
    friend bool operator<=(const BigInteger &a, const BigInteger &b);
    friend bool operator>(const BigInteger &a, const BigInteger &b);
    friend bool operator>=(const BigInteger &a, const BigInteger &b);
    friend bool operator==(const BigInteger &a, const BigInteger &b);
    friend bool operator!=(const BigInteger &a, const BigInteger &b);

    friend bool operator||(const BigInteger &a, const BigInteger &b);
    friend bool operator&&(const BigInteger &a, const BigInteger &b);
    bool operator!();

    friend ostream& operator<<(ostream &out, const BigInteger &n);
    friend istream& operator>>(istream &in, BigInteger &n);
};

#endif // BIGINTEGER_H_

biginteger.cpp 代码实现文件:

#include "biginteger.h"

void BigInteger::cutLeadingZero() {
    while(num.back() == 0 && num.size() != 1) {
        num.pop_back();
    }
}

void BigInteger::setLength() {
    cutLeadingZero();
    int tmp = num.back();
    if(tmp == 0) {
        length = 1;
    } else {
        length = (num.size() - 1) * 8;
        while(tmp > 0) {
            ++length;
            tmp /= 10;
        }
    }
}

BigInteger::BigInteger(int n) {
    *this = n;
}

BigInteger::BigInteger(long long n) {
    *this = n;
}

BigInteger::BigInteger(const char *n) {
    *this = n;
}

BigInteger::BigInteger(const BigInteger &n) {
    *this = n;
}

const BigInteger& BigInteger::operator=(int n) {
    *this = (long long)n;
    return *this;
}

const BigInteger& BigInteger::operator=(long long n) {
    num.clear();
    if(n == 0) {
        num.push_back(0);
    }
    if(n >= 0) {
        sign = true;
    } else if(n == LONG_LONG_MIN) {
        *this = "-9223372036854775808";
        return *this;
    } else if(n < 0) {
        sign = false;
        n = -n;
    }
    while(n != 0) {
        num.push_back(n % BASE);
        n /= BASE;
    }
    setLength();
    return *this;
}

const BigInteger& BigInteger::operator=(const char *n) {
    int len = strlen(n);
    int tmp = 0;
    int ten = 1;
    int stop = 0;
    num.clear();
    sign = (n[0] != '-');
    if(!sign) {
        stop = 1;
    }
    for(int i = len; i > stop; --i) {
        tmp += (n[i - 1] - '0') * ten;
        ten *= 10;
        if((len - i) % 8 == 7) {
            num.push_back(tmp);
            tmp = 0;
            ten = 1;
        }
    }
    if((len - stop) % WIDTH != 0) {
        num.push_back(tmp);
    }
    setLength();
    return *this;
}

const BigInteger& BigInteger::operator=(const BigInteger &n) {
    num = n.num;
    sign = n.sign;
    length = n.length;
    return *this;
}

size_t BigInteger::size() const {
    return length;
}

BigInteger BigInteger::e(size_t n) const {
    int tmp = n % 8;
    BigInteger ans;
    ans.length = n + 1;
    n /= 8;
    while(ans.num.size() <= n) {
        ans.num.push_back(0);
    }
    ans.num[n] = 1;
    while(tmp--) {
        ans.num[n] *= 10;
    }
    return ans * (*this);
}

BigInteger BigInteger::abs() const {
    BigInteger ans(*this);
    ans.sign = true;
    return ans;
}

const BigInteger& BigInteger::operator+() const {
    return *this;
}

BigInteger operator+(const BigInteger &a, const BigInteger &b) {
    if(!b.sign) {
        return a - (-b);
    }
    if(!a.sign) {
        return b - (-a);
    }
    BigInteger ans;
    int carry = 0;
    int aa, bb;
    size_t lena = a.num.size();
    size_t lenb = b.num.size();
    size_t len = max(lena, lenb);
    ans.num.clear();
    for(size_t i = 0; i < len; ++i) {
        if(lena <= i) {
            aa = 0;
        } else {
            aa = a.num[i];
        }
        if(lenb <= i) {
            bb = 0;
        } else {
            bb = b.num[i];
        }
        ans.num.push_back((aa + bb + carry) % BigInteger::BASE);
        carry = (aa + bb + carry) / BigInteger::BASE;
    }
    if(carry > 0) {
        ans.num.push_back(carry);
    }
    ans.setLength();
    return ans;
}

const BigInteger& BigInteger::operator+=(const BigInteger &n) {
    *this = *this + n;
    return *this;
}

const BigInteger& BigInteger::operator++() {
    *this = *this + 1;
    return *this;
}

BigInteger BigInteger::operator++(int) {
    BigInteger ans(*this);
    *this = *this + 1;
    return ans;
}

BigInteger BigInteger::operator-() const {
    BigInteger ans(*this);
    if(ans != 0) {
        ans.sign = !ans.sign;
    }
    return ans;
}

BigInteger operator-(const BigInteger &a, const BigInteger &b) {
    if(!b.sign) {
        return a + (-b);
    }
    if(!a.sign) {
        return -((-a) + b);
    }
    if(a < b) {
        return -(b - a);
    }
    BigInteger ans;
    int carry = 0;
    int aa, bb;
    size_t lena = a.num.size();
    size_t lenb = b.num.size();
    size_t len = max(lena, lenb);
    ans.num.clear();
    for(size_t i = 0; i < len; ++i) {
        aa = a.num[i];
        if(i >= lenb) {
            bb = 0;
        } else {
            bb = b.num[i];
        }
        ans.num.push_back((aa - bb - carry + BigInteger::BASE) % BigInteger::BASE);
        if(aa < bb + carry) {
            carry = 1;
        } else {
            carry = 0;
        }
    }
    ans.setLength();
    return ans;
}

const BigInteger& BigInteger::operator-=(const BigInteger &n) {
    *this = *this - n;
    return *this;
}

const BigInteger& BigInteger::operator--() {
    *this = *this - 1;
    return *this;
}

BigInteger BigInteger::operator--(int) {
    BigInteger ans(*this);
    *this = *this - 1;
    return ans;
}

BigInteger operator*(const BigInteger &a, const BigInteger&b) {
    size_t lena = a.num.size();
    size_t lenb = b.num.size();
    vector<long long> ansLL;
    for(size_t i = 0; i < lena; ++i) {
        for(size_t j = 0; j < lenb; ++j) {
            if(i + j >= ansLL.size()) {
                ansLL.push_back((long long)a.num[i] * (long long)b.num[j]);
            } else {
                ansLL[i + j] += (long long)a.num[i] * (long long)b.num[j];
            }
        }
    }
    while(ansLL.back() == 0 && ansLL.size() != 1) {
        ansLL.pop_back();
    }
    size_t len = ansLL.size();
    long long carry = 0;
    long long tmp;
    BigInteger ans;
    ans.sign = (ansLL.size() == 1 && ansLL[0] == 0) || (a.sign == b.sign);
    ans.num.clear();
    for(size_t i = 0; i < len; ++i) {
        tmp = ansLL[i];
        ans.num.push_back((tmp + carry) % BigInteger::BASE);
        carry = (tmp + carry) / BigInteger::BASE;
    }
    if(carry > 0) {
        ans.num.push_back(carry);
    }
    ans.setLength();
    return ans;
}

const BigInteger& BigInteger::operator*=(const BigInteger &n) {
    *this = *this * n;
    return *this;
}

BigInteger operator/(const BigInteger &a, const BigInteger &b) {
    BigInteger aa(a.abs());
    BigInteger bb(b.abs());
    if(aa < bb) {
        return 0;
    }
    char *str = new char[aa.size() + 1];
    memset(str, 0, sizeof(char) * (aa.size() + 1));
    BigInteger tmp;
    int lena = aa.length;
    int lenb = bb.length;
    for(int i = 0; i <= lena - lenb; ++i) {
        tmp = bb.e(lena - lenb - i);
        while(aa >= tmp) {
            ++str[i];
            aa = aa - tmp;
        }
        str[i] += '0';
    }

    BigInteger ans(str);
    delete[]str;
    ans.sign = (ans == 0 || a.sign == b.sign);
    return ans;
}

const BigInteger& BigInteger::operator/=(const BigInteger &n) {
    *this = *this / n;
    return *this;
}

BigInteger operator%(const BigInteger &a, const BigInteger &b) {
    return a - a / b * b;
}

const BigInteger& BigInteger::operator%=(const BigInteger &n) {
    *this = *this - *this / n * n;
    return *this;
}

bool operator<(const BigInteger &a, const BigInteger &b) {
    if(a.sign && !b.sign) {
        return false;
    } else if(!a.sign && b.sign) {
        return true;
    } else if(a.sign && b.sign) {
        if(a.length < b.length) {
            return true;
        } else if(a.length > b.length) {
            return false;
        } else {
            size_t lena = a.num.size();
            for(int i = lena - 1; i >= 0; --i) {
                if(a.num[i] < b.num[i]) {
                    return true;
                } else if(a.num[i] > b.num[i]) {
                    return false;
                }
            }
            return false;
        }
    } else {
        return -b < -a;
    }
}

bool operator<=(const BigInteger &a, const BigInteger &b) {
    return !(b < a);
}

bool operator>(const BigInteger &a, const BigInteger &b) {
    return b < a;
}

bool operator>=(const BigInteger &a, const BigInteger &b) {
    return !(a < b);
}

bool operator==(const BigInteger &a, const BigInteger &b) {
    return !(a < b) && !(b < a);
}

bool operator!=(const BigInteger &a, const BigInteger &b) {
    return (a < b) || (b < a);
}

bool operator||(const BigInteger &a, const BigInteger &b) {
    return a != 0 || b != 0;
}

bool operator&&(const BigInteger &a, const BigInteger &b) {
    return a != 0 && b != 0;
}

bool BigInteger::operator!() {
    return *this == 0;
}

ostream& operator<<(ostream &out, const BigInteger &n) {
    size_t len = n.num.size();
    if(!n.sign) {
        out << '-';
    }
    out << n.num.back();
    for(int i = len - 2; i >= 0; --i) {
        out << setw(BigInteger::WIDTH) << setfill('0') << n.num[i];
    }
    return out;
}

istream& operator>>(istream &in, BigInteger &n) {
    string str;
    in >> str;
    size_t len = str.length();
    size_t i, start = 0;
    if(str[0] == '-') {
        start = 1;
    }
    if(str[start] == '\0') {
        return in;
    }
    for(i = start; i < len; ++i) {
        if(str[i] < '0' || str[i] > '9') {
            return in;
        }
    }
    n = str.c_str();
    return in;
}

test.cpp 测试文件

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "biginteger.h"
using namespace std;

typedef int Type;
const int TESTS = 80000;
const char typefile[] = "type.txt";
const char bigfile[] = "big.txt";
const Type ZeroType = 0;
const BigInteger ZeroBig = 0;

Type type[TESTS + 5];
BigInteger big[TESTS + 5];

void Rand(bool half = false, bool Sqrt = false);
void Output();
void Input();
void Absolute();
void Compare_Calculate();

int main() {
    ios::sync_with_stdio(false);
    srand((unsigned)time(NULL));
    Rand();
    Output();
    Input();
    Absolute();
    Compare_Calculate();
    return 0;
}

void Rand(bool half, bool Sqrt) {
    Type tmp;
    for (int i = 0; i < TESTS; ++i) {
        do {
            tmp = ((Type)rand()) << (rand() % (sizeof(Type) * 4));
            if(rand() % 2 == 1) {
                tmp *= ((Type)rand()) << (rand() % (sizeof(Type) * 4));
            }
            if(half) {
                tmp = abs(tmp / 2) - 1;
            }
            if(Sqrt) {
                if(abs(tmp) < 0) {
                    --tmp;
                }
                tmp = sqrt(abs(tmp)) - 1;
            }
            if(rand() % 2 == 1) {
                tmp = -tmp;
            }
        } while(tmp == 0);
        type[i] = tmp;
        big[i] = tmp;
    }
}

void Output() {
    ofstream fout;
    int cnt;
    clock_t start, stop;
    double time_of_type, time_of_big;

    fout.open(typefile);
    cnt = 0;
    start = clock();
    while(cnt != TESTS) {
        fout << type[cnt++] << endl;
    }
    fout << ZeroType << endl;
    stop = clock();
    fout.close();
    time_of_type = stop - start;

    fout.open(bigfile);
    cnt = 0;
    start = clock();
    while(cnt != TESTS) {
        fout << big[cnt++] << endl;
    }
    fout << ZeroBig << endl;
    stop = clock();
    fout.close();
    time_of_big = stop - start;

    cout << "Output time of type: " << time_of_type << endl
         << "Output time of big: " << time_of_big << endl
         << "time_of_big / time_of_type = " << time_of_big / time_of_type << endl << endl;

    system((string("fc ") + typefile + " " + bigfile).c_str());
}

void Input() {
    ifstream fin;
    Type typetmp;
    BigInteger bigtmp;
    clock_t start, stop;
    double time_of_type, time_of_big;

    fin.open(typefile);
    start = clock();
    while(fin >> typetmp);
    stop = clock();
    fin.close();
    time_of_type = stop - start;

    fin.open(bigfile);
    start = clock();
    while(fin >> bigtmp);
    stop = clock();
    fin.close();
    time_of_big = stop - start;

    cout << "Input time of type: " << time_of_type << endl
         << "Input time of big: " << time_of_big << endl
         << "time_of_big / time_of_type = " << time_of_big / time_of_type << endl << endl;
}

void Absolute() {
    int cnt;
    ofstream fout;
    clock_t start, stop;
    double time_of_type, time_of_big;

    fout.open(typefile);
    cnt = 0;
    start = clock();
    while(cnt != TESTS) {
        if(type[cnt] == LONG_LONG_MIN) {
            fout << "9223372036854775808" << endl;
        } else if(type[cnt] == INT_MIN) {
            fout << "2147483648" << endl;
        } else {
            fout << abs(type[cnt]) << endl;
        }
        ++cnt;
    }
    fout << abs(ZeroType) << endl;
    stop = clock();
    fout.close();
    time_of_type = stop - start;

    fout.open(bigfile);
    cnt = 0;
    start = clock();
    while(cnt != TESTS) {
        fout << big[cnt].abs() << endl;
        ++cnt;
    }
    fout << ZeroBig.abs() << endl;
    stop = clock();
    fout.close();
    time_of_big = stop - start;

    cout << "Abs time of type: " << time_of_type << endl
         << "Abs time of big: " << time_of_big << endl
         << "time_of_big / time_of_type = " << time_of_big / time_of_type << endl << endl;

    system((string("fc ") + typefile + " " + bigfile).c_str());
}

template<typename T>
void cmpcal(T *arr, int command, ofstream &fout) {
    int cnt;
    const T ZERO = 0;
    cnt = 0;
    while(cnt != TESTS) {
        switch(command) {
            case 1: {
                fout << (arr[cnt] == arr[cnt + 1]) << endl
                     << (arr[cnt] != arr[cnt + 1]) << endl
                     << (arr[cnt] < arr[cnt + 1]) << endl
                     << (arr[cnt] <= arr[cnt + 1]) << endl
                     << (arr[cnt] > arr[cnt + 1]) << endl
                     << (arr[cnt] >= arr[cnt + 1]) << endl;
                break;
            }
            case 2: fout << arr[cnt] / arr[cnt + 1] << endl; break;
            case 3: fout << arr[cnt] % arr[cnt + 1] << endl; break;
            case 4: fout << arr[cnt] + arr[cnt + 1] << endl; break;
            case 5: fout << arr[cnt] - arr[cnt + 1] << endl; break;
            case 6: fout << arr[cnt] * arr[cnt + 1] << endl; break;
            default: break;
        }
        cnt += 2;
    }
    switch(command) {
        case 2: fout << ZERO / arr[0] << endl; break;
        case 3: fout << ZERO % arr[0] << endl; break;
        case 4: fout << ZERO + arr[0] << endl << arr[0] + ZERO << endl; break;
        case 5: fout << ZERO - arr[0] << endl << arr[0] - ZERO << endl; break;
        case 6: fout << ZERO * arr[0] << endl << arr[0] * ZERO << endl; break;
        default: break;
    }
}

void Compare_Calculate() {
    ofstream fout;
    clock_t start, stop;
    double time_of_type, time_of_big;
    string command[6] = {"Compare", "Div", "Mod", "Add", "Cut", "Multiply"};

    for(int i = 1; i <= 6; ++i) {
        switch(i) {
            case 4: Rand(true, false); break;
            case 6: Rand(false, true); break;
            default: break;
        }

        fout.open(typefile);
        start = clock();
        cmpcal(type, i, fout);
        stop = clock();
        fout.close();
        time_of_type = stop - start;

        fout.open(bigfile);
        start = clock();
        cmpcal(big, i, fout);
        stop = clock();
        fout.close();
        time_of_big = stop - start;

        cout << command[i - 1] << " time of type: " << time_of_type << endl
             << command[i - 1] << " time of big: " << time_of_big << endl
             << "time_of_big / time_of_type = " << time_of_big / time_of_type << endl << endl;

        system((string("fc ") + typefile + " " + bigfile).c_str());
    }
}

你可能感兴趣的:(可复用代码)