日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Java double轉BigDecimal的注意事項說明

瀏覽:157日期:2022-08-18 09:08:39
先上結論:

不要直接用double變量作為構造BigDecimal的參數。

線上有這么一段Java代碼邏輯:

1,接口傳來一個JSON串,里面有個數字:57.3。

2,解析JSON并把這個數字保存在一個float變量。

3,把這個float變量賦值給一個 BigDecimal對象,用的是BigDecimal的double參數的構造:

new BigDecimal(double val)

4,把這個BigDecimal保存到MySQL數據庫,字段類型是decimal(15,2)。

這段代碼邏輯在線上跑了好久了,數據庫保存的值是57.3也沒什么問題,但是在今天debug的時候發現,第三步的BigDecimal對象保存的值并不是57.3,而是57.299999237060546875,很明顯,出現了精度的問題。

至于數據庫最終保存了正確的57.3完全是因為字段類型設置為2位小數,超過2位小數就四舍五入,所以才得到了正確的結果,相當于MySQL給我們把這個精度問題掩蓋了。

總覺得這是個坑,所以研究了一下相關的知識。

首先是BigDecimal的double參數構造,在官方JDK文檔中對這個構造是這么描述的:

public BigDecimal(double val)

Translates a double into a BigDecimal which is the exact decimal representation of the double’s binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.

Notes:

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal('0.1') creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.

When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.

Parameters:

val - double value to be converted to BigDecimal.

Throws:

NumberFormatException - if val is infinite or NaN.

翻譯一下大概是這樣的:

1,BigDecimal(double val)構造,用double當參數來構造一個BigDecimal對象。

2,但是這個構造不太靠譜(unpredictable),你可能以為BigDecimal(0.1)就是妥妥的等于0.1,但是你以為你以為的就是你以為的?還真不是,BigDecimal(0.1)這貨實際上等于0.1000000000000000055511151231257827021181583404541015625,因為準確的來說0.1本身不能算是一個double(其實0.1不能代表任何一個定長二進制分數)。

3,BigDecimal(String val)構造是靠譜的,BigDecimal(“0.1”)就是妥妥的等于0.1,推薦大家用這個構造。

4,如果你非得用一個double變量來構造一個BigDecimal,沒問題,我們貼心的提供了靜態方法valueOf(double),這個方法跟new Decimal(Double.toString(double))效果是一樣的。

說白了就是別直接拿double變量做參數,最好使用String類型做參數或者使用靜態方法valueOf(double),我寫了個例子試了一下:

public static void main(String[] args) { float a=57.3f; BigDecimal decimalA=new BigDecimal(a); System.out.println(decimalA); double b=57.3; BigDecimal decimalB=new BigDecimal(b); System.out.println(decimalB); double c=57.3; BigDecimal decimalC=new BigDecimal(Double.toString(c)); System.out.println(decimalC); double d=57.3; BigDecimal decimalD=BigDecimal.valueOf(d); System.out.println(decimalD); }

輸出結果:

57.29999923706054687557.299999999999997157829056959599256515502929687557.357.3

以后還是盡量按照官方推薦的套路來,否則不知道什么時候又給自己挖坑了。

補充:double轉bigDecimal精度問題

float的精度 : 2^23 7位

double的精度: 2^52 16位

十進制 轉 二進制 存在精度差

double g= 12.35;BigDecimal bigG=new BigDecimal(g).setScale(1, BigDecimal.ROUND_HALF_UP); //期望得到12.4System.out.println(“test G:”+bigG.doubleValue());test G:12.3原因:

定義double g= 12.35; 而在計算機中二進制表示可能這是樣:定義了一個g=12.34444444444444449,

new BigDecimal(g) g還是12.34444444444444449new BigDecimal(g).setScale(1, BigDecimal.ROUND_HALF_UP); 得到12.3正確的定義方式是使用字符串構造函數:

new BigDecimal(“12.35”).setScale(1, BigDecimal.ROUND_HALF_UP)

首先得從計算機本身去討論這個問題。我們知道,計算機并不能識別除了二進制數據以外的任何數據。無論我們使用何種編程語言,在何種編譯環境下工作,都要先 把源程序翻譯成二進制的機器碼后才能被計算機識別。以上面提到的情況為例,我們源程序里的2.4是十進制的,計算機不能直接識別,要先編譯成二進制。但問 題來了,2.4的二進制表示并非是精確的2.4,反而最為接近的二進制表示是2.3999999999999999。原因在于浮點數由兩部分組成:指數和尾數,這點如果知道怎樣進行浮點數的二進制與十進制轉換,應該是不難理解的。如果在這個轉換的過程中,浮點數參與了計算,那么轉換的過程就會變得不可預 知,并且變得不可逆。我們有理由相信,就是在這個過程中,發生了精度的丟失。而至于為什么有些浮點計算會得到準確的結果,應該也是碰巧那個計算的二進制與 十進制之間能夠準確轉換。而當輸出單個浮點型數據的時候,可以正確輸出,如

double d = 2.4;System.out.println(d);

輸出的是2.4,而不是2.3999999999999999。也就是說,不進行浮點計算的時候,在十進制里浮點數能正確顯示。這更印證了我以上的想法,即如果浮點數參與了計算,那么浮點數二進制與十進制間的轉換過程就會變得不可預知,并且變得不可逆。

事實上,浮點數并不適合用于精確計算,而適合進行科學計算。這里有一個小知識:既然float和double型用來表示帶有小數點的數,那為什么我們不稱 它們為“小數”或者“實數”,要叫浮點數呢?因為這些數都以科學計數法的形式存儲。當一個數如50.534,轉換成科學計數法的形式為5.053e1,它 的小數點移動到了一個新的位置(即浮動了)。可見,浮點數本來就是用于科學計算的,用來進行精確計算實在太不合適了。

在《Effective Java》這本書中也提到這個原則,float和double只能用來做科學計算或者是工程計算,在商業計算中我們要用java.math.BigDecimal。使用BigDecimal并且一定要用String來夠造。

BigDecimal用哪個構造函數?

BigDecimal(double val)BigDecimal(String val)

上面的API簡要描述相當的明確,而且通常情況下,上面的那一個使用起來要方便一些。我們可能想都不想就用上了,會有什么問題呢?等到出了問題的時候,才發現參數是double的構造方法的詳細說明中有這么一段:

Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding.

The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal('.1') is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.

原來我們如果需要精確計算,非要用String來夠造BigDecimal不可!

簡單來說 精確計算 ,需要用到bigDeicmal的String 構造

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持好吧啦網。如有錯誤或未考慮完全的地方,望不吝賜教。

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
中文字幕在线看片| 国产精品一区二区三区av麻| 蜜臀国产一区二区三区在线播放 | 亚洲精品日本| 夜鲁夜鲁夜鲁视频在线播放| 国产福利资源一区| 日本三级亚洲精品| 中文字幕一区二区三区四区久久| 女主播福利一区| 欧美日韩精品在线一区| 精品一区视频| 欧美xxxx性| 国产精品综合色区在线观看| 蜜臀久久99精品久久久久久9| 欧美日韩国产探花| 久久精品播放| 亚洲精品.com| 日韩大片免费观看| 国产成人精品免费视| 欧美日韩亚洲一区三区| 欧美偷窥清纯综合图区| 国产日韩中文在线中文字幕| 亚洲精品在线二区| 日韩精品亚洲专区| 日韩久久99| 日韩精品五月天| 一区二区高清| 日韩中文字幕无砖| 青青草精品视频| 欧美久久一区二区三区| 91在线成人| 国产女人18毛片水真多18精品| 日韩国产在线观看| 国产精品视频一区二区三区四蜜臂 | 国产中文在线播放| 成人在线观看免费视频| 久久精品午夜| 日韩黄色大片网站| 久久婷婷一区| 不卡一区综合视频| 国产一区成人| 亚洲va久久久噜噜噜久久| 日韩不卡免费视频| 国产精品久久久久久久久免费高清 | 黄色网一区二区| 久久一区精品| 92国产精品| 欧美日韩国产传媒| 综合色就爱涩涩涩综合婷婷| 丝袜诱惑制服诱惑色一区在线观看| 免费在线观看不卡| 综合激情视频| 91精品国产自产在线丝袜啪| 天堂久久av| 欧美精品91| 老鸭窝一区二区久久精品| 97在线精品| 狠狠色狠狠色综合日日tαg| 日韩精品91亚洲二区在线观看| 国产欧美另类| 日本欧美不卡| 亚洲精品观看| 国产中文字幕一区二区三区| 欧美精品自拍| 国产欧美日韩一区二区三区四区 | 欧美成人一二区| 午夜av成人| 亚洲综合精品四区| 欧美性www| 日韩毛片在线| 一区二区三区四区日韩| 亚洲精品影院在线观看| 美女国产一区二区三区| 国产国产精品| 国产精品羞羞答答在线观看| 欧美.日韩.国产.一区.二区| 日韩av在线免费观看不卡| 精品三区视频| 中文亚洲欧美| 免费在线观看一区| 久久精品在线| 久久精品97| 日韩激情一区| 日本久久一区| 久久香蕉国产| 国产精品欧美在线观看| 日韩一级精品| 久久精品人人| 亚洲午夜免费| 亚洲www啪成人一区二区| 欧美有码在线| 亚洲男女av一区二区| 欧美成人一二区| 噜噜噜久久亚洲精品国产品小说| 你懂的国产精品永久在线| 亚洲激情二区| 精品免费视频| 亚洲精品乱码日韩| 老司机精品视频网| 蜜臀a∨国产成人精品| 波多野结衣久久精品| 日本精品另类| 不卡在线一区| 色一区二区三区| 日韩av网站在线免费观看| 亚洲天堂久久| 国产a亚洲精品| 91亚洲无吗| 久久国产精品久久久久久电车| 国产一区二区久久久久| 日韩欧美中文字幕在线视频| 极品裸体白嫩激情啪啪国产精品| 麻豆中文一区二区| 99国产精品视频免费观看一公开| 国产66精品| 国产精品一站二站| 亚洲另类视频| 亚洲精品1区2区| 日韩啪啪电影网| 九九99久久精品在免费线bt| 欧美亚洲自偷自偷| 日韩影院免费视频| 久久中文视频| 日本免费久久| 久久在线91| 国产乱码精品一区二区三区四区| 亚洲乱码一区| 免费人成在线不卡| 成人免费电影网址| 久久久久久色| 久久裸体视频| 国产中文欧美日韩在线 | 日韩亚洲精品在线| 99久久夜色精品国产亚洲1000部| 久久99国产精品视频| 欧美日韩一区自拍| 亚洲精品影院在线观看| 免费日韩视频| 亚洲作爱视频| 好吊视频一区二区三区四区| 亚洲午夜视频| 国产白浆在线免费观看| 精品国产乱码久久久久久樱花 | 伊人久久婷婷| 日韩一区二区久久| 婷婷综合网站| 欧美在线网站| 国产亚洲精品自拍| 尹人成人综合网| 亚洲免费播放| 免费在线观看日韩欧美| 免费国产亚洲视频| 亚洲ab电影| 日本色综合中文字幕| 精品捆绑调教一区二区三区| 久久国产日韩| 五月精品视频| 欧美一区=区| 亚洲男人在线| 欧美精品三级在线| 久久成人高清| 毛片在线网站| 久久三级福利| 欧美成人久久| 玖玖精品视频| 日韩欧美中文字幕在线视频| 亚洲精品一级| 欧美日韩 国产精品| 国产精品久久久久毛片大屁完整版| 日本欧美一区二区| 欧美精品aa| 国产欧美日韩精品一区二区三区| 麻豆传媒一区二区三区| 美女av在线免费看| 久久麻豆精品| 三级一区在线视频先锋| 亚洲人妖在线| 国产精品一线| 国产精品啊v在线| 久久中文在线| 国产福利片在线观看| 久久精品官网| 欧美a级一区| 香蕉精品久久| 99国内精品| 亚洲精品欧美| 国产激情一区| 精品国模一区二区三区| 在线亚洲成人| 久久精品99国产精品| 国产中文在线播放| 最新亚洲一区| 欧美日韩一区二区三区不卡视频 | 影音先锋久久| 精品视频自拍| 亚洲理论在线| 激情综合自拍| 国产一区二区三区免费在线| 亚洲色图网站| 激情欧美一区二区三区|