计算机浮点存储,001-IEEE754 浮点数在计算机中的存储方式:近似存储

本帖最后由 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

1270

1281

1292

254127

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种类型浮点数据,如下表:SEM意义

0/100±0

0/10非0非规格化数

0/11~254任意规格化数

0/12550±无穷大

0/1255非0NaN

三:十进制数转换成浮点数的步骤

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

#include

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

b5b0b1954d7b1b86a4242bbd9d0c05eb.gif

1.png (4.89 KB, 下载次数: 4)

2017-10-12 00:26 上传

b5b0b1954d7b1b86a4242bbd9d0c05eb.gif

2.png (18.81 KB, 下载次数: 0)

2017-10-12 00:27 上传

小端对齐:

数值的高位字节存储在内存的低位地址上,数值的低位字节存储在内存的高位地址上。

例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

#include

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

b5b0b1954d7b1b86a4242bbd9d0c05eb.gif

3.png (17.36 KB, 下载次数: 0)

2017-10-12 00:29 上传

b5b0b1954d7b1b86a4242bbd9d0c05eb.gif

4.png (22.5 KB, 下载次数: 0)

2017-10-12 00:29 上传

具体推导过程:(无法上传excel,只能传图片了)

b5b0b1954d7b1b86a4242bbd9d0c05eb.gif

AA.png (134.75 KB, 下载次数: 1)

2017-10-12 00:51 上传

b5b0b1954d7b1b86a4242bbd9d0c05eb.gif

BB.png (370.59 KB, 下载次数: 0)

2017-10-12 00:51 上传

五:几个特殊数据的存储规则:

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格式再转换为浮点数才能使用,上位机把数据转换完成在对外部做相应的逻辑控制。

b5b0b1954d7b1b86a4242bbd9d0c05eb.gif

A.png (172.75 KB, 下载次数: 0)

2017-10-12 00:32 上传测控仪器发送----à---à---à---à----上位机接收后转换

数据142C7合并数据:42C785E9

85E9转换浮点:99.76154327

数据2419D合并数据:419DCA4C

CA4C转换浮点:19.72377777

数据3C7C3合并数据:C7C35000

500转换浮点:-100000

数据4C7C3合并数据:C7C35000

500转换浮点:-100000

数据5C7C3合并数据:C7C35000

500转换浮点:-100000

数据6C7C3合并数据:C7C35000

500转换浮点:-100000

合计24个字节/4  = 6组数据

参考资料:

1.单精度浮点数的存储-郝斌老师

2.IEEE-754关于浮点数的规定.ppt 百度文库

因初学C,以上是个人在网上搜集了一些资料,学习完后个人的理解,下面也只是小弟的一些不成熟的心得,不对之处恳请指正!

我的Email是  [email protected],不对之处,恳请诸位诸位发邮件指正!

2017年10月11日   深圳黑马6期

你可能感兴趣的:(计算机浮点存储)