计算机中的浮点数(二)

IEEE 754-2008 标准(二进制)

计算机中的浮点数(一)-CSDN博客文章浏览阅读188次,点赞12次,收藏12次。这篇文章介绍了计算机系统中浮点数的正式定义,关于浮点数的介绍总共分两篇文章,这是第一篇。https://blog.csdn.net/daduzimama/article/details/141902866

IEEE 754的参数说明:

        书接上文,IEEE 754-2008标准(以下简称标准754)对底(radix)β指数e(exponents)的最小/大值e_{min}e_{max}做了进一步规定。其中:

1,底数β只能是2或者是10,也就是说该标准只支持二进制和十进制

2,指数e的极限范围必须符合:e_{min}=1-e_{max}

        该标准定义了一些interchange formats交换格式,这些交换格式对所有的比特位都进行了编码,使得他们彼此之间能够在不同平台之间进行无损的数据交换。在所有的交换格式中标准定义了5个basic formats基础格式: 三个32位,64位和128位的二进制格式,以及两个64位和128位的十进制格式。

二进制交换格式的主要参数
十进制交换格式的主要参数


浮点数的编码方式:

        如上图所示,浮点数的编码使用了1个符号位(sign)S、一个宽度为W_{E}位的指数字段E,以及一个p−1位有效数字的尾数(trailing significand)字段T。我们来回顾一下“有效数字的尾数(或者简称尾数)”是什么意思?在上一篇文章中,介绍了浮点数的正式定义后,又介绍了正规数次正规数。其中提到了“如果有一种方法,特别是在指数字段中。。。隐藏位约定(leading bit convention/implicit bit convention/hidden bit convention)”。

        事实上,在标准754中就使用了这种方法。在二进制浮点数的表示中,对常规数(normal number)而言,他的有效数字(significand)的第一位必然是“1”。而对于相对少见的数(sub-normal number)而言,他的有效数字(significand)的第一位必然是“0”。因此,不论表示成normal number还是sub-normal number都没必要存储这一位,而是把更多的空间用来存储其他有用信息。即,只储小数点后面的p−1位:这就是有效数字的尾数(在有的地方也称“分数”)。这种不存储有效数字最左边一位的方式被称为“前导位约定(leading bit convention)”或“隐藏位约定(hidden bit convention)”。

        简而言之,如果有效数位是24位,实际只储存23位。


二进制浮点数的编码方式:

        基于上面的三个不同字段,E是指数字段的位组成的整数,T为由尾数字段的位组成的整数,S为表示符号位的整数,一个数用二进制浮点数来表示,可表示为(S,E,T)的函数,具体编码方式如下,主要是由E和T这两个字段所共同决定的:

        1,如果E=2^{W_{E}}-1(即,指数字段全为1)且T\neq 0,则浮点数为NaN(not a number)。这个NaN是quiet NaN或者signaling NaN二者中的一种。其中,quiet NaN特指无效操作(例如,\sqrt{-5.0}这种操作)。而signaling NaN则特指操作异常。


        2,如果E=2^{W_{E}}-1(指数字段全为1)且T=0(尾数字段全为0),则专门用于表示正无穷或者负无穷

(-1)^{S}\times (\infty )


        3,如果E=0T=0,表示带符号的零

(-1)^{S}\times (0)


        4,如果E=0T\neq 0,这种情况专门用于表示Sub-normal number相对少见的数

(-1)^{S}\times 2^{e_{min}}\times (0+T\cdot 2^{1-p})


        5,只有E在1\leq E\leqslant 2^{W_{E}}-2之间的时候,才被用于表示normal number常规数

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})

   

        其中,b表示偏移量(bias),且b=e_{max}=2^{W_{E}}-1。对于不同的交换格式b的值也随之而改变。   


单精度浮点数的常规数表示(normal number)

        就二进制单精度而言,暂且先不考虑前面提到的NaN,正负无穷大等等,我们先用一个例子来看看32位单精度浮点数的表示方法。

        首先,根据标准754给定的参数单精度浮点数共有32bit:

32=1+8+23

        他们分别是1bit的符号位,8bit的指数,23bit的尾数(不需要保存隐藏位,隐藏位由指数字段指出)。精度p=24,log_{10}(2^{24})\approx 7.225,大约相当于是7.225个十进制数字的精度。

        假设一个数N在32位浮点数的系统中被表示/编译(encoding)为:

        1,从左至右逐一解码,先看符号位S,符号位为0,根据公式得到

(-1)^{S}=(-1)^{0}=1

这说明N是一个大于等于0的数(不一定是正数,可能是0)。

        2,其次再看指数E,指数部分既不是00000000_{2}也不是11111111_{2},参考标准754所定义的表格,这说明N是一个常规数(normal number)。同时,这也指出了尾数的隐含位一定是1(sub-normal number的隐含位是0)。

        表示常规数要使用标准754定义的公式:

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})

         再度参考标准可知,在表示常规数时需要用到偏移量b(bias),且b=e_{max}=127。因此,实际指数应该是:

E-b=01101011_{2}-127_{10}

其中: 

 01101011_{2}=1\cdot 2^{6}+1\cdot 2^{5}+1\cdot 2^{3}+1\cdot 2^{1}+1\cdot 2^{0}=107

Python code:

1*(2**6)+1*(2**5)+1*(2**3)+1*(2**1)+1*(2**0)

E-b=107_{10}-127_{10}=-20_{10}

        即:

 2^{-20}=0.00000095367431640625_{10}

 Python code:

2**(-20)

        3,有效数字的尾数(trailing significand)+隐含位(hidden bit)得到真正的有效数字:

1+T\cdot 2^{1-p}=1_{2}+01010101010101010101010_{2}\cdot 2^{1-24}=1_{2}+01010101010101010101010_{2}\cdot 2^{-23}=1_{2}+0.01010101010101010101010_{2}

        这里我们分别把二进制数的整数部分和小数部分转化到十进制,对于小数部分而言有:

0.01010101010101010101010_{2}=0\times 2^{-1}+1\times 2^{-2}+...+0\times 2^{-23}=0.33333325386047363_{10}

        对于整数部分而言:

1\times 2^{0}=1_{10} 

        综合整数与小数部分最终得到:

 1_{10}+0.33333325386047363_{10}=1.33333325386047363_{10}

Python代码:

1/(2**2)+1/(2**4)+1/(2**6)+1/(2**8)+1/(2**10)+1/(2**12)+1/(2**14)+1/(2**16)+1/(2**18)+1/(2**20)+1/(2**22)

        4,合并所有计算结果,最终得到十进制的原始数N

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})=1\times 0.00000095367431640625_{10}\times1.33333325386047363_{10}=0.0000012715656794171082_{10}


单精度浮点数相对少见的数的表示(sub-normal number)

        假设一个数N在32位浮点数的系统中被表示/编译(encoding)为:

        1,还是从左至右逐一解码,先看符号位S,符号位为1,根据公式得到

(-1)^{S}=(-1)^{1}=-1

这说明N是一个负数。

        2,再看指数E。参考标准754所定义的表格,指数部分E是00000000_{2}且有效数字的尾数T不为0,这说明N是一个相对少见的数(sub-normal number)。同时,这也进一步指出了尾数的隐含位一定是0。

表示sub-normal number要使用标准754定义的公式:

(-1)^{S}\times 2^{e_{min}}\times (0+T\cdot 2^{1-p})

其中e^{min}=-126,代入上式得到: 

-1\times 2^{-126}\times (0+T\cdot 2^{1-p})

        3,有效数字的尾数(trailing significand)+隐含位(hidden bit)得到真正的有效数字:

0+T\cdot 2^{1-p}=0_{2}+01100000000000000000000_{2}\cdot 2^{1-24}=0_{2}+01100000000000000000000_{2}\cdot 2^{-23}=0.01100000000000000000000_{2}

        把二进制小数转换为十进制得到:

 0.01100000000000000000000_{2}=1\times 2^{-2}+1\times 2^{-3}=0.375_{10}

Python代码:

1/(2**2)+1/(2**3)

        4,合并所有计算结果

(-1)^{S}\times 2^{e_{min}}\times (0+T\cdot 2^{1-p})=-1\times 2^{-126}\times 0.375=-4.408103815583578\times 10^{-39}

Python代码:

-1*2**(-126)*0.375


 单精度normal number所能表示的极限

        根据标准754定义的用于表示normal number的公式:

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})

        最小的正normal number(the smallest positive normal number)是由规定范围内所允许的最小指数E和最小的尾数T所决定的,即令E=00000001,T等于0时的数:

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})=1\times 2^{1-127}\times (1+0\cdot 2^{1-p})=2^{-126} 

 2^{-126}\approx 1.175\times 10^{-38}

        最大的正normal number(the largest finite floating-point number)是由规定范围内所允许的最大的指数和最大的尾数确定的,即,令E=11111110,T为全1时的数:

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})=1\times 2^{254-126}\times (1+T\cdot 2^{1-24})=2^{127}\times(1+11111111111111111111111_{2}\cdot 2^{1-24})=2^{127}\times(1+0.11111111111111111111111_{2})

        又因为在二进制中:

1.000_{2}-0.001_{2}=0.111_{2}

        故而上面的计算公式可改为:

 (-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})=1\times 2^{254-126}\times (1+T\cdot 2^{1-24})=2^{127}\times(1+11111111111111111111111_{2}\cdot 2^{1-24})=2^{127}\times(1+0.11111111111111111111111_{2})=2^{127}\times(1+1-0.00000000000000000000001_{2})=2^{127}\times(1+1-1\times 2^{-23}_{2})=2^{127}\times(2-1\times 2^{-23}_{2})

        最终得到:

 (-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})=1\times 2^{254-126}\times (1+T\cdot 2^{1-24})=2^{127}\times(2-1\times 2^{-23}_{2})\approx3.4028234663852886\times 10^{38}


单精度sub-normal number所能表示的极限

         sub-normal number常用于表示非常小的数,所以一般情况下,他的所能表示的极限往往特指他能表示的最小的数。根据标准754定义的用于表示sub-normal number的公式:

(-1)^{S}\times 2^{e_{min}}\times (0+T\cdot 2^{1-p})=1\times 2^{-126}\times (0+T\cdot 2^{1-p}) 

        最小的正normal number(the smallest positive sub-normal number)由最小的指数和最小的尾数确定,其中,E=00000000,T为000...1的数:

1\times 2^{-126}\times (0+T\cdot 2^{1-p})=2^{-126}\times (T\cdot 2^{1-p})=2^{-126}\times 00000000000000000000001_{2}\cdot 2^{1-24}=00000000000000000000001_{2}\cdot 2^{-126+1-24}=00000000000000000000001_{2}\cdot 2^{-149}

        把二进制转换为十进制后,最终得到:

 00000000000000000000001_{2}\cdot 2^{-149}=1_{10}\cdot 2^{-149}\approx 1.401298464324817\times 10^{-45}


32位单精度浮点数的一些极限数值: 


 双精度浮点数的常规数表示

        首先,根据标准754给定的参数双精度浮点数共有64bit:

64=1+11+52

        他们分别是1bit的符号位,11bit的指数,52bit的尾数(不需要保存隐藏位,隐藏位由指数字段指出)。精度p=53,log_{10}(2^{53})\approx 15.955,大约相当于是15.96个十进制数字的精度。

        浮点数的表示太长了,书上没有给例子我这里也不再给了。具体都可以参考32bit单精度的转换方法。 


双精度normal number所能表示的极限

         根据标准754定义的用于表示normal number的公式:

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})

        最小的正normal number(the smallest positive normal number)是由规定范围内所允许的最小指数E和最小的尾数T所决定的,即令E=000...01,T等于0时的数:

(-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})=1\times 2^{1-1023}\times (1+0\cdot 2^{1-p})=2^{-1022}

 2^{-1022}\approx 2.2250738585072014\times 10^{-308}

        最大的正normal number(the largest finite floating-point number)是由规定范围内所允许的最大的指数和最大的尾数确定的,即,令E=111...10,T为全1时的数:

 (-1)^{S}\times 2^{E-b}\times (1+T\cdot 2^{1-p})=2^{1023}\times(2-1\times 2^{-52}_{2})\approx1.7976931348623157\times 10^{308}


 双精度sub-normal number所能表示的极限

         sub-normal number常用于表示非常小的数,所以一般情况下,他的所能表示的极限往往特指他能表示的最小的数。根据标准754定义的用于表示sub-normal number的公式:

(-1)^{S}\times 2^{e_{min}}\times (0+T\cdot 2^{1-p})=1\times 2^{-1022}\times (0+T\cdot 2^{1-p}) 

        最小的正normal number(the smallest positive sub-normal number)由最小的指数和最小的尾数确定,其中,E=00...000,T为000...01的数:

1\times 2^{-1022}\times (0+T\cdot 2^{1-p})=2^{-1022}\times (T\cdot 2^{1-p})=2^{-1022}\times 0000...01_{2}\cdot 2^{1-53}=0000...01_{2}\cdot 2^{-1022+1-53}=0000...01_{2}\cdot 2^{-1074}

        把二进制转换为十进制后,最终得到:

 00000000000000000000001_{2}\cdot 2^{-1074}=1_{10}\cdot 2^{-1074}\approx 4.9406564584124654417656879286822\times 10^{-324}


By the way:

        算到这个地方的时候,我发现python基本上已经算不出来了,需要引入“decimal”模块进行高精度运算。

python code: 

import decimal

# 设置精度为50位
decimal.getcontext().prec = 50

# 计算 1/(2**1074)
result = decimal.Decimal(1) / decimal.Decimal(2**1074)

print(result)


64位双精度浮点数的一些极限数值:  


(全文完) 

--- 作者,松下J27

参考文献(鸣谢): 

1,《Handbook of floating-point arithmetic》 ,second edition, Jean-Michel Muller

2,《Elementary Functions Algorithms and Implementation》,Jean-Michel Muller

3,https://en.wikipedia.org/wiki/Floating-point_arithmetic#IEEE_754:_floating_point_in_modern_computers

4,https://en.wikipedia.org/wiki/Single-precision_floating-point_format

5,https://en.wikipedia.org/wiki/Double-precision_floating-point_format

版权声明:所有的笔记,可能来自很多不同的网站和说明,在此没法一一列出,如有侵权,请告知,立即删除。欢迎大家转载,但是,如果有人引用或者COPY我的文章,必须在你的文章中注明你所使用的图片或者文字来自于我的文章,否则,侵权必究。 ----松下J27  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

松下J27

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值