gpt4 book ai didi

c++ - 原始双类型比较的 GCC 问题

转载 作者:可可西里 更新时间:2023-11-01 17:33:58 25 4
gpt4 key购买 nike

我有以下代码,但是当使用带有各种优化标志的 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 < 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"

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

  • 当编译时:"g++ -pedantic -Wall -Werror -O3 -o test test.cpp"我没有得到任何错误

  • 编译时使用:"g++ -pedantic -Wall -Werror -o test test.cpp"我没有得到任何错误

我不认为这是与舍入或比较中的 epsilon 差异相关的问题。我已经用 Intel v10 和 MSVC 9.0 试过了,它们似乎都按预期工作。我相信这应该只是按位比较。

如果我将 if 语句替换为以下内容: if (static_cast<long long int>(lst[i]) != static_cast<long long int>(d)) ,并添加“-Wno-long-long”运行时我在任何优化模式下都没有错误。

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

这是我代码中的错误,还是 GCC 及其处理 double 类型的方式有问题?

注意:我刚刚用 gcc 版本 4.3 和 3.3 尝试了这个,没有显示错误。

解决方案:Mike Dinsdale 注意到以下错误报告:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323看来 GCC 团队对问题的性质并不完全确定

正如错误报告中所建议的,一个可能的解决方案是使用 ffloat-store 选项。我已经尝试过这个并且它有效,但是从性能的角度来看结果并不是很好,尽管 ymmv。

最佳答案

结果取决于优化设置的事实表明它可能是 x87 扩展精度搞砸了(正如 Michael Burr 所说)。

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

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

关于c++ - 原始双类型比较的 GCC 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2497825/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com