IEEE浮点标准用符号位、有效数、指数位来表示一个数
符号位:决定是负数(s=1)还是正数(s=0)
有效数:无符号二进制小数(exp)
指数位:2的幂(frac可能为负数),加权
在单精度浮点浮点格式(C语言中的float)中,s、exp、frac域分别为1位、8位、23位,产生一个32位的表示。在双精度浮点格式(C语言中的double)中,s、exp、frac域分别为1位、11位、52位,产生一个64位的表示。
规格化值:exp域不是全0全1, 小数域frac描述小数值f(0<=f<1),有效数定义为M = 1 + f,既然第一位始终为1,我们就不需要显式表示它(隐含的以1开头的表示)
如,若要表示1.5,二进制就是1.1 ==> 0.1*2^0
对于小数位:0.1 即 100 0000 0000 0000
对于指数位:0 偏置形式的有符号数 x - 2^(8-1) = 0, 求得x = 127 即 0111 1111
程序验证:
#include <stdio.h>
#include <stdlib.h>
//模拟小端数据
typedef struct stFloat
{
int frac:23;
int exp:8;
int s:1;
}ST_FLOAT;
int main(int argc, char *argv[])
{
float f;
ST_FLOAT stF;
stF.s = 0;
stF.exp = 0x7f; // 0111 1111
stF.frac = 0x400000; // 0100 0000 0000 0000
f = *(float*)(&stF);
printf("%f\n", f);
return 0;
}
[[email protected] C]$ gcc -o ieee ieee.c
[[email protected] C]$ ./ieee
1.500000
非规格化值:指数域全为0,这种情况指数值是1-[2^(8-1)-1] = -126,有效位的值M=f,不包含隐含的1
1)提供了一种表示值0的方法
2)表示那些非常接近于0.0的数,对“逐渐溢出”属性的支持
#include <stdio.h>
#include <stdlib.h>
//模拟小端数据
typedef struct stFloat
{
int frac:23;
int exp:8;
int s:1;
}ST_FLOAT;
int main(int argc, char *argv[])
{
float f;
ST_FLOAT stF;
stF.s = 0;
stF.exp = 0x0;
stF.frac = 0x400000;
f = *(float*)(&stF);
printf("%.42f\n", f);
return 0;
}
二进制126位相当于八进制42位,因此十进制42位有效位我们一定可以看到0.00 05的出现,看输出吧
[[email protected] C]$ gcc -o ieee ieee.c
[[email protected] C]$ ./ieee
0.000000000000000000000000000000000000005877
按说,5后面都应该是0。这个输出也暴露出浮点数的不精确的特点
特殊数值:指数域全为1,看程序吧
#include <stdlib.h>
//模拟小端数据
typedef struct stFloat
{
int frac:23;
int exp:8;
int s:1;
}ST_FLOAT;
int main(int argc, char *argv[])
{
float f;
ST_FLOAT stF;
stF.s = 0;
stF.exp = 0xff;
stF.frac = 0x0;
f = *(float*)(&stF);
printf("%.42f\n", f);
stF.frac = 0x1; //小数位不是全0
f = *(float*)(&stF);
printf("%.42f\n", f);
return 0;
}
输出如下:
[[email protected] C]$ ./ieee
inf
nan
这两个符号,我们应该见过,第一个表示无穷大,第二个表示实数和无穷以外的数