Aku ingin a
yang akan dibulatkan ke 13.95.
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
The bulat
fungsi tidak bekerja dengan cara yang saya harapkan.
Anda berjalan ke dalam tahun dengan angka floating point bahwa tidak semua angka dapat direpresentasikan dengan tepat. Baris perintah ini hanya menunjukkan anda full floating point bentuk dari memori.
Dengan representasi titik mengambang, anda bulat versi nomor yang sama. Sejak komputer biner, mereka menyimpan floating point bilangan sebagai integer dan kemudian membaginya dengan kekuatan dua jadi 13.95 akan diwakili dengan cara yang sama untuk 125650429603636838/(2**53).
Presisi ganda nomor 53 bit (16 digit) presisi dan teratur mengapung memiliki 24 bit (8 digit) presisi. The floating point tipe di Python menggunakan double precision untuk menyimpan nilai-nilai.
Misalnya,
>>> 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
Jika anda setelah hanya dua tempat desimal (untuk menampilkan nilai mata uang, misalnya), maka anda memiliki beberapa pilihan yang lebih baik:
Ada format baru spesifikasi, Format String Spesifikasi Mini-Bahasa:
Anda bisa melakukan hal yang sama seperti:
"{0:.2f}".format(13.949999999999999)
Catatan yang di atas mengembalikan sebuah string. Dalam rangka untuk mendapatkan float, cukup bungkus dengan float(...)
:
float("{0:.2f}".format(13.949999999999999))
Catatan yang membungkus dengan float()
doesn't mengubah apa-apa:
>>> 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
Built-in round()
bekerja dengan baik dengan Python 2.7 atau yang lebih baru.
Contoh:
>>> round(14.22222223, 2)
14.22
Check out dokumentasi.
Angka paling tidak sama persis diwakili dalam mengapung. Jika anda ingin putaran jumlah karena itu's apa yang anda rumus matematika atau algoritma yang membutuhkan, maka anda ingin menggunakan putaran. Jika anda hanya ingin membatasi tampilan dengan presisi tertentu, kemudian don't bahkan menggunakan putaran dan hanya format sebagai string. (Jika anda ingin menampilkannya dengan beberapa alternatif metode pembulatan, dan ada ton, maka anda perlu untuk mencampur dua pendekatan.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
Dan terakhir, meskipun mungkin yang paling penting, jika anda ingin tepat math maka anda don't ingin mengapung di semua. Contoh biasa berurusan dengan uang dan untuk menyimpan 'sen' sebagai integer.
Gunakan
print"{:.2f}".format(a)
bukan
print"{0:.2f}".format(a)
Karena yang terakhir dapat menyebabkan output kesalahan ketika mencoba untuk output beberapa variabel (lihat komentar).
Dengan Python < 3 (misalnya 2.6 atau 2,7), ada dua cara untuk melakukannya.
# Option one
older_method_string = "%.9f" % numvar
# Option two (note ':' before the '.9f')
newer_method_string = "{:.9f}".format(numvar)
Tetapi perhatikan bahwa untuk Python versi 3 di atas (misalnya 3.2 3.3), pilihan kedua adalah pilihan.
Untuk informasi lebih lanjut tentang opsi dua, saya sarankan link ini di string format dari dokumentasi Python.
Dan untuk informasi lebih lanjut tentang opsi satu, link ini akan cukup dan memiliki informasi tentang berbagai bendera.
Pembulatan masalah input / output telah diselesaikan secara definitif oleh Python 2.7.0 dan 3.1.
Benar bulat nomor dapat reversibel dikonversi bolak-balik:
str -> float() -> repr() -> float() ...
atau Desimal -> float -> str -> Desimal
Desimal tidak diperlukan untuk penyimpanan lagi.
(Tentu, hal itu dapat diperlukan untuk melengkapi hasil dari penjumlahan atau pengurangan bilangan bulat untuk menghilangkan akumulasi terakhir sedikit kesalahan. Eksplisit Desimal aritmatika bisa tetap berguna, tapi konversi ke string dengan str()
(yang dengan pembulatan ke 12 digit) cukup baik biasanya jika ada akurasi ekstrim atau tidak ekstrim nomor berturut-turut operasi aritmatika diperlukan.)
Tak terbatas tes:
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+ :-)
Lihat catatan Rilis Python 2.7 - Perubahan Bahasa Lain alinea keempat:
Konversi antara angka floating-point dan string sekarang benar bulat pada kebanyakan platform. Konversi ini terjadi di banyak tempat yang berbeda: str() pada mengapung dan bilangan kompleks; float dan kompleks konstruktor; format numerik; serialisasi dan de-serialisasi mengapung dan bilangan kompleks menggunakan
marshal
,acar
danjson
modul; parsing mengapung dan imajiner literal di kode Python; dan Desimal-untuk-float konversi.Terkait hal ini, repr() floating-point nomor x sekarang kembali hasil berdasarkan terpendek desimal string yang dijamin untuk putaran kembali ke x di bawah yang benar pembulatan (round-setengah-untuk-bahkan mode pembulatan). Sebelumnya itu memberi sebuah string berdasarkan pembulatan x 17 digit desimal.
Informasi lebih lanjut: format float
sebelum Python 2.7 mirip dengan saat ini numpy.float64
. Kedua tipe ini sama-sama menggunakan 64 bit IEEE 754 presisi ganda dengan 52 bit mantissa. Perbedaan besar adalah bahwa np.float64.__repr__
diformat sering dengan berlebihan bilangan desimal sehingga tidak ada sedikit bisa hilang, tapi tidak berlaku IEEE 754 jumlah yang ada antara 13.949999999999999 dan 13.950000000000001. Hasilnya tidak bagus dan konversi repr(float(number_as_string))
adalah tidak reversibel dengan numpy. Di sisi lain: float.__repr__
diformat sehingga setiap digit adalah penting; urutan tanpa celah dan konversi adalah reversibel. Sederhana: Jika anda mungkin memiliki numpy.float64 nomor, mengkonversi ke normal mengapung agar dapat diformat untuk manusia, bukan untuk numerik prosesor, jika tidak ada lagi yang diperlukan dengan Python 2.7+.
Anda dapat menggunakan format operator untuk pembulatan nilai sampai dengan 2 angka desimal di python:
print(format(14.4499923, '.2f')) // output is 14.45
Tak seorang pun di sini tampaknya telah disebutkan itu belum, jadi biarkan saya memberikan contoh dalam Python 3.6's f-string/template-format string, yang saya pikir adalah indah rapi:
>>> f'{a:.2f}'
Ia bekerja dengan baik lagi contoh-contoh juga, dengan operator dan tidak membutuhkan parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
Di Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
Python tutorial memiliki lampiran yang disebut Aritmatika Floating Point: Masalah dan Keterbatasan. Baca itu. Ini menjelaskan apa yang terjadi dan mengapa Python adalah melakukan yang terbaik. Bahkan contoh yang cocok dengan anda. Mari saya kutip sedikit:
0.1 0.10000000000000001
anda mungkin akan tergoda untuk menggunakan
round()
fungsi untuk memotong kembali untuk single digit yang anda harapkan. Tapi itu tidak membuat perbedaan:bulat(0.1, 1) 0.10000000000000001
masalahnya adalah bahwa biner nilai floating-point yang disimpan untuk
"0.1"
sudah yang terbaik biner pendekatan1/10
, jadi mencoba untuk bulat lagi tidak bisa membuatnya lebih baik: itu sudah sebagai baik karena mendapat.konsekuensi Lain adalah bahwa sejak
0.1
bukan1/10
, menyimpulkan sepuluh nilai-nilai dari0.1
mungkin tidak menghasilkan persis1.0
, berupa:sum = 0.0 for i in range(10): ... jumlah += 0.1 ... sum 0.99999999999999989
Salah satu alternatif dan solusi untuk masalah-masalah anda akan menggunakan decimal
modul.
Seperti @Matt mencontohkan, Python 3.6 menyediakan f-string, dan mereka juga dapat menggunakan bersarang parameter:
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
yang akan menampilkan hasil: 2.35
It's melakukan apa yang anda diberitahu untuk melakukan dan bekerja dengan benar. Baca lebih lanjut tentang floating point kebingungan dan mungkin mencoba desimal benda-benda yang bukan.
Untuk memperbaiki floating point di jenis-bahasa dinamis seperti Python dan JavaScript, saya menggunakan teknik ini
# 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
Anda juga dapat menggunakan Desimal sebagai berikut:
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')
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)
Hasil:
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'
Menggunakan kombinasi dari Desimal objek dan bulat() metode.
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')