【问题标题】:Why does fetestexcept() sometimes complain when multiplying floats?为什么 fetestexcept() 在乘以浮点数时有时会抱怨?
【发布时间】:2012-10-10 11:37:11
【问题描述】:

我在 C99 中使用 fetestexcept(),它有时会抱怨浮点数相乘会得到不精确的结果 (FE_INEXACT)。将浮点变量与浮点文字相乘时似乎会发生这种情况。我怎样才能修改这个以便 fetestexcept() 不会抱怨?

gcc -std=c99 -lm test.c

#include <stdio.h>
#include <math.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON

int main(void)
{
    float a = 1.1f;
    float b = 1.2f;
    float c = a * b * 1.3f;

    int exception = fetestexcept(FE_ALL_EXCEPT);
    if(exception != 0)
    {
        printf("Exception: 0x%x\n", exception); // 0x20 FE_INEXACT
    }

    return 0;
}

【问题讨论】:

    标签: c linux posix


    【解决方案1】:

    好吧,如果您对该异常不感兴趣,就不要测试 FE_INEXACT?例如。而不是

    
    int exception = fetestexcept(FE_ALL_EXCEPT);
    

    
    int exception = fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT);
    

    【讨论】:

    • 但是为什么只有在使用浮点变量时才会发生呢?
    • @JaneS:因为 FPU 仅针对浮点运算发出异常信号?或者你是什么意思?
    • 我的意思是 float c = a * b * 1.3f; 给出了例外但不是 float c = 1.1f * 1.2f * 1.3f;
    • 一种猜测可能是您使用的 GCC 版本在常量折叠时不会发出 FP 异常。或者您正在为 32 位 x86 进行编译,而 x87 精度过高的问题又出现了丑陋的问题。在任何情况下,您几乎肯定不想检查 FP_INEXACT,除非您正在做一些非常特别的事情,因为您所做的任何不平凡的事情或多或少都会发出异常信号。
    • GCC 在编译时计算常量表达式。因为c 只是在运行时设置为预先计算的值,所以不会发生精度损失。如果将常量定义为static const float A = 1.1f, B = 1.2f, C = 1.3f; 并使用-O0 进行编译(无优化),那么GCC 实际上会执行乘法float c = A * B * C;,并且FP_INEXACT 会被提升。在默认优化下,GCC 发现 ABC 都是常量,并将值预先计算为 c,将其从乘法转换为普通赋值。如果你编译成程序集-S,你可以看到这个。
    【解决方案2】:

    您可以使用Diagnostic-Pragmas 忽略某些警告。

    例如,如果我要编译您的代码子集:

    #include <stdio.h>
    #include <math.h> 
    #include <fenv.h>  
    #pragma STDC FENV_ACCESS ON  
    int main(void) {
       float a = 1.1f;
       float b = 1.2f;
       float c = a * b * 1.3f;
       int exception = c;
       return 0;
     } 
    

    与:

    gcc -Wall test.c
    

    我会收到一堆警告,例如:

    test.c:22:0: warning: ignoring #pragma STDC FENV_ACCESS [-Wunknown-pragmas]
    test.c: In function ‘main’:
    test.c:28:11: warning: unused variable ‘exception’ [-Wunused-variable]
    

    然后,您可以添加“忽略的”编译指示来使它们静音:

    #pragma GCC diagnostic ignored "-Wunknown-pragmas"
    #pragma GCC diagnostic ignored "-Wunused-variable"
    

    重新编译,警告消失。

    【讨论】:

      猜你喜欢
      • 2016-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-17
      相关资源
      最近更新 更多