如何在R中舍入到0.25或0.75,而不是0.00或0.50?

如何在R中舍入到0.25或0.75,而不是0.00或0.50?,r,rounding,R,Rounding,我正在使用R,我想将数据四舍五入到最接近的0.25或0.75,但不包括0.00或0.50 例如,如果我想四舍五入到最接近的0.00或0.50,我将执行以下操作: test <- seq(1,10,0.33) [1] 1.00 1.33 1.66 1.99 2.32 2.65 2.98 3.31 3.64 3.97 4.30 4.63 4.96 5.29 5.62 5.95 6.28 6.61 6.94 7.27 7.60 7.93 8.26 8.59 8.92 9.25 9.58 9.9

我正在使用R,我想将数据四舍五入到最接近的0.250.75,但不包括0.00或0.50

例如,如果我想四舍五入到最接近的0.00或0.50,我将执行以下操作:

test <- seq(1,10,0.33) 
[1] 1.00 1.33 1.66 1.99 2.32 2.65 2.98 3.31 3.64 3.97 4.30 4.63 4.96 5.29 5.62 5.95 6.28 6.61 6.94 7.27 7.60 7.93 8.26 8.59 8.92 9.25 9.58 9.91
对于0.25的倍数,我也可以这样做。我该怎么做才能将这些数字四舍五入到0.25或0.75(不包括0.50和0.00)

轮((测试+0.25)*2)/2-0.25怎么样?对于您的
测试
,它给出:

# [1] 0.75 1.25 1.75 1.75 2.25 2.75 2.75 3.25 3.75 3.75 4.25 4.75 4.75 5.25 5.75
#[16] 5.75 6.25 6.75 6.75 7.25 7.75 7.75 8.25 8.75 8.75 9.25 9.75 9.75
你也可以做
轮((测试-0.25)*2)/2+0.25
,给出

# [1] 1.25 1.25 1.75 1.75 2.25 2.75 2.75 3.25 3.75 3.75 4.25 4.75 4.75 5.25 5.75
#[16] 5.75 6.25 6.75 6.75 7.25 7.75 7.75 8.25 8.75 8.75 9.25 9.75 9.75

对于整数,行为在舍入方向上不同。以
1
为例。在第一种情况下,它向下舍入到
0.75
,而在第二种情况下,它向上舍入到
1.25
。整数在这里是一个“灰色区域”;您需要决定您想要的方向。

几年前,我编写了一些函数,允许使用可选偏移量将数字舍入到最接近的指定值,并支持六种常见的偏移类型。对于你的问题,我已经尝试将我的代码移植到R

这里有一个与精确性相关的重要警告。由于R使用浮点编码来表示小数,因此很容易导致精度不足,无法正确应用分层规则。这是因为未调整的舍入结果和舍入间隔之间的差异可能仅仅由于浮点错误而偏离半个单位,因此无法检测是否应该应用分段中断。这对我的原始代码来说不是问题,因为bc是一个无限精度的计算器,但在R中是一个问题。我试图通过宽容地进行计算来缓解这个问题,但它并不完美。如果舍入间隔的数量级与要舍入的值的数量级相差过大,则结果将不正确。但是,应该提到的是,这个警告适用于任何使用浮点运算的解决方案,而不仅仅是我的代码

不管怎样,我得到的是:

FTOL <- 1e-8;
feq <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),abs(a-b)<=max(abs(a),abs(b))*tol,a==b);
fne <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),abs(a-b)>max(abs(a),abs(b))*tol,a!=b);
fgt <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),a-b>max(abs(a),abs(b))*tol,a>b);
fge <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),a-b>=-max(abs(a),abs(b))*tol,a>=b);
flt <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),b-a>max(abs(a),abs(b))*tol,a<b);
fle <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),b-a>=-max(abs(a),abs(b))*tol,a<=b);

HALFRULE_UP   <- 1L; ## round towards +Inf
HALFRULE_DOWN <- 2L; ## round towards -Inf
HALFRULE_IN   <- 3L; ## round towards zero
HALFRULE_OUT  <- 4L; ## round away from zero
HALFRULE_EVEN <- 5L; ## round to the even multiple of the two multiples of nearest that are tied
HALFRULE_ODD  <- 6L; ## round to the odd multiple of the two multiples of nearest that are tied
nearest <- function(x,nearest=1,offset=0,halfrule=HALFRULE_EVEN) {

    ## ensure correct types
    x <- as.double(x);
    nearest <- as.double(nearest);
    offset <- as.double(offset);
    halfrule <- as.integer(halfrule);

    ## validate
    v <- which(!halfrule%in%c(HALFRULE_UP,HALFRULE_DOWN,HALFRULE_IN,HALFRULE_OUT,HALFRULE_EVEN,HALFRULE_ODD)); if (length(v)>0L) stop(paste0('invalid halfrule: ',halfrule[v[1L]],'.'));

    ## normalize lengths
    len <- max(length(x),length(nearest),length(halfrule));
    x <- rep(x,len=len);
    nearest <- rep(nearest,len=len);
    offset <- rep(offset,len=len);
    halfrule <- rep(halfrule,len=len);

    ## apply offset
    x <- x-offset;

    ## must treat zero nearests different from non-zero
    nonzero <- fne(nearest,0);

    ## start building result
    res <- double(length(x));

    ## nearest zero doesn't really make any sense; but you can consider every possible number to be at the nearest zero
    res[!nonzero] <- x[!nonzero];

    ## simplify subsequent operations to only focus on non-zero nearest
    x <- x[nonzero];
    nearest <- nearest[nonzero];
    halfrule <- halfrule[nonzero];
    offset <- offset[nonzero];

    ## don't care about negativity of nearest
    nearest <- abs(nearest);

    ## get how many times nearest goes into x, truncated
    mult <- as.integer(x/nearest); ## note: can't use %/%, since that actually floors toward -Inf

    ## get round-truncated result
    r.trunc <- mult*nearest;

    ## get absolute excess over r.trunc
    excess <- abs(x - r.trunc);

    ## get half of nearest
    half.of.nearest <- nearest*0.5;

    ## add one to mult if necessary; whether we need to do this in the case of a tie depends on the specified tiebreaker rule and which side of the zero multiple x is on
    adds <- which(
        fgt(excess,half.of.nearest)
        | feq(excess,half.of.nearest) & (
            halfrule==HALFRULE_UP & fgt(x,0)
            | halfrule==HALFRULE_DOWN & flt(x,0)
            | halfrule==HALFRULE_OUT
            | halfrule==HALFRULE_EVEN & mult%%2L!=0L
            | halfrule==HALFRULE_ODD & mult%%2L==0L
        )
    );
    mult[adds] <- mult[adds] + ifelse(flt(x[adds],0),-1,1);

    ## recover target value from mult, and at the same time unshift offset
    res[nonzero] <- nearest*mult+offset;

    res;

}; ## end nearest()
nearest.halfup   <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_UP  );
nearest.halfdown <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_DOWN);
nearest.halfin   <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_IN  );
nearest.halfout  <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_OUT );
nearest.halfeven <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_EVEN);
nearest.halfodd  <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_ODD );

在你的结果中,它似乎四舍五入为1.0到0.75?很好的解决方案。看来我需要确定我希望0和0.50的去向。你也可以考虑像“代码> 0.5×Lead(2×x)+ 0.25</COD>和<代码> 0.5×CEIL(2×x)-0.25 < /代码>这两个表达式,它们都绕过最近的<代码> XXX。25 < /代码>或<代码> XXX。75 /代码>值,但在半整数边情况下有不同的行为:第一个总是将整数和半整数向上舍入(即,朝向正无穷大);第二个总是向下取整(接近负无穷大)。我想,为了避免类似宏的定义,
HALFRULE_X
s可以被包装在一个“字符”向量中,作为
nearest
的“HALFRULE”参数的默认值,并在函数中使用
match.arg
FTOL <- 1e-8;
feq <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),abs(a-b)<=max(abs(a),abs(b))*tol,a==b);
fne <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),abs(a-b)>max(abs(a),abs(b))*tol,a!=b);
fgt <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),a-b>max(abs(a),abs(b))*tol,a>b);
fge <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),a-b>=-max(abs(a),abs(b))*tol,a>=b);
flt <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),b-a>max(abs(a),abs(b))*tol,a<b);
fle <- function(a,b,tol=FTOL) ifelse(is.finite(a) & is.finite(b),b-a>=-max(abs(a),abs(b))*tol,a<=b);

HALFRULE_UP   <- 1L; ## round towards +Inf
HALFRULE_DOWN <- 2L; ## round towards -Inf
HALFRULE_IN   <- 3L; ## round towards zero
HALFRULE_OUT  <- 4L; ## round away from zero
HALFRULE_EVEN <- 5L; ## round to the even multiple of the two multiples of nearest that are tied
HALFRULE_ODD  <- 6L; ## round to the odd multiple of the two multiples of nearest that are tied
nearest <- function(x,nearest=1,offset=0,halfrule=HALFRULE_EVEN) {

    ## ensure correct types
    x <- as.double(x);
    nearest <- as.double(nearest);
    offset <- as.double(offset);
    halfrule <- as.integer(halfrule);

    ## validate
    v <- which(!halfrule%in%c(HALFRULE_UP,HALFRULE_DOWN,HALFRULE_IN,HALFRULE_OUT,HALFRULE_EVEN,HALFRULE_ODD)); if (length(v)>0L) stop(paste0('invalid halfrule: ',halfrule[v[1L]],'.'));

    ## normalize lengths
    len <- max(length(x),length(nearest),length(halfrule));
    x <- rep(x,len=len);
    nearest <- rep(nearest,len=len);
    offset <- rep(offset,len=len);
    halfrule <- rep(halfrule,len=len);

    ## apply offset
    x <- x-offset;

    ## must treat zero nearests different from non-zero
    nonzero <- fne(nearest,0);

    ## start building result
    res <- double(length(x));

    ## nearest zero doesn't really make any sense; but you can consider every possible number to be at the nearest zero
    res[!nonzero] <- x[!nonzero];

    ## simplify subsequent operations to only focus on non-zero nearest
    x <- x[nonzero];
    nearest <- nearest[nonzero];
    halfrule <- halfrule[nonzero];
    offset <- offset[nonzero];

    ## don't care about negativity of nearest
    nearest <- abs(nearest);

    ## get how many times nearest goes into x, truncated
    mult <- as.integer(x/nearest); ## note: can't use %/%, since that actually floors toward -Inf

    ## get round-truncated result
    r.trunc <- mult*nearest;

    ## get absolute excess over r.trunc
    excess <- abs(x - r.trunc);

    ## get half of nearest
    half.of.nearest <- nearest*0.5;

    ## add one to mult if necessary; whether we need to do this in the case of a tie depends on the specified tiebreaker rule and which side of the zero multiple x is on
    adds <- which(
        fgt(excess,half.of.nearest)
        | feq(excess,half.of.nearest) & (
            halfrule==HALFRULE_UP & fgt(x,0)
            | halfrule==HALFRULE_DOWN & flt(x,0)
            | halfrule==HALFRULE_OUT
            | halfrule==HALFRULE_EVEN & mult%%2L!=0L
            | halfrule==HALFRULE_ODD & mult%%2L==0L
        )
    );
    mult[adds] <- mult[adds] + ifelse(flt(x[adds],0),-1,1);

    ## recover target value from mult, and at the same time unshift offset
    res[nonzero] <- nearest*mult+offset;

    res;

}; ## end nearest()
nearest.halfup   <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_UP  );
nearest.halfdown <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_DOWN);
nearest.halfin   <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_IN  );
nearest.halfout  <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_OUT );
nearest.halfeven <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_EVEN);
nearest.halfodd  <- function(x,nearest=1,offset=0) nearest(x,nearest,offset,HALFRULE_ODD );
nearest(seq(1,10,0.33),0.5,0.25);
##  [1] 1.25 1.25 1.75 1.75 2.25 2.75 2.75 3.25 3.75 3.75 4.25 4.75 4.75 5.25 5.75 5.75 6.25
## [18] 6.75 6.75 7.25 7.75 7.75 8.25 8.75 8.75 9.25 9.75 9.75