- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm using IVF v. 10.1.025 to compile for a 32 bit Windows system and running the compiled program under XP.
An IVF-compiled exe on a user's machine is generating a lot of NaN values which it shouldn't, and I'm not able to duplicate it on my machine. I'd like to create a debug version of the exe which would stop and report the first place a floating point overflow or other problem occurs. But I haven't been able to figure out how. I've tried compiling for debug with, among others, the following compiler options:
/traceback
/check: all
/fpe:0
/Zi
and the /DEBUG linker option.
It sounds from the description of the /fpe option that specifying /fpe:0 should cause an exception to occur when a floating point overflow occurs. But it doesn't. In a test program which does the operation 1./0. and assigns it to a floating point variable, no error occurs. A printout of the variable's value shows "Infinity". Assigning the variable's infinite value to an integer results in the integer having the value -2147483648. Dividing an integer variable equal to 1 by an integer variable equal to zero results in a Windows exception message "[program] has encountered a problem and needs to close. We are sorry for the inconvenience."
Is it possible to trap floating point overflows and other errors in an .exe file and get any meaningful information about where in the program it occurred? If so, how? The user won't, of course, have the compiler available.
Thanks!
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Can you post a test case? I tried to build one and gotdifferent result from yours:
>type test.f90
program main
real a, b, c
a = 0
b = 1
c = b / a
write(*,*) "c = ",c
end
>ifort test.f90
>test.exe
c = Infinity
>ifort /fpe:0 /traceback /check:all /Zi test.f90
>test.exe
forrtl: error (73): floating divide by zero
Image PC Routine Line Source
test.exe 00401079 _MAIN__ 6 test.f90
test.exe 004762AD Unknown Unknown Unknown
test.exe 0044C5A1 Unknown Unknown Unknown
kernel32.dll 7C816FD7 Unknown Unknown Unknown
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the response. Your test program works just as you said. However, mine isn't a console application but a "Windowing" application. Here's a test program that's more like mine:
INTEGER (KIND = 4) function WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow )
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_WinMain@16' :: WinMain
INTEGER (KIND = 4) :: hInstance, hPrevInstance, lpszCmdLine, nCmdShow
real a, b, c
open (UNIT=1, FILE='Test.txt', STATUS='replace')
a = 0
b = 1
c = b / a
write(1,*) "c = ",c
a = 5
write(1,*) "a = ",a
WinMain = 0
end
I used the default settings for a debug build except for setting fpe:0. Here's what's printed in Text.txt after running the program:
c = Infinity
a = 5.000000
The fact that the new assignment for the value of a was made and printed shows that the divide by zero error didn't stop the program. I expect to see a window showing the same error tracking information that your program sends to the console. But no error message shows, and the program just keeps going after happily dividing by zero.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the response. Your test program works just as you said. However, mine isn't a console application but a "Windowing" application. Here's a test program that's more like mine:
INTEGER (KIND = 4) function WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow )
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_WinMain@16' :: WinMain
INTEGER (KIND = 4) :: hInstance, hPrevInstance, lpszCmdLine, nCmdShow
real a, b, c
open (UNIT=1, FILE='Test.txt', STATUS='replace')
a = 0
b = 1
c = b / a
write(1,*) "c = ",c
a = 5
write(1,*) "a = ",a
WinMain = 0
end
I used the default settings for a debug build except for setting fpe:0. Here's what's printed in Text.txt after running the program:
c = Infinity
a = 5.000000
The fact that the new assignment for the value of a was made and printed shows that the divide by zero error didn't stop the program. I expect to see a window showing the same error tracking information that your program sends to the console. But no error message shows, and the program just keeps going after happily dividing by zero.
In a windows application, you have to set up the floating point control word yourself to enable the traps. This is described in the documentation. See the sections about handling floating point exceptions,impact of application type, etc.
Bill Hilliard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In a windows application, you have to set up the floating point control word yourself to enable the traps. This is described in the documentation. See the sections about handling floating point exceptions,impact of application type, etc.
Bill Hilliard
Thanks. I added a CALL SETCONTROLFPQQ statement to the program, and now the divide by zero produces a general Windows fault ("
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
[cpp]__try {
[/cpp]
Thanks. I added a CALL SETCONTROLFPQQ statement to the program, and now the divide by zero produces a general Windows fault ("
How hard it is depends on your comfort level with Windows structured exception handling I suppose. The idea is to wrap your Fortran code in a try/except block. In your example above, you would move the Fortran code into some other function, call it MyFortranCode() or whatever you like. Then write your WinMain() code in a C file. The WinMain() code just calls MyFortranCode() something like:
[cpp]__try {
sts = MyFortranCode();
} __except(insert useful filter expression that invokes your handler)
{;}
[/cpp]
The filter expression needs to capture the exception information returned by the OS. Your handler could be a Fortran routine that just calls TRACEBACKQQ() and exits, for example. You would pass the exceptioninfo to tracebackqq().
That is the basic idea. I guess you willhave todecide if it is worth your time to figure out the details. Hope this helps some.
Bill
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I was able to adapt your initial Fortran WinMain example and code I received from a Fortran RTL developer recently based on another customer's interest that I believe closely matches yours, and fits with Bill's guidance too, so I thought I would share it.
The example creates a WinMain driver in C to call the Fortran function and leverages the Fortran RTLs to trap the floating-point divide and present the Fortran RTL symbolized traceback in a pop-up window (see attached .bmp).
I hope it is useful.
Compile the code as follows:
ifort -c -Od -Zi /fpe:0 /traceback formain.f90
cl -c -Od -Zi MyWinMain.c
ifort /exe:myFPE.exe formain.obj MyWinMain.obj /link /machine:i386 /subsystem:windows
MyWinMain.c:
============
[cpp]#include#include #include #include #define FPE_M_TRAP_DIV0 0x00000004 static LPEXCEPTION_POINTERS qwin_eptr; static int qwin_fpe_ieee_sts; #if defined(__cplusplus) /* C linkage */ extern "C" { #endif extern int for_set_fpe_ (unsigned int *); extern int for_rtl_init_ (void); /* RTL initialization routine */ extern int for_rtl_finish_ (void); /* RTL Cleanup routine */ extern int for__nt_signal_handler( _FPIEEE_RECORD *pieee, LPEXCEPTION_POINTERS eptr, int fpe_ieee_sts, int *code_ptr, void (__cdecl **user_handler_ptr)(int) ); #if defined(__cplusplus) /* end C linkage */ } #endif int qwin__nt_handler_jacket ( _FPIEEE_RECORD *pieee ) { return ( for__nt_signal_handler( pieee, qwin_eptr, qwin_fpe_ieee_sts, NULL, NULL ) ); } /*------------------------------------------* | WinMain | *------------------------------------------*/ int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { int nReturn; unsigned int trap_mask ; __try { __try { for_rtl_init_(); trap_mask = FPE_M_TRAP_DIV0; trap_mask = for_set_fpe_ (&trap_mask); nReturn = FORMAIN(hInstance, hPrevInstance, lpszCmdLine, nCmdShow); } __except ( (qwin_fpe_ieee_sts = _fpieee_flt ( GetExceptionCode(), qwin_eptr = GetExceptionInformation(), qwin__nt_handler_jacket ) ) == EXCEPTION_CONTINUE_SEARCH ? qwin__nt_handler_jacket( NULL ) : qwin_fpe_ieee_sts ) {;} /* Just leave this null for now. */ } /* End of try/except block */ __finally { /* ** Do any clean up required. */ for_rtl_finish_(); } nReturn = 0; exit (nReturn); } /* WinMain */ [/cpp]
formain.f90:
============
[cpp]INTEGER (KIND = 4) function ForMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow ) INTEGER (KIND = 4) :: hInstance, hPrevInstance, lpszCmdLine, nCmdShow real a, b, c open (UNIT=1, FILE='Test.txt', STATUS='replace') a = 0 b = 1 c = b / a write(1,*) "c = ",c a = 5 write(1,*) "a = ",a ForMain = 0 end [/cpp]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I want to thank you very much for taking the time and trouble to put this together. However, the program I really need this for would almost certainly require a good deal more work to adapt, since it's composed of a large number of files and modules, and it's taken quite a while for me to determine what options I need to use, which files I need to include, and so forth. I haven't done any C programming for quite a long time, so I'm also apprehensive that I'd have a fair amount of fiddling to do in getting the compiler up and running and happy with the code. I was looking for a simple solution, but see that there isn't any. Although it'll take quite a while to make up diagnostic programs to try and find where the NaN results first happen, I'm pretty sure it'll be faster overall than pursuing the dual language route.
Thanks again to everyone who responded.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For fpe's, the all Fortran solution would be via theIEEE EXCEPTION HANDLING feature of F2003. IVF doesn't support it yet. FWIT, lodge acomplaint (not a request, it's long overdue) with Premier Support.
BTW, don't assume that the posted workaround actually works under all circumstances likely to be encountered on Windows by the average Joe programmer.
Gerry
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The IEEE modules are in v11 - coming REAL SOON to a PC near you.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The IEEE modules are in v11 - coming REAL SOON to a PC near you.
That's great. Horrah for v11.
Gerry
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
i have an old unix code that uses FFLAGS -K, -C +u77 +fp_exception +01
and LDFLAGS = +u77 -W1 -a, archive +FPVZO
im porting the code over to linux, and when i use the fpe0 flag, the program crashes.
i look in the code and there is a variable X = A/B. B happens to be 0, which is why of course the program
crashes. In the old code I am able to get results that have X = 0, but in the new code using less scrict fpe flags
the number is NAN. Is there a way to get the output to run and compile and set NAN values to 0? Some kinda loader flag or option?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is no option to set the result of a zerodivide to zero. While you could use the IEEE modules to do the computation, test for the error and then change the value, the simpler way is to just test for the divisor being zero before doing the divide.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is no option or flag. I'm not aware that our compiler has ever offered such a thing - perhaps some other compiler on another platform did.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
In an earlier reply to this thread you said that the fpe feature of FORTRAN 2003 would be available soon in version 11.??. Are we talking days, weeks or months?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
How about negative months? The intrinsic modules IEEE_ARITHMETIC, IEEE_EXCEPTIONS and IEEE_FEATURES are in version 11.0, available for a month and a half now.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
How about negative months? The intrinsic modules IEEE_ARITHMETIC, IEEE_EXCEPTIONS and IEEE_FEATURES are in version 11.0, available for a month and a half now.
Thanks Steve,
I was deceived by COMING SOON which implies it's not yet available. I do have version 11 so I'll have a look in the release notes and at any samples that are included.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I wrote that on November 3. Version 11 was released the next day. I think.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here's an example from the standard on using the IEEE FP support.
[cpp]USE, INTRINSIC :: IEEE_EXCEPTIONS
USE, INTRINSIC :: IEEE_FEATURES, ONLY: IEEE_INVALID_FLAG
! The other exceptions of IEEE_USUAL (IEEE_OVERFLOW and
! IEEE_DIVIDE_BY_ZERO) are always available with IEEE_EXCEPTIONS
TYPE(IEEE_STATUS_TYPE) STATUS_VALUE
LOGICAL, DIMENSION(3) :: FLAG_VALUE
...
CALL IEEE_GET_STATUS(STATUS_VALUE)
CALL IEEE_SET_HALTING_MODE(IEEE_USUAL,.FALSE.) ! Needed in case the
! default on the processor is to halt on exceptions
CALL IEEE_SET_FLAG(IEEE_USUAL,.FALSE.)
! First try the "fast" algorithm for inverting a matrix:
MATRIX1 = FAST_INV(MATRIX) ! This shall not alter MATRIX.
CALL IEEE_GET_FLAG(IEEE_USUAL,FLAG_VALUE)
IF (ANY(FLAG_VALUE)) THEN
! "Fast" algorithm failed; try "slow" one:
CALL IEEE_SET_FLAG(IEEE_USUAL,.FALSE.)
MATRIX1 = SLOW_INV(MATRIX)
CALL IEEE_GET_FLAG(IEEE_USUAL,FLAG_VALUE)
IF (ANY(FLAG_VALUE)) THEN
WRITE (*, *) Cannot invert matrix
STOP
END IF
END IF
CALL IEEE_SET_STATUS(STATUS_VALUE)
[/cpp]
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page