搜尋
首頁Javajava教程java中float與double精度遺失的實例詳解
java中float與double精度遺失的實例詳解Jun 28, 2017 am 11:38 AM
java數值浮點計算避免

1.java中int,float,long,double取值範圍

[java] view plain copy

public class TestOutOfBound {  

public static void main( String[] args) {  

  

#System.out.println(Integer.MAX_VALUE-(-Integer.MAX_VALUE)); //記憶體溢位  

#System.out. println(Integer.MAX_VALUE); //2的31次方-1,10個數位,正的20億左右,用在錢上面不一定夠  

System.out.println(Integer.MIN_VALUE) ; //負的2的31次方  

System.out.println(Long.MAX_VALUE); //2的64次方-1,19個數位,很大了,可放心用在錢上方  

System.out.println(Long.MIN_VALUE); //負的2的64次方  

System.out.println(Float.MAX_VALUE); //2的128次方-1,38個數位,比long多了一倍,這個主要用來做簡單數學精確運算使用  

System.out.println(Float.MIN_VALUE); //2的-149次方

System.out.println(Double.MAX_VALUE); //2的1024次方-1,308個數位,是float數位的10倍,主要用來做複雜運算和天文運算  

# #System.out.println(Double.MIN_VALUE); //2的-1074次方  

  

}  

}  

2.float與double精度丟失問題

例子:

[java] view plain copy

舉例:double result = 1.0 - 0.9;  

  

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


為什麼會出現這個問題呢,就這是java和其它計算機語言都會出現的問題,下面我們分析一下為什麼會出現這個問題:
float和double類型主要是為了科學計算和工程計算而設計的。他們執行二元浮點運算,這是為了在廣泛的數字範圍上提供較為精確的快速近似計算而精心設計的。然而,它們並沒有提供完全精確的結果,所以我們不應該用於精確計算的場合。 float和double類型尤其不適合用於貨幣運算,因為要讓一個float或double精確的表示0.1或10的任何其他負數次方值是不可能的(其實道理很簡單,十進制系統中能不能準確表示出1/3呢?

浮點運算很少是精確的,只要是超過精度能表示的範圍就會產生誤差。往往產生誤差不是因為數的大小,而是因為數的精度。因此,產生的結果接近但不等於想要的結果。尤其在使用 float 和 double 作精確運算的時候要特別小心。

現在我們就詳細剖析一下浮點型運算為什麼會造成精確度遺失?



[java] view plain copy

首先我們要先搞清楚以下兩個問題:  

#  

   (1) 十進位整數如何轉換為二進位數  

  

          

         演算法演算法演算法。舉例,11表示成二進位數:  

  

#                                 5/2=2   餘   1  

#  

                     2/2=1           1/2=0   餘   1  

  

         11二進位表示為(從下往上):1011  

  

        這裡提一點:只要遇到除以後的結果為0了就結束了,大家想一想,所有的整數大家除以2是不是一定能夠最終得到0。換句話說,所有的整數轉變為二進制數的演算法會不會無限地循環下去呢?絕對不會,整數絕對可以用二進位精確表示 ,但小數就不一定了。  

  

    (2) 十進位小數如何轉換為二進位數  

  

##

         演算法是乘以2至沒有了小數。舉例,0.9表示成二進位數  

  

#                                0.8(1.8的小數部分)* 2=1.6    取整數部份 1  

  

          ,                         0.2*2=0.4   取整數部分 0  

  

                   0.4*2=0.8   取整數部分      0.8*2=1.6 取整數部分 1  

  

                   0.6*2=1.2    取整數部分 0  

#         .........      0.9二進位表示為(由上至下): 1100100100100..... .  

  

         以注意:上面的計算過程循環了,也就是說*2永遠不可能消滅小數部分,使演算法將無限下去。很顯然,小數的二進位表示有時是不可能精確的 。其實道理很簡單,十進制系統中能不能準確表示出1/3呢?同樣二進位系統也無法準確表示1/10。這也就解釋了為什麼浮點型減法出現了"減不盡"的精度丟失問題。

3.解決方法一:

#如果不介意自己記錄十進制的小數點,而且數值不大,那麼可以使用long ,int等基本類型,具體用int還是long要看涉及的數值範圍大小,缺點是要自己處理十進制小數點,最明顯的做法就是處理貨幣使用分來計算,而不用元(只涉及加減)。

如:

[java] view plain copy

#int resultInt = 10 - 9;    


#double result = (double)  

double result = (double) /最後時候自己控制小數點  

4.解決方法二:

使用BigDecmal,而且需要在建構參數使用String類型。

在《Effective Java》這本書中就給了一個解決方法。書中也指出,float和double只能用來做科學計算或是工程計算,在商業計算等精確計算中,我們要用java.math.BigDecimal。

    BigDecimal類別一個有4個方法,我們只關心對我們解決浮點型資料進行精確計算有用的方法,即

BigDecimal(double value) // 將double型資料轉換變成BigDecimal型數據

    思路很簡單,我們先透過BigDecimal(double value)方法,將double型數據轉換成BigDecimal數據,然後就可以正常進行精確計算了。等計算完畢後,我們可以對結果做一些處理,例如 對除不盡的結果可以進行四捨五入。最後,再把結果由BigDecimal型數據轉換回double型數據。

    這個想法很正確,但如果你仔細看看API裡關於BigDecimal的詳細說明,你就會知道,如果需要精確計算,我們不能直接用double,而非要用String來構造BigDecimal不可!所以,我們又開始關心BigDecimal類別的另一個方法,就是能夠幫助我們正確完成精確計算的 BigDecimal(String value)方法。

// BigDecimal(String value)能夠將String型資料轉換成BigDecimal型資料

    那麼問題來了,想像一下吧,如果我們要做一個浮點型數據的加法運算,需要先將兩個浮點數轉為String型數據,然後用BigDecimal(String value)建構成BigDecimal,之後要在其中一個上呼叫add方法,傳入另一個作為參數,然後把運算的結果(BigDecimal)再轉換為浮點數。如果每次做浮點型資料的計算都要如此,你能夠忍受這麼煩瑣的過程嗎?至少我不能。所以最好的方法,就是寫一個類,在類中完成這些繁瑣的轉換過程。這 樣,在我們需要進行浮點型資料計算的時候,只要呼叫這個類別就可以了。網路上已經有高手為我們提供了一個工具類Arith來完成這些轉換操作。它提供以下靜態方法,可以完成浮點型資料的加減乘除運算和對其結果進行四捨五入的操作:

public static double add(double v1,double v2)
public static double sub (double v1,double v2)
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,int scale)
public static double round(double v,int scale)

#下面會附上Arith的原始碼,大家只要把它編譯保存好,要進行浮點數計算的時候,在你的在原始程式中導入Arith類別就可以使用以上靜態方法來進行浮點數的精確計算了。

附錄:Arith原始碼

[java] view plain copy

import java.math.BigDecimal;  

  

C

#/** 

* 由於Java的簡單型別無法精確的對浮點數運算,這個工具類別提供精 

* 確的浮點數運算,包括加減乘除和四捨五入。 

#*/  

  

public class Arith{  

    //預設除法運算精確度  ## DEF_DIV_SCALE = 10;  

    //此類別無法為實例化  

#    //這個類別中 

     * 提供精確的加法運算。 

     * @param v1 被加數 

     * @param v2 加數 

 */  

    public static double add(double v1,double v2){  

              BigDecimal b2 = new BigDecimal(Double.toString(v2));  

        return b1.add(b2).doubleValue();  

##> */  

    public static double sub(double v1,double v2){  

卷      BigDecimal b2 = new BigDecimal(Double.toString(v2));  

#        return b1.subtract(b2).doubleValue();  

## 

##    public static double mul(double v1,double v2){  

        Big    BigDecimal b2 = new BigDecimal(Double .toString(v2));  

#

        return b1.multiply(b2).doubleValue();  

    }  

#  

    /** 

     * 提供(相對)精確的除法運算,當發生除不盡的情況時,精確到 

     * 小數點以後10位元,以後的數字則為四捨五入。 

     * @param v1 被除數 

     * @param v2 除數 

 */  

#    public static double #        返回div(v1,v2,DEF_DIV_SCALE);  

    }  

#  

    /** 

     * 提供(相對)精確的除法運算。當發生除不盡的情況時,由scale參數指 

     * 定精確度,以後的數字四捨五入。 

     * @param v1 被除數 

     * @param v2 除數 

o   

     * @return 兩個參數的商 

     */  

#    public static double

#        if(scale            拋出新的IllegalArgumentEx整數或零”);  

        }  

#        BigDecimal b1 = new BigDecimal(Double.toString(v1));  

        BigDecimal b2 = new BigDecimal(Double.toString(v2));  

        return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();  

    }  

#    /** 

     * 提供精確的小數位元四捨五入處理。 

     * @param v 需要四捨五入的數字 

     * @param scale 小數點後保留幾位五 */  

    public static double round( #        if(scale            拋出new Illegal ”);  

        }  

#        BigDecimal b = 新 BigDecimal(Double.toString(v));  

        BigDecimal one = new BigDecimal("1");  

        return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();  

    }  

};  

以上是java中float與double精度遺失的實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
带你搞懂Java结构化数据处理开源库SPL带你搞懂Java结构化数据处理开源库SPLMay 24, 2022 pm 01:34 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于结构化数据处理开源库SPL的相关问题,下面就一起来看一下java下理想的结构化数据处理类库,希望对大家有帮助。

Java集合框架之PriorityQueue优先级队列Java集合框架之PriorityQueue优先级队列Jun 09, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于PriorityQueue优先级队列的相关知识,Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,下面一起来看一下,希望对大家有帮助。

完全掌握Java锁(图文解析)完全掌握Java锁(图文解析)Jun 14, 2022 am 11:47 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于java锁的相关问题,包括了独占锁、悲观锁、乐观锁、共享锁等等内容,下面一起来看一下,希望对大家有帮助。

一起聊聊Java多线程之线程安全问题一起聊聊Java多线程之线程安全问题Apr 21, 2022 pm 06:17 PM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于多线程的相关问题,包括了线程安装、线程加锁与线程不安全的原因、线程安全的标准类等等内容,希望对大家有帮助。

Java基础归纳之枚举Java基础归纳之枚举May 26, 2022 am 11:50 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于枚举的相关问题,包括了枚举的基本操作、集合类对枚举的支持等等内容,下面一起来看一下,希望对大家有帮助。

详细解析Java的this和super关键字详细解析Java的this和super关键字Apr 30, 2022 am 09:00 AM

本篇文章给大家带来了关于Java的相关知识,其中主要介绍了关于关键字中this和super的相关问题,以及他们的一些区别,下面一起来看一下,希望对大家有帮助。

Java数据结构之AVL树详解Java数据结构之AVL树详解Jun 01, 2022 am 11:39 AM

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于平衡二叉树(AVL树)的相关知识,AVL树本质上是带了平衡功能的二叉查找树,下面一起来看一下,希望对大家有帮助。

一文掌握Java8新特性Stream流的概念和使用一文掌握Java8新特性Stream流的概念和使用Jun 23, 2022 pm 12:03 PM

本篇文章给大家带来了关于Java的相关知识,其中主要整理了Stream流的概念和使用的相关问题,包括了Stream流的概念、Stream流的获取、Stream流的常用方法等等内容,下面一起来看一下,希望对大家有帮助。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),