Форматирование плавающих в Python без конечных нулей - PullRequest
148 голосов
/ 14 марта 2010

Как мне отформатировать число с плавающей точкой, чтобы оно не содержало конечных нулей?Другими словами, я хочу, чтобы полученная строка была как можно короче.

Например:

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

Ответы [ 15 ]

159 голосов
/ 14 марта 2010

Я, я бы сделал ('%f' % x).rstrip('0').rstrip('.') - гарантирует форматирование с фиксированной запятой, а не научную запись и т. Д. И т. Д. Да, не так гладко и элегантно, как %g, но это работает (и я не знаю, как заставить %g никогда не использовать научную запись; -).

123 голосов
/ 14 марта 2010

Вы можете использовать %g для достижения этой цели:

'%g'%(3.140)

или, для Python 2.6 или выше:

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

Из документов для format: g причин (среди прочего)

незначительные конечные нули [будет] удалены от значения, а десятичная точка также удаляется, если есть после него нет оставшихся цифр.

11 голосов
/ 02 мая 2016

Как насчет того, чтобы попробовать самый простой и, вероятно, самый эффективный подход?Метод normalize () удаляет все крайние правые нули.

from decimal import Decimal

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

Работает в Python 2 и Python 3 .

- Обновлено -

Единственная проблема, на которую указывает @ BobStein-VisiBone, заключается в том, что такие числа, как 10, 100, 1000 ... будут отображаться в экспоненциальном представлении.Это можно легко исправить с помощью следующей функции:

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()
10 голосов
/ 10 июня 2016

После просмотра ответов на несколько похожих вопросов, мне кажется, это лучшее решение:

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
5 голосов
/ 22 июня 2017

Вот решение, которое сработало для меня. Это смесь решения от PolyMesh и использования нового синтаксиса .format() .

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

Выход

3
3
3
3.1
3.14
3.14
2 голосов
/ 30 августа 2017

Хотя форматирование, вероятно, наиболее распространено в Pythonic, здесь есть альтернативное решение с использованием инструмента 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"

Число преобразуется в строку, в которой отсутствуют завершающие символы, удовлетворяющие предикату. Определение функции fmt не требуется, но оно используется здесь для проверки утверждений, которые все проходят. Примечание: он работает со строковыми входами и принимает необязательные предикаты.

См. Также подробности об этой сторонней библиотеке, more_itertools.

2 голосов
/ 28 мая 2017
>>> str(a if a % 1 else int(a))
2 голосов
/ 17 января 2017

Вы можете просто использовать format () для достижения этой цели:

format(3.140, '.10g') где 10 - требуемая точность.

1 голос
/ 05 апреля 2018

Если вы можете жить с 3. и 3.0, выглядящими как «3.0», очень простой подход, который удаляет нули справа от представлений с плавающей точкой:

print("%s"%3.140)

(спасибо @ellimilial за указание на исключения)

0 голосов
/ 27 января 2019

Обработка% f, и вы должны поставить

%. 2f

, где: .2f == .00 float.

Пример:

печать "Цена:% .2f"% цены [товар]

вывод:

Цена: 1,50

...