loading...

re: How do you do random? VIEW POST

FULL DISCUSSION
 

There is a subtle bug to consider with your code, though. If you want to guarantee an even spread among the numbers in the set of [0, 10], you'll have problems with 10 never showing up in your histogram. The reason for this is that the random value will almost never be exactly 1, as most PRNGs will actually output something in the range of [0, 1) (note the non-inclusiveness of 1 in the return values).

To correct that problem, you have to be a little smarter about how you map the [0,1] interval to buckets of integers:

const rand = (max) => Math.floor(Math.random() * (max + 1 - Number.EPSILON));

In the case of 10, you'll be multiplying a number in the [0,1] range to something that's just under 11. Number.EPSILON is the smallest float fraction that JavaScript numbers can express, so it's as close as the JavaScript number precision gets. And because the number 11 is never a value that appears in the output, Math.floor will never return anything above 10, guaranteed.

Of course, if your PRNG never returns 1 in its output, it's safe to just do max + 1. :)

Here's an illustration:

repl.it/@KrofDrakula/safeRandom

 

What about using Math.round() in place of Math.floor() in the original?

 

Also, try out the above repl.it link, you can make your own random functions to see if your hunches are correct. :)

I'm on my smartphone at the moment, but thanks. Your other response makes a lot of sense. That's something I hadn't thought about before.

 

In that case, 0 and 10 would appear with about 50% the frequency of every other element.

If you imagine the number line after multiplying by 10, you'll understand what I mean:

0                    1                    2
|--------------------|--------------------|---....

<---------0---------><---------1---------><---....   Math.floor()
0---------><---------1---------><---------2---....   Math.round()
0<--------1----------><--------2----------><--....   Math.ceil()

This diagram shows you which floats map to which integer with different functions. As you can see, in the case of Math.round(), 0 has only half the length of every other number, so it would appear half as often. Same goes for 10 at the end of the interval:

9                    10
|--------------------|

9---------><--------10    Math.round()
<----------9--------->    Math.floor()

While 10 would appear in the resulting histogram, its frequency would be about half the frequency of every other non-zero integer.

FYI, Math.round() is just:

const round = n => Math.floor(n + 0.5);

You're effectively just shifting the mapping from floats to integers, but you're not making room for the max number. To have even distribution, you must have all intervals of equal length, and all the intervals covered by the scaled random number interval.

 

Typically don't people mean the set of numbers [0, 9] when they say they want a random int between 0 and 10? I would assume they want something out of 10 vs something out of 11

 

Well that is where your specification definition alarm bells should start ringing like crazy. We don't have a precise mathematical definition for ranges and sets like this in everyday language among lay folk, therefore you have to clarify what you mean. The example I gave above explicitly lays out the expectations, which the original text hadn't.

Technically speaking saying "between 0 and 10" could mean (0, 10), [0, 10], (0, 10] or [0, 10). In most conversations I've had, people tend to treat ranges as inclusive, so [0, 10] would probably be my best guess, but that's just anecdotal evidence on my part, and should always be checked.

code of conduct - report abuse