欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中double精度丟失問題原因及解決辦法

 更新時間:2024年01月06日 09:05:02   作者:雨汨  
使用Java double進行運算時,經(jīng)常出現(xiàn)精度丟失的問題,總是在一個正確的結(jié)果左右偏0.0000**1,這篇文章主要給大家介紹了關(guān)于Java中double精度丟失問題原因及解決辦法,需要的朋友可以參考下

double類型精度丟失問題:

0.1*0.1使用計算器計算是0.01,代碼里卻是0.010000000000000002

public class HelloWorld {
    public static void main(String []args) {
       double number1 = 0.1;
	   double number2 = 0.1;
	   double result = number1 * number2 ;
	   System.out.println("使用double運算結(jié)果: "+result);
    }
}

為什么會這樣呢?這就是精度丟失問題造成的。

為什么會出現(xiàn)精度丟失?

因為計算機只能識別0和1,即二進制,無論哪種編程語言,都需要翻譯成二進制才能被計算機識別。

很多人還知道這樣一句話:這種舍入誤差的主要原因是浮點數(shù)值采用二進制系統(tǒng)表示, 而在二進制系統(tǒng)中無法精確地表示分數(shù) 1/10。這就好像十進制無法精確地表示分數(shù) 1/3—樣。

針對十進制,1除以3是除不盡的。很好理解,因為我們一直接觸的就是十進制,等于0.333333… 很好理解

但是:二進制系統(tǒng)中無法精確地表示分數(shù) 1/10。為啥呢。就有點不理解了

《Java核心技術(shù)卷》書上也是這么寫的。

十進制 轉(zhuǎn)二進制(每次將小數(shù)部分乘2,取出整數(shù)部分,如果小數(shù)部分為0,就可以停止這個過程):十進制0.1

0.1*2=0.2
0.2*2=0.4
0.4*2=0.8
0.8*2=1.6

0.6*2=1.2
0.2*2=0.4
0.4*2=0.8
//... 應該已經(jīng)發(fā)現(xiàn),上面的過程已經(jīng)開始循環(huán),小數(shù)部分永遠不能為0

怎么解決精度丟失問題?

在商城里面計算訂單金額的時候,我們就不得不解決這個問題了,這時候就用到了BigDecimal

BigDecimal類位于java.math包下,用于對超過16位有效位的數(shù)進行精確的運算。

一般來說,double類型的變量可以處理16位有效數(shù),

但實際應用中,如果超過16位,就需要BigDecimal類來操作

new BigDecimal(double val)

new BigDecimal(String val)

BigDecimal.valueOf(double val)

將double轉(zhuǎn)為BigDecimal的時候,需要先把double轉(zhuǎn)換為字符串,然后再作為BigDecimal(String val)構(gòu)造函數(shù)的參數(shù),這樣才能避免出現(xiàn)精度問題。

import java.math.BigDecimal;

public class BigDecimalUtil {

    /**
     * double類型的加法運算(不需要舍入)
     * @param d1
     * @param d2
     * @return 不加doubleValue()則, 返回BigDecimal對象
     */
    public static double addDouble(double d1, double d2) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.add(p2).doubleValue();
    }

    /**
     * double類型的加法運算(需要舍入)
     * @param d1
     * @param d2
     * @param scale 保留scale位小數(shù)
     * @return 不加doubleValue()則, 返回BigDecimal對象
     */
    public static double addDouble(double d1, double d2, int scale) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.add(p2).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * double類型的超大數(shù)值加法運算(超過50 0000)(需要舍入)
     * @param d1
     * @param d2
     * @param scale 保留scale位小數(shù)
     * @return 返回字符串,不然double數(shù)字會轉(zhuǎn)成科學計數(shù)法顯示
     */
    public static String addDoubleToStr(double d1, double d2, int scale) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.add(p2).setScale(scale, BigDecimal.ROUND_HALF_UP).toPlainString();
    }

    /**
     * double類型的減法運算
     * @param d1
     * @param d2
     * @return 不加doubleValue()則, 返回BigDecimal對象
     */
    public static double subtractDouble(double d1, double d2) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.subtract(p2).doubleValue();
    }

    /**
     * double類型的減法運算(需要舍入)
     * @param d1
     * @param d2
     * @param scale  保留scale位小數(shù)
     * @return  不加doubleValue()則, 返回BigDecimal對象
     */
    public static double subtractDouble(double d1, double d2, int scale) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.subtract(p2).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * double類型的超大數(shù)值減法運算(需要舍入)
     * @param d1
     * @param d2
     * @param scale 保留scale位小數(shù)
     * @return  返回字符串,不然double數(shù)字會轉(zhuǎn)成科學計數(shù)法顯示
     */
    public static String subtractDoubleToStr(double d1, double d2, int scale) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.subtract(p2).setScale(scale, BigDecimal.ROUND_HALF_UP).toPlainString();
    }

    /**
     * double類型的乘法運算
     *
     * @param d1
     * @param d2
     * @return 不加doubleValue()則, 返回BigDecimal對象
     */
    public static double multiplyDouble(double d1, double d2) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.multiply(p2).doubleValue();
    }

    /**
     * double類型的乘法運算(需要舍入)
     * @param d1
     * @param d2
     * @param scale 保留scale位小數(shù)
     * @return 不加doubleValue()則, 返回BigDecimal對象
     */
    public static double multiplyDouble(double d1, double d2, int scale) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.multiply(p2).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * double類型的超大數(shù)值的乘法運算(需要舍入)
     * @param d1
     * @param d2
     * @param scale 保留scale位小數(shù)
     * @return 返回字符串,不然double數(shù)字會轉(zhuǎn)成科學計數(shù)法顯示
     */
    public static String multiplyDoubleToStr(double d1, double d2, int scale) {
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.multiply(p2).setScale(scale, BigDecimal.ROUND_HALF_UP).toPlainString();
    }

    /**
     * double類型的除法運算(需要舍入)
     *
     * @param d1
     * @param d2
     * @param scale 保留scale位小數(shù)
     * @return 不加doubleValue()則, 返回BigDecimal對象
     */
    public static double divideDouble(double d1, double d2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("Parameter error");
        }
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.divide(p2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * double類型的超大數(shù)值的除法運算(需要舍入)
     * @param d1
     * @param d2
     * @param scale 保留scale位小數(shù)
     * @return 返回字符串,不然double數(shù)字會轉(zhuǎn)成科學計數(shù)法顯示
     */
    public static String divideDoubleToStr(double d1, double d2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("Parameter error");
        }
        BigDecimal p1 = new BigDecimal(Double.toString(d1));
        BigDecimal p2 = new BigDecimal(Double.toString(d2));
        return p1.divide(p2, scale, BigDecimal.ROUND_HALF_UP).toPlainString();
    }
}

各個roundingMode詳解如下:

  • ROUND_UP:非0時,舍棄小數(shù)后(整數(shù)部分)加1,比如12.49結(jié)果為13,-12.49結(jié)果為 -13
  • ROUND_DOWN:直接舍棄小數(shù)
  • ROUND_CEILING:如果 BigDecimal 是正的,則做 ROUND_UP 操作;如果為負,則做 ROUND_DOWN 操作 (一句話:取附近較大的整數(shù))
  • ROUND_FLOOR: 如果 BigDecimal 是正的,則做 ROUND_DOWN 操作;如果為負,則做 ROUND_UP 操作(一句話:取附近較小的整數(shù))
  • ROUND_HALF_UP:四舍五入(取更近的整數(shù))
  • ROUND_HALF_DOWN:跟ROUND_HALF_UP 差別僅在于0.5時會向下取整
  • ROUND_HALF_EVEN:取最近的偶數(shù)
  • ROUND_UNNECESSARY:不需要取整,如果存在小數(shù)位,就拋ArithmeticException 異常

總結(jié)

到此這篇關(guān)于Java中double精度丟失問題原因及解決辦法的文章就介紹到這了,更多相關(guān)Java double精度丟失問題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java使用kafka發(fā)送和生產(chǎn)消息的示例

    Java使用kafka發(fā)送和生產(chǎn)消息的示例

    本篇文章主要介紹了Java使用kafka發(fā)送和生產(chǎn)消息的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Spring使用@Autowired為抽象父類注入依賴代碼實例

    Spring使用@Autowired為抽象父類注入依賴代碼實例

    這篇文章主要介紹了Spring使用@Autowired為抽象父類注入依賴代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • 全面解析Java中的引用類型

    全面解析Java中的引用類型

    在Java中對象以引用來指向JVM的內(nèi)存區(qū)塊,這里我們總結(jié)了強引用、軟引用、弱引用和假象引用(幽靈引用),下面就具體來全面解析Java中的引用類型:
    2016-05-05
  • idea打包不出現(xiàn)target的原因及解決

    idea打包不出現(xiàn)target的原因及解決

    文章主要介紹了在使用Maven進行項目打包時,`packaging` 屬性的重要性和配置方法,默認情況下,Maven會將項目打包成jar包,如果項目是父級項目,則`packaging`屬性應設置為`pom`,并通過`modules`標簽引入子項目,這樣可以確保項目的模塊化管理和正確的構(gòu)建順序
    2024-11-11
  • 基于Java回顧之多線程詳解

    基于Java回顧之多線程詳解

    在這篇文章里,我們關(guān)注多線程。多線程是一個復雜的話題,包含了很多內(nèi)容,這篇文章主要關(guān)注線程的基本屬性、如何創(chuàng)建線程、線程的狀態(tài)切換以及線程通信,我們把線程同步的話題留到下一篇文章中
    2013-05-05
  • IDEA新建javaWeb以及Servlet簡單實現(xiàn)小結(jié)

    IDEA新建javaWeb以及Servlet簡單實現(xiàn)小結(jié)

    這篇文章主要介紹了IDEA新建javaWeb以及Servlet簡單實現(xiàn)小結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • Java之JSF框架案例詳解

    Java之JSF框架案例詳解

    這篇文章主要介紹了Java之JSF框架案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • SpringBoot 導出數(shù)據(jù)生成excel文件返回方式

    SpringBoot 導出數(shù)據(jù)生成excel文件返回方式

    這篇文章主要介紹了SpringBoot 導出數(shù)據(jù)生成excel文件返回方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • SpringBoot優(yōu)化接口響應時間的九個技巧

    SpringBoot優(yōu)化接口響應時間的九個技巧

    在實際開發(fā)中,提升接口響應速度是一件挺重要的事,特別是在面臨大量用戶請求的時候,本文為大家整理了9個SpringBoot優(yōu)化接口響應時間的技巧,希望對大家有所幫助
    2024-01-01
  • Java?數(shù)據(jù)結(jié)構(gòu)進階二叉樹題集下

    Java?數(shù)據(jù)結(jié)構(gòu)進階二叉樹題集下

    二叉樹可以簡單理解為對于一個節(jié)點來說,最多擁有一個上級節(jié)點,同時最多具備左右兩個下級節(jié)點的數(shù)據(jù)結(jié)構(gòu)。本文將帶你通過實際題目來熟練掌握
    2022-04-04

最新評論