乍一看似乎很简单,但是我找不到关于此案例的任何好的描述。
我有一个返回64位值的方法。该值是使用long double
值在内部计算的。在方法结束时,我想检查long double
是否在long long
值的范围内,否则只需分配最大的long long
值。
我使用以下代码,它仅检查正范围,因为没有负结果:
long long calculateSomething()
{
long double calculatedValue = ...;
long long result;
if (calculatedValue > static_cast<long double>(std::numeric_limits<long long>::max())) {
result = std::numeric_limits<long long>::max();
} else {
result = static_cast<long long>(std::floor(calculatedValue));
}
return result;
}
现在我想知道,
long double
是否可以等于double
。转换static_cast<long double>(std::numeric_limits<long long>::max())
能否始终正常运行?还是有另一种更好的方法来检查范围?
最佳答案
在C ++标准的第4.9节[conv.fpint]中指定了浮点和整数类型之间的转换:
1浮点类型的prvalue可以转换为的prvalue
整数类型。转换被截断;即,分数
部分被丢弃。如果截断值,则行为未定义
无法以目标类型表示。 [注意:如果
目标类型为bool
,请参阅4.12。 —尾注]
2整数类型或无作用域枚举类型的prvalue可以
转换为浮点类型的prvalue。结果是
如果可能的话,精确。如果要转换的值在
可以表示但不能表示的值
确切地说,这是下一个实现的定义选择
较低或较高的可表示值。 [注意:精度损失
如果积分值不能精确表示为一个值,则会发生
的浮动类型。 —尾注]如果要转换的值是
超出可表示的值范围,则行为是
未定义。如果源类型为bool
,则值false
为
转换为零,值true
转换为1。
典型的long long
是64位,因此std::numeric_limits<long long>::max()
是263-1。这比LDBL_MAX
的最小可能值1E+37
小得多。因此,我们安全地处于long double
的可表示范围内。但是,如果long double
是64位,则263-1几乎不可能完全可表示,并且您会遇到麻烦,因为该标准说结果是“实现定义的下一个较低或较高的可表示值的选择” ”。换句话说,它可以以任何一种方式进行,并且那里存在问题。
如果编译器选择了下一个较低的可表示值进行转换,那么一切都很好。即使calculatedValue == static_cast<long double>(std::numeric_limits<long long>::max())
,它仍然在long long
的可表示范围内,并且转换是明确定义的。
如果编译器选择了下一个较高的可表示值进行转换(并且舍入为最接近值,即通常使用的舍入方法,由于263可以精确表示,因此很可能会这样),并且calculatedValue == static_cast<long double>(std::numeric_limits<long long>::max())
表示calculatedValue
实际上不在long long
的可表示范围,但是在您的代码中,您仍然尝试将其强制转换为long long
。因此,根据上面的第一段,您具有未定义的行为。哎哟。
最简单的解决方法是测试calculatedValue >= static_cast<long double>(std::numeric_limits<long long>::max())
而不是calculatedValue > static_cast<long double>(std::numeric_limits<long long>::max())
。万一编译器四舍五入,您将错过一种情况。另一个可能的解决方法是利用calculatedValue >= static_cast<long double>(std::numeric_limits<long long>::max() + 1ULL)
的测试,因为对于合理的n
来说2n在浮点数中可以精确表示。
关于c++ - 如果将“double”或“long double”放入“long long”中,该如何正确检查?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25691533/