Python rundet die Ganzzahl auf die nächsten hundert auf

78

Scheint, das hätte schon hunderte Male gefragt werden sollen (Wortspiel macht Spaß =), aber ich kann nur eine Funktion zum Runden von Schwimmern finden. Wie runde ich eine ganze Zahl auf, zum Beispiel : 130 -> 200?

userBG
quelle
3
Möchten Sie, dass 100 auch auf 200 aufgerundet werden?
DSM
Nein, Thomas 'Antwort macht genau das, was ich brauche
userBG
1
Thomas' Antwort hat rund 100 bis 200. Deshalb fragte ich.
DSM
Überprüfen Sie die Bearbeitung, das habe ich in der ersten Antwort nicht beachtet.
Thomas Orozco
1
@ofko: Sie haben eine Antwort akzeptiert, die mit großen Ganzzahlen fehlschlägt. Einzelheiten finden Sie in meiner aktualisierten Antwort.
John Machin

Antworten:

150

Das Runden erfolgt normalerweise mit Gleitkommazahlen. Hier sollten Sie drei grundlegende Funktionen kennen: round(auf die nächste Ganzzahl runden), math.floor(immer abrunden) und math.ceil(immer aufrunden).

Sie fragen nach ganzen Zahlen und runden auf Hunderte auf, aber wir können immer noch verwenden math.ceil, solange Ihre Zahlen kleiner als 2 53 sind . Zur Verwendung math.ceilteilen wir einfach zuerst durch 100, runden auf und multiplizieren danach mit 100:

>>> import math
>>> def roundup(x):
...     return int(math.ceil(x / 100.0)) * 100
... 
>>> roundup(100)
100
>>> roundup(101)
200

Wenn Sie zuerst durch 100 dividieren und anschließend mit 100 multiplizieren, werden zwei Dezimalstellen nach rechts und links verschoben, sodass math.ceilHunderte funktionieren. Sie können 10**nanstelle von 100 auch verwenden, wenn Sie auf Zehner ( n = 1), Tausender ( n = 3) usw. runden möchten .

Eine alternative Möglichkeit besteht darin, Gleitkommazahlen zu vermeiden (sie haben eine begrenzte Genauigkeit) und stattdessen nur Ganzzahlen zu verwenden. Ganzzahlen haben in Python eine beliebige Genauigkeit, sodass Sie Zahlen beliebiger Größe runden können. Die Regel für das Runden ist einfach: Finden Sie den Rest nach der Division mit 100 und addieren Sie 100 minus diesen Rest, wenn er nicht Null ist:

>>> def roundup(x):
...     return x if x % 100 == 0 else x + 100 - x % 100

Dies funktioniert für Zahlen jeder Größe:

>>> roundup(100)
100
>>> roundup(130)
200
>>> roundup(1234567891234567891)
1234567891234567900L

Ich habe einen Mini-Benchmark der beiden Lösungen durchgeführt:

$ python -m timeit -s 'import math' -s 'x = 130' 'int(math.ceil(x/100.0)) * 100'
1000000 loops, best of 3: 0.364 usec per loop
$ python -m timeit -s 'x = 130' 'x if x % 100 == 0 else x + 100 - x % 100'
10000000 loops, best of 3: 0.162 usec per loop

Die reine ganzzahlige Lösung ist im Vergleich zur math.ceilLösung um den Faktor zwei schneller .

Thomas schlug eine ganzzahlige Lösung vor, die mit der oben beschriebenen identisch ist, außer dass sie einen Trick durch Multiplizieren von Booleschen Werten verwendet. Es ist interessant zu sehen, dass es keinen Geschwindigkeitsvorteil gibt, den Code so zu schreiben:

$ python -m timeit -s 'x = 130' 'x + 100*(x%100>0) - x%100'
10000000 loops, best of 3: 0.167 usec per loop

Lassen Sie mich abschließend noch bemerken, dass die eingebaute Funktion dies für Sie tun kann , wenn Sie 101–149 auf 100 und 150–199 auf 200 runden wollten, z. B. auf die nächsten hundert runden möchten round:

>>> int(round(130, -2))
100
>>> int(round(170, -2))
200
Martin Geisler
quelle
Ich mache hier keine normale Rundung, wenn ich ja wäre, würde ich round ()
userBG
3
@ofko: Richtig, du willst abrunden. Dies math.ceilist der kanonische Weg, dies zu tun - Teilen und Multiplizieren mit 100 ist der kanonische Weg round,ceil und die floorArbeit an Hunderten.
Martin Geisler
1
Nach den letzten Änderungen ist es jetzt sinnvoll, diese Antwort zu akzeptieren.
UserBG
2
-1 Dieser Ansatz mag bei Floats "kanonisch" sein, schlägt jedoch bei großen ganzen Zahlen fehl . Siehe meine Antwort für Details. Das OP fragte speziell nach ganzen Zahlen und drückte keine Obergrenze für die Größe der Zahlen aus.
John Machin
1
@ JohnMachin: Die Abwertung bezieht sich auf Fragen, die "nicht nützlich" sind, und ich verstehe nicht, warum diese einfache und direkte Antwort nicht nützlich ist. Infact, markiert die OP als angenommen, so dass es ist nützlich. Wenn jemand Hilfe braucht, um 130 bis 200 zu runden, dann ist es meiner Meinung nach etwas anstrengend, sich darüber zu beschweren, dass 1234567891234567891 nicht richtig gerundet wird. Sie haben Recht, dass es im floatVergleich zu long(natürlich!) Eine begrenzte Präzision gibt , aber für die meisten praktischen Situationen floatist a ziemlich groß.
Martin Geisler
26

Dies ist eine späte Antwort, aber es gibt eine einfache Lösung, die die besten Aspekte der vorhandenen Antworten kombiniert: Das nächste Vielfache von 100bis xist x - x % -100(oder wenn Sie es vorziehen x + (-x) % 100).

>>> x = 130
>>> x -= x % -100  # Round x up to next multiple of 100.
>>> x
200

Dies ist schnell und einfach, liefert korrekte Ergebnisse für jede ganze Zahl x(wie die Antwort von John Machin) und liefert auch vernünftige Ergebnisse (modulo die üblichen Vorbehalte bezüglich der Gleitkommadarstellung), wenn xes sich um ein Gleitkomma handelt (wie die Antwort von Martin Geisler).

>>> x = 0.1
>>> x -= x % -100
>>> x
100.0
Mark Dickinson
quelle
1
Ihre Lösung ist so schnell wie die von Martin, aber die Notation ist kürzer. Vielen Dank. % timeit 'x = 110' 'x - = x% -100' # 100000000 Schleifen, am besten 3: 9,37 ns pro Schleife VS% timeit 'x = 110' 'x + 100 * (x% 100> 0) - x % 100 '# 100000000 Schleifen, am besten 3: 9,38 ns pro Schleife
Tagoma
21

Versuche dies:

int(round(130 + 49, -2))
Fred Foo
quelle
warum int ()? Typ (rund (999, -2)) ist int (Python 3.8)
Tim Richardson
Dies ist jedoch nicht immer eine Zusammenfassung, wie die Frage gestellt hat.
Tim
18

Hier ist eine allgemeine Methode zum Aufrunden auf das nächste Vielfache einer positiven Ganzzahl:

def roundUpToMultiple(number, multiple):
    num = number + (multiple - 1)
    return num - (num % multiple)

Beispielnutzung:

>>> roundUpToMultiple (101, 100)
200
>>> roundUpToMultiple (654, ​​321)
963
Luke Woodward
quelle
äquivalente, kürzere Methode:lambda number, multiple: multiple * (1 + (number - 1) // multiple)
mic_e
8

Für anicht negativ, bpositiv, beide ganzen Zahlen:

>>> rup = lambda a, b: (a + b - 1) // b * b
>>> [(x, rup(x, 100)) for x in (199, 200, 201)]
[(199, 200), (200, 200), (201, 300)]

Aktualisieren Die aktuell akzeptierte Antwort fällt mit ganzen Zahlen auseinander, sodass float (x) / float (y) nicht genau als a dargestellt werden kann float. Siehe diesen Code:

import math

def geisler(x, y): return int(math.ceil(x / float(y))) * y

def orozco(x, y): return x + y * (x % y > 0) - x % y

def machin(x, y): return (x + y - 1) // y * y

for m, n in (
    (123456789123456789, 100),
    (1234567891234567891, 100),
    (12345678912345678912, 100),
    ):
    print; print m, "m"; print n, "n"
    for func in (geissler, orozco, machin):
        print func(m, n), func.__name__

Ausgabe:

123456789123456789 m
100 n
123456789123456800 geisler
123456789123456800 orozco
123456789123456800 machin

1234567891234567891 m
100 n
1234567891234568000 geisler <<<=== wrong
1234567891234567900 orozco
1234567891234567900 machin

12345678912345678912 m
100 n
12345678912345680000 geisler <<<=== wrong
12345678912345679000 orozco
12345678912345679000 machin

Und hier sind einige Timings:

>\python27\python -m timeit -s "import math;x =130" "int(math.ceil(x/100.0))*100"
1000000 loops, best of 3: 0.342 usec per loop

>\python27\python -m timeit -s "x = 130" "x + 100 * (x % 100 > 0) - x % 100"
10000000 loops, best of 3: 0.151 usec per loop

>\python27\python -m timeit -s "x = 100" "(x + 99) // 100 * 100"
10000000 loops, best of 3: 0.0903 usec per loop
John Machin
quelle
I know the OP was about rounding an integer- aber ich wollte darauf hinweisen, dass Sie versuchen würden, diese 3 Optionen für (0.5,10) zu verwenden, von denen ich erwarten würde, dass sie 10 zurückgeben, dann geben die ersten beiden Methoden (geisler & orozco) wie erwartet 10 zurück, während
machin
3

Wenn Ihr int x ist: x + 100 - x % 100

Wie in den Kommentaren angegeben, gibt dies jedoch 200 zurück, wenn x==100.

Wenn dies nicht das erwartete Verhalten ist, können Sie verwenden x + 100*(x%100>0) - x%100

Thomas Orozco
quelle
Vielleicht möchten Sie die anderen Lösungen verwenden, wenn Sie keine magischen Zahlen mögen. Wenn Sie sich mit der Leistung befassen, läuft dies jedoch schneller.
Thomas Orozco
Ja, 100 sollte nicht aufgerundet bleiben, aber wenn das die Formel zu kompliziert machen würde, kann ich verhindern, dass Code verwendet wird, kein Problem
userBG
Nun, die andere Version löst dieses Problem, da sie die Prüfung vor dem Hinzufügen von 100 enthält! Wenn dies Ihren Bedürfnissen entspricht, vergessen Sie nicht zu akzeptieren! :)
Thomas Orozco
1
Es tut mir leid, aber ich finde diesen Code sehr unpythonisch. Ja, a boolhat einen numerischen Wert, also können Sie mit einem booleschen Ausdruck multiplizieren. Die anderen Lösungen sind jedoch klarer.
Martin Geisler
Nun, ich habe in der Tat darauf hingewiesen, dass anderer Code bevorzugt werden könnte, wenn die Leistung kein Schlüsselparameter ist.
Thomas Orozco
3

Versuche dies:

import math
def ceilm(number,multiple):
    '''Returns a float rounded up by a factor of the multiple specified'''
    return math.ceil(float(number)/multiple)*multiple

Beispielnutzung:

>>> ceilm(257,5)
260
>>> ceilm(260,5)
260
Sukrit Gupta
quelle
3

Warnung: Vorzeitige Optimierungen voraus ...

Da so viele der Antworten hier den Zeitpunkt dafür bestimmen, wollte ich eine weitere Alternative hinzufügen.

Nehmen Sie @Martin Geislers

def roundup(x):
    return x if x % 100 == 0 else x + 100 - x % 100

(was mir aus mehreren Gründen am besten gefällt)

aber die% Aktion herausrechnen

def roundup2(x):
    x100= x % 100
    return x if x100 == 0 else x + 100 - x100

Ergibt eine Geschwindigkeitsverbesserung von ~ 20% gegenüber dem Original

def roundup3(x):
    x100 = x % 100
    return x if not x100 else x + 100 - x100

Ist noch besser und ~ 36% schneller als das Original

Schließlich dachte ich, ich könnte den notOperator fallen lassen und die Reihenfolge der Zweige ändern, in der Hoffnung, dass dies auch die Geschwindigkeit erhöhen würde, war aber verblüfft, als ich herausfand, dass es tatsächlich langsamer ist, zurückzufallen und nur 23% schneller als das Original zu sein.

def roundup4(x):
    x100 = x % 100
    return x + 100 - x100  if x100 else x


>python -m timeit -s "x = 130" "x if x % 100 == 0 else x + 100 - x % 100"
1000000 loops, best of 3: 0.359 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if x100 == 0 else x + 100 - x100"
1000000 loops, best of 3: 0.287 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x if not x100 else x + 100 - x100"
1000000 loops, best of 3: 0.23 usec per loop

>python -m timeit -s "x = 130" "x100 = x % 100"  "x + 100 - x100 if x100 else x"
1000000 loops, best of 3: 0.277 usec per loop

Erklärungen, warum 3 schneller ist als 4, wären sehr willkommen.

Epeleg
quelle
0

Hier ist eine sehr einfache Lösung:

next_hundred = x//100*100+100

Wie funktioniert es?

  1. Führen Sie die ganzzahlige Division durch 100 durch (sie schneidet im Grunde den Bruchteil der normalen Division ab). Auf diese Weise erhalten Sie die Zehnerzahl. Zum Beispiel: 243 // 100 = 2.
  2. Mit 100 multiplizieren, um die ursprüngliche Zahl ohne Zehner und Einsen zu erhalten. Zum Beispiel: 2 * 100 = 200.
  3. Addiere 100, um das gewünschte Ergebnis zu erhalten. Zum Beispiel: 200 + 100 = 300

Einige Beispiele

  • 0 ... 99 auf 100 gerundet
  • 100 ... 199 auf 200 gerundet
  • usw.

Ein leicht modifizierter Ansatz rundet 1 ... 100 bis 100, 101 ... 200 bis 200 usw.:

next_hundred = (x-1)//100*100+100
Riccardo Bucco
quelle