【问题标题】:R: Find length of bigz vector without using the length functionR:在不使用长度函数的情况下查找bigz向量的长度
【发布时间】:2016-06-28 14:43:05
【问题描述】:

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

【问题讨论】:

  • gmp:::print.bigz 同样,使用gmp:::length.bigz 计算length。似乎length.bigz 不仅仅是像length 这样的属性访问函数——例如见ns = c(1, 10, 50, 100, 200, 500, 1e3, 5e3, 1e4); timings = sapply(ns, function(n) { x = as.bigz(seq_len(n)); summary(microbenchmark(length(x), unit = "ms"))$median }); plot(ns, timings)。我想,在创建“bigz”时将“length”保存为属性可能是值得的。
  • 不要把你的答案放在你的问题中(让问题看起来没有解决),你应该回答你自己的问题。
  • @Gregor,我对发布作为答案犹豫不决,因为我不确定我的答案是否足够彻底。任何人,我已经接受了你的建议。
  • 它似乎回答了你的问题,所以我认为它作为一个答案比作为一个问题更好。如果有人提出了更好的答案,您总是可以投票/接受那个答案。我相信无论如何都要等待 48 小时才能接受您自己的答案。

标签: r optimization vector biginteger gmp


【解决方案1】:

正如@alexis_laz 在 cmets 中指出的那样,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文件中找到。

【讨论】:

    猜你喜欢
    • 2020-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    相关资源
    最近更新 更多