Perché le operazioni math.ceil () e math.floor () di Python restituiscono float anziché interi?


170

Qualcuno può spiegare questo (direttamente dai documenti - l'enfasi mia):

math.ceil (x) Restituisce il soffitto di x come float , il valore intero più piccolo maggiore o uguale a x.

math.floor (x) Restituisce il piano di x come float , il valore intero più grande minore o uguale a x.

Perché dovrebbero .ceile .floorrestituire i float quando per definizione si suppone che calcolino numeri interi?


MODIFICARE:

Bene, questo ha alcuni ottimi argomenti per spiegare perché dovrebbero tornare galleggianti, e mi è stato appena abituando all'idea, quando @jcollado rilevare che in realtà fanno interi ritorno in Python 3 ...


1
La mia ipotesi sarebbe che è perché x è un float, non un numero intero, ma poiché non conosco o uso Python, lascerò che qualcun altro risponda in modo più definitivo. :)
Adam V,

6
@Adamo- ma il punto centrale delle operazioni del soffitto / pavimento è di arrotondare i galleggianti agli interi!
Yarin,

1
Questo mi ha anche infastidito la prima volta che l'ho incontrato, perché sembra proprio sbagliato. Almeno, non è troppo difficile da usare int(floor(n)).
mercoledì

1
Ironia della sorte (poiché i float sono stati usati per evitare traboccamenti), il valore restituito da floor / ceil non ha senso nelle cifre basse a causa della rappresentazione float, ben prima che traboccasse un int a 64 bit. [Questo non era vero ai vecchi tempi di 32 bit.]
Yves Daoust,

Risposte:


99

L'intervallo di numeri in virgola mobile di solito supera l'intervallo di numeri interi. Restituendo un valore in virgola mobile, le funzioni possono restituire un valore sensibile per i valori di input che si trovano al di fuori dell'intervallo rappresentabile di numeri interi.

Considerare: se floor()restituito un numero intero, cosa dovrebbe floor(1.0e30)restituire?

Ora, mentre gli interi di Python sono ora precisione arbitraria, non è stato sempre così. Le funzioni di libreria standard sono wrapper sottili attorno alle equivalenti funzioni di libreria C.


13
E anche se gli interi Python sono ora precisione arbitraria, ci sono ancora float il cui pavimento e soffitto non possono essere rappresentati da interi. Prova floor(float("inf"))o ceil(float("nan")).
Michael Hoffman,

4
@ Michael- Apparentemente in P3 ora otterrai OverflowExceptions se lo provi. Vedere jcollado 's risposta
Yarin

4
Ehm, dovrebbe restituire un tipo "lungo" (aka "bigint"), non è vero? Mi sembra una risposta ovvia, ma ora mi sento in qualche modo ingenuo.
Koschei,

3
@koschei: funziona in Python 3.x, vedi la risposta di jcollado.
Greg Hewgill il

Vedi anche un commento ad un'altra risposta sul perché questo ha senso anche per i numeri che sono nell'intervallo.
ivan_pozdeev,

96

Come sottolineato da altre risposte, in pitone restituiscono galleggianti probabilmente a causa di ragioni storiche per prevenire problemi di overflow. Tuttavia, restituiscono numeri interi in Python 3.

>>> import math
>>> type(math.floor(3.1))
<class 'int'>
>>> type(math.ceil(3.1))
<class 'int'>

Puoi trovare maggiori informazioni in PEP 3141 .


@ jcollado- Dove vedi che restituiscono numeri interi in P3?
Yarin,

4
@Yarin Ho appena digitato i comandi sopra. Inoltre, se provi con float("inf")o float("nan"), otterrai OverflowErrorun'eccezione.
jcollado,

10
Per completezza, Python's numpy.floore ceilreturn float (<class 'numpy.float64'>)
Neil G

1
@jcollado: float("inf")non produce un'eccezione in Python 2.7 o 3
endolito

1
@endolith Hai ragione, l'ho verificato e non succede più. Probabilmente è qualcosa che è stato cambiato da dicembre 2011.
jcollado,

18

La fonte della tua confusione è evidente nel tuo commento:

Il punto centrale delle operazioni ceil / floor è convertire i float in numeri interi!

Il punto delle operazioni del soffitto e del pavimento è di arrotondare i dati in virgola mobile a valori integrali . Non fare una conversione di tipo. Gli utenti che devono ottenere valori interi possono eseguire una conversione esplicita a seguito dell'operazione.

Si noti che non sarebbe possibile implementare un valore arrotondato a integrale come banale se tutto ciò che era disponibile fosse un'operazione ceil o float che restituiva un numero intero. Dovresti prima controllare che l'input sia all'interno dell'intervallo rappresentabile, quindi chiama la funzione; dovresti gestire NaN e infinity in un percorso di codice separato.

Inoltre, è necessario disporre di versioni di ceil e floor che restituiscono numeri in virgola mobile se si desidera conformarsi a IEEE 754 .


Stephen- Ho riscritto il mio commento. Avevo intenzione di arrotondare, non di convertirmi. Ma quella non era la fonte della mia confusione, piuttosto era che non stavo riconoscendo la disparità di portata.
Yarin,

Purtroppo oggi non ho più voti. Questa è la risposta corretta, molto più di qualsiasi limitazione della rappresentazione.
Marcin

13
Nei miei anni di programmazione, non ricordo di aver mai incontrato una situazione in cui volevo che il risultato di floor / ceil fosse un float anziché un numero intero. Il fatto che python3 fa interi di ritorno dimostra che questo è in realtà la cosa più utile da fare. Non compro l'affermazione "il punto di ..."; sembra che tu stia definendo il punto in base a ciò che fa, piuttosto che a ciò che un programmatore potrebbe desiderare.
ShreevatsaR,

2
@ShreevatsaR Ho avuto quella situazione un paio di volte (tuttavia, principalmente al di fuori di un contesto Python). I tempi che ricordo sono quando lavoravo con i set Mandelbrot. A volte è necessario creare un valore integrale, ma quindi applicare alcune operazioni in virgola mobile al valore immediatamente successivo (ad esempio, ridimensionandolo di 0,5). Quindi è molto più efficiente mantenere il float con il pavimento e applicare un'operazione in virgola mobile rispetto a prima convertirlo in un int e poi convertirlo immediatamente in float.
Blubberdiblub,

17

Perché la libreria matematica di Python è un involucro sottile attorno alla libreria matematica C che restituisce float.


La libreria matematica C supporta numeri interi di precisione arbitraria? Perché è quello che restituiscono altre funzioni matematiche di Python.
endolith

5

Prima di Python 2.4, un numero intero non poteva contenere l'intera gamma di numeri reali troncati.

http://docs.python.org/whatsnew/2.4.html#pep-237-unifying-long-integers-and-integers


2
Ora non può contenere nemmeno la "gamma completa di numeri reali troncati", perché ovviamente è un insieme infinito e richiederebbe quindi una quantità infinita di memoria. Può contenere la gamma di galleggianti troncati , che è solo un piccolo sottoinsieme di ℝ.
circa il

6
@leftaroundabout - schizzinoso! Sapevi cosa intendevo dire.
Mark Ransom il

4

Poiché l'intervallo per i float è maggiore di quello degli interi, la restituzione di un intero potrebbe traboccare


7
Gli interi non traboccano in Python; i suoi numeri interi si convertono in origini quando diventano troppo grandi. Apri un interprete Python e digita "2 ** 500" e vedrai che ottieni un oggetto che puoi trattare in ogni modo come un int.
Koschei,

@koschei: anche le origini traboccano quando provano a rappresentare l'infinito.
Stephen Canon,

4

Questa è una domanda molto interessante! Poiché un float richiede alcuni bit per memorizzare l'esponente (= bits_for_exponent) qualsiasi numero in virgola mobile maggiore di 2**(float_size - bits_for_exponent)sarà sempre un valore integrale! All'altro estremo un galleggiante con un esponente negativo darà uno 1, 0o -1. Ciò rende discutibile la discussione dell'intervallo intero rispetto all'intervallo mobile perché queste funzioni restituiranno semplicemente il numero originale ogni volta che il numero è al di fuori dell'intervallo del tipo intero. Le funzioni Python sono wrapper della Cfunzione e quindi questa è davvero una carenza delle Cfunzioni in cui avrebbero dovuto restituire un numero intero e costringere il programmatore a fare il range / NaN/ Infcheck prima di chiamare ceil / floor.

Quindi la risposta logica è l'unica volta in cui queste funzioni sono utili restituiscono un valore nell'intervallo intero e quindi il fatto che restituiscono un float è un errore e tu sei molto intelligente per realizzarlo!


1

Forse perché anche altre lingue lo fanno, quindi è un comportamento generalmente accettato. (Per buoni motivi, come mostrato nelle altre risposte)


O quello che ha detto Charles. :)
Almo,
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.