猿问

启用优化的不同浮点结果-编译器错误?

以下代码在经过优化和未经优化的情况下都适用于Visual Studio 2008。但是,它仅适用于未经优化(O0)的g ++。


#include <cstdlib>

#include <iostream>

#include <cmath>


double round(double v, double digit)

{

    double pow = std::pow(10.0, digit);

    double t = v * pow;

    //std::cout << "t:" << t << std::endl;

    double r = std::floor(t + 0.5);

    //std::cout << "r:" << r << std::endl;

    return r / pow;

}


int main(int argc, char *argv[])

{

    std::cout << round(4.45, 1) << std::endl;

    std::cout << round(4.55, 1) << std::endl;

}

输出应为:


4.5

4.6

但是带有优化(O1- O3)的g ++ 将输出:


4.5

4.5

如果我volatile在t之前添加关键字,那么它会起作用,那么是否可能存在某种优化错误?


在g ++ 4.1.2和4.4.4上进行测试。


这是在ideone上的结果:http ://ideone.com/Rz937


我在g ++上测试的选项很简单:


g++ -O2 round.cpp

更有趣的结果是,即使我/fp:fast在Visual Studio 2008 上启用了选项,结果仍然是正确的。


进一步的问题:


我想知道,是否应该始终打开该-ffloat-store选项?


因为我测试的g ++版本随CentOS / Red Hat Linux 5和CentOS / Redhat 6一起提供。


我在这些平台上编译了许多程序,我担心它会导致程序内部出现意外错误。研究我所有的C ++代码和使用的库是否存在此类问题似乎有点困难。有什么建议吗?


是否有人对为什么即使/fp:fast打开Visual Studio 2008仍然可以工作感兴趣?似乎Visual Studio 2008在此问题上比g ++更可靠?


德玛西亚99
浏览 623回答 3
3回答

慕仙森

英特尔x86处理器内部使用80位扩展精度,而double通常为64位宽。不同的优化级别会影响来自CPU的浮点值保存到内存的频率,从而从80位精度四舍五入到64位精度。使用-ffloat-storegcc选项可获得具有不同优化级别的相同浮点结果。或者,使用long double通常在gcc上为80位宽的类型,以避免精度从80位舍入到64位。man gcc 全部说明:&nbsp; &nbsp;-ffloat-store&nbsp; &nbsp; &nbsp; &nbsp;Do not store floating point variables in registers, and inhibit&nbsp; &nbsp; &nbsp; &nbsp;other options that might change whether a floating point value is&nbsp; &nbsp; &nbsp; &nbsp;taken from a register or memory.&nbsp; &nbsp; &nbsp; &nbsp;This option prevents undesirable excess precision on machines such&nbsp; &nbsp; &nbsp; &nbsp;as the 68000 where the floating registers (of the 68881) keep more&nbsp; &nbsp; &nbsp; &nbsp;precision than a "double" is supposed to have.&nbsp; Similarly for the&nbsp; &nbsp; &nbsp; &nbsp;x86 architecture.&nbsp; For most programs, the excess precision does&nbsp; &nbsp; &nbsp; &nbsp;only good, but a few programs rely on the precise definition of&nbsp; &nbsp; &nbsp; &nbsp;IEEE floating point.&nbsp; Use -ffloat-store for such programs, after&nbsp; &nbsp; &nbsp; &nbsp;modifying them to store all pertinent intermediate computations&nbsp; &nbsp; &nbsp; &nbsp;into variables.

婷婷同学_

输出应为:4.5 4.6如果您具有无限精度,或者正在使用使用基于十进制而不是基于二进制的浮点表示的设备,那么输出就是这样。但是,事实并非如此。大多数计算机使用二进制IEEE浮点标准。正如Maxim Yegorushkin在回答中指出的那样,部分问题是计算机内部使用的是80位浮点表示形式。不过,这只是问题的一部分。问题的基础是n.nn5形式的任何数字都没有确切的二进制浮点表示形式。这些极端情况总是不精确的数字。如果您确实希望舍入能够可靠地舍入这些极端情况,则需要一种舍入算法来解决以下事实:n.n5,n.nn5或n.nnn5等(而不是n.5)始终是不精确。找到确定某些输入值是向上舍入还是向下舍入的特殊情况,并根据与该特殊情况的比较返回四舍五入后的值。而且,您确实需要注意,优化的编译器不会将找到的特殊情况放入扩展的精度寄存器中。请参阅即使不精确,Excel如何如何成功舍入浮点数?对于这样的算法。或者,您可以忍受极端情况有时会错误舍入的事实。

手掌心

不同的编译器具有不同的优化设置。根据IEEE 754的规定,某些较快的优化设置未维护严格的浮点规则。Visual Studio中有一个特定的设置,/fp:strict,/fp:precise,/fp:fast,其中/fp:fast违反了什么可以做标准。您可能会发现,此标志是控制此类设置中的优化的因素。您可能还会在GCC中找到类似的设置,该设置会更改行为。如果是这种情况,则编译器之间的唯一不同之处在于,默认情况下,GCC会在更高的优化条件下寻找最快的浮点行为,而Visual Studio不会在更高的优化级别下更改浮点行为。因此,它不一定是实际的错误,而是您不知道要打开的选项的预期行为。
随时随地看视频慕课网APP
我要回答