一文读懂 IEEE754 浮点数的表示方法

您所在的位置:网站首页 ieee754浮点数的计算 一文读懂 IEEE754 浮点数的表示方法

一文读懂 IEEE754 浮点数的表示方法

2024-06-15 18:49| 来源: 网络整理| 查看: 265

在这里插入图片描述 FBI WARNING:鄙人首个开源电子书 《Go 编码建议》已经上线啦,欢迎各位大佬斧正指导,协同共建。

文章目录 1.浮点数的存储格式2.移码3.浮点数的规格化3.1 单精度浮点数真值3.2 双精度浮点数真值 4.浮点数的具体表示4.1 十进制到机器码4.2 机器码到十进制 5.浮点数的几种特殊情况6.浮点数的精度和数值范围6.1 浮点数的数值范围6.2 浮点数的精度 7.小结参考文献

1.浮点数的存储格式

浮点数(Floating-point Number)是对实数的一种近似表示,由一个有效数字(即尾数)加上幂数来表示,通常是乘以某个基数的整数次幂得到。以这种表示法表示的数值,称为浮点数。表示方法类似于基数为 10 的科学计数法。利用浮点进行运算,称为浮点计算,这种运算通常伴随着因为无法精确表示而进行近似或舍入。

计算机对浮点数的表示规范遵循电气和电子工程师协会(IEEE)推出的 IEEE754 标准,浮点数在 C/C++ 中对应 float 和 double 类型,我们有必要知道浮点数在计算机中实际存储的内容。

IEEE754 标准中规定 float 单精度浮点数在机器中表示用 1 位表示数字的符号,用 8 位表示指数,用 23 位表示尾数,即小数部分。对于 double 双精度浮点数,用 1 位表示符号,用 11 位表示指数,52 位表示尾数,其中指数域称为阶码。IEEE754 浮点数的格式如下图所示。 这里写图片描述 注意,IEE754 规定浮点数阶码 E 采用"指数e的移码-1"来表示,请记住这一点。为什么指数移码要减去 1,这是 IEEE754 对阶码的特殊要求,以满足特殊情况,比如对正无穷的表示。

2.移码

移码(又叫增码)是对真值补码的符号位取反,一般用作浮点数的阶码,引入的目的是便于浮点数运算时的对阶操作。

对于定点整数,计算机一般采用补码的来存储。正整数的符号位为 0,反码和补码等同于原码。负整数符号位为1,原码、反码和补码的表示都不相同,由原码变成反码和补码有如下规则: (1)原码符号位为1不变,整数的每一位二进制数位求反得反码; (2)反码符号位为1不变,反码数值位最低位加1得补码。

比如,以一个字节 8bits 来表示 -3,那么 [ − 3 ] 原 = 10000011 [-3]_原=10000011 [−3]原​=10000011, [ − 3 ] 反 = 11111100 [-3]_反=11111100 [−3]反​=11111100, [ − 3 ] 补 = 11111101 [-3]_补=11111101 [−3]补​=11111101,那么 -3 的移码就是 [ − 3 ] 移 = 01111101 [-3]_移=01111101 [−3]移​=01111101。

如何将移码转换为真值 -3 呢?先将移码转换为补码,再求值。

3.浮点数的规格化

若不对浮点数的表示作出明确规定,同一个浮点数的表示就不是唯一的。例如 ( 1.75 ) 10 (1.75)_{10} (1.75)10​可以表示成 1.11 × 2 0 1.11\times 2^0 1.11×20, 0.111 × 2 1 0.111\times2^1 0.111×21, 0.0111 × 2 2 0.0111\times2^2 0.0111×22 等多种形式。当尾数不为 0 时,尾数域的最高有效位为1,这称为浮点数的规格化。否则,以修改阶码同时左右移动小数点位置的办法,使其成为规格化数的形式。

3.1 单精度浮点数真值

IEEE754 标准中,一个规格化的 32 位浮点数 x 的真值表示为: x = ( − 1 ) S × ( 1. M ) × 2 e x=(-1)^S\times(1.M)\times2^e x=(−1)S×(1.M)×2e e = E − 127 e=E-127 e=E−127 其中尾数域值是 1.M。因为规格化的浮点数的尾数域最左位总是 1,故这一位不予存储,而认为隐藏在小数点的左边。

在计算指数 e 时,对阶码E的计算采用原码的计算方式,因此 32 位浮点数的 8bits 的阶码 E 的取值范围是 0 到 255。其中当E为全 0 或者全 1 时,是 IEEE754 规定的特殊情况,下文会另外说明。

3.2 双精度浮点数真值

64 位的浮点数中符号为 1 位,阶码域为 11 位,尾数域为 52 位,指数偏移值是 1023。因此规格化的 64 位浮点数 x 的真值是: x = ( − 1 ) S × ( 1. M ) × 2 e x=(-1)^S\times(1.M)\times2^e x=(−1)S×(1.M)×2e e = E − 1023 e=E-1023 e=E−1023

4.浮点数的具体表示 4.1 十进制到机器码

(1)0.5 0.5 = ( 0.1 ) 2 0.5=(0.1)_2 0.5=(0.1)2​,符号位S为0,指数为 e = − 1 e=-1 e=−1,规格化后尾数为1.0。

单精度浮点数尾数域共23位,右侧以0补全,尾数域: M = [ 000   0000   0000   0000   0000   0000 ] 2 M=[000\ 0000\ 0000\ 0000\ 0000\ 0000]_2 M=[000 0000 0000 0000 0000 0000]2​

阶码E: E = [ − 1 ] 移 − 1 = [ 0111   1111 ] 2 − 1 = [ 0111   1110 ] 2 E=[-1]_移-1=[0111\ 1111]_2-1=[0111\ 1110]_2 E=[−1]移​−1=[0111 1111]2​−1=[0111 1110]2​

对照单精度浮点数的存储格式,将符号位S,阶码E和尾数域M存放到指定位置,得0.5的机器码: 0.5 = [ 0011   1111   0000   0000   0000   0000   0000   0000 ] 2 0.5=[0011\ 1111\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000]_2 0.5=[0011 1111 0000 0000 0000 0000 0000 0000]2​。

十六进制表示为0.5=0x3f000000。

(2)1.5 1.5 = [ 1.1 ] 2 1.5=[1.1]_2 1.5=[1.1]2​,符号位为0,指数 e = 0 e=0 e=0,规格化后尾数为1.1。

尾数域M右侧以0补全,得尾数域: M = [ 100   0000   0000   0000   0000   0000 ] 2 M=[100\ 0000\ 0000\ 0000\ 0000\ 0000]_2 M=[100 0000 0000 0000 0000 0000]2​

阶码E: E = [ 0 ] 移 − 1 = [ 10000000 ] 2 − 1 = [ 01111111 ] 2 E=[0]_移-1=[1000 0000]_2-1=[0111 1111]_2 E=[0]移​−1=[10000000]2​−1=[01111111]2​

得1.5的机器码: 1.5 = [ 0011   1111   1100   0000   0000   0000   0000   0000 ] 2 1.5=[0011\ 1111\ 1100\ 0000\ 0000\ 0000\ 0000\ 0000]_2 1.5=[0011 1111 1100 0000 0000 0000 0000 0000]2​

十六进制表示为1.5=0x3fc00000。

(3)-12.5 − 12.5 = [ − 1100.1 ] 2 -12.5=[-1100.1]_2 −12.5=[−1100.1]2​,符号位S为1,指数e为3,规格化后尾数为1.1001,

尾数域M右侧以0补全,得尾数域: M = [ 100   1000   0000   0000   0000   0000 ] 2 M=[100\ 1000\ 0000\ 0000\ 0000\ 0000]_2 M=[100 1000 0000 0000 0000 0000]2​

阶码E: E = [ 3 ] 移 − 1 = [ 1000   0011 ] 2 − 1 = [ 1000   0010 ] 2 E=[3]_移-1=[1000\ 0011]_2-1=[1000\ 0010]_2 E=[3]移​−1=[1000 0011]2​−1=[1000 0010]2​

即-12.5的机器码: − 12.5 = [ 1100   0001   0100   1000   0000   0000   0000   0000 ] 2 -12.5=[1100\ 0001\ 0100\ 1000\ 0000\ 0000\ 0000\ 0000]_2 −12.5=[1100 0001 0100 1000 0000 0000 0000 0000]2​

十六进制表示为-12.5=0xc1480000。

用如下程序验证上面的推算,代码编译运行平台 Win32+VC++ 2012:

#include using namespace std; int main() { float a=0.5; float b=1.5; float c=-12.5; unsigned int* pa=NULL; pa=(unsigned int*)&a; unsigned int* pb=NULL; pb=(unsigned int*)&b; unsigned int* pc=NULL; pc=(unsigned int*)&c; cout float a = 16777215; // 二进制原码 1111111 11111111 11111111 有效数字 24 位 => 机器码为 0 10010110 111111 11111111 11111111 = 0x4b7fffff float b = 16777215.5; // 二进制原码 1111111 11111111 11111111.1 有效数字超过 24 位,无法精确表示 unsigned int *pa = NULL; pa = (unsigned int *) &a; unsigned int *pb = NULL; pb = (unsigned int *) &b; cout


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3