这很可能是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变得有效了吗?
当我在阅读此代码的补丁时出现了这个问题:
为便于参考:
相关的排序:
答案 0 :(得分:4)
使用这些特殊值作为初始化标志只有在变量无法获得特殊值时才有效。在数学运算方面,无穷大并不难,因为溢出也会得到它。所以这可能会有问题。使用安静的NaN,如果它的可用性更容易使用,那么这个浮点值不能由用户设置为该值。
就这三种方法而言,只有方法&#34; a&#34;与初始值完全匹配。因此,如果不变量只是初始值表示为初始化值,那么它是最准确的方法。当然,这些方法都没有做任何关于保护开头的不变量的事情,这在我的脑海中是更多的问题:是否可以有效地执行不变量。
虽然这不是代码评论网站,但就github上的OGREnvelope
类(看起来只是AABB)的链接代码编辑而言,我认为应该做的一些事情请注意:
IsInit
- 基于其代码 - 似乎意味着返回AABB是否实际上已由用户设置。不论它是否处于初始状态/价值可以说是IsInit
暗示(并误导我相信)。就个人而言,我更喜欢IsValid
这样的名字。MinX
的{{1}}值和MaxX
这大于MinY
。换句话说,它们永远不应该在有效的AABB中被逆转。 MaxY
应始终小于或等于MinX
(对于最小和最大Y变量,相同)。MaxX
和max()
值更广泛的有效AABB。lowest()
,MinX
,MaxX
,MinY
成员变量可公开访问这一事实意味着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()
更有效率。