Python Infinity – есть какие-нибудь предостережения?
Вопрос
Итак, Python имеет положительную и отрицательную бесконечность:
float("inf"), float("-inf")
Это просто похоже на тип функции, которая должна иметь некоторые предостережения.Есть ли что-то, о чем мне следует знать?
Решение
Вы все еще можете получить значения не числа (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 довольно хорошо, и вы можете использовать его в качестве руководства, но он зависит от базовой системы, на которой он был скомпилирован, поэтому различия платформ может возникнуть.Недавно¹ было применено исправление, позволяющее «бесконечность», а также «инф», но здесь это не имеет большого значения.
Следующие разделы одинаково применимы к любому языку, который правильно реализует арифметику с плавающей запятой 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
, результат не определен:NaN
; - когда делаешь
inf - -inf
, результатinf
; - когда делаешь
-inf - inf
, результат-inf
; - когда делаешь
-inf - -inf
, результат не определен:NaN
.
- когда делаешь
- при добавлении это тоже может быть удивительно:
- когда делаешь
inf + inf
, результатinf
; - когда делаешь
inf + -inf
, результат не определен:NaN
; - когда делаешь
-inf + inf
, результат не определен: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 & # 8800; 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 .