2012-01-14 12 views
43

Parece que ya debería haber pedido cientos (los juegos de palabras son divertidos =) de veces, pero solo puedo encontrar la función para redondear los flotantes. ¿Cómo puedo redondear un entero, por ejemplo: 130 -> 200?Python redondea el número entero al siguiente cien

+0

¿Desea que 100 se redondeen hasta 200 también? – DSM

+0

No, la respuesta de Thomas hace justo lo que necesito – ofko

+0

La respuesta de Thomas * hace * alrededor de 100 hasta 200. Por eso pregunté. – DSM

Respuesta

78

redondeo se realiza normalmente en números de punto flotante, y aquí hay tres funciones básicas que debe saber: round (redondea al número entero más cercano), math.floor (siempre redondea hacia abajo) y math.ceil (siempre redondea).

Pregunta sobre enteros y redondeo a cientos, pero aún podemos usar math.ceil siempre que sus números sean menores que 2 . Para utilizar math.ceil, simplemente dividimos por 100 en primer lugar, reunir, y se multiplican con 100 después:

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

Dividiendo por 100 primero y multiplicamos con 100 después "cambia" dos cifras decimales a la derecha e izquierda de manera que math.ceil trabaja en los cientos. Se podría utilizar en lugar de 10**n 100 si desea redondear a decenas (n = 1), miles (n = 3), etc.

Una forma alternativa de hacer esto es para evitar los números de punto flotante (que han limitado la precisión) y en su lugar utilizar enteros solamente Los enteros tienen una precisión arbitraria en Python, por lo que le permite redondear números de cualquier tamaño. La regla de redondeo es simple: encontrar el resto después de la división con 100, y añadir 100 menos ese resto si es distinto de cero:

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

Esto funciona para los números de cualquier tamaño:

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

I hizo un mini-punto de referencia de las dos soluciones:

$ 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 

la solución entera pura es más rápido por un factor de dos en comparación con la solución math.ceil.

Thomas propuso una solución basada en enteros que es idéntica a la que tengo arriba, excepto que usa un truco multiplicando los valores booleanos. Es interesante ver que no hay ninguna ventaja de la velocidad de escribir el código de esta manera:

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

Como observación final, también quisiera señalar, que si hubiera querido redondear 101-149 de 100 y alrededor de 150 -199 a 200, por ejemplo, Y vuelta a la más cercana cien, a continuación, la incorporada en round función puede hacer eso por usted:

>>> int(round(130, -2)) 
100 
>>> int(round(170, -2)) 
200 
+0

No estoy haciendo un redondeo normal aquí, si fuera sí, usaría round() – ofko

+3

@ofko: derecho, quieres redondear. El 'math.ceil' es la forma canónica de hacerlo: dividir y multiplicar por 100 es la manera canónica de hacer que 'round', 'ceil' y' floor' funcionen en cientos. –

+1

Después de las ediciones recientes, ahora tiene sentido aceptar esta respuesta. – ofko

13

Prueba esto:

int(round(130 + 49, -2)) 
3

Si su int x es: x + 100 - x % 100

Sin embargo, como se ha señalado en los comentarios, esto devolverá 200 si x==100.

Si este no es el comportamiento esperado, puede utilizar x + 100*(x%100>0) - x%100

+0

¿Qué pasa si 'x' ya es un múltiplo de 100? –

+0

Es posible que desee utilizar las otras soluciones si no le gustan los números mágicos. Si le preocupa el rendimiento, esto sin embargo se ejecuta más rápido. –

+0

@LukeWoodward Gran punto, voy a editar –

17

Aquí está una manera general de redondeo al múltiplo más cercano de cualquier número entero positivo:

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

muestra:

 
>>> roundUpToMultiple(101, 100) 
200 
>>> roundUpToMultiple(654, 321) 
963 
+0

demasiado complicado –

+0

método equivalente, más corto: 'número lambda, múltiple: múltiple * (1 + (número - 1) // múltiple)' –

8

Para a no negativo, b posi tiva, ambos enteros:

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

actualizacióncae la respuesta aceptada actualmente-aparte con números enteros tales que flotador (x)/flotador (y) no puede representarse con precisión como una float. Ver este código:

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__ 

de salida:

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 

y aquí están algunos tiempos:

>\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 
+0

'Sé que el OP se trataba de redondear un número entero' - pero quería señalar que Intentarías usar esas 3 opciones en (0.5,10) que esperaría que regresas 10, luego los primeros dos métodos (geisler y orozco) devuelven 10 como se esperaba, mientras machin devuelve 0 – epeleg

12

Ésta es una respuesta tardía, pero no hay una solución simple que combina los mejores aspectos de las respuestas existentes: el siguiente múltiplo de 100 desde x es x - x % -100 (o si lo prefiere, x + (-x) % 100).

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

Esto es rápido y sencillo, da resultados correctos para cualquier entero x (como la respuesta de John Machin) y también da resultados razonables-ish (módulo las advertencias habituales acerca de la representación de punto flotante) si x es un flotador (como la respuesta de Martin Geisler).

>>> x = 0.1 
>>> x -= x % -100 
>>> x 
100.0 
+0

tu solución es tan rápida como la notación de Martin es más corto Gracias. % timeit 'x = 110' 'x - = x% -100' # 100000000 bucles, mejor de 3: 9.37 ns por ciclo VS % timeit 'x = 110' 'x + 100 * (x% 100> 0) - x% 100 ' # 100000000 bucles, lo mejor de 3: 9.38 ns por ciclo – tagoma

1

Prueba esto: el uso

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 

muestra:

>>> ceilm(257,5) 
260 
>>> ceilm(260,5) 
260 
0

Advertencia: optimizaciones prematuros por delante ...

Dado que muchas de las respuestas aquí hacer la sincronización de esto quería agregar otra alternativa.

Tomando @ Martin Geisler 's

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

(que me gusta mejor por varias razones)

pero factorizar la acción%

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

produce una mejora de la velocidad ~ 20% sobre el original

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

Es aún mejor y es ~ 36% más rápido que el original

finalmente estaba pensando que podía dejar caer el operador not y cambiar el orden de las ramas esperando que esto también aumentara la velocidad pero me desconcerté al descubrir que en realidad, es más lento y cae solo un 23% más rápido que el original.

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 

explicaciones sobre por qué 3 es más rápido que 4 sería muy bienvenido.

Cuestiones relacionadas