Zaokrąglij liczbę do najbliższej liczby całkowitej

229

Próbowałem zaokrąglać długie liczby zmiennoprzecinkowe, takie jak:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Jak dotąd bez powodzenia. Próbowałem math.ceil(x), math.floor(x)(mimo że zaokrąglić w górę lub w dół, co jest nie to, czego szukam) i round(x)które nie działało (wciąż unosić numery).

Co mógłbym zrobić?

EDYCJA: KOD:

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
źródło
3
Spróbowałbymint(x)
The Brofessor
czy to nie dałoby błędu? niepoprawny literał dla int () z bazą 10:
snh_nl

Odpowiedzi:

366
int(round(x))

Zaokrągli go i zmieni na liczbę całkowitą

EDYTOWAĆ:

Nie przypisujesz int (round (h)) do żadnej zmiennej. Kiedy wywołujesz int (round (h)), zwraca liczbę całkowitą, ale nic więcej nie robi; musisz zmienić ten wiersz dla:

h = int(round(h))

Aby przypisać nową wartość do h

EDYCJA 2:

Jak powiedział @plowman w komentarzach, Python's round() nie działa tak, jak normalnie by się tego spodziewał, a to dlatego, że sposób, w jaki liczba jest przechowywana jako zmienna, zwykle nie jest taki, jak na ekranie. Istnieje wiele odpowiedzi, które wyjaśniają to zachowanie:

round () nie wydaje się poprawnie zaokrąglać

Jednym ze sposobów uniknięcia tego problemu jest użycie wartości dziesiętnych zgodnie z poniższą odpowiedzią: https://stackoverflow.com/a/15398691/4345659

Aby ta odpowiedź działała poprawnie bez użycia dodatkowych bibliotek, wygodne byłoby użycie niestandardowej funkcji zaokrąglania. Po wielu poprawkach wymyśliłem następujące rozwiązanie, które, o ile testowałem, pozwoliło uniknąć wszystkich problemów związanych z przechowywaniem. Opiera się na użyciu reprezentacji ciągu uzyskanej za pomocą repr()(NOT str()!). Wygląda na zrzędliwego, ale to był jedyny sposób, w jaki udało mi się rozwiązać wszystkie sprawy. Działa zarówno z Python2, jak i 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])

Testy:

>>> 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

Wreszcie poprawiona odpowiedź brzmi:

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

EDYCJA 3:

Testy:

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

Gotcha polega na tym, że dec-te miejsce po przecinku może wynosić 9, a jeśli dec+1-ta cyfra> = 5, 9 stanie się 0, a 1 należy przenieść na dec-1-tą cyfrę.

Jeśli weźmiemy to pod uwagę, otrzymujemy:

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])

W sytuacji opisanej powyżej b = 10i poprzedniej wersji po prostu concatenate ai bktóre doprowadziłoby do konkatenacji 10gdzie tylna 0 zniknie. Ta wersja przekształca bsię na właściwe miejsce po przecinku na podstawie dec, jako prawidłowego przeniesienia.

francisco sollima
źródło
2
print („4.5)”, int (round (4.5))) # dał mi 4 print („5.5)”, int (round (5.5))) # dał mi 6
:,
Jest to związane z wersją Pythona. Daje mi 5 i 6 za pomocą Python 2.7.9 i, jak powiedziałeś, 4 i 6 za pomocą Python 3.4.2
francisco sollima
1
Warto zauważyć: to rozwiązanie nie spełnia oczekiwań. Na przykład int(round(4.5))zaokrągla w dół do 4, a jednocześnie int(round(4.500001))zaokrągla do 5.
oracz
Jeśli chcesz liczbę całkowitą, round(x)wystarczy w Pythonie 3.6.2 (i może także w niższych wersjach). Wynik jest już typu int. Uwaga: round(x, n)będzie typu float.
Elmex80s
1
To nie działa dla 112439.50093565206. Daje o / p -> 11253,0. Cholernie dziwne .. !!!!
ajin
24

Zastosowanie round(x, y). Zaokrągli liczbę w górę do żądanego miejsca po przecinku.

Na przykład:

>>> round(32.268907563, 3)
32.269
Satyaki Sanyal
źródło
20

round(value,significantDigit)jest zwykłym rozwiązaniem, jednak nie działa tak, jak można by się tego spodziewać z perspektywy matematycznej, gdy zaokrąglone wartości kończą się na 5. Jeśli 5cyfra znajduje się tuż za tą, do której chcesz zaokrąglić, wartości te są tylko czasami zaokrąglane w górę zgodnie z oczekiwaniami (tzn. 8.005Zaokrąglanie do dwóch cyfr dziesiętnych daje 8.01). Dla niektórych wartości z powodu dziwactwa matematyki zmiennoprzecinkowej są one zaokrąglane w dół!

to znaczy

>>> 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

Dziwne.

Zakładając, że Twoim celem jest wykonanie tradycyjnego zaokrąglania dla statystyk w nauce, jest to przydatne opakowanie, aby roundfunkcja działała zgodnie z oczekiwaniami i wymagała importdodatkowych rzeczy Decimal.

>>> round(0.075,2)

0.07

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

0.08

Aha! Na tej podstawie możemy wykonać funkcję ...

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

Zasadniczo dodaje to wartość, która ma być mniejsza niż najmniej podana cyfra ciągu, którego próbujesz użyć round. Dodając tę ​​niewielką ilość, roundw większości przypadków zachowuje zachowanie, a jednocześnie zapewnia, że ​​cyfra gorsza od tej, do której jest zaokrąglana, zaokrągla w 5górę, a jeśli jest4 to zaokrągla w dół.

Podejście polegające na użyciu 10**(-len(val)-1)było celowe, ponieważ jest to największa mała liczba, jaką można dodać, aby wymusić przesunięcie, jednocześnie zapewniając, że dodana wartość nigdy nie zmienia zaokrąglenia, nawet jeśli .brakuje dziesiętnego . Mógłbym użyć tylko 10**(-len(val))warunku, if (val>1)aby odjąć 1więcej ... ale łatwiej jest po prostu zawsze odjąć, 1ponieważ nie zmieni to zbytnio odpowiedniego zakresu liczb dziesiętnych, które to obejście może poprawnie obsłużyć. To podejście zakończy się niepowodzeniem, jeśli twoje wartości osiągną granice danego typu, to się nie powiedzie, ale dla prawie całego zakresu prawidłowych wartości dziesiętnych powinno działać.

Aby to zrobić, możesz również użyć biblioteki dziesiętnej , ale proponuję opakowanie jest prostsze i może być preferowane w niektórych przypadkach.


Edycja: Dzięki Blckknght za wskazanie, że wielkość 5marginesu występuje tylko dla niektórych wartości. Również wcześniejsza wersja tej odpowiedzi nie była wystarczająco wyraźna, aby dziwne zaokrąglanie występowało tylko wtedy, gdy cyfra bezpośrednio gorsza od cyfry, do której zaokrąglasz, ma5 .

Jason R. Mick
źródło
Nie jestem pewien, dlaczego uważasz, że dziesiętne, 5ponieważ ich ostatnia cyfra zawsze będzie zaokrąglać w dół. To nie jest przypadek szybkiego testu po prostu zrobił z numerami jak 1.5, 2.5, 3.5i tak dalej, i 1.05, 1.15, 1.25, 1.35zaokrąglenia do jednego miejsca po przecinku. Pierwszy zestaw (dokładne zaokrąglenie połówek do małych liczb całkowitych) zawsze zaokrągla do parzystej liczby całkowitej. Ten ostatni zestaw nie zaokrągla się konsekwentnie, prawdopodobnie z powodu niedokładnych reprezentacji binarnych niektórych wartości. Elementy zmiennoprzecinkowe, które mają dokładne reprezentacje binarne, takie jak 1.25okrągły, mają nawet najmniej znaczącą cyfrę, ale pozostałe wydają się zaokrąglać losowo.
Blckknght,
Ciekawe ... masz rację. round(4.0005,3)daje 4.0i round(1.0005,3)daje 1.0, ale round(2.0005,3)daje 2.001i round(3.0005,3)daje 3.001. Ale właśnie dlatego moje proponowane rozwiązanie jest konieczne ... nie wiesz, czego oczekiwać od rundy giełdowej, w tym znaczącym przypadku!
Jason R. Mick
Dzięki za to. Twoja funkcja przyda się, gdy pojawi się ten problem.
TMWP
1
Czy miałeś na myśli to , digitsna końcu tego oświadczenia zwrotnego? Gra słów nie przeznaczona. ( mam na myśli to znaczy)
user3342816
Ach, prawda, rzeczywiście powinno tam być. Dobry połów ... zaskoczony, że nikt inny tego nie zauważył! Oszczędzi tym, którzy korzystają z rozwiązania, pewnej frustracji. :-)
Jason R. Mick
15

W przypadku pozytywów spróbuj

int(x + 0.5)

Aby działało również w przypadku negatywów, spróbuj

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

int()działa jak funkcja podłogi i dlatego możesz wykorzystać tę właściwość. To zdecydowanie najszybszy sposób.

Dezorientować
źródło
4
nie działa w przypadku negatywów>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
użytkownik2907934
3
Jeśli zależy Ci na obudowach narożnych, nie używaj techniki „dodaj 0,5 i podłogę” - są pewne wartości, które mogą nie spełniać twoich oczekiwań! Zobacz stackoverflow.com/a/47302585/2732969, aby uzyskać ujęcie w C ++, a stackoverflow.com/a/38744026/2732969 odpowiedz na to samo pytanie.
Anon,
Potrzebowałem szybkiej metody, nie musiałem być dokładny i nie miałby wielu przypadków narożnych, a błąd w przypadkach narożnych nie jest ważny w moim scenariuszu. To zdecydowanie moje podejście do niektórych szczególnych przypadków, w których szybkość jest priorytetem. Nie zaleca się precyzji ani dokładności.
AgentM
11

Nie działa tylko Python okrągłej połowy nawet , jak zalecono w IEEE 754 ?

Zachowaj ostrożność przedefiniowując lub używając „niestandardowego” zaokrąglenia…

(Zobacz także https://stackoverflow.com/a/33019948/109839 )

Mapio
źródło
2
Ta odpowiedź jest nieco niejasna. Round half to evennie jest absolutnie zalecany przez IEEE 754, ale jest tylko jedną z kilku opcji zaokrąglania opisanych w normie . Round to nearest, ties away from zero(tj. zachowanie, którego oczekuje większość ludzi) jest również opcją i jest domyślne, na przykład w C / C ++.
tel
Zgadzam się, sformułowanie jest dość mylące. Co miałem na myśli, że Python zaokrągla połowę do heven (patrz tabela na końcu docs.python.org/3.7/library/... gdzie roundjest wyjaśnione) i robi to zgodnie ze sposobem, w jaki zalecana jest „okrągła połowa do parzystej” pracować (lub opisać) według normy.
Mapio
8

Możesz także użyć numpy, zakładając, że używasz python3.x. Oto przykład

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0
sushmit
źródło
7

Twoje rozwiązanie dzwoni bez podania drugiego argumentu (liczba miejsc dziesiętnych)

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

co jest znacznie lepszym wynikiem niż

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

Z dokumentacji Pythona na https://docs.python.org/3/library/functions.html#round

okrągły (liczba [, ndigits])

Zwraca liczbę zaokrągloną do dokładności ndigits po przecinku. Jeśli ndigits zostanie pominięte lub ma wartość None, zwraca najbliższą liczbę całkowitą na swoje wejście.

Uwaga

Zachowanie round () dla float może być zaskakujące: na przykład round (2.675, 2) daje 2,67 zamiast oczekiwanego 2,68. To nie jest błąd: wynika z faktu, że większości ułamków dziesiętnych nie można przedstawić dokładnie jako liczbę zmiennoprzecinkową. Aby uzyskać więcej informacji, zobacz Arytmetyka zmiennoprzecinkowa: problemy i ograniczenia.

Sójka
źródło
1

Jeśli potrzebujesz (na przykład) dwucyfrowego przybliżenia dla A, int(A*100+0.5)/100.0zrobisz to, czego szukasz.

Jeśli potrzebujesz przybliżenia trzycyfrowego, pomnóż go i podziel przez 1000 itd.

Hoo
źródło
1

Coś takiego powinno również działać

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
źródło
0

W tym celu proponuję po prostu wykonać następujące czynności -

int(round(x))

To da ci najbliższą liczbę całkowitą.

Mam nadzieję że to pomoże!!

Rahul Ranjan
źródło
0

Korzystam i mogę doradzić następujące rozwiązanie (python3.6):

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

Działa dobrze w przypadku liczb połówkowych (dodatnich i ujemnych) i działa nawet szybciej niż int (round (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
===========
Василий Прядченко
źródło