【问题标题】:Using random in a for loop gives strange values在 for 循环中使用 random 会给出奇怪的值
【发布时间】:2020-05-23 09:01:20
【问题描述】:

为什么在三个 console.log 中我得到的数字是 17 到 70,000

但是在循环中,y 总是在 200 到 800 之间?

console.log("RND " + Math.floor(Math.random()*5000)*17)
console.log("RND " + Math.floor(Math.random()*5000)*17)
console.log("RND " + Math.floor(Math.random()*5000)*17)

let y=0;
for (let x = 0; x < Math.floor(Math.random()*5000)*17; x++) {
  y++
}
console.log("y " + y)

random() 在 for 循环中的工作方式有什么不同吗?

【问题讨论】:

  • Math.floor(Math.random()*5000)*17 正在为每次迭代执行,并给出不同的随机值。我想这就是原因。
  • 啊!!哈哈哈我没想到!! - 我会立即测试:D
  • @TulshiDas 你会如何测试它?
  • 我尝试了 100 个循环,并在 1 和 1000 之间进行随机化,其中大多数最终都低于 10 :D 所以是的 - 这是正确的!做一个答案,这样我就可以给你点:)

标签: javascript


【解决方案1】:

这是因为循环中的 Math.... 每次都会被评估。

但是你用它作为停止循环的条件。 这意味着通常需要 200 到 800 次尝试才能使整个表达式的计算结果低于当前的x。迭代次数越高,退出循环的可能性就越大。

也许你的意思是

console.log("RND " + Math.floor(Math.random()*5000)*17)
console.log("RND " + Math.floor(Math.random()*5000)*17)
console.log("RND " + Math.floor(Math.random()*5000)*17)

let y=0;
for (let x = 0, iterations = Math.floor(Math.random()*5000)*17; x < iterations; x++) {
    y++
}
console.log("y " + y)

这将只创建一次iterations 变量并在整个循环周期中使用它。


如果您想查看原始代码中发生的情况,请运行以下代码

let y = 0;
let limit;
for (let x = 0; x < (limit = Math.floor(Math.random() * 5000) * 17); x++) {
  console.log(`${x} < ${limit} : ${x<limit}`);
  y++
}
console.log("y " + y, 'last limit was', limit);

【讨论】:

  • 这似乎合乎逻辑,但您将如何测试它?
  • @radulle 添加了另一个 sn-p 以显示发生了什么。
  • 在发布另一个 sn-p 后才注意到它,这导致我找到另一个 JS for loop 怪癖,当 x 等于限制时,循环会隐式停止。非常激动人心的早晨:D
  • @radulle 它在​​等于限制时停止,因为我们说 loop while x &lt; limit 如果你这样做 x &lt;= limit 它将被包括在内。
  • 这很清楚,但是看看我的答案中的代码 sn-p ,即使它被定义为 for (let x = 0; b = Math.floor(Math.random()*5000)*17; x++) { ,它也会停止,这意味着只要有一个值而不是就足够了一个条件。
【解决方案2】:

不,但是您设置 for 循环的方式基本上是创建了一种正态分布,并且 y 将呈现正态分布中的一个值。

解释为什么会有点数学,但基本上是因为这个。

(let x = 0; x &lt; Math.floor(Math.random()*5000)*17; x++)

注意你的 for 循环的结束条件是一个随机数,所以基本上,你的循环将在随机时间结束。理论上,它可能会在第一次迭代后停止(如果 RNG 出现 0),或者最迟到 85000(如果它持续滚动非常高,连续多次,但这极不可能),但与原始随机函数,变化分布不均匀。

它更像是一个钟形曲线,显然在 200 到 800 范围内结束的机会非常高,而在这些范围之外则非常低。

我可能可以准确计算出哪些值具有哪些概率,但我不会。询问 numberphile 或其他数学 youtuber,他们会喜欢的。

用最基本的方式解释:

您生成了一个函数,该函数返回满足 x 大于随机生成数的条件所需的随机数生成器的尝试次数,其中 x 每次递增 1(因此每次迭代问题变得更容易)并且要比较的值是随机的,介于 0 和 85000 之间。

前几轮不太可能,因为 x 仍然非常小,所以目标很难命中(它必须掷出一个非常低的数字)。但随着 x 变大,RNG 更可能小到足以击中它。以及每一卷都有改变来击中它。因此,它在统计上变得越来越有可能在某个时候达到它。 (不太可能一直保持高数字)。

最终它变得越来越可能滚动,因为只要生成的随机数足够低(低于 x,x 每次都会增加),它就会通过。

【讨论】:

  • 所以它可以达到 70,000 但我们必须比赢得超级球更幸运:D
【解决方案3】:

这将是求职面试中的一个很好的问题:D 有趣的是,您可以像下面的代码一样访问生成的值:

console.log("RND " + Math.floor(Math.random()*5000)*17)
console.log("RND " + Math.floor(Math.random()*5000)*17)
console.log("RND " + Math.floor(Math.random()*5000)*17)

let y=0;
for (let x = 0; b = Math.floor(Math.random()*5000)*17; x++) {
    console.log(x, y, b)
    y++
}
console.log("y " + y, b)

事实证明,这是因为在该迭代中 b 被评估为零,这是一个虚假值。在这种情况下,由于 Math.floor(),生成的数字小于 0.0002 就足够了,因为它乘以 5000,这并不少见,因为生成的数字有 16 个数字。它只是表明不应依赖 Math.floor(Math.random()*X) 来生成随机数。

【讨论】:

  • 嗯?该循环的结束条件是什么?
  • 隐含地是 x == b 或 x === b。不知道怎么解释。
  • 在这种情况下没有什么意外,也不是暗示x === b。发生的情况是for 的第二部分被评估为布尔值。所以它在false 时结束。在您的情况下,当表达式计算为 0 时它会停止,并且与等于 x 无关。
  • @GabrielePetrioli 刚刚检查过,您完全正确。好推理。尽管如此,非常有趣的是,需要如此少量的随机生成才能产生零。
  • @ZimriLeijen 似乎是因为Math.floor()。生成的数字小于 0.0002 就足够了,因为它乘以 5000,这并不少见,因为生成的数字有 16 个数字。它只是表明不应依赖 Math.floor(Math.random()*X) 来生成随机数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-05
  • 2017-05-19
  • 2019-02-11
  • 2019-04-30
  • 2017-04-09
相关资源
最近更新 更多