【问题标题】:Why does `gcc -ffast-math` disable the correct result of `isnan()` and `isinf()`?为什么`gcc -ffast-math`会禁用`isnan()`和`isinf()`的正确结果?
【发布时间】:2021-11-26 11:51:18
【问题描述】:

我了解使用 -ffast-math 标志允许不安全的数学运算并禁用信号 NaN。但是,我希望函数 isnan()isinf() 仍然能够返回正确的结果,但它们没有。

这是一个例子:

文件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() 捕获这些nans 和infs?我错过了什么?

如果它可能相关,这是我的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.

【问题讨论】:

    标签: c gcc isnan


    【解决方案1】:

    来自https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

    -ffast-数学
    设置选项 -fno-math-errno、-funsafe-math-optimizations、-ffinite-math-only、-fno-rounding-math、-fno-signaling-nans、-fcx-limited-范围和 -fexcess-precision=fast。

    地点:

    -仅有限数学
    允许对假设参数和结果不是 NaN 或 +-Infs的浮点算术进行优化。

    一旦你打破这个假设,你就不能指望这些功能会起作用。

    我了解您希望此设置能够优化所有其他操作,同时仍然为这两个函数提供正确的结果,但这不是它的工作方式。我不认为有办法解决这个问题。也许你可以看看 Clang,但我不认为它会有所不同。

    【讨论】:

    • “允许优化浮点运算”:我不知道isnanisinf 会是算术...?
    • 他们为什么不呢?诚然,他们不计算一个值,如果这就是你的意思,但他们仍然工作一个。
    【解决方案2】:

    -ffast-math

    设置选项 ... -ffinite-math-only ...

    -仅有限数学

    允许优化浮点运算,假设参数和结果不是 NaNs 或 +-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");
    

    因为编译器知道表达式不能返回naninf

    【讨论】:

    • 与其他答案相同的评论:为什么 isnanisinf 被视为算术......?
    • 我不明白。不是isnan 是算术,sqrtf 是。编译器假定sqrtf不能返回nan,所以它优化了isnan
    • 问题是即使阅读例如一个来自外界的nan:double* ptr = (double*)mmap(...); if(!isnan(*ptr)) { /* proceed with business logic which expects no NaNs*/ }也不起作用。
    猜你喜欢
    • 2011-11-07
    • 2019-09-22
    • 2011-11-17
    • 2016-03-25
    • 1970-01-01
    • 2014-05-20
    • 2013-12-10
    • 2018-08-03
    • 2016-03-07
    相关资源
    最近更新 更多