R如何舍入到0.25或0.75,但不是0.00或0.50?

时间:2016-08-16 22:01:57

标签: r rounding

我正在使用R而我想将数据舍入到最接近的 0.25 0.75 ,但不包括0.00或0.50。

例如,如果我想要舍入到最接近的0.00或0.50,我会按如下方式进行:

round(test * 2)/2
[1]  1.0  1.5  1.5  2.0  2.5  2.5  3.0  3.5  3.5  4.0  4.5  4.5  5.0  5.5  5.5  6.0  6.5  6.5  7.0  7.5  7.5  8.0  8.5  8.5  9.0  9.0  9.5 10.0

舍入到0.00或0.50:

{{1}}

我可以做0.25的倍数。我该怎么做才能将这些数字专门用于0.25或0.75,不包括0.50和0.00?

2 个答案:

答案 0 :(得分:7)

round((test + 0.25) * 2) / 2 - 0.25怎么样?对于test,它会给出:

# [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

你也可以round((test - 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。整数是一个灰色区域"这里;你需要决定你想要的方向。

答案 1 :(得分:2)

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

这里有一个与精确度有关的重要警告。由于R使用浮点编码来表示小数,因此您可以很容易地以不足的精度来正确应用tiebreaking规则。这是因为未调整的舍入结果和舍入间隔之间的差异可能仅仅由于浮点错误而偏离半个单位,因此无论是否应该应用tiebreaking都可能无法检测到。这对我的原始代码来说不是问题,因为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 );

对于您的示例输入,我们需要舍入到最接近的0.5,偏移量为0.25:

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