GCC 中具有不同优化级别的不同输出

Different output with different optimization levels in GCC

我正在重写上学期为大学开发的光线追踪器,我 运行 遇到以下问题: 当我编译 运行 我在 Debug 中的代码时,输​​出符合预期

但是当我启用更高的优化级别时,例如“-O2”结果完全不同:

而且我不确定为什么会这样。我追踪到球体相交代码

//#pragma GCC push_options
//#pragma GCC optimize("O0")

Intersection Sphere::intersect(const Ray& ray, const float previous) const
{
    const auto oc = ray.origin - center_;
    const auto lhv = -dot(ray.direction, oc);
    const auto discriminant = lhv * lhv - (oc.lensqr() - radius_ * radius_);

    if (discriminant < 0.0F)
    {
        return Intersection::failure();
    }
    float distance;
    const auto rhv = std::sqrt(discriminant);
    const auto r = std::minmax(lhv + rhv, lhv - rhv);
    if (r.first <= 0.0F)
    {
        if (r.second <= 0.0F)
        {
            return Intersection::failure();
        }
        distance = r.second;
    }
    else
    {
        distance = r.first;
    }

    const auto hit = ray.getPoint(distance);
    const auto normal = (hit - center_).normalize();

    if (0.0F <= distance && distance < previous - epsilon)
    {
        return {distance, ray, this, normal, hit};
    }
    return Intersection::failure();
}

//#pragma GCC pop_options

如果我在发布模式下取消注释 pragma,我会再次得到预期的结果。也许我的代码中有一些未定义的行为导致了这个?

您也可以在此处查看,因为不容易实现最小的可重现示例。 https://github.com/Yamahari/RayTracer/blob/master/rt/solid/Sphere.cpp

(您也可以克隆 repo 并使用 cmake 构建项目,您只需要 SFML 作为依赖项。

将 -DSFML_INCLUDE_DIR="include_dir" 和 -DSFML_LIB_DIR="lib_dir" 与使用所需编译器编译的 sfml 库一起使用)

std::minmax returns 一对对其参数的引用。如果你用纯右值作为参数调用它,这对中的引用将在完整表达式结束后悬空,这意味着访问 r.first in

if (r.first <= 0.0F)

这里会有未定义的行为。

因此将 lhv + rhvlhv - rhv 存储在变量中并调用 std::minmax 或使用

std::minmax({lhv + rhv, lhv - rhv})

到select std::initializer_list重载,其中returns一对实际值。


正如@Jarod42 在评论中指出的那样,您实际上不需要 std::minmax 这里。 rhvstd::sqrt 调用的结果,所以它总是非负的,使得 lhv + rhv 总是更大(或等于)的值。