【问题标题】:How to distinguish different types of NaN float in PythonPython中如何区分不同类型的NaN浮点数
【发布时间】:2010-10-08 00:58:43
【问题描述】:

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

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

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

这意味着 Python 的 float('nan') 在通过 COM 传递时实际上是 Signaling NaN。然而,从我读到的关于 Signaling NaN 的内容来看,似乎 Signaling NaN 有点“异国情调”,而 Quiet NaN 是你的“常规”NaN。所以我怀疑 Python 是否会通过 COM 传递 Signaling NaN我如何知道 Python float('nan') 是否作为 Signaling NaNQuiet NaNIndeterminate 通过 COM ?

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

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

【问题讨论】:

  • 您究竟为什么要这样做?你可能把事情复杂化了。也许你可以使用 NoneType...
  • 我想通过 COM 使用 Python 在 TestStand 中将变量设置为 NAN(而不是 IND)。如果我们可以在整个系统中始终如一地使用NAN,那么最终用户的文档记录会更容易。

标签: python windows com interop nan


【解决方案1】:

我为您挖掘了一点,我认为您可以结合Kevin's Summary Charts 上的信息使用struct 模块。他们解释了用于各种 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') 在技术上实际上是 Indeterminate 值,而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 平台上是这样。

【讨论】:

  • 感谢您的回答 Stigma。我冒昧地对其进行了编辑以添加代码示例。非常感谢。
  • 我很高兴你从中得到了你需要的东西,感谢你添加代码示例供像我这样的其他人学习。 :)
  • 我不确定当您更改系统时float('nan') 是否总是其中一个,但您可以通过运行-float('nan') 获得另一个nan。此外,在 Python 3.5+ 中,查看十六进制 repr 的代码需要为 struct.pack(">d", float('nan')).hex()
【解决方案2】:

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中的Cdouble

所以看起来我已经从 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)

但这仍然以IND 的形式出现在TestStand 中。然后我创建了一个 TestStand 文件,变量设置为INDNAN,并从 Python 读取值。事实证明,TestStand 的NAN 的值为FFFF000000000001。根据Kevin's Summary Charts,这是一个否定安静的 NAN。 TestStand 的IND 确实具有Indeterminate 的预期值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)

【讨论】:

    【解决方案3】:

    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
    

    【讨论】:

    • 您可能打算链接here
    • 这是学习 Python 中的 NAN 和 INF 的有用参考。不幸的是,它并没有回答我的问题。
    • scipy.nan 听起来很有趣。请注意,在 Windows 上,它仅打印为 nan。因此,如果您收到1.#QNAN,我假设您使用的是 Linux。不幸的是,我今天病了,我有一台 Windows 笔记本电脑,但它没有 TestStand 来试试这个。
    • 我在 Windows Vista 上使用 python 2.5,scipy 0.8。不确定它是否有区别,但它是 64 位的。
    【解决方案4】:

    据我所知,认为NaN 的符号决定它是否安静似乎有些混乱。相反,惯例是尾数的最高有效位决定了这一点。来自Wikipedia(强调):

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

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

    【讨论】:

    • 似乎 NI TestStand 对不同类型的 NaN 有非常规的解释。至少,当我问这个问题时,它确实如此。过去 7 年我没有使用过 TestStand。
    猜你喜欢
    • 2012-03-09
    • 1970-01-01
    • 2018-08-04
    • 1970-01-01
    • 2013-05-05
    • 2022-01-20
    • 1970-01-01
    • 2021-10-30
    • 2015-01-05
    相关资源
    最近更新 更多