¿Cómo redondeas un número en Python?


487

Este problema me está matando. ¿Cómo se acumula un número UP en Python?

Intenté redondear (número) pero redondeó el número hacia abajo. Ejemplo:

round(2.3) = 2.0 and not 3, what I would like

¡Intenté int (número + .5) pero redondea el número nuevamente! Ejemplo:

int(2.3 + .5) = 2

Luego intenté round (número + .5) pero no funcionará en casos extremos. Ejemplo:

WAIT! THIS WORKED!

Por favor avise.


44
round(number + .5)no funciona si el número es entero. round(3+.5) == 4, cuando realmente quieres 3.
Nearoo

Respuestas:


846

El ceil función (techo):

import math
print(math.ceil(4.2))

21
Elaboración: math.ceil devuelve el entero más pequeño que es mayor o igual que el valor de entrada. Esta función trata la entrada como flotante (Python no tiene variables fuertemente tipadas) y la función devuelve un flotante. Si desea un int, puede construir un int a partir del valor de retorno, es decir,int(math.ceil(363))
RW Sinnet

99
@Sinnet: En realidad, se podría decir que Python está fuertemente tipado stackoverflow.com/a/11328980/5069869
Bernhard el

1
@TheEspinosa: Sí, python definitivamente está fuertemente tipado, es solo que muchas funciones hacen preguntas sobre el tipo de algunos parámetros y ejecutan diferentes códigos dependiendo de la respuesta.
quamrana

12
@RWSinnet En Python 3, math.ceildevuelve un objeto entero real, no solo un objeto flotante con valor entero.
Arthur Tacca

Tenga cuidado con la precisión del flotador, ya que el 10000000 * 0.00136 = 13600.000000000002techo puede aumentar muchomath.ceil(10000000 * 0.00136) = 13601.0
calle

171

Sé que esta respuesta es para una pregunta de hace un tiempo, pero si no quieres importar matemáticas y solo quieres redondear, esto funciona para mí.

>>> int(21 / 5)
4
>>> int(21 / 5) + (21 % 5 > 0)
5

La primera parte se convierte en 4 y la segunda parte se evalúa como "Verdadero" si hay un resto, que además es Verdadero = 1; False = 0. Entonces, si no hay resto, entonces permanece el mismo número entero, pero si hay un resto agrega 1.


38
Agradable. También puede usar //para la división de enteros, por lo que esto se convierte 21 // 5 + (21 % 5 > 0).
naught101

66
Esta es la mejor solución si solo están involucrados los enteros. No innecesario floats. Agradable.
Nico Schlömer

158

Interesante tema de Python 2.x a tener en cuenta:

>>> import math
>>> math.ceil(4500/1000)
4.0
>>> math.ceil(4500/1000.0)
5.0

El problema es que dividir dos entradas en python produce otro int y se trunca antes de la llamada al techo. Tienes que hacer que un valor sea flotante (o lanzado) para obtener un resultado correcto.

En javascript, el mismo código exacto produce un resultado diferente:

console.log(Math.ceil(4500/1000));
5

44
En Python 2.x : int / int -> int e int / float -> float En Python 3.x : int / int puede resultar en un float
gecco

77
puede obtener el comportamiento de Python 3.x en ciertas versiones de Python 2.x habilitando la "división verdadera" como se muestra aquí
Rob Dennis

110

Si trabaja con números enteros, una forma de redondear es aprovechar el hecho de que se //redondea hacia abajo: simplemente haga la división en el número negativo y luego niegue la respuesta. No se necesita importación, coma flotante ni condicional.

rounded_up = -(-numerator // denominator)

Por ejemplo:

>>> print(-(-101 // 5))
21

1
¿Qué pasa cuando no necesitas realizar ninguna operación matemática? Es decir, solo tienes un número.
Klik

2
@Klik: entonces puedes dividir entre 1 ==> - (-num // 1) y obtendrás tu respuesta :-) ¡Que tengas un buen día! David Bau: muy buena propuesta!
Marco smdm

10
Calculé todas las respuestas aquí y esto fue cinco veces más rápido que el siguiente mejor (math.ceil). @Andreas tuvo el mismo tiempo
mini totent

@minitotent Eso no es sorprendente, ya que es una división entera simple y un par de operaciones de ciclo único. Este es el tipo de respuesta que le da trabajo: comprender no solo el lenguaje, sino todas las capas de abstracciones que hay debajo.
Nearoo

¡Agradable! Siempre he usado (num + den - 1) // den, lo cual está bien para intentradas con denominadores positivos, pero falla si incluso floatestá involucrado un solo no integral (numerador o denominador); Esto tiene un aspecto más mágico, pero funciona tanto para ints como para floats. Para numeradores pequeños, también es más rápido (en CPython 3.7.2), aunque curiosamente, cuando solo el numerador es lo suficientemente grande como para que se necesiten matemáticas basadas en matrices, su enfoque es más lento; No está claro por qué esto es así, ya que el trabajo de división debería ser similar y dos negaciones unitarias deberían ser más baratas que la suma + resta.
ShadowRanger

56

También te puede interesar numpy:

>>> import numpy as np
>>> np.ceil(2.3)
3.0

No digo que sea mejor que las matemáticas, pero si ya estabas usando numpy para otros fines, puedes mantener tu código consistente.

De todos modos, solo un detalle que encontré. Uso mucho numpy y me sorprendió que no se mencionara, pero, por supuesto, la respuesta aceptada funciona perfectamente bien.


3
Usar numpy también es bueno. Lo más fácil sería con las matemáticas ya que ya es parte de Python integrado en las bibliotecas. Tiene más sentido En cambio, como mencionó si usa mucho numpy para otros problemas, entonces tiene sentido y es consistente usar numpy.ceil :-) ¡Buena sugerencia!
Marco smdm

30

Usemath.ceil para redondear:

>>> import math
>>> math.ceil(5.4)
6.0

NOTA : La entrada debe ser flotante.

Si necesita un número entero, llame intpara convertirlo:

>>> int(math.ceil(5.4))
6

Por cierto, use math.floorpara redondear hacia abajo y roundpara redondear al entero más cercano.

>>> math.floor(4.4), math.floor(4.5), math.floor(5.4), math.floor(5.5)
(4.0, 4.0, 5.0, 5.0)
>>> round(4.4), round(4.5), round(5.4), round(5.5)
(4.0, 5.0, 5.0, 6.0)
>>> math.ceil(4.4), math.ceil(4.5), math.ceil(5.4), math.ceil(5.5)
(5.0, 5.0, 6.0, 6.0)

1
La entrada no necesariamente tiene que ser flotante si se usa Python 3: ceil() se encargará de ello internamente
guival


11

Me sorprende que nadie sugirió

(numerator + denominator - 1) // denominator

para división entera con redondeo. Solía ​​ser la forma común de C / C ++ / CUDA (cf. divup)


2
Relevante solo para idiomas tipados estáticamente. Si el denominador es un flotador, estás muerto.
Bharel

Esto también solo funciona de manera consistente si el denominador es positivo; Si el denominador es negativo, debe sumar en 1lugar de restarlo, o cambiar los signos de numerador y denominador antes de realizar las matemáticas.
ShadowRanger

7

El valor redondeado debe ser flotante

a = 8 
b = 21
print math.ceil(a / b)
>>> 0

pero

print math.ceil(float(a) / b)
>>> 1.0

6

Prueba esto:

a = 211.0
print(int(a) + ((int(a) - a) != 0))

1
Inteligente. La ((int(a) - a) != 0)expresión vuelve 1siempre que sea anecesario redondearla. Es posible que desee ampliar su respuesta y explicar cómo funciona esto.
Tom Aranda

@TomAranda ¿Alguien puede explicar cómo una expresión booleana se evalúa como un valor, por favor?
Bowen Liu

6
>>> def roundup(number):
...     return round(number+.5)
>>> roundup(2.3)
3
>>> roundup(19.00000000001)
20

Esta función no requiere módulos.


¿Qué pasa si su número es 3, entonces sería redondear hasta 4que puede o no ser lo que alguien quiere
buydadip

15
Esto solo funciona en el 99% de todos los casos. No pensaste esto correctamente. Tales soluciones deben evitarse a toda costa.
Nearoo

así que en lugar de +.5 do + .49999999 lo suficientemente bueno para mí.
FlyingZebra1

5

Las respuestas anteriores son correctas, sin embargo, importar el mathmódulo solo para esta función generalmente me parece un poco exagerado. Afortunadamente, hay otra forma de hacerlo:

g = 7/5
g = int(g) + (not g.is_integer())

Truey Falsese interpretan como 1y 0en una declaración que involucra números en python. g.is_interger()Básicamente se traduce como g.has_no_decimal()o g == int(g). Entonces se lee la última declaración en inglés round g down and add one if g has decimal.


1
Y si te apetece, puedes usarlo int(g) + (g % 1 > 0)en su lugar ;-)
Nearoo

from math import ceilparece solucionar la importación del módulo matemático completo :)
SH7890

@ SH7890 Me temo que esa línea no es muy diferente import mathen términos de lo que sucede detrás de escena. Simplemente deja caer todos los símbolos excepto ceil.
Nearoo

5

Sin importar matemáticas // usando el entorno básico:

a) método / método de clase

def ceil(fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

def ceil(self, fl): 
  return int(fl) + (1 if fl-int(fl) else 0)

b) lambda:

ceil = lambda fl:int(fl)+(1 if fl-int(fl) else 0)

5

Para aquellos que quieren redondear a / b y obtener un número entero:

Otra variante que usa la división de enteros es

def int_ceil(a, b):
    return (a - 1) // b + 1

>>> int_ceil(19, 5)
4
>>> int_ceil(20, 5)
4
>>> int_ceil(21, 5)
5

3

En caso de que alguien esté buscando redondear a un lugar decimal específico:

import math
def round_up(n, decimals=0):
    multiplier = 10 ** decimals
    return math.ceil(n * multiplier) / multiplier

1

Me sorprende no haber visto esta respuesta todavía round(x + 0.4999), así que la voy a dejar. Tenga en cuenta que esto funciona con cualquier versión de Python. Los cambios realizados en el esquema de redondeo de Python han dificultado las cosas. Ver esta publicación .

Sin importar, uso:

def roundUp(num):
    return round(num + 0.49)

testCases = list(x*0.1 for x in range(0, 50))

print(testCases)
for test in testCases:
    print("{:5.2f}  -> {:5.2f}".format(test, roundUp(test)))

Por que esto funciona

De los documentos

Para los tipos integrados que admiten round (), los valores se redondean al múltiplo más cercano de 10 a la potencia menos n; si dos múltiplos están igualmente cerca, el redondeo se realiza hacia la opción pareja

Por lo tanto, 2.5 se redondea a 2 y 3.5 se redondea a 4. Si este no fuera el caso, entonces se podría redondear agregando 0.5, pero queremos evitar llegar al punto medio. Entonces, si agrega 0.4999, se acercará, pero con un margen suficiente para redondear a lo que normalmente esperaría. Por supuesto, esto fallará si x + 0.4999es igual a [n].5000, pero eso es poco probable.


2
Usando 0.4999, no dará un resultado correcto para cualquier entrada entre ???. 0000 y ???. 0001 (intervalo abierto), no solo exactamente ???. 0001. Por ejemplo, si lo prueba con 3.00005, obtendrá un resultado de 3 en lugar del esperado 4. Por supuesto, puede disminuir la probabilidad de que esto suceda agregando más y más dígitos hasta la máxima precisión de flotadores, pero ¿cuál es el señale eso si hay soluciones más robustas e intuitivas disponibles, como usar math.ceil()?
blubberdiblub

@blubberdiblub En mi respuesta, afirmo Without importing I use:. También he mencionado que fallará si x + 0.4999es igual a [n].5000.
Klik

44
Sí, usted declara en su respuesta que su solución es sin importar, pero no veo su valor. El mathmódulo y math.ceil()está en la biblioteca estándar, por lo que está disponible en todas partes para todos los fines prácticos sin instalar material adicional. Y con respecto a su mención de cuándo falla, esto está incompleto en su respuesta, ya que falla durante un intervalo completo, no solo por un solo punto. Técnicamente, podría argumentar que está en lo correcto, como dice si y no si , pero causará la impresión en el lector casual de que es menos probable de lo que realmente es.
blubberdiblub

0

Para hacerlo sin importar nada:

>>> round_up = lambda num: int(num + 1) if int(num) != num else int(num)
>>> round_up(2.0)
2
>>> round_up(2.1)
3

0

Sé que esto fue hace bastante tiempo, pero encontré una respuesta bastante interesante, así que aquí va:

-round(-x-0.5)

Esto soluciona los casos de bordes y funciona tanto para números positivos como negativos, y no requiere ninguna función de importación

Salud


2
Esto todavía redondeará-round(-x-0.3) = x
Diblo Dk

0

cuando opera 4500/1000 en python, el resultado será 4, porque para python predeterminado se asume como entero el resultado, lógicamente: 4500/1000 = 4.5 -> int (4.5) = 4 y el límite de 4 obviamente es 4

usando 4500 / 1000.0, el resultado será 4.5 y un techo de 4.5 -> 5

Al usar JavaScript, recibirá 4.5 como resultado de 4500/1000, porque JavaScript solo asume el resultado como "tipo numérico" y devuelve un resultado directamente como flotante

¡¡Buena suerte!!


Eso solo es cierto en Python 2.x. En Python 3, la división con un solo /siempre resulta en un flotante, por 4500/1000lo que siempre es 4.5.
Nearoo

0

Si no desea importar nada, siempre puede escribir su propia función simple como:

def RoundUP(num): if num== int(num): return num return int(num + 1)


2
Esto no funciona si num es 2.05. Debe tener al menos tantos dígitos con un 9 como su entrada, dejándolo con un 0.999 ... que es 1. Pero luego su caso de esquina 2 se redondea nuevamente. - Bueno, supongo que hay una razón por la cual Math.ceil está ahí.
Johannes Maria Frank

-1

Puede usar el diseño del piso y agregarle 1. 2,3 // 2 + 1


2
o usar en ceil()lugar de hacer extrañamente lo contrario y luego compensar
Guival

2
Esto no funcionara. Por ejemplo:from math import ceil; assert 4 // 2 + 1 == ceil(4 / 2)
Carl Thomé

-1

Creo que estás confundiendo los mecanismos de trabajo entre int()y round().

int()siempre trunca los números decimales si se da un número flotante; mientras que round(), en el caso de 2.5dónde 2y 3ambos están a la misma distancia 2.5, Python devuelve el que esté más alejado del punto 0.

round(2.5) = 3
int(2.5) = 2

"redondear" significa que, por ejemplo, 2.3se convierte en 3, lo que sucede en ninguno de sus ejemplos.
Nearoo

-2

Mi parte

He probado print(-(-101 // 5)) = 21 ejemplo anterior.

Ahora para redondear:

101 * 19% = 19.19

No puedo usar, **así que extendí la multiplicación a la división:

(-(-101 //(1/0.19))) = 20

-3

Básicamente soy un principiante en Python, pero si solo estás intentando redondear en lugar de bajar, ¿por qué no hacerlo?

round(integer) + 1

2
Esto no funcionará para ningún entero i donde 2.5 <entero <3. El valor deseado después de redondear es 3, pero su expresión lo convertirá en 4.
Pranav Shukla

1
Creo que te refieres a que round(integer + 0.5)esto es lo que hago a menudo
Klik
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.