交替調和級數 S = Σ (-1)^(k+1) / k (k=1..100) 是迴圈控制與正負號切換的經典練習。本文展示 for、while、do-while 三種寫法,並分析浮點精度與優化技巧。
#include <stdio.h>
int main() {
double sum = 0.0;
int sign = 1; // 正負號:1, -1, 1, -1...
for (int i = 1; i <= 100; i++) {
sum += sign * (1.0 / i); // 1.0 強制浮點除法
sign = -sign; // 翻轉正負號
}
printf("sum = %.10f\n", sum); // 0.6881721793
return 0;
}
int main() {
double sum = 0.0;
int sign = 1;
int i = 1;
while (i <= 100) {
sum += sign * (1.0 / i);
sign = -sign;
i++;
}
printf("sum = %.10f\n", sum);
return 0;
}
int main() {
double sum = 0.0;
int sign = 1;
int i = 1;
do {
sum += sign * (1.0 / i);
sign = -sign;
i++;
} while (i <= 100);
printf("sum = %.10f\n", sum);
return 0;
}
| 特性 | for | while | do-while |
|---|---|---|---|
| 判斷時機 | 迴圈前 | 迴圈前 | 迴圈後 |
| 執行保證 | 可能 0 次 | 可能 0 次 | **至少 1 次** |
| 適用場景 | 已知次數 | 未知次數、條件複雜 | 菜單、至少一次輸入 |
| 本題適用性 | ⭐⭐⭐ 最佳 | ⭐⭐ 適用 | ⭐ 適用但非首選 |
sign = -sign 比 pow(-1, i) 高效百倍,避免函數調用與浮點運算。1.0 / i 強制雙精度運算;1 / i 為整數除法,i>1 時結果全為 0。交替調和級數收斂至 ln(2) ≈ 0.6931471806。100 項部分和:
S_100 = 0.688172179310195... ln(2) = 0.693147180559945... 誤差 ≈ 0.004975 (約 1/201,符合萊布尼茨判別法誤差界)
double kahan_sum() {
double sum = 0.0, c = 0.0; // c 為補償項
int sign = 1;
for (int i = 1; i <= 100; i++) {
double term = sign * (1.0 / i);
double y = term - c;
double t = sum + y;
c = (t - sum) - y;
sum = t;
sign = -sign;
}
return sum;
}
**for 迴圈是已知次數迭代的首選**,結構清晰、語意明確。掌握 sign = -sign 正負號翻轉技巧、強制浮點除法、累加順序對精度的影響,是數值計算程式設計的基本功。