日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

大数除法(超长整数运算除法器)详解

發布時間:2023/12/20 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大数除法(超长整数运算除法器)详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在大數運算中,比較難實現的應該是高精度/高精度的除法器。

目錄

一、原理

二、具體代碼解析

三、超長整數運算


一、原理

1.大數存儲

????????先說說大數在C語言程序中是怎么存儲的。我們使用長度為N的int數組來存儲無符號超長整數,其中數組每個元素存儲的值上限為M。如下:???????

#define M 10000 //M進制,int數組每個元素取值上限 #define N 5 //數組長度 int x[N]={0};

?????????因為int類型最多表示10位有效數字(最大值為2147483648),當兩個有效位數為5的int類型變量相乘時其結果可能溢出,為了便于乘法器的實現M取值最好小于10000?

????????舉個例子,當我們要用x存儲一個無符號超長整數6543210435135314時,數組x的值是這樣的:x[0]=5314,x[1]=3513,x[2]=2104,x[3]=6543,x[4]=0。

2.除法算法

除法操作數的關系如下:

????????被除數/除數=商......余數,其中被除數=商*除數+余數

首先除數不能為0;

當被除數為0時,商為0;

當被除數小于除數時,商為0,余數為被除數;

當被除數等于除數時,商為1,余數為0;

?……

1)日常生活中,我們是這樣算除法的:

?

2)但是在大數除法中,我們不能直接這么算。例如:對于1234 5678 9000 / 1 2345,計算機沒法直接計算1234 5678 / 1 2345的結果。

3)在計算機中,減法的實現要比除法簡單得多,因此我們考慮把除法轉變成減法來計算。例如:對于7894/32,我們有:

?

通過被除數不斷地減去除數,我們得到了余數22,而除數被減的次數就是商246。?

4)現在我們已經知道了如何在計算機中把除法轉變成減法來運算,但一個除數一個除數的減實在太慢了,那么有沒有更快的算法呢?答案是肯定的,我們可以通過移位來加快“減”的速度,例如:

?

?如圖,7894=32*2*100+32*4*10+32*6*1+22,一共減去了2*100+4*10+6*1=246個32,所以7894/32的商為246。


二、具體代碼解析

1.首先函數原型如下:

#define M 10000 //M進制,int數組每個元素取值上限 #define N 5 //數組長度 int div2(int n1[],int n2[],int quotient[]); /* 大數除法:無符號高精度整數/無符號高精度整數,n1為被除數,n2為除數,quotient為商。函數正確執行時返回整數1 */

此外還涉及到這些函數:?

int add(int num1[],int num2[],int sum[]); /* 大數加法 */ int sub(int num1[],int num2[],int difference[]); /* 大數減法 */ int mul(int num1[],int num2[],int product[]); /* 大數乘法 */ int div(int num1[],int num2,int quotient[]); /* 大數除法:無符號高精度整數/無符號低精度整數,其中num2>0且num2<=M */ int cmp(int num1[],int num2[]); /* 大數比較,num1>num2時return1,小于時返回-1,等于時返回0 */

?2.異常值處理

????????因為我們這里存儲的是無符號超長整數,參與運算的操作數也應該是無符號,并且數組的每個元素應該小于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;//運算正確 }

????????這里說明一下為什么函數不直接用n1、n2參與運算,這是因為這個函數div2傳遞的參數都是指針,而接下來的算法將會改變被除數的值。為防止函數結束后被除數的值被改變,所以新定義了和n1、n2值相等的兩個局部變量num1、num2。

3.特殊值處理

????????包含以下特殊情況的處理:?(1)首先除數不能為0;(2)當被除數為0時,商為0;(3)當被除數小于除數時,商為0;(4)當被除數等于除數時,商為1。

/*----特殊值處理----*///檢查除數是否為0for(i=N-1;i>=0&&(num2[i]==0);i--);//從高位開始尋找num2首個不為0的下標if(i<0){printf("除數不能為0\n");return -1;}//被除數小于除數if((flag=cmp(num1,num2))==-1){quotient[0]=0;return 1;}//被除數等于除數else if(flag==0){quotient[0]=1;return 1;} /*---特殊值處理end---*/

?//別忘了在前面聲明flag!

4.處理完上述特殊情況,剩下的就是被除數大于除數的情況了,從這里開始就是算法的核心部分。

????????首先,為了加快減的速度,我們要盡可能地把除數左移。因為M取值10000,num2[i]有效位數為4,我們先4位(十進制位)4位(十進制位)的左移,直到除數num2大于被除數num1時停止。接下來把除數1位(十進制位)1位(十進制位)地右移,直到num1>num2時停止。這時,被除數num1剛好大于除數num2。?

/*---計算除數最大移位---*/if(num2[N-1]>0)flag=0;//flag=0表示除數不能移位,因為最高位>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++;//左移次數+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;//如果除數num2大于被除數num1,右移1位}counts=counts-i;//此時counts為除數左移位數 /*--計算除數最大移位end--*/

//這里左移一個10進制位是用高精度整數/低精度整數除法div實現的

//counts為num2左移位數(十進制位),別忘了在前面聲明!

5.計算被除數減去除數的次數

for(;counts>=0;counts--){if(cmp(num1,num2)>=0){//除數num2左移counts位時,num1最多能減去num2的次數times:for(times=0;times<M&&(cmp(num1,num2)>=0);times++){sub(num1,num2,num1);}//除數num2左移counts位時,被除數最多能減去除數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;}//“減”的次數:if(add(quotient,t,quotient)!=1) return -1;}if(div(num2,10,num2)!=1) return -1;//除數右移1位 }

?//別忘了在前面聲明times、t、m!

6.完整的div2函數定義如下:

#define M 10000 //M進制,int數組每個元素取值上限 #define N 5 //數組長度 //函數聲明: 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[]); /* ===無符號超長整數 除法=== quotient=n1/n2 高精度整數/高精度整數 */ 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;}/*----特殊值處理----*///檢查除數是否為0for(i=N-1;i>=0&&(num2[i]==0);i--);//從高位開始尋找num2首個不為0的下標if(i<0){printf("除數不能為0\n");return -1;}//被除數小于除數if((flag=cmp(num1,num2))==-1){quotient[0]=0;return 1;}//被除數等于除數else if(flag==0){quotient[0]=1;return 1;}/*---特殊值處理end---*//*---計算除數最大移位---*/if(num2[N-1]>0)flag=0;//flag=0表示除數不能移位,因為最高位>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++;//左移次數+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;//如果除數num2大于被除數num1,右移1位}counts=counts-i;//此時counts為除數左移位數/*--計算除數最大移位end--*/for(;counts>=0;counts--){if(cmp(num1,num2)>=0){//除數num2左移counts位時,num1最多能減去num2的次數times:for(times=0;times<M&&(cmp(num1,num2)>=0);times++){sub(num1,num2,num1);}//除數num2左移counts位時,被除數最多能減去除數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;}//“減”的次數:if(add(quotient,t,quotient)!=1) return -1;}if(div(num2,10,num2)!=1) return -1;//除數右移1位}return 1;//運算正確 }

三、超長整數運算

? ? ? ? 如果需要大數運算的完整代碼(包括輸入輸出、加減乘除函數),可以參考我的另一篇文章:超長整數運算——從斐波那契數列說起?的<無符號超長整數運算>部分。

總結

以上是生活随笔為你收集整理的大数除法(超长整数运算除法器)详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。