lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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

/s/ Adam

Adam,
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)).

/s/ Adam


What about this?

return abs(lhs - rhs) <= epsilon * (abs(lhs) + abs(rhs)) / 2


Cheers,
Vicente.