Python Infinity: ¿alguna advertencia?

179

Entonces Python tiene infinito positivo y negativo:

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

Esto simplemente parece ser el tipo de característica que debe tener alguna advertencia. ¿Hay algo que deba tener en cuenta?

Casebash
fuente
25
Tenga en cuenta que la constante 1e309se interpretará como +infy -1e309se interpretará como -inf.
Chris Taylor

Respuestas:

97

Todavía puede obtener valores que no sean un número (NaN) a partir de aritmética simple que involucra inf:

>>> 0 * float("inf")
nan

Tenga en cuenta que normalmente no obtendrá un infvalor a través de los cálculos aritméticos habituales:

>>> 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')

El infvalor se considera un valor muy especial con una semántica inusual, por lo que es mejor saber de OverflowErrorinmediato a través de una excepción, en lugar de tener un infvalor silenciosamente inyectado en sus cálculos.

Greg Hewgill
fuente
8
Sin embargo, una simple adición de flotador, multiplicación, etc. producirá inf: f = 1.3407807929942597e + 154; f * f => inf. Parece más bien una excepción de ** para generar un OverflowError.
eregon
@eregon, en realidad, **parece un poco defectuoso. Cuando se desborda con números reales, arroja un error, pero cuando cualquiera de sus operandos es info -inf, devuelve 0.0o inf. Por lo que hace el trabajo correctamente cuando la entrada es inifinty, pero no cuando el resultado debe ser infinito.
Abel
2
@Abel Eso no tiene errores. Desbordarse significa que el número es muy grande. Demasiado grande para representarlo, pero aún más pequeño que el infinito. Poner el infinito en tal lugar puede ser útil para el controlador de excepciones de su lógica de aplicación particular, pero sería incorrecto para Python en general.
Lutz Prechelt
66
@Lutz si aparece como multiplicación, entonces todavía es un comportamiento inconsistente. Ciertamente, big * big tampoco es infinito.
Richard Rast el
100

La implementación de Python sigue el estándar IEEE-754 bastante bien, que puede usar como guía, pero se basa en el sistema subyacente en el que se compiló, por lo que pueden producirse diferencias de plataforma . Recientemente¹, se ha aplicado una solución que permite "infinito" así como "inf" , pero aquí es de menor importancia.

Las siguientes secciones se aplican igualmente a cualquier lenguaje que implemente la aritmética de coma flotante IEEE correctamente, no es específico solo de Python.

Comparación por desigualdad

Cuando se trata >de <operadores infinitos y mayores o menores que , lo siguiente cuenta:

  • cualquier número incluido +infes mayor que-inf
  • cualquier número incluido -infes inferior a+inf
  • +infno es ni más alto ni más bajo que+inf
  • -inf no es ni más alto ni más bajo que -inf
  • cualquier comparación que implique NaNes falsa ( infno es mayor ni menor que NaN)

Comparación por igualdad

Cuando se compara para igualdad, +infy +infson iguales, como son -infy -inf. Este es un tema muy debatido y puede sonar controvertido para usted, pero está en el estándar IEEE y Python se comporta así.

Por supuesto, +infes desigual -infy todo, incluido él NaNmismo, es desigual NaN.

Cálculos con infinito.

La mayoría de los cálculos con infinito producirán infinito, a menos que ambos operandos sean infinitos, cuando la división o módulo de operación, o con multiplicación con cero, hay algunas reglas especiales a tener en cuenta:

  • cuando se multiplica por cero, para lo cual el resultado no está definido, produce NaN
  • al dividir cualquier número (excepto el infinito) por infinito, lo que produce 0.0o -0.0².
  • al dividir (incluido el módulo) infinito positivo o negativo por infinito positivo o negativo, el resultado es indefinido, entonces NaN.
  • al restar, los resultados pueden ser sorprendentes, pero siguen el sentido matemático común :
    • cuando se hace inf - inf, el resultado es indefinido: NaN;
    • al hacer inf - -inf, el resultado es inf;
    • al hacer -inf - inf, el resultado es -inf;
    • cuando se hace -inf - -inf, el resultado es indefinido: NaN.
  • al agregar, también puede ser igualmente sorprendente:
    • al hacer inf + inf, el resultado es inf;
    • cuando se hace inf + -inf, el resultado es indefinido: NaN;
    • cuando se hace -inf + inf, el resultado es indefinido: NaN;
    • al hacer -inf + -inf, el resultado es -inf.
  • usando math.pow, powo **es complicado, ya que no se comporta como debería. Lanza una excepción de desbordamiento cuando el resultado con dos números reales es demasiado alto para ajustarse a un flotador de doble precisión (debería devolver infinito), pero cuando la entrada es info -inf, se comporta correctamente y devuelve info 0.0. Cuando el segundo argumento es NaN, regresa NaN, a menos que el primer argumento sea 1.0. Hay más problemas, no todos cubiertos en los documentos .
  • math.expsufre los mismos problemas que math.pow. Una solución para solucionar esto por desbordamiento es usar un código similar a este:

    try:
        res = math.exp(420000)
    except OverflowError:
        res = float('inf')

Notas

Nota 1: como advertencia adicional, según lo definido por el estándar IEEE, si el resultado de su cálculo se desborda o desborda, el resultado no será un error de desbordamiento o desbordamiento, sino infinito positivo o negativo: 1e308 * 10.0rendimientos inf.

Nota 2: debido a que cualquier cálculo con NaNretornos NaNy cualquier comparación con NaN, incluido él NaNmismo false, debe usar la math.isnanfunción para determinar si un número es realmente NaN.

Nota 3: aunque Python admite la escritura float('-NaN'), el signo se ignora porque no existe ningún signo NaNinterno. Si divide -inf / +inf, el resultado es que NaNno -NaN(no existe tal cosa).

Nota 4: tenga cuidado de confiar en cualquiera de los anteriores, ya que Python se basa en la biblioteca C o Java para la que fue compilada y no todos los sistemas subyacentes implementan todo este comportamiento correctamente. Si quieres estar seguro, prueba el infinito antes de hacer tus cálculos.

¹) Recientemente significa desde la versión 3.2 .
²) Los puntos flotantes admiten cero positivo y negativo, por lo tanto: x / float('inf')mantiene su signo y -1 / float('inf')rendimientos -0.0, 1 / float(-inf)rendimientos -0.0, 1 / float('inf')rendimientos 0.0y -1/ float(-inf)rendimientos 0.0. Además, 0.0 == -0.0es necesariotrue verificar manualmente el signo si no desea que sea cierto.

Abel
fuente
11
Un pequeño detalle: no todos los cálculos con infinito rinden infinito:-1 * float('infinity') == -inf
Evan Krall
44
Por eso dije que era una pequeña trampa. Me preocupó por un minuto que esa señal se ignoraría totalmente cuando se trabaja con infinito, y quería aclarar para otras personas.
Evan Krall
12
Bueno, casi: 1 / float ('infinito') == 0.0
Phil
3
@ Phil: Aunque estoy bastante seguro de que solo estabas tratando de demostrar que no todos los cálculos con inf resultan en inf o NaN, solo quería dejar en claro a otros que pueden estar leyendo los comentarios, que 1 / float ('infinito ') == 0.0 es verdadero; porque, a medida que se acerca al infinito, el resultado de la división se aproxima a 0. Sé que es solo un cálculo básico, pero quería asegurarme de que los que leen entiendan, o al menos tengan una idea de por qué, el resultado es lo que es.
Anthony Pace
1
Tengo la sensación de que esta respuesta es mucho mejor que la respuesta aceptada.
Christian Herenz
3

También lo hace C99 .

La representación de coma flotante IEEE 754 utilizada por todos los procesadores modernos tiene varios patrones de bits especiales reservados para infinito positivo (signo = 0, exp = ~ 0, frac = 0), infinito negativo (signo = 1, exp = ~ 0, frac = 0 ) y muchos NaN (no es un número: exp = ~ 0, frac ≠ 0).

Todo de lo que debe preocuparse: algunas operaciones aritméticas pueden causar excepciones / trampas de coma flotante, pero estas no se limitan solo a estas constantes "interesantes".

efímero
fuente
1
Entonces, si mi aritmética es demasiado grande, ¿podría convertirse en un inf?
Casebash
@Casebash No, causará un OverflowError.
wizzwizz4
2

Encontré una advertencia que nadie hasta ahora ha mencionado. No sé si se presentará a menudo en situaciones prácticas, pero aquí es en aras de la integridad.

Por lo general, el cálculo de un número de módulo de infinito se devuelve como flotante, pero una fracción de módulo de infinito se devuelve nan(no un número). Aquí hay un ejemplo:

>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan

Archivé un problema en el rastreador de errores de Python. Se puede ver en https://bugs.python.org/issue32968 .

Actualización: esto se solucionará en Python 3.8 .

Elias Zamaria
fuente
2

UNA CUEVA MUY MALA: División por cero

en una 1/xfracción, hasta x = 1e-323que es infpero cuando x = 1e-324o poco arrojaZeroDivisionError

>>> 1/1e-323
inf

>>> 1/1e-324
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero

así que ten cuidado!

Seyfi
fuente