dnrajugade / guava-libraries

Automatically exported from code.google.com/p/guava-libraries
Apache License 2.0
0 stars 0 forks source link

Fuzzy comparisons for floats #1204

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
I very much enjoyed the additions documented in issue 725, but they concern 
only doubles.

Unless I missed another issue with this question already, please consider 
adding fuzzy comparisons for floats. This was alrady asked as part of issue 
864, but the whole issue was considered a duplicate, without consideration for 
the float part.

Original issue reported on code.google.com by ogregoire on 14 Nov 2012 at 2:05

GoogleCodeExporter commented 9 years ago
I'm not seeing how a theoretical FloatMath.fuzzyEquals(a, b, tolerance) 
wouldn't be fully equivalent to DoubleMath.fuzzyEquals((double) a, (double) b, 
(double) tolerance).

Original comment by lowas...@google.com on 14 Nov 2012 at 7:00

GoogleCodeExporter commented 9 years ago
Or is there some specific platform/performance reason why you would prefer to 
do the math only in floats for some particular application?

Original comment by lowas...@google.com on 14 Nov 2012 at 7:07

GoogleCodeExporter commented 9 years ago
No, I would like this change because DoubleMath.fuzzyEquals() is practically 
not suited for floats.

Check the code in the following file (and run it). On 2^32 comparisons between 
the current doubles version and a float-optimized version of the fuzzyEquals, I 
get 17.958.971 errors, which means roughly 0,42% errors.

Plus, I'll add the "strangeness" to have to add *Double* in imports in 
float-only classes is tickling me.

I have no issue with the performances as Doubles.fuzzyEquals.

Original comment by ogregoire on 15 Nov 2012 at 1:31

Attachments:

GoogleCodeExporter commented 9 years ago
Why do you call it errors? I'd say, your tolerance is fairly intolerant as 
you're testing if

f1 + 0.001f + 0.001f ... (ten times) <= f1 + 0.01f

and

f1 + 0.001f + 0.001f ... (ten times) <= f1 + 0.01

agree (note the missing "f" suffix). These sometimes differ, more precisely it 
may happen that in double the LHS is slightly larger than the RHS, while in 
float they equal.

But that's actually what the tolerance is for. What you're doing is insisting 
on an exact behavior for your exact tolerance value. I fail to see what it 
could be good for.

Original comment by Maaarti...@gmail.com on 15 Nov 2012 at 2:53

GoogleCodeExporter commented 9 years ago
I encountered such a corner-case and couldn't find the issue until I wrote my 
own float-specific fuzzyEqual (see previous code), which fixed it. Hence this 
request.

Theoretically, it should be the same, but my code proves that practically it's 
not. That's what I expect to be fixed.

I know I'm not dealing with precise values (if I'd want that, I'd use 
BigDecimal), but I'd still want something that takes the specificities of float 
rather than having to fallback to doubles and therefore having 
unwanted/unexpected behavior.

Original comment by ogregoire on 15 Nov 2012 at 6:59

GoogleCodeExporter commented 9 years ago
But you did *not* fix it, 'cause the idea itself is totally wrong. When dealing 
with floats or doubles, there's (nearly) always some error and this error is 
(nearly) always much bigger when floats get used. This error can be 
upper-bounded and when this bound is low enough, the computation is usable. 
Whenever you depend on the exact value of the error, it's plain wrong.

I'm pretty sure that there's nothing to be fixed with DoubleMath.fuzzyEquals. 
There are always cases when double and float computations return different 
results. There's no case when anybody should depend on the results being the 
same.

There's no usage example in the Javadoc to fuzzyEquals, so maybe this one helps:

Assume you're computing some triangles which should be right-angled. Testing 
a*a+b*b==c*c is futile due to rounding errors, so you use

assertTrue(DoubleMath.fuzzyEquals(a*a+b*b, c*c, 1e-6));

instead. This is far from perfect (for many reasons), but it might be exactly 
what you need. You might need a different tolerance, maybe 2e-3, maybe 1.5e-7, 
but nobody needs to specify a tolerance of 1.000012345789e-6. And specifying 
that the test is to be performed using floats instead of doubles makes even 
much less sense!

Original comment by Maaarti...@gmail.com on 15 Nov 2012 at 8:51

GoogleCodeExporter commented 9 years ago

Original comment by kak@google.com on 22 Aug 2013 at 11:31

GoogleCodeExporter commented 9 years ago
This issue has been migrated to GitHub.

It can be found at https://github.com/google/guava/issues/<id>

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:13

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 1 Nov 2014 at 4:18

GoogleCodeExporter commented 9 years ago

Original comment by cgdecker@google.com on 3 Nov 2014 at 9:08