用字符串模擬手算求極大數和極小數的和

算法步驟:

(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的時候小數部分就沒法全部連接上了。

嗯,暫時就這樣吧!如果發現問題,煩請指出,萬分感謝。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章