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,
() *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()
виробляє просто суму a випадковий вибір цих 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 двійкових дробів), є лише 2 ** 53
1 дюйм (тобто 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