R中的for循环与while循环

Posted

技术标签:

【中文标题】R中的for循环与while循环【英文标题】:For-loop vs while loop in R 【发布时间】:2011-05-11 08:19:22 【问题描述】:

我在 R 中工作时注意到一件奇怪的事情。 当我有一个使用 for-loop 和 while-loop 实现计算从 1 到 N 的平方的简单程序时,行为是不一样的。 (在这种情况下,我不关心矢量化或应用函数)。

fn1 <- function (N) 

    for(i in 1:N) 
        y <- i*i
    

fn2 <- function (N) 

    i=1
    while(i <= N) 
        y <- i*i
        i <- i + 1
    

结果是:

system.time(fn1(60000))
   user  system elapsed 
  2.500   0.012   2.493 
There were 50 or more warnings (use warnings() to see the first 50)
Warning messages:
1: In i * i : NAs produced by integer overflow
.
.
.

system.time(fn2(60000))
   user  system elapsed 
  0.138   0.000   0.137 

现在我们知道 for-loop 更快,我猜是因为那里的预分配和优化。但是为什么会溢出呢?

更新:所以现在尝试使用向量的另一种方式:

fn3 <- function (N) 

    i <- 1:N
    y <- i*i

system.time(fn3(60000))
   user  system elapsed 
  0.008   0.000   0.009 
Warning message:
In i * i : NAs produced by integer overflow

所以也许这是一个时髦的内存问题?我在具有 4Gb 内存和 R 中所有默认设置的 OS X 上运行。这发生在 32 位和 64 位版本中(除了时间更快)。

亚历克斯

【问题讨论】:

根据你的时间,while循环更快。 当你将 for 循环中的计数器转换为浮点数时,它会比 while 循环更快,但这只是因为 for 循环没有警告。 R 充满了这种废话。 好问题,不过。我喜欢性能分析。 【参考方案1】:

关于时间安排:

fn1 <- function (N) 
    for(i in as.numeric(1:N))  y <- i*i 

fn2 <- function (N) 
    i=1
    while (i <= N) 
        y <- i*i
        i <- i + 1
    


system.time(fn1(60000))
# user  system elapsed 
# 0.06    0.00    0.07 
system.time(fn2(60000))
# user  system elapsed 
# 0.12    0.00    0.13

现在我们知道 for 循环比 while 循环快。您不能在计时期间忽略警告。

【讨论】:

这仍然不完全公平,因为 while 循环有更大的主体;我知道,这是有必要效仿的,但在某些问题中并非如此。 @mbq 这就是为什么 for-loop 和 while-loop 不能比较的原因。每个都有不同的目的。您可以在fn1 中添加i&lt;-i+1 行,但它仍然更快,因为fn2 必须检查条件,这意味着对&lt;= 的60k 次调用。如果将另一行 i&lt;=N 添加到 fn1 则时间相等。【参考方案2】:

因为1 是数字而非整数(即它是浮点数),而1:6000 是数字和整数。

> print(class(1))
[1] "numeric"
> print(class(1:60000))
[1] "integer"

60000 的平方是 36 亿,不能用带符号的 32 位整数表示,因此会出现溢出错误:

> as.integer(60000)*as.integer(60000)
[1] NA
Warning message:
In as.integer(60000) * as.integer(60000) : NAs produced by integer overflow

36 亿很容易用浮点数表示,但是:

> as.single(60000)*as.single(60000)
[1] 3.6e+09

要修复您的for 代码,请转换为浮点表示:

function (N)

    for(i in as.single(1:N)) 
        y <- i*i
    

【讨论】:

这就是为什么 seq(N) 优于 1:N 的原因吗? @Marek:我也是这么想的,但这给出了一个整数向量。正是我们不想要的。 seq(1,N,1) 给出一个数值向量。 @David:这是一个选择问题。两者都是等价的,并且都给出了一个整数向量。 seq(1,N,1) 等价于 as.single(1:N)。也请参阅 Spacedman 的答案。【参考方案3】:

for 循环中的变量是一个整数序列,所以最终你会这样做:

> y=as.integer(60000)*as.integer(60000)
Warning message:
In as.integer(60000) * as.integer(60000) : NAs produced by integer overflow

而在 while 循环中,您正在创建一个浮点数。

这也是这些东西不同的原因:

> seq(0,2,1)
[1] 0 1 2
> seq(0,2)
[1] 0 1 2

不相信我?

> identical(seq(0,2),seq(0,2,1))
[1] FALSE

因为:

> is.integer(seq(0,2))
[1] TRUE
> is.integer(seq(0,2,1))
[1] FALSE

【讨论】:

但为什么浮点数的范围比整数大? 更新:“请注意,在 R 的几乎所有实现中,可表示整数的范围都限制在大约 +/-2*10^9:双精度数可以精确地容纳更大的整数。”来自整数的 R 文档:( @Alex(不是 Brown):整数是 32 位的二进制表示。所以最大范围是 2^32,或 ~ [-2e9, +2e9]。浮点使用不同的 32 位:它为数字保存了一些位(其中小数点在第一个数字之后),并为幂保存了另一组位。显然,这使得范围非常大。顺便说一下,这是一般的计算知识,除了一些小细节之外,这个系统在每种计算机语言/应用程序中都是相同的。

以上是关于R中的for循环与while循环的主要内容,如果未能解决你的问题,请参考以下文章

R中的“for循环”中的“while循环”不起作用?

python中的while循环与for循环怎么样那个比较好用?

R中的并行while循环

R循环函数(forwhilebreaknext)

JavaScript 中的 While 循环与 For 循环? [关闭]

python while循环与for循环