基础算法-高精度的加、减、乘、除运算-C++实现

高精度的加、减、乘、除运算-C++实现

算法基本思想及步骤
1.用可变数组储存大整数,从低位到高位依次存储
2.模拟人工加、减、乘、除法运算过程

AcWing题库-791-高精度加法

题目
给定两个正整数,计算它们的和。

输入格式
共两行,每行包含一个整数。

输出格式
共一行,包含所求的和。

数据范围
1≤整数长度≤1000000

输入样例
12
23

输出样例
35

思路解析:
高精度的运算,都采取先用字符串存储再转存入vector可变数组中,这里注意需要倒着存,因为我们手工运算加法的时候一般从低位到高位开始算,而数字存储一般先存高位再存低位,所以我们这里倒着先存低位再存高位,以便运算的时候需要向上进位。当要运算的数字分别存入 A 和 B 中后,就可以依次开始运算了,想象我们手工算加法的时候,从低位开始,将 A 和 B 的每一位数字对齐,依次相加,多的就向前进位,转移到代码上就是循环遍历 A 和 B 的每一位,这里就需要引入一个中间值 t ,因为我们需要判断每次相加后的值需不需要进位,且需要将得到的结果一位一位地存入结果数组 C 中,所以先把 A[i] 加上 B[i] 的值存入 t 中,因为不知道需不需要进位,所以可直接将 t % 10 的值加入 C 中,不管进不进位,t % 10得到的都一定是结果数组中这一位的值,然后再将 t / 10 ,如果 t < 10 ,这里得到的 t 就是 0 ,也就是说没有进位,如果 t > 10 ,得到的 t 就是 1 ,也就是说进位是1,在下一次循环运算的时候直接将 t 的值加进 A[i] 和 B[i] 的和里就行了。以此类推,在最后退出循环后再判断一次 t 的值确定是否最高位需要进位就得到了结果数组 C ,输出的时候再倒着输出就可以了。

代码

#include <iostream>
#include <vector>

using namespace std;
//C = A + B, 满足A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
    vector<int> C;

    if (A.size() < B.size()) return add(B, A);  //确保A的长度大于B,便于计算

    int t = 0;
    for (int i = 0; i < A.size(); i++)
    {
        t += A[i];  //将上一次计算的进位数t也加进去
        if (i < B.size()) t += B[i];  //如果B已经加完了就只用加A的数
        C.push_back(t % 10);  //如果逐位相加的和大于10,将个位输入给C
        t /= 10;  //逐位相加的和的十位进位给下一位
    }

    if (t) C.push_back(1); //若最后得到的t不为0,则向最高位前进位
    return C;
}

int main()
{
    string a, b;
    vector<int> A, B;

    cin >> a >> b;
    
    for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');  
    for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');//利用数字字符减去'0'得到数字储存在数组中

    vector<int> C = add(A, B);

    for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
    cout << endl;
    
    return 0;
}

AcWing题库-792-高精度减法

题目
给定两个正整数,计算它们的差。

输入格式
共两行,每行包含一个整数。

输出格式
共一行,包含所求的差。

数据范围
1≤整数长度≤10^6

输入样例
32
11

输出样例
21

思路解析:
高精度减法与高精度加法的存储方式一样,也是倒着存,但需要注意模板的代码只能用大数减小数,所以需要对被减数和减数的大小进行一个判断,如果被减数小于减数就让其对调,给结果加一个负号。减法的中间值t 需要完成的工作是存储每一位依次相减时向前借的位,也就是在计算 A[i] - B[i] 前先让 A[i] 减去 t ,减完之后由于不知道 t 是不是正数,可直接把 (t + 10) % 10 存入 C 中,直接提前借位,不管 t 是大于 0 还是小于 0 都能把结果数组中这一位的正确数字存进去,之后再进行判断,如果 t < 0 ,也就是需要向前借位,就令 t = 1 ,等到下一位运算的时候就能直接把借的位减掉,如果 t > 0 ,也就是不需要向前借位,就令 t = 0 ,对下一位运算无影响。由于运算的时候并没有判断如果最高位出现 0 该怎么办,所以在循环结束后需要加一个判断以消去最高位的 0 。最后,输出的时候仍然是倒着输出。

代码

#include <iostream>
#include <vector>

using namespace std;
//比较A、B大小
bool cmp(vector<int> &A, vector<int> &B)
{
    if (A.size() != B.size()) return A.size() > B.size();  
    //若A、B长度不相同,则设置比较条件为A和B的长度
    for (int i = A.size() - 1; i >= 0; i--)
    {    
    	if (A[i] != B[i])
            return A[i] > B[i];  
            //若A、B长度相同但A不等于B,则设置比较条件为从最高位开始A和B不相同的那一位
    }
    return true;  //若A、B相等,则不管谁减谁都一样
}
//C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {
        t = A[i] - t;  //先减去上一次运算借的位
        if (i < B.size()) t -= B[i];  //如果B被减完了就只需要保留A这一位的数
        C.push_back((t + 10) % 10);  //若中间值为负,则将借位后的差存入C,若中间值为正,直接将其存入C
        if (t < 0) t = 1;  //若t为负,则借位为1
        else t = 0;  //若t为正,则不需要借位
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();  //消去C中最高位可能出现的0
    return C;
}

int main()
{
    string a, b;
    vector<int> A, B;

    cin >> a >> b;
    for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');
    for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');

    if (cmp(A, B))  //保证一定是大数减小数
    {
        vector<int> C = sub(A, B);
        for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
        cout << endl;
    }
    else
    {
        vector<int> C = sub(B, A);
        cout << "-";  //若A小于B,求B-A的值,在结果前添加负号
        for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
        cout << endl;
    }

    return 0;
}

AcWing题库-793-高精度乘法

题目
给定两个正整数A和B,请你计算A*B的值。

输入格式
共两行,第一行包含整数A,第二行包含整数B。

输出格式
共一行,包含A*B的值。

数据范围
1≤A的长度≤1000000
1≤B≤10000

输入样例
2
3

输出样例
6

思路解析:
注意高精度乘法和除法模板是对于一个大数和小数的乘除,也就是小数的范围是在1~10000,远小于大数,所以对于小的这个数就不用采用字符串的方式输入,可以直接获取。对于乘法采取用大的数的每一位分别乘以小的数,中间值 t 即为每次乘完需要进位的值,每次循环运算时,需要将上一次运算进的位 t 加入A[i] * b 的结果中,再把得到的结果的个位存入结果数组 C 中,即 t % 10,最后删去个位(即 t /= 10),剩下的就是需要向前进的位。注意循环完也要删去高位 0 。

代码

#include <iostream>
#include <vector>

using namespace std;
//C = A * b,满足A >= 0, b > 0
vector<int> mul(vector<int> &A, int b)
{
    vector<int> C;
    
    int t = 0;
    for (int i = 0, t = 0; i < A.size() || t; i ++ )  
    //如果已经算到最高位但进位不为0,仍然要继续循环
    {
        if (i < A.size()) t += A[i] * b;  //只要没算到最高位就还需要乘以b
        C.push_back(t % 10);  //t的个位即为当前位置的结果数
        t /= 10;  //t删去个位,即为需要进的位
    }
    
    while (C.size() > 1 && C.back() == 0) C.pop_back();  //消去C中最高位可能出现的0

    return C;
}

int main()
{
    string a;
    int b;
    cin >> a >> b;
    vector<int> A;
    for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');

    vector<int> C = mul(A, b);
    
    for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
    cout << endl;
    return 0;
}

AcWing题库-794-高精度除法

题目
给定两个正整数A,B,请你计算A/B的商和余数。

输入格式
共两行,第一行包含整数A,第二行包含整数B。

输出格式
共两行,第一行输出所求的商,第二行输出所求余数。

数据范围
1≤A的长度≤1000000
1≤B≤10000

输入样例
7
2

输出样例
3
1

思路解析:
除法仍然是较小的数直接输入,较大的数用字符串转换为可变数组,由于除法的计算方式是从高位向低位逐个除,所以在输入的时候不用倒着输,直接按原顺序输入即可。因为除法需要得到的数多了一个余数,所以参数传递的时候也多了一个余数 r ,而且除法在计算的时候,每次高位除完得到的余数需要与下一位合并,所以这里的中间值也是余数 r ,在循环中,因为每次余数的位数相对于下一位的位数靠前一位,所以每次合并余数和被除数的时候需要将余数乘以10再加上下一位数字 A[i] ,结果数则可以直接用整数除法计算式,即存入 r / b ,最后再将 r 转换成当前位数字除完的余数即可(即 r % b )。注意这里C的存储方法是从高位到低位,所以去掉高位0的时候需要先将C前后翻转,最后将C倒着输出即可。

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;
//A / b, 商是C,余数是r
vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    r = 0;
    
    for (int i = 0; i < A.size(); i ++)
    {
        r = r * 10 + A[i];  //余数与下一位被除数合并
        C.push_back(r / b);  //存入当前位的商
        r %= b;  //使r变为当前位的余数
    }
    
    reverse(C.begin(), C.end());
    while (C.size() > 1 && C.back() == 0) C.pop_back();  //去掉高位0
    return C;
}
int main()
{
    string a;
    int b, r;
    vector<int> A;
    cin >> a >> b;
    for (int i = 0; i < a.size(); i ++) A.push_back(a[i] - '0');
    
    vector<int> C = div(A, b, r);
    
    for (int i = C.size() - 1; i >= 0; i --) cout << C[i];
    cout << endl << r << endl;
    
    return 0;
}

(模板来源于AcWing算法基础课

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值