redondear - truncar a 2 decimales python
Limitar los flotantes a dos puntos decimales (19)
Quiero que sea redondeado a 13.95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
La función round
no funciona como esperaba.
TLDR;)
El problema de redondeo en la entrada / salida se resolvió mediante Python 2.7.0 y 3.1 definitivamente.
Prueba infinita:
import random
for x in iter(random.random, None): # Verify FOREVER that rounding is fixed :-)
assert float(repr(x)) == x # Reversible repr() conversion.
assert len(repr(round(x, 10))) <= 12 # Smart decimal places in repr() after round.
if x >= 0.1: # Implicit rounding to 12 significant digits
assert str(x) == repr(round(x, 12)) # by str() is good enough for small errors.
y = 1000 * x # Decimal type is excessive for shopping
assert str(y) == repr(round(y, 12 - 3)) # in the supermaket with Python 2.7+ :-)
Documentación
Consulte las Notas de la versión Python 2.7 - Otros idiomas cambia el cuarto párrafo:
Las conversiones entre números de punto flotante y cadenas ahora se redondean correctamente en la mayoría de las plataformas. Estas conversiones ocurren en muchos lugares diferentes: str () en flotadores y números complejos; Los constructores de flotadores y complejos; formateo numérico; serialización y deserialización de flotadores y números complejos utilizando los módulos
marshal
,pickle
yjson
; análisis de literales flotantes e imaginarios en código Python; y conversión de decimal a flotación.En relación con esto, el repr () de un número de coma flotante x ahora devuelve un resultado basado en la cadena decimal más corta que se garantiza redondear de nuevo a x en el redondeo correcto (con el modo de redondeo de la mitad a la mitad). Anteriormente, daba una cadena basada en el redondeo de x a 17 dígitos decimales.
Más información:: el formato de float
antes de Python 2.7 era similar al número actual. Ambos tipos utilizan la misma doble precisión IEEE 754 de 64 bits con una mantisa de 52 bits. Una gran diferencia es que np.float64.__repr__
se formatea con frecuencia con un número decimal excesivo para que no se pierda ningún bit, pero no existe un número IEEE 754 válido entre 13.949999999999999 y 13.950000000000001. El resultado no es bueno y la conversión repr(float(number_as_string))
no es reversible. Por otro lado: float.__repr__
está formateado para que cada dígito sea importante; La secuencia es sin huecos y la conversión es reversible. Simplemente: si tiene un número numpy.float64, conviértalo a flotación normal para que se formatee para humanos, no para procesadores numéricos, de lo contrario no es necesario nada más con Python 2.7+.
Como señaló @Matt, Python 3.6 proporciona f-strings , y también pueden usar parámetros anidados :
value = 2.34558
precision = 2
width = 4
print(f''result: {value:{width}.{precision}f}'')
que mostrará el result: 2.35
Con Python <3 (por ejemplo, 2.6 o 2.7), hay dos formas de hacerlo.
# Option one
older_method_string = "%.9f" % numvar
# Option two (note '':'' before the ''.9f'')
newer_method_string = "{:.9f}".format(numvar)
Pero tenga en cuenta que para las versiones de Python superiores a 3 (por ejemplo, 3.2 o 3.3), se preferred opción dos.
Para obtener más información sobre la opción dos, sugiero este enlace en el formato de cadena de la documentación de Python .
Y para obtener más información sobre la opción uno, este enlace será suficiente y contiene información sobre los distintos indicadores .
Referencia: Convierta el número de punto flotante a una cierta precisión, y luego cópielo a la cadena
El round()
integrado funciona bien en Python 2.7 o posterior.
Ejemplo:
>>> round(14.22222223, 2)
14.22
Echa un vistazo a la documentación .
El método que utilizo es el de corte de cadena. Es relativamente rápido y simple.
Primero, convierta el flotador en una cadena, elija la longitud que desea que sea.
float = str(float)[:5]
En la línea única de arriba, hemos convertido el valor en una cadena, luego conservamos la cadena solo en sus primeros cuatro dígitos o caracteres (inclusive).
¡Espero que ayude!
El tutorial de Python tiene un apéndice llamado Aritmética de punto flotante: problemas y limitaciones . Leerlo Explica lo que está sucediendo y por qué Python está haciendo todo lo posible. Incluso tiene un ejemplo que coincide con el tuyo. Déjame citar un poco:
>>> 0.1 0.10000000000000001
puede tener la tentación de usar la función
round()
para recortarla al dígito que espera. Pero eso no hace ninguna diferencia:
>>> round(0.1, 1) 0.10000000000000001
El problema es que el valor binario de punto flotante almacenado para
“0.1”
ya era la mejor aproximación binaria posible a1/10
, por lo que tratar de redondearlo de nuevo no puede mejorarlo: ya era tan bueno como es.Otra consecuencia es que dado que
0.1
no es exactamente1/10
, sumar diez valores de0.1
puede no producir exactamente1.0
, ya sea:
>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Una alternativa y solución a sus problemas sería utilizar el módulo decimal
.
En Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
Está haciendo exactamente lo que le dijiste que hiciera y está funcionando correctamente. Lea más sobre la confusión de punto flotante y quizás intente objetos decimal lugar.
Hay nuevas especificaciones de formato, Mini-lenguaje de especificación de formato de cadena :
Puedes hacer lo mismo que:
"{0:.2f}".format(13.949999999999999)
Tenga en cuenta que lo anterior devuelve una cadena. Para obtener el flotador, simplemente envuélvalo con float(...)
:
float("{0:.2f}".format(13.949999999999999))
Tenga en cuenta que envolver con float()
no cambia nada:
>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{0:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
La mayoría de los números no pueden ser representados exactamente en flotadores. Si desea redondear el número porque eso es lo que requiere su fórmula matemática o algoritmo, entonces quiere usar la ronda. Si solo desea restringir la visualización a una cierta precisión, entonces ni siquiera use redondear y simplemente formatee como esa cadena. (Si desea mostrarlo con algún método de redondeo alternativo, y hay toneladas, entonces necesita mezclar los dos enfoques).
>>> "%.2f" % 3.14159
''3.14''
>>> "%.2f" % 13.9499999
''13.95''
Y, por último, aunque quizás lo más importante, si quieres cálculos exactos , entonces no quieres flotadores en absoluto. El ejemplo habitual es tratar con dinero y almacenar ''centavos'' como un entero.
Para corregir el punto flotante en lenguajes de tipo dinámico como Python y JavaScript, utilizo esta técnica
# For example:
a = 70000
b = 0.14
c = a * b
print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980
También puedes usar decimal como sigue:
from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal(''0.142857'')
getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal(''0.1428571428571428571428571429'')
Para redondear un número a una resolución, la mejor manera es la siguiente, que puede funcionar con cualquier resolución (0.01 para dos decimales o incluso otros pasos):
>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95
>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0
Parece que nadie aquí lo ha mencionado todavía, así que déjeme dar un ejemplo en el formato f-string / template-string de Python 3.6, que creo que es muy bonito:
>>> f''{a:.2f}''
También funciona bien con ejemplos más largos, con operadores y sin necesidad de parens:
>>> print(f''Completed in {time.time() - start:.2f}s'')
Pruebe el siguiente código:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
Puede modificar el formato de salida:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Se está encontrando en el problema anterior con los números de punto flotante que todos los números no pueden ser representados. La línea de comando solo muestra la forma de punto flotante completa de la memoria.
En punto flotante su versión redondeada es el mismo número. Como las computadoras son binarias, almacenan números de punto flotante como un número entero y luego lo dividen por una potencia de dos, por lo que 13.95 se representará de manera similar a 125650429603636838 / (2 ** 53).
Los números de precisión doble tienen 53 bits (16 dígitos) de precisión y los flotadores regulares tienen 24 bits (8 dígitos) de precisión. El punto flotante en Python utiliza doble precisión para almacenar los valores.
Por ejemplo,
>>> 125650429603636838/(2**53)
13.949999999999999
>>> 234042163/(2**24)
13.949999988079071
>>> a=13.946
>>> print(a)
13.946
>>> print("%.2f" % a)
13.95
>>> round(a,2)
13.949999999999999
>>> print("%.2f" % round(a,2))
13.95
>>> print("{0:.2f}".format(a))
13.95
>>> print("{0:.2f}".format(round(a,2)))
13.95
>>> print("{0:.15f}".format(round(a,2)))
13.949999999999999
Si busca solo dos lugares decimales en moneda, entonces tiene un par de mejores opciones: 1) Use números enteros y almacene valores en centavos, no en dólares y luego divida por 100 para convertir a dólares. 2) O usa un número de punto fijo como decimal .
Siento que el enfoque más simple es usar la función format()
.
Por ejemplo:
a = 13.949999999999999
format(a, ''.2f'')
13.95
Esto produce un número flotante como una cadena redondeada a dos puntos decimales.
Utilizar
print"{:.2f}".format(a)
en lugar de
print"{0:.2f}".format(a)
Debido a que esto último puede llevar a errores de salida al intentar generar múltiples variables (ver comentarios).
orig_float = 232569 / 16000.0
14.5355625
short_float = float("{:.2f}".format(orig_float))
14.54