跳转到内容

为何`float value{4.0};`不被视为窄化转换?

将一种数据类型转换为另一种数据类型,如果这一操作过程可能导致数据丢失,那么这种转换操作就被叫做窄化转换(narrowing cast)。

例如,将浮点数3.14储存为int将导致.14丢失,只剩下3

#include <iostream>
int main() {
int value = 3.14;
std::cout << value;
return 0;
}

使用统一初始化(uniform initialization)可以避免窄化转换。如果发生了窄化转换,将会编译失败。

#include <iostream>
int main() {
int value {3.14};
std::cout << value;
return 0;
}
/*
error: narrowing conversion of '3.1400000000000001e+0' from 'double' to 'int'
*/

问题

根据C++标准,字面量3.14的类型是double(从上面一段代码的报错信息中也能得知)。那代码float value{4.0};不是将双精度浮点数窄化转换为单精度浮点数了吗?为什么能正常运行呢?


float value{4.0};不是窄化转换。

浮点数4.0可以被精确表示为一个float类型的值,不会发生精度丢失。

由于精度不会丢失,所以尽管float相对于double是一个“窄”类型,编译器仍然允许这种转换。

但是,下面这段代码(应当)是会编译出错的:

#include <iostream>
int main() {
double valueDouble{3.14};
float valueFloat {valueDouble};
std::cout << valueFloat;
return 0;
}

编译结果:

g++给出一个warning,但编译成功:

warning: narrowing conversion of 'valueDouble' from 'double' to 'float' [-Wnarrowing]

MSVC编译出错:

error C2397: 从“double”转换到“float”需要收缩转换

我的理解是,valueDouble的值是3.1400000000000001e+0valueFloat的值是3.1400001e+0f,所以从valueDouble转换到valueFloat发生了精度下降,所以是窄化转换,所以编译出错;而double类型的3.14转换到float类型后,精度并没有下降,所以不是窄化转换。