高精度計算BigDecimal,DecimalFormat

編碼中一般遇到金額以及小數點精度計算,爲避免精度丟失,將double類型轉換爲BigDecimal再進行相關計算,或者使用DecimalFormat進行轉換。java

1.BigDecimal

BigDecimal是Java提供的一個不變的、任意精度的有符號十進制數對象,繼承自Number類。BigDecimal類提供了算術操做,操做規模,四捨五入,比較,哈希和格式轉換。git

BigDecimal經常使用的構造方法及普通方法:
  • 將double表示形式轉換爲BigDecimal
public BigDecimal(double val)
  • 將int表示形式轉換爲BigDecimal
public BigDecimal(int val)
  • 將字符串表示形式轉換爲BigDecimal
public BigDecimal(String val)
  • 加法
public BigDecimal add(BigDecimal augend)
  • 減法
public BigDecimal subtract(BigDecimal subtrahend)
  • 乘法
public BigDecimal multiply(BigDecimal multiplicand)
  • 除法
public BigDecimal divide(BigDecimal divisor)
  • 取餘
public BigDecimal remainder(BigDecimal divisor)
  • 求商和餘數
public BigDecimal[] divideAndRemainder(BigDecimal divisor)
  • BigDecimal中setScale(int newScale)方法設置保留幾位小數以及舍入模式
public BigDecimal setScale(int newScale) {
       return setScale(newScale, RoundingMode.UNNECESSARY);
   }
   // ......
   public BigDecimal setScale(int newScale, int roundingMode) {
       return setScale(newScale, RoundingMode.valueOf(roundingMode));
   }
BigDecimal常見的計算方法以下:
/** * 加法運算。 * * @param amount1 被加數 * @param amount2 加數 * @return 兩個參數的和 */
    public static double add(double amount1, double amount2) {
        BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
        BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
        return mDecimal1.add(mDecimal2).doubleValue();
    }

    /** * 減法運算。 * * @param amount1 被減數 * @param amount2 減數 * @return 兩個參數的差 */
    public static double subtraction(double amount1, double amount2) {
        BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
        BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
        return mDecimal1.subtract(mDecimal2).doubleValue();
    }

    /** * 乘法運算。 * * @param amount1 被乘數 * @param amount2 乘數 * @return 兩個參數的積 */
    public static double multiplication(double amount1, double amount2) {
        BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
        BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
        return mDecimal1.multiply(mDecimal2).doubleValue();
    }

    /** * 除法運算。 * MathContext.DECIMAL128其精度設置與Decimal128格式,34位數字和 [HALF_EVEN]的舍入模式同樣。 * divide()方法默認爲MathContext.UNLIMITED無限取值,不作限制陷入死循環會拋出ArithmeticException(計算溢出)異常。 * * @param amount1 被除數 * @param amount2 除數 * @return 兩個參數的商 */
    public static double divisionOperation(double amount1, double amount2) {
        BigDecimal mDecimal1 = new BigDecimal(Double.toString(amount1));
        BigDecimal mDecimal2 = new BigDecimal(Double.toString(amount2));
        return mDecimal1.divide(mDecimal2, MathContext.DECIMAL128).doubleValue();
    }

2.DecimalFormat

DecimalFormat是一個NumberFormat的子類的格式小數。它有各類各樣的功能設計使它能夠解析和格式化數字在任何地區,包括支持西方,阿拉伯語和印度語的數字。它還支持不一樣類型的數據,包括整數(123),定點數(123.4),科學記數法(1.23 e4)百分比(12%)和貨幣數量(123美圓)等。web

DecimalFormat經常使用的構造方法及普通方法:
  • 建立一個DecimalFormat使用默認模式(Locale.Category.FORMAT)
public DecimalFormat() {
  Locale def = Locale.getDefault(Locale.Category.FORMAT);
  // try to get the pattern from the cache
  String pattern = cachedLocaleData.get(def);
  if (pattern == null) {  /* cache miss */
   // Get the pattern for the default locale.
   pattern = LocaleData.get(def).numberPattern;
   /* update cache */
   cachedLocaleData.putIfAbsent(def, pattern);
  }
   this.symbols = new DecimalFormatSymbols(def);
   init(pattern);
}
  • 建立一個使用給定的DecimalFormat模式和默認
public DecimalFormat(String pattern)
  • 建立一個使用給定的DecimalFormat模式和符號。
public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
  • 適用於給定的地區設置固定的格式 ,如」#0.00」—>1.25
public void applyPattern(String pattern)
  • 格式化生成一個字符串
public final String format(double number)
  • 設置格式時這個數字格式所使用的貨幣幣值。
public void setCurrency(Currency currency)
  • 設置數的小數部分所容許的最大位數
public void setMaximumFractionDigits(int newValue)
  • 設置數的小數部分所容許的最小位數
public void setMinimumFractionDigits(int newValue)
  • 設置區域
public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
  • 設置返回前綴
public void setNegativePrefix(String newValue)
  • 設置先後綴
public void setPositiveSuffix(String newValue)
  • 設置分組
public void setGroupingUsed(boolean newValue)
  • 設置分組大小
public void setGroupingSize(int newValue)
DecimalFormat經常使用方法以下:
/** * 格式化保留兩位小數,默認四捨五入 * * @param amount * @return */
    public static String formatTwoDecimals(double amount) {
        DecimalFormat mFormat = new DecimalFormat();
        // 設置區域
        mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
        // 設置格式化保留兩位小數
        mFormat.applyPattern("#0.00");
        return mFormat.format(amount);
    }

    /** * 格式化保留兩位小數,只舍不入 * * @param amount * @return */
    public static String formatTwoDecimalsDown(double amount) {
        DecimalFormat mFormat = new DecimalFormat();
        // 設置區域
        mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
        // 設置格式化保留兩位小數
        mFormat.applyPattern("#0.00");
        // 設置只舍不入
        mFormat.setRoundingMode(RoundingMode.DOWN);
        return mFormat.format(amount);
    }

    /** * 保留有效數,最多保留兩位 * * @return */
    public static String formatTwoEffectiveNumber(double amount) {
        DecimalFormat mFormat = new DecimalFormat();
        // 設置區域
        mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
        // 設置保留兩位有效數
        mFormat.applyPattern("#0.##");
        // 設置只舍不入
        mFormat.setRoundingMode(RoundingMode.DOWN);
        return mFormat.format(amount);
    }

    /** * 金額3位數分組,如10000——>10,000 * * @param amount * @return */
    public static String formatAmountGrouping(double amount) {
        DecimalFormat mFormat = new DecimalFormat();
        // 設置區域
        mFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.CHINA));
        // 設置使用逗號「,」將金額分隔開
        mFormat.setGroupingUsed(true);
        // 設置分隔位數
        mFormat.setGroupingSize(3);
        return mFormat.format(amount);
    }
DecimalFormat中格式字符說明
符號 位置 本地化 含義
0 數字 阿拉伯數字
# 數字 阿拉伯數字,若是不存在則顯示爲空
. 數字 小數分隔符或貨幣小數分隔符
- 數字 缺省負數前綴
, 數字 分組分隔符
E 數字 分隔科學計數法中的尾數和指數。在前綴或後綴中無需加引號
% 前綴或後綴 乘以100和做爲百分比顯示
/u2030 前綴或後綴 乘以1000並顯示爲千分數
3.BigDecimal和DecimalFormat中保留小數位進行舍入模式都是RoundingMode模式

源碼以下:app

public enum RoundingMode {

    /** * 向上進位,如: * 2.56計算後保留一位小數則爲2.6 * 1.1保留整數則爲2 * -2.5保留整數爲-3 */
    UP(BigDecimal.ROUND_UP),

    /** * 舍入模式爲零。 */
    DOWN(BigDecimal.ROUND_DOWN),

    /** * 舍入模式正無窮。 */
    CEILING(BigDecimal.ROUND_CEILING),

    /** * 舍入模式向負無窮。 */
    FLOOR(BigDecimal.ROUND_FLOOR),

    /** * 舍入模式向「最近鄰」輪除非鄰居都是等距的,在這種狀況下一輪。 */
    HALF_UP(BigDecimal.ROUND_HALF_UP),

    /** * 舍入模式向「最近鄰」輪除非鄰居都是等距的,在這種狀況下一輪下來。 */
    HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),

    /** * 舍入模式向「最近鄰」輪除非鄰居都是等距的,在這種狀況下,甚至向鄰居。 */
    HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),

    /** * 舍入模式斷言請求的操做有一個確切的結果,所以不須要舍入。 */
    UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);

    private final int bigDecimalRM;

    RoundingMode(int rm) {
        bigDecimalRM = rm;
    }

    /** * 返回與指定名稱這種類型的枚舉常量。 * 字符串必須匹配徹底一個標識符用於聲明一個枚舉常數在這個類型。 (多餘的空格字符是不容許的。) 參數 */
    public static RoundingMode valueOf(int mode) {
        switch (mode) {
            case BigDecimal.ROUND_CEILING:
                return CEILING;
            case BigDecimal.ROUND_DOWN:
                return DOWN;
            case BigDecimal.ROUND_FLOOR:
                return FLOOR;
            case BigDecimal.ROUND_HALF_DOWN:
                return HALF_DOWN;
            case BigDecimal.ROUND_HALF_EVEN:
                return HALF_EVEN;
            case BigDecimal.ROUND_HALF_UP:
                return HALF_UP;
            case BigDecimal.ROUND_UNNECESSARY:
                return UNNECESSARY;
            case BigDecimal.ROUND_UP:
                return UP;
            default:
                throw new IllegalArgumentException("Invalid rounding mode");
        }
    }
}

本文分享 CSDN - 秦川小將。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。ide

相關文章
相關標籤/搜索