浮点数在内存中的存储方式

目录

1 常见的浮点数

2 一个小例子

3 浮点数存储规则

4 解释前面的例子

学完整数在内存中的存储,大家一定很好奇浮点数在内存中是如何存储的,本文将介绍浮点数在内存中是如何存储的,并举例说明其存储规则。

1 常见的浮点数

5.00

3e10

3.1415926

浮点数类型有:float, double, long double

浮点数表示的范围:C语言中由 float.h 定义

2 一个小例子

int main()
{
    int a = 15;
    float* pa = (float*)&a;
​
    printf("a = %d\n", a);
    printf("*pa = %f\n", *pa);
​
    *pa = 15.25;
    printf("a = %d\n", a);
    printf("*pa = %f\n", *pa);
​
    return 0;
}

输出的结果如下

下面将详细介绍浮点数存储规则,然后分析上述代码

3 浮点数存储规则

根据相关国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数 V 可以表示成下面的形式:

(-1)^S × M × 2^E

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

M表示有效数字,大于等于1,小于2

2^E表示指数位

什么意思呢,举例说明,一个十进制数字15.25,其中的15转换成二进制数是

00000000 00000000 00000000 00001111

0.25转换成二进制数是

01000000 ...

第一位的权重为2^(-1),第二位的权重为2^(-2),0.25=2^(-2),所以写成二进制是如上的二进制数

两个数合起来就是1111.01,相当于(-1)^0 × 1.11101 × 2^3,那么 S = 0,M = 1.11101,E = 3

IEEE 754规定:

对于32位浮点数,最高1位是存放符号位S,紧接着的8位是指数E,剩下的23位是有效数字M

对于64位浮点数,最高1位是存放符号位S,紧接着的11位是指数E,剩下的52位是有效数字M

IEEE 754对有效数字M和指数E,还有一些特别规定。

对于有效数字M

因为数据是以二进制的形式存放在内存中的,所以M的每一位非0即1

若首位为0,则小数点向后移动k位,指数E = k,直到首位为1,所以才会有1≤M<2

此时,M的首位必为1,那么就不用再额外花费空间存储这个1了,只用保存小数点后面的数字

将第一位的1舍去以后,单精度浮点数可以保存24位有效数字

指数E的存储

首先,E在内存里是一个无符号的整数

如果E为8位,则取值范围为0~255;如果E为11位,则取值范围为0~2047

但是实际上科学计数法的E是可以出现负数的,比如0.125,它等于

0.001

(-1)^0 × 1.0 × 2^(-3)

所以 IEEE 754 规定

存入内存时E的真实值必须再加上一个中间数

对于8位的E,这个中间数是127

对于11位的E,这个中间数是1023

因此,若使用 float 存放数据,则科学计数法中E为-127~128时才可以正常存储

所以E = -3,保存成32位浮点数时,需保存 -3 + 127 = 124,即1111100

指数E的读取还可分成三种情况

  • E不全为0或1

    这时,指数E的真实值等于内存中的值转换成十进制,然后减去中间值127(或1023),得到真实值,再将有效数字M前面加上第一位的1

  • E全为0

    这时,根据尾数M的不同可以分为两种情况:

    有效数字M为0:表示浮点0

    有效数字M不为0:那么E = 1-127 = -126(或者1-1023)有效数字M不再加上第一位的1,而是还原为形如0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。

  • E全为1

    有效数字M为0:根据符号位S表示±无穷大

    有效数字M不为0:表示NaN(Not a Number)

4 解释前面的例子

int main()
{
    int a = 15;
    float* pa = (float*)&a;
​
    printf("a = %d\n", a);
    printf("*pa = %f\n", *pa);
    
    *pa = 15.25;
    printf("a = %d\n", a);
    printf("*pa = %f\n", *pa);
    
    return 0;
​
}

现在,让我们回到一开始的问题

15的补码是00000000 00000000 00000000 00001111

站在浮点数的角度,S=0,E= -126,M= 0000000 00000000 00001111

这是 一个非常小的数字,保留6位小数的话*pa = 0.000000

*pa = 15.25;

而上面这行代码是把浮点数15.25赋给了*pa

但 a 的类型是 int,它会站在整型的角度计算15.25

15.25 -> 1111.01 = (-1)^0 × 1.11101 × 2^3 -> 0 10000010 11101000 00000000 0000000

直接将上面的二进制数换算成十进制数就是 a 的值

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕瞿三谲丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值