首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 精確控制小數位數:DecimalFormat 完整指南

     編輯:程式設計綜合問答

在 Android 開發中,金額、比率、測量數據常需精確控制小數位數。本文系統介紹 DecimalFormat、String.format、BigDecimal 三大方案,針對您的「只保留小數點後兩位」需求提供最佳實踐。

您的場景分析

累加商品總價:

Double mGTotal = ...; // 例:179.257856
// 需顯示:179.25 (非四捨五入,直接截斷?或四捨五入?)

關鍵澄清:「只顯示小數點後兩位」通常指四捨五入 (179.26),而非截斷 (179.25)。您的範例輸出 179.25 暗示需截斷,但財務場景多為四捨五入。下文將涵蓋兩種情況。

方案一:DecimalFormat(最靈活、推薦)

// 四捨五入模式 (標準財務)
DecimalFormat dfRound = new DecimalFormat("#.##"); // 或 "0.00" 強制兩位
String result1 = dfRound.format(179.257856); // "179.26"

// 截斷模式 (直接捨去)
DecimalFormat dfTruncate = new DecimalFormat("#.##");
dfTruncate.setRoundingMode(RoundingMode.DOWN); // 關鍵:設定截斷模式
String result2 = dfTruncate.format(179.257856); // "179.25"

// 強制顯示兩位小數 (含尾數 0)
DecimalFormat dfFixed = new DecimalFormat("0.00");
dfFixed.setRoundingMode(RoundingMode.HALF_UP);
String result3 = dfFixed.format(100.1); // "100.10"

關鍵模式字符對照表

模式輸入輸出說明
#.##179.257856179.26最多兩位,整數部不補 0
0.00179.257856179.26固定兩位,不足補 0
#,##0.001234.51,234.50含千分位分隔符
¥#,##0.001234.5¥1,234.50貨幣符號前綴

RoundingMode 完整選項

  • HALF_UP:四捨五入 (預設),1.5 → 2, -1.5 → -1
  • DOWN:向零截斷 (您的範例需求),1.99 → 1, -1.99 → -1
  • UP:遠離零進位,1.01 → 2
  • HALF_EVEN:銀行家算法 (統計學推薦)

方案二:String.format(簡單場景足夠)

// 四捨五入,固定兩位
String result = String.format(Locale.getDefault(), "%.2f", 179.257856); // "179.26"

// 截斷需配合 BigDecimal
String truncated = String.format("%.2f", 
    new BigDecimal(179.257856).setScale(2, RoundingMode.DOWN)); // "179.25"

注意:String.format 依賴 Locale,德語環境下小數點為逗號。財務顯示建議指定 Locale.US。

方案三:BigDecimal(高精度計算必備)

核心原則:浮點運算不可用於金融計算。您的代碼使用 Double 累加已產生精度誤差:

// 錯誤示範
Double total = 0.1 + 0.2; // 0.30000000000000004

// 正確:全程使用 BigDecimal
BigDecimal total = BigDecimal.ZERO;
for (Item item : items) {
    total = total.add(new BigDecimal(item.getPrice())); // 傳入 String 或長整數分
}
// 格式化輸出
String display = total.setScale(2, RoundingMode.HALF_UP).toPlainString();

您的代碼優化版

@Override
protected void onResume() {
    super.onResume();
    if (Constants.mItem_Detail.isEmpty()) return;
    
    // 1. 使用 BigDecimal 避免浮點誤差
    BigDecimal grandTotal = BigDecimal.ZERO;
    for (Map detail : Constants.mItem_Detail) {
        String priceStr = detail.get(SingleProductActivity.KEY_TOTAL);
        if (priceStr != null) {
            grandTotal = grandTotal.add(new BigDecimal(priceStr));
        }
    }
    
    // 2. 格式化:四捨五入保留兩位 (財務標準)
    DecimalFormat df = new DecimalFormat("0.00");
    df.setRoundingMode(RoundingMode.HALF_UP);
    String displayText = df.format(grandTotal);
    
    // 3. 更新 UI
    mTxtViewGrandTotal.setText(displayText);
    myTextVeiwGrandTotal.setText(displayText); // 注意:變數名拼寫錯誤 myTextVeiwGrandTotal
    
    mItems.setText(String.valueOf(Constants.mItem_Detail.size()));
}

效能與記憶體考量

  • DecimalFormat 非執行緒安全,每次使用建議 new 實例,或使用 ThreadLocal 緩存
  • 高頻格式化 (如 RecyclerView 滾動) 建議預編譯模式或使用 String.format
  • BigDecimal 物件創建開銷較大,大量計算可考慮以「分」為單位用 long 運算

總結

針對「保留兩位小數」:

  1. 顯示層:使用 DecimalFormat("0.00") + RoundingMode.HALF_UP (四捨五入) 或 DOWN (截斷)
  2. 計算層:嚴禁使用 Double/Float,全程採用 BigDecimal 或整數分單位
  3. 國際化:指定 Locale.US 確保小數點一致性

您的原始代碼只需在 setText 前加上格式化即可修復顯示問題,但強烈建議同步修正計算層精度隱患。

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