“C 编译器默认将浮点常量保存为 double”的含义

问题描述 投票:0回答:1

我刚开始接触 C(K.N king 的 C 编程)时,我遇到了以下段落:

** 默认情况下,浮点常量存储为双精度数。其他 换句话说,当 C 编译器在程序中找到常量 57.0 时,它会安排 以与双变量相同的格式存储在内存中的数字。这 规则通常不会引起问题,因为双精度值会自动转换 必要时浮动。 **

假设我有以下陈述:

浮点数 x = 5.0;

浮点 y = 5.0f;

这个例子中的段落是什么意思?语句 1 和语句 2 在以位存储值方面有什么区别?

第一条语句中,5.0是不是先保存为double,然后作为float分配给x?

谢谢你。

c bit
1个回答
2
投票

作者的断言“默认情况下,浮点常量存储为双精度数”很可能出自 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
    ,相同值的另一种表示形式。

© www.soinside.com 2019 - 2024. All rights reserved.