Python Infinity - любые оговорки?

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

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

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

Ответ 1

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

Ответ 2

Реализация 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.

Вычисления с бесконечностью

Большинство вычислений с бесконечностью дадут бесконечность, если оба операнда не являются бесконечными, когда операционное деление или по модулю или с умножением на ноль есть некоторые специальные правила, которые следует иметь в виду:

  • при умножении на ноль, для которого результат undefined, он дает NaN
  • при делении любого числа (кроме бесконечности) на бесконечность, что дает 0.0 или -0.0 ².
  • при делении (включая по модулю) положительной или отрицательной бесконечности на положительную или отрицательную бесконечность, результат undefined, поэтому 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, вам нужно вручную проверить знак, если вы не хотите, чтобы оно было истинным.

Ответ 3

Итак, C99.

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

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

Ответ 4

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

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

Ответ 5

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

во фракции 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

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