Whose fault is my problem?

T

The Podman

I've recently started to write an appliaction in Ruby. It's the first
time I'm using the language. Infact, the only reason I'm using it is
because it's all my friends EEE laptop had on it at the time :) (What?!
No gcc!!?) Still, I've started now so I'll stick with it. Anyway, after
reading the the pickaxe book from cover to cover, I decided to change my
unit tests from a bunch of "puts blahblah, stuff" to those lovely
Test::Unit modules..... and then I encountered a problem.

As some point, I'm asking Ruby to assert_equal(a,b), where a and b are
Vectors (from the matrix.rb file). Unfortunatley one test fails,
specifically in the case where Vector[27.8, 0.0] does not equal
Vector[27.8, 0.0]. After much head scratching and playing about with the
debugger, I realised it's the age old problem of floating point
comparison. For some reason I just didn't expect to have to worry about
this in Ruby! Annoyingly, I don't know how to go about "fixing" my
problem. and my problem is this:

* I want to unit test.
* I want to use assert_equal, because I'm using it for the other 20 or
so tests called by the same looping iterator and it works just fine for
these :}
* Unfortunatley assert_equals calls == on the two objects in question.
* These two objects (in this case) are Vectors. Vector == Vector simply
hands of equality checking to array's == method, asking if Vector.array
== Vector.array.
* Array == iterates though both arrays and uses == between the elements.
* Float == Float does not perform any delta difference checking. In a
way, this is expected. In another way, it's not.

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?
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?

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?

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. 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?
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?

Cheers,
Pod.

ps, you can emulate the problem with a simple bit of "p 37.8 - 10 ==
27.8" -> false.
 
R

Robert Klemme

2008/8/4 The Podman <[email protected]>:

[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
 
W

William Rutiser

The said:
As some point, I'm asking Ruby to assert_equal(a,b), where a and b are
Vectors (from the matrix.rb file). Unfortunatley one test fails,
specifically in the case where Vector[27.8, 0.0] does not equal
Vector[27.8, 0.0]. After much head scratching and playing about with the
debugger, I realised it's the age old problem of floating point
comparison. For some reason I just didn't expect to have to worry about
this in Ruby! Annoyingly, I don't know how to go about "fixing" my
problem. and my problem is this:
You may find something like this useful. Its based on the tolerant
compare function used in APL where it is used as the definition of
equality for floating point numbers. Note that in APL fuzz is actually a
special global that can be set as necessary to change the relative
tolerance. Note that this is quick and dirty code and does not handle
the special case when one of the arguments is zero. This value of fuzz
would be appropriate for "equality within 10 decimal places".

Ruby has a variety of means to extend or modify assert_equal to work
this way.

--------------------------------

def fuzzy_equals( x, y )
fuzz = 1.0E-10
max = [x.abs, y.abs].max
( x - y ).abs / max < fuzz
end

class TC_Fuzzy < Test::Unit::TestCase
def test_01
assert( fuzzy_equals( 17 + 1.0E-10, 17 ) )
assert( fuzzy_equals( 1.7 + 1.0E-10, 1.7 ) )
assert( ! fuzzy_equals( 0.7 + 1.0E-10, 0.7 ) )

assert( fuzzy_equals( 17 - 1.0E-10, 17 ) )
assert( fuzzy_equals( 1.7 - 1.0E-10, 1.7 ) )
assert( ! fuzzy_equals( 0.7 - 1.0E-10, 0.7 ) )

assert( fuzzy_equals( -17 + 1.0E-10, -17 ) )
assert( fuzzy_equals( -1.7 + 1.0E-10, -1.7 ) )
assert( ! fuzzy_equals( -0.7 + 1.0E-10, -0.7 ) )

assert( fuzzy_equals( -17 - 1.0E-10, -17 ) )
assert( fuzzy_equals( -1.7 - 1.0E-10, -1.7 ) )
assert( ! fuzzy_equals( -0.7 - 1.0E-10, -0.7 ) )
end
end
 
G

Gregory Brown

Ruby has a variety of means to extend or modify assert_equal to work this
way.

Test::Unit actually has an assertion for this, better to use it than
roll your own:

require "test/unit"

class FooTest < Test::Unit::TestCase

def test_in_delta
assert_in_delta 17.001, 17.00100001, 0.0001
end

end
 
D

Dejan Dimic

Test::Unit actually has an assertion for this, better to use it than
roll your own:

require "test/unit"

class FooTest < Test::Unit::TestCase

  def test_in_delta
    assert_in_delta 17.001, 17.00100001, 0.0001
  end

end

Just to add that this is an universal programming issue present in all
programming languages that deals with floats without any assumptions.
You should get used to it and always kip in mind when using floats,
doubles, double precision or currency data types even some date and
time data types that internally stored as double or float.

That is one of the small things that make our lives more
interesting. :)
 
D

Daniel Moore

* Float == Float does not perform any delta difference checking. In a
way, this is expected. In another way, it's not.

If you don't like the == method of Float just crack it open and change it:

a = 12.60000000000001
b = 12.59999999999999

puts a
puts b

puts a == b # => false

class Float
def ==(other)
fuzz = 1.0E-10
max = [self.abs, other.abs].max
( self - other ).abs / max < fuzz
end
end

puts a == b # => true

I would only recommend doing this for your tests though, other code
might want the original == method intact.
 
S

Stefan Lang

2008/8/4 Daniel Moore said:
* Float == Float does not perform any delta difference checking. In a
way, this is expected. In another way, it's not.

If you don't like the == method of Float just crack it open and change it:

a = 12.60000000000001
b = 12.59999999999999

puts a
puts b

puts a == b # => false

class Float
def ==(other)
fuzz = 1.0E-10
max = [self.abs, other.abs].max
( self - other ).abs / max < fuzz
end
end

puts a == b # => true

I would only recommend doing this for your tests though, ...

I think that's a bad strategy. If he has == comparisons of Float
in his code where a delta check would be the right thing,
this would hide it from the tests.

Stefan
 
L

Lee Griffiths

Di said:
* Float == Float does not perform any delta difference checking. In a
way, this is expected. In another way, it's not.

If you don't like the == method of Float just crack it open and change
it:

a = 12.60000000000001
b = 12.59999999999999

puts a
puts b

puts a == b # => false

class Float
def ==(other)
fuzz = 1.0E-10
max = [self.abs, other.abs].max
( self - other ).abs / max < fuzz
end
end

puts a == b # => true

I would only recommend doing this for your tests though, other code
might want the original == method intact.


I did just that for this project. :) Well, not exactly that, but
something similiar (I copied and pasted it from an old C file I had). I
still have the old == aliased as "old_equ". Infact my new equ method
uses it as an inital check.

I'm used to dealing with floats. I _know_ the ways in which they should
be compared. However, right now I don't require my points to be deadly
accurate. I'll be happy just as long as they're floating. I also don't
see Ruby being used for precise mathmatical simulations (even though
that's what I'm using it for. Erk!) and think it should have some built
in support for delta-comparison. After all, if it's happy enough to
display something as "2.85", why can't it just treat it like 2.85?*
Sometimes that 0.3e-27 really, really isn't important and should just
/go away/ and stop ruining things :)

My main issue that sparked the first post was that so many things will
just assume == gives the correct result. It does give the correct
result, but my problem is when they're imbedded deep inside two objects
that are compared to each other using ==, and these objects just naivey
ask all their internal attributes if they == other.attribute . So why
doesn't Ruby have, by default:

a) a built in =~ or Float#approx(other) method?
b) The ability to "switch on" and "off" wether == or =~ is used whenever
== is called (I hope that makes sense!)?

Whilst for now my extensions to Float will do (for me, at least), I
think that the default Ruby float class should deal with this issue
without having to drag up BigDecimal. What do you all think? Is built in
fuzzy checking, and the option to use it on or off to much to ask?

* Of course, to many people the 0.3e-27 difference is very important,
but those people could turn off the fuzzy checking :)
 
R

Robert Klemme

2008/8/5 Lee Griffiths said:
My main issue that sparked the first post was that so many things will
just assume == gives the correct result. It does give the correct
result, but my problem is when they're imbedded deep inside two objects
that are compared to each other using ==, and these objects just naivey
ask all their internal attributes if they == other.attribute . So why
doesn't Ruby have, by default:

a) a built in =~ or Float#approx(other) method?
b) The ability to "switch on" and "off" wether == or =~ is used whenever
== is called (I hope that makes sense!)?

Whilst for now my extensions to Float will do (for me, at least), I
think that the default Ruby float class should deal with this issue
without having to drag up BigDecimal. What do you all think? Is built in
fuzzy checking, and the option to use it on or off to much to ask?

I believe the problem with this is its high potential for catastrophe:
assume you have a bit of code that uses a library which in turn uses
another lib. You switch fuzzy on but it is not selective, i.e. will
affect all comparisons - in both libs, one of them you might not even
be aware of using. Code written with the assumption that the flag is
switched off will go awry.

After all, there is a standard and I believe it is a bad idea to allow
standard classes to deviate from that. And embedding the flag switch
in code that requires standard behavior will clutter it quite a lot.

IMHO the proper solution would be to craft your own float math class
that just wraps a Float and implements == the way you like while
otherwise behaving as float. I would not mess with Float#== not even
temporarily.

Kind regards

robert
 
D

Dave Bass

I think it may be best to regard floats conceptually as reals.
Mathematics tells us that almost all reals are irrational and almost
none of them are rational. That means that almost every comparison of
the form x == 2.85 (where the LHS is real and the RHS is rational) will
be false.

Therefore the best guidance, often seen in Programming 101, is "Never
compare floats for equality!" The only numbers that are guaranteed to be
exact in a computer are integers, so one should only compare integers
for equality.

Of course in a computer we're always dealing with rational numbers (due
to finite precision) so this isn't quite true, but it's a good guiding
principle.

Using a fuzzy comparison dressed up as an exact comparison is a bad idea
IMHO. If you want to do that, do it explicitly, something like
assert_in_delta.

In many years of numerical simulation work (Fortran, C, Perl, ...) I've
never had to compare floats for equality. There has always been a better
way to do the job.

Dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top