On Feb 8, 2008, at 8:35 AM, Rodrigo Kochenburger wrote:
> On Feb 7, 10:42 pm, Rob Biedenharn <R... / AgileConsultingLLC.com>
> 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?


Well, my machine is only 32bits.  You shouldn't have a problem with  
small integers.  It's when you attempt to represent some fractional  
decimal values in binary.  Now, if you wanted to say something about  
the apparent difference between BigDecimal#to_f and String#to_f, then  
you could be onto something.

irb> require 'bigdecimal'
=> true
irb> "%.30f" % (61.0/4.0)
=> "15.250000000000000000000000000000"
irb> (61.0/4.0) == 15.25
=> true
irb> "%.30f" % 15.25
=> "15.250000000000000000000000000000"
irb> "%.30f" % BigDecimal.new("15.25")
=> "15.250000000000001776356839400250"
irb> "%.30f" % BigDecimal.new("15.25").to_s.to_f
=> "15.250000000000000000000000000000"

-Rob

Rob Biedenharn		http://agileconsultingllc.com
Rob / AgileConsultingLLC.com