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.