最近被R中的round函數搞得鬱悶,有人說round函數的規則是如此定義的:
引用cos 版主肖楠:這個規則有個俗名叫「四捨六入五湊偶」,也叫「銀行家舍入」,完整版如下: 1. 被修約的數字等於或小於 4 時,該數字捨去;
2. 被修約的數字等於或大於 6 時,則進位;
3. 被修約的數字等於 5 時,要看 5 前面的數字,若是奇數則進位,若是偶數則將 5 舍掉,即修約後末尾數字都成為偶數;若 5 的後面還有不為 “0” 的任何數,則此時無論 5 的前面是奇數還是偶數,均應進位。
舉例,用上述規則對下列資料保留 3 位有效數字:
9.8249=9.82, 9.82671=9.83
9.8350=9.84, 9.8351 =9.84
9.8250=9.82, 9.82501=9.83
好像是說明了問題,但是:
round(9.9995,3)結果是9.999,難道9是奇數中一個特例。
一下為自己在R中實現的小數的四捨五入(主要是想按照數學中的規則:對該數的的絕對值四捨五入再加上加號或減號)
一下代碼還有許多改進的方面,目前只是滿足個人的需要(對某個數小數位後保留n位後四捨五入):
myRound <- function(x, keep=4){ x <- as.character(x) if(grepl("[.]", x)){ xSplit <- unlist(strsplit(x, "[.]")) xSplitBef <- xSplit[1] minusYN <- substring(xSplitBef, 1, 1) # minusYN <- minusYN == "-" xSplitAft <- xSplit[2] xSplitAft <- substring(xSplitAft, 1:nchar(xSplitAft), 1:nchar(xSplitAft)) if(minusYN == "-"){ xSplitBef <- substring(xSplitBef, 2:nchar(xSplitBef), 2:nchar(xSplitBef)) lenBef <- length(xSplitBef) lenAft <- length(xSplitAft) if(lenAft > keep){ all <- c(xSplitBef, xSplitAft[1:(keep + 1)]) if(as.integer(tail(all,1)) < 5){ res1 <- c(xSplitBef, xSplitAft[1:keep]) res1 <- paste(c(res1[1:lenBef], ".", res1[(lenBef+1):length(res1)]), collapse="") res1 <- -as.numeric(res1) }else{ res1 <- c(xSplitBef, xSplitAft[1:keep]) res1 <- as.integer(res1) for(i in length(res1):1){ if(i == length(res1)){ res1[i] <- res1[i] + 1 } if(res1[i] != 10){ break }else{ res1[i - 1] <- res1[i - 1] + 1 } } if(res1[1] == 10){ res1[-1] <- 0 res1 <- c(1,0,res1[-1]) res1 <- paste(c(res1[1:(lenBef+1)], ".", res1[(lenBef+2):length(res1)]), collapse="") res1 <- -as.numeric(res1) }else{ res1[which(res1 == 10)] <- 0 res1 <- paste(c(res1[1:lenBef], ".", res1[(lenBef+1):length(res1)]), collapse="") res1 <- -as.numeric(res1) } } }else{ res1 <- as.numeric(x) } }else{ xSplitBef <- substring(xSplitBef, 1:nchar(xSplitBef), 1:nchar(xSplitBef)) lenBef <- length(xSplitBef) lenAft <- length(xSplitAft) if(lenAft > keep){ all <- c(xSplitBef, xSplitAft[1:(keep + 1)]) if(as.integer(tail(all,1)) < 5){ res1 <- c(xSplitBef, xSplitAft[1:keep]) res1 <- paste(c(res1[1:lenBef], ".", res1[(lenBef+1):length(res1)]), collapse="") res1 <- as.numeric(res1) }else{ res1 <- c(xSplitBef, xSplitAft[1:keep]) res1 <- as.integer(res1) for(i in length(res1):1){ if(i == length(res1)){ res1[i] <- res1[i] + 1 } if(res1[i] != 10){ break }else{ res1[i - 1] <- res1[i - 1] + 1 } } if(res1[1] == 10){ res1[-1] <- 0 res1 <- c(1,0,res1[-1]) res1 <- paste(c(res1[1:(lenBef+1)], ".", res1[(lenBef+2):length(res1)]), collapse="") res1 <- as.numeric(res1) }else{ res1[which(res1 == 10)] <- 0 res1 <- paste(c(res1[1:lenBef], ".", res1[(lenBef+1):length(res1)]), collapse="") res1 <- as.numeric(res1) } } }else{ res1 <- as.numeric(x) } } }else{ res1 <- as.numeric(x) } return(res1)}myRound(-0.374832,3)
該函數不適合向量計算,x必須為單一數值
對多個數值可使用:
( x1 <- seq(-.2, .4, by = .05) )sapply(x1, myRound, keep=1)