我刚开始接触 C(K.N king 的 C 编程)时,我遇到了以下段落:
** 默认情况下,浮点常量存储为双精度数。其他 换句话说,当 C 编译器在程序中找到常量 57.0 时,它会安排 以与双变量相同的格式存储在内存中的数字。这 规则通常不会引起问题,因为双精度值会自动转换 必要时浮动。 **
假设我有以下陈述:
浮点数 x = 5.0;
浮点 y = 5.0f;
这个例子中的段落是什么意思?语句 1 和语句 2 在以位存储值方面有什么区别?
第一条语句中,5.0是不是先保存为double,然后作为float分配给x?
谢谢你。
作者的断言“默认情况下,浮点常量存储为双精度数”很可能出自 C 标准中的这一段,C 2018 6.4.4.2 4:
无后缀浮点常量的类型为
。如果后缀为字母double
或f
,则其类型为F
。如果后缀为字母float
或l
,则其类型为L
。long double
该段落清楚地表明,源代码中的浮点常量默认情况下(意味着它没有后缀)被解释为
double
。但作者关于价值被“存储”的说法并不准确。 C 标准告诉我们如何解释源代码,但它不要求存储常量。即使在 C 标准用来指定 C 语义的抽象模型中,在考虑优化之前,也只是指定将变量的值存储在变量的内存中,而不是存储常量的值。
此规则通常不会产生问题,因为必要时双精度值会自动转换为浮点数。
我想说的是,这种自动转换引起的问题很少见。说它“通常”不会引起问题可能会导致学生将其视为一般规则,而不是对何时可能发生问题保持谨慎。在为特定任务精心设计浮点常量的情况下,应使用后缀来确保常量具有完全所需的值。
在您的示例中,有 5 个,
float x = 5.0;
和 float y = 5.0f;
将在 x
中产生相同的值,因为 5 在 float
和 double
中都可以表示。但是,请考虑以下代码:
#include <stdio.h>
int main(void)
{
float x = 0x9.876548000000000000001p0;
float y = 0x9.876548000000000000001p0f;
printf("%a\n", x);
printf("%a\n", y);
}
在我的 C 实现中,
x
和 y
获得不同的值,并且打印:
0x1.30eca8p+3 0x1.30ecaap+3
原因是这样的:
在
float x = 0x9.876548000000000000001p0;
中,9.87654800000000000000116 转换为 double
。最后 1 位比双精度数可表示的位低几位,因此向下舍入,产生 9.87654816。然后将这个double
转换为float
存储在x
中。 4 的低位是最后一个适合 float
的位,因此 8 的第一位是第一个不适合的位。这是 float
中可表示的两个值 9.8765416 和 9.8765516 之间的中间值。如果平局,则规则是四舍五入到偶数低位,因此转换结果为 9.8765416,并存储在 x
中。 0x1.30eca8p+3
是该数字的另一种表示形式。
在
float x = 0x9.876548000000000000001p0;
中,9.87654800000000000000116 转换为 float
。同样,4 的低位适合,所以不适合的部分是 8000000000000001。由于 1,这超过了从 9.8765416 到 9.8765516 的一半,所以没有平局,并且是圆形的最接近的值会产生 9.8765516,这就是存储在 y
中的内容。打印它会产生 0x1.30ecaap+3
,相同值的另一种表示形式。