Python Infinity - Qualche avvertimento?


179

Quindi Python ha infinito positivo e negativo:

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

Questo sembra proprio il tipo di funzionalità che deve avere qualche avvertimento. C'è qualcosa di cui dovrei essere a conoscenza?


25
Si noti che la costante 1e309verrà interpretata come +infe -1e309verrà interpretata come -inf.
Chris Taylor,

Risposte:


97

Puoi ancora ottenere valori non numerici (NaN) da una semplice aritmetica che coinvolge inf:

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

Nota che normalmente non otterrai un infvalore attraverso i soliti calcoli aritmetici:

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

Il infvalore è considerato un valore molto speciale con semantica insolita, quindi è meglio conoscere OverflowErrorimmediatamente un'eccezione, piuttosto che avere un infvalore iniettato silenziosamente nei calcoli.


8
Una semplice aggiunta float, moltiplicazione, ecc produrrà felicemente inf però: f = 1.3407807929942597e + 154; f * f => inf. Sembra piuttosto un'eccezione di ** per generare un OverflowError.
eregon,

@eregon, in realtà, **sembra un po 'difettoso. Quando trabocca di numeri reali, genera un errore, ma quando uno dei suoi operandi è info -inf, restituisce uno 0.0o inf. Così fa correttamente il lavoro quando l'ingresso è inifinty, ma non quando il risultato dovrebbe essere infinito.
Abele,

2
@Abel Quello non è buggy. Traboccante significa che il numero è molto grande. Troppo grande per rappresentarlo, ma ancora molto più piccolo dell'infinito. Mettere l'infinito in un posto simile può essere utile per il gestore delle eccezioni della tua particolare logica applicativa, ma sarebbe errato per Python in generale.
Lutz Prechelt,

6
@Lutz se si presenta come moltiplicazione, allora è ancora un comportamento incoerente. Certamente grande * grande non è neanche l'infinito.
Richard Rast,

100

L'implementazione di Python segue abbastanza bene lo standard IEEE-754 , che puoi usare come guida, ma si basa sul sistema sottostante su cui è stata compilata, quindi potrebbero verificarsi differenze di piattaforma . Recentemente¹, è stata applicata una correzione che consente "infinito" e "inf" , ma questo è di minore importanza qui.

Le seguenti sezioni si applicano ugualmente bene a qualsiasi linguaggio che implementa correttamente l'aritmetica in virgola mobile IEEE, non è specifico solo per Python.

Confronto per disuguaglianza

Quando si tratta >di <operatori infinito e maggiore o minore di , valgono i seguenti elementi:

  • qualsiasi numero compreso +infè superiore a-inf
  • qualsiasi numero compreso -infè inferiore a+inf
  • +infnon è né superiore né inferiore a+inf
  • -inf non è né superiore né inferiore a -inf
  • qualsiasi confronto che coinvolge NaNè falso ( infnon è né superiore né inferiore a NaN)

Confronto per l'uguaglianza

Se confrontato per l'uguaglianza, +infe +infsono uguali, come lo sono -infe -inf. Questo è un problema molto dibattuto e può sembrare controverso per te, ma è nello standard IEEE e Python si comporta proprio così.

Certo, +infè disuguale -infe tutto, incluso NaNse stesso, è disuguale NaN.

Calcoli con infinito

La maggior parte dei calcoli con infinito produrrà infinito, a meno che entrambi gli operandi siano infiniti, quando la divisione dell'operazione o il modulo, o con la moltiplicazione con zero, ci sono alcune regole speciali da tenere a mente:

  • moltiplicato per zero, per il quale il risultato non è definito, produce NaN
  • quando si divide un numero (tranne l'infinito stesso) per l'infinito, che produce 0.0o -0.0².
  • quando si divide (compreso il modulo) l'infinito positivo o negativo per l'infinito positivo o negativo, il risultato non è definito, quindi NaN.
  • quando si sottrae, i risultati possono essere sorprendenti, ma seguire il senso matematico comune :
    • quando si fa inf - inf, il risultato è indefinito: NaN;
    • quando si fa inf - -inf, il risultato è inf;
    • quando si fa -inf - inf, il risultato è -inf;
    • quando si fa -inf - -inf, il risultato è indefinito: NaN.
  • quando si aggiunge, può essere altrettanto sorprendente anche:
    • quando si fa inf + inf, il risultato è inf;
    • quando si fa inf + -inf, il risultato è indefinito: NaN;
    • quando si fa -inf + inf, il risultato è indefinito: NaN;
    • quando lo fa -inf + -inf, il risultato è -inf.
  • usare math.pow, powo **è complicato, in quanto non si comporta come dovrebbe. Genera un'eccezione di overflow quando il risultato con due numeri reali è troppo alto per adattarsi a un float a doppia precisione (dovrebbe restituire l'infinito), ma quando l'input è info -inf, si comporta correttamente e restituisce info 0.0. Quando il secondo argomento è NaN, restituisce NaN, a meno che non sia il primo argomento 1.0. Ci sono più problemi, non tutti trattati nei documenti .
  • math.expsoffre degli stessi problemi di math.pow. Una soluzione per risolvere questo problema di overflow è utilizzare un codice simile al seguente:

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

Appunti

Nota 1: come ulteriore avvertimento, quello come definito dallo standard IEEE, se il risultato del calcolo è under-overflow o overflow, il risultato non sarà un errore underflow o overflow, ma infinito positivo o negativo: 1e308 * 10.0rese inf.

Nota 2: poiché qualsiasi calcolo con NaNrendimenti NaNe qualsiasi confronto NaN, incluso NaNse stesso false, è necessario utilizzare la math.isnanfunzione per determinare se un numero è effettivamente NaN.

Nota 3: sebbene Python supporti la scrittura float('-NaN'), il segno viene ignorato, perché non esiste alcun segno NaNinternamente. Se dividi -inf / +inf, il risultato è NaNno -NaN(non esiste una cosa del genere).

Nota 4: fare attenzione a fare affidamento su quanto sopra, poiché Python si basa sulla libreria C o Java per la quale è stata compilata e non tutti i sistemi sottostanti implementano correttamente tutto questo comportamento. Se vuoi essere sicuro, prova all'infinito prima di fare i tuoi calcoli.

¹) Recentemente significa dalla versione 3.2 .
²) I punti fluttuanti supportano lo zero positivo e negativo, quindi: x / float('inf')mantiene il segno e-1 / float('inf') rendimenti -0.0, i 1 / float(-inf)rendimenti -0.0, i 1 / float('inf')rendimenti 0.0e i -1/ float(-inf)rendimenti 0.0. Inoltre, 0.0 == -0.0ètrue necessario controllare manualmente il segno se non si desidera che sia vero.


11
Un piccolo pignolo: non tutti i calcoli con l'infinito producono l'infinito:-1 * float('infinity') == -inf
Evan Krall

4
Ecco perché ho detto che era un piccolo pignolo. Mi hai fatto preoccupare per un minuto che quel segno sarebbe stato totalmente ignorato quando si lavorava con l'infinito, e volevo chiarire per le altre persone.
Evan Krall,

12
Bene, quasi: 1 / float ('infinito') == 0,0
Phil

3
@Phil: Anche se sono abbastanza sicuro che stavi solo cercando di dimostrare che non tutti i calcoli con inf risultano in inf o NaN, volevo solo chiarire agli altri che potrebbero leggere i commenti, che 1 / float ('infinito ') == 0.0 è vero; poiché, mentre ti avvicini all'infinito, il risultato della divisione si avvicina a 0. So che è solo un calcolo di base, ma volevo essere sicuro che quelli che leggessero capissero, o almeno avessero un indizio sul perché, il risultato è quello che è.
Anthony Pace,

1
Ho la sensazione che questa risposta sia molto meglio della risposta accettata.
Christian Herenz,

3

Così fa C99 .

La rappresentazione in virgola mobile IEEE 754 utilizzata da tutti i processori moderni ha diversi schemi di bit speciali riservati per l'infinito positivo (segno = 0, exp = ~ 0, frac = 0), l'infinito negativo (segno = 1, exp = ~ 0, frac = 0 ) e molti NaN (Not a Number: exp = ~ 0, frac ≠ 0).

Tutto ciò di cui devi preoccuparti: un po 'di aritmetica può causare eccezioni / trappole in virgola mobile, ma quelle non sono limitate solo a queste costanti "interessanti".


1
Quindi se la mia aritmetica troppo grande potrebbe diventare un inf?
Casebash,

@Casebash No, causerà un OverflowError.
wizzwizz4,

2

Ho trovato un avvertimento che nessuno finora ha menzionato. Non so se si presenterà spesso in situazioni pratiche, ma qui è per completezza.

Di solito, il calcolo di un numero modulo infinito restituisce se stesso come un valore a virgola mobile, ma una frazione modulo infinito ritorna nan(non un numero). Ecco un esempio:

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

Ho presentato un problema sul tracker dei bug di Python. Può essere visto su https://bugs.python.org/issue32968 .

Aggiornamento: questo sarà risolto in Python 3.8 .


2

UNA CAVEAT MOLTO MALE: Division by Zero

in una 1/xfrazione, fino a che x = 1e-323lo è infma quando x = 1e-324o poco gettaZeroDivisionError

>>> 1/1e-323
inf

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

quindi sii cauto!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.