Math.Random() Explanation

Math.random() explanation


int randomWithRange(int min, int max)
{
int range = (max - min) + 1;
return (int)(Math.random() * range) + min;
}

Output of randomWithRange(2, 5) 10 times:

5
2
3
3
2
4
4
4
5
4

The bounds are inclusive, ie [2,5], and min must be less than max in the above example.

EDIT: If someone was going to try and be stupid and reverse min and max, you could change the code to:

int randomWithRange(int min, int max)
{
int range = Math.abs(max - min) + 1;
return (int)(Math.random() * range) + (min <= max ? min : max);
}

EDIT2: For your question about doubles, it's just:

double randomWithRange(double min, double max)
{
double range = (max - min);
return (Math.random() * range) + min;
}

And again if you want to idiot-proof it it's just:

double randomWithRange(double min, double max)
{
double range = Math.abs(max - min);
return (Math.random() * range) + (min <= max ? min : max);
}

Explain Math.floor(Math.random())

Math.random will give you a floating point number between 0 (inclusive) and 1 (exclusive).

Multiplying that by 256 will give you a number in the range 0 (inclusive) through 256 (exclusive), but still floating point.

Taking the floor of that number will give you an integer between 0 and 255 (both inclusive).

It's the integer from 0 to 255 that you need to construct RGB values like rgb(72,25,183).

How does Math.floor(Math.random() * (Max - Min + 1) + Min) work in JavaScript? (Theory)

I'll explain this formula:

Math.floor(Math.random() * (myMax - myMin + 1) + myMin);

Say we want a random number from 5-15 (including both 5 and 15 as possible results). Well, we're going to have to work with Math.random(), which only produces values from 0 through approximately 0.99999999999999, so we need to do two tricks to be able to work with this.

The first trick is recognizing that Math.random()'s lowest possible return value is 0, and 0 times anything is 0, so we need to start our range at 0 and adjust to account for this at the end. Instead of calculating 5-15 from the beginning, we recognize that there are 11 values in 5-15 (5, 6, 7, 8, 9, 10, 11, 12, 13, 14, and 15) and count up that many from 0 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) to use 0-10 as our range instead. This is what the myMax - myMin part of the formula does. It defines our new max as 10. Then, at the end of the calculations, we'll just add 5 back to whatever result we get to make the possible result range change from 0-10 to 5-15. This is what the + myMin part of the formula does.

The second trick is recognizing that multiplying Math.random() by our new max range of 10 can only give us a result as high as about 9.999999999999 because Math.random() only goes as high as about 0.99999999999 (never actually 1). When we Math.floor() that later to make it an integer, it brings the result down to 9, so we need to add 1 there to make the maximum possible value 10 instead of 9. That's what the + 1 part of the formula does.


Let's finish this off by walking through an example.

Math.random() can be 0 at lowest and approximately 0.99999999999999 at highest (never 1). Let's just look at what happens with those two cases to see how the range works out.

If we run the case where we've called randomRange(5, 15) and Math.random() gives us 0, here's what we end up with:

Math.floor(Math.random() * (myMax - myMin + 1) + myMin);

=

Math.floor(0 * (15 - 5 + 1) + 5);

=

Math.floor(0 * 11 + 5);

=

Math.floor(0 + 5);

=

Math.floor(5);

=

5

So the lowest value possible is 5. If we run the case where we've called randomRange(5, 15) and Math.random() gives us 0.99999999999999, here's what we end up with:

Math.floor(Math.random() * (myMax - myMin + 1) + myMin);

=

Math.floor(0.99999999999999 * (15 - 5 + 1) + 5);

=

Math.floor(0.99999999999999 * 11 + 5);

=

Math.floor(10.9999999999999 + 5);

=

Math.floor(15.9999999999999);

=

15

So the highest value possible is 15.

How does Math.random() EXACTLY work in Java?


I was however, puzzled why a random number (say 0.78396954122) multiplied by 6 could become a random number between 1 to 6. Supposedly the random number 0.78396954122 multiplied by 6, is always 6, right?

No. 0.78396954122 * 6 is 4.70381724732 which when truncated by (int) becomes 4 which then becomes 5 when the + 1 is done.

Similarly, Math.random might return 0.2481654 which when multiplied by 6 is 1.4889924, which (int) truncates to 1, and then becomes 2 thanks to the + 1.

If it were, say, 0.0485847 * 6, that would be 0.2915082, which (int) truncates to 0, which becomes 1 thanks to the + 1.

The lowest value Math.random will ever return is 0.0, which is truncated to 0 by (int). 0 * 6 is 0, which becomes 1 after the + 1. The highest value Math.random will ever return is 0.99999999(etc) (e.g.,. it will be < 1). Multiplying that by 6 gives us 5.999999(etc) which is truncated to 5 by (int), and then turned into 6 by + 1.

So that's how we get the range 1-6 from that code.

Concept of Math.floor(Math.random() * 5 + 1), what is the true range and why?

From the Mozilla Developer Networks' documentation on Math.random():

The Math.random() function returns a floating-point, pseudo-random number in the range [0, 1) that is, from 0 (inclusive) up to but not including 1 (exclusive).

Here are two example randomly generated numbers:

Math.random() // 0.011153860716149211
Math.random() // 0.9729151880834252

Because of this, when we multiply our randomly generated number by another number, it will range from 0 to a maximum of 1 lower than the number being multiplied by (as Math.floor() simply removes the decimal places rather than rounding the number (that is to say, 0.999 becomes 0 when processed with Math.floor(), not 1)).

Math.floor(0.011153860716149211 * 5) // 0
Math.floor(0.9729151880834252 * 5) // 4

Adding one simply offsets this to the value you're after:

Math.floor(0.011153860716149211 * 5) + 1 // 1
Math.floor(0.9729151880834252 * 5) + 1 // 5

What is the meaning of : ballDX = math.random(2) == 1 and 100 or -100

It means, that ballDX will get only two random values: 100 or -100.

  • If math.random(2) returns 2, then statement 2 == 1 and 100 will
    be false, ballDX gets value false or -100, it means -100.
  • if math.random(2) returns 1, then statement 1 == 1 and 100 will
    be true, ballDX gets value 100 or -100, it means it gets first
    true variable, it means 100.

Generating random whole numbers in JavaScript in a specific range

There are some examples on the Mozilla Developer Network page:

/**
* Returns a random number between min (inclusive) and max (exclusive)
*/
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}

/**
* Returns a random integer between min (inclusive) and max (inclusive).
* The value is no lower than min (or the next integer greater than min
* if min isn't an integer) and no greater than max (or the next integer
* lower than max if max isn't an integer).
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}

Here's the logic behind it. It's a simple rule of three:

Math.random() returns a Number between 0 (inclusive) and 1 (exclusive). So we have an interval like this:

[0 .................................... 1)

Now, we'd like a number between min (inclusive) and max (exclusive):

[0 .................................... 1)
[min .................................. max)

We can use the Math.random to get the correspondent in the [min, max) interval. But, first we should factor a little bit the problem by subtracting min from the second interval:

[0 .................................... 1)
[min - min ............................ max - min)

This gives:

[0 .................................... 1)
[0 .................................... max - min)

We may now apply Math.random and then calculate the correspondent. Let's choose a random number:

                Math.random()
|
[0 .................................... 1)
[0 .................................... max - min)
|
x (what we need)

So, in order to find x, we would do:

x = Math.random() * (max - min);

Don't forget to add min back, so that we get a number in the [min, max) interval:

x = Math.random() * (max - min) + min;

That was the first function from MDN. The second one, returns an integer between min and max, both inclusive.

Now for getting integers, you could use round, ceil or floor.

You could use Math.round(Math.random() * (max - min)) + min, this however gives a non-even distribution. Both, min and max only have approximately half the chance to roll:

min...min+0.5...min+1...min+1.5   ...    max-0.5....max
└───┬───┘└────────┬───────┘└───── ... ─────┘└───┬──┘ ← Math.round()
min min+1 max

With max excluded from the interval, it has an even less chance to roll than min.

With Math.floor(Math.random() * (max - min +1)) + min you have a perfectly even distribution.

min.... min+1... min+2 ... max-1... max.... max+1 (is excluded from interval)
| | | | | |
└───┬───┘└───┬───┘└─── ... ┘└───┬───┘└───┬───┘ ← Math.floor()
min min+1 max-1 max

You can't use ceil() and -1 in that equation because max now had a slightly less chance to roll, but you can roll the (unwanted) min-1 result too.

JavaScript Random Number

Math.random() will give you a "real" number from 0 to 1 (not including 1.0).

That's cool and all, but what if I want a "real" number from 1 to 2?

The answer: "transform" your [0,1) into [1,2).

In practical terms, it means adding 1 to your result.

Try it out -- Math.random()+1 will give you a number from 1 to 2.

In mathematics this is known as a "mapping". That is -- for every possible real number in [0,1), find a way to "map" that real number to another real number in [1,2). That is, if I give you any real number between [0,1), you should be able to map that number -- apply that number to a function that will return a number between [1,2).

In our case, that function f(x) = x+1.

Do you see how this gives us random numbers between [1,2)? Visualize the two intervals next to each other and imagine a line going from every point in [0,1) to its corresponding map in [1,2). Now, pick a random point on [0,1) ... and follow the line. You'll follow the line to a random point in [1,2)!

Now, all complete one-to-one maps from [0,1) to [1,2) will turn a random number between [0,1) to a random number between [1,2)...but not all of them will give you an evenly distributed random number between [1,2). The mathematics behind what maps give you evenly distributed results is a bit complicated but in short, if your map only involves adding, subtracting, multiplying, and dividing by constants, it's "legal" in the sense that the results will also be evenly distributed.

So, now we know how to transform [0,1) into [1,2).

What if I want to map [0,1) onto [0,2)? I can't just add numbers anymore ...

How about I multiply everything by two?

This should work -- the function f(x) = x*2 does indeed map every point on [0,1) to a point on [0,2) --- and because it only involves multiplication by constants (2), it is a distribution-preserving map.

This works! Math.random()*2 will give you a random number between 0 and 2.

Okay, now something a bit more complicated ... transforming [0,1) into [1,3).

Multiplying by two doesn't work ... 0*2 = 0, and that's not in your target range.
Adding one doesn't work... even though 0+1 is in your target range and 1+1 is, as well, there is no way you can ever reach 3.

If we can't transform [0,1) into [1,3), let's try and see if we can transform something else into [1,3).

How about [0,2)? Yes, we can do this ... the function f(x) = x+1 perfectly maps [0,2) to [1,3). You can think of + as "shifting" the range up.

And so the solution here is clear -- first, turn [0,1) into [0,2), then turn [0,2) into [1,3).

We already know the first (f(x) = x*2), and we figured out the second (f(x) = x+1). So the "combined" transformation/map is f(x) = (x*2)+1.

That is, Math.random()*2 + 1 will give you a number from 0 to 3.

Now for the final trick...mapping [0,1) to an arbitrary range [min,max).

The secret here is to re-write this as [min,min+range), where range = max-min.

Here you can see that it's simple to transform the range [0,range) to [min,min+range) -- you just add "min" to it. So if I had the range [0,range), and I wanted to get [min,min+range), i would use f(x) = x+min.

So how do we get from [0,1) to [0,range) ?

Multiply by range!

f(x) = (x*range) + min

Now writing things back to original terms, using range = max-min

f(x) = (x*(max-min)) + min

will transform a real number from [0,1) to a real number from [min,max)

I'll leave the rest (turning it into a useful integer) to you



Related Topics



Leave a reply



Submit