矢量化优化是否与浮点异常处理不兼容,或者 g++-11 中是否存在错误?

如何解决矢量化优化是否与浮点异常处理不兼容,或者 g++-11 中是否存在错误?

使用不同优化选项的 g++-11.1.1 编译时,下面的代码片段的行为是不同的。该代码段启用了浮点异常处理。我不认为算法细节很重要(有点 3D 几何)。它所做的事情自然容易受到执行无效浮点运算的影响,但编写代码的目的是使这些无效运算永远不会真正发生(例如,使用 if 语句来确保非零分母)。

#include <array>
#include <cfenv>
#include <csignal>
#include <fstream>
#include <iostream>
#include <limits>
#include <cmath>
#include <vector>

// Vector structure -----------------------------------------------------------
struct Vector
{
    double xs[3];

    Vector(double x)
    {
        xs[0] = x;
        xs[1] = x;
        xs[2] = x;
    }

    Vector(double x,double y,double z)
    {
        xs[0] = x;
        xs[1] = y;
        xs[2] = z;
    }

    Vector(std::istream& is)
    {
        is >> xs[0] >> xs[1] >> xs[2];
    }
};

// Vector output stream operator ----------------------------------------------
inline std::ostream& operator<<(std::ostream& os,const Vector& v)
{   
    return os << '(' << v.xs[0] << ' ' << v.xs[1] << ' ' << v.xs[2] << ')';
}

// Vector geometry operators --------------------------------------------------
inline void operator+=(Vector& a,const Vector& b)
{
    a.xs[0] += b.xs[0];
    a.xs[1] += b.xs[1];
    a.xs[2] += b.xs[2];
}
inline void operator/=(Vector& a,const double b)
{
    a.xs[0] /= b;
    a.xs[1] /= b;
    a.xs[2] /= b;
}
inline Vector operator+(const Vector& a,const Vector& b)
{   
    return Vector(a.xs[0] + b.xs[0],a.xs[1] + b.xs[1],a.xs[2] + b.xs[2]);
}
inline Vector operator-(const Vector& a,const Vector& b)
{
    return Vector(a.xs[0] - b.xs[0],a.xs[1] - b.xs[1],a.xs[2] - b.xs[2]);
}
inline Vector operator*(const double& a,const Vector& b)
{
    return Vector(a*b.xs[0],a*b.xs[1],a*b.xs[2]);
}
inline Vector operator/(const Vector& a,const double& b)
{
    return Vector(a.xs[0]/b,a.xs[1]/b,a.xs[2]/b);
}
inline double operator&(const Vector& a,const Vector& b)
{
    return a.xs[0]*b.xs[0] + a.xs[1]*b.xs[1] + a.xs[2]*b.xs[2];
}
inline Vector operator^(const Vector& a,const Vector& b)
{
    return Vector
    (
        a.xs[1]*b.xs[2] - a.xs[2]*b.xs[1],a.xs[2]*b.xs[0] - a.xs[0]*b.xs[2],a.xs[0]*b.xs[1] - a.xs[1]*b.xs[0]
    );
}

// polygon centre algorithm ---------------------------------------------------
template<class PointList>
typename PointList::value_type polygonCentre(const PointList& ps)
{
    typedef typename PointList::value_type Point;

    // Compute an estimate of the centre as the average of the points
    Point pAvg(0);
    for (typename PointList::size_type pi = 0; pi < ps.size(); ++ pi)
    {   
        pAvg += ps[pi];
    }
    pAvg /= ps.size();

    // Compute the polygon area normal and unit normal by summing up the
    // normals of the triangles formed by connecting each edge to the
    // point average.
    Point sumA(0);
    for (typename PointList::size_type pi = 0; pi < ps.size(); ++ pi)
    {
        const Point& p = ps[pi];
        const Point& pNext = ps[(pi + 1) % ps.size()];

        const Point a = (pNext - p)^(pAvg - p);
        
        sumA += a;
    }
    double sumAMagSqr = sumA & sumA; 
    const Point sumAHat = sumAMagSqr > 0 ? sumA/sqrt(sumAMagSqr) : Point(0);

    // Compute the area-weighted sum of the triangle centres
    double sumAn = 0;
    Point sumAnc(0);
    for (typename PointList::size_type pi = 0; pi < ps.size(); ++ pi)
    {
        const Point& p = ps[pi];
        const Point& pNext = ps[(pi + 1) % ps.size()];

        const Point a = (pNext - p)^(pAvg - p);
        const Point c = p + pNext + pAvg;

        const double an = a & sumAHat;

        sumAn += an;
        sumAnc += an*c;
    }

    // Complete calculating centres and areas. If the area is too small
    // for the sums to be reliably divided then just set the centre to
    // the initial estimate.
    if (sumAn > std::numeric_limits<double>::min())
    {   
        return (1.0/3.0)*sumAnc/sumAn;
    }
    else
    {
        return pAvg;
    }
}

// Signal handler -------------------------------------------------------------
void signalHandler(int signum)
{
    std::cout << "Signal " << signum << " caught." << std::endl;
    exit(1);
}

// Main routine ---------------------------------------------------------------
int main(int argc,char *argv[])
{
    feenableexcept(FE_INVALID);

    signal(SIGFPE,signalHandler);

    /*
    std::array<Vector,4> ps
    ({
        Vector(0,0),Vector(1,Vector(0,0)
    });
    */

    std::ifstream is("example.dat");

    std::array<Vector,4> ps
    ({
        Vector(is),Vector(is),Vector(is)
    });

    std::cout << "Centre = " << polygonCentre(ps) << std::endl;

    return 0;
}

使用以下数据 example.dat 文件

0 0 0
1 0 0
1 0 0
0 0 0

当这样编译时:

g++-11 -O3 example.cpp

运行触发浮点异常,被捕获,程序通过signalHandler函数退出

当这样编译时:

g++-11 -O2 example.cpp

或者这个:

g++-11 -O3 -fno-tree-slp-vectorize example.cpp

程序没有触发任何异常,正常退出

这是 g++-11.1.1 中优化器的错误吗?早期版本不表现出这种行为;所有优化选项都会导致可执行文件正常退出。或者,像 O3 启用的那些向量化优化不适合与浮点异常处理一起使用吗?

编辑:从文件中读取点以确保优化不依赖于值

解决方法

这是 Gcc-11.1 中的一个错误。它已在 11.2 的候选版本中修复。

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101634

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?