相关疑难解决方法(0)

信号NaN的有用性?

我最近读了很多关于IEEE 754和x87架构的内容.我正在考虑在我正在研究的一些数值计算代码中使用NaN作为"缺失值",我希望使用信令 NaN将允许我在我不想要的情况下捕获浮点异常继续"缺失值".相反,我会使用安静的 NaN来允许"缺失值"通过计算传播.但是,信号NaN不起作用,因为我认为它们将基于它们上存在的(非常有限的)文档.

以下是我所知道的摘要(所有这些都使用x87和VC++):

  • _EM_INVALID(IEEE"无效"异常)在遇到NaN时控制x87的行为
  • 如果屏蔽了_EM_INVALID(禁用了异常),则不会生成异常,操作可以返回安静的NaN.涉及信令NaN的操作不会引发异常,但会转换为安静的NaN.
  • 如果_EM_INVALID未被屏蔽(启用了异常),则无效操作(例如,sqrt(-1))会导致抛出无效异常.
  • x87 从不生成信令NaN.
  • 如果_EM_INVALID是未屏蔽的,任何使用的信令的NaN(即使初始化与它的变量)的导致一个无效引发异常.

标准库提供了一种访问NaN值的方法:

std::numeric_limits<double>::signaling_NaN();
Run Code Online (Sandbox Code Playgroud)

std::numeric_limits<double>::quiet_NaN();
Run Code Online (Sandbox Code Playgroud)

问题是我认为信号NaN没有任何用处.如果屏蔽了_EM_INVALID,则其行为与安静NaN完全相同.由于没有NaN与任何其他NaN相当,因此没有逻辑差异.

如果屏蔽_EM_INVALID (启用异常),则甚至无法使用信号NaN初始化变量: double dVal = std::numeric_limits<double>::signaling_NaN();因为这会引发异常(信号NaN值被加载到x87寄存器以将其存储到存储器地址).

您可以像我一样思考以下内容:

  1. 掩码_EM_INVALID.
  2. 使用信令NaN初始化变量.
  3. Unmask_EM_INVALID.

但是,步骤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) …
Run Code Online (Sandbox Code Playgroud)

c++ floating-point ieee-754 visual-c++ x87

50
推荐指数
1
解决办法
1万
查看次数

自定义NaN的行为在Python和Numpy中浮动

我需要将一些额外的信息打包到浮点NaN值中.我在Python中使用单精度IEEE 754浮点数(32位浮点数).Python和NumPy如何处理这些值?

理论

如果指数位(23..30)被设置,并且至少有一个有效位被设置,则IEEE 754-2008标准似乎认为数字实际上不是数字.因此,如果我们将float转换为32位整数表示,则满足以下条件的任何内容都会变为:

  • i & 0x7f800000 == 0x7f800000
  • i & 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])
Run Code Online (Sandbox Code Playgroud)

这给出了:

7fc00000
7fc00001 <<< should be 7f800001
7fc00001
Run Code Online (Sandbox Code Playgroud)

这个和一些进一步的测试似乎暗示某些东西(struct.unpack?)总是设置is_quiet位.

NumPy的

我尝试使用NumPy,因为我总是可以依赖转换而不是改变一个位:

import numpy as np

intarr = np.array([0x7f800001], dtype='uint32')
f = np.fromstring(intarr.tostring(), dtype='f4') …
Run Code Online (Sandbox Code Playgroud)

python numpy python-2.7

11
推荐指数
1
解决办法
1369
查看次数

标签 统计

c++ ×1

floating-point ×1

ieee-754 ×1

numpy ×1

python ×1

python-2.7 ×1

visual-c++ ×1

x87 ×1