算法步驟:
(1)確定小數點位置,若沒有小數點,默認爲strlen(str);
(2)以小數點爲分界線,將兩個加數分別分割爲兩部分:
整數部分右對齊放入數組中,小數部分左對齊放入數組中。
(3)將兩個加數的小數部分和整數部分看成整數,模擬手算方法,分別相加求和;
(4)將求和之後的小數部分和整數部分連接在一起:
若小數數組首元素爲0,說明不用進位,直接相連;
若小數數組首元素爲1,說明要進位,將整數部分加1,然後同小數部分相連接。
代碼如下:
/* ---求兩個多位數數相加------2018年5月9日0:50:44 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N (100)//N表示兩個相加數的最大位數(包含小數點)
char * BigIntegerAdd(char*a1, char*a2);//求兩個大整數相加的和
char *BigNumberAdd(char*aa, char*bb);//求任意兩個多位數數相加的和(可帶或不帶小數點)
char*Connect(char*, char*);
void Split(const char*, char*, char*);
char*Sum(char*, char*);
int main(void)
{
char a1[N+1], a2[N+1];
char*result;
printf("Input two big numbers please:\n");
scanf("%s", a1);
scanf("%s", a2);
//result = BigIntegerAdd(a1, a2);
result = BigNumberAdd(a1, a2);
printf("\n\nThe result is:\n");
printf("%s\n", result);
return 0;
}
char* BigNumberAdd(char*aa, char*bb)
{
char a1[N + 1], a2[N + 1], b1[N + 1], b2[N + 1];
//初始化數組
for (int i = 0; i < N; ++i)
{
a1[i]=a2[i]=b1[i]=b2[i]='0';
}
a1[N] = a2[N] = b1[N] = b2[N] = '\0';
Split(aa,a1,a2);//將數拆分爲整數和小數部分
Split(bb, b1, b2);
char*r1=Sum(a1, b1);//求整數部分的和
char*r2 = Sum(a2, b2);//求小數部分的和
return Connect(r1, r2);//將整數部分與小數部分相連接
}
char * Connect(char*r1, char*r2)
{
/*
將存放在數組中的整數部分和小數部分合並,得到最終的計算結果
*/
char*result = (char*)malloc(sizeof(char)*(2*N));
for (int i = 0; i < 2*N-1; ++i)
result[i] = '0';
result[2*N-1] = '\0';
if (r2[0] != '0')//判斷小數部分和是否有進位
{
r1 = BigIntegerAdd(r1, "1");//整數部分加1,然後再合併
}
int n ;
for ( n = 0; n < N; ++n)
{
if (r1[n] != '0')
{
break;
}
}
int j = 0;
for (int i = n; i < strlen(r1) && j < 2*N-1; i++, j++)
result[j] = r1[i];
result[j++] = '.';
for (int i = 1; i < strlen(r2) && j < 2*N-1; i++, j++)
result[j] = r2[i];
return result;
}
void Split(const char*a, char*intPart, char*pointPart)
{
/*
將一個數拆分爲整數和小數部分,並放入數組中
*/
int n = strlen(a); //保存小數點位置
for (int i = 0; i < strlen(a);++i)
if (a[i] == '.')
{
n = i;
break;
}
for (int i = n - 1, j = N - 1; i>-1 && j > -1; --i, --j)//整數部分右對齊裝填到整數數組中
intPart[j] = a[i];
for (int i = n + 1, j = 0; i < strlen(a) && j < N; i++, j++)//小數部分左對齊裝填到小數數組中
pointPart[j] = a[i];
}
char* Sum(char*a1, char*a2)
{
/*
求以數組形式表示的兩個整數的和
*/
char*result = (char*)malloc(sizeof(char)*(N + 2));
for (int i = 0; i<N; ++i)
result[i] = '0';
result[N + 1] = '\0';
int m = 0;//m爲進位標誌 不進位m=0 進位m=1
int i = N - 1;
for (; i > -1; --i)//模擬手算過程 對裝填好的a1、a2數組進行求和,計算結果保存到result數組中
{
int tp = a1[i] - '0' + a2[i] - '0' + m;
if (tp >= 10)
{
result[i + 1] = tp - 10 + '0';
m = 1;
}
else
{
result[i + 1] = tp + '0';
m = 0;
}
}
if (i == -1 && m == 1)
result[i+1] = '1';
return result;
}
char * BigIntegerAdd(char*aa1, char*aa2)
{
/*
求兩個大整數的和,aa1、aa2爲表示兩個整數的字符串——2018年5月9日0:45:28
*/
char a1[N + 1], a2[N + 1];//因爲要設置尾標記“/0”所以申請的長度比最大位數N多一個字符
char *result=(char*)malloc(sizeof(char)*(N + 2));//因爲除了要設置標記"/0"以外,兩個N位數相加,和最大爲N+1位,所以申請N+2個字符
for (int i = 0; i<N; ++i)//初始化數組
{
a1[i] = '0';
a2[i] = '0';
result[i] = '0';
}
a1[N] = a2[N] = result[N + 1] = '\0'; //設置尾標記
for (int i = strlen(aa1) - 1, j = N - 1; i>-1 && j > -1; --i, --j)//將字符串形式的加數aa1裝填到數組a1中
{
a1[j] = aa1[i];
}
for (int i = strlen(aa2) - 1, j = N - 1; i>-1 && j > -1; --i, --j)//將字符串形式的加數aa2裝填到數組a2中
{
a2[j] = aa2[i];
}
int m = 0;//m爲進位標誌 不進位m=0 進位m=1
int i = N - 1;
for (; i > -1; --i)//模擬手算過程 對裝填好的a1、a2數組進行求和,計算結果保存到result數組中
{
int tp = a1[i] - '0' + a2[i] - '0' + m;
if (tp >= 10)
{
result[i + 1] = tp - 10 + '0';
m = 1;
}
else
{
result[i + 1] = tp + '0';
m = 0;
}
}
if (i == -1 && m == 1)
result[i+1] = '1';
return result;
}
感 悟:昨天完成了求兩個大整數的和的算法,然後就想嘗試把它擴展一下,求帶小數的“長數”的和,一開始寫這個算法的時候,覺得很簡單,在草稿紙上面大概演示了一下,就跟着上面的思想開始碼代碼了,碼完之後。用“59.6235+3.14”這組數據來測試,沒有問題。可是當我換成兩個純整數或兩個純小數,比如“59+65”、“0.12356+0.689”測試的時候,就出錯了。經過一番排查,原來是Split()函數裏面小數點的初值賦錯了(一開始int n=0),導致純整數的時候a1數組得不到字符串的整數部分。後面又測試了小數部分進位的數,如“0.99+0.35”幾組數據下來結果都比真實值小1,一開始以爲是Connect()裏面出錯了,設置斷點調試,發現r2[0]竟然等於0,而不是1。然後又去Sum()裏面看,才注意到如果兩個加數相加之後和的位數正好等於N的話,原來的代碼裏沒有進1。而且數組是左對齊,又恰好要進1的話正是需要進1而沒有進1這種情況,因此補充了判斷:if (i == -1 && m == 1) result[i+1] = '1'。
最後再囉嗦一下,爲什麼Connect()裏面的result要分配2N個字符,因爲一個N位的整數加上一個N位的小數(含小數點和前面的0),得到的結果有2N-1個字符,比如:N=6的情況下,789984+0.2554=789984.2554,兩個加數都是滿位6位,結果爲11位,再加上末尾的‘\0’正好是12位。若分配少了,Connect的時候小數部分就沒法全部連接上了。
嗯,暫時就這樣吧!如果發現問題,煩請指出,萬分感謝。