Why if I use random number generator and range 0 - 9 I don't get the same uniform distribution as combined it with the floor function?
-
5Can you add example code? (and for extra credit, some statistical data that compares both and demonstrates the problem) – Merlyn Morgan-Graham Sep 11 '11 at 10:57
2 Answers
Math.floor(Math.random() * 10)
gives quite uniform distribution, while Math.round(Math.random() * 10)
doesn't.
Math.floor() returns 0 for any value in the range [0, 1) (1 exclusive), 1 for any value in the range [1, 2), etc.
So if we have equal chances of getting a number in one of these ranges, we will get an equal distribution of 0's and 1's.
Math.round(), however, returns 0 for values under 0.5, 1 for values under 1.5, etc.
So we actually have half the chances of getting a 0, as only values from 0 to 0.5 will round to 0.
╔═════════╦═════════╦═════════╗
║ Range ║ floor() ║ round() ║
╠═════════╬═════════╬═════════╣
║ [0, 1) ║ 0 ║ 0 or 1 ║
║ [1, 2) ║ 1 ║ 1 or 2 ║
║ [2, 3) ║ 2 ║ 2 or 3 ║
║ ... ║ ... ║ ... ║
║ [9, 10) ║ 9 ║ 9 or 10 ║
╚═════════╩═════════╩═════════╝

- 98,321
- 23
- 206
- 194
-
1yes, That's what I'm doing at the moment. But I'm asking **why** without floor this distribution isn't as uniform as with floor. – user336635 Sep 11 '11 at 11:04
-
3Imagine a line on graph paper, 10 squares long. 0 at the left, 10 at the right, 5 right in the middle. If you use round(), then the region half a square left of 5, *and* half a square right of 5, will map to 5. However, only half a square right of 0 maps to 0, there is no half a square left of 0 on the line. When you use floor(), only the values one square to the right of n will map to n you reduce the number of possible outcomes, as you can't get 10 any more. However, each of the 10 possible outcomes (0-9 inc) has the same "share" of the line, and therefore the same odds of occuring. – Sophistifunk Jun 13 '14 at 04:06
-
1`Math.round(Math.random())` is accurate in one case, though: When you "flip a coin", i.e. want to have 0 or 1. – wortwart Dec 21 '16 at 22:31
-
Would this hold true for the following algorithm `Math.round(Math.random() * 10 + 1)`? – oldboy May 17 '17 at 22:45
I really like to trigger 31-bit int instead of Math.floor()
, by doing a binary "or 0" operation. It makes it slightly faster (stack vs heap,) seems a tad neater, and does the same thing, in a practical sense. Here is an example that gets a random element of an array:
var ar=[1,2,3,4,5,6,7,8,9,0,'a','b','c','d']
console.log(ar[(Math.random() * ar.length) |0])
This might seem like premature optimization, but as I said, I like how it looks, and it takes less typing than Math.floor()
. Using Math.round()
would require an extra step (because the spread is 1
to ar.length
not 0
to ar.length-1
)

- 3,411
- 1
- 30
- 31
-
How do you know it's slightly faster and, excuse my ignorance, what is stack vs. heap? I know they having something to do with sorting algorithms – oldboy May 17 '17 at 22:48
-
1https://jsperf.com/random-array-item shows that it is slightly faster on my browser (on average about ±0.5% - x±0.8% on Mac Chrome Version 58.0.3029.110 (64-bit)) here is more about stack/heap: http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap the `|0` forces it into int32 (rounds it, and types it) so it can sit in the stack, wheras general Numbers are always in the heap (just in case they end up larger or have a decimal point.) – konsumer May 18 '17 at 01:16
-
It's not a huge difference in speed, but it is a small one, and as I said, I think it looks nice, too. – konsumer May 18 '17 at 01:18
-
thanks. i'll have to read that once i get some free time. i didn't know you had any control over "computer memory"? with javascript (i.e. int32) like you do with C languages. or am i just misunderstanding this. – oldboy May 18 '17 at 06:01
-
1It's not so much control, but a quick hack to herd memory usage into the stack, indirectly. see more about it here: http://stackoverflow.com/questions/7487977/using-bitwise-or-0-to-floor-a-number – konsumer May 18 '17 at 07:53