Robert Klemme
8/4/2008 3:07:00 PM
2008/8/4 The Podman <poddster@gmail.com>:
[Vectors with floats in them are not equal according to ==.]
> So who is to blame? Me, for not realising that the objects I'm trying to
> compare have two floats somewhere in some array and that I should
> descend into these objects and manually compare their internal data?
I am afraid, yes.
> Whilst in this case it's rather explicit where the problem is, as it's
> just a math's style Vector of Floats, in most cases I won't know the
> implementation details of the objects, I'm dealing with, right? And if
> those objects happened to bring in a Floating point number somewhere,
> how am I to know that a != b purely because of this issue?
>
> Or is it the fault of Vector, for not realising that it'll often have
> floating point numbers stuffed into it and that it should do something a
> bit cleverer that array == array?
No, because a Vector cannot make any assumptions about when you as a
user would consider two floats equivalent (i.e. what is the maximum
delta you would accept - or is it a factor? Does it depend on the
number's sizes etc.).
> Or is it the fault of Float, for not realising that Ruby programmers
> shouldn't have to care about trivial things like two floats being
> 0.00000003e-17 out?
Same here, Float cannot know what your requirements are.
In light of this for library code it is the most reasonable thing to
implement == as binary identity for floats.
> When I get home I'm going to have to make my unit tests care about delta
> difference between two floating point numbers (infact, there's a method
> to help me do that...), but annoyingly I'm going to have to start
> plucking data out of an object and essentially re-implement == between
> two Vectors.
Depending on the lib you might as well be able to calculate the abs
difference of the two Vectors and assert that the result is less than
a Vector with all deltas that you define as constant somewhere.
> Whilst this will fix my problem in this case, I imagine it
> won't fix other people's problems in the general case. So, Ruby fans,
> what should be done? Should this problem exist in a language like Ruby?
Unfortunately there is no general one size fits all solution when it
comes to floating point number equivalence. This is the same for all
languages - apart from algebraic tools such as Mathematica which work
quite different internally.
> Or not? After all, if it quacks like a 27.8 and displays like a 27.8,
> shouldn't Ruby treat it as 27.8?
Well it does, but "27.8" might not be the full truth. You need to
keep in mind that "27.8" is a _decimal representation_ while
internally the number is stored in a _binary representation_.
Conversion between the two introduces errors which is the reason for
the phenomena you (and a lot others) are seeing.
For results that resemble more closely what you would expect you could
use BigDecimal.
17:02:08 bas$ irb -r bigdecimal
Ruby version 1.8.7
irb(main):001:0> a = BigDecimal.new '37.8'
=> #<BigDecimal:7ff91634,'0.378E2',8(8)>
irb(main):002:0> b = BigDecimal.new '27.8'
=> #<BigDecimal:7ff88084,'0.278E2',8(8)>
irb(main):003:0> a - b
=> #<BigDecimal:7ff813b0,'0.1E2',4(16)>
irb(main):004:0> (a - b).to_s
=> "0.1E2"
irb(main):005:0> (a - b) == 10
=> true
irb(main):006:0> "%10.3f" % (a - b)
=> " 10.000"
irb(main):007:0> "%.3f" % (a - b)
=> "10.000"
Kind regards
robert
--
use.inject do |as, often| as.you_can - without end