Чи може випадковий уніформа (0,1) коли-небудь генерувати 0 або 1?


9

У документації сказано, що є шанс, який uniform(0,1)може генерувати значення 0та 1.

Я пробіг uniform(0, 1)10000 разів, але це ніколи не дало нуля. Навіть у випадку з uniform(0, 0.001).

Можна random.uniform(0,1) ever generate 0 or 1?


3
Теоретично це можливо, але практично ніколи не станеться. Математично, стандартна рівномірна випадкова величина може приймати будь-яке значення в інтервалі від 0 до 1. Якщо X ~ U(0,1), то P(X=x)це майже напевно 0, для всіх значень х. (Це тому, що в інтервалі є нескінченно багато можливих значень.) Якщо ви шукаєте рівно 0 або 1, вам слід скористатися іншою функцією, наприкладrandom.choice
пауза

1
@pault майже напевно має дуже специфічне значення в математиці, що насправді не має сенсу, оскільки ми маємо дискретний розподіл, а не безперервний інтервал. Є лише обмежена кількість поплавків між 0 і 1.
wim

2
@pault Отже, чому ви говорите математично, коли ОП запитує про реалізацію random.uniform?
wim

1
Якщо ця документація є точною, мені цікаво, як це робиться для можливого отримання і 0, і 1. Здається, що [0, 1) було б набагато простіше (наприклад, як це Math.random()працює в JavaScript).
Ри-

1
50 балів за першу особу, яка опублікувала випадкову насінню, яка random.uniform(0, 1)при першому виклику повертає 0
wim

Відповіді:


13

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* produces1,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 ** 531 дюйм (тобто 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

5

"Кілька разів" недостатньо. 10 000 недостатньо. random.uniformвибирає серед 2 ^ 53 (9,007,199,254,740,992) різних значень. Вас цікавлять дві з них. Таким чином, ви повинні розраховувати на генерацію декількох квадрильйонів випадкових значень, перш ніж отримати значення, рівне рівно 0 або 1. Тож це можливо, але дуже ймовірно, що ви його ніколи не помітите.


2
Бо uniform(0, 1)це неможливо дати 1як результат. Це тому, що функція просто визначена як def uniform(a, b): return a + (b - a) * random()та random()ніколи не може виробляти 1.0.
Martijn Pieters

2
@MartijnPieters Я вважаю, що ти прав, і я підтримав твою відповідь. Я запідозрив стільки ж, але не був впевнений, і це було вбік від головної тяги моєї відповіді, тому я дозволю це бути :)
hobbs

1

Ви можете спробувати створити цикл, який підраховує кількість ітерацій, необхідних для того, щоб було відображено точне 0 (не).

Крім того, як зазначив Гоббс, кількість uniformlyвибіркових значень становить 9,007,199,254,740,992. Що означає, що ймовірність побачити 0 - це рівно 1 / 9,007,199,254,740,992. Що, загалом, і округлення означає, що вам знадобиться в середньому 10 квадратних мільйонів зразків, щоб знайти 0. Звичайно, ви можете знайти його в своїх перших 10 спробах, або ніколи.

Відбір проб 1 не можливий, оскільки інтервал, визначений для значень, закритий дужками, отже, не включає 1.


1

Звичайно. Ви вже були на правильному шляху, намагаючись uniform(0, 0.001)натомість. Просто продовжуйте обмежувати межі достатньо, щоб це відбулося швидше.

>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
0.0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.