超大整數的加減乘除計算方法

My_name_is_ZwZ發表於2018-10-11

目錄

 

問題由來及解決思路:

超大整數的加法運算:

超大整數的減法運算:

超大整數的乘法運算:

超大整數的除法運算:


問題由來及解決思路:

在任何一種程式語言中,基本型別的資料都是具有一定的範圍的。例如:在Java中長整型long佔有8個位元組,即64位。那麼當兩個數足夠大,大到無法用long來定義的時候,如何進行他們的加減乘除這種簡單的運算?

在程式語言中用於儲存超級大的資料我們首先就會想到陣列。也就是用陣列的方式進行儲存,然後對陣列中的資料進行加減乘除的操作。

例如:

 思路:陣列中的每一位都相對應的加減,需要進位或借位的就使用一個變數進行記錄。

超大整數的加法運算:

以下是加法運算函式:

const int N=4;//定義陣列的長度為4 也可以更長,這個看自己計算的資料的大小
static int carry=0;//定義初始進位值
//加法函式 a,b,c是使用者呼叫此函式時傳來的陣列名 
void add(int *a, int *b, int *c)
{int i;
 //陣列的高位儲存的資料的低位 所以我們從i=N-1開始迴圈
 for(i = N - 1; i >= 0; i--)
  {c[i] = a[i] + b[i] + carry;
      carry=c[i]/10000;
      c[i]=c[i]%10000;
  }
}

 其就是在模擬平時的加法運算過程。按照低位到高位的順序對應的位相加,如果有進位就使用carry進行儲存,儲存之後當進入下一個迴圈也就是其相鄰的高位進行相加時在將carry加到高位上。

以下是得出加法結果存在於c[ ]之後的輸出函式:

void print(int *c,int k)//引數k指陣列的長度
{int i;
 for (i=0;i<k;i++)
    printf("%04d",c[i]);//不足四位的,前面補0輸出 
 printf("\n");
}

這裡一定要注意的一點就是:我們在進行加法運算的時候,陣列每一個地方儲存的數不一定是4位,例如上邊例子裡面的a[ ]陣列中,有一個地方儲存的是123,b[ ]陣列中有一個地方儲存的是456,在執行加法運算的時候這個是不影響的,但是輸出的時候我們要在它的前面補0。這也算是add函式使用時候的一個規定吧,就是說陣列的每一位上都要儲存4位數。如果不這樣子規定的話,使用者想在哪裡儲存多少就儲存多少的話就會亂掉。而且add函式中/10000和%1000也就沒有了它的道理所在(與N=4無關,N=4是規定這個陣列長度,而我們這裡說的4是指陣列中每一位上必須有4個數) 為了更好的理解這個問題,我們寫個main方法去呼叫一下這個add函式:

int main()
{//1234034523670098+213654305769786
 int i,d=123,a[N]={1234,345,2367,98},b[N]={213,6543,576,9786},c[N];
 //將c[]清零
 for (i=0;i<N;i++)
 {c[i]=0;}
 //呼叫add函式
 add(a,b,c);
 if (carry==1)
 printf("%d",carry);
 //呼叫print函式
 print(c,N);
}

超大整數的減法運算:

以下是減法運算函式:

const int N=4;//定義陣列的長度為4 也可以更長,這個看自己計算的資料的大小
int borrow=0;//用於儲存借位的變數
void sub(int *a, int *b, int *c) 
{int i;
 for(i =N- 1; i >= 0; i--) 
   {c[i] = a[i] - b[i] - borrow;
    if(c[i] >= 0)
       borrow = 0;
    else // 借位
      {c[i] = c[i] + 10000;
       borrow = 1;}
   }
}

則上面的sub函式就是模擬的下面這種減法運算的過程。讓陣列對應的每一組資料進行減法運算,然後將借位borrow記下,如果有借位,在下一次迴圈也就是它的相鄰的高位的資料進行減法運算時,將borrow減下來。就是我們平時做減法運算時候的一個過程。

以下是列印輸出函式(與加法運算時的列印輸出函式相同):

void print(int *c,int k)//引數k指陣列的長度
{int i;
 for (i=0;i<k;i++)
    printf("%04d",c[i]);
 printf("\n");
}

 我們寫一個main對其進行呼叫:

int main()
{int i,a[N]={1234,5678,3344,5566},b[N]={4321,8765,8899,7766},c[N];
 for (i=0;i<N;i++)
   {c[i]=0;}
 sub(a,b,c);
 if (borrow==0) 
     print(c,N);
 //對於執行完sub方法後的進位進行判斷,如果borrow!=0,表示a-b<0
 else
    {borrow=0;
     sub(b,a,c);printf("-");print(c,N);
    }
}

 超大整數的乘法運算:

以下是乘法運算的函式:

const int N=4;
static int carry=0;//儲存進位的變數
void mul(int *a, int b, int *c)
{ // b 為乘數且其數值較小,不屬於大整數的範圍
int i, tmp;
carry = 0;
for(i =N- 1; i >=0; i--) {
tmp = a[i] * b + carry;
c[i] = tmp % 10000;
carry = tmp / 10000;
}
}

以下是列印輸出函式:

void print(int *c,int k)
{int i;
 for (i=0;i<k;i++)
    printf("%04d",c[i]);
 printf("\n");
}

我們寫一個main對其進行測試:

int main()
{int i,d=123,a[N]={1234,5678,3344,5566},c[N];
 for (i=0;i<N;i++)
 {c[i]=0;}

 mul(a,d,c);
 //執行完mul後,如果carry!=0表示最高位上有了進位,那麼就要先把carry列印出來再呼叫print函式
 if (carry!=0) 
    printf("%d",carry);
 print(c,N);
}

  超大整數的除法運算:

以下是除法運算的函式:

const int N=4;
int remain=0;

void div(int *a, int b, int *c) 
{ 
  int i, tmp;
  //除法函式與其他三種不同的是它迴圈從i=0開始,因為a[0]處儲存的是資料的高位,而除法是從高位開始算起
  for(i =0; i <N; i++) 
  {
    tmp = a[i] + remain;
    c[i] = tmp / b;
    remain = (tmp % b) * 10000;
  }
}

以下是手動進行除法運算的過程:

 由以上除法運算過程大家可以看出除法是從高位向低位進行。為了更好的理解上邊的div函式,可以對其過程進行模擬,例如使用12347851 / 4列一個豎式。由實踐可知:tmp表示每次 / 4的那個數,而沒有除盡的話,是要把這個餘數加在後面的數上面接著/4,而remain就是用於儲存餘數的變數。

輸出函式:

void print(int *c,int k)
{int i;
 for (i=0;i<k;i++)
    printf("%04d",c[i]);
 printf("\n");
}

 寫一個main函式對其進行測試:

int main()
{int i,d=123,a[N]={1234,5678,3344,5566},c[N];
 for (i=0;i<N;i++)
 {c[i]=0;}
 div(a,d,c);
 print(c,N);
}

 

相關文章