大整数运算

本篇博客记录大整数运算相关问题。
包括:
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//以位数多的数为基准 
        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)

你可能感兴趣的:(《算法笔记》学习笔记)