2012-08-31 31 views
8

我最近在一個項目中開始使用Sonar,並且使用構造函數new BigDecimal(double val)破壞了PMD規則。當我閱讀java文檔時,發現新的BigDecimal(double val)有點不可預知,我應該使用可預測的new BigDecimal(String val)BigDecimal(double)構造函數的不可預測性

這裏是BigDecimalpublic 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)構造函數?

回答

5

爲什麼這個構造函數真的存在?

它將實際表示的值double轉換爲BigDecimal。 BigDecimal的要點是儘可能地提供精確性,這就是構造函數的作用。

如果你想利用你與舍入Double.toString(double)少量獲取的價值採用什麼時候應該使用新的BigDecimal可以使用

System.out.println(BigDecimal.valueOf(0.1)); 

打印

0.1 

(雙val)構造函數

當你想知道值double真的代表。您可以根據需要應用您自己的舍入。

當您使用double時,應始終應用合理的舍入。但是,如果你這樣做了,你可能會發現你不需要BigDecimal。 ;)

2

因爲如果您已經開始以double作爲數據值,那麼您已經失去了該精確度。所以沒有它會迫使你將它轉換爲StringBigDecimal將其轉換回來。

而且,也許有時您只需要的值。

+0

因此,如果我是一個雙值的工作,並轉換爲字符串,然後到bigdecimal,我鬆散的精度?使用例如Double.toString? – gdfbarbosa

+3

你這樣做,因爲Double.toString()是一個棘手的野獸。它並不真正返回你傳遞給它的雙精度值。相反,它返回最短的字符串,在解析時仍然會被轉換爲完全指定的double值。這有點令人困惑,但基本上,這意味着如果Double.toString(0.100000000000000005551115123)爲「0.1」,則確保Double.parseDouble(「0.1」)也是0.100000000000000005551115123。而這個棘手的問題就是爲什麼你失去了精度,但是當你向控制檯輸出雙精度值時,它看起來從未如此。 – LordOfThePigs

+1

由於新的BigDecimal(Double.toString(0.1d))實際上表示精確的「0.1」值,即使0.1d不等於0.1(因爲它實際上是0.100000000000000005551115123),也會發生精度損失。在某些情況下,這種行爲可能是可取的,但在其他一些情況下,這是不可接受的精確度損失。 – LordOfThePigs

1

當您想要使用的數據已經存在爲雙精度值時,您將使用雙構造函數。在將其轉換爲BigDecimal之前將其轉換爲字符串在這種情況下將是浪費。

1

When should I use the new BigDecimal(double val) constructor?

優選地 - 不通。

如果你願意玩BigDecimals,那麼使用帶double的構造函數會失去確切數字表示的所有好處。

Why does this constructor really exists?

因爲有時候你只有加倍,你想翻譯爲BigDecimal。強迫你在中間使用.toString()將是愚蠢的;)

0

我想發表評論,但找不出如何「代碼」放到一個評論,所以我回答:

double val = 0.1; // this is not 0.1, but an approximination as pointed out in other answers. BigDecimal biggy = new BigDecimal(val); // this variable conatains the "same" value as val does, however it is not 0.1, but as pointed out in other answers: 0.100000000000000005551115123

所以,在這裏的情況列出,你有充分的在源代碼控制,應該寫入VAL爲「字符串VAL =‘0.1’」

然而構造器BigDecimal(double val)是如果你從文件中讀取二進制雙打有用。顯然你會想在幾乎所有的情況下,BigDecimals是完全一樣的'雙打'

0

不可預知?我不同意。

final double before = 0.1; 
BigDecimal bd = new BigDecimal(before); 
double after = bd.doubleValue(); 
assert before == after; 

關鍵是理解:

assert 0.1 == 0.1000000000000000055511151231257827021181583404541015625; 

如果你真正的意思是 「0.1」,那麼,使用String構造=)但是,如果你有一個double已經,那麼雙不「0.1 」。

你報的JavaDoc的說:

當double必須用作BigDecimal的源時,請注意,這 構造提供了一個確切的轉換;

我不明白精確轉換是如何「不可預知」,我非常贊成從這個引用中刪除「must」一詞。

在一天結束時,兩個構造函數都像預期一樣工作。如果你有字符串「0.1」,那麼BigDecimal(String)就精確地轉換這個值。如果你有一個0.1的雙精度值,那麼BigDecimal(double)精確地轉換這個值。

相關問題