大整数的四则运算
對一道A+B的題目,如果A和B的范圍在int范圍內(nèi),那么相信大家很快就能寫出程序。但是如果A和B是有著1000個(gè)數(shù)位的整數(shù),恐怕就沒有辦法用已有的數(shù)據(jù)類型來表示
這時(shí)就只能老實(shí)去模擬加減乘除的過程。怎么樣?聽起來像是小學(xué)生學(xué)的東西吧?實(shí)際上原理就是小學(xué)的,所以不要去害怕這個(gè)看上去很高深的東西。此外,大整數(shù)又稱為高精度整數(shù),其含義就是用基本數(shù)據(jù)類型無法存儲其精度的整數(shù)。
目錄
- 大整數(shù)的存儲
- 大整數(shù)的加法
- 大整數(shù)的減法
- 大整數(shù)的乘法
- 大整數(shù)的除法
大整數(shù)的存儲
很簡單,使用數(shù)組即可。例如定義int型數(shù)組d[1000],那么這個(gè)數(shù)組中的每一位就代表了存放的整數(shù)的每一位。如將整數(shù)235813存儲到數(shù)組中,則有d[0] =3, d[1]= 1, d[2]=8, d[3] =5, d[4] =3, d[5]=2,即整數(shù)的高位存儲在數(shù)組的高位,整數(shù)的低位存儲在數(shù)組的低位。不反過來存儲的原因是,在進(jìn)行運(yùn)算的時(shí)候都是從整數(shù)的低位到高位進(jìn)行枚舉,順位存儲和這種思維相合。但是也會由此產(chǎn)生一個(gè)需要注意的問題:把整數(shù)按字符串%s讀入的時(shí)候,實(shí)際上是逆位存儲的,即str[0] =‘2, st[]=’,… str[5]=3,因此在讀入之后需要在另存為至d[]數(shù)組的時(shí)候反轉(zhuǎn)一下。
而為了方便隨時(shí)獲取大整數(shù)的長度,一般都會定義一個(gè)int型變量len來記錄其長度,并和d數(shù)組組合成結(jié)構(gòu)體:
這里bign是big number
顯然,在定義結(jié)構(gòu)體變量之后,需要馬上初始化結(jié)構(gòu)體。為了減少在實(shí)際輸入代碼時(shí)總是忘記初始化的問題,
我們盡量在結(jié)構(gòu)體里寫一個(gè)構(gòu)造函數(shù)來初始化。
代碼如下:
構(gòu)造函數(shù)是用來初始化結(jié)構(gòu)體的函數(shù),函數(shù)名和結(jié)構(gòu)體名相同、無返回值,
因此非常好寫。大整數(shù)結(jié)構(gòu)體bign就變成了這樣:
這樣在每次定義結(jié)構(gòu)體變量時(shí),都會自動對該變量進(jìn)行初始化。
而輸入大整數(shù)時(shí),一般都是先用字符串讀入,然后再把字符串另存為至bign結(jié)構(gòu)體。
由于使用char數(shù)組進(jìn)行讀入時(shí),整數(shù)的高位會變成數(shù)組的低位,而整數(shù)的低位會變成數(shù)組的高位,
因此為了讓整數(shù)在bign中是順位存儲,需要讓字符串倒著賦給d[]數(shù)組:
如果要比較bign變量的大小,規(guī)則也很簡單:
先判斷兩者的len大小,
如果不相等,則以長的為大。
如果相等,則從高位到地位進(jìn)行比較,直到出現(xiàn)某一位不等,就可以判斷兩個(gè)數(shù)的大小。
下面的代碼直接依照了這個(gè)規(guī)則:
大整數(shù)的加法
由上圖可以歸納出對其中一位進(jìn)行加法的步驟:
將該位上的兩個(gè)數(shù)字與進(jìn)位相加,得到的結(jié)果取個(gè)位數(shù)作為該位的結(jié)果,取十位數(shù)作為新的進(jìn)位。
代碼如下:
下面是完整的A+B的代碼:
#include<cstdio> #include<cstring> struct bign {int d[1000];int len;bign(){memset(d,0,sizeof(d));len=0;} }; bign change(char str[])//將字符串轉(zhuǎn)換為bign {bign a;a.len=strlen(str);//bign的長度就是字符串的長度for(int i=0;i<a.len;i++){a.d[i]=str[a.len-i-1]-'0';//逆著賦值}return a; } int compare(bign a,bign b) {if(a.len>b.len) return 1;else if(a.len<b.len) return -1;else{for(int i=a.len-1;i>=0;i--)//從高位到低位比較{if(a.d[i]>b.d[i]) return 1;//只要有一位a大,則a大else if(a.d[i]<b.d[i]) return -1;//只要有一位a小,則a小}return 0;//兩數(shù)相等} } bign add(bign a,bign b) {bign c;int carry=0;//carry是進(jìn)位for(int i=0;i<a.len||i<b.len;i++){int temp=a.d[i]+b.d[i]+carry;//兩個(gè)對應(yīng)位與進(jìn)位相加c.d[c.len++]=temp%10;//個(gè)位數(shù)為該位的結(jié)果carry=temp/10;//十進(jìn)制為新的進(jìn)位if(carry!=0){c.d[c.len++]=carry;}}return c; } void print(bign a) {for(int i=a.len-1;i>=0;i--){printf("%d",a.d[i]);} } int main(void) {char str1[1000],str2[1000];scanf("%s %s",&str1,&str2);bign a=change(str1);bign b=change(str2);print(add(a,b));return 0; }最后指出,這樣寫法的條件是兩個(gè)對象都是非負(fù)整數(shù)。
如果有一方是負(fù)的,可以在轉(zhuǎn)換到數(shù)組這一步時(shí)去掉負(fù)號,然后采用高精度減法;
如果兩個(gè)都是負(fù)的,就都去掉負(fù)號后用高精度加法,最后再把符號加回去即可。
大整數(shù)的減法
同樣可以得到一個(gè)簡練的步驟:
對某一步,比較被減位和減位,如果不夠減,則令被減位的高位減1,被減位加10再進(jìn)行減法。
如果夠減,則直接減。
最后一步要注意減法后高位可能有多余的0,要去除它們,但也要保證結(jié)果至少有一位數(shù)。
代碼如下:
bign sub(bign a,bign b) {bign c;for(int i=0;i<a.len||i<b.len;i++)//以較長的為界限{if(a.d[i]<b.d[i])//如果不夠減{a.d[i+1]--;//向高位借位a.d[i]+=10;//當(dāng)前位加10}c.d[c.len++]=a.d[i]-b.d[i];//減法結(jié)果為當(dāng)前位}while(c.len-1>=1&&c.d[c.len-1]==0){c.len--;//去除高位的0,同時(shí)至少保留一位最低位}return c; }最后需要指出的是,使用sub函數(shù)前要比較兩個(gè)數(shù)的大小,如果被減數(shù)小于減數(shù),
需要交換兩個(gè)變量,然后輸出負(fù)號,再使用sub函數(shù)。
大整數(shù)的乘法
bign nulti(bign a,int b) {bign c;int carry=0;//進(jìn)位for(int i=0;i<a.len;i++){int temp=a.d[i]*b+carry;c.d[c.len++]=temp%10;//個(gè)位做為該位結(jié)果carry=temp/10;//高位部分作為新的進(jìn)位}while(carry!=0)//和加法不一樣,乘法的進(jìn)位可能不止一位{c.d[c.len++]=carry%10;carry/=10;}return c; }需要注意的是如果a和b中存在負(fù)數(shù),需要先記錄下來其負(fù)號,然后取它們的絕對值帶入函數(shù)。
大整數(shù)的除法
bign divide(bign a,int b,int& r)//高精度除法,r為余數(shù) {bign c;c.len=a.len;//被除數(shù)的每一位和商的每一位都是一 一對應(yīng)的,因此先令長度相等for(int i=a.len-1;i>=0;i--)//從高位開始{r=r*10+a.d[i];//和上一位遺留的余數(shù)組合if(r<b) c.d[i]=0;//不夠除,該位為0else//夠除{c.d[i]=r/b;//商r=r%b;//獲得新的余數(shù)}}while(c.len-1>=1&&c.d[c.len-1]==0){c.len--;//去除高位的0,同時(shí)至少保留一位最低位}return c; }在上述代碼中,考慮到函數(shù)每次只能返回一個(gè)數(shù)據(jù),而很多題目里面會經(jīng)常要求得到余數(shù),
因此把余數(shù)寫成"引用"的形式直接作為參數(shù)傳入,或是把r設(shè)成全局變量。
用了引用,其作用是在函數(shù)中可以視作直接對原變量進(jìn)行修改。
總結(jié)
- 上一篇: 质因子分解习题
- 下一篇: vector相关习题