如何在Python中区分不同类型的NaN float

时间:2010-10-08 00:58:43

标签: python windows com interop nan

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

显然,TestStand区分浮点“IND”和“NAN”值。根据{{​​3}}:

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

这意味着Python的float('nan')在通过COM时实际上是信令NaN 。但是,从我读到的关于信令NaN 的内容来看,似乎信令NaN 有点“异国情调”而 Quiet NaN 就是你的“定期“NaN。所以我怀疑Python会通过COM传递一个 Signaling NaN 如何判断Python float('nan')是否作为信令NaN 安静的NaN 传递给COM,或者 Indeterminate

在与其他语言连接时,有没有办法在Python中制作信令NaN QuietNaN Indeterminate ? (也许使用ctypes?)我认为这将是一个特定于平台的解决方案,在这种情况下我会接受。

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

4 个答案:

答案 0 :(得分:7)

我为你挖了一下,我想你可以将struct模块与Kevin's Summary Charts上的信息结合使用。它们解释了用于各种IEEE 754浮点数的确切位模式。

如果我阅读关于此IND - eterminate值的主题,那么您可能必须要小心的是,当直接在C代码中分配时,该值往往会触发某种浮点中断,使它变成普通的NaN。这反过来意味着那些人被建议在ASM而不是C中做这种事情,因为C抽象了那些东西。因为它不是我的领域,而且我不确定这种价值会在多大程度上混乱Python,我想我会提到它,所以你至少可以留意任何这种奇怪的行为。 (参见this question的接受答案)。

>>> import struct

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

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

参考Kevin's Summary Charts,表明float('nan')实际上在技术上是不确定的值,而scipy.nan是一个安静的NaN。

让我们尝试制作一个信令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'

不,信令NaN转换为安静的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()制作适当的静音NaN - 至少在Windows平台上。

答案 1 :(得分:3)

CPython对nan的定义

当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值。
    • 这只会返回double成员PyFloatObject中直接包含的C ob_fval

所以看起来我已经从COM接口追溯到NaN回到包含double的普通C Py_NAN类型,无论结果是什么原因都在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)

但是,它仍然作为IND出现在TestStand中。然后我创建了一个TestStand文件,其变量设置为INDNAN,并从Python中读取值。事实证明,TestStand的NAN的值为FFFF000000000001。根据{{​​3}},否定安静NAN。 TestStand的IND确实具有 Indeterminate FFF8000000000000的预期值。

<强>成功

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

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

答案 2 :(得分:2)

约翰库克有一个很好的帖子,可能会有所帮助:

更新:这不会有效吗?

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

答案 3 :(得分:0)

据我所知,似乎似乎有些困惑,认为fetch的符号决定了它是否安静。相反,惯例是尾数的最高有效位决定了这一点。来自Wikipedia(添加了重点):

  

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

由于大多数实现都符合IEEE 754-2008,因此这是您应遵循的约定。通常,您不能计划符号位与NaN保持一致,即使同一平台上的不同NaN也是如此。根据此约定,NaNfloat('nan')似乎都是安静的NaN,至少在上述情况下如此。