Я хочу 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("{:.2f}".format(a))
13.95
>>> print("{:.2f}".format(round(a, 2)))
13.95
>>> print("{:.15f}".format(round(a, 2)))
13.949999999999999
Если вам нужно только два десятичных знака (например, для отображения значения валюты), у вас есть пара лучших вариантов:
"%.2f" % round(a,2)
вы можете вставить не только в printf, но и в такие вещи, какstr()
float
) является лишь ближайшим доступным приближением десятичного числа (с которым вы знакомы как человек). Не существует такого (конечно представимого) двоичного значения, как 0,245. Он просто не существует и математически не может существовать. Двоичное значение, которое ближе всего к 0,245, немного меньше, чем 0,245, поэтому, естественно, оно округляется вниз. Аналогично, в двоичном коде нет такой вещи, как 0,225, но двоичное значение, которое ближе всего к 0,225, немного больше, чем 0,225, поэтому, естественно, оно округляется.
Decimal
, и это было одно из решений, представленных в этом ответе. Другой - преобразовать ваши величины в целое и использовать целочисленную арифметику. Оба этих подхода также появились в других ответах и комментариях.
Появились новые спецификации формата, спецификация формата строки мини-язык :
Вы можете сделать так же, как:
"{:.2f}".format(13.949999999999999)
Примечание 1: выше возвращает строку. Для того, чтобы получить как поплавок, просто оберните float(...)
:
float("{:.2f}".format(13.949999999999999))
Примечание 2: упаковка с помощью float()
ничего не меняет:
>>> x = 13.949999999999999999
>>> x
13.95
>>> g = float("{:.2f}".format(x))
>>> g
13.95
>>> x == g
True
>>> h = round(x, 2)
>>> h
13.95
>>> x == h
True
'{0:,.2f}'.format(1333.949999999)
распечатать '1,333.95'
.
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
Встроенный round()
прекрасно работает в Python 2.7 или более поздней версии.
Пример:
>>> round(14.22222223, 2)
14.22
Ознакомьтесь с документацией .
round(2.16, 1)
дать 2.2
почему питон просто предлагают truncate
FUNC
>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.html
Note The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float.
Я чувствую, что самый простой подход - это использовать format()
функцию.
Например:
a = 13.949999999999999
format(a, '.2f')
13.95
Это создает число с плавающей точкой в виде строки, округленной до двух десятичных знаков.
использование
print"{:.2f}".format(a)
вместо
print"{0:.2f}".format(a)
Поскольку последнее может привести к ошибкам вывода при попытке вывести несколько переменных (см. Комментарии).
Большинство чисел не могут быть точно представлены в числах с плавающей точкой. Если вы хотите округлить число, потому что это то, чего требует ваша математическая формула или алгоритм, тогда вы хотите использовать округление. Если вы просто хотите ограничить отображение с определенной точностью, то даже не используйте округление и просто отформатируйте его как эту строку. (Если вы хотите отобразить его каким-либо альтернативным методом округления, и есть тонны, то вам нужно смешать два подхода.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
И, наконец, хотя, возможно, самое главное, если вы хотите точную математику, то вы вообще не хотите плавать. Обычный пример - работа с деньгами и хранение центов в виде целого числа.
Попробуйте код ниже:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
round
функции в первую очередь. Во-вторых, поскольку в этом решении все еще используется число с плавающей запятой, исходная проблема ОП сохраняется даже для «исправленной» версии этого «решения».
round
функции (которая использовалась в вопросе).
round()
не работает, как упомянуто OP.
Проблема округления ввода / вывода была окончательно решена в 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+ больше ничего не нужно.
float
(двойной точности) и обычном round
, а не о numpy.double и его преобразовании в строку. Простое округление Python действительно не может быть сделано лучше, чем в Python 2.7. Большинство ответов было написано до 2.7, но они устарели, хотя изначально они были очень хорошими. Это причина моего ответа.
1
, кроме как во время «постепенного снижения уровня».
a*b
против b*a
. Спасибо за ссылки - Ностальгия.
С 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 .
И для получения дополнительной информации по первому варианту, эта ссылка будет достаточной и содержит информацию о различных флагах .
Ссылка: Преобразовать число с плавающей запятой с определенной точностью, а затем скопировать в строку
numvar=12.456
, то "{:.2f}".format(numvar)
дает, 12.46
но "{:2i}".format(numvar)
дает ошибку, и я ожидаю 12
.
Вы можете изменить формат вывода:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Никто здесь, кажется, еще не упомянул об этом, поэтому позвольте мне привести пример в формате f-string / template-string в Python 3.6, который, на мой взгляд, прекрасно выглядит:
>>> f'{a:.2f}'
Это хорошо работает и с более длинными примерами, с операторами и не нуждающимися в скобках:
>>> 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
output
имеет точно такое же значение, как a
, так что вы могли бы написать print a
вместо print output
последней строки.
13.95
. Но так же print a
, для этого конкретного значения a
, в Python 2.7, так что не очень понятно, какой смысл был в шаге форматирования.
a == output
код, который вы показываете? Это дает True
мне, и я подозреваю, что это делает и для вас.
В руководстве по 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
Он делает именно то, что вы сказали, и работает правильно. Узнайте больше о путанице с плавающей точкой и, возможно, вместо этого попробуйте использовать десятичные объекты.
Используйте комбинацию десятичного объекта и метода 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')
Для исправления плавающей запятой в динамических типах языков, таких как 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')
getcontext().prec = 6
работает только для объема функции или всех местах?
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'
Как насчет лямбда-функции, как это:
arred = lambda x,n : x*(10**n)//1/(10**n)
Таким образом, вы можете просто сделать:
arred(3.141591657,2)
и получить
3.14
Это просто как 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: критика других: форматирование не округляет.
Для округления числа до разрешения лучше всего подходит следующий способ, который может работать с любым разрешением (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
numpy.round
точности / точности. Таким образом, он требует определить его как int перед умножением с разрешением. Я обновил код. Спасибо за это!
numpy.float64
результат np.round в float
или просто использовать round(value, 2)
. Действительный номер IEEE 754 не существует между 13,949999999999999 (= 1395/100) и 3,950000000000001 (= 1395 * .01). Почему вы думаете, что ваш метод является лучшим? Исходное значение 13,949999999999999289 (= значение = округлое (значение, 2)) еще точнее, чем ваше 13,95000000000000178 (напечатано np.float96). Теперь к моему ответу добавлена дополнительная информация о numpy, по которой вы, вероятно, ошибочно проголосовали. Первоначально это не было о numpy.
int
вас также можно использовать float
пример @szeitlin. Спасибо за ваш дополнительный комментарий. (Извините, но я вас не понизил)
Я использую метод нарезки строк. Это относительно быстро и просто.
Во-первых, преобразуйте число с плавающей точкой в строку и выберите желаемую длину.
float = str(float)[:5]
В приведенной выше строке мы преобразовали значение в строку, а затем сохранили строку только до первых четырех цифр или символов (включительно).
Надеюсь, это поможет!