Java中浮點(diǎn)數(shù)精度問(wèn)題的解決方法
問(wèn)題描述
在項(xiàng)目中用Java做浮點(diǎn)數(shù)計(jì)算時(shí),發(fā)現(xiàn)對(duì)于4.015*100這樣的計(jì)算,結(jié)果不是預(yù)料中的401.5,而是401.49999999999994。如此長(zhǎng)的位數(shù),對(duì)于顯示來(lái)說(shuō)很不友好。
問(wèn)題原因:浮點(diǎn)數(shù)表示
查閱相關(guān)資料,發(fā)現(xiàn)原因是:計(jì)算機(jī)中的浮點(diǎn)數(shù)并不能完全精確表示。例如,對(duì)于一個(gè)double型的38414.4來(lái)說(shuō),計(jì)算機(jī)是這樣存儲(chǔ)它的:
轉(zhuǎn)成二進(jìn)制:1001011000001110.0110011001100110011001100110011001100
轉(zhuǎn)成科
學(xué)計(jì)數(shù)法:1.0010110000011100110011001100110011001100110011001100×2^15
double型編碼格式是這樣的:
double 符號(hào)位1位 階碼11位 尾數(shù)52位
符號(hào)位:正數(shù)統(tǒng)一是0
階碼:15是正數(shù),因此最高位是1,最低位減1,為10000001110
尾數(shù):去掉最高位默認(rèn)的1,為0010110000011100110011001100110011001100110011001100
組合起來(lái),最終得到的編碼是:0 10000001110 0010110000011100110011001100110011001100110011001100
從這里可以看出來(lái),主要原因在于二進(jìn)制編碼使得小數(shù)部分無(wú)法完全精確表示,例如0.4 = 0.25 + 0.125 + ...,只能無(wú)限接近。所以在對(duì)浮點(diǎn)數(shù)做計(jì)算時(shí)會(huì)產(chǎn)生精度誤差。
解決辦法:高精度
Java中的BigDecimal可以支持任意精度的浮點(diǎn)數(shù)運(yùn)算。在《Effective Java 》這本書(shū)中建議:float 和double 用來(lái)做科學(xué)計(jì)算或者是工程計(jì)算,而在商業(yè)計(jì)算中使用java.math.BigDecimal 。
BigDecimal有多種構(gòu)造方法,如BigDecimal(double),BigDecimal(String),需要注意的是:構(gòu)造參數(shù)為String類(lèi)型時(shí)才能保證不丟失精度,因?yàn)閐ouble類(lèi)型本身就是不完全精確的。故需要寫(xiě)成這樣:BigDecimal("0.02")。
double類(lèi)型的基本運(yùn)算都能在BigDecimal中找到相對(duì)應(yīng)的方法。另外,BigDecimal還可以配合NumberFormat做格式化輸出。
BigDecimal在做運(yùn)算的時(shí)候都會(huì)生成新的BigDecimal對(duì)象,因此相對(duì)double來(lái)說(shuō)會(huì)帶來(lái)更多的性能開(kāi)銷(xiāo)。
高精度實(shí)現(xiàn)初探
那么BigDecimal是如何做到能夠表示任意精度的呢?這里只做一個(gè)初步的分析。
首先看BigInteger的實(shí)現(xiàn)。普通的int型是32位,因此有范圍限制。BigInteger中有成員變量int[] mag,這樣變長(zhǎng)的int數(shù)組使得表示任意大小的整數(shù)成為可能。
再看BigDecimal的實(shí)現(xiàn)。它的官方介紹中說(shuō),任意一個(gè)BigDecimal都可以表示為unscaledValue × 10^-scale的形式。unscaledValue是一個(gè)任意大小的整數(shù),在源代碼中對(duì)應(yīng)BigInteger intVal這個(gè)成員變量;scale是階數(shù),在源代碼中對(duì)應(yīng)int scale這個(gè)變量。這樣就在BigInteger的基礎(chǔ)上得到了BigDecimal的實(shí)現(xiàn)。
以上所述是小編給大家介紹的Java中浮點(diǎn)數(shù)精度問(wèn)題的解決方法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)歡迎給我留言。
- Java使用BigDecimal精確運(yùn)算浮點(diǎn)數(shù)
- java.math包下計(jì)算浮點(diǎn)數(shù)和整數(shù)的類(lèi)的實(shí)例
- Java判斷字符串是否是整數(shù)或者浮點(diǎn)數(shù)的方法
- JAVA浮點(diǎn)數(shù)計(jì)算精度損失底層原理與解決方案
- Java中使用BigDecimal進(jìn)行浮點(diǎn)數(shù)運(yùn)算
- java大數(shù)乘法的簡(jiǎn)單實(shí)現(xiàn) 浮點(diǎn)數(shù)乘法運(yùn)算
- java實(shí)現(xiàn)浮點(diǎn)數(shù)轉(zhuǎn)人民幣的小例子
- Java中的浮點(diǎn)數(shù)分析
- Java正確比較浮點(diǎn)數(shù)的方法
相關(guān)文章
Java中為什么要實(shí)現(xiàn)Serializable序列化
在Java編程中,Serializable序列化是一個(gè)常見(jiàn)的概念,它允許對(duì)象在網(wǎng)絡(luò)上傳輸或持久化到磁盤(pán)上,本文將深入探討為什么在Java中要實(shí)現(xiàn)Serializable序列化,并通過(guò)示例代碼來(lái)解釋其重要性2023-10-10Java中保證多線(xiàn)程間的數(shù)據(jù)共享的方法詳解
這篇文章詳解的發(fā)給大家介紹了Java中是如何保證多線(xiàn)程間的數(shù)據(jù)共享的,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-11-11探討:使用httpClient在客戶(hù)端與服務(wù)器端傳輸對(duì)象參數(shù)的詳解
本篇文章是對(duì)使用httpClient在客戶(hù)端與服務(wù)器端傳輸對(duì)象參數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Java隨手筆記8之包、環(huán)境變量和訪問(wèn)控制及maven profile實(shí)現(xiàn)多環(huán)境打包
這篇文章主要介紹了Java隨手筆記8之包、環(huán)境變量和訪問(wèn)控制及maven profile實(shí)現(xiàn)多環(huán)境打包的相關(guān)資料,需要的朋友可以參考下2015-11-11淺談springboot中tk.mapper代碼生成器的用法說(shuō)明
這篇文章主要介紹了淺談springboot中tk.mapper代碼生成器的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09Java程序初始化啟動(dòng)自動(dòng)執(zhí)行的三種方式
這篇文章主要介紹了Java程序初始化啟動(dòng)自動(dòng)執(zhí)行的三種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01