Warum geben Pythons Operationen math.ceil () und math.floor () Floats anstelle von Ganzzahlen zurück?

170

Kann jemand dies erklären (direkt aus den Dokumenten - Hervorhebung von mir):

math.ceil (x) Gibt die Obergrenze von x als Gleitkommawert zurück , den kleinsten ganzzahligen Wert größer oder gleich x.

math.floor (x) Gibt den Boden von x als Float zurück , den größten ganzzahligen Wert kleiner oder gleich x.

Warum sollte .ceilund .floorRückkehr schwebt , wenn sie per Definition sollen berechnen ganzen Zahlen?


BEARBEITEN:

Nun hätte dies einige sehr gute Argumente, warum sie sollten Schwimmer zurückkehren, und ich war nur die Idee zu gewöhnen, wenn @jcollado darauf hingewiesen , dass sie in der Tat zu tun Rückkehr Ints in Python 3 ...

Yarin
quelle
1
Meine Vermutung wäre, dass x ein Float ist, keine Ganzzahl, aber da ich Python nicht kenne oder nicht benutze, lasse ich jemanden definitiver antworten. :)
Adam V
6
@ Adam- aber der springende Punkt bei Decken- / Bodenoperationen ist es, Floats auf ganze Zahlen zu runden!
Yarin
1
Das ärgerte mich auch, als ich das erste Mal darauf stieß, weil es einfach falsch zu sein scheint. Zumindest ist es nicht zu schwer zu bedienen int(floor(n)).
wim
1
Ironischerweise (da Floats verwendet wurden, um Überläufe zu verhindern) ist der von Boden / Decke zurückgegebene Wert aufgrund der Float-Darstellung in den niedrigen Ziffern bedeutungslos, lange bevor ein 64-Bit-Int überlaufen würde. [Dies war in den alten Tagen von 32 Bit nicht wahr.]
Yves Daoust

Antworten:

99

Der Bereich der Gleitkommazahlen überschreitet normalerweise den Bereich der ganzen Zahlen. Durch die Rückgabe eines Gleitkommawertes können die Funktionen einen sinnvollen Wert für Eingabewerte zurückgeben, die außerhalb des darstellbaren Bereichs von Ganzzahlen liegen.

Bedenken Sie: Wenn floor()eine Ganzzahl zurückgegeben wird, was sollte floor(1.0e30)zurückgegeben werden?

Während Pythons ganze Zahlen jetzt willkürliche Genauigkeit haben, war dies nicht immer so. Die Standardbibliotheksfunktionen sind Thin Wrapper um die entsprechenden C-Bibliotheksfunktionen.

Greg Hewgill
quelle
13
Und obwohl Python-Ganzzahlen jetzt eine willkürliche Genauigkeit haben, gibt es immer noch Floats, deren Boden und Decke nicht durch Ganzzahlen dargestellt werden können. Versuchen Sie es floor(float("inf"))oder ceil(float("nan")).
Michael Hoffman
4
@ Michael- Anscheinend bekommst du in P3 jetzt OverflowExceptions, wenn du das versuchst. Siehe jcollados Antwort
Yarin
4
Ähm, es sollte einen 'langen' Typ (auch bekannt als 'bigint') zurückgeben, nicht wahr? Scheint mir eine offensichtliche Antwort zu sein, aber jetzt fühle ich mich irgendwie naiv.
Koschei
3
@koschei: In Python 3.x, siehe Antwort von jcollado.
Greg Hewgill
Siehe auch einen Kommentar zu einer anderen Antwort, warum dies auch für Zahlen im Bereich sinnvoll ist.
ivan_pozdeev
96

Wie aus anderen Antworten hervorgeht, geben sie in Python Floats zurück, wahrscheinlich aus historischen Gründen, um Überlaufprobleme zu vermeiden. In Python 3 geben sie jedoch Ganzzahlen zurück.

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

Weitere Informationen finden Sie in PEP 3141 .

jcollado
quelle
@ jcollado- Wo sehen Sie, dass sie in P3 ganze Zahlen zurückgeben?
Yarin
4
@ Yarin Ich habe gerade die Befehle oben eingegeben. Auch wenn Sie es mit float("inf")oder versuchen float("nan"), erhalten Sie eine OverflowErrorAusnahme.
JCollado
10
Der Vollständigkeit halber schwebt Python numpy.floorund ceilreturn (<class 'numpy.float64'>)
Neil G
1
@jcollado: float("inf")erzeugt keine Ausnahme in Python 2.7 oder 3
Endolith
1
@endolith Du hast recht, ich habe das überprüft und es passiert nicht mehr. Wahrscheinlich ist das etwas, das seit Dezember 2011 geändert wurde.
JCollado
18

Die Quelle Ihrer Verwirrung ist in Ihrem Kommentar ersichtlich:

Der springende Punkt bei Decken- / Bodenoperationen ist die Umwandlung von Floats in ganze Zahlen!

Der Punkt der Decken- und Bodenoperationen besteht darin, Gleitkommadaten auf ganzzahlige Werte zu runden . Keine Typkonvertierung durchführen. Benutzer, die ganzzahlige Werte abrufen müssen, können nach der Operation eine explizite Konvertierung durchführen.

Beachten Sie, dass es nicht möglich wäre, eine Rundung auf einen ganzzahligen Wert als trivial zu implementieren, wenn Sie nur eine Ceil- oder Float-Operation zur Verfügung hätten, die eine Ganzzahl zurückgibt. Sie müssen zuerst überprüfen, ob die Eingabe innerhalb des darstellbaren Ganzzahlbereichs liegt, und dann die Funktion aufrufen. Sie müssten NaN und Unendlichkeiten in einem separaten Codepfad behandeln.

Darüber hinaus benötigen Sie Versionen von Ceil und Floor, die Gleitkommazahlen zurückgeben, wenn Sie IEEE 754 entsprechen möchten .

Stephen Canon
quelle
Stephen: Ich habe meinen Kommentar umgeschrieben. Ich hatte gemeint, nicht konvertieren. Aber das war nicht die Quelle meiner Verwirrung - vielmehr war es, dass ich die Reichweitenunterschiede nicht erkannte.
Yarin
Leider habe ich heute keine Stimmen mehr. Dies ist die richtige Antwort, viel mehr als jede Einschränkung der Darstellung.
Marcin
13
In meinen Jahren der Programmierung erinnere ich mich nicht daran, jemals auf eine Situation gestoßen zu sein, in der ich wollte, dass das Ergebnis von Boden / Decke ein Float anstelle einer ganzen Zahl ist. Die Tatsache , dass python3 tut Rückkehr ganze Zahlen zeigen , dass dies in der Tat ist umso nützlicher , was zu tun. Ich kaufe nicht die Behauptung "the point of ..."; Es scheint, dass Sie den Punkt basierend auf dem definieren, was er tut, und nicht auf dem, was ein Programmierer möchte.
ShreevatsaR
2
@ShreevatsaR Ich hatte diese Situation ein paar Mal (jedoch hauptsächlich außerhalb eines Python-Kontexts). Die Zeiten, an die ich mich erinnere, sind bei der Arbeit mit Mandelbrot-Sets. Manchmal müssen Sie einen ganzzahligen Wert erstellen, aber unmittelbar danach eine Gleitkommaoperation auf den Wert anwenden (z. B. um 0,5 skalieren). Dann ist es viel effizienter, den Float auf dem Boden zu halten und eine Gleitkommaoperation auf ihn anzuwenden, als ihn zuerst in einen Int zu konvertieren und ihn dann sofort wieder in Float umzuwandeln.
Blubberdiblub
17

Weil die Python-Mathematikbibliothek ein dünner Wrapper um die C-Mathematikbibliothek ist, der Floats zurückgibt.

Charles
quelle
Die C-Mathematikbibliothek unterstützt Ganzzahlen mit beliebiger Genauigkeit. Denn genau das geben andere Python-Mathematikfunktionen zurück.
Endolith
5

Vor Python 2.4 konnte eine Ganzzahl nicht den gesamten Bereich abgeschnittener reeller Zahlen enthalten.

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

Mark Ransom
quelle
2
Es kann jetzt auch nicht den "gesamten Bereich abgeschnittener reeller Zahlen" halten, da dies offensichtlich eine unendliche Menge ist und daher unendlich viel Speicher erfordern würde. Es kann den Bereich der abgeschnittenen Floats enthalten , der nur eine kleine Teilmenge von ℝ ist.
links um den
6
@leftaroundabout - wählerisch wählerisch! Du wusstest was ich meinte.
Mark Ransom
4

Da der Bereich für Floats größer ist als der für Ganzzahlen, kann die Rückgabe einer Ganzzahl überlaufen

Kyle
quelle
7
Ganzzahlen laufen in Python nicht über. Seine ganzen Zahlen werden in Bigint umgewandelt, wenn sie zu groß werden. Öffnen Sie einen Python-Interpreter und geben Sie "2 ** 500" ein. Sie werden sehen, dass Sie ein Objekt erhalten, das Sie auf jede Weise wie ein Int behandeln können.
Koschei
@koschei: Sogar Bigints laufen über, wenn versucht wird, Unendlichkeit darzustellen.
Stephen Canon
4

Das ist eine sehr interessante Frage! Da ein bits_for_exponentGleitkomma einige Bits benötigt, um den Exponenten (= ) zu speichern, ist jede Gleitkommazahl größer als 2**(float_size - bits_for_exponent)immer ein ganzzahliger Wert! Am anderen Ende der Skala ein Schwimmer mit einem negativen Exponenten wird eines geben 1, 0oder -1. Dies macht die Diskussion des Integer-Bereichs gegenüber dem Float-Bereich umstritten, da diese Funktionen einfach die ursprüngliche Nummer zurückgeben, wenn die Nummer außerhalb des Bereichs des Integer-Typs liegt. Die Python-Funktionen sind Wrapper der CFunktion, und dies ist wirklich ein Mangel der CFunktionen, bei denen sie eine Ganzzahl hätten zurückgeben und den Programmierer zwingen sollen, den Bereich / auszuführen.NaN / InfCheck durchzuführen, bevor Ceil / Floor aufgerufen wird.

Daher ist die logische Antwort das einzige Mal, wenn diese Funktionen nützlich sind, dass sie einen Wert innerhalb eines ganzzahligen Bereichs zurückgeben. Die Tatsache, dass sie einen Float zurückgeben, ist ein Fehler, und Sie sind sehr klug, dies zu realisieren!

Justin Finnerty
quelle
1

Vielleicht, weil andere Sprachen dies auch tun, so dass es allgemein akzeptiertes Verhalten ist. (Aus guten Gründen, wie in den anderen Antworten gezeigt)

Almo
quelle
Oder was Charles gesagt hat. :)
Almo