浮点数的类型
3.1415926,1e13等(XeY为科学计数法X*10^Y的表示形式)
浮点数包括float、double、long double 类型。
浮点数的范围在头文件float.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;
}
很明显,将整型以浮点型的形式打印,将浮点型以整型的形式打印,结果天差地别,我们很容易推断整型与浮点型在内存中的存储方式不同。
规则
根据国际标准
IEEE
(电气和电子工程协会)
754
,任意一个二进制浮点数
V
可以表示成以下形式
其中(-1)^S是符号位表示正负,M是一个介于1和2之间的浮点数,E为指数位。
例如:
十进制的5.5
写成二进制就是101.1,即1.011*2^2
对于小数部分,小数点后n位表示2的-n次方。
根据上面的公式,5.5的S为0,M为1011,E为2。也就是说,只需要存储0,1011,2这三个数就可以存储5.5。
IEEE 754规定,对于 float类型浮点数,S占1个bite,E占8个bite,M占23个bite;对于double类型浮点数,S占1个bite,E占11个bite,M占52个bite。
而前述可知,M介于1和2之间,即M=1.xxxxxxx,所以可以省去1,待取出时再前面补上1即可,这样就可以多存一位,提高精度。
E的情况则相对复杂,E在存储时是一个无符号整型,只能存储0~255或者0~2047,而我们知道在科学计数法中,E可以是负数,那么便需要在真实的有正有负的E的基础上加上一个中间常量,使E成为正数,取出时再还原。这个正数在float中是127,在dounle中是1023。
比如2^10中E是10,存储时便要加上123,即133,存储10000101。
E的三种情况
一、E不全为0或不全为1
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将
有效数字M前加上第一位的1。
0.5的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为
1.0*2^(-1),其E为-1+127=126,表示为 01111110,而M为1.0省去1即为0,补齐23位即可。
0.5的二进制存储形式为0 01111110 00000000000000000000000
二、E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,
有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于
0的很小的数字。
三、E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)
回顾
那么我们来回顾一下前面的例子。
第一部分
n=9,则n中存储的是 00000000 00000000 00000000 00001001
按照浮点型打印,将被拆分为S=0 E=00000000 M=00000000000000000001001
此时E全为0,符合M不加1而加0,E真实值为-126的情况,则指数部分为2^(-126)
打印结果为(-1)^0*0.00000000000000000001001*2^(-126)=1.001*2(-146)
是一个很小很小的数,浮点型无法显示这么多位数,故而打印结果为0.00000000
第二部分
9.0的二进制表示形式为1001.0=(-1)^0*1.0010*(2^3)
则s=0,M=1.0010,E=3+127=130
那么存在内存中的形式就是0 10000010 00100000000000000000000
而这个数还原成十进制数正好是1091567616