赞
踩
本文将对IEEE 754 二进制表示十进制浮点数的标准进行介绍。单精度浮点和双精度浮点特性总结如下
IEEE754详解(最详细简单有趣味的介绍)
IEEE 754浮点数十六进制相互转换(32位,四字节,单精度)
IEEE754浮点数标准
首先介绍协议内容,float和double的二进制表示如下
● 符号 1bit: 0为正数、1为负数
● 阶码 float为8bit、double为11bit: 用于表示以2为底的指数,公式如下
if(阶码==0): # 非规格数,非常靠近0的数
指数 = 1 - 偏移量
elif(阶码有1有0): # 规格数
指数 = 阶码 - 偏移量
elif(阶码全为1): # 表示无穷大 或 无效数
指数 = infinity or NaN
定义无穷大和无效数好理解,那为什么还要将阶码全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} 2−47对应阶码为-47+127=80=8'b0101_0000
● 尾数 float为23bit、double为52bit: 表示二进制下的小数部分,公式如下
if(阶码==0): # 非规格数,非常靠近0的数
有效数 = {'b0.尾数} = {1'b0, 尾数} × 2^{-23}
elif(阶码有1有0): # 规格数
有效数 = {'b1.尾数} = {1'b1, 尾数} × 2^{-23}
elif(阶码全为1): # 表示无穷大 或 无效数
if(尾数全为0):
有效数 = infinity
else:
有效数 = NaN
即一般数尾数表示小数部分,整数部分是1。阶码为0时,尾数也表示小数部分,但是整数部分是0。
那么一个任意浮点数就可以用IEEE 754标准来表示。例如float 20.5
就为{1'b0,8'd131,23'b0100_1000_0000_0000_000} = 32'b0_10000011_0100100000000000000
。
高级语言中,编译器会自动将用户输入的十进制浮点小数转化成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
那么编译器是如何实现十进制小数与IEEE 754小数转换的呢?
对于正常的规格数,取值范围可以计算
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\}]
=[{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}]
∈
±
[
1
,
2
)
×
2
[
−
126
,
127
]
∈ ±[1,2)×2^{[-126,127]}
∈±[1,2)×2[−126,127]
=
(
−
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×2−126]∪[1×2−126,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×10−38]∪[1.18×10−38,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\}]
=[{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}]
∈
±
[
1
,
2
)
×
2
[
−
1022
,
1023
]
∈ ±[1,2)×2^{[-1022,1023]}
∈±[1,2)×2[−1022,1023]
=
(
−
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×2−1022]∪[1×2−1022,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×10−308]∪[1.80×10−308,2.23×10308)
根据非规格数的算法,非规格数的值域为
f
l
o
a
t
:
±
尾数
×
2
指数
=
±
(
0.
尾数
)
×
2
(
1
−
127
)
float: ±尾数×2^{指数}=±(0.尾数)×2^{(1-127)}
float:±尾数×2指数=±(0.尾数)×2(1−127)
=
[
{
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\}]
=[{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}]
∈
±
[
0
,
1
)
×
2
−
126
∈ ±[0,1)×2^{-126}
∈±[0,1)×2−126
=
(
−
1
×
2
−
126
,
1
×
2
−
126
)
=(-1×2^{-126},1×2^{-126})
=(−1×2−126,1×2−126)
≈
(
−
1.18
×
1
0
−
38
,
1.18
×
1
0
−
38
)
≈(-1.18×10^{-38},1.18×10^{-38})
≈(−1.18×10−38,1.18×10−38)
d
o
u
b
l
e
:
±
尾数
×
2
指数
=
±
(
0.
尾数
)
×
2
(
1
−
1023
)
double: ±尾数×2^{指数}=±(0.尾数)×2^{(1-1023)}
double:±尾数×2指数=±(0.尾数)×2(1−1023)
=
[
{
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\}]
=[{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}]
∈
±
[
0
,
1
)
×
2
−
1022
∈ ±[0,1)×2^{-1022}
∈±[0,1)×2−1022
=
(
−
1
×
2
−
1022
,
1
×
2
−
1022
)
=(-1×2^{-1022},1×2^{-1022})
=(−1×2−1022,1×2−1022)
≈
(
−
1.80
×
1
0
−
308
,
1.80
×
1
0
−
308
)
≈(-1.80×10^{-308},1.80×10^{-308})
≈(−1.80×10−308,1.80×10−308)
这样一来,非规格数就填补了一部分规格数中间不含零的部分。这是因为,以float
为例,非规格数尾数部分是取不到
±
1
×
2
−
126
±1×2^{-126}
±1×2−126的,所以非规格数和规格数值域的并集其实没有完全覆盖
=
(
−
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(0−127)
= [ { 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\}] =[{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}]
∈ ± [ 1 , 2 ) × 2 − 127 ∈ ±[1,2)×2^{-127} ∈±[1,2)×2−127
= ( − 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×2−127,−1×2−127]∪[1×2−127,2×2−127)
根据算法,当阶码全为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:{1′b0,8′hFF,23′h0}=+inf
{
1
′
b
1
,
8
′
h
F
F
,
2
3
′
h
0
}
=
−
i
n
f
\{1'b1,8'hFF,23'h0\} = -inf
{1′b1,8′hFF,23′h0}=−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
{1′bx,8′hFF,23′h...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:{1′b0,11′h7FF,52′h0}=+inf
{
1
′
b
1
,
1
1
′
h
7
F
F
,
5
2
′
h
0
}
=
−
i
n
f
\{1'b1,11'h7FF,52'h0\} = -inf
{1′b1,11′h7FF,52′h0}=−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
{1′bx,11′h7FF,52′h...1...0...}=NaN
首先明确一下精度的概念,无论二进制还是十进制,精度是数字集合的最小间隔
例如
8'd1200、8'd1300、8'd1400、...
每个数之间最小间隔是100所以精度就是8'd100
,8'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
那么对于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:{{1′b0.},{22′b0},1′b1}×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:{{1′b0.},{51′b0},1′b1}×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) |
---|---|---|---|---|
-126 | 1 | |||
… | … | … | … | … |
-1 | 126 | 0.5 | ≈0.999999940395 | ≈5.96046e-8 |
0 | 127 | 1 | ≈1.999999880791 | ≈1.19209e-7 |
1 | 128 | 2 | ≈3.999999761581 | ≈2.38419e-7 |
2 | 129 | 4 | ≈7.999999523163 | ≈4.76837e-7 |
… | … | … | … | … |
10 | 137 | 1024 | ≈2047.999877930 | ≈1.22070e-4 |
11 | 138 | 2048 | ≈4095.999755859 | ≈2.44141e-4 |
… | … | … | … | … |
23 | 150 | 8388608 | 16777215 | 1 |
24 | 151 | 16777216 | 33554430 | 2 |
… | … | … | … | … |
127 | 254 | ≈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,223−1]
例如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:{{1′b0.},{22′b0},1′b1}×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:{{1′b0.},{51′b0},1′b1}×2(阶码−1023)
显然尾数位宽越大,间隔也就越小,精度也就越高。
float
十进制精度约为7位有效数,double
十进制精度约为16位有效数,有待验证
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。