float_equal lua (lua 浮点数相等判断)
原文地址:http://lua-users.org/lists/lua-l/2013-08/msg00456.html
- 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". >>>> >>>> /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. > 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--
浙公网安备 33010602011771号