【问题标题】:Why this while Javascript loop is infinite?为什么这个while Javascript循环是无限的?
【发布时间】:2012-05-02 23:29:12
【问题描述】:

我不明白为什么这个while 循环是无限的:

window.prevRandomNumber = -1;
function getRandomNumber(limit) {
    if (!limit)
        limit = 9;

    var actualRandomNumber = Math.floor((Math.random() * limit) + 1);

    while (window.prevRandomNumber == actualRandomNumber) {
        actualRandomNumber = Math.floor((Math.random() * limit) + 1)
    }

    window.prevRandomNumber = actualRandomNumber;

    return actualRandomNumber;
}

对此进行 QUnit 测试:

    test("getRandomNumber() should never return the same number once and again", function () {
        //http://www.askageek.com/2006/01/31/javascript-random-function-that-does-not-return-two-consecutive-identical-results/

        var prevNumber, actualNumber, assertResult;

        for (var i = 0; i <= 200; i++) {
            actualNumber = getRandomNumber();
            assertResult = prevNumber != actualNumber;

            equal(assertResult, true);

            if (!assertResult)
                break;

            prevNumber = actualNumber;
        }
    });

解决方案:

抱歉,错误出现在另一个测试中,就像@Jon 回答的描述,当 anyNumber 等于 1 时,会发生无限循环:

    test("getRandomNumber(anyNumber) should return a number between 1..anyNumber", function () {

        var anyNumber, result;

        for (var i = 0; i <= 100; i++) {
            anyNumber = Math.floor((Math.random() * 9) + 1);
            result = getRandomNumber(anyNumber);

            equal((0 < result && result < (anyNumber + 1)), true);
        }
    });

【问题讨论】:

  • limit 的值是多少?例如,如果limit == 1,那么由于简单的数学运算,它是一个无限循环。
  • 旁注:如果您使用 do...while 循环,您可以使代码更加干燥。

标签: javascript while-loop qunit


【解决方案1】:

无限循环#1

如果limit == 1,循环将无限循环。考虑:

var actualRandomNumber = Math.floor((Math.random() * limit) + 1);

Math.random 返回 [0, 1) 范围内的数字。乘以 limit 不会改变这一点,加一会将其带到 [1, 2) 因此根据定义 Math.floor 将返回 1

while (window.prevRandomNumber == actualRandomNumber) {
    actualRandomNumber = Math.floor((Math.random() * limit) + 1)
}

这里我们有同样的逻辑,所以:

  • 第一次调用该方法时将返回1(它不会进入循环,因为prevRandomNumber 为-1)
  • 该方法的第二次和后续时间将永远不会返回,因为prevRandomNumber 已经是 1

如果limit 是一个大于 1 的数字,我看不出循环是如何无限的。

无限循环#2

考虑如果limit 不是数字会发生什么。

var actualRandomNumber = Math.floor((Math.random() * limit) + 1);

这里,Math.random() * limit 将是 NaN,表达式的最终结果也是如此。所以actualRandomNumber总是等于NaN。该方法第一次调用时会返回Nan,第二次不会返回,原因同上。

解决方案

function getRandomNumber(limit) {
    limit = Number(limit) || 9;

    var actualRandomNumber = Math.floor(Math.random() * (limit + 1));

第一行修复了无限循环#2,第二行修复了循环#1,方法是在限制结果之前加1。因此,如果limit 为 1,您将拥有

Math.floor( /* something in [0, 1) */ * 2 )

很容易看到返回 0 或 1(而不是总是 1)。

【讨论】:

  • 是的,即使我从测试中调用 getRandomNumber(9),while 循环仍然处于无限状态。
  • @AcazSouza:Works for me。你确定是9 而不是"9"
  • 等等...我有一个奇怪的行为,我的限制并不总是 9... 为什么?如果我调用 getRandomNumber(9);限制并不总是 9...
  • 对不起,我确定限制总是 9,但仍然是无限的。
  • @AcazSouza:我不知道无限循环有什么作用,但这段代码不知道。请参阅我上面提供的链接。
猜你喜欢
  • 2011-11-15
  • 2012-11-01
  • 2016-07-14
  • 1970-01-01
  • 2018-03-17
  • 2016-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多