1

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

我有一个返回 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())始终正常工作吗?

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

4

1 回答 1

0

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

1 浮点类型的纯右值可以转换为整数类型的纯右值。转换截断;也就是说,小数部分被丢弃。如果截断的值不能在目标类型中表示,则行为未定义。[:如果目的地类型是bool,见4.12。——<em>尾注]

2 整数类型或无作用域枚举类型的纯右值可以转换为浮点类型的纯右值。如果可能,结果是准确的。如果要转换的值在可以表示的值范围内但不能准确表示,则它是下一个较低或较高可表示值的实现定义选择。[注意:如果整数值不能精确地表示为浮点类型的值,则会发生精度损失。—<em>end note ] 如果要转换的值超出可表示的值范围,则行为未定义。如果源类型为bool,则将值false转换为 0,并将值true转换为 1。

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

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

如果编译器为转换选择了下一个更高的可表示值(并且舍入到最接近,使用的典型舍入,可能会采用这种方式,因为 2 63是完全可表示的),并且calculatedValue == static_cast<long double>(std::numeric_limits<long long>::max()), 那么calculatedValue实际上在 a 的可表示范围之外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),利用合理s 的 2 nn可以精确表示为浮点的事实。

于 2014-09-08T04:06:29.193 回答