Link to home
Start Free TrialLog in
Avatar of richelieu7777
richelieu7777

asked on

Passing NaN as an argument

I need to *pass* NaN as one of several other arguments in a function of a 3rd party company's DLL.  I'm using the Visual Studio.NET 2008 compiler.  My project is in "C", not "C++"; that is, it has no classes.  One of the functions of this DLL returns a "bool" data type.  All of the rest of the files in my project have ".c" extensions but I had to change the extension of this one file which calls this DLL from ".c" to ".cpp" in order to handle the "bool".

I've tried using the NaN this way:
            test(Double::NaN,0,0,0,0,0,0,0);
but it doesn't compile

I tried including the following line at the top of the file but it didn't compile
      using namespace System;
Does anyone know how to pass NaN in a C project?

Thank you in advance.
Avatar of richelieu7777
richelieu7777

ASKER

FYI:  the 3rd party developer coded the function such that if any of the arguments to the function are "NaN" then they are ignored.  That way one single function can handle mutlple cases.
You also posted in the C# area. Here's how you can do it with C#

if (Double.NaN == myvalue)
      ;  // do something

Open in new window

And, in C, you can do this, apparently:

// must include math.h
 
if(isnan(value))
   // do your thing

Open in new window

Dear abel:
I included C# as a zone for this question is if someone in that zone also had straight C programming experience.

The "if(isnan(value))" is fine if you are testing the value of a variable.  In my case I need to *pass* it as an argument.

If there were a function which *returned* a NaN that might work--in that case I might be able to then pass it as an argument.  Do you know whether something like that exists . . . . in C (not C#)??

From the C standard, it is suggested you use;

nan('')

which will return NaN like explained here: http://www.opengroup.org/onlinepubs/009695399/functions/nan.html
Ok, just found out that Microsoft's C library and math.h do not contain those standard functions. With a bit of experimenting (actually, the source of some apache libs brought me to the idea: http://svn.apache.org/repos/asf/stdcxx/trunk/tests/support/18.numeric.special.float.cpp) I found out that the following gives a fine quiet NaN. The correct bit pattern was not in the apache lib, I got it here: http://steve.hollasch.net/cgindex/coding/ieeefloat.html

Not really your everyday science, but fun to experiment with.

The _isnan() function is part of the C libs of Microsoft. In the below code, isNaN is 1.

int inan = 0x7FC00000;
float nan = *reinterpret_cast<float*>(&inan);
int isNaN = _isnan(nan);

Open in new window

Note that this does not work directly with doubles, but this does:

double dnan = (double) nan;

Some libs support easier methods of getting a nan. strtod should also be capable of returning a nan, but unfortunately, that does not happen.

I explicitly created a quiet nan, to prevent any errors when you use this in calculations.
PS: it also works with simpler casting:


int inan = 0x7FC00000;
float nan = *(float*)(&inan);
double dnan = (double) nan;

Open in new window

Dear abel:

I tried the following, but _isnan() always returns "false" !  Strange.  Do you get the same thing?
#include <math.h>
#include <float.h>//for the _isnan() funciton
void test(void)
{
  bool xB;
  double xD,xD2;

    xD2 = 0.0;
    xD = 5.0 / xD2;
    //xD = "1.#INF000000000000" according to the debugger

    xB = _isnan(xD);
   
   //xB is always false !
}

Are you able to reproduce this behavior?
Maybe #INF and NaN are two different things.
Apparently
NaN = 1.#QNAN00000000000
and a divide by zero = 1.#INF000000000000
,two separate cases
NaN and +/-INF are very different. NaN means: don't know, undefined, as in 0.0 / 0.0. But INF means infinitive, as when you divide by zero or when the result is simply too large to be represented by a double: 2.0 / 0.0.

Note that NaN does not have a sign, though there's a quiet NaN and a signaling NaN (try compiling with a 0.0 / 0.0 constant, it will throw, that's a signaling NaN). INF does have a sign: negative or positive infinity.

Everything is in this link, I'll repeat here for ease of reference: http://steve.hollasch.net/cgindex/coding/ieeefloat.html, it's a good read.
abel:

How do you do this for a *double*?  The code you provided works for a *float* not a *double*.  I tried changing "float" to "double" in your code, below, but "nan" is *not*  NaN (i.e. "isNaN" = 0):

int inan = 0x7FC00000;
float nan = *reinterpret_cast<float*>(&inan);
int isNaN = _isnan(nan);
Note, the method I show above sets the bits explicitly in memory, according to the IEEE standard. This works on all processors and compilers. Because of the limited support for NaN and the absence of the C standard functions nan and nanf, you can use the trick above.
ASKER CERTIFIED SOLUTION
Avatar of abel
abel
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
abel:

Thanks!
The most thorough investigation and response to a question that I have ever received in Experts Exchange.  Good job, abel.
Thanks for the nice compliment!
abel:
I selected the grade of "A" for all categories and expected to see a perfect rating at the top of the screen, but it only shows 8.5 -- "very good".  How could that be?  You did the best job possible I've experienced on Experts Exchange; and I've been a member for about 5 years or so.

Do I need to complain to administration?
one more thing: as you noticed, doing the cast of int to double does not work, but doing it first to a float does work. The reason is: the double has a larger mantissa and the mantissa must be all ones. To do it in one pass, you can use the following (the one in the end is on purpose, the fraction part must be nonzero):

__int64 i64nan = 0x7FF0000000000001; //bit 2-11 set to 1 and nonzero fraction
double dnan = *(double*)(&i64nan);

Open in new window

> Do I need to complain to administration?
haha, that would be a good thing! I have no idea why it doesn't show a high figure, but to get it higher, you can click the "comment helpful >> yes" buttons (but only if you feel the comment was helpful, of course ;-)

I'm glad you liked my, kinda chaotic, answers!