IEEE754-2008 标准详解(二):二进制交换格式编码

IEEE754-2008 标准详解(二):二进制交换格式编码


本文为原创文章,转载请注明出处,并注明转载自“黄邦勇帅(原名:黄勇)”
本文是对《C++语法详解》一书相关章节的增补,以增强读者对浮点数的理解,《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

有兴趣的读者可参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。


2.1 二进制交换格式编码的格式


目前计算机通常使用的是二进制交换格式编码。

一、讲解之前的说明

1、二进制交换格式编码是对二进制浮点数据的编码,因此,在编码之前,需要把真实浮点数据转换为二进制形式。

2、二进制交换格式编码的真实浮点数据均使用形如(−1)s× m × be 的指数表示法,其中尾数m为二进制小数,基数b默认为2,为便于讲解,e使用十进制整数。
3、注意:编码一词既是动词,也是名词,读者需从上下文区分。如,“把9编码为10012”,这里的“编码”是动词,再如,“10012是9的编码”,这里的编码是名词,指的是9被编码后的二进制位串。

二、二进制交换格式编码的各字段详解

1、IEEE 754把浮点数据的编码分为3个字段(或部分),即:

  • 一位符号位S

  • w位偏移指数E,

    E = e + bias //公式2.1

    其中bias是偏移值(详见后文),e是真实指数

  • t位末尾有效数字段T (trailing significand field),其中

    t = p − 1, //T的宽度,==公式2.2 ==
    T = d1 d2…dp−1; //T的值,公式2.3

    尾数m的前导位d0隐式编码在偏移指数E中,注意:T仅仅存储了尾数的小数部分,最高有效位d0并不包含在T中。

2、图XXX显示了二进制交换格式编码的格式,图中同时给出了float、double各字段所占的宽度。通常float型使用总宽度32位存储,而double使用64位总宽度存储。注:总宽度就是指的存储宽度,使用k表示。

3、注意:在存储宽度k (即,总宽度)是64或32的倍数且≥128的情况下,各参数可使用以下公式计算,(其中round()四舍五入到最接近的整数,ceiling()表示向上取整):

k = 1+w+t=w+p=32 × ceiling((p + round(4 × log2(p + round(4 × log2( p))− 13)) − 13) /32)
w = k – t − 1 =k − p = round(4 × log2(k)) − 13
t= k – w − 1 =p − 1 = k − round(4 × log2(k)) + 12
p = k − w = t +1 = k − round(4 × log2(k)) + 13
emax = bias = 2(w−1) − 1 //公式2.4
emin = 1 − emax = 2 − 2(w−1) //公式2.5

注:以上公式中带有round()或ceiling()的公式不适合于k<64的情形,如w = round(4 × log2(k)) − 13不适合于k为16位或32位的情形,但w = k – t − 1 =k − p仍适用于k = 16或k = 32的情形。

4、注意区分以下概念

  • E是指的偏移指数,是已编码的值;而e是真实指数,是未编码的值。
  • 注意:末尾有效数与末尾有效数字段T的区别,末尾有效数是m的小数部分,T是用于编码末尾有效数的。
  • m的前导有效数d0被隐式编码在E中

在这里插入图片描述
5、表XXX给出了二进制编码格式各参数的取值

在这里插入图片描述


2.2 二进制交换格式编码规则及方法


注意区分编码之前的数据和参数与编码之后的数据和参数,否则很容易弄混淆。浮点数据表示法表示的是编码之前的真实值,因此,指数表示法中的参数e、emin、emax、p、b都是指的编码之前的真实参数,而E、T、S是指的编码之后的二进制位串,而t、w、k指的是编码之后的二进制位串的长度(真实数据的长度由有效数位数p指定)

一、指数的编码规则

1、偏移指数和偏移值的概念

IEEE 754使用移码的形式来编码真实指数e,编码后的真实指数被称为偏移指数E。移码就是在将数据存入计算机时加上某个固定的数,这个固定的数被称为指数偏移值,简称偏移值,使用bias表示。使用移码的好处是可以避免指数出现负数,从而可以不用存储指数的符号位。

2、偏移值bias

IEEE 754规定,二进制交换格式编码的偏移值就是emax,即,偏移值的公式是

bias = emax = 2k−p−1 −1 = 2w−1 − 1 //公式2.6

其中w为存储偏移指数E的位数长度,对于float型,bias = 28−1 − 1=127。

3、偏移指数E的编码

  • 1)、规约数的偏移指数
    规约数只需把真实指数e加上偏移值就得到了编码后的偏移指数E,因此

    E = e + bias = e + 2w−1 − 1 //公式2.7

    比如1.11012× 23,其真实指数e = 3,对于float型,E = 3+127 = 130 = 1000 00102,因此E = 1000 00102

  • 2)、非规约数的偏移指数

    IEEE754规定,非规约数的偏移指数E比规约数的偏移指数小1,可使用以下公式计算,也可直接编码为0

    E非 = e + bias − 1 ,或 E = 0 //公式2.8

    由于非规约数的真实指数e = emin (详见前文),因此,
    

    E = e + bias −1 = emin + emax−1 = 0

  • 3)、0的偏移指数

    直接使用0编码即可。注:0和非规约数怎样区分,详见后文解码部分的内容。

  • 4)、∞和NaN的偏移指数

    ∞和NaN的偏移指数都使用全1编码,即

    E = ENaN = 2w−1 //公式2.9

    注:∞和NaN怎样区分,详见后文解码部分的内容。

  • 5)、同理在将偏移指数E转换为真实指数e时需要减去偏移值,比如若E=1000 00102 = 130,对于float型,则真实指数e = 130 − 127 = 3。

4、真实指数e的最小值

由于emin = 1 − emax,所以

emin = 1 − emax = 2 − 2w−1 //公式2.10

因此,真实指数e的取值范围为

2 − 2w−1 ≤ e ≤ 2w−1 − 1 (即emin ≤ e ≤ emax) //公式2.11

对于float型,e的取值范围为 −126 ≤ e ≤ 127

二、其他字段的编码规则

1、符号位S,若为正则编码为0,为负则编码为1。

2、有限浮点数的尾数m

  • IEEE 754使用原码的形式编码有限浮点数的尾数m的小数部分,即末尾有效数字段T为m小数部分的原码。
  • m的前导有效数d0被隐式编码在E中(原因见下文),注意:隐式编码并没有真正的存储该数据。如下所示:
    • 若该数是规约数,则隐式编码为1
    • 若该数是非规约数,则隐式编码为0
    • 若该数是0,IEEE754并未说明应编码为多少,但,理论上来讲,应是0,因为,该数据都已经表示0了,所以尾数也应必然是0,那么,最高有效位也应为0。
    • 若是无穷大,IEEE754也未说明应编码为多少,但,理论上来讲,应是1。
    • 若是NaN,其编码规则见下文
      注:怎样从编码判断或还原为真实浮点数据,在后文会专门讲解。

3、从前一章的讲解可知,规约数的最高有效位d0位于1 ≤ d0 < b之间,对于二进制交换格式,由于基数b = 2,因此,规约数的最高有效位一定是1,而非规约数的最高有效位一定是0 (前一章已讲过,非规约数的d0 = 0),因此,只要明确了该数是规约数还是非规约数,其最高有效位就没必要存储了,这样一来,在存储时就可以隐藏最高位(即,没必要存储),从而可以多存储一位二进制数,因此对于float型真实二进制浮点数的有效数(尾数)位数是24位(即p = 24),而不是23位(只存储了23位数),对于double则是53位有效数位数(即p= 53),而不是52位。因此IEEE 754规定,在存储浮点数的尾数时最高位可以省略,而将小数点后的纯小数部分存入计算机中

4、有效载荷(payload)的编码规则 (见图XXX所示)

NaN的有效载荷编码在末尾有效数字段T中,这可能是诊断信息。其规则如下:

  • T的第一位d1用于识别NaN的类型(即,sNaN或qNaN)
    • qNaN应该以末尾有效数字段T的第一个位d1为1进行编码。
    • sNaN应该以末尾有效数字段的第一个位为0 (即d1 = 0)进行编码,此时末尾有效数字段的其他位必须是非零的,以区别NaN和无穷大。
    • 若将sNaN的d1设为1,T的其余位保持不变,则sNaN成为qNaN
  • 对于二进制交换格式,有效载荷被编码在末尾有效数字段的p−2个最低有效位中,即d2 ~ dp−1,编码有效载荷。

在这里插入图片描述

三、二进制交换格式的编码方法及判断真实浮点数据的类型

1、以下讲解均是指的正规约数和正非规约数,负数可根据类似规则同理推出。

2、浮点数的规格化

当一个浮点数不做明确规定时会有很多种表示法,比如0.4可以表示为0.04×101,0.004×102,0.0004×103,40×10−2等,因此把符合以下格式的浮点数称为规格化数或规格化浮点数

±d0.d1d2…dp-1 × be (前导有效数d0≠0) //规格化数的格式,公式2.12

若浮点数不能达到这一要求,则需进行移位使其达到这一要求,对浮点数进行的这一操作被称为浮点数的规格化。从此处可见,规约数是规格化数,但规格化数的范围比规约数的范围大,也就是说,规格化数不一定是规约数。而非规约数则不能表示为规格化数的形式,因为若非规约数表示为规格化数的形式后,则指数必然会超出取值范围。

3、编码及判断真实浮点数据类型的方法

  • 1)、规格化:根据情况左移小数点(增大真实指数)或右移小数点(减小真实指数),将其规格化为规格化数

  • 2)、以上过程完成后,判断数据的类型,然后根据相应类型的编码规则进行编码即可,类型判断方法如下:

    • 若min ≤ e ≤ emax,则该数是规约数,此时,尾数m ≥ 1,或d0 = 1。
      此时可能产生尾数溢出的情形(即,尾数长度超过p位),可采用舍入的方法解决,即,将尾数舍入为p位。

    • 若e < emin,则再次左移小数点(增大真实指数),直到e = emin,此时,尾数m位于0 < m < 1间,或d0 = 0,此时,该数是非规约数或是比最小非规约数更小的数。非规约数(和零)用预留的偏移指数值(即E = 0)进行编码,此时可能出现以下情形

      • 尾数溢出,即该数在非规约数范围内,但尾数长度超过p位,此时可将尾数舍入为p位。
      • 下溢,即尾数舍入处理后其值为0,也就是说,该数比最小非规约数还要小,通常采用的办法是,将该数近似为0或近似为最小非规约数。
    • 若e > emax,则该数是无穷大、NaN或指数上溢,此时,尾数m ≥ 1。具体细节IEEE754并未讲解清楚怎样的数为无穷大,怎样的数为NaN。
      以下为本人个人推断,以float型为例(其emax = 127,因此,比emax大的最小的指数值是128),实现IEEE754标准的软件(如编译器)不一定是按以下规则执行的,他们有可能会把所有e > emax的数都作为无穷大处理。

      • 1.0…02 ×2128应是无穷大
      • 1.x…x2 ×2128应是NaN,其中x不全为0。
      • 1.x…x2 ×2n ,其中n >128,则该数为指数上溢。
      • 最高位一定是1,因为若不是1,可通过右移小数点(减小真实指数)的方式使其成为1,如0.12 ×2128 = 1.02 ×2127 ,0.12 ×2129 = 1.02 ×2128

4、需要注意的是,规约数真实指数e的最小值与非规约数的真实指数e的值是相等的,都为e = emin,这时应注意对规约数与非规约数的区分(根据尾数m是否大于等于1来判断)。比如,float型二进制浮点数,1.02 × 2−126 是规约数,而0.12 × 2−126 是非规约数,再如,1.01112 × 2−126是规约数,而 0.101112 × 2−126 是非规约数

示例1:假设二进制浮点数为−11001.00011101012(若不是二进制数,应转换为二进制的形式),将其存储为float型浮点数

1)、规格化:−1 1001.0001 1101 012 = −1.1001 0001 1101 012×24

2)、判断类型:由于−126 ≤ e = 4 ≤127,因此该数是规约数

3)、编码:

  • 末尾有效数字段T = 100 1000 1110 1010 0000 0000 ,共23位,不足位在末尾添0,规格化后的真实数的最高有效位1被隐式存储在E中
  • 偏移指数E = e + bias = 4 + 127 = 131 = 1000 0011
  • 符号位S = 1,因为真实值为负数

4)、最终编码后的值如下所示:

在这里插入图片描述

示例2:编码二进制float型数1101.012 × 2−129

1)、规格化:因为1101.012 × 2−129 = 1.101012 × 2−126

2)、判断类型:由于e = emin且m > 1,因此该数不是非规约数,但该数是规约数,

3)、编码:

  • 末尾有效数字段T = 101 0100 0000 0000 0000 0000 (规格化后的真实数的最高有效位1不用存储,共23位,不足位在末尾添0)
  • 偏移指数E = e + bias = −126 + 127 = 1
  • 符号位S = 0

4)、最终结果如下图所示
在这里插入图片描述

示例3:编码二进制float型数1101.012 × 2−130

1)、规格化:因为1101.012 × 2−130 = 1.101012 × 2−127

2)、判断类型:由于e < emin,需再次左移小数点直到e = emin,因此,
1101.012 × 2−130 = 1.101012 × 2−127 = 0.1101012 × 2−126
因此,该数是非约规数

3)、编码:

  • 末尾有效数字段T = 110 1010 0000 0000 0000 0000 (真实数的最高有效位0不用存储,共23位,不足位在末尾添0)
  • 偏移指数E = e + bias − 1 = −126 + 127 − 1= 0,注:若判断出该数为非规约数,也可直接将E编码为0。
  • 符号位S = 0

4)、最终结果如下图所示

在这里插入图片描述

5、从以上示例可看到,当二进制的尾数位数超过23位时,会出现数据溢出的情况,这时就需要进行舍入处理。除了尾数会溢出,指数同样存在溢出的情况。


2.3 二进制交换格式解码规则及方法


一、二进制交换格式解码规则

1、NaN

若 E = 2w − 1 (即全为1),且T ≠ 0,无论S如何,则这个数是NaN(即不是一个数),可能是qNaN,也可能是sNaN,真实浮点数据v = NaN

2、无穷大

若E = 2w-1(即全为1),且T = 0,则这个数是无穷大(有正负无穷大之分,与符号位S有关),真实浮点数据v = (−1) S × (+∞)

3、0

  • 1)、满足以下条件的数是0(有正负0之分,与符号位S有关),

    • E = 0 (即全为0),可见,E是一个固定值。
    • 且T = 0
  • 2)、0的真实指数e

    IEEE 754规定,0的真实指数为emin。因此

    e = emin = 1 − (2w−1 − 1 ) = 2 − 2w−1 //0的真实指数,公式2.12

    对于float型而言,e = emin = −126

  • 3)、0的真实浮点数据为v = (−1) S × (+0)

4、规约数

  • 1)、满足以下条件的数是规约数,

    • E在0<E<2w−1之间,因为E是整数,因此,
      1 ≤ E ≤ 2w− 2 //公式2.13
      也就是说,E不是全0或全1。
      对于float而言1 ≤ E ≤ 254
    • 且具有隐藏的前导有效数1,即d0 = 1
  • 2)、规约数的真实指数e及其取值范围

    e = E − bias = E − (2w−1 − 1) //规约数的真实指数,公式2.14

    e的取值范围的推导过程如下:

    由于,1 ≤ E ≤ 2w− 2 ,bais = emax,emin = 1 − emax,因此
    e = E − bias = E − (2w−1 − 1)
    ⟹ 1 − bias ≤ E− bias ≤ 2w− 2 − bias
    ⟹ 1 − emax ≤ e ≤ 2w− 2 − (2w−1 − 1 )
    ⟹ emin ≤ e ≤ 2w− 2w−1 − 1
    ⟹ emin ≤ e ≤ 2w−1 − 1
    ⟹ emin ≤e ≤ emax //规约数e的取值范围,公式2.15
    ⟹ 2−2w−1≤ e ≤ 2w−1 −1 //规约数e的取值范围,公式2.16

    对于float型而言,e = E − 27 + 1= E − 127,位于−126 ≤ e ≤ 127之间

  • 3)、规约数的真实浮点数据为

    v = (−1) S ×(1.T)×2 E−bias //规约数的真实浮点数据,公式2.17

    对于float型而言,v = (−1) S × (1.T) × 2 E−127
    注:1.T是指的二进制数字

5、非规约数

  • 1)、满足以下条件的数是非规约数,

    • E = 0(即全为0),可见,E是一个固定值。
    • T ≠ 0
    • 具有隐藏的前导有效数0,即d0 = 0。
  • 2)、非规约数的真实指数e

    IEEE 754规定,非规约数的真实指数为emin,或者说,非规约数的真实指数应比实际计算出来的值大1。因此

    e = emin = 0 −(2w−1 − 1 )+1 = 2 − 2w−1 //非规约数的e,公式2.18

    对于float型而言,e = emin = 2 − 27 = −126
    注:实际解码时,使用公式e = emin = 1 − emax计算更为快捷简便,此处使用“真实指数应比实际计算出来的值大1”的目的是为了讲明白其更进一层的原理。
    非规约数的偏移指数E可使用以下公式计算(也可直接编码为0,前文已讲过)
    E = e + bias − 1

  • 3)、非规约数的真实浮点数据为

    v = (−1) S × (0.T) × 2 emin //非规约数的真实浮点数据,公式2.19

    对于float型而言,v = (−1)S·(0.T)·2-126
    注:0.T是指的二进制数字

二、二进制交换格式解码方法及步骤

1、由前小节的编码规则及本小节解码规则讲解可见

  • 当E = 0时(即全为0),用于编码 ± 0和非规约数

  • 当E = 2w-1时(即全为1),用于 ±∞ 和NaN的编码

  • 当1 ≤ E ≤ 2w-2时(即,只要不是全0或全1时),用于编码规约数

    因此,根据编码判断浮点数据的类型时,应首先判断偏移指数E的取值,之后再结合末尾有效数字段T来判断浮点数据的类型。只要偏移指数E不是全0或全1(即在取值范围内),此时无论尾数为何值,都可确定该数是规约浮点数,规约数含有隐含的前导有效数1。注意:规约浮点数与末尾有效字段T的值是否为0没有关系。表XXX是对二进制交换格式编码规则的总结,以及根据编码判断浮点数据类型的方法,
    在这里插入图片描述

2、将编码还原为真实二进制数时,只需在判断为规约数或非规约数后,使用相应的公式即可还原为真实浮点数据,注:0,∞,NaN可直接判断得出

示例4:float型浮点数的编码形式如下,试还原为真实浮点数

0 1110 0011 0000 0000 0000 0000 0000 000(共32位)

解:

  • 1)、float型共32位,其中符号位S占据最高位的1位,偏移指数E占据其后的8位(即w = 8),末尾有效数字段T占据最后的23位(即t =23)。

  • 2)、判断类型
    由于E所在8位不全为0,也不是全为1,所以该数是一个规约数。

  • 3)、计算真实指数e
    由于E = 1110 00112 = 227,因此,真实指数e = E − bias = 227−127 = 100

  • 4)、计算尾数m
    T = 0000 0000 0000 0000 0000 000(末尾23位全为0),但由于规约数隐含的最高有效位为1,即d0 = 1,因此,其尾数应在T的前面加上隐藏了的最高位1,因此,尾数
    m = 1.0000 0000 0000 0000 0000 000

  • 5)、还原后的真实二进制数是(判断出是规约数后,也可直接使用公式还原)
    v = (−1) S ×(1.T)×2 E−bias = (-1)0×1.0000 0000 0000 0000 0000 0002×2227-127=1.02×2100

示例5:float型浮点数的编码形式如下,试还原为真实浮点数

0 1110 0011 0000 0000 0000 1111 0110 001(共32位)

解:

  • 1)、float型共32位,其中S占1位,E占8位(即w = 8),T占23位(即t =23)。

  • 2)、判断类型
    由于偏移指数E所在8位不全为0,也不是全为1,末尾有效数字段T的23位非0,所以该数是一个规约数。

  • 3)、计算真实指数e
    由于E = 1110 00112 = 227,因此,真实指数e = E − bias = 227-127 = 100

  • 4)、计算真实尾数m
    由于T = 0000 0000 0000 1111 0110 001(末尾23位),且是规约数,因此,尾数应在T的前面加上隐藏了的最高位1,即d0 = 1,因此,尾数
    m = 1.0000 0000 0000 1111 0110 001

  • 5)、因此还原后的真实二进制数是
    v = (−1) S ×(1.T)×2 E−bias
    =(−1)0×1.0000 0000 0000 1111 0110 0012×2227-127
    =1.0000 0000 0000 1111 0110 0012×2100

示例6:float型浮点数的编码形式如下,试还原为真实浮点数

0 0000 0000 0000 0000 0000 0000 1100 000(共32位)

解:

  • 1)、判断类型
    由于E所在8位全为0,T所在23位非0,所以该数是一个非规约数。

  • 2)、最高位0表示符号位S

  • 3)、计算e
    由于该数是非规约数,因此,e为
    e = emin = 0 − (2w−1 − 1) + 1 = −126

  • 4)、计算m
    由于T = 0000 0000 0000 0000 1100 000,且是非规约数,因此,尾数应在T前面加上隐藏了的最高位0,即d0 = 0,因此,尾数m = 0.0000 0000 0000 0000 1100 000

  • 5)、因此还原后的真实二进制数是:
    v = (−1) S × (0.T) × 2 emin
    = (−1)0×0.0000 0000 0000 0000 1100 0002×2-126
    = 0.0000 0000 0000 0000 112×2-126


2.4 二进制交换格式总结


一、二进制交换格式下的规约数与非规约数最大最小值的计算

1、规约数和非规约数最大最小值的计算

由前文讲解可知(负数的计算方法类似),

  • 最小的正规约数是(具有隐藏的前导有效数1)

    1 × b emin = b emin //最小的正规约数,公式2.20

    对于float型,此时E = 0000 0001,e = −126,T = 0,因此,最小正规约数是

    1 × 2−126 ≈ 1.175494351 × 10−38 ≈ 1.18 × 10−38 //float型最小正规约数

  • 最大的正规约数是(具有隐藏的前导有效数1)

    (b−b1−p) × b emax //最大的正规约数,公式2.21

    对于float型,此时E = 1111 1110,e = 127,T = 111 1111 1111 1111 1111 1111,最大正规约数是

    (2 − 2 −23) × 2127 ≈ 3.40282 × 1038 ≈ 3.40 × 1038 //float型最大正规约数

  • 最小的正非规约数是(具有隐藏的前导有效数0)

    b1−p × b emin //最小的非正规约数,公式2.22

    对于float型,此时E = 0,e =−126, T = 000 0000 0000 0000 0000 0001,最小正非规约数是

    2 −23×2−126=2−149≈1.4012985×10−45 ≈1.40×10−45 //float型最小正非规约数

  • 最大的正非规约数是(具有隐藏的前导有效数0)

    (1− b1−p ) × b emin //最大的非正规约数,公式2.23

    对于float型,此时E = 0,e =−126,T = 111 1111 1111 1111 1111 1111,最大正非规约数是

    (1−2−23) ×2−126 ≈1.175494211×10−38 ≈1.18×10−38 //float型最大正非规约数

4、表XXXX为float和doulbe规约数和非规约数的取值范围,表XXX为C++浮点数的取值范围

在这里插入图片描述

在这里插入图片描述

二、二进制交换格式总结

表XXX为二进制交换格式总结

在这里插入图片描述
在这里插入图片描述


作者:黄邦勇帅(原名:黄勇)

2021年11月28日

在这里插入图片描述


猜你喜欢

转载自blog.csdn.net/hyongilfmmm/article/details/121599599