上篇介紹了基礎的表示結構以及函數介紹,本篇將開始介紹加減實現的過程。
由於整數有正負之分,所以兩個整數相加有四種情況:a+b,a+(-b),(-a)+b和-a+(-b)。
對於a+b和-a+(-b),可以通過對數組對應位元素相加即可,主要是考慮進位問題。而a+(-b)和(-a)+b,
其實就是兩個大整數的減法,其主要考慮的問題是向高位借位的問題。所以減法可以通過加法的運算得到結果。
1、符號相同的加法運算
符號相同的加法運算的實現過程是基於這樣的一個原因:因爲兩個整數的符號相同,可以直接對兩個整數數組對應位元素相加,並考慮進位問題。因爲兩個整數的數位存在以下三種情況(不妨設兩個大整數分別爲src1和src2):src1->length == src2->length;src1->length > src2->length; src1->length < src2->length。所以在處理加法的時候,對數位較大的整數一分爲二,第一部分是跟另一大整數的長度相等。可以先把相同長度部分先計算,然後再對多出的長度部分直接賦值,這樣可以不用考慮誰大誰小問題,而且可以加快運算速度。如下表所示:
分段運算過程:
1 2 3 |
4 5 6 7 8 9 |
— — — |
4 5 6 7 8 9 |
— — — |
9 1 3 5 7 8 |
1 2 3 |
9 1 3 5 7 8 |
2、符號不同的加法運算,即減法運算
符號不同的加法運算的過程,也是跟符號相同的加法過程類似。也是對數位較大的整數進行分段,不過,它也有不同的地方。因爲符號不相同,這個加法就是減法。因爲不知道是哪個大整數較大,當它們做減法運算的時候,就有可能會在最高數位出現負數問題,而大整數各位元素都爲正數,所以要多處理一步,即對負數轉換成正整。而如果把無符號整數的較大者作爲被減數,就可以省略這一步。所以此運算過程是:先對兩個大整數進行無符號比較,最大者作爲被減數,然後進行減法操作。
/*
加法運算
*/
int addHBInt(HBigInt* dst, HBigInt* src1, HBigInt* src2){
long dstlen=0, len=0, i;
un_short mark = 0; //進位標誌
un_short result; //數組對應元素相加結果
HBigInt *pSrc=NULL;
len = (src1->length >= src2->length) ? src1->length : src2->length;
dstlen = len;
if(FAILE_MEMORY_BINT == extendHBInt(dst,len)) return FAILE_MEMORY_BINT;
//較小數位的整數的長度
len = (src1->length>src2->length) ? src2->length : src1->length;
//對兩個大整數的數位相同部分進行計算
for(i = 0; i < len; i++) {
result = src1->pBigInt[i] + src2->pBigInt[i] + mark;
dst->pBigInt[i] = (result & 0xffff);
mark = result >> 16;
}
//對較大的大整數數位多出部分進行計算
pSrc = (src1->length > src2->length) ? src1 : src2;
while(i < pSrc->length) {
result = pSrc->pBigInt[i] + mark;
dst->pBigInt[i] = result & 0xffff;
mark = result >> 16;
i++;
}
if(mark) {
dst->pBigInt[i] = mark;
dstlen = pSrc->length + 1;
}
dst->sign = src1->sign;
dst->length = dstlen;
return RETURN_OK_BINT;
}
/*
減法運算(保證是同號相減,否則採用加法實現)
*/
int subHBInt(HBigInt* dst, HBigInt* src1, HBigInt* src2) {
long i=0,len_max = 0,len_min=0 ;
un_short *psrc_max,*psrc_min,*pdst;
long dstlen = dst->alloclen; //目標數組分配的最大值
un_short mark = 0; //借位標誌
<span style="white-space:pre"> </span>long result = 0; //數組對應元素相加結果
int sign = src1->sign; //整數的符號
int re;
len_max = (src1->length >= src2->length) ? src1->length : src2->length;
len_min = (src1->length > src2->length) ? src2->length : src1->length;
psrc_max=src1->pBigInt;
psrc_min=src2->pBigInt;
pdst = NULL;
if(FAILE_MEMORY_BINT == extendHBInt(dst,len_max)) return FAILE_MEMORY_BINT;
re = compareHBInt(src1,src2); //對兩個大整數進行無符號比較
// 兩個大整數大小相等,進行加法運算後位0
if(re == 0) {
dst -> length = 0;
dst -> sign = 1;
return RETURN_OK_BINT;
}
// src2比src1大,交換臨時指針變量,保證psrc1始終大於psrc2
if(re == -1) {
sign = -1;
psrc_max = src2->pBigInt;
psrc_min = src1->pBigInt;
len_min = src1->length;
}
// 對兩整數相同長度部分進行計算
for(i=0; i<len_min; i++) {
if((result = (psrc_max[i]-psrc_min[i]-mark))<0) mark = 1; // 向高一位借1
else mark = 0;
if(mark) result += CARRY_RADIX; //高位借1後,該值變成正值
dst->pBigInt[i] = result;
}
// 對數位較大部分的借位計算
while(i < len_max) {
result = psrc_max[i] - mark;// 給低位借走1
if(result >= 0) {
dst->pBigInt[i++] = result;
//mark = 0;
break; // 剩餘高位直接賦值,不需要再循環處理
} else { //表示向高一位借了1
dst->pBigInt[i++] = result + CARRY_RADIX;
}
}
// 剩餘高位直接賦值
memcpy(dst->pBigInt+i,psrc_max+i,sizeof(un_short)*(len_max-i));
dst->length = len_max;
dst->sign = sign;
trimHBInt(dst); //對結果去掉前面的0,當最高位爲0時,需要修改length的值
return 1;
}
說明:以上函數中使用到的其他函數,例如extendHBInt和assignHBInt等將在系列介紹完大整數運算結束後將代碼貼出。