Risposte:
Puoi ancora ottenere valori non numerici (NaN) da una semplice aritmetica che coinvolge inf
:
>>> 0 * float("inf")
nan
Nota che normalmente non otterrai un inf
valore 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 inf
valore è considerato un valore molto speciale con semantica insolita, quindi è meglio conoscere OverflowError
immediatamente un'eccezione, piuttosto che avere un inf
valore iniettato silenziosamente nei calcoli.
**
sembra un po 'difettoso. Quando trabocca di numeri reali, genera un errore, ma quando uno dei suoi operandi è inf
o -inf
, restituisce uno 0.0
o inf
. Così fa correttamente il lavoro quando l'ingresso è inifinty, ma non quando il risultato dovrebbe essere infinito.
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.
Quando si tratta >
di <
operatori infinito e maggiore o minore di , valgono i seguenti elementi:
+inf
è superiore a-inf
-inf
è inferiore a+inf
+inf
non è né superiore né inferiore a+inf
-inf
non è né superiore né inferiore a -inf
NaN
è falso ( inf
non è né superiore né inferiore a NaN
)Se confrontato per l'uguaglianza, +inf
e +inf
sono uguali, come lo sono -inf
e -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 -inf
e tutto, incluso NaN
se stesso, è disuguale NaN
.
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:
NaN
0.0
o -0.0
².NaN
.inf - inf
, il risultato è indefinito: NaN
;inf - -inf
, il risultato è inf
;-inf - inf
, il risultato è -inf
;-inf - -inf
, il risultato è indefinito: NaN
.inf + inf
, il risultato è inf
;inf + -inf
, il risultato è indefinito: NaN
;-inf + inf
, il risultato è indefinito: NaN
;-inf + -inf
, il risultato è -inf
.math.pow
, pow
o **
è 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 è inf
o -inf
, si comporta correttamente e restituisce inf
o 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.exp
soffre 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')
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.0
rese inf
.
Nota 2: poiché qualsiasi calcolo con NaN
rendimenti NaN
e qualsiasi confronto NaN
, incluso NaN
se stesso false
, è necessario utilizzare la math.isnan
funzione 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 NaN
internamente. Se dividi -inf / +inf
, il risultato è NaN
no -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.0
e 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.
-1 * float('infinity') == -inf
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".
OverflowError
.
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 .
UNA CAVEAT MOLTO MALE: Division by Zero
in una 1/x
frazione, fino a che x = 1e-323
lo è inf
ma quando x = 1e-324
o 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!
1e309
verrà interpretata come+inf
e-1e309
verrà interpretata come-inf
.