0

考虑以下规范:

require 'bigdecimal'

def total_percent(amounts)
  percent_changes = amounts.each_cons(2).map { |a|
    (a[1] - a[0]) / a[0] * BigDecimal.new('100.0')
  }
  (percent_changes.map { |pc| BigDecimal.new('1') + pc / BigDecimal.new('100') }.inject(BigDecimal.new('1'), :*) - BigDecimal.new('1')) * BigDecimal.new('100')
end

describe 'total_percent' do

  specify {
    values = [10000.0, 10100.0, 10200.0, 10000.0].map { |v|
      BigDecimal.new(v.to_s)
    }
    total_percent(values).class.should == BigDecimal
    total_percent(values).should == BigDecimal.new('0.0')
  }

end

该方法total_percent以百分比计算值列表的总差异。请忽略算法本身(仅查看第一个和最后一个值可以获得相同的结果)。

规范失败,因为计算结果不等于0.0。问题是它在哪里失去了精度。

编辑:在 OS X 10.7.2 上使用 JRuby 1.6.5。

4

2 回答 2

0

并不是说它失去了精度,而是某些部门无法用BigDecimal.

问题是为什么 JRuby 会吞下/定义它应该在 100.0/10200.0 等时抛出的异常。JRuby 可能会定义一个舍入模式,或者它的运算符可能会将自己包装在ArithmeticException由相同计算生成的捕获中(没有舍入模式)在 Java 中(附加在下面)。

尝试设置自己的舍入模式,或进行可接受的增量比较(我忘记了这个术语)。

例外

java.lang.ArithmeticException: Non-terminating decimal expansion;
    no exact representable decimal result.
于 2011-11-23T15:54:02.793 回答
0

这是浮点运算的问题。JRuby 将Java 的BigDecimal类包装到Ruby 的BigDecimal类中。因此,BigDecimal值包含文本表示和实际值之间的微小差异。你不应该==用来比较它们。

请注意,这些规格同样适用于 MRI。

于 2011-11-24T03:14:34.767 回答