ここに別のアプローチがあります。繰り返し実行する必要がある回数を減らすと、通常、コードは高速になります。具体的には、すべてのrunif(1,0,1)
呼び出しを 1 つの大きな値のベクトルに置き換えてからrunif()
、それに基づいてベクトルをサブセット化できます。
@Mark Miller の関数を出発点として使用し、次の変更を加えました。オーバーサンプラーが前の乱数のセットから適切な値を保持し、n
到達するまでのみ埋められた場合、これはさらに改善される可能性がありますが、これは関係なくかなり高速です。速度比較のために、私は彼のコードを逐語的に取り、それをfun2 <- function() {...}
fun1 <- function(n, oversample = 1.50){
#oversample
over <- ceiling(n * oversample)
goodvars <- NA
while (length(goodvars) < n){
z1 <- runif(over,-1,1)
z2 <- runif(over,-1,1)
h <- z1^2 + z2^2
goodvars <- which(h > 0 & h < 1)
}
goodvars <- goodvars[1:n]
x <- z1[goodvars]
y <- z2[goodvars]
q <- h[goodvars]
p <- sqrt((-2 * log(q)) / q)
a <- x * p
b <- y * p
return(cbind(a,b))
}
##Mark's code put into a function
fun2 <- function() {
i <- 1
x <- rep(NA, 20)
y <- rep(NA, 20)
q <- rep(NA, 20)
p <- rep(NA, 20)
while (i <= 20) {
repeat{
z1=((runif(1,0,1)*2)-1)
z2=((runif(1,0,1)*2)-1)
h=z1**2+z2**2
if((h > 0) & (h <= 1)){break}
}
x[i] <- z1
y[i] <- z2
q[i] <- h
i <- i + 1
}
j <- 1
while (j <= 20) {
h=sqrt((-2*log(q[j]))/q[j])
p[j] <- h
j <- j + 1
}
a=x*p
b=y*p
}
#Do some speed checking with rbenchmark. Also checkout compiler package for some free speed
library(compiler)
library(rbenchmark)
#Compile functions to see improvements
cfun1 <- cmpfun(fun1)
cfun2 <- cmpfun(fun2)
#run benchmark tests
benchmark(fun1(n = 20), fun2(), cfun1(n = 20), cfun2(),
replications = 1000,
columns=c("test", "elapsed", "relative"),
order = "elapsed")
そして結果
test elapsed relative
3 cfun1(n = 20) 0.042 1.000000
1 fun1(n = 20) 0.055 1.309524
4 cfun2() 0.407 9.690476
2 fun2() 0.882 21.000000
新しい R セッションから始めて、上記のコードをコピーして貼り付けてもエラーは返されません。次に例を示します。
test <- fun1(n = 1000)
plot(test)