級數 Σ (1/n!) (n=1..∞) 收斂於 e - 1 ≈ 1.718281828...。本文實現高精度計算,分析原始碼的整數除法陷阱,提供雙精度與長雙精度驗證。
// 原始碼
double s=0, t=1;
for (n=1; n<=20; n++) {
t = t * (1/n); // 錯誤!1/n 為整數除法,n>1 時結果恆為 0
s = s + t;
}
// 實際運算:t 首項 1*1=1,第二項 1*0=0,後續全 0,結果 s=1.0
修正:1.0 / n 或 1 / (double)n 強制浮點除法。
#include <stdio.h>
#include <math.h> // M_E
int main() {
double sum = 0.0;
double term = 1.0; // 1/0! = 1,但題目從 1! 開始
for (int n = 1; n <= 20; n++) {
term /= n; // 遞推:1/n! = (1/(n-1)!) / n
sum += term;
}
printf("Σ(1/n!) n=1..20 = %.15f\n", sum);
printf("e - 1 = %.15f\n", M_E - 1.0);
printf("差值 = %.3e\n", fabs(sum - (M_E - 1.0)));
return 0;
}
Σ(1/n!) n=1..20 = 1.718281828459045 e - 1 = 1.718281828459045 差值 = 0.000e+00
term₁ = 1/1! = 1 term₂ = 1/2! = term₁ / 2 term₃ = 1/3! = term₂ / 3 ... termₙ = termₙ₋₁ / n // 避免重複計算階乘,無溢出風險,數值穩定
int main() {
long double sum = 0.0L;
long double term = 1.0L;
for (int n = 1; n <= 30; n++) { // long double 可算更多項
term /= n;
sum += term;
}
printf("長雙精度 Σ(1/n!) n=1..30 = %.25Lf\n", sum);
printf("e - 1 (長雙精度) = %.25Lf\n", expl(1.0L) - 1.0L);
return 0;
}
| n | 項值 1/n! | 部分和 | 與 e-1 差值 |
|---|---|---|---|
| 1 | 1.000000 | 1.000000 | 0.718282 |
| 2 | 0.500000 | 1.500000 | 0.218282 |
| 3 | 0.166667 | 1.666667 | 0.051615 |
| 4 | 0.041667 | 1.708333 | 0.009948 |
| 5 | 0.008333 | 1.716667 | 0.001615 |
| 6 | 0.001389 | 1.718056 | 0.000226 |
| 7 | 0.000198 | 1.718254 | 0.000028 |
| 8 | 0.000025 | 1.718279 | 0.000003 |
| 9 | 0.000003 | 1.718282 | 0.000000 |
| 10 | 2.8e-7 | 1.718282 | < 1e-15 |
**第 10 項已達雙精度極限**,20 項遠超需求。
eˣ = Σ xⁿ/n! (n=0..∞) e = Σ 1/n! (n=0..∞) = 1 + Σ 1/n! (n=1..∞) ∴ Σ 1/n! (n=1..∞) = e - 1
| 錯誤 | 後果 | 修正 |
|---|---|---|
| `t = t * (1/n)` | 整數除法,n>1 時項值歸零 | `t /= n` 或 `t *= 1.0/n` |
| 重複計算階乘 `fact *= n` | 20! 溢出 64 位整數 | 遞推除法 `term /= n` |
| 用 float 累加 | 7 位精度,尾項精度丟失 | 用 double 或 long double |
級數 Σ(1/n!) 以極快速度收斂於 e-1。關鍵技巧:**遞推除法 `term /= n` 替代階乘計算**,避免溢出且數值穩定。雙精度下 10 項即達機器精度極限,20 項結果 **1.718281828459045** 與 e-1 完全一致。**切記:除法常數必須帶小數點**。