当前位置:   article > 正文

IEEE 754 浮点数标准介绍_ieee754

ieee754

本文将对IEEE 754 二进制表示十进制浮点数的标准进行介绍。单精度浮点和双精度浮点特性总结如下

在这里插入图片描述

IEEE754详解(最详细简单有趣味的介绍)
IEEE 754浮点数十六进制相互转换(32位,四字节,单精度)
IEEE754浮点数标准


1. 协议

1.1. 协议内容

首先介绍协议内容,float和double的二进制表示如下

在这里插入图片描述

符号 1bit: 0为正数、1为负数

阶码 float为8bit、double为11bit: 用于表示以2为底的指数,公式如下

if(阶码==0):				# 非规格数,非常靠近0的数
	指数 = 1 - 偏移量
elif(阶码有10):			# 规格数
	指数 = 阶码 - 偏移量
elif(阶码全为1):				# 表示无穷大 或 无效数
	指数 = infinity or NaN
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

定义无穷大和无效数好理解,那为什么还要将阶码全0和不全0分开呢?这是为了将取值范围包含0,下文介绍

例如float偏移量为127、那么float类型可表示的指数为[1,254]-127 = [-126,127]

double偏移量为1023,double类型可表示的指数为[1,2046]-1023 = [-1022,1023]

例如float类型,指数为 2 56 2^{56} 256对应的阶码为56+127=183=8'b1011_0111 2 − 47 2^{-47} 247对应阶码为-47+127=80=8'b0101_0000

尾数 float为23bit、double为52bit: 表示二进制下的小数部分,公式如下

if(阶码==0):				# 非规格数,非常靠近0的数
	有效数 = {'b0.尾数} = {1'b0, 尾数} × 2^{-23}
elif(阶码有10):			# 规格数
	有效数 = {'b1.尾数} = {1'b1, 尾数} × 2^{-23}
elif(阶码全为1):				# 表示无穷大 或 无效数
	if(尾数全为0):
		有效数 = infinity
	else:
		有效数 = NaN
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

即一般数尾数表示小数部分,整数部分是1。阶码为0时,尾数也表示小数部分,但是整数部分是0。

那么一个任意浮点数就可以用IEEE 754标准来表示。例如float 20.5就为{1'b0,8'd131,23'b0100_1000_0000_0000_000} = 32'b0_10000011_0100100000000000000

1.2. 浮点数 与 定点数转换

高级语言中,编译器会自动将用户输入的十进制浮点小数转化成IEEE 754标准下的二进制浮点数。

之后硬件电路所有计算均是以IEEE 754为标准进行的,思路是将阶码和尾数分开来看,而不是将IEEE754再转化为定点数。

最终计算完毕后要输出给CPU时,编译器再将IEEE 754二进制浮点数转化为十进制浮点小数。

例如要计算20.5 + 20.25,SoC中流程是这样的

软件编译器: 20.5{1'b0,8'd131,23'b0100_1000_0000_0000_000};
			20.25{1'b0,8'd131,23'b0100_0100_0000_0000_000};
CPU:加法指令→硬件RTL
硬件RTL:{1'b0,8'd131,23'b0100_1000_0000_0000_000} + {1'b0,8'd131,23'b0100_0100_0000_0000_000} = 
		{1'b0,8'd132,23'b0100_1100_0000_0000_000} → CPU → 软件编译器
软件编译器:{1'b0,8'd132,23'b0100_1100_0000_0000_000}40.75
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

那么编译器是如何实现十进制小数与IEEE 754小数转换的呢?

2. 取值范围

在这里插入图片描述

在这里插入图片描述

2.1. 规格数值域 (阶码有1有0)

对于正常的规格数,取值范围可以计算

f l o a t : ± 尾数 × 2 指数 = ± ( 1. 尾数 ) × 2 ( 阶码 − 127 ) float: ±尾数×2^{指数}=±(1.尾数)×2^{(阶码-127)} float:±尾数×2指数=±(1.尾数)×2(阶码127)
= [ { 1 ′ b 1 , 8 ′ h F E , 2 3 ′ h 7 F _ F F F F } , { 1 ′ b 1 , 8 ′ h 1 , 2 3 ′ h 0 } ] ∪ [ { 1 ′ b 0 , 8 ′ h 1 , 2 3 ′ h 0 } , { 1 ′ b 0 , 8 ′ h F E , 2 3 ′ h 7 F _ F F F F } ] =[\{1'b1,8'hFE,23'h7F\_FFFF\},\{1'b1,8'h1,23'h0\}]∪[\{1'b0,8'h1,23'h0\},\{1'b0,8'hFE,23'h7F\_FFFF\}] =[{1b1,8hFE,23h7F_FFFF},{1b1,8h1,23h0}][{1b0,8h1,23h0},{1b0,8hFE,23h7F_FFFF}]
∈ ± [ 1 , 2 ) × 2 [ − 126 , 127 ] ∈ ±[1,2)×2^{[-126,127]} ±[1,2)×2[126127]
= ( − 2 × 2 127 , − 1 × 2 − 126 ] ∪ [ 1 × 2 − 126 , 2 × 2 127 ) =(-2×2^{127},-1×2^{-126}]∪[1×2^{-126},2×2^{127}) =(2×2127,1×2126][1×2126,2×2127)
≈ ( − 3.4 × 1 0 38 , − 1.18 × 1 0 − 38 ] ∪ [ 1.18 × 1 0 − 38 , 3.4 × 1 0 38 ) ≈(-3.4×10^{38},-1.18×10^{-38}]∪[1.18×10^{-38},3.4×10^{38}) (3.4×1038,1.18×1038][1.18×1038,3.4×1038)

d o u b l e : ± 尾数 × 2 指数 = ± ( 1. 尾数 ) × 2 ( 阶码 − 1023 ) double: ±尾数×2^{指数}=±(1.尾数)×2^{(阶码-1023)} double:±尾数×2指数=±(1.尾数)×2(阶码1023)
= [ { 1 ′ b 1 , 1 1 ′ h 7 F E , 5 2 ′ h F _ F F F F _ F F F F _ F F F F } , { 1 ′ b 1 , 1 1 ′ h 1 , 5 2 ′ h 0 } ] ∪ [ { 1 ′ b 0 , 1 1 ′ h 1 , 5 2 ′ h 0 } , { 1 ′ b 0 , 1 1 ′ h 7 F E , 5 2 ′ h F _ F F F F _ F F F F _ F F F F } ] =[\{1'b1,11'h7FE,52'hF\_FFFF\_FFFF\_FFFF\},\{1'b1,11'h1,52'h0\}]∪[\{1'b0,11'h1,52'h0\},\{1'b0,11'h7FE,52'hF\_FFFF\_FFFF\_FFFF\}] =[{1b1,11h7FE,52hF_FFFF_FFFF_FFFF},{1b1,11h1,52h0}][{1b0,11h1,52h0},{1b0,11h7FE,52hF_FFFF_FFFF_FFFF}]
∈ ± [ 1 , 2 ) × 2 [ − 1022 , 1023 ] ∈ ±[1,2)×2^{[-1022,1023]} ±[1,2)×2[10221023]
= ( − 2 × 2 1023 , − 1 × 2 − 1022 ] ∪ [ 1 × 2 − 1022 , 2 × 2 1023 ) =(-2×2^{1023},-1×2^{-1022}]∪[1×2^{-1022},2×2^{1023}) =(2×21023,1×21022][1×21022,2×21023)
≈ ( − 2.23 × 1 0 308 , − 1.80 × 1 0 − 308 ] ∪ [ 1.80 × 1 0 − 308 , 2.23 × 1 0 308 ) ≈(-2.23×10^{308},-1.80×10^{-308}]∪[1.80×10^{-308},2.23×10^{308}) (2.23×10308,1.80×10308][1.80×10308,2.23×10308)

2.2. 非规格数值域 (阶码全0)

根据非规格数的算法,非规格数的值域为

f l o a t : ± 尾数 × 2 指数 = ± ( 0. 尾数 ) × 2 ( 1 − 127 ) float: ±尾数×2^{指数}=±(0.尾数)×2^{(1-127)} float:±尾数×2指数=±(0.尾数)×2(1127)
= [ { 1 ′ b 1 , 8 ′ h 0 , 2 3 ′ h 7 F _ F F F F } , { 1 ′ b 1 , 8 ′ h 0 , 2 3 ′ h 0 } ] ∪ [ { 1 ′ b 0 , 8 ′ h 0 , 2 3 ′ h 0 } , { 1 ′ b 0 , 8 ′ h 0 , 2 3 ′ h 7 F _ F F F F } ] =[\{1'b1,8'h0,23'h7F\_FFFF\},\{1'b1,8'h0,23'h0\}]∪[\{1'b0,8'h0,23'h0\},\{1'b0,8'h0,23'h7F\_FFFF\}] =[{1b1,8h0,23h7F_FFFF},{1b1,8h0,23h0}][{1b0,8h0,23h0},{1b0,8h0,23h7F_FFFF}]
∈ ± [ 0 , 1 ) × 2 − 126 ∈ ±[0,1)×2^{-126} ±[0,1)×2126
= ( − 1 × 2 − 126 , 1 × 2 − 126 ) =(-1×2^{-126},1×2^{-126}) =(1×2126,1×2126)
≈ ( − 1.18 × 1 0 − 38 , 1.18 × 1 0 − 38 ) ≈(-1.18×10^{-38},1.18×10^{-38}) (1.18×1038,1.18×1038)

d o u b l e : ± 尾数 × 2 指数 = ± ( 0. 尾数 ) × 2 ( 1 − 1023 ) double: ±尾数×2^{指数}=±(0.尾数)×2^{(1-1023)} double:±尾数×2指数=±(0.尾数)×2(11023)
= [ { 1 ′ b 1 , 1 1 ′ h 0 , 5 2 ′ h F _ F F F F _ F F F F _ F F F F } , { 1 ′ b 1 , 1 1 ′ h 0 , 5 2 ′ h 0 } ] ∪ [ { 1 ′ b 0 , 1 1 ′ h 0 , 5 2 ′ h 0 } , { 1 ′ b 0 , 1 1 ′ h 0 , 5 2 ′ h F _ F F F F _ F F F F _ F F F F } ] =[\{1'b1,11'h0,52'hF\_FFFF\_FFFF\_FFFF\},\{1'b1,11'h0,52'h0\}]∪[\{1'b0,11'h0,52'h0\},\{1'b0,11'h0,52'hF\_FFFF\_FFFF\_FFFF\}] =[{1b1,11h0,52hF_FFFF_FFFF_FFFF},{1b1,11h0,52h0}][{1b0,11h0,52h0},{1b0,11h0,52hF_FFFF_FFFF_FFFF}]
∈ ± [ 0 , 1 ) × 2 − 1022 ∈ ±[0,1)×2^{-1022} ±[0,1)×21022
= ( − 1 × 2 − 1022 , 1 × 2 − 1022 ) =(-1×2^{-1022},1×2^{-1022}) =(1×21022,1×21022)
≈ ( − 1.80 × 1 0 − 308 , 1.80 × 1 0 − 308 ) ≈(-1.80×10^{-308},1.80×10^{-308}) (1.80×10308,1.80×10308)

这样一来,非规格数就填补了一部分规格数中间不含零的部分。这是因为,以float为例,非规格数尾数部分是取不到 ± 1 × 2 − 126 ±1×2^{-126} ±1×2126的,所以非规格数和规格数值域的并集其实没有完全覆盖 = ( − 2 × 2 127 , 2 × 2 127 ) =(-2×2^{127},2×2^{127}) =(2×2127,2×2127)。但这一部分数很小,

如果阶码为0时,依然按照规格数的算法计算的话,取值范围含不了零。
float型为例,
f l o a t : ± 尾数 × 2 指数 = ± ( 1. 尾数 ) × 2 ( 0 − 127 ) float: ±尾数×2^{指数}=±(1.尾数)×2^{(0-127)} float:±尾数×2指数=±(1.尾数)×2(0127)
= [ { 1 ′ b 1 , 8 ′ h 0 , 2 3 ′ h 7 F _ F F F F } , { 1 ′ b 1 , 8 ′ h 0 , 2 3 ′ h 0 } ] ∪ [ { 1 ′ b 0 , 8 ′ h 0 , 2 3 ′ h 0 } , { 1 ′ b 0 , 8 ′ h 0 , 2 3 ′ h 7 F _ F F F F } ] =[\{1'b1,8'h0,23'h7F\_FFFF\},\{1'b1,8'h0,23'h0\}]∪[\{1'b0,8'h0,23'h0\},\{1'b0,8'h0,23'h7F\_FFFF\}] =[{1b1,8h0,23h7F_FFFF},{1b1,8h0,23h0}][{1b0,8h0,23h0},{1b0,8h0,23h7F_FFFF}]
∈ ± [ 1 , 2 ) × 2 − 127 ∈ ±[1,2)×2^{-127} ±[1,2)×2127
= ( − 2 × 2 − 127 , − 1 × 2 − 127 ] ∪ [ 1 × 2 − 127 , 2 × 2 − 127 ) =(-2×2^{-127},-1×2^{-127}]∪[1×2^{-127},2×2^{-127}) =(2×2127,1×2127][1×2127,2×2127)

2.3. ±inf与NaN (阶码全1)

根据算法,当阶码全为1且尾数全为0是±inf,阶码全为1且尾数不全为0则是NaN

f l o a t : { 1 ′ b 0 , 8 ′ h F F , 2 3 ′ h 0 } = + i n f float: \{1'b0,8'hFF,23'h0\} = +inf float:{1b0,8hFF,23h0}=+inf
{ 1 ′ b 1 , 8 ′ h F F , 2 3 ′ h 0 } = − i n f \{1'b1,8'hFF,23'h0\} = -inf {1b1,8hFF,23h0}=inf
{ 1 ′ b x , 8 ′ h F F , 2 3 ′ h . . . 1...0... } = N a N \{1'bx,8'hFF,23'h...1...0...\} = NaN {1bx,8hFF,23h...1...0...}=NaN

d o u b l e : { 1 ′ b 0 , 1 1 ′ h 7 F F , 5 2 ′ h 0 } = + i n f double: \{1'b0,11'h7FF,52'h0\} = +inf double:{1b0,11h7FF,52h0}=+inf
{ 1 ′ b 1 , 1 1 ′ h 7 F F , 5 2 ′ h 0 } = − i n f \{1'b1,11'h7FF,52'h0\} = -inf {1b1,11h7FF,52h0}=inf
{ 1 ′ b x , 1 1 ′ h 7 F F , 5 2 ′ h . . . 1...0... } = N a N \{1'bx,11'h7FF,52'h...1...0...\} = NaN {1bx,11h7FF,52h...1...0...}=NaN

3. 精度

首先明确一下精度的概念,无论二进制还是十进制,精度是数字集合的最小间隔

在这里插入图片描述

例如8'd1200、8'd1300、8'd1400、...每个数之间最小间隔是100所以精度就是8'd1008'b1000、8'b1100、8'b0000精度就是8'b100=8'd4

所以如果有超过精度的数字,就需要将小于精度的数四舍五入截去

例如无符号数8'b1100.1101精度为8'b1,即保留4bit有效数字,那么就是8'b1100 + 8'b1 = 8'b1101。如果精度是8'b0.1,即保留5bit有效数字,那么就是8'b1100.1 + 8'b0.1 = 8'b1101.0
四舍五入方法详见RTL Arithmetic - 整数数制

也就是说数字集合中的数字按照一定间隔离散分布的,例如[1,2]间隔为0.1,那么数字集合就是{1, 1.1, 1.2, 1.3,..., 1.9, 2.0}。那么对于1.15就会四舍五入将小数第1位之后的位全部舍去,变为1.2

3.1. 浮点数的二进制精度

那么对于IEEE 754而言浮点数的二进制精度是多少呢?看间隔

对于规格数而言,间隔是

f l o a t : { { 1 ′ b 0. } , { 2 2 ′ b 0 } , 1 ′ b 1 } × 2 ( 阶码 − 127 ) float: \{\{1'b0.\},\{22'b0\},1'b1\}×2^{(阶码-127)} float:{{1b0.},{22b0},1b1}×2(阶码127)

d o u b l e : { { 1 ′ b 0. } , { 5 1 ′ b 0 } , 1 ′ b 1 } × 2 ( 阶码 − 1023 ) double: \{\{1'b0.\},\{51'b0\},1'b1\}×2^{(阶码-1023)} double:{{1b0.},{51b0},1b1}×2(阶码1023)

可见数字间隔不是均匀分布的,随着阶码变化而变化,浮点数精度是变化的,即阶码确定时,数字间隔不变。阶码越大、数字间隔越大、精度越小

在这里插入图片描述

这个精度变化是怎样的呢?WIKI给出了表格,完全版见IEEE754 WIKI

float规格数正数部分表见下

Actual Exponent(unbiased)=(Exp-127)Exp(biased)Minimum=1×2^(Exp-127)Maximum={{1'h1.},23'h7F_FFFF}×2^(Exp-127)Gap={{1'b0.},{22'b0},1'b1}×2^(Exp-127)
-1261
-11260.5≈0.999999940395≈5.96046e-8
01271≈1.999999880791≈1.19209e-7
11282≈3.999999761581≈2.38419e-7
21294≈7.999999523163≈4.76837e-7
101371024≈2047.999877930≈1.22070e-4
111382048≈4095.999755859≈2.44141e-4
231508388608167772151
2415116777216335544302
127254≈1.70141e38≈3.40282e38≈2.02824e31

从表中可知,用户在高级语言中写的小数在Minimum~Maximum的哪个区间就对应着怎么样Gap,比Gap更加精确的数无法表示。即只能表示 M i n i m u m + d × G a p , d ∈ [ 0 , 2 23 − 1 ] Minimum + d×Gap, d\in[0,2^{23}-1] Minimum+d×Gap,d[0,2231]

例如Exp为150时,Gap为1,那么浮点数可以表示8388608和8488609,但无法表示8388608.5,编译器会四舍五入至8488609,而8388608.1就会四舍五入至8388608。

再如Exp为126,Gap为5.96046e-8,浮点数0.50000006, 会被舍入为0.5000000596046

增加尾数位宽→增加精度

那么如何增加浮点数精度呢?

由于间隔决定精度,所以减少数字集合中的每个离散值之间的间隔即可。如何减少间隔?间隔定义如下

f l o a t : { { 1 ′ b 0. } , { 2 2 ′ b 0 } , 1 ′ b 1 } × 2 ( 阶码 − 127 ) float: \{\{1'b0.\},\{22'b0\},1'b1\}×2^{(阶码-127)} float:{{1b0.},{22b0},1b1}×2(阶码127)

d o u b l e : { { 1 ′ b 0. } , { 5 1 ′ b 0 } , 1 ′ b 1 } × 2 ( 阶码 − 1023 ) double: \{\{1'b0.\},\{51'b0\},1'b1\}×2^{(阶码-1023)} double:{{1b0.},{51b0},1b1}×2(阶码1023)

显然尾数位宽越大,间隔也就越小,精度也就越高。

3.2. 浮点数的十进制精度

float十进制精度约为7位有效数,double十进制精度约为16位有效数,有待验证

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/258354
推荐阅读
相关标签
  

闽ICP备14008679号