После просмотра ответов на несколько похожих вопросов, мне кажется, это лучшее решение:
def floatToString(inputValue):
return ('%.15f' % inputValue).rstrip('0').rstrip('.')
Мои рассуждения:
%g
не избавляется от научных обозначений.
>>> '%g' % 0.000035
'3.5e-05'
15 знаков после запятой, кажется, избегают странного поведения и обладают достаточной точностью для моих нужд.
>>> ('%.15f' % 1.35).rstrip('0').rstrip('.')
'1.35'
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.')
'1.3500000000000001'
Я мог бы использовать format(inputValue, '.15f').
вместо '%.15f' % inputValue
, но это немного медленнее (~ 30%).
Я мог бы использовать Decimal(inputValue).normalize()
, но это также имеет несколько проблем. Во-первых, это НАМНОГО медленнее (~ 11x). Я также обнаружил, что, хотя он имеет довольно большую точность, он все еще страдает от потери точности при использовании normalize()
.
>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')
Самое главное, я все равно буду конвертировать в Decimal
из float
, что может привести к чему-то другому, чем число, которое вы там указали. Я думаю, Decimal
работает лучше всего, когда арифметика остается в Decimal
, а Decimal
инициализируется строкой.
>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')
Я уверен, что проблема точности Decimal.normalize()
может быть скорректирована в соответствии с тем, что необходимо, с помощью настроек контекста, но с учетом и без того низкой скорости и не требующей смехотворной точности, а также того факта, что я все еще буду конвертировать из поплавка и В любом случае, теряя точность, я не думал, что это стоит того, чтобы преследовать.
Меня не интересует возможный результат "-0", так как -0.0 является допустимым числом с плавающей запятой, и это, вероятно, будет в любом случае редким случаем, но так как вы упомянули, что хотите сохранить строковый результат таким коротким, как возможно, вы всегда можете использовать дополнительные условия при очень небольших дополнительных затратах на скорость.
def floatToString(inputValue):
result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
return '0' if result == '-0' else result