【问题标题】:Compare two doubles to see if they are the same NaN比较两个双打,看看它们是否相同 NaN
【发布时间】:2021-04-18 23:05:02
【问题描述】:

我有两个双打 xyy 已知是一个特定的 NaN 值,我想看看它们是否按位相同。也就是说,我想确定x 是否与y 完全相同的NaN 值。

NaN 无法与 == 运算符进行有用的比较,因为 NaN 永远不会等于任何其他值(甚至它们本身也不等于!)。

有没有比以下“按位相等”方法更好的方法(这种方法合法吗?):

bool bitwise_equal(double x, double y) {
    unsigned char xbytes[sizeof(x)];
    unsigned char ybytes[sizeof(y)];
    memcpy(xbytes, &x, sizeof(x));
    memcpy(ybytes, &y, sizeof(y));
    return memcmp(xbytes, ybytes, sizeof(x)) == 0;
}

【问题讨论】:

  • 您不需要先复制字节,只需使用return 0 == memcmp(&x, &y, sizeof x);
  • 在 C 中,很多东西都不是“合法的”与“非法的”;它们由 C 标准定义或未定义(有时介于两者之间,如实现定义或定义为一组可能性之一或满足某些属性)。 memcmp(&x, &y, sizeof x); 被定义为比较字节。如果double 是无填充的 IEEE-754 二进制类型,则当且仅当它们是相同的数字(将 -0 和 +0 视为不同)或相同的 NaN 时,它将返回 true。 (如果是十进制类型,同一个数可以有多种表示。)
  • 请注意,NaN 应该通过各种操作传播。在符合 IEEE-754 的实现中,如果 c = a + b 的一个操作数恰好是 NaN,则 c 应该是该 NaN。如果两个操作数都是 NaN,c 应该是其中之一。因此,您可以预期 NaN 的计算链结果将是输入 NaN 之一或由异常条件生成的 NaN。但是,否定可能会改变 NaN 的符号。因此,它在有效负载(有效位)中将相同,但按位不完全相同。如果要处理这种情况,则需要从比较中排除符号位。
  • @jdweng:如果“转换为 uint”是指 * (uint32_t *) &x,那么 C 标准没有定义其行为。除非 OP 想要接受已转换为与原始 NaN 相同的安静 NaN 的信令 NaN,否则有两种类型的 NaN(信令和安静)是无关紧要的。该问题询问的是“双精度”,而不是“单点浮点数”,double 最常见的是八个字节,而不是四个。
  • 如果你只在 x86_64 之后我认为 vpcmpeq 可能有用,因为你只需要 1 3latency vmovq 指令来获取结果,而不是需要 2 来将双打移动到 GPR。不得不恢复到内联汇编以获得我认为理想的代码,但here 是我认为更快的两个版本。不知道如何让编译器发出这个 w.o 使你的代码特定于 x86_64。

标签: c floating-point ieee-754 memcmp


【解决方案1】:

比较两个双精度,看看它们是否是相同的 NaN

如果它们按位相同

我想确定 x 是否与 y 完全相同的 NaN 值。

直接将位模式与memcmp() 进行比较是一种合理的方法。

C 没有详细说明 NaN 有效载荷的相同性。注意:一个实现可以用多个位模式定义“相同”。请参阅sign 考虑。

#include <math.h>
#include <stdbool.h>
#include <string.h>

bool NaN_bitwise_equal(double x, double y) {
    return isnan(x) && isnan(y) && memcmp(&x, &y, sizeof x) == 0;
}

“相同的 NaN 值”有些矛盾,因为这些值在数值上不具有可比性,但 NaN 有效负载可能是。

【讨论】:

  • 按值传递 NaN 可能会改变其表示。通过指针获取参数对于 OP 可能更可行
猜你喜欢
  • 2017-05-02
  • 1970-01-01
  • 2013-09-08
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多