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

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

问题描述

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

  #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 lst [i] = v [i%4] * i;
}

for(unsigned int i = 0; 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


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


  • g ++ -pedantic -Wall -Werror - o test test.cpp 我没有错误




成为与舍入相关的问题,或者在比较中的ε差。我试过这与英特尔v10和MSVC 9.0,他们似乎按预期工作。



如果我将if语句替换为以下内容: if(static_cast< long long int>(lst [i])!= static_cast< long long int>(d))

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



这是我的代码中的一个错误,或者是GCC和处理double类型的方式有问题吗?



注意: / strong>我刚刚试过这个与gcc版本4.3和3.3,错误不显示。



分辨率: Mike Dinsdale注意到以下错误报告: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 似乎GCC团队并不完全确定有关问题的性质。



根据错误报告中的建议,可能的解决方法是使用ffloat-store选项。我试过这个和它的工作,但是从性能的观点的结果是不是很大,虽然ymmv。

解决方案

事实上,结果取决于优化设置,这表明它可能是x87扩展精度麻烦事情(如迈克尔·伯尔说)。



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

  static const unsigned int PRECISION_BIT_MASK = 0x300; 
///<位掩码来掩蔽fpu控制字\ cite {INTEL}中的所有非精度位。
static const unsigned int EXTENDED_PRECISION_BITS = 0x300;
///<添加到fpu控制字(清零精度位后)以打开扩展精度\ cite {INTEL}。
static const unsigned int STANDARD_PRECISION_BITS = 0x200;
///<添加到fpu控制字(清零精度位后)以关闭扩展精度\cite {INTEL}。

void set_fpu_control_word(unsigned int mode)
{
asm(fldcw%0::m(*&
}

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位寄存器,并且对于像这样的短程序可能更容易!


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;
}

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

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

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

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

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 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.

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

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

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

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.

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.

解决方案

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).

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);
}

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天全站免登陆