Divide Underflow

4.1k views Asked by At

Why is a divide underflow only caused when the divisor is much smaller than the dividend, shouldn't it occur anytime the denominator is close enough to zero regardless of the size of the dividend?

1

There are 1 answers

6
3Dave On BEST ANSWER

From http://www.strw.leidenuniv.nl/docs/intel/f_ug/ieee_ovw.htm

The underflow exception occurs if the rounded result has an exponent that is too small to be represented using the floating-point format of the result.

This implies that the error occurrs when the ratio of the dividend and divisor is small enough to exceed the precision of the floating point format, rather than any dependence on a specific value such as epsilon.

As the denominator approaches zero, assuming a non-zero numerator, the result of a division will approach infinity. As the numerator approaches zero, assuming a non-zero denominator, the result approaches zero. When this value gets small enough, an will occurr.

If the numerator and denominator are very close in value, even if they are very small, you can get a useful result, so a very small numerator does not necessarily cause an underflow.

Example:

In C#, epsilon is 1.401298E-45.

epsilon/epsilon == 1.0f

Even though the numerator is very, very small, the result is still a valid float.

Now, if you were to try something like this:

float max = 3.40282347E+38f;

/// underflow, denominator will be 0.0f
float denominator = epsilon / max; 

denominator will have an order of 1e-83. Since 83 far exceeds the maximum single-precision float exponent, the value will be clamped to zero. This is where the underflow occurrs.

/// generates a divide-by-zero error.
float result = 10 / denominator; 

This generates a divide-by-zero instead of infinity, because the intermediate result, stored in denominator, is first clamped to 0 before being used in the second operation.

Whether you get an underflow or a divide-by zero can depend on the compiler, your use and order of parenthisis, etc.

For instance, again in C#:

10f / float.Epsilon / float.MaxValue

as well as

(10f / float.Epsilon) / float.MaxValue

gives 20971522.0f.

However, the mathematically equivelant expression:

10f / (float.Epsilon / float.MaxValue)

gives Infinity.