本篇博客记录大整数运算相关问题。
包括:
1. 大整数的存储
2. 大整数的四则运算
1 大整数的存储
大整数又叫高精度数,一般指其范围已经超出了基本数据类型能够表示的范围的数。
很容易想到,对于高进度数我们需要用数组来存储。有以下几点注意事项:
1. 顺位存储
如123,我们这么保存:num[0] = 3, num[1] = 2, num[2] = 1,即整数的高位保存在数组的高位,整数的低位保存在数组的低位。这么保存方便我们从低位到高位进行整数的运算。
2. 用一个变量保存大整数的长度
我们一般将长度变量和数组num组合成结构体
3. 结构体的初始化
这里可以使用到构造函数,在结构体变量创建时对其进行初始化
得到的结构体如下:
struct bign{ //big number
int num[100];
int len;
bign(){
len = 0;
memset(num, 0, sizeof(num));
}
};
2 大整数的四则运算
下面主要记录了四种四则运算:
1. 高精度加法
2. 高精度减法
3. 高精度与低精度乘法
4. 高精度与低精度除法
要明确:大整数的四则运算其实就是模拟手动运算的过程,也就是我们小学学过的列竖式计算。如果读者对下面的代码有疑问,不妨举例进行手动计算,以此总结出每一位的计算规律,即可容易理解以下代码。
2.1 高精度加法
bign add(bign a, bign b){ //大整数加法
bign res;
int carry = 0; //进位
for(int i = 0; i<a.len || i<b.len; i++){ //以位数多的数为基准
carry = a.num[i]+b.num[i]+carry;
res.num[i] = carry%10;
carry /= 10;
res.len++;
}
res.num[res.len++] = carry;
//去除前导0
while(res.len-1 >= 1 && res.num[res.len-1] == 0){ //将res.len-1想成数组下标会便于理解
res.len--;
}
return res;
}
要记得去除前导零。
在这里你会发现,顺位保存大整数在去除前导零这一点上也会给我们带来便利,如果体会不深刻,可以想一想如果是逆位保存,那么去除前导零应该怎么写?看后面的几个运算的实现之后你会惊喜的发现,所有运算的去除前导零的实现都是一样的。
2.2 高精度减法
bign sub(bign a, bign b){ //a-b(保证a>b)
bign res;
for(int i = 0; i < a.len; i++){
if(a.num[i] < b.num[i]){ //不够减
a.num[i+1] -= 1; //借位
a.num[i] += 10;
}
res.num[i] = a.num[i]-b.num[i];
res.len++;
}
//去除前导零
while(res.len-1 >= 1 && res.num[res.len-1]==0){
res.len--;
}
return res;
}
如上述实现方式,需要保证a>=b。即我们在进行减法运算之前,应先判断减数和被减数的大小,自己判断出结果的符号,再进行大的数减小的数的运算。
2.3 高精度与低精度乘法
bign res;
int carry = 0;
for(int i = 0; i < a.len; i++){
int temp = a.num[i] * x;
res.num[i] = temp % 10 + carry;
carry = temp / 10;
res.len++;
}
while(carry != 0){ //乘法的进位可能不止一位
res.num[res.len++] = carry % 10;
carry /= 10;
}
//去除前导零
while(res.num[res.len-1] == 0 && res.len-1 >= 1) {
res.len--;
}
return res;
}
这里我们需要注意的是:乘法的进位可能不只一位。
2.4 高精度与低精度除法
//高精度和低精度除法
bign divide(bign a , int b, int &r){
bign res;
res.len = a.len; //被除数的每一位和上的每一位是一一对应的,因此先令长度相等
for(int i = a.len-1; i >= 0; i--){
r = r*10+a.num[i];
if(r >= b){ //够除
res.num[i] = (r/b);
r %= b;
}else{ //不够除
res.num[i] = 0;
}
}
//去除前导0
while(res.num[res.len-1] == 0 && res.len-1 >= 1){
res.len--;
}
return res;
}
由于很多题目一般都会需要得到余数,我们通过应引用的形式(&r)将其带出。
3 练习题
以下是PAT中的几道练习题题解,读者可以先自行练习。
PAT-A 1023. Have Fun with Numbers (20)
PAT-A 1024. Palindromic Number (25)
PAT-B 1017. A除以B (20)