1. 程式人生 > >RoundingMode 幾個引數詳解 java.math.RoundingMode 幾個引數詳解

RoundingMode 幾個引數詳解 java.math.RoundingMode 幾個引數詳解

第一版

java.math.RoundingMode 幾個引數詳解

java.math.RoundingMode裡面有幾個引數搞得我有點暈,現以個人理解對其一一進行總結:

為了能更好理解,我們可以畫一個XY軸

RoundingMode.CEILING:取右邊最近的整數

RoundingMode.DOWN:去掉小數部分取整,也就是正數取左邊,負數取右邊,相當於向原點靠近的方向取整

RoundingMode.FLOOR:取左邊最近的正數

RoundingMode.HALF_DOWN:五舍六入,負數先取絕對值再五舍六入再負數

RoundingMode.HALF_UP:四捨五入,負數原理同上

RoundingMode.HALF_EVEN:這個比較繞,整數位若是奇數則四捨五入,若是偶數則五舍六入

第二版

roundMode是指舍位時候的模式,傳引數的時候用BigDecimal.ROUND_XXXX_XXX,   
  有:   
    一下例子是setScale(0,BigDecimal.ROUND_XXXX_XXX));的情況。如果保留小數位數不是零,如

setScale(2,BigDecimal.ROUND_XXXX_XXX)); 是 2 ,則 此數字的小數位數要大於2位。第三位才是要取捨得位。
  ROUND_CEILING:   舍位時往正無窮方向移動   1.1->2   1.5->2   1.8->2   -1.1->-1   -1.5->-1   -1.8->-1   
  ROUND_DOWN:向0的方向移動1.1->1   1.5->1   1.8->1   -1.1->-1   -1.5->-1   -1.8>-1   
  ROUND_FLOOR:與CEILING相反,往負無窮   1.1->1   1.5->1   1.8->1   -1.1->-2   -1.5->-2   -1.8->-2   
  ROUND_HALF_DOWN:以5為分界線,或曰五舍六入1.5->1   1.6->1   -1.5->-1   -1.6->-2 1.15->1.1   1.16->1.2 1.55->1.6  1.56->1.6
  ROUND_HALF_EVEN:同樣以5為分界線,如果是5,則前一位變偶數1.15->1.2   1.16->1.2   1.25->1.2   1.26->1.3   
  ROUND_HALF_UP:最常見的四捨五入   
  ROUND_UNNECESSARY:無需舍位   
  ROUND_UP:與ROUND_DOWN,遠離0的方向1.1->2   1.5->2   1.8->2   -1.1->-2   -1.5->-2   -1.8->-2   
    
  具體精確到幾位因該採用   
  商=被除數.devide(除數,保留小數位數,精確方法)



第三版


BigDecimal 由任意精度的整數非標度值 和 32 位的整數標度 (scale) 組成。如果為零或正數,則標度是小數點後的位數。如果為負數,則將該數的非標度值乘以 10 的負 scale 次冪。因此,BigDecimal 表示的數值是 (unscaledValue × 10-scale)。 


可以處理任意長度的浮點數運算。 

BigDecimal add(BigDecimal val) //BigDecimal 加法 

BigDecimal subtract (BigDecimal val) //BigDecimal 減法 


BigDecimal multiply (BigDecimal val)  //BigDecimal 乘法 

BigDecimal divide (BigDecimal val,RoundingMode mode)  除法 


具體使用 計算: 

   
  加:   a.add(b); 

  減: a.subtract(b); 

  乘:   a.multiply(b); 

  除:   a.divide(b,2);//2為精度取值 
除法細解: 
  //注意以下相除會丟擲異常,原因: 通過BigDecimal的divide方法進行除法時當不整除,出現無限迴圈小數時,就會拋異常  
        //BigDecimal divideBg = a.divide(b);   
        //解決方法是:設定精確度;就是給divide設定精確的小數點 
divide(xxxxx,2, BigDecimal.ROUND_HALF_EVEN)   
        //其中的第二個引數表示的是:保留小數點之後多少位  

BigDecimal不整除丟擲的異常,請設定精確度! 
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 
at java.math.BigDecimal.divide(BigDecimal.java:1278) 
at main.Main.main(Main.java:41) 

下面我們來看看除法的詳細說明: 
   divide(BigDecimal divisor, int scale, introundingMode) 


BigDecimal的setScale方法 

BigDecimal.setScale() 

方法用於格式化小數點 

表示保留一位小數,預設用四捨五入方式 

setScale(1) 

直接刪除多餘的小數位,如2.35會變成2.3 setScale(1,BigDecimal.ROUND_DOWN) 

進位處理,2.35變成2.4  setScale(1,BigDecimal.ROUND_UP) 

四捨五入,2.35變成2.4  setScale(1,BigDecimal.ROUND_HALF_UP) 

四捨五入,2.35變成2.3,如果是5則向下舍setScaler(1,BigDecimal.ROUND_HALF_DOWN) 

  
注意點一 

scale指的是你小數點後的位數。 
scale()就是BigDecimal類中的方法。如 

BigDecimal b = new BigDecimal("123.456"); 

b.scale()返回的就是3 
注意點二roundingMode是小數的保留模式。它們都是BigDecimal中的常量欄位, 

有很多種,如 
BigDecimal.ROUND_HALF_UP表示的就是4舍5入 

注意點三 

divide(BigDecimal divisor, int scale, introundingMode)的意思是說: 
我用一個BigDecimal物件除以divisor後的結果,並且要求這個結果保留有scale個小數位,roundingMode表示的就是保留模式是什麼,是四捨五入啊還是其它的 


BigDecimal aa = new  BigDecimal(135.95 );  

BigDecimal bb=new  BigDecimal("100" );  

BigDecimal result=aa.multiply(bb);  //做加法 



3.java中 BigDecimal型別的可以轉換到double型別: 
  用 變數.doubleValue();函式  即可將 BigDecimal 型別資料 轉化為 double型別! 
4.java BigDecimal比較大小 

可以通過BigDecimal的compareTo方法來進行比較。 
返回的結果是int型別,-1表示小於,0是等於,1是大於。 

看下面這個例子: 
BigDecimal a = new BigDecimal("1.00"); 
BigDecmial b = new BigDecimal(1); 

想比較一下a和b的大小,一般都會用equals 

System.out.println(a.equals(b)); 
但是輸出結果是:false 
原因是:BigDecimal比較時,不僅比較值,而且還比較精度? 


if(a.compareTo(b)==0) 結果是true 

比較大小可以用 a.compareTo(b) 
返回值    -1 小於   0 等於    1 大於 

5.BigDecimal取其中最大、最小值、絕對值、相反數: 

  a.max (b) //比較取最大值 

  a.min(b) //比較取最小值 

  a.abs()//取最絕對值 

  a.negate()//取相反數 


6.下面是注意 : 

BigDecimal列舉常量用法摘要  : 

CEILING   
          向正無限大方向舍入的舍入模式。 
DOWN   
          向零方向舍入的舍入模式。 
FLOOR   
          向負無限大方向舍入的舍入模式。 
HALF_DOWN   
          向最接近數字方向舍入的舍入模式,如果與兩個相鄰數字的距離相等,則向下舍入。 
HALF_EVEN   
          向最接近數字方向舍入的舍入模式,如果與兩個相鄰數字的距離相等,則向相鄰的偶數舍入。 
HALF_UP   
          向最接近數字方向舍入的舍入模式,如果與兩個相鄰數字的距離相等,則向上舍入。 
UNNECESSARY   
          用於斷言請求的操作具有精確結果的舍入模式,因此不需要舍入。 
UP   
          遠離零方向舍入的舍入模式。 



7.關於BigDecimal格式化 

public String formatValue(Object value){ 
        String content = null; 
        if (value == null) { 
             content = ""; 
         } else { 
             if(value instanceof BigDecimal){ 
                 //conver to fortmat String 
                 NumberFormat nf = NumberFormat.getInstance(); 
                 nf.setMinimumFractionDigits(2); 
                 nf.setMaximumFractionDigits(2); 
                 content = nf.format(value);  
             }else{ 
                 content = String.valueOf(value); 
             } 
         } 
        return content; 
    } 

使用這樣一個方法可以達到格式化的效果,其中value instanceof BigDecimal,表示的是字元型別是BigDecimal型別的時候執行,這裡的NumberFormat就表示字元型別,下面的兩句程式碼就表示小數點後面的精確位數。 

這裡還要提到NumberFormat的其他兩個型別: 

getCurrencyInstance(): 返回當前預設 環境的貨幣格式 

CurrencyInstance(): 返回指定語言 環境的數字格式,一般是百分比格式 


8.在《Effective Java》這本書中也提到這個原則,float和double只能用來做科學計算或者是工程計算,在商業計算中我們要用java.math.BigDecimal。 
我們如果需要精確計算,非要用String來夠造BigDecimal不可! 

下面的這個工具類是是轉載別人的,可以通過個工具類實現小數的精確計算。 

1import java.math.BigDecimal;   
2/** *//**  
3* 由於Java的簡單型別不能夠精確的對浮點數進行運算,這個工具類提供精  
4* 確的浮點數運算,包括加減乘除和四捨五入。  
5*/  
6public class Arith{   
7    //預設除法運算精度   
8    private static final int DEF_DIV_SCALE = 10;   
9    //這個類不能例項化   
10    private Arith(){   
11    }   
12  
13    /** *//**  
14     * 提供精確的加法運算。  
15     * @param v1 被加數  
16     * @param v2 加數  
17     * @return 兩個引數的和  
18     */  
19    public static double add(double v1,double v2){   
20        BigDecimal b1 = new BigDecimal(Double.toString(v1));   
21        BigDecimal b2 = new BigDecimal(Double.toString(v2));   
22        return b1.add(b2).doubleValue();   
23    }   
24    /** *//**  
25     * 提供精確的減法運算。  
26     * @param v1 被減數  
27     * @param v2 減數  
28     * @return 兩個引數的差  
29     */  
30    public static double sub(double v1,double v2){   
31        BigDecimal b1 = new BigDecimal(Double.toString(v1));   
32        BigDecimal b2 = new BigDecimal(Double.toString(v2));   
33        return b1.subtract(b2).doubleValue();   
34    }    
35    /** *//**  
36     * 提供精確的乘法運算。  
37     * @param v1 被乘數  
38     * @param v2 乘數  
39     * @return 兩個引數的積  
40     */  
41    public static double mul(double v1,double v2){   
42        BigDecimal b1 = new BigDecimal(Double.toString(v1));   
43        BigDecimal b2 = new BigDecimal(Double.toString(v2));   
44        return b1.multiply(b2).doubleValue();   
45    }   
46  
47    /** *//**  
48     * 提供(相對)精確的除法運算,當發生除不盡的情況時,精確到  
49     * 小數點以後10位,以後的數字四捨五入。  
50     * @param v1 被除數  
51     * @param v2 除數  
52     * @return 兩個引數的商  
53     */  
54    public static double div(double v1,double v2){   
55        return div(v1,v2,DEF_DIV_SCALE);   
56    }   
57  
58    /** *//**  
59     * 提供(相對)精確的除法運算。當發生除不盡的情況時,由scale引數指  
60     * 定精度,以後的數字四捨五入。  
61     * @param v1 被除數  
62     * @param v2 除數  
63     * @param scale 表示表示需要精確到小數點以後幾位。  
64     * @return 兩個引數的商  
65     */  
66    public static double div(double v1,double v2,int scale){   
67        if(scale<0){   
68            throw new IllegalArgumentException(   
69                "The scale must be a positive integer or zero");   
70        }   
71        BigDecimal b1 = new BigDecimal(Double.toString(v1));   
72        BigDecimal b2 = new BigDecimal(Double.toString(v2));   
73        return b1.divid(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();   
74    }   
75  
76    /** *//**  
77     * 提供精確的小數位四捨五入處理。  
78     * @param v 需要四捨五入的數字  
79     * @param scale 小數點後保留幾位  
80     * @return 四捨五入後的結果  
81     */  
82    public static double round(double v,int scale){   
83        if(scale<0){   
84            throw new IllegalArgumentException(   
85                "The scale must be a positive integer or zero");   
86        }   
87        BigDecimal b = new BigDecimal(Double.toString(v));   
88        BigDecimal one = new BigDecimal("1");   
89        return b.divid(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();   
90     }   
91  }   BigDecimal 由任意精度的整數非標度值 和 32 位的整數標度 (scale) 組成。如果為零或正數,則標度是小數點後的位數。如果為負數,則將該數的非標度值乘以 10 的負 scale 次冪。因此,BigDecimal 表示的數值是 (unscaledValue × 10-scale)。  
可以處理任意長度的浮點數運算。 

BigDecimal add(BigDecimal val) //BigDecimal 加法 

BigDecimal subtract (BigDecimal val) //BigDecimal 減法 

BigDecimal multiply (BigDecimal val)  //BigDecimal 乘法 

BigDecimal divide (BigDecimal val,RoundingMode mode)  除法 


具體使用 計算: 

   
  加:   a.add(b); 

  減: a.subtract(b); 

  乘:   a.multiply(b); 

  除:   a.divide(b,2);//2為精度取值 
除法細解: 
  //注意以下相除會丟擲異常,原因: 通過BigDecimal的divide方法進行除法時當不整除,出現無限迴圈小數時,就會拋異常  
        //BigDecimal divideBg = a.divide(b);   
        //解決方法是:設定精確度;就是給divide設定精確的小數點 
divide(xxxxx,2, BigDecimal.ROUND_HALF_EVEN)   
        //其中的第二個引數表示的是:保留小數點之後多少位  

BigDecimal不整除丟擲的異常,請設定精確度! 
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 
at java.math.BigDecimal.divide(BigDecimal.java:1278) 
at main.Main.main(Main.java:41) 

下面我們來看看除法的詳細說明: 
   divide(BigDecimal divisor, int scale, introundingMode) 


BigDecimal的setScale方法 

BigDecimal.setScale() 

方法用於格式化小數點 

表示保留一位小數,預設用四捨五入方式 

setScale(1) 

直接刪除多餘的小數位,如2.35會變成2.3 setScale(1,BigDecimal.ROUND_DOWN) 

進位處理,2.35變成2.4  setScale(1,BigDecimal.ROUND_UP) 

四捨五入,2.35變成2.4  setScale(1,BigDecimal.ROUND_HALF_UP) 

四捨五入,2.35變成2.3,如果是5則向下舍setScaler(1,BigDecimal.ROUND_HALF_DOWN) 

  
注意點一 

scale指的是你小數點後的位數。 
scale()就是BigDecimal類中的方法。如 

BigDecimal b = new BigDecimal("123.456"); 

b.scale()返回的就是3 
注意點二roundingMode是小數的保留模式。它們都是BigDecimal中的常量欄位, 

有很多種,如 
BigDecimal.ROUND_HALF_UP表示的就是4舍5入 

注意點三 

divide(BigDecimal divisor, int scale, introundingMode)的意思是說: 
我用一個BigDecimal物件除以divisor後的結果,並且要求這個結果保留有scale個小數位,roundingMode表示的就是保留模式是什麼,是四捨五入啊還是其它的 


BigDecimal aa = new  BigDecimal(135.95 );  

BigDecimal bb=new  BigDecimal("100" );  

BigDecimal result=aa.multiply(bb);  //做加法 



3.java中 BigDecimal型別的可以轉換到double型別: 
  用 變數.doubleValue();函式  即可將 BigDecimal 型別資料 轉化為 double型別! 
4.java BigDecimal比較大小 

可以通過BigDecimal的compareTo方法來進行比較。 
返回的結果是int型別,-1表示小於,0是等於,1是大於。 

看下面這個例子: 
BigDecimal a = new BigDecimal("1.00"); 
BigDecmial b = new BigDecimal(1); 

想比較一下a和b的大小,一般都會用equals 

System.out.println(a.equals(b)); 
但是輸出結果是:false 
原因是:BigDecimal比較時,不僅比較值,而且還比較精度? 


if(a.compareTo(b)==0) 結果是true 

比較大小可以用 a.compareTo(b) 
返回值    -1 小於   0 等於    1 大於 

5.BigDecimal取其中最大、最小值、絕對值、相反數: 

  a.max (b) //比較取最大值 

  a.min(b) //比較取最小值 

  a.abs()//取最絕對值 

  a.negate()//取相反數 


6.下面是注意 : 

BigDecimal列舉常量用法摘要  : 

CEILING   
          向正無限大方向舍入的舍入模式。 
DOWN   
          向零方向舍入的舍入模式。 
FLOOR   
          向負無限大方向舍入的舍入模式。 
HALF_DOWN   
          向最接近數字方向舍入的舍入模式,如果與兩個相鄰數字的距離相等,則向下舍入。 
HALF_EVEN   
          向最接近數字方向舍入的舍入模式,如果與兩個相鄰數字的距離相等,則向相鄰的偶數舍入。 
HALF_UP   
          向最接近數字方向舍入的舍入模式,如果與兩個相鄰數字的距離相等,則向上舍入。 
UNNECESSARY   
          用於斷言請求的操作具有精確結果的舍入模式,因此不需要舍入。 
UP   
          遠離零方向舍入的舍入模式。 



7.關於BigDecimal格式化 

public String formatValue(Object value){ 
        String content = null; 
        if (value == null) { 
             content = ""; 
         } else { 
             if(value instanceof BigDecimal){ 
                 //conver to fortmat String 
                 NumberFormat nf = NumberFormat.getInstance(); 
                 nf.setMinimumFractionDigits(2); 
                 nf.setMaximumFractionDigits(2); 
                 content = nf.format(value);  
             }else{ 
                 content = String.valueOf(value); 
             } 
         } 
        return content; 
    }