为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++
德玛西亚99 2019-11-29 09:16:00
以下代码在经过优化和未经优化的情况下都适用于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.54.6但是带有优化(O1- O3)的g ++ 将输出:4.54.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 ++更可靠?
查看完整描述

3 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

英特尔x86处理器内部使用80位扩展精度,而double通常为64位宽。不同的优化级别会影响来自CPU的浮点值保存到内存的频率,从而从80位精度四舍五入到64位精度。


使用-ffloat-storegcc选项可获得具有不同优化级别的相同浮点结果。


或者,使用long double通常在gcc上为80位宽的类型,以避免精度从80位舍入到64位。


man gcc 全部说明:


   -ffloat-store

       Do not store floating point variables in registers, and inhibit

       other options that might change whether a floating point value is

       taken from a register or memory.


       This option prevents undesirable excess precision on machines such

       as the 68000 where the floating registers (of the 68881) keep more

       precision than a "double" is supposed to have.  Similarly for the

       x86 architecture.  For most programs, the excess precision does

       only good, but a few programs rely on the precise definition of

       IEEE floating point.  Use -ffloat-store for such programs, after

       modifying them to store all pertinent intermediate computations

       into variables.


查看完整回答
反对 回复 2019-11-29
?
婷婷同学_

TA贡献1844条经验 获得超8个赞

输出应为:4.5 4.6如果您具有无限精度,或者正在使用使用基于十进制而不是基于二进制的浮点表示的设备,那么输出就是这样。但是,事实并非如此。大多数计算机使用二进制IEEE浮点标准。


正如Maxim Yegorushkin在回答中指出的那样,部分问题是计算机内部使用的是80位浮点表示形式。不过,这只是问题的一部分。问题的基础是n.nn5形式的任何数字都没有确切的二进制浮点表示形式。这些极端情况总是不精确的数字。


如果您确实希望舍入能够可靠地舍入这些极端情况,则需要一种舍入算法来解决以下事实:n.n5,n.nn5或n.nnn5等(而不是n.5)始终是不精确。找到确定某些输入值是向上舍入还是向下舍入的特殊情况,并根据与该特殊情况的比较返回四舍五入后的值。而且,您确实需要注意,优化的编译器不会将找到的特殊情况放入扩展的精度寄存器中。


请参阅即使不精确,Excel如何如何成功舍入浮点数?对于这样的算法。


或者,您可以忍受极端情况有时会错误舍入的事实。


查看完整回答
反对 回复 2019-11-29
?
手掌心

TA贡献1942条经验 获得超3个赞

不同的编译器具有不同的优化设置。根据IEEE 754的规定,某些较快的优化设置未维护严格的浮点规则。Visual Studio中有一个特定的设置,/fp:strict/fp:precise/fp:fast,其中/fp:fast违反了什么可以做标准。您可能会发现,标志是控制此类设置中的优化的因素。您可能还会在GCC中找到类似的设置,该设置会更改行为。

如果是这种情况,则编译器之间的唯一不同之处在于,默认情况下,GCC会在更高的优化条件下寻找最快的浮点行为,而Visual Studio不会在更高的优化级别下更改浮点行为。因此,它不一定是实际的错误,而是您不知道要打开的选项的预期行为。


查看完整回答
反对 回复 2019-11-29
  • 3 回答
  • 0 关注
  • 612 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信