Я хочу 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()
це не працює, як згадується в ОП.
Проблема округлення вводу / виводу була остаточно вирішена 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
модулів; розбір плаваючих та уявних літералів в коді Python; і десяткове перетворення в плавати.З цим пов'язано, repr () числа з плаваючою комою x тепер повертає результат на основі найкоротшого десяткового рядка, який гарантовано округлює назад до x при правильному округленні (при режимі округлення від пів-до рівного). Раніше він давав рядок на основі округлення х до 17 десяткових цифр.
Додаткова інформація: Форматування float
до Python 2.7 було схожим на поточне numpy.float64
. Обидва типи використовують однакову 64-бітну IEEE 754 подвійної точності з 52-бітною мантісою. Велика різниця полягає в тому, що np.float64.__repr__
вони часто форматуються з надмірним десятковим числом, так що жоден біт не може бути втрачений, але не існує дійсного номера IEEE 754 між 13.9499999999999999 та 13.950000000000001. Результат не є приємним, і перетворення repr(float(number_as_string))
не є оборотним з нумером. З іншої сторони: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) варіант 2 є кращим .
Для отримання додаткової інформації щодо другого варіанту пропоную це посилання щодо форматування рядків з документації 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')
Ви можете використовувати оператор формату для округлення значення до двох знаків після коми в 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
Це робить саме те, що ви йому сказали, і працює правильно. Детальніше про плутанину з плаваючою комою та, можливо, спробуйте десяткові об'єкти замість цього.
Використовуйте комбінацію методу об'єкта Decimal і 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
Ви також можете використовувати 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')
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:
використовувати десятковий модуль для швидкої арифметики з десятковою плаваючою колом:
d = десяткова (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, що ви, мабуть, спростували помилково. Спочатку мова не йшла про нудоту.
int
вас також можна використовувати float
приклад @szeitlin. Дякую за додатковий коментар (Вибачте, але я вас не порушив)
Я використовую метод методу нарізки струн. Це відносно швидко і просто.
Спочатку перетворіть поплавок на рядок, виберіть довжину, яку ви хотіли б.
float = str(float)[:5]
У наведеному вище рядку ми перетворили значення на рядок, а потім зберегли рядок лише до перших чотирьох цифр або символів (включно).
Сподіваюся, що це допомагає!