信息的表示和处理(4):浮点数
1.1 二进制小数的定点表示
- 符号"."变成了二进制的点,点左边的位的权是2的正幂,右边的位的权是2的负幂。如 101.1 1 2 101.11_2 101.112 表示
1 ∗ 2 2 + 0 ∗ 2 1 + 1 ∗ 2 1 + 1 ∗ 2 − 1 + 1 ∗ 2 − 2 = 5 3 4 1 * 2^2 + 0 * 2^1 + 1 * 2^1 + 1 * 2^{-1} + 1 * 2^{-2} = 5\frac{3}{4} 1∗22+0∗21+1∗21+1∗2−1+1∗2−2=543 。
- 二进制小数点左移一位相当于这个数被2除,右移一位相当于该数乘2。
- 形如 0.11... 1 2 0.11...1_2 0.11...12 的数表示刚好小于1 的数。如 0.11111 1 2 0.111111_2 0.1111112 表示 63 64 \frac{63}{64} 6463 ,可以用简单表达法1.0- ε \varepsilon ε 表示。
- 有限长度的编码,并不能表示 1 3 \frac{1}{3} 31 和 5 7 \frac{5}{7} 75 这样的数。小数的二进制表示法只能表示那些能被写成 x ∗ 2 y x * 2^y x∗2y 的数,其他的值只能被近似地表示。可通过增加二进制表示的长度提高表示的长度。
1.2 IEEE浮点表示
-
定点表示法不能有效表示非常大的数,因此可用浮点标准 V = ( − 1 ) s ∗ M ∗ 2 E V = (-1)^s * M * 2^E V=(−1)s∗M∗2E的形式表示一个数。
- 符号s 决定这个数是负数(s=1)还是正数(s=0),数值0的符号位做特殊处理。
- 尾数M 是一个二进制小数,范围是1~2- ε \varepsilon ε ,或者是0~1- ε \varepsilon ε 。
- 阶码E 的作用是对浮点数加权,权重是2的E次幂(可能是负数)
注意,这里的s、M、E都是可以通过二进制数编码的数。
-
将浮点数的位表示划分为三个字段,分别对s、M、E进行编码
- 一个单独的符号位s直接编码符号s
- k位的阶码字段 e x p = e k − 1 . . . . e 1 e 0 exp=e_{k-1}....e_{1}e_{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,但是编码出来的值依赖于阶码字段是否等于0
浮点格式
-
C语言中的单精度浮点格式(float),符号位s、阶码exp和小数frac的位数分别为1位,k=8位和n=23位,加起来共32位的位表示。
-
双精度浮点格式(double)中,符号位s、阶码exp和小数frac的位数分别为1位,k=11位和n=52位,加起来共64位的位表示。
浮点数值的分类
根据exp的值,编码值可分成三种情况:
-
规格化的浮点数(exp的位模式既不全为0,也不全为1)
- 当exp的位模式既不全为0,也不全为1时(当全为1时,单精度数值为255,双精度数值为2047),浮点数是规格化的。
- 阶码E的定义:
- 对规格化的浮点数来说,阶码字段被解释为以偏置形式表示的有符号整数,即阶码 E = e − B i a s E=e-Bias E=e−Bias ,其中e是无符号数,位表示是 e k − 1 . . . . e 1 e 0 e_{k-1}....e_{1}e_{0} ek−1....e1e0 (实际上,即上面提到的阶码字段exp所对应的值),而 B i a s = 2 k − 1 − 1 Bias = 2^{k-1} - 1 Bias=2k−1−1 (单精度格式下Bias=127,双精度格式下Bias=1023)。
- 由此产生的阶码E的取值范围,单精度是-126 ~ +127,双精度是-1022 ~ +1023
- 尾数M的定义:
- 小数字段frac被解释为小数值f,其中 0 ≤ f < 1 0\le f \lt 1 0≤f<1 ,二进制表示为 0. f n − 1 . . . f 1 f 0 0.f_{n-1}...f_1f_0 0.fn−1...f1f0 ,即二进制小数点在小数的最高有效位的左边,小数值f表示一个数的小数部分。
- 尾数M=1+f,这种方式叫隐含的以1开头的表示。因此M也可看成是一个二进制表达式为 1. f n − 1 . . . f 1 f 0 1.f_{n-1}...f_1f_0 1.fn−1...f1f0 的数字。由定义可知, 1 ≤ M < 2 1\le M \lt 2 1≤M<2 。
-
非规格化的浮点数(exp全0)
- 当阶码域全0的时候,表示的数就是非规格化形式。此时阶码 E = 1 − B i a s E=1-Bias E=1−Bias ,尾数M=f,即此时M不包含隐含的开头的1。
- 非规格化数的用途
- 提供了一种表示数值0的方法。用规格化数表示时,因为 M ≥ 1 M\ge1 M≥1 ,所以规格化数不能表示0。当阶码和尾数的位表示全为0时,符号位为0,可得到+0.0的值;符号位为1,其他域为0时可得到-0.0的值。
- 非规格化数可表示那些非常接近于0.0的数。它提供了一种称为逐渐溢出的属性,可能的数值分布均匀地接近于0.0。
-
特殊值(exp全为1)
当阶码全为1时,出现特殊值。又分几种情况:- 小数域全为0时,得到的值表示无穷:
- 符号位s=0时表示正无穷。
- 符号位s=1时表示负无穷。
- 小数域非0时,得到的值为"NaN",即不是一个数(Not a Number)的缩写。当一些运算结果不能是实数或无穷时(如根号-1),就会返回NaN值。
- 小数域全为0时,得到的值表示无穷:
浮点数的数字示例
重要浮点数的表示和数字值,以及整数值转换成浮点形式:
1.3 舍入
浮点数的表示方法限制了浮点数的范围和精度,因此浮点运算只能近似表示实数运算。
舍入方式
- 向偶数舍入:将数字向上或者向下舍入,使得结果的最低有效数字是偶数。
- 向零舍入:把正数向下舍入,把负数向上舍入。(即向靠近0的方向舍入)
- 向下舍入:把正数和负数都向下舍入,得到 x − x^- x− ,使得 x − ≤ x x^- \le x x−≤x 。
- 向上舍入:把正数和负数都向上舍入,得到 x + x^+ x+ ,使得 x ≤ x + x \le x^+ x≤x+ 。
将偶数舍入法应用到二进制小数上,将最低有效位的值0认为是偶数,值1认为是奇数,只有形如XX…X . YY….Y100…的二进制位模式的数,这种舍入方式才有效,其中X和Y表示任意位值,最右边的Y是要被舍入的位置。只有这种位模式表示两个可能的结果的正中间的值。
对不满足上述形式的浮点数,观察舍入位置的下一位的值,若为1,可考虑向上舍入,若为0,则可考虑向下舍入。
1.4 浮点运算
把浮点数x和y看成是实数,而某个运算 ⊙ \odot ⊙ 定义在实数上,计算将产生 R o u n d ( x ⊙ y ) Round(x \odot y) Round(x⊙y) ,这是对实际运算的精确结果进行舍入后的结果。
浮点加法
将 x + f y x+^fy x+fy 定义为 R o u n d ( x + y ) Round(x+y) Round(x+y) ,有如下特点:
- 满足交换律
- 不满足结合律(因为存在溢出和舍入)
- 大多数值都存在加法逆元。
- 满足单调属性:若 a ≥ b a\ge b a≥b, 则除了NaN外,对于任意的a, b, x的值,都有 x + a ≥ x + b x + a \ge x + b x+a≥x+b 。(无符号或补码加法不具有单调性)
- 特殊情况: , 1 / − 0 = − ∞ , 1 / + 0 = + ∞ , + ∞ − ∞ = N a N , x + f N a N = N a N ,1/-0=-\infty, 1/+0=+\infty, +\infty -\infty = NaN,x+^fNaN = NaN ,1/−0=−∞,1/+0=+∞,+∞−∞=NaN,x+fNaN=NaN 。
浮点乘法
将 x ∗ f y x*^fy x∗fy 定义为 R o u n d ( x ∗ y ) Round(x*y) Round(x∗y) ,有如下特点:
-
运算是封闭的
-
满足交换律
-
乘法单位元为1.0
-
不满足结合律(因为存在溢出和舍入)
-
不满足分配律
-
满足单调属性:对任意的a, b, c,且都不等于NaN,有
且 , 则 a ≥ b 且 c ≥ 0 , 则 a ∗ f c ≥ b ∗ f c 且,则a \ge b 且 c \ge 0, 则a *^f c \ge b *^f c 且,则a≥b且c≥0,则a∗fc≥b∗fc
且 , 则 a ≥ b 且 c ≤ 0 , 则 a ∗ f c ≤ b ∗ f c 且,则a \ge b 且 c \le 0, 则a *^f c \le b *^f c 且,则a≥b且c≤0,则a∗fc≤b∗fc
只要 a ≠ N a N a \ne NaN a̸=NaN, 就有 a ∗ f a ≥ 0 a *^f a \ge 0 a∗fa≥0。
无符号数和补码乘法没有这个单调性。
1.5 C语言中的浮点数
int float double 之间进行类型强制转换的原则:
- int -> float,数字不会溢出但可能会被舍入
- int / float -> double,能保留精确的数值(double可表示的值范围更大,有效位数也更多)
- double -> float,因为范围较小,可能溢出成正无穷或负无穷;精度较小,也可能被舍入
- float / double -> int,将会向零舍入,也可能会溢出。与Intel兼容的微处理器指定位模式[10…00] 为整数不确定值。一个浮点数到整数的转换,如果不能为该浮点数找到一个合理的整数近似值,就会产生整数不确定值。