文章目录
- 小数表示
- 练习1
- 练习2
- IEEE浮点表示
- 数字示例
- 练习1
- 练习2
- 练习3
- 舍人
- 练习1
- 练习2
- 练习3
- 浮点运算
- C语言中的浮点数
- 练习1
- 练习2
浮点数对形如 V = x ∗ 2 y V=x*2^y V=x∗2y的有理数进行编码。它对表示非常大的数( ∣ V ∣ > > 0 |V|>>0 ∣V∣>>0)、非常接近
0
的数(
∣
V
∣
<
<
1
|V|<<1
∣V∣<<1),以及实数的
近似运算是很有用的。
小数表示
十进制表示小数:
d
m
d
m
−
1
.
.
.
d
1
d
0
.
d
−
1
d
−
2
.
.
.
d
−
n
\begin{align} d_md_{m-1}...d_1d_0.d_{-1}d_{-2}...d_{-n} \end{align}
dmdm−1...d1d0.d−1d−2...d−n
其中每个十进制数字
d
i
d_i
di的取值范围是0 ~ 9
,这个表达式所表示的值为:
d
=
∑
i
=
−
n
m
1
0
i
∗
d
i
\begin{align} d=\sum_{i=-n}^{m}10^i*d_i \end{align}
d=i=−n∑m10i∗di
小数点左边的数字表示正幂,得到整数值;小数点右边的数字表示负幂,得到小数值。
小数点向左移动1
位表示d
被10
除;小数点向右移动1
位表示d
乘以10
。
类似地,二进制表示小数:
b
m
b
m
−
1
.
.
.
b
1
b
0
.
b
−
1
b
−
2
.
.
.
b
−
n
\begin{align} b_mb_{m-1}...b_1b_0.b_{-1}b_{-2}...b_{-n} \end{align}
bmbm−1...b1b0.b−1b−2...b−n
其中每个二进制数字(比特位)
b
i
b_i
bi的取值是0
或1
,这个表达式所表示的值为:
b
=
∑
i
=
−
n
m
2
i
∗
b
i
\begin{align} b=\sum_{i=-n}^{m}2^i*b_i \end{align}
b=i=−n∑m2i∗bi
同理,小数点左边的数字表示正幂,得到整数值;小数点右边的数字表示负幂,得到小数值。
小数点向左移动1
位表示b
被2
除;小数点向右移动1
位表示b
乘以2
。
形如 0.11... 1 2 0.11...1_2 0.11...12的二进制数表示无限接近
1
的数。用 1.0 − ε 1.0 - \varepsilon 1.0−ε表示。
仅使用有限长度的编码,十进制表示法不能表示像 1 3 、 5 7 \frac{1}{3}、\frac{5}{7} 31、75这样的数,它只能表示那些能够被写成 x ∗ 1 0 y x*10^y x∗10y这样的数。同理,有限长度的二进制编码,只能表示那些能够被写成 x ∗ 2 y x*2^y x∗2y这样的数。其它的数只能被近似地表示,增加编码的长度可以提升精度。
练习1
填写下表中缺失的信息。
小数值 | 二进制表示 | 十进制表示 |
---|---|---|
1 8 \frac{1}{8} 81 | 0.001 | 0.125 |
3 4 \frac{3}{4} 43 | 0.11 | 0.75 |
25 16 \frac{25}{16} 1625 | 1.1001 | 1.5625 |
42 16 \frac{42}{16} 1642 | 10.1011 | 2.6875 |
9 8 \frac{9}{8} 89 | 1.001 | 1.125 |
47 8 \frac{47}{8} 847 | 101.111 | 5.875 |
55 16 \frac{55}{16} 1655 | 11.0011 | 3.1875 |
练习2
十进制数0.1
的二进制表示是一个无穷序列:
0.000110011
[
0011
]
.
.
.
2
\begin{align} 0.000110011[0011]..._2 \end{align}
0.000110011[0011]...2
方括号里面的部分是无限重复的。
某系统内含一个时钟,类似一个计数器,每0.1
秒加1
。有一个变量x
,该变量用24
位二进制编码十进制数0.1
,x = 0.00011001100110011001100
。程序用x
乘以这个计数器的值,来以秒为单位确定时间。
0.1 - x
的二进制表示是什么?
是 0.000000000000000000000001100 [ 1100 ] . . . 2 0.000000000000000000000001100[1100]..._2 0.000000000000000000000001100[1100]...20.1 - x
的近似的十进制值是多少?
可以观察到,0.1
的二进制表示可以写成 0.0001100 [ 1100 ] . . . 2 0.0001100[1100]..._2 0.0001100[1100]...2,
因此0.1 - x
的近似值为 0.1 ∗ 2 − 20 0.1*2^{-20} 0.1∗2−20- 计数器从
0
开始计数,实际时间100
小时以后,程序计算出的时间和实际时间相差多少?
实际时间100
小时以后,计数器的值为:100 * 3600 * 10 = 3600000
。
因此,程序计算出的时间和实际时间相差: 3600000 ∗ 0.1 ∗ 2 − 20 = 0.343 3600000 * 0.1 * 2^{-20} = 0.343 3600000∗0.1∗2−20=0.343秒。 - 假设导弹的速率为
2000
米每秒,系统对导弹的位置预测偏差了多少?
2000 * 0.343 = 687
米。
IEEE浮点表示
前面谈到的定点表示法不能很有效地表示非常大的数。IEEE
浮点标准用
V
=
(
−
1
)
s
∗
M
∗
2
E
V=(-1)^s*M*2^E
V=(−1)s∗M∗2E的形式表示一个数。
- 符号:
s = 1
表示负数,s = 0
表示正数。 - 尾数:
M
是一个二进制小数,它的范围是 [ 1 , 2 − ε ] [1,2-\varepsilon] [1,2−ε],或者 [ 0 , 1 − ε ] [0, 1-\varepsilon] [0,1−ε]。 ε \varepsilon ε是很小的接近于0
的正数。 - 阶数:
E
的作用是对浮点数加权,这个权重是2
的E
次幂(E
可能是负数)。
将浮点数的位表示划分为三个部分,分别对这些值进行编码:
- 对符号位
s
的编码,占一个bit
。 k
位的阶码字段 e x p = e k − 1 . . . e 1 e 0 exp=e_{k-1}...e_1e_0 exp=ek−1...e1e0编码阶数E
。n
位的小数码字段 f r a c = f n − 1 . . . f 1 f 0 frac=f_{n-1}...f_1f_0 frac=fn−1...f1f0编码尾数M
。
注意数与码的区别和联系。码是数的二进制表示,码和数之间有一定的转换关系,这种关系是相关标准定义的。 数 → 码 数 \to 码 数→码是编码, 码 → 数 码 \to 数 码→数是解码。
使用阶码 e x p exp exp编码阶数E
;使用小数码(或尾码) f r a c frac frac编码尾数M
。
在单精度浮点格式(C
语言float
)中,s
、exp
和frac
字段分别是1
位、k = 8
位和n = 23
位,得到一个32
位的表示。
在双精度浮点格式(C
语言double
)中,s
、exp
和frac
字段分别是1
位、k = 11
位和n = 52
位,得到一个64
位的表示。
给定表示,根据exp
的值,被编码的值可以分成3
种不同的情况:
情况1:规格化的值。
exp
字段既不是全0
也不是全1
。
阶码字段被解释为以偏置量形式表示的有符号整数。阶数E
的值是E = exp - bias
,其中exp
是无符号数,bias
等于
2
k
−
1
−
1
2^{k-1}-1
2k−1−1(对于单精度bias = 127
,对于双精度bias = 1023
)。由此产生E
的取值范围,对于单精度是-126 ~ +127
,对于双精度是-1022 ~ +1023
。
小数码字段frac
描述小数值f
,其中
0
≤
f
<
1
0\le f <1
0≤f<1,其二进制表示为
0.
f
n
−
1
.
.
.
f
1
f
0
0.f_{n-1}...f_1f_0
0.fn−1...f1f0。尾数M
定义为M = 1 + f
。
情况2:非规格化的值
exp
字段是全0
。
阶数E = 1 - bias
,尾数M = f
。
定义阶数为
1 - bias
提供了一种从非规格化值平滑转换到规格化值的方法。
非规格化数有两个用途:
1)表示数值0
。符号位是0
,阶码字段是0
,小数码字段是0
,表示+0.0
;符号位是1
,阶码字段是0
,小数码字段是0
,表示-0.0
。值+0.0
和-0.0
在某些方面被认为是不同的,有些方面是相同的。
2)表示非常接近0.0
的数。通过逐渐溢出,可能的数值分布均匀地接近于0.0
。
情况3:特殊值
exp
字段是全1
。
无穷大: frac
字段是全0
。当s = 0
时是
+
∞
+\infty
+∞,当s = 1
时是
−
∞
-\infty
−∞。无穷值表示计算溢出的结果,如两个很大的数相乘、除以零。
NaN
:frac
字段不全是0
。当一些运算的结果不能是实数或者无穷时,结果就是NaN
。如
−
1
\sqrt{-1}
−1、
∞
−
∞
\infty - \infty
∞−∞。
NaN
的意思是Not a Number
。
数字示例
已知一种6
位浮点格式:1
位的符号位,k = 3
位的阶码和n = 2
位的小数码,偏置量
2
k
−
1
−
1
=
3
2^{k-1}-1=3
2k−1−1=3。
下图展示了该浮点格式可表示的数的分布。规格化数值的最大绝对值是
(
1
+
2
−
1
+
2
−
2
)
∗
2
6
−
3
=
14
(1+2^{-1}+2^{-2})*2^{6-3}=14
(1+2−1+2−2)∗26−3=14,规格化数值的最小绝对值是
1
∗
2
1
−
3
=
0.25
1*2^{1-3}=0.25
1∗21−3=0.25。非规格化数聚集在0
附近,+0.0
和-0.0
是特殊的非规格化数。那些可表示的数并不是均匀分布的,越靠近0越稠密。
[-14, -0.25]
和[0.25, 14]
之间是规格化数,(-0.25, 0.25)
之间是非规格化数。如果要表示绝对值大于14
的数,就会溢出到
∞
\infty
∞。
已知一种8
位浮点格式:1
位的符号位,k = 4
位的阶码和n = 3
位的小数码,偏置量
2
k
−
1
−
1
=
7
2^{k-1}-1=7
2k−1−1=7。下表所示它能表示的数值:
描述 | 位表示 | 指数 | 小数 | 值 | |||||
e | E | 2^E | f | M | M*2^E | V | 十进制 | ||
0 | 0 0000 000 | 0 | -6 | 1/64 | 0 | 0 | 0 | 0 | 0.0 |
最小的非零的 非规格化数 | 0 0000 001 | 0 | -6 | 1/64 | 1/8 | 1/8 | 1/512 | 1/512 | 0.001953 |
0 0000 010 | 0 | -6 | 1/64 | 2/8 | 2/8 | 2/512 | 1/256 | 0.003906 | |
0 0000 011 | 0 | -6 | 1/64 | 3/8 | 3/8 | 3/512 | 3/512 | 0.005859 | |
... | |||||||||
最大的 非规格化数 | 0 0000 111 | 0 | -6 | 1/64 | 7/8 | 7/8 | 7/512 | 7/512 | 0.013672 |
最小的 规格化数 | 0 0001 000 | 1 | -6 | 1/64 | 0 | 8/8 | 8/512 | 1/64 | 0.015625 |
0 0001 001 | 1 | -6 | 1/64 | 1/8 | 9/8 | 9/512 | 9/512 | 0.017578 | |
... | |||||||||
0 0110 110 | 6 | -1 | 1/2 | 6/8 | 14/8 | 14/16 | 7/8 | 0.875 | |
0 0110 111 | 6 | -1 | 1/2 | 7/8 | 15/8 | 15/16 | 15/16 | 0.9375 | |
1 | 0 0111 000 | 7 | 0 | 1 | 0/8 | 8/8 | 8/8 | 1 | 1.0 |
0 0111 001 | 7 | 0 | 1 | 1/8 | 9/8 | 9/8 | 9/8 | 1.125 | |
0 0111 010 | 7 | 0 | 1 | 2/8 | 10/8 | 10/8 | 5/4 | 1.25 | |
... | |||||||||
0 1110 110 | 14 | 7 | 128 | 6/8 | 14/8 | 1792/8 | 224 | 224.0 | |
最大的 规格化数 | 0 1110 111 | 14 | 7 | 128 | 7/8 | 15/8 | 1920/8 | 240 | 240.0 |
无穷大 | 0 1111 000 | — | — | — | — | — | — | +∞ | — |
可以观察到最大的非规格化数
7
512
\frac{7}{512}
5127和最小的规格化数
8
512
\frac{8}{512}
5128之间是平滑过渡的。
当要表示的数值超过最大的规格化数的时候,会溢出到
∞
\infty
∞。
如果把浮点数中的位当作无符号整数编码看待,随着浮点数的增大,无符号数也是增大的。这么设计是为了使浮点数复用整数的比较和排序函数(对负数要特殊处理)。
单精度和双精度浮点数的表示范围如下表所示。
描述 | e x p exp exp | f r a c frac frac | 单精度 | 双精度 |
---|---|---|---|---|
0 | 00…00 | 0…00 | 0.0 | 0.0 |
最小的非零的非规格化数 | 00…00 | 0…01 | 2 − 23 ∗ 2 − 126 = 1.4 ∗ 1 0 − 45 2^{-23}*2^{-126}=1.4*10^{-45} 2−23∗2−126=1.4∗10−45 | 2 − 52 ∗ 2 − 1022 = 4.9 ∗ 1 0 − 324 2^{-52}*2^{-1022}=4.9*10^{-324} 2−52∗2−1022=4.9∗10−324 |
最大的非规格化数 | 00…00 | 1…11 | ( 1 − ε ) ∗ 2 − 126 = 1.2 ∗ 1 0 − 38 (1-\varepsilon)*2^{-126}=1.2*10^{-38} (1−ε)∗2−126=1.2∗10−38 | ( 1 − ε ) ∗ 2 − 1022 = 2.2 ∗ 1 0 − 308 (1-\varepsilon)*2^{-1022}=2.2*10^{-308} (1−ε)∗2−1022=2.2∗10−308 |
最小的规格化数 | 00…01 | 0…00 | 1 ∗ 2 − 126 = 1.2 ∗ 1 0 − 38 1*2^{-126}=1.2*10^{-38} 1∗2−126=1.2∗10−38 | 1 ∗ 2 − 1022 = 2.2 ∗ 1 0 − 308 1*2^{-1022}=2.2*10^{-308} 1∗2−1022=2.2∗10−308 |
1 | 01…11 | 0…00 | 1 ∗ 2 0 = 1.0 1*2^{0}=1.0 1∗20=1.0 | 1 ∗ 2 0 = 1.0 1*2^{0}=1.0 1∗20=1.0 |
最大的规格化数 | 11…10 | 1…11 | ( 2 − ε ) ∗ 2 127 = 3.4 ∗ 1 0 38 (2-\varepsilon)*2^{127}=3.4*10^{38} (2−ε)∗2127=3.4∗1038 | ( 2 − ε ) ∗ 2 1023 = 1.8 ∗ 1 0 308 (2-\varepsilon)*2^{1023}=1.8*10^{308} (2−ε)∗21023=1.8∗10308 |
练习把整数值转换成浮点格式对理解浮点表示很有用。
如十进制数12345
的二进制表示为[11000000111001]
,写作
1.1000000111001
∗
2
13
1.1000000111001*2^{13}
1.1000000111001∗213,用单精度(k = 8
、n = 23
、bias = 127
)的规格化数表示该值:
尾数部分是1.1000000111001
,去掉整数部分的1
,再在低位补充0
,得到小数码为[10000001110010000000000]
。
指数是13
,加上偏置量,得到140
,再在高位补充0
,得到阶码为[10001100]
。
再加上符号位0
,最终得到结果[0 10001100 10000001110010000000000]
。
可以看到,无符号编码结果除了最高位的1
,其余均作为了浮点格式的小数码部分。
练习1
假设有一种基于IEEE
浮点格式的5
位浮点表示:1
个符号位、k = 2
个阶码位、n = 2
个小数码位,偏置量bias = 1
。
e
:假定阶码字段是一个无符号整数所表示的值。
E
:阶数。
2
E
2^E
2E:阶码的权重。
f
:小数码字段表示的值。
M
:尾数。
M
∗
2
E
M*2^E
M∗2E:未归约的数值。
V
:归约后的数值。
十进制:该数的十进制表示。
填写下表中的空白项。
位 | e | E | 2 E 2^E 2E | f | M | M ∗ 2 E M*2^E M∗2E | V | 十进制 |
---|---|---|---|---|---|---|---|---|
0 00 00 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0.0 |
0 00 01 | 0 | 0 | 1 | 1 4 \frac{1}{4} 41 | 1 4 \frac{1}{4} 41 | 1 4 \frac{1}{4} 41 | 1 4 \frac{1}{4} 41 | 0.25 |
0 00 10 | 0 | 0 | 1 | 1 2 \frac{1}{2} 21 | 1 2 \frac{1}{2} 21 | 1 2 \frac{1}{2} 21 | 1 2 \frac{1}{2} 21 | 0.5 |
0 00 11 | 0 | 0 | 1 | 3 4 \frac{3}{4} 43 | 3 4 \frac{3}{4} 43 | 3 4 \frac{3}{4} 43 | 3 4 \frac{3}{4} 43 | 0.75 |
0 01 00 | 1 | 0 | 1 | 0 | 4 4 \frac{4}{4} 44 | 4 4 \frac{4}{4} 44 | 4 4 \frac{4}{4} 44 | 1.0 |
0 01 01 | 1 | 0 | 1 | 1 4 \frac{1}{4} 41 | 5 4 \frac{5}{4} 45 | 5 4 \frac{5}{4} 45 | 5 4 \frac{5}{4} 45 | 1.25 |
0 01 10 | 1 | 0 | 1 | 1 2 \frac{1}{2} 21 | 3 2 \frac{3}{2} 23 | 3 2 \frac{3}{2} 23 | 3 2 \frac{3}{2} 23 | 1.5 |
0 01 11 | 1 | 0 | 1 | 3 4 \frac{3}{4} 43 | 7 4 \frac{7}{4} 47 | 7 4 \frac{7}{4} 47 | 7 4 \frac{7}{4} 47 | 1.75 |
0 10 00 | 2 | 1 | 2 | 0 | 1 | 2 | 2 | 2.0 |
0 10 01 | 2 | 1 | 2 | 1 4 \frac{1}{4} 41 | 5 4 \frac{5}{4} 45 | 10 4 \frac{10}{4} 410 | 5 2 \frac{5}{2} 25 | 2.5 |
0 10 10 | 2 | 1 | 2 | 1 2 \frac{1}{2} 21 | 3 2 \frac{3}{2} 23 | 6 2 \frac{6}{2} 26 | 3 | 3.0 |
0 10 11 | 2 | 1 | 2 | 3 4 \frac{3}{4} 43 | 7 4 \frac{7}{4} 47 | 14 4 \frac{14}{4} 414 | 7 2 \frac{7}{2} 27 | 3.5 |
0 11 00 | - | - | - | - | - | - | ∞ \infty ∞ | - |
0 11 01 | - | - | - | - | - | - | NaN | - |
0 11 10 | - | - | - | - | - | - | NaN | - |
0 11 11 | - | - | - | - | - | - | NaN | - |
练习2
整数3510593
的十六进制表示为0x00359141
,单精度浮点数3510593.0
的十六进制表示为0x4A564504
。推导出这个浮点表示,并解释整数和浮点数表示之间的关系。
单精度浮点数的阶码有k = 8
位,小数码有n = 23
位,偏置量是127
。
整数3510593
的二进制表示为0000 0000 0011 0101 1001 0001 0100 0001
,写作
1.101011001000101000001
∗
2
21
1.1 0101 1001 0001 0100 0001 *2^{21}
1.101011001000101000001∗221。以单精度规格化数的表示方式,该数的小数码是1 0101 1001 0001 0100 0001 00
。阶码是21 + 127 = 148
的无符号二进制表示,即1001 0100
。符号位是0
。
因此单精度浮点数3510593.0
的二进制表示为0 1001 0100 1 0101 1001 0001 0100 0001 00
,即0100 1010 0101 0110 0100 0101 0000 0100
,十六进制表示为0x4A564504
。
整数的二进制表示中,除了最高位的1
,其余部分与浮点数的小数码的有效位一一对应。
练习3
- 对于一种具有
n
位小数的浮点格式,给出不能准确描述的最小正整数的公式。假设阶码字段k
足够大。
正整数肯定是规格化数。
n + 1
位小数能表示的最小的小数码是0...01
,1
前面n
个0
,因此尾数 M = 1 + 2 − ( n + 1 ) M=1+2^{-(n+1)} M=1+2−(n+1),以此为尾数的最小正整数是 ( 1 + 2 − ( n + 1 ) ) ∗ 2 ( n + 1 ) = 2 ( n + 1 ) + 1 (1+2^{-(n+1)})*2^{(n+1)}=2^{(n+1)}+1 (1+2−(n+1))∗2(n+1)=2(n+1)+1。 - 对于单精度格式
k = 23
,这个整数的数值是多少?
2 ( n + 1 ) + 1 = 2 ( 23 + 1 ) + 1 = 16 , 777 , 217 2^{(n+1)}+1=2^{(23+1)}+1=16,777,217 2(n+1)+1=2(23+1)+1=16,777,217。
舍人
因为表示方法限制了浮点数的范围和精度,所以浮点运算只能近似地表示实数运算。因此,对于值x
,我们期待能够找到与它“最接近”的能用浮点形式表示的匹配值
x
′
x'
x′,这就是舍入运算的任务。
IEEE
浮点格式定义了4
种不同的舍入方式:向偶数舍入,向零舍入,向下舍入,向上舍入。
向偶数舍入也被称为向最接近的值舍入,是默认的方式。如果某个值距离向上舍入值和向下舍入值相等,它将向上或者向下舍入,使得结果的最低有效位数字是偶数。
向零舍入把正数向下舍入,负数向上舍入。向下舍入得到
x
−
x^-
x−。向上舍入得到
x
+
x^+
x+。
方式 | 1.40 | 1.60 | 1.50 | 2.50 | -1.50 |
---|---|---|---|---|---|
向偶数舍入 | 1 | 2 | 2 | 2 | -2 |
向零舍入 | 1 | 1 | 1 | 2 | -1 |
向下舍入 | 1 | 1 | 1 | 2 | -2 |
向上舍入 | 2 | 2 | 2 | 3 | -1 |
相比于其他
3
种舍入方式,向偶数舍入可以优化对大量数据的统计偏差:当某些值距离其向上舍入值和向下舍入值相等,理论上会有50%
的数据向上舍入,50%
的数据向下舍入。
练习1
将下列2
进制小数舍入到最接近的二分之一(小数点后一位)。
-
10.01
0
2
10.010_2
10.0102
10. 0 2 10.0_2 10.02 -
10.01
1
2
10.011_2
10.0112
10. 1 2 10.1_2 10.12 -
10.11
0
2
10.110_2
10.1102
11. 0 2 11.0_2 11.02 -
11.00
1
2
11.001_2
11.0012
11. 0 2 11.0_2 11.02
练习2
飞毛腿导弹软件把0.1
的近似表示为
0.0001100110011001100110
0
2
0.00011001100110011001100_2
0.000110011001100110011002,假设使用IEEE
舍入到偶数方式来确定0.1
的二进制小数点右边23
位的近似表示
x
′
x'
x′。
-
x
′
x'
x′的二进制表示是什么?
0.0001100110011001100110 1 2 0.00011001100110011001101_2 0.000110011001100110011012 -
x
′
−
0.1
x'-0.1
x′−0.1的十进制表示的近似值是什么?
0.1
的二进制表示是 0.0001100 [ 1100 ] . . . 2 0.0001100[1100]..._2 0.0001100[1100]...2,因此 x ′ − 0.1 x'-0.1 x′−0.1的二进制表示是 0.00000000000000000000000001100 [ 1100 ] 2 0.00000000000000000000000001100[1100]_2 0.00000000000000000000000001100[1100]2,其值为 0.1 ∗ 2 − 22 0.1*2^{-22} 0.1∗2−22。 - 运行
100
小时后,计算时钟会有多少偏差?
100 ∗ 3600 ∗ 10 ∗ 0.1 ∗ 2 − 22 = 0.0858306884765625 100 * 3600 * 10 *0.1*2^{-22}=0.0858306884765625 100∗3600∗10∗0.1∗2−22=0.0858306884765625秒 - 该程序对导弹位置的预测有多大偏差?
0.0858306884765625 ∗ 2000 = 171.661376953125 0.0858306884765625*2000=171.661376953125 0.0858306884765625∗2000=171.661376953125米
练习3
考虑下列基于IEEE
浮点格式的7
位浮点表示,均没有符号位。
- 格式
A
有k=3
个阶码位,阶码的偏置量是3
。
有n=4
个小数位。 - 格式
B
有k=4
个阶码位,阶码的偏置量是7
。
有n=3
个小数位。
填写下表,必要时使用向偶数舍入的原则。
格式A | 格式B | ||
位 | 值 | 位 | 值 |
011 0000 | 1 | 0111 000 | 1 |
101 1110 | 15/2 | 1001 111 | 15/2 |
010 1001 | 25/32 | 0110 100 | 3/4 |
110 1111 | 31/2 | 1011 000 | 16 |
000 0001 | 1/64 | 0001 000 | 1/64 |
浮点运算
对于实数x
和y
,我们定义
x
+
f
y
=
R
o
u
n
d
(
x
+
y
)
x+^fy=Round(x+y)
x+fy=Round(x+y),Round
是舍入的意思。
大多数值在浮点加法下都有逆元:
x
+
f
−
x
=
0
x+^f-x=0
x+f−x=0。浮点加法满足交换律,
x
+
f
y
=
y
+
f
x
x+^fy=y+^fx
x+fy=y+fx;但不满足结合律,
(
3.14
+
1
e
10
)
−
1
e
10
=
0
(3.14+1e10)-1e10=0
(3.14+1e10)−1e10=0但
3.14
+
(
1
e
10
−
1
e
10
)
=
3.14
3.14+(1e10-1e10)=3.14
3.14+(1e10−1e10)=3.14。浮点加法满足单调性:对于任何的a
、b
、x
(除了NaN
),如果
a
≥
b
a\ge b
a≥b,那么
a
+
x
≥
b
+
x
a+x\ge b+x
a+x≥b+x,无符号和补码加法没有这个属性。
浮点乘法满足交换律、单调性;不满足结合律、分配律。
编译器优化代码时,倾向于保守,避免任何对功能产生影响的优化,即使是很轻微的影响。
C语言中的浮点数
所有的C
语言版本提供了2
种不同的浮点数据类型:单精度的float
、双精度的double
。使用向偶数舍入的舍入方式。
C
语言标准不要求机器使用IEEE
浮点,所以没有标准的方法改变舍入方式,得到-0
、无穷大值、NaN
之类的特殊值。GNU
编译器GCC
在头文件math.h
里定义了程序常数INFINITY
表示
+
∞
+\infty
+∞,定义了NaN
表示非数值。
双精度所能表示的最大的有限数,大约是 1.8 ∗ 1 0 308 1.8*10^{308} 1.8∗10308。
当在int
(4
字节)、float
(4
字节)、double
(8
字节)格式之间进行强制类型转换时,原则如下:
- 从
int
转换成float
,不会溢出,但可能被舍入。 - 从
int
或float
转成double
,因为double
有更大的表示范围和表示精度,所以能保留精确的数值。 - 从
double
转成float
,可能被溢出,也可能被舍入。 - 从
float
或double
转成int
,值会向零舍入,也可能溢出,溢出值依系统架构而不同。
练习1
完成下列宏定义。
- #define POS_INFINITY
#define POS_INFINITY INFINITY
- #define NEG_INFINITY
#define NEG_INFINITY -POS_INFINITY
- #define NEG_ZERO
#define NEG_ZERO (-1.0 / POS_INFINITY)
练习2
假定变量x
、f
和d
的类型分别是int
、float
和double
。除了f
和d
都不能等于
−
∞
-\infty
−∞、
+
∞
+\infty
+∞或者NaN
,它们的值是任意的。对于下面的每个C
表达式,证明它总是真,或者给出它为假的情况。
- x == (int)(double)x
真。double
能准确表示int
。 - x == (int)(float)x
x
的有效位大于24
时,结果为假。 - d == (double)(float)d
d
的小数码位大于23
时,float
就不能准确地表示d
。 - f == (float)(double)f
真。double
能准确表示float
。 - f == -(-f)
真。只有符号位变动,没有阶码和小数码变动。 - 1.0 / 2 == 1 / 2.0
真。都是double
类型。 - d * d >= 0.0
真。即便结果是 + ∞ +\infty +∞,只要 d ≠ N a N d\ne NaN d=NaN,就一定存在 d ∗ d > = 0.0 d * d>= 0.0 d∗d>=0.0。 - (f + d) - f == d
左边可能溢出,表达式为假。
由于编码的长度有限,与真实的整数和实数运算相比,计算机运算具有非常不同的属性。当超出表示范围时,会引起数值的截断或溢出。