2011-11-09 89 views
7

我在维基百科(http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion)上偶然发现了下面的例子。C中的隐式类型转换

#include <stdio.h> 

int main() 
{ 
    int i_value = 16777217; 
    float f_value = 16777217.0; 
    printf("The integer is: %i\n", i_value); // 16777217 
    printf("The float is: %f\n", f_value); // 16777216.000000 
    printf("Their equality: %i\n", i_value == f_value); // result is 0 
} 

他们的解释:“这奇数行为是由i_value的隐式转换引起的浮起当它与f_value比较;被比较,其损失精度,使得值的铸造不同”

这不正确吗?如果i_value被转换为浮点数,那么两者在精度上会有相同的损失,并且它们会相等。 所以i_value必须转换成双倍。

+0

使用g ++(GCC 4.6.2)我得到'1'的等式。 –

+0

@Kerrek:和我。在VS中,我得到0. –

+0

@OliCharlesworth:我很好奇将字面值改为f或将类型改为double值 - 在所有情况下我都得到了'1' ... –

回答

7

否,在平等操作者的情况下,“通常的算术转换”发生,这开始:

  • 首先,如果对应的实数型有一个操作数的是long double,所述其他操作数将被转换,而不会将类型为 的域更改为对应的实际类型为long double的类型。否则,如果任一操作数的对应实型为double,则另一个操作数将被转换,而不会更改类型为 域的类型,其类型对应的实型为double
  • 否则,如果对应的真实类型有一个操作数的是float,则另一个操作数转换,而不 型结构域的变化,以一类型,其相应的实际类型是float

最后一种情况适用于这里:i_value转化为float

,你可以从比较看到一个奇怪的结果,尽管这样做的原因,是因为这个警告通常的算术转换:

浮动操作数的值浮动的结果,并表达式可以以比该类型所需的 更高的精度和范围表示;类型不会因此而改变。

这是正在发生的事情:转换后的i_value的类型仍然是float,但在此表达你的编译器正在利用这个纬度和代表它在更高的精度比float。编译387兼容浮点时,这是典型的编译器行为,因为编译器会在浮点堆栈上留下临时值,浮点堆栈以80位扩展精度格式存储浮点数。

如果您的编译器为gcc,则可以通过给出-ffloat-store命令行选项来禁用此附加精度。

+0

在x64上,gcc使用显式cvtsi2ssl指令将整数转换为浮点型。然而,在x86上,这正是发生的事情,实际上更高的精度甚至超过了两倍。 –

+0

@ konrad.kruczynski:是的,你可以通过提供'-mfpmath = sse'选项(这也需要'-msse'或者一个暗示这个选项的选项)来在x86上得到相同的结果。 – caf

-1

我相信32位IEEE浮点可以容纳的最大整数值是1048576,它比上面的数字要小。所以,浮点数值不会完全对应16777217.

我不确定的部分是编译器如何比较两种不同类型的数字(即float和int) 。我能想到的三种不同的方式,这可能做到:

1)转换两个值“浮动”(这应该使这些值是相同的,所以这可能是不是编译器做什么)

2)将这两个值转换为“int”(这可能会或可能不会显示它们相同...转换为经常截断的int,因此如果浮点值为16777216.99999,则转换为“int”将截断)

3)将这两个值转换为“double”。我的猜测是这是编译器会做的。如果这是编译器所做的,那么这两个值肯定会不同。 double可以精确地保存16777217,它也可以精确地表示16777217.0转换为的浮点值(不完全是16777217.0)。

+3

1048576是2^20,所以这是不正确的。 –

0

这里有一些很好的答案。您必须非常小心地在各种整数和各种浮点表示之间进行转换。

我通常不会测试相等的浮点数,特别是如果其中一个来自整数类型的隐式或显式转换。我在一个充满几何计算的应用程序上工作。尽可能地,我们使用规范化整数(通过强制输入数据中我们将接受的最大精度)。对于必须使用浮点的情况,如果需要比较,我们将对差值应用绝对值。