www.digitalmars.com Home | Search | C & C++ | D | DMDScript | News Groups | index | prev | next
Archives

D Programming
D
D.gnu
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.ide
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger

C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows

digitalmars.empire
digitalmars.DMDScript
electronics



c++ - Traping divide by zero

↑ ↓ ← DQNOK <davidlqualls gmail.com> writes:
== 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


Ican'tfigureouthowtotrapeitherfloatingpoint,orinteger
dividebyzero.

Onsomeothercompilers,IcantrapSIGFPEandthatdoesthetrick
forbothfloatingpoint,andforintegerdividebyzero.Ondmc
andmicrosoftVC(inthisregard,thetwocompilersseemtoact
identically),theexpression:
doubled=8.0/0.0;//doesnotraiseasignalthatIcantell.
doesnothingbutassigninftodandmoveon.However,the
expression:
inti=8/0;
causestheprogramtoabort.Ican'tfigureouthowtotrapthe
errorandpreventtheabort,orhowtotrapthefloatingpoint
dividebyzero.

David
Jan 16 2008
Imbecil <shefututurorshefilor yahoo.com> writes:
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;
}

//-----------------------------------------------------------------
Jan 18 2008
↑ ↓ → DQNOK <davidlqualls yahoo.com> writes:
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.
Jan 22 2008
Sunny Pal Singh <arorasp2000 hotmail.com> writes:
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
 

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.
Jan 23 2008
↑ ↓ → DQNOK <davidlqualls_at gmail_dot.com> writes:
== 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

 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
Jan 24 2008
Yeg <spamtrap gmail.com> writes:
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.
Feb 08 2008
↑ ↓ Damian <damian.dixon gmail.com> writes:
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
Feb 13 2008
↑ ↓ → DQNOK <davidlqualls yahoo.com> writes:
== 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_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
Mar 17 2008