Redondea a 5 (u otro número) en Python

162

¿Existe una función incorporada que pueda redondear como la siguiente?

10 -> 10
12 -> 10
13 -> 15
14 -> 15
16 -> 15
18 -> 20
Pydev UA
fuente

Respuestas:

304

No sé de una función estándar en Python, pero esto funciona para mí:

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)

Es fácil ver por qué funciona lo anterior. Desea asegurarse de que su número dividido entre 5 sea un número entero, correctamente redondeado. Entonces, primero hacemos exactamente eso ( round(float(x)/5)donde floatsolo se necesita en Python2), y luego, dado que dividimos entre 5, también multiplicamos por 5. La conversión final a intes porque round()devuelve un valor de punto flotante en Python 2.

Hice la función más genérica dándole un baseparámetro, por defecto a 5.

Alok Singhal
fuente
3
Si solo son enteros y redondean hacia abajo, entonces también puedes hacerlox // base * base
Tjorriemorrie
77
soy yo paranoico, pero prefiero usarlo floor()y ceil()no usarlo :base * floor(x/base)
user666412
1
@ user666412 math.floory math.ceilno permite su uso con una base personalizada, por lo que la preferencia es irrelevante.
Acumenus
48

Para redondear a valores no enteros, como 0.05:

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

Encontré esto útil ya que podía hacer una búsqueda y reemplazar en mi código para cambiar "round (" a "myround (", sin tener que cambiar los valores de los parámetros.

CCKx
fuente
2
Puede usar: def my_round(x, prec=2, base=0.05): return (base * (np.array(x) / base).round()).round(prec) que acepta matrices numpy también.
saubhik
23

Es solo cuestión de escalar

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

Eliminar el 'descanso' funcionaría:

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

Si el valor es ya un entero:

rounded = val - val % 5

Como una función:

def roundint(value, base=5):
    return int(value) - int(value) % int(base)
hgdeoro
fuente
Me gusta esta respuesta para redondear al valor fraccionario más cercano. es decir, si solo quiero incrementos de 0.25.
jersey bean
14
def round_to_next5(n):
    return n + (5 - n) % 5
Andy Wong
fuente
9

round (x [, n]): los valores se redondean al múltiplo más cercano de 10 a la potencia menos n. Entonces, si n es negativo ...

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

Como 10 = 5 * 2, puede usar la división entera y la multiplicación con 2, en lugar de la división flotante y la multiplicación con 5.0. No es que eso importe mucho, a menos que te guste un poco de desplazamiento

def round5(x):
    return int(round(x << 1, -1)) >> 1
pwdyson
fuente
1
+1 por mostrarnos que round () puede manejar el redondeo a múltiplos distintos de 1.0, incluidos los valores más altos. (Tenga en cuenta, sin embargo, que el enfoque de cambio de bits no funcionará con flotadores, sin mencionar que es mucho menos legible para la mayoría de los programadores)
Peter Hansen
1
@ Peter Hansen gracias por el +1. Necesita tener un int (x) para que el desplazamiento de bits funcione con flotantes. No estaba de acuerdo con lo más legible y no lo usaría yo mismo, pero me gustó la "pureza" que solo involucra 1 y no 2 o 5.
pwdyson
6

Lo siento, quería comentar la respuesta de Alok Singhai, pero no me lo permite debido a la falta de reputación = /

De todos modos, podemos generalizar un paso más e ir:

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

Esto nos permite usar bases no enteras, como .25o cualquier otra base fraccional.

ArturJ
fuente
No intente eludir las restricciones de nuevos usuarios publicando un comentario como respuesta. Las restricciones existen por una razón . Tenga esto en cuenta como una posible razón de por qué y cómo se eliminan algunas respuestas.
Adiós StackExchange el
4

Versión modificada de divround :-)

def divround(value, step, barrage):
    result, rest = divmod(value, step)
    return result*step if rest < barrage else (result+1)*step
Christian Hausknecht
fuente
entonces en este caso usas divround (valor, 5, 3)? o tal vez divround (valor, 5, 2.5)?
pwdyson
divround (valor, 5, 3), exactamente.
Christian Hausknecht
4

Utilizar:

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

No usa multiplicación y no convertirá de / a flotantes.

Redondeando al múltiplo de 10 más cercano:

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

Como puede ver, funciona tanto para números negativos como positivos. Los empates (por ejemplo, -15 y 15) siempre se redondearán hacia arriba.

Un ejemplo similar que se redondea al múltiplo más cercano de 5, lo que demuestra que también se comporta como se espera para una "base" diferente:

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

En caso de que alguien necesite "redondeo financiero" (0.5 rondas siempre arriba):

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

Según la documentación, otras opciones de redondeo son:

ROUND_CEILING (hacia Infinity),
ROUND_DOWN (hacia cero),
ROUND_FLOOR (hacia -Infinity),
ROUND_HALF_DOWN (al más cercano con lazos que van hacia cero),
ROUND_HALF_EVEN (al más cercano con lazos que van al número entero más cercano),
ROUND_HALF_UP (al más cercano con lazos que van lejos de cero) o
ROUND_UP (lejos de cero).
ROUND_05UP (lejos de cero si el último dígito después del redondeo hacia cero hubiera sido 0 o 5; de lo contrario hacia cero)

Por defecto, Python usa ROUND_HALF_EVEN ya que tiene algunas ventajas estadísticas (los resultados redondeados no están sesgados).

Piotr Siejda
fuente
2

Para enteros y con Python 3:

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


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

Productor:

>>> [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
fuente
1

Siguiente múltiplo de 5

Considere que 51 necesita convertirse a 55:

code here

mark = 51;
r = 100 - mark;
a = r%5;
new_mark = mark + a;
vijay
fuente
1

Aquí está mi código C. Si lo entiendo correctamente, debería ser algo como esto;

#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);
  }
}

y esto también se redondea al múltiplo más cercano de 5 en lugar de simplemente redondear hacia arriba;

#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
fuente
1

Otra forma de hacer esto (sin operadores explícitos de multiplicación o división):

def rnd(x, b=5):
    return round(x + min(-(x % b), b - (x % b), key=abs))
consulta_cósmica
fuente
-3

Puede "engañar" int()para redondear en lugar de redondear hacia abajo agregando 0.5al número al que pasa int().

Franciska Zsiros
fuente
2
Esto en realidad no responde a la pregunta
Uri Agassi