Ограничение числа с плавающей запятой до двух десятичных знаков - PullRequest
1384 голосов
/ 18 января 2009

Я хочу, чтобы a было округлено до 13,95 .

>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999

Функция round работает не так, как я ожидал.

Ответы [ 24 ]

1384 голосов
/ 18 января 2009

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

В плавающей точке ваша округленная версия - это то же число. Поскольку компьютеры являются двоичными, они хранят числа с плавающей запятой в виде целого числа, а затем делят его на степень два, поэтому 13,95 будет представлено аналогично 125650429603636838 / (2 ** 53).

Числа двойной точности имеют точность 53 бита (16 цифр), а обычные числа с плавающей точкой имеют точность 24 бита (8 цифр). с плавающей точкой в ​​Python использует двойную точность для хранения значений.

Например,

  >>> 125650429603636838/(2**53)
  13.949999999999999

  >>> 234042163/(2**24)
  13.949999988079071

  >>> a=13.946
  >>> print(a)
  13.946
  >>> print("%.2f" % a)
  13.95
  >>> round(a,2)
  13.949999999999999
  >>> print("%.2f" % round(a,2))
  13.95
  >>> print("{0:.2f}".format(a))
  13.95
  >>> print("{0:.2f}".format(round(a,2)))
  13.95
  >>> print("{0:.15f}".format(round(a,2)))
  13.949999999999999

Если вам нужно только два знака после запятой, как в валюте, у вас есть пара лучших вариантов: 1) Используйте целые числа и сохраняйте значения в центах, а не в долларах, а затем делите на 100, чтобы конвертировать в доллары. 2) Или используйте число с фиксированной точкой, например десятичное .

495 голосов
/ 30 июня 2011

Появились новые спецификации формата, Спецификация формата строки Mini-Language :

Вы можете сделать так же, как:

"{0:.2f}".format(13.949999999999999)

Обратите внимание , что приведенное выше возвращает строку. Для того, чтобы получить как поплавок, просто оберните с float(...):

float("{0:.2f}".format(13.949999999999999))

Примечание , что перенос с float() ничего не меняет:

>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{0:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
227 голосов
/ 31 декабря 2016

Встроенный round() прекрасно работает в Python 2.7 или более поздней версии.

Пример:

>>> round(14.22222223, 2)
14.22

Ознакомьтесь с документацией .

132 голосов
/ 26 января 2015

Мне кажется, что самый простой подход - использовать функцию format().

Например:

a = 13.949999999999999
format(a, '.2f')

13.95

Получает число с плавающей точкой в ​​виде строки, округленной до двух десятичных знаков.

89 голосов
/ 18 января 2009

Большинство чисел не могут быть точно представлены в числах с плавающей точкой. Если вы хотите округлить число, потому что это то, чего требует ваша математическая формула или алгоритм, тогда вы хотите использовать округление. Если вы просто хотите ограничить отображение с определенной точностью, то даже не используйте округление и просто отформатируйте его как эту строку. (Если вы хотите отобразить его каким-либо альтернативным методом округления, и есть тонны, то вам нужно смешать два подхода.)

>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'

И, наконец, хотя, пожалуй, самое главное, если вы хотите точную математику, тогда вы вообще не хотите плавать. Обычный пример - работа с деньгами и хранение центов в виде целого числа.

79 голосов
/ 04 августа 2017

Используйте

print"{:.2f}".format(a)

вместо

print"{0:.2f}".format(a)

Поскольку последнее может привести к ошибкам вывода при попытке вывести несколько переменных (см. Комментарии).

69 голосов
/ 26 августа 2013

Попробуйте код ниже:

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
51 голосов
/ 11 декабря 2013

При Python <3 (например, 2.6 или 2.7) это можно сделать двумя способами. </p>

# Option one 
older_method_string = "%.9f" % numvar

# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)

Но учтите, что для версий Python выше 3 (например, 3.2 или 3.3) вариант два - предпочтительный .

Для получения дополнительной информации о втором варианте, я предлагаю эту ссылку на форматирование строки из документации Python .

А для получения дополнительной информации по первому варианту эта ссылка будет достаточной и содержит информацию о различных флагах .

Ссылка: Преобразовать число с плавающей запятой с определенной точностью, а затем скопировать в строку

44 голосов
/ 18 января 2009

Вы можете изменить формат вывода:

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
39 голосов
/ 31 января 2016

TLDR;)

Проблема округления ввода / вывода была окончательно решена с помощью Python 2.7.0 и 3.1 .

.

Правильно округленное число может быть обратимо преобразовано назад и вперед:
str -> float() -> repr() -> float() ... или Decimal -> float -> str -> Decimal
Десятичный тип больше не нужен для хранения.

(Естественно, может потребоваться округлить результат сложения или вычитания округленных чисел, чтобы исключить накопленные ошибки в последнем бите. Явная десятичная арифметика все еще может быть удобной, но преобразование в строку на str() (то есть с округлением до 12 действительных цифр) обычно достаточно хорош, если не требуется предельная точность или экстремальное число последовательных арифметических операций.)

Бесконечный тест :

import random
from decimal import Decimal
for x in iter(random.random, None):           # Verify FOREVER that rounding is fixed :-)
    assert float(repr(x)) == x                # Reversible repr() conversion.
    assert float(Decimal(repr(x))) == x
    assert len(repr(round(x, 10))) <= 12      # Smart decimal places in repr() after round.
    if x >= 0.1:                              # Implicit rounding to 12 significant digits
        assert str(x) == repr(round(x, 12))   # by str() is good enough for small errors.
        y = 1000 * x                             # Decimal type is excessive for shopping
        assert str(y) == repr(round(y, 12 - 3))  # in a supermaket with Python 2.7+ :-)

Документация

См. Примечания к выпуску Python 2.7 - Изменения в других языках четвертый абзац:

Преобразования между числами с плавающей точкой и строками теперь правильно округлены на большинстве платформ. Эти преобразования происходят во многих разных местах: str () для чисел с плавающей точкой и комплексных чисел; поплавок и сложные конструкторы; числовое форматирование; сериализация и десериализация чисел с плавающей точкой и комплексных чисел с использованием модулей marshal, pickle и json; парсинг float и мнимых литералов в коде Python; и десятичное преобразование в число с плавающей точкой.

В связи с этим repr () числа с плавающей запятой x теперь возвращает результат, основанный на самой короткой десятичной строке , которая гарантированно округляется до x при правильном округлении (с режимом округления от половины до четности). Ранее он давал строку, основанную на округлении x до 17 десятичных цифр.

Смежный вопрос


Дополнительная информация: Форматирование float до Python 2.7 было похоже на текущий numpy.float64. Оба типа используют одинаковую 64-битную IEEE 754 двойную точность с 52-битной мантиссой. Большая разница в том, что np.float64.__repr__ часто форматируется с чрезмерным десятичным числом, так что ни один бит не может быть потерян, но между 13.949999999999999 и 13.950000000000001 не существует действительного номера IEEE 754. Результат не очень хороший, и преобразование repr(float(number_as_string)) не обратимо с помощью numpy. С другой стороны: float.__repr__ отформатирован так, что важна каждая цифра; последовательность без пробелов и конверсия обратима. Проще говоря: если у вас, возможно, есть номер numpy.float64, преобразуйте его в обычное число с плавающей точкой, чтобы его можно было отформатировать для людей, а не для числовых процессоров, в противном случае в Python 2.7 + больше ничего не нужно

...