从“四舍五入”到“奇进偶舍”
处理取整时,大概下意识的可以想到的方法,都是“四舍五入”吧?不过我们可以先看两个例子,在Python 3中,round(4.5) == 4
,而在mongodb 以上的版本中,{$round: 4.5}
的结果也是4。对于习惯了只存在“四舍五入”这一种舍入方法的同学们来说,估计是要去怀疑这是不是代码的bug了。其实,这里舍入的方法并不是“四舍五入”,而是采用了所谓的“奇进偶舍”或者“四舍六入五成双”的方法,这种方法也被称为Banker’s Rounding(银行家舍入法)。Python 3选择了这种舍入方法作为标准库的实现,最主要的原因还是因为这个舍入方法被IEEE 754标准选为了默认的浮点数舍入方法和Decimal的推荐默认舍入方法(Round to nearest, ties to even)。
作为默认舍入方法被推荐,并且还有Banker’s Rounding这么一个拉风的名字,这个方法的优势在什么地方呢?首先,以舍入到整数为例,让我们来看一下,“奇进偶舍”这个方法的规则是什么。这里,我们就从Round to nearest, ties to even这个定义来解释。首先是Round to nearest,就是向最接近的整数来舍入,比如5.6最接近的整数是6,而-3.2最接近的整数是-3,前面举得几个例子其实和“四舍五入”的规则是完全一样的,不同之处在于,当小数部分正好是0.5时,那么这个数到两边的整数的距离是完全一样的,这时ties to even这后半条规则就要派上用场了,也就是当到两边整数的距离相等时,向最接近的偶数舍入,比如0.5舍入到0,4.5舍入到4,而1.5则要舍入到2。
从上面的规则可以看出来,广为人知的“四舍五入”的规则还是要简单很多的,但是“四舍五入”这种方法会引入一个比较容易积累误差的问题。还是舍入到整数为例,当小数部分恰好是最中间的0.5时,这个部分总是向上取整的,于是向上取整的可能性就会比向下取整多,那么得到舍入之后的数字就会倾向于偏大,尤其是在类似于在计算比如收入数据之类只需要保留一两位小数这些情形中,这个误差就很容易提现出来。而进一步的,如果对已经舍入过的数字进行求和等计算,这个误差会被积累和放大,经过多级的数据统计之后,一些最终统计报表上的结果就会与实际数字差的很远。采用“奇进偶舍”这种方法时,如果小数部分恰好是0.5,舍入时会以均等的概率向上或者向下取整,所以舍入之后偏大或者偏小的倾向也会相互抵消,从而在概率上让实际的误差趋向于0。
下面我们设计一个实验来对比两种舍入方法的误差积累。我们可以使用Python的decimal模块来完成这个实验,在decimal模块的Decimal.to_integral_value函数中,可以指定rounding参数为decimal.ROUND_HALF_UP或者decimal.ROUND_HALF_EVEN在两种舍入方法中进行选择。主要的测试程序如下:
import decimal
import math
import randomdef get_random_decimal(n, f):'''生成decimal.Decimal随机数,整数n位,小数f位'''return decimal.Decimal(int(random.random() * 10 ** (n + f))) / decimal.Decimal(10 ** f)def test(n, f, count=1000):'''进行求和测试并计算舍入的误差,count为随机数的个数,整数n位,小数f位'''sum_float = decimal.Decimal(0.0)sum_round_half_up = decimal.Decimal(0.0)sum_round_half_even = decimal.Decimal(0.0)for i in range(count):v = get_random_decimal(n, f)sum_float += vsum_round_half_up += v.to_integral_value(rounding=decimal.ROUND_HALF_UP)sum_round_half_even += v.to_integral_value(rounding=decimal.ROUND_HALF_EVEN)error_round_half_up = (sum_float - sum_round_half_up).copy_abs()error_round_half_even = (sum_float - sum_round_half_even).copy_abs()rate_round_half_up = '%.4f%%' % (error_round_half_up / sum_float * 100)rate_round_half_even = '%.4f%%' % (error_round_half_even / sum_float * 100)return [count, sum_float,sum_round_half_up, error_round_half_up, rate_round_half_up,sum_round_half_even, error_round_half_even, rate_round_half_even]# 范例调用方法
# test(2, 2, count=10000)
我们把随机数值控制在100以内,并且保留两位小数(n2, f2),在不同的count下可以得到如下的结果
count | sum_float | sum_up | error_up | rate_up | sum_even | error_even | rate_even | |
---|---|---|---|---|---|---|---|---|
0 | 10000 | 502250 | 502336 | 86.33 | 0.0172% | 502279 | 29.33 | 0.0058% |
1 | 100000 | 5.00007e+06 | 5000671 | 604.66 | 0.0121% | 5000208 | 141.66 | 0.0028% |
2 | 1000000 | 5.00414e+07 | 50046394 | 5008.05 | 0.0100% | 50041434 | 48.05 | 0.0001% |
3 | 10000000 | 5.00122e+08 | 500170946 | 48962.4 | 0.0098% | 500120975 | 1008.57 | 0.0002% |
从上面的结果中(以_up结尾的为"四舍五入"的,以_even结尾的为"奇进偶舍"的)可以看出,“奇进偶舍”的误差是明显小于“四舍五入”的,而且会随着count的增大而越来越趋于0(“四舍五入”在这个设定下会趋于0.01%)。虽然计算的规则稍微复杂一些,但是“奇进偶舍”这种舍入方法的优势还是非常明显的,这也是这种方法成为推荐标准,也被越来越多的编程语言和数据库把这种方法作为默认实现的原因。
从“四舍五入”到“奇进偶舍”相关推荐
- python random.round 修约方法 4舍6入5看齐,奇进偶不进
奇进偶不进 根据国家标准的有关规定,过去所采用的"四舍五入"的方法早已被"4舍6入5看齐,奇进偶不进"的方法所取代. 就是说,拟舍弃数小于5时,均应按" ...
- 回忆高中数学--概述“奇变偶不变,符号看象限”
详讲口诀"奇变偶不变,符号看象限" 在学习三角函数这部分内容的时候,你一定记得"奇变偶不变,符号看象限"这个口诀吧.它是专门用来记诱导公式的.下面就详细解 ...
- 1到100之间所有奇(偶)数的和,奇(偶)数的个数,奇(偶)数的平均数
/*程序的功能:1到100之间所有奇(偶)数的和,奇(偶)数的个数,奇(偶)数的平均数实现的思路:for循环 从1到100之间 判断一个数是奇数还是偶数,如果是奇数count加1,如果是 偶数coun ...
- 差分信号,差分对和耦合(四)——差分共模信号和奇模偶模电压分量,远端噪声的产生
对于差分信号,两条信号线之间的电压差就是其差分分量,对于共模信号,两条信号线的电压平均值就是其共模分量. 对于一个对称的差分对而言,差分信号在差分线上以奇模方式传输,共模信号以偶模方式传输.也可以用奇 ...
- 差分信号,差分对和耦合(三)——奇模偶模、差分阻抗奇模阻抗、共模阻抗偶模阻抗
奇模和偶模(ODD AND EVEN MODES) 对于一个差分对,如果在一条线中加0V-1V的变化信号,在另一条线加0V的持续信号,随着信号的传输,两条线之间会出现远端串扰,在第二条线上会出现噪声, ...
- javascript 数字近似值(JS四舍五入 四舍六入五凑偶 截取)
四舍五入是最常见的,四舍六入五凑偶(银行家取舍法)会计中常用,还有就是截取指定位数 原生js编写,无需任何外部库,直接复制使用(建议处理后放到类中使用) 废话不多说,下面展示 代码. /*** 数字格 ...
- Verilog-实现时钟分频(1KHZ、奇、偶分频,占空比为50%)
文章目录 一.将系统时钟50MHZ分为占空比为50%的1khz时钟 二.偶数分频: 三.奇数分频: 一.将系统时钟50MHZ分为占空比为50%的1khz时钟 本篇文章使用Xilinx公司的ISE软件 ...
- matlab中偶分量怎么表示,如何在matlab中画出一个函数的奇分量偶分量
满意答案 mxd_joan 2013.12.02 采纳率:50% 等级:11 已帮助:3101人 即 f(x,y)=i(x,y).r(x,y) i(x,y)为照明分量(入射分量),是入射到景物上 ...
- #3 GPA计算(python)
欢迎光临我的blog!专栏记录本萌新初学python解题情况,欢迎大家交流思考 题目如上,较为简单,需掌握字典 [解] 首先获取输入的百分制成绩,并四舍五入 score=eval(input('请输入 ...
最新文章
- 如何从Java中打印XML?
- python爬取百度图片(用于深度学习中数据集的收集)
- How to change max_allowed_packet size
- 使用C# 探索 ML.NET 中的不同机器学习任务
- 配置交换机端口聚合(思科、华为、锐捷)
- 鸿蒙卡片-物联网DTU污水液位计卡片
- 设计灵感|元素拼接的海报到底好看在哪里?
- TinkPad E40 CentOS 6.5 无线网卡驱动 RTL8191SEvB 安装
- Linux 运行.exe程序
- Xcode6在iPhone5+iOS7模拟器上编译,上下有黑边问题
- 计算机组成原理74138译码器连接,74138(74138译码器工作原理)
- DaZeng:Vue全家桶实现小米商城(二)
- MAML代码及理论的深度学习 PyTorch二阶导数计算
- html 网页地图集制作ECHARTS,在页面使用echarts的地图(解决地图不完整)
- 软件工程-非功能需求撰写参考案例
- 【jzoj2220】【二分】愤怒的奶牛2(angry)
- 听完“Java 教父”李刚的分享,我总结了两点建议
- 计算机求职英语作文,英语作文_计算机专业大学毕业生求职信范文_沪江英语
- 解释一下浏览器解析HTTP的过程
- git error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
热门文章
- (PTA)6-9 字符串压缩
- HTML5初学----基础代码案例汇总
- vim资源很全的一个网站
- NAG: Network for Adversary Generation 笔记
- 程序员不能忍996了!发起抗议网站,GitHub一小时破千星
- 苹果开发者证书提示编辑电话号码
- ubuntu14设置在当前目录打开终端
- IDEA编译报错Failure to find com.lowagie:itext:jar:2.1.7.js4,依赖报错
- rand()函数用法
- MySQL数据库引擎、数据事务与隔离级别