我在维基百科(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必须加倍。
答案 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)。