Created
December 5, 2011 14:25
-
-
Save nmk/1433735 to your computer and use it in GitHub Desktop.
Testing percent summation using BigDecimal values
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'bigdecimal' | |
require 'benchmark' | |
require 'rspec/autorun' | |
module Calculator | |
ONE = BigDecimal('1') | |
ONE_HUNDRED = BigDecimal('100') | |
DECIMAL_ROUNDING_SCALE = 6 # number of fractional digits to retain | |
# no rounding | |
def self.sum_percent_deltas_procedural_no_rounding(pds) | |
result = ONE | |
pds.each { |pd| | |
result = (result * (1 + pd / ONE_HUNDRED)) | |
} | |
(result - 1) * ONE_HUNDRED | |
end | |
# rounding each intermediate result | |
def self.sum_percent_deltas_procedural_intermediate_rounding(pds) | |
result = ONE | |
pds.each { |pd| | |
# There is no need to call #round explicitly. | |
# BigDecimal#mult supports # inherent rounding to a specified scale. | |
# | |
# See http://ruby-doc.org/stdlib-1.8.7/libdoc/bigdecimal/rdoc/BigDecimal.html#method-i-mult | |
result = result.mult(ONE + pd / ONE_HUNDRED, DECIMAL_ROUNDING_SCALE) | |
} | |
(result - 1) * ONE_HUNDRED | |
end | |
end | |
NR_OF_ELEMENTS = 2_000 | |
PERCENT_DELTAS = Array.new(NR_OF_ELEMENTS) { i = rand * 100.0 - 50.0; BigDecimal.new(i.to_s, 6) } | |
Benchmark.bm(60) do |x| | |
Calculator.singleton_methods.sort.each do |meth| | |
x.report(meth.to_s) { Calculator.send(meth, PERCENT_DELTAS) } | |
end | |
end | |
describe Calculator do | |
GOLD_STANDARD = Calculator.sum_percent_deltas_procedural_no_rounding(PERCENT_DELTAS) | |
context 'comparing non-rounded results' do | |
result = Calculator::sum_percent_deltas_procedural_intermediate_rounding(PERCENT_DELTAS) | |
specify { result.should_not == GOLD_STANDARD } | |
specify { result.should be_within(BigDecimal('0.00001')).of(GOLD_STANDARD) } | |
end | |
context 'comparing rounded results' do | |
result = Calculator::sum_percent_deltas_procedural_intermediate_rounding(PERCENT_DELTAS).round(Calculator::DECIMAL_ROUNDING_SCALE) | |
rounded_gold_standard = GOLD_STANDARD.round(Calculator::DECIMAL_ROUNDING_SCALE) | |
specify { result.should_not == GOLD_STANDARD } | |
specify { result.should be_within(BigDecimal('0.00001')).of(rounded_gold_standard) } | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
~ $ rvm 1.9.3,1.9.2,1.6.5@us exec ruby -rrubygems big-decimal-test.rb -- INSERT -- | |
user system total real | |
sum_percent_deltas_procedural_intermediate_rounding 0.010000 0.000000 0.010000 ( 0.011952) | |
sum_percent_deltas_procedural_no_rounding 0.150000 0.010000 0.160000 ( 0.156943) | |
.... | |
Finished in 0.49579 seconds | |
4 examples, 0 failures | |
user system total real | |
sum_percent_deltas_procedural_intermediate_rounding 0.010000 0.000000 0.010000 ( 0.004836) | |
sum_percent_deltas_procedural_no_rounding 0.180000 0.010000 0.190000 ( 0.189087) | |
.... | |
Finished in 0.66567 seconds | |
4 examples, 0 failures | |
user system total real | |
sum_percent_deltas_procedural_intermediate_rounding 0.728000 0.000000 0.728000 ( 0.728000) | |
sum_percent_deltas_procedural_no_rounding 17.135000 0.000000 17.135000 ( 17.136000) | |
.... | |
Finished in 38.6 seconds | |
4 examples, 0 failures |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment