val!= std :: numeric_limits <double> :: infinity()或!isinf(val)或isfinite(val)

时间:2017-03-21 14:47:49

标签: c++ c++11 nan infinity numeric-limits

这很可能是bike-shedding,但也许有一些我很想念的东西......

如果一个类将一个成员val初始化为std::numeric_limits<double>::infinity(),然后想要检查val是否已被更改为有效的东西(+/- inf在这里无效),那么这些是什么权衡3种方法,我错过了任何其他有趣的方法来解决这个问题。 (为了便于阅读,删除了const。)

bool IsInit() { return MinX != std::numeric_limits<double>::infinity(); }  // a

bool IsInit() { return !std::isinf(MinX); }  // b

bool IsInit() { return std::isfinite(MinX); }  // c

现在代码是C ++ 03,但是如何用C ++ 11,C ++ 14和C ++ 17改变选项。例如使用C ++ 17,此代码可能只是std::optional<double> val。或者安静的NaN是一个更安全的赌注,只是因为未来+/- inf变得有效了吗?

当我在阅读此代码的补丁时出现了这个问题:

为便于参考:

相关的排序:

2 个答案:

答案 0 :(得分:4)

使用这些特殊值作为初始化标志只有在变量无法获得特殊值时才有效。在数学运算方面,无穷大并不难,因为溢出也会得到它。所以这可能会有问题。使用安静的NaN,如果它的可用性更容易使用,那么这个浮点值不能由用户设置为该值。

就这三种方法而言,只有方法&#34; a&#34;与初始值完全匹配。因此,如果不变量只是初始值表示为初始化值,那么它是最准确的方法。当然,这些方法都没有做任何关于保护开头的不变量的事情,这在我的脑海中是更多的问题:是否可以有效地执行不变量。

虽然这不是代码评论网站,但就github上的OGREnvelope类(看起来只是AABB)的链接代码编辑而言,我认为应该做的一些事情请注意:

  • IsInit - 基于其代码 - 似乎意味着返回AABB是否实际上已由用户设置。不论它是否处于初始状态/价值可以说是IsInit暗示(并误导我相信)。就个人而言,我更喜欢IsValid这样的名字。
  • 至于实际上是不变量,编辑本身似乎认识到有效的AABB永远不应该具有大于MinX的{​​{1}}值和MaxX这大于MinY。换句话说,它们永远不应该在有效的AABB中被逆转。 MaxY应始终小于或等于MinX(对于最小和最大Y变量,相同)。
  • 使用反向无穷大值,使其成为:(a)更容易使AABB成长以包围其他AABB(并且编辑演示了将代码行从14减少到4的含义); (b)使其能够处理比使用MaxXmax()值更广泛的有效AABB。
  • lowest()MinXMaxXMinY成员变量可公开访问这一事实意味着MaxY和不变量本身仅提供咨询感觉没有封装来保护不变量。

在更广泛的背景下,NaN并不合适。不变量永远不是IsInit。并且MinX != std::numeric_limits<double>::infinity()(在该代码中实现)充其量是不完整的。在将其重命名为IsInit之类的上下文中,则更符合逻辑的实现是:

IsValid

通过此实现,有效AABB是bool IsValid() const { return !std::isnan(MinX) && !std::isnan(MinY) && MinX <= MaxX && MinY <= MaxY; } ,其值均为有效数字(均不是NaN)且其最小值必须分别小于或等于X和Y的最大值。

答案 1 :(得分:0)

我不希望这是一个可以接受的答案,但希望它能提供一些有用的信息。

我使用Godbolt工具对上述三个建议的实现进行了彻底的比较:https://godbolt.org/z/184Zb6

基本观察结果是,打开编译器优化功能,与std::numeric_limits<double>::infinity()相比,std::isfinite()的效率更高(CPU指令和内存移动更少);也就是说,由于添加了逻辑求反运算,它仅比!std::isinf()更有效率。