I'm writing Python 2.6 code that interfaces with NI TestStand 4.2 via COM in Windows. I want to make a "NAN" value for a variable, but if I pass it float('nan')
, TestStand displays it as IND
.
Apparently TestStand distinguishes between floating point "IND" and "NAN" values. According to TestStand help:
IND
corresponds to Signaling NaN in Visual C++, whileNAN
corresponds to QuietNaN
That implies that Python's float('nan')
is effectively a Signaling NaN when passed through COM. However, from what I've read about Signaling NaN, it seems that Signaling NaN is a bit "exotic" and Quiet NaN is your "regular" NaN. So I have my doubts that Python would be passing a Signaling NaN through COM. How could I find out if a Python float('nan')
is passed through COM as a Signaling NaN or Quiet NaN, or maybe Indeterminate?
Is there any way to make a Signaling NaN versus QuietNaN or Indeterminate in Python, when interfacing with other languages? (Using ctypes
perhaps?) I assume this would be a platform-specific solution, and I'd accept that in this case.
Update: In the TestStand sequence editor, I tried making two variables, one set to NAN
and the other set to IND
. Then I saved it to a file. Then I opened the file and read each variable using Python. In both cases, Python reads them as a nan
float.
From what I can gather, it seems there is some confusion as to thinking that the sign of a
NaN
determines whether or not it is quiet. On the contrary, the convention is that the most significant bit of the mantissa determines this. From Wikipedia (emphasis added):Since most implementations are IEEE 754-2008 conformant, this is the convention you should follow. In general, you cannot plan on the sign bit being consistent for NaNs, even for different NaNs on the same platform. Under this convention,
float('nan')
andscipy.nan
both seem to be quiet NaNs, at least in the cases discussed above.John Cook had a nice post on this that might be helpful:
Update: won't this work?
CPython definition of nan
When Python reports a
nan
, where does that come from?Py_NAN
in the CPython C source code(Py_HUGE_VAL * 0.)
Py_HUGE_VAL
is probably defined asHUGE_VAL
--it has a note to say it should beHUGE_VAL
except on platforms where that is broken.float('nan')
which is defined fromPy_NAN
in CPython's C source code.Reading Python and pywin32 Source Code
I've had a look at the C source code for
pywin32
, in particularwin32com
, which forms the Python↔COM translation layer. That code:PyNumber_Float()
to convert it to a Pythonfloat
(if it isn't already)PyFloat_AsDouble()
to convert it to a plain Cdouble
value.double
directly contained in thePyFloatObject
memberob_fval
.So it looks as though I've traced a
NaN
from the COM interface back to a plain Cdouble
type containingPy_NAN
, whatever that turns out to be on the Windows platform.TestStand NAN Value
Now I've tried this with NI TestStand. First I tried:
But that still appeared in TestStand as
IND
. So then I created a TestStand file with variables set toIND
andNAN
, and read the values from Python. It turns out that TestStand'sNAN
has a value ofFFFF000000000001
. According to Kevin's Summary Charts that is a negative quiet NAN. TestStand'sIND
does have the expected value for Indeterminate,FFF8000000000000
.Success
So, after all that, I have succeeded in setting a NAN in TestStand, from Python:
I dug a bit for you, and I think you might be able to use the
struct
module in combination with the information on at Kevin's Summary Charts. They explain the exact bit patterns used for the various kinds of IEEE 754 floating point numbers.The only thing you probably will have to be careful for, if I read the topics on this
IND
-eterminate value, is that that value tends to trigger some kind of floating point interrupt when assigned directly in C code, causing it to be turned into a plain NaN. Which in turn meant those people were advised to do this kind of thing in ASM rather than C since C abstracted that stuff away.. Since it is not my field, and that I am not sure to what extent this kind of value would mess with Python, I figured I'd mention it so you can at least keep an eye for any such weird behaviour. (See the accepted answer for this question).Referring to Kevin's Summary Charts, that shows that
float('nan')
is actually technically the Indeterminate value, whilescipy.nan
is a Quiet NaN.Let's try making a Signaling NaN, and then verify it.
No, the Signaling NaN gets converted to a Quiet NaN.
Now let's try making a Quiet NaN directly, and then verify it.
So that's how to make a proper Quiet NaN using
struct.unpack()
--at least, on a Windows platform.