任何数据在内存中都是以二进制的形式存在,例如一个short型数据1156,其二进制的表示形式为:100 1000 0100。则在Intel CPU架构的系统中,存放方式为:0000 0100(高地址单元) 1000 0100(低地址单元),因为Intel CPU的架构是小端模式。但是对于浮点数在内存是如何存储的?目前所有的C/C++编译器都是采用IEEE所指定的标准浮点格式,即二进制科学表示法。
在二进制科学表示法中,S=M*2^N 主要由三部分构成:符号位+阶码(N)+尾数(M)。对于float型数据,其由4个字节组成,由32位二进制bit位表示。其中符号位1位,阶码8位,尾码23位组成;对于double类型的数据由64位二进制bit位组成。
符号位 阶码 尾数
float 1(31) 8(30~23) 23(22~0)
double 1(63) 11(62~52) 52(51~0)
符号位:0表示正,1表示负
阶码:阶码使用移码表示。对于float型数据,规定其偏移量为127,阶码有正有负,对于8bit二进制,则其表示范围为-128~127;double型数据规定其偏移量为1023,其表示范围为-1024~1023,。例如,对于float型数据,其真实阶码为2,则加上127后为129,其阶码的二进制表示为:1000 0001。
尾数:将实数转换成二进制 有效数字位,即部分二进制位(小数点后面的二进制位),因为规定M的整数部分恒为1,所以这个1就不进行存储
举例说明:
float型数据125.5转换成标准浮点格式
符号位:正数,符号位为0
尾数:125.5转换成二进制为:1111101.1,所以尾数为1.1111011,因尾数的整数部分固定为1,不进行存储。所以尾数的二进制表示为:1111011,在其后面补0,使其达到23位,则为:1111 0110 0000 0000 0000 000
阶码:125.5转换成二进制为:1111101.1,所以其阶码的真实值为6,偏移量为127,所以阶码为133.用二进制表示为:1000 0101
则其二进制表示为:0 1000 0101 1111 0110 0000 0000 0000 000
小端存储 大端存储
0000 0000 1000 0101 低地址
0000 0001 111 01100
111 01100 0000 0001
1000 0101 0000 0000 高地址
而反过来若要根据二进制形式求算浮点数如0 10000101 11110110000000000000000
由于符号为为0,则为正数。阶码为133-127=6,尾数为11110110000000000000000,则其真实尾数为1.1111011。所以其大小为
1.1111011*2^6,将小数点右移6位,得到1111101.1,而1111101的十进制为125,0.1的十进制为1*2^(-1)=0.5,所以其大小为125.5。
同理若将float型数据0.5转换为二进制形式
0.5的二进制形式为0.1,由于规定正数部分必须为1,将小数点右移1位,则为1.0*2^(-1),其阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进制表示形式为
0 01111110 00000000000000000000000
由上分析可知float型数据最大表示范围为1.11111111111111111111111*2^127=3.4*10^38
对于double型数据情况类似,只不过其阶码为11位,偏置量为1023,尾数为52位。
测试程序:
/*测试浮点型数据在内存中存放方式 2011.10.2*/
#include
using namespace std;
int main(int argc, char *argv[])
{
float a=125.5;
char *p=(char *)&a;
printf("%d\n",*p);
printf("%d\n",*(p+1));
printf("%d\n",*(p+2));
printf("%d\n",*(p+3));
return 0;
}
输出结果为:
0
0
-5
66
在上面已经知道float型125.5在内存中存放方式为:
00000000 低地址
00000000
11111011
01000010 高地址
因此对于p和p+1指向的单元,其中存储的二进制数表示的十进制整数为0;
而对于p+2指向的单元,由于为char型指针,为带符号的数据类型,因此11111011,符号位为1,则为负数,由于在内存中二进制是以补码存储的,所以其真值为-5.
对于p+3指向的单元,01000010,为正数,则其大小为66。上面程序输出结果验证了其正确性。