当整数很大,在计算机可以表示的范围内无法通过常规的加减等运算计算时,这里介绍的大数运算是一种有效的计算方法。
这里介绍一种方式:将大数表示为一个n进制的数组(分别将大数表示成十进制和N进制),介绍大数的加减乘三种运算。这里仅考虑了非负整数
一、将大数表示为10进制
使用C++
string AddLongInteger(string addend, string augend)
{
if(addend.size() < augend.size())
return AddLongInteger(augend,addend);
int i,j,temp,flag = 0;
for(i = addend.size() - 1,j = augend.size() - 1; i >= 0;i--,j--)
{
if(j >= 0)
temp = addend[i] - '0' + augend[j] - '0' + flag ;
else
temp = addend[i] - '0' + flag;
if(temp > 9)
{
flag = 1;
temp %= 10;
}
else flag = 0;
addend[i] = temp + '0';
}
if(flag)
addend = "1" + addend;
return addend;
}
int main()
{
string str1,str2;
cin >> str1 >> str2;
cout << AddLongInteger(str1,str2) << endl;
return 0;
}
单独的实现函数
大数加法
const int maxn = 1001;
void BigdataAdd() {
char data1_str[maxn], data2_str[maxn];
int data1[maxn] = {0}, data2[maxn] = {0}, data_sum[maxn] = {0}; //这里初始化为0很重要,之后计算依赖于初始值
int len_data1, len_data2, i;
scanf("%s", data1_str); //由控制台读入第一个char数组形式的大数
len_data1 = strlen(data1_str);
for (i = 0; i < len_data1; ++i) //将这个大数存入到int数组中,注意将char数组高位存入int数组地位,方便计算时对齐
data1[i] = data1_str[len_data1 - i - 1] - '0';
scanf("%s", data2_str);
len_data2 = strlen(data2_str);
for (i = 0; i < len_data2; i++)
data2[i] = data2_str[len_data2 - i - 1] - '0';
int max_len = len_data1 > len_data2 ? len_data1 : len_data2; //计算两个数中较大的长度值
int flag = 0; // flag:需要进位的值
for (i = 0; i < max_len; ++i) { //加法运算
data_sum[i] = (data1[i] + data2[i] + flag) % 10; //本位的数值
flag = (data1[i] + data2[i] + flag) / 10; //需要进位的数值
}
printf("Sum: ");
if (flag != 0) { //考虑最高位是否进位
data_sum[max_len] = 1;
printf("%d", data_sum[max_len]); //输出计算结果最高位
}
for (i = max_len - 1; i >= 0; --i) //输出计算结果其他位
printf("%d", data_sum[i]);
printf("\n");
}
int main() {
BigdataAdd();
return 0;
}
输出结果(一):
1
2
Sum: 3
请按任意键继续. . .
输出结果(二):
大数减法:
void BigdataSubtraction() {
char data1_str[maxn], data2_str[maxn];
int data1[maxn] = {0}, data2[maxn] = {0}, data_sub[maxn] = {0}; //这里初始化为0很重要,之后计算依赖于初始值
int len_data1, len_data2;
scanf("%s", data1_str);
scanf("%s", data2_str);
len_data1 = strlen(data1_str);
len_data2 = strlen(data2_str);
int bigdata;
if (len_data1 > len_data2) //判断哪个数大,将该数作为被减数
bigdata = 1;
else if (len_data1 < len_data2)
bigdata = -1;
else
bigdata = strcmp(data1_str, data2_str);
int i;
if (bigdata >= 0) {
for (i = 0; i < len_data1; ++i)
data1[i] = data1_str[len_data1 - i - 1] - '0';
for (i = 0; i < len_data2; i++)
data2[i] = data2_str[len_data2 - i - 1] - '0';
}
else {
for (i = 0; i < len_data2; ++i)
data1[i] = data2_str[len_data2 - i - 1] - '0';
for (i = 0; i < len_data1; i++)
data2[i] = data1_str[len_data1 - i - 1] - '0';
}
int flag = 0; //flag表示借位
int max_len = len_data1 >= len_data2 ? len_data1 : len_data2;
for (i = 0; i < max_len; ++i) {
int this_sub = data1[i] - flag;
data_sub[i] = this_sub - data2[i];
if (data_sub[i] >= 0) {
flag = 0;
}
else {
flag = 1;
data_sub[i] += 10;
}
}
printf("Subtraction: ");
if (bigdata < 0) //如果输入的第一个数小,则为结果添加负号
printf("-");
while (max_len > 1 && !data_sub[max_len - 1])
max_len--;
for (i = max_len - 1; i >= 0; --i)
printf("%d", data_sub[i]);
printf("\n");
}
输出结果(一):
1245
Subtraction: -33
请按任意键继续. . .
输出结果(二):
大数乘法:
这里的乘法操作是比较完善的,考虑了数据输入非法、乘数为负数、乘数为0时的输出形式等情况。
string Mutiplication(const string data1, const string data2) {
if (data1 == "" || data2 == "") //非法输入
return "";
string result;
int length_data1 = data1.size();
int length_data2 = data2.size();
vector<int> result_number(length_data1 + length_data2 - 1, 0);
//处理有负数的情况,data1为负数则data1_end等于1,data2为负数则data2_end等于1
int data1_end = 0, data2_end = 0;
if (data1[0] - '-' == 0 && data2[0] - '-' == 0) {
data1_end = 1;
data2_end = 1;
}
else if (data1[0] - '-' == 0)
data1_end = 1;
else if (data2[0] - '-' == 0)
data2_end = 1;
else {}
for (int i = length_data2 - 1; i >= data2_end; --i) {
for (int j = length_data1 - 1; j >= data1_end; --j) {
if (!isdigit(data1[j]) || !isdigit(data2[i])) {
cerr << "invalid number";
return "";
}
//result_number记录乘法过程中每一位
result_number[i + j] += (data2[i] - '0') * (data1[j] - '0');
}
}
//处理进位并将结果存到字符串result
int carry = 0;
for (int i = result_number.size() - 1; i >= 0; --i) {
result_number[i] += carry;
carry = result_number[i] / 10;
result = string(1, result_number[i] % 10 + '0') + result;
}
if (carry > 0) //最高位的进位
result = string(1, carry + '0') + result;
//下面几行处理有乘数为0的情况,如果不处理,会出现:
//1234 * 0 = 0000的情况
string::iterator iter = result.begin();
//如果乘法结果的前n - 1位为0,则将其删除,只保留最后一位
while (*iter - '0' == 0 && iter < result.end() - 1) {
iter = result.erase(iter);
}
//如果结果为负数则在结果字符串中添加负号
if (data1_end ^ data2_end)
result = "-" + result;
return result;
}
int main() {
string a;
string b;
while (cin >> a >> b)
cout << "result: " << Mutiplication(a, b) << endl;
}
以上C语言的实现方式只是做了几个单独的测试,各个函数间代码的重复率很高,没有整合,这里仅是给出了大整数运算的实现方法。本文第三部分给出了这部分代码的C++类实现方式。
二、将大数表示为N进制数组
N的取值越大,数组大小越小,这样可以缩短运算时间以及空间复杂度,提高运算效率。在32位系统中,N可以取2的32次方,此时一位的大小为0~0xffffffff.
当进行加法和乘法运算会进位,则可能要判断溢出,因此,选用long long型(64位)。这里的运算思想和第一部分十进制的运算思想是一致的。
1. 加法运算:
运用”竖式计算“的思想,首先将两个操作数的低位对齐,如果本位所加的结果大于0xffffffff - 1才做进位(flag)处理,否则不进位。
计算0x12 0x2 + 0xffffffff 0xfffffff:
(1)个位:0x2 + 0xffffffff 大于0xfffffff,所以进位,本位结果为1,进位标志flag = 1;
(2)十位:0x12 + 0xffffffff + flag大于0xfffffff,所以进位,本位结果为12,flag = 1;
(3)计算第三位,两个加数均为0,进位为1,所以本位结果为1;
最终计算结果为1 12 1。
2.减法运算:
计算0x1 0x1 0x1 - 0xffffff:
(1)0x1 - 0xfffffff 小于0, 需要借位,本位为2;
(2)十位被个位借了1,因此本位结果为0;
(3)百位结果为1;
最终结果为102。
3. 乘法运算:
计算0x1 0x1 0x1 * 0xffffff 0xfffffff:
(1)个位:0x1 0x1 0x1 * 0xffffffff = 0xffffffff0xffffffff0xffffffff;
(2)十位:0x1 0x1 0x1 * 0xffffffff =0xffffffff0xffffffff0xffffffff,因为这是十位,所以结果为0xffffff0xffffff 0xffffff 0x0;
最终结果:0xffffffff0xffffffff0xffffffff 0x0 + 0xffffffff0xffffffff0xffffffff = 1 0 0xffffffff 0xfffffffe0xffffffff。
三、第一部分的C++实现:
const int maxn = 1001;
class BigData {
int len;
int data[maxn];
BigData Sub(const BigData& a, const BigData& b) {
int i;
BigData result;
int flag = 0;
for (i = 0; i < a.len; ++i) {
int this_sub = a.data[i] - flag;
result.data[i] = this_sub - b.data[i];
if (result.data[i] >= 0)
flag = 0;
else {
flag = 1;
result.data[i] += 10;
}
result.len = a.len;
}
result.clean();
return result;
}
void clean() {
while (len > 1 && !data[len - 1])
len--;
}
string str() const {
string res = "";
int i;
for (i = 0; i < len; i++)
res = (char)(data[i] + '0') + res;
if (res.empty())
res = "0";
return res;
}
public:
BigData() {
memset(data, 0, sizeof(data));
len = 1;
}
BigData(int num) {
*this = num;
}
BigData(const char* num) {
*this = num;
}
BigData& operator=(int num) {
char data[maxn];
sprintf(data, "%d", num);
*this = data;
return *this;
}
BigData& operator=(const char *num) {
len = strlen(num);
int i;
for (i = 0; i < len; ++i)
data[i] = num[len - i - 1] - '0';
return *this;
}
BigData operator+(const BigData& b) const {
BigData c;
c.len = 0;
int i, flag = 0;
int max_len = len > b.len ? len : b.len;
for (i = 0; i < max_len; ++i) {
int sum = (flag + data[i] + b.data[i]);
c.data[c.len++] = sum % 10;
flag = sum / 10;
}
if (flag != 0)
c.data[c.len++] = 1;
c.clean();
return c;
}
BigData& operator+=(const BigData& b) {
*this = *this + b;
return *this;
}
BigData& operator-=(const BigData& b) {
*this = *this - b;
return *this;
}
bool operator<(const BigData& b) const {
if (len != b.len)
return len < b.len;
int i;
for (i = len - 1; i >= 0; --i) {
if (data[i] != b.data[i])
return data[i] < b.data[i];
}
return false;
}
bool operator>(const BigData& b) const {
return b < *this;
}
bool operator<=(const BigData& b) const {
return !(*this > b);
}
bool operator>=(const BigData& b) const {
return !(*this < b);
}
bool operator==(const BigData& b) const {
return !(*this > b) && !(*this < b);
}
BigData operator-(const BigData& b) {
BigData c;
c.len = 0;
if (*this == b) {
c.data[++c.len] = 0;
return c;
}
else if (*this > b) {
c = Sub(*this, b);
}
else {
c = Sub(b, *this);
c.data[c.len++] = '-' - '0';
}
return c;
}
BigData operator*(const BigData& b) {
int i, j, flag;
BigData result;
for (i = 0; i < len; ++i) {
for (j = 0; j < b.len; ++j) {
result.data[i + j] = data[i] * b.data[j];
}
}
result.len = len + b.len;
for (i = 0; i <result.len; ++i) {
result.data[i + 1] += result.data[i] / 10;
result.data[i] %= 10;
}
result.clean();
return result;
}
friend ostream& operator<<(ostream& out, const BigData& bd) {
out << bd.str();
return out;
}
friend istream& operator>>(istream& in, BigData& bd) {
string s;
in >> s;
bd = s.c_str();
return in;
}
};
int main() {
BigData a, b;
cin >> a >> b;
cout << "a: " << a << endl;
cout << "b: " << b << endl;
cout << "a+b: " << a + b<< endl;
cout << "a-b: " << a - b << endl;
cout << "a*b: " << a * b << endl;
a += b;
cout << "a += b: " << a << endl;
a -= b;
cout << "a -= b: " << a << endl;
return 0;
}
输出结果: