I\'m trying to generate a random number between 0.1 and 1.0.
We can\'t use rand.randint
because it returns integers.
We have also tried random.uniform(0.1
Random.uniform() is just:
def uniform(self, a, b):
"Get a random number in the range [a, b) or [a, b] depending on rounding."
return a + (b-a) * self.random()
where self.random()
returns a random number in the range [0.0, 1.0)
.
Python (as well as many other languages) uses floating point to represent real numbers. How 0.1 is represented is described in detail in the docs:
from __future__ import division
BPF = 53 # assume IEEE 754 double-precision binary floating-point format
N = BPF + 3
assert 0.1 == 7205759403792794 / 2 ** N
It allows to find a random number in [0.1, 1]
(inclusive) using
randint()
without losing precision:
n, m = 7205759403792794, 2 ** N
f = randint(n, m) / m
randint(n, m)
returns a random integer in [n, m]
(inclusive)
therefore the above method can potentially return all floating points
numbers in [0.1, 1]
.
An alternative is to find the smallest x
such that x > 1
and use:
f = uniform(.1, x)
while f > 1:
f = uniform(.1, x)
x
should be the smallest value to avoid losing precision and to
reduce number of calls to uniform()
e.g.:
import sys
# from itertools import count
# decimal.Decimal(1).next_plus() analog
# x = next(x for i in count(1) for x in [(2**BPF + i) / 2**BPF] if x > 1)
x = 1 + sys.float_info.epsilon
Both solutions preserve uniformness of the random distribution (no skew).