【发布时间】:2021-04-18 23:05:02
【问题描述】:
我有两个双打 x 和 y 与 y 已知是一个特定的 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 3latencyvmovq指令来获取结果,而不是需要 2 来将双打移动到 GPR。不得不恢复到内联汇编以获得我认为理想的代码,但here 是我认为更快的两个版本。不知道如何让编译器发出这个 w.o 使你的代码特定于 x86_64。
标签: c floating-point ieee-754 memcmp