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

问题描述 投票:6回答:1

我正在重写上学期为大学开发的raytracer,但遇到了以下问题:当我在Debug中编译并运行我的代码时,输​​出如预期的那样

expected result

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

actual result

而且我不确定为什么会这样。我将其跟踪到球面相交代码

//#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

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

您也可以在这里查看,因为很难再现一个最小的示例。 https://github.com/Yamahari/RayTracer/blob/master/rt/solid/Sphere.cpp

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

将-DSFML_INCLUDE_DIR =“ include_dir”和-DSFML_LIB_DIR =“ lib_dir”与通过所需编译器编译的sfml库一起使用]

c++ gcc c++17 sfml
1个回答
4
投票

std::minmax返回一对对其参数的引用。如果使用prvalues作为参数调用它,则在完整表达式结束后,该对中的引用将悬空,这意味着访问r.first in

if (r.first <= 0.0F)

这里将有未定义的行为。

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

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

选择std::initializer_list重载,它返回一对实际值。


正如@ Jarod42在评论中指出的那样,您实际上实际上不需要std::minmaxrhvstd::sqrt调用的结果,因此它始终为非负数,从而使lhv + rhv始终为更大(或相等)的值。

© www.soinside.com 2019 - 2024. All rights reserved.