次の仕様を検討してください。
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を使用。