本帖最后由 yongheng0852 于 2017-10-12 23:39 编辑
目标:
学习:IEEE754浮点数存储的相关知识
验证:浮点数在计算机中的存储方式:近似存储
一:数据存储方式
二: IEEE 754 关于浮点数的规定
三:十进制数转换成浮点数的步骤
四:数据转换案例
五:几个特殊数据的存储规则
六:浮点数转换成十进制数的步骤
七:实际应用 一:数据存储方式: 1.整型:以补码的方式存储 正整数:源码,反码,补码 都相等。 负整数:补码为(符号位不变),源码的反码加1
2.浮点数:以IEEE754标准存储。 二: IEEE 754 关于浮点数的规定
在计算机中,浮点数一般由三部分组成: 数值的符号位、阶码和尾数。 这种浮点数是用科学记数法来表示的,即: 浮点数=符号位.尾数×2阶码。
1.据IEEE 754国际标准,常用的浮点数有两种格式: (1)单精度浮点数(32位),阶码8位,尾数24位(内含1位符号位)。 (2)双精度浮点数(64位),阶码11位,尾数53位(内含1位符号位)。 (3)临时浮点数(80位),阶码15位,尾数65位(内含1位符号位)。
2.根据IEEE 754标准: (1)符号位也是“0”代表正数;“1”代表负数. (2)阶码用移码表示,尾数规格化形式,但格式如下: 1.XXX…X。 由于最高位总是1,因此省略,称隐藏位(临时实数则不隐藏). 尾数比规格化表示大一倍,而阶码部分则比一般小1, 即[E]移=2n+E-1=127+E 这样,尾数与通常意义的尾数的含义不一致,为了区别,754 中的尾数称为有效数.
3.IEEE754对阶码作如下规定 偏移阶码E | 实际阶码值 | 0 | 保留做操作数 | 1 | -126 | 2 | -125 | … | | 127 | 0 | 128 | 1 | 129
| 2 | …
| | 254 | 127 | 255 | 保留做操作数 |
4.对上溢和下溢的处理 当运算结果小于规格化浮点数所能表示的最小值时,以前硬件处理策略,或者结果置0或者产生一个下溢陷阱,这两种方案均不能令人满意。 IEEE754处理方法是使用非规格化数。这时阶码为0(即移码-127),尾数没有隐含位,最高位是0。 这样的结果是降低精度,扩大表示范围。如原来规格化单精度最小值是1.0x2-126,而非规格化单精度最小值是2-23 x2-126=2-149(只有1位有效位)。
5. 对上溢用无穷大表示,同时规定: 无穷大+任何数=无穷大 任何有限数÷0=无穷大 任何有限数÷无穷大=0 无穷大÷无穷大=NaN NaN(Not A Number)
6.这样IEEE754有5种类型浮点数据,如下表: S | E | M | 意义 | 0/1 | 0 | 0 | ±0 | 0/1 | 0 | 非0 | 非规格化数 | 0/1 | 1~254 | 任意 | 规格化数 | 0/1 | 255 | 0 | ±无穷大 | 0/1 | 255 | 非0 | NaN |
三:十进制数转换成浮点数的步骤
1.将十进制数转换成二进制数: (1)整数部分用2来除,小数部分用2来乘; a)整数部分转二进制((按源码的二进制形式) b)小数部分转换 2.规格化二进制数: (1)科学计数法方式表示,使小数点前面仅有第一位有效数字,改变阶码(阶码由10进制转换为2进制)
3.计算阶码 (1)短型浮点数的阶码加上偏移量7FH (2)长型浮点数的阶码加上偏移量3FFH (3)扩展型浮点数的阶码加上偏移量3FFFH
4.尾码计算 (1)尾码是小数点后的数据 (2)如果尾码不足23位,则后面补零 (3)大于23位只保留23bit,如果后一位为1时,向前进1。 5.以32bit浮点数据格式存储。
(1)把数值的符号位、阶码和尾数合在一起就得到了该数的浮点存储形式。 四:数据转换案例 例1-把十进制数100.25转换成协处理器中的浮点数
解: (1)进制转换: (100.25)10=(1100100.01)2 (2)规格化: (1100100.01)2=1.10010001×26 =1.10010001×2110 (3)计算阶码(阶码+偏移量(7FH)) 110+01111111=10000101 (4)尾码计算(不足23位) 10010001 0000 0000 0000 000 (5)组合 符号位(01bit) 0, 阶码为(08bit) 10000101, 尾数为(23bit) 10010001000000000000000 组合后的32bit数据: 01000010110010001000000000000000 16进制: 0x42C88000
综合上述可得: (100.25)10的浮点形式为:0x42C88000
1.程序验证(VS2015-控制台程序)
[C] 纯文本查看 复制代码 #define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
float a = 100.25f;
unsigned int* p = (unsigned int*)&a;//以无符号的方式操作,避免了转码问题,(浮点数,转换为正整数)
int len = sizeof(float);
int i;
char k;
printf("p = %p\n", p);//打印变量地址
printf("len = %d\n", len);//打印变量的长度
printf("a = %f\n", a);//输出原始数据
printf("----------------------------------\n");
for (i = 31; i >= 0; --i)//实际存入的数据是
{
k = (*p) >> i & 1;//右移,从高位开始提取,与运算,按位提取
printf("%d ", k);
if (31 == i || 23 == i)//输出分隔符
printf(" - ");
}
printf("\n");
system("pause");
return 0;
}
(100.25)10的浮点形式:0x42C88000
小端对齐: 数值的高位字节存储在内存的低位地址上,数值的低位字节存储在内存的高位地址上。 例2 -把十进制数-33.33转换成协处理器中的浮点数
解: (1)进制转换: (33.33)10=(100001. 01010100011110101110000)2 (2)规格化: (100001.01010100011110101110000)2 =1.0000101010100011110101110000)2×25 =1.0000101010100011110101110000)2×2101 (3)计算阶码(阶码+偏移量(7FH)) 101+01111111=10000100 (4)尾码计算(超过23位,后位为1,则进1) 0000 1010 1010 0011 1101 011 10000 0000 1010 1010 0011 1101 100 (5)组合 符号位(01bit) 1, 阶码为(08bit) 10000100, 尾数为(23bit) 0000 1010 1010 0011 1101 100 组合后的32bit数据: 110000100000010101010 00111101100 16进制: 0xC20551EC 综合上述可得: (-33.33)10的浮点形式为:0xC20551EC 再次解读数据: -33.330002
再把: 0xC20551EC 还原为10进制,则数据为:-33.330002 浮点数在计算机中采用近似的方式存储。
为什么后面会多了0.000002,这是因为我们在计算尾码的时候,尾码超过了23位,舍去了23位后面的数据,第24bit为1,向前进1, 所以多了0.000002
2.程序验证 (VS2015-控制台程序) [C] 纯文本查看 复制代码 #define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
float a = 100.25f;//-33.33f是个很有代表型的数字,它再一次证明了浮点数是不能精确存储的
unsigned int* p = (unsigned int*)&a;
int len = sizeof(float);
int i;
char k;
printf("p = %p\n", p);
printf("len = %d\n", len);
printf("a = %f\n", a);//输出原始数据、但实际输出的是-33.330002
printf("----------------------------------\n");
for (i = 31; i >= 0; --i)
{
k = (*p) >> i & 1;//与运算,按位提取
printf("%d ", k);
if (31 == i || 23 == i)
printf(" - ");
}
printf("\n");
system("pause");
return 0;
}
(-33.33)10的浮点形式为: 0xC20551EC 再次解读数据: -33.330002
![]()
具体推导过程:(无法上传excel,只能传图片了)
![]()
五:几个特殊数据的存储规则:
1.正0: 所有的数据位都是0;
2.负0: 最高位为1,其它的数据位是0;
3.正/负无穷: 符号位为0/1,阶码位全为1,有效数字全为0;
NAN: 非法的浮点数,阶码位全为1,有效数字不全为0;
其中:NAN —Not-A-Number。
![]()
六:浮点数转换成十进制数的步骤
1.该步骤与前面“十进制数转换成浮点数”的步骤是互逆的,其具体步骤如下: (1)分割数字的符号、阶码和有效数字; (2)将偏移阶码减去偏移,得到真正的阶码; (3)把数字写成规格化的二进制数形式; (4)把规格化的二进制数改变成非规格化的二进制数; (5)把非规格化的二进制数转换成十进制数。 例3 -把浮点数 1100000111001001000000000000转换成十进制数。
解: 1.把浮点数 1100000111001001000000000000 分割成三部分,可得: (1)符号位是1, (2)阶码 是10000011, (3)尾数 是1001001000000000000
2.还原阶码: 10000011 –01111111=100
3.该浮点数的规格化形式: 1.1001001×24 (其中前面的“1.”从隐含位而来)
4.该浮点数的非规格化形式: 11001.001
5.该浮点数的十进制数为-25.125 (因为符号位为1,所以,该数是负数)
七:实际应用(工业):
设备说明:采集测试产品在指定温度的阻抗状态
在温度检测项目中,测试仪器使用的是8位CPU(8bit单片机)把采集的实际温度和电阻值数据以IEEE754的格式,通过modbus协议,按8bit的方式发送,连续发送4次,接收设备接收到数据之后,必须按照IEEE754格式再转换为浮点数才能使用,上位机把数据转换完成在对外部做相应的逻辑控制。
测控仪器发送----à---à---à---à----上位机接收后转换 | 数据1 | 42 | C7 | 合并数据: | 42C785E9 | 85 | E9 | 转换浮点: | 99.76154327
| 数据2 | 41 | 9D | 合并数据: | 419DCA4C | CA | | 转换浮点: | 19.72377777 | 数据3 | C7 | C3 | 合并数据: | C7C35000 | 50 | 0 | 转换浮点: | -100000 | 数据4 | C7 | C3 | 合并数据: | C7C35000 | 50 | 0 | 转换浮点: | -100000 | 数据5 | C7 | C3 | 合并数据: | C7C35000 | 50 | 0 | 转换浮点: | -100000 | 数据6 | C7 | C3 | 合并数据: | C7C35000 | 50 | 0 | 转换浮点: | -100000 | 合计24个字节/4 = 6组数据 | | |
参考资料:
1.单精度浮点数的存储-郝斌老师 2.IEEE-754关于浮点数的规定.ppt 百度文库 因初学C,以上是个人在网上搜集了一些资料,学习完后个人的理解,下面也只是小弟的一些不成熟的心得,不对之处恳请指正! 2017年10月11日 深圳黑马6期
|