功能速度测试的奇怪结果

时间:2014-02-04 20:33:59

标签: r recursion

我写了一个函数,它使用递归来找到最大的公因子(分母):

> gcd
function(a,b){
 if (length(a)*length(b)>1) {
        warning("Only scalars allowed; using first elements.")
        a<-a[1]
        b<-b[1]
        }
 ifelse (b==0, a, gcd(b, a %% b))
}

然后我针对microbenchmark运行了一些pracma::gcd次测试,它使用了重复的分频和减法例程。以下是几个案例结果:

Rgames>microbenchmark(pracma::gcd(2^2*3*5^2*7*11^8*23^5*41^2,2^1*3^8*5^2*7*11^3*23^5*47^2),gcd(2^2*3*5^2*7*11^8*23^5*41^2,2^1*3^8*5^2*7*11^3*23^5*47^2),times=10)
Unit: microseconds
                                                                                               expr
 pracma::gcd(2^2 * 3 * 5^2 * 7 * 11^8 * 23^5 * 41^2, 2^1 * 3^8 *      5^2 * 7 * 11^3 * 23^5 * 47^2)
         gcd(2^2 * 3 * 5^2 * 7 * 11^8 * 23^5 * 41^2, 2^1 * 3^8 * 5^2 *      7 * 11^3 * 23^5 * 47^2)
     min      lq   median      uq     max neval
 140.260 142.399 158.0070 184.733 285.225    10
 237.759 241.607 250.3725 255.291 282.231    10
Rgames> microbenchmark(pracma::gcd(2^16,2^16*3),gcd(2^16,2^16*3),times=10)
Unit: microseconds
                        expr    min     lq  median     uq     max neval
 pracma::gcd(2^16, 2^16 * 3) 58.585 59.867 61.5780 67.992 140.688    10
         gcd(2^16, 2^16 * 3) 25.658 26.941 28.8655 30.790  41.052    10

我不完全确定,但似乎pracma代码在涉及大量素数时速度更快,而我的玩具代码则更快。素数的力量似乎不是主要的推动力。 有什么想法控制这里的相对时间? 这是pracma代码:

function (a, b, extended = FALSE) 
{
    stopifnot(is.numeric(a), is.numeric(b))
    if (length(a) == 1) {
        a <- rep(a, times = length(b))
    }
    else if (length(b) == 1) {
        b <- rep(b, times = length(a))
    }
    n <- length(a)
    e <- d <- g <- numeric(n)
    for (k in 1:n) {
        u <- c(1, 0, abs(a[k]))
        v <- c(0, 1, abs(b[k]))
        while (v[3] != 0) {
            q <- floor(u[3]/v[3])
            t <- u - v * q
            u <- v
            v <- t
        }
        e[k] <- u[1] * sign(a[k])
        d[k] <- u[2] * sign(a[k])
        g[k] <- u[3]
    }
    if (extended) {
        return(list(g = g, c = e, d = d))
    }
    else {
        return(g)
    }
}

编辑:红利问题:如果我们能够识别导致差异的数据类型,我们是否可以提前预测哪个函数将解析gcd(x,y)而不分析xy&# 39;事实性?

1 个答案:

答案 0 :(得分:0)

我将ifelse更改为简单if(b==0) a else gcd(...)并重复运行。函数cgcd是修改后的gcd函数的字节编译版本; oldgcd是上面发布的原文。

Rgames> microbenchmark(pracma::gcd(2^2*3*5^2*7*11^8*23^5*41^2,2^1*3^8*5^2*7*11^3*23^5*47^2),gcd(2^2*3*5^2*7*11^8*23^5*41^2,2^1*3^8*5^2*7*11^3*23^5*47^2),cgcd(2^2*3*5^2*7*11^8*23^5*41^2,2^1*3^8*5^2*7*11^3*23^5*47^2),oldgcd(2^2*3*5^2*7*11^8*23^5*41^2,2^1*3^8*5^2*7*11^3*23^5*47^2),times=10)
Unit: microseconds
                                                                                               expr
 pracma::gcd(2^2 * 3 * 5^2 * 7 * 11^8 * 23^5 * 41^2, 2^1 * 3^8 * 5^2 * 7 * 11^3 * 23^5 * 47^2)
         gcd(2^2 * 3 * 5^2 * 7 * 11^8 * 23^5 * 41^2, 2^1 * 3^8 * 5^2 * 7 * 11^3 * 23^5 * 47^2)
        cgcd(2^2 * 3 * 5^2 * 7 * 11^8 * 23^5 * 41^2, 2^1 * 3^8 * 5^2 * 7 * 11^3 * 23^5 * 47^2)
      oldgcd(2^2 * 3 * 5^2 * 7 * 11^8 * 23^5 * 41^2, 2^1 * 3^8 * 5^2 * 7 * 11^3 * 23^5 * 47^2)
     min      lq  median      uq     max neval
 140.261 142.826 144.109 148.386 218.516    10
  68.420  73.124  73.979  74.834  99.209    10
  68.420  70.986  72.696  74.835  78.683    10
  81.677  82.532  84.028  87.663  94.078    10

因此,消除ifelse确实可以改善事情。我很遗憾为什么今天 pracma版本以与昨天相同的速度运行,但较旧的gcd运行得更快。无论哪种方式,看起来我的版本更快。但是,这很重要,对于具有大量素数因子的真正大数字,%%函数会抛出警告并返回错误值,因此pracma版本更强大。