Runde Zahl auf nächste Ganzzahl

227

Ich habe versucht, lange Float-Zahlen zu runden wie:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Bisher ohne Erfolg. Ich habe versucht math.ceil(x), math.floor(x)(obwohl das aufrunden würde oder nach unten, was nicht ist , was ich suche) und round(x)die nicht funktioniert entweder (noch Zahlen schwimmen).

Was könnte ich tuen?

EDIT: CODE:

for i in widthRange:
    for j in heightRange:
        r, g, b = rgb_im.getpixel((i, j))
        h, s, v = colorsys.rgb_to_hsv(r/255.0, g/255.0, b/255.0)
        h = h * 360
        int(round(h))
        print(h)
Vandernath
quelle
3
Ich würde versuchenint(x)
The Brofessor
würde das nicht fehler geben? ungültiges Literal für int () mit Basis 10:
snh_nl

Antworten:

364
int(round(x))

Wird es runden und in eine Ganzzahl ändern

BEARBEITEN:

Sie weisen keiner Variablen int (round (h)) zu. Wenn Sie int (round (h)) aufrufen, wird die Ganzzahl zurückgegeben, es wird jedoch nichts anderes ausgeführt. Sie müssen diese Zeile ändern für:

h = int(round(h))

Zuweisen des neuen Werts zu h

EDIT 2:

Wie @plowman in den Kommentaren sagte, round()funktioniert Pythons nicht wie normalerweise erwartet, und das liegt daran, dass die Art und Weise, wie die Zahl als Variable gespeichert wird, normalerweise nicht so ist, wie Sie sie auf dem Bildschirm sehen. Es gibt viele Antworten, die dieses Verhalten erklären:

round () scheint nicht richtig zu runden

Eine Möglichkeit, dieses Problem zu vermeiden, besteht darin, die in dieser Antwort angegebene Dezimalzahl zu verwenden: https://stackoverflow.com/a/15398691/4345659

Damit diese Antwort ohne Verwendung zusätzlicher Bibliotheken ordnungsgemäß funktioniert, ist es zweckmäßig, eine benutzerdefinierte Rundungsfunktion zu verwenden. Nach vielen Korrekturen habe ich die folgende Lösung gefunden, die, soweit ich sie getestet habe, alle Speicherprobleme vermeidet. Es basiert auf der Verwendung der Zeichenfolgendarstellung, die mit repr()(NOT str()!) Erhalten wurde . Es sieht hackig aus, aber es war der einzige Weg, alle Fälle zu lösen. Es funktioniert sowohl mit Python2 als auch mit Python3.

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
        return float(num[:-2-(not dec)]+str(int(num[-2-(not dec)])+1))
    return float(num[:-1])

Tests:

>>> print(proper_round(1.0005,3))
1.001
>>> print(proper_round(2.0005,3))
2.001
>>> print(proper_round(3.0005,3))
3.001
>>> print(proper_round(4.0005,3))
4.001
>>> print(proper_round(5.0005,3))
5.001
>>> print(proper_round(1.005,2))
1.01
>>> print(proper_round(2.005,2))
2.01
>>> print(proper_round(3.005,2))
3.01
>>> print(proper_round(4.005,2))
4.01
>>> print(proper_round(5.005,2))
5.01
>>> print(proper_round(1.05,1))
1.1
>>> print(proper_round(2.05,1))
2.1
>>> print(proper_round(3.05,1))
3.1
>>> print(proper_round(4.05,1))
4.1
>>> print(proper_round(5.05,1))
5.1
>>> print(proper_round(1.5))
2.0
>>> print(proper_round(2.5))
3.0
>>> print(proper_round(3.5))
4.0
>>> print(proper_round(4.5))
5.0
>>> print(proper_round(5.5))
6.0
>>> 
>>> print(proper_round(1.000499999999,3))
1.0
>>> print(proper_round(2.000499999999,3))
2.0
>>> print(proper_round(3.000499999999,3))
3.0
>>> print(proper_round(4.000499999999,3))
4.0
>>> print(proper_round(5.000499999999,3))
5.0
>>> print(proper_round(1.00499999999,2))
1.0
>>> print(proper_round(2.00499999999,2))
2.0
>>> print(proper_round(3.00499999999,2))
3.0
>>> print(proper_round(4.00499999999,2))
4.0
>>> print(proper_round(5.00499999999,2))
5.0
>>> print(proper_round(1.0499999999,1))
1.0
>>> print(proper_round(2.0499999999,1))
2.0
>>> print(proper_round(3.0499999999,1))
3.0
>>> print(proper_round(4.0499999999,1))
4.0
>>> print(proper_round(5.0499999999,1))
5.0
>>> print(proper_round(1.499999999))
1.0
>>> print(proper_round(2.499999999))
2.0
>>> print(proper_round(3.499999999))
3.0
>>> print(proper_round(4.499999999))
4.0
>>> print(proper_round(5.499999999))
5.0

Schließlich wäre die korrigierte Antwort:

# Having proper_round defined as previously stated
h = int(proper_round(h))

EDIT 3:

Tests:

>>> proper_round(6.39764125, 2)
6.31 # should be 6.4
>>> proper_round(6.9764125, 1)
6.1  # should be 7

Das Problem hierbei ist, dass die dec-te Dezimalstelle 9 sein kann und wenn die dec+1-te Ziffer> = 5 ist, wird die 9 zu einer 0 und eine 1 sollte zur dec-1-ten Ziffer übertragen werden.

Wenn wir dies berücksichtigen, erhalten wir:

def proper_round(num, dec=0):
    num = str(num)[:str(num).index('.')+dec+2]
    if num[-1]>='5':
      a = num[:-2-(not dec)]       # integer part
      b = int(num[-2-(not dec)])+1 # decimal part
      return float(a)+b**(-dec+1) if a and b == 10 else float(a+str(b))
    return float(num[:-1])

In der Situation , wie oben beschrieben b = 10und die vorherigen Version würde nur verketten aund bdas in einer Verkettung führen würde , 10wo der Hinter 0 verschwinden würde. Diese Version wird bbasierend auf deceinem richtigen Übertrag in die richtige Dezimalstelle umgewandelt .

francisco sollima
quelle
2
print ("4.5)", int (round (4.5))) # gab mir 4 print ("5.5)", int (round (5.5))) # gab mir 6 :, (
Komm
Es hängt mit der Python-Version zusammen. Es gibt mir 5 und 6 mit Python 2.7.9 und, wie Sie sagten, 4 und 6 mit Python 3.4.2
Francisco Sollima
1
Bemerkenswert: Diese Lösung rundet nicht so ab, wie Sie es wahrscheinlich erwarten. Zum Beispiel int(round(4.5))rundet auf 4 ab, während int(round(4.500001))richtig auf 5
Pflüger
Wenn Sie eine Ganzzahl wünschen, round(x)ist dies in Python 3.6.2 (und möglicherweise auch in niedrigeren Versionen) ausreichend. Das Ergebnis ist bereits vom Typ int. Hinweis: round(x, n)wird vom Typ float sein.
Elmex80s
1
Dies funktioniert nicht für 112439.50093565206. Es gibt o / p -> 11253.0. Verdammt komisch .. !!!!
Ajin
24

Verwenden Sie round(x, y). Es wird Ihre Zahl auf die gewünschte Dezimalstelle aufrunden.

Beispielsweise:

>>> round(32.268907563, 3)
32.269
Satyaki Sanyal
quelle
20

round(value,significantDigit)ist die gewöhnliche Lösung, funktioniert jedoch nicht so, wie man es aus mathematischer Sicht erwarten würde, wenn runde Werte mit enden 5. Wenn das 5in der Ziffer direkt nach der Ziffer steht, auf die Sie gerundet sind, werden diese Werte nur manchmal wie erwartet aufgerundet (dh es wird 8.005auf zwei Dezimalstellen gerundet 8.01). Für bestimmte Werte werden sie aufgrund der Macken der Gleitkomma-Mathematik stattdessen abgerundet!

dh

>>> round(1.0005,3)
1.0
>>> round(2.0005,3)
2.001
>>> round(3.0005,3)
3.001
>>> round(4.0005,3)
4.0
>>> round(1.005,2)
1.0
>>> round(5.005,2)
5.0
>>> round(6.005,2)
6.0
>>> round(7.005,2)
7.0
>>> round(3.005,2)
3.0
>>> round(8.005,2)
8.01

Seltsam.

Angenommen, Sie beabsichtigen, die traditionelle Rundung für Statistiken in den Wissenschaften durchzuführen, ist dies ein praktischer Wrapper, damit die roundFunktion wie erwartet funktioniert und importzusätzliche Dinge wie erforderlich sind Decimal.

>>> round(0.075,2)

0.07

>>> round(0.075+10**(-2*5),2)

0.08

Aha! Auf dieser Grundlage können wir also eine Funktion erstellen ...

def roundTraditional(val,digits):
   return round(val+10**(-len(str(val))-1), digits)

Grundsätzlich wird dadurch ein Wert hinzugefügt, der garantiert kleiner ist als die am wenigsten angegebene Ziffer der Zeichenfolge, für die Sie verwenden möchten round. Durch Hinzufügen dieser kleinen Menge bleibt das roundVerhalten in den meisten Fällen erhalten, und jetzt wird sichergestellt, dass die Ziffer, die der gerundeten unterlegen ist, aufgerundet wird 5und ob sie abgerundet wird 4.

Der Ansatz der Verwendung 10**(-len(val)-1)war bewusst, da er die größte kleine Zahl ist, die Sie hinzufügen können, um die Verschiebung zu erzwingen, und gleichzeitig sicherstellt, dass der hinzugefügte Wert die Rundung niemals ändert, selbst wenn die Dezimalstelle .fehlt. Ich könnte nur 10**(-len(val))mit einer Bedingung verwenden, if (val>1)um 1mehr zu subtrahieren ... aber es ist einfacher, immer die zu subtrahieren, 1da dies den anwendbaren Bereich von Dezimalzahlen, mit dem diese Problemumgehung richtig umgehen kann, nicht wesentlich ändert. Dieser Ansatz schlägt fehl, wenn Ihre Werte die Grenzen des Typs erreichen. Dies schlägt fehl, aber für fast den gesamten Bereich gültiger Dezimalwerte sollte er funktionieren.

Sie können auch die Dezimalbibliothek verwenden, um dies zu erreichen. Der von mir vorgeschlagene Wrapper ist jedoch einfacher und kann in einigen Fällen bevorzugt werden.


Bearbeiten: Vielen Dank an Blckknght für den Hinweis, dass der Randfall5 nur für bestimmte Werte auftritt. Auch eine frühere Version dieser Antwort war nicht explizit genug, dass das ungerade Rundungsverhalten nur auftritt, wenn die Ziffer, die der Ziffer, auf die Sie runden, unmittelbar unterlegen ist, eine hat5 .

Jason R. Mick
quelle
Ich bin mir nicht sicher, warum Sie denken, dass Dezimalstellen mit 5ihrer letzten Ziffer immer abgerundet werden. Das ist nicht der Fall in einem Schnelltest Ich habe gerade mit Zahlen wie 1.5, 2.5, 3.5und so weiter und 1.05, 1.15, 1.25, 1.35auf eine Dezimalstelle gerundet wird . Der erste Satz (exakte Hälften, die auf kleine ganze Zahlen gerundet werden) rundet immer auf eine gerade ganze Zahl. Letztere runden nicht konsistent, wahrscheinlich aufgrund ungenauer binärer Darstellungen einiger Werte. Die Floats mit exakten binären Darstellungen wie " 1.25rund" haben eine noch am wenigsten signifikante Ziffer, die anderen scheinen jedoch zufällig zu runden.
Blckknght
Interessant ... du hast recht. round(4.0005,3)gibt 4.0und round(1.0005,3)gibt 1.0, aber round(2.0005,3)gibt 2.001und round(3.0005,3)gibt 3.001. Aber genau deshalb ist meine vorgeschlagene Lösung notwendig ... Sie wissen nicht, was Sie in diesem wichtigen Fall von der Aktienrunde erwarten können!
Jason R. Mick
Danke dafür. Ihre Funktion wird nützlich sein, wenn dieses Problem auftritt.
TMWP
1
Wollten Sie , digitsam Ende dieser Rückgabeerklärung haben? Kein Wortspiel beabsichtigt. ( meine ich meine)
user3342816
Ah richtig, tatsächlich hätte das da drin sein sollen. Guter Fang ... überrascht, dass niemand anderes es bemerkt hatte! Spart denjenigen, die die Lösung nutzen, etwas Frust. :-)
Jason R. Mick
15

Versuchen Sie es mit positiven Ergebnissen

int(x + 0.5)

Versuchen Sie es, damit es auch für Negative funktioniert

int(x + (0.5 if x > 0 else -0.5))

int()funktioniert wie eine Bodenfunktion und daher können Sie diese Eigenschaft ausnutzen. Dies ist definitiv der schnellste Weg.

Verwechseln
quelle
4
funktioniert nicht für Negative>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934
3
Wenn Sie sich für Eckfälle interessieren, verwenden Sie nicht die Technik "0,5 und Boden hinzufügen" - es gibt einige Werte, die möglicherweise nicht so sind, wie Sie es erwarten! Unter stackoverflow.com/a/47302585/2732969 finden Sie eine C ++ - Aufnahme und die Antwort auf stackoverflow.com/a/38744026/2732969 in genau dieser Frage.
Anon
Ich brauchte eine schnelle Methode, sie musste nicht genau sein und hatte nicht viele Eckfälle, und Fehler in Eckfällen sind in meinem Szenario nicht wichtig. Dies ist definitiv meine Wahl für einige Sonderfälle, in denen Geschwindigkeit Priorität hat. Nicht für Präzision oder Genauigkeit empfehlen.
AgentM
11

Macht Python nicht nur die Hälfte bis gerade , wie es IEEE 754 vorschreibt ?

Seien Sie vorsichtig bei der Neudefinition oder bei der Verwendung von "nicht standardmäßigen" Rundungen.

(Siehe auch https://stackoverflow.com/a/33019948/109839 )

Mapio
quelle
2
Diese Antwort ist etwas unklar. Round half to evenwird von IEEE 754 absolut nicht vorgeschrieben, sondern ist nur eine von mehreren Rundungsoptionen, die in der Norm beschrieben sind . Round to nearest, ties away from zero(dh das Verhalten, das die meisten Leute erwarten) ist ebenfalls eine Option und die Standardeinstellung in beispielsweise C / C ++.
Tel
Ich stimme zu, der Wortlaut ist ziemlich verwirrend. Was ich damit gemeint habe, dass Python die Hälfte auf sieben rundet (siehe die Tabelle am Ende von docs.python.org/3.7/library/…, wo rounderklärt wird) und dies gemäß der vorgeschriebenen Art und Weise, wie "die Hälfte auf gerade runden" vorgeschrieben ist nach dem Standard arbeiten (oder beschrieben).
Mapio
8

Sie können auch numpy verwenden, vorausgesetzt, Sie verwenden python3.x. Hier ist ein Beispiel

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0
Sushmit
quelle
7

Ihre Lösung ruft rund auf, ohne das zweite Argument anzugeben (Anzahl der Dezimalstellen).

>>> round(0.44)
0
>>> round(0.64)
1

Das ist ein viel besseres Ergebnis als

>>> int(round(0.44, 2))
0
>>> int(round(0.64, 2))
0

Aus der Python-Dokumentation unter https://docs.python.org/3/library/functions.html#round

rund (Zahl [, ndigits])

Geben Sie die Zahl nach dem Dezimalpunkt auf ndigits gerundet zurück. Wenn ndigits weggelassen wird oder None ist, wird die nächste Ganzzahl an die Eingabe zurückgegeben.

Hinweis

Das Verhalten von round () für Floats kann überraschend sein: Beispielsweise ergibt round (2.675, 2) 2,67 anstelle der erwarteten 2,68. Dies ist kein Fehler: Es ist das Ergebnis der Tatsache, dass die meisten Dezimalbrüche nicht genau als Float dargestellt werden können. Weitere Informationen finden Sie unter Gleitkomma-Arithmetik: Probleme und Einschränkungen.

Jay
quelle
1

Wenn Sie (zum Beispiel) eine zweistellige Näherung für A int(A*100+0.5)/100.0benötigen , tun Sie, wonach Sie suchen.

Wenn Sie eine dreistellige Näherung benötigen, multiplizieren und dividieren Sie durch 1000 und so weiter.

Hoo
quelle
1

So etwas sollte auch funktionieren

import numpy as np    

def proper_round(a):
    '''
    given any real number 'a' returns an integer closest to 'a'
    '''
    a_ceil = np.ceil(a)
    a_floor = np.floor(a)
    if np.abs(a_ceil - a) < np.abs(a_floor - a):
        return int(a_ceil)
    else:
        return int(a_floor)
Aabhaas
quelle
0

Zu diesem Zweck würde ich vorschlagen, nur Folgendes zu tun:

int(round(x))

Dies gibt Ihnen die nächste Ganzzahl.

Hoffe das hilft!!

rahul ranjan
quelle
0

Ich verwende und kann die folgende Lösung empfehlen (python3.6):

y = int(x + (x % (1 if x >= 0 else -1)))

Es funktioniert gut für Halbzahlen (Positive und Negative) und funktioniert sogar schneller als int (Runde (x)):

round_methods = [lambda x: int(round(x)), 
                 lambda x: int(x + (x % (1 if x >= 0 else -1))),
                 lambda x: np.rint(x).astype(int),
                 lambda x: int(proper_round(x))]

for rm in round_methods:
    %timeit rm(112.5)
Out:
201 ns ± 3.96 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
159 ns ± 0.646 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
925 ns ± 7.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
1.18 µs ± 8.66 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

for rm in round_methods:
    print(rm(112.4), rm(112.5), rm(112.6))
    print(rm(-12.4), rm(-12.5), rm(-12.6))
    print('=' * 11)

Out:
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
112 112 113
-12 -12 -13
===========
112 113 113
-12 -13 -13
===========
Василий Прядченко
quelle