【问题标题】:Return Random Number but not 2返回随机数但不返回 2
【发布时间】:2009-08-19 15:37:56
【问题描述】:

为什么有时会返回 2?

function pickServer(){
    $varr = rand(1,4);
    if($varr==2){
        pickServer();
    }
    return $varr;
}

【问题讨论】:

  • 谢谢大家,都正确,但我只能选择一个。 :)
  • 实际上他们中的大多数都错过了真正的问题(包括接受的答案)。不要将递归用作 Goto。在 $var=rand(1,4) 调用周围放置一个循环,直到它返回一个值!=2,不要在此方法内再次调用 pickServer。想想孩子们!想想你的堆栈框架!如果您运行此代码并连续获得 2,则理论上您可以创建 StackOverflow 条件,我不是在谈论问答 Wiki 站点。
  • 根本不循环。您的随机生成范围太大 - 您看不到它,因为您要排除的数字在范围内。如果它在开头或结尾你​​不会循环,那么为什么仅仅因为它在中间就循环呢?重新映射。
  • +! JohnFX - 谢谢。这就是我刚刚写的。其中许多解决方案在技术上可能有效,但具有不确定的 递归(包括接受的答案)的不良副作用。这是一个危险的组合,它会变成一个虚幻的错误,会随机崩溃你的系统……偶尔……没有明显的原因。
  • @Nosredna - 我同意。最技术上正确的答案是将您的随机空间重新映射到不包含“2”的空间。然后您的方法将在 O(1) 时间内执行。在方法内部循环是一种快速、实用的方法,可以解决基本问题,但从学术角度来看并不是最佳解决方案。但我确实同意你的观点,方法不应该是不确定的并且肯定不是递归的。

标签: php recursion random


【解决方案1】:

正如其他人指出的那样,您的问题的答案是您的代码没有返回就失败了。如果在第一次尝试第二次尝试(发生这种情况的可能性为 1/16)时调用 rand() 返回了 2,您将得到 2 作为结果。

但你解决问题的方法可能会更好。

递归和循环都不能解决这个问题。这是一个映射问题,而不是随机性问题。 (它类似于一些常见的随机编码面试问题,可以在拒绝循环中最容易地处理,但它确实不是该类的问题。)

您想要三个结果之一,而不是四个。 (1、3 和 4。)这意味着您应该生成三个随机数的范围,而不是四个。您可以使用数组重新映射或使用if。两种可能性如下所示。如果我有语法错误,请告诉我——我的 PHPfu 今天早上很弱。

/* array remapping */
function pickServer() {
    $remap = array(1, 3, 4);
    return $remap[rand(1,3)];
}

/* if remapping */
function pickServer() {
    $server = rand(1,3);
    if ($server==2) {
        $server=4;
    }
    return $server;
}

我之前没有注意到,但 balpha 预料到了我的回答。在他的第二个示例中,他使用if 重新映射。他没有将 2 重新映射到 4,而是在 1 以上的任何答案中添加了一个,这是一个等效的解决方案。

【讨论】:

  • 语法对我来说是正确的。做得好。 应该是选择的答案。
  • 真正的随机 RNG 可能永远返回 2。至少这不会陷入循环。
  • 我想你会发现真正的 RNG 总是返回 4:imgs.xkcd.com/comics/random_number.png
  • +1。原始功能和接受的答案都效率低下。无论您的范围内有多少“洞”,您都可以将其概括为映射问题。
【解决方案2】:

因为您没有在此处停止该功能。第四行应该是:

return pickServer();

【讨论】:

  • 这仍然是递归的并且有潜在的危险。请参阅关于原始问题的评论讨论。
  • 这对于回答“为什么”很有用。但正如 Robert 指出的那样,它导致了一个可怕的解决方案。
【解决方案3】:

另一种方法是使用do … while

function pickServer() {
    do {
        $varr = rand(1,4);
    } while ($varr == 2);
    return $varr;
}

【讨论】:

  • 可以说更好,因为大多数语言都没有优化尾递归,这并不比递归的更清楚。
  • 终于有人指出使用递归作为 goto 是疯狂的。 +1
  • 我认为对于手头的问题,递归和循环都很疯狂。 :-)
  • 第二好的答案,但远远落后于 Nosrednas。
【解决方案4】:

你可能想要的是

function pickServer(){
  $varr = rand(1,4);
  if($varr==2){
    $varr = pickServer();
  }
  return $varr;
}

-- 但请注意,不能保证这不会进入太长的递归。也许你应该做这样的事情:

function pickServer(){
  $varr = rand(1,3);
  if($varr > 1){
    $varr = $varr + 1;
  }
  return $varr;
}

【讨论】:

  • 效果和 Nosredna 的一样好,但必须考虑一下。
  • 您的第二段代码很好地解决了这个问题。我对它的担心只是它有点难以破译。事实上,当我第一次阅读答案时,我错过了它,因为它不明显。我为错过它而道歉。如果我第一次注意到它,我会在我的回答中归功于你。
  • 更新:我在回答中给了你道具。
  • 记不住 PHP,但出于好奇,你能做到 $varr+=$var>1;在 PHP 中? (我知道它看起来很糟糕。)
【解决方案5】:

因为当值为 2 时,您不会返回 pickserver。并且该函数继续返回 $varr。

【讨论】:

    【解决方案6】:
    function pickServer(){
        $varr = rand(1,4);
        if($varr==2){
            return pickServer(); //leave here
        }
        return $varr;
    }
    

    【讨论】:

      【解决方案7】:

      我会是这样的:

      function pickServer()
      {
      $servers = array(1,3,4);
      return $servers[rand(1,count($servers))]; 
      }
      

      【讨论】:

      • 我认为 rand() 在 PHP 中是用零个或两个参数调用的。
      • rand 返回整数。我想这就是你想要的... return $servers[rand(1,count($servers))];
      【解决方案8】:

      它递归调用该函数以获取另一个不是 2 的数字,但对该结果不执行任何操作。

      尝试将 pickServer() 更改为 return pickServer()

      更好的是,迭代地编写函数,让它循环直到返回的值不是 2。

      【讨论】:

        【解决方案9】:

        你忘了返回值...

        function pickServer(){
        $varr = rand(1,4);
        if($varr==2){
            return pickServer();
        }
        return $varr;
        }
        

        【讨论】:

          【解决方案10】:

          您可以删除递归并重新映射随机选择的 2。只需减小范围并将范围的开头(在本例中为 2)映射到 1。

          function pickServer(){
              $varr = rand(2,4);
              if($varr==2){
                  return 1;
              }
              return $varr;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-04-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-21
            • 1970-01-01
            • 2012-11-09
            相关资源
            最近更新 更多