uniform(0, 1)
может производить 0
, но никогда не даст 1
.
Документация говорит вам , что конечная точка b
может быть включена в значениях , полученных:
Значение конечной точки b
может или не может быть включено в диапазон в зависимости от округления с плавающей точкой в уравнении a + (b-a) * random()
.
Таким образом uniform(0, 1)
, формула 0 + (1-0) * random()
, упрощенная до 1 * random()
, должна была бы быть способной производить 1
точно. Это произойдет, только если random.random()
1.0 exactly. However,
random () *never* produces
1.0`.
Цитирование random.random()
документации :
Вернуть следующее случайное число с плавающей запятой в диапазоне [0.0, 1.0).
Обозначение [..., ...)
означает, что первое значение является частью всех возможных значений, а второе - нет. random.random()
будет в большинстве случаев производить значения очень близко к 1.0
. float
Тип Python - это значение с плавающей точкой IEEE 754 base64 , которое кодирует число двоичных дробей (1/2, 1/4, 1/5 и т. Д.), Составляющих значение, а полученное значение random.random()
представляет собой просто сумму случайный выбор этих 53 таких фракций от 2 ** -1
(1/2) до 2 ** -53
(1/9007199254740992).
Однако, поскольку он может давать очень близкие значения 1.0
, а также ошибки округления, возникающие при умножении чисел с плавающей запятой, вы можете получить b
для некоторых значений a
и b
. Но 0
и 1
не входят в число этих ценностей.
Обратите внимание, что random.random()
может выдавать 0.0, поэтому a
всегда включается в возможные значения для random.uniform()
( a + (b - a) * 0 == a
). Поскольку существуют 2 ** 53
различные значения, которые random.random()
могут быть получены (все возможные комбинации этих 53 двоичных дробей), существует только 1 2 ** 53
(так что 1 в 9007199254740992) вероятность того, что это когда-либо произойдет.
Итак, максимально возможная ценность, которую random.random()
можно произвести, это 1 - (2 ** -53)
; просто выберите достаточно маленькое значение для того, b - a
чтобы округление включалось при умножении на более высокие random.random()
значения. Чем меньше b - a
, тем больше шансов на это:
>>> 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
Если вы нажмете b = 0.0
, то мы делим 1023 раза, указанное выше значение означает, что нам повезло после 1019 делений. Наибольшее значение, которое я нашел до сих пор (выполнение вышеуказанной функции в цикле с max()
), составляет 8.095e-320
(1008 делений), но, вероятно, существуют более высокие значения. Это все азартная игра. :-)
Это также может произойти, если между a
и не слишком много дискретных шагов b
, например, когда a
и b
имеют высокий показатель степени, и поэтому может показаться, что они далеко впереди. Значения с плавающей запятой по-прежнему являются только приблизительными, и число значений, которые они могут кодировать, конечно. Например, существует только одна двоичная дробь разница между sys.float_info.max
и sys.float_info.max - (2 ** 970)
, таким образом есть шанс , 50-50 random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)
производит 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
X ~ U(0,1)
, тоP(X=x)
это почти наверняка 0, для всех значений х. (Это потому, что в интервале бесконечно много возможных значений.) Если вы ищете ровно 0 или 1, вам следует использовать другую функциюrandom.choice