Saya ingin a
dibulatkan ke 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
The round
fungsi tidak bekerja seperti yang saya harapkan.
Saya ingin a
dibulatkan ke 13,95 .
>>> a
13.949999999999999
>>> round(a, 2)
13.949999999999999
The round
fungsi tidak bekerja seperti yang saya harapkan.
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,
>>> 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
Jika Anda hanya mengejar dua tempat desimal (untuk menampilkan nilai mata uang, misalnya), maka Anda memiliki beberapa pilihan yang lebih baik:
"%.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:
"{:.2f}".format(13.949999999999999)
Catatan 1: di atas mengembalikan sebuah string. Untuk mendapatkan float, cukup bungkus dengan float(...)
:
float("{:.2f}".format(13.949999999999999))
Catatan 2: membungkus dengan float()
tidak mengubah apa pun:
>>> 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)
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:
>>> round(14.22222223, 2)
14.22
Lihatlah dokumentasinya .
round(2.16, 1)
berikan 2.2
mengapa python hanya menawarkan 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.
Saya merasa bahwa pendekatan yang paling sederhana adalah menggunakan format()
fungsinya.
Sebagai contoh:
a = 13.949999999999999
format(a, '.2f')
13.95
Ini menghasilkan angka float sebagai string dibulatkan ke dua titik desimal.
Menggunakan
print"{:.2f}".format(a)
dari pada
print"{0:.2f}".format(a)
Karena yang terakhir dapat menyebabkan kesalahan output ketika mencoba untuk output beberapa variabel (lihat komentar).
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.)
>>> "%.2f" % 3.14159
'3.14'
>>> "%.2f" % 13.9499999
'13.95'
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.
Coba kode di bawah ini:
>>> a = 0.99334
>>> a = int((a * 100) + 0.5) / 100.0 # Adding 0.5 rounds it up
>>> print a
0.99
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.
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() ...
atau Decimal -> 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 :
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 Lainnya paragraf keempat:
Konversi antara angka floating-point dan string sekarang dibulatkan dengan benar di sebagian besar platform. Konversi ini terjadi di banyak tempat berbeda: str () pada float dan bilangan kompleks; konstruktor apung dan kompleks; pemformatan numerik; serialisasi dan de-serialisasi pelampung dan bilangan kompleks menggunakan
marshal
,pickle
danjson
modul; parsing float dan imajiner literal dalam kode Python; dan konversi Desimal ke float.Terkait dengan ini, repr () dari angka floating-point x sekarang mengembalikan hasil berdasarkan string desimal terpendek yang dijamin untuk dibulatkan kembali ke x di bawah pembulatan yang benar (dengan mode pembulatan setengah-ke-even). Sebelumnya memberi string berdasarkan pembulatan x hingga 17 angka desimal.
Informasi lebih lanjut: Pemformatan float
sebelum Python 2.7 mirip dengan saat ini numpy.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 konversi repr(float(number_as_string))
tidak reversibel dengan numpy. Di samping itu:float.__repr__
float
(presisi ganda) dan normal round
, 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
vs b*a
. Terima kasih atas tautannya - Nostalgia.
Dengan Python <3 (mis. 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 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
numvar=12.456
, maka "{:.2f}".format(numvar)
menghasilkan 12.46
tetapi "{:2i}".format(numvar)
memberikan kesalahan dan saya mengharapkan 12
.
Anda dapat mengubah format output:
>>> a = 13.95
>>> a
13.949999999999999
>>> print "%.2f" % a
13.95
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:
>>> f'{a:.2f}'
Ini bekerja dengan baik dengan contoh yang lebih panjang juga, dengan operator dan tidak perlu parens:
>>> print(f'Completed in {time.time() - start:.2f}s')
Anda dapat menggunakan operator format untuk membulatkan nilai hingga 2 tempat desimal dengan python:
print(format(14.4499923, '.2f')) // output is 14.45
Dengan Python 2.7:
a = 13.949999999999999
output = float("%0.2f"%a)
print output
output
memiliki yang sama persis nilai seperti a
, sehingga Anda mungkin juga telah menulis print a
bukan print output
di baris terakhir.
13.95
. Namun demikian print a
, untuk nilai khusus ini a
, dalam Python 2.7, jadi tidak terlalu jelas apa gunanya langkah pemformatan.
a == output
kode yang Anda perlihatkan? Itu memberi True
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:
>>> 0.1 0.10000000000000001
Anda mungkin tergoda untuk menggunakan
round()
fungsi ini untuk memotongnya kembali ke satu digit yang Anda harapkan. Tapi itu tidak ada bedanya:>>> round(0.1, 1) 0.10000000000000001
Masalahnya adalah bahwa nilai floating-point biner yang disimpan
“0.1”
sudah merupakan perkiraan biner terbaik1/10
, jadi mencoba membulatkannya lagi tidak bisa membuatnya lebih baik: itu sudah sebaik yang didapat.Konsekuensi lain adalah bahwa karena
0.1
tidak tepat1/10
, menjumlahkan sepuluh nilai0.1
mungkin tidak menghasilkan dengan tepat1.0
, baik:>>> sum = 0.0 >>> for i in range(10): ... sum += 0.1 ... >>> sum 0.99999999999999989
Salah satu alternatif dan solusi untuk masalah Anda adalah menggunakan decimal
modul.
Seperti yang ditunjukkan @Matt, Python 3.6 menyediakan f-string , dan mereka juga dapat menggunakan parameter bersarang :
value = 2.34558
precision = 2
width = 4
print(f'result: {value:{width}.{precision}f}')
yang akan ditampilkan result: 2.35
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.
Gunakan kombinasi objek Decimal dan metode 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')
Untuk memperbaiki titik mengambang dalam bahasa tipe-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')
getcontext().prec = 6
berfungsi hanya untuk lingkup fungsi atau semua tempat?
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'
Bagaimana dengan fungsi lambda seperti ini:
arred = lambda x,n : x*(10**n)//1/(10**n)
Dengan cara ini Anda bisa melakukan:
arred(3.141591657,2)
dan dapatkan
3.14
Sederhana seperti 1,2,3:
gunakan modul desimal untuk aritmatika floating point desimal yang dibulatkan dengan benar:
d = Desimal (10000000.0000009)
untuk mencapai pembulatan:
d.quantize(Decimal('0.01'))
akan menghasilkan dengan Decimal('10000000.00')
def round_decimal(number, exponent='0.01'):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(exponent))
ATAU
def round_decimal(number, decimal_places=2):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
PS: kritik orang lain: format tidak pembulatan.
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):
>>> 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
akurasi / presisi. Jadi itu perlu mendefinisikannya sebagai int sebelum perkalian dengan resolusi. Saya memperbarui kode. Terima kasih untuk itu!
numpy.float64
hasil np.round menjadi float
atau hanya menggunakan round(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 menggunakan float
contoh @szeitlin. Terima kasih atas komentar ekstra Anda. (Maaf tapi saya tidak
Metode yang saya gunakan adalah mengiris string. Ini relatif cepat dan sederhana.
Pertama, ubah float menjadi string, pilih panjang yang Anda inginkan.
float = str(float)[:5]
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!