Usefulness of Signaling Nan

Usefulness of signaling NaN?

As I understand it, the purpose of signaling NaN is to initialize data structures, but, of course runtime initialization in C runs the risk of having the NaN loaded into a float register as part of initialization, thereby triggering the signal because the the compiler isn't aware that this float value needs to be copied using an integer register.

I would hope that you could could initialize a static value with a signaling NaN, but even that would require some special handling by the compiler to avoid having it converted to a quiet NaN. You could perhaps use a bit of casting magic to avoid having it treated as a float value during initialization.

If you were writing in ASM, this would not be an issue. but in C and especially in C++, I think you will have to subvert the type system in order to initialize a variable with NaN. I suggest using memcpy.

What is the difference between quiet NaN and signaling NaN?

When an operation results in a quiet NaN, there is no indication that anything is unusual until the program checks the result and sees a NaN. That is, computation continues without any signal from the floating point unit (FPU) or library if floating-point is implemented in software. A signalling NaN will produce a signal, usually in the form of exception from the FPU. Whether the exception is thrown depends on the state of the FPU.

C++11 adds a few language controls over the floating-point environment and provides standardized ways to create and test for NaNs. However, whether the controls are implemented is not well standardized and floating-point exceptions are not typically caught the same way as standard C++ exceptions.

In POSIX/Unix systems, floating point exceptions are typically caught using a handler for SIGFPE.

Using NaN in C++?

After looking into this some more, it looks like signaling_NaN is useless as provided. If floating point exceptions are enabled, then calling it counts as processing a signaling NaN, so it immediately raises an exception. If floating point exceptions are disabled, then processing a signaling NaN automatically demotes it to a quiet NaN, so signaling_NaN doesn't work either way.

Menkboy's code works, but trying to use signaling NaNs runs into other problems: there's no portable way to enable or disable floating point exceptions (as alluded to here and here), and if you're relying on exceptions being enabled, third party code may disable them (as described here).

So it seems like Motti's solution is really the best choice.

There are 2 kinds of NaN: signaling_NaN, quiet_NaN, and... NAN itself?

You machine does not have a signaling NaN. I presume the Q in #QNAN stands for Quiet. Check numeric_limits::has_signaling_NaN. As for signaling_NaN, the standard says this:

Meaningful for all specializations for which has_signaling_NaN != false. Required in specializations
for which is_iec559 != false.

Therefore, it may be required yet meaningless… the natural thing to do is supply a quiet NaN instead.

I haven't found an authoritative resource for QNAN vs IND, but they appear to both be quiet NaNs. There are potentially millions of different NaNs, one for each mantissa value. If I were to guess, IND may be like an error code for an ind‍eterminate value, e.g. 0/0. Not really an appropriate choice for a generic NAN macro, but they might have been stuck with it after defining the C numeric binding that way.

How to convert signalling NaN to quiet NaN?

I guess I'll expand on my comment and provide a solution.

The tricky part here is being able to read/compare the sNaN without triggering an exception. After all it's called "signalling" for a reason. Wikipedia says that even comparison operations on sNaN will trigger an exception.

So a direct use of number != number or isnan(value) probably don't work because they invoke comparisons and will trigger a hardware exception. (I'm not entirely sure how isnan(value) is implemented though.)

EDIT : Correction, it looks like isnan() will never trigger an exception even on a signalling NaN so that makes the rest of this answer pointless.

The predicate isNaN(x) determines if a value is a NaN and never
signals an exception, even if x is a signaling NaN.

Meaning it can be done as just this as suggested by Chrisoph in the comments:

if(isnan(value))
value = NAN;

Here's my original answer that doesn't use isnan(value):

So the only way I can think of doing this is to go the bitwise route.

Assuming float is standard IEEE single-precision and int is a 32-bit integer, then here's one way to go about this: (Note that I haven't tested this.)

union{
int i;
float f;
} val;

val.f = // Read the value here.

// If NaN, force it to a quiet NaN.
if ((val.i & 0x7f800000) == 0x7f800000){
val.i |= 0x00400000;
}

Note that this approach is not completely C-compliant and will invoke implementation defined behavior. Also note that this approach is not particularly efficient due to the need to move data between the FP and integer units.

Here's how this works:

  1. The union obviously is used to get the bits of the float into an int.
  2. All NaNs will have the bits in the 0x7f80000 set. The if-statement test will check if all of these bits are set.
  3. i |= 0x00400000; forces the NaN to a quiet NaN. Bit 22 determines whether the NaN is silent or quiet. Forcing it to 1 will make it a quiet NaN.

EDIT 2: If you can't use unions, here's are some other approaches (each of which have their own drawbacks):

Method 1:

float f = //  Read the value here.

int i = *(int*)&f;
if ((i & 0x7f800000) == 0x7f800000){
i |= 0x00400000;
}

f = *(float*)&i;

Downside: It violates strict aliasing, but will probably still work.

Method 2:

char buf[sizeof(float)];

float f = // Read the value here.

*(float*)&buf = f;
int i = *(int*)&buf;

if ((i & 0x7f800000) == 0x7f800000){
i |= 0x00400000;
}

*(int*)&buf = i;
f = *(float*)&buf;

Same idea works with memcpy().

Downside: If alignment matters, you need to make sure buf is aligned.

Method 3: Implement your own isnan():

See this question: Where is the source code for isnan?

How do I get C++ signaling_nan() to throw an exception, without needing if tests?

So, there's a lot of ways to go about this problem:

Custom Classes, Which Check for FPE in Operations

The simplest way is just to write a wrapper class, that checks for floating-point exceptions, and then never have to deal with it later, with all the numeric operations built-in.

#include <exception>
#include <fenv.h>

class FloatingPointException: public std::exception {
const char* what() const throw() {
return "Exception raised in floating-point operation.";
}
};

class F64 {
public:
F64(double f): m_f(f) {}
F64(const F64 &other): m_f(other.m_f) {}
F64(F64 &&other): m_f(other.m_f) {}
F64& operator=(const F64& other) { m_f = other.m_f; return *this; }
F64& operator=(F64&& other) { m_f = other.m_f; return *this; }

operator double() const { return m_f; }

// This is where we use fenv.
F64 operator*(F64 other) const {
feclearexcept(FE_ALL_EXCEPT);
auto result = m_f * other.m_f;
if (fetestexcept(FE_INVALID)) {
throw FloatingPointException();
}
return F64(result);
}

F64& operator*=(F64 other) {
operator=(operator*(other));
return *this;
}

// This is where we use fenv.
F64 operator/(F64 other) const {
feclearexcept(FE_ALL_EXCEPT);
auto result = m_f / other.m_f;
if (fetestexcept(FE_INVALID)) {
throw FloatingPointException();
}
return F64(result);
}

F64& operator/=(F64 other) {
operator=(operator/(other));
return *this;
}

// Implement all other operations.
private:
double m_f;
};

feenableexcept

Another approach is to use feenableexcept at the start of the program:

#include <fenv.h>
int main() {
feenableexcept(FE_INVALID);
...
return 0;
}

This will produce a SIGFPE if an invalid floating-point exception occurs. You can also use a GCC extension so this automatically occurs before main.

#define _GNU_SOURCE 1
#include <fenv.h>
static void __attribute__ ((constructor)) trapfpe {
feenableexcept(FE_INVALID);
}

You can also use this with signal handlers.

Bespoke Assembly

I highly recommend not doing this, since it won't be portable (even on x86, since it would differ for x87 FPUs vs. newer x86 CPUs with SSE2. However, you could try to use inline assembly to check for floating-point exceptions, even though this is likely a very bad idea. For example, dealing with the x87 FPU status register is detailed here.

Is it considered normal that f = NAN may cause raising floating-point exceptions?

For the record, this ...

The macro NAN is defined if and only if the implementation supports quiet NaNs for the float type. It expands to a constant expression of type float representing a quiet NaN.

... is C17 7.12/5, and it probably has the same or similar numbering in C2x.


Updated

The fact that when used with MSVC or Clang on Windows, your test program causes the FE_INVALID FP exception to be raised suggests that the combination of

  • Microsoft's C standard library and runtime environment with
  • the MSVC and Clang compilers and
  • the options you are specifying to those

is causing a signaling NaN to be generated and used as an arithmetic operand. I would agree that that is an unexpected result, probably indicating that these combinations fail to fully conform to the C language specification in this area.

has nothing to do with whether the resulting NaN is a quiet or a signaling one. The misconception there is that the FE_INVALID flag would be raised only as a consequence of generating or operating on a signaling NaN. That is not the case.

For one thing, IEEE-754 does not define any case in which a signaling NaN is generated. All defined operations that produce an NaN produce a quiet NaN, including operations in which one operand is a signaling NaN (so MSVC and Clang on Windows almost certainly do produce a quiet NaN as the value of the NAN macro). Most operations with at least one signaling NaN as an operand do, by default, cause the FE_INVALID flag to be raised, but that is not the usual reason for that flag to be raised.

Rather, under default exception handling, the FE_INVALID flag is raised simply because of a request to compute an operation with no defined result, such as infinity times 0. The result will be a quiet NaN. Note that this does not include operations with at least one NaN operand, which do have a defined result: a quiet NaN in many cases, unordered / false for comparisons, and other results in a few cases.

With that for context, it is important to recognize that just because NAN expands to a constant expression (in a conforming C implementation) does not mean that the value of that expression is computed at compile time. Indeed, given the specifications for MSVC's and Clang's strict fp modes, I would expect those modes to disable most, if not all, compile-time computation of FP expressions (or at minimum to propogate FP status flags as if the computations were performed at run time).

Thus, raising FE_INVALID is not necessarily an effect of the assignment in f = NAN. If (as in Microsoft's C standard library) NAN expands to an expression involving arithmetic operations then the exception should be raised as a result of the evaluating that expression, notwithstanding that the resulting NaN is quiet. At least in implementations that claim full conformance with IEC 60559 by defining the __STDC_IEC_559__ feature-test macro.

Therefore, although I will not dispute that

people may wonder: "how writing to memory may cause raising floating-point exceptions?".

, no convincing evidence has been presented to suggest that such causation has been observed.

Nevertheless, the value represented by a particular appearance of NAN in an expression that is evaluated has some kind of physical manifestation. It is plausible for that to be in an FPU register, and storing a signaling NaN from an FPU register to memory indeed could cause a FP exception to be raised on some architectures.



Related Topics



Leave a reply



Submit