R中漂移的布朗运动的有效模拟

时间:2016-07-07 16:13:00

标签: r performance simulation

我想有效地模拟漂移d> 0的布朗运动,其中漂移的方向改变,如果超过一些障碍b或-b(没有反射,只是改变漂移方向!)。 for - 循环是这样做的简单方法

 step<-0.1 #step size
 sig<-1 #sign of drift
 T<-10^4 #length of process
 b<-300; d<-0.5#barrier and drift
 W<-rep(NA,(T/step))
 W[1]<-0
 for (i in 2:(T/step))
 {
  if (W[i-1]>b) {sig<- -1} #change drift to -1
  if (W[i-1]< -b) {sig<-1} #change drift to +1
  W[i]<-W[i-1]+rnorm(1,d*sig*step,sqrt(step))
 }

当然,这个循环在R中需要很长时间,特别是对于小步长。 因此,我对使用矢量运算或apply() - 命令的更有效的解决方案感兴趣。 (如果是简单的布朗运动,我可以使用cumsum(rnorm()),这里是否有类似的解决方案?)

非常感谢!!

1 个答案:

答案 0 :(得分:1)

您对W[i]sig进行了递归计算,这在每一步都有一些逻辑。在R中可能没有太多可以减少执行时间的因素,但有几件事情会使时间减少近50%。特别是,而不是在每个步骤上调用rnorm,通过rnorm调用mean=0来计算num_step以计算sig值并存储结果,从而对此计算进行矢量化。在循环的每个步骤中,此向量的值将添加到该步骤的平均值。确定 step<-0.1 #step size T<-10^4 #length of process b<-300; d<-0.5 #barrier and drift print(system.time({ sig <- 1 #sign of drift set.seed(123) # set seed W<-rep(NA,(T/step)) W[1]<-0 for (i in 2:(T/step)) { if (W[i-1]>b) {sig<- -1} #change drift to -1 if (W[i-1]< -b) {sig<-1} #change drift to +1 W[i]<-W[i-1]+rnorm(1,d*sig*step,sqrt(step)) } })) print(system.time({ sig <- 1 # reset value of sig set.seed(123) # reset seed num_steps <- trunc(T/step) W1 <- numeric(num_steps) ep <- rnorm(num_steps, 0, sqrt(step)) for (i in 2:num_steps) { if(abs(W1[i-1]) > b) sig <- ifelse( W1[i-1] >b, -1, 1) W1[i] <- W1[i-1]+d*sig*step +ep[i-1] } })) 的值的逻辑也可以简化一点。具有发布方法和新代码的时间的代码是:

W

两项计算W1function move(touchDown) { if(touchDown) { touchMoves = setTimeout(function(){ if (Math.floor(touchX) < Math.floor(player.x + player.width)) { if ((Math.floor(player.x + player.width) - Math.floor(touchX)) <= 10 ) { touchDown = false; clearTimeout(touchMoves); } else { player.x -= Math.floor(CANVAS_WIDTH / player.width); } } else if ((Math.floor(touchX) == Math.floor(player.x + player.width)) || (player.x == (CANVAS_WIDTH - player.width))) { touchDown = false; clearTimeout(touchMoves); } else { if ((Math.floor(touchX) - Math.floor(player.x + player.width)) <= 10 ) { touchDown = false; clearTimeout(touchMoves); } else { player.x += Math.floor(CANVAS_WIDTH / player.width); } } if (touchDown) { move(touchDown); } }, 100); } } mc.on("press", function(ev) { if (gameIsActive) { touchDown = true; touchX = ev.center.x; move(touchDown); } }); mc.on("pressup", function(ev) { if (gameIsActive) { touchDown = false; } }); 的结果应该相同。