Может ли random.uniform (0,1) генерировать 0 или 1? - PullRequest
9 голосов
/ 04 октября 2019

В документации сказано, что есть вероятность, что uniform(0,1) может сгенерировать значения 0 и 1.

Я пробежал uniform(0, 1) 10000 раз, но он никогда не выдавал ноль. Даже в случае uniform(0, 0.001).

Может ли random.uniform(0,1) когда-либо генерировать 0 или 1?

Ответы [ 4 ]

13 голосов
/ 04 октября 2019

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) существует только 1 двоичная дробь, поэтому есть вероятность 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 голосов
/ 04 октября 2019

«Несколько раз» недостаточно. 10000 не достаточно. random.uniform выбирает из 2 ^ 53 (9 007 199 254 740 992) различных значений. Вы заинтересованы в двух из них. Таким образом, вы должны ожидать генерации нескольких квадриллионов случайных значений, прежде чем получите значение, которое в точности равно 0 или 1. Так что это возможно, но очень вероятно, что вы никогда его не заметите.

1 голос
/ 04 октября 2019

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

Кроме того, как указал Хоббс, количество uniformly выборочных значений составляет 9 007 199 254 740 992. Это означает, что вероятность увидеть 0 в точности равна 1 / 9,007,199,254,740,992. Что в общих чертах и ​​округлении означает, что вам понадобится в в среднем 10 кватриллионов выборок, чтобы найти 0. Конечно, вы можете найти его в своих первых 10 попытках или никогда.

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

1 голос
/ 04 октября 2019

Конечно. Вы уже на правильном пути, пытаясь вместо этого 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...