1

I would like to use numpy to draw a random value from a continuous uniform distribution from the open range (0,5). My eyes have fallen on numpy.random.uniform(0,5). However, according to the documentation and some posts, this includes the closed interval [0,5] or a semi-open interval [0,5).

I have looked at many posts and so far not found good answers. Answers so far include: you don't need to use a fully open range because drawing the start and end values is nearly impossible (only in theory) or there are debates about whether it is actually semi-open or fully closed. The best solution I thought about so far is:

import numpy as np
rn = np.random.uniform(sys.float_info.epsilon, 5-sys.float_info.epsilon)
print(rn)

or using numpy's next_after:

import numpy as np
rn = np.random.uniform(np.nextafter(0,1), np.nextafter(5,0))
print(rn)

Obviously, I would not bother everyone if I did not have a very good reason for drawing (in theory) from a completely open range. I would really appreciate thoughts about how I could plausibly argue that I am drawing a random value from a continuous uniform distribution on the completely open interval (0,5).

Thanks in advance!

  • 1
    Can you elaborate on what problems getting `0.0` would cause you? Your second proposed solution includes the smallest representable finite positive number (approx. `5e-324`) as a potential output, and in many practical situations I'd expect that to be just as problematic as `0.0`. (Incidentally, you don't need the `np.nextafter(5, 0)`: `5` is enough here; the way that the output is constructed means that `5.0` is not a possible output. And for your first solution, `5 - sys.float_info.epsilon` is not different from `5`.) – Mark Dickinson Feb 12 '20 at 18:16
  • The primary reason why I need to draw from a completely open interval is because I am replicating an experiment with human participants. In this experiment, a random variable is drawn from an open interval. Also, it is common in my field not to lie to participants. Thus, I had to find a way to do this. Thank you for your suggestions. – Victor van Pelt Feb 13 '20 at 06:57

1 Answers1

2

What about checking if rn == 0 and rejecting it?

rn = np.random.uniform(5)
while rn == 0.0:
   rn = np.random.uniform(5)
Andreas K.
  • 9,282
  • 3
  • 40
  • 45
  • Thanks for this solution. I think I will use it. Is there no need to include a check in there for ```rn == 5.0``` ? – Victor van Pelt Feb 13 '20 at 06:54
  • There is no need to exclude 5 because according to documentation of np.random.uniform, "Samples are uniformly distributed over the half-open interval [low, high) (includes low, but excludes high)" – Andreas K. Feb 13 '20 at 07:12
  • @AndreasK. That piece of documentation is misleading. See https://github.com/numpy/numpy/issues/10803. (In this case, it _is_ true that `5.0` can't be generated, but the reason is a bit more subtle than `high` always being excluded.) – Mark Dickinson Feb 14 '20 at 16:53
  • Indeed you are right. I think that even in this case the 5.0 can be generated because `4.9999999999999999 == 5` is True. But the chance for this is very low. So yes I think you could exclude it too to be entirely sure. – Andreas K. Feb 14 '20 at 17:47
  • So if IEEE 754 binary64 floating-point is in use (which it almost certainly is), and the rounding mode is the default round-ties-to-even rounding mode (which again is very likely), then `5.0` can't be generated, essentially because `5.0 * (1 - 2**-53)` rounds to the next float down from `5.0`. (Related: https://stackoverflow.com/q/3037952/270986) But I agree that there wouldn't be any harm in adding an extra check to be sure. – Mark Dickinson Feb 16 '20 at 12:53