有符號 32 位整數範圍:`[-2^31, 2^31-1]` = `[-2147483648, 2147483647]`。
加法溢出條件:
#include
#include
int32_t sat_add(int32_t x, int32_t y, int32_t* flag) {
int64_t sum = (int64_t)x + y; // 擴展到 64 位判斷,避免 UB
if (sum > INT32_MAX) {
if (flag) *flag = INT32_MAX; // 正溢出
return INT32_MAX;
}
if (sum < INT32_MIN) {
if (flag) *flag = INT32_MIN; // 負溢出
return INT32_MIN;
}
if (flag) *flag = 0; // 無溢出
return (int32_t)sum;
}
uint32_t sat_sub(uint32_t x, uint32_t y, int32_t* flag) {
if (x < y) { // 無符號下溢
if (flag) *flag = -1;
return 0; // 飽和到 0
}
if (flag) *flag = 0;
return x - y;
}
| 輸入 x | 輸入 y | 數學和 | 溢出類型 | 輸出結果 | 說明 |
|---|---|---|---|---|---|
| -2147483648 | -128 | -2147483776 | 負溢出 | -2147483648 (INT32_MIN) | 超出下界,飽和到最小值 |
| -2147483648 | -2147483648 | -4294967296 | 負溢出 | -2147483648 | 同理,注意:若用補碼環繞會得到 0,但飽和語義要求飽和 |
| 2147483647 | -128 | 2147483519 | 無 | 2147483519 | 範圍內 |
| 2147483646 | 1 | 2147483647 | 無 | 2147483647 | 恰好等於最大值 |
C 標準規定有符號整數溢出行為未定義,編譯器可假設不發生溢出並優化掉判斷代碼。因此不能寫 `if (x+y > INT_MAX)`,必須:
int32_t sat_add_fast(int32_t x, int32_t y, int32_t* flag) {
int32_t sum = x + y;
// 同號且結果號異於運算元 → 溢出
bool overflow = ((x ^ y) >= 0) && ((x ^ sum) < 0);
if (overflow) {
if (flag) *flag = (x > 0) ? INT32_MAX : INT32_MIN;
return (x > 0) ? INT32_MAX : INT32_MIN;
}
if (flag) *flag = 0;
return sum;
}