从“四舍五入”到“奇进偶舍”

简介: 处理取整时,大概下意识的想到的方法,都是“四舍五入”吧?不过我们可以先看两个例子,在Python 3中,round(4.5) == 4,而在mongodb 以上的版本中,{$round: 4.5}的结果也是4。

处理取整时,大概下意识的可以想到的方法,都是“四舍五入”吧?不过我们可以先看两个例子,在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 random


def 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 += v
        sum_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以内,并且保留两位小数(n==2, f==2),在不同的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%)。虽然计算的规则稍微复杂一些,但是“奇进偶舍”这种舍入方法的优势还是非常明显的,这也是这种方法成为推荐标准,也被越来越多的编程语言和数据库把这种方法作为默认实现的原因。

目录
相关文章
无影云电脑使用感受
简单谈谈无影云电脑使用的感受
1525 1
无影云电脑使用感受
|
机器学习/深度学习 存储 算法
深度学习中的稀疏注意力
深度学习中的稀疏注意力
1384 0
|
存储 固态存储 数据库
SSD接口选择指南:PCIe与SATA性能大比拼
【4月更文挑战第21天】
3667 0
|
3月前
|
存储 弹性计算 安全
阿里云99元一年和199元一年云服务器怎么买更划算?组合套餐价格参考
阿里云推出的云服务器ECS“99计划”活动,提供99元/年和199元/年的经济型及通用算力型云服务器,新老用户同享“新购续费同价”政策,活动持续到2027年3月31日。此外,阿里云还推出专属组合套餐,涵盖建站、安全防护、弹性数据库、高效存储及特定运行环境,如LNMP环境等,满足用户全方位需求。这些组合套餐通过打包销售,提供一站式服务,降低用户上云成本,是个人开发者和初创企业的最经济实惠的上云方案。
|
机器学习/深度学习 算法 数据安全/隐私保护
基于FPGA的SNN脉冲神经网络之LIF神经元verilog实现,包含testbench
本项目展示了 LIF(Leaky Integrate-and-Fire)神经元算法的实现与应用,含无水印运行效果预览。基于 Vivado2019.2 开发,完整代码配有中文注释及操作视频。LIF 模型模拟生物神经元特性,通过积分输入信号并判断膜电位是否达阈值产生脉冲,相较于 Hodgkin-Huxley 模型更简化,适合大规模神经网络模拟。核心程序片段示例,助您快速上手。
|
Java Shell 应用服务中间件
Mac系统下配置环境变量:Javajdk、maven、tomcat 环境变量配置及对应配置文件
这篇文章介绍了如何在Mac系统下配置Java JDK、Maven和Tomcat的环境变量,包括配置文件的选择、解决环境变量在zsh shell中无效的问题、查看和设置系统环境变量的方法,以及JDK和Maven的下载、配置和测试步骤。
7237 1
Mac系统下配置环境变量:Javajdk、maven、tomcat 环境变量配置及对应配置文件
|
安全 数据安全/隐私保护
Burp Suite暴力破解表单账密步骤
Burp Suite暴力破解表单账密步骤
758 0
软件著作权申请流程及费用_快速登记_软著材料及常见问题解答FAQ
阿里云软件著作权申请涉及账号注册、实名认证和选择服务。在阿里云官网注册账号,通过实名认证后,选择登记服务,如普通359.1元/件或加急1080元/件。在线填报申请表,阿里云初审后授权提交,打印申请表并邮寄材料。版权中心审查后,通过则领取证书,未通过需补正。整个过程约20天。详细步骤见阿里云百科相关教程。
831 3
|
机器学习/深度学习 虚拟化 异构计算
浅析GPU通信技术(上)-GPUDirect P2P
1. 背景 GPU在高性能计算和深度学习加速中扮演着非常重要的角色, GPU的强大的并行计算能力,大大提升了运算性能。随着运算数据量的不断攀升,GPU间需要大量的交换数据,GPU通信性能成为了非常重要的指标。
31555 1
|
安全 Linux 调度
Linux线程管理:深入探索多线程编程的原理与实践
在Linux操作系统中,线程是轻量级的执行单元,多线程编程允许程序在同一进程内执行多个并发任务,提高程序性能和资源利用率。本文将深入探讨Linux线程管理的相关知识,包括线程的创建、终止与调度,以及线程间通信的实现,旨在帮助读者深入理解多线程编程的原理与实践。
1163 1

热门文章

最新文章