Signaling or trapping "nan" as they arise in calculations in a numerical code base in C ++

We have a numerical code written in C ++. Rarely, but at certain specific costs, some calculations result in a nan value.

Is there a standard or recommended method by which we can stop and warn the user when a certain numerical calculation leads to the generation of "nan"? (in debug mode). Checking each result, if it is equal to "nan", seems impractical, given the huge size of the matrices and vectors.

How does a standard digital library deal with this situation? Could you talk about this?

+4
source share
4 answers

NaN spreads when applied to a numerical operation. Thus, it is enough to verify the final result in order to be NaN. As for how to do this - if for building for> = C ++ 11 there is std :: isnan, as Goz noted. For <C ++ 11 - if you want to be bulletproof - I would personally do a bit check (especially if optimization could be involved). Sample for NaN is

? 11.......1 xx.......x sign bit ^ ^exponent^ ^fraction^ 

Where? can be any, and at least one x must be equal to 1.

For a platform-specific solution, there is another possibility of seams. There is a feenableexcept function in glibc (possibly using the signal function and the compiler option -fnon-call-exceptions ) that enables the generation of SIGFPE syntax when an invalid floating point operation occurs. And the _control87 function (possibly with the _set_se_translator function and the /EHa compiler /EHa ), which is almost the same in VC.

+1
source

Although this is a non-standard extension, originally from glibc, on many systems you can use the feenableexcept subroutine declared in <fenv.h> to request that the machine catch specific floating point exceptions and deliver SIGFPE to your process. You can use fedisableexcept to mask the capture and fegetexcept to request the set of exceptions that have been exposed. By default, all are masked.

On older BSD systems without these procedures, you can use fpsetmask and fpgetmask from <ieeefp.h> , but the world seems to converge in glibc-API.

Warning: glibc currently has an error that fegetenv (standard procedure C99) has an unintended side effect of masking all x86 exception traps, so you must call fesetenv to recover them after. (Shows how much someone relies on this stuff ...)

+1
source

On many architectures, you can expose an invalid exception that will throw an interrupt when NaN is usually thrown by computation such as 0*infinity . By running in this debugger, you will interrupt this interrupt and be able to check the calculations that led to this point. Outside of the debugger, you can install a trap handler to record information about the computation state that caused the invalid operation.

On x86, for example, you must clear the mask bit of the invalid operation in FPCR (bit 0) and MXCSR (bit 7) to enable capture for invalid operations from operations x87 and SSE, respectively.

Some individual platforms provide facilities for writing to these control registers from C, but there is no portable interface that works cross-platform.

0
source

Testing f! = F can give problems using g ++ with -ffast-math optimization turned on: Checking whether double (or float) is NaN in C ++

The only reliable way is to check the beatpattern.

As for where to implement checks, it largely depends on the specifics of your calculation and how common Nan errors are, for example, performance degradation for constant trial calculations and verification at certain stages.

-1
source

Source: https://habr.com/ru/post/1481122/


All Articles