Skip to content

Instantly share code, notes, and snippets.

@clemens
Created November 23, 2011 15:14
Show Gist options
  • Save clemens/1388927 to your computer and use it in GitHub Desktop.
Save clemens/1388927 to your computer and use it in GitHub Desktop.
Ruby 1.9.3 BigDecimal bug?
>> require 'bigdecimal'
=> true
>> require 'bigdecimal/util'
=> true
>> BigDecimal('40.30') == 40.3
=> true
>> BigDecimal('40.90') == 40.9
=> true
>> BigDecimal('40.10') == 40.1
=> true
>> BigDecimal('49.10') == 49.1
=> true
>> BigDecimal('69.10') == 69.1
=> false
# WTF?!
@bhuga
Copy link

bhuga commented Nov 23, 2011

can't compare floats to bigdecimals this way. you run in to floating point imprecision. to cast floats to bigdecimal, you need to tell bigdecimal how many digits of precision to use, and if you use all of them for 69.1, you end up at 69.0999999999. you need to compare within a range as with all float comparisons, or never let your data turn in to an actual float.

> x = BigDecimal(69.1, 15)
=> #<BigDecimal:100a35b50,'0.691E2',18(45)> 
> x == BigDecimal('69.1')
=> true
> x = BigDecimal(69.1, 16)
=> #<BigDecimal:100a2a2f0,'0.6909999999 999999E2',27(45)> 
> x == BigDecimal('69.1')
=> false 

@clemens
Copy link
Author

clemens commented Nov 23, 2011

Hey Ben,

thanks for answering. I'm aware that one can run into precision errors here. What I'm wondering, however, is why the comparison works in Ruby 1.8.7 and Ruby 1.9.2 but fails in 1.9.3. Do you have any insights into that?

@bhuga
Copy link

bhuga commented Nov 23, 2011

I see, sorry, I misunderstood the context of the question. The new bigdecimal constructors were added in 1.9.3 (allowing options other than string), so it may well have new coercion semantics for how it interacts with other numerics. And lo and behold, the 1.9.3 changelogs say that coercion semantics for bigdecimal been slightly mucked with, it's halfway down at http://svn.ruby-lang.org/repos/ruby/tags/v1_9_3_0/NEWS.

This particular case is not covered by those changelogs, and it may well be a bug in the intended semantics. But it looks like the implicit precision semantics are being deprecated, and probably this change is a result of the bigdecimal library now examining what it's being compared to and using a 'more correct' precision instead of some random default, which was probably below 16 in the past.

In any case, nasty upgrade gotcha, and making it work for both 1.9.3. and 1.9.2 may be hard, because the 1.9.3. constructors don't exist yet in 1.9.2. Ouch.

@clemens
Copy link
Author

clemens commented Nov 23, 2011

Oh, I see. :(

On the positive side: They've finally added to_d to BigDecimal itself (!) and Integer. I used to have to monkeypatch these ... :)

Anyway, thanks for the hints – I'll fix that some other way, then, I guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment