Мог random.randint (1,10) когда-нибудь возврат 11?

При исследовании для этого вопроса и чтении исходного кода в random.py, Я начал задаваться вопросом ли randrange и randint действительно ведите себя, как "рекламируется". Я очень склонен верить так, но путь я считал его, randrange по существу реализован как

start + int(random.random()*(stop-start))

(принимающий целочисленные значения для start и stop), таким образом, randrange(1, 10) должен возвратить случайное число между 1 и 9.

randint(start, stop) звонит randrange(start, stop+1), таким образом, возвращая число между 1 и 10.

Мой вопрос теперь:

Если random() должны были когда-либо возвращаться 1.0, затем randint(1,10) возвратился бы 11, не был бы он?

10
задан Community 23 May 2017 в 12:23
поделиться

3 ответа

Из random.py и документации:

"""Get the next random number in the range [0.0, 1.0)."""

The ) indicates that the interval is exclusive 1.0. То есть, он никогда не вернет 1.0.

Это общее соглашение в математике, [ и ] является инклюзивным, а ( и ) - эксклюзивным, и эти два типа скобок можно смешивать как (a, b) или [a, b). Загляните в Википедию: Интервал (математика) для формального объяснения.

27
ответ дан 3 December 2019 в 13:44
поделиться

В других ответах указано, что результат random () всегда строго меньше, чем 1.0 ; однако это только половина дела.

Если вы вычисляете randrange (n) как int (random () * n) , вы также должны знать, что для любого Python с плавающей точкой x , удовлетворяющий 0,0 <= x <1,0 , и любое положительное целое число n , верно, что 0,0 <= x * n , так что int (x * n) строго меньше, чем n .

Здесь могут возникнуть две ошибки: во-первых, когда мы вычисляем x * n , n неявно преобразуется в число с плавающей запятой. Для достаточно большого n это преобразование может изменить значение. Но если вы посмотрите на исходный код Python, вы увидите, что он использует метод int (random () * n) только для n меньше, чем 2 ** 53 (здесь и ниже я предполагаю, что платформа использует двойники IEEE 754), это диапазон, в котором при преобразовании n в число с плавающей запятой гарантированно не будет потеряна информация (потому что n можно представить в точности как число с плавающей запятой).

Второе, что может пойти не так, это то, что результат умножения x * n (который сейчас выполняется как произведение чисел с плавающей запятой, помните), вероятно, не будет точно представлен, поэтому будет некоторое округление. Если x достаточно близко к 1.0 , возможно, что округление округлит результат до n .

Чтобы понять, что этого не может быть, нам нужно только рассмотреть максимально возможное значение для x , которое (почти на всех машинах, на которых работает Python) 1-2 ** -53 . Итак, нам нужно показать, что (1-2 ** - 53) * n для нашего положительного целого числа n , поскольку всегда будет верно, что random ( ) * n <= (1-2 ** - 53) * n .

Доказательство (набросок) Пусть k будет уникальным целым числом k такое, что 2 ** (k-1) . Затем следующий номер с плавающей запятой из n будет n - 2 ** (k-53) . Нам нужно показать, что n * (1-2 ** 53) (т.е. фактическое, неокругленное, значение продукта) ближе к n - 2 ** (k-53) , чем до n , так что оно всегда будет округляться в меньшую сторону. Но небольшая арифметика показывает, что расстояние от n * (1-2 ** - 53) до n равно 2 ** - 53 * n , а расстояние от n * (1-2 ** - 53) до n - 2 ** (k-53) равно (2 ** k - n) * 2 ** - 53 . Но 2 ** k - n (потому что мы выбрали k так, что 2 ** (k-1) ), поэтому произведение ближе к n - 2 ** (k-53) , поэтому будет округляться в меньшую сторону (при условии, что платформа выполняет некоторую форму округления до ближайшего).

Итак, мы в безопасности.Уф!


Дополнение (04.07.2015): Вышеупомянутое предполагает арифметику двоичного 64-го стандарта IEEE 754 с режимом равномерного округления. На многих машинах это предположение довольно безопасно. Однако на машинах x86, которые используют FPU x87 для операций с плавающей запятой (например, различные варианты 32-разрядной версии Linux), существует возможность двойного округления при умножении, что делает возможным random () * n для округления вверх до n в случае, когда random () возвращает максимально возможное значение. Наименьший такой n , для которого это может произойти, равен n = 2049 . См. Обсуждение на http://bugs.python.org/issue24546 для получения дополнительной информации.

12
ответ дан 3 December 2019 в 13:44
поделиться

Из документации Python:

Практически все функции модуля зависят от базовой функции random (), которая равномерно генерирует случайное число с плавающей запятой в полуоткрытом диапазоне [0.0, 1.0).

Как почти каждый ГПСЧ чисел с плавающей запятой ..

3
ответ дан 3 December 2019 в 13:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: