
123

Hi,
I'm writing some unit tests, where I compare numbers and I have problem with something like this: 300 * 0.07 == 21 => false. print (300 * 0.07, 21, 300 * 0.07 == 21)
What is the best way, for test float equality?
I consider to use tostring function: print (300 * 0.07, 21, tostring (300 * 0.07) == tostring (21)), But i wonder, maybe there is a better way, to compare something like this?
Thanks for any response.
 Karol Drożak


Hi
On 08/09/2013 12:53 PM, Karol Dro wrote:
>
> What is the best way, for test float equality?
>
You don't.
If you really need to, you need to compare with epsilon:
epsilon = X * 0.00001
XequalY = ((X  epsilon < Y) and (X + espilon > Y))

Thomas


> What is the best way, for test float equality?
>
> I consider to use tostring function:
> print (300 * 0.07, 21, tostring (300 * 0.07) == tostring (21)),
For this kind of numbers I think this is the best option, especially
since it's in a unit test. But you make sure you know why tests like
300 * 0.07 == 21 give false. Otherwise, tell us more about the problem
you're trying to solve.


On Friday, August 9, 2013, Karol Dro wrote: Hi,
I'm writing some unit tests, where I compare numbers and I have problem with something like this:
300 * 0.07 == 21 => false. print (300 * 0.07, 21, 300 * 0.07 == 21)
What is the best way, for test float equality?
I consider to use tostring function: print (300 * 0.07, 21, tostring (300 * 0.07) == tostring (21)), But i wonder, maybe there is a better way, to compare something like this?
Thanks for any response.
 Karol Drożak
This is exactly the problem that I've been working with. My first attempt was to do it is to do the calculation in the same way as I did in the function, but that created a tight coupling.
The format("%.10f", x) method was the most reasonable, for my testing needs, because it allowed me to specify the precision that I needed.
In the end, floats were too challenging to work with because my conversions were being rounded down or up, depending upon where the conversion was coming from and the size of the values.
I decided to go with integers by using Luiz's lint64 package. I keep multiplying everything as long as possible and then deal with division at the last step. I mod the division if I need to know what the partial portion of the sample is.
I don't know your specific case and others made my same suggestion. I just couldn't help but chime in, given this has been my life for the last few days. :)
Andrew


Hi!
2013/8/9 Karol Dro < [hidden email]>:
> I'm writing some unit tests, where I compare numbers and I have problem with
> something like this:
> 300 * 0.07 == 21 => false.
> print (300 * 0.07, 21, 300 * 0.07 == 21)
>
> What is the best way, for test float equality?
>
> I consider to use tostring function:
> print (300 * 0.07, 21, tostring (300 * 0.07) == tostring (21)),
> But i wonder, maybe there is a better way, to compare something like this?
In short: Use a reasonable "epsilon".
But excuse me for mentioning the usual hint: Do a search for "What
Every Computer Scientist Should Know About FloatingPoint Arithmetic".
The document may be a bit lengthy and answer a few more questions than
you have, but it tells the basic characteristics of floating point
arithmetics including important points as cancellation and the IEEE
standard.
Regards,
Matthias


On Fri, Aug 9, 2013 at 12:37 PM, Matthias Kluwe < [hidden email]> wrote:
> Hi!
>
> 2013/8/9 Karol Dro < [hidden email]>:
>
>> I'm writing some unit tests, where I compare numbers and I have problem with
>> something like this:
>> 300 * 0.07 == 21 => false.
>> print (300 * 0.07, 21, 300 * 0.07 == 21)
>>
>> What is the best way, for test float equality?
>>
>> I consider to use tostring function:
>> print (300 * 0.07, 21, tostring (300 * 0.07) == tostring (21)),
>> But i wonder, maybe there is a better way, to compare something like this?
>
> In short: Use a reasonable "epsilon".
Slightly longer "in short"  this means use something like:
function float_equal(lhs, rhs, epsilon)
return math.abs(lhs  rhs) < epsilon
end
/s/ Adam


> 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
Floatingpoin numbers are not distributed uniformily in their range;
there's lot of clustering and empty intervals, due to scaling.


On Fri, Aug 9, 2013 at 3:18 PM, Luiz Henrique de Figueiredo
< [hidden email]> 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
>
> Floatingpoin numbers are not distributed uniformily in their range;
> there's lot of clustering and empty intervals, due to scaling.
>
Ah, whoops, yeah, you're right, I got sloppy there. Really that ought
to be epsilon*math.max(lhs,rhs) even.
/s/ Adam


On Fri, Aug 9, 2013 at 3:47 PM, Coda Highland < [hidden email]> wrote:
> On Fri, Aug 9, 2013 at 3:18 PM, Luiz Henrique de Figueiredo
> < [hidden email]> 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
>>
>> Floatingpoin numbers are not distributed uniformily in their range;
>> there's lot of clustering and empty intervals, due to scaling.
>>
>
> Ah, whoops, yeah, you're right, I got sloppy there. Really that ought
> to be epsilon*math.max(lhs,rhs) even.
>
> /s/ Adam
Er. Actually, I just need to get some sleep. It doesn't matter which
side you multiply by there because if the two terms are close enough
that an epsilon comparison is necessary in the first place then you're
going to get basically the same result.
I don't usually need to do that kind of orderofmagnitude scaling
because my epsilon comparisons are with code where I already know the
range of the numbers involved.
/s/ Adam


On 10/08/2013 0.47, Coda Highland wrote:
> Ah, whoops, yeah, you're right, I got sloppy there. Really that ought
> to be epsilon*math.max(lhs,rhs) even.
Do you mean epsilon*math.max(math.abs(lhs),math.abs(rhs)) ?

Enrico


In reply to this post by Luiz Henrique de Figueiredo


> What is the best way, for test float equality?
Since everybody else is clearly expert enough not worry about
the following point, I suppose it does not need mentioning. But
still …
Once you have a satisfactory `float_eq` function, don't think that
debug.setmetatable(0.0,{__eq=float_eq})
will hencefore allow you to test `if a==b` by that metamethod.
Please do not think that.


On Sat, Aug 10, 2013 at 12:48 AM, Enrico Colombini < [hidden email]> wrote:
> On 10/08/2013 0.47, Coda Highland wrote:
>>
>> Ah, whoops, yeah, you're right, I got sloppy there. Really that ought
>> to be epsilon*math.max(lhs,rhs) even.
>
>
> Do you mean epsilon*math.max(math.abs(lhs),math.abs(rhs)) ?
>
> 
> Enrico
>
No, but you have a good point that it should be math.abs(epsilon*rhs).
/s/ Adam


Given that this subject comes up every couple of months, and that there are some subtleties to it, that this warrants a new function in the math library to do it the right way?
On Aug 10, 2013, at 9:04 AM, Coda Highland < [hidden email]> wrote:
> On Sat, Aug 10, 2013 at 12:48 AM, Enrico Colombini < [hidden email]> wrote:
>> On 10/08/2013 0.47, Coda Highland wrote:
>>>
>>> Ah, whoops, yeah, you're right, I got sloppy there. Really that ought
>>> to be epsilon*math.max(lhs,rhs) even.
>>
>>
>> Do you mean epsilon*math.max(math.abs(lhs),math.abs(rhs)) ?
>>
>> 
>> Enrico
>>
>
> No, but you have a good point that it should be math.abs(epsilon*rhs).
>
> /s/ Adam
>


On Aug 10, 2013, at 3:08 PM, Tim Hill wrote:
[context:
> for i=1,78 do s="." if (i*0.1)*10~=i then s="X" end io.write(s) end print()
..X..XX....X.X........XX...XX...........X....X.X..X.X..X.X..X.X...............
]
> Given that this subject comes up every couple of months, and that there are some subtleties to it, that this warrants a new function in the math library to do it the right way?
The criteria for inclusion in the standard Lua library aren't clear to me. The module system is there since it's a minimal thing everybody needs to coordinate on. Is that true of this?
Much of the library seems to be important functionality for everyday use which cannot be implemented outside C, at least efficiently. That's definitely not true of equals_within_epsilon, so that suggests the place it would go is Microlight. Maybe.
Some people, including me, wish that more of _PiL_ were in the manual. But I'm not volunteering to write the gloss.
Jay


> Given that this subject comes up every couple of months, and that there are some subtleties to it, that this warrants a new function in the math library to do it the right way?
I don't think so. Floatingpoint arithmetic is not simple. I think it'd be
a disservice to try to hide its complexities in a official function that
may give the impression that it solves the problem reliably, when it can't.
On the other hand, there is nothing instrinsically wrong with floatingpoint
equality. The only catches come from numbers that should be equal but are
computed in two different ways and from naive expectations such as
300 * 0.7 == 21, due to a misunderstanding that floatingpoint representation
is a binary one, not a decimal one.


On Saturday, August 10, 2013, Luiz Henrique de Figueiredo wrote: > Given that this subject comes up every couple of months, and that there are some subtleties to it, that this warrants a new function in the math library to do it the right way?
I don't think so. Floatingpoint arithmetic is not simple. I think it'd be
a disservice to try to hide its complexities in a official function that
may give the impression that it solves the problem reliably, when it can't.
On the other hand, there is nothing instrinsically wrong with floatingpoint
equality. The only catches come from numbers that should be equal but are
computed in two different ways and from naive expectations such as
300 * 0.7 == 21, due to a misunderstanding that floatingpoint representation
is a binary one, not a decimal one.
In an effort to understand (not debate), where would:
return math.abs(lhs  rhs) < epsilon*rhs
...be unsuitable? Imagine that I'm dealing with float equality and it isn't working. Also imagine that I don't know very much about the issue. I dig into the math library and find a function that does this.
How am I likely to be confused further? What knowledge would I still lack that would keep me from understanding, provided that PiL offered some additional context?
As a post script, I took the advice found in Programming In Lua[1] and found myself utterly lost (although ever so slightly closer to my Calculus Through Googling degree). I read the part of the discussion related to the epsilon, but since so much of it was aimed at an audience that wasn't me, I failed to identify the solution.
As a result, I believe that once I feel like I understand the common issues, I should (or someone like me should) write a wiki on it. I was unable to find a really good document aimed at someone who can't read calculus notation. Several Microsoft articles came very close, however.
 Andrew


In case rhs < 0
 Original Message 
Sent: Sunday, August 11, 2013 5:19
PM
Subject: Re: Float numbers
equality.
On Saturday, August 10, 2013, Luiz Henrique de
Figueiredo wrote:
>
Given that this subject comes up every couple of months, and that there are
some subtleties to it, that this warrants a new function in the math library
to do it the right way?
I don't think so. Floatingpoint arithmetic
is not simple. I think it'd be a disservice to try to hide its
complexities in a official function that may give the impression that it
solves the problem reliably, when it can't.
On the other hand, there
is nothing instrinsically wrong with floatingpoint equality. The only
catches come from numbers that should be equal but are computed in two
different ways and from naive expectations such as 300 * 0.7 == 21, due
to a misunderstanding that floatingpoint representation is a binary one,
not a decimal one.
In an effort to understand (not debate), where would:
return math.abs(lhs  rhs) < epsilon*rhs
...be unsuitable? Imagine
that I'm dealing with float equality and it isn't working. Also
imagine that I don't know very much about the issue. I dig
into the math library and find a function that does
this.
How am I likely to be
confused further? What knowledge would I still lack that would keep me from
understanding, provided that PiL offered some additional
context?
As a post script, I took
the advice found in Programming In Lua[1] and found myself utterly lost
(although ever so slightly closer to my Calculus Through Googling degree). I
read the part of the discussion related to the epsilon, but since so much
of it was aimed at an audience that wasn't me, I failed to identify the
solution.
As a result,
I believe that once I feel like I understand the common issues, I
should (or someone like me should) write a wiki on it. I was unable to find a
really good document aimed at someone who can't read calculus notation.
Several Microsoft articles came very close, however.

Andrew


2013/8/11 Victor Bombi < [hidden email]>:
> In case rhs < 0
True, but one we know what Andrew means.
>  Original Message 
> From: Andrew Starks
>
> In an effort to understand (not debate), where would:
>
> return math.abs(lhs  rhs) < epsilon*rhs
>
> ...be unsuitable?
Suppose lhs and rhs are both sums of many terms of both signs, and
the total is close to zero, in theory might even be equal to zero.
The above test may well not be satisfied when actually the numbers
are equal on paper. Instead, one should be using
return math.abs(lhs  rhs) < epsilon*scale
where 'scale' is a rough approximation to the sums of the absolute
values.
There are other situations. You can't fix epsilon by looking at
machine precision: the more computations it takes to compute the
operands, the bigger epsilon should be, etc.
Luiz is right here: the appropriate test for floatingpoint equality
is never so simple that any one method is always foolproof. There is
no substitute for consulting an experienced numerical analyst. :)


>  Original Message 
> From: Andrew Starks
> To: Lua mailing list
> Sent: Sunday, August 11, 2013 5:19 PM
> Subject: Re: Float numbers equality.
>
>
>
> On Saturday, August 10, 2013, Luiz Henrique de Figueiredo wrote:
>>
>> > Given that this subject comes up every couple of months, and that there
>> > are some subtleties to it, that this warrants a new function in the math
>> > library to do it the right way?
>>
>> I don't think so. Floatingpoint arithmetic is not simple. I think it'd be
>> a disservice to try to hide its complexities in a official function that
>> may give the impression that it solves the problem reliably, when it
>> can't.
>>
>> On the other hand, there is nothing instrinsically wrong with
>> floatingpoint
>> equality. The only catches come from numbers that should be equal but are
>> computed in two different ways and from naive expectations such as
>> 300 * 0.7 == 21, due to a misunderstanding that floatingpoint
>> representation
>> is a binary one, not a decimal one.
>
>
> In an effort to understand (not debate), where would:
>
> return math.abs(lhs  rhs) < epsilon*rhs
>
> ...be unsuitable? Imagine that I'm dealing with float equality and it isn't
> working. Also imagine that I don't know very much about the issue. I dig
> into the math library and find a function that does this.
>
> How am I likely to be confused further? What knowledge would I still lack
> that would keep me from understanding, provided that PiL offered some
> additional context?
>
> As a post script, I took the advice found in Programming In Lua[1] and found
> myself utterly lost (although ever so slightly closer to my Calculus Through
> Googling degree). I read the part of the discussion related to the epsilon,
> but since so much of it was aimed at an audience that wasn't me, I failed to
> identify the solution.
>
> As a result, I believe that once I feel like I understand the common issues,
> I should (or someone like me should) write a wiki on it. I was unable to
> find a really good document aimed at someone who can't read calculus
> notation. Several Microsoft articles came very close, however.
>
>  Andrew
> [1] http://www.fer.unizg.hr/_download/repository/paper%5B1%5D.pdfOn Sun, Aug 11, 2013 at 9:03 AM, Victor Bombi < [hidden email]> wrote:
> In case rhs < 0
For the sake of having an actually productive discussion, let's assume
he ACTUALLY meant the bugfixed version:
return math.abs(lhs  rhs) < math.abs(epsilon * rhs)
The expression itself is never really WRONG (if you're paranoid you
might replace the < with a <= to handle underflow in the epsilon*rhs
term, but more on this later), but there are cases when direct
floatingpoint equality works just fine and the expression is a
comparativelyexpensive waste of time.
The real problem is in understanding what a suitable epsilon really is
and how to minimize the error in the calculation. This requires an
understanding of your specific problem domain and gets into analysis
of the behavior of rounding error of floatingpoint operations. A
*single* addition/subtraction won't introduce relative error greater
than IIRC 2^52 (maybe 2^51? I forget exactly), while a
multiplication or division can introduce more, and more complicated
expressions like logarithm or square root could really throw the whole
thing off if you do it wrong.
Long story short, this expression is often the right thing to do, but
it's meaningless to do it if your calculation leading into it triggers
nasty rounding errors. Proper understanding of how to rearrange a FP
calculation to minimize error is far more important than the actual
epsilon comparison.
/s/ Adam

123
