java中浮點型數據的大小比較問題

一. 精度java

 

舉例:double result = 1.0 - 0.9;算法

這個結果不用說了吧,都知道了,0.09999999999999998apache

float和double類型主要是爲了科學計算和工程計算而設計的。他們執行二進制浮點運算,這是爲了在普遍的數字範圍上提供較爲精確的快速近似計算而精心設計的。然而,它們並無提供徹底精確的結果,因此咱們不該該用於精確計算的場合。float和double類型尤爲不適合用於貨幣運算,由於要讓一個float或double精確的表示0.1或者10的任何其餘負數次方值是不可能的(其實道理很簡單,十進制系統中能不能準確表示出1/3呢?一樣二進制系統也沒法準確表示1/10)。api

浮點運算不多是精確的,只要是超過精度能表示的範圍就會產生偏差。每每產生偏差不是由於數的大小,而是由於數的精度。所以,產生的結果接近但不等於想要的結果。尤爲在使用 float 和 double 做精確運算的時候要特別當心。數組

 

 

Java代碼 dom

double result = 1.0 - 0.9;//壞代碼

 

二. 解決精度丟失有幾種比較經常使用的方法函數

 

1. 用NumberFormat類來格式化計算結果,按照本身想要的結果進行格式化,缺點就是要手動去格式化,舍入方式不一樣結果不必定精確。工具

 

Java代碼 測試

// 好代碼  
double result = 1.0 - 0.9;  
NumberFormat nf = NumberFormat.getInstance();// 根據本身的需求格式化  
String resultStr = nf.format(result);

 

 

2. 若是不介意本身記錄十進制的小數點,並且數值不大,那麼可使用long ,int等基本類型,具體用int仍是long要看涉及的數值範圍大小,缺點是要本身處理十進制小數點,最明顯的作法就是處理貨幣使用分來計算,而不用元(只涉及加減)。spa

 

Java代碼 

// 好代碼  
int resultInt = 10 - 9;  
double result = (double) resultInt / 100;//最終時候本身控制小數點

 

 

3. 使用BigDecimal來代替double,它能讓你徹底控制精度,結果會很是精確,加減乘除寫起來也很方便,不過他有兩個缺點:1,不是基本類型,與基本類型相比,操做起來不方便;2. 速度沒有基本類型快,算是用速度換精度。相比第2個缺點並沒關係,可是第一個缺點會讓你寫起代碼很不舒服。

 

Java代碼 

// 好代碼  
String result = new BigDecimal("1").subtract(new BigDecimal("0.9")) .toString();

 

我的比較喜歡這個,並且BigDecimal還支持經常使用的格式化方法,如

BigDecimal num = new BigDecimal("384400000");

String str = new DecimalFormat("地球和月球的距離:#,##,###,###米").format(num);

結果:地球和月球的距離:384,400,000米

 

三. 浮點類型的比較

因爲精度問題,double/float比較相等也不能直接使用==,可是比較大小能夠用<、 >號

 

 

Java代碼 

double d1 = 0.1, d2 = 0.1;  
if (d1 == d2) {}// 壞代碼  
if (Double.compare(d1, d2) == 0) {}// 好代碼  
if (Double.doubleToLongBits(d1) == Double.doubleToLongBits(d2)) {}// 好代碼  
if (Double.valueOf(d1).equals(d2)) {}// 好代碼,1.5以上

 

 

四. 合理使用第三方工具類

apache的commons-lang工具包中個math包,提供了經常使用的計算方法,數字處理方法,若是項目中涉及到的計算比較多,能夠考慮使用commons-math包,這個包過於專業化,估計我們用到的地方很少。

apache的commons-lang的math包,主要有4大類功能

1. 處理分數的Fraction類,分數表示數字,更爲精確。

 

Java代碼 

Fraction fraction = Fraction.getFraction(10, 3);// 三分之十  
System.out.println(fraction);// 10/3  
System.out.println(fraction.floatValue());// 3.3333333  
System.out.println(fraction.doubleValue());// 3.3333333333333335  
System.out.println(fraction.toProperString());// 三又三分之一  
System.out.println(fraction.reduce());// 約分,如2/4約分後1/2

 

2. 處理數值的NumberUtils類;這個比較簡單,看看api就能夠。封裝了一些經常使用數字操做方法,如數字轉換、比較,獲取一個數字數組中最大值,最小值等。

3. 處理數值範圍的Range、NumberRange、IntRange、LongRange、FloatRange、DoubleRange類;

 

Java代碼 

// 拿int舉例,其餘相似  
IntRange intRange = new IntRange(100, 200);// 建立一個範圍  
intRange.containsDouble(111.1);// 是否包含指定數字  
int[] range = intRange.toArray();// 獲取範圍內的int  
intRange.getMaximumDouble();// 獲取最大值,轉換成double  
intRange.getMinimumDouble();// 獲取最小值,轉換成double

 

4. 處理隨機數的JVMRandom和RandomUtils類。這個也比較簡單,看看api就能夠,獲取隨機數時比較方便而已。

 

commons-math工具包是apache 上一個輕量級自容器的數學和統計計算方法包,包含大多數經常使用的數值算法,這個進行專業數學處理時會很是方便。

如:計算方法,方差和一組數的機率統計問題;

一套擬合曲線的數據點應用線性迴歸問題;

插值問題(可能包括線性、樣條等插值);

用來進行參數擬合的最小二乘方法;

求解方程組值問題(例如,求方程組的根);

解決系統的線性方程組;

求解常微分方程;

求最小值問題的方法;

利用Commons Math包產生指定要求的隨機數;

生成隨機抽樣,數據集;

進行統計測試;

繁雜的數學函數,如組二項式係數、特殊函數(如gamma, beta functions);

我的認爲這個包過於專業,若是用到了,再查詢不遲,知道這個包能解決問題就行。

固然,這個包很專業,可是不表明只能解決專業數學問題,處理簡單的計算也是很方便的。

 

總結:普通的計算最好使用BigDecimal類,這個類能夠很是精確的計算出結果,並且你能夠徹底控制精度,不用額外其餘操做,並且與基本類型轉換都很是方便。

相關文章
相關標籤/搜索