В других ответах указывалось, что результат random()
всегда строго меньше 1.0
;однако, это только половина истории.
Если вы вычисляете randrange(n)
как int(random() * n)
, вам также нужно знать, что для любого числа с плавающей точкой Python x
, удовлетворяющего 0.0 <= x < 1.0
и любое положительное целое число n
, это правда, что 0.0 <= x * n < 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
для нашего положительного целого числа n
, поскольку всегда будет верно, что random() * n <= (1 - 2**-53) * n
.
Доказательство (эскиз) Пусть k
будетуникальное целое число k
такое, что 2**(k-1) < n <= 2**k
.Тогда следующий поплавок вниз от 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 < n
(потому что мы выбрали k
, чтобы 2**(k-1) < n
), так что произведение на ближе к n - 2**(k-53)
, так что будет округляться (при условии, чтов том, что платформа выполняет ту или иную форму округления до ближайшего).
Итак, мы в безопасности.Фу!
Приложение (2015-07-04): В приведенном выше примере используется арифметика IEEE 754 для двоичных чисел 64, с режимом округления числа к четному.На многих машинах это предположение довольно безопасно.Однако на машинах x86, использующих FPU x87 для чисел с плавающей запятой (например, различные разновидности 32-битного Linux), существует вероятность двойного округления при умножении, что делает возможным *От 1073 * до до до n
в случае, когда random()
возвращает максимально возможное значение.Наименьшее значение n
, для которого это может произойти, - n = 2049
.См. Обсуждение в http://bugs.python.org/issue24546 для получения дополнительной информации.