#include // 缺少標頭檔名稱
int main() {
int i, w = 1;
float e = 1.0, s;
for (i = 1; i <= 20; i++) {
w = w * i; // w 為 int,13! = 6227020800 超過 32 位有號整數範圍 → 溢位
s = 1 / w; // 整數除法:1 / w (w>1 時結果為 0),非浮點除法
e += s;
}
printf("\ne=%f", e);
return 0;
}
| 錯誤 | 說明 | 後果 |
|---|---|---|
| 標頭檔缺失 | #include 後無檔案名 | 編譯錯誤 |
| 整數溢位 | w 為 int,13! 超過 INT_MAX (2,147,483,647) | 未定義行為,數值環繞變負或零 |
| 整數除法 | 1 / w 兩邊皆整數,C 語言執行整數除法,結果截斷為整數 | w>1 時 s=0,w=0 時觸發 Divide Error (除零中斷) |
當 i=13 時,w = 13! 溢位導致 w = 0(或負數後續乘法變 0)。接著 s = 1 / 0 觸發硬體除零例外,程式被作業系統終止,顯示 Divide Error 或 Floating point exception。
#include <stdio.h>
int main() {
int i;
double e = 1.0; // 用 double 提高精度,e = 1 + 1/1! + 1/2! + ... + 1/20!
double term = 1.0; // 當前項 1/i!
for (i = 1; i <= 20; ++i) {
term /= i; // term = 1/i! 避免大數階乘溢位,累除更穩定
e += term;
}
printf("e = %.15f\n", e); // e ≈ 2.718281828459045
return 0;
}
double 而非 float:雙精度 15-16 位有效數字,單精度僅 6-7 位,計算 e 需高精度。term /= i 計算 1/i!,完全避開整數溢位與大數除法。term 為 double,term / i 自動提升為浮點除法。int main() 返回 0。e = Σ (1/k!) from k=0 to ∞ = 1 + 1/1! + 1/2! + 1/3! + ...
本題計算前 21 項 (k=0..20),雙精度下已達機器精度極限。
| 錯誤寫法 | 問題 | 正確寫法 |
|---|---|---|
int w; w=w*i; s=1/w; | 整數溢位 + 整數除法 | double term=1; term/=i; e+=term; |
float w; s=1/w; | 1 為整數,仍是整數除法後轉浮點 | s=1.0/w; 或 s=1.0f/w; |
s=1/w; 後 w=0 | 除零硬體異常 | 演算法避免分母為零 |
void main() | 非標準 | int main() |
-Wall -Wextra 會提示「integer division in floating point context」或「division by zero」。run 崩潰後 bt 查看堆疊,print w 觀察變數值。printf("i=%d, w=%d, s=%f\n", i, w, s); 即可看到 w 變 0 的瞬間。-fsanitize=undefined 可捕捉除零、溢位等 UB。Divide Error 本質是 整數除以零觸發硬體異常。本題根因在於 整數階乘溢位導致分母變零,配合 整數除法語意誤解。修正核心:用浮點遞推避開大數運算,這是數值計算的基本功。