见我的评论。
这是很好定义的。中间表达式 forz
将扩展为double
,因此y * z
将是一个double
表达式。然后隐式缩小转换将其转换为float
用于存储在res2
. 同样的缩小适用于res1
.
这反映在 C++11 标准的§5¶9 表达式 [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 非限定类型。
§4 标准转换 [conv]状态如下:
标准转换是具有内置含义的隐式转换。第 4 条列举了所有此类转换。标准转换序列是按以下顺序的标准转换序列:
...
- 来自以下集合的零个或一个转换:整数提升、浮点提升、整数转换、浮点转换、浮点整数转换、指针转换、指向成员转换的指针和布尔转换。
如§4.6 浮点提升 [conv.fpprom]中所述,
- 类型的纯右值
float
可以转换为类型的纯右值double
。值不变。
- 这种转换称为浮点提升。
...和§4.8 浮点转换 [conv.double],
浮点类型的纯右值可以转换为另一种浮点类型的纯右值。如果源值可以在目标类型中精确表示,则转换的结果就是该精确表示。如果源值介于两个相邻的目标值之间,则转换的结果是实现定义的对这些值中的任何一个的选择。否则,行为未定义。
允许作为浮点提升的转换不包括在浮点转换集中。
这里的问题是我们有多种情况,我们的转换不是提升,而是缩小到潜在的低精度类型(double
到float
)。
本质上,任何时候转换double
为float
,都可能会丢失精度。