Formato de flotadores en Python sin ceros superfluos

¿Cómo formatear un flotador para que no contenga los ceros restantes? En otras palabras, quiero que la cadena resultante sea lo más corta posible ..?

Me gusta:

3 -> "3" 3. -> "3" 3.0 -> "3" 3.1 -> "3.1" 3.14 -> "3.14" 3.140 -> "3.14" 

Yo, lo haría ('%f' % x).rstrip('0').rstrip('.') : Garantiza el formato de punto fijo en lugar de la notación científica, etc. etc. Sí, no es tan elegante y elegante como %g , pero funciona (y no sé cómo forzar a %g a no usar nunca la notación científica ;-).

Podrías usar %g para lograr esto:

 '%g'%(3.140) 

o, para Python 2.6 o mejor:

 '{0:g}'.format(3.140) 

De los documentos para el format : g causas (entre otras cosas)

ceros finales insignificantes [para ser] eliminados del significando, y el punto decimal también se elimina si no hay dígitos restantes a continuación.

¿Qué hay de probar el enfoque más fácil y probablemente el más efectivo? El método normalize () elimina todos los ceros al final de la derecha.

 from decimal import Decimal print (Decimal('0.001000').normalize()) # Result: 0.001 

Trabaja en Python 2 y Python 3 .

— Actualizado —

El único problema que señala @ BobStein-VisiBone es que los números como 10, 100, 1000 … se mostrarán en representación exponencial. Esto se puede arreglar fácilmente usando la siguiente función:

 from decimal import Decimal def format_float(f): d = Decimal(str(f)); return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize() 

Después de revisar las respuestas a varias preguntas similares, esta parece ser la mejor solución para mí:

 def floatToString(inputValue): return ('%.15f' % inputValue).rstrip('0').rstrip('.') 

Mi razonamiento:

%g no se deshace de la notación científica.

 >>> '%g' % 0.000035 '3.5e-05' 

15 decimales parecen evitar comportamientos extraños y tienen mucha precisión para mis necesidades.

 >>> ('%.15f' % 1.35).rstrip('0').rstrip('.') '1.35' >>> ('%.16f' % 1.35).rstrip('0').rstrip('.') '1.3500000000000001' 

Podría haber usado el format(inputValue, '.15f'). en lugar de '%.15f' % inputValue , pero eso es un poco más lento (~ 30%).

Podría haber usado Decimal(inputValue).normalize() , pero esto también tiene algunos problemas. Por un lado, es mucho más lento (~ 11x). También encontré que aunque tiene una precisión bastante grande, todavía sufre una pérdida de precisión cuando se usa normalize() .

 >>> Decimal('0.21000000000000000000000000006').normalize() Decimal('0.2100000000000000000000000001') >>> Decimal('0.21000000000000000000000000006') Decimal('0.21000000000000000000000000006') 

Lo más importante es que aún estaría convirtiendo a Decimal desde un float que puede hacer que termines con algo más que el número que ingresaste allí. Creo que el Decimal funciona mejor cuando la aritmética permanece en Decimal y el Decimal se inicializa con una cadena.

 >>> Decimal(1.35) Decimal('1.350000000000000088817841970012523233890533447265625') >>> Decimal('1.35') Decimal('1.35') 

Estoy seguro de que el problema de precisión de Decimal.normalize() se puede ajustar a lo que se necesita mediante la configuración del contexto, pero teniendo en cuenta la velocidad ya lenta y sin necesitar una precisión ridícula y el hecho de que todavía estaría convirtiendo de un flotador y perdiendo Precisión de todos modos, no pensé que valiera la pena seguir.

No me preocupa el posible resultado “-0”, ya que -0.0 es un número de punto flotante válido y es probable que ocurra algo raro de todos modos, pero como mencionó que desea mantener el resultado de la cadena lo más corto posible, Siempre se podría usar un condicional adicional a muy poca velocidad extra.

 def floatToString(inputValue): result = ('%.15f' % inputValue).rstrip('0').rstrip('.') return '0' if result == '-0' else result 

Aquí hay una solución que funcionó para mí. Es una mezcla de la solución de PolyMesh y el uso de la nueva syntax .format() .

 for num in 3, 3., 3.0, 3.1, 3.14, 3.140: print('{0:.2f}'.format(num).rstrip('0').rstrip('.')) 

Salida :

 3 3 3 3.1 3.14 3.14 

Simplemente puede usar format () para lograr esto:

format(3.140, '.10g') donde 10 es la precisión que desea.

Si bien es probable que el formateo sea la forma más pythonica, aquí hay una solución alternativa que utiliza la herramienta more_itertools.rstrip .

 import more_itertools as mit def fmt(num, pred=None): iterable = str(num) predicate = pred if pred is not None else lambda x: x in {".", "0"} return "".join(mit.rstrip(iterable, predicate)) assert fmt(3) == "3" assert fmt(3.) == "3" assert fmt(3.0) == "3" assert fmt(3.1) == "3.1" assert fmt(3.14) == "3.14" assert fmt(3.140) == "3.14" assert fmt(3.14000) == "3.14" assert fmt("3,0", pred=lambda x: x in set(",0")) == "3" 

El número se convierte en una cadena, que se despoja de los caracteres finales que satisfacen un predicado. La función fmt definición no es obligatoria, pero se usa aquí para probar aserciones, que pasan todas. Nota: funciona en entradas de cadena y acepta predicados opcionales.

Consulte también los detalles sobre esta biblioteca de terceros, more_itertools .

 >>> str(a if a % 1 else int(a)) 

Si puede vivir con 3. y 3.0 que aparecen como “3.0”, un enfoque muy simple que elimina los ceros a la derecha de las representaciones flotantes:

 print("%s"%3.140) 

(Gracias @ellimilial por señalar las excepciones)

OP desea eliminar los ceros superfluos y hacer que la cadena resultante sea lo más corta posible.

Encuentro que el formato exponencial% g acorta la cadena resultante para valores muy grandes y muy pequeños. El problema viene para los valores que no necesitan notación exponencial, como 128.0, que no es ni muy grande ni muy pequeño.

Aquí hay una forma de dar formato a los números como cadenas cortas que usan% g de notación exponencial solo cuando Decimal.normalize crea cadenas que son demasiado largas. Esta podría no ser la solución más rápida (ya que utiliza Decimal.normalize)

 def floatToString (inputValue, precision = 3): rc = str(Decimal(inputValue).normalize()) if 'E' in rc or len(rc) > 5: rc = '{0:.{1}g}'.format(inputValue, precision) return rc inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0] outputs = [floatToString(i) for i in inputs] print(outputs) # ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10'] 

Para flotar puedes usar esto:

 def format_float(num): return ('%i' if num == int(num) else '%s') % num 

Pruébalo:

 >>> format_float(1.00000) '1' >>> format_float(1.1234567890000000000) '1.123456789' 

Para Decimal vea la solución aquí: https://stackoverflow.com/a/42668598/5917543

Manejando% f y deberías poner

% .2f

, donde: .2f == .00 flota.

Ejemplo:

imprimir “Precio:% ​​.2f”% precios [producto]

salida:

Precio: 1.50

Use% g con un ancho suficientemente grande, por ejemplo ‘% .99g’. Se imprimirá en notación de punto fijo para cualquier número razonablemente grande.

EDIT: no funciona

 >>> '%.99g' % 0.0000001 '9.99999999999999954748111825886258685613938723690807819366455078125e-08' 

Puedes usar max() así:

print(max(int(x), x))

Puedes lograr eso de la manera más pythonica así:

python3:

 "{:0.0f}".format(num)