1. 程式人生 > >大整數的四則運算(C語言實現)(2)——大整數的加法和減法運算

大整數的四則運算(C語言實現)(2)——大整數的加法和減法運算

斷斷續續調了好久個演算法的程式碼終於除錯好了,廢話不多說了,直接說思路,然後上程式碼。

上一篇文章介紹了大整數的輸入的處理,包括接收方式、儲存方式、前導零的處理等內容。本文接著上一篇的內容。簡述大整數加減運算的思路。

首先對於加法運算,存在以下四種情況:

              a     b 
1.   +    -    : 傳入相減函式,然後返回結果即可 


2.   -    +    : 交換兩個數,傳入相減函式,返回結果即可 


3.  +    +    : 直接傳入加法函式,返回結果即可 


4.  -     -    : 取反,執行相加函式 結果的符號儲存為負號 

由此可見,對不同情況的處理方法是不同的。顯而易見的不同之處在於對資料正負的判斷,這一點很好實現,因為我們大整數的結構體中有一個數據專門用於儲存資料的正負(包括零)。此外其實如果能判斷大整數的絕對值的大小,會使得邏輯變簡單,這裡不展開討論了,下面的程式碼有比較清楚的註釋,如果仔細研究下面的程式碼會知道其中的作用。

總結一下,在輸入輸出處理函式之外,為了完成大整數的加法,我們需要編寫的函式:

①大整數的分析判斷函式(不進行真正的加法運算,只做判斷分析及結果符號位的處理);

②大整數資料域相加函式(進行加法運算的函式);

③大整數資料域相減函式(進行減法運算的函式);

④兩數絕對值比較大小的函式;

對於減法運算:  a-b=a+(-b)

即對減數的符號位取反,然後呼叫加法函式即可。

除錯這段程式碼花費時間最多的地方是加法函式的進位處理和減法函式的借位處理。

文字不是重點,看程式碼:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 20	//最大可以處理二十位以內的數字的運算 
typedef struct bigint{
	char *num;	//大整數資料域 
	int sign;	//大整數符號位 
	int digit;	//大整數位數 
}BIGINT;

BIGINT ScanfBigInt();	//大整數的讀取處理函式 
void PrintBigInt(BIGINT BigInt);
void Add(BIGINT BigInt1,BIGINT BigInt2);
BIGINT AddTwoBigInt(BIGINT BigInt1,BIGINT BigInt2);
BIGINT SubTwoBigInt(BIGINT BigInt1,BIGINT BigInt2);
int CompareBigInt(BIGINT BigInt1,BIGINT BigInt2);
BIGINT Sum(BIGINT BigInt1,BIGINT BigInt2);
BIGINT Sub(BIGINT BigInt1,BIGINT BigInt2);

int main(void)
{
	BIGINT BigInt1,BigInt2;
	BIGINT BigIntResult;
	int key;
	
	printf("請輸入兩個大整數:\n");
	BigInt1=ScanfBigInt();
	printf("您輸入的第一個數是:");//測試程式碼 
 	PrintBigInt(BigInt1);	
 	
	BigInt2=ScanfBigInt();
 	printf("您輸入的第二個數是:");//測試程式碼
 	PrintBigInt(BigInt2);
	
	printf("請輸入序號選擇相應的操作:\n");
	printf("1.求兩個數的和。\n");
	printf("2.求兩個數的差。");
	
	while(1){
		scanf("%d",&key);
		switch(key){
			case 1:	BigIntResult=AddTwoBigInt(BigInt1,BigInt2);	break;
			case 2:	BigIntResult=SubTwoBigInt(BigInt1,BigInt2); break;
			default:printf("請輸入正確的序號!\n");				break;
		}
		if(key==1 || key==2){
			break;
		}
	}

	//結果輸出部分 
	printf("計算結果為:");
	PrintBigInt(BigIntResult);

	free(BigInt2.num);
	free(BigInt1.num);
	return 0;
}

/*     a  b 
	1. +  - :傳入相減函式,返回結果即可。 
	2. -  + :交換兩個數,傳入相減函式,返回結果即可。 
	3. +  + :直接傳入加法函式,返回結果即可。 
	4. -  - :取反 執行相加函式,結果的符號儲存為負號。 
*/

BIGINT AddTwoBigInt(BIGINT BigInt1,BIGINT BigInt2)
{
	BIGINT BigIntSum;
	char *swap;
	int flag;
	int digit,sign;
	flag=CompareBigInt(BigInt1,BigInt2);//比較兩數絕對值的大小 

	if(flag==-1){//1 比 2 小 (絕對值)則交換兩個數 
		swap=BigInt1.num;
		BigInt1.num=BigInt2.num;
		BigInt2.num=swap;
		 
		sign=BigInt1.sign;
		BigInt1.sign=BigInt2.sign;
		BigInt2.sign=sign;
		
		digit=BigInt1.digit;
		BigInt1.digit=BigInt2.digit;
		BigInt2.digit=digit;
	}//交換完成後BigInt1 >= BigInt2(絕對值)
	BigIntSum.num=(char *)malloc(sizeof(char)*(BigInt1.digit+2));
	BigIntSum.digit=BigInt1.digit;
	
	//兩數同號 
	if(BigInt1.sign==1 && BigInt2.sign==1){// + +  兩個正數相加   
		BigIntSum=Sum(BigInt1,BigInt2);
		BigIntSum.sign=1;
	}
	if(BigInt1.sign==-1 && BigInt2.sign==-1){// - -  兩個負數相加  
		BigIntSum=Sum(BigInt1,BigInt2);
		BigIntSum.sign=-1;
	}
	
	//兩數異號 
	if(BigInt1.sign+BigInt2.sign==0){
		if(flag==0){//b2==b1 結果為零  
			BigIntSum.sign=0;
			BigIntSum.digit=1;
			BigIntSum.num[0]='0';
		}
		else{//一定是b1>=b2
			BigIntSum=Sub(BigInt1,BigInt2);
		}
	}
	return BigIntSum;
}

/*   
	a-b = a+(-b)
*/
BIGINT SubTwoBigInt(BIGINT BigInt1,BIGINT BigInt2)
{
	BIGINT BigIntSub;
	BigInt2.sign=-BigInt2.sign;
	BigIntSub=AddTwoBigInt(BigInt1,BigInt2);
	return BigIntSub;
}

BIGINT Sum(BIGINT BigInt1,BIGINT BigInt2)//求和函式 
{
	BIGINT Int;
	int n,t;
	int i=0,j=0,cp=0;
	int k=0;
	t=BigInt1.digit > BigInt2.digit ? BigInt1.digit : BigInt2.digit;//取位數長的一個數為Int的數值域分空間 
	Int.num=(char *)malloc(sizeof(char)*(t+2));
	Int.digit=t; 
	t=0;
	//相加操作 BigInt1.num+BigInt2.num(注意BigInt1的絕對值大於BigInt2的絕對值) 
	while(i<BigInt1.digit || j<BigInt2.digit){
		if(i<BigInt1.digit && j<BigInt2.digit){//兩個都沒跑完 
			k=BigInt1.num[i++]-'0'+BigInt2.num[j++]-'0'+cp;
		}
		else{
			k=BigInt1.num[i++]-'0'+cp;
		}
		cp=k/10;
		Int.num[t++]=k%10+'0';//數字轉字元 
	}
	if(cp!=0){
		Int.num[t++]='1';
		Int.digit=Int.digit+1;	
	}
	return Int;
}

BIGINT Sub(BIGINT BigInt1,BIGINT BigInt2)//傳入的資料保證 BigInt1.num > BigInt2.num(絕對值)所以結果一定為正 
{
	BIGINT Int;
	int i,k;
	char temp;
	int digit1,digit2;
	int borrow=0;
	int key; 
	Int.num=(char *)malloc(sizeof(char)*(BigInt1.digit+2));	
	Int.sign=1;//返回數的結果一定為正 
	//公有的位數部分的相減操作 
	for(i=0;i<BigInt2.digit;i++){//迴圈的次數等於小的數的位數
		key=BigInt1.num[i]-BigInt2.num[i];
		if(key<0){//存在借位		
			Int.num[i]=10+key+'0'-borrow;
			borrow=1;
		}
		if(key>=0){//不存在借位 
			Int.num[i]=key+'0'-borrow;
			borrow=0;
		}
	}
	//下面處理BigInt1可能會多出的位數
	for(i=BigInt2.digit;i<BigInt1.digit;i++){
		Int.num[i]=BigInt1.num[i]-borrow;
		borrow=0;
	}
	//下面確定最後結果的位數 處理可能存在的前導0
	Int.digit=BigInt1.digit;
	for(k=Int.digit-1;k>=0 && Int.num[k]=='0';k--);
	if(k<Int.digit-1){//這個數有前導0 
		Int.digit=k+1;
	}
	return Int;
}

int CompareBigInt(BIGINT BigInt1,BIGINT BigInt2)//比較絕對值大小函式 
{
	int flag;
	int digit1,digit2;
	//digit1,digit2放到 最高位上
	digit1=BigInt1.digit-1;
	digit2=BigInt2.digit-1;
	if(digit1!=digit2){//位數不同 
		return digit1>digit2 ? 1 : -1 ;
	}
	while(digit1>=0){//位數相同 
		if(BigInt1.num[digit1]>BigInt2.num[digit1]){
			flag=1;
			break;
		}
		if(BigInt1.num[digit1]<BigInt2.num[digit1]){
			flag=-1;
			break;
		}
		digit1--;
	}
	if(digit1<0)//從while的條件退出迴圈 兩數相等 
	flag=0;
	return flag; 
}

BIGINT ScanfBigInt()//大整數的輸入處理 
{
	BIGINT BigInt;
	int bit,cnt;
	int i,j,k;
	char *tempnum=NULL;
	tempnum=(char *)malloc(sizeof(char)*(N+2));//多兩個空間,一個預留存負號,一個存'\0' 
	BigInt.num=(char *)malloc(sizeof(char)*(N+2));
	printf("請輸入大整數:");
	scanf("%s",tempnum);
	cnt=strlen(tempnum);
	BigInt.digit=cnt;	//確定大整數的位數
	if(tempnum[0]=='-'){//確定大整數的正負 
		BigInt.sign=-1;
		tempnum[0]='0';//把負號換成字元0,後面統一處理 
	}
	else{
		BigInt.sign=1;
	}
	for(i=0,j=cnt-1;i<cnt;j--,i++){//倒序儲存大整數的值 
		BigInt.num[j]=tempnum[i];
	}
	//處理可能存在的前導0 
	for(k=BigInt.digit-1;k>=0 && BigInt.num[k]=='0';k--);
	if(k<BigInt.digit-1){//這個數有前導0 
		BigInt.digit=k+1;
	}
	if(k==-1){//這個數是0
		BigInt.digit=1;
	}
	free(tempnum);
	return BigInt;
}

void PrintBigInt(BIGINT BigInt)//列印大整數  
{
	int j;
	if(BigInt.sign==-1){
		printf("-");
	}
	for(j=BigInt.digit-1;j>=0;j--){
		printf("%c",BigInt.num[j]);
	}
	printf("\n");
}


博主學生一枚,文章內容描述有不當之處歡迎大家指正,謝謝。