Thread overview |
---|
January 16, 2008 Traping divide by zero | ||||
---|---|---|---|---|
| ||||
== 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 Re: Traping divide by zero | ||||
---|---|---|---|---|
| ||||
Posted in reply to DQNOK | 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 Re: Traping divide by zero | ||||
---|---|---|---|---|
| ||||
Posted in reply to Imbecil | 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 Re: Traping divide by zero | ||||
---|---|---|---|---|
| ||||
Posted in reply to DQNOK | 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 Re: Traping divide by zero | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sunny Pal Singh | == 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 Re: Traping divide by zero | ||||
---|---|---|---|---|
| ||||
Posted in reply to DQNOK | 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 Re: Traping divide by zero | ||||
---|---|---|---|---|
| ||||
Posted in reply to Yeg | 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 Re: Traping divide by zero | ||||
---|---|---|---|---|
| ||||
Posted in reply to Damian | == 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 |
Copyright © 1999-2021 by the D Language Foundation