我只是想对 std::set<> 应用无穷大的加载因子,因为我想要有固定数量的存储桶。所以我使用了 1.0f / 0.0f 的负载因子,因为它比 numeric_limits<float>::infinity() 更短。MSVC 由于被零除而给出错误。clang-cl 和 clang++ 编译代码没有错误。那么哪个编译器是正确的呢?
根据 C++ 标准,第二个操作数为 0 的除法/取模始终是未定义的行为,无论是整型还是浮点类型:
7.6.5 乘法运算符(重点是我的)
(4)二元
/运算符产生商,二元运算%符产生第一个表达式除以第二个表达式的余数。如果or的第二个操作数为零,则行为未定义。/%对于整数操作数,/运算符产生代数商,并丢弃任何小数部分;如果商a/b可以用结果的类型表示,(a/b)*b + a%b则等于a;a/b否则,和的行为a%b都是未定义的。
因此,从纯粹的标准角度来看,除以 0 始终是未定义的行为。
鉴于这是未定义的行为,您不能依赖任何编译器来为此生成一致的结果 - 但尽管如此,当前发生的情况如下:
示例程序:godbolt
#include <limits>
int main() {
float f = 1.0f / 0.0f;
//float f = std::numeric_limits<float>::infinity();
if(f == std::numeric_limits<float>::infinity())
return 123;
else
return 345;
}
Run Code Online (Sandbox Code Playgroud)
1.0 / 0.0为无穷大,可以进行恒定折叠1.0 / 0.0将在运行时发生!)error C2124: divide or mod by zero所以有 3 种不同的结果,具体取决于您使用的编译器。
与 相比std::numeric_limits<float>::infinity(),这对所有 4 个都可以正常工作。
始终使用std::numeric_limits<float>::infinity(),因为除以零始终是未定义的行为。
如果你想缩短它,你可以轻松地做到这一点,例如:
template<std::floating_point T>
constexpr T Inf = std::numeric_limits<T>::infinity();
// usage:
float f = Inf<float>;
double d = Inf<double>;
Run Code Online (Sandbox Code Playgroud)
或者
constexpr float fInf = std::numeric_limits<float>::infinity();
constexpr double dInf = std::numeric_limits<double>::infinity();
// usage:
float f = fInf;
double d = dInf;
Run Code Online (Sandbox Code Playgroud)
或类似的东西。
| 归档时间: |
|
| 查看次数: |
489 次 |
| 最近记录: |