2

How come that in the three console.log I get numbers from 17 to 70,000

But in the loop, y always ends up between 200 and 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)

Is there a different way that random() works in for loops?

4
  • 3
    Math.floor(Math.random()*5000)*17 is being executed for each iteration, and giving different random values. I think that is the reason. Commented May 23, 2020 at 9:05
  • ARGH!! hahaha I had no idea!! - I will test that at once :D Commented May 23, 2020 at 9:05
  • @TulshiDas how would you test it? Commented May 23, 2020 at 9:06
  • I tried 100 of the loops and made the random between 1 and 1000 Most of them ended up below 10 :D So yes - that is correct! Make an answer so I can give you the point :) Commented May 23, 2020 at 9:10

3 Answers 3

4

That is because the Math.... in your loop gets evaluated each time.

But you use it as the condition to stop looping. What that means is that usually takes between 200 and 800 tries for your whole expression to evaluate to less that the current x. The higher the iteration the more likely it will exit the loop.

Perhaps what you meant to do was

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)

which will create the iterations variable only once and use it in the full loop cycle.


If you want to see what is happening in the original code run the following

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

Sign up to request clarification or add additional context in comments.

6 Comments

It seems logical, but how would you test it?
@radulle added another snippet to show what was going on.
Just noticed it after posting another snippet which led me to find another JS for loop quirk where loop is stopped implicitly when x is equal to the limit. Very exciting morning :D
@radulle it stops when equal to the limit because we say loop while x < limit if you do x <= limit it will be included.
That is clear, but look at the code snippet in my answer, it will stop even if it is defined like for (let x = 0; b = Math.floor(Math.random()*5000)*17; x++) { which means that it would be enough just to have a value and not a condition.
|
1

No, but the way you set up your for loop, you basically created a sort of normal distribution, and y will present one of the values in the normal distribution.

It will get a little mathy to explain why, but it's basically because of this.

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

Note how your ending condition of your for loop is a random number, so basically, your loop will end at a random time. In theory, it could end stop after the first iteration (if the RNG comes up with 0), or as late as 85000 (if it keeps rolling really high, many times in a row, this is extremely unlikely though), but unlike the original random functions, the changes are not distributed evenly.

It's more like a bell curve, and apparently the chances are very high to end in the range of 200 to 800, and very low outside of these ranges.

I could probably calculate exactly which values have which probability, but I'm not going to. Ask numberphile or that other math youtuber, they'll love it.

Explained in the most basic way:

You generated a function that returns the number of try the random number generator needed to satisfy the condition of x being larger than the randomly generated number, where x increments by 1 each time (so the problem gets easier every iteration) and the value to compare to is random, between 0 and 85000.

the first few rounds are pretty unlikely, as x is still really small, so the target is very hard to hit (it has to roll a very low number). But as x gets bigger, it becomes more likely that the RNG is small enough to hit it. As well as every single roll has a change to hit it. So it becomes statistically more and more likely to have hit it at some point. (It's unlikely to keep rolling high numbers all the time).

Eventually it becomes more and more likely to roll because as long as the random number generated is low enough (lower than x, which increases every time), it will pass.

1 Comment

So it could hit 70,000 but we would have to be more lucky than winning the super ball :D
-1

This would be a great question on a job interview :D What is also interesting is that you could access the generated value like in the code below:

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)

Turns out that it is because in that iteration b is evaluated to zero which is a falsy value. In this case because of Math.floor() it is enough that the number generated is smaller than 0.0002 because it was multiplied by 5000 which is not too uncommon as generated number has 16 figures. It just shows that Math.floor(Math.random()*X) shouldn't be relied on to generate random numbers.

8 Comments

huh? what is even the ending condition on that loop?
Implicitly it is x == b or x === b. Not sure how to explain it.
Nothing unexpected in this case, and it is not implied x === b. What happens is that the second part of the for is evaluated to a boolean. So it ends when it is false. In your case it stops when the expression evaluates to 0 and has nothing to do with equaling the x.
@GabrielePetrioli just checked, you are completely right. Good reasoning. Still, very interesting that it takes such a small number of random generations to yield a zero.
@ZimriLeijen seems it is because of Math.floor(). It is enough that the number generated is smaller than 0.0002 because it was multiplied by 5000 which is not too uncommon as generated number has 16 figures. It just shows that Math.floor(Math.random()*X) shouldn't be relied on to generate random numbers.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.