淺談高精度算法(加減乘除)


  在C/C++中,不時會遇到限定數據范圍的情況,我們先來看看常用的int和long long兩種數據類型的范圍吧。

  C++標准規定,int占一個機器字長。在32位系統中int占32位,也就是4個字節,所以在32位系統中,int的范圍是[-2^31,2^31-1],為10^9數量級;而long long的范圍則是[-2^63,2^63-1],為10^18數量級,但當一些ACM/OI題目中測試數據范圍超過此范圍,甚至超過double(1.7*10^308數量級)時,該怎么辦?Java有大數類,而python的整數也是不限制長度的,雖然C++的整數長度受到限制,但我們也有高精度算法,下面,我將介紹幾種常見的高精度整算法。

  一、高精度加法。

  對於10^308以上的大數,確實不能用C++內置的數據類型直接處理,但回想我們曾經做過的小學算術問題,兩個整數相加,先從個位算起,過十進位,依照這個思路,我們可以將大數存放在數組中,再利用數組去模擬加法運算的過程,代碼如下:

#include<iostream>
#include<cstring>
using namespace std;
char s1[505],s2[505];
int a[505],b[505],c[505];
int main(){
    int m,n,v,t;
    std::ios::sync_with_stdio(false);
    cin>>s1>>s2;
    m=strlen(s1);
    n=strlen(s2);
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
    for(int i=0;i<m;i++){
        a[m-1-i]=s1[i]-'0';
    }
    for(int i=0;i<n;i++){
        b[n-1-i]=s2[i]-'0';
    }
    m=max(m,n);
    m++;
    memset(c,0,sizeof(c));
    for(int i=0;i<m;i++){         
        v=a[i]+b[i];
        if((c[i]+v)<10)
            c[i]+=v;
        else{
            c[i+1]+=(c[i]+v)/10;
            c[i]=(c[i]+v)%10;        
        }    
    }        

//下面是一種更簡單的做法,結果直接儲存在a中 /*for(int i=0;i<m;i++){ a[i]+=b[i]; a[i+1]+=a[i]/10; a[i]%=10; }*/ if(c[m-1]==0) m--; for(int i=m-1;i>=0;i--) cout<<c[i]; return 0; }

  二、高精度減法。

  和高精度加法的基本思路相同,不過在減法中,需要確定輸入數字的相對大小來判斷是否輸出負號,還需要注意是否要"借位"。上代碼:

#include<iostream>
#include<cstring>
using namespace std;
bool compare(char s1[],char s2[]){
    int u=strlen(s1),v=strlen(s2);
    if(u!=v)
        return u>v;
    for(int i=0;i<u;i++)
        if(s1[i]!=s2[i])    return s1[i]>s2[i];
    return true;
}                                                  //比較兩個數相對大小 
int main(){
    std::ios::sync_with_stdio(false);
    int flag=1,i,j;
    char s1[100005],s2[100005],s3[100005];              //這里為節省空間考慮,直接用char數組運算 
    cin>>s1>>s2;
    if(compare(s1,s2));
    else{
        flag=-1;
        strcpy(s3,s1);
        strcpy(s1,s2);
        strcpy(s2,s3);
    }
    int u=strlen(s1),v=strlen(s2);
    for(i=u-1,j=v-1;j>=0;i--,j--){
        if(s1[i]<s2[j]){
            s1[i-1]-=1;
            s3[i]=s1[i]-s2[j]+10+'0';
        }
        else    s3[i]=s1[i]-s2[j]+'0';
    }                                                  //從最后一位向前減 
    for(;i>=0;i--)    {
        if(s1[i]<'0'){
            s1[i-1]-=1;
            s3[i]=s1[i]+10;
        }
        else    s3[i]=s1[i];
    }                                                  //s1數位大,所以還有s1減'0' 
    for(i=0;i<u-1&&s3[i]=='0';i++);                     //只到u-1的原因時 
    if(flag==-1)    cout<<'-';
    cout<<s3+i;
    return 0;
}

  三、高精度乘法。

  依舊是模擬算術做豎式乘法的過程,要注意進位,貼代碼:

#include<iostream>
#include<cstring>
using namespace std;
char a[2005],b[2005];
int c[2005],d[2005],e[4005];
int u,v,w;
int main(){
    int i,j;
    cin>>a>>b;
    u=strlen(a);
    v=strlen(b);
    memset(c,0,4005);
    for(int i=0;i<u;i++)
        c[u-1-i]=a[i]-'0';
    for(int i=0;i<v;i++)
        d[v-1-i]=b[i]-'0';
    for(i=0;i<u;i++){
        for(j=0;j<v;j++){
            w=c[i]*d[j];
            if(e[i+j]+w<10)    e[i+j]+=w;
            else{
                e[i+j+1]+=(e[i+j]+w)/10;
                e[i+j]=(e[i+j]+w)%10;
            }
        }
    }
    for(i=u+v-1;i>0&&e[i]==0;i--);            //此處是為了不漏掉輸出結果為0而將條件寫為i>0 
    for(;i>=0;i--)    cout<<e[i];
    return 0;
}

  四、高精度除法。

  高精度除法分兩種,都是仿照豎式除法實現,一種是高精度除以低精度,較為容易實現,主要是利用一個數,在線處理:

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
char s1[5005];
int a[5005],b,c[5005],x=0;
int main(){
    cin>>s1>>b;
    a[0]=strlen(s1);
    for(int i=1;i<=a[0];i++)    a[i]=s1[i-1]-48;
    memset(c,0,sizeof(c));
    for(int i=1;i<=a[0];i++){
        c[i]=(x*10+a[i])/b;
        x=(x*10+a[i])%b;  
    }                              //核心部分
    x=1;
    while(c[x]==0&&x<a[0])    x++;
    for(;x<=a[0];x++)    cout<<c[x]; 
    return 0;
}

  另一種,是運用逐次相減的方法確定出商和余數,代碼如下:

#include<iostream>
#include<cstring>
using namespace std;
int a[5005],b[5005],c[5005],d[5005];
bool compare(int a[],int b[]){
    if(a[0]!=b[0])    return a[0]>b[0];
    for(int i=a[0];i>0;i--){
        if(a[i]!=b[i])    return a[i]>b[i];
    }
    return true;
}
int main(){
    std::ios::sync_with_stdio(false);
    string s1,s2;
    cin>>s1>>s2;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    a[0]=s1.length();
    b[0]=s2.length();
    for(int i=1;i<=a[0];i++)    a[i]=s1[a[0]-i]-'0';
    for(int i=1;i<=b[0];i++)    b[i]=s2[b[0]-i]-'0';
    c[0]=a[0]-b[0]+1;
    for(int i=c[0];i>0;i--){            //c[0]代表最初a,b的數位差 
        memset(d,0,sizeof(d));
        for(int j=1;j<=b[0];j++)
            d[j+i-1]=b[j];
        d[0]=b[0]+i-1;                           //先讓b中存下的數與a在一個數量級 
        while(compare(a,d)){                    //比較,如果a比較大,用a直接減去d,如果a比較小,下一次大循環中,d的位數會減一 
            c[i]++;
            for(int i=1;i<=a[0];i++){
                a[i]-=d[i];
                if(a[i]<0){
                    a[i+1]--;
                    a[i]+=10;
                }
            }
            while(a[0]>0&&a[a[0]]==0)    a[0]--;
        }
    }
    while(c[0]>1&&c[c[0]]==0)    c[0]--;
    cout<<"商:";
    for(int i=c[0];i>0;i--)    cout<<c[i];
    cout<<endl<<"余數:";
    for(int i=a[0];i>0;i--)    cout<<a[i];           //a中最后剩下的就是余數  
    return 0;
}

  好的,高精度基礎算法介紹完畢,大家不妨自行動手一試。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM