Ограничение поплавков на две десятичные точки

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

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

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

Ответы

Ответ 1

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

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

Ответ 2

Существуют спецификации нового формата, спецификация формата строки 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

Ответ 3

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

Пример:

>>> round(14.22222223, 2)
14.22

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

Ответ 4

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

Например:

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

13.95

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

Ответ 5

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

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

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

Ответ 6

использование

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

вместо

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

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

Ответ 7

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

>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99

Ответ 8

С Python & lt; 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.

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

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

Ответ 9

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

Ответ 10

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

>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95

Ответ 11

Никто здесь, кажется, не упомянул об этом, поэтому позвольте мне привести пример в формате f-string/template-string Python 3.6, который, я думаю, красиво опрятен:

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

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

>>> print(f'Completed in {time.time() - start:.2f}s')

Ответ 12

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

print(format(14.4499923, '.2f')) // output is 14.45

Ответ 13

В Python 2.7:

a = 13.949999999999999
output = float("%0.2f"%a)
print output

Ответ 14

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

>>> 0.1
0.10000000000000001

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

>>> round(0.1, 1)
0.10000000000000001

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

Другое следствие - это то, что с 0.1 не совсем 1/10, суммируя десять значения 0.1 могут не дать точно 1.0, либо:

>>> sum = 0.0
>>> for i in range(10):
...     sum += 0.1
...
>>> sum
0.99999999999999989

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

Ответ 16

Как отметил @Matt, Python 3.6 предоставляет f-строки, и они также могут использовать вложенные параметры:

value = 2.34558
precision = 2
width = 4

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

который отобразит result: 2.35

Ответ 17

Для исправления плавающей запятой в динамических языках типа 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

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

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')

Ответ 18

orig_float = 232569 / 16000.0

14.5355625

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

14.54

Ответ 19

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'

Ответ 20

Это просто как 1,2,3:

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

    д = Десятичный (10000000.0000009)

добиться округления:

   d.quantize(Decimal('0.01'))

будет результат с Decimal('10000000.00')

  1. сделать выше СУХОЙ:
    def round_decimal(number, exponent='0.01'):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(exponent))

ИЛИ ЖЕ

    def round_decimal(number, decimal_places=2):
        decimal_value = Decimal(number)
        return decimal_value.quantize(Decimal(10) ** -decimal_places)
  1. одобряю этот ответ :)

PS: критика других: форматирование не округляет.

Ответ 21

Как насчет лямбда-функции, как это:

arred = lambda x,n : x*(10**n)//1/(10**n)

Таким образом, вы можете просто сделать:

arred(3.141591657,2)

и получить

3.14

Ответ 22

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

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')

Ответ 23

Чтобы округлить число до разрешения, наилучшим способом является следующий, который может работать с любым разрешением (0,01 для двух десятичных знаков или даже других шагов):

>>> import numpy as np
>>> value = 13.949999999999999
>>> resolution = 0.01
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
13.95

>>> resolution = 0.5
>>> newValue = int(np.round(value/resolution))*resolution
>>> print newValue
14.0

Ответ 24

Метод, который я использую, - это метод нарезания строк. Это относительно быстро и просто.

Сначала преобразуем float в строку, выберите нужную длину.

float = str(float)[:5]

В одной строке выше мы преобразовали значение в строку, а затем сохранили строку только до ее первых четырех цифр или символов (включительно).

Надеюсь, что это поможет!