高精度加减乘除运算

本文是刷算法记录的第一篇,是按照ACWING的算法课的顺序来的,写一下题解以供参考。

一、问题描述

1.高精度加法

给定两个正整数(不含前导 00),计算它们的和。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的和。

数据范围

1≤整数长度≤100000

2.高精度减法

给定两个正整数(不含前导 00),计算它们的差,计算结果可能为负数。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的差。

数据范围

1≤整数长度≤105

3.高精度乘法

给定两个非负整数(不含前导 00) A 和 B,请你计算 A×B的值。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

共一行,包含 A×B 的值。

数据范围

1≤A的长度≤100000
0≤B≤10000

4.高精度除法

给定两个非负整数(不含前导 00) A,B,请你计算 A/B 的商和余数。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

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

数据范围

1≤A的长度≤100000,
1≤B≤10000,
B一定不为 0

二、算法分析

高精度问题仅在C++语言中存在,在JAVA和Python语言中并不存在。在处理高精度问题时,要注意以下几个问题:

1.高精度的模拟。高精度由于输入数据和存储数据过大,无法用C++中的数据类型进行存储和表示,故利用数组进行存储。在利用数组进行存储后,对加减乘除的模拟更接近于传统的手算模拟,而加减乘都是从个位开始运算,除法从最高位开始运算,所以我们将最低位存储在数组最低位(a[0]),进行模拟运算。

2.前导0问题:前导0指,最后的计算结果中,在最高位出现连0的情况,例如000012312的情况,此时需要处理掉前导0。在加法中,显然不会出现前导0的问题;减法和除法会出现前导0的问题;乘法唯一可能出现前导0的情况是,000000000,即0。在对前导0处理时,应该从最高位开始处理,直到最后一位。

3.算法流程:

(1)输入:将大数倒置保存在数组中。在读入大数时,我们用字符串进行读入,输入数组时,由于字符串的单个元素为char型,在输入时需要进行“a[i]-'0'”的操作,完成隐式类型转换。

(2)运算:进行竖式计算的模拟,注意对前导0进行处理。

(3)输出:输出即可。

三、代码实现

1.高精度加法

源代码
#include<iostream>
#include<vector>
using namespace std;

vector<int> add(vector<int> &a,vector<int> &b){
    vector<int> c;
    //模拟运算,从低位到高位
    int t = 0;//进位,我们在高精度运算中,统一把值填进进位,方便统一处理。
    for(int i=0;i<a.size()||i<b.size();i++){
        if(i<a.size()) t+=a[i]; 
        if(i<b.size()) t+=b[i];
        c.push_back(t%10);
        t/=10;
    }
    if(t==1) c.push_back(1);
    return c;
}

int main(){
    //输入
    string s1,s2;
    cin>>s1>>s2;
    //倒序输入,将末位填入数组的第一位

    vector<int> a,b;
    for(int i=s1.size()-1;i>=0;i--){
        a.push_back(s1[i]-'0');
    }
    for(int i=s2.size()-1;i>=0;i--){
        b.push_back(s2[i]-'0');
    }

    //计算
    auto c = add(a,b);

    //输出
    for(int i=c.size()-1;i>=0;i--){
        cout<<c[i];
    }
    return 0;
}
解析

1.在计算过程中,我们利用进位变量作为运算的中转单元,完成结果输出与下一级进位的保存。这一思想同样用于其他三种运算,

2.运算要保证两个都算完,这里是利用||来进行判断,加法有可能位数加1,所以要判断最后一位是否输入。

2.高精度减法

源代码
#include<iostream>
#include<vector>
using namespace std;

//判断两个大数的大小
bool cmp(vector<int> &a,vector<int> &b){
    //判断逻辑:先比较两个数的位数,若相同,则从最高位起依次比较每一位的大小
    if(a.size()<b.size())  return false;
    if(a.size()>b.size())  return true;
    for(int i=a.size()-1;i>=0;i--){
        if(a[i]<b[i]) return false;
        if(a[i]>b[i]) return true;
    }
    return true;
}
    
//大数相减
vector<int> sub(vector<int> &a,vector<int> &b){
    vector<int> c;
    int t=0;
    //从最低位开始依次相减,t这里表示借位,需要在循环开始时减去
    for(int i=0;i<a.size();i++){
        t=a[i]-t;
        if(i<b.size()) t-=b[i];
        c.push_back((t+10)%10);
        //如果t<0,说明需要借位,t=1,否则t=0
        if(t<0) t=1;
        else t=0;
    }

    //去除高位的0
    while(c.back()==0&&c.size()>1) c.pop_back();
    return c;
}

int main(){
    //输入
    vector<int> a,b;
    string s1,s2;
    cin>>s1>>s2;
    for(int i=s1.size()-1;i>=0;i--){
        a.push_back(s1[i]-'0');
    }
    for(int i=s2.size()-1;i>=0;i--){
        b.push_back(s2[i]-'0');
    }

    //处理和输出
    //利用CMP函数判断大小,如果a>b,则进行处理后还需要添加‘-’号
    if(cmp(a,b)) {
        auto c=sub(a,b);
        for(int i=c.size()-1;i>=0;i--){
            cout<<c[i];
        }
    }
    else{
        auto c=sub(b,a);
        cout<<'-';
        for(int i=c.size()-1;i>=0;i--){
            cout<<c[i];
        }
    }

    return 0;
}
解析

1.在计算过程中,我们利用借位变量作为运算的中转单元,完成结果输出与下一级借位的保存。不同于加法的进位,减法的借位需要在循环开始时剪掉。在运算完成后,借位为负则借位为1.

2.减法需要去除前导0.

3.减法需要判断大小,用以调整sub函数和输出负号。

3.高精度乘法

源代码
#include<iostream>
#include<vector>
using namespace std;

vector<int> mul(vector<int> &a, int b){
    vector<int> c;
    // 高精度乘法,循环终止条件为进位为0且a数组算完
    int t = 0;
    for(int i = 0; i < a.size() || t; i++){
        if(i<a.size()) t+=a[i]*b;
        c.push_back(t%10);
        t/=10;
    }
    // 去除前导0
    while(c.size() > 1 && c.back() == 0) c.pop_back();
    return c;
}

int main(){
    // 读入数据
    string s;
    int b;
    cin >> s >> b;
    vector<int> a;
    for(int i = s.size() - 1; i >= 0; i--) a.push_back(s[i] - '0');
    // 高精度乘法
    auto c = mul(a, b);
    // 输出结果
    for(int i = c.size() - 1; i >= 0; i--) cout<<c[i];

    return 0;
}
解析

1.以进位为中间单元,直到进位也最终为0.

2.有可能全为0,记得去除前导0。

4.高精度除法

源代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

vector<int> div(vector<int> &a, int &b, int &r) {
    vector<int> c; 
    // 高精度除法,循环终止条件为a数组算完
    // 除法是从最高位开始算,所以要从数组末端开始
    r=0;//余数作为中间运算单元
    for(int i=a.size()-1;i>=0;i--){
        r=a[i]+ 10*r;
        c.push_back(r/b);
        r%=b;
    }
    //处理后得到的结果是高位在数组低位,需要倒转
    reverse(c.begin(),c.end());
    while (c.size() > 1 && c.back() == 0) c.pop_back();
    return c;
}

int main(){
    // 读入数据
    string s;
    vector<int> a;
    int b;
    cin>>s>>b;
    for(int i=s.size()-1;i>=0;i--) a.push_back(s[i]-'0');
    // 高精度除法
    int r=0;// 余数
    auto c=div(a,b,r);

    // 输出结果
    for(int i=c.size()-1;i>=0;i--) cout<<c[i];
    cout<<endl<<r;

    return 0;
}
解析

1.在计算过程中,我们利用余数变量作为运算的中转单元,完成结果输出与下一级的保存。

2.余数r利用引用完成余数部分和商部分的同时处理。

5.运算单元汇总

源代码
int t=0
//add
    if(i<a.size()) t+=a[i];
    if(i<b.size()) t+=b[i];
//sub
    t=a[i]-t;
    if(i<b.size()) t-=b[i];
//mul
    t+=a[i]*b;
//div
    t=a[i]+t*10;

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值