Quiero a
ser redondeado a 13.95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
La round
función no funciona como esperaba.
Quiero a
ser redondeado a 13.95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
La round
función no funciona como esperaba.
Respuestas:
Se encuentra con el viejo problema con los números de coma flotante que no todos los números pueden representarse exactamente. La línea de comando solo le muestra el formulario de coma flotante completo de la memoria.
Con la representación de coma flotante, su versión redondeada es el mismo número. Dado que las computadoras son binarias, almacenan números de coma flotante como un número entero y luego lo dividen por una potencia de dos para que 13.95 se represente de manera similar a 125650429603636838 / (2 ** 53).
Los números de doble precisión tienen 53 bits (16 dígitos) de precisión y los flotantes regulares tienen 24 bits (8 dígitos) de precisión. El tipo de coma flotante en Python usa 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("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999
Si solo busca dos decimales (para mostrar un valor de moneda, por ejemplo), entonces tiene un par de opciones mejores:
"%.2f" % round(a,2)
puede incluir no solo en printf, sino también en cosas comostr()
float
) es solo la aproximación más cercana disponible del número decimal (con el que está familiarizado como ser humano). No existe tal valor binario (finitamente representable) como 0.245. Simplemente no existe, y matemáticamente no puede existir. El valor binario más cercano a 0.245 es ligeramente menor que 0.245, por lo que naturalmente se redondea hacia abajo. Del mismo modo, no existe el valor 0.225 en binario, pero el valor binario más cercano a 0.225 es ligeramente mayor que 0.225, por lo que naturalmente se redondea.
Decimal
, usar , y esa fue una de las soluciones presentadas en esta respuesta. El otro era convertir sus cantidades a enteros y usar aritmética de enteros. Ambos enfoques también aparecieron en otras respuestas y comentarios.
Hay nuevas especificaciones de formato, Mini-Idioma de especificación de formato de cadena :
Puedes hacer lo mismo que:
"{:.2f}".format(13.949999999999999)
Nota 1: lo anterior devuelve una cadena. Para obtener el flotador, simplemente envuelva con float(...)
:
float("{:.2f}".format(13.949999999999999))
Nota 2: envolver con float()
no cambia nada:
>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
'{0:,.2f}'.format(1333.949999999)
que imprime '1,333.95'
.
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
El incorporado round()
funciona bien en Python 2.7 o posterior.
Ejemplo:
>>> round(14.22222223, 2)
14.22
Echa un vistazo a la documentación .
round(2.16, 1)
dará 2.2
por qué pitón sólo ofrece una truncate
func
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
Siento que el enfoque más simple es usar la format()
función.
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 vez de
print"{0:.2f}".format(a)
Debido a que esto último puede generar errores de salida al intentar generar múltiples variables (ver comentarios).
La mayoría de los números no pueden representarse exactamente en carrozas. Si desea redondear el número porque eso es lo que requiere su fórmula matemática o algoritmo, entonces desea usar redondear. Si solo desea restringir la visualización a una cierta precisión, 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 matemáticas exactas , entonces no quieres flotadores en absoluto. El ejemplo habitual es tratar con dinero y almacenar 'centavos' como un número entero.
Prueba 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
round
función en primer lugar. Por otro lado, debido a que esta solución todavía usa coma flotante, el problema original del OP permanece, incluso para la versión "corregida" de esta "solución".
round
función (que se utilizó en la pregunta).
round()
no funciona como el OP mencionado.
El problema de redondeo de entrada / salida ha sido resuelto definitivamente por Python 2.7.0 y 3.1 .
Un número correctamente redondeado puede convertirse reversiblemente de un lado a otro:
str -> float() -> repr() -> float() ...
o Decimal -> float -> str -> Decimal
Un tipo decimal ya no es necesario para el almacenamiento.
(Naturalmente, puede ser necesario redondear un resultado de la suma o resta de números redondeados para eliminar los errores acumulados del último bit. Una aritmética decimal explícita puede ser útil, pero una conversión a cadena por str()
(es decir, redondeando a 12 dígitos válidos) ) es lo suficientemente bueno generalmente si no se requiere una precisión extrema o no se requiere un número extremo de operaciones aritméticas sucesivas).
Prueba infinita :
import random
from decimal import Decimal
for x in iter(random.random, None): # Verify FOREVER that rounding is fixed :-)
assert float(repr(x)) == x # Reversible repr() conversion.
assert float(Decimal(repr(x))) == x
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 a supermaket with Python 2.7+ :-)
Consulte las notas de la versión Python 2.7 - Otros cambios de idioma en 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 flotantes y números complejos; el flotador y los constructores complejos; formato numérico; serializar y de-serializar los flotadores y los números complejos utilizando los
marshal
,pickle
yjson
módulos; análisis de flotantes y literales imaginarios en código Python; y conversión de decimal a flotante.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 que redondea a x bajo el redondeo correcto (con el modo de redondeo de redondeo a medio redondeo). Anteriormente daba una cadena basada en redondear x a 17 dígitos decimales.
Más información: El formato float
anterior a Python 2.7 era similar al actual numpy.float64
. Ambos tipos usan la misma precisión doble IEEE 754 de 64 bits con 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 pueda perder 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 con numpy. Por otra parte:float.__repr__
está formateado para que cada dígito sea importante; la secuencia no tiene espacios y la conversión es reversible. Simplemente: si tal vez tiene un número numpy.float64, conviértalo a flotante normal para formatearlo para humanos, no para procesadores numéricos, de lo contrario, no se necesita nada más con Python 2.7+.
float
(doble precisión) y normal round
, no sobre numpy.double y su conversión a cadena. El redondeo simple de Python realmente no se puede hacer mejor que en Python 2.7. La mayoría de las respuestas se han escrito antes de 2.7, pero están obsoletas, aunque originalmente eran muy buenas. Esta es la razón de mi respuesta.
1
, excepto durante el "desbordamiento gradual".
a*b
vs b*a
. Gracias por los enlaces - Nostalgia.
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 anteriores a 3 (por ejemplo, 3.2 o 3.3), se prefiere la opción dos .
Para obtener más información sobre la opción dos, sugiero este enlace sobre el formato de cadenas de la documentación de Python .
Y para obtener más información sobre la opción uno, este enlace será suficiente y tiene información sobre los distintos indicadores .
Referencia: Convierta el número de coma flotante con cierta precisión y luego cópielo en una cadena
numvar=12.456
, entonces "{:.2f}".format(numvar)
cede 12.46
pero "{:2i}".format(numvar)
da un error y estoy esperando 12
.
Puede modificar el formato de salida:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Nadie parece haberlo mencionado todavía, así que permítanme dar un ejemplo en el formato f-string / template-string de Python 3.6, que creo que está muy bien:
>>> f'{a:.2f}'
Funciona bien con ejemplos más largos también, con operadores y que no necesitan parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
Puede usar el operador de formato para redondear el valor hasta 2 decimales en python:
print(format(14.4499923, '.2f')) // output is 14.45
En Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
tiene exactamente el mismo valor que a
, por lo que bien podría haber escrito en print a
lugar de print output
en la última línea.
13.95
. Pero también lo hace print a
, para este valor particular de a
, en Python 2.7, por lo que no está realmente claro cuál era el punto del paso de formateo.
a == output
el código que muestras? Da True
por mí, y sospecho que también por ti.
El tutorial de Python tiene un apéndice llamado Aritmética de coma flotante: problemas y limitaciones . Léelo Explica qué 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
Es posible que sienta la tentación de utilizar la
round()
función para volver a cortarla en el único dígito que espera. Pero eso no hace ninguna diferencia:>>> round(0.1, 1) 0.10000000000000001
El problema es que el valor de punto flotante binario almacenado
“0.1”
ya era la mejor aproximación binaria posible1/10
, por lo que intentar redondearlo de nuevo no puede mejorarlo: ya era tan bueno como parece.Otra consecuencia es que, dado que
0.1
no es exactamente1/10
, sumar diez valores de0.1
puede no rendir exactamente1.0
, tampoco:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Una alternativa y solución a sus problemas sería usar el decimal
módulo.
Como señaló @Matt, Python 3.6 proporciona cadenas f , y también pueden usar parámetros anidados :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
que mostrará result: 2.35
Está haciendo exactamente lo que le dijo que hiciera y funciona correctamente. Lea más sobre la confusión de coma flotante y quizás intente con objetos decimales .
Use la combinación del objeto Decimal y el método round ().
Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
Para arreglar 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 puede usar Decimal de la siguiente manera:
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')
getcontext().prec = 6
funciona solo para el alcance de la función o para todos los lugares?
from decimal import Decimal
def round_float(v, ndigits=2, rt_str=False):
d = Decimal(v)
v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
if rt_str:
return v_str
return Decimal(v_str)
Resultados:
Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
¿Qué pasa con una función lambda como esta:
arred = lambda x,n : x*(10**n)//1/(10**n)
De esta manera, podrías hacer:
arred(3.141591657,2)
y obten
3.14
Es simple como 1,2,3:
usar decimal módulo para la aritmética rápida de coma flotante decimal correctamente redondeada:
d = Decimal (10000000.0000009)
para lograr el redondeo:
d.quantize(Decimal('0.01'))
será resultados con Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
O
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PD: crítica de los demás: el formateo no es redondeado.
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
numpy.round
precisión / precisión. Por lo tanto, requiere definirlo como int antes de la multiplicación con resolución. Actualicé el código. ¡Gracias por eso!
numpy.float64
resultado de np.round ao float
simplemente usarlo round(value, 2)
. No existe un número IEEE 754 válido entre 13.94999999999999999 (= 1395 / 100.) y 3.950000000000001 (= 1395 * .01). ¿Por qué crees que tu método es el mejor? El valor original 13.949999999999999289 (= value = round (value, 2)) es aún más exacto que su 13.95000000000000178 (impreso por np.float96). Ahora se agrega más información también para numpy a mi respuesta que probablemente desestimó su voto por error. No se trataba de numpy originalmente.
int
ti también puedes usar el float
ejemplo @szeitlin. Gracias por tu comentario extra. (Lo siento pero no te
El método que uso es el de corte de cadenas. Es relativamente rápido y simple.
Primero, convierta el flotador en una cadena, luego elija la longitud que le gustaría que fuera.
float = str(float)[:5]
En la única línea de arriba, convertimos el valor en una cadena, luego mantuvimos la cadena solo en sus primeros cuatro dígitos o caracteres (inclusive).
¡Espero que ayude!