**:
前言在很多情況下,c/c++所提供的基本資料型別已經不能滿足我們的需求了,所以我們需要一種方法來解決一些大數的運算,在小學進行加法運算的時候,無論資料是什麼,有多少位,都通通採取列豎式的方法進行計算並得出結果,本文將使用陣列模擬列豎式計算來解決大數的加法運算。
問題分析
首先我們先給定一組資料,來輔助說明整個計算過程
a = 987654321
b = 56789
計算 a + b 的結果
將兩個數字的每一位分別存入兩個陣列:因為所給定的資料不是很大,這裡就開闢長度為10的陣列進行說明,a陣列(a)用來儲存數字a的每一位,b陣列(b)用來儲存數字b的每一位,c陣列(c)用來儲存計算的結果(在程式中開闢乙個新的陣列,陣列的每一位都是隨機數,所以需要將陣列初始化,把陣列的每一位都賦值為0)。陣列0
1234
5678
9a98
7654
3210
b567
8900
000c
0000
0000
00我們通過某種方式將其存入了陣列中,從左往右觀察上面這個**,雖然我們想計算的是987654321 + 56789,但是存入陣列中後我們發現,現在已經無法分辨 a 和 b 的值了。
a 的值變成了9876543210?
b 的值變成了5678900000?
我們可以記錄下數字 a 最後一位所在陣列的位置,數字 b 最後一位所在陣列的位置,這樣雖然不會出現上面的問題了,但是在實際的計算過程中會很繁瑣,並伴隨著各種問題。接下來,我們換一種思路來將數字存入陣列(逆序存入),存入的結果如下表所示:陣列0
1234
5678
9a12
3456
7890
b887
6500
000c
0000
0000
00此時我們從右往左看這個表:
a = 0987654321 = 987654321
b = 0000056789 = 56789
這樣的結果才是我們所需要的,接下來我們繼續來模仿列豎式的方法進行計算,c[n] = a[n] + b[n] + c[n], 如果結果大於等於10,我們就向前進一位。
c[0] = a[0] + b[0] + c[0] = 1 + 9 + 0 = 10,結果等於10, 向前進一位,進製之後c[1] = 1,c[0] = 0;
c[1] = a[1] + b[1] + c[1] = 2 + 8 + 1 = 11,結果大於10,向前進一位,進製之後c[2] = 1, c[1] = 1;
c[2] = a[2] + b[2] + c[2] = 3 + 7 + 1 = 11,結果大於10,向前進一位,進製之後c[3] = 1, c[2] = 1;
重複這樣的操作,直到陣列的最後乙個元素。
執行完上述操作後,**變成如下所示:陣列0
1234
5678
9a12
3456
7890
b987
6500
000c
0111
1778
90現在我們從右向左觀察陣列c(c),每一位分別是0987711110,如果忽略前置0,結果就是98771110,這便是987654321 + 56789的結果。
以上就是大數加法的基本步驟了,實際上,我們並不需要陣列 c 進行輔助運算,前文中使用原因只是為了方便說明,如果不利用c陣列,那麼初始的表將會變成如下樣子:陣列0
1234
5678
9a12
3456
7890
b987
6500
000只需要將陣列a中的每乙個元素加到陣列b中,即b[n] = a[n] + b[n],再根據結果決定是否需要進製。
b[0] = a[0] + b[0] = 1 + 9 = 10,結果等於10,向前進一位,進製之後b[1] = 9, b[0] = 0;
b[1] = a[1] + b[1] = 2 + 9 = 11,結果大於10,向前進一位,進製之後b[2] = 8, b[1] = 1;
b[2] = a[2] + b[2] = 3 + 8 = 11,結果大於10,向前進一位,進製之後b[3] = 7, b[2] = 1;
重複這樣的操作,直到陣列的最後乙個元素。
執行完上述操作後,我們可以得到這樣乙個表:陣列0
1234
5678
9a12
3456
7890
b011
1177
890結果同樣是987711110
**實現
首先是如何逆序將資料存入陣列,我們可以在輸入資料的時候將 a 和 b 分別存入兩個字串,然後獲取字串的長度,從字串的最後乙個元素開始依次新增到陣列中,新增的時候只需要把字元減去字元0。
//這裡str1是字串,a是陣列
//逆序存入str1中的元素到a陣列
for(
int i =
strlen
(str1)-1
, j =
0; i >=
0; i--
) a[j++
]= str1[i]
-'0'
;//這裡str2是字串,b是陣列
//逆序存入str2中的元素到b陣列
for(
int i =
strlen
(str2)-1
, j =
0; i >=
0; i--
) b[j++
]= str2[i]
-'0'
;//執行完這兩個迴圈之後就完成了逆序存入的操作
2.相加和進製:兩個陣列的每一位都分別相加,再通過相加的結果判斷是否需要進製,maxn為陣列的長度,但是這樣的話,會有很多沒用意義的計算,就比如上文中的例子,a[9] + b[9]就是沒有意義的,後面會說到這個該如何優化。
//這裡的maxn是陣列的長度
for(
int i =
0; i < maxn; i++
)}
3.結果的輸出:因為輸出的時候需要從陣列的最後一位向前輸出,也就是說會有很多前置的零,上文中的例子,如果直接輸出的話結果就是0987711110,但是我們並不需要前置0,所以在輸出結果的時候應該過濾掉前置0,也就是說在輸出的時候從第乙個不為0的位置開始輸出,實現這個的方式有很多,我是用以下的方式實現的輸出:
//這裡的maxn同上
int i;
//注意:這個for迴圈有乙個分號
for(i = maxn -
1; i >=
0&& b[i]==0
; i--);
if(i >=0)
for(
; i >=
0; i--
) cout << b[i]
;else
cout <<0;
cout << endl;
下面是完整的**:
#include
#include
#include
using
namespace std;
const
int maxn =
1000
;char str1[maxn]
, str2[maxn]
;int a[maxn]
, b[maxn]
;void
sum()}
//輸出結果
int i;
//過濾掉前置0
for(i = maxn -
1; i >=
0&& b[i]==0
; i--);
if(i >=0)
for(
; i >=
0; i--
) cout << b[i]
;//如果儲存結果的陣列中全部為0,上面的操作會過濾掉所有的0,不會有輸出,所以這裡輸出乙個0
else
cout <<0;
cout << endl;
}int
main()
關於maxn
maxn是在程式中定義的乙個常量,但是在計算的過程中如果直接使用,會執行很多沒有意義的計算過程,我們可以這樣做乙個優化,定義乙個變數max,令max的值等於最長的字串長度 + 1,即:
max = max(strlen(str1), strlen(str2)) + 1;
加1的原因:n位+n位的結果可能會是n+1位,舉個例子來說,如果計算999+111,實際的結果應該是1110,如果不加1,那麼輸出的結果就是110。
用max替換sum()函式中的一些邊界值即可。
大數運算 加法(C C 實現)
前言 問題分析 將兩個數字的每一位分別存入兩個陣列 因為所給定的資料不是很大,這裡就開闢長度為10的陣列進行說明,a陣列 a 用來儲存數字a的每一位,b陣列 b 用來儲存數字b的每一位,c陣列 c 用來儲存計算的結果 在程式中開闢乙個新的陣列,陣列的每一位都是隨機數,所以需要將陣列初始化,把陣列的每...
大數運算 加法
include include include void add const char a,const char b,char c if carry 0 result result length carry 0 while result length 0 c result result length...
大數運算 加法
究竟為什麼要用大數加法呢。我們來看下資料 bool型為布林型,佔1個位元組,取值0或1。bool型為int型,一般認為佔4個位元組,取值true false error。sbyte型為有符號8位整數,佔1個位元組,取值範圍在128 127之間。bytet型為無符號16位整數,佔2個位元組,取值範圍在...