浮点型
在C语言里,实数的类型有单精度float类型和双精度double类型。其中double类型表示的实数精度比单精度的类型要高。
在计算机系统的发展过程中,曾经提出过多种方法表示实数,但是到目前为止使用最广泛的是浮点表示法。相对于定点数而言,浮点数利用指数使小数点的位置可以根据需要而上下浮动,从而可以灵活地表达更大范围的实数。
float x =
double y = 0.3555;//定义了一个双精度浮点数
上面的2句话在程序里的意思是:第一句,定义了一个单精度实数变量x,并把一个实数
目前C/C++编译器标准都遵照IEEE制定的浮点数表示法来进行float,double运算。这种结构是一种科学计数法,用符号、指数和尾数来表示,底数定为2——即把一个浮点数表示为尾数乘以2的指数次方再添上符号。下面是具体的规格:
|
符号位 |
阶码 |
尾数 |
长度 |
float |
1 |
8 |
23 |
32 |
double |
1 |
11 |
52 |
64 |
由于通常C编译器默认浮点数是double型的,下面以double为例:
共计64位,折合8字节。由最高到最低位分别是第63、62、61、……、0位。最高位63位是符号位,1表示该数为负,0正;62-52位,一共11位是指数位;51-0位,一共52位是尾数位。
按照IEEE浮点数表示法,下面将把double型浮点数38414.4转换为十六进制代码。 把整数部和小数部分开处理:整数部直接化十六进制:960E。小数的处理:
0.4=0.5*0+0.25*1+0.125*1+0.0625*0+……
实际上这永远算不完!这就是著名的浮点数精度问题。所以直到加上前面的整数部分算够53位就行了(隐藏位技术:最高位的1不写入内存)。
如果你够耐心,手工算到53位那么因该是:38414.4(10)=1001011000001110.0110101010101010101010101010101010101(2)
科学记数法为:1.001……乘以2的15次方。指数为15。于是来看阶码,一共11位,可以表示范围是-1024 ~ 1023。因为指数可以为负,为了便于计算,规定都先加上1023,在这里,15+1023=1038。二进制表示为:100 00001110
符号位:正,0。合在一起(尾数二进制最高位的1不要):
01000000 11100010 11000001 11001101 01010101 01010101 01010101 01010101
按字节倒序存储的十六进制数就是: 55 55 55 55 CD C1 E2 40
首先了解一下实数的表示和存储。计算机中的实数一般是通过浮点数的形式来表示的。浮点数的主要特点是让小数点的位置根据需要而浮动,它既能表示整数又能表示小数,并且小数部分的位数可以变化。浮点数据表示的基本原理来源于十进制数中的科学记数法。
一个浮点数包含:符号,小数和指数,其形式可写成:
其中M为尾数(用纯小数来表示,所谓纯小数,即为没有整数部分的小数,R为底数(常为2),E为阶码(指数)。比如:f = 0.123456 * 29。
一个带符号的float的内存结构体描述如下:
typedef struct _float
{
bool
bSign : 1; // 符号,表示正负,1位
char
cExponent : 8; // 指数,8位
unsigned
long ulMantissa : 23; // 尾数,23位
} float;
typedef struct _double
{
bool
bSign : 1; // 符号,表示正负,1位
char
cExponent : 11; // 指数,11位
unsigned
long ulMantissa : 52; // 尾数,52位
} double;
它的存储结构如图3-13所示:
图3-13 实数float与double的存储
用来表示尾数的位数越多,表示实数的精度越大。指数占多少位,尾数占多少位,由计算机系统决定。对编程人员来说,double 和 float 的区别是double精度高,但double消耗内存是float的两倍。程序员都更喜欢用double而不是float。
以下通过程序的方式把浮点数在计算机内的表示方式输出:
int func(float fval)
{
char *p, tmp;
int i, j, t;
float fvalue = fval;
p = (char *)&fvalue;
for (i = sizeof(float)-1; i >= 0; i--)
{
t = 0x80;
tmp = *(p+i);
for (j = 0; j < 8; j++)
{
if (tmp&t)
printf("1");
else
printf("0");
t >>= 1;
}
printf("\n");
}
return 0;
}
实数存储格式计算,以计算178.125为例子,试着计算它在内存中的存储格式如下,共分为3步:
第一步:将178.125表示成二进制数:(178.125)(十进制数)=(10110010.001)(二进制形式);
第二步:将二进制形式的浮点实数转化为规格化的形式:(小数点向左移动7个二进制位可以得到)
10110010.001=1.0110010001*2^7 因而产生了以下三项:
符号位:该数为正数,故第31位为0,占一个二进制位.
阶码:指数(e)为7,故其阶码为127+7=134=(10000110)(二进制),占从第30到第23共8个二进制位.
(注:指数有正负即有符号数,但阶码为正即无符号数,所以将e加个127作为偏移,方便指数的比较)
尾数为小数点后的部分, 即0110010001.因为尾数共23个二进制位,在后面补13个0,即01100100010000000000000
第三步:将符号位,阶码,尾数结合在一起,所以,178.125单精度浮点数在内存中的实际表示方式为:
0 10000110 01100100010000000000000