--- title: BigDecimal 详解 category: Java tag: - Javaåºç¡ --- ãé¿éå·´å·´ Java å¼åæåã䏿å°ï¼â为äºé¿å 精度丢失ï¼å¯ä»¥ä½¿ç¨ `BigDecimal` æ¥è¿è¡æµ®ç¹æ°çè¿ç®âã æµ®ç¹æ°çè¿ç®ç«ç¶è¿ä¼æç²¾åº¦ä¸¢å¤±çé£é©åï¼ç¡®å®ä¼ï¼ 示ä¾ä»£ç ï¼ ```java float a = 2.0f - 1.9f; float b = 1.8f - 1.7f; System.out.println(a);// 0.100000024 System.out.println(b);// 0.099999905 System.out.println(a == b);// false ``` **为ä»ä¹æµ®ç¹æ° `float` æ `double` è¿ç®çæ¶åä¼æç²¾åº¦ä¸¢å¤±çé£é©å¢ï¼** è¿ä¸ªåè®¡ç®æºä¿åæµ®ç¹æ°çæºå¶æå¾å¤§å ³ç³»ãæä»¬ç¥éè®¡ç®æºæ¯äºè¿å¶çï¼èä¸è®¡ç®æºå¨è¡¨ç¤ºä¸ä¸ªæ°åæ¶ï¼å®½åº¦æ¯æéçï¼æ é循ç¯çå°æ°åå¨å¨è®¡ç®æºæ¶ï¼åªè½è¢«æªæï¼æä»¥å°±ä¼å¯¼è´å°æ°ç²¾åº¦åçæå¤±çæ åµãè¿ä¹å°±æ¯è§£éäºä¸ºä»ä¹æµ®ç¹æ°æ²¡æåæ³ç¨äºè¿å¶ç²¾ç¡®è¡¨ç¤ºã å°±æ¯å¦è¯´åè¿å¶ä¸ç 0.2 å°±æ²¡åæ³ç²¾ç¡®è½¬æ¢æäºè¿å¶å°æ°ï¼ ```java // 0.2 转æ¢ä¸ºäºè¿å¶æ°çè¿ç¨ä¸ºï¼ä¸æä¹ä»¥ 2ï¼ç´å°ä¸åå¨å°æ°ä¸ºæ¢ï¼ // å¨è¿ä¸ªè®¡ç®è¿ç¨ä¸ï¼å¾å°çæ´æ°é¨åä»ä¸å°ä¸æåå°±æ¯äºè¿å¶çç»æã 0.2 * 2 = 0.4 -> 0 0.4 * 2 = 0.8 -> 0 0.8 * 2 = 1.6 -> 1 0.6 * 2 = 1.2 -> 1 0.2 * 2 = 0.4 -> 0ï¼åç循ç¯ï¼ ... ``` å ³äºæµ®ç¹æ°çæ´å¤å 容ï¼å»ºè®®çä¸ä¸[è®¡ç®æºç³»ç»åºç¡ï¼åï¼æµ®ç¹æ°](http://kaito-kidd.com/2018/08/08/computer-system-float-point/)è¿ç¯æç« ã ## BigDecimal ä»ç» `BigDecimal` å¯ä»¥å®ç°å¯¹æµ®ç¹æ°çè¿ç®ï¼ä¸ä¼é æç²¾åº¦ä¸¢å¤±ã é常æ åµä¸ï¼å¤§é¨åéè¦æµ®ç¹æ°ç²¾ç¡®è¿ç®ç»æçä¸å¡åºæ¯ï¼æ¯å¦æ¶åå°é±çåºæ¯ï¼é½æ¯éè¿ `BigDecimal` æ¥åçã ãé¿éå·´å·´ Java å¼åæåã䏿å°ï¼**æµ®ç¹æ°ä¹é´ççå¼å¤æï¼åºæ¬æ°æ®ç±»åä¸è½ç¨ == æ¥æ¯è¾ï¼å è£ æ°æ®ç±»åä¸è½ç¨ equals æ¥å¤æã**  å ·ä½åå æä»¬å¨ä¸é¢å·²ç»è¯¦ç»ä»ç»äºï¼è¿éå°±ä¸å¤æäºã æ³è¦è§£å³æµ®ç¹æ°è¿ç®ç²¾åº¦ä¸¢å¤±è¿ä¸ªé®é¢ï¼å¯ä»¥ç´æ¥ä½¿ç¨ `BigDecimal` æ¥å®ä¹æµ®ç¹æ°çå¼ï¼ç¶ååè¿è¡æµ®ç¹æ°çè¿ç®æä½å³å¯ã ```java BigDecimal a = new BigDecimal("1.0"); BigDecimal b = new BigDecimal("0.9"); BigDecimal c = new BigDecimal("0.8"); BigDecimal x = a.subtract(b); BigDecimal y = b.subtract(c); System.out.println(x.compareTo(y));// 0 ``` ## BigDecimal å¸¸è§æ¹æ³ ### å建 æä»¬å¨ä½¿ç¨ `BigDecimal` æ¶ï¼ä¸ºäºé²æ¢ç²¾åº¦ä¸¢å¤±ï¼æ¨è使ç¨å®ç`BigDecimal(String val)`æé æ¹æ³æè `BigDecimal.valueOf(double val)` éææ¹æ³æ¥å建对象ã ãé¿éå·´å·´ Java å¼åæåã对è¿é¨åå 容乿æå°ï¼å¦ä¸å¾æç¤ºã  ### å åä¹é¤ `add` æ¹æ³ç¨äºå°ä¸¤ä¸ª `BigDecimal` 对象ç¸å ï¼`subtract` æ¹æ³ç¨äºå°ä¸¤ä¸ª `BigDecimal` 对象ç¸åã`multiply` æ¹æ³ç¨äºå°ä¸¤ä¸ª `BigDecimal` 对象ç¸ä¹ï¼`divide` æ¹æ³ç¨äºå°ä¸¤ä¸ª `BigDecimal` 对象ç¸é¤ã ```java BigDecimal a = new BigDecimal("1.0"); BigDecimal b = new BigDecimal("0.9"); System.out.println(a.add(b));// 1.9 System.out.println(a.subtract(b));// 0.1 System.out.println(a.multiply(b));// 0.90 System.out.println(a.divide(b));// æ æ³é¤å°½ï¼æåº ArithmeticException å¼å¸¸ System.out.println(a.divide(b, 2, RoundingMode.HALF_UP));// 1.11 ``` è¿ééè¦æ³¨æçæ¯ï¼å¨æä»¬ä½¿ç¨ `divide` æ¹æ³çæ¶åå°½éä½¿ç¨ 3 ä¸ªåæ°çæ¬ï¼å¹¶ä¸`RoundingMode` ä¸è¦éæ© `UNNECESSARY`ï¼å¦åå¾å¯è½ä¼éå° `ArithmeticException`ï¼æ æ³é¤å°½åºç°æ é循ç¯å°æ°çæ¶åï¼ï¼å ¶ä¸ `scale` 表示è¦ä¿çå ä½å°æ°ï¼`roundingMode` 代表ä¿çè§åã ```java public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) { return divide(divisor, scale, roundingMode.oldMode); } ``` ä¿çè§åé常å¤ï¼è¿éå举å ç§: ```java public enum RoundingMode { // 2.5 -> 3 , 1.6 -> 2 // -1.6 -> -2 , -2.5 -> -3 UP(BigDecimal.ROUND_UP), // 2.5 -> 2 , 1.6 -> 1 // -1.6 -> -1 , -2.5 -> -2 DOWN(BigDecimal.ROUND_DOWN), // 2.5 -> 3 , 1.6 -> 2 // -1.6 -> -1 , -2.5 -> -2 CEILING(BigDecimal.ROUND_CEILING), // 2.5 -> 2 , 1.6 -> 1 // -1.6 -> -2 , -2.5 -> -3 FLOOR(BigDecimal.ROUND_FLOOR), // 2.5 -> 3 , 1.6 -> 2 // -1.6 -> -2 , -2.5 -> -3 HALF_UP(BigDecimal.ROUND_HALF_UP), //...... } ``` ### 大尿¯è¾ `a.compareTo(b)` : è¿å -1 表示 `a` å°äº `b`ï¼0 表示 `a` çäº `b` ï¼ 1 表示 `a` å¤§äº `b`ã ```java BigDecimal a = new BigDecimal("1.0"); BigDecimal b = new BigDecimal("0.9"); System.out.println(a.compareTo(b));// 1 ``` ### ä¿çå ä½å°æ° éè¿ `setScale`æ¹æ³è®¾ç½®ä¿çå ä½å°æ°ä»¥åä¿çè§åãä¿çè§åææºå¤ç§ï¼ä¸éè¦è®°ï¼IDEA ä¼æç¤ºã ```java BigDecimal m = new BigDecimal("1.255433"); BigDecimal n = m.setScale(3,RoundingMode.HALF_DOWN); System.out.println(n);// 1.255 ``` ## BigDecimal ç弿¯è¾é®é¢ ãé¿éå·´å·´ Java å¼åæåã䏿å°ï¼  `BigDecimal` ä½¿ç¨ `equals()` æ¹æ³è¿è¡ç弿¯è¾åºç°é®é¢ç代ç 示ä¾ï¼ ```java BigDecimal a = new BigDecimal("1"); BigDecimal b = new BigDecimal("1.0"); System.out.println(a.equals(b));//false ``` è¿æ¯å 为 `equals()` æ¹æ³ä¸ä» ä» ä¼æ¯è¾å¼ç大å°ï¼valueï¼è¿ä¼æ¯è¾ç²¾åº¦ï¼scaleï¼ï¼è `compareTo()` æ¹æ³æ¯è¾çæ¶åä¼å¿½ç¥ç²¾åº¦ã 1.0 ç scale æ¯ 1ï¼1 ç scale æ¯ 0ï¼å æ¤ `a.equals(b)` çç»ææ¯ falseã  `compareTo()` æ¹æ³å¯ä»¥æ¯è¾ä¸¤ä¸ª `BigDecimal` çå¼ï¼å¦æç¸çå°±è¿å 0ï¼å¦æç¬¬ 1 ä¸ªæ°æ¯ç¬¬ 2 个æ°å¤§åè¿å 1ï¼åä¹è¿å-1ã ```java BigDecimal a = new BigDecimal("1"); BigDecimal b = new BigDecimal("1.0"); System.out.println(a.compareTo(b));//0 ``` ## BigDecimal å·¥å ·ç±»å享 ç½ä¸æä¸ä¸ªä½¿ç¨äººæ°æ¯è¾å¤ç `BigDecimal` å·¥å ·ç±»ï¼æä¾äºå¤ä¸ªéææ¹æ³æ¥ç®å `BigDecimal` çæä½ã æå¯¹å ¶è¿è¡äºç®åæ¹è¿ï¼å享ä¸ä¸æºç ï¼ ```java import java.math.BigDecimal; import java.math.RoundingMode; /** * ç®åBigDecimal计ç®çå°å·¥å ·ç±» */ public class BigDecimalUtil { /** * é»è®¤é¤æ³è¿ç®ç²¾åº¦ */ private static final int DEF_DIV_SCALE = 10; private BigDecimalUtil() { } /** * æä¾ç²¾ç¡®çå æ³è¿ç®ã * * @param v1 è¢«å æ° * @param v2 å æ° * @return ä¸¤ä¸ªåæ°çå */ public static double add(double v1, double v2) { BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.add(b2).doubleValue(); } /** * æä¾ç²¾ç¡®çåæ³è¿ç®ã * * @param v1 è¢«åæ° * @param v2 åæ° * @return ä¸¤ä¸ªåæ°çå·® */ public static double subtract(double v1, double v2) { BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.subtract(b2).doubleValue(); } /** * æä¾ç²¾ç¡®ç乿³è¿ç®ã * * @param v1 è¢«ä¹æ° * @param v2 乿° * @return ä¸¤ä¸ªåæ°ç积 */ public static double multiply(double v1, double v2) { BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.multiply(b2).doubleValue(); } /** * æä¾ï¼ç¸å¯¹ï¼ç²¾ç¡®ç餿³è¿ç®ï¼å½åçé¤ä¸å°½çæ 嵿¶ï¼ç²¾ç¡®å° * å°æ°ç¹ä»¥å10ä½ï¼ä»¥åçæ°ååèäºå ¥ã * * @param v1 è¢«é¤æ° * @param v2 餿° * @return ä¸¤ä¸ªåæ°çå */ public static double divide(double v1, double v2) { return divide(v1, v2, DEF_DIV_SCALE); } /** * æä¾ï¼ç¸å¯¹ï¼ç²¾ç¡®ç餿³è¿ç®ãå½åçé¤ä¸å°½çæ 嵿¶ï¼ç±scaleåæ°æ * å®ç²¾åº¦ï¼ä»¥åçæ°ååèäºå ¥ã * * @param v1 è¢«é¤æ° * @param v2 餿° * @param scale 表示表示éè¦ç²¾ç¡®å°å°æ°ç¹ä»¥åå ä½ã * @return ä¸¤ä¸ªåæ°çå */ public static double divide(double v1, double v2, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); } /** * æä¾ç²¾ç¡®çå°æ°ä½åèäºå ¥å¤çã * * @param v éè¦åèäºå ¥çæ°å * @param scale å°æ°ç¹åä¿çå ä½ * @return åèäºå ¥åçç»æ */ public static double round(double v, int scale) { if (scale < 0) { throw new IllegalArgumentException( "The scale must be a positive integer or zero"); } BigDecimal b = BigDecimal.valueOf(v); BigDecimal one = new BigDecimal("1"); return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); } /** * æä¾ç²¾ç¡®çç±»å转æ¢(Float) * * @param v éè¦è¢«è½¬æ¢çæ°å * @return è¿å转æ¢ç»æ */ public static float convertToFloat(double v) { BigDecimal b = new BigDecimal(v); return b.floatValue(); } /** * æä¾ç²¾ç¡®çç±»å转æ¢(Int)ä¸è¿è¡åèäºå ¥ * * @param v éè¦è¢«è½¬æ¢çæ°å * @return è¿å转æ¢ç»æ */ public static int convertsToInt(double v) { BigDecimal b = new BigDecimal(v); return b.intValue(); } /** * æä¾ç²¾ç¡®çç±»å转æ¢(Long) * * @param v éè¦è¢«è½¬æ¢çæ°å * @return è¿å转æ¢ç»æ */ public static long convertsToLong(double v) { BigDecimal b = new BigDecimal(v); return b.longValue(); } /** * è¿å两个æ°ä¸å¤§çä¸ä¸ªå¼ * * @param v1 éè¦è¢«å¯¹æ¯ç第ä¸ä¸ªæ° * @param v2 éè¦è¢«å¯¹æ¯ç第äºä¸ªæ° * @return è¿å两个æ°ä¸å¤§çä¸ä¸ªå¼ */ public static double returnMax(double v1, double v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.max(b2).doubleValue(); } /** * è¿å两个æ°ä¸å°çä¸ä¸ªå¼ * * @param v1 éè¦è¢«å¯¹æ¯ç第ä¸ä¸ªæ° * @param v2 éè¦è¢«å¯¹æ¯ç第äºä¸ªæ° * @return è¿å两个æ°ä¸å°çä¸ä¸ªå¼ */ public static double returnMin(double v1, double v2) { BigDecimal b1 = new BigDecimal(v1); BigDecimal b2 = new BigDecimal(v2); return b1.min(b2).doubleValue(); } /** * 精确对æ¯ä¸¤ä¸ªæ°å * * @param v1 éè¦è¢«å¯¹æ¯ç第ä¸ä¸ªæ° * @param v2 éè¦è¢«å¯¹æ¯ç第äºä¸ªæ° * @return å¦æä¸¤ä¸ªæ°ä¸æ ·åè¿å0ï¼å¦æç¬¬ä¸ä¸ªæ°æ¯ç¬¬äºä¸ªæ°å¤§åè¿å1ï¼åä¹è¿å-1 */ public static int compareTo(double v1, double v2) { BigDecimal b1 = BigDecimal.valueOf(v1); BigDecimal b2 = BigDecimal.valueOf(v2); return b1.compareTo(b2); } } ``` ## æ»ç» æµ®ç¹æ°æ²¡æåæ³ç¨äºè¿å¶ç²¾ç¡®è¡¨ç¤ºï¼å æ¤åå¨ç²¾åº¦ä¸¢å¤±çé£é©ã ä¸è¿ï¼Java æä¾äº`BigDecimal` æ¥æä½æµ®ç¹æ°ã`BigDecimal` çå®ç°å©ç¨å°äº `BigInteger` ï¼ç¨æ¥æä½å¤§æ´æ°ï¼, æä¸åçæ¯ `BigDecimal` å å ¥äºå°æ°ä½çæ¦å¿µã