[英]C++ : Implicit type conversion
我对隐式类型转换感到有点困惑。 鉴于以下计划
float x = 4.23423451;
double y = 4.23423451;
float z = 101.9876;
float res1 = x * z;
float res2 = y * z;
std::cout << "res1 & res2 " << res1 << " & " << res2 << std::endl;
std::cout << "equality " << (res1 == res2) << std::endl;
输出是
res1 & res2 431.839 & 431.839
equality 1
我的问题是“对于x,y和z(x = y)的任何值以及任何编译器,等式是否总是正确的?”
在
res2 = y * z;
变量“y”是否会被类型化为浮点数或变量“z”是否被类型转换为double?
看我的评论 。
这是明确的定义。
z
的中间表达式将经历加宽为double
,因此y * z
将是double
表达式。 然后,隐式缩小转换将其转换为float
以存储在res2
。 同样的缩小适用于res1
。
这由C ++ 11标准的§5¶9Expressions[expr]反映出来。
许多期望算术或枚举类型的操作数的二元运算符会以类似的方式引起转换并产生结果类型。 目的是产生一个通用类型,它也是结果的类型。 这种模式称为通常的算术转换 ,定义如下:
...
- 否则,如果任一操作数为
double
,则另一个操作数应转换为double
。- 否则,如果任一操作数是
float
,则另一个操作数应转换为float
。...
然而,这并不能确保平等会成立。
话虽这么说,
res1
不一定等同于res2
- 它高度依赖于float
的精度和环境中的double
。 这两个文字甚至可能不相等 -4.23423451f
甚至不需要等同于4.23423451
。 您无法确定static_cast<double>(static_cast<float>(4.23423451))
是否等于4.23423451
。
参见§5.17¶3赋值和复合赋值运算符[expr.ass] 。
如果左操作数不是类类型,则表达式被隐式转换(第4节)到左操作数的cv-unqualified类型。
§4标准转换[转]声明如下:
标准转化是具有内置含义的隐式转化。 第4条列举了全套此类转换。 标准转换序列是一系列标准转换,顺序如下:
...
- 来自以下集合的零或一次转换:整数促销,浮点促销,积分转换,浮点转换,浮点积分转换,指针转换,成员转换指针和布尔转换。
如§4.6浮点促销[conv.fpprom]所述 ,
float
类型的prvalue可以转换为double
类型的prvalue。 该值保持不变。- 此转换称为浮点提升 。
...和§4.8浮点转换[conv.double] ,
浮点类型的prvalue可以转换为另一个浮点类型的prvalue。 如果源值可以在目标类型中准确表示,则转换的结果就是精确表示。 如果源值在两个相邻目标值之间,则转换结果是这些值中任一个的实现定义选择。 否则,行为未定义。
浮点促销中允许的转化从浮点转化集中排除。
这里的问题是我们有多种情况,我们的转换不是促销 ,而是缩小到可能更低精度的类型( double
to float
)。
基本上,任何时候你将double
转换为float
,你可能会失去精度。
您永远不应该将浮点值与相等性进行比较。
不,这不能保证。 x
和y
不一定具有相同的值。 确实,在表达式 而x * z
和y * z
中两者都被提升为double
,但是将x
提升为double的结果不必等于y
的值。x * z
是作为评价float
,所述表达y * z
促进z
加倍,并且乘法结果不必是相等的,使得转化回较窄类型可能会导致不同的值。
铸件应保持不变; 但是,我看到处理器和操作系统以高精度影响实际数学。
但是,除此之外,使用static_cast是明确的:
float res2 = static_cast<float>(y * static_cast<double>(z));
通过这种方式,每个人都知道你的意思,并且你的意思是铸造东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.