淺談java的浮點數(shù)精度問題及如何解決精度缺失問題_第1頁
淺談java的浮點數(shù)精度問題及如何解決精度缺失問題_第2頁
淺談java的浮點數(shù)精度問題及如何解決精度缺失問題_第3頁
淺談java的浮點數(shù)精度問題及如何解決精度缺失問題_第4頁
淺談java的浮點數(shù)精度問題及如何解決精度缺失問題_第5頁
已閱讀5頁,還剩4頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

1、java float double精度為什么會丟失?淺談java的浮點數(shù)精度問題由于對float或double 的使用不當(dāng),可能會出現(xiàn)精度丟失的問題。問題大概情況可以通過如下代碼理解:javaview plaincopyprint?1. publicclassFloatDoubleTest2. publicstaticvoidmain(Stringargs3. floatf=20014999;4. doubled=f;5. doubled2=20014999;6. System.out.println(f=+f;7. System.out.println(d=+d;8. System.out.

2、println(d2=+d2;9. System.out.println(0.05+0.01;System.out.println(1.0-0.42;System.out.println(4.015*100;System.out.println(123.3/100; 10. 11. public class FloatDoubleTest public static void main(String args float f = 20014999; double d = f; double d2 = 20014999; System.out.println(f= + f; System.out

3、.println(d= + d; System.out.println(d2= + d2; 得到的結(jié)果如下:f=2.0015E7d=2.0015E7d2=2.0014999E7從輸出結(jié)果可以看出double 可以正確的表示20014999 ,而float 沒有辦法表示20014999 ,得到的只是一個近似值。這樣的結(jié)果很讓人訝異。20014999 這么小的數(shù)字在float下沒辦法表示。于是帶著這個問題,做了一次關(guān)于float和double學(xué)習(xí),做個簡單分享,希望有助于大家對java 浮點數(shù)的理解。關(guān)于 java 的 float 和 doubleJava 語言支持兩種基本的浮點類型: float

4、 和 double 。java 的浮點類型都依據(jù) IEEE 754 標(biāo)準(zhǔn)。IEEE 754 定義了32 位和 64 位雙精度兩種浮點二進制小數(shù)標(biāo)準(zhǔn)。IEEE 754 用科學(xué)記數(shù)法以底數(shù)為 2 的小數(shù)來表示浮點數(shù)。32 位浮點數(shù)用 1 位表示數(shù)字的符號,用 8 位來表示指數(shù),用 23 位來表示尾數(shù),即小數(shù)部分。作為有符號整數(shù)的指數(shù)可以有正負(fù)之分。小數(shù)部分用二進制(底數(shù) 2 )小數(shù)來表示。對于64 位雙精度浮點數(shù),用 1 位表示數(shù)字的符號,用 11 位表示指數(shù),52 位表示尾數(shù)。如下兩個圖來表示:float(32位:double(64位:都是分為三個部分:(1 一個單獨的符號位s 直接編碼符號s

5、。(2k 位的冪指數(shù)E ,移碼表示 。(3n 位的小數(shù),原碼表示 。那么 20014999 為什么用 float 沒有辦法正確表示?結(jié)合float和double的表示方法,通過分析 20014999 的二進制表示就可以知道答案了。以下程序可以得出 20014999 在 double 和 float 下的二進制表示方式。javaview plaincopyprint?1. publicclassFloatDoubleTest32. publicstaticvoidmain(Stringargs3. doubled=8;4. longl=Double.doubleToLongBits(d;5. S

6、ystem.out.println(Long.toBinaryString(l;6. floatf=8;7. inti=Float.floatToIntBits(f;8. System.out.println(Integer.toBinaryString(i;9. 10. public class FloatDoubleTest3 public static void main(String args double d = 8; long l = Double.doubleToLongBits(d; System.out.println(Long.toBinaryString(l; float

7、 f = 8; int i = Float.floatToIntBits(f; System.out.println(Integer.toBinaryString(i; 輸出結(jié)果如下:Double:100000101110011000101100111100101110000000000000000000000000000Float:1001011100110001011001111001100對于輸出結(jié)果分析如下。對于都不 double 的二進制左邊補上符號位 0 剛好可以得到 64 位的二進制數(shù)。根據(jù)double的表示法,分為符號數(shù)、冪指數(shù)和尾數(shù)三個部分如下:0 10000010111 0

8、011000101100111100101110000000000000000000000000000對于 float 左邊補上符號位 0 剛好可以得到 32 位的二進制數(shù)。 根據(jù)float的表示法, 也分為 符號數(shù)、冪指數(shù)和尾數(shù)三個部分如下 :0 10010111 00110001011001111001100綠色部分是符號位,紅色部分是冪指數(shù),藍(lán)色部分是尾數(shù)。對比可以得出:符號位都是 0 ,冪指數(shù)為移碼表示,兩者剛好也相等。唯一不同的是尾數(shù)。在 double 的尾數(shù)為: 001100010110011110010111 0000000000000000000000000000 ,省略后面的

9、零,至少需要24位才能正確表示 。而在 float 下面尾數(shù)為: 00110001011001111001100 ,共 23 位。為什么會這樣?原因很明顯,因為 float尾數(shù) 最多只能表示 23 位,所以 24 位的 001100010110011110010111 在 float 下面經(jīng)過四舍五入變成了 23 位的 00110001011001111001100 。所以 20014999 在 float 下面變成了 20015000 。也就是說 20014999 雖然是在float的表示范圍之內(nèi),但 在 IEEE 754 的 float 表示法精度長度沒有辦法表示出 20014999 ,而

10、只能通過四舍五入得到一個近似值。總結(jié):浮點運算很少是精確的,只要是超過精度能表示的范圍就會產(chǎn)生誤差。往往產(chǎn)生誤差不是因為數(shù)的大小,而是因為數(shù)的精度。因此,產(chǎn)生的結(jié)果接近但不等于想要的結(jié)果。尤其在使用 float 和 double 作精確運算的時候要特別小心??梢钥紤]采用一些替代方案來實現(xiàn)。如通過 String 結(jié)合 BigDecimal 或者通過使用 long 類型來轉(zhuǎn)換。解決方案:package A;import java.math.BigDecimal; /* * 由于Java的簡單類型不能夠精確的對浮點數(shù)進行運算,這個工具類提供精 * 確的浮點數(shù)運算,包括加減乘除和四舍五入。 */ pu

11、blic class Arith /默認(rèn)除法運算精度 private static final int DEF_DIV_SCALE = 10; /這個類不能實例化 private Arith( /* * 提供精確的加法運算。 * param v1 被加數(shù) * param v2 加數(shù) * return 兩個參數(shù)的和 */ public static double add(double v1,double v2 BigDecimal b1 = new BigDecimal(Double.toString(v1; BigDecimal b2 = new BigDecimal(Double.toStr

12、ing(v2; return b1.add(b2.doubleValue(; /* * 提供精確的減法運算。 * param v1 被減數(shù) * param v2 減數(shù) * return 兩個參數(shù)的差 */ public static double sub(double v1,double v2 BigDecimal b1 = new BigDecimal(Double.toString(v1; BigDecimal b2 = new BigDecimal(Double.toString(v2; return b1.subtract(b2.doubleValue(; /* * 提供精確的乘法運算

13、。 * param v1 被乘數(shù) * param v2 乘數(shù) * return 兩個參數(shù)的積 */ public static double mul(double v1,double v2 BigDecimal b1 = new BigDecimal(Double.toString(v1; BigDecimal b2 = new BigDecimal(Double.toString(v2; return b1.multiply(b2.doubleValue(; /* * 提供(相對)精確的除法運算,當(dāng)發(fā)生除不盡的情況時,精確到 * 小數(shù)點以后10位,以后的數(shù)字四舍五入。 * param v1

14、被除數(shù) * param v2 除數(shù) * return 兩個參數(shù)的商 */ public static double div(double v1,double v2 return div(v1,v2,DEF_DIV_SCALE; /* * 提供(相對)精確的除法運算。當(dāng)發(fā)生除不盡的情況時,由scale參數(shù)指 * 定精度,以后的數(shù)字四舍五入。 * param v1 被除數(shù) * param v2 除數(shù) * param scale 表示表示需要精確到小數(shù)點以后幾位。 * return 兩個參數(shù)的商 */ public static double div(double v1,double v2,int

15、scale if(scale0 throw new IllegalArgumentException( The scale must be a positive integer or zero; BigDecimal b1 = new BigDecimal(Double.toString(v1; BigDecimal b2 = new BigDecimal(Double.toString(v2; return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP.doubleValue(; /* * 提供精確的小數(shù)位四舍五入處理。 * param v 需要四舍五入的數(shù)字 * param scale 小數(shù)點后保留幾位 * return 四舍五入后的結(jié)果 */ public static double round(double v,int scale i

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論