概念介绍
我们大家都知道,浮点数的标准是IEEE754。关于IEEE754格式这里不讲了,主要是要讲一下它的默认舍入方式。
因为表示方法限制了浮点数的范围和精度,所以使用浮点数只能近似地表示实数运算。而此时就不得不考虑舍入的问题了。舍入的原则是找到最接近的匹配值。
为此,IEEE754定义了四种不同的舍入方式:
- 向偶数舍入
- 向零舍入
- 向下舍入
- 向上舍入
IEEE754默认采用向偶数舍入,用来找到最接近的匹配近似值。而其他三种方式则用于计算上下界。
下表是按照四种不同的方式保留整数后的舍入结果:
对于上表,除了向偶数舍入之外,大家应该都很熟悉了。会不会有人产生疑问:1.40向偶数舍入的结果竟然是一个奇数。哈哈,如果你有这个疑问,那表明你还没有搞懂什么是向偶数舍入。
向偶数舍入
所谓向偶数舍入(round-to-even),其真实的意思是向最接近的值舍入(round-to-nearest)。用通俗的话讲就是四舍六入五成双,或者四舍六入五凑偶。当然这句通俗的口诀是针对十进制来说的。
向偶数舍入只有两条规则:
- 如果最接近的值唯一,则直接向最接近的值舍入;
- 如果是处在“中间值”,那么要看保留位(Guard bit)是否是偶数,如果是偶数则直接舍去后面的数不进位,如果是奇数则进位后再舍去后面的数。
只要理解了上面两条规则,那么就完全掌握了向偶数舍入。为了详细解读这两条规则,下面将分别用十进制和二进制来举例说明。
保留位(Guard bit)、近似位(Round bit)和粘滞位(Sticky bit)
我们以十进制数来举例。如果我们想保留两位小数,即留下十分位和百分位上的数。那么保留位(Guard bit)就是结果的最低位,即百分位;近似位(Round bit)就是第一个被舍掉的位,即千分位;而千分位之后的所有位(包括万分位、十万分位等等)或起来构成粘滞位(Sticky bit)。
同理,对于二进制,如果我们想要保留两位小数,那么小数点右边第二位就是保留位(Guard bit),小数点右边第三位就是近似位(Round bit),小数点右边第四位开始一直向右的所有小数位或起来构成粘滞位(Sticky bit)。
用CMU的课件也许更容易理解一点。
中间值
在进行举例说明之前,我们有必要引入一个中间值的概念。这对于理解 “向偶数舍入” 至关重要。对于十进制来说,如果要保留一位小数,即百分位和百分位之后的小数都会被近似掉,那么此时中间值就是xxx.x5000…(5之后全零)。
也就是说,求中间值的方法如下:
- 保留位(Guard bit)和左边的数字保持不变;
- 近似位(Round bit)改写为N/2(N为进制数,十进制就是10,二进制就是2)
- 粘滞位(Sticky bit)全部写零
原始值(十进制) | 中间值 (保留一位小数) | 中间值 (保留两位小数) |
---|---|---|
1.334 | 1.350 | 1.335 |
1.622 | 1.650 | 1.625 |
1.744 | 1.750 | 1.745 |
1.835 | 1.850 | 1.835 |
1.668 | 1.650 | 1.665 |
1.774 | 1.750 | 1.775 |
1.488 | 1.450 | 1.485 |
原始值(二进制) | 中间值 (保留一位小数) | 中间值 (保留两位小数) |
---|---|---|
1.101 | 1.110 | 1.101 |
101.111 | 101.110 | 101.111 |
11.001 | 11.010 | 11.001 |
1.010 | 1.010 | 1.011 |
1.100 | 1.110 | 1.101 |
向偶数舍入 十进制举例
对于以下十进制的数值,我们采用向偶数舍入的方式,保留精确度到十分位,即保留一位小数。
-
请看第一组例子:
原始值 中间值 近似值 (向偶数舍入) 1.36 1.35 1.4 1.751 1.75 1.8 1.852 1.85 1.9 1.77 1.75 1.8 1.45001 1.45 1.5 可以看到,上述这些原始值都比中间值要大,也就是“四舍六入五成双”中的“六入”。所以都向十分位进一,从而使得损失的精度最小。
-
请看第二组例子:
原始值 中间值 近似值 (向偶数舍入) 1.33 1.35 1.3 1.74 1.75 1.7 1.82 1.85 1.8 1.71 1.75 1.7 1.43 1.45 1.4 可以看到,上述这些原始值都比中间值要小,也就是“四舍六入五成双”中的“四舍”。所以直接舍弃,不进位,从而使得损失的精度最小。
-
请看第三组例子:
原始值 中间值 近似值 (向偶数舍入) 1.35 1.35 1.4 1.75 1.75 1.8 1.85 1.85 1.8 1.25 1.25 1.2 1.45 1.45 1.4 可以看到,上述这些原始值和中间值相等,也就是“四舍六入五成双”中的“五成双”。对于这些和中间值完全相等的原始值,我们考察保留位(Guard bit),如果保留位是偶数,则直接舍弃近似位(Round bit)和粘滞位(Sticky bit);如果保留位是奇数,则先向保留位进一,之后舍弃近似位(Round bit)和粘滞位(Sticky bit)。这样,结果中的保留位就是偶数了。这就是向偶数舍入 名字的由来。
向偶数舍入 二进制举例
对于以下二进制的数值,我们采用向偶数舍入的方式,保留一位小数。
-
请看第一组例子:
原始值(二进制) 中间值 近似值 (向偶数舍入) 1.111 1.11 10.0 1.0101 1.01 1.1 1.0111 1.01 1.1 可以看到,上述这些原始值都比中间值要大,也就是“四舍六入五成双”中的“六入”。所以都向小数点右边第1位进一,从而使得损失的精度最小。
-
请看第二组例子:
原始值(二进制) 中间值 近似值 (向偶数舍入) 1.001 1.01 1.0 1.10 1.11 1.1 可以看到,上述这些原始值都比中间值要小,也就是“四舍六入五成双”中的“四舍”。所以直接舍弃,不进位,从而使得损失的精度最小。
-
请看第三组例子:
原始值(二进制) 中间值 近似值 (向偶数舍入) 1.110 1.11 10.0 1.010 1.01 1.0 可以看到,上述这些原始值和中间值相等,也就是“四舍六入五成双”中的“五成双”。对于这些和中间值完全相等的原始值,我们考察保留位(Guard bit),如果保留位是偶数,则直接舍弃近似位(Round bit)和粘滞位(Sticky bit);如果保留位是奇数,则先向保留位进一,之后舍弃近似位(Round bit)和粘滞位(Sticky bit)。这样,结果中的保留位就是偶数了。这就是向偶数舍入 名字的由来。
怎么样?现在彻底搞懂什么是向偶数舍入了吧。