Python Infinity - есть какие-нибудь предостережения?

179

Итак, Python имеет положительную и отрицательную бесконечность:

float("inf"), float("-inf")

Это просто похоже на тип функции, которая должна иметь некоторые оговорки. Есть ли что-то, о чем я должен знать?

Casebash
источник
25
Обратите внимание, что константа 1e309будет интерпретироваться как +infи -1e309будет интерпретироваться как -inf.
Крис Тейлор

Ответы:

97

Вы все еще можете получить значения не числа (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значение молча впрыскивается в свои расчеты.

Грег Хьюгилл
источник
8
Простое сложение с плавающей точкой, умножение и т. Д., К счастью, даст inf: f = 1.3407807929942597e + 154; f * f => инф. Это скорее исключение **, чтобы вызвать ошибку OverflowError.
Эрегон
@eregon, на самом деле, **кажется немного глючит. Когда он переполняется действительными числами, он выдает ошибку, но когда любой из его операндов равен infили -inf, он возвращает либо 0.0или inf. Так что он работает правильно, когда ввод бесконечен, но не когда результат должен быть бесконечностью.
Авель
2
@Abel Это не глючит. Переполнение означает, что число очень велико. Слишком большой, чтобы представлять его, но все же намного меньше бесконечности. Помещение бесконечности в такое место может быть полезно для обработчика исключений вашей конкретной логики приложения, но в целом для Python будет некорректно.
Лутц Пречелт
6
@Lutz, если это произойдет как умножение, это все еще непоследовательное поведение. Конечно, большой * большой тоже не бесконечность.
Ричард Раст
100

Реализация языка 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, то результат не определен: 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, для которой он был скомпилирован, и не все базовые системы правильно реализуют все это поведение. Если вы хотите быть уверенным, проверьте бесконечность, прежде чем делать свои вычисления.

Recently) В последнее время означает, что начиная с версии 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 , вы должны вручную проверить знак , если вы не хотите , чтобы это было правдой.

Абель
источник
11
Небольшая мелочь: не каждый расчет с бесконечностью дает бесконечность:-1 * float('infinity') == -inf
Эван Кралл
4
Вот почему я сказал, что это был маленький придурок. Вы на минуту меня беспокоили, что знак будет полностью игнорироваться при работе с бесконечностью, и я хотел уточнить для других людей.
Эван Кралл
12
Ну, почти: 1 / float ('бесконечность') == 0.0
Фил
3
@Phil: Хотя я почти уверен, что вы просто пытались показать, что не все вычисления с inf приводят к inf или NaN, я просто хотел дать понять другим, которые могут читать комментарии, что 1 / float ('infinity ') == 0.0 верно; поскольку, когда вы приближаетесь к бесконечности, результат деления приближается к 0. Я знаю, что это просто базовое исчисление, но я хотел убедиться, что читающие понимают или, по крайней мере, имеют представление о том, почему результат такой, какой он есть.
Энтони Пейс
1
У меня такое ощущение, что этот ответ намного лучше, чем принятый ответ.
Кристиан Херенц
3

Как и С99 .

Представление IEEE 754 с плавающей запятой, используемое всеми современными процессорами, имеет несколько специальных битовых комбинаций, зарезервированных для положительной бесконечности (знак = 0, exp = ~ 0, frac = 0), отрицательной бесконечности (знак = 1, exp = ~ 0, frac = 0 ) и много NaN (не число: exp = ~ 0, frac ≠ 0).

Все, что вам нужно беспокоиться: некоторая арифметика может вызывать исключения / ловушки с плавающей запятой, но они не ограничиваются только этими «интересными» константами.

ephemient
источник
1
Так что, если моя арифметика слишком большая, она может стать инфой?
Casebash
@ Casebash Нет, это вызовет OverflowError.
wizzwizz4
2

Я нашел оговорку, о которой никто до сих пор не упомянул. Я не знаю, будет ли это часто встречаться в практических ситуациях, но здесь это делается для полноты картины.

Обычно вычисление числа по бесконечности по модулю возвращает себя в виде числа с плавающей запятой, но возвращает бесконечность по модулю 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 .

Элиас Замария
источник
2

ОЧЕНЬ ПЛОХАЯ ПЕРЕДАЧА: Деление на ноль

в 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

так что будьте осторожны!

Seyfi
источник