高精度算法

高精度加法

  1. 大整数存储:为了方便进位,数的最高位存在数组的末端(push_back()),数组下标从0开始存储的是该数从个位到最高位。

  2. 运算:模拟人工加法的过程,对应数相加(结果取模),逢十进一(Ai + Bi + 进位)。巧妙:用t来记录Ai + Bi + 进位的总和

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

const int N = 100000+10;
vector<int> add(vector<int> &A, vector<int> &B)
{
    //保证大的数在上方(符合现实加法计算)
    if(A.size() < B.size()) return add(B,A);
    vector<int> C;//用来存储结果
    int t = 0;// 初始进位为0
    //遍历求和
    for(int i = 0; i < A.size(); i++)
    {   
        t += A[i];
        if(i < B.size()) t += B[i];
         //执行到这里t里记录A和B数组对应位以及进位的和 Ai + Bi + 进位
        C.push_back(t % 10);//记录结果
        //进位
        t = t / 10;
    }
    //判断最后一位求和后要不要进位
    if(t) C.push_back(1);
    
    return C;
}
int main()

{
    string a, b;
    //a = "123456"
    //将大整数用数组存下来(vector)
    vector<int>A, B;
    cin>>a>>b;
    
    //a[i] - '0'将字符a[i]转为整数
    for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0'); //A = [6,5,4,3,2,1];
    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];
    
    return 0;
}

注:

  1. 数不知道多大用string来输入(int 的范围有限)
  2. 存储时用vector:动态大小、方便进位操作(利用push_back(),将最高位放到后面)
  3. 因为输入的是string类,在存入数组时要将字符(每一位)转为整数(字符 - '0'
  4. 返回结果是vector(数组),因此函数类型是vector< int >
  5. 为了加快效率添加引用符&:add(vector< int > &A, vector< int > &B)
  6. ​ if(t) C.push_back(1);判断最后一位求和后要不要进位。如(411 + 811 最后一位8 + 4=12如果没有进位1则答案只有A.size()个数,答案并不完整)

高精度减法

1、定义存储数组:大整数存储同高精度加法

2、被减数和减数确认。由于减法可能出现负数(3-5 = -2 ---> - (5 - 3))。

3、读入数据到数组中。注意:保证被减数大于减数;(A>=B ---> cmp(A,B))

4、从个位开始模拟竖式减法的过程,完成整个减法。

5、差值为>=0或者<0两种情况(<0则需要借位)

6、删除前导 0 。所谓前导零,就是出现类似这样数据 01234,这个 0 实际是不需要的。(注:当相等的两数相减的结果0,它不是前导0)

7、输出减法的结果。倒序输出减法的结果数组 C,因为我们的个位是存储在下标为 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();
    
    //长度一样:从最高位开始逐一比较判断,不相等,高位大的就大;都相同则相等
    for(int i = A.size() - 1; i >= 0; i--)
    {
        if(A[i] != B[i]) return A[i] > B[i];
    }
        //都相同则相等
        return true;
}

vector<int> sub(vector<int> &A, vector<int> &B)
{
    int t = 0;
    vector<int> C;
    
    for(int i = 0; i < A.size(); i++)
    {
       t = A[i] - t;
       if(i < B.size()) t -= B[i];// 到这里此时得到的是Ai - Bi的结果,t记录两数之差(大于/小于0) 
       C.push_back((t + 10) % 10);//记录答案(包含了差 >=0 和 <0 两种情况)
       if(t < 0) t = 1; // 差结果t<0 则借一位
       else t = 0;// t > 0则不借位
    }
    //除去前导0
    //注:C.size() > 1,而不是>0 (4-4 = 0 size = 1,若是>0 4-4 = 0的结果0就会被删去了) 
    while(C.size() > 1 && C.back() == 0) C.pop_back();
    
    return C;
}

int main()
{
    string a, b;
    cin>>a>>b;
    
    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');
    
    
    //判断A,B大小
    if(cmp(A,B)) // A > B
    {
      auto C = sub(A,B);
      for(int i = C.size() - 1; i >= 0; i--)
      cout<<C[i];
    }
    else // A < B
    {
        auto C = sub(B,A);
        cout<<"-";
        for(int i = C.size() - 1; i >= 0; i--)
        cout<<C[i];
    }
    
    return 0;
}

高精度乘法

高精度X低精度

存储:高精度以字符串形式输入保存(同上),低精度以整数形式输入即可

运算:不是我们认为的模拟乘法。把b看成一个整体,而不是一位一位的乘

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

// a * 整体b
vector<int> mul(vector<int> &A, int b)
{
    vector<int> C;
    //用t来记录乘积结果以及进位
    int t = 0;
    for(int i = 0; i < A.size() || t; i++) // i没有循环完或者t不为0
    {
        if(i < A.size())
        {
            t += A[i] * b; // 用t来记录乘积结果
            C.push_back(t % 10); // 记录答案
        }
        else 
        {
            C.push_back(t % 10); //若t不为0 记录最高位答案
        }
        t = t / 10; // 进位
    }
    
    //去除前导0(当b为0时)乘以0的时候,就会有前导0,如 123 x 0=000
    while(C.size() > 1 && C.back() ==0) C.pop_back();
    
    return C;
}

int main()
{
    string a;
    int b;
    vector<int> A;
    cin>> a>> b;
    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--)
    cout<<C[i];
    
    return 0;
}

for(int i = 0; i < A.size() || t; i++) // i没有循环完或者t不为0。 关于|| t理解

比如一个三位数乘二位数可能会有等于四位数(进位)的情况,而如果没有||t的话,C的长度最长就是三,||t就是用来储存A的最高位和b相乘的结果

image

注:

在for循环的条件判断语句中,首先执行i =0;再执行判断语句,如果条件判断为真,则执行for循环中的内容,最后对i进行加1操作。然后依次循环进行判断,代码段和i++中的内容。

高精度X高精度

  • 相乘累加(乘法交换律)
  • 进位求余
#include <iostream>
#include <vector>

using namespace std;

vector<int> mul(vector<int> &A, vector<int> &B)
{
   vector<int>C(A.size() + B.size());
   //相乘累加
   for(int i = 0; i < A.size(); i++){
       for(int j = 0; j < B.size(); j++){
           C[i + j] += A[i] * B[j];
       }
   }
   
   //进位求余
   int t = 0;
   for(int i = 0; i < C.size() || t; i++) // i没有循环完或者t不为0
   {
       if(i < C.size())
       {
           t += C[i];
           C[i] = t % 10; // 记录答案
       }
       else C.push_back(t % 10); // t不为0时,记录最高位
       
       t = t / 10; // 进位
   }
   
   //清除前导0
   while(C.size() > 1 && C.back() == 0) C.pop_back();
   
   return C;
}

int main()
{
    string a, b;
    cin >> a >> b;
    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');
    auto C = mul(A, B);

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

    return 0;
}

image

高精度除法(高精度 除 低精度)

存储方式:同前

运算:模拟手算除法,但是一位一位的除

image

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

vector<int> div(vector<int> &A, int b, int &r)
{
    r = 0; // 初始剩余的数为0
    vector<int> C;
    //从最高位开始除
    for(int i = A.size() - 1; i >= 0; i--)
    {
        r = r*10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    // 与前几个高精度输出方式相对应
    reverse(C.begin(), C.end());
    //去除前导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');
    
    int r;
    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. 除了高精度加法其它三种都要去除前导0
posted @ 2021-10-17 23:32  时间最考验人  阅读(170)  评论(0编辑  收藏  举报