想要摆脱循环的建议
我编写了一个解决 3n + 1 问题(又名“奇妙数字”和其他各种问题)的程序。但它有一个双环。我如何对其进行矢量化?
代码是
count <- vector("numeric", 100000)
L <- length(count)
for (i in 1:L)
{
x <- i
while (x > 1)
{
if (round(x/2) == x/2)
{
x <- x/2
count[i] <- count[i] + 1
} else
{
x <- 3*x + 1
count[i] <- count[i] + 1
}
}
}
谢谢!
I have written a program that works with the 3n + 1 problem (aka "wondrous numbers" and various other things). But it has a double loop. How could I vectorize it?
the code is
count <- vector("numeric", 100000)
L <- length(count)
for (i in 1:L)
{
x <- i
while (x > 1)
{
if (round(x/2) == x/2)
{
x <- x/2
count[i] <- count[i] + 1
} else
{
x <- 3*x + 1
count[i] <- count[i] + 1
}
}
}
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我通过创建一个向量 x 来“由内而外”地翻转这个过程,其中第 i 个元素是算法每次迭代后的值。结果相对容易理解,因为
这可以优化为(a)仅跟踪仍在运行的那些值(通过 idx)和(b)避免不必要的操作,例如,ifelse 评估 x 的所有值的两个参数,x/2 评估两次。
使用 f0 原始函数,我有
一个调整是将奇数更新为 3 * x[i] + 1,然后无条件除以 2 将
其作为 f3 (不知道为什么今天早上 f2 较慢!) 我明白
了似乎在除以二的阶段可以采取更大的步骤,例如,8 是 2^3,所以我们可以采取 3 步(加 3 来计数)并完成,20 是 2^2 * 5,所以我们可以采取两步并在 5. 实现中进入下一次迭代?
I turned this 'inside-out' by creating a vector x where the ith element is the value after each iteration of the algorithm. The result is relatively intelligible as
This can be optimized to (a) track only those values still in play (via idx) and (b) avoid unnecessary operations, e.g., ifelse evaluates both arguments for all values of x, x/2 evaluated twice.
with f0 the original function, I have
A tweak is to update odd values to 3 * x[i] + 1 and then do the division by two unconditionally
With this as f3 (not sure why f2 is slower this morning!) I get
It seems like larger steps can be taken at the divide-by-two stage, e.g., 8 is 2^3 so we could take 3 steps (add 3 to count) and be finished, 20 is 2^2 * 5 so we could take two steps and enter the next iteration at 5. Implementations?
因为您需要迭代
x
的值,所以您无法真正对其进行矢量化。在某些时候,R 必须依次单独处理 x 的每个值。您也许能够在单独的 CPU 核心上运行计算来加快速度,也许可以使用同名包中的foreach
。否则,(这只是对您隐藏循环),将循环的主体包装为一个函数,例如:
然后您可以使用 sapply() 在一组上运行该函数数字:
或者您可以使用
Vectorize
返回wonderous
的矢量化版本,它本身就是一个函数,可以向您隐藏更多内容:我认为这大约是就目前标准 R 工具所能达到的程度而言。@Martin Morgan 表明,通过巧妙地解决使用 R 向量化确实的问题,您可以做得更好。能力。Because you need to iterate on values of
x
you can't really vectorize this. At some point, R has to work on each value of x separately and in turn. You might be able to run the computations on separate CPU cores to speed things up, perhaps usingforeach
in the package of the same name.Otherwise, (and this is just hiding the loop from you), wrap the main body of your loop as a function, e.g.:
and then you can use
sapply()
to run the function on a set of numbers:Or you can use
Vectorize
to return a vectorized version ofwonderous
which is itself a function that hides even more of this from you:I think that is about as far as you can get with standard R tools at the moment.@Martin Morgan shows you can do a lot better than this with an ingenious take on solving the problem that does used R's vectorised abilities.另一种方法认识到人们经常重新访问低数字,那么为什么不记住它们并节省重新计算成本呢?
这给出了
This 可能不能很好地并行化,但是对于 50 倍的加速来说也许这不是必需的?此外,递归可能会变得太深,但递归可以写成循环(无论如何,这可能更快)。
A different approach recognizes that one frequently revisits low numbers, so why not remember them and save the re-calculation cost?
which gives
This might not parallelize well, but then maybe that's not necessary with the 50x speedup? Also the recursion might get too deep, but the recursion could be written as a loop (which is probably faster, anyway).