[JS] So, I'm really curious about how Math.ceil works in conjunction with multiplying things from Math.random

js

#1

So, when fooling around with the coding section of the page on the final part of the first JavaScript lesson, I typed in some code to test it out, because I was actually really curious.

  1. console.log(Math.ceil(Math.random() * 1000) / 10);
  2. console.log(Math.ceil(Math.random() * 100));
  3. console.log(Math.ceil(Math.random() * 10) * 10);
  4. console.log(Math.ceil(Math.random() * 5) * 20);

I had assumed that, by doing Math.random, multiplying by 1000 in Math.ceil, and then diving that total by ten, I’d get what could be a percentage of 100 with one float point, and I was right.

My next one, I had assumed that I could get an accurate rounded percentage to have no float point by doing Math.random times 100 in a Math.ceil, and I was also right.

Now, my third one was a bit tricky. I wanted to count by 10s, but still have a percentage. It worked somewhat as expected, but it only seemed to return 10, 20, or 30, even after refreshing the console many times by clicking “Run”. Not sure of why that occured.

My fourth and final one was one where I wanted to get an accurate percentage counting up by fives. I’d get a random number between 1 and 100 every time, but it would never end with a 5, just a 0. Again, not sure of why that occured.

I understand that the console in the course might not be perfect, but if I am going about it wrong, I’d really appreciate someone telling me the proper way to type it, as well as explaining what each part of the equation would do in that case. It would be easiest for me to understand if you limited it to Math.ceil and Math.random like I did for this description, as I’m still on the end of the first lesson, which is around 7% of the actual course.


#2

There is only one justification for using the ceiling value in random generation expressions… The desired outcome is to fit a range from zero to some upper value with both endpoints included.

 Math.ceil(Math.random() * 10)

The range would include all values, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]. Notice that there are eleven values in that list. We would only do this if this is in fact the desired range (interval).

In most cases, we would want only ten elements in that range, so would floor the generated value.

 Math.floor(Math.random() * 10)

which generates a whole number between zero and nine, inclusive.

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Now there are ten values instead of eleven. The side-effect of the function is something we must dictate so we don’t get false positives or unwanted values.

Math.floor(Math.random() * 10 + 1)

The range of outputs would be,

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

This is the generally preferred approach since that are no unexpected side-effects. If we want the zero and the 10, then it can be achieved with either the ceiling, or a slight modification of the above expression…

Math.floor(Math.random() * 11)

See where the ambiguity comes in to play? What is with the 11? Code needs to be readable, and understandable if a reader is to disseminate it accurately. The floor expression is unambiguous, which is why it is the preferred method. The above question never comes up because there are no mysterious numbers in the expression.


#3

Well, I suppose you’re right, but I didn’t understand half of it, I asked more specifically about Math.ceil due to the fact that it rounds up to the nearest whole number. Sure, adding one could possibly achieve what I want, but what if, like in the case of my first equation, I wanted to retain a decimal? That would make the equation that much harder, and if done wrong, could yield a result over 100.


#4

This will give you a float without using division, or a ceiling…

Math.random() * 100

but it won’t give you 100. The problem with using ceil() is that it will give 0 if random() returns 0, which it can. We cannot assume that it will always round up.

The objective of floor() and ceil() is to get a rounded result. Convoluting an expression to force an outcome only confuses the code and makes clear dissemination difficult for readers and for debugging. There are more explicit ways of rendering floats (though in JavaScript this is difficult).

The only expression above that is clearly on par with reader reasoning is the first one, but it will only return a float if the number is not evenly divisible by 10, otherwise it will be an integer.


Part of the problem is that JavaScript has no Float class, only a Number class. Any number that ends in .0 will be rendered as an integer.


#5

I understand that ceil can return zero, that was actually kinda my point. 0% is nothing and 100% is everything, which is exactly why I used ceil.

I don’t really understand the concept of convoluting an expression, as I’ve never heard of it before.

Also, I was curious about a math expression that would return a number between 0 and 100 in counts of 5s or 10s, not all this random stuff that still doesn’t really answer my question.

Sorry if that may seem rude, as I don’t intend for it to be.


#6

Dont understand about this part, what you want to achieve. Because your goal stated below:

I run it in a loop for 50 times, and the results are all counted by 10s, up until 100. No problem at all.


Your real problem is in Q4:

This is because your code:

Dissecting your code into simple pieces, the possible numbers generated after Math.ceil are 0, 1, 2, 3, 4, 5. So if you calculate, neither all those numbers will give you a number ending with 5 after you multiply it with 20. Then you know, you need to tweak the formula just a little to achieve what you intended, it’s a math problem rather than coding problem.


@mtf proposed Math.floor is very reasonable. If you tinker with your project long enough, you will notice you hardly ever get 0 as a result in console.log. This is because how Math.ceil works, it return the smallest integer greater than or equal to a given number.

For you to get 0 as the result, unless your Math.random return a 0, then your Math.ceil will return a 0 as well. If your Math.random return any number above 0 like 0.000001, you will not get a 0 through Math.ceil because Math.ceil(0.000001) equals to 1. So the chances of getting 0 is minuscule.

You can put your console.log into a loop for 1000 times. Still, barely get a 0. Different goes for Math.floor because Math.floor returns the largest integer less than or equal to a given number.

So if ever you get a Math.random that generate anything from 0 to numbers like 0.989, your Math.floor will be able to produce a 0. That way, mathematically speaking and probability speaking, the chances are much fair and more distributed.


Just my two cents. Happy Coding! :slight_smile: