R:在不使用长度函数的情况下找到bigz向量的长度

时间:2016-06-28 14:43:05

标签: r optimization vector biginteger gmp

R中,要查找向量的长度(bigz或不是),通常使用length函数。 E.g。

NonBigZ <- 1:10

NonBigZ
[1]  1  2  3  4  5  6  7  8  9 10

length(NonBigZ)
[1] 10

但是,使用gmp包,如果声明bigz向量,则会自动返回向量的长度。 E.g。

BigZ <- as.bigz(1:10)

BigZ
Big Integer ('bigz') object of length 10:  ## <<-- length given here
 [1] 1  2  3  4  5  6  7  8  9  10

## This seems redundant as it is already given above
length(BigZ)
[1] 10

我想在不对length进行额外调用的情况下检索该信息。我知道length闪电般快,但如果你能避免调用它,它可以节省相当多的时间。观察:

system.time(sapply(1:10^6, function(x) length(BigZ)))
user  system elapsed 
7.81    0.00    7.84

我已尝试attributes(BigZ)以及str(BigZ)无济于事。我也阅读了gmp文档,但找不到任何内容。

1 个答案:

答案 0 :(得分:1)

正如@alexis_laz在评论中指出的那样,gmp::print.bigz已经计算了长度,但并没有以任何可用的格式返回它。我做了一些挖掘gmp源代码,发现了这个:

print.bigz <- function(x, quote = FALSE, initLine = is.null(modulus(x)), ...)
{
  if((n <- length(x)) > 0) {
    if(initLine) {
      cat("Big Integer ('bigz') ")
      kind <- if(isM <- !is.null(nr <- attr(x, "nrow")))
        sprintf("%d x %d matrix", nr, n/nr)
      else if(n > 1) sprintf("object of length %d", n) else ""
      cat(kind,":\n", sep="")
    }
    print(as.character(x), quote = quote, ...)
  }
  else
    cat("bigz(0)\n")
  invisible(x)
}

如您所见,它使用cat函数返回您的bigz对象。从this questionthis answer,可以检索所请求的信息,但是,它并不像简单地调用length那样有效。以下是获得长度的非常粗略的函数。

BigZLength <- function(x) {
    b <- capture.output(x)
    a <- strsplit(b[1], split=" ")[[1]][7]
    if (!is.na(a)) {as.integer(substr(a,1,nchar(a)-1))} else {1L}
}

system.time(sapply(1:10^5, function(x) length(BigZ)))
 user  system elapsed 
0.67    0.00    0.67 

system.time(sapply(1:10^5, function(x) BigZLength(BigZ)))
 user  system elapsed 
24.57    0.01   24.71

我确定你可以使用正则表达式(或其他东西)编写更有效的函数,但是,我不相信它会像调用length一样高效。事实上,简单地获取cat的输出大部分时间都在上面的代码中。

system.time(sapply(1:10^5, function(x) capture.output(BigZ)))
 user  system elapsed 
20.00    0.00   20.03



关于获取上面的源代码的说明

如果您熟悉R,您只需在控制台中键入该功能并打印出来就可以查看给定功能的源代码:

numbers::nextPrime
function (n) 
{
    if (n <= 1) 
        n <- 1
    else n <- floor(n)
    n <- n + 1
    d1 <- max(3, round(log(n)))
    P <- Primes(n, n + d1)
    while (length(P) == 0) {
        n <- n + d1 + 1
        P <- Primes(n, n + d1)
    }
    return(as.numeric(min(P)))
}
<environment: namespace:numbers>

然而,有时这是不可能的。例如,gmp::print.bigz我们获得:

gmp::print.bigz
Error: 'print.bigz' is not an exported object from 'namespace:gmp'

输入Joshua Ulrich的精彩questionanswer。使用他在下面建议的代码,您可以下载任何软件包的源代码并将其解压缩到一行。

untar(download.packages(pkgs = "gmp",
                        destdir = ".",
                        type = "source")[,2])

这会在目录中创建一个包含所有已编译代码的文件夹。上面的源代码可以在.\gmp\R\biginteger.R文件中找到。