我最近读了很多关于IEEE 754和x87架构的内容.我正在考虑在我正在研究的一些数值计算代码中使用NaN作为"缺失值",我希望使用信令 NaN将允许我在我不想要的情况下捕获浮点异常继续"缺失值".相反,我会使用安静的 NaN来允许"缺失值"通过计算传播.但是,信号NaN不起作用,因为我认为它们将基于它们上存在的(非常有限的)文档.
以下是我所知道的摘要(所有这些都使用x87和VC++):
标准库提供了一种访问NaN值的方法:
std::numeric_limits<double>::signaling_NaN();
和
std::numeric_limits<double>::quiet_NaN();
问题是我认为信号NaN没有任何用处.如果屏蔽了_EM_INVALID,则其行为与安静NaN完全相同.由于没有NaN与任何其他NaN相当,因此没有逻辑差异.
如果未屏蔽_EM_INVALID (启用异常),则甚至无法使用信号NaN初始化变量:
 double dVal = std::numeric_limits<double>::signaling_NaN();因为这会引发异常(信号NaN值被加载到x87寄存器以将其存储到存储器地址).
您可以像我一样思考以下内容:
但是,步骤2会导致信令NaN转换为安静的NaN,因此后续使用它不会导致异常被抛出!那么WTF?!
信号NaN是否有任何实用性或目的?我理解其中一个原始意图是使用它初始化内存,以便可以捕获使用单位化浮点值.
有人能告诉我,如果我在这里遗失了什么吗?
编辑:
为了进一步说明我希望做的事情,这里有一个例子:
考虑对数据向量(双精度)执行数学运算.对于某些操作,我想允许向量包含"缺失值"(假设这对应于电子表格列,例如,其中一些单元格没有值,但它们的存在很重要).对于某些操作,我不希望允许向量包含"缺失值".如果集合中存在"缺失值",也许我想采取不同的行动 - 可能执行不同的操作(因此这不是无效的状态).
这个原始代码看起来像这样:
const double MISSING_VALUE = 1.3579246e123;
using std::vector;
vector<double> missingAllowed(1000000, MISSING_VALUE);
vector<double> missingNotAllowed(1000000, MISSING_VALUE);
// ... populate missingAllowed and missingNotAllowed with (user) data...
for (vector<double>::iterator it = missingAllowed.begin(); it != missingAllowed.end(); ++it) …我需要将一些额外的信息打包到浮点NaN值中.我在Python中使用单精度IEEE 754浮点数(32位浮点数).Python和NumPy如何处理这些值?
理论
如果指数位(23..30)被设置,并且至少有一个有效位被设置,则IEEE 754-2008标准似乎认为数字实际上不是数字.因此,如果我们将float转换为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') …