web-dev-qa-db-esp.com

Limitar los flotantes a dos puntos decimales

Quiero que a sea redondeado a 13.95 .

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

La función round no funciona como esperaba.

1355
kevin

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 coma flotante su versión redondeada es el mismo número. Dado que 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 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("{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 use un número de punto fijo como decimal .

1368
Rex Logan

Hay nuevas especificaciones de formato, Especificación de formato de cadena Mini-Language :

Puedes hacer lo mismo que:

"{0:.2f}".format(13.949999999999999)

Nota que lo anterior devuelve una cadena. Para obtener el flotador, simplemente envuélvelo con float(...):

float("{0:.2f}".format(13.949999999999999))

Nota 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
493
Xolve

El round() incorporado funciona bien en Python 2.7 o posterior.

Ejemplo:

>>> round(14.22222223, 2)
14.22

Echa un vistazo a la documentación .

220
chribsen

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.

131
grant zukowski

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 algoritmo o fórmula matemática, entonces desea 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 exacto math entonces no quieres flotadores en absoluto. El ejemplo habitual es tratar con dinero y almacenar 'centavos' como un entero.

89
Roger Pate

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

78
Alexey Antonenko

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

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), la opción dos es preferida .

Para obtener más información sobre la opción dos, sugiero este enlace en 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 tendrá información sobre las distintas banderas .

Referencia:Convierta el número de punto flotante a una cierta precisión, y luego cópielo a la cadena

51
A.J.

Puede modificar el formato de salida:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
43
Greg Hewgill

TLDR;)

El problema de redondeo de entrada/salida ha sido resuelto definitivamente por Python 2.7.0 y 3.1.

Un número correctamente redondeado se puede convertir 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 suma o resta de números redondeados para eliminar los últimos errores de bit acumulados. Una aritmética decimal explícita puede ser útil, pero una conversión a cadena por str() (es decir, con redondeo a 12 válido) los dígitos) son suficientemente buenos por lo general si no se requiere una precisión extrema o 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+ :-)

Documentación

Consulte la Notas de la versión Python 2.7 - Otros cambios de idioma el cuarto párrafo:

Conversiones entre los números de punto flotante y las cadenas ahora son redondeadas 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 y json; 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 el la cadena decimal más corta que está garantizada para redondear de nuevo a x bajo el redondeo correcto (con redondeo -modo de redondeo medio a par). Anteriormente, daba una cadena basada en el redondeo de x a 17 dígitos decimales.

La cuestión relacionada


Más información: El formato de float antes de Python 2.7 fue similar al numpy.float64 actual. Ambos tipos utilizan la misma precisión de 64 bits IEEE 754 doble 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.95000000000000001. El resultado no es agradable y la conversión repr(float(number_as_string)) no es reversible con numpy. 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 sea formateado para humanos, no para procesadores numéricos, de lo contrario no es necesario nada más con Python 2.7+.

38
hynekcer

En Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
27
Shashank Singh

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')
23
Matt Fletcher

El tutorial de Python tiene un apéndice llamadoAritmé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 único 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 de 1/10, por lo que tratar de redondearlo de nuevo no puede mejorarlo: ya era tan bueno como parece.

Otra consecuencia es que dado que 0.1 no es exactamente 1/10, sumar diez valores de 0.1 puede no producir exactamente 1.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 módulo decimal .

20
nosklo

Puede usar format operator para redondear el valor hasta 2 lugares decimales en python:

print(format(14.4499923, '.2f')) // output is 14.45
13
Asad Manzoor

Está haciendo exactamente lo que le dijiste que hiciera y está funcionando correctamente. Lea más acerca de confusión de punto flotante y tal vez intente decimal objetos en su lugar.

12
HUAGHAGUAH

Como @Matt señaló,Python 3.6 proporciona f-strings, y también pueden usarparámetros anidados

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

que mostrará result: 2.35

11
toto_tico

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')
7
Siamand Maroufi
orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54

6
MikeL
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'
6
weaming

Es simple como 1,2,3:

  1. use decimal module para una aritmética de coma flotante decimal redondeada correctamente y rápida:

    d = Decimal (10000000.0000009)

para lograr el redondeo:

   d.quantize(Decimal('0.01'))

resultados con Decimal('10000000.00')

  1. hacer arriba SECO:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

OR

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. upvote esta respuesta :)

PD: crítica de otros: el formateo no es redondeado.

3
Sławomir Lenart

¿Qué pasa con una función lambda como esta:

arred = lambda x,n : x*(10**n)//1/(10**n)

De esta manera usted podría simplemente hacer:

arred(3.141591657,2)

y obten

3.14
1

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

Usa combinación de objeto decimal y 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')
0
Jonathan L