Reputation: 8631
I don't understand why this while
loop is infinite:
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 for this:
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;
}
});
Solution:
Sorry, the mistake was in another test, like describe by @Jon answer, when anyNumber equal a 1, infinite loop happens:
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);
}
});
Upvotes: 1
Views: 284
Reputation: 437336
The loop will be endless if limit == 1
. Consider:
var actualRandomNumber = Math.floor((Math.random() * limit) + 1);
Math.random
returns a number in the range [0, 1). Multiplying by limit
does not change that, adding one brings it to [1, 2) so by definition Math.floor
on that will return 1
.
while (window.prevRandomNumber == actualRandomNumber) {
actualRandomNumber = Math.floor((Math.random() * limit) + 1)
}
Here we have the same logic, so:
1
(it will not go into a loop because prevRandomNumber
is -1)prevRandomNumber
will be already 1I can't see how the loop would be infinite if limit
is a number greater than 1.
Consider what happens if limit
is not a number.
var actualRandomNumber = Math.floor((Math.random() * limit) + 1);
Here, Math.random() * limit
is going to be NaN
, and so will the end result of the expression. So actualRandomNumber
will always be equal to NaN
. The method will return Nan
the first time it's invoked and will not return the second time, for the same reason as above.
function getRandomNumber(limit) {
limit = Number(limit) || 9;
var actualRandomNumber = Math.floor(Math.random() * (limit + 1));
The first line fixes endless loop #2, and the second fixes loop #1 by adding 1 to limit before flooring the result. Therefore, if limit
is 1 you will have
Math.floor( /* something in [0, 1) */ * 2 )
which is easy to see returns either 0 or 1 (and not always 1).
Upvotes: 7