【发布时间】:2020-07-06 00:32:48
【问题描述】:
我正在重写上学期为大学开发的光线追踪器,但遇到了以下问题: 当我在 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
如果我在发布模式下取消注释,我会再次得到预期的结果。也许我的代码中有一些未定义的行为会导致这种情况?
您也可以在这里查看,因为一个最小的可重现示例并不容易。 https://github.com/Yamahari/RayTracer/blob/master/rt/solid/Sphere.cpp
(你也可以clone repo并用cmake构建项目,你只需要SFML作为依赖。
将 -DSFML_INCLUDE_DIR="include_dir" 和 -DSFML_LIB_DIR="lib_dir" 与使用所需编译器编译的 sfml 库一起使用)
【问题讨论】:
-
也许我的代码中有一些未定义的行为会导致这种情况? 99.44% 的可能性。您是否尝试过打开所有编译器警告?
-
是的,我正在使用'-Wall -Wextra -Wpedantic',我得到的唯一警告是未使用的参数和非标准 gcc 扩展,但使用该扩展的代码未用于例子
-
我会使用
-O3,然后禁用所有可禁用的警告-fno-blahblah,然后分批打开它们,直到您可以隔离特定的优化。一旦你找到了优化的罪魁祸首,你就可以深入了解代码绊倒了哪些未定义的行为。虽然,并非所有优化都有明确的编译器标志来启用/禁用。提供代码 sn -p 不是minimal reproducible example。 -
你能用调试器逐步检查可疑代码吗?一次调试,一次发布
-
Intersection是否有任何引用成员,或者构造函数是否复制了它获得的所有参数?