1

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);
        }
    });
4

1 に答える 1

7

無限ループ #1

の場合、ループは無限になりますlimit == 1。検討:

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

Math.random[0, 1) の範囲の数値を返します。を掛けてlimitもそれは変わらず、1 を足しても [1, 2) になるので、定義Math.floor上は を返し1ます。

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

ここでは同じロジックを使用しているため、次のようになります。

  • メソッドが初めて呼び出されたときに返されます( -1である1ため、ループにはなりません)prevRandomNumber
  • prevRandomNumber2回目以降は、すでに1になるため、メソッドが返されることはありません

limitが 1 より大きい場合、ループが無限になる方法がわかりません。

無限ループ #2

が数値でない場合に何が起こるかを考えてみましょうlimit

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

ここでMath.random() * limitは になりNaN、式の最終結果も同様になります。したがって、常にと等しくなりactualRandomNumberます。上記と同じ理由で、メソッドは最初に呼び出されたときに戻りますが、2 回目は戻りません。NaNNan

解決

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

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

1 行目は無限ループ #2 を修正し、2 行目は制限に 1 を加算してループ #1 を修正してから、結果をフロアリングします。したがって、limitが 1 の場合、次のようになります。

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

これは簡単にわかりますが、0 または 1 を返します (常に1 とは限りません)。

于 2012-04-21T19:21:01.133 に答える