亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

double類型計算精度丟失問題及解決方法

發布時間:2021-11-12 17:14:45 來源:億速云 閱讀:3577 作者:柒染 欄目:大數據

本篇文章為大家展示了double類型計算精度丟失問題及解決方法,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

public class Test{
    public static void main(String [] args){
        System.out.println(0.06+0.01);
        System.out.println(1.0-0.42);
        System.out.println(4.015*100);
        System.out.println(303.1/1000);    
    }
}

輸出

0.06999999999999999
0.5800000000000001
401.49999999999994
0.30310000000000004

我們發現,計算出來的值和我們預期結果不一致。原因在于我們的計算機是二進制的。浮點數沒有辦法使用二進制進行精確表示。計算機的CPU表示浮點數由兩個部分組成:指數和尾數,這樣的表示方法一般都會失去一定的精確度,有些浮點數運算也會產生一定的誤差。如:2.4的二進制表示并非就是精確的2.4。反而最為接近的二進制表示是 2.3999999999999999。浮點數的值實際上是由一個特定的數學公式計算得到的。可參考http://blog.csdn.net/abing37/article/details/5332798

    那么我們如何才能夠獲取我們想要的預期結果呢?特別是在處理金額交易計算上。其實java的float只能用來進行科學計算或工程計算,在大多數的商業計算中,一般采用java.math.BigDecimal類來進行精確計算。在使用BigDecimal類來進行計算的時候,主要分為以下步驟:

  (1) 用float或者double變量構建BigDecimal對象。通常使用BigDecimal的構造方法或者靜態方法的valueOf()方法把基本類型的變量構建成BigDecimal對象。

  (2) 通過調用BigDecimal的加,減,乘,除等相應的方法進行算術運算。

  (3) 把BigDecimal對象轉換成float,double,int等類型。

BigDecimal類基本介紹
    在修改實例之前,我們先簡單了解一下BigDecimal類的構造函數和成員方法。

BigDecimal(int var)  //創建一個具有參數所指定整數值的對象。
BigDecimal(double var) //創建一個具有參數所指定雙精度值的對象。
BigDecimal(long var)  //創建一個具有參數所指定長整數值的對象。
BigDecimal(String var) //創建一個具有參數所指定以字符串表示的數值的對象。

成員方法(BigDecimal 的運算方式 不支持 + - * / 這類的運算 它有自己的運算方法)

BigDecimal add(BigDecimal augend)  //加法運算
BigDecimal subtract(BigDecimal subtrahend) //減法運算
BigDecimal multiply(BigDecimal multiplicand) //乘法運算
BigDecimal divide(BigDecimal divisor) //除法運算

好,既然我們知道方法了,那么我們就用新方法來解決一下上述的問題。修改一下代碼,如下:

import java.math.*;

public class Test{
    public static void main(String [] args){
        double d1 = 0.06;
        double d2 = 0.01;
        BigDecimal b1 = new BigDecimal(d1);
        BigDecimal b2 = new BigDecimal(d2);
        
        System.out.println(b1.add(b2).doubleValue());
        
        double d3 = 1.0;
        double d4 = 0.42;
        BigDecimal b3 = new BigDecimal(d3);
        BigDecimal b4 = new BigDecimal(d4);
        System.out.println(b3.subtract(b4).doubleValue());
        
        double d5 = 4.015;
        double d6 = 100;
        BigDecimal b5 = new BigDecimal(d5);
        BigDecimal b6 = new BigDecimal(d6);
        System.out.println(b5.multiply(b6).doubleValue());
        
        double d7 = 303.1;
        double d8 = 1000;
        BigDecimal b7 = new BigDecimal(d7);
        BigDecimal b8 = new BigDecimal(d8);
        System.out.println(b7.divide(b8).doubleValue());    
    }
}

輸出

0.06999999999999999
0.5800000000000001
401.49999999999994
0.30310000000000004

我們發現結果還是不對。從上述實例我們知道調用的構造方法為BigDecimal(double var)。 BigDecimal(double val)將 double 轉換為 BigDecimal,后者是double的二進制浮點值準確的十進制表示形式。返回的BigDecimal的標度是使 (10scale × val) 為整數的最小值。這里也幾個特別要注意的地方:

  (1)此構造方法的結果有一定的不可預知性。有人可能認為在 Java 中寫入 new BigDecimal(0.1) 所創建的 BigDecimal 正好等于 0.1(非標度值 1,其標度為 1),但是它實際上等于 0.1000000000000000055511151231257827021181583404541015625。這是因為 0.1 無法準確地表示為 double(或者說對于該情況,不能表示為任何有限長度的二進制小數)。這樣,傳入 到構造方法的值不會正好等于 0.1(雖然表面上等于該值)。
  (2)另一方面,String 構造方法是完全可預知的:寫入 new BigDecimal("0.1") 將創建一個 BigDecimal,它正好 等于預期的 0.1。因此,比較而言,通常建議優先使用 String 構造方法。
  (3)當 double 必須用作 BigDecimal 的源時,請注意,此構造方法提供了一個準確轉換;它不提供與以下操作相同的結果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 構造方法,將 double 轉換為 String。要獲取該結果,請使用 static valueOf(double) 方法。

  根據上述描述,我們繼續修改下例子,修改后如下:

import java.math.*;

public class Test{
    public static void main(String [] args){
        double d1 = 0.06;
        double d2 = 0.01;
        BigDecimal b1 = new BigDecimal(Double.toString(d1));
        BigDecimal b2 = new BigDecimal(Double.toString(d2));
        
        System.out.println(b1.add(b2).doubleValue());
        
        double d3 = 1.0;
        double d4 = 0.42;
        BigDecimal b3 = new BigDecimal(Double.toString(d3));
        BigDecimal b4 = new BigDecimal(Double.toString(d4));
        System.out.println(b3.subtract(b4).doubleValue());
        
        double d5 = 4.015;
        double d6 = 100;
        BigDecimal b5 = new BigDecimal(Double.toString(d5));
        BigDecimal b6 = new BigDecimal(Double.toString(d6));
        System.out.println(b5.multiply(b6).doubleValue());
        
        double d7 = 303.1;
        double d8 = 1000;
        BigDecimal b7 = new BigDecimal(Double.toString(d7));
        BigDecimal b8 = new BigDecimal(Double.toString(d8));
        System.out.println(b7.divide(b8).doubleValue());    
    }
}

輸出

0.07
0.58
401.5
0.3031

計算精度正確。

總結
(1)需要精確的表示兩位小數時我們需要把他們轉換為BigDecimal對象,然后再進行運算。
(2)使用BigDecimal(double val)構造函數時仍會存在精度丟失問題,建議使用BigDecimal(String val)。這就需要先把double類型(調用Double.toString(double var))轉換為字符串然后在作為BigDecimal(String val)構造函數的參數。轉換為BigDecimal對象之后再進行加減乘除操作,這樣精度就不會出現問題了。這也是為什么有關金錢數據存儲都使用BigDecimal。

上述內容就是double類型計算精度丟失問題及解決方法,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

错那县| 子长县| 罗源县| 讷河市| 南汇区| 涟水县| 保德县| 图木舒克市| 乌鲁木齐市| 拉萨市| 怀远县| 沙湾县| 福安市| 灵武市| 方城县| 澎湖县| 湖南省| 呼图壁县| 社旗县| 江油市| 明水县| 连平县| 麟游县| 伊金霍洛旗| 安仁县| 阆中市| 榕江县| 莎车县| 威信县| 凤翔县| 双桥区| 灵山县| 巢湖市| 邳州市| 丰宁| 名山县| 四会市| 滁州市| 深州市| 江川县| 海盐县|