# Bug in BigDecimal#round?

**URL:** <https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627>\
**Category:** Ruby\
**Created:** [September 27, 2007, 12:31am UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627 "2007-09-27T00:31:53Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [September 27, 2007, 12:31am UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/1 "2007-09-27T00:31:53Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [September 27, 2007, 3:47am UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/2 "2007-09-27T03:47:45Z")

</div>

On 9/27/07, Ryan P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> 97, 98, 99]  
> require ‘bigdecimal’  
> }  
> p number\_of\_zeroes\_triggering\_misbehavior  
> 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](http://rubyforge.org/tracker/?func=add&group_id=426&atid=1698)  
> ([rubyforge.org](http://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

---

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [September 27, 2007, 1:26pm UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/3 "2007-09-27T13:26:11Z")

</div>

On 9/27/07, Jano S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
> > 
> > bd = BigDecimal.new(“0.#{‘0’ \* i}7”); [i, bd.round.to\_s]  
> > BigDecimal#round to return nonzero:"  
> > We would be grateful for a pointer to a patch that fixes this issue if  
> > As you have probably noticed, it happens when 1. the number of leading  
> > BigDecimal.new(“0.000000005”).round(-4) #=\> 0.1E5 == 10000

reported as #14271

---

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [September 27, 2007, 3:16pm UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/4 "2007-09-27T15:16:21Z")

</div>

On Sep 27, 6:25 am, “Jano S.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > It seems to me as a bug. The code in trunk is the same, so I guess  
> > it’s not fixed yet.
> 
> reported as #14271

Thank you very much for reporting the bug.

---

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [September 27, 2007, 3:47pm UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/5 "2007-09-27T15:47:31Z")

</div>

On 9/27/07, Ryan P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> On Sep 27, 6:25 am, “Jano S.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > > It seems to me as a bug. The code in trunk is the same, so I guess  
> > > it’s not fixed yet.
> > 
> > reported as #14271
> 
> Thank you very much for reporting the bug.

I guess you can workaround the bug until it gets properly fixed - by  
opening the BigDecimal class. Last night I could not come with  
anything reasonable though 😉

class BigDecimal  
alias\_method :old\_round, :round  
def round(\*args)  
if XXX  
self.class.new(YYY)  
else  
old\_round(\*args)  
end  
end  
end

the problematic parts are XXX and YYY… 😉  
args[0] and self.exponent might be usable…

I haven’t found any unit tests for BigDecimal, so if you create some,  
please post them somewhere (I’m not sure where - possible choises are:  
ruby tracker, [http://rubyforge.org/projects/bfts/](http://rubyforge.org/projects/bfts/) tracker, ruby-core  
mailing list)

Jano

---

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [September 27, 2007, 4:12pm UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/6 "2007-09-27T16:12:11Z")

</div>

On 9/27/07, Jano S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> opening the BigDecimal class. Last night I could not come with  
> end  
> end
> 
> the problematic parts are XXX and YYY… 😉  
> args[0] and self.exponent might be usable…
> 
> I haven’t found any unit tests for BigDecimal, so if you create some,  
> please post them somewhere (I’m not sure where - possible choises are:  
> ruby tracker, [http://rubyforge.org/projects/bfts/](http://rubyforge.org/projects/bfts/) tracker, ruby-core  
> mailing list)

JRuby has some:  
[http://svn.codehaus.org/jruby/trunk/jruby/test/test\_big\_decimal.rb](http://svn.codehaus.org/jruby/trunk/jruby/test/test_big_decimal.rb)

If you come up with some more, you could either submit them as a patch  
there, or post them to ruby-core.

When we get around to BigDecimal in Rubinius, we will probably use the  
JRuby test case as a starting point, and then fill in any gaps we  
find. If you’ve posted some of them to ruby-core, that makes life  
easier.

---

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [October 2, 2007, 5:51am UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/7 "2007-10-02T05:51:10Z")

</div>

From: “Ryan P.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

I haven’t seen the bug yet in detail.  
But I will fix it anyway.  
Thank you for reporting.

removed\_email\_address@domain.invalid

---

<div class="post-metadata">

**Author:** ![parrfolio](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/47e85d/32.png) [@parrfolio](https://www.ruby-forum.com/u/parrfolio)\
**Post date:** [October 9, 2007, 3:16pm UTC](https://www.ruby-forum.com/t/bug-in-bigdecimal-round/115627/8 "2007-10-09T15:16:43Z")

</div>

Subject: Re: Bug in BigDecimal#round ?

I attached the fix as a patch file.  
Could anyone(perhaps Matz ?) apply the patch ?

With a change log like:  
Round method bug pointed by Ryan P. fixed(Patch of the patch from  
“NATORI Shin”).

Thank you in advance.

Shigeo Kobayashi.
