Форматирование плавает в 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()
вы можете просто использовать format () для достижения этого:
format(3.140, '.10g')
где 10-точность, которую вы хотите.
хотя форматирование, вероятно, наиболее 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
вы можете добиться того, что в наиболее подходящие для Python способ, как это:
python3:
"{:0.0f}".format(num)