Python中如何区分不同类型的NaN浮点数

发布于 2024-09-27 01:43:00 字数 1224 浏览 7 评论 0原文

我正在编写 Python 2.6 代码,通过 Windows 中的 COM 与 NI TestStand 4.2 交互。我想为变量创建一个“NAN”值,但如果我传递float('nan'),TestStand会将其显示为IND

显然,TestStand 区分浮点“IND”和“NAN”值。根据 TestStand 帮助

  • < code>IND 对应于 Visual C++ 中的 Signaling NaN,而
  • NAN 对应于 QuietNaN

这意味着 Python 的 float(当通过 COM 传递时,'nan') 实际上是一个Signaling NaN。然而,从我读到的有关Signaling NaN的内容来看,Signaling NaN似乎有点“异国情调”,而Quiet NaN才是你的“常规”NaN。所以我怀疑 Python 是否会通过 COM 传递Signaling NaN如何确定 Python float('nan') 是否作为 Signaling NaNQuiet NaN 通过 COM 传递,或者可能不确定

有什么办法可以使Signaling NaNQuietNaN不确定在Python 与其他语言交互时? (也许使用ctypes?)我认为这将是一个特定于平台的解决方案,在这种情况下我会接受这一点。

更新:在TestStand序列编辑器中,我尝试创建两个变量,一个设置为NAN,另一个设置为IND。然后我把它保存到一个文件中。然后我打开该文件并使用 Python 读取每个变量。在这两种情况下,Python 将它们读取为 nan 浮点数。

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++, while
  • NAN 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

浪推晚风 2024-10-04 01:43:00

我为您挖掘了一些内容,我认为您也许可以结合 Kevin 的摘要图表。它们解释了用于各种 IEEE 754 浮点数的确切位模式。

如果我阅读有关此 IND 确定值的主题,您可能需要注意的唯一一件事是,当直接在 C 代码中赋值时,该值往往会触发某种浮点中断,导致它变成一个普通的 NaN。这反过来意味着那些人被建议在 ASM 而不是 C 中做这种事情,因为 C 抽象了这些东西。因为这不是我的领域,而且我不确定这种值会在多大程度上混乱Python,我想我应该提到它,这样你至少可以留意任何这种奇怪的行为。 (请参阅此问题的已接受答案)。

>>> import struct

>>> struct.pack(">d", float('nan')).encode("hex_codec")
'fff8000000000000'

>>> import scipy
>>> struct.pack(">d", scipy.nan).encode("hex_codec")
'7ff8000000000000'

参考 Kevin 的摘要图表,显示 < code>float('nan') 实际上从技术上讲是不确定值,而 scipy.nan 是 Quiet NaN。

让我们尝试创建一个 Signaling NaN,然后​​验证它。

>>> try_signaling_nan = struct.unpack(">d", "\x7f\xf0\x00\x00\x00\x00\x00\x01")[0]
>>> struct.pack(">d", try_signaling_nan).encode("hex_codec")
'7ff8000000000001'

不,Signaling NaN 会转换为 Quiet NaN。

现在我们尝试直接制作一个Quiet NaN,然后​​验证一下。

>>> try_quiet_nan = struct.unpack(">d", "\x7f\xf8\x00\x00\x00\x00\x00\x00")[0]
>>> struct.pack(">d", try_quiet_nan).encode("hex_codec")
'7ff8000000000000'

这就是如何使用 struct.unpack() 生成正确的 Quiet NaN——至少在 Windows 平台上是这样。

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).

>>> import struct

>>> struct.pack(">d", float('nan')).encode("hex_codec")
'fff8000000000000'

>>> import scipy
>>> struct.pack(">d", scipy.nan).encode("hex_codec")
'7ff8000000000000'

Referring to Kevin's Summary Charts, that shows that float('nan') is actually technically the Indeterminate value, while scipy.nan is a Quiet NaN.

Let's try making a Signaling NaN, and then verify it.

>>> try_signaling_nan = struct.unpack(">d", "\x7f\xf0\x00\x00\x00\x00\x00\x01")[0]
>>> struct.pack(">d", try_signaling_nan).encode("hex_codec")
'7ff8000000000001'

No, the Signaling NaN gets converted to a Quiet NaN.

Now let's try making a Quiet NaN directly, and then verify it.

>>> try_quiet_nan = struct.unpack(">d", "\x7f\xf8\x00\x00\x00\x00\x00\x00")[0]
>>> struct.pack(">d", try_quiet_nan).encode("hex_codec")
'7ff8000000000000'

So that's how to make a proper Quiet NaN using struct.unpack()--at least, on a Windows platform.

青瓷清茶倾城歌 2024-10-04 01:43:00

nan 的 CPython 定义

当 Python 报告 nan 时,它来自哪里?

  • 的计算结果(特定于平台的值?)
  • CPython C 源代码中 Py_NAN
    • 定义为(Py_HUGE_VAL * 0.)
      • 值因平台而异
      • Py_HUGE_VAL 可能被定义为 HUGE_VAL - 它有一条注释表明它应该是 HUGE_VAL,除非在有问题的平台上。
  • float('nan') 由 CPython 的 C 源代码中的 Py_NAN 定义。

阅读 Python 和 pywin32 源代码

我查看了 pywin32 的 C 源代码,特别是 win32com,它构成了 Python↔ COM 翻译层。该代码:

  • 获取输入对象
  • ,调用 PyNumber_Float() 将其转换为 Python float(如果还没有)
  • 调用 PyFloat_AsDouble() > 将其转换为纯 C double 值。
    • 这只是返回直接包含在 PyFloatObject 成员 ob_fval 中的 C double

所以看起来好像我已经从 COM 接口追踪了一个 NaN 到包含 Py_NAN 的普通 C double 类型,无论结果如何是在Windows平台上。

TestStand NAN 值

现在我已经使用 NI TestStand 进行了尝试。首先我尝试了:

quiet_nan = struct.unpack(">d", "\x7f\xf8\x00\x00\x00\x00\x00\x01")[0]
# Set the variable's value in TestStand
locals_prop_object.SetValNumber(var_name, 0, quiet_nan)

但是在 TestStand 中仍然显示为 IND 。然后我创建了一个 TestStand 文件,其中变量设置为 IND 和 NAN,并从 Python 读取值。事实证明,TestStand 的 NAN 的值为 FFFF000000000001。根据 Kevin 的摘要图表,这是一个负安静的NAN。 TestStand 的 IND 确实具有不确定的预期值,FFF8000000000000

成功

所以,毕竟,我已经成功地从Python在TestStand中设置了一个NAN:

# Make a NAN suitable for TestStand
teststand_nan = struct.unpack(">d", "\xff\xff\x00\x00\x00\x00\x00\x01")[0]
# Set the variable's value in TestStand
locals_prop_object.SetValNumber(var_name, 0, teststand_nan)

CPython definition of nan

When Python reports a nan, where does that come from?

  • Result of a calculation (platform specific values?)
  • Py_NAN in the CPython C source code
    • defined as (Py_HUGE_VAL * 0.)
      • Value is platform-specific
      • Py_HUGE_VAL is probably defined as HUGE_VAL--it has a note to say it should be HUGE_VAL except on platforms where that is broken.
  • float('nan') which is defined from Py_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 particular win32com, which forms the Python↔COM translation layer. That code:

  • takes the input object
  • calls PyNumber_Float() to convert it to a Python float (if it isn't already)
  • calls PyFloat_AsDouble() to convert it to a plain C double value.
    • This simply returns the C double directly contained in the PyFloatObject member ob_fval.

So it looks as though I've traced a NaN from the COM interface back to a plain C double type containing Py_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:

quiet_nan = struct.unpack(">d", "\x7f\xf8\x00\x00\x00\x00\x00\x01")[0]
# Set the variable's value in TestStand
locals_prop_object.SetValNumber(var_name, 0, quiet_nan)

But that still appeared in TestStand as IND. So then I created a TestStand file with variables set to IND and NAN, and read the values from Python. It turns out that TestStand's NAN has a value of FFFF000000000001. According to Kevin's Summary Charts that is a negative quiet NAN. TestStand's IND does have the expected value for Indeterminate, FFF8000000000000.

Success

So, after all that, I have succeeded in setting a NAN in TestStand, from Python:

# Make a NAN suitable for TestStand
teststand_nan = struct.unpack(">d", "\xff\xff\x00\x00\x00\x00\x00\x01")[0]
# Set the variable's value in TestStand
locals_prop_object.SetValNumber(var_name, 0, teststand_nan)
风吹雪碎 2024-10-04 01:43:00

约翰·库克(John Cook)就此发表了一篇很好的文章,可能会有所帮助:

更新:这行不通?

In [144]: import scipy

In [145]: scipy.nan
Out[145]: 1.#QNAN

In [146]: scipy.inf
Out[146]: 1.#INF

In [147]: scipy.inf * 0
Out[147]: -1.#IND

John Cook had a nice post on this that might be helpful:

Update: won't this work?

In [144]: import scipy

In [145]: scipy.nan
Out[145]: 1.#QNAN

In [146]: scipy.inf
Out[146]: 1.#INF

In [147]: scipy.inf * 0
Out[147]: -1.#IND
原来分手还会想你 2024-10-04 01:43:00

据我所知,认为 NaN 的符号决定它是否安静的想法似乎有些混乱。相反,惯例是尾数的最高有效位决定了这一点。来自维基百科(添加了重点):

在符合 IEEE 754 标准的浮点存储格式中,NaN 通过 NaN 特有的特定预定义位模式来标识。 符号位并不重要。二进制格式 NaN 用填充有 1(如无穷大值)的指数字段和有效数字字段中的一些非零数字(以使其与无穷大值不同)表示。 1985 年的原始 IEEE 754 标准 (IEEE 754-1985) 仅描述了二进制浮点格式,并没有指定如何标记信令/安静状态。实际上,有效数字段的最高有效位决定 NaN 是信令状态还是静默状态……IEEE 754 标准 (IEEE 754-2008) 的 2008 年修订版对信令/静默状态的编码提出了正式建议。 对于二进制格式,有效数字段的最高有效位应该是“is_quiet”标志。即,如果 NaN 安静,则该位非零;如果 NaN 发信号,则该位为零。

由于大多数实现都符合 IEEE 754-2008,因此这是您应该遵循的约定。一般来说,您不能计划 NaN 的符号位保持一致,即使对于同一平台上的不同 NaN 也是如此。根据此约定,float('nan')scipy.nan 似乎都是安静的 NaN,至少在上面讨论的情况下是如此。

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):

In IEEE 754 standard-conforming floating-point storage formats, NaNs are identified by specific, pre-defined bit patterns unique to NaNs. The sign bit does not matter. Binary format NaNs are represented with the exponential field filled with ones (like infinity values), and some non-zero number in the significand field (to make them distinct from infinity values). The original IEEE 754 standard from 1985 (IEEE 754-1985) only described binary floating-point formats, and did not specify how the signaling/quiet state was to be tagged. In practice, the most significant bit of the significand field determined whether a NaN is signaling or quiet... The 2008 revision of the IEEE 754 standard (IEEE 754-2008) makes formal recommendations for the encoding of the signaling/quiet state. For binary formats, the most significant bit of the significand field should be an 'is_quiet' flag. I.e. this bit is non-zero if the NaN is quiet, and zero if the NaN is signaling.

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') and scipy.nan both seem to be quiet NaNs, at least in the cases discussed above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文