【问题标题】:Passing double types to ceil results in different values for different optimization levels in GCC将双精度类型传递给 ceil 会导致 GCC 中不同优化级别的不同值
【发布时间】:2010-07-24 05:08:12
【问题描述】:

下面,result1 和 result2 变量值根据是否报告不同的值 您在 GCC 4.2.1 和 GCC 3.2.0 上使用 -g 或 -O 编译代码(我还没有尝试过更新的 GCC 版本):

double double_identity(double in_double)
{
    return in_double;
}

...

double result1 = ceil(log(32.0) / log(2.0));
std::cout << __FILE__ << ":" << __LINE__ << ":" << "result1==" << result1 << std::endl;

double result2 = ceil(double_identity(log(32.0) / log(2.0)));
std::cout << __FILE__ << ":" << __LINE__ << ":" << "result2==" << result2 << std::endl;

result1 和 result2 == 5 仅在使用 -g 编译时,但如果改为使用 -O 编译,我会得到 result1 == 6 和 result2 == 5。

这似乎是编译器如何进行优化的差异,或者与内部的 IEEE 浮点表示有关,但我很好奇这种差异究竟是如何发生的。我希望尽可能避免查看汇编程序。

上面是用 C++ 编译的,但我认为如果使用 printfs 将其转换为 ANSI-C 代码,情况也是如此。

上述差异发生在 32 位 Linux 上,但不在 64 位 Linux 上。

谢谢 bg

【问题讨论】:

  • 你应该从中吸取的教训:不要使用浮点 log/pow/etc。当您想要执行精确的整数运算时使用函数(或任何浮点数),除非您拥有数值分析博士学位。
  • 同意。在我的辩护中,我使用的代码 sn-p 是另一个开发人员代码的精简副本,当然它坏了,这就是我在这里的原因。

标签: c++ c math compiler-optimization logarithm


【解决方案1】:

在 x86 上,通过优化,子表达式的结果在用作更大表达式的一部分之前不一定存储到 64 位内存位置。

因为 x86 的标准浮点寄存器是 80 位,这意味着在这种情况下,可以使用额外的精度。如果您随后将该特别精确的值除以(或乘以)另一个值,则提高精度的效果会放大到肉眼可以感知的程度。

英特尔的 64 位处理器使用 SSE 寄存器进行浮点数学运算,而这些寄存器没有额外的精度。

如果您真的在意,可以使用g++ flags 来解决此问题。

【讨论】:

  • 我将“肉眼可以感知的位置”翻译为“这些计算的值可以保存在 80 位宽度的浮点寄存器中,然后通过到 ceil 函数,它尽职地检测额外的精度并返回下一个更大的整数值”。
  • 我将此标记为答案,因为您指向stackoverflow.com/questions/3234042/… 的链接引导我前往stackoverflow.com/questions/3234042/…,我在上面的代码上进行了尝试,它给出了我想要的结果。当然,现在我有一个不同的问题,我怀疑原始源代码中可能有大量这样的代码,如果我抛出 -ffloat-store 选项,现在的行为会有所不同。
猜你喜欢
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
相关资源
最近更新 更多