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

R: Find length of bigz vector without using the length function

R中,要找到向量的长度(bigz或不是),通常使用length函数。例如

NonBigZ <- 1:10

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

length(NonBigZ)
[1] 10

然而,使用 gmp 包,如果你声明一个 bigz 向量,向量的长度会自动返回。例如

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 文档,但找不到任何内容。

正如@alexis_laz 在评论中指出的那样,gmp::print.bigz 已经计算了长度,但没有return 以任何可用格式计算。我深入研究了 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 函数来 return 您的 bigz 对象。从 this question and this 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 的精彩 question and answer。使用他在下面建议的代码,您可以下载任何包的源代码并在一行中解压。

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

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