【发布时间】:2021-03-24 12:42:16
【问题描述】:
代码 (t125.c):
#include <fenv.h>
#include <stdint.h>
#include <stdio.h>
#if _MSC_VER
#pragma fenv_access (on)
#else
#pragma STDC FENV_ACCESS ON
#endif
void show_fe_exceptions(void)
{
printf("exceptions raised: ");
if (fetestexcept(FE_DIVBYZERO)) printf(" FE_DIVBYZERO");
if (fetestexcept(FE_INEXACT)) printf(" FE_INEXACT");
if (fetestexcept(FE_INVALID)) printf(" FE_INVALID");
if (fetestexcept(FE_OVERFLOW)) printf(" FE_OVERFLOW");
if (fetestexcept(FE_UNDERFLOW)) printf(" FE_UNDERFLOW");
if (fetestexcept(FE_ALL_EXCEPT)==0) printf(" none");
printf("\n");
}
typedef union { uint32_t u; float f; } ufloat;
int main(void)
{
_Bool b;
ufloat uqnan;
volatile float f;
uqnan.u = 0x7fc00000;
f = uqnan.f;
b = f == f;
show_fe_exceptions();
return b ? 1 : 0;
}
调用:
$ gcc t125.c -Wall -Wextra -pedantic -std=c17 && ./a.exe
t125.c:7: warning: ignoring ‘#pragma STDC FENV_ACCESS’ [-Wunknown-pragmas]
7 | #pragma STDC FENV_ACCESS ON
|
exceptions raised: none
$ clang t125.c -Wall -Wextra -pedantic -std=c17 && ./a.exe
t125.c:7:14: warning: pragma STDC FENV_ACCESS ON is not supported, ignoring pragma [-Wunknown-pragmas]
#pragma STDC FENV_ACCESS ON
^
1 warning generated.
exceptions raised: none
$ cl t125.c /fp:strict /std:c17 && t125
exceptions raised: none
问题:为什么QNAN == QNAN 不会引发FE_INVALID 异常?
UPD。问题原因:(错误,见下文)假设<any_NAN> == <any_NAN> 导致引发FE_INVALID 异常。
UPD2。更改代码:从 f = *(float*)&qnan 到 f = uqnan.f(通过联合输入双关语)。这是为了避免违反 C 标准的别名规则。
【问题讨论】:
-
你能说说为什么你认为这个操作应该导致设置了无效标志吗?诚然,相关标准在这里并非完全明确:假设定义了
__STDC_IEC_559__,C 标准的附件 F 只是说“关系和相等运算符提供 IEC 60559 比较”,而 IEC 60559 描述“compareQuietEqual”和“compareSignalingEqual”。然而,IEC 60559 确实也说:“语言标准应该将它们的符号 = 和 ≠ 映射到 Quiet 谓词 [...]”。 -
因为 QNaN 中的 Q 代表 Quiet。
-
不要写
*(float*)&,因为它违反了C标准中的别名规则。使用float f; memcpy(&f, &qnan, sizeof f);或float f = (union { unsigned u; float f; }) {0x7fc00000} .f;。 -
f <= f代替f == f的代码是什么? -
@MarkRansom:它是在 C 中定义的,但不是在 C++ 中。
标签: c floating-point ieee-754 floating-point-exceptions c17