为什么语句 "f == (float)(double)f;" 是错误的?

8
我最近听了一堂系统编程的讲座,我的教授告诉我f == (float) (double) f是错误的,但我不理解为什么错了。
我知道在将double类型转换为float类型时会失去数据,但我认为只有当double类型中存储的数字无法用float类型表示时才会发生数据丢失。
难道它不应该像x == (int)(double)x;那样正确吗?
下面是我理解这个问题的方式的图片:

enter image description here


非常抱歉我的问题没有表达清楚。
问题不在于声明,而是关于double类型的转换。 希望你不要因为我的错误而浪费宝贵的时间。

4
你的教授为什么认为这是错误的? - Daniel Pryden
7
我看到的唯一问题是你用变量本身来进行初始化。 - Eugene Sh.
3
你这句话的目的是什么? - Sander De Dycker
@SanderDeDycker 没什么,这只是我教授给学生展示的一个简单的关于转换的小测验。 - I_like_rainy_days
据我所知,从浮点数到双精度浮点数的转换是无损的。 - bolov
显示剩余4条评论
3个回答

11
假设IEC 60559f == (float)(double) f的结果取决于f的类型。
进一步假设f是一个float,那么这个表达式没有问题-它将计算为true(除非f持有NaN,在这种情况下,该表达式将计算为false)。
另一方面,x == (int)(double)x(假设x是一个int)可能存在问题,因为双精度IEC 60559浮点值仅具有53位有效数字1,如果int使用超过53位的值,则无法表示所有可能的值,如果您的平台上的值使用31位,则会计算为true,并且可能会计算为false,如果您的平台上的int使用63位(取决于值)。
相关的C标准引用(6.3.1.4和6.3.1.5):
当将整数类型的值转换为实浮点类型时,如果要转换的值可以在新类型中准确表示,则不会改变该值。

 

当一个实数浮点类型的有限值被转换为除了_Bool以外的整数类型时,小数部分会被舍去(即向零舍入)。如果整数部分的值无法被整数类型表示,则行为未定义。

 

当将实浮点数的值转换为另一种实浮点数类型时,如果被转换的值可以在新类型中精确表示,则其保持不变。

 


1 一个双精度IEC 60559浮点值由1位符号、11位指数和53位有效数字(其中1位是隐含的且不存储)组成,共计64个(存储的)位。


谢谢您的回答,但我再次发现了我的错误并编辑了问题。 非常抱歉。他说double类型可以表示int类型表示的每个数字,您的意思是他教错了吗? - I_like_rainy_days
@VeomchanKim:我已相应地编辑了我的答案——要点是一样的。 - Sander De Dycker
1
@VeomchanKim:C标准允许int类型具有比double类型精确表示的范围更大的范围。但在今天的大多数平台上,这不是一个问题。因此,严格来说,你的教授所说的那句话(“double类型可以表达int类型表达的每个数字”)是错误的,但实际上(或者当谈论特定环境时),这个说法是可以接受的。 - Sander De Dycker
非常感谢您的评论,我非常欣赏它们。 - I_like_rainy_days
1
细节:典型的双精度浮点数可以准确地表示所有带符号和53位精度的int54_t,而double具有带符号和52个显式编码加1个隐含精度位。 - chux - Reinstate Monica
显示剩余3条评论

1

如果按照标题中所提出的问题字面意思来看,

为什么语句“f == (float)(double)f;”是错误的?

这个语句的“错误”与浮点数值的表示方式无关,而是因为它在任何编译器中都可以轻松优化掉,因此你完全可以节省用于存储它的电子。它与以下语句完全等效:

1;

或者,如果你愿意,可以看一下这个陈述(来自原始问题)。
x == (int)(double)x;

(无论类型intfloatdouble的可用精度如何,其效果与标题中的完全相同,也就是根本没有)。

编程有点关注精度,您应该注意一个语句和一个表达式之间的区别。一个表达式有一个值,可能为真或假或其他值,但当您添加分号(如在问题中所示)时,它变成了一个语句(正如您在问题中所称),如果没有副作用,编译器可以自由地将其丢弃。


NaNs怎么办? - Aki Suihkonen
@AkiSuihkonen NaN将永远不会与自己或其他任何东西相等,但没有副作用的语句0;仍然与语句1;相同。 - mlp

0

NaN在浮点数 => 双精度浮点数 => 浮点数的转换中保留,但它们本身不相等。

#include <math.h>
#include <stdio.h>

int main(void) {
    float f = HUGE_VALF;
    printf("%d\n", f == (float)(double) f);
    f = NAN;
    printf("%d\n", f == (float)(double) f);
    printf("%d\n", f == f);
}

打印

1
0 
0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接