轉載:C++之高精度演算法

Tiny_W發表於2018-02-04

原地址:http://blog.sina.com.cn/s/blog_4fdb102b010087ng.html

特別讚的一篇關於高精度的文章,特別感謝原作者!

前言:由於計算機運算是有模運算,資料範圍的表示有一定限制,如整型int(C++中int 與long相同)表達範圍是(-2^31~2^31-1),unsigned long(無符號整數)是(0~2^32-1),都約為幾十億.如果採用實數型,則能儲存最大的double只能提供15~16位的有效數字,即只能精確表達數百萬億的數.因此,在計算位數超過十幾位的數時,不能採用現有型別,只能自己程式設計計算.

高精度計算通用方法:高精度計算時一般用一個陣列來儲存一個數,陣列的一個元素對應於數的一位(當然,在以後的學習中為了加快計算速度,也可用陣列的一個元素表示數的多位數字,暫時不講),表示時,由於數計算時可能要進位,因此為了方便,將數由低位到高位依次存在陣列下標對應由低到高位置上,另外,我們申請陣列大小時,一般考慮了最大的情況,在很多情況下,表示有富餘,即高位有很多0,可能造成無效的運算和判斷,因此,我們一般將陣列的第0個下標對應位置來儲存該數的位數.如數:3485(三千四百八十五),表達在陣列a[10]上情況是:
下標  0    1    2    3     4                 
內容  4    5    8    4     3    0             0
說明:位數   個位  十位  百位 千位
具體在計算加減乘除時方法就是小學時採用的列豎式方法.
注:高精度計算時一般用正數,對於負數,通過處理符號位的修正.
一.高精度數的儲存
1.如對數採用的字串輸入
#include <iostream>
#include <cstring>
using namespace std;
const int N=100;//最多100位
int main()
{
int a[N+1],i;
string s1;
cin>>s1;//數s1
memset(a,0,sizeof(a)); //陣列清0
a[0]=s1.length(); //位數
for(i=1;i<=a[0];i++) a[i]=s1[a[0]-i]-'0';//將字元轉為數字並倒序儲存.
return 0;
}
2.直接讀入
#include <iostream>
using namespace std;
const int N=100;//最多100位
int main()
{
int a[N+1],i,s,key;
cin>>key;//數key
memset(a,0,sizeof(a)); //陣列清0
i=0;//第0位
while(key)  //當key大於0
{
  a[++i]=key%10;//取第i位的數
  key=key/10;
}
a[0]=i; //共i位數
return 0;
}
3.直接初始化(用a[]儲存)
初始化為0: memset(a,0,sizeof(a));
初始化為1: memset(a,0,sizeof(a));a[0]=1;a[1]=1;

以下程式都只寫函式,不寫完整程式,所有高精度數儲存都滿足上述約定。
二.高精度數比較
int compare(int a[],int b[])   //比較a和b的大小關係,若a>b則為1,a<b則為-1,a=b則為0
{int i;
if (a[0]>b[0]) return 1;//a的位數大於b則a比b大
if (a[0]<b[0]) return -1;//a的位數小於b則a比b小
for(i=a[0];i>0;i--)  //從高位到低位比較
     {if (a[i]>b[i]) return 1;
      if (a[i]<b[i]) return -1;}
return 0;//各位都相等則兩數相等。
}
三、高精度加法
int plus(int a[],int b[]) //計算a=a+b
{int i,k;
k=a[0]>b[0]?a[0]:b[0]; //k是a和b中位數最大的一個的位數
for(i=1;i<=k;i++)
    {a[i+1]+=(a[i]+b[i])/10;  //若有進位,則先進位
    a[i]=(a[i]+b[i])%10;}  //計算當前位數字,注意:這條語句與上一條不能交換。
if(a[k+1]>0) a[0]=k+1;  //修正新的a的位數(a+b最多隻能的一個進位)
               else a[0]=k;
return 0;
}
四、高精度減法
int gminus(int a[],int b[]);//計算a=a-b,返加符號位0:正數 1:負數
{ int flag,i
  flag=compare(a,b); //呼叫比較函式判斷大小
if (falg==0)//相等
  {memset(a,0,sizeof(a));return 0;}  //若a=b,則a=0,也可在return前加一句a[0]=1,表示是 1位數0
if(flag==1) //大於  
   for(i=1;i<=a[0];i++)
       if(a[i]<b[i]){ a[i+1]--;a[i]+=10;} //若不夠減則向上借一位
        a[i]=a[i]-b[i];}
     while(a[a[0]]==0) a[0]--; //修正a的位數
    return 0;}
if (flag==-1)//小於  則用a=b-a,返回-1
    { for(i=1;i<=b[0];i++)       {  if(b[i]<a[i]){ b[i+1]--;b[i]+=10;} //若不夠減則向上借一位
        a[i]=b[i]-a[i];}
      a[0]=b[0];
     while(a[a[0]]==0) a[0]--; //修正a的位數
    return -1;}
}
五、高精度乘法1(高精度乘單精度數,單精度數是指通常的整型數)
int multi1(int a[],long  key) //a=a*key,key是單精度數  
{
int i,k;
if (key==0)
{
memset(a,0,sizeof(a));
a[0]=1;
return 0;
} //單獨處理key=0
for(i=1;i<=a[0];i++)a[i]=a[i]*key;//先每位乘起來
for(i=1;i<=a[0];i++){a[i+1]+=a[i]/10;a[i]%=10;} //進位
//注意上一語句退出時i=a[0]+1
while(a[i]>0)
{
a[i+1]=a[i]/10;
a[i]=a[i]%10;
i++;
a[0]++];
}  //繼續處理超過原a[0]位數的進位,修正a的位數
return 0;
}

int multi2(int a[],int b[]) //a=a*b
{
}

相關文章