Pertanyaan Kesetaraan cek dengan fraksi di Common Lisp


Jadi saya belajar bahwa Lisp melakukan fraksi yang sangat bagus. Tapi mengapa kemudian cek kesetaraan ini mengembalikan NIL:

* (= 0.2 1/5)          

NIL

... saat mengembalikan True jika dikonversi menjadi float pertama:

* (= 0.2 (float 1/5))

T

Saya sudah mencoba SBCL dan CLISP.

Apakah pelaksanaannya tidak lengkap atau apakah ada alasan atau logika khusus di balik perilaku ini?


5
2017-10-01 14:03


asal


Jawaban:


Rasio dalam Lisp Biasa

Perhatikan itu fraksi (yang itu sendiri bukan tipe numerik dalam Common Lisp) diubah menjadi rationals di Lisp. rational, ratio dan integer (dan lainnya) adalah tipe numerik yang sebenarnya dalam Common Lisp. Jika Anda memasukkan pecahan, itu dinormalisasi menjadi rasional (angka integer atau rasio).

CL-USER 16 > 3/9
1/3

CL-USER 17 > 9/9
1

CL-USER 18 > 6/9
2/3

Perbandingan numerik

Ketika float dan rasio dibandingkan, nilai float diubah menjadi perbandingan rasional dan kemudian tepat dilakukan. Lihat: CLHS, Rule of Float and Rational Contagion.

Rasio ini tidak diubah menjadi float, tetapi float diubah menjadi rasional.

Masalahnya muncul karena beberapa pelampung tidak dikonversi ke rasio yang Anda harapkan. Masalah mendasar adalah bahwa angka-angka floating point belum tentu merupakan tepat perwakilan. Konversi angka yang tidak pasti ke yang pasti tidak perlu memberikan hasil yang diharapkan secara naif.

Sayangnya konversi 0.2 ke angka yang rasional belum tentu 1/5, tapi ini:

CL-USER 7 > (rational 0.2)
13421773/67108864

Tapi 0.5 aku s 1/2.

CL-USER 8 > (rational 0.5)
1/2

Inilah yang terjadi dalam contoh Anda:

CL-USER 9 > (= 1/2 (rational 0.5))
T

CL-USER 10 > (= 1/5 (rational 0.2))
NIL

Jadi tidak demikian

CL-USER 14 > (= 0.2 (float 1/5))
T

Tapi:

CL-USER 15 > (= (rational 0.2) 1/5)
NIL

Perhatikan bahwa jenisnya rational menggabungkan subtipe disjoint ratio dan integer. Demikian (rational 1.0) bisa berupa bilangan bulat, dan bukan rasio.


6
2017-10-01 15:00



Itu spesifikasi tentang = mengatakan:

Nilai dari = benar jika semua angka memiliki nilai yang sama; kalau tidak itu salah.

Selagi spesifikasi di real mengatakan:

Tipe-tipe rational dan float adalah subtipe tipe tak terputus real.

Dengan kata lain, Anda dapat membandingkannya karena keduanya angka, tetapi mereka berbeda karena, karena subtipe yang disjoint, mereka berbeda nilai-nilai.

Apa yang dapat Anda lakukan adalah mengonversikannya ke "bagian" yang sama dari angka, mengambang, dan kemudian perbandingan akan kembali benar.

Alasan untuk perilaku ini adalah itu float angka-angka pada umumnya memiliki representasi perkiraan (lihat komentar oleh @coredump dan tautan), sementara angka-angka rasional memiliki representasi yang tepat, sehingga tidak terlalu masuk akal untuk membandingkan nilai-nilai yang dapat "melihat" secara eksternal identik tetapi berbeda dalam internal ( biner) representasi.


3
2017-10-01 14:26