Форматирование плавает в Python без лишних нулей
Как отформатировать поплавок, чтобы он не содержал нулей remaing? Другими словами, Я хочу, чтобы результирующая строка была как можно короче..?
Как:
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)
С docs for
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
Как насчет того, чтобы попробовать самый простой и, вероятно, самый эффективный подход? Метод нормализация() удаляет все правые нули.
from decimal import Decimal print (Decimal('0.001000').normalize()) # Result: 0.001
работает в Python 2 и Python 3.
-- обновление --
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(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", очень простой подход, который справа удаляет нули из представлений float:
print("%s"%3.140)
(спасибо @ellimilial за указание исключений)
используйте %g с достаточно большой шириной, например'%.99g'. Он будет печатать в фиксированной точке для любого достаточно большого числа.
EDIT: это не работает
>>> '%.99g' % 0.0000001 '9.99999999999999954748111825886258685613938723690807819366455078125e-08'
OP хотел бы удалить суперфлуоус нули и сделать полученную строку как можно короче.
Я нахожу, что экспоненциальное форматирование %g сокращает полученную строку для очень больших и очень малых значений. Проблема возникает для значений, которые не нуждаются в экспоненциальной нотации, например 128.0, которая не является ни очень большой, ни очень маленькой.
вот один из способов форматирования чисел в виде коротких строк, который использует % G экспоненциальную нотацию только при десятичной.нормализация создает строки это слишком долго. Это может быть не самое быстрое решение (так как оно использует десятичное число.нормализовать)
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']