Apa cara terbaik untuk membandingkan pelampung untuk hampir-kesetaraan dalam Python?

333

Sudah diketahui bahwa membandingkan floats untuk persamaan adalah sedikit rumit karena masalah pembulatan dan ketepatan.

Misalnya: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

Apa cara yang disarankan untuk menangani hal ini dengan Python?

Tentunya ada fungsi perpustakaan standar untuk ini di suatu tempat?

Gordon Wrigley
sumber
@tolomea: Karena ini tergantung pada aplikasi Anda dan data Anda dan domain masalah Anda - dan itu hanya satu baris kode - mengapa ada "fungsi perpustakaan standar"?
S.Lott
9
@ S. Lott: all, any, max, minmasing-masing pada dasarnya satu-liners, dan mereka tidak hanya disediakan di perpustakaan, mereka builtin fungsi. Jadi alasan BDFL bukan itu. Satu baris kode yang ditulis kebanyakan orang cukup tidak canggih dan seringkali tidak berfungsi, yang merupakan alasan kuat untuk memberikan sesuatu yang lebih baik. Tentu saja setiap modul yang menyediakan strategi lain juga harus memberikan peringatan yang menjelaskan kapan mereka sesuai, dan yang lebih penting ketika mereka tidak. Analisis numerik itu sulit, itu tidak memalukan bahwa perancang bahasa biasanya tidak mencoba alat untuk membantunya.
Steve Jessop
@Steve Jessop. Fungsi-fungsi yang berorientasi koleksi tidak memiliki dependensi aplikasi, data, dan domain yang dimiliki oleh float-point. Jadi "one-liner" jelas tidak sepenting alasan sebenarnya. Analisis numerik sulit, dan tidak bisa menjadi bagian kelas pertama dari perpustakaan bahasa tujuan umum.
S.Lott
6
@ S.Lott: Saya mungkin setuju jika distribusi Python standar tidak disertai dengan beberapa modul untuk antarmuka XML. Jelas fakta bahwa aplikasi yang berbeda perlu melakukan sesuatu secara berbeda bukanlah halangan untuk menempatkan modul pada basis yang ditetapkan untuk melakukannya dengan satu atau lain cara. Tentu saja ada trik untuk membandingkan pelampung yang sering digunakan kembali, yang paling dasar adalah jumlah ulp yang ditentukan. Jadi saya hanya setuju sebagian - masalahnya adalah analisis numerik sulit. Python bisa pada prinsipnya menyediakan alat-alat untuk membuatnya agak lebih mudah, beberapa waktu. Saya kira tidak ada yang mengajukan diri.
Steve Jessop
4
Juga, "itu bermuara pada satu baris kode yang sulit dirancang" - jika itu masih satu baris setelah Anda melakukannya dengan benar, saya pikir monitor Anda lebih lebar dari milik saya ;-). Bagaimanapun, saya pikir seluruh area cukup khusus, dalam arti bahwa kebanyakan programmer (termasuk saya) sangat jarang menggunakannya. Dikombinasikan dengan susah, itu tidak akan mencapai puncak daftar "paling dicari" untuk perpustakaan inti dalam kebanyakan bahasa.
Steve Jessop

Jawaban:

326

Python 3.5 menambahkan math.isclosedan cmath.isclosefungsinya seperti dijelaskan dalam PEP 485 .

Jika Anda menggunakan versi Python sebelumnya, fungsi yang setara diberikan dalam dokumentasi .

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

rel_toladalah toleransi relatif, itu dikalikan dengan semakin besar besarnya dua argumen; karena nilainya semakin besar, begitu pula perbedaan yang diizinkan di antara mereka sambil tetap menganggapnya sama.

abs_toladalah toleransi mutlak yang diterapkan apa adanya dalam semua kasus. Jika perbedaannya kurang dari toleransi tersebut, nilainya dianggap sama.

Mark tebusan
sumber
26
catat kapan aatau ba numpy array, numpy.iscloseberfungsi.
dbliss
6
@arsh rel_toladalah toleransi relatif , ini dikalikan dengan semakin besar dari dua argumen; karena nilainya semakin besar, begitu pula perbedaan yang diizinkan di antara mereka sambil tetap menganggapnya sama. abs_toladalah toleransi mutlak yang diterapkan apa adanya dalam semua kasus. Jika perbedaannya kurang dari toleransi tersebut, nilainya dianggap sama.
Mark Ransom
5
Tidak mengurangi nilai jawaban ini (saya pikir itu bagus), perlu dicatat bahwa dokumentasi juga mengatakan: "Modulo memeriksa kesalahan, dll, fungsi akan mengembalikan hasil ..." Dengan kata lain, isclosefungsi ini (di atas) bukan implementasi yang lengkap .
rkersh
5
Permintaan maaf untuk menghidupkan kembali utas lama, tetapi sepertinya pantas ditunjukkan yang iscloseselalu berpegang pada kriteria yang kurang konservatif. Saya hanya menyebutkannya karena perilaku itu berlawanan dengan saya. Jika saya menentukan dua kriteria, saya selalu mengharapkan toleransi yang lebih kecil untuk menggantikan yang lebih besar.
Mackie Messer
3
@ MackieMesser Anda berhak atas pendapat Anda tentu saja, tetapi perilaku ini sangat masuk akal bagi saya. Menurut definisi Anda tidak ada yang bisa "mendekati" nol, karena toleransi relatif dikalikan dengan nol selalu nol.
Mark Ransom
72

Apakah sesederhana yang berikut ini tidak cukup baik?

return abs(f1 - f2) <= allowed_error
Andrew White
sumber
8
Seperti yang ditunjukkan oleh tautan yang saya berikan, mengurangi hanya berfungsi jika Anda tahu perkiraan besarnya angka di muka.
Gordon Wrigley
8
Dalam pengalaman saya, metode terbaik untuk membandingkan mengapung adalah: abs(f1-f2) < tol*max(abs(f1),abs(f2)). Toleransi relatif semacam ini adalah satu-satunya cara yang bermakna untuk membandingkan pelampung secara umum, karena biasanya dipengaruhi oleh kesalahan pembulatan di tempat desimal kecil.
Sesquipedal
2
Hanya menambahkan contoh sederhana mengapa ini tidak berhasil >>> abs(0.04 - 0.03) <= 0.01:, ia menghasilkan False. Saya menggunakanPython 2.7.10 [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
schatten
3
@ Schatten agar adil, contoh itu lebih berkaitan dengan presisi / format biner mesin daripada perbandingan algo tertentu. Ketika Anda memasukkan 0,03 ke dalam sistem, itu bukan benar-benar angka yang membuatnya ke CPU.
Andrew White
2
@AndrewWhite contoh itu menunjukkan bahwa abs(f1 - f2) <= allowed_errortidak berfungsi seperti yang diharapkan.
schatten
45

Saya setuju bahwa jawaban Gareth mungkin paling tepat sebagai fungsi / solusi ringan.

Tapi saya pikir akan sangat membantu untuk dicatat bahwa jika Anda menggunakan NumPy atau sedang mempertimbangkannya, ada fungsi yang dikemas untuk ini.

numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)

Namun sedikit penafian: menginstal NumPy bisa menjadi pengalaman yang tidak sepele tergantung pada platform Anda.

J.Makela
sumber
1
"Memasang numpy bisa menjadi pengalaman non-sepele tergantung pada platform Anda." ... um Apa? Platform mana yang "non-sepele" untuk menginstal numpy? Apa sebenarnya yang membuatnya tidak sepele?
John
10
@ John: sulit untuk mendapatkan biner 64-bit untuk Windows. Sulit untuk mendapatkan numpy via pipWindows.
Ben Bolker
@Ternak: Ya, tetapi beberapa murid saya menggunakan Windows, jadi saya harus berurusan dengan hal ini.
Ben Bolker
4
@ BenBolker Jika Anda harus menginstal platform sains data terbuka yang ditenagai oleh Python, cara terbaik adalah kontinum Anaconda.io/downloads (panda, numpy, dan lebih banyak lagi)
jrovegno
Memasang Anaconda itu sepele
endolith
14

Gunakan decimalmodul Python , yang menyediakan Decimalkelas.

Dari komentar:

Perlu dicatat bahwa jika Anda melakukan pekerjaan matematika-berat dan Anda tidak benar-benar membutuhkan ketelitian dari desimal, ini dapat benar-benar menghambat semuanya. Mengapung adalah cara, cara yang lebih cepat untuk dihadapi, tetapi tidak tepat. Desimal sangat tepat tetapi lambat.

jathanisme
sumber
11

Saya tidak mengetahui apa pun di pustaka standar Python (atau di tempat lain) yang mengimplementasikan AlmostEqual2sComplementfungsi Dawson . Jika itu jenis perilaku yang Anda inginkan, Anda harus menerapkannya sendiri. (Dalam hal ini, daripada menggunakan retas bitwise Dawson yang cerdik, Anda mungkin akan lebih baik menggunakan tes yang lebih konvensional dari bentuk if abs(a-b) <= eps1*(abs(a)+abs(b)) + eps2atau sejenisnya. Untuk mendapatkan perilaku seperti Dawson, Anda mungkin mengatakan sesuatu seperti if abs(a-b) <= eps*max(EPS,abs(a),abs(b))untuk beberapa perbaikan kecil EPS; ini bukan tepatnya sama seperti Dawson, tetapi memiliki semangat yang serupa.

Gareth McCaughan
sumber
Saya tidak cukup mengikuti apa yang Anda lakukan di sini, tetapi ini menarik. Apa perbedaan antara eps, eps1, eps2 dan EPS?
Gordon Wrigley
eps1 dan eps2 tentukan kerabat dan toleransi absolut: Anda siap membiarkan adan bberbeda sekitar eps1berapa kali mereka ditambah eps2. epsadalah toleransi tunggal; Anda siap untuk mengizinkan adan bberbeda sekitar epsberapa kali mereka, dengan ketentuan bahwa ukuran apa pun EPSatau lebih kecil dianggap berukuran EPS. Jika Anda menganggapnya EPSsebagai nilai non-abnormal terkecil dari tipe floating-point Anda, ini sangat mirip dengan komparator Dawson (kecuali untuk faktor 2 ^ # bit karena Dawson mengukur toleransi dalam ulp).
Gareth McCaughan
2
Kebetulan, saya setuju dengan S. Lott bahwa Right Thing akan selalu bergantung pada aplikasi Anda yang sebenarnya, itulah sebabnya mengapa tidak ada fungsi pustaka standar tunggal untuk semua kebutuhan perbandingan titik mengambang Anda.
Gareth McCaughan
@ gareth-mccaughan Bagaimana cara menentukan "nilai non-abnormal terkecil dari tipe floating-point Anda" untuk python?
Gordon Wrigley
Halaman ini docs.python.org/tutorial/floatingpoint.html mengatakan hampir semua implementasi python menggunakan pelampung presisi ganda IEEE-754 dan halaman ini en.wikipedia.org/wiki/IEEE_754-1985 mengatakan angka normalisasi yang paling dekat dengan nol adalah ± 2 * * −1022.
Gordon Wrigley
11

Kebijaksanaan umum bahwa angka floating-point tidak dapat dibandingkan untuk kesetaraan adalah tidak akurat. Bilangan floating-point tidak berbeda dari bilangan bulat: Jika Anda mengevaluasi "a == b", Anda akan menjadi kenyataan jika bilangan itu identik dan salah (dengan pengertian bahwa dua NaN tentu saja bukan bilangan identik).

Masalah sebenarnya adalah ini: Jika saya telah melakukan perhitungan dan tidak yakin dua angka yang harus saya bandingkan benar, lalu apa? Masalah ini sama untuk floating-point seperti halnya untuk bilangan bulat. Jika Anda mengevaluasi ekspresi integer "7/3 * 3", itu tidak akan sama dengan "7 * 3/3".

Jadi misalkan kita bertanya, "Bagaimana cara membandingkan bilangan bulat untuk kesetaraan?" dalam situasi seperti itu. Tidak ada jawaban tunggal; apa yang harus Anda lakukan tergantung pada situasi spesifik, terutama kesalahan apa yang Anda miliki dan apa yang ingin Anda capai.

Berikut beberapa pilihan yang mungkin.

Jika Anda ingin mendapatkan hasil "benar" jika angka yang tepat secara matematis akan sama, maka Anda dapat mencoba menggunakan properti dari perhitungan yang Anda lakukan untuk membuktikan bahwa Anda mendapatkan kesalahan yang sama dalam dua angka. Jika itu layak, dan Anda membandingkan dua angka yang dihasilkan dari ekspresi yang akan memberikan angka yang sama jika dihitung secara tepat, maka Anda akan mendapatkan "benar" dari perbandingan. Pendekatan lain adalah bahwa Anda dapat menganalisis properti perhitungan dan membuktikan bahwa kesalahan tidak pernah melebihi jumlah tertentu, mungkin jumlah absolut atau jumlah relatif terhadap salah satu input atau salah satu output. Dalam hal ini, Anda dapat bertanya apakah dua angka yang dihitung berbeda paling banyak jumlah itu, dan mengembalikan "benar" jika mereka berada dalam interval. Jika Anda tidak dapat membuktikan kesalahan terikat, Anda mungkin menebak dan berharap untuk yang terbaik. Salah satu cara menebak adalah dengan mengevaluasi banyak sampel acak dan melihat jenis distribusi yang Anda dapatkan dalam hasil.

Tentu saja, karena kami hanya menetapkan persyaratan bahwa Anda mendapatkan "benar" jika hasil yang tepat secara matematis sama, kami membiarkan kemungkinan bahwa Anda mendapatkan "benar" walaupun tidak sama. (Faktanya, kita dapat memenuhi persyaratan dengan selalu mengembalikan "benar". Ini membuat perhitungannya sederhana tetapi umumnya tidak diinginkan, jadi saya akan membahas memperbaiki situasi di bawah ini.)

Jika Anda ingin mendapatkan hasil "false" jika angka yang tepat secara matematis tidak sama, Anda perlu membuktikan bahwa evaluasi Anda terhadap angka menghasilkan angka yang berbeda jika angka yang tepat secara matematis tidak sama. Ini mungkin mustahil untuk tujuan praktis dalam banyak situasi umum. Jadi mari kita pertimbangkan alternatifnya.

Persyaratan yang berguna mungkin bahwa kita mendapatkan hasil "salah" jika angka yang tepat secara matematis berbeda lebih dari jumlah tertentu. Sebagai contoh, mungkin kita akan menghitung di mana bola dilemparkan dalam permainan komputer bepergian, dan kami ingin tahu apakah itu memukul kelelawar. Dalam hal ini, kami tentu ingin mendapatkan "benar" jika bola memukul kelelawar, dan kami ingin mendapatkan "salah" jika bola jauh dari kelelawar, dan kami dapat menerima jawaban "benar" yang salah jika bola masuk simulasi matematis yang tepat melewatkan kelelawar tetapi dalam milimeter memukul kelelawar. Dalam hal itu, kita perlu membuktikan (atau menebak / memperkirakan) bahwa perhitungan kita tentang posisi bola dan posisi kelelawar memiliki kesalahan gabungan paling banyak satu milimeter (untuk semua posisi yang menarik). Ini akan memungkinkan kita untuk selalu kembali "

Jadi, bagaimana Anda memutuskan apa yang akan dikembalikan ketika membandingkan angka floating-point sangat tergantung pada situasi spesifik Anda.

Mengenai cara Anda membuktikan batas kesalahan untuk perhitungan, itu bisa menjadi subjek yang rumit. Setiap implementasi floating-point menggunakan standar IEEE 754 dalam mode round-to-terdekat mengembalikan angka floating-point terdekat dengan hasil yang tepat untuk setiap operasi dasar (terutama perkalian, pembagian, penambahan, pengurangan, akar kuadrat). (Dalam kasus seri, bulat sehingga bit rendahnya genap.) (Berhati-hatilah tentang akar kuadrat dan pembagian; implementasi bahasa Anda mungkin menggunakan metode yang tidak sesuai dengan IEEE 754 untuk itu.) Karena persyaratan ini, kita tahu kesalahan dalam hasil tunggal paling banyak 1/2 dari nilai bit paling signifikan. (Jika lebih, pembulatan akan pergi ke nomor yang berbeda yaitu dalam 1/2 nilai.)

Pergi dari sana menjadi jauh lebih rumit; langkah selanjutnya adalah melakukan operasi di mana salah satu input sudah memiliki beberapa kesalahan. Untuk ekspresi sederhana, kesalahan ini dapat diikuti melalui perhitungan untuk mencapai batas kesalahan akhir. Dalam praktiknya, ini hanya dilakukan dalam beberapa situasi, seperti mengerjakan perpustakaan matematika berkualitas tinggi. Dan, tentu saja, Anda perlu kontrol yang tepat atas operasi yang dilakukan. Bahasa tingkat tinggi sering memberi kompiler banyak kelonggaran, jadi Anda mungkin tidak tahu di mana operasi urutan dilakukan.

Ada banyak lagi yang bisa (dan) ditulis tentang topik ini, tetapi saya harus berhenti di situ. Singkatnya, jawabannya adalah: Tidak ada rutinitas perpustakaan untuk perbandingan ini karena tidak ada solusi tunggal yang sesuai dengan sebagian besar kebutuhan yang layak dimasukkan ke dalam rutinitas perpustakaan. (Jika membandingkan dengan interval kesalahan relatif atau absolut sudah mencukupi untuk Anda, Anda dapat melakukannya hanya tanpa rutin perpustakaan.)

Eric Postpischil
sumber
3
Dari diskusi di atas dengan Gareth McCaughan, dengan benar membandingkan dengan kesalahan relatif pada dasarnya berjumlah "abs (ab) <= eps max (2 * -1022, abs (a), abs (b))", itu bukan sesuatu yang akan saya jelaskan sesederhana dan jelas bukan sesuatu yang akan saya kerjakan sendiri. Juga seperti yang ditunjukkan Steve Jessop, kompleksitasnya hampir sama dengan max, min, semua dan semua, yang semuanya bawaan. Jadi memberikan perbandingan kesalahan relatif dalam modul matematika standar sepertinya ide yang bagus.
Gordon Wrigley
(7/3 * 3 == 7 * 3/3) mengevaluasi True in python.
xApple
@xApple: Saya baru saja menjalankan Python 2.7.2 di OS X 10.8.3 dan masuk (7/3*3 == 7*3/3). Itu dicetak False.
Eric Postpischil
3
Anda mungkin lupa mengetik from __future__ import division. Jika Anda tidak melakukan itu, tidak ada angka floating point dan perbandingannya adalah antara dua bilangan bulat.
xApple
3
Ini adalah diskusi penting, tetapi tidak terlalu membantu.
Dan Hulme
6

Jika Anda ingin menggunakannya dalam konteks pengujian / TDD, saya akan mengatakan ini adalah cara standar:

from nose.tools import assert_almost_equals

assert_almost_equals(x, y, places=7) #default is 7
volodymyr
sumber
5

math.isclose () telah ditambahkan ke Python 3.5 untuk itu ( kode sumber ). Ini adalah port-nya untuk Python 2. Perbedaannya dari One-liner dari Mark Ransom adalah ia dapat menangani "inf" dan "-inf" dengan benar.

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    '''
    Python 2 implementation of Python 3.5 math.isclose()
    https://hg.python.org/cpython/file/tip/Modules/mathmodule.c#l1993
    '''
    # sanity check on the inputs
    if rel_tol < 0 or abs_tol < 0:
        raise ValueError("tolerances must be non-negative")

    # short circuit exact equality -- needed to catch two infinities of
    # the same sign. And perhaps speeds things up a bit sometimes.
    if a == b:
        return True

    # This catches the case of two infinities of opposite sign, or
    # one infinity and one finite number. Two infinities of opposite
    # sign would otherwise have an infinite relative tolerance.
    # Two infinities of the same sign are caught by the equality check
    # above.
    if math.isinf(a) or math.isinf(b):
        return False

    # now do the regular computation
    # this is essentially the "weak" test from the Boost library
    diff = math.fabs(b - a)
    result = (((diff <= math.fabs(rel_tol * b)) or
               (diff <= math.fabs(rel_tol * a))) or
              (diff <= abs_tol))
    return result
pengguna2745509
sumber
2

Saya menemukan perbandingan berikut bermanfaat:

str(f1) == str(f2)
Kresimir
sumber
ini menarik, tetapi tidak terlalu praktis karena str (.1 + .2) == .3
Gordon Wrigley
str (.1 + .2) == str (.3) mengembalikan True
Henrikh Kantuni
Bagaimana ini berbeda dari f1 == f2 - jika keduanya dekat tetapi masih berbeda karena presisi, representasi string juga akan tidak sama.
MrMas
2
.1 + .2 == .3 mengembalikan False sementara str (.1 + .2) == str (.3) mengembalikan Benar
Kresimir
4
Dalam Python 3.7.2, str(.1 + .2) == str(.3)mengembalikan False. Metode yang dijelaskan di atas hanya berfungsi untuk Python 2.
Danibix
1

Untuk beberapa kasus di mana Anda dapat memengaruhi representasi nomor sumber, Anda bisa merepresentasikannya sebagai fraksi alih-alih mengapung, menggunakan pembilang bilangan bulat dan penyebut. Dengan begitu Anda dapat memiliki perbandingan yang tepat.

Lihat Fraksi dari fraksi modul untuk rincian.

eis
sumber
1

Saya menyukai saran @Sesquipedal tetapi dengan modifikasi (kasus penggunaan khusus ketika kedua nilai 0 mengembalikan False). Dalam kasus saya, saya menggunakan Python 2.7 dan hanya menggunakan fungsi sederhana:

if f1 ==0 and f2 == 0:
    return True
else:
    return abs(f1-f2) < tol*max(abs(f1),abs(f2))
IronYeti
sumber
1

Berguna untuk kasus di mana Anda ingin memastikan 2 angka sama 'hingga presisi', tidak perlu menentukan toleransi:

  • Temukan presisi minimum dari 2 angka

  • Bulat keduanya hingga presisi minimum dan bandingkan

def isclose(a,b):                                       
    astr=str(a)                                         
    aprec=len(astr.split('.')[1]) if '.' in astr else 0 
    bstr=str(b)                                         
    bprec=len(bstr.split('.')[1]) if '.' in bstr else 0 
    prec=min(aprec,bprec)                                      
    return round(a,prec)==round(b,prec)                               

Seperti yang ditulis, hanya berfungsi untuk angka tanpa 'e' dalam representasi string mereka (artinya 0,9999999999995e-4 <angka <= 0,9999999999995e11)

Contoh:

>>> isclose(10.0,10.049)
True
>>> isclose(10.0,10.05)
False
CptHwK
sumber
Konsep penutupan tanpa batas tidak akan membantu Anda dengan baik. isclose(1.0, 1.1)menghasilkan False, dan isclose(0.1, 0.000000000001)mengembalikan True.
kfsone
1

Untuk membandingkan hingga desimal yang diberikan tanpa atol/rtol:

def almost_equal(a, b, decimal=6):
    return '{0:.{1}f}'.format(a, decimal) == '{0:.{1}f}'.format(b, decimal)

print(almost_equal(0.0, 0.0001, decimal=5)) # False
print(almost_equal(0.0, 0.0001, decimal=4)) # True 
Vlad
sumber
1

Ini mungkin hack yang agak jelek, tetapi ini bekerja cukup baik ketika Anda tidak membutuhkan lebih dari presisi float default (sekitar 11 desimal).

Fungsi round_to menggunakan metode format dari kelas str bawaan untuk mengumpulkan float menjadi string yang mewakili float dengan jumlah desimal yang diperlukan, dan kemudian menerapkan fungsi built-in eval ke string float bulat untuk kembali. ke tipe numerik float.

Fungsi is_close hanya menerapkan persyaratan sederhana untuk float yang dibulatkan ke atas.

def round_to(float_num, prec):
    return eval("'{:." + str(int(prec)) + "f}'.format(" + str(float_num) + ")")

def is_close(float_a, float_b, prec):
    if round_to(float_a, prec) == round_to(float_b, prec):
        return True
    return False

>>>a = 10.0
10.0
>>>b = 10.0001
10.0001
>>>print is_close(a, b, prec=3)
True
>>>print is_close(a, b, prec=4)
False

Memperbarui:

Seperti yang disarankan oleh @stepehjfox, cara yang lebih bersih untuk membangun fungsi rount_to menghindari "eval" menggunakan pemformatan bersarang :

def round_to(float_num, prec):
    return '{:.{precision}f}'.format(float_num, precision=prec)

Mengikuti ide yang sama, kode ini bahkan bisa lebih sederhana menggunakan f-string baru yang hebat (Python 3.6+):

def round_to(float_num, prec):
    return f'{float_num:.{prec}f}'

Jadi, kita bahkan bisa membungkusnya semua dalam satu fungsi 'is_close' yang sederhana dan bersih :

def is_close(a, b, prec):
    return f'{a:.{prec}f}' == f'{b:.{prec}f}'
Albert Alomar
sumber
1
Anda tidak harus menggunakan eval()untuk mendapatkan pemformatan parameter. Sesuatu seperti return '{:.{precision}f'.format(float_num, precision=decimal_precision) harus melakukannya
stephenjfox
1
Sumber untuk komentar saya dan lebih banyak contoh: pyformat.info/#param_align
stephenjfox
1
Terima kasih @stephenjfox saya tidak tahu tentang pemformatan bersarang. Btw, kode sampel Anda tidak memiliki kurung kurawal:return '{:.{precision}}f'.format(float_num, precision=decimal_precision)
Albert Alomar
1
Tangkapan yang bagus, dan peningkatan yang dilakukan dengan f-string. Dengan kematian Python 2 di tikungan, mungkin ini akan menjadi norma
stephenjfox
0

Dalam hal kesalahan absolut, Anda bisa mengeceknya

if abs(a - b) <= error:
    print("Almost equal")

Beberapa informasi tentang mengapa float bertindak aneh dengan Python https://youtu.be/v4HhvoNLILk?t=1129

Anda juga dapat menggunakan math.isclose untuk kesalahan relatif

Rahul Sharma
sumber