大数除法(超长整数运算除法器)详解
在大數(shù)運算中,比較難實現(xiàn)的應(yīng)該是高精度/高精度的除法器。
目錄
一、原理
二、具體代碼解析
三、超長整數(shù)運算
一、原理
1.大數(shù)存儲
????????先說說大數(shù)在C語言程序中是怎么存儲的。我們使用長度為N的int數(shù)組來存儲無符號超長整數(shù),其中數(shù)組每個元素存儲的值上限為M。如下:???????
#define M 10000 //M進(jìn)制,int數(shù)組每個元素取值上限 #define N 5 //數(shù)組長度 int x[N]={0};?????????因為int類型最多表示10位有效數(shù)字(最大值為2147483648),當(dāng)兩個有效位數(shù)為5的int類型變量相乘時其結(jié)果可能溢出,為了便于乘法器的實現(xiàn)M取值最好小于10000?
????????舉個例子,當(dāng)我們要用x存儲一個無符號超長整數(shù)6543210435135314時,數(shù)組x的值是這樣的:x[0]=5314,x[1]=3513,x[2]=2104,x[3]=6543,x[4]=0。
2.除法算法
除法操作數(shù)的關(guān)系如下:
????????被除數(shù)/除數(shù)=商......余數(shù),其中被除數(shù)=商*除數(shù)+余數(shù)
首先除數(shù)不能為0;
當(dāng)被除數(shù)為0時,商為0;
當(dāng)被除數(shù)小于除數(shù)時,商為0,余數(shù)為被除數(shù);
當(dāng)被除數(shù)等于除數(shù)時,商為1,余數(shù)為0;
?……
1)日常生活中,我們是這樣算除法的:
?
2)但是在大數(shù)除法中,我們不能直接這么算。例如:對于1234 5678 9000 / 1 2345,計算機(jī)沒法直接計算1234 5678 / 1 2345的結(jié)果。
3)在計算機(jī)中,減法的實現(xiàn)要比除法簡單得多,因此我們考慮把除法轉(zhuǎn)變成減法來計算。例如:對于7894/32,我們有:
?
通過被除數(shù)不斷地減去除數(shù),我們得到了余數(shù)22,而除數(shù)被減的次數(shù)就是商246。?
4)現(xiàn)在我們已經(jīng)知道了如何在計算機(jī)中把除法轉(zhuǎn)變成減法來運算,但一個除數(shù)一個除數(shù)的減實在太慢了,那么有沒有更快的算法呢?答案是肯定的,我們可以通過移位來加快“減”的速度,例如:
?
?如圖,7894=32*2*100+32*4*10+32*6*1+22,一共減去了2*100+4*10+6*1=246個32,所以7894/32的商為246。
二、具體代碼解析
1.首先函數(shù)原型如下:
#define M 10000 //M進(jìn)制,int數(shù)組每個元素取值上限 #define N 5 //數(shù)組長度 int div2(int n1[],int n2[],int quotient[]); /* 大數(shù)除法:無符號高精度整數(shù)/無符號高精度整數(shù),n1為被除數(shù),n2為除數(shù),quotient為商。函數(shù)正確執(zhí)行時返回整數(shù)1 */此外還涉及到這些函數(shù):?
int add(int num1[],int num2[],int sum[]); /* 大數(shù)加法 */ int sub(int num1[],int num2[],int difference[]); /* 大數(shù)減法 */ int mul(int num1[],int num2[],int product[]); /* 大數(shù)乘法 */ int div(int num1[],int num2,int quotient[]); /* 大數(shù)除法:無符號高精度整數(shù)/無符號低精度整數(shù),其中num2>0且num2<=M */ int cmp(int num1[],int num2[]); /* 大數(shù)比較,num1>num2時return1,小于時返回-1,等于時返回0 */?2.異常值處理
????????因為我們這里存儲的是無符號超長整數(shù),參與運算的操作數(shù)也應(yīng)該是無符號,并且數(shù)組的每個元素應(yīng)該小于M。所以有:?
int div2(int n1[],int n2[],int quotient[]){ int i=0; int num1[N]={0},num2[N]={0};for(i=0;i<N;i++){ //異常值處理if(n1[i]<0||n2[i]<0||n1[i]>=M||n2[i]>=M){printf("div2():Operand are forbidden!\n");return -2;} //初始化:num1[i]=n1[i];num2[i]=n2[i];quotient[i]=0; } return 1;//運算正確 }????????這里說明一下為什么函數(shù)不直接用n1、n2參與運算,這是因為這個函數(shù)div2傳遞的參數(shù)都是指針,而接下來的算法將會改變被除數(shù)的值。為防止函數(shù)結(jié)束后被除數(shù)的值被改變,所以新定義了和n1、n2值相等的兩個局部變量num1、num2。
3.特殊值處理
????????包含以下特殊情況的處理:?(1)首先除數(shù)不能為0;(2)當(dāng)被除數(shù)為0時,商為0;(3)當(dāng)被除數(shù)小于除數(shù)時,商為0;(4)當(dāng)被除數(shù)等于除數(shù)時,商為1。
/*----特殊值處理----*///檢查除數(shù)是否為0for(i=N-1;i>=0&&(num2[i]==0);i--);//從高位開始尋找num2首個不為0的下標(biāo)if(i<0){printf("除數(shù)不能為0\n");return -1;}//被除數(shù)小于除數(shù)if((flag=cmp(num1,num2))==-1){quotient[0]=0;return 1;}//被除數(shù)等于除數(shù)else if(flag==0){quotient[0]=1;return 1;} /*---特殊值處理end---*/?//別忘了在前面聲明flag!
4.處理完上述特殊情況,剩下的就是被除數(shù)大于除數(shù)的情況了,從這里開始就是算法的核心部分。
????????首先,為了加快減的速度,我們要盡可能地把除數(shù)左移。因為M取值10000,num2[i]有效位數(shù)為4,我們先4位(十進(jìn)制位)4位(十進(jìn)制位)的左移,直到除數(shù)num2大于被除數(shù)num1時停止。接下來把除數(shù)1位(十進(jìn)制位)1位(十進(jìn)制位)地右移,直到num1>num2時停止。這時,被除數(shù)num1剛好大于除數(shù)num2。?
/*---計算除數(shù)最大移位---*/if(num2[N-1]>0)flag=0;//flag=0表示除數(shù)不能移位,因為最高位>0for(counts=0;counts<N&&(flag>0);){//num2左移4位:for(i=N-1;i>0;i--)num2[i]=num2[i-1];num2[0]=0;counts++;//左移次數(shù)+4,counts+1flag=cmp(num1,num2);}counts=counts*4;for(i=0;i<counts&&(cmp(num1,num2)<0);i++){if(div(num2,10,num2)!=1) return -1;//如果除數(shù)num2大于被除數(shù)num1,右移1位}counts=counts-i;//此時counts為除數(shù)左移位數(shù) /*--計算除數(shù)最大移位end--*///這里左移一個10進(jìn)制位是用高精度整數(shù)/低精度整數(shù)除法div實現(xiàn)的
//counts為num2左移位數(shù)(十進(jìn)制位),別忘了在前面聲明!
5.計算被除數(shù)減去除數(shù)的次數(shù)
for(;counts>=0;counts--){if(cmp(num1,num2)>=0){//除數(shù)num2左移counts位時,num1最多能減去num2的次數(shù)times:for(times=0;times<M&&(cmp(num1,num2)>=0);times++){sub(num1,num2,num1);}//除數(shù)num2左移counts位時,被除數(shù)最多能減去除數(shù)t=times*(10^counts)次:for(i=0;i<N;i++){t[i]=0;m[i]=0;}//初始化t、mt[0]=times;m[0]=10;for(i=0;i<counts;i++){if(mul(t,m,t)!=1)return -1;}//“減”的次數(shù):if(add(quotient,t,quotient)!=1) return -1;}if(div(num2,10,num2)!=1) return -1;//除數(shù)右移1位 }?//別忘了在前面聲明times、t、m!
6.完整的div2函數(shù)定義如下:
#define M 10000 //M進(jìn)制,int數(shù)組每個元素取值上限 #define N 5 //數(shù)組長度 //函數(shù)聲明: int add(int num1[],int num2[],int sum[]); int cmp(int num1[],int num2[]); int sub(int num1[],int num2[],int difference[]); int mul(int num1[],int num2[],int product[]); int div(int num1[],int num2,int quotient[]); /* ===無符號超長整數(shù) 除法=== quotient=n1/n2 高精度整數(shù)/高精度整數(shù) */ int div2(int n1[],int n2[],int quotient[]){int i=0,flag=1,counts=0,times=0;int t[N]={0},m[N]={0},num1[N]={0},num2[N]={0};for(i=0;i<N;i++){//異常值處理if(n1[i]<0||n2[i]<0||n1[i]>=M||n2[i]>=M){printf("div2():Operand are forbidden!\n");return -2;}//初始化:num1[i]=n1[i];num2[i]=n2[i];quotient[i]=0;}/*----特殊值處理----*///檢查除數(shù)是否為0for(i=N-1;i>=0&&(num2[i]==0);i--);//從高位開始尋找num2首個不為0的下標(biāo)if(i<0){printf("除數(shù)不能為0\n");return -1;}//被除數(shù)小于除數(shù)if((flag=cmp(num1,num2))==-1){quotient[0]=0;return 1;}//被除數(shù)等于除數(shù)else if(flag==0){quotient[0]=1;return 1;}/*---特殊值處理end---*//*---計算除數(shù)最大移位---*/if(num2[N-1]>0)flag=0;//flag=0表示除數(shù)不能移位,因為最高位>0for(counts=0;counts<N&&(flag>0);){//num2左移4位:for(i=N-1;i>0;i--)num2[i]=num2[i-1];num2[0]=0;counts++;//左移次數(shù)+4,counts+1flag=cmp(num1,num2);}counts=counts*4;for(i=0;i<counts&&(cmp(num1,num2)<0);i++){if(div(num2,10,num2)!=1) return -1;//如果除數(shù)num2大于被除數(shù)num1,右移1位}counts=counts-i;//此時counts為除數(shù)左移位數(shù)/*--計算除數(shù)最大移位end--*/for(;counts>=0;counts--){if(cmp(num1,num2)>=0){//除數(shù)num2左移counts位時,num1最多能減去num2的次數(shù)times:for(times=0;times<M&&(cmp(num1,num2)>=0);times++){sub(num1,num2,num1);}//除數(shù)num2左移counts位時,被除數(shù)最多能減去除數(shù)t=times*(10^counts)次:for(i=0;i<N;i++){t[i]=0;m[i]=0;}//初始化t、mt[0]=times;m[0]=10;for(i=0;i<counts;i++){if(mul(t,m,t)!=1)return -1;}//“減”的次數(shù):if(add(quotient,t,quotient)!=1) return -1;}if(div(num2,10,num2)!=1) return -1;//除數(shù)右移1位}return 1;//運算正確 }三、超長整數(shù)運算
? ? ? ? 如果需要大數(shù)運算的完整代碼(包括輸入輸出、加減乘除函數(shù)),可以參考我的另一篇文章:超長整數(shù)運算——從斐波那契數(shù)列說起?的<無符號超長整數(shù)運算>部分。
總結(jié)
以上是生活随笔為你收集整理的大数除法(超长整数运算除法器)详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目[P2P文件下载器]
- 下一篇: 以太网(Ethenet)协议