標籤:java 小數精度 java小數處理
一、 電腦的小數計算一定範圍內精確,超過範圍只能取近似值:
電腦儲存的浮點數受儲存bit位元影響,只能保證一定範圍內精準,超過bit範圍的只能取近似值。 java中各類型的精度範圍參見:http://blog.csdn.net/longshenlmj/article/details/47616481
編程時注意:
doulbe類型的數,不能用等號判定是否相等(或者是一定範圍內可以)。因為兩次同樣的計算(除法)結果可能出現小數部分不同。甚至極端的時候,初始化兩個小數時,都可能不相等(用數值和字串分別初始化bigdecimal的小數就會不等)
java小數處理方法的經驗總結:
(1)小數計算對精度無要求時,使用float節省時間。(2)如果有精度要求,用BigDecimal類處理(初始化必須使用字串,因為用數值初始化會得到近似值,不準確),然後設定保留位元和 舍入法(half_up四捨五入,half_even銀行家,half_down向下取整)(3)精度要求低時可轉化為整數處理(集體統一擴大數量級): 乘以10的級數轉化為整數處理,小數點右移幾位,但整數值不要超過對應類型的取值範圍。比如保留4位小數,可統一乘以10000,然後只保留整數計算結果,保留近位的話就多乘一位。 這種方式在RTB項目MDSP的演算法核心模組中使用,幾十萬的投放量,用int或long就可以處理,更大範圍的整數處理BigInteger。
這樣的好處是:
a,計算快,除了除法,其他運算上整數計算(加減乘)節省時間;b,除法中,小數部分可直接省略,或向上取整(小數大於0時則加1)也可以讓小數點多移動一位來保留進位。
二、java專門的小數運算類:BigDecimal類型(比double和float小數運算更精準的小數計算)
float和double只能用來做科學計算或者是工程計算,在廣域數值範圍上提供較為精確的快速近似計算;而在商業計算要求結果精確(比如,有的程式設計語言中提供了專門的貨幣類型來處理),所以Java使用java.math.BigDecimal專門處理小數精度
構造器描述:
BigDecimal(int) 建立一個具有參數所指定整數值的對象。 BigDecimal(double) 建立一個具有參數所指定雙精確度值的對象。 BigDecimal(long) 建立一個具有參數所指定長整數值的對象。 BigDecimal(String) 建立一個具有參數所指定以字串表示的數值的對象。
使用原則:初始化小數必須用String來夠造,BigDecimal(String),因為用double的小數是近似值,不是精確值。
BigDecimal成員方法
add(BigDecimal) 對象自身與參數相加,然後返回這個對象。 subtract(BigDecimal) 對象自身與參數相減,然後返回這個對象。 multiply(BigDecimal) 對象自身與參數相乘,然後返回這個對象。 divide(BigDecimal) 對象自身與參數相除,然後返回這個對象。 toString() BigDecimal對象的數值轉換成對應的字串。 doubleValue() BigDecimal對返回double值。 floatValue() BigDecimal對返回float。 longValue() BigDecimal對返回long值。 intValue() BigDecimal對返回int值。
三、java小數保留精度的舍入方式1,java 常用的四捨五入法實現:
Math類中的round方法不能設定保留幾位小數,但可以乘100達到保留2位的目的: Math.round(value*100)/100.0;或者,直接用java.text.DecimalFormat指定保留幾位小數,用哪幾種舍入法: DecimalFormat decFormat = new DecimalFormat("#.00"); decFormat.setRoundingMode(RoundingMode.HALF_UP);
2,java的8種舍入方式:
1、 ROUND_UP:向上取整(丟掉小數,整數加1) 遠離零方向舍入。向絕對值最大的方向舍入,只要捨棄位非0即進位。2、ROUND_DOWN:向下取整(丟掉小數)。趨向零方向舍入。向絕對值最小的方向輸入,所有的位都要捨棄,不存在進位情況。3、ROUND_CEILING:向正無窮方向走,始終不會減少計算值。如果 BigDecimal 為正,則舍入行為與 ROUND_UP 相同;如果為負,則舍入行為與 ROUND_DOWN 相同。Math.round()方法就是使用的此模式。4、ROUND_FLOOR:向負無窮方向舍入。向負無窮方向靠攏。若是正數,舍入行為類似於ROUND_DOWN;若為負數,舍入行為類似於ROUND_UP。5、 HALF_UP:四捨五入,最近數字舍入(5進)。6、 HALF_DOWN:四捨六入,最近數字舍入(5舍)。7、 HAIL_EVEN:銀行家舍入法。四捨六入五偶舍。即捨棄位4舍6入,當為5時看前一位,奇進偶舍。向“最接近的”數字舍入,如果與兩個相鄰數位距離相等,則向相鄰的偶數舍入。 也就是說,如果捨棄部分左邊的數字為奇數,則舍入行為與 ROUND_HALF_UP 相同; 如果為偶數,則舍入行為與 ROUND_HALF_DOWN 相同。 注意,在重複進行一系列計算時,此舍入模式可以將累加錯誤減到最小。8、ROUND_UNNECESSARY 斷言請求的操作具有精確的結果,因此不需要舍入。如果對獲得精確結果的操作指定此舍入模式,則拋出ArithmeticException。
四、BigDecimal的java代碼執行個體
package test;import java.math.BigDecimal;public class bigDecimalTest { public static void main(String[] args) { BigDecimal a = new BigDecimal(1); BigDecimal b = new BigDecimal(3); BigDecimal sum = new BigDecimal("0"); for(int i=0;i<2;i++) { sum = sum.add(a); } //除法運算 System.out.println("a/b="+a.divide(b,5,BigDecimal.ROUND_HALF_UP).doubleValue()); System.out.println("a/b="+a.divide(b,6,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100"))); System.out.println("a/b="+a.divide(b,6,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100")).doubleValue());// System.out.println("a/b="+a.divide(b,11).doubleValue()); //不指定舍入方式,報錯“Invalid rounding mode” int mytt= 100;//整數可以隨意初始化 BigDecimal oirginC = new BigDecimal(Integer.toString(mytt)); BigDecimal oirgin2 = new BigDecimal(mytt); System.out.println("oirginC:"+oirginC); System.out.println("oirgin2:"+oirgin2); BigDecimal scale = new BigDecimal("0.002");//小數必須用string, 否則會出現誤差,如double double testfloat=0.001; BigDecimal scale2 = new BigDecimal(testfloat); System.out.println(scale); System.out.println(scale2);//輸出為近似數0.001000000000000000020816681711721685132943093776702880859375 System.out.println(scale.equals(scale2));//兩個比較對象必須在相同尺度才能用equal,2.0和2.00不相等,所以要用compare System.out.println(scale.compareTo(scale2));//輸出中,小於、等於、大於分別對應-1、0、1。可以用與不同尺度scale的對象,只要值相等就行了,如1.0等於1.00 if(0 == b.compareTo(new BigDecimal("3.00"))){//不同尺度的數 System.out.println("equal"); } //bigDecimal乘法運算返回int類型 System.out.println("multipy:"+oirginC.multiply(scale).intValue()); //bigDecimal加法運算返回int類型 System.out.println("add:"+b.add(a).doubleValue()); //bigDecimal減法運算返回int類型 System.out.println("substract:"+b.subtract(new BigDecimal(3.00)).doubleValue()); //Math.ceil()向上取整,就是小數不為0則整數加1捨去小數 int test1 =3; double test2=0.01; System.out.println(Double.valueOf(Math.ceil(test1 * test2)).intValue()); System.out.println(Math.ceil(1.02)); }}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
java中小數的處理:高精度運算用bigDecimal類,精度保留方法,即舍入方式的指定