如果一个`double`或`long double`适合'long long`,怎么检查呢?

时间:2014-09-05 18:03:03

标签: c++ visual-c++ c++11 type-conversion numeric-limits

初看起来似乎很简单,但我找不到任何有关此案例的好描述。

我有一个返回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())始终可以正常运行吗?

还是有另一种更好的检查范围的方法吗?

1 个答案:

答案 0 :(得分:0)

浮点和整数类型之间的转换在C ++标准的§4.9[conv.fpint]中指定:

  

1浮点类型的prvalue可以转换为prvalue   整数类型。转换截断;也就是说,分数   部分被丢弃。如果截断值,则行为未定义   无法在目标类型中表示。 [注意:如果是   目的地类型为bool,见4.12。 - 结束记录]

     

2整数类型或无范围枚举类型的prvalue可以   转换为浮点类型的prvalue。结果是   如果可能的话确切如果转换的值在范围内   可以表示的值,但无法表示该值   确切地说,它是下一个实现定义的选择   更低或更高的可表示价值。 [注意:精度损失   如果积分值不能完全表示为值,则会发生   浮动类型。 - 结束注释]如果要转换的值是   在可以表示的值范围之外,行为是   未定义。如果源类型为bool,则值为false   转换为零,值true转换为一。

典型的long long是64位,因此std::numeric_limits<long long>::max()是2 63 -1。这远小于LDBL_MAX的最小可能值,即1E+37。因此,我们安全地处于long double的可表示范围内。但是,如果long double是64位,则2 63 -1极不可能完全表示,并且您遇到了麻烦,因为标准说结果是“实现定义的”选择下一个较低或较高的可表示值“。换句话说,它可以是任何一种方式,并且你有问题。

如果编译器为转换选择了下一个较低的可表示值,那么一切都很好。即使calculatedValue == static_cast<long double>(std::numeric_limits<long long>::max()),它仍然在long long的可表示范围内,并且转换定义明确。

如果编译器为转换选择了下一个更高的可表示值(并且舍入到最近,使用的典型舍入,可能会这样,因为2 63 是完全可表示的),并且{ {1}},然后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)的2 n 在浮点中可以准确表示的事实。