Как я могу отформатировать число с плавающей точкой, чтобы оно не содержало конечных нулей? Другими словами, я хочу, чтобы полученная строка была как можно короче.
Например:
3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"
Как я могу отформатировать число с плавающей точкой, чтобы оно не содержало конечных нулей? Другими словами, я хочу, чтобы полученная строка была как можно короче.
Например:
3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"
Me, я бы сделал ('%f' % x).rstrip('0').rstrip('.')
- гарантирует форматирование с фиксированной запятой, а не научную нотацию и т.д. и т.д. Да, не такой гладкий и элегантный, как %g
, но он работает (и я не знаю как заставить %g
никогда не использовать научную нотацию, -).
Вы можете использовать %g
для достижения этой цели:
'%g'%(3.140)
или, для Python 2.6 или выше:
'{0:g}'.format(3.140)
Из docs для format
: g
вызывает (между прочим)
несущественные конечные нули [будут] удалены из значимости, а десятичная точка также удаляется, если после него не осталось оставшихся цифр.
Как пробовать самый простой и, вероятно, самый эффективный подход? Метод 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()
После просмотра ответов на несколько похожих вопросов это кажется лучшим решением для меня:
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()
может быть скорректирована с учетом настроек контекста, но, учитывая уже медленную скорость и не требующую смешной точности, и тот факт, что я все еще буду преобразовывать из float и во всяком случае, потеря точности, я не думал, что это стоит того, чтобы преследовать.
Меня не интересует возможный результат "-0", поскольку -0.0 является допустимым числом с плавающей запятой, и, вероятно, это будет редкое событие, но, поскольку вы упоминали, что хотите сохранить строковый результат короче возможно, вы всегда можете использовать дополнительные условные условия при очень низкой стоимости дополнительной скорости.
def floatToString(inputValue):
result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
return '0' if result == '-0' else result
Вот решение, которое сработало для меня. Это смесь решения 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 - это точная точность.
Хотя форматирование, вероятно, является наиболее more_itertools.rstrip
для more_itertools.rstrip
, здесь есть альтернативное решение с использованием инструмента 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
.
>>> str(a if a % 1 else int(a))
Если вы можете жить с 3. и 3.0, выглядящими как "3.0", очень простой подход, который удаляет нули прямо из представлений с плавающей точкой:
print("%s"%3.140)
(спасибо @ellimilial за указание на исключения)
Возможно использование функции format
:
{}.format(float)
Я думаю, что есть более простой способ сделать это с помощью новой функциональности str.format
. Если вы просто преобразуете его с помощью str (например, str(.0300)
→ 0.3
), он делает то, что желательно, в основном. Если число мало или достаточно велико, оно будет прибегать к экспоненциальной нотации, но в основном оно будет просто печатать число с плавающей запятой без конечных (или ведущих) нулей. Если строка формата пуста, то она в основном использует вывод str()
, поэтому это должно работать, если желаемая функциональность:
'{0}'.format(fp_num)
Даже это должно работать, если это единственное, что формируется:
'{}'.format(fp_num)
OP хотел бы удалить сверкающие нули и сделать результирующую строку как можно короче.
Я нахожу, что экспоненциальное форматирование% g сокращает результирующую строку для очень больших и очень малых значений. Проблема возникает для значений, которые не нуждаются в экспоненциальной нотации, например, 128.0, которая не очень большая или очень маленькая.
Вот один из способов форматирования чисел как коротких строк, который использует экспоненциальную нотацию% g только тогда, когда Decimal.normalize создает слишком длинные строки. Это может быть не самое быстрое решение (поскольку оно использует Decimal.normalize)
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
Проверьте это:
>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'
Для десятичного числа см. решение здесь: fooobar.com/questions/60707/...
Обработка% f, и вы должны положить
%.2f
где:.2f ==.00 плавает.
Пример:
печать "Цена:%.2f"% цены [товар]
Цена: 1.50
Используйте% g с большой шириной, например '%.99g'. Он будет печатать в нотации с фиксированной точкой для любого достаточно большого числа.
EDIT: он не работает
>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'
Вы можете использовать max()
следующим образом:
print(max(int(x), x))
Вы можете достичь этого в большинстве способов pythonic:
python3:
"{:0.0f}".format(num)