Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't 'd /= d' throw a division by zero exception when d == 0?

I don't quite understand why I don't get a division by zero exception:

int d = 0; d /= d; 

I expected to get a division by zero exception but instead d == 1.

Why doesn't d /= d throw a division by zero exception when d == 0?

like image 643
Valerii Boldakov Avatar asked Aug 23 '19 15:08

Valerii Boldakov


People also ask

What is the exception if you divide a number by zero?

Any number divided by zero gives the answer “equal to infinity.” Unfortunately, no data structure in the world of programming can store an infinite amount of data. Hence, if any number is divided by zero, we get the arithmetic exception .

What happens if you divide by 0 in C?

In languages like C, C++ etc. division by zero invokes undefined behaviour. So according to the language definition, anything can happen.

How do you allow division by 0 in Python?

You can't divide by zero! If you don't specify an exception type on the except line, it will cheerfully catch all exceptions. This is generally a bad idea in production code, since it means your program will blissfully ignore unexpected errors as well as ones which the except block is actually prepared to handle.

What happens if a CPU executes a divide instruction in which the divider is zero ie divide by zero is attempted?

When a divide by zero occurs, it triggers an exception. The CPU responds by invoking the exception handler in the interrupt vector corresponding to a divide by zero.


2 Answers

C++ does not have a "Division by Zero" Exception to catch. The behavior you're observing is the result of Compiler optimizations:

  1. The compiler assumes Undefined Behavior doesn't happen
  2. Division by Zero in C++ is undefined behavior
  3. Therefore, code which can cause a Division by Zero is presumed to not do so.
    • And, code which must cause a Division by Zero is presumed to never happen
  4. Therefore, the compiler deduces that because Undefined Behavior doesn't happen, then the conditions for Undefined Behavior in this code (d == 0) must not happen
  5. Therefore, d / d must always equal 1.

However...

We can force the compiler to trigger a "real" division by zero with a minor tweak to your code.

volatile int d = 0; d /= d; //What happens? 

So now the question remains: now that we've basically forced the compiler to allow this to happen, what happens? It's undefined behavior—but we've now prevented the compiler from optimizing around this undefined behavior.

Mostly, it depends on the target environment. This will not trigger a software exception, but it can (depending on the target CPU) trigger a Hardware Exception (an Integer-Divide-by-Zero), which cannot be caught in the traditional manner a software exception can be caught. This is definitely the case for an x86 CPU, and most other (but not all!) architectures.

There are, however, methods of dealing with the hardware exception (if it occurs) instead of just letting the program crash: look at this post for some methods that might be applicable: Catching exception: divide by zero. Note they vary from compiler to compiler.

like image 170
Xirema Avatar answered Sep 21 '22 06:09

Xirema


Just to complement the other answers, the fact that division by zero is undefined behavior means that the compiler is free to do anything in cases where it would happen:

  • The compiler may assume that 0 / 0 == 1 and optimize accordingly. That's effectively what it appears to have done here.
  • The compiler could also, if it wanted to, assume that 0 / 0 == 42 and set d to that value.
  • The compiler could also decide that the value of d is indeterminate, and thus leave the variable uninitialized, so that its value will be whatever happened to be previously written into the memory allocated for it. Some of the unexpected values observed on other compilers in the comments may be caused by those compilers doing something like this.
  • The compiler may also decide to abort the program or raise an exception whenever a division by zero occurs. Since, for this program, the compiler can determine that this will always happen, it can simply emit the code to raise the exception (or abort execution entirely) and treat the rest of the function as unreachable code.
  • Instead of raising an exception when division by zero occurs, the compiler could also choose to stop the program and start a game of Solitaire instead. That also falls under the umbrella of "undefined behavior".
  • In principle, the compiler could even issue code that caused the computer to explode whenever a division by zero occurs. There is nothing in the C++ standard that would forbid this. (For certain kinds of applications, like a missile flight controller, this might even be considered a desirable safety feature!)
  • Furthermore, the standard explicitly allows undefined behavior to "time travel", so that the compiler may also do any of the things above (or anything else) before the division by zero happens. Basically, the standard allows the compiler to freely reorder operations as long as the observable behavior of the program is not changed — but even that last requirement is explicitly waived if executing the program would result in undefined behavior. So, in effect, the entire behavior of any program execution that would, at some point, trigger undefined behavior is undefined!
  • As a consequence of the above, the compiler may also simply assume that undefined behavior does not happen, since one permissible behavior for a program that would behave in an undefined manner on some inputs is for it to simply behave as if the input had been something else. That is, even if the original value of d was not known at compile time, the compiler could still assume that it's never zero and optimize the code accordingly. In the particular case of the OP's code, this is effectively indistinguishable from the compiler just assuming that 0 / 0 == 1, but the compiler could also, for example, assume that the puts() in if (d == 0) puts("About to divide by zero!"); d /= d; never gets executed!
like image 25
Ilmari Karonen Avatar answered Sep 21 '22 06:09

Ilmari Karonen