最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA浮點數(shù)計算精度損失底層原理與解決方案

 更新時間:2017年02月14日 09:52:43   作者:星火燎原智勇  
本文主要介紹了JAVA浮點數(shù)計算精度損失底層原理與解決方案。具有很好的參考價值,下面跟著小編一起來看下吧

問題:

對兩個double類型的值進行運算,有時會出現(xiàn)結(jié)果值異常的問題。比如:

  System.out.println(19.99+20);
  System.out.println(1.0-0.66);
  System.out.println(0.033*100);
  System.out.println(12.3/100);

輸出:

39.989999999999995
0.33999999999999997
3.3000000000000003
0.12300000000000001

Java中的簡單浮點數(shù)類型float和double不能夠精確運算。這個問題其實不是JAVA的bug,因為計算機本身是二進制的,而浮點數(shù)實際上只是個近似值,所以從二進制轉(zhuǎn)化為十進制浮點數(shù)時,精度容易丟失,導(dǎo)致精度下降。

關(guān)于精度損失的原理可以很簡單的講,首先一個正整數(shù)在計算機中表示使用01010形式表示的,浮點數(shù)也不例外。

比如11,11除以2等于5余1

       5除以2等于2余1

       2除以2等于1余0

       1除以2等于0余1

所以11二進制表示為:1011.

double類型占8個字節(jié),64位,第1位為符號位,后面11位是指數(shù)部分,剩余部分是有效數(shù)字。

正整數(shù)除以2肯定會有個盡頭的,之后二進制還原成十進制只需要乘以2即可。

舉個例子:0.99用的有效數(shù)字部分,

       0.99 * 2 = 1+0.98 --> 1
       0.98 * 2 = 1+0.96 --> 1
       0.96 * 2 = 1+0.92 -- >1
       0.92 * 2 = 1+0.84 -- >1
         ...............

這樣周而復(fù)始是沒法有盡頭的,而double有效數(shù)字有限,所以必定會有損失,所以二進制無法準(zhǔn)確表示0.99,就像十進制無法準(zhǔn)確表示1/3一樣。

解決辦法:

在《Effective Java》中提到一個原則,那就是float和double只能用來作科學(xué)計算或者是工程計算,但在商業(yè)計算中我們要用java.math.BigDecimal,通過使用BigDecimal類可以解決上述問題,首先需要注意的是,直接使用字符串來構(gòu)造BigDecimal是絕對沒有精度損失的,如果用double或者把double轉(zhuǎn)化成string來構(gòu)造BigDecimal依然會有精度損失,所以我覺得這種解決方法就是在使用中就把浮點數(shù)用string來表示存放,涉及到運算直接用string構(gòu)造double,否則肯定會有精度損失。

1. 相加

/**
 * 相加
 * @param double1
 * @param double2
 * @return
 */
public static double add(String doubleValA, String doubleValB) { 
  BigDecimal a2 = new BigDecimal(doubleValA); 
  BigDecimal b2 = new BigDecimal(doubleValB); 
  return a2.add(b2).doubleValue(); 
}

2. 相減

/**
 * 相減
 * @param double1
 * @param double2
 * @return
 */
public static double sub(String doubleValA, String doubleValB) { 
  BigDecimal a2 = new BigDecimal(doubleValA); 
  BigDecimal b2 = new BigDecimal(doubleValB); 
  return a2.subtract(b2).doubleValue();
}

3. 相乘

/**
 * 相乘
 * @param double1
 * @param double2
 * @return
 */
public static double mul(String doubleValA, String doubleValB) { 
  BigDecimal a2 = new BigDecimal(doubleValA); 
  BigDecimal b2 = new BigDecimal(doubleValB); 
  return a2.multiply(b2).doubleValue();
}

4. 相除

/**
 * 相除
 * @param double1
 * @param double2
 * @param scale 除不盡時指定精度
 * @return
 */
public static double div(String doubleValA, String doubleValB, int scale) { 
  BigDecimal a2 = new BigDecimal(doubleValA); 
  BigDecimal b2 = new BigDecimal(doubleValB);
  return a2.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); 
}

5. 主函數(shù)調(diào)用

public static void main(String[] args) {
  String doubleValA = "3.14159267";
  String doubleValB = "2.358";
  System.out.println("add:" + add(doubleValA, doubleValB));
  System.out.println("sub:" + sub(doubleValA, doubleValB));
  System.out.println("mul:" + mul(doubleValA, doubleValB));
  System.out.println("div:" + div(doubleValA, doubleValB, 8));
}

結(jié)果展示如下所示:

 add:5.49959267
 sub:0.78359267
 mul:7.40787551586
 div:1.33231241

所以最好的方法是完全拋棄double,用string和java.math.BigDecimal。

java遵照IEEE制定的浮點數(shù)表示法來進行float,double運算。這種結(jié)構(gòu)是一種科學(xué)計數(shù)法,用符號、指數(shù)和尾數(shù)來表示,底數(shù)定為2——即把一個浮點數(shù)表示為尾數(shù)乘以2的指數(shù)次方再添上符號。具體底層如何存儲以及如何進行運行請繼續(xù)關(guān)注我的博客,后續(xù)我會將詳情總結(jié)好的。

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!

相關(guān)文章

  • Spring 跨域配置請求詳解

    Spring 跨域配置請求詳解

    這篇文章主要介紹了Spring 跨域配置請求詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • 使用Java編寫導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類

    使用Java編寫導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類

    這篇文章主要為大家詳細介紹了如何使用Java編寫導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • MyBatis實現(xiàn)數(shù)據(jù)庫類型和Java類型的轉(zhuǎn)換

    MyBatis實現(xiàn)數(shù)據(jù)庫類型和Java類型的轉(zhuǎn)換

    MyBatis 在處理數(shù)據(jù)庫查詢結(jié)果或傳遞參數(shù)時,需要將數(shù)據(jù)庫類型與 Java 類型之間進行轉(zhuǎn)換,本文就給大家介紹MyBatis如何實現(xiàn)數(shù)據(jù)庫類型和 Java 類型的轉(zhuǎn)換的,需要的朋友可以參考下
    2024-09-09
  • 全面探究 Java 內(nèi)部類

    全面探究 Java 內(nèi)部類

    說起內(nèi)部類這個詞,想必很多人都不陌生,但是又會覺得不熟悉。原因是平時編寫代碼時可能用到的場景不多,用得最多的是在有事件監(jiān)聽的情況下,并且即使用到也很少去總結(jié)內(nèi)部類的用法。今天我們就來一探究竟
    2021-09-09
  • Spring?Boot?打包成Jar包運行原理分析

    Spring?Boot?打包成Jar包運行原理分析

    這篇文章主要為大家介紹了Spring?Boot?打包成Jar包運行的原理分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • SpringBoot2.0集成Swagger2訪問404的解決操作

    SpringBoot2.0集成Swagger2訪問404的解決操作

    這篇文章主要介紹了SpringBoot2.0集成Swagger2訪問404的解決操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • springboot使用hibernate validator校驗方式

    springboot使用hibernate validator校驗方式

    hibernate validator提供了一套比較完善、便捷的驗證實現(xiàn)方式。下面小編給大家介紹下springboot使用hibernate validator校驗方式,感興趣的朋友一起看看吧
    2018-01-01
  • mybatis if test 不為空字符串且不為null的問題

    mybatis if test 不為空字符串且不為null的問題

    這篇文章主要介紹了mybatis if test 不為空字符串且不為null的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java實現(xiàn)動態(tài)規(guī)劃背包問題

    Java實現(xiàn)動態(tài)規(guī)劃背包問題

    本文主要介紹使用java實現(xiàn)動態(tài)規(guī)劃的背包問題,詳細使用圖文和多種案例進行解析,幫助理解該算法
    2021-06-06
  • Lombok?安裝和使用小技巧

    Lombok?安裝和使用小技巧

    這篇文章主要介紹了Lombok?安裝和使用指南,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05

最新評論

牡丹江市| 旬阳县| 平塘县| 连平县| 喀什市| 吴桥县| 兴隆县| 英超| 墨玉县| 博湖县| 灵寿县| 子长县| 陕西省| 紫阳县| 高邮市| 大埔区| 湟源县| 枣阳市| 威宁| 郸城县| 瓦房店市| 敦化市| 惠水县| 松滋市| 喀喇| 韶山市| 克山县| 江安县| 长宁区| 溆浦县| 喀喇| 茌平县| 永平县| 九江市| 灌阳县| 敦煌市| 巴彦淖尔市| 九龙城区| 铁岭县| 林州市| 老河口市|