高精度的加减乘除 算法细讲

高精度应用场景:

在某些算法应用场景中,我们可能看到在存放数字时候,int和long已经不能满足我们的需求,我们需要很长的数组去存储我们的数字,让我们更好的运算。

高精度加法:
在这里插入图片描述
从小学开始学习算法的相加,第一开始学习的就是竖式相加,现在我们一个学习如和利用这种数学思维去实现代码的运行
编写代码的前提,先学习以下c++语言中vector中的函数的用法:
verctor是一个能够存放任意类型的动态数组。
size():返回的是vector中元素的个数,这是vector中保存的实际对象的数量,不一定等于它的存储容量。
push_back():就是在vector尾部加入一个数据。当数组中新增加一个元素x时,先判断是否还有备用空间:有,将当前指针的值设为x,并将当前指针+1;如果备用空间已经用完,如果之前空间为0,则重新分配大小为1的空间,否则将空间扩容为之前的两倍,然后将旧容器中的值重新拷贝到新空间中,并重新分配起始指针和当前指针。vector需要注意一点是尽量不要动态给它分配空间。而且重新空间分配之后,之前的所有指针都会失效。

//为了方便计算,高精度加法采用的是倒序的相加进行计算。例如:123+12  变成321+210   其结果再倒序输出来
#include <iostream>
#include <vector>
using namespace std;
vector<int> add(vector<int> &A, vector<int> &B)
{
    //为了方便计算,让A中保存较长的数字, B中保存较短的数字
    //可能是对应的数字就一个进行比较这是一个重点。
    if (A.size() < B.size()) return add(B, A);
    //保存结果的数组
    vector<int> C;
    //进位,开始时是0
    int t = 0;
    //依次计算每一位
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];//加上 A 的第 i 位上的数字
        if (i < B.size()) t += B[i];//加上 B 的第 i 位上的数字
        C.push_back(t % 10); //C 中放入结果
        t /= 10;//t 更新成进位
    }
    //最后如果进位上有数,放进结果数组
    if (t) C.push_back(t);
    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');//倒序存储第二个数
    auto C = add(A, B);//调用加和函数
    for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];//倒序输出C中的数字
    cout << endl;
    return 0;
}

高精度减法:
vector中的pop_back():是删除对应的vector中的尾部指针。
在这里插入图片描述
在这里插入图片描述

高精度减法最重要的是要注意其进位

#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
//看对应的题目,题目上就是说对应的A-B  已经是够明确的了,所以就是直接拿来函数算就行。
bool cmp(vector<int> &A,vector<int> &B){
    if(A.size()!=B.size()) return A.size()>B.size();
    for(int i=A.size()-1;i>=0;i--) {
        if(A[i]]!=B[i])  return A[i]>B[i];
    }
    //如果是对应的A与B相等的情况下,直接为true。
    return true;
}
vector<int> sub(vector<int> &A,<vector>int &B){
    vector<int> C;
    //借出对应的t
    int t=0;
    for(int i=0;i<A.size();i++){
        t=A[i]-t;
        if(i<B.size()) t-=B[i];
        //下面这一点最为关键  不借位(1 + 10) % 10 = 1 , 借位(-1 + 10) % 10 = 9
        C.push_back((t+10)%10);
        if(t<0) t=1;
        else t=0;
    }
    //这个只是针对对应以免会出现002的情况,去掉前置0,因为是倒序输出,去掉后边的0就可以了
    while(C.size()>1&&C.back()==0) C.pop_back();

    return C;
}
int main(){
    string a,b;
    cin>>a;
    vector<int> 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)){
        auto C=sub(A,B);
        for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    }else{
        auto C=sub(A,B);
        printf("-");
        for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    }

    return 0;

}

高精度乘法:

高精度乘法需要讲究一些技巧方面的知识:
例如:123 * 12==>123 * 10+123 * 2

//例子:我们举一个高精度*低精度的例子
#include<iostream>
#include<vector>
using namespace std;
vector<int> mul(vector<int> &A,int b){
    vector<int> C;
    int t=0;
    //乘法和加法不一样,乘法的进位不止为1,进位要考虑1~8
    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 a;
    int b;
    cin>>a>>b;
    vector<int> A;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    auto C=mul(A,b);
    for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    return 0;   
}

高精度除法:

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

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

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

数据范围
1≤A的长度≤100000 , 1≤B≤10000 ,
B 一定不为 0
输入样例:
7 2
输出样例:
3 1

在这里插入图片描述

#include<iostream>
#include <algorithm>
#include<vector>
using namespace std;


vector<int> div(vector<int> &A,int b,int &r){
    vector<int> C;
    r=0;
    //需要从高位开始计算
    for(int i=A.size()-1;i>=0;i--){
     r=r*10+A[i];
     C.push_back(r/b);
     r%=b;
    }
    //把对应的数字又开始反转过来了
    /*
    由于在除法运算中,高位到低位运算,因此C的前导零都在vector的前面而不是尾部,vector只有删除最后一个数字pop_back是常数复杂度,而对于删除第一位没有相应的库函数可以使用,而且删除第一位,其余位也要前移,因此我们将C翻转,这样0就位于数组尾部,可以使用pop函数删除前导0
    */
    reverse(C.begin(),C.end());
    while(C.size()>1&&C.back()==0) C.pop_back();
    return C;
    
}
int main(){
    string a;
    vector<int> A;
    
    int B;
    cin>>a>>B;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    int r;
    auto C=div(A,B,r);
   
    for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    
    printf("\n");
    printf("%d",r);
    return 0;
    
    
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值