Ограничение плавающих значений двумя десятичными точками

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

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

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

Комментарии к вопросу (10)

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

При представлении с плавающей точкой ваша округленная версия - это то же самое число. Поскольку компьютеры двоичные, они хранят числа с плавающей точкой как целое число, а затем делят его на степень двойки, поэтому 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. Или использовать число с фиксированной точкой, например decimal.
Комментарии (13)

Существуют новые спецификации формата, String Format Specification Mini-Language:

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

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

Примечание, что вышеприведенное возвращает строку. Для того, чтобы получить число в виде float, просто оберните его с помощью 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
Комментарии (8)

Встроенная функция round() отлично работает в Python 2.7 или более поздней версии.

Пример:

>>> round(14.22222223, 2)
14.22

Посмотрите документацию.

Комментарии (6)

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

Например:

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

13.95

Это создает число с плавающей запятой в строку с точностью до двух знаков после запятой.

Комментарии (1)

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

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

И наконец, хотя, возможно, самое главное, если вы хотите точное математика тогда вы не'т хотим, чтобы поплавки на всех. Обычным примером является дело с деньгами и в магазине 'копеек' как целое.

Комментарии (0)

Использовать

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

вместо

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

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

Комментарии (5)

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

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
Комментарии (9)

С помощью Python < 3 (например, 2.6 или 2.7), есть два способа сделать это.

# 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.

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

Ссылка: https://stackoverflow.com/questions/15263597/convert-floating-point-number-to-certain-precision-then-copy-to-string

Комментарии (2)

Прям ;)

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

Правильно округленное число может быть обратимо преобразуется и обратно: стр -> поплавка() -> предст() -> поплавка (из) ... " или " десятичное -> плавающая> стр -> десятичное Тип decimal не нужно для хранения.


(Естественно, это может быть в результате сложения или вычитания из округленных цифр, чтобы устранить накопленные в прошлом ошибок. Явной десятичной арифметики может быть еще пригодится, но преобразование в строку (ул.) (то есть с округлением до 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))) = 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() на поплавки и комплексных чисел; поплавок и сложные конструкторы; форматирование; сериализации и де-сериализации плавает и комплексных чисел с помощью маршал, рассол и JSON с модулей; разбора поплавка и мнимой литералы в Python код; и десятичной плавающей преобразования.

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

Проблема


*Дополнительная информация: форматирование "плывет" перед питоном 2.7 был похож на пакете numpy в настоящее время.float64. Оба типа используют тот же 64-битный [стандарт IEEE 754](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) двойной точности с 52 бита мантиссы. Большая разница заключается в том, чтоНП.float64.предстчасто отформатирован с чрезмерным количеством десятичных так что не может быть потеряно, но не действует по стандарту IEEE 754 число существует между 13.949999999999999 и 13.950000000000001. Результат не хороший и преобразованиепредст(поплавка(number_as_string)) не обратимых операций с numpy. С другой стороны: поплавок.__предст__ форматируется так, что каждая цифра важна; последовательность без пробелов и преобразование является обратимым. Просто: если вы, возможно, есть и NumPy.float64 число, преобразовать его в обычный поплавок для того, чтобы быть отформатирован для людей, а не для числовых процессоров, в противном случае больше ничего и не надо с Python 2.7+.

Комментарии (7)

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

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Комментарии (0)

Вы можете использовать формат оператор округления значения до 2 знаков после запятой в Python:

print(format(14.4499923, '.2f')) // output is 14.45
Комментарии (1)

Здесь, кажется, никто не упоминал об этом, поэтому позвольте мне привести пример в Python 3.6'С Ф-строку/шаблон-строка форматирования, я думаю, красиво аккуратно:

>>> f'{a:.2f}'

Он хорошо работает с уже слишком примерами, с операторами и не нуждающихся в скобки:

>>> print(f'Completed in {time.time() - start:.2f}s')
Комментарии (0)

В Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output
Комментарии (6)

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

0.1 0.10000000000000001

У вас может возникнуть соблазн использовать круглые()` функция порубить его обратно в один цифры вы ожидаете. Но это не делает никакой разница:

круглая(0.1, 1) 0.10000000000000001

проблема в том, что бинарные значение с плавающей точкой хранятся на “0.1” уже был самый лучший бинарный приближение к 1/10, таким образом пытаясь вокруг него снова не может сделать это лучше: Это было уже так хорошо, как он получает.

другим следствием является то, что с 0.1 > есть не совсем 1/10, подводя десять значения 0.1 может точно не выход 1.0, либо:

сумма = 0.0 Для я в диапазоне(10): ... сумма += 0.1 ... сумма 0.99999999999999989

Одним из альтернативных и решение ваших проблем будет использовать десятичное число модуль.

Комментарии (0)

Как @Мэтт указал, питон 3.6 обеспечивает Ф-строк, и они могут также использовать вложенный параметров:

value = 2.34558
precision = 2
width = 4

print(f'result: {value:{width}.{precision}f}')

который будет отображать результат: 2.35`

Комментарии (0)

Он делает именно то, что вы ему сказали, и работает правильно. Прочитайте больше о floating point confusion и, возможно, попробуйте вместо этого использовать decimal объекты.

Комментарии (0)

Для фиксации плавающей точкой в тип-динамических языков, таких как Python и JavaScript, я использую эту технику

# For example:
a = 70000
b = 0.14
c = a * b

print c # Prints 980.0000000002
# Try to fix
c = int(c * 10000)/100000
print c # Prints 980

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

from decimal import *
getcontext().prec = 6
Decimal(1) / Decimal(7)
# Results in 6 precision -> Decimal('0.142857')

getcontext().prec = 28
Decimal(1) / Decimal(7)
# Results in 28 precision -> Decimal('0.1428571428571428571428571429')
Комментарии (2)
orig_float = 232569 / 16000.0

14.5355625

short_float = float("{:.2f}".format(orig_float)) 

14.54

Комментарии (0)
from decimal import Decimal

def round_float(v, ndigits=2, rt_str=False):
    d = Decimal(v)
    v_str = ("{0:.%sf}" % ndigits).format(round(d, ndigits))
    if rt_str:
        return v_str
    return Decimal(v_str)

Результаты:

Python 3.6.1 (default, Dec 11 2018, 17:41:10)
>>> round_float(3.1415926)
Decimal('3.14')
>>> round_float(3.1445926)
Decimal('3.14')
>>> round_float(3.1455926)
Decimal('3.15')
>>> round_float(3.1455926, rt_str=True)
'3.15'
>>> str(round_float(3.1455926))
'3.15'
Комментарии (0)

Используйте комбинацию десятичных предмет и круглым() метод.

Python 3.7.3
>>> from decimal import Decimal
>>> d1 = Decimal (13.949999999999999) # define a Decimal
>>> d1 
Decimal('13.949999999999999289457264239899814128875732421875')
>>> d2 = round(d1, 2) # round to 2 decimals
>>> d2
Decimal('13.95')
Комментарии (0)