浮点数在内存中的存储方式
1、在使用switch(value)时,value的类型可以是浮点吗?
2、判断浮点数是否相等时,可以用float f1,f2; if(fi==f2){do something;}吗?
都不可以。
这涉及浮点数在内存中的存储方式。
一、float型在内存中占4字节,double占8字节。
单精度float在内存中的存储格式如下图(1位符号位S,8位指数位E,23位有效数字M):
双精度double在内存中的存储格式如下图(1位符号位S,11位指数位E,52位有效数字M):
本文主要说单精度浮点型float,double类似。
float型可以表现在以下形式:(参考:https://blog.csdn.net/aixiaodeshushu/article/details/81186397?tdsourcetag=s_pctim_aiomsg)
- (-1)^S * M * 2^E
- (-1)^S表示正负,S=1时为负,S=0时为正;
- M表示有效数字,1<=M<2;
- 2^(E-127)表示指数位。
如十进制8.125,将其转化成二进制形式:
- 对于整数部分8:
- 8/2 商:4 余:0
- 4/2 商:2 余:0
- 2/2 商:1 余:0
- 1/2 商:0 余:1
- 余数逆序,所以8的二进制为:1000
- 对于小数部分0.125,:
- 0.125*2 整数:0 小数:0.25
- 0.25*2 整数:0 小数:0.5
- 0.5*2 整数:1 小数:0
- 整数部分正序,所以0.125的二进制为:001
所以8.125的二进制形式为:1000.001,即1.000001 * 2^3。
因是正数,所以,S=0;
因M表示有效数字,1<=M<2,所以M=1.xxxxxxx,其中小数点前的1是固定的,可省略,则M只需要表示小数点后的数即可,故可用23位有效数字表示M部分,
则8.125的M部分为 000 0010 0000 0000 0000 0000;
而E部分8位是unsigned char,范围为0~255,但科学计数法的指数部分有正有负,故整体偏移127,用0~255来 表示-127~128,所以8.125的指数E部分,实际写的是E:3+127=130=1000 0010,
综上:8.125在内存中的存放bit为 0 1000 0010 000 0010 0000 0000 0000 0000 0000 ,即0x41020000
程序验证一下:
float f=8.125f;
unsigned char *p = (unsigned char *)&f;
printf("%x %x %x %x\n",p[0], p[1], p[2], p[3]);
结果:
0 0 2 41
小端存储模式,低字节在前,高字节在后。
二、float值的组成形式——加权
先看下面程序:(参考https://blog.csdn.net/ZYZMZM_/article/details/89008707)
#include <stdio.h> int main(void) { float sum = 0.0; unsigned char i; for(i=0; i<100; i++) { sum += 0.1; } printf("sum = %f\n", sum); return 0; }
运行结果为:
sum = 10.000002
将0.1加上100次,正常值应该为10.0,结果却是10.000002。
程序计算结果不对,是因为有些十进制小数无法转成二进制数。
二进制小数0.1,转化成十进制为2^(-1)=0.5
二进制小数0.01,转化成十进制为2^(-2)=0.25
二进制小数0.001,转化成十进制为2^(-3)=0.125
二进制小数0.0001,转化成十进制为2^(-4)=0.0625
二进制小数0.00001,转化成十进制为2^(-5)=0.0.03125
……
二进制小数0.000 0000 0000 0000 0000 0001,转化成十进制为2^(-23)
则内存中能存的M的值只能是A1*2^(-1) + A1*2^(-2) + A3*2^(-3) + …… + A23*2^(-23),其中Ai为1或0。有些小数是无法用这个式子表达出来的,如0.1
0.1的二进制形式为:、0.000 1100 1100 1100 1100 1100……(1100无限循环),在内存中只有23位bit存有效数字,只能为0.000 1100 1100 1100 1100 1100,是个近似值,就像十进制无法表示出1/3。
故对于有些小数,在内存中只能存近似的值,所以在本文开头的switch(value)和float f1,f2; if(fi==f2)都不可以。
若想判断两个浮点数是否相等,可用判断两个值直接的绝对误差小于一个很小的值,如if( fabs(f1 - f2) < 1e-6)。
三、float类型的范围
遇到点疑问,再补充