在使用java時運算浮點數會發現有這樣的問題

System.out.println(Double.parseDouble("3.4")-Double.parseDouble("0.8"));

運算出來竟然會是 2.5999999999999996
而不是我們想要的 2.6


其實這問題不是 Java 的bug
double 跟 float 的運算本來就不是一種精確性的運算

因為浮點數可以說是不存在,因為浮點數是一種根據cpu架構上的不同虛擬出來的處理單元
正確的運用在科學運算或是工程上
如果要做精準的商業運算運算要使用 BigDecimal

在 BigDecimal 的說明檔中也有特別註明
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, onthe other hand, is perfectly predictable: new BigDecimal(".1") isexactly equal to .1, as one would expect. Therefore, it is generallyrecommended that the (String) constructor be used in preference to thisone.

我們宣告一個0.1時 ,其實真正的值是 0.1000000000000000055511151231257827021181583404541015625

所以我們在做重複的運算,就會出現無法精準的狀況
為什麼會有這樣的差異用幾個簡單的式子來說明
因為在Java中浮點數是這樣產生的

0.5 = 1/2
0.75 = 1/2 + 1/4
0.875 = 1/2 + 1/4 + 1/8
0.1 = 1/16 + 1/32 + 1/256 + 1/512 +1/4096 + 1/8192 + ......
才會有上述不精準的狀況


所以記得哦!遵循《Effective java》這本書提過的原則
商業運算記得使用 BigDecimal

arrow
arrow
    全站熱搜

    lindsay 發表在 痞客邦 留言(0) 人氣()