Форматирование плавает в Python без лишних нулей

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

Как:

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

14 ответов


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


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

'%g'%(3.140)

или, для Python 2.6 или лучше:

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

С документы на format: g причин (среди прочего)

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


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

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

Как насчет того, чтобы попробовать самый простой и, вероятно, самый эффективный подход? Метод 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()

вот решение, которое сработало для меня. Это смесь решение by 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

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

format(3.140, '.10g') где 10-точность, которую вы хотите.


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

хотя форматирование, вероятно, наиболее 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.


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

print("%s"%3.140)

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


используйте %g с достаточно большой шириной, например'%.99г'. Он будет печатать в фиксированной точке обозначения для любого разумно большого числа.

EDIT: это не работает

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

OP хотел бы удалить сверхбольшие нули и сделать полученную строку как можно короче.

Я нахожу, что экспоненциальное форматирование %g сокращает полученную строку для очень больших и очень малых значений. Проблема возникает для значений, которые не нуждаются в экспоненциальной нотации, например 128.0, которая не очень велика или очень мала.

вот один из способов форматирования чисел в виде коротких строк, который использует экспоненциальную нотацию %g только в десятичном формате.нормализовать создает строки это слишком долго. Это может быть не самое быстрое решение (поскольку оно использует Decimal.нормализовать)

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']

для float вы можете использовать это:

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

можно использовать max() такой:

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


вы можете добиться того, что в наиболее подходящие для Python способ, как это:

python3:

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