Thread overview
Traping divide by zero
Jan 16, 2008
DQNOK
Jan 18, 2008
Imbecil
Jan 22, 2008
DQNOK
Jan 23, 2008
Sunny Pal Singh
Jan 24, 2008
DQNOK
Feb 08, 2008
Yeg
Feb 14, 2008
Damian
Mar 17, 2008
DQNOK
January 16, 2008
== Repost the article of DQNOK (davidlqualls@gmail.com)
== Posted at 2008/01/03 11:19 to c++.windows.32-bits
After two weeks of ripening in the windows32-bit forum, I thought
perhaps someone here might read and assist.  Thanks in advance.
David


I can't figure out how to trap either floating point, or integer divide by zero.

On some other compilers, I can trap SIGFPE and that does the trick
for both floating point, and for integer divide by zero.  On dmc
and microsoft VC (in this regard, the two compilers seem to act
identically), the expression:
 double d = 8.0/0.0; //does not raise a signal that I can tell.
does nothing but assign inf to d and move on.  However, the
expression:
 int i = 8/0;
causes the program to abort.  I can't figure out how to trap the
error and prevent the abort, or how to trap the floating point
divide by zero.

David

January 18, 2008
Hi,

The x87 FPU has a register called "x87 FPU Control Word".
Some bits in this register control whether exceptions should be
generated by conditions such as (floating point) precision issues,
underflow, overflow, division by 0, denormal/invalid operands.

This register can be controlled using the Assembler instructions FLDCW, FSTCW/FNSTCW, FCLEX/FNCLEX.

The documentation can be found in Section 8
of "(Intel 64 and) IA-32 Software Developer's Manual"
(http://www.intel.com/products/processor/manuals/).

The default value for the x87 Control Word is:

  0x1372 (Borland)      -> division by 0 is signaled
  0x027F (Visual)       -> division by 0 is NOT signaled
  0x137F (Digital Mars) -> division by 0 is NOT signaled

For greater portability (eg: Alpha CPU's) while using
Windows compilers, the _control87, _status87, _clear87 functions
and the EM_ZERODIVIDE (or _EM_ZERODIVIDE) and similar constants
from the header <cfloat> can be used.

After setting the control register so that division by 0
raises an exception, the next question is how to catch it.
Windows SEH (Structured Exception Handling) can be used
for this purpose (__try/__except/__finally).
This should not be confused with standard C++ exception handling
(try/catch).

A very good documentation for SEH is here:
http://www.jorgon.freeserve.co.uk/ExceptFrame.htm,
but one can also search the web for "structured exception handling"
and follow the links to the Microsoft documentation.

Here is an example program. I think you should modify it to use _control87 etc. instead of inline assembler.



//-----------------------------------------------------------------
#if defined (__BORLANDC__)
 #pragma inline
#endif

#include <iostream>
#include <iomanip>
//#include <cfloat>

#define NOMINMAX
#include <windows.h>

// The functions Double0 and Int0 attempt to prevent
// precomputing the result at compile-time
// (eg. Borland does that, even in some debug builds).
// In order to prevent these precomputations even in release builds,
// you should move these 2 functions to a separate .cpp file !

double Double0 (bool bReturnZero)
{
  if (bReturnZero)
    return 0.0;
  else
    return 1.0;
}

int Int0 (bool bReturnZero)
{
  if (bReturnZero)
    return 0;
  else
    return 1;
}

int main ()
{
  WORD w;
  __asm fstcw w;

  std::cout
    << "FPU Control Word = "
    << std::hex << std::uppercase << std::setfill ('0') <<
std::setw (2) << w << "h\n";

  if (w & 4)
  {
    std::cout << "Your environment masks division by 0 by default,
but we're about to change that now. ^^\n";
    w &= ~4;
    __asm fldcw w;
    __asm fwait;
  }

  double d = 10.0;
  __try
  {
    std::cout << "Performing floating-point division by 0; fasten
your seatbelts !\n" << std::flush;

    d = 8.0 / Double0 (true);
    std::cout << "This message should not be displayed !\n";
  }
  __except (EXCEPTION_EXECUTE_HANDLER)
  {
    __asm fnclex;
    std::cout << "Caught by Structured Exception Handling.\n";
  }
  std::cout << "d = " << d << "\n";

  int i = 10;
  __try
  {
    std::cout << "Performing integer division by 0. This is gonna
hurt !\n" << std::flush;
    i = 8 / Int0 (true);
    std::cout << "This message should not be displayed !\n";
  }
  __except (EXCEPTION_EXECUTE_HANDLER)
  {
    __asm fnclex;
    std::cout << "Caught by Structured Exception Handling.\n";
  }
  std::cout << "i = " << std::dec << i << "\n";

  std::cout << "I hope you've enjoyed this example !\n";

  return 0;
}

//-----------------------------------------------------------------
January 22, 2008
Thanks!  Very nice.

I haven't tried any of this yet.  I wonder if setting the EM_ZERODIVIDE flag causes an INTEGER divide-by-zero to signal...

I don't plan to use structured exception handling: plan on using standard C signals and longjmp instead.  I just couldn't figure how to convince the compilers to raise signals on divide by zero.

Thanks again.
January 23, 2008
DQNOK wrote:
> == Repost the article of DQNOK (davidlqualls@gmail.com)
> == Posted at 2008/01/03 11:19 to c++.windows.32-bits
> After two weeks of ripening in the windows32-bit forum, I thought
> perhaps someone here might read and assist.  Thanks in advance.
> David
> 
> 
> I�can't�figure�out�how�to�trap�either�floating�point,�or�integer
> divide�by�zero.
> 
> On�some�other�compilers,�I�can�trap�SIGFPE�and�that�does�the�trick
> for�both�floating�point,�and�for�integer�divide�by�zero.��On�dmc
> and�microsoft�VC�(in�this�regard,�the�two�compilers�seem�to�act
> identically),�the�expression:
> �double�d�=�8.0/0.0;�//does�not�raise�a�signal�that�I�can�tell.
> does�nothing�but�assign�inf�to�d�and�move�on.��However,�the
> expression:
> �int�i�=�8/0;
> causes�the�program�to�abort.��I�can't�figure�out�how�to�trap�the
> error�and�prevent�the�abort,�or�how�to�trap�the�floating�point
> divide�by�zero.
> 
> David
> 
C++ exceptions are not thrown for machine-level events like divide-by-zero. It’s assumed these are dealt with by some other mechanism, like the operating system or hardware. That way, C++ exceptions can be reasonably efficient, and their use is isolated to program-level exceptional conditions.

Currently I am also looking for the solution. I'll take a look at Windows SEH as suggested by Imbecil.
January 24, 2008
== Quote from Sunny Pal Singh (arorasp2000@hotmail.com)'s article
> C++ exceptions are not thrown for machine-level events like divide-by-zero. It's assumed these are dealt with by some other mechanism, like the operating system or hardware. That way, C++ exceptions can be reasonably efficient, and their use is
isolated to
> program-level exceptional conditions.
> Currently I am also looking for the solution. I'll take a look at
> Windows SEH as suggested by Imbecil.

That's good to know.

I was trying to get the machine (or OS) to raise a signal.  I'm using the classic C (NOT C++) signals and longjmp mechanisms. While I haven't yet tried monkeying with the x87 control word, this does seem to be the way to do it.  It explains why Borland raises the signal, but Visual and DMC do not.

David
February 08, 2008
This apear to be by design. You can divide by zero in "Floating-
Point Arithmetics".
In other words if huge calculations (sub-atomic to galaxies), you
might want to have access to "Infinity" as a value.

Your only choice here is to if( val == INF ) or something like
that.
February 14, 2008
Hi,

Good practice is to check for division by zero before it occurs.

The following code should enable floating point exceptions along with a few other floating point issues (it works with vc++):

  unsigned int u;
  unsigned int control_word;
  _controlfp_s(&control_word, 0, 0);
  u = control_word & ~(_EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE
| _EM_OVERFLOW | _EM_UNDERFLOW /*| _EM_INEXACT*/);
  _controlfp_s( &control_word, u, _MCW_EM);

Use a try catch block to capture the exception.

Regards
Damian
March 17, 2008
== Quote from Damian (damian.dixon@gmail.com)'s article
> Hi,
> Good practice is to check for division by zero before it occurs.

Not exactly sure what you have in mind here, but if you mean:

   ...
   if( 0 == x ) throw( DivByZero );
 //otherwise, press ahead with the division.
   z = y/x;
   ...

then I contend that:
1) it bloats the code,
2) it interrupts the natural logical flow of the code, and
3) it slows execution by requireing a test before the div.

The couple of architectures I am familiar with have a hardware trap (an unmaskable interrupt) that prevents the illegal operation of division by zero.  This doesn't take any extra processor cycles -- the processor itself raises the error; not the software.  In a C environment, this (should?) translate to a signal.  (well, it appears the programmer has to alter the control word to convert it to a trappable signal.)  Anyway, my goal was to allow the processor/OS to raise the exception without having to manually test for it on every single divide operation.

> The following code should enable floating point exceptions along
> with a few other floating point issues (it works with vc++):
>   unsigned int u;
>   unsigned int control_word;
>   _controlfp_s(&control_word, 0, 0);
>   u = control_word & ~(_EM_INVALID | _EM_DENORMAL |
_EM_ZERODIVIDE
> | _EM_OVERFLOW | _EM_UNDERFLOW /*| _EM_INEXACT*/);
>   _controlfp_s( &control_word, u, _MCW_EM);
> Use a try catch block to capture the exception.

Perhaps an example would help me understand how to use what you are proposing.

> Regards
> Damian


Thanks for your thoughts.
David