Ich möchte 3/2 gleich 2 nicht 1,5
Ich weiß, dass es einen mathematischen Ausdruck für diese Operation gibt (nicht als Aufrunden bezeichnet), aber ich kann mich im Moment nicht daran erinnern. Wie auch immer, wie mache ich das, ohne zwei Funktionen zu machen?
von dem, was ich NICHT will:
%Vor%ex von was ich will:
%Vor%Um eine kurze Antwort zu geben ...
Python bietet nur native Operatoren für zwei Arten von Unterteilungen an: "echte" Division und "abgerundete" Division. Was Sie wollen, ist nicht als einzelne Funktion verfügbar. Es ist jedoch möglich, eine Anzahl verschiedener Typen von Division-mit-Rounding unter Verwendung einiger kurzer Ausdrücke einfach zu implementieren.
Auf Antrag des Titels: Bei streng integer Eingaben kann "Aufrunden" mit (a+(-a%b))//b
implementiert werden, und "Runden weg von Null" kann mit der komplexeren a//b if a*b<0 else (a+(-a%b))//b
implementiert werden. Einer davon ist wahrscheinlich, was Sie wollen. Warum?
Um eine längere Antwort zu geben ...
Lassen Sie mich zuerst die Unterfrage über warum 3/2==1
und math.ceil(3/2)==1.0
beantworten, um zu erklären, wie der Python-Divisionsoperator funktioniert. Es gibt zwei Hauptprobleme ...
float
vs int
division: Unter Python 2 verhält sich die Division abhängig vom Typ der Eingaben unterschiedlich. Wenn sowohl a
als auch b
Integer sind, führt a/b
die Division "Abrunden" oder "Floor Integer" durch (zB 3/2==1
, aber -3/2==-2
). Dies entspricht int(math.floor(float(a)/b))
.
Wenn jedoch mindestens eines von a
und b
Gleitkommazahlen sind, führt Python eine "wahre" Division durch und gibt Ihnen ein float
Ergebnis (zB 3.0/2==1.5
und -3.0/2==-1.5
). Deshalb sehen Sie manchmal die Konstruktion float(a)/b
: Sie wird verwendet, um eine echte Division zu erzwingen, obwohl beide Eingaben ganze Zahlen sind (zB float(3)/2==1.5
). Deshalb gibt Ihr Beispiel math.ceil(3/2)
1.0
zurück, während math.ceil(float(3)/2)
2.0
zurückgibt. Das Ergebnis wurde bereits abgerundet, bevor es math.ceil()
erreicht.
"true division" standardmäßig : Im Jahr 2001 wurde entschieden ( PEP 238 ), dass Pythons Division-Operator so geändert werden sollte, dass er immer "echte" Divisionen ausführt, unabhängig davon, ob die Eingaben Floats oder Integers sind (zB würde dies 3/2==1.5
ergeben). Um bestehende Skripte nicht zu unterbrechen, wurde die Änderung des Standardverhaltens solange zurückgestellt, bis Python 3.0; Um dieses Verhalten unter Python 2.x zu erhalten, müssen Sie es pro Datei aktivieren, indem Sie from __future__ import division
am Anfang der Datei hinzufügen. Ansonsten wird das alte typabhängige Verhalten verwendet.
Aber die "Abrundung" wird immer noch häufig gebraucht, so dass die PEP nicht ganz damit klarkommt. Stattdessen wurde ein neuer Divisionsoperator eingeführt: a//b
, der immer eine Abrundung durchführt, auch wenn die Eingaben Floats enthalten. Dies kann verwendet werden, ohne etwas besonderes unter Python 2.2+ und 3.x zu tun.
Aus diesem Grund, Division-mit-Rundung:
Um die Dinge zu vereinfachen, benutzen die folgenden Ausdrücke den a//b
Operator, wenn sie an Ganzzahlen arbeiten, da sie sich unter allen Python-Versionen gleich verhalten. Ich nehme auch an, dass 0<=a%b<b
wenn b
positiv ist und b<=a%b<=0
wenn b negativ ist. So verhält sich Python, aber andere Sprachen können leicht unterschiedliche Moduloperatoren haben.
Die vier Grundtypen der Ganzzahldivision mit Rundung:
"abrunden" aka "floor integer" aka "rund zu minus infinity" divsion: python bietet dies nativ via a//b
an.
"Aufrunden" aka "Decke-Ganzzahl" aka "Runde zu positiver Unendlichkeit" -Teilung: Dies kann über int(math.ceil(float(a)/b))
oder (a+(-a%b))//b
erreicht werden. Die letztere Gleichung funktioniert, weil -a%b
0 ist, wenn a
ein Vielfaches von b
ist, und ansonsten die Menge, die wir a
hinzufügen müssen, um zum nächsthöheren Vielfachen zu kommen.
"Runde gegen Null" aka "abgeschnittene" Division - dies kann über int(float(a)/b)
erreicht werden. Dies zu tun, ohne Fließkomma zu verwenden, ist komplizierter ... Da Python nur eine abgerundete Ganzzahldivision bietet und der %
-Operator eine ähnliche Abrundungsverzerrung hat, haben wir keine Nicht-Gleitkommaoperatoren, die symmetrisch runden etwa 0. Also kann ich mir nur einen stückweisen Ausdruck aus Abrundung und Zusammenfassung zusammenstellen: a//b if a*b>0 else (a+(-a%b))//b
.
"Runde weg von Null" aka "Runde zu (entweder) Unendlichkeit" -Teilung - das ist leider noch kniffliger als rund-gegen-Null. Wir können das Abschneideverhalten des int
-Operators nicht mehr nutzen, daher kann ich mir auch bei Floating-Point-Operationen keinen einfachen Ausdruck vorstellen. Also muss ich mit der Umkehrung des Rund-zu-Null-Ausdrucks gehen und a//b if a*b<0 else (a+(-a%b))//b
verwenden.
Beachten Sie, dass (a+b-1)//b
, wenn Sie nur positive Ganzzahlen verwenden, eine noch effizientere Rundung von Null als jede der obigen Lösungen bietet, aber für Negative auseinanderfällt.
Ich hoffe, das hilft ... und freut mich, Änderungen vornehmen zu können, wenn jemand bessere Gleichungen für die Entfernung von Null vorschlagen kann. Ich finde diejenigen, die ich besonders unbefriedigend finde.
Integrale Aufteilung in Python 3:
3 // 2 == 1
Nicht-integrale Division in Python 3:
3 / 2 == 1.5
Wovon du sprichst, ist keine Teilung.
Die Frage des OP lautet wie folgt: "Wie implementiere ich in Python die Division mit Rundung in Richtung Unendlichkeit?" (schlagen Sie vor, den Titel zu ändern).
Dies ist ein vollkommen legitimer Rundungsmodus gemäß dem IEEE-754 Standard (lesen Sie diese Übersicht ), und der Begriff dafür ist "rund zu Unendlichkeit "(oder" weg von Null "). Die meisten der 9 Downvotes verprügelten die OP unfair. Ja, es gibt keine single-function Methode, dies in nativem Python zu tun, aber wir können round(float(a)/b)
oder auch die Unterklasse numbers.Number
verwenden und __div__()
überschreiben.
Das OP müsste klären, ob -3/2 auf -2 oder -1 runden soll (oder nicht - negative Operanden beachten). Da sie bereits gesagt haben, dass sie keine Runde nach oben wollen, können wir ableiten, dass -3/2 auf -2 runden sollte.
Genug Theorie. Für Implementierungen:
round(float(a)/b)
math.ceil(float(a)/b)
gibt Ihnen eine Runde nach oben, die Sie sagten, dass Sie nicht wollen
Aber wenn dies Ihre Standard-Divisionsoperation ist, oder Sie tun eine Menge davon, dann mögen Sie den Pseudocode unten: von einer der Unterklassen von numbers.Number
Real, Rational oder Integral (neu in 2.6) erben, __div__()
neu definieren oder eine nicht standardmäßige alternative __divra__()
-Operation definieren. Sie könnten ein Klassenmitglied oder eine Klassenmethode rounding_mode
definieren und während der Divisionen nachschlagen. Seien Sie vorsichtig mit __rdiv__()
und mischen Sie mit normalen Floats.
.
%Vor% Wenn Sie zwei ganze Zahlen teilen, ist das Ergebnis eine ganze Zahl.
3 / 2
ist gleich 1
, nicht 1.5
.
Siehe die Dokumentation , Anmerkung 1:
Bei (ganzzahligen oder langen) Ganzzahlen ist das Ergebnis eine Ganzzahl. Das Ergebnis wird immer auf minus unendlich gerundet: 1/2 ist 0, (-1) / 2 ist -1, 1 / (- 2) ist -1 und (-1) / (- 2) ist 0. Beachten Sie, dass Das Ergebnis ist eine lange Ganzzahl, wenn einer der Operanden unabhängig vom numerischen Wert eine lange Ganzzahl ist.
Sobald Sie 1
von der Division erhalten haben, können Sie das nicht in 2
umwandeln.
Um 1.5
zu erhalten, benötigen Sie eine Gleitkommadivision: 3.0 / 2
.
Sie können dann math.ceil
aufrufen, um 2
zu erhalten.
Sie sind falsch; es gibt keine mathematische Funktion, die sich teilt, dann aufrundet.
Das Beste, was Sie tun können, ist eine eigene Funktion zu schreiben, die zwei Gleitkommazahlen benötigt und math.ceil
aufruft.
Was Sie wahrscheinlich wollen, ist etwas wie:
%Vor%Sie könnten auch einen Import aus der Zukunft machen:
%Vor%Wenn Sie dies tun, müssen Sie den doppelten Schrägstrich verwenden, um das aktuelle Verhalten der Ganzzahldivision zu erhalten:
%Vor%Ich denke, wonach Sie suchen:
vorausgesetzt, Sie haben x (3) und y (2),
result = (x + y - 1) // y;
Dies entspricht einer Obergrenze ohne die Verwendung von Gleitpunkten.
Natürlich kann y nicht 0 sein.
Zuerst möchten Sie die Gleitkommadivision in den Argumenten verwenden. Verwenden Sie:
%Vor% Wenn Sie immer aufrunden möchten, also f(3/2)==2
und f(1.4)==2
, dann möchten Sie, dass f
math.trunc(math.ceil(x))
ist.
Wenn Sie die nächste Ganzzahl erhalten möchten, aber die Verbindungen aufgerundet werden, dann möchten Sie math.trunc(x + 0.5)
. Auf diese Weise f(3/2)==2
und f(1.4)==1
.
Tags und Links python math rounding floating-point division