为什么 `gcc -ffast-math` 禁用 `isnan()` 和 `isinf()` 的正确结果?
Why does `gcc -ffast-math` disable the correct result of `isnan()` and `isinf()`?
我知道使用 -ffast-math
标志允许不安全的数学运算并禁用信号 NaN。但是,我希望函数 isnan()
和 isinf()
仍然能够 return 正确的结果,但它们没有。
这是一个例子:
文件test_isnan.c
:
#include <stdio.h>
#include <math.h>
int main(void){
/* Produce a NaN */
const float my_nan = sqrtf(-1.f);
/* Produce an inf */
const float my_inf = 1.f/0.f;
printf("This should be a NaN: %.6e\n", my_nan);
printf("This should be inf: %.6e\n", my_inf);
if (isnan(my_nan)) {
printf("Caugth the nan!\n");
} else {
printf("isnan failed?\n");
}
if (isinf(my_inf)) {
printf("Caugth the inf!\n");
} else {
printf("isinf failed?\n");
}
}
现在让我们编译 运行 没有 -ffast-math
的程序:
$ gcc test_isnan.c -lm -o test_isnan.o && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
Caugth the nan!
Caugth the inf!
但有了它:
$ gcc test_isnan.c -lm -o test_isnan.o -ffast-math && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
isnan failed?
isinf failed?
那么为什么 isnan()
和 isinf()
不捕捉这些 nan
和 inf
呢?我错过了什么?
如果它可能相关,这是我的 gcc
版本:
gcc (Spack GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-ffast-math
Sets the options ... -ffinite-math-only ...
-ffinite-math-only
Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.
编译器将代码优化为:
printf("This should be a NaN: %.6e\n", sqrtf(-1.f));
printf("This should be inf: %.6e\n", 1.f/0.f);
printf("isnan failed?\n");
printf("isinf failed?\n");
因为编译器知道表达式不能 return nan
或 inf
.
来自https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html:
-ffast-math
Sets the options -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast.
其中:
-ffinite-math-only
Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.
一旦你打破了这个假设,你就不能指望这些功能会起作用。
我知道您希望此设置优化所有其他操作,同时仍为这两个函数提供正确的结果,但这不是它的工作方式。我认为没有办法解决这个问题。也许你可以看看 Clang,但我不希望它有所不同。
我知道使用 -ffast-math
标志允许不安全的数学运算并禁用信号 NaN。但是,我希望函数 isnan()
和 isinf()
仍然能够 return 正确的结果,但它们没有。
这是一个例子:
文件test_isnan.c
:
#include <stdio.h>
#include <math.h>
int main(void){
/* Produce a NaN */
const float my_nan = sqrtf(-1.f);
/* Produce an inf */
const float my_inf = 1.f/0.f;
printf("This should be a NaN: %.6e\n", my_nan);
printf("This should be inf: %.6e\n", my_inf);
if (isnan(my_nan)) {
printf("Caugth the nan!\n");
} else {
printf("isnan failed?\n");
}
if (isinf(my_inf)) {
printf("Caugth the inf!\n");
} else {
printf("isinf failed?\n");
}
}
现在让我们编译 运行 没有 -ffast-math
的程序:
$ gcc test_isnan.c -lm -o test_isnan.o && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
Caugth the nan!
Caugth the inf!
但有了它:
$ gcc test_isnan.c -lm -o test_isnan.o -ffast-math && ./test_isnan.o
This should be a NaN: -nan
This should be inf: inf
isnan failed?
isinf failed?
那么为什么 isnan()
和 isinf()
不捕捉这些 nan
和 inf
呢?我错过了什么?
如果它可能相关,这是我的 gcc
版本:
gcc (Spack GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-ffast-math
Sets the options ... -ffinite-math-only ...
-ffinite-math-only
Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.
编译器将代码优化为:
printf("This should be a NaN: %.6e\n", sqrtf(-1.f));
printf("This should be inf: %.6e\n", 1.f/0.f);
printf("isnan failed?\n");
printf("isinf failed?\n");
因为编译器知道表达式不能 return nan
或 inf
.
来自https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html:
-ffast-math
Sets the options -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans, -fcx-limited-range and -fexcess-precision=fast.
其中:
-ffinite-math-only
Allow optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs.
一旦你打破了这个假设,你就不能指望这些功能会起作用。
我知道您希望此设置优化所有其他操作,同时仍为这两个函数提供正确的结果,但这不是它的工作方式。我认为没有办法解决这个问题。也许你可以看看 Clang,但我不希望它有所不同。