承接前文「比較操作、絕對值加法、絕對值減法」,本文將這些基礎組件組裝,實現完整的有符號大整數加減法。核心思想是「分類討論,化繁為簡」。
設兩數為 x、y,結果為 z。
|z| = |x| + |y||z| = ||x| - |y||,用大減小|x| = |y| 時結果為 0,但可能出現 -0,需強制修正符號為正int bn_add_bn(bignum *z, const bignum *x, const bignum *y) {
int ret, sign = x->sign;
if (x->sign == y->sign) { // 同號
BN_CHECK(bn_add_abs(z, x, y));
z->sign = sign;
} else { // 異號
if (bn_cmp_abs(x, y) >= 0) { // |x| >= |y|
BN_CHECK(bn_sub_abs(z, x, y));
z->sign = sign;
} else { // |x| < |y|
BN_CHECK(bn_sub_abs(z, y, x));
z->sign = -sign;
}
}
if (BN_IS_ZERO(z)) z->sign = 1; // 消除 -0
return ret;
}
減法可轉化為加法:x - y = x + (-y),但直接實現更高效。
x - (-y) = x + y,結果符號同 x。
大減小,結果符號由絕對值大小決定,同樣需處理 -0。
int bn_sub_bn(bignum *z, const bignum *x, const bignum *y) {
int ret, sign = x->sign;
if (x->sign != y->sign) { // 異號
BN_CHECK(bn_add_abs(z, x, y));
z->sign = sign;
} else { // 同號
if (bn_cmp_abs(x, y) >= 0) {
BN_CHECK(bn_sub_abs(z, x, y));
z->sign = sign;
} else {
BN_CHECK(bn_sub_abs(z, y, x));
z->sign = -sign;
}
}
if (BN_IS_ZERO(z)) z->sign = 1;
return ret;
}
將單精度數 y 封裝為臨時 bignum,複用上述邏輯:
int bn_add_int(bignum *z, const bignum *x, bn_sint y) {
bignum t; bn_digit p[1];
p[0] = (y >= 0) ? y : -y;
t.used = (y != 0) ? 1 : 0;
t.sign = (y >= 0) ? 1 : -1;
t.dp = p; t.alloc = 1;
return bn_add_bn(z, x, &t);
}
#define BN_IS_ZERO(x) ((x->used == 0) ? 1 : 0)
有符號加減法的本質是「符號分類 + 絕對值運算」。通過復用 bn_add_abs、bn_sub_abs、bn_cmp_abs 三大基石,結構清晰、邊界處理完善。下一步將進入更複雜的乘法優化領域。