10
\$\begingroup\$

The javascript method Math.random() returns a (pseudo-)random float between 0 (inclusive) and 1 (exclusive).

In some use cases, I need both limits to be excluded, a random float between 0 (exclusive) and 1 (exclusive).

This is what I currently use to generate said random float:

do {
    var random = Math.random();
} while(random === 0);

But I have a feeling that the (possibly) multiple draws from the random pool somehow mess up the distribution of my random floats.

Is there any downside to using this snippet and if so, how could I generate random floats while excluding both the lower and the upper limits?

\$\endgroup\$
7
  • 3
    \$\begingroup\$ This is not a code review question as it does not contain real-world working code but rather hypothetical code. I belive this question to be off-topic for this site. \$\endgroup\$
    – Emily L.
    Jul 3, 2015 at 8:33
  • 1
    \$\begingroup\$ @EmilyL.: I disagree. The three lines shown above are real-world working code, which I actually use to generate a float between 0 and 1 and about which I have doubts. \$\endgroup\$
    – Lars Ebert
    Jul 3, 2015 at 8:36
  • 1
    \$\begingroup\$ There is nothing to review. The question boils down to "Is this correct code or not?" as such it is better suited for StackOverflow. \$\endgroup\$
    – Emily L.
    Jul 3, 2015 at 8:46
  • 5
    \$\begingroup\$ @Yann Code Review does not endorse MCVE's! That's SO style. \$\endgroup\$
    – Mast
    Jul 3, 2015 at 8:53
  • 1
    \$\begingroup\$ @janos: But the provided code works as intended, to the best of my knowledge. I don't know if using a loop has any unintended side-effects, that is what I am asking. By the way, the code snippet is not even intended to be an MCVE, I just copied it out of my source code. \$\endgroup\$
    – Lars Ebert
    Jul 3, 2015 at 9:04

2 Answers 2

14
+50
\$\begingroup\$

Too long for a comment:

Please do not use the approach given in @Yann's answer:

var random = Math.random() * (1 - Number.MIN_VALUE) + Number.MIN_VALUE;

The reason is that Number.MIN_VALUE == 5E-324. As numbers in javascript are doubles with 52 bit mantissa and the largest number smaller than 1.0 that can be represented is somewhere around 1.0 - 2^(-52). The expression (1 - 5e-324) is not representable and will truncate to exactly 1.0.

The addition of Number.MIN_VALUE to the random value will also truncate for large parts of the number range, skewing your distribution.

The correct (and fastest) way to do this is by using the original code in OP's question (as also pointed out by @200_success's answer).

Addendum:

Even if we let: almost_one be the largest value smaller than 1.0 and then did:

var random = Math.random()*almost_one + Number.MIN_VALUE;

then the value would still be wrong.

To achieve a uniform distribution Math.random() must only return values with the same exponent (i.e. only the mantissa differs). Otherwise you'd have many more numbers between [0, 0.01] than you would between [0.01, 1.0].

So for any return value of Math.random() besides 0.0 the addition of Number.MIN_VALUE will truncate. However if Math.random() returns 0.0 you will get the smallest value larger than 0.0 that is representable (5e-324) as your result. But then there will be a huge gap to the next number that you can get as a result, so your distribution will not be uniform any more.

The following is also wrong:

var random = Math.random()*almost_one + (1.0 - almost_one);

This can easily be seen by assuming that Math.random() returns its maximal value which is almost_one, then you would have:

var random = almost_one*almost_one + (1.0 - almost_one);

which is not equal to almost_one (it's close, but not correct).

\$\endgroup\$
1
  • 2
    \$\begingroup\$ I yield to your greater knowledge, I've deleted my answer to not confuse anyone further. \$\endgroup\$
    – Yann
    Jul 3, 2015 at 13:47
9
\$\begingroup\$

This is a loop that almost always executes just once. It's not going to drain more entropy or skew the distribution. It's also easy to understand.

I'd leave it as it is.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.