Chcę a
zostać zaokrąglony do 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Ta round
funkcja nie działa w oczekiwany sposób.
Chcę a
zostać zaokrąglony do 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
Ta round
funkcja nie działa w oczekiwany sposób.
Odpowiedzi:
Napotykasz stary problem z liczbami zmiennoprzecinkowymi, że nie wszystkie liczby mogą być dokładnie reprezentowane. Wiersz poleceń pokazuje tylko pełną postać zmiennoprzecinkową z pamięci.
W przypadku reprezentacji zmiennoprzecinkowej zaokrąglona wersja ma ten sam numer. Ponieważ komputery są binarne, przechowują liczby zmiennoprzecinkowe jako liczby całkowite, a następnie dzielą je przez potęgę dwóch, więc 13,95 będzie reprezentowane w podobny sposób jak 125650429603636838 / (2 ** 53).
Liczby o podwójnej precyzji mają 53 bity (16 cyfr) precyzji, a zwykłe zmiennoprzecinkowe mają 24 bity (8 cyfr) precyzji. Typ zmiennoprzecinkowy w Pythonie używa podwójnej precyzji do przechowywania wartości.
Na przykład,
>>> 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
Jeśli szukasz tylko dwóch miejsc po przecinku (na przykład, aby wyświetlić wartość waluty), masz kilka lepszych możliwości:
"%.2f" % round(a,2)
że możesz umieścić nie tylko w printf, ale także w takich rzeczach jakstr()
float
) jest po prostu najbliższym dostępnym przybliżeniem liczby dziesiętnej (którą znasz jako człowiek). Nie ma takiej (finalnie reprezentowalnej) wartości binarnej jak 0.245. Po prostu nie istnieje i matematycznie nie może istnieć. Wartość binarna, która jest najbliższa 0,245, jest nieco mniejsza niż 0,245, więc naturalnie zaokrągla w dół. Podobnie, nie ma czegoś takiego jak 0.225 w binarnie, ale wartość binarna najbliższa 0,225 jest nieco większa niż 0,225, więc naturalnie zaokrągla się w górę.
Decimal
, i było to jedno z rozwiązań przedstawionych w tej odpowiedzi. Drugim było przekonwertowanie ilości na liczby całkowite i użycie arytmetyki liczb całkowitych. Oba te podejścia pojawiły się również w innych odpowiedziach i komentarzach.
Istnieją nowe specyfikacje formatu, mini-język specyfikacji formatu ciągu :
Możesz zrobić to samo co:
"{:.2f}".format(13.949999999999999)
Uwaga 1: powyższe zwraca ciąg znaków. Aby uzyskać pływak, po prostu owiń float(...)
:
float("{:.2f}".format(13.949999999999999))
Uwaga 2: zawijanie float()
nic nie zmienia:
>>> 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)
wydrukować '1,333.95'
.
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
Wbudowany round()
działa dobrze w Pythonie 2.7 lub nowszym.
Przykład:
>>> round(14.22222223, 2)
14.22
Sprawdź dokumentację .
round(2.16, 1)
podaj, 2.2
dlaczego python oferuje po prostu 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.
Uważam, że najprostszym podejściem jest użycie format()
funkcji.
Na przykład:
a = 13.949999999999999
format(a, '.2f')
13.95
Daje to liczbę zmiennoprzecinkową jako ciąg zaokrąglony do dwóch miejsc po przecinku.
Posługiwać się
print"{:.2f}".format(a)
zamiast
print"{0:.2f}".format(a)
Ponieważ to ostatnie może prowadzić do błędów wyjściowych podczas próby wyprowadzenia wielu zmiennych (patrz komentarze).
Większość liczb nie może być dokładnie przedstawiona w liczbach zmiennoprzecinkowych. Jeśli chcesz zaokrąglić liczbę, ponieważ tego właśnie wymaga twoja formuła matematyczna lub algorytm, to chcesz użyć rundy. Jeśli chcesz ograniczyć wyświetlanie do określonej precyzji, nie używaj nawet okrągłego formatu i po prostu sformatuj go jako ten ciąg. (Jeśli chcesz wyświetlić go za pomocą alternatywnej metody zaokrąglania, a istnieją tony, musisz połączyć oba podejścia.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
I wreszcie, choć być może najważniejsze, jeśli chcesz dokładnej matematyki, to wcale nie chcesz pływaków. Typowym przykładem jest zajmowanie się pieniędzmi i przechowywanie „centów” jako liczby całkowitej.
Wypróbuj poniższy kod:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
round
funkcji. Po drugie, ponieważ to rozwiązanie nadal wykorzystuje zmiennoprzecinkowy, pierwotny problem PO pozostaje, nawet w przypadku „poprawionej” wersji tego „rozwiązania”.
round
funkcji (która została użyta w pytaniu).
round()
nie działa tak, jak wspomniany PO.
Problem zaokrąglania wejścia / wyjścia został definitywnie rozwiązany w Pythonie 2.7.0 i 3.1 .
Prawidłowo zaokrągloną liczbę można odwrócić do przodu i do tyłu:
str -> float() -> repr() -> float() ...
lub Decimal -> float -> str -> Decimal
Typ dziesiętny nie jest już potrzebny do przechowywania.
(Oczywiście może być konieczne zaokrąglenie wyniku dodawania lub odejmowania zaokrąglonych liczb w celu wyeliminowania nagromadzonych błędów ostatniego bitu. Wyraźna arytmetyka dziesiętna może być nadal przydatna, ale konwersja na ciąg znaków o str()
(tzn. Z zaokrągleniem do 12 prawidłowych cyfr ) jest zwykle wystarczająca, jeśli nie jest wymagana ekstremalna dokładność lub ekstremalna liczba kolejnych operacji arytmetycznych).
Test nieskończony :
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+ :-)
Zobacz informacje o wersji Python 2.7 - inny język Zmienia czwarty akapit:
Konwersje między liczbami zmiennoprzecinkowymi a łańcuchami są teraz poprawnie zaokrąglane na większości platform. Te konwersje zachodzą w wielu różnych miejscach: str () na liczbach zmiennoprzecinkowych i liczbach zespolonych; konstrukcje zmiennoprzecinkowe i złożone; formatowanie numeryczne; szeregowania i DE-szeregowania pływaków i liczbach zespolonych z wykorzystaniem
marshal
,pickle
ijson
modułów; parsowanie pływaków i urojonych literałów w kodzie Pythona; oraz konwersja dziesiętna na zmiennoprzecinkową.W związku z tym repr () liczby zmiennoprzecinkowej x zwraca teraz wynik oparty na najkrótszym ciągu dziesiętnym, który gwarantuje zaokrąglenie z powrotem do x przy prawidłowym zaokrągleniu (w trybie zaokrąglania od połowy do parzystej). Poprzednio dawał ciąg oparty na zaokrąglaniu x do 17 cyfr dziesiętnych.
Więcej informacji: Formatowanie float
przed Pythonem 2.7 było podobne do bieżącego numpy.float64
. Oba typy używają tej samej 64-bitowej podwójnej precyzji IEEE 754 z 52-bitową mantysą. Dużą różnicą jest to, że jest sformatowana tak, że każda cyfra jest ważna; sekwencja jest bez przerw, a konwersja jest odwracalna. Po prostu: jeśli być może masz numer numpy.float64, przekonwertuj go na zwykły zmiennoprzecinkowy, aby sformatować go dla ludzi, a nie dla procesorów numerycznych, w przeciwnym razie nic więcej nie jest potrzebne w Pythonie 2.7+.np.float64.__repr__
jest często formatowany z nadmierną liczbą dziesiętną, aby żaden bit nie mógł zostać utracony, ale nie istnieje poprawna liczba IEEE 754 między 13,94999999999999999 a 13,950000000000001. Wynik nie jest przyjemny, a konwersja repr(float(number_as_string))
nie jest odwracalna w przypadku numpy. Z drugiej strony:float.__repr__
float
(podwójna precyzja) i normalnego round
, a nie numpy.double i jego konwersji na ciąg. Zwykłe zaokrąglanie w Pythonie naprawdę nie może być wykonane lepiej niż w Pythonie 2.7. Większość odpowiedzi została napisana przed wersją 2.7, ale są one przestarzałe, choć początkowo były bardzo dobre. To jest powód mojej odpowiedzi.
1
, z wyjątkiem „stopniowego niedomiaru”.
a*b
kontra b*a
. Dzięki za linki - Nostalgia.
W przypadku języka Python <3 (np. 2.6 lub 2.7) można to zrobić na dwa sposoby.
# Option one
older_method_string = "%.9f" % numvar
# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)
Ale zauważ, że dla wersji Pythona powyżej 3 (np. 3.2 lub 3.3) preferowana jest opcja druga .
Aby uzyskać więcej informacji na temat opcji drugiej, sugeruję ten link na temat formatowania ciągów z dokumentacji Pythona .
Aby uzyskać więcej informacji na temat opcji pierwszej, ten link wystarczy i zawiera informacje na temat różnych flag .
Odniesienie: Konwertuj liczbę zmiennoprzecinkową na określoną dokładność, a następnie skopiuj do ciągu
numvar=12.456
, to "{:.2f}".format(numvar)
daje, 12.46
ale "{:2i}".format(numvar)
daje błąd i oczekuję 12
.
Możesz zmodyfikować format wyjściowy:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Wydaje się, że nikt tutaj jeszcze o tym nie wspominał, więc pozwólcie, że podam przykład w formacie f-string / template-string w Pythonie 3.6, który moim zdaniem jest pięknie schludny:
>>> f'{a:.2f}'
Działa dobrze również z dłuższymi przykładami, z operatorami i nie potrzebującymi parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
Możesz użyć operatora formatu do zaokrąglenia wartości do 2 miejsc po przecinku w pythonie:
print(format(14.4499923, '.2f')) // output is 14.45
W Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
ma dokładnie taką samą wartość jak a
, więc równie dobrze możesz napisać print a
zamiast print output
w ostatnim wierszu.
13.95
. Podobnie jest print a
w przypadku tej konkretnej wartości a
w Pythonie 2.7, więc nie jest do końca jasne, jaki był sens kroku formatowania.
a == output
pokazać kod? Daje True
mi to i podejrzewam, że to także dla ciebie.
Samouczek języka Python zawiera dodatek o nazwie Arytmetyka zmiennoprzecinkowa: problemy i ograniczenia . Przeczytaj to. Wyjaśnia, co się dzieje i dlaczego Python robi wszystko, co w jego mocy. Ma nawet przykład, który pasuje do twojego. Pozwól, że zacytuję trochę:
>>> 0.1 0.10000000000000001
możesz pokusić się o użycie tej
round()
funkcji, aby przyciąć ją z powrotem do oczekiwanej cyfry. Ale to nie robi różnicy:>>> round(0.1, 1) 0.10000000000000001
Problem polega na tym, że przechowywana binarna wartość zmiennoprzecinkowa
“0.1”
była już najlepszym możliwym przybliżeniem binarnym1/10
, więc próba zaokrąglenia jej ponownie nie może poprawić: była już tak dobra, jak to możliwe.Inną konsekwencją jest to, że ponieważ
0.1
nie jest dokładnie1/10
, sumowanie dziesięciu wartości0.1
może nie dać dokładnie1.0
:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Jedną alternatywą i rozwiązaniem twoich problemów byłoby użycie decimal
modułu.
Jak wskazał @Matt, Python 3.6 dostarcza ciągi f , a także może używać zagnieżdżonych parametrów :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
który wyświetli się result: 2.35
Robi dokładnie to, co mu kazałeś i działa poprawnie. Przeczytaj więcej o pomyleniu zmiennoprzecinkowym i spróbuj zamiast tego obiektów dziesiętnych .
Użyj kombinacji obiektu Decimal i metody 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')
Używam tej techniki do ustalania liczb zmiennoprzecinkowych w językach dynamicznych typu, takich jak Python i 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
Możesz także użyć Dziesiętnej w następujący sposób:
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
działa tylko dla zakresu funkcji lub wszystkich miejsc?
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)
Wyniki:
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'
Co z taką funkcją lambda:
arred = lambda x,n : x*(10**n)//1/(10**n)
W ten sposób możesz po prostu:
arred(3.141591657,2)
i dostać
3.14
To proste jak 1,2,3:
użyj dziesiętnego modułu do szybkiej poprawnie zaokrąglonej arytmetyki zmiennoprzecinkowej dziesiętnej:
d = dziesiętny (10000000,0000009)
aby zaokrąglić:
d.quantize(Decimal('0.01'))
spowoduje wyniki z Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
LUB
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: krytyka innych: formatowanie nie jest zaokrąglone.
Aby zaokrąglić liczbę do rozdzielczości, najlepszym sposobem jest następujący sposób, który może działać z dowolną rozdzielczością (0,01 dla dwóch miejsc po przecinku lub nawet innych kroków):
>>> 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
dokładności / precyzji. Wymaga więc zdefiniowania go jako int przed pomnożeniem przez rozdzielczość. Zaktualizowałem kod. Dziękuję za to!
numpy.float64
wyniku np.round na float
lub po prostu użycie round(value, 2)
. Nie istnieje prawidłowy numer IEEE 754 między 13,949999999999999 (= 1395 / 100.) a 3.950000000000001 (= 1395 * .01). Dlaczego uważasz, że twoja metoda jest najlepsza? Oryginalna wartość 13,949999999999999289 (= wartość = zaokrąglona (wartość, 2)) jest jeszcze bardziej dokładna niż twoja 13,95000000000000178 (wydrukowana przez np.float96). Więcej informacji na temat numpy jest teraz dodanych do mojej odpowiedzi , którą prawdopodobnie przypadkowo przegłosowałeś. Pierwotnie nie chodziło o numpy.
int
ciebie możesz również użyć float
na przykład @szeitlin. Dziękujemy za dodatkowy komentarz. (Przepraszam, ale nie przegłosowałem)
Metodą, której używam, jest cięcie strun. Jest to stosunkowo szybkie i proste.
Najpierw przekonwertuj liczbę zmiennoprzecinkową na ciąg, wybierz długość, jaką chcesz.
float = str(float)[:5]
W powyższym pojedynczym wierszu przekonwertowaliśmy wartość na ciąg znaków, a następnie zachowaliśmy ciąg tylko pierwszych czterech cyfr lub znaków (włącznie).
Mam nadzieję, że to pomaga!