2011-06-13 57 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()