Saya ingin a
dibulatkan ke 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
The round
fungsi tidak bekerja seperti yang saya harapkan.
python
floating-point
rounding
precision
ShadowRanger
sumber
sumber
Jawaban:
Anda mengalami masalah lama dengan angka floating point yang tidak semua angka dapat diwakili secara tepat. Baris perintah hanya menunjukkan kepada Anda formulir floating point penuh dari memori.
Dengan representasi floating point, versi bulat Anda adalah angka yang sama. Karena komputer adalah biner, mereka menyimpan angka floating point sebagai bilangan bulat dan kemudian membaginya dengan kekuatan dua sehingga 13,95 akan diwakili dengan cara yang sama dengan 125650429603636838 / (2 ** 53).
Angka presisi ganda memiliki 53 bit (16 digit) presisi dan float reguler memiliki 24 bit (8 digit) presisi. Tipe floating point di Python menggunakan presisi ganda untuk menyimpan nilai-nilai.
Sebagai contoh,
Jika Anda hanya mengejar dua tempat desimal (untuk menampilkan nilai mata uang, misalnya), maka Anda memiliki beberapa pilihan yang lebih baik:
sumber
"%.2f" % round(a,2)
Anda dapat dimasukkan tidak hanya di printf, tetapi juga dalam hal-hal sepertistr()
float
) adalah perkiraan terdekat yang tersedia dari angka desimal (yang Anda kenal sebagai manusia). Tidak ada nilai biner (yang dapat diwakili) seperti 0,245. Itu tidak ada, dan secara matematis tidak bisa ada. Nilai biner yang paling dekat dengan 0,245 sedikit lebih kecil dari 0,245, jadi secara alami itu dibulatkan ke bawah. Demikian juga, tidak ada yang namanya 0,225 dalam biner, tetapi nilai biner yang paling dekat dengan 0,225 sedikit lebih besar dari 0,225, jadi secara alami itu akan bertambah.Decimal
, dan itu adalah salah satu solusi yang disajikan dalam jawaban ini. Yang lainnya adalah mengubah jumlah Anda menjadi bilangan bulat dan menggunakan bilangan bulat aritmatika. Kedua pendekatan ini juga muncul dalam jawaban dan komentar lainnya.Ada spesifikasi format baru, Spesifikasi Format Mini-Bahasa String :
Anda dapat melakukan hal yang sama seperti:
Catatan 1: di atas mengembalikan sebuah string. Untuk mendapatkan float, cukup bungkus dengan
float(...)
:Catatan 2: membungkus dengan
float()
tidak mengubah apa pun:sumber
'{0:,.2f}'.format(1333.949999999)
mencetak'1,333.95'
.float()
;float("{0:.2f}".format(13.9499999))
f"Result is {result:.2f}"
Built-in
round()
berfungsi dengan baik di Python 2.7 atau yang lebih baru.Contoh:
Lihatlah dokumentasinya .
sumber
round(2.16, 1)
berikan2.2
mengapa python hanya menawarkantruncate
func>>> round(2.675, 2) 2.67
docs.python.org/2/tutorial/floatingpoint.htmlNote 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.
Saya merasa bahwa pendekatan yang paling sederhana adalah menggunakan
format()
fungsinya.Sebagai contoh:
Ini menghasilkan angka float sebagai string dibulatkan ke dua titik desimal.
sumber
Menggunakan
dari pada
Karena yang terakhir dapat menyebabkan kesalahan output ketika mencoba untuk output beberapa variabel (lihat komentar).
sumber
Sebagian besar angka tidak dapat direpresentasikan secara tepat dalam pelampung. Jika Anda ingin membulatkan angka karena itu yang dibutuhkan rumus atau algoritma matematika Anda, maka Anda ingin menggunakan angka bulat. Jika Anda hanya ingin membatasi tampilan hingga presisi tertentu, maka jangan gunakan putaran dan format saja sebagai string itu. (Jika Anda ingin menampilkannya dengan beberapa metode pembulatan alternatif, dan ada banyak, maka Anda perlu mencampur kedua pendekatan tersebut.)
Dan terakhir, meskipun mungkin yang paling penting, jika Anda ingin matematika yang tepat maka Anda tidak ingin mengapung sama sekali. Contoh biasa adalah berurusan dengan uang dan menyimpan 'sen' sebagai bilangan bulat.
sumber
Coba kode di bawah ini:
sumber
round
fungsi di tempat pertama. Untuk hal lain, karena solusi ini masih menggunakan floating point, masalah asli OP tetap ada, bahkan untuk versi "yang diperbaiki" dari "solusi" ini.round
fungsi yang tidak perlu (yang digunakan dalam pertanyaan).round()
tidak berfungsi seperti OP yang disebutkan.TLDR;)
Masalah pembulatan input / output telah diselesaikan secara definitif oleh Python 2.7.0 dan 3.1 .
Angka yang dibulatkan dengan benar dapat dikonversi secara bolak-balik:
str -> float() -> repr() -> float() ...
atauDecimal -> float -> str -> Decimal
Jenis desimal tidak diperlukan lagi untuk penyimpanan.
(Secara alami, mungkin perlu untuk membulatkan hasil penambahan atau pengurangan angka bulat untuk menghilangkan akumulasi kesalahan bit terakhir. Aritmatika Desimal eksplisit masih bisa berguna, tetapi konversi ke string oleh
str()
(yaitu dengan membulatkan menjadi 12 digit yang valid) ) cukup baik biasanya jika tidak ada akurasi ekstrim atau tidak ada jumlah ekstrim operasi aritmatika berturut-turut diperlukan.)Tes tak terbatas :
Dokumentasi
Lihat catatan Rilis Python 2.7 - Perubahan Bahasa Lainnya paragraf keempat:
Masalah terkait
Informasi lebih lanjut: Pemformatan
float
sebelum Python 2.7 mirip dengan saat ininumpy.float64
. Kedua jenis menggunakan 64 bit IEEE 754 ganda yang sama presisi dengan mantissa 52 bit. Perbedaan besar adalah yang diformat sehingga setiap digit penting; urutannya tanpa celah dan konversi dapat dibalik. Cukup: Jika Anda mungkin memiliki nomor numpy.float64, ubah nomor itu menjadi float normal untuk diformat untuk manusia, bukan untuk pengolah angka, jika tidak, tidak ada lagi yang diperlukan dengan Python 2.7+.np.float64.__repr__
sering diformat dengan angka desimal yang berlebihan sehingga tidak ada bit yang bisa hilang, tetapi tidak ada nomor IEEE 754 yang valid ada antara 13,949999999999999 dan 13.950000000000001. Hasilnya tidak bagus dan konversirepr(float(number_as_string))
tidak reversibel dengan numpy. Di samping itu:float.__repr__
sumber
float
(presisi ganda) dan normalround
, bukan tentang numpy.double dan konversi ke string. Pembulatan Python benar-benar tidak bisa dilakukan lebih baik daripada di Python 2.7. Sebagian besar jawaban telah ditulis sebelum 2.7, tetapi mereka sudah usang, meskipun awalnya sangat bagus. Inilah alasan jawaban saya.1
, kecuali selama "aliran bawah bertahap".a*b
vsb*a
. Terima kasih atas tautannya - Nostalgia.Dengan Python <3 (mis. 2.6 atau 2.7), ada dua cara untuk melakukannya.
Tetapi perhatikan bahwa untuk versi Python di atas 3 (mis. 3.2 atau 3.3), opsi dua lebih disukai .
Untuk informasi lebih lanjut tentang opsi dua, saya sarankan tautan ini pada pemformatan string dari dokumentasi Python .
Dan untuk informasi lebih lanjut tentang opsi satu, tautan ini akan cukup dan memiliki informasi tentang berbagai flag .
Referensi: Konversi angka floating point ke presisi tertentu, dan kemudian salin ke string
sumber
numvar=12.456
, maka"{:.2f}".format(numvar)
menghasilkan12.46
tetapi"{:2i}".format(numvar)
memberikan kesalahan dan saya mengharapkan12
.Anda dapat mengubah format output:
sumber
Tidak ada yang tampaknya telah menyebutkannya, jadi izinkan saya memberi contoh dalam format f-string / template-string Python 3.6, yang menurut saya sangat rapi:
Ini bekerja dengan baik dengan contoh yang lebih panjang juga, dengan operator dan tidak perlu parens:
sumber
Anda dapat menggunakan operator format untuk membulatkan nilai hingga 2 tempat desimal dengan python:
sumber
Dengan Python 2.7:
sumber
output
memiliki yang sama persis nilai sepertia
, sehingga Anda mungkin juga telah menulisprint a
bukanprint output
di baris terakhir.13.95
. Namun demikianprint a
, untuk nilai khusus inia
, dalam Python 2.7, jadi tidak terlalu jelas apa gunanya langkah pemformatan.a == output
kode yang Anda perlihatkan? Itu memberiTrue
untuk saya, dan saya curiga itu juga untuk Anda.Tutorial Python memiliki lampiran yang disebut Floating Point Arithmetic: Issues and Limitations . Membacanya. Ini menjelaskan apa yang terjadi dan mengapa Python melakukan yang terbaik. Ia bahkan memiliki contoh yang cocok dengan milik Anda. Biarkan saya kutip sedikit:
Salah satu alternatif dan solusi untuk masalah Anda adalah menggunakan
decimal
modul.sumber
Seperti yang ditunjukkan @Matt, Python 3.6 menyediakan f-string , dan mereka juga dapat menggunakan parameter bersarang :
yang akan ditampilkan
result: 2.35
sumber
Itu melakukan persis apa yang Anda perintahkan dan lakukan dengan benar. Baca lebih lanjut tentang kebingungan floating point dan mungkin coba objek desimal sebagai gantinya.
sumber
Gunakan kombinasi objek Decimal dan metode round ().
sumber
Untuk memperbaiki titik mengambang dalam bahasa tipe-dinamis seperti Python dan JavaScript, saya menggunakan teknik ini
Anda juga dapat menggunakan Desimal sebagai berikut:
sumber
getcontext().prec = 6
berfungsi hanya untuk lingkup fungsi atau semua tempat?Hasil:
sumber
sumber
Bagaimana dengan fungsi lambda seperti ini:
Dengan cara ini Anda bisa melakukan:
dan dapatkan
sumber
Sederhana seperti 1,2,3:
gunakan modul desimal untuk aritmatika floating point desimal yang dibulatkan dengan benar:
d = Desimal (10000000.0000009)
untuk mencapai pembulatan:
akan menghasilkan dengan
Decimal('10000000.00')
ATAU
PS: kritik orang lain: format tidak pembulatan.
sumber
Untuk membulatkan angka ke resolusi, cara terbaik adalah yang berikut, yang dapat bekerja dengan resolusi apa pun (0,01 untuk dua desimal atau bahkan langkah lain):
sumber
numpy.round
akurasi / presisi. Jadi itu perlu mendefinisikannya sebagai int sebelum perkalian dengan resolusi. Saya memperbarui kode. Terima kasih untuk itu!numpy.float64
hasil np.round menjadifloat
atau hanya menggunakanround(value, 2)
. Tidak ada nomor IEEE 754 yang valid antara 13.949999999999999 (= 1395 / 100.) dan 3.95000000000000001 (= 1395 * .01). Mengapa Anda berpikir bahwa metode Anda adalah yang terbaik? Nilai asli 13.949999999999999289 (= value = round (value, 2)) bahkan lebih tepat daripada 13.9500000000000000178 Anda (dicetak oleh np.float96). Info lebih lanjut juga untuk numpy sekarang ditambahkan ke jawaban saya bahwa Anda mungkin downvoted karena kesalahan. Awalnya itu bukan tentang numpy.int
Anda juga dapat menggunakanfloat
contoh @szeitlin. Terima kasih atas komentar ekstra Anda. (Maaf tapi saya tidaklambda x, n: int (x * 10 n + .5) / 10 n telah bekerja untuk saya selama bertahun- tahun dalam banyak bahasa.
sumber
Metode yang saya gunakan adalah mengiris string. Ini relatif cepat dan sederhana.
Pertama, ubah float menjadi string, pilih panjang yang Anda inginkan.
Pada baris tunggal di atas, kami telah mengonversi nilai menjadi string, lalu menyimpan string hanya hingga empat digit pertama atau karakter (inklusif).
Semoga itu bisa membantu!
sumber