Python Infinity - есть какие-нибудь предостережения? - PullRequest
171 голосов
/ 27 октября 2009

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

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

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

Ответы [ 4 ]

98 голосов
/ 27 октября 2009

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

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

95 голосов
/ 27 октября 2009

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

3 голосов
/ 27 октября 2009

Так же C99 .

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

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

2 голосов
/ 28 февраля 2018

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...