大數問題
一、基本觀念
在某些情況下,我們必須處理位數相當多的一個整數,例如 100 位數,系統內建的資料型態不管是 int、long int、long long int 等,位數顯然都不夠用。要解決這個問題,我們必須自己用程式來處理,最簡單的方法,就是模仿人工處理數字的方式,也就是把數字拆成一個位數一個位數,這個時候我們可以用一個陣列來完成這個動作。不過,這樣一來,所有對於這種超大整數的處理,包括輸入一個大數、兩個大數相加、印出一個大數等等,都需要我們自己寫一個函數來處理。至於這個陣列要用什麼樣的資料型態,因為兩個一位數相乘也不過才 81,所以我們可以用 char 的陣列來記錄一個超長整數,如:
char n[300];
就可以記錄 300 位數的資料。前面提到大數的輸入及輸出,都需要我們自己寫函數來處理,我們分別把它們定名為 Input() 及 Print():
#include <stdio.h>
#include <string.h>
#define LEN 300
int Input(char n[])
{
}
void Print(char n[])
{
}
void main()
{
char a[LEN];
Input(a);
Print(a);
}
上面第三行 #define LEN 300 的意思,即是定義一個常數叫做 LEN,而它的值是 300,下面用到 LEN 的地方,在執行的時候便會自動變成 300。這樣寫的好處是,如果我們有好個地方都用到 300 這個數字,但是後來發現不夠用了,要將它改成 1000,這個時候要一行一行改,還可能不小心漏掉,如果用 #define 定義一個常數,則只要改一個地方就行了。接下來我們看到 Input() 函數要做的步驟:
我們把上面提到的字串及超長整數的陣列做一個比較:
|
字串 |
|
||||||||||||||||||||
|
陣列 |
|
上面提到的 Input() 的程式碼可以寫成:
int Input(char n[])
{
char s[LEN];
int i, l;
for(i=0; i<LEN; i++)
n[i]=0;
if(scanf("%s", s)<1) return -1;
l=strlen(s);
for(i=0; i<l; i++)
n[i]=s[l-i-1]-'0';
return 0;
}
上面的 Input() 函數為了要得知是否有資料輸入,所以我們利用傳回值 0 代表輸入成功,傳回 -1 代表傳入失敗。至於 Print() 函數要做的步驟為:
它的程式碼可以寫成:
void Print(char n[])
{
int i;
for(i=LEN-1; i>0; i--)
if(n[i]!=0) break;
for(; i>=0; i--)
printf("%d", n[i]);
printf("\n");
}
寫成之後,我們可以先輸入一個約 60 位數的數字,看是不是可以正常印出結果。
二、大數相加
接下來我們來寫一個處理兩個大數相加的題目,接著上一段的程式,我們接下來要寫一個處理相加的函數 Add(),它的做法就跟小學時的加法運算一樣,從個位數開始,一個位數一個位數相加,如果有超過 10 的部分,就把它往前進位。例如:
|
大數 A |
|
||||||||||
|
大數 B |
|
||||||||||
|
相加 |
|
||||||||||
|
進位 |
|
下面的程式碼可以參考看看:
void Add(char a[], char b[], char c[])
{
int i;
for(i=0; i<LEN; i++)
c[i]=a[i]+b[i];
for(i=0; i<LEN-1; i++) {
if(c[i]>=10) {
c[i+1]+=c[i]/10;
c[i]=c[i]%10;
}
}
}
接下來把主程式 main() 改寫成:
void main()
{
char a[LEN], b[LEN], c[LEN];
Input(a);
Input(b);
Add(a, b, c);
Print(c);
}
三、#10106 ─ Product
題目:按這裡。
說明:每組測試資料有 2 列,分別代表 2 個大數 X、Y ( 0 <= X、Y < 10250),輸出 X*Y 的結果。
這一題的大數位數有 250 位,我們原先宣告的 LEN 有 300 所以已經夠用了。因為乘出來的積的最大位數為原來的兩倍,所以那一行 C[LEN] 要改成 C[LEN*2],而 Print() 函數裡面的 i=LEN-1 也要改成 i=LEN*2-1。接下來,我們要寫一個乘(Multiply)的函數 Mul(),它的做法就跟小學的乘法原理是一樣的,下面我們來看到它的程式碼:
void Mul(char a[], char b[], char c[])
{
int i, j;
for(i=0; i<LEN*2; i++)
c[i]=0;
for(i=0; i<LEN; i++) {
for(j=0; j<LEN; j++) {
c[i+j]+=a[j]*b[i];
if(c[i+j]>=10) {
c[i+j+1]+=c[i+j]/10;
c[i+j]=c[i+j]%10;
}
}
}
}
再把主程式改成:
void main()
{
char a[LEN], b[LEN], c[LEN*2];
Input(a);
Input(b);
Mul(a, b, c);
Print(c);
}
最後再改成連續輸入的寫法:
void main()
{
char a[LEN], b[LEN], c[LEN*2];
while(1) {
if(Input(a)) return;
Input(b);
Mul(a, b, c);
Print(c);
}
}