您的位置:首页 > 编程语言 > C语言/C++

C++ 实现BigInteger 类

2017-07-01 22:32 483 查看

说明

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

已重载的运算符

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

函数声明函数功能
size_t size() const返回 BigInteger 对象的位数
BigInteger e(size_t n) const返回 BigInteger 对象 ×10n 后的值
BigInteger abs() const返回 BigInteger 对象的绝对值
  更多函数请使用者在已有代码基础上自行编写。

计算耗时比(tBigIntegertint/longlong)

运算符intlong long
ostream& operator<<(ostream&, const T&)1.0871.097
istream& operator>>(istream&, T&)1.3551.211
abs()1.4071.273
比较运算符1.4901.506
T operator+(const T&, const T&)3.1803.063
T operator-(const T&, const T&)3.1403.014
T operator*(const T&, const T&)1.9382.121
T operator/(const T&, const T&)8.69819.616
T operator%(const T&, const T&)11.03820.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 <vector>
#include <iostream>
#include <cstring>
#include <iomanip>
#include <string>
#include <algorithm>
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
= 1;
while(tmp--) {
ans.num
*= 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 <iostream>
#include <fstream>
#include <ctime>
#include <cstdlib>
#include <cmath>
#include <windows.h>
#include <climits>
#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());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息