首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C/C++ 浮點數判斷整數的正確姿勢:避開精度陷阱

     編輯:關於C語言

判斷浮點數變數是否代表整數值 (如 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;
}

關鍵細節解析

  1. 使用 long long 而非 int:避免大數值截斷 (int 通常 32 位,double 整數精確範圍 53 位)
  2. 絕對值統一處理正負:diff = fabs(n - (long long)n) 簡化邏輯
  3. 雙重邊界檢查:
    • diff < EPS:接近 0 (如 4.000...001)
    • fabs(diff - 1.0) < EPS:接近 1 (負數情況,如 -3.999... ≈ -4,diff ≈ 0.999...)
  4. EPS 選擇:double 用 1e-15,float 用 1e-6,long double 可用 1e-18

實測驗證 (雙精度 15 位有效)

測試輸入預期實際說明
0.000000000000001 (14個0)NONO超過 EPS
0.0000000000000001 (15個0)不確定YES超出有效位數,四捨五入為 0
9.000000000000001 (14個0)NONO小數部份 > EPS
9.0000000000000001 (15個0)不確定YES超出有效位數,表示為 9.0

結果符合預期:有效位數內嚴格判斷,超出位數由硬體四捨五入決定。

常見型別後綴補充

  • 123L / 123LL:long / long long 整數
  • 3.14F:float 常數
  • 3.14L:long double 常數 (GCC 延伸精度,MSVC 同 double)

總結

判斷浮點數是否為整數值,核心是設定合理誤差容忍度 (EPS)並處理正負邊界。切勿直接比較浮點數相等。此方法適用於輸入驗證、金融計算驗整、科學計算結果檢查等場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved