2011-06-13 59 views
3

給出以下行Groovy的BigDecimal的精度問題

BigDecimal step = 10.0G**-1.0G 

常規1.7.5返回錯誤

0.1000000000000000055511151231257827021181583404541015625 

和Groovy 1.8返回正確的

0.1 

不幸的是,我想在Grails中解決我的問題。 1.4使用Groovy 1.8不夠穩定,但(控制器未處於開發模式刷新)和Grails 1.3.7帶有常規1.7.x

兩個問題:

  • 我做錯了什麼或這是1.7.5中的錯誤嗎?

  • 我該如何避免這種行爲?我通過BigDecimals來完善這種舍入問題嗎?

第二更新:(忘記第一更新) - ;

我現在感到有點困惑。看來,我得到每次我試圖不同的結果....:

BigDecimal step = 10.0G**-1.0G 
println step 

回報0.1000000000000000055511151231257827021181583404541015625

println 10.0G**-1.0G 

回報

0.1 

兩個常規版本。

但是,如果您只需將BigDec step = 10.0G**-1.0G放入groovyConsole並讓控制檯輸出最後一個響應,您將得到不同常規版本的不同結果。所以一個問題似乎是groovyConsole。

另一個問題似乎是執行的toString轉換。

而且似乎有些自動裝箱參與......當我做了

def step = 10.0G**-1.0G 

結果是雙...

我想這下沸騰的問題兩個問題:

  • a)哪些數學運算是BigDecimal運算?

  • 二)我怎麼能輕鬆地圓一個BigDecimal,這樣我可以糾正上述問題?

感謝名單的耐心

+1

如果只是在groovy控制檯,它仍然是一個問題? – RonK 2011-06-13 15:45:36

+0

是的。主要問題是我的計算會遇到這些舍入問題。我雖然已經用上面的例子對它進行了跟蹤。我會嘗試再次追蹤它。請繼續關注... :-) – rdmueller 2011-06-13 17:19:49

回答

4

我想我已經明白了。下面是從Java文檔的線索:

BigDecimal的(雙VAL) double轉換爲BigDecimal其爲確切小數 double的二進制 浮點值的表示。

  • 因此,Math.-功能我在代碼中使用似乎不支持的BigDecimal。
  • 將結果轉換從雙幕後BIGDECIMAL的
  • 確切表示double的二進制0.1000000000000000055511151231257827021181583404541015625當雙是0.1
  • println 10.0G**-1.0G打印雙值(0.1
  • BigDecimal step = 10.0G**-1.0G; println step打印雙重0.1的BigDecimal表示,這是上面醜陋的數字

groovy版本的行爲似乎沒有區別(關於BigDecimals),但是在groovyConsole中如何輸出結果的行爲有所不同。

1

我懷疑是10.0G ** - 1.0G變成Math.pow(10,-1),math.pow返回一個double,然後給出了一個舍入錯誤。 要避免它,如果你只升到-1,你可以將它作爲一個部門(1.0G/10.0G)來實現。這就是說,我不太瞭解Groovy,所以我的猜測可能是錯誤的,但這當然是它的樣子,並且它由Groovy的文檔說了什麼。

+0

在這個例子中,用簡單的代碼替換數學函數的好主意。不幸的是,我的代碼使用了更多的數學函數(例如日誌)。有沒有特殊的BigMath功能? – rdmueller 2011-06-13 07:20:04

+1

不是我知道的標準java。你需要多少精度?如果小於16位數字,則可以使用雙打。如果更多,你需要看看使用外部庫或寫自己的。在編寫你自己的BigDecimal實現的時候,有一些關於堆棧溢出的問題,比如[log](http://stackoverflow.com/questions/739532/logarithm-of-a-bigdecimal) – Sysyphus 2011-06-13 07:40:02

+0

它的精確度並不是很高。我更想避免那些舍入誤差......-不容易解釋。它是繪製圖表軸的代碼。 – rdmueller 2011-06-13 08:47:08

2

我使用Groovy 1.7.5和我10.0G**-1.0G回報0.1

的JDK,你上運行?

+0

hm。兩個groovyConsole從環境變量中讀取爲JAVA_HOME jdk1.6.0_21 ...但似乎有一個'BigDecimal step = 10.0G ** - 1.0G ; println step'和'println 10.0G ** - 1.0G' ... – rdmueller 2011-06-13 15:01:20

+0

請參閱我的更新。 – rdmueller 2011-06-13 15:10:34

1

如果你想從Double轉換到BigDecimal而不是獲得所有的額外數字,一種方法是將Double放入一個String中,然後將其轉換爲BigDecimal,這將防止所有額外的數字來從確切二進制表示的雙。

Double someFraction = 1.23456789 
BigDecimal sameFraction = "${someFraction}".toBigDecimal()