我最近在一個項目中開始使用Sonar,並且使用構造函數new BigDecimal(double val)
破壞了PMD規則。當我閱讀java文檔時,發現新的BigDecimal(double val)有點不可預知,我應該使用可預測的new BigDecimal(String val)
。BigDecimal(double)構造函數的不可預測性
這裏是BigDecimal
public BigDecimal(double val)
說什麼的javadoc:
double轉換爲BigDecimal,後者是double的二進制浮點值準確的十進制 表示。返回BigDecimal的比例尺 是(10scale× val)是整數的最小值。
注:
此構造方法的結果有一定的不可預知的。一個 可能會認爲,用Java編寫
new BigDecimal(0.1)
創建BigDecimal
這正好等於0.1(1未測量的值, 爲1的比例),但它實際上是等於 0.1000000000000000055511151231257827021181583404541015625。這是因爲0.1不能完全表示爲雙精度(或者對於任何有限長度的二元分數)。因此,傳遞給構造函數的值 並不完全等於 0.1,儘管如此。String構造,在另一方面,是完全可以預測的: 寫
new BigDecimal("0.1")
創建BigDecimal
是 正好等於0.1,正如人們所期望。因此,一般建議 使用String構造函數而不是此 之一。當必須使用double作爲
BigDecimal
的源時,請注意,此構造函數提供了精確的轉換;它不會給 的結果與使用Double.toString(double)
方法,然後使用構造函數的 方法將double轉換爲字符串的結果相同。要獲得該結果,請使用靜態的valueOf(double)
方法。
爲什麼這個構造函數真的存在? Isnt new BigDecimal(String val)
就夠了嗎?何時應該使用new BigDecimal(double val)
構造函數?
因此,如果我是一個雙值的工作,並轉換爲字符串,然後到bigdecimal,我鬆散的精度?使用例如Double.toString? – gdfbarbosa
你這樣做,因爲Double.toString()是一個棘手的野獸。它並不真正返回你傳遞給它的雙精度值。相反,它返回最短的字符串,在解析時仍然會被轉換爲完全指定的double值。這有點令人困惑,但基本上,這意味着如果Double.toString(0.100000000000000005551115123)爲「0.1」,則確保Double.parseDouble(「0.1」)也是0.100000000000000005551115123。而這個棘手的問題就是爲什麼你失去了精度,但是當你向控制檯輸出雙精度值時,它看起來從未如此。 – LordOfThePigs
由於新的BigDecimal(Double.toString(0.1d))實際上表示精確的「0.1」值,即使0.1d不等於0.1(因爲它實際上是0.100000000000000005551115123),也會發生精度損失。在某些情況下,這種行爲可能是可取的,但在其他一些情況下,這是不可接受的精確度損失。 – LordOfThePigs