我写了一个函数,它使用递归来找到最大的公因子(分母):
> 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)
而不分析x
和y
&# 39;事实性?
答案 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
版本更强大。