Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can random.uniform(0,1) ever generate 0 or 1?

In the documentation it is said that there is a chance that uniform(0,1) can generate the values 0 and 1.

I have run uniform(0, 1) 10000 times, but it never produced zero. Even in the case of uniform(0, 0.001).

Can random.uniform(0,1) ever generate 0 or 1?

like image 742
Venkatesh Gandi Avatar asked Oct 04 '19 18:10

Venkatesh Gandi


People also ask

Does random random () include 0 and 1?

The Random random() method generates the number between 0.0 and 1.0.

Can random random () give 1?

A random number generator always returns a value between 0 and 1, but never equal to one or the other. Any number times a randomly generated value will always equal to less than that number, never more, and never equal.

How are uniform random numbers generated?

The Uniform Random Number block generates uniformly distributed random numbers over an interval that you specify. To generate normally distributed random numbers, use the Random Number block. Both blocks use the Normal (Gaussian) random number generator ( 'v4' : legacy MATLAB® 4.0 generator of the rng function).

Which function returns a random number between 0.0 and 1.0 where 0.0 is inclusive but 1.0 is exclusive in Python?

The Python uniform() function takes two parameters: the lower limit and the upper limit, and returns a random number between the range. The lower limit is inclusive, but the upper limit is exclusive.


4 Answers

uniform(0, 1) can produce 0, but it'll never produce 1.

The documentation tells you that the endpoint b could be included in the values produced:

The end-point value b may or may not be included in the range depending on floating-point rounding in the equation a + (b-a) * random().

So for uniform(0, 1), the formula 0 + (1-0) * random(), simplified to 1 * random(), would have to be capable of producing 1 exactly. That would only happen if random.random() is 1.0 exactly. However, random() never produces 1.0.

Quoting the random.random() documentation:

Return the next random floating point number in the range [0.0, 1.0).

The notation [..., ...) means that the first value is part of all possible values, but the second one is not. random.random() will at most produce values very close to 1.0. Python's float type is a IEEE 754 base64 floating point value, which encodes a number of binary fractions (1/2, 1/4, 1/5, etc.) that make up the value, and the value random.random() produces is simply the sum of a random selection of those 53 such fractions from 2 ** -1 (1/2) through to 2 ** -53 (1/9007199254740992).

However, because it can produce values very close to 1.0, together with rounding errors that occur when you multiply floating point nubmers, you can produce b for some values of a and b. But 0 and 1 are not among those values.

Note that random.random() can produce 0.0, so a is always included in the possible values for random.uniform() (a + (b - a) * 0 == a). Because there are 2 ** 53 different values that random.random() can produce (all possible combinations of those 53 binary fractions), there is only a 1 in 2 ** 53 (so 1 in 9007199254740992) chance of that ever happening.

So the highest possible value that random.random() can produce is 1 - (2 ** -53); simply pick a small enough value for b - a to allow for rounding to kick in when multiplied by higher random.random() values. The smaller b - a is, the greater the chances of that happening:

>>> import random, sys
>>> def find_b():
...     a, b = 0, sys.float_info.epsilon
...     while random.uniform(a, b) != b:
...         b /= 2
...     else:
...         return b
...
>>> print("uniform(0, {0}) == {0}".format(find_b()))
...
uniform(0, 4e-323) == 4e-323

If you hit b = 0.0, then we've divided 1023 times, the above value means we got lucky after 1019 divisions. The highest value I found so far (running the above function in a loop with max()) is 8.095e-320 (1008 divisions), but there are probably higher values. It's all a game of chance. :-)

It can also happen if there are not many discrete steps between a and b, like when a and b have a high exponent and so may appear to be far appart. Floating point values are still only approximations, and the number of values they can encode is finite. For example, there is only 1 binary fraction of difference between sys.float_info.max and sys.float_info.max - (2 ** 970), so there is a 50-50 chance random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max) produces sys.float_info.max:

>>> a, b = sys.float_info.max - (2 ** 970), sys.float_info.max
>>> values = [random.uniform(a, b) for _ in range(10000)]
>>> values.count(sys.float_info.max)  # should be roughly 5000
4997
like image 119
Martijn Pieters Avatar answered Oct 19 '22 07:10

Martijn Pieters


"Several times" isn't enough. 10,000 isn't enough. random.uniform chooses from among 2^53 (9,007,199,254,740,992) different values. You're interested in two of them. As such, you should expect to generate several quadrillion random values before getting a value that is exactly 0 or 1. So it's possible, but it's very very likely that you will never observe it.

like image 28
hobbs Avatar answered Oct 19 '22 07:10

hobbs


Sure. You were already on the right track with trying uniform(0, 0.001) instead. Just keep restricting the bounds enough to make it happen sooner.

>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
0.0
like image 41
wim Avatar answered Oct 19 '22 05:10

wim


You can try and generate a loop that counts the amount of iterations needed in order to be shown an exact 0 (don't).

Furthermore, as Hobbs stated, the amount of values being uniformly sampled are 9,007,199,254,740,992. Which means the probability of seeing a 0 is exactly 1/9,007,199,254,740,992. Which in general terms and rounding up means you will need in average 10 quatrillion samples to find a 0. Of course you might find it in your first 10 attempts, or never ever.

Sampling a 1 is impossible as the interval defined for the values is closed with a parenthesis, hence not including 1.

like image 1
Celius Stingher Avatar answered Oct 19 '22 06:10

Celius Stingher