C中的隐式类型转换

时间:2011-11-09 23:14:50

标签: c floating-point type-conversion

我在维基百科(http://en.wikipedia.org/wiki/Type_conversion#Implicit_type_conversion)上偶然发现了以下示例。

#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
}

他们的解释是:“这种奇怪的行为是由于当与f_value进行比较时,i_value隐式转换为浮动;一个失去精度的转换,使得比较的值不同。”

这不是错的吗?如果i_value被转换为浮动,那么两者都会有相同的精度损失并且它们是相等的。 所以i_value必须加倍。

3 个答案:

答案 0 :(得分:7)

不,在等于运算符的情况下,“通常的算术转换”发生,它开始于:

  
      
  • 首先,如果任一操作数的相应实数类型为long double,则转换另一个操作数,而不更改类型   domain,对应的实际类型为long double的类型。
  •   
  • 否则,如果任一操作数的相应实数类型为double,则转换另一个操作数,而不更改类型   domain,对应的实际类型为double的类型。
  •   
  • 否则,如果任一操作数的相应实数类型为float,则转换另一个操作数,而不更改类型   domain,对应的实际类型为float的类型。
  •   

最后一种情况适用于此:i_value已转换为float

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

  

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

这就是发生的事情:转换后的i_value的类型仍为float,但在此表达式中,您的编译器正在利用此纬度并以比{{1}更高的精度表示它}。这是编译387兼容浮点时的典型编译器行为,因为编译器在浮点堆栈上保留临时值,浮点堆栈以80位扩展精度格式存储浮点数。

如果编译器为float,则可以通过提供gcc命令行选项来禁用此额外精度。

答案 1 :(得分:0)

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

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

答案 2 :(得分:-1)

我认为32位IEEE浮点可以容纳的最大整数值是1048576,小于上面的数字。因此,浮点值肯定不能完全保持16777217。

我不确定的部分是编译器如何在两种不同类型的数字(即float和int)之间进行比较。我可以想到三种不同的方式:

1)将两个值都转换为“float”(这应该使值相同,所以这可能不是编译器所做的)

2)将两个值都转换为“int”(这可能会也可能不会显示它们相同...转换为int经常被截断,所以如果浮点值是16777216.99999,那么转换为“int”会截断)

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