R与Python取整规则疑问:为何从6而非5向上进位?
解决R中round函数的非预期取整问题
为什么R的round行为和你预期不一样?
首先明确:不存在取整定义的地区差异,这是算法和浮点数精度共同导致的结果,主要有两个核心原因:
浮点数的二进制存储精度限制
像62.495这类十进制小数,无法被精确转换为二进制浮点数存储。在计算机中它实际是一个略小于62.495的近似值(你可以用sprintf("%.20f", 62.495)查看真实存储的数值),所以调用round(62.495, 2)时,R会基于这个偏小的数值计算,结果自然是62.49而非预期的62.5。R默认使用「银行家舍入」(四舍六入五成双)
即使数值能被精确表示,R的round函数默认采用银行家舍入规则:当尾数恰好为5时,会舍入到最近的偶数,而非无条件向上进位。比如:round(62.485, 2):若数值精确,第三位是5,第二位是8(偶数),结果保持62.48;round(62.495, 2):第二位是9(奇数),理论上会舍入到62.50,但因为实际存储值略小,最终输出62.49。
另外你设置的options(digits.secs=6)和这个问题无关,它仅影响时间类型数据中小数秒的显示位数,不会改变数值取整的逻辑。
如何实现传统的「四舍五入」(尾数≥5则向上进位)?
如果你需要符合直觉的传统取整逻辑,可以通过以下几种方法实现:
方法1:自定义取整函数
通过放大数值、加0.5后取整再缩小的方式,实现传统四舍五入,同时兼容负数处理:
round_traditional <- function(x, digits = 0) { sign(x) * trunc(abs(x) * 10^digits + 0.5) / 10^digits } # 测试示例 round_traditional(62.495, 2) # 输出 62.5 round_traditional(62.485, 2) # 输出 62.49 round_traditional(-62.495, 2) # 输出 -62.5
方法2:使用formatC进行十进制格式化
formatC基于十进制逻辑处理数值,避开浮点数精度问题,之后再转回数值类型:
as.numeric(formatC(62.495, digits = 2, format = "f")) # 输出 62.5
方法3:借助plyr包的round_any(需提前安装包)
如果你已经在使用plyr工具包,可以通过自定义规则实现传统取整:
library(plyr) round_any(62.495, 0.01, f = function(x, y) floor(x/y + 0.5)*y)
关于Python和Matlab的差异补充
- Python 3的
round函数同样默认采用银行家舍入,但受浮点数存储的细微差异影响,部分案例会表现出向下取整的结果; - Matlab的
round函数默认采用传统四舍五入,且内部对十进制小数做了特殊处理,所以会得到你预期的62.5。
内容的提问来源于stack exchange,提问作者Vanessa Klaas
相关产品推荐
相关产品推荐

