Итак, у Python есть положительная и отрицательная бесконечность:
float("inf"), float("-inf")
Это похоже на тип функции, который должен иметь некоторые оговорки. Есть ли что-нибудь, о чем я должен знать?
Итак, у Python есть положительная и отрицательная бесконечность:
float("inf"), float("-inf")
Это похоже на тип функции, который должен иметь некоторые оговорки. Есть ли что-нибудь, о чем я должен знать?
Вы все равно можете получить значения not-a-number (NaN) из простой арифметики с участием inf
:
>>> 0 * float("inf")
nan
Обратите внимание, что вы обычно не получаете значение inf
через обычные арифметические вычисления:
>>> 2.0**2
4.0
>>> _**2
16.0
>>> _**2
256.0
>>> _**2
65536.0
>>> _**2
4294967296.0
>>> _**2
1.8446744073709552e+19
>>> _**2
3.4028236692093846e+38
>>> _**2
1.157920892373162e+77
>>> _**2
1.3407807929942597e+154
>>> _**2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
OverflowError: (34, 'Numerical result out of range')
Значение inf
считается очень особенным значением с необычной семантикой, поэтому лучше знать о OverflowError
сразу через исключение, а не иметь значение inf
, которое тихо вводится в ваши вычисления.
Реализация Python следует стандарт IEEE-754 довольно хорошо, который вы можете использовать в качестве руководства, но он полагается на базовую систему, на которой он был скомпилирован, поэтому могут возникать различия в платформе . Недавно было применено исправление, которое позволяет "бесконечность" , а также "inf" , но это имеет второстепенное значение.
Следующие разделы одинаково хорошо применимы к любому языку, который правильно выполняет арифметику с плавающей запятой IEEE, это не относится только к Python.
При работе с операторами бесконечности и большей, чем >
или менее <
, следующие значения:
+inf
, больше, чем -inf
-inf
, меньше +inf
+inf
не выше и ниже, чем +inf
-inf
не выше и ниже -inf
NaN
ложно (inf
не выше и не ниже NaN
)При сравнении для равенства +inf
и +inf
равны, как и -inf
и -inf
. Это очень обсуждаемый вопрос и может показаться спорным для вас, но в стандарте IEEE и Python ведет себя так же, как это.
Конечно, +inf
не соответствует -inf
, и все, включая NaN
, неравномерно NaN
.
Большинство вычислений с бесконечностью дадут бесконечность, если оба операнда не являются бесконечными, когда операционное деление или по модулю или с умножением на ноль есть некоторые специальные правила, которые следует иметь в виду:
NaN
0.0
или -0.0
².NaN
.inf - inf
результат undefined: NaN
;inf - -inf
результат inf
;-inf - inf
результат -inf
;-inf - -inf
результат undefined: NaN
.inf + inf
результат inf
;inf + -inf
результат undefined: NaN
;-inf + inf
результат undefined: NaN
;-inf + -inf
результат -inf
.math.pow
, pow
или **
сложно, так как оно не ведет себя так, как должно. Он генерирует исключение переполнения, когда результат с двумя действительными числами слишком высок, чтобы соответствовать плаванию с двойной точностью (он должен возвращать бесконечность), но когда ввод inf
или -inf
, он ведет себя корректно и возвращает либо inf
или 0.0
. Когда второй аргумент NaN
, он возвращает NaN
, если первый аргумент не равен 1.0
. Есть больше проблем, не все описанные в документах. math.exp
имеет те же проблемы, что и math.pow
. Решение исправить это для переполнения - использовать код, подобный этому:
try:
res = math.exp(420000)
except OverflowError:
res = float('inf')
Примечание 1: в качестве дополнительной оговорки, которая, как определено стандартом IEEE, если результат вычисления будет недостаточным или переполнен, результат не будет ошибкой недо- или переполнения, но положительной или отрицательной бесконечностью: 1e308 * 10.0
дает inf
.
Примечание 2: поскольку любой расчет с помощью NaN
возвращает NaN
и любое сравнение с NaN
, включая NaN
себя false
, вы должны использовать math.isnan
, чтобы определить, действительно ли число NaN
.
Примечание 3: хотя Python поддерживает запись float('-NaN')
, знак игнорируется, потому что внутри NaN
не существует знака внутри. Если вы разделите -inf / +inf
, результат будет NaN
, а не -NaN
(такой вещи нет).
Примечание 4: будьте осторожны с любым из вышеперечисленных способов, поскольку Python полагается на библиотеку C или Java, для которой он был скомпилирован, а не все базовые системы правильно реализуют все это поведение. Если вы хотите быть уверенным, испытайте бесконечность перед выполнением вычислений.
¹) В последнее время означает, что версия 3.2.
²) Плавающие точки поддерживают положительный и отрицательный ноль, поэтому: x / float('inf')
сохраняет свой знак и -1 / float('inf')
дает -0.0
, 1 / float(-inf)
дает -0.0
, 1 / float('inf')
дает 0.0
и -1/ float(-inf)
дает 0.0
, Кроме того, 0.0 == -0.0
- true
, вам нужно вручную проверить знак, если вы не хотите, чтобы оно было истинным.
Итак, C99.
Представление с плавающей запятой IEEE 754, используемое всеми современными процессорами, имеет несколько специальных битовых шаблонов, зарезервированных для положительной бесконечности (знак = 0, exp = ~ 0, frac = 0), отрицательная бесконечность (знак = 1, exp = ~ 0, frac = 0) и много NaN (не число: exp = ~ 0, frac ≠ 0).
Все, о чем вам нужно беспокоиться: некоторые арифметические действия могут вызывать исключения/ловушки с плавающей запятой, но они не ограничиваются только этими "интересными" константами.
Я нашел оговорку, о которой никто до сих пор не упомянул. Я не знаю, будет ли это часто встречаться в практических ситуациях, но здесь это ради полноты.
Обычно вычисление числа по модулю бесконечности возвращает себя как число с плавающей запятой, но дробь по модулю бесконечности возвращает nan
(не число). Вот пример:
>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan
Я подал проблему на трекер ошибок Python. Это можно увидеть на https://bugs.python.org/issue32968.
Обновление: это будет исправлено в Python 3.8.
ОЧЕНЬ ПЛОХАЯ ПЕРЕДАЧА: Деление на ноль
во фракции 1/x
, до x = 1e-323
это inf
, но когда x = 1e-324
или мало, он выбрасывает ZeroDivisionError
>>> 1/1e-323
inf
>>> 1/1e-324
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero
так что будь осторожен!