From: Rodrigo Kochenburger Date: 2008-02-08T22:35:04+09:00 Subject: Re: BigDecimal.new('15.25') == 15.25, false ?? On Feb 7, 10:42 pm, Rob Biedenharn wrote: > On Feb 7, 2008, at 6:59 PM, Henry Jones wrote: > > > > > Rob Biedenharn wrote: > >> On Feb 7, 2008, at 5:26 PM, Henry Jones wrote: > > >>> BigDecimal.new('15.25').to_f == 15.25.to_f also returns false. > > >>> Substracting both values returns 1.7763... e-015 > > >>> This is on ruby 1.8.6, Win32. > > >>> I'm a comp. engineer, so I know it's ultimately related to the > >>> binary > >>> value of 15.25 which cannot be precisely represented (without an > >>> infinite number of bits) , but I'm still amazed that such a simple > >>> comparison with a literal value should fail... > > >> 15.25 in decimal > >> is exactly > >> 1111.01 in binary > > >> Seems like a finite number of bits to me ;-) However, the > >> construction of 15.25 as a literal is likely something roughly > >> (1*10^1 > >> + 5*10^0) + (2*10^-1 + 5*10^-2) and those intermediate fractional > >> terms are problematic. > > >> Hey, this is Ruby! Roll your own with === > > >> irb> class Float > >> irb> def ===(other,eps=0.000000001) > >> irb> (self - other.to_f).abs < eps > >> irb> end > >> irb> end > >> => nil > >> irb> require 'bigdecimal' > >> => true > >> irb> 15.25 == BigDecimal.new("15.25") > >> => false > >> irb> 15.25 === BigDecimal.new("15.25") > >> => true > > >> Of course, you'd have to add a similar BigDecimal#=== to get > >> symmetry. > > >> -Rob > > >> Rob Biedenharn http://agileconsultingllc.com > >> R...@AgileConsultingLLC.com > > > Apparently the problem lies with BigDecimal, and not the literal > > value : > > > "%.30f" % 15.25 > > will print : "15.250000000000000000000000000000" (not copy pasted, > > don't count the zeros =) ) > > > but > > "%.30f" % BigDecimal("15.25") > > will print : "15.250000000000002000000000000000" (notice the '2' in > > there) > > -- > > Posted viahttp://www.ruby-forum.com/. > > Well, now you're pulling in the BigDecimal#to_f which isn't so much a > problem in BigDecimal as it is the same limitation of a Float. > > irb> "%.30f" % 15.25 > => "15.250000000000000000000000000000" > irb> require 'bigdecimal' > => [] > irb> "%.30f" % BigDecimal.new('15.25') > => "15.250000000000001776356839400250" > irb> "%.30f" % BigDecimal.new('15.25').to_f > => "15.250000000000001776356839400250" > > And that just gets back to the problem of building the number up from > its decimal pieces: > > irb> "%.30f" % BigDecimal.new('0.05') > => "0.050000000000000002775557561563" > irb> "%.30f" % BigDecimal.new('0.2') > => "0.200000000000000011102230246252" > irb> "%.30f" % BigDecimal.new('5.0') > => "5.000000000000000000000000000000" > irb> "%.30f" % BigDecimal.new('10.0') > => "10.000000000000000000000000000000" > > (and your '2' is off by two places ;-) > > -Rob > > Rob Biedenharn http://agileconsultingllc.com > R...@AgileConsultingLLC.com I agree this is a problem with BigDecimal. The problem is not with the floating point representation: >> "%.30f" % BigDecimal.new("15.00") => "15.000000000000001776356839400250" >> "%.30f" % BigDecimal.new("15.00").to_f => "15.000000000000001776356839400250" >> "%.30f" % 15.00 => "15.000000000000000000000000000000" Also, it looks like it happens on 64bits machines only. This is from a 32bits: >> "%.30f" % BigDecimal.new("15.00") => "15.000000000000000000000000000000" >> "%.30f" % BigDecimal.new("15.00").to_f => "15.000000000000000000000000000000" >> "%.30f" % 15.00 => "15.000000000000000000000000000000" Anybody familiar with the BigDecimal internals could check this, please?