On 9/27/07, Jano Svitok <jan.svitok / gmail.com> wrote: > On 9/27/07, Ryan Platte <ryan.platte / gmail.com> wrote: > > A coworker discovered some disturbing behavior in BigDecimal#round. > > The output I get from the program below is: > > > > ===== begin output > > > > These values appended to '0.0000' cause BigDecimal#round to return > > nonzero: > > [5, 6, 7, 8, 9, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, > > 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, > > 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, > > 97, 98, 99] > > > > These numbers of zeroes between the decimal point and a 7 cause > > BigDecimal#round to return nonzero: > > [4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, > > 76, 80, 84, 88, 92, 96, 100] > > > > ===== end output > > > > ===== begin code > > > > require 'bigdecimal' > > > > vary_number_after_four_zeroes = (1..100).map { |i| > > bd = BigDecimal.new("0.0000#{i}"); [i, bd.round.to_s] > > } > > seed_values_triggering_misbehavior_with_four_zeroes = > > vary_number_after_four_zeroes.reject {|i, bds| bds == '0.0'}.map {| > > i, bds| i} > > > > vary_number_of_zeroes = (1..100).map { |i| > > bd = BigDecimal.new("0.#{'0' * i}7"); [i, bd.round.to_s] > > } > > number_of_zeroes_triggering_misbehavior = > > vary_number_of_zeroes.reject {|i, bds| bds == '0.0'}.map {|i, bds| > > i} > > > > puts "These values appended to '0.0000' cause BigDecimal#round to > > return nonzero:" > > p seed_values_triggering_misbehavior_with_four_zeroes > > puts > > puts "These numbers of zeroes between the decimal point and a 7 cause > > BigDecimal#round to return nonzero:" > > p number_of_zeroes_triggering_misbehavior > > > > ===== end code > > > > I get identical reports on Linux and Windows versions of Ruby: > > > > ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-linux] > > > > ruby 1.8.6 (2007-03-13 patchlevel 0) [i386-mswin32] > > > > We would be grateful for a pointer to a patch that fixes this issue if > > one is available. > > It seems to me as a bug. The code in trunk is the same, so I guess > it's not fixed yet. > Please file a bug at > http://rubyforge.org/tracker/?func=add&group_id=426&atid=1698 > (rubyforge.org, project ruby) > > The problem is most probably in ext/bigdecimal/bigdecimal.c, VpMidRound(). > > As you have probably noticed, it happens when 1. the number of leading > zeros is divisible by 4 (BASE_FIG, the number of decimal digits stored > in one U_LONG), and the next digit is >= 5 (I guess due to selected > rounding mode) > > That means, the problematic numbers have format 0.XE-Y where X in > [5..9] and Y%4 == 0 > > It's even visible in > BigDecimal.new("0.5").round(-4).to_i # => 10000 > BigDecimal.new("0.000000005").round(4) #=> 0.1E-3 == 0.0001 > BigDecimal.new("0.000000005").round(-4) #=> 0.1E5 == 10000 > reported as #14271