加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux – GCC处理不同优化级别的浮点数比较

发布时间:2020-12-13 19:53:54 所属栏目:Linux 来源:网络整理
导读:我有一些简单的代码比较两个浮点值,以说明我在GCC优化中看到的问题,并希望有人可以帮我弄清楚为什么它产生的输出在某些可重复的情况下是不同的. 首先,我知道将浮点值与==进行比较是不好的,因为你可以在尾数中关闭一些非常小的数量,但在我的例子中并非如此.我
我有一些简单的代码比较两个浮点值,以说明我在GCC优化中看到的问题,并希望有人可以帮我弄清楚为什么它产生的输出在某些可重复的情况下是不同的.

首先,我知道将浮点值与==进行比较是不好的,因为你可以在尾数中关闭一些非常小的数量,但在我的例子中并非如此.我遇到的问题是基于2个因素的输出变化. 1)我传入的优化标志,以及2)如果我取消注释std :: cout线.

为什么代码GCC在-O2下产生不同的运行?
如果取消注释打印,为什么在-O2下编译的代码有效?

这是我正在测试的代码:

#include <iostream>

const float ft_to_m          =  (float)0.3048; 
const float m_to_ft          =  (float)3.28083989501;


float FeetToKilometers( float & Feet ) {
  float Kilometers;
  Kilometers = (ft_to_m * Feet) / 1000.;
  return Kilometers;
}

int main(void)
{
    float feet = 20000.;
    float old_val = 0;
    float new_val = FeetToKilometers(feet );
    float diff_val = 0;

    int *old_int = reinterpret_cast<int*>(&old_val);
    int *new_int = reinterpret_cast<int*>(&new_val);

    for (int i=0; i<2; i++)
    {

    new_val = FeetToKilometers(feet );
    diff_val = old_val-new_val;

    //std::cout << "Random COUT that makes this work" << std::endl;

        if(old_val==new_val)
    {
             std::cout << "old_val==new_val" << std::endl;
         std::cout << std::hex << *old_int << "," << std::hex << *new_int << std::endl;
             std::cout << "diff_val = " << diff_val <<std::endl;
    }
        else
        {
            std::cout << "old_val!=new_val" <<std::endl;
        std::cout << std::hex << *old_int << "," << std::hex << *new_int << std::endl;
            std::cout << "diff_val = " << diff_val <<std::endl;
            old_val=FeetToKilometers(feet);
        }
    }

    return 0;
}

当使用-O0,-O1和-O3(g -O test.cpp)在linux / cygwin上编译时,我得到以下输出:

$./a.exe
old_val!=new_val
0,40c3126f
diff_val = -6.096
old_val==new_val
40c3126f,40c3126f
diff_val = 0

该输出是正确的,您可以看到浮点数(new_val和old_val)的位是相同的.当我使用-O2标志(g -O2 test.cpp)编译时,我得到以下内容:

$./a.exe
old_val!=new_val
0,40c3126f
diff_val = -6.096
old_val!=new_val
40c3126f,40c3126f
diff_val = 1.19209e-07

我会认为这个输出错了.即使两个值相同,但减去它们和==检查表明它们是不同的.如果我然后取消注释std :: cout行,并使用-O2标志(g -O2 test.cpp)重建,我得到以下内容:

$./a.exe
Random COUT that makes this work
old_val!=new_val
0,40c3126f
diff_val = -6.096
Random COUT that makes this work
old_val==new_val
40c3126f,40c3126f
diff_val = 1.19209e-07

这在old_val == new_val中是正确的,即使减法仍然显示略有差异.

如果脚是2000而不是20000,此代码也可以在-O2下工作.

任何人都可以解释为什么编译的代码行为像这样?我想知道为什么2位相同的浮点值不能与==进行比较.

gcc版本3.4.4

解决方法

优化级别和周围代码可能会影响diff_val计算中使用的值是从内存中获取还是从寄存器中获取.处理器
可能在一种情况下使用80位内部浮点寄存器,并且32位浮动
在另一种情况下从内存中指出值,给出意想不到的结果.

避免使用==进行浮点比较的另一个原因!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读