整數的高精度加、減法的實現
整數的高精度加、減法的實現
由於屑C++不自帶高精,所以常常無法處理一些大數的運算。最近我學習了高精度,將所學內容整理於此。其實是為了應付這週五的學習筆記。(我剛接觸C++,也是第一次用部落格,,如果有什麼錯誤請多多包涵,,)
- 為什麼要用高精度?
因為long long最大也只能存20位的數,強行輸入大數會爆 掉。
- 那要怎麼實現高精度計算?
那就用用字元陣列或string類儲存大數,然後根據小學生加減法原理進行加減乘除,得出結果。
接下來先對最簡單的高精度加法進行實現。
整數的高精度加法 (負數見減法部分)
先從離我們最近的入手:小學生加法原理
我們計算$a_1b_1c_1d_1+b_2c_2d_2$時,先是個位$d_1+d_2$,滿$10$進$1$,可以理解為滿$10$,就讓$d_1+d_2$的結果減去$10$,記為個位,下一次計算$c_1+c_2$時就同時加上一個$1$,如果滿$10$同上操作,記為十位。如果都不滿$10$,那就不減$10$也不進$1$。其他依次往前推。
這樣我們就不難得出整個演算法的核心:
c for (i=0;i<=c3;++i)
{
c[i]+=a1[i]+a2[i]; //a1,a2用來儲存兩個相加的數
c[i+1]=c[i]/10; //進位的實現
c[i]=c[i]%10;
}
那具體要怎麼實現?
輸入部分不必多說,輸入後我們必須先知道兩個字元陣列的最長的長度,由此來知道進行加法的最高位數,這也是字元陣列的便利所在:
c1=strlen(s1);
c2=strlen(s2);
len=max(c1,c2);
之後將字元陣列逆序賦值給整型陣列,為什麼呢?()
for (i=0;i<c1;++i) a1[i]=s1[c1-1-i]-'0';//要減去個‘0’ for(i=0;i<c2;++i) a2[i]=s2[c2-1-i]-'0';
之後就可以進行加法啦!
for (i=0;i<=len;++i)//這裡len為什麼要用等號?
{
c[i]+=a1[i]+a2[i];
c[i+1]=c[i]/10;
c[i]=c[i]%10;
}
然後逆序輸出,記得刪除前導0
if (c[len]==0) --len;//刪除前導0
for (i=len;i>=0;--i)
cout<<c[i];
這樣就大工造成啦!
附上我自己第一次做時候的程式碼:
#include <iostream> #include <cstring> using namespace std; int main() { char s1[505]={0},s2[505]={0}; int a1[505]={0},a2[505]={0},c[506]={0}; int i=0,c1=0,c2=0,c3=0; cin>>s1>>s2; c1=strlen(s1); c2=strlen(s2); c3=max(c1,c2); for (i=0;i<c1;++i) a1[i]=s1[c1-1-i]-'0'; for(i=0;i<c2;++i) a2[i]=s2[c2-1-i]-'0'; for (i=0;i<=c3;++i) { c[i]+=a1[i]+a2[i]; c[i+1]=c[i]/10; c[i]=c[i]%10; } if (c[c3]==0) { for (i=c3-1;i>=0;--i) cout<<c[i]; } else { for (i=c3;i>=0;--i) cout<<c[i]; } return 0; }
接下來是小學生減法(結果負數也得輸出,以下用string做答)
也先從原理入手:
嘛,,豎式減法,如果$\ a_1b_1c_1d_1-b_2c_2d_2$,先個位相減,也就是$\ d1-d2$,若小於$\ 0$,則讓$\ c_1$減去$\ 1$,再把$\ d1+d2$加上10,記為個位,然後進行$\ c_1-c_2$,如果結果大於$\ 0$,就直接記為十位,再進行$\ b_1-b_2$,依次往前推。
這樣可以得出:
for (i=0;i<lim;++i)//lim為兩個數中最高位的位數
{
ans[i]+=arr1[i]-arr2[i];
if (ans[i]<0)
{
--ans[i+1];
ans[i]+=10;
}
}
我用 --ans[i+1] 來實現退位。
然而這只是應付arr1中存的數比arr2中大的情況,那麼:
當arr1<arr2時,用swap進行交換,並用 bool flag 記錄結果正負
if (( n1=str1.size())==(n2=str2.size())&&str1<str2||n1<n2)
{
str1.swap(str2);//保證str1>=str2
flag=1;
}
這樣就可以隨意進行任意整數的加減了,其餘部分基本與加法一致。
搭嘎!刪除前導0這裡有坑:
- 和加法不一樣,減法的最高位數可能是多個0,可以用迴圈進行刪除:
while (ans[lim-1]==0) lim--;
- 如果結果等於 0 ,則要特殊考慮:
if (lim-1<0) cout<<0;
貼程式碼:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main()
{
string str1,str2;
int n1=0,n2=0,lim=0,i=0;//n用來存字串長度
bool flag=0;
int arr1[10500]={0},arr2[10500]={0},ans[10500]={0};
cin>>str1>>str2;
if (( n1=str1.size())==(n2=str2.size())&&str1<str2||n1<n2)
{
str1.swap(str2);//保證str1>=str2
flag=1;
}
n1=str1.size();
n2=str2.size();
for (i=n1-1;i>=0;--i) arr1[n1-1-i]=str1[i]-'0';
for (i=n2-1;i>=0;--i) arr2[n2-1-i]=str2[i]-'0';
lim=max(n1,n2);
for (i=0;i<lim;++i)
{
ans[i]+=arr1[i]-arr2[i];
if (ans[i]<0)
{
--ans[i+1];
ans[i]+=10;
}
}
while (ans[lim-1]==0) lim--;
if (flag==true) cout<<'-';
if (lim-1<0) cout<<0;
for (i=lim-1;i>=0;--i)
cout<<ans[i];
return 0;
}
順帶一提,我之前用字元陣列實現高精減法的是這個的2倍長
寫完之後感覺格式好亂,,,
高精度減法的實現我參考了這個
別人說的蠻詳細的,,不像我,,很多地方都懶得解釋