【C++高精度演算法】
阿新 • • 發佈:2019-02-10
前言:由於計算機運算是有模運算,資料範圍的表示有一定限制,如整型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 5 6 7 8 9
內容 4 5 8 4 3 0 0 0 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;//各位都相等則兩數相等。
}
三、高精度加法
void 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;
}
四、高精度減法
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)); //若a=b,則a=0,也可在return前加一句a[0]=1,表示是 1位數0
return 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(高精度乘單精度數,單精度數是指通常的整型數)
void Mul(int a[],long key) //a=a*key,key是單精度數
{
int i,k;
if (key==0)
{
memset(a,0,sizeof(a)); //單獨處理key=0
a[0]=1;
return 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[0]位數的進位,修正a的位數
a[i]=a[i]%10;
i++;
a[0]++;
}
}