判斷浮點數變數是否代表整數值 (如 4.0、-3.0) 看似簡單,實則暗藏浮點精度陷阱。直接比較 n == (int)n 或 n - (int)n == 0.0 極不可靠,本文詳細分析誤區並給出工業級解法。
| 類型 | 判斷目標 | 方法 |
|---|---|---|
| 型別整數 | 變數型別是否為 int/long 等 | typeid(n).name() (C++ RTTI) |
| 數值整數 | 浮點數值是否等於某整數 (如 4.000) | 數值比較,需容忍精度誤差 |
本文專注數值整數判斷:輸入 4.000 → YES,4.001 → NO。
// 錯誤 1:直接比較浮點數與 0
if (n - (int)n == 0) // 錯!左邊 double,右邊 int,且浮點誤差導致 3.999... 或 4.000...1
// 錯誤 2:改為 0.0 仍錯
if (n - (int)n == 0.0) // 錯!浮點運算誤差不可預測
浮點數無法精確表示許多十進制小數。雙精度約 15-16 位有效數字,單精度約 6-7 位。判斷邏輯:
diff = n - (long long)n (取小數部分)|diff| < epsilon → 整數|diff - 1.0| < epsilon → 整數 (負數情況,如 -0.999... ≈ -1)#include <stdio.h>
#include <math.h>
int is_integer(double n) {
const double EPS = 1e-15; // 雙精度誤差容忍度
double diff = n - (long long)n; // 取小數部分
if (diff < 0) diff = -diff; // 取絕對值
return (diff < EPS) || (fabs(diff - 1.0) < EPS);
}
int main() {
double n;
while (scanf("%lf", &n) == 1) {
printf("%s\n", is_integer(n) ? "YES" : "NO");
}
return 0;
}
long long 而非 int:避免大數值截斷 (int 通常 32 位,double 整數精確範圍 53 位)diff = fabs(n - (long long)n) 簡化邏輯diff < EPS:接近 0 (如 4.000...001)fabs(diff - 1.0) < EPS:接近 1 (負數情況,如 -3.999... ≈ -4,diff ≈ 0.999...)1e-15,float 用 1e-6,long double 可用 1e-18| 測試輸入 | 預期 | 實際 | 說明 |
|---|---|---|---|
| 0.000000000000001 (14個0) | NO | NO | 超過 EPS |
| 0.0000000000000001 (15個0) | 不確定 | YES | 超出有效位數,四捨五入為 0 |
| 9.000000000000001 (14個0) | NO | NO | 小數部份 > EPS |
| 9.0000000000000001 (15個0) | 不確定 | YES | 超出有效位數,表示為 9.0 |
結果符合預期:有效位數內嚴格判斷,超出位數由硬體四捨五入決定。
123L / 123LL:long / long long 整數3.14F:float 常數3.14L:long double 常數 (GCC 延伸精度,MSVC 同 double)判斷浮點數是否為整數值,核心是設定合理誤差容忍度 (EPS)並處理正負邊界。切勿直接比較浮點數相等。此方法適用於輸入驗證、金融計算驗整、科學計算結果檢查等場景。