将 DBL_MAX 转换为 int 的结果不同于 std::<double>numeric_limits::max() 到 int

results from convert DBL_MAX to int is different from std::numeric_limits<double>::max() to int

本文关键字:int gt double numeric limits max 转换 MAX 结果 DBL std      更新时间:2023-10-16

在做转换测试时,我在c++中遇到一些奇怪的行为。

<<h2>上下文/h2>

在线c++参考表明,std::numeric_limits<double>::max()(定义在limit.h中)的返回值应该是DBL_MAX(定义在float.h中)。在我的测试中,当我打印出这些值时,两者确实完全相同。然而,当我把它们从double转换到int时,奇怪的事情出现了。

相同的输入,不同的结果?

int32_t t1 = (int) std::numeric_limits<double>::max();设置t1INT_MIN, int32_t t2 = (int) DBL_MAX;设置t2INT_MAX。当使用static_cast<int>进行强制转换时也是如此。

相同的输入,相同的结果在类似的情况下

但是,如果我定义一个函数
int32_t doubleToInt(double dvalue) {
    return (int) value;
}

doubleToInt(std::numeric_limits<double>::max())doubleToInt(DBL_MAX)都返回INT_MIN

为了帮助理解,我用Java实现了一个类似的程序。在这里,所有类型转换都返回INT_MAX的值,无论是否在函数中。

谁能指出为什么在c++中结果在某些情况下是INT_MIN,而在其他情况下是INT_MAX ?在c++中,当将DBL_MAX转换为int时,预期的行为应该是什么?

c++示例代码

#include <iostream>
#include <limits>
#include <float.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
template <typename T, typename D> D cast(T a, D b) { return (D) a;}
int main()
{
    int32_t t1 = 9;
    std::cout << std::numeric_limits<double>::max() << std::endl;
    std::cout << DBL_MAX << std::endl;
    std::cout << (int32_t) std::numeric_limits<double>::max() << std::endl;
    std::cout << (int32_t) DBL_MAX << std::endl;
    std::cout << cast(std::numeric_limits<double>::max(), t1) << std::endl;
    std::cout << cast(DBL_MAX, t1) << std::endl;
    return 0;
}

为了完整:我使用cygwin gcc和java 8

尝试将大于INT_MAX的浮点数转换为int未定义的行为:

浮点型的右值可以转换为整型的右值。转换截断;也就是说,小数部分被丢弃。如果截断的值不能为,则行为未定义以目标类型表示。(§4.9, para;1)

因此编译器可以为转换生成任何值(甚至可以做其他事情,例如抛出异常)。不同的编译器可以做不同的事情。同一个编译器可以在不同的时间做不同的事情。

试图理解为什么未定义行为的特定实例会显示它所显示的结果是没有真正意义的(除非您试图对编译器进行反向工程,即使这样UB通常也不是特别有趣)。相反,您需要专注于避免未定义的行为。

例如,由于任何浮点值到整数的范围外强制转换都是未定义的,因此您需要确保此类强制转换不涉及范围外值。与其他一些语言不同[注1],c++标准不提供易于识别的可测试的结果,因此您需要在进行强制转换之前进行测试。


注意DBL_MAX是一个宏,它的替换是一个表示最大可表示浮点数近似值的字符串。另一方面,std::numeric_limits<double>::max()是精确的最大可表示浮点数。

差异通常不应该是明显的,但是(正如标准& section;5.20 [expr]中的注释所指出的那样)。Const],第6段):

由于本国际标准对浮点运算的精度没有限制,因此在翻译过程中对浮点表达式求值是否与在程序执行过程中对相同表达式(或对相同值进行相同操作)求值产生相同的结果是未指定的。

虽然std::numeric_limits<double>::max()被声明为constexpr,但是转换为int不是常量表达式(根据& section;5.20/p2.5),因为它的行为是未定义的。


指出

    例如,在Java中,转换定义得很好。有关详细信息,请参阅Java语言规范。