乍一看似乎很简单,但是我找不到关于此案例的任何好的描述。

我有一个返回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/

10-13 05:02
查看更多