【发布时间】:2014-07-06 22:46:35
【问题描述】:
我需要将一些额外信息打包到浮点 NaN 值中。我在 Python 中使用单精度 IEEE 754 浮点数(32 位浮点数)。 Python 和 NumPy 如何处理这些值?
理论
IEEE 754-2008 标准似乎认为数字实际上不是数字,如果设置了指数位 (23..30),并且至少设置了一个有效位。因此,如果我们将浮点数转换为 32 位整数表示,则任何满足以下条件的都可以:
i & 0x7f800000 == 0x7f800000i & 0x007fffff != 0
这会让我有很多选择。但是,标准似乎说有效数字的最高位是is_quiet,应该设置以避免计算中的异常。
实际测试
Python 2.7
为了确定,我进行了一些测试,结果很有趣:
import math
import struct
std_nan = struct.unpack("f4", struct.pack("I", 0x7fc00000))[0]
spec_nan = struct.unpack("f4", struct.pack("I", 0x7f800001))[0]
spec2_nan = struct.unpack("f4", struct.pack("I", 0x7fc00001))[0]
print "{:08x}".format(struct.unpack("I", struct.pack("f4", std_nan))[0])
print "{:08x}".format(struct.unpack("I", struct.pack("f4", spec_nan))[0])
print "{:08x}".format(struct.unpack("I", struct.pack("f4", spec2_nan))[0])
这给出了:
7fc00000
7fc00001 <<< should be 7f800001
7fc00001
这个和一些进一步的测试似乎表明某些东西 (struct.unpack?) 总是设置 is_quiet 位。
NumPy
我对 NumPy 进行了同样的尝试,因为我总是可以依靠转换而不改变一个位:
import numpy as np
intarr = np.array([0x7f800001], dtype='uint32')
f = np.fromstring(intarr.tostring(), dtype='f4')
print np.isnan(f)
这给出了:
RuntimeWarning: invalid value encountered in isnan
[True]
但如果将值替换为0x7fc00001,则没有错误。
假设
如果我设置 is_quiet 并将其余位用于我自己的目的,Python 和 NumPy 都会很高兴。 Python 自行处理,NumPy 依赖于低级语言实现和/或硬件 FP 实现。
问题
我的假设是否正确,是否可以通过一些官方文档来证明或反驳?或者它是那些依赖于平台的东西之一?
我在这里找到了一些非常相关的东西:How to distinguish different types of NaN float in Python,但我找不到任何关于如何在 Python 或 NumPy 中处理携带额外信息的 NaN 的官方消息。
【问题讨论】:
-
我的第一反应 - 如果您的设计要求您使用自己的实现特定信息破解现有的价值/约定,同时保持向后兼容性,我会称之为“糟糕的设计”并恳请您回到画板并重新设计。必须有更好的方法来做到这一点。如果有这样做的标准方法,它将被记录在案。
-
这可能有助于查看
struct.unpack:_PyFloat_Unpack4source 的行为。 -
@TonySuffolk66:我在很大程度上同意你的看法。然而,IEEE 754-2008 第 6.2.1 条:“在编码时,所有 NaN 都有一个符号位和一个位模式,这些位模式需要将编码识别为 NaN 并确定其类型(sNaN 与 qNaN)。其余位,在尾随有效数字字段中,对有效载荷进行编码,这可能是诊断信息(见上文)。”所以,我在我所做的事情中找不到任何不标准的东西。 (加上存档文件格式在某些情况下可能会很奇怪。这不会成为公共 API 的一部分。)
-
@PietroSaccardi:感谢您提醒我查看源代码!我在那里找到的东西——尤其是我在那里没有找到的东西——解决了这个谜题!我会发布一个答案来说明我认为真正发生的事情。
-
@DrV 乐于助人。非常有趣的答案!
标签: python python-2.7 numpy