大數問題
一、基本觀念
在某些情況下,我們必須處理位數相當多的一個整數,例如 100 位數,系統內建的資料型態不管是 int、long int、long long int 等,位數顯然都不夠用。要解決這個問題,我們必須自己用程式來處理,最簡單的方法,就是模仿人工處理數字的方式,也就是把數字拆成一個位數一個位數,這個時候我們可以用一個陣列來完成這個動作。不過,這樣一來,所有對於這種超大整數的處理,包括輸入一個大數、兩個大數相加、印出一個大數等等,都需要我們自己寫一個函數來處理。至於這個陣列要用什麼樣的資料型態,因為兩個一位數相乘也不過才 81,所以我們可以用 char 的陣列來記錄一個超長整數,如:
char n[300];
就可以記錄 300 位數的資料。前面提到大數的輸入及輸出,都需要我們自己寫函數來處理,我們分別把它們定名為 Input() 及 Print() :
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······15001.#include <stdio.h>
02.#include <string.h>
03.#define LEN 300
04.int Input(char n[])
05.{
06.}
07.void Print(char n[])
08.{
09.}
10.void main()
11.{
12. char a[LEN];
13. Input(a);
14. Print(a);
15.}
#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() 函數要做的步驟:
1.把該陣列的每一格數字歸零。
2.將使用者輸入的數字以字串方式存到另一個字串。
3.計算該字串的長度。
4.從該字串的尾端(即個位數)開始一個一個位數往左,將它轉換成數字後,存到陣列對應的格子中。
我們把上面提到的字串及超長整數的陣列做一個比較:
字串
s[0]
s[1]
s[2]
s[3]
s[4]
s[5]
s[6]
s[7]
s[8]
s[9]
'1'
'2'
'3'
'4'
'5'
'6'
0
×
×
×
陣列
n[0]
n[1]
n[2]
n[3]
n[4]
n[5]
n[6]
n[7]
n[8]
n[9]
6
5
4
3
2
1
0
0
0
0
上面提到的 Input() 的程式碼可以寫成:
view plaincopy to clipboardprint?
01.int Input(char n[])
02.{
03. char s[LEN];
04. int i, l;
05. for(i=0; i<LEN; i++)
06. n[i]=0;
07. if(scanf("%s", s)<1) return -1;
08. l=strlen(s);
09. for(i=0; i<l; i++)
10. n[i]=s[l-i-1]-'0';
11. return 0;
12.}
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() 函數要做的步驟為:
1.從該陣列最後面往回找到第一個不是 0 的數字。
2.從該位數字往左邊依序把它們一個一個印出來。
3.印出換行符號。
它的程式碼可以寫成:
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······15001.void Print(char n[])
02.{
03. int i;
04. for(i=LEN-1; i>0; i--)
05. if(n[i]!=0) break;
06. for(; i>=0; i--)
07. printf("%d", n[i]);
08. printf("/n");
09.}
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
0
1
2
3
4
5
6
7
8
9
大數 B
0
1
2
3
4
5
6
7
8
9
相加
0
2
4
6
8
10
12
14
16
18
進位
0
2
4
6
9
1
3
5
7
8
下面的程式碼可以參考看看:
view plaincopy to clipboardprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······15001.void Add(char a[], char b[], char c[])
02.{
03. int i;
04. for(i=0; i<LEN; i++)
05. c[i]=a[i]+b[i];
06. for(i=0; i<LEN-1; i++) {
07. if(c[i]>=10) {
08. c[i+1]+=c[i]/10;
09. c[i]=c[i]%10;
10. }
11. }
12.}
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);
}
}