Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Divide by zero prevention

Tags:

c++

What is 1.#INF and why does casting to a float or double prevent a division by 0 of crashing?
Also, any great ideas of how to prevent division by 0? (Like any macro or template)?

int nQuota = 0;

int nZero = 3 / nQuota; //crash
cout << nZero << endl;

float fZero = 2 / nQuota; //crash
cout << fZero << endl;

if I use instead:

int nZero = 3 / (float)nQuota;
cout << nZero << endl;
//Output = -2147483648

float fZero = 2 / (float)nQuota;
cout << fZero << endl;
//Output = 1.#INF
like image 851
Vinicius Horta Avatar asked Jul 02 '12 19:07

Vinicius Horta


3 Answers

1.#INF is positive infinity. You will get it when you divide a positive float by zero (if you divide the float zero itself by zero, then the result will be "not a number").

On the other hand, if you divide an integer by zero, the program will crash.

The reason float fZero = 2 / nQuota; crashes is because both operands of the / operator are integers, so the division is performed on integers. It doesn't matter that you then store the result in a float; C++ has no notion of target typing.

Why positive infinity cast to an integer is the smallest integer, I have no idea.

like image 186
fredoverflow Avatar answered Oct 14 '22 16:10

fredoverflow


Wwhy using (float) or (double) prevents a division by 0 of crashing?

It doesn't necessarily. The standard is amazing spare when it comes to floating point. Most systems use the IEEE floating point standard nowadays, and that says that the default action for division by zero is to return ±infinity rather than crash. You can make it crash by enabling the appropriate floating point exceptions.

Note well: The only thing the floating point exception model and the C++ exception model have in common is the word "exception". On every machine I work on, a floating point exception does not throw a C++ exception.

Also, any great ideas of how to prevent division by 0?

  1. Simple answer: Don't do it.
    This is one of those "Doctor, doctor it hurts when I do this!" kinds of situations. So don't do it!

  2. Make sure that the divisor is not zero.
    Do sanity checks on divisors that are user inputs. Always filter your user inputs for sanity. A user input value of zero when the number is supposed to be in the millions will cause all kinds of havoc besides overflow. Do sanity checks on intermediate values.

  3. Enable floating point exceptions.
    Making the default behavior to allow errors (and these are almost always errors) to go through unchecked was IMHO a big mistake on the part of the standards committee. Use the default and those infinities and not-a-numbers will eventually turn everything into an Inf or a NaN.
    The default should have been to stop floating point errors in their tracks, with an option to allow things like 1.0/0.0 and 0.0/0.0 to take place. That isn't the case, so you have to enable those traps. Do that and you can oftentimes find the cause of the problem in short order.

  4. Write custom divide, custom multiply, custom square root, custom sine, ... functions.
    This unfortunately is the route that many safety critical software systems must take. It is a royal pain. Option #1 is out because it's just wishful thinking. Option #3 is out because the system cannot be allowed to crash. Option #2 is still a good idea, but it doesn't always work because bad data always has a way of sneaking in. It's Murphy's law.

BTW, the problem is a bit worse than just division by zero. 10200/10-200 will also overflow.

like image 3
David Hammen Avatar answered Oct 14 '22 15:10

David Hammen


You usually check to make sure you aren't dividing by zero. The code below isn't particularly useful unless nQuota has a legitimate value but it does prevent crashes

int nQuota = 0;
int nZero = 0;
float fZero = 0;
if (nQuota)
    nZero = 3 / nQuota;
cout << nZero << endl;

if (nQuota)
    fZero = 2 / nQuota;
cout << fZero << endl;
like image 2
Chris McKnight Avatar answered Oct 14 '22 14:10

Chris McKnight