浮点表示的问题

Issue with floating point representation

int x=25,i; 
float *p=(float *)&x;
printf("%f\n",*p);

我知道浮点数和 int 的位表示是不同的,但无论我存储什么值,答案总是 0.000000。根据浮点表示,它不应该是其他值吗?

您的代码有未定义的行为 -- 但它很可能会按照您的预期运行,只要类型 intfloat 的大小和对齐方式兼容。

使用“%f”格式打印 *p,您丢失了很多信息。

试试这个:

#include <stdio.h>
int main(void) {
        int x = 25; 
        float *p = (float*)&x;
        printf("%g\n", *p);
        return 0;
}

在我的系统上(也可能在你的系统上),它打印:

3.50325e-44

int25 的大部分高位为零。这些位可能与 float 类型的指数字段位于同一位置 - 导致数字非常小。

查找 IEEE 浮点表示以获取更多信息。字节顺序将成为一个问题。 (不要在实际代码中做这种事情,除非你有 非常 充分的理由。)

正如 rici 在评论中建议的那样,了解浮点表示的更好方法是从浮点值开始,将其转换为相同大小的无符号整数,并以十六进制显示整数值.例如:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void show(float f) {
    unsigned int rep;
    memcpy(&rep, &f, sizeof rep);
    printf("%g --> 0x%08x\n", f, rep);
}


int main(void) {
    if (sizeof (float) != sizeof (unsigned int)) {
        fprintf(stderr, "Size mismatch\n");
        exit(EXIT_FAILURE);
    }
    show(0.0);
    show(1.0);
    show(1.0/3.0);
    show(-12.34e5);
    return 0;
}

出于讨论的目的,我们假设 intfloat 都是 32 位宽。我们还将假设 IEEE-754 浮动。

浮点值表示为<em>sign</em> * β<sup><em>exp</em></sup> * <em>符号</em>。对于 32 位二进制浮点数,β2,指数 exp 范围从 -126127significandnormalized 二进制小数,因此在小数点之前有一个前导非零位。例如25的二进制整数表示为

11001<sub>2</sub>

25.0 的二进制浮点表示为:

1.1001<sub>2</sub> * 2<sup>4</sup> // normalized 

32 位浮点数的 IEEE-754 编码是

s eeeeeeee fffffffffffffffffffffff

其中 s 表示符号位,e 表示指数位,f 表示有效数(小数)位。指数使用 "excess 127" 表示法进行编码,这意味着指数值 127 (01111111<sub>2</sub>) 表示 0,而 1 (00000001<sub>2</sub>) 表示 -126254 (11111110<sub>2</sub>)表示127。有效数的前导位未明确存储,因此 25.0 将被编码为

0 10000011 10010000000000000000000 // exponent 131-127 = 4

但是,当您将 32 位 整数 25 位模式 映射到 32 位时会发生什么位浮点格式?我们得出以下结果:

0 00000000 00000000000000000011001

事实证明,在IEEE-754浮点数中,指数值00000000<sub>2</sub>被保留用于表示0.0次正规(或非正规)数字。次正规数是接近 0 的数,不能表示为 1。??? * 2<sup><em>exp</em></sup>,因为指数必须小于我们可以用 8 位编码的指数。这些数字被解释为 0。??? * 2<sup>-126</sup>,根据需要有尽可能多的前导 0

这样的话,加起来就是0.00000000000000000011001<sub>2</sub> * 2<sup>-126</sup>,这给了我们 3.50325 * 10<sup>-44</sup>

您必须映射大整数值(超过 2<sup>24</sup>)才能看到除 0 以外的任何值一堆小数位。而且,正如 Keith 所说,无论如何这都是未定义的行为。