概要
在计算机科学和工程中,整数类型有一个上限,称为其最大值或最大表示值,这限制了数字的大小范围。在一些应用中,需要处理比这个上限更大的整数,这时就需要使用大整数类。
大整数类允许处理比计算机所提供的整数类型更大的整数,通常是以字符串形式存储,可以进行算术运算、比较和转换等操作。这在密码学、数值计算、物理仿真、金融等领域中非常有用。
比如在密码学中,RSA加密算法就需要对非常大的整数进行加密和解密。在数值计算中,需要进行高精度计算,避免舍入误差,保证计算结果的准确性。在物理仿真中,需要模拟非常大或非常小的量。在金融领域中,需要处理非常大的金额或精确的计算结果。
因此,大整数类是一个非常有用的工具,可以扩展计算机的数字处理能力,解决很多实际问题。
然而,C++并没有自己的大整数类,因此便想要自己实现一个头文件,方便一般高精度计算的使用。
备注
这里实现的大整数类只有逻辑运算和+-*/基本操作,以及重载输入输出,并且无法输入负数,只有在实现减法时,可以输出负数。因此有一定的局限性,有时间的话我会将取模,幂运算,自增,自减等加上去的!
具体实现
1.定义大整型类
用数组模拟大数,读入使用字符串,并且倒序放置
即 123456-->654321 进行存放,1记为第一位
typedef class BigInt {
private:
int num[MAXN];
int len;
bool sign;
public:
static int max_Big(int x, int y) {
return x > y ? x : y;
}
BigInt(int x) { //初始化使得大整型能够表示整型
memset(num, 0, sizeof(num));
for (len = 1; x; len++) {
num[len] = x % 10;
x /= 10;
}
sign = 1;
len--;//由于上述循环中len多加了一次,因此这里减去
}
BigInt() {
memset(num, 0, sizeof(num));
len = 0;
sign = 1;
}
BigInt(std::string s) {
len = s.length();
int cnt = len - 1;
for (int i = 1; i <= len; i++) {
num[i] = s[cnt--] - '0';
}
sign = 1;
}
BigInt(char *s) {
len = strlen(s);
int cnt = 1;
for (int i = len - 1; i >= 0; i--) num[cnt++] = s[i] - '0';
}
void flatten(int L) { //进行展平操作
len = L;
for (int i = 1; i <= len; i++) {
num[i + 1] += num[i] / 10;
num[i] %= 10;
}
while (!num[len]) { //删除多余位数
len--;
}
}
friend std::ostream& operator<<(std::ostream&iout, BigInt&I1);
friend std::istream& operator>>(std::istream&iint, BigInt&I1);
BigInt& operator = (const BigInt &I) { //重载赋值运算符
len = I.len;
sign=I.sign;
memset(num, 0, sizeof(num));
for (int i = 1; i <=len; i++)
num[i] = I.num[i];
return *this;
}
friend BigInt operator+(BigInt&I1, BigInt&I2);
friend BigInt operator-(BigInt&I1, BigInt&I2);
friend BigInt operator*(BigInt&I1, BigInt&I2);
friend BigInt operator/(BigInt I1, BigInt&I2);//大整型除以大整型-减法模拟除法
friend BigInt operator/(BigInt&I1, int I2);//大整型除以整型-逐位试商法
friend bool operator<(const BigInt&I1, const BigInt&I2);
friend bool operator>(const BigInt&I1, const BigInt&I2);
friend bool operator!=(const BigInt&I1, const BigInt&I2);
friend bool operator==(const BigInt&I1, const BigInt&I2);
friend bool operator<=(const BigInt&I1, const BigInt&I2);
friend bool operator>=(const BigInt&I1, const BigInt&I2);
} BigInt;
2.算数运算符重载
Ⅰ.加法重载
将每一位的数加起来,最后一次性铺平即可
BigInt operator+(BigInt&I1, BigInt&I2) {
int L = BigInt::max_Big(I1.len, I2.len) + 1;
BigInt I3;
for (int i = 1; i <= L; i++) {
I3.num[i] = I1.num[i] + I2.num[i];
}
I3.flatten(L);
return I3;
}
以下是铺平操作的代码
void flatten(int L) { //进行展平操作
len = L;
for (int i = 1; i <= len; i++) {
num[i + 1] += num[i] / 10;
num[i] %= 10;
}
while (!num[len]) { //删除多余位数
len--;
}
}
Ⅱ.减法重载
如果减数大于被减数,则倒置,即让减数减去被减数,最后在结果前加一个符号即可。
利用我们小学学习的知识:减法的竖式计算,向前一位借一位进行计算。
BigInt operator-(BigInt&I1, BigInt&I2) {
int L = BigInt::max_Big(I1.len, I2.len);
BigInt i1, i2, I3;
if (I1 < I2) {
i1 = I2;
i2 = I1;
I3.sign = 0;
} else {
i1 = I1;
i2 = I2;
I3.sign = 1;
}
for (int i = 1; i <= L; i++) {
if (i1.num[i] < i2.num[i]) {
i1.num[i + 1]--;
i1.num[i] += 10;
}
I3.num[i] = i1.num[i] - i2.num[i];
}
while (I3.num[L] == 0 && L > 1) L--;
I3.len = L;
return I3;
}
Ⅲ.乘法重载
第一个数的第i位×第二个数的第j位的贡献在结果的第i+j-1的位置上。
完成后,将结果数铺平即可。
BigInt operator*(BigInt&I1, BigInt&I2) {
BigInt I3;
int len1 = I1.len, len2 = I2.len;
int L = len1 + len2;
for (int i = 1; i <= len1; i++)
for (int j = 1; j <= len2; j++) {
I3.num[i + j - 1] += I1.num[i] * I2.num[j];
}
I3.flatten(L);
return I3;
}
Ⅳ.除法重载
①大数/小数
使用逐位试商法进行计算,类似于除法的竖式计算
BigInt operator/(BigInt&I1, int I2) {
BigInt I3;
int x = 0;
int len = I1.len;
for (int i = len; i >= 1; i--) {
I3.num[i] = (x * 10 + I1.num[i]) / I2;
x = ((x * 10 + I1.num[i])) % I2;
}
I3.flatten(len);
return I3;
}
②大数/大数
使用减法模拟除法
BigInt operator/(BigInt I1, BigInt&I2) {
BigInt I3;
int len1 = I1.len, len2 = I2.len;
int start = len1 - len2 + 1;
for (int i = start; i >= 1; i--) {
BigInt tmp1, tmp2(10);
tmp1 = I2;
while (tmp1.len < i) {
tmp1 = tmp1 * tmp2;
}
while (I1 >= tmp1) {
I3.num[i]++;
I1 = I1 - tmp1;
}
}
I3.flatten(start);
return I3;
}
3.赋值运算符,输入输出运算符重载
Ⅰ.赋值运算符重载
BigInt& operator = (const BigInt &I) { //重载赋值运算符
len = I.len;
sign=I.sign;
memset(num, 0, sizeof(num));
for (int i = 1; i <=len; i++)
num[i] = I.num[i];
return *this;
}
要注意的是,该赋值运算符在类内定义
Ⅱ.输入输出运算符重载
std::istream& operator>>(std::istream&iint, BigInt&I1) { //重载输入
std::string s;
iint >> s;
I1.len = s.length();
int cnt = I1.len - 1;
for (int i = 1; i <= I1.len; i++) {
I1.num[i] = s[cnt--] - '0';
}
return iint;
}
std::ostream& operator<<(std::ostream&iout, BigInt &I1) { //重载输出
if (!I1.sign) std::cout<< '-';
for (int i = BigInt::max_Big(I1.len, 1); i >= 1; i--) {
iout << I1.num[i];
}
return iout;
}
4.逻辑运算符重载
bool operator<(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 < len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] < I2.num[i];
}
return false;
}
bool operator<=(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 < len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] < I2.num[i];
}
return true;
}
bool operator>(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 > len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] > I2.num[i];
}
return false;
}
bool operator>=(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 > len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] > I2.num[i];
}
return true;
}
bool operator==(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return false;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return false;
}
return true;
}
bool operator!=(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return true;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return true;
}
return false;
}
完整代码
#ifndef BIGINT_H
#define BIGINT_H
#define MAXN 100000
#include <string.h>
#include <iostream>
#include <string>
typedef class BigInt {
private:
int num[MAXN];
int len;
bool sign;
public:
static int max_Big(int x, int y) {
return x > y ? x : y;
}
BigInt(int x) { //初始化使得大整型能够表示整型
memset(num, 0, sizeof(num));
for (len = 1; x; len++) {
num[len] = x % 10;
x /= 10;
}
sign = 1;
len--;//由于上述循环中len多加了一次,因此这里减去
}
BigInt() {
memset(num, 0, sizeof(num));
len = 0;
sign = 1;
}
BigInt(std::string s) {
len = s.length();
int cnt = len - 1;
for (int i = 1; i <= len; i++) {
num[i] = s[cnt--] - '0';
}
sign = 1;
}
BigInt(char *s) {
len = strlen(s);
int cnt = 1;
for (int i = len - 1; i >= 0; i--) num[cnt++] = s[i] - '0';
}
void flatten(int L) { //进行展平操作
len = L;
for (int i = 1; i <= len; i++) {
num[i + 1] += num[i] / 10;
num[i] %= 10;
}
while (!num[len]) { //删除多余位数
len--;
}
}
friend std::ostream& operator<<(std::ostream&iout, BigInt&I1);
friend std::istream& operator>>(std::istream&iint, BigInt&I1);
BigInt& operator = (const BigInt &I) { //重载赋值运算符
len = I.len;
sign=I.sign;
memset(num, 0, sizeof(num));
for (int i = 1; i <=len; i++)
num[i] = I.num[i];
return *this;
}
friend BigInt operator+(BigInt&I1, BigInt&I2);
friend BigInt operator-(BigInt&I1, BigInt&I2);
friend BigInt operator*(BigInt&I1, BigInt&I2);
friend BigInt operator/(BigInt I1, BigInt&I2);//大整型除以大整型-减法模拟除法
friend BigInt operator/(BigInt&I1, int I2);//大整型除以整型-逐位试商法
friend bool operator<(const BigInt&I1, const BigInt&I2);
friend bool operator>(const BigInt&I1, const BigInt&I2);
friend bool operator!=(const BigInt&I1, const BigInt&I2);
friend bool operator==(const BigInt&I1, const BigInt&I2);
friend bool operator<=(const BigInt&I1, const BigInt&I2);
friend bool operator>=(const BigInt&I1, const BigInt&I2);
} BigInt;
bool operator<(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 < len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] < I2.num[i];
}
return false;
}
bool operator<=(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 < len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] < I2.num[i];
}
return true;
}
bool operator>(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 > len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] > I2.num[i];
}
return false;
}
bool operator>=(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return len1 > len2;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return I1.num[i] > I2.num[i];
}
return true;
}
bool operator==(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return false;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return false;
}
return true;
}
bool operator!=(const BigInt&I1, const BigInt&I2) {
int len1 = I1.len, len2 = I2.len;
if (len1 != len2) {
return true;
}
for (int i = len1; i >= 1; i--) {
if (I1.num[i] != I2.num[i]) return true;
}
return false;
}
BigInt operator+(BigInt&I1, BigInt&I2) {
int L = BigInt::max_Big(I1.len, I2.len) + 1;
BigInt I3;
for (int i = 1; i <= L; i++) {
I3.num[i] = I1.num[i] + I2.num[i];
}
I3.flatten(L);
return I3;
}
BigInt operator-(BigInt&I1, BigInt&I2) {
int L = BigInt::max_Big(I1.len, I2.len);
BigInt i1, i2, I3;
if (I1 < I2) {
i1 = I2;
i2 = I1;
I3.sign = 0;
} else {
i1 = I1;
i2 = I2;
I3.sign = 1;
}
for (int i = 1; i <= L; i++) {
if (i1.num[i] < i2.num[i]) {
i1.num[i + 1]--;
i1.num[i] += 10;
}
I3.num[i] = i1.num[i] - i2.num[i];
}
while (I3.num[L] == 0 && L > 1) L--;
I3.len = L;
return I3;
}
BigInt operator*(BigInt&I1, BigInt&I2) {
BigInt I3;
int len1 = I1.len, len2 = I2.len;
int L = len1 + len2;
for (int i = 1; i <= len1; i++)
for (int j = 1; j <= len2; j++) {
I3.num[i + j - 1] += I1.num[i] * I2.num[j];
}
I3.flatten(L);
return I3;
}
BigInt operator/(BigInt&I1, int I2) {
BigInt I3;
int x = 0;
int len = I1.len;
for (int i = len; i >= 1; i--) {
I3.num[i] = (x * 10 + I1.num[i]) / I2;
x = ((x * 10 + I1.num[i])) % I2;
}
I3.flatten(len);
return I3;
}
BigInt operator/(BigInt I1, BigInt&I2) {
BigInt I3;
int len1 = I1.len, len2 = I2.len;
int start = len1 - len2 + 1;
for (int i = start; i >= 1; i--) {
BigInt tmp1, tmp2(10);
tmp1 = I2;
while (tmp1.len < i) {
tmp1 = tmp1 * tmp2;
}
while (I1 >= tmp1) {
I3.num[i]++;
I1 = I1 - tmp1;
}
}
I3.flatten(start);
return I3;
}
std::istream& operator>>(std::istream&iint, BigInt&I1) { //重载输入
std::string s;
iint >> s;
I1.len = s.length();
int cnt = I1.len - 1;
for (int i = 1; i <= I1.len; i++) {
I1.num[i] = s[cnt--] - '0';
}
return iint;
}
std::ostream& operator<<(std::ostream&iout, BigInt &I1) { //重载输出
if (!I1.sign) std::cout<< '-';
for (int i = BigInt::max_Big(I1.len, 1); i >= 1; i--) {
iout << I1.num[i];
}
return iout;
}
#endif
实际演示
将代码包裹成头文件,放在项目文件夹中,即可调用大数型了。
#include "BIGINT.h"
using namespace std;
int main(){
BigInt I1,I2;
BigInt I3;
cin>>I1>>I2;
I3=I1+I2;
cout<<"I1+I2="<<I3<<endl;
I3=I1-I2;
cout<<"I1-I2="<<I3<<endl;
I3=I1*I2;
cout<<"I1*I2="<<I3<<endl;
I3=I1/I2;
cout<<"I1/I2="<<I3<<endl;
return 0;
}