Redondea el número al entero más cercano

230

He estado tratando de redondear números flotantes largos como:

32.268907563;
32.268907563;
31.2396694215;
33.6206896552;
...

Sin éxito hasta ahora. Lo intenté math.ceil(x), math.floor(x)(aunque eso se redondearía hacia arriba o hacia abajo, que no es lo que estoy buscando) y round(x)que tampoco funcionó (todavía números flotantes).

¿Qué puedo hacer?

EDITAR: CÓDIGO:

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
fuente
3
Lo intentaríaint(x)
The Brofessor
¿eso no daría error? literal no válido para int () con base 10:
snh_nl

Respuestas:

366
int(round(x))

Lo redondeará y lo cambiará a entero

EDITAR:

No está asignando int (round (h)) a ninguna variable. Cuando llama a int (round (h)), devuelve el número entero pero no hace nada más; tienes que cambiar esa línea por:

h = int(round(h))

Para asignar el nuevo valor a h

EDITAR 2:

Como @plowman dijo en los comentarios, Python round()no funciona como uno esperaría normalmente, y eso se debe a que la forma en que se almacena el número como variable generalmente no es la forma en que lo ves en la pantalla. Hay muchas respuestas que explican este comportamiento:

round () no parece estar redondeando correctamente

Una forma de evitar este problema es usar el decimal como se indica en esta respuesta: https://stackoverflow.com/a/15398691/4345659

Para que esta respuesta funcione correctamente sin usar bibliotecas adicionales, sería conveniente usar una función de redondeo personalizada. Después de muchas correcciones, se me ocurrió la siguiente solución, que por lo que probé evitó todos los problemas de almacenamiento. Se basa en el uso de la representación de cadena, obtenida con repr()( str()¡ NO !). Parece hacky pero fue la única forma que encontré para resolver todos los casos. Funciona con Python2 y 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])

Pruebas:

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

Finalmente, la respuesta corregida sería:

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

EDITAR 3:

Pruebas:

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

El problema aquí es que el decenésimo decimal puede ser 9 y si el dec+1enésimo dígito> = 5, el 9 se convertirá en un 0 y un 1 debería llevarse al dec-1enésimo dígito.

Si tomamos esto en consideración, obtenemos:

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

En la situación descrita anteriormente b = 10y la versión anterior sería simplemente concatenar ay bque daría lugar a una concatenación de 10donde el 0 se arrastra desaparecería. Esta versión se transforma ben el lugar decimal correcto basado en dec, como un acarreo adecuado.

francisco sollima
fuente
2
print ("4.5)", int (round (4.5))) # me dio 4 print ("5.5)", int (round (5.5))) # me dio 6:, (
Komm
Está relacionado con la versión de Python. Me da 5 y 6 usando Python 2.7.9 y, como dijiste, 4 y 6 usando Python 3.4.2
francisco sollima
1
Vale la pena señalar: esta solución no se redondea de la manera que probablemente espera. Por ejemplo, int(round(4.5))redondea a 4 mientras que int(round(4.500001))redondea correctamente a 5.
labrador
Si quiere un número entero, entonces round(x)es suficiente en Python 3.6.2 (y quizás también en versiones inferiores). El resultado ya es de tipo int. Nota: round(x, n)será de tipo flotante.
Elmex80s
1
Esto no funciona para 112439.50093565206. Da o / p -> 11253.0. Maldita sea raro .. !!!!
ajin
24

Uso round(x, y). Redondeará su número al lugar decimal deseado.

Por ejemplo:

>>> round(32.268907563, 3)
32.269
Satyaki Sanyal
fuente
20

round(value,significantDigit)es la solución ordinaria, sin embargo, esto no funciona como cabría esperar desde una perspectiva matemática cuando los valores redondos terminan en 5. Si el 5está en el dígito justo después del que se redondea, estos valores solo se redondean a veces como se esperaba (es decir, se 8.005redondea a dos dígitos decimales 8.01). Para ciertos valores debido a las peculiaridades de las matemáticas de coma flotante, ¡se redondean hacia abajo!

es decir

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

Extraño.

Suponiendo que su intención es hacer el redondeo tradicional para las estadísticas en las ciencias, este es un útil contenedor para que la roundfunción funcione como se espera y necesita importcosas adicionales como Decimal.

>>> round(0.075,2)

0.07

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

0.08

¡Ajá! Entonces, en base a esto, podemos hacer una función ...

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

Básicamente, esto agrega un valor garantizado para ser más pequeño que el dígito menos dado de la cadena que está tratando de usar round. Al agregar esa pequeña cantidad, preserva el roundcomportamiento de la mayoría de los casos, al tiempo que garantiza que el dígito inferior al redondeado se redondea hacia 5arriba y, si es así, 4se redondea hacia abajo.

El enfoque de uso 10**(-len(val)-1)fue deliberado, ya que es el número pequeño más grande que puede agregar para forzar el cambio, al tiempo que garantiza que el valor que agregue nunca cambie el redondeo, incluso si .falta el decimal . Podría usar solo 10**(-len(val))con una condición if (val>1)para restar 1más ... pero es más simple restar siempre, 1ya que eso no cambiará mucho el rango aplicable de números decimales que esta solución puede manejar adecuadamente. Este enfoque fallará si sus valores alcanzan los límites del tipo, esto fallará, pero para casi todo el rango de valores decimales válidos debería funcionar.

También puede usar la biblioteca decimal para lograr esto, pero el contenedor que propongo es más simple y puede preferirse en algunos casos.


Editar: Gracias Blckknght por señalar que el 5caso marginal se produce solo para ciertos valores. Además, una versión anterior de esta respuesta no fue lo suficientemente explícita como para que el comportamiento de redondeo impar ocurra solo cuando el dígito inmediatamente inferior al dígito al que está redondeando tiene un5 .

Jason R. Mick
fuente
No estoy seguro de por qué crees que los decimales 5como su último dígito siempre se redondearán hacia abajo. Ese no es el caso en una prueba rápida que acabo de hacer con números como 1.5, 2.5, 3.5y así sucesivamente y 1.05, 1.15, 1.25, 1.35redondeando a un decimal. El primer conjunto (mitades exactas redondeando a enteros pequeños) siempre se redondea a un entero par. El último conjunto no se redondea consistentemente, probablemente debido a representaciones binarias inexactas de algunos de los valores. Los flotadores que tienen representaciones binarias exactas como 1.25redondear tienen un dígito aún menos significativo, pero los otros parecen redondearse al azar.
Blckknght
Interesante ... tienes razón. round(4.0005,3)da 4.0y round(1.0005,3)da 1.0, pero round(2.0005,3)da 2.001y round(3.0005,3)da 3.001. Pero es precisamente por eso que mi solución propuesta es necesaria ... ¡no sabes qué esperar de la ronda de acciones, en este caso significativo!
Jason R. Mick
Gracias por esto. Su función será útil cuando surja este problema.
TMWP
1
¿Querías tener , digitsal final de esa declaración de devolución? Sin juego de palabras. ( Quiero decir, quiero decir)
user3342816
Ah correcto, de hecho eso debería haber estado allí. Buena captura ... ¡sorprendido de que nadie más lo haya notado! Ahorrará cierta frustración a quienes utilizan la solución. :-)
Jason R. Mick
15

Para aspectos positivos, intente

int(x + 0.5)

Para que funcione también para los negativos, intente

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

int()funciona como una función de piso y, por lo tanto, puede explotar esta propiedad. Esta es definitivamente la forma más rápida.

Confundir
fuente
44
no funciona para negativos>>> x=-0.999 >>> int(x), round(x), int(x+0.5) (0, -1.0, 0)
user2907934
3
Si le interesan las vitrinas de esquina, no use la técnica de "agregar 0.5 y piso", ¡hay algunos valores que pueden no redondearse de la forma esperada! Consulte stackoverflow.com/a/47302585/2732969 para obtener una versión de C ++ y la respuesta stackoverflow.com/a/38744026/2732969 en esta misma pregunta.
Anon
Necesitaba un método rápido, no tenía que ser preciso y no tendría muchos casos de esquina, y el error en los casos de esquina no es importante en mi escenario. Así que este es definitivamente mi destino para algunos casos especiales donde la velocidad es prioridad. No lo recomiendo por precisión o exactitud.
AgentM
11

¿No solo Python está haciendo la mitad de la ronda , como lo prescribe IEEE 754 ?

Tenga cuidado al redefinir, o al usar el redondeo "no estándar" ...

(Ver también https://stackoverflow.com/a/33019948/109839 )

Mapio
fuente
2
Esta respuesta es un poco confusa. Round half to evenabsolutamente no está prescrito por IEEE 754, sino que es solo una de varias opciones de redondeo descritas por el estándar . Round to nearest, ties away from zero(es decir, el comportamiento que la mayoría de la gente espera) también es una opción, y es el predeterminado en, por ejemplo, C / C ++.
Tel
Estoy de acuerdo, la redacción es bastante confusa. Lo que quise decir es que Python está redondeando a la mitad (vea la tabla al final de docs.python.org/3.7/library/… donde roundse explica) y lo hace de acuerdo con la forma en que se prescribe "redondear a la mitad para igualar" para trabajar (o descrito) por el estándar.
Mapio
8

También puede usar numpy asumiendo si está usando python3.x aquí hay un ejemplo

import numpy as np
x = 2.3
print(np.rint(x))
>>> 2.0
sushmit
fuente
7

Su solución es llamar sin especificar el segundo argumento (número de decimales)

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

que es un resultado mucho mejor que

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

De la documentación de Python en https://docs.python.org/3/library/functions.html#round

ronda (número [, ndigits])

Número de retorno redondeado a ndigits de precisión después del punto decimal. Si se omite ndigits o es None, devuelve el entero más cercano a su entrada.

Nota

El comportamiento de round () para flotadores puede ser sorprendente: por ejemplo, round (2.675, 2) da 2.67 en lugar del esperado 2.68. Esto no es un error: es el resultado del hecho de que la mayoría de las fracciones decimales no se pueden representar exactamente como un flotante. Consulte Aritmética de coma flotante: problemas y limitaciones para obtener más información.

Arrendajo
fuente
1

Si necesita (por ejemplo) una aproximación de dos dígitos para A, entonces int(A*100+0.5)/100.0hará lo que está buscando.

Si necesita una aproximación de tres dígitos, multiplique y divida por 1000 y así sucesivamente.

Hoo
fuente
1

Algo como esto también debería funcionar

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

Para este propósito, sugeriría hacer lo siguiente:

int(round(x))

Esto te dará el entero más cercano.

¡¡Espero que esto ayude!!

rahul ranjan
fuente
0

Utilizo y puedo recomendar la siguiente solución (python3.6):

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

Funciona bien para números medios (positivos y negativos) y funciona incluso más rápido que 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
===========
Василий Прядченко
fuente