2017-04-21 81 views
2

Oracle中的BINARY_DOUBLE和Java中的Double使用IEEE 754標準。Oracle和Java中的double值之間的區別(IEEE 754)

但它們的準確性有所不同。

例如值:

456.67d

甲骨文:

declare 
    a BINARY_DOUBLE := 456.67d; 
begin 
    SYS.DBMS_OUTPUT.PUT_Line(TO_CHAR(a,'9.99999999999999999999EEEE')); 
end; 

結果:4.56670000000000020000E + 02

的Java:

Double d = 456.67d; 
DecimalFormat formatter = new DecimalFormat("0.000000000000000000000E000"); 
System.out.println(formatter.format(d)); 

結果:4.566700000000000000000E002

Java中的價值並不像甲骨文一樣精確。

在線轉換器說,456.67d最準確的表示是:

4.56670000000000015916157281026E2

那麼,爲什麼在Java中的精度是不一樣的像甲骨文? 而我如何才能在Java中獲得更準確的價值?

回答

3

使用BigDecimal

Double d = 456.67d; 
BigDecimal bd = new BigDecimal(d); 
bd.setScale(50); 
System.out.println(bd); 
DecimalFormat formatter = new DecimalFormat("0.000000000000000000000E000"); 
System.out.println(formatter.format(bd)); 

輸出:

456.67000000000001591615728102624416351318359375 
4.566700000000000159162E002 
1

兩者都是準確的。他們只是採用不同的打印策略。

以下是通過佳樂Smalltalk的打印精確值(但語言沒有關係,這是相同的表示和相同的算術):

d := 456.67. 
{ 
    d predecessor asFraction printShowingMaxDecimalPlaces: 50. 
    d asFraction printShowingMaxDecimalPlaces: 50. 
    d successor asFraction printShowingMaxDecimalPlaces: 50}. 

- >

#(
    '456.6699999999999590727384202182292938232421875' 
    '456.67000000000001591615728102624416351318359375' 
    '456.670000000000072759576141834259033203125' 
)  

因此,任何十進制表示在(d predecessor asFraction + d asFraction)/2 printShowingMaxDecimalPlaces: 50.(d successor asFraction + d asFraction)/2 printShowingMaxDecimalPlaces: 50.之間將被四捨五入爲相同的浮點值(不包括邊界,因爲精確的平局四捨五入爲偶數,並且該浮點具有奇數有效數......)

所以邊界是:

#(
    '456.669999999999987494447850622236728668212890625' 
    '456.670000000000044337866711430251598358154296875' 
) 

甲骨文只使用17位和17,因爲衆所周知,足以區分任何兩個雙精度浮點值不會再打擾數字。

Java更聰明一點:它只使用足夠的數字來區分下一個可表示的浮點值。所以把0,1,2,3或4放在17位,甚至4.5666999999999999e2都沒關係,它仍然是相同的浮點值。