Я хочу, чтобы a
округлялся до 13.95.
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Функция round
работает не так, как я ожидал.
Я хочу, чтобы a
округлялся до 13.95.
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Функция round
работает не так, как я ожидал.
Вы столкнулись с старой проблемой с числами с плавающей запятой, что не все числа могут быть представлены точно. Командная строка просто показывает вам полную форму с плавающей запятой из памяти.
С представлением с плавающей точкой ваша округленная версия - это то же число. Поскольку компьютеры являются двоичными, они хранят числа с плавающей запятой в виде целого числа, а затем делят его на степень двойки, поэтому 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
Если вам нужно только два десятичных знака (например, для отображения значения валюты), у вас есть несколько вариантов:
Существуют спецификации нового формата, спецификация формата строки 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
Встроенный round()
работает отлично в Python 2.7 или новее.
Пример:
>>> round(14.22222223, 2)
14.22
Проверьте документацию.
Я считаю, что самый простой способ - использовать функцию format()
.
Например:
a = 13.949999999999999
format(a, '.2f')
13.95
Это создает число с плавающей точкой в виде строки, округленной до двух десятичных точек.
Большинство чисел не могут быть точно представлены в поплавках. Если вы хотите округлить число, потому что это то, что требует ваша математическая формула или алгоритм, то вы хотите использовать раунд. Если вы просто хотите ограничить отображение определенной точностью, тогда даже не используйте раунд и просто не форматируйте его как эту строку. (Если вы хотите отобразить его с помощью какого-то альтернативного метода округления, и есть тонны, то вам нужно смешать два подхода.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
И, наконец, хотя, возможно, самое главное, если вам нужна точная математика, то вы вообще не хотите плавать. Обычный пример - это деньги и хранить центы как целое.
использование
print"{:.2f}".format(a)
вместо
print"{0:.2f}".format(a)
Потому что последнее может привести к ошибкам вывода при попытке вывода нескольких переменных (см. Комментарии).
Попробуйте код ниже:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
С 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.
А для получения дополнительной информации по первому варианту этой ссылки будет достаточно и она содержит информацию о различных флагах.
Ссылка: Преобразовать число с плавающей запятой с определенной точностью, а затем скопировать в строку
Проблема округления ввода/вывода была окончательно решена 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+.
Вы можете изменить формат вывода:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Никто здесь, кажется, не упомянул об этом, поэтому позвольте мне привести пример в формате f-string/template-string Python 3.6, который, я думаю, красиво опрятен:
>>> f'{a:.2f}'
Он хорошо работает и с более длинными примерами, с операторами и не нуждающимися в parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
Вы можете использовать оператор формата для округления значения до 2 десятичных знаков в python:
print(format(14.4499923, '.2f')) // output is 14.45
В Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
В руководстве по 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
.
Он делает именно то, что вы ему сказали, и работает правильно. Узнайте больше о путанице с плавающей точкой и, возможно, попробуйте десятичные объекты.
Как отметил @Matt, Python 3.6 предоставляет f-строки, и они также могут использовать вложенные параметры:
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
который отобразит result: 2.35
Для исправления плавающей запятой в динамических языках типа 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')
orig_float = 232569 / 16000.0
14.5355625
short_float = float("{:.2f}".format(orig_float))
14.54
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'
Это просто как 1,2,3:
используйте десятичный модуль для быстрой правильно округленной десятичной арифметики с плавающей точкой:
д = Десятичный (10000000.0000009)
добиться округления:
d.quantize(Decimal('0.01'))
будет результат с Decimal('10000000.00')
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)
PS: критика других: форматирование не округляет.
Как насчет лямбда-функции, как это:
arred = lambda x,n : x*(10**n)//1/(10**n)
Таким образом, вы можете просто сделать:
arred(3.141591657,2)
и получить
3.14
Используйте комбинацию десятичного объекта и метода 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')
Чтобы округлить число до разрешения, наилучшим способом является следующий, который может работать с любым разрешением (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
Метод, который я использую, - это метод нарезания строк. Это относительно быстро и просто.
Сначала преобразуем float в строку, выберите нужную длину.
float = str(float)[:5]
В одной строке выше мы преобразовали значение в строку, а затем сохранили строку только до ее первых четырех цифр или символов (включительно).
Надеюсь, что это поможет!