• Subject: Re: Float numbers equality.
• From: Leo Razoumov <slonik.az@...>
• Date: Mon, 26 Aug 2013 07:53:25 -0400

```On Fri, Aug 23, 2013 at 12:01 PM, Vicente Hernando
<vhernando@systemonenoc.com> wrote:
> On 08/19/2013 03:46 AM, Coda Highland wrote:
>>
>> On Sun, Aug 18, 2013 at 5:16 PM, Leo Razoumov <slonik.az@gmail.com> wrote:
>>>
>>> On 8/18/13, Coda Highland <chighland@gmail.com> wrote:
>>>>
>>>> On Sun, Aug 18, 2013 at 4:33 PM, Leo Razoumov <slonik.az@gmail.com>
>>>> wrote:
>>>>>
>>>>> On 8/18/13, Coda Highland <chighland@gmail.com> wrote:
>>>>>>
>>>>>> On Sun, Aug 18, 2013 at 4:09 PM, Leo Razoumov <slonik.az@gmail.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> On 8/9/13, Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> function float_equal(lhs, rhs, epsilon)
>>>>>>>>>      return math.abs(lhs - rhs) < epsilon
>>>>>>>>> end
>>>>>>>>
>>>>>>>> As mentioned before, if you have to do this, you need to use
>>>>>>>> *relative*
>>>>>>>> error,
>>>>>>>> not absolute error:
>>>>>>>>        return math.abs(lhs - rhs) < epsilon*rhs
>>>>>>>>
>>>>>>> The code above is incorrect for rhs <= 0.
>>>>>>>
>>>>>>> It is better to try the following (untested):
>>>>>>>
>>>>>>> function float_equal(lhs, rhs, epsilon)
>>>>>>>      local abs= math.abs
>>>>>>>      epsilon  = epsilon or 1E-12
>>>>>>>      return abs(lhs - rhs) <= epsilon * (abs(lhs) + abs(rhs))
>>>>>>> end
>>>>>>>
>>>>>>> This implementation handles correctly the cases when one or both
>>>>>>> numbers are zero or negative,
>>>>>>>   and, (the added bonus) the function is symmetrical w.r.t. lhs<->rhs
>>>>>>> substitutions.
>>>>>>>
>>>>>>> --Leo--
>>>>>>>
>>>>>> Actually, the correction is simply to use "epsilon * abs(rhs)" instead
>>>>>> of "epsilon * rhs".
>>>>>>
>>>>> No, expression
>>>>>      return abs(lhs - rhs) <= epsilon * abs(rhs)
>>>>> does not handle the case of rhs=0.
>>>>> E.g.: epsilon=1E-12; lhs= 1E-16; rhs=0;
>>>>>
>>>>> --Leo--
>>>>>
>>>> Hmm. That's a good point on the degenerate case, but at THAT point I
>>>> would use an if statement for rhs == 0.0 rather than trying to bake it
>>>> into the expression -- perhaps "if rhs == 0.0 then return abs(lhs) <=
>>>> epsilon end".
>>>>
>>>>
>>> in general one expects the equality operation to be symmetrical so that
>>> float_equal(x,y) and float_equal(y,x) return the same result.
>>> I think the simplest form that satisfies symmetry requirement and which
>>> does
>>> not require any special case handling is
>>>
>>>      return abs(lhs - rhs) <= epsilon * (abs(lhs) + abs(rhs))
>>>
>>> --Leo--
>>>
>> As I said, this causes a misinterpretation of epsilon by an order of
>> magnitude. If you wish to avoid special case code (which makes the
>> function much more readable and probably runs faster), then you must
>> use something like epsilon * max(abs(lhs), abs(rhs)).
>>
>>
>>
>
> return abs(lhs - rhs) <= epsilon * (abs(lhs) + abs(rhs)) / 2
>
>
> Cheers,
> Vicente.
>

Why do you want an extra unnecessary division (which is typically 5
times slower than multiplicaiton)?
Simply redefine epsilon -> 0.5*epsilon somewhere to achieve the same result.

--Leo--

```