舍入数字并保留足够的有效数字以区别于邻居

Moo*_*per 4 r rounding

我有一个增加数字的向量,如下所示:

set.seed(1)
numbers  <- cumsum(abs(rnorm(10,100,100)))
# [1]   37.35462  155.71895  172.15609  431.68417  564.63495  582.58811  731.33101  905.16348 1062.74162 1132.20278
Run Code Online (Sandbox Code Playgroud)

我想选择最小数量的有效数字,然后舍入这些数字,确保我始终保持足够的数字,以便连续的数字不会四舍五入到相同的值.

请参阅以下示例(预期输出):

magic(numbers, n = 1)
# [1]   40  160  170  400  560  580  700  900 1060 1130
Run Code Online (Sandbox Code Playgroud)
  • 37.35462四舍五入到40因为我在这里只要求一位数(n = 1)
  • 我不能圆155.71895200,因为172.15609会被四舍五入到200太受同样的规则,所以我圆155.71895160,并172.15609170
  • 我可以肯定地圆431.68417400,因为它是远远不够的172.15609,并564.63495

等等...

对于n = 2或3,我们将获得:

magic(numbers, n = 2)
# [1]   37  160  170  430  560  580  730  910 1060 1130

magic(numbers, n = 3)
# [1]   37.4  156  172  432  565  583  731  905 1060 1130
Run Code Online (Sandbox Code Playgroud)

我的目标是获得非线性分布的分位数的可读值.

r2e*_*ans 5

#' Minimum preferred significant digits
#'
#' @details
#' Facilitate reducing numbers to their least *distinguishable*
#' significant digits, where "distinguishable" means
#' "between neighbors". This means that if reducing more digits would
#' cause two neighbors to reduce to the same number, then the
#' reduction cannot take place.
#'
#' References:
#'
#' - [Original question on StackOverflow](https://stackoverflow.com/q/51616332/3358272) (and [my answer](https://stackoverflow.com/a/51617325/3358272))
#' 
#' @param numbers numeric, length 2 or more
#' @param n integer, number of preferred remaining significant digits
#' @return numeric vector
#' @export
#' @md
#' @examples
#' \dontrun{
#' set.seed(1)
#' numbers  <- cumsum(abs(rnorm(10,100,100)))
#' # [1]   37.35462  155.71895  172.15609  431.68417  564.63495  582.58811  731.33101  905.16348 1062.74162 1132.20278
#' magic(numbers, 1)
#' #  [1]   40  160  170  400  560  580  700  900 1060 1130
#' magic(numbers, 2)
#' #  [1]   37  160  170  430  560  580  730  910 1060 1130
#' magic(numbers, 3)
#' #  [1]   37.4  156.0  172.0  432.0  565.0  583.0  731.0  905.0 1060.0 1130.0
#' magic(c(1,2.4,2.6,4),1)
#' # [1] 1 2 3 4
#' }
magic <- function(numbers, n=1L) {
  stopifnot(length(numbers) > 1L)
  logscale <- ceiling(log10(abs(numbers)))
  logdiff <- log10(diff(numbers))
  keepoom <- floor(pmin(c(Inf, logdiff), c(logdiff, Inf)))
  roundpoints <- 5*(10^keepoom)
  out <- signif(numbers, pmax(n, logscale - (1+keepoom)))
  dupes <- duplicated(out)
  if (any(dupes)) {
    dupes <- dupes | c(dupes[-1], FALSE)
    out2 <- signif(numbers, pmax(n, logscale - keepoom))
    out[dupes] <- out2[dupes]
  }
  out
}
Run Code Online (Sandbox Code Playgroud)

样品用法:

magic(numbers, 1)
#  [1]   40  160  170  400  560  580  700  900 1060 1130
## [1]   40  160  170  400  560  580  700  900 1060 1130 # yours
magic(numbers, 2)
#  [1]   37  160  170  430  560  580  730  910 1060 1130
## [1]   37  160  170  430  560  580  730  910 1060 1130 # yours
magic(numbers, 3)
#  [1]   37.4  156.0  172.0  432.0  565.0  583.0  731.0  905.0 1060.0 1130.0
## [1]   37.4  156  172  432  565  583  731  905 1060 1130 # yours
magic(c(1,2.4,2.6,4),1)
# [1] 1 2 3 4
## [1] 1:4 # yours, from comments
Run Code Online (Sandbox Code Playgroud)