一.大數加法
定義兩個足夠大的數字,其數值遠超過long的取值范圍,設該大數的位數有兩百位,求其相加所得
大數加法的核心思想詳見此鏈接,內有詳細的動畫演示,這里不再贅述
直接上代碼:
#include<string.h> #include<stdio.h> #define N 10//定義當前一個足夠大的數字為10位,可任意更改 void print_num(int a[],int n) { int i=n-1;//從逆序數組的最后一項開始查找,進行反逆序 while(a[i]==0)//由於規定的數組比真實計算的數字大,所以數組最后幾位必定存在0的情況 --i;//這種情況下一定要將0舍去,否則會抬高數組的位數 for(;i>=0;i--)//找到非零的數組,進行反逆序輸出 printf("%d",a[i]); } void plus(int num1[],int num2[],int n) {//尤其注意!由於數組是逆序的,所以num[0]是個位,num[1]是十位,num[2]是百位 for(int i=0,up=0;i<n;i++)//算法參考小學加法,這里定義一個up進位標記 { int temp=num1[i]+num2[i]+up;//up最開始設為0,因為在個位無法獲取進位 num1[i]=temp%10;//若產生進位行為,則選取個位部分賦給num1 up=temp/10;//在個位上,若個位相加產生進位,則用temp/10取整加到下一次的十位上 } print_num(num1, n); } int main(){ char buffer1[]="123456";//緩沖數組,將當前數組倒序寫入num1中 char buffer2[]="78951234";//同上,寫入num2中 int num1[N]={0};//將num1,2全部置為0,用來將緩沖數組寫入到num數組當中 int num2[N]={0}; int n=N;//定義上述兩個數組的長度為10 for(int i=0,temp=(int)strlen(buffer1)-1;temp>=0;temp--) num1[i++]=buffer1[temp]-'0';//用倒序的方式將緩沖數組寫入num中,意味着num的第一位是個位,第二位是十位,三是百位... for(int i=0,temp=(int)strlen(buffer2)-1;temp>=0;temp--) num2[i++]=buffer2[temp]-'0'; plus(num1, num2, n);//將兩數字相加 printf("\n"); }
二.大數階乘
大數階乘的中心思想參考上述視頻和一篇博客,博客詳情:大數階乘運算
但是,這里需要說明一個點:
1*2=2,將2存到a[0]中,
接下來是用a[0]*3;
2*3=6,將6儲存在a[0]中,
接下來是用a[0]*4;
6*4=24,是兩位數,那么24%10==4存到a[0]中,24/10==2存到a[1]中,
接下來是用a[0]*5;a[1]*5+num(如果前一位相乘結果位數是兩位數,那么num就等於十位上的那個數字;如果是一位數,num==0)
24*5=120,是三位數,那么120%10==0存到a[0]中,120/10%10==2存到a[1]中,120/100==1存到a[2]中
由於上述博客存在某些地方沒有說清楚的情況,這里解釋一下
關於上述博客的Q&A:
1.這里的num指的是什么?
答:這里的num指的是前面兩數值相乘后進位數位多少:例如6*4得24,這里的num值的是24/10=2,進位數為2,num=2
2.下面代碼為什么要充i=2開始?
答:如果這里看懂了代碼其實理解2不是很難,但是沒有看懂是真的難懂:
首先明確一點:5的階乘是1*2*3*4*5,我定義的value數組的第一位為1,而我的i是從2起的,這樣以來不就直接湊出了1*2了嗎?當我的i自增到3,我直接在value數組中找出1*2的值,拿他們去和3相乘,也就湊成了1*2*3了
3.如何在代碼當中表現出進位的思想?
答:我們以5!為例,當計算到1*2*3*4的時候,value當中的表現形式是42000000,從左到右依次是個位,十位,百位,千位...etc
(value表示的是24這個數字)
我們在關於j的循環當中拿i=5去和value數組求乘積:
5先和位於個位的4求積得20:20%10得0,0放入個位中;20/10得2,進位為2,up=2。(此時個位為0)
j++后,5再和value中的value[1]=2做乘積並且加上up進制:5*2+2=12,12%10=2放入十位,12%10=1放入up中(此時十位為2)
j++后,5再和value中百位value[2]=0做乘積同時加上up:5*0+1=1,1%10=1放入百位,1/10=0放入up中(此時百位為1)
j++,5再和千位做運算,運算結果為0,重復上述循環一直到關於i=5的j循環結束,開始下一輪。
4.若上述舉例子的不再是5而是20呢?最后幾項如何處理
答:假設1*2...19為止其結果==‘56’(純假設),
那么最后一項如何處理:56*20?
首先拿個位6和20相乘得120,120%10得0,0放到個位;120/10得12,up=12;(個位為0)
十位5和20相乘+up=112,112&10=2,2放到十位,112/10得11,up=11;(十位為2)
百位0與20相乘+up=11,11&10=1放到百位,11/10=1,up=1;(百位為1)
千位0與20相乘+up=1,1&10=1放到千位,1/10=0,up=0;(千位為1)
下面全都是0了,循環一直持續到value數組的末尾,方法同上一致。
最后value數組為0211000000
倒序之后就是1120,即56*20的結果就是1120。
#define n 13 int main(){ int number=11;//定義要求階乘的數位number int value[n]={1}; //將存放number的階乘后結果的數組定義為value[]數組 //根據算法,階乘的第一項為1,因為階乘運算中最小的數字為1 for(int up=0,i=2;i<=number;i++)//定義倆變量up和i,up負責進制,i是階乘當中的數字,i逐漸增大 for(int j=0;j<n;j++)//我們是拿1*2*3*...,首先拿value[0]=1和2乘 { int temp=value[j]*i+up; value[j]=temp%10; up=temp/10; } int i=n-1;//value是一個倒序的數組,第一位是個位,所以輸出是需要倒置的 while(value[i]==0) --i; for(;i>=0;i--) printf("%d",value[i]); printf("\n"); }
三.大數乘法
兩個數值遠大於long long的表示范圍的數字相乘,用程序表示出來
這里我模擬正常運算的對位相乘思想,但是把最后一步相加進位的步驟單獨抽出來寫出來,用convert_normal函數表示
具體演示過程參考該視頻前幾分鍾的講解:高精度乘法
在傳統乘法中需要兩數值對位運算,例如357*384:
當位於個位上的4與7,5,3相乘的時候,其結果必須對應個位,十位,百位
當位於百位上的8與7,5,3相乘的時候,結果必須要對應十位,百位,千位
這也是為什么我要在multiply函數中引入k這個變量,k起到對位的作用。
這個算法當中,將最后一步(即3排數字的相加進位過程抽離出來,當讀寫成一個convert_normal函數)
在multiply函數中,result所得的結果直接將這三排數字對位相加,結果為28,76,73,39,9
接着在normal函數中這些數字全按照上面大數加法的思想轉化為正常數字
#include<string.h> #define N 10 void transition(char buffer[],int num[])//把輸入的數組從char類型轉為int類型 { for(int i=(int)strlen(buffer)-1,j=0;i>=0;i--) num[j++]=buffer[i]-'0'; } void bigdata_multiply(int num1[],int num2[],int after[])//大數乘法運算 {//函數模擬乘法的過程 for(int i=0;i<N;i++)//num1 { int k=i; for(int j=0;j<N;j++)//num2 after[k++]+=num1[i]*num2[j]; } } void print(int num[]) { int i=N-1; while(num[i]==0) --i; for(;i>=0;i--) printf("%d",num[i]); } void convert_normal(int number[])//轉換函數,將result數組中的數值轉化為正常數字 { for(int i=0,up=0;i<N;i++) { int temp=number[i]+up; number[i]=temp%10; up=temp/10; } } int main(){ char buffer1[N];//定義一個過渡數組 char buffer2[N]; int result[N]={0};//定義計算結果的數組 int num1[10]={0};//定義第一個數字 int num2[10]={0};//定義第二個數字 printf("num1="); scanf("%s",buffer1); printf("num2="); scanf("%s",buffer2); transition(buffer1, num1);//將num1,2數組逆置轉換為int數組 transition(buffer2,num2); bigdata_multiply(num1,num2,result); convert_normal(result); print(result); printf("\n"); }