单精度浮点数的存 储
首先声明一点:由于我所能看到的讲编码的书都是一帮 SB 写的狗屎,所以对于单精度浮点数的存储,我也不敢说已彻底掌握, 下面也只是小弟的一些不成熟的心得,不对之处恳请指正!
先贴一个输出单精度浮点数二进制代码的程序
/*
2007-5-22
修改于 2007年 10月 27日 16:46:12 沙坡村 IBM
将一个单精度浮点数的二进制数字显示出来
*/
# include <stdio.h>
int main(void)
{
float a = -33.33f; //-33.33f 是个很有代表型的数字,它再一次证明了浮点数是不能精确存储的
unsigned int* p = (unsigned int* )&a;
int len = sizeof(float);
int i;
char k;
printf("a = %f/n",a);
for (i=31; i>=0; --i)
{
k = (*p)>>i & 1;
printf("%d ",k);
if (31== i || 23==i)
printf(" - ");
}
printf("/n");
return 0;
}
/*
具体的若干次输出结果是:
***********************
a = -5.000000
1 - 1 0 0 0 0 0 0 1 - 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Press any key to continue
***********************
a = 5.000000
0 - 1 0 0 0 0 0 0 1 - 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Press any key to continue
*************************
a = 12.687500
0 - 1 0 0 0 0 0 1 0 - 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Press any key to continue
*************************
a = -12.687500
1 - 1 0 0 0 0 0 1 0 - 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Press any key to continue
*************************
a = 0.810000
0 - 0 1 1 1 1 1 1 0 - 1 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 0 1 0 0 1
Press any key to continue
*************************
a = -0.810000
1 - 0 1 1 1 1 1 1 0 - 1 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 0 1 0 0 1
Press any key to continue
*************************
a = -33.330002
1 - 1 0 0 0 0 1 0 0 - 0 0 0 0 1 0 1 0 1 0 1 0 0 0 1 1 1 1 0 1 1 0 0
Press any key to continue
*************************
*/
下面我再谈谈自己的看法:
浮点数的表示分三部分:
符号位 阶码 数字位
比如: 123.45678 在内存中的表示就是 + 2 1.2345678 即 1 * 12345678*102
- 123.45678 在内存中的表示就是 - 2 12345678 即 -1 * 12345678*102
1879978.3 在内存中的表示就是 + 6 1.8799783 即 1 * 18799783*106
-1879978.3 在内存中的表示就是 - 6 1.8799783 即 -1 * 18799783*106
换句话说符号位表示该数字的正负,数字位可以先暂时认为表示这个数字到底是那几个数字,阶码表示的是 10 的某次方,阶码刚好确定了该数字的小数点的位置
当然这只是一种比喻,实际内存中只有由 0 和 1 组成的代码,阶码不是 10 的某次方,而是 2 的某次方,数字位也是在某种编码规则下的 01 代码组成,符号位是用 1 表示负,用 0 表示正。
待会我们再详细讨论这个问题。
浮点数当然也分为 1 、正的浮点数 2 、零 3 、负的浮点数,
下面我分别讨论这三类数的存储 !
一、零的二进制代码无论是整数型,还是字符型,还是浮点型,都是0
二、正浮点数的二进制代码
以 12.6875f 为例, 我们可以先将 12.6875f 转化为二进制数字, 12 的二进制是 1100, 0. 6875 的二进制是 0.1011, 【此处省略了整数和小数的二进制求法,不懂者可参阅相关书籍】 , 则 12.6875f 的二进制是 1100.1011,
一般情况下,浮点数是以 IEEE754 标准来存储的,即以
(-1)S * (1.f)*2e-127
来存储的 , 并规定如果该数字是单精度浮点数,则 s 占 1 位, e 占 8 位, f 占 23 位
s 就是我上面所说的 符号位 , f 就是我上面所说的 数字位 , e 就是上面所说的阶码 . 注意不是 1.f ,也就是说我们存储的是 f 而不是 1.f , OK , 如果看不明白,没关系,请继续往下看
好,再回到 12.6875f 这个数字,我们已求得它的二进制是 1100.1011, 套用 IEEE754 标准
(-1)S * (1.f)*2e-127
就是 (-1)0 * (1.1001011) * 2 130-127
则 s 就是 0 , f 就是 1001011, e 就是 130
130 的二进制就是 1000 0010
又得知 s 占 1 位, f 占 23 位, e 占 8 位 则
e 就是 1000 0010
则 s 是 0
f 就是 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
即 12.6875f 的二进制代码是
0 1000 0010 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
二、负浮点数的二进制代码
负浮点数 的二进制代码和与它所绝对值相等的正浮点数 的代码几乎是一摸一样的,唯一的不同的是把s 由0 改为了1 ,即把第一个位由0 改为了1 ,其余位的二进制代码都是一样的
入:
-5.000000 的二进制代码是
1 - 1 0 0 0 0 0 0 1 - 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
5.000000 的二进制代码是
0 - 1 0 0 0 0 0 0 1 - 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
12.687500 的二进制代码是
0 - 1 0 0 0 0 0 1 0 - 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-12.687500 的二进制代码是
1 - 1 0 0 0 0 0 1 0 - 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0.810000 的二进制代码是
0 - 0 1 1 1 1 1 1 0 - 1 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 0 1 0 0 1
-0.810000 的二进制代码是
1 - 0 1 1 1 1 1 1 0 - 1 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 0 1 0 0 1
我的 Email 是 hb.g@163.com , 不对之处,恳请诸位诸位发邮件指正
2007年 10月 28日
西安