On Thu, Jan 26, 2012 at 2:58 PM, Gavin Sinclair <gsinclair / gmail.com> wrote=
:
> On Thu, Jan 26, 2012 at 7:33 PM, Intransition <transfire / gmail.com> wrote=
:
>> Seriously? You blame the example? Reminds me of that old joke.
>>
>> Patient: "Doctor, it hurts when I do this."
>> Doctor: =A0"Well, don't do that!"
>>
>> The problem is you're looking at in only as an engineer might, dealing w=
ith
>> very small deltas. But as an=A0implementer=A0of such a method as #close_=
to? or
>> #approx? I would never assume there are no valid applications that are
>> concerned with bulkier scales.
>
> We're talking at cross purposes here, and Yossef's impoliteness
> doesn't help. =A0Implementing #close_to? or #approx? is trivial, and
> yes, it needs to provide for different applications. =A0But talking
> about Float#approx?, you may as well be talking about String#approx?,
> as in "foobar".approx?("foobaz").
>
> But that has nothing to do with this thread. =A0(Of course, it's a long
> thread and can take in different aspects of the topic, but...) You
> started the thread complaining that 1.1 - 1.0 was not equal to 0.1,
> that Ruby lacked "math skills".
>
> The answer to that is: don't use Float.=3D=3D. =A0It's a revealing answer=
,
> because the natural follow-up question is "Why does the language
> provide a useless method but not provide a useful replacement?". =A0When
> it comes to floats, everyone has to be aware of their shortcomings and
> roll their own comparison method.

+1

> If your application demands you use some implementation of #approx?
> with a specific delta -- e.g. collision detection in a game -- then
> we're talking about an application-specific problem that is NOT caused
> by the underlying representation of floats.
>
> If your application would like to use "x =3D=3D 4.75" but can't, this is
> NOT an application-specific problem; it's a float representation
> problem.

But doesn't this boil down to the question: what algorithm do we want
to use to determine both as equivalent?  We know that x is in binary
representation and 4.75 is a decimal representation of a number.  But
every literal is converted to binary representation, likely by the
parser or other stage before runtime evaluation.  And for reasons of
simplicity, speed and consistency that translation will always be the
same - regardless whether the literal appears in a comparison,
assignment or other expression.  So in "x =3D=3D 4.75" both values have
the same representation.  And all comparisons which do not directly
compare the binary representation must apply some algorithm.  That's
the same problem solved by #approx?: input two floats, output true /
false.  All of these algorithms I know need a third input (even if it
is hard coded into the algorithm).

> "x =3D=3D 4.75" needs to be replaced by something. =A0Should it be
> "x.approx?(4.75)" ? =A0No. =A0That's using an application-layer approach
> to a non-application-layer problem.
>
> "x =3D=3D 4.75" should be replaced with x.essentially_equals?(4.75), whic=
h
> tackles the representation problem, not the non-existent application
> problem.

There is no common definition of Float#essentially_equals? hence it
cannot be implemented in core library.  The reason is that these
questions can only be answered application specifically:

- What algorithm do we want to use to determine "essentially equality"
(difference, factor, decimal representation)?
- What value for the difference or factor do we use?  Put informally:
what is the level of imprecision that we accept to call two floats
"essentially equal"?

With decimal representation I mean something like this:

class Float
  def essentially_equals?(str)
    a, b =3D to_s, str.to_s
    a.start_with? b || b.start_with? a
  end
end

> Mixing up these ideas makes for a confusing and (unfortunately)
> potentially impolite discussion.
>
> The problem is, Ruby doesn't implement Float#essentially_equals?.
> (Yes, a better name would be good.) =A0If it did, there would be an
> argument for simply defining Float.=3D=3D in that way. =A0The current
> definition of Float.=3D=3D is insufficient for its task, and simply
> reflects Ruby's C heritage. =A0I wonder if anybody would be put out if
> it were redefined to be more useful and less surprising.

For the reasons above there is also no common implementation possible
other than what =3D=3D does today.  We would need at least one additional
input (the level of imprecision) to perform this calculation.  A
binary operator always has only two operands so the third value could
only be provided by the environment (constant or variable in Float,
thread local variable).  This is error prone since two parts in an
application might need totally different values.

So basically =3D=3D is the way it is because every object must respond to
this method and there is no better implementation available which
works for the common case.

Kind regards

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/