val != std::numeric_limits:<double>:infinity() 或 !isinf(val) 或 isfinite(val)
val != std::numeric_limits<double>::infinity() or !isinf(val) or isfinite(val)
这可能是自行车脱落,但也许我错过了一些有趣的东西......
如果一个类初始化一个成员val
std::numeric_limits<double>::infinity()
,后来想检查 val 是否已更改为有效的东西(+/- inf 在这里无效),这 3 种方法的权衡是什么,我是否错过了任何其他有趣的方法来解决这个问题。(为了提高示例中的可读性,删除了常量。
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 在未来生效?
当我阅读此代码的补丁时,出现了这种情况:
- https://github.com/OSGeo/gdal/commit/30194c640f403008625ff0c8be7aca155ac7ebe1
- https://trac.osgeo.org/gdal/browser/trunk/gdal/ogr/ogr_core.h?rev=37821#L76
为了便于参考:
- std::numeric_limits::infinity()
- 标准::伊辛夫
- 标准::是有限的
- 标准::numeric_limits::quiet_NaN
- 标准::可选
有点相关:
- 使用 std::numeric_limits::max() 作为特殊的"标志"是否安全?
使用这些特殊值作为初始化标志仅在变量无法到达特殊值时才有效。在数学运算方面,无穷大并不难获得,因为溢出也会得到它。所以这可能是有问题的。如果安静 NaN 可用,则使用安静 NaN 会更容易使用,因为不变的是用户无法将此浮点值设置为此值。
就这三种方法而言,只有方法"a"与初始值完全匹配。因此,如果不变是只有该初始值表示初始化值,则这是最准确的方法。当然,这些方法一开始就没有保护不变性,这对我来说更多的是问题:不变性是否有效或是否可以有效执行。
虽然这不是一个代码审查网站,但就 github 上对OGREnvelope
类(似乎只是一个 AABB)的链接代码编辑而言,我认为应该注意几点:
IsInit
- 基于其代码 - 似乎意味着返回AABB是否实际由用户设置。而不是它是否像IsInit
所暗示的那样处于初始状态/值(并误导我相信)。就个人而言,我更喜欢像IsValid
这样的名字来做这个测试。- 至于不变性实际上是什么,编辑本身似乎认识到有效的 AABB 不应该有大于
MaxX
的MinX
值,也不应该有大于MaxY
的MinY
。换句话说,它们永远不应该在有效的 AABB 中被逆转。MinX
应始终小于或等于MaxX
(最小和最大 Y 变量也是如此)。
使用 - 反向无穷大值可以:(a)更容易潜在地增长AABB以包裹其他AABB(编辑演示了我的意思,将代码行从14行减少到4行);(b)使其能够处理比使用
max()
和lowest()
值更广泛的有效AABB。 MinX
、MaxX
、MinY
、MaxY
成员变量是可公开访问的,这意味着IsInit
和不变本身只是建议性的,因为没有封装来保护不变量。
在注意到这些事情的更广泛背景下,NaN 是不合适的。不变性从来没有那么MinX != std::numeric_limits<double>::infinity()
.IsInit
(在该代码中实现)充其量是不完整的。在它被重命名为类似IsValid
的上下文中,逻辑上更一致的实现是:
bool IsValid() const
{
return !std::isnan(MinX) && !std::isnan(MinY) && MinX <= MaxX && MinY <= MaxY;
}
通过此实现,有效的 AABB 是一个OGREnvelope
,其值都是有效数字(没有一个是 NaN),并且其最小值必须分别小于或等于 X 和 Y 的最大值。
我不认为这是一个公认的答案,但希望它确实提供了一些好的信息。
我使用 Godbolt 工具对上述三个提议的实现进行了直接比较: https://godbolt.org/z/184Zb6
基本的观察结果是,在打开编译器优化的情况下,与std::numeric_limits<double>::infinity()
相比比std::isfinite()
更有效(更少的CPU指令和内存移动);也就是说,由于添加了逻辑否定操作,它只比!std::isinf()
更有效。
- 'val' Arduino 错误代码之前的预期'('
- C++算法标头中,为什么要使用 "!(val < *first)" ?
- C++ 一个lambda浅拷贝const Type&如果它被赋予一个命名捕获,如[copy=val](){}?
- 为什么 std::find( s.begin(), s.end(), val ) 比集合 s 的 s.find(val) 慢 1000 倍<int>?
- std::numeric_limits::infinity() 的逆数为零吗?
- APInt(unsigned numBits, uint64_t val, bool isSigned = false)
- 在模板元编程中使用"struct xxx<>::val"导致错误
- 为什么 std::numeric_limits<SomeStruct>::infinity() "work"?
- SWIG:包装 std::map<key 时编译器错误,val *>
- C++ std::map::find to C# 字典<键,val>
- val != std::numeric_limits:<double>:infinity() 或 !isinf(val) 或 isfinite(val)
- 在 for (int val :arr) 中,冒号是什么意思
- 使用 std::transform 将 std::vector<struct{key; val;}> 转换为 std::map<key, val>
- 为什么 numeric_limits<int>::max() 是 <int>> numeric_limits::infinity()?
- IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 Constant Val
- 为什么 std::map 没有 insert(key &k, val &v) 类型的插入函数
- C++ code for do Python struct.pack('>I',val)
- C++ 异常情况下的错误 C2228(".val"的左侧必须具有类/结构/联合)
- "isNaN(INFINITY)==false"是假的
- #pragma 注释(链接器,"/STACK:val"),哪个基础值可以?