Después de buscar 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 en format(inputValue, '.15f').
lugar de '%.15f' % inputValue
, pero eso es un poco más lento (~ 30%).
Podría haberlo usado Decimal(inputValue).normalize()
, pero esto también tiene algunos problemas. Por un lado, es MUCHO más lento (~ 11x). También descubrí que aunque tiene una precisión bastante grande, aún sufre pérdida de precisión cuando se usa normalize()
.
>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')
Lo que es más importante, todavía me convertiría Decimal
de una float
que puede hacer que termines con algo más que el número que pones allí. Creo que Decimal
funciona mejor cuando la aritmética permanece Decimal
y 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 Decimal.normalize()
se puede ajustar a lo que se necesita usando la configuración de contexto, pero teniendo en cuenta la velocidad ya lenta y no necesita 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 lo hice No creo que valiera la pena perseguirlo.
No estoy preocupado con el posible resultado "-0" ya que -0.0 es un número de coma flotante válido y probablemente sea una ocurrencia rara de todos modos, pero como mencionó que desea mantener el resultado de la cadena lo más corto posible, usted siempre podría usar un condicional adicional a muy bajo costo de velocidad adicional.
def floatToString(inputValue):
result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
return '0' if result == '-0' else result
3.14 == 3.140
- Son el mismo número de coma flotante. Por lo demás, 3.140000 es el mismo número de coma flotante. El cero no existe en primer lugar.