C语言中的浮点数存储:深入探讨

简介: C语言中的浮点数存储:深入探讨

案例引入

请看下面一段代码并思考结果:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  int n = 9;
  float* pFloat = (float*)&n;
  printf("n的值为:%d\n", n);
  printf("*pFloat的值为:%f\n", *pFloat);
  *pFloat = 9.0;
  printf("num的值为:%d\n", n);
  printf("*pFloat的值为:%f\n", *pFloat);
  return 0;
} 

结果如下:

引言

在C语言中,浮点数用于表示实数,尤其是那些带有小数点的数值。浮点数的存储机制复杂,但它是计算机科学中的重要组成部分。本文将详细介绍C语言中的浮点数在内存中的存储方式,基于IEEE 754标准,并涵盖单精度和双精度浮点数的内部表示。

1. 浮点数的基本概念

浮点数的表示由三个主要部分组成:

  • 符号位(Sign Bit):表示数值的正负。0表示正数,1表示负数。
  • 指数位(Exponent):确定浮点数的范围或数量级。通过调整指数,浮点数可以表示非常大或非常小的值。
  • 尾数(Mantissa):也称为有效数字,表示浮点数的精确值。尾数在计算中决定了浮点数的精度。

2. IEEE 754标准

IEEE 754标准是浮点数存储的国际标准,定义了浮点数的表示和运算规则。

根据国际标准IEEE(电⽓和电⼦⼯程协会) 754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

(−1)^S 表⽰符号位,当S=0,V为正数;当S=1,V为负数

 M 表⽰有效数字,M是⼤于等于1,⼩于2的

2^E 表⽰指数位

浮点数的存储,实际上存储的就是S、M、E相关的值。

根据IEEE 754标准,浮点数分为单精度(32位)和双精度(64位)两种格式。

2.1 单精度浮点数(32位)

单精度浮点数使用32位存储,其中包括:

  • 符号位:1位
  • 指数位:8位
  • 尾数:23位(实际尾数有24位,因为有一个隐含的1位)

单精度浮点数的存储格式如下:

对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M。

存储示例:

假设我们要存储浮点数 -5.75。首先将 -5.75 转换为二进制格式,并按照IEEE 754标准进行编码。

表示步骤:

符号位:-5.75 是负数,所以符号位是 1。

绝对值转换为二进制:5.75 的二进制表示是 101.11。

标准化:将 101.11 转换为标准化形式 1.0111 × 2^2。

阶码:IEEE 754 使用偏移量为 127 的阶码。在这里,实际阶码是 2,所以存储的阶码是 2 + 127 = 129,其二进制形式是 10000001。

尾数:标准化形式的尾数部分是 0111,补充至 23 位得到 01110000000000000000000。

因此,-5.75的32位表示为:

1 10000001 01110000000000000000000

2.2 双精度浮点数(64位)

双精度浮点数使用64位存储,其中包括:

  • 符号位:1位
  • 指数位:11位
  • 尾数:52位(实际尾数有53位,因为有一个隐含的1位)

双精度浮点数的存储格式如下:

对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M 。

存储示例: 对于浮点数 -5.75,转换步骤如下:

表示步骤:

符号位:-5.75 是负数,所以符号位是 1。

绝对值转换为二进制:5.75 的二进制表示是 101.11。

标准化:将 101.11 转换为标准化形式 1.0111 × 2^2。

阶码:IEEE 754 使用偏移量为 1023 的阶码。在这里,实际阶码是 2,所以存储的阶码是 2 + 1023 = 1025,其二进制形式是 10000000001。

尾数:标准化形式的尾数部分是 0111,补充至 52 位得到 0111000000000000000000000000000000000000000000000000。

最终,64 位双精度浮点数的表示为:

因此,-5.75的64位表示为:

1 10000000001 0111000000000000000000000000000000000000000000000000

3. 内存中的浮点数存储

浮点数在内存中的实际存储取决于系统的字节序(大端或小端)。例如,在大端系统中,较低位字节存储在较高内存地址。以下是如何查看浮点数在内存中的实际存储示例:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 将浮点数以大端格式打印
void print_memory_representation(void* p, size_t size) {
    unsigned char* byte = (unsigned char*)p;
 
    // 大端打印需要从高位字节开始
    for (size_t i = size; i > 0; i--) {
        printf("%02X ", byte[i - 1]);
    }
    printf("\n");
}
int main() {
    float f = -5.75;
    double d = -5.75;
    printf("Float value: %f\n", f);
    printf("Double value: %lf\n", d);
    printf("Float类型内存表示(大端):\n");
    print_memory_representation(&f, sizeof(f));
    printf("Double类型内存表示(大端):\n");
    print_memory_representation(&d, sizeof(d));
    return 0;
}

在此代码中,print_memory_representation 函数将浮点数在内存中的每个字节打印为十六进制格式。运行代码可以观察到浮点数在内存中的具体存储方式。

4. 精度问题与误差

浮点数表示有限精度的实数,可能导致精度问题。例如,0.1 不能精确地用二进制表示,这会在浮点运算中引入微小的误差。因此,比较浮点数时,通常要考虑误差范围,使用一个接近的值进行比较而非直接等于比较。

题⽬解析

下⾯,让我们分析一开始的案例。

先看第1环节,为什么 9 还原成浮点数,就成了 0.000000 ? 9以整型的形式存储在内存中,得到如下⼆进制序列:

1 0000 0000 0000 0000 0000 0000 0000 1001

⾸先,将 9 的⼆进制序列按照浮点数的形式拆分,得到第⼀位符号位s=0,后⾯8位的指数

E=00000000 , 最后23位的有效数字M=000 0000 0000 0000 0000 1001。 由于指数E全为0,所以符合E为全0的情况。因此,浮点数V就写成:

V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)

显然,V是⼀个很⼩的接近于0的正数,所以⽤⼗进制⼩数表⽰就是0.000000

再看第2环节,浮点数9.0,为什么整数打印是 1091567616

⾸先,浮点数9.0 等于⼆进制的1001.0,即换算成科学计数法是:1.001×2^3

所以: 那么,第⼀位的符号位S=0,有效数字M等于001后⾯再加20个0,凑满23位,指数E等于3+127=130, 即10000010

所以,写成⼆进制形式,应该是S+E+M,即 1 0 10000010 001 0000 0000 0000 0000 0000

这个32位的⼆进制数,被当做整数来解析的时候,就是整数在内存中的补码,原码正是

1091567616

总结

C语言中的浮点数存储是一个复杂而重要的主题。它涉及到符号位、指数位和尾数的详细布局,以及IEEE 754标准的规范。通过理解浮点数的存储机制,你可以更好地处理浮点数的计算和调试问题。希望本文对你理解C语言中的浮点数存储有所帮助。


相关文章
|
5月前
|
存储 程序员 C语言
深入探讨C语言中的字符型数据类型及其应用
深入探讨C语言中的字符型数据类型及其应用
113 0
|
5月前
|
存储 小程序 编译器
C语言中数据类型的存储
C语言中数据类型的存储
|
11月前
|
存储 C语言 C++
C语言-数据类型的本质
C语言-数据类型的本质
72 0
C语言-数据类型的本质
|
存储 C语言
C语言进阶:浮点型数据的存储
C语言进阶:浮点型数据的存储
150 0
|
5月前
|
存储 编译器 C语言
C语言基础知识:数据在内存中的存储解析(整数,浮点数)
C语言基础知识:数据在内存中的存储解析(整数,浮点数)
|
5月前
|
存储 小程序 编译器
C语言数据存储 — 整型篇
C语言数据存储 — 整型篇
41 0
|
11月前
|
存储 C语言
C语言之浮点数_数据存储篇(2)
C语言之浮点数_数据存储篇(2)
67 0
|
11月前
|
存储 小程序 编译器
C语言之整数_数据存储篇(1)
C语言之整数_数据存储篇(1)
69 0
|
存储 机器学习/深度学习 编译器
【C语言】你知道浮点数是怎么存储的吗?(上)
【C语言】你知道浮点数是怎么存储的吗?
104 0
【C语言】你知道浮点数是怎么存储的吗?(上)
|
存储 编译器 C语言
【C语言进阶】整型在内存中的存储(上)
【C语言进阶】整型在内存中的存储
113 1