5

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 1e-17 or 0.00000000000000001.

There are two approaches for this now:

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

or

  1. 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:

  1. 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.
  2. 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?
  • 2
    if abs(a - b) < epsilon then won't ever divide by zero. If your denominator is not zero, but just very close to zero, then you won't get a divide by zero error; you'll just get a very large number as the result of the divide. If you want a number very close to zero to equal zero for your denominator == zero check, then just include the epsilon as part of your calculation. There's no standard; the "correct" way is the way that most closely meets your application's requirements. – Robert Harvey Feb 5 '16 at 15:43
  • It's an example of a way to compare two floats for "almost equality". The division-by-zero things starts below that. – Alfe Feb 5 '16 at 15:47
  • Ok, but if the denominator's not zero, then it's not zero, and you won't get the divide by zero error. If you want almost zero to actually be treated as if it's zero, then just say so in your code. – Robert Harvey Feb 5 '16 at 15:47
  • There is no universally applicable solution to the division-by-zero problem; all solutions are context-specific (or application or use-case specific). In some cases the end-users (people using the API or GUI, i.e. non-programmers) need to be told the limitations and the software's handling of such cases. Usually, each "division-by-zero" situation has an explanation that can be understood by end-users when phrased appropriately. However, you have to know what your software is being used for in order to phrase it. – rwong Feb 5 '16 at 15:47
  • 1
    My idea is that the appearance of a 0 is a clear sign for a design issue in the caller. Noticing that, the caller should be fixed, and no zeros could happen again. Then the question whether or how or where to handle the div-by-zero is gone. My question is: Are there counterexamples for this theory. The only ones I heard of yet is when I'm providing a library for a general-purpose user (like in Matlab or for spreadsheets or similar). – Alfe Feb 8 '16 at 10:07
4

I side with OP's personal theory that it is not a normal practice to allow a computer program to proceed with a division-by-zero operation, or to only perform a minimal check before the division.

The exception is when you are implementing something that is too general - a programming language (such as MATLAB) where you (as the programmer) do not know the context / application / use-case / physical meaning of the mathematical operations it is asked to perform. This may be because the formula it is evaluating is provided by the customer, and you do not know the customer's use-case of that formula. In that case you use a special representation such as Inf or NaN as a placeholder.

If, however, the formula is provided as part of a statistical toolbox, then you should be able to provide an explanation when the situation arises. See the "weighted averaging when the total weight is zero" example below.


There is a way to "invert" a divisor underflow test. Mathematically if b is not zero, and
abs(a) / abs(b) > abs(c) where c is the largest representable floating point value, then
abs(a) > abs(c) * abs(b). However, in practice it requires a more careful implementation than that. You may be able to find a mathematical library function that allows you to pass in (a, b) and it will return whether the division will overflow, underflow, or otherwise have poor precision.


Source code analyzers look for patterns in the code; they are not sophisticated enough to decide whether someone's workaround logic is sufficient for the application's design purpose. (In fact even the average programmer may be unqualified to make that decision.) Source code analyzers are supposed to be augmented with a person qualified to make that decision.


A denominator of zero can occur in a lot of mathematical manipulations: formulas, infinite series (summation of sequence), etc. There are many mathematical methods to calculate the result despite having denominators that approach zero (i.e. not exactly zero, but are smaller than the machine-representable value). These means the formulas are not to be evaluated verbatim - they are transformed using some calculus methods, and for each formula there may be several alternative versions which is chosen to avoid the division-by-zero issue.


Another situation arises in weighted averaging of data. If you perform a query that selects a subset of data, and when:

  1. the sum of weights for the subset of data turns out to be zero, or
  2. when the subset is indeed empty, i.e. the query returns no result

then the proper way to phrase that situation is "insufficient samples (data) for the query", etc.


In basic trigonometry, some representations (slope) are very sensitive to division problems, whereas an alternative representation (bearing, i.e. angle) would not be sensitive. For example, to represent a line on a 2D plane, where vertical and near-vertical lines need to be represented as robustly as horizontal and near-horizontal lines, you can:

  1. have a toggle between lines that are steep vs. those that are not. For lines steeper than 45 degrees, you would use (x / y) instead of (y / x) as the "flipped" slope of the line, so as to avoid the division by small numbers.
  2. Use an alternative representation such as a*x + b*y + c == 0 and store the parameters (a, b, c) with the requirement that (a^2 + b^2) must equal 1.0 for normal case, and 0.0 if the line is degenerate (not-a-line).

It is worth mentioning that degeneracy is unavoidable in many different contexts (and in context-specific ways). For example, if user passes in a "line" from point (x1, y1) to point (x2, y2) and asks to calculate its slope, and it happens that (x1 == x2 and y1 == y2), then there is no slope, because there is no line, because there is only a single point in the user's input.

  • I'm not asking for this. Sorry. I was clearly asking for something completely different: Is there a context thinkable (examples please!) in which a function expecting a float by which it is supposed to divide should reasonably check this value for being zero or should not the context be designed in a way that surely never a zero-ish value should be passed to that function? I have the theory that no such context exists and ask for counterexamples (i. e. examples for a context which should reasonably do that). – Alfe Feb 5 '16 at 16:04
  • @Alfe: on Programmers.SE you do not restrict answers to be only one side or the other. – rwong Feb 5 '16 at 16:14
  • @Alfe: I think you need to ask a new question and give the exact context (i.e. the bigger picture) where you see the situation (the division) happening, and then ask whether it is a context where the division should have been reformulated. On Programmers.SE you do not ask people to guess what your context would have been. – rwong Feb 5 '16 at 16:16
  • @Alfe: I think the question you wanted to ask (but had difficulty phrasing) is really a question about error-handling philosophy: whether the caller or callee should have the bigger burden of checking for and handling a potentially failable operation. – rwong Feb 5 '16 at 16:51
  • The question I ask is whether such an error should be handled at all. If I find out here (on an abstract level) that at programming time the design should be fixed so that zero-ish values can never happen, then the question for checking for div-by-zero does not even arise. – Alfe Feb 8 '16 at 10:04
2

Question 1) I wouldn't call it a 'theory', but there is a lot of pragmatic knowledge in statistical and scientific computing on handling division by 0 or taking the log of 0. There isn't a 'theory', because how you handle it depends entirely on the context. Sometimes it's entirely expected and desirable that a computed quantity exactly reach 0. It may just indicate that your solution has fully converged. In other cases it's could mean that you are trying to apply an algorithm out of it's valid domain, and you should re-frame your problem.

Question 2) One of the most common operations in statistics is to divide one probability by another to form an odds-ratio. Both of those probabilities could be arbitrarily small. However, claiming that an event has a probability of exactly 0 is an absurdly strong claim in most circumstances, so when you are setting up your problem you may add some very small number to all the input probabilities. This represents our 'prior' knowledge that none of the events is absolutely impossible. This also has the effect of preventing division by 0, or of taking the log of 0 when calculating odds-ratios.

1

I think this is quite misguided. In most implementations nowadays, division by zero will give you infinity, which behaves very much like a very, very, large number. If you have a quotient that might become zero, then it will get very close to zero, then your quotient will be very large, then you have a problem - which you have to solve, whether you check for division by zero or not.

If you calculate a function like sin (x) / x, where both numerator and denominator can become zero simultaneously, then the test for x == 0 is absolutely fine (and obviously you need to return 1.0 in that case, but if you calculate (2 sin x) / x, you need to return 2.0. If you calculate x / sin (x) and x is close to a multiple of pi, then checking for division by zero except when x = 0 is just wrong.

  • It is worth mentioning that for the evaluation of sin(x)/x for small values of x, one would switch over to an asymptotic formula of it for an entire range. In the case of sin(x)/x it is easy because the asymptotic formula evaluates to be a constant of 1.0, but in other cases (different formulas), the asymptotic formula may depend on the value of x, however small it is. – rwong Feb 5 '16 at 23:32
  • 1
    I'm setting up the idea that special-handling a zero-ish value in float contexts might always be the second-best solution. The best might be to go back to the caller algorithm and fix whatever created the zero-ish value there because with a clean design (so my theory) it never should happen to have such a value in such a spot. I'm asking for counterexamples. – Alfe Feb 8 '16 at 10:18
0

a) If division by zero is a problem, then overflows are also a problem.

b) If you have checks to guard against overflows, you don't need checks to guard against division by zero

c) You never need to care about division by zero.

d) Doing if( divisor == 0) before division is always either unnecessary or wrong.

  • (d) sin x / x is a rare exception. – gnasher729 Feb 5 '16 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.