3

我对隐式类型转换有点困惑。给定以下程序

   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”被类型转换为双精度?

4

4 回答 4

7

我的评论

这是很好定义的。中间表达式 forz将扩展为double,因此y * z将是一个double表达式。然后隐式缩小转换将其转换为float用于存储在res2. 同样的缩小适用于res1.

这反映在 C++11 标准的§5¶9 表达式 [expr]中。

许多期望算术或枚举类型的操作数的二元运算符会以类似的方式导致转换和产生结果类型。目的是产生一个通用类型,这也是结果的类型。这种模式称为通常的算术转换,其定义如下:

...

  • 否则,如果任一操作数为double,则另一个应转换为double
  • 否则,如果任一操作数为float,则另一个应转换为float

...

然而,这并不能确定等式是否成立。

话虽如此,res1不一定等同于res2——它高度依赖于环境的精度floatdouble环境。这两个文字甚至可能不相等——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]中所述,

  1. 类型的纯右值float可以转换为类型的纯右值double。值不变。
  2. 这种转换称为浮点提升

...和§4.8 浮点转换 [conv.double]

  1. 浮点类型的纯右值可以转换为另一种浮点类型的纯右值。如果源值可以在目标类型中精确表示,则转换的结果就是该精确表示。如果源值介于两个相邻的目标值之间,则转换的结果是实现定义的对这些值中的任何一个的选择。否则,行为未定义。

  2. 允许作为浮点提升的转换不包括在浮点转换集中。

这里的问题是我们有多种情况,我们的转换不是提升,而是缩小到潜在的低精度类型(doublefloat)。

本质上,任何时候转换doublefloat,都可能会丢失精度。

于 2012-09-12T21:06:55.717 回答
3

永远不应该比较浮点值是否相等。

于 2012-09-12T21:47:17.587 回答
1

不,这不能保证。x并且y不一定具有相同的值。确实,double在表达式x * zand中两者都被提升为y * z,但提升x为 double 的结果不必等于 的值y虽然x * z被评估为 a float,但表达式y * z提升z为 double ,并且乘法的结果不必相等,因此转换回更窄的类型可能会导致不同的值。

于 2012-09-12T21:07:27.607 回答
0

铸件应保持不变;但是,我已经看到处理器和操作系统以高精度影响实际数学。

但是,除此之外,使用static_cast是明确的:

float res2 = static_cast<float>(y * static_cast<double>(z));

这样,每个人都知道您的意思以及您的意思。

于 2012-09-12T21:06:48.593 回答