信号的有用性NaN? [英] Usefulness of signaling NaN?

查看:198
本文介绍了信号的有用性NaN?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近在IEEE 754和x87架构上阅读了很多。我正在考虑使用NaN作为一个缺失值在一些数字计算代码我正在努力,我希望使用信号 NaN将允许我捕获浮点异常在那里我不想继续缺失值。相反,我将使用 quiet NaN来允许缺失值通过计算传播。然而,信号NaNs不工作,因为我认为他们将基于(非常有限的)文件存在他们。

I've recently read up quite a bit on IEEE 754 and the x87 architecture. I was thinking of using NaN as a "missing value" in some numeric calculation code I'm working on, and I was hoping that using signaling NaN would allow me to catch a floating point exception in the cases where I don't want to proceed with "missing values." Conversely, I would use quiet NaN to allow the "missing value" to propagate through a computation. However, signaling NaNs don't work as I thought they would based on the (very limited) documentation that exists on them.

这里是我所知道的所有这些使用x87和VC ++):

Here is a summary of what I know (all of this using x87 and VC++):


  • _EM_INVALID(IEEE无效异常)控制x87遇到NaNs

  • 如果_EM_INVALID被屏蔽(异常被禁用),则不会生成异常,并且操作可以返回quiet NaN。

  • 如果_EM_INVALID未被屏蔽(启用了异常),则一个包含信号NaN的操作将导致抛出异常,无效操作(例如,sqrt(-1))会导致无效的异常。

  • x87 从不生成信号NaN。

  • 如果_EM_INVALID未屏蔽,任何使用信号NaN(即使使用它初始化变量)会导致无效的异常被抛出。

  • _EM_INVALID (the IEEE "invalid" exception) controls the behavior of the x87 when encountering NaNs
  • If _EM_INVALID is masked (the exception is disabled), no exception is generated and operations can return quiet NaN. An operation involving signaling NaN will not cause an exception to be thrown, but will be converted to quiet NaN.
  • If _EM_INVALID is unmasked (exception enabled), an invalid operation (e.g., sqrt(-1)) causes an invalid exception to be thrown.
  • The x87 never generates signaling NaN.
  • If _EM_INVALID is unmasked, any use of a signaling NaN (even initializing a variable with it) causes an invalid exception to be thrown.

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

The Standard Library provides a way to access the NaN values:

std::numeric_limits<double>::signaling_NaN();

std::numeric_limits<double>::quiet_NaN();

问题是我看不到任何信号NaN的使用。如果掩码了_EM_INVALID,它的行为与quiet NaN完全相同。由于没有NaN可与任何其他NaN比较,因此没有逻辑上的区别。

The problem is that I see no use whatsoever for the signaling NaN. If _EM_INVALID is masked it behaves exactly the same as quiet NaN. Since no NaN is comparable to any other NaN, there is no logical difference.

如果_EM_INVALID不是甚至不能用信令NaN:
double dVal = std :: numeric_limits< double> :: signaling_NaN(); 来初始化变量,因为这会抛出异常

If _EM_INVALID is not masked (exception is enabled), then one cannot even initialize a variable with a signaling NaN: double dVal = std::numeric_limits<double>::signaling_NaN(); because this throws an exception (the signaling NaN value is loaded into an x87 register to store it to the memory address).

您可以这样认为:


  1. 掩码_EM_INVALID。

  2. 使用信号NaN初始化变量。

  3. Unmask_EM_INVALID。 / li>
  1. Mask _EM_INVALID.
  2. Initialize the variable with signaling NaN.
  3. Unmask_EM_INVALID.

然而,步骤2使得信令NaN转换为安静的NaN,因此其后续的使用将<强>引起异常抛出!所以WTF?!

However, step 2 causes the signaling NaN to be converted to a quiet NaN, so subsequent uses of it will not cause exceptions to be thrown! So WTF?!

有什么实用程序或目的信号NaN?我理解原始意图之一是用它初始化内存,以便使用单位化的浮点值可以被捕获。

Is there any utility or purpose whatsoever to a signaling NaN? I understand one of the original intents was to initialize memory with it so that use of an unitialized floating point value could be caught.

有人可以告诉我,如果我缺少的东西这里?

Can someone tell me if I am missing something here?

编辑

为了进一步说明我希望做什么,下面是一个例子:

To further illustrate what I had hoped to do, here is an example:

考虑对数据向量(双精度)执行数学运算。对于某些操作,我想允许向量包含缺失值(假设这对应于电子表格列,例如,其中一些单元格没有值,但它们的存在是显着的)。对于某些操作,我不要允许向量包含缺失值。也许我想采取不同的行动方案,如果一个缺失值存在于集合 - 可能执行不同的操作(因此这不是无效的状态)。

Consider performing mathematical operations on a vector of data (doubles). For some operations, I want to allow the vector to contain a "missing value" (pretend this corresponds to a spreadsheet column, for example, in which some of the cells do not have a value, but their existence is significant). For some operations, I do not want to allow the vector to contain a "missing value." Perhaps I want to take a different course of action if a "missing value" is present in the set -- perhaps performing a different operation (thus this is not an invalid state to be in).

这个原始代码看起来像这样:

This original code would look something like this:

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) {
    if (*it != MISSING_VALUE) *it = sqrt(*it); // sqrt() could be any operation
}

for (vector<double>::iterator it = missingNotAllowed.begin(); it != missingNotAllowed.end(); ++it) {
    if (*it != MISSING_VALUE) *it = sqrt(*it);
    else *it = 0;
}

请注意,必须执行缺失值的检查每个循环迭代。虽然我在大多数情况下理解, sqrt 函数(或任何其他数学运算)可能会掩盖这种检查,有些情况下,操作是最小的(也许只是一个加法)并且支票是昂​​贵的。更不用说,缺失值使得一个合法的输入值失效,并且如果计算合法地到达该值(可能不太可能),则可能导致错误。同样在技术上正确,应当针对该值检查用户输入数据,并且应该采取适当的行动方案。我发现这个解决方案不够优秀,性能不够理想。这是性能关键的代码,我们绝对没有奢侈的并行数据结构或某种类型的数据元素对象。

Note that the check for the "missing value" must be performed every loop iteration. While I understand in most cases, the sqrt function (or any other mathematical operation) will likely overshadow this check, there are cases where the operation is minimal (perhaps just an addition) and the check is costly. Not to mention the fact that the "missing value" takes a legal input value out of play and could cause bugs if a calculation legitimately arrives at that value (unlikely though it may be). Also to be technically correct, the user input data should be checked against that value and an appropriate course of action should be taken. I find this solution inelegant and less-than-optimal performance-wise. This is performance-critical code, and we definitely do not have the luxury of parallel data structures or data element objects of some sort.

NaN版本将如下所示:

The NaN version would look like this:

using std::vector;

vector<double> missingAllowed(1000000, std::numeric_limits<double>::quiet_NaN());
vector<double> missingNotAllowed(1000000, std::numeric_limits<double>::signaling_NaN());

// ... populate missingAllowed and missingNotAllowed with (user) data...

for (vector<double>::iterator it = missingAllowed.begin(); it != missingAllowed.end(); ++it) {
    *it = sqrt(*it); // if *it == QNaN then sqrt(*it) == QNaN
}

for (vector<double>::iterator it = missingNotAllowed.begin(); it != missingNotAllowed.end(); ++it) {
    try {
        *it = sqrt(*it);
    } catch (FPInvalidException&) { // assuming _seh_translator set up
        *it = 0;
    }
}

现在明确的检查被取消, 。我想这一切都可以工作,如果我可以初始化向量而不触摸FPU寄存器...

Now the explicit check is eliminated and performance should be improved. I think this would all work if I could initialize the vector without touching the FPU registers...

此外,我想象任何自尊重的 sqrt 执行检查NaN并立即返回NaN。

Furthermore, I would imagine any self-respecting sqrt implementation checks for NaN and returns NaN immediately.

推荐答案

信号NaN是初始化数据结构,但是当然C中的运行时初始化运行将NaN加载到浮点寄存器作为初始化的一部分的风险,从而触发信号,因为编译器我知道这个浮点值需要使用整数寄存器复制。

As I understand it, the purpose of signaling NaN is to initialize data structures, but, of course runtime initialization in C runs the risk of having the NaN loaded into a float register as part of initialization, thereby triggering the signal because the the compiler isn't aware that this float value needs to be copied using an integer register.

我希望你可以初始化一个 static 值与信号NaN,但即使这将需要一些特殊的处理由编译器,以避免它转换为一个安静的NaN。你也许可以使用一点魔法,以避免在初始化期间将它当作一个浮点值。

I would hope that you could could initialize a static value with a signaling NaN, but even that would require some special handling by the compiler to avoid having it converted to a quiet NaN. You could perhaps use a bit of casting magic to avoid having it treated as a float value during initialization.

如果你是在ASM写作,这不会是一个问题。但在C,特别是在C ++,我认为你必须颠覆类型系统,以初始化一个变量与NaN。我建议使用 memcpy

If you were writing in ASM, this would not be an issue. but in C and especially in C++, I think you will have to subvert the type system in order to initialize a variable with NaN. I suggest using memcpy.

这篇关于信号的有用性NaN?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆