在进行转换测试时,我在C ++中遇到了一些奇怪的行为。
在线C ++参考指示std::numeric_limits<double>::max()
(在limit.h
中定义)的返回值应为DBL_MAX
(在float.h
中定义)。在我的测试中,当我打印出这些值时,两者确实完全相同。但是,当我将它们从double
投射到int
时,出现了奇怪的事情。
int32_t t1 = (int) std::numeric_limits<double>::max();
将t1
设置为INT_MIN
,但int32_t t2 = (int) DBL_MAX;
将t2
设置为INT_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
时,预期的行为应该是什么样的?
#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。
答案 0 :(得分:2)
尝试将大于INT_MAX
的浮点数转换为int
未定义的行为:
浮点类型的prvalue可以转换为整数类型的prvalue。转换截断;也就是说,丢弃小数部分。如果截断值不能,则行为未定义 以目的地类型表示。 (§4.9[conv.fpint],第1段)
因此,编译器可以为转换生成任何值(甚至可以执行其他操作,例如抛出异常)。不同的编译器可以做不同的事情。同一个编译器可以在不同的时间做不同的事情。
尝试理解为什么未定义行为的特定实例显示其显示的结果(除非您尝试对编译器进行反向工程,即使那时UB通常不是特别有趣)也没有实际意义。相反,您需要专注于避免未定义的行为。
例如,由于未定义浮点值到整数的任何超出范围的转换,您需要确保此类转换不涉及超出范围的值。与其他一些语言[注1]不同,C ++标准不提供易于识别的结果,可以进行测试,因此您需要在进行演员表之前进行测试。
请注意,DBL_MAX
是一个宏,其替换是一个字符串,表示最大可表示浮点数的近似值。另一方面,std::numeric_limits<double>::max()
是精确的最大可表示浮点数。
差异通常不应引人注意,但(如§5.20[expr.const]标准中的注释所示,第6段):
由于本国际标准对浮点运算的准确性没有任何限制,因此未指定在转换期间对浮点表达式的求值是否与对同一表达式的求值产生相同的结果(或相同的操作程序执行期间的相同值。
虽然std::numeric_limits<double>::max()
被声明为constexpr
,但转化为int
不是一个常量表达式(根据§5.20/ p2.5),因为它的行为是不确定的。