原始双类型比较的GCC问题 [英] GCC problem with raw double type comparisons

查看:171
本文介绍了原始双类型比较的GCC问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码,但是当使用GCC 4.4编译它时,它会运行各种优化标志,当我们得到一些意想不到的结果。

I have the following bit of code, however when compiling it with GCC 4.4 with various optimization flags I get some unexpected results when its run.

#include <iostream>

int main()
{
   const unsigned int cnt = 10;
   double lst[cnt] = { 0.0 };
   const double v[4] = { 131.313, 737.373, 979.797, 731.137 };

   for(unsigned int i = 0; i < cnt; ++i) {
      lst[i] = v[i % 4] * i;
   }

   for(unsigned int i = 0; i < cnt; ++i) {
      double d = v[i % 4] * i;
      if(lst[i] != d) {
         std::cout << "error @ : " << i << std::endl;
         return 1;
      }
   }
   return 0;
}




  • > g ++ -pedantic -Wall -Werror -O1 -o test test.cpp 我得到以下输出:error @:3

    • when compiled with: "g++ -pedantic -Wall -Werror -O1 -o test test.cpp" I get the following output: "error @ : 3"

      当编译时: g ++ -pedantic -Wall -Werror -O2 -o test test.cpp 我得到以下输出:编译时使用 g ++ -pedantic -Wall -Werror -O3 -o test test.cpp,error @:3

      when compiled with: "g++ -pedantic -Wall -Werror -O2 -o test test.cpp" I get the following output: "error @ : 3"

      我没有收到错误

      编译时: g ++ -pedantic -Wall -Werror - o test test.cpp 我没有错误

      when compiled with: "g++ -pedantic -Wall -Werror -o test test.cpp" I get no errors

      我不相信成为与四舍五入相关的问题,或者是epsilon的差异。我已经尝试使用英特尔v10和MSVC 9.0,它们似乎都按预期工作。我相信这应该只是一个比较的比较。

      I do not believe this to be an issue related to rounding, or epsilon difference in the comparison. I've tried this with Intel v10 and MSVC 9.0 and they all seem to work as expected. I believe this should be nothing more than a bitwise compare.

      如果我用以下代码替换if语句: if(static_cast< long long int>(lst [i])!= static_cast< long long int>(d)) ,并添加-Wno-long-长我运行时没有任何优化模式的错误。

      If I replace the if-statement with the following: if (static_cast<long long int>(lst[i]) != static_cast<long long int>(d)), and add "-Wno-long-long" I get no errors in any of the optimization modes when run.

      如果我添加 std :: cout< ;< d< std :: endl; 在返回1之前,运行时没有任何优化模式的错误。

      If I add std::cout << d << std::endl; before the "return 1", I get no errors in any of the optimization modes when run.

      这是我的代码中的错误,还是GCC有什么问题以及处理双重类型的方式?

      Is this a bug in my code, or is there something wrong with GCC and the way it handles the double type?

      注意: / strong>我刚刚尝试过gcc版本4.3和3.3,错误没有展现。

      Note: I've just tried this with gcc versions 4.3 and 3.3, the error is not exhibited.

      解决方案: Mike Dinsdale指出以下错误报告: http://gcc.gnu.org/bugzilla/show_bug.cgi ?id = 323 看来,GCC团队对于问题的本质并不完全肯定。

      Resolution: Mike Dinsdale noted the following bug report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 It seems the GCC team are not completely sure about nature of problem.

      如错误报告中所建议的,可能的解决方案是使用ffloat-store选项。我已经尝试了这个工作,但是从性能的角度来看,结果并不是那么好,尽管如此。

      As suggested in the bug report a possible resolution is to use the ffloat-store option. I've tried this and it works, however the results from a performance point of view are not that great, though ymmv.

      推荐答案

      结果取决于优化设置的事实表明,x87扩展精度可能会与事情发生混淆(如Michael Burr所说)。

      The fact that the result depends on the optimization settings suggests it might be the x87 extended precision messing with things (as Michael Burr says).

      这是我使用的一些代码在x86处理器上使用gcc)来关闭扩展精度:

      Here's some code I use (with gcc on x86 processors) to switch the extended precision off:

      static const unsigned int PRECISION_BIT_MASK = 0x300;
      ///< bitmask to mask out all non-precision bits in the fpu control word \cite{INTEL}.
      static const unsigned int EXTENDED_PRECISION_BITS = 0x300;
      ///< add to the fpu control word (after zeroing precision bits) to turn on extended precision \cite{INTEL}.
      static const unsigned int STANDARD_PRECISION_BITS = 0x200;
      ///< add to the fpu control word (after zeroing precision bits) to turn off extended precision \cite{INTEL}.
      
      void set_fpu_control_word(unsigned int mode)
      {
        asm ("fldcw %0" : : "m" (*&mode));
      }
      
      unsigned int get_fpu_control_word()
      {
        volatile unsigned int mode = 0;
        asm ("fstcw %0" : "=m" (*&mode));
        return mode;
      }
      
      bool fpu_set_extended_precision_is_on(bool state)
      {
        unsigned int old_cw = get_fpu_control_word();
        unsigned int masked = old_cw & ~PRECISION_BIT_MASK;
        unsigned int new_cw;
        if(state)
          new_cw = masked + EXTENDED_PRECISION_BITS;
        else
          new_cw = masked + STANDARD_PRECISION_BITS;
        set_fpu_control_word(new_cw);
        return true;
      }
      
      bool fpu_get_extended_precision_is_on()
      {
        unsigned int old_cw = get_fpu_control_word();
        return  ((old_cw & PRECISION_BIT_MASK) == 0x300);
      }
      

      或者你可以运行你的代码与valgrind,它不模拟80位寄存器,这样一个简短的程序可能更容易!

      Or you can just run your code with valgrind, which doesn't simulate the 80-bit registers, and is probably easier for a short program like this!

      这篇关于原始双类型比较的GCC问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆