Zaokrąglij do 5 (lub innej liczby) w Pythonie

162

Czy istnieje wbudowana funkcja, która może zaokrąglać w następujący sposób?

10 -> 10
12 -> 10
13 -> 15
14 -> 15
16 -> 15
18 -> 20
Pydev UA
źródło

Odpowiedzi:

304

Nie znam standardowej funkcji w Pythonie, ale to działa dla mnie:

Python 2

def myround(x, base=5):
    return int(base * round(float(x)/base))

Python3

def myround(x, base=5):
    return base * round(x/base)

Łatwo zobaczyć, dlaczego powyższe działa. Chcesz się upewnić, że Twoja liczba podzielona przez 5 jest liczbą całkowitą, prawidłowo zaokrągloną. Więc najpierw robimy dokładnie to ( round(float(x)/5)gdzie floatjest to potrzebne tylko w Pythonie2), a następnie, ponieważ podzieliliśmy przez 5, mnożymy również przez 5. Ostateczna konwersja do intjest taka, ponieważ round()zwraca wartość zmiennoprzecinkową w Pythonie 2.

Uczyniłem funkcję bardziej ogólną, nadając jej baseparametr, domyślnie 5.

Alok Singhal
źródło
3
Jeśli tylko liczby całkowite i zaokrąglanie w dół, możesz też po prostu zrobićx // base * base
Tjorriemorrie
7
to ja jestem paranoikiem, ale wolę używać floor()i ceil()zamiast przesyłać:base * floor(x/base)
user666412
1
@ user666412 math.floori math.ceilnie zezwalaj na używanie z niestandardową bazą, więc preferencja nie ma znaczenia.
Acumenus
48

Aby zaokrąglić do wartości niecałkowitych, takich jak 0,05:

def myround(x, prec=2, base=.05):
  return round(base * round(float(x)/base),prec)

Okazało się to przydatne, ponieważ mogłem po prostu przeprowadzić wyszukiwanie i zamienić w moim kodzie, aby zmienić „round (” na „myround (”) bez konieczności zmiany wartości parametrów.

CCKx
źródło
2
Możesz użyć: def my_round(x, prec=2, base=0.05): return (base * (np.array(x) / base).round()).round(prec) który akceptuje również tablice numpy.
saubhik
23

To tylko kwestia skalowania

>>> a=[10,11,12,13,14,15,16,17,18,19,20]
>>> for b in a:
...     int(round(b/5.0)*5.0)
... 
10
10
10
15
15
15
15
15
20
20
20
amo-ej1
źródło
14

Usunięcie „reszty” zadziałałoby:

rounded = int(val) - int(val) % 5

Jeśli wartość jest równa liczbie całkowitej:

rounded = val - val % 5

Jako funkcja:

def roundint(value, base=5):
    return int(value) - int(value) % int(base)
hgdeoro
źródło
Podoba mi się ta odpowiedź za zaokrąglenie do najbliższej wartości ułamkowej. tj. jeśli chcę tylko przyrosty 0,25.
fasola jersey
14
def round_to_next5(n):
    return n + (5 - n) % 5
Andy Wong
źródło
9

round (x [, n]): wartości są zaokrąglane do najbliższej wielokrotności 10 do potęgi minus n. Więc jeśli n jest ujemne ...

def round5(x):
    return int(round(x*2, -1)) / 2

Ponieważ 10 = 5 * 2, zamiast dzielenia liczb zmiennoprzecinkowych i mnożenia przez 5,0 można użyć dzielenia liczb całkowitych i mnożenia przez 2. Nie ma to większego znaczenia, chyba że lubisz trochę zmieniać

def round5(x):
    return int(round(x << 1, -1)) >> 1
pwdyson
źródło
1
+1 za pokazanie nam, że funkcja round () może obsłużyć zaokrąglanie do wielokrotności innych niż 1,0, w tym wyższych wartości. (Należy jednak pamiętać, że podejście z przesunięciem bitów nie zadziała z pływakami, nie wspominając o tym, że jest znacznie mniej czytelne dla większości programistów.)
Peter Hansen
1
@Peter Hansen dzięki za +1. Potrzebujesz int (x), aby przesunięcie bitu działało z liczbami zmiennoprzecinkowymi. Zgodziłem się, że nie jest to najczytelniejszy i sam bym go nie używał, ale podobała mi się „czystość” tylko z 1, a nie 2 czy 5.
pwdyson
6

Przepraszam, chciałem skomentować odpowiedź Aloka Singhai, ale nie pozwala mi na to z powodu braku reputacji = /

W każdym razie możemy uogólnić jeszcze jeden krok i przejść:

def myround(x, base=5):
    return base * round(float(x) / base)

To pozwala nam używać niecałkowitych baz, takich jak .25lub dowolnej innej podstawy ułamkowej.

ArturJ
źródło
Nie próbuj omijać nowych ograniczeń użytkowników, zamieszczając komentarz jako odpowiedź. Ograniczenia istnieją z jakiegoś powodu . Weź to pod uwagę jako możliwy powód dlaczego i w jaki sposób niektóre odpowiedzi są usuwane?
Goodbye StackExchange
4

Zmodyfikowana wersja divround :-)

def divround(value, step, barrage):
    result, rest = divmod(value, step)
    return result*step if rest < barrage else (result+1)*step
Christian Hausknecht
źródło
więc w tym przypadku używasz divround (value, 5, 3)? a może divround (wartość, 5, 2,5)?
pwdyson
divround (value, 5, 3), dokładnie.
Christian Hausknecht
4

Posługiwać się:

>>> def round_to_nearest(n, m):
        r = n % m
        return n + m - r if r + r >= m else n - r

Nie używa mnożenia i nie konwertuje z / na liczby zmiennoprzecinkowe.

Zaokrąglanie do najbliższej wielokrotności liczby 10:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 10)))
-21  =>  -20
-18  =>  -20
-15  =>  -10
-12  =>  -10
 -9  =>  -10
 -6  =>  -10
 -3  =>    0
  0  =>    0
  3  =>    0
  6  =>   10
  9  =>   10
 12  =>   10
 15  =>   20
 18  =>   20
 21  =>   20
 24  =>   20
 27  =>   30

Jak widać, działa to zarówno dla liczb ujemnych, jak i dodatnich. Remisy (np. -15 i 15) zawsze będą zaokrąglane w górę.

Podobny przykład, który zaokrągla do najbliższej wielokrotności liczby 5, pokazując, że również zachowuje się zgodnie z oczekiwaniami dla innej „bazy”:

>>> for n in range(-21, 30, 3): print('{:3d}  =>  {:3d}'.format(n, round_to_nearest(n, 5)))
-21  =>  -20
-18  =>  -20
-15  =>  -15
-12  =>  -10
 -9  =>  -10
 -6  =>   -5
 -3  =>   -5
  0  =>    0
  3  =>    5
  6  =>    5
  9  =>   10
 12  =>   10
 15  =>   15
 18  =>   20
 21  =>   20
 24  =>   25
 27  =>   25
wouter bolsterlee
źródło
2

Jeśli ktoś potrzebuje „zaokrąglenia finansowego” (0,5 zaokrąglenia zawsze w górę):

def myround(x, base=5):
    roundcontext = decimal.Context(rounding=decimal.ROUND_HALF_UP)
    decimal.setcontext(roundcontext)
    return int(base *float(decimal.Decimal(x/base).quantize(decimal.Decimal('0'))))

Zgodnie z dokumentacją inne opcje zaokrąglania to:

ROUND_CEILING (w kierunku Infinity),
ROUND_DOWN (w kierunku zera),
ROUND_FLOOR (w kierunku -Infinity),
ROUND_HALF_DOWN (do najbliższego z remisami zbliżającymi się do zera),
ROUND_HALF_EVEN (do najbliższej z remisami zbliżającymi się do najbliższej parzystej liczby całkowitej),
ROUND_HALF_UP (do najbliższej od zera) lub
ROUND_UP (od zera).
ROUND_05UP (od zera, jeśli ostatnia cyfra po zaokrągleniu do zera wynosiłaby 0 lub 5; w przeciwnym razie w kierunku zera)

Domyślnie Python używa ROUND_HALF_EVEN, ponieważ ma pewne zalety statystyczne (zaokrąglone wyniki nie są obciążone).

Piotr Siejda
źródło
2

Dla liczb całkowitych i Python 3:

def divround_down(value, step):
    return value//step*step


def divround_up(value, step):
    return (value+step-1)//step*step

Produkcja:

>>> [divround_down(x,5) for x in range(20)]
[0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15]
>>> [divround_up(x,5) for x in range(20)]
[0, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 15, 15, 15, 15, 15, 20, 20, 20, 20]
Sylvain Leroux
źródło
1

Następna wielokrotność 5

Rozważmy, że 51 należy przekonwertować na 55:

code here

mark = 51;
r = 100 - mark;
a = r%5;
new_mark = mark + a;
vijay
źródło
1

Oto mój kod C. Jeśli dobrze to rozumiem, powinno to być coś takiego;

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        number++;
  printf("%d\n",number);
  }
}

i to również zaokrągla do najbliższej wielokrotności liczby 5 zamiast tylko zaokrąglać w górę;

#include <stdio.h>

int main(){
int number;

printf("Enter number: \n");
scanf("%d" , &number);

if(number%5 == 0)
    printf("It is multiple of 5\n");
else{
    while(number%5 != 0)
        if (number%5 < 3)
            number--;
        else
        number++;
  printf("nearest multiple of 5 is: %d\n",number);
  }
}
Ege Merey
źródło
1

Inny sposób, aby to zrobić (bez jawnych operatorów mnożenia lub dzielenia):

def rnd(x, b=5):
    return round(x + min(-(x % b), b - (x % b), key=abs))
cosmic_inquiry
źródło
-3

int()Zamiast zaokrąglania w dół możesz „oszukać”, dodając 0.5do podanej liczby int().

Franciska Zsiros
źródło
2
To właściwie nie odpowiada na pytanie
Uri Agassi