【问题标题】:Infinite loop using WHILE even though condition is met in R即使在 R 中满足条件,也使用 WHILE 进行无限循环
【发布时间】:2020-11-28 05:49:37
【问题描述】:

我正在尝试学习如何实现控制结构,例如 FOR 和 while 循环。

我创建了一个模拟著名巴西乐透投注的函数。 在乐透中,玩家从 1:60 向量(称为 your_bet)中下注 6 个唯一整数。 该函数从 1 到 60 的全域(“结果”)中采样 6 个值,并测试结果中有多少值与 your_bet 匹配,打印出来:

你的赌注

结果

总分(满分 6 分)

对投注结果的三种可能评论之一。

代码如下:

```

LOTTO<-function(your_bet=sample(1:60, size=6, replace=FALSE)){
    result<-sample(1:60, size=6, replace=FALSE)
    logical_vector<-(your_bet %in% result)
    total_points<-sum(as.integer(logical_vector))
    print(paste(c("Your bet:", as.character(your_bet))), collapse="")
    print(paste(c("Result", as.character(result))), collapse="")
    print(paste(c("Total points", as.character(total_points))), collapse="")
    if (total_points==6)
            print("You are a millonaire")
    else if (total_points==5)
            print("5 points, you are rich!")
    else print("good luck next time")
    }

```

然后我尝试实现一个循环,使函数在一个循环中一遍又一遍地循环,直到总点数>=给定目标(此处为 target_points),修改函数如下。

```

LOTTO<-function(your_bet=sample(1:60, size=6, replace=FALSE), stubborn_until_x_points=FALSE, 
target_points)#inserted stubborn_until_x_points and target_points arguments{
    result<-sample(1:60, size=6, replace=FALSE)
    logical_vector<-(your_bet %in% result)
    total_points<-sum(as.integer(logical_vector))
    print(paste(c("Your bet:", as.character(your_bet))), collapse="")
    print(paste(c("Result", as.character(result))), collapse="")
    print(paste(c("Total points", as.character(total_points))), collapse="")
    if (total_points==6)
            print("You are a millonaire")
    else if (total_points==5)
            print("5 points, you are rich!")
    else print("good luck next time")
    if (stubborn_until_x_points==TRUE)#Inserted WHILE loop here{
            while(total_points < target_points){
                    LOTTO(your_bet, stubborn_until_x_points=TRUE, target_points)}
    }
}

```

这确实使函数在循环中重复,但由于某种原因,即使满足条件,它也会继续循环。

观察 - 我意识到当第一次运行时满足条件时,它实际上会停止,但进入循环后,它会一直持续下去。

我找不到问题所在。有任何想法吗? 提前致谢。

【问题讨论】:

  • 看起来你没有更新循环内的 total_points
  • 友好的评论。这个函数有一些不必要的递归。将所有代码包含在 while 循环中会更有效(并且 C 堆栈安全)。只需从定义total_points &lt;- -Inftarget_points &lt;- Inf 开始,然后使用if(stubborn_until_x_points != TRUE)break 来测试早期中断。 R 中的递归限制通常相当严格,因此对于可能达到相当深度的函数,可以删除递归。
  • 我该怎么做?可以展示给我吗? @rootkonda
  • 如果 target_points 大于 60 那么它也将处于无限循环不是吗?你检查了吗?

标签: r while-loop


【解决方案1】:

我还没有深入研究这个函数,但在任何时候这都不应该break 的唯一原因是target_points &gt; n_samples(此处为6)。

这种情况下的问题非常明显且易于修复。将target_points 减少到小于6 或添加n_samples(6 个大气压)并使其大于target_points。而不是这个,我怀疑主要问题在于递归函数。 R 在递归方面是相当严格的,例如,如果尝试进行简单的递归

i <- 0
f <- function(){
  i <<- i + 1
  f()
}
f()
i
# 896 on my pc

可以看出我们不能将递归用于非常深的递归函数(在 R 中)。这会引发非常无用的错误

错误:C 堆栈使用 7974196 太接近限制

为了缓解这种情况,一个简单地 必须删除递归(简单地说是意大利语,因为有时它并不简单)。在这种情况下,我们只需移动 while 循环以包含函数的主体,并在必要时使用 if 语句提前中断。

下面是函数的略微修改版本(请注意,sample_nnumber_range 已作为参数添加)。
在这个函数中,while 循环被移动到包含主体,并且结果被打印在最后(使用变量res 来计算结果)。在循环结束时,我使用if(isFALSE(stubborn_until_x_points))break 语句在必要时提前退出。

LOTTO <- function(your_bet, 
                  sample_n = 6, 
                  number_range = 1:60,
                  stubborn_until_x_points = FALSE, 
                  target_points){
  if(missing(target_points) || target_points > sample_n) 
    stop('missing target_points or target_points too large')
  total_points <- -Inf # Always smaller than target_points
  i <- 0
  res <- 0
  # If you want a new bet every iteration.
  # Add this at the end of the loop, but remove the 'if' 
  if(missing(your_bet)) 
    your_bet <- sample(number_range, size=sample_n, replace=FALSE)
  while(total_points < target_points){
    result <- sample(number_range, size=sample_n, replace=FALSE)
    logical_vector <- your_bet %in% result
    total_points <- sum(logical_vector)
    if (total_points==6){
      res <- 1
    }else if (total_points==5){
      res <- 2
    }
    i <- i + 1
    if(isFALSE(stubborn_until_x_points))
      break
  }
  if(res == 1)
    cat(res <- 'You\'re a millionaire!\n', sep = '\n')
  else if(res == 2)
    cat(res <- '5  points, you are rich!\n', sep = '\n')
  else 
    cat(res <- 'Better luck next time.', sep = '\n')
  c(result = res, number_of_tries = i)
}

该函数像以前一样被调用,但现在还返回尝试次数和从试验中获得的结果,如下所示。

LOTTO(target_points = 6, stubborn_until_x_points = TRUE)
You're a millionaire!
#Output:
                   result           number_of_tries 
"You're a millionaire!\n"                 "8297820"

【讨论】:

    【解决方案2】:

    删除递归,包括while循环内的函数体,将-Inf分配给初始total_points并添加break语句非常有用。 添加@Oliver 的答案正是我想要的:

    LOTTO<-function(your_bet=sample(1:60, size=6, replace=FALSE), stubborn_until_x_points=FALSE, 
                    target_points=0){
            total_points<--Inf
            while(total_points < target_points){
            result<-sample(1:60, size=6, replace=FALSE)
            logical_vector<-(your_bet %in% result)
            total_points<-sum(as.integer(logical_vector))
            print(paste(c("Your bet:", as.character(your_bet))), collapse="")
            print(paste(c("Result", as.character(result))), collapse="")
            print(paste(c("Total points", as.character(total_points))), collapse="")
            if (total_points==6)
                    print("You are a millonaire")
            else if (total_points==5)
                    print("5 points, you are rich!")
            else print("good luck next time")
            if (isFALSE(stubborn_until_x_points==TRUE))
                    break
                    
            }
    

    然而,他的回答产生了有趣的额外结果,并更好地控制了参数输入不足

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-07
      • 2023-03-11
      • 2016-03-14
      • 2013-04-08
      • 1970-01-01
      • 2012-10-01
      • 1970-01-01
      相关资源
      最近更新 更多