Source code analyzers (like SonarQube) complain about float (or double) equality comparisons because equality is a tricky thing with floats; the values compared can be the results of computations which often have minute rounding effects, so that
0.3 - 0.2 == 0.1 often returns false while mathematically it should always return true (as tested with Python 2.7). So this complaint makes perfect sense to warn about potentially dangerous code.
A typical approach for such situations is to check for a margin, an epsilon, which should compensate all rounding effects, e. g.
if abs(a - b) < epsilon then …
On the other hand one can often see code which avoids a division-by-zero problem by checking the divisor for equality with zero before the division takes place:
if divisor == 0.0 then // do some special handling like skipping the list element, // return 0.0 or whatever seems appropriate, depending on context else result = divident / divisor endif
This seems to handle the div-by-zero issue but is not compliant with the source code analyzer who still complains about the spot
divisor == 0.0. On first sight it looks like a problem with the analyzer. It seems like a false positive. Float-equality checks for 0.0 should be allowed, shouldn't they?
After some consideration I thought about the case that the divisor was the result of a computation which should have resulted in 0.0 (like
0.3 - 0.2 - 0.1) and which now was something in the range of
There are two approaches for this now:
- The value is not exactly 0.0, hence the division can take place, the resulting value will be a "normal" floating point number (probably; consider 1e200 / 1e-200 which is
inf). Let it happen, the caller has to take care of the results.
- The value should have been 0.0, it logically is in this case, the computer just doesn't notice it, so whatever special handling of the zero case was intended should take place here as well.
If we vote for the second option, we could use the epsilon approach and be fine. But that would treat true non-zero values which are just very small like zero-ish values. We have no way of distinguishing the two cases.
This leads to the next consideration whether such a true non-zero value which is very close to 0.0 nevertheless should be divided by or whether it should be handled like the zero case (i. e. receive the special handling). After all, dividing by such a small value will result in very large values which will often be problematic (in graphs or similar). This is surely up to the context and cannot be answered in general.
I also considered whether the existence of zero(-ish) values in the input was maybe not the root of the problem but just an effect in itself, i. e. maybe the root of the trouble lay deeper: Maybe an algorithm which expects a float and which is supposed to divide by it should never receive values which can become zero(-ish) in the first place.
I can think of use cases with integers where one may need to check for them being zero before dividing (e. g. an index whose difference to a reference index is used as divisor, when both become the same in some iteration, the difference is
0), but I couldn't think of a good example where a float value could become zero-ish. Maybe if such a thing occurred, it was just a logical error?
So, now my questions are:
- Is there a theory about the topic of float-zero-checks to avoid division-by-zero problems addressing my considerations? I found nothing on the Internet about it yet.
- Can someone provide a reasonable example of a context and an algorithm therein which is supposed to expect float values which can become zero and by which it should divide? And depending on that context which solution (epsilon, pure
== 0.0-check, maybe a different approach) would you prefer there?