什么是高精度?

高精度算法High Accuracy Algorithm)是处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方,阶乘,开方等运算。对于非常庞大的数字无法在计算机中正常存储,于是,将这个数字拆开,拆成一位一位的,或者是四位四位的存储到一个数组中, 用一个数组去表示一个数字,这样这个数字就被称为是高精度数。

本文将介绍四种常见的高精度计算,包括高精度加法、减法、高精度乘低精度、高精度除低精度。

1.高精度存储

我们使用数组来存储高精度数字,并且采用倒序的方法,如下图。




多精度机器学习 多级精度_多精度机器学习


在数组中逆序存储

逆序存储的原因:由于在后面的计算中常常涉及到进位,如果将高位放在数组第一位则会频繁的移动数字,造成时间复杂度的增加。

2.高精度加法

通过模拟人工加法的方式,逐个进位。


```
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<int> add (vector<int> &A,vector<int> &B){
    if(A.size()<B.size()) return add(B,A);
    vector<int> C;
    int t = 0;
    for(int i = 0; i < A.size() ;i ++){
        t += A[i];
        if(i < B.size()) t+=B[i];
        C.push_back(t%10);
        t /= 10;
    }
    if(t) C.push_back(t);//最后的进位压入数组
    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 = add(A,B);
    for(int i = C.size()-1; i >=0 ; i--) printf("%d",C[i]);
    return 0;
}


3.高精度减法

通过模拟人工减法的方式,逐个相减。


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

bool cmp(string a,string b){
    return 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;
    
}

//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];
        C.push_back((t+10)%10);
        if(t<0) t= 1;
        else t = 0;
    }
/*
  for(int i=0,t=0;i<A.size();++i){
        t+=A[i];
        if(i<B.size()) t-=B[i];
        C.push_back((t+10)%10);
        if(t>=0) t = 0;
        else t = -1;
    }
*/
    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');

    if(cmp(A,B)){
    //if(cmp(a,b)){ //! string比较有bug
        auto C = sub(A,B);
        for(int i=C.size()-1; i >=0 ; i --) printf("%d",C[i]);
    }else{
        auto C = sub(B,A);
        printf("-");
        for(int i=C.size()-1; i >=0 ; i --) printf("%d",C[i]);
    }
    return 0;
}


4.高精度乘低精度

高精度模拟乘法,每次乘法将计算高精度的每一位乘以低精度,并进位(所以就可能进位较多,加法中进位最多一位)


多精度机器学习 多级精度_数组_02

每次将大数字中的一位乘以小数字,进位累加


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

//$高精度A乘低精度b乘法

vector<int> mul(vector<int> &A,int b){
    vector<int> C;

    for(int i =0,t=0;i<A.size()|| t;++i ){
        if(i<A.size()) t+= A[i] *b;
        C.push_back(t%10);
        t/=10;
    }
    
    while(C.size()>1&&C.back()==0)C.pop_back();//去除前导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');
//    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--) printf("%d",C[i]);
   
    return 0;
}


5.高精度除以低精度

高精度除法实现关键在于余数。(不知道哪些绘图软件好用...)

每一次迭代,余数乘10+下一位,并且余上除数(相当于做减法)


多精度机器学习 多级精度_数组_03


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

//$794. 高精度除法

vector<int> div(vector<int> &A,int b,int &r){
    vector<int> C;
    r = 0;
    for(int i =A.size()-1,t=0;i>=0;i-- ){
        r = r*10+ A[i];
        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 a;int b;
    cin>>a>>b;
    vector<int> A;
    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');
    int r;
    auto C = div(A,b,r);
    
    for(int i =C.size()-1;i>=0;i--) printf("%d",C[i]);
    printf("n%d",r);
   

    
    return 0;
}