13,95'ea
yuvarlanmak istiyorum .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
round
Fonksiyon beklediğim şekilde çalışmıyor.
13,95'ea
yuvarlanmak istiyorum .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
round
Fonksiyon beklediğim şekilde çalışmıyor.
Yanıtlar:
Sen içine çalıştıran eski bir sorun değil tüm sayılar tam olarak temsil edilebilir kayan nokta numaraları ile. Komut satırı, bellekten tam kayan nokta formunu gösterir.
Kayan nokta gösterimi ile, yuvarlatılmış versiyonunuz aynı sayıdır. Bilgisayarlar ikili olduğundan, kayan nokta sayılarını bir tamsayı olarak saklarlar ve daha sonra ikiye bölerler, böylece 13.95, 125650429603636838 / (2 ** 53) ile aynı şekilde temsil edilir.
Çift kesinlikli rakamların 53 bit (16 basamaklı) hassasiyeti vardır ve normal şamandıraların 24 bit (8 basamaklı) hassasiyeti vardır. Python kayan nokta tipi çift hassas kullanır değerlerini saklamak için.
Örneğin,
>>> 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
Yalnızca iki ondalık basamağın peşindeyseniz (örneğin bir para birimi değeri görüntülemek için), daha iyi birkaç seçeneğiniz vardır:
"%.2f" % round(a,2)
sizin gibi printf değil, aynı zamanda bu tür şeylere sadece koyabilirsinizstr()
float
), ondalık sayının (bir insan olarak aşina olduğunuz) mevcut en yakın yaklaşımı olduğunu anlamalısınız . 0.245 gibi (sonlu olarak temsil edilebilir) bir ikili değer yoktur. Basitçe mevcut değildir ve matematiksel olarak var olamaz . 0.245'e en yakın ikili değer 0.245'ten biraz daha azdır , bu nedenle doğal olarak yuvarlanır. Benzer şekilde, ikili dosyada 0.225 diye bir şey yoktur, ancak 0.225'e en yakın ikili değer 0.225'ten biraz daha büyüktür , bu yüzden doğal olarak yuvarlanır.
Decimal
ve bu cevapta sunulan çözümlerden biriydi. Diğeri miktarlarınızı tamsayıya dönüştürmek ve tamsayı aritmetiği kullanmaktı. Bu yaklaşımların her ikisi de diğer cevaplarda ve yorumlarda da ortaya çıktı.
Yeni biçim özellikleri vardır, Dize Biçimi Belirtimi Mini Dil :
Aynı şeyi yapabilirsiniz:
"{:.2f}".format(13.949999999999999)
Not 1: Yukarıdaki bir dize döndürür. Şamandıra olarak almak için şunlarla sarın float(...)
:
float("{:.2f}".format(13.949999999999999))
Not 2: ile sarmak float()
hiçbir şeyi değiştirmez:
>>> 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)
hangi baskıları da yapabilirsiniz '1,333.95'
.
float()
; float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
Yerleşik round()
eserlerin gayet Python 2.7 veya daha sonra.
Misal:
>>> round(14.22222223, 2)
14.22
Check belgelere .
round(2.16, 1)
vermek 2.2
piton sadece sunuyoruz truncate
fonk
>>> 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.
En basit yaklaşımın format()
işlevi kullanmak olduğunu hissediyorum .
Örneğin:
a = 13.949999999999999
format(a, '.2f')
13.95
Bu, iki ondalık basamağa yuvarlanmış bir dize olarak bir kayan sayı oluşturur.
kullanım
print"{:.2f}".format(a)
onun yerine
print"{0:.2f}".format(a)
Çünkü ikincisi birden çok değişken çıkarmaya çalışırken çıkış hatalarına yol açabilir (bkz. Yorumlar).
Çoğu sayı şamandıralarda tam olarak temsil edilemez. Eğer sayıyı yuvarlamak istiyorsanız, matematiksel formülünüzün veya algoritmanızın gerektirdiği şeyse, o zaman raund kullanmak istiyorsunuz. Ekranı belirli bir hassasiyetle kısıtlamak istiyorsanız, yuvarlak bile kullanmayın ve sadece bu dize olarak biçimlendirmeyin. (Alternatif bir yuvarlama yöntemiyle görüntülemek istiyorsanız ve ton varsa, iki yaklaşımı karıştırmanız gerekir.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
Ve son olarak, belki de en önemlisi, tam matematik istiyorsanız o zaman hiç yüzer istemezsiniz. Genel örnek parayla uğraşmak ve 'sent'leri bir tamsayı olarak saklamaktır.
Aşağıdaki kodu deneyin:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
round
işlevi kullanarak bunu yapmanın bir yararı yoktur . Başka bir şey için, bu çözüm hala kayan nokta kullandığından, OP'nin orijinal sorunu, bu "çözümün" "düzeltilmiş" sürümü için bile kalır.
round
işlevin gereksiz bir şekilde yeniden uygulanmasıdır (bu soruda kullanılmıştır).
round()
, OP'nin belirttiği gibi çalışmazsa gereklidir .
Girdi / çıktının yuvarlama problemi Python 2.7.0 ve 3.1 tarafından kesin olarak çözülmüştür .
Doğru yuvarlanmış bir sayı geri dönüşümlü olarak ileri geri dönüştürülebilir:
str -> float() -> repr() -> float() ...
veya Decimal -> float -> str -> Decimal
artık depolama için A Ondalık türü gerekli değildir.
(Doğal olarak, biriken son bit hatalarını ortadan kaldırmak için yuvarlak sayıların toplanması veya çıkarılmasının bir sonucunu yuvarlamak gerekebilir. Açık bir Ondalık aritmetik yine de kullanışlı olabilir, ancak dizeye bir dönüştürme str()
(12 geçerli basamağa yuvarlama ile) ) genellikle aşırı doğruluk veya aşırı sayıda ardışık aritmetik işlem gerekmiyorsa yeterince iyidir.)
Sonsuz test :
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+ :-)
Sürüm notlarına bakın Python 2.7 - Diğer Dil Dördüncü paragrafı değiştirir:
Kayan nokta sayıları ve dizeler arasındaki dönüşümler artık çoğu platformda doğru şekilde yuvarlanmaktadır . Bu dönüşümler birçok farklı yerde gerçekleşir: şamandıralar ve karmaşık sayılar üzerinde str (); şamandıra ve kompleks yapıcılar; sayısal biçimlendirme; seri ve kullanma yüzen ve karmaşık sayıları de-serializing
marshal
,pickle
vejson
modüller; Python kodunda şamandıra ve sanal değişmez değerlerin ayrıştırılması; ve Ondalık-kayan nokta dönüştürme.Bununla ilgili olarak, kayan nokta sayısı x'in repr () değeri artık doğru yuvarlama altında (yuvarlamadan ikiye yuvarlama modunda) x'e geri dönmesi garanti edilen en kısa ondalık dizeye dayalı bir sonuç döndürür . Daha önce, x ila 17 ondalık basamağa yuvarlamaya dayalı bir dize veriyordu.
Daha fazla bilgi:float
Python 2.7'den önceki biçimlendirmesi akıma benzerdi numpy.float64
. Her iki tip de 52 bit mantis ile aynı 64 bit IEEE 754 çift kesinlik kullanır. Büyük bir fark, np.float64.__repr__
aşırı bir ondalık sayı ile sık sık biçimlendirilmesidir, böylece bit kaybedilemez, ancak 13.94999999999999999 ile 13.950000000000001 arasında geçerli bir IEEE 754 numarası yoktur. Sonuç hoş değil ve dönüşüm repr(float(number_as_string))
numpy ile tersine çevrilemez. Diğer yandan:float.__repr__
her basamak önemli olacak şekilde biçimlendirilir; sekans boşluksuzdur ve dönüşüm tersine çevrilebilir. Basitçe: Belki bir numpy.float64 numaranız varsa, sayısal işlemciler için değil, insanlar için biçimlendirmek için normal şamandıraya dönüştürün, aksi takdirde Python 2.7+ ile başka bir şey gerekmez.
float
(çift kesinlik) ve normal round
, numpy.double ve dizeye dönüşümü hakkında değildi. Düz Python yuvarlama gerçekten Python 2.7'den daha iyi yapılamaz. Cevapların çoğu 2.7'den önce yazılmıştır, ancak orijinal olarak çok iyi olmalarına rağmen eskimişlerdir. Cevabımın nedeni bu.
1
, "kademeli alt akış" hariç , dolaylı olarak 53 bit .
a*b
vs b*a
. Linkler için teşekkürler - Nostalji.
Python <3 (ör. 2.6 veya 2.7) ile bunu yapmanın iki yolu vardır.
# Option one
older_method_string = "%.9f" % numvar
# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)
Ancak 3'ün üzerindeki Python sürümleri için (örn. 3.2 veya 3.3), ikinci seçeneğin tercih edildiğine dikkat edin .
İkinci seçenek hakkında daha fazla bilgi için , Python belgelerinden dize biçimlendirme ile ilgili bu bağlantıyı öneriyorum .
Birinci seçenek hakkında daha fazla bilgi için, bu bağlantı yeterli olacak ve çeşitli bayraklar hakkında bilgi sahibi olacaktır .
Başvuru: Kayan nokta numarasını belirli bir kesinlike dönüştürün ve sonra dizeye kopyalayın
numvar=12.456
, o zaman "{:.2f}".format(numvar)
verir 12.46
ama "{:2i}".format(numvar)
bir hata verir ve ben bekliyorum 12
.
Çıktı biçimini değiştirebilirsiniz:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
Burada kimse henüz bahsetmemiş gibi görünüyor, bu yüzden güzelce düzgün olduğunu düşünüyorum Python 3.6'nın f-string / template-string biçiminde bir örnek vereyim:
>>> f'{a:.2f}'
Operatörlerle ve parenlere ihtiyaç duymadan daha uzun örneklerle de iyi çalışır:
>>> print(f'Completed in {time.time() - start:.2f}s')
Python'da değeri 2 ondalık basamağa yuvarlamak için format operatörünü kullanabilirsiniz :
print(format(14.4499923, '.2f')) // output is 14.45
Python 2.7'de:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
ile tam olarak aynı değere sahiptir a
, bu nedenle son satır print a
yerine yazmış da olabilirsiniz print output
.
13.95
. Ancak , Python 2.7'deki print a
bu özel değer için a
, biçimlendirme adımının amacının ne olduğu gerçekten net değil.
a == output
kodu gerçekten denediniz mi? Benim için veriyor True
ve sizin için de olduğundan şüpheleniyorum.
Python dersinde Kayan Nokta Aritmetiği adlı bir ek bulunmaktadır : Sorunlar ve Sınırlamalar . Oku onu. Neler olduğunu ve Python'un neden elinden gelenin en iyisini yaptığını açıklıyor. Sizinkiyle eşleşen bir örneği bile var. Biraz alıntı yapmama izin verin:
>>> 0.1 0.10000000000000001
round()
beklediğiniz tek basamağa geri kesmek için bu işlevi kullanabilirsiniz . Ancak bu bir fark yaratmaz:>>> round(0.1, 1) 0.10000000000000001
Sorun şu ki, depolanan ikili kayan nokta değeri
“0.1”
zaten mümkün olan en iyi ikili yaklaşımdı1/10
, bu yüzden tekrar yuvarlamaya çalışmak daha iyi olamaz: zaten olduğu kadar iyi.Başka bir sonuç,
0.1
tam olarak olmadığı için1/10
, on değerin toplanmasının0.1
tam olarak verilemeyebileceğidir1.0
:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Bir alternatif ve sorunlarınıza çözüm decimal
modülü kullanmak olacaktır .
@Matt'ın belirttiği gibi, Python 3.6 f-dizeleri sağlar ve ayrıca iç içe parametreleri de kullanabilirler :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
hangisi görüntülenecek result: 2.35
Tam olarak söylediklerinizi yapıyor ve düzgün çalışıyor. Kayan nokta karışıklığı hakkında daha fazla bilgi edinin ve bunun yerine ondalık nesneleri deneyin .
Ondalık nesne ve round () yönteminin birleşimini kullanın.
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')
Kayan noktayı Python ve JavaScript gibi tip-dinamik dillerde düzeltmek için bu tekniği kullanıyorum
# 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
Ondalık'ı aşağıdaki gibi de kullanabilirsiniz:
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
sadece işlevin kapsamı veya tüm yerler için çalışır?
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)
Sonuçlar:
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'
Peki bu gibi bir lambda işlevi hakkında:
arred = lambda x,n : x*(10**n)//1/(10**n)
Bu şekilde şunları yapabilirsiniz:
arred(3.141591657,2)
ve Al
3.14
1,2,3 gibi basit:
Kullanım ondalıkhızlı doğru yuvarlanmış ondalık kayan nokta aritmetiği için modülü :
d = Ondalık (10000000.0000009)
yuvarlama elde etmek için:
d.quantize(Decimal('0.01'))
ile sonuçlanacak Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
VEYA
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: başkalarının eleştirisi: biçimlendirme yuvarlama değildir.
Bir sayıyı bir çözünürlüğe yuvarlamak için en iyi yol, herhangi bir çözünürlükle (iki ondalık veya 0,01 adım için 0,01) çalışabilen şu değerdir:
>>> 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
doğruluk / kesinlikten geldiğini görüyorum . Bu yüzden çözünürlükle çarpmadan önce int olarak tanımlanması gerekir. Kodu güncelledim. Bunun için teşekkür ederim!
numpy.float64
np.round'un sonucunu float
veya sadece kullanmak için dönüştürmektir round(value, 2)
. 13.949999999999999 (= 1395 / 100.) ile 3.950000000000001 (= 1395 * .01) arasında geçerli bir IEEE 754 numarası yok. Neden yönteminizin en iyisi olduğunu düşünüyorsunuz? Orijinal değer 13.949999999999999289 (= değer = yuvarlak (değer, 2)) 13.95000000000000178 (np.float96 ile basılmıştır) değerinden daha kesindir. Numpy için de diğer bilgiler artık eklenir cevabım muhtemelen yanlışlıkla downvoted söyledi. Başlangıçta numpy ile ilgili değildi.
int
de kullanabilirsin float
. Ek yorumunuz için teşekkür ederiz. (Üzgünüm ama seni küçümsemedim)
Kullandığım yöntem dize dilimleme yöntemidir. Nispeten hızlı ve basit.
İlk olarak, şamandırayı bir dizeye dönüştürün, olmasını istediğiniz uzunluğu seçin.
float = str(float)[:5]
Yukarıdaki tek satırda, değeri bir dizeye dönüştürdük, sonra dizeyi yalnızca ilk dört basamağına veya karakterine (dahil) tuttuk.
Umarım yardımcı olur!