Bagaimana menangani pembagian dengan nol dalam bahasa yang tidak mendukung pengecualian?


62

Saya sedang mengembangkan bahasa pemrograman baru untuk menyelesaikan beberapa persyaratan bisnis, dan bahasa ini ditargetkan untuk pengguna pemula. Jadi tidak ada dukungan untuk penanganan pengecualian dalam bahasa, dan saya tidak akan mengharapkan mereka untuk menggunakannya bahkan jika saya menambahkannya.

Saya telah mencapai titik di mana saya harus mengimplementasikan operator pembagian, dan saya bertanya-tanya bagaimana cara terbaik menangani pembagian dengan nol kesalahan?

Sepertinya saya hanya memiliki tiga cara yang mungkin untuk menangani kasus ini.

  1. Abaikan kesalahan dan hasilkan 0sebagai hasilnya. Jika memungkinkan, mencatat peringatan.
  2. Tambahkan NaNsebagai nilai yang mungkin untuk angka, tetapi itu menimbulkan pertanyaan tentang bagaimana menangani NaNnilai di bidang lain bahasa.
  3. Hentikan pelaksanaan program dan laporkan kepada pengguna kesalahan parah terjadi.

Opsi # 1 tampaknya satu-satunya solusi yang masuk akal. Opsi # 3 tidak praktis karena bahasa ini akan digunakan untuk menjalankan logika sebagai cron malam.

Apa alternatif saya untuk menangani kesenjangan dengan nol kesalahan, dan apa risiko dengan opsi # 1.


12
jika Anda menambahkan dukungan pengecualian dan pengguna tidak menangkapnya, maka Anda akan memiliki opsi # 3
ratchet freak

82
Saya ingin tahu, persyaratan bodoh macam apa yang mengharuskan Anda membuat bahasa pemrograman baru? Dalam pengalaman saya, setiap bahasa yang pernah dibuat menyebalkan (dalam desain atau pelaksanaan, sering di kedua) dan butuh masuk akal banyak usaha untuk bahkan mendapatkan yang banyak. Ada beberapa pengecualian untuk yang pertama, tetapi tidak untuk yang kedua, dan karena mereka dengan mudah <0,01% dari kasus, mereka mungkin kesalahan pengukuran ;-)

16
@delnan, sebagian besar bahasa baru dibuat untuk memungkinkan aturan bisnis dipisahkan dari cara penerapannya. Pengguna tidak perlu tahu bagaimana reject "Foo"itu diterapkan, tetapi hanya bahwa ia menolak dokumen jika mengandung kata kunci Foo. Saya mencoba membuat bahasa menjadi mudah dibaca dengan menggunakan istilah yang biasa digunakan pengguna. Memberikan pengguna bahasa pemrograman mereka sendiri memberdayakan mereka untuk menambahkan aturan bisnis tanpa tergantung pada staf teknis.
Reactgular

19
@Mathew Foscarini. Tidak pernah, mengabaikan kesalahan dan diam-diam kembali 0. Ketika melakukan pembagian, 0 mungkin nilai yang sangat legal (untuk beberapa alasan, ada hal seperti itu di Power Basic, dan itu benar-benar menyebalkan). Jika Anda membagi angka floating point, Nan atau Inf akan lebih baik (lihat IEEE 754 untuk memahami alasannya). Jika Anda membagi bilangan bulat, Anda dapat menghentikan program, bagi dengan 0 tidak boleh diizinkan (yah, kecuali Anda ingin menerapkan sistem pengecualian yang benar).

16
Saya terhibur dan terpesona oleh kompleks domain bisnis yang cukup untuk menjustifikasi bahasa pemrograman Turing-complete yang eksklusif, tetapi cukup longgar untuk mentolerir hasil yang tidak akurat secara drastis.
Mark E. Haase

Jawaban:


98

Saya akan sangat menyarankan terhadap # 1, karena mengabaikan kesalahan adalah anti-pola yang berbahaya. Ini dapat menyebabkan bug yang sulit dianalisis. Mengatur hasil pembagian dengan nol ke 0 tidak masuk akal sama sekali, dan melanjutkan eksekusi program dengan nilai tidak masuk akal akan menyebabkan masalah. Apalagi saat program berjalan tanpa pengawasan. Ketika juru bahasa program mengetahui bahwa ada kesalahan dalam program (dan pembagian-by-nol hampir selalu merupakan kesalahan desain), batalkan dan simpan semuanya apa adanya biasanya lebih disukai daripada mengisi database Anda dengan sampah.

Juga, Anda tidak akan mungkin berhasil dengan tuntas mengikuti pola ini. Cepat atau lambat Anda akan mengalami situasi kesalahan yang tidak dapat diabaikan (seperti kehabisan memori atau stack overflow) dan Anda harus menerapkan cara untuk menghentikan program.

Opsi # 2 (menggunakan NaN) akan sedikit bekerja, tetapi tidak sebanyak yang Anda kira. Cara menangani NaN dalam perhitungan berbeda didokumentasikan dengan baik dalam standar IEEE 754, jadi Anda mungkin bisa melakukan apa saja yang dilakukan oleh penerjemah bahasa Anda.

Omong-omong: Membuat bahasa pemrograman yang dapat digunakan oleh non-programmer adalah sesuatu yang sudah kami coba lakukan sejak 1964 (Dartmouth BASIC). Sejauh ini, kami tidak berhasil. Tapi semoga berhasil juga.


14
+1 terima kasih. Anda meyakinkan saya untuk melakukan kesalahan, dan sekarang setelah saya membaca jawaban Anda, saya tidak mengerti mengapa saya ragu-ragu. PHPtelah memberi pengaruh buruk pada saya.
Reactgular

24
Ya, sudah. Ketika saya membaca pertanyaan Anda, saya langsung berpikir bahwa itu adalah hal yang sangat PHP-esque untuk menghasilkan output yang salah dan terus mengikuti truk dalam menghadapi kesalahan. Ada alasan bagus mengapa PHP merupakan pengecualian dalam melakukan ini.
Joel

4
+1 untuk komentar BASIC. Saya tidak menyarankan menggunakan NaNdalam bahasa pemula, tetapi secara umum, jawaban yang bagus.
Ross Patterson

8
@ Joel Jika dia hidup cukup lama, Dijkstra mungkin akan mengatakan, "Penggunaan [PHP] melumpuhkan pikiran; oleh karena itu pengajarannya harus dianggap pelanggaran pidana."
Ross Patterson

12
@Ross. "kesombongan dalam ilmu komputer diukur dalam nano-Dijkstras" - Alan Kay

33

1 - Abaikan kesalahan dan hasilkan 0sebagai hasilnya. Jika memungkinkan, mencatat peringatan.

Itu bukan ide yang bagus. Sama sekali. Orang-orang akan mulai bergantung padanya dan jika Anda pernah memperbaikinya, Anda akan merusak banyak kode.

2 - Tambahkan NaNsebagai nilai yang mungkin untuk angka, tetapi itu menimbulkan pertanyaan tentang bagaimana menangani NaNnilai di bidang lain bahasa.

Anda harus menangani NaN dengan cara runtimes bahasa lain melakukannya: Setiap perhitungan lebih lanjut juga menghasilkan NaN dan setiap perbandingan (bahkan NaN == NaN) menghasilkan false.

Saya pikir ini dapat diterima, tetapi tidak selalu ramah pendatang baru.

3 - Hentikan pelaksanaan program dan laporkan kepada pengguna kesalahan parah terjadi.

Ini adalah solusi terbaik yang saya pikir. Dengan informasi itu di tangan, pengguna harus dapat menangani 0. Anda harus menyediakan lingkungan pengujian, terutama jika itu dimaksudkan untuk dijalankan sekali malam.

Ada juga opsi keempat. Jadikan pembagian sebagai operasi ternary. Salah satu dari dua ini akan berfungsi:

  • div (pembilang, pembilang, alternative_result)
  • div (pembilang, pembilang, alternative_denumerator)

Tetapi jika Anda membuat NaN == NaNmenjadi false, maka Anda akan harus menambahkan isNaN()fungsi sehingga pengguna dapat mendeteksi NaNs.
AJMansfield

2
@AJMansfield: Entah itu, atau orang-orang menerapkannya sendiri: isNan(x) => x != x. Namun, ketika Anda telah NaNmuncul dalam kode pemrograman Anda, Anda tidak harus mulai menambahkan isNaNcek, tetapi melacak penyebabnya dan melakukan pemeriksaan yang diperlukan di sana. Karena itu penting untuk NaNdisebarkan sepenuhnya.
back2dos

5
NaNIni terutama kontra-intuitif. Dalam bahasa pemula, mereka mati pada saat kedatangan.
Ross Patterson

2
@RossPatterson Tapi seorang pemula dapat dengan mudah mengatakan 1/0- Anda harus melakukan sesuatu dengannya. Tidak ada hasil yang bermanfaat selain Infatau NaN- sesuatu yang akan menyebarkan kesalahan lebih lanjut ke dalam program. Kalau tidak, satu-satunya solusi adalah berhenti dengan kesalahan pada titik ini.
Mark Hurd

1
Opsi 4 dapat ditingkatkan dengan memungkinkan doa fungsi, yang pada gilirannya dapat melakukan tindakan apa pun yang diperlukan untuk memulihkan dari pembagi 0 tak terduga.
CyberFonic

21

Hentikan aplikasi yang sedang berjalan dengan prasangka ekstrem. (Sambil memberikan informasi debug yang memadai)

Kemudian ajarkan pengguna Anda untuk mengidentifikasi dan menangani kondisi di mana pembagi mungkin nol (nilai yang dimasukkan pengguna, dll.)


13

Dalam Haskell (dan serupa dalam Scala), alih-alih melemparkan pengecualian (atau mengembalikan referensi nol) jenis pembungkus Maybedan Eitherdapat digunakan. Dengan Maybepengguna memiliki kesempatan untuk menguji apakah nilai yang ia dapatkan adalah "kosong", atau ia mungkin memberikan nilai default ketika "membuka bungkus". Eitherserupa, tetapi dapat digunakan mengembalikan objek (mis. string kesalahan) yang menjelaskan masalah jika ada.


1
Benar, tetapi perhatikan bahwa Haskell tidak menggunakan ini untuk pembagian dengan nol. Sebaliknya, setiap tipe Haskell secara implisit memiliki "bottom" sebagai nilai yang memungkinkan. Ini bukan seperti pointer nol dalam arti bahwa itu adalah "nilai" dari ekspresi yang gagal untuk dihentikan. Anda tidak dapat menguji nonterminasi sebagai nilai, tentu saja, tetapi dalam semantik operasional kasus-kasus yang gagal untuk mengakhiri adalah bagian dari makna ekspresi. Di Haskell, nilai "terbawah" itu juga menangani hasil kasus kesalahan tambahan seperti error "some message"fungsi yang sedang dievaluasi.
Steve314

Secara pribadi, jika efek batal seluruh program dianggap valid, saya tidak tahu mengapa kode murni tidak dapat memiliki efek melemparkan pengecualian, tapi itu hanya saya - Haskelltidak mengizinkan ekspresi murni untuk membuang pengecualian.
Steve314

Saya pikir ini adalah ide yang baik karena selain melemparkan pengecualian, semua opsi yang diajukan tidak berkomunikasi dengan pengguna bahwa mereka membuat kesalahan. Gagasan dasarnya adalah bahwa pengguna melakukan kesalahan dengan nilai yang mereka berikan pada program, sehingga program harus memberi tahu pengguna bahwa mereka memberikan input yang salah (maka pengguna dapat memikirkan cara untuk memperbaiki). Tanpa memberi tahu pengguna tentang kesalahan mereka, solusi apa pun terasa aneh.
DiinformasikanA

Saya pikir ini adalah cara untuk pergi ... Bahasa pemrograman Rust menggunakannya secara luas di perpustakaan standarnya.
aochagavia

12

Jawaban lain telah mempertimbangkan manfaat relatif dari ide-ide Anda. Saya mengusulkan yang lain: gunakan analisis aliran dasar untuk menentukan apakah suatu variabel bisa nol. Kemudian Anda bisa dengan mudah melarang pembagian oleh variabel yang berpotensi nol.

x = ...
y = ...

if y ≠ 0:
  return x / y    // In this block, y is known to be nonzero.
else:
  return x / y    // This, however, is a compile-time error.

Atau, miliki fungsi penegasan cerdas yang menetapkan invarian:

x = ...
require x ≠ 0, "Unexpected zero in calculation"
// For the remainder of this scope, x is known to be nonzero.

Ini sama baiknya dengan melempar kesalahan runtime — Anda sepenuhnya menjalankan operasi yang tidak terdefinisi — tetapi memiliki keuntungan bahwa jalur kode bahkan tidak perlu mengenai kemungkinan kegagalan untuk diekspos. Hal ini dapat dilakukan seperti halnya pemeriksaan ketik biasa, dengan mengevaluasi semua cabang program dengan lingkungan pengetikan bersarang untuk melacak dan memverifikasi invarian:

x = ...           // env1 = { x :: int }
y = ...           // env2 = env1 + { y :: int }
if y ≠ 0:         // env3 = env2 + { y ≠ 0 }
  return x / y    // (/) :: (int, int ≠ 0) → int
else:             // env4 = env2 + { y = 0 }
  ...
...               // env5 = env2

Selain itu, ia meluas secara alami ke jangkauan dan nullmemeriksa, jika bahasa Anda memiliki fitur tersebut.


4
Gagasan yang rapi, tetapi jenis penyelesaian kendala ini adalah NP-complete. Bayangkan sesuatu seperti def foo(a,b): return a / ord(sha1(b)[0]). Analyzer statis tidak dapat membalikkan SHA-1. Dentang memiliki jenis analisis statis dan ini bagus untuk menemukan bug yang dangkal tetapi ada banyak kasus yang tidak dapat ditangani.
Mark E. Haase

9
ini bukan NP-lengkap, ini tidak mungkin - kata menghentikan lemma. Namun, penganalisa statis tidak perlu menyelesaikan ini, itu hanya bisa omong kosong pada pernyataan seperti ini dan mengharuskan Anda untuk menambahkan pernyataan atau dekorasi eksplisit.
MK01

1
@ MK01: Dengan kata lain, analisisnya “konservatif”.
Jon Purdy

11

Nomor 1 (masukkan nol untuk debuggable) selalu buruk. Pilihan antara # 2 (menyebarkan NaN) dan # 3 (membunuh proses) tergantung pada konteks dan idealnya harus menjadi pengaturan global, seperti di Numpy.

Jika Anda melakukan satu perhitungan besar, terintegrasi, menyebarkan NaN adalah ide yang buruk karena pada akhirnya akan menyebar dan menginfeksi seluruh perhitungan Anda --- ketika Anda melihat hasilnya di pagi hari dan melihat bahwa semuanya NaN, Anda saya harus membuang hasilnya dan mulai lagi lagi. Akan lebih baik jika program dihentikan, Anda mendapat telepon di tengah malam dan memperbaikinya --- dalam hal jumlah jam yang terbuang, setidaknya.

Jika Anda melakukan banyak perhitungan kecil yang sebagian besar independen (seperti penghitungan peta atau penghitungan paralel yang memalukan), dan Anda dapat mentolerir sebagian dari persentase itu tidak dapat digunakan karena NaN, itu mungkin pilihan terbaik. Menghentikan program dan tidak melakukan 99% yang akan baik dan bermanfaat karena 1% yang cacat dan dibagi dengan nol mungkin merupakan kesalahan.

Pilihan lain, terkait dengan NaN: spesifikasi floating-point IEEE yang sama mendefinisikan Inf dan -Inf, dan ini diperbanyak secara berbeda dari NaN. Sebagai contoh, saya cukup yakin bahwa Inf> angka apa saja dan -Jika <angka apa pun, yang akan menjadi apa yang Anda inginkan jika pembagian Anda dengan nol terjadi karena nol itu seharusnya hanya angka kecil. Jika input Anda dibulatkan dan mengalami kesalahan pengukuran (seperti pengukuran fisik yang dilakukan dengan tangan), perbedaan dua jumlah besar dapat menghasilkan nol. Tanpa pembagian dengan nol, Anda akan mendapatkan sejumlah besar, dan mungkin Anda tidak peduli seberapa besar itu. Dalam hal ini, In dan -Inf adalah hasil yang valid sempurna.

Itu bisa benar secara resmi, juga --- katakan saja Anda bekerja di real diperpanjang.


Tetapi kami tidak dapat mengatakan apakah penyebutnya dimaksudkan untuk menjadi positif atau negatif, sehingga pembagian mungkin menghasilkan + inf ketika -inf diinginkan, atau sebaliknya.
Daniel Lubarov

Benar, kesalahan pengukuran Anda terlalu kecil untuk membedakan antara + inf dan -inf. Ini sangat mirip dengan bola Riemann, di mana seluruh bidang kompleks dipetakan ke bola dengan tepat satu titik tak terbatas (titik yang secara diametris berlawanan dengan titik asal). Angka positif yang sangat besar, angka negatif yang sangat besar, dan bahkan angka imajiner dan kompleks yang sangat besar semuanya dekat dengan satu titik yang tak terbatas. Dengan sedikit kesalahan pengukuran, Anda tidak dapat membedakannya.
Jim Pivarski

Jika Anda bekerja dalam sistem semacam itu, Anda harus mengidentifikasi + inf dan -inf sebagai setara, sama seperti Anda harus mengidentifikasi +0 dan -0 sebagai setara, meskipun mereka memiliki representasi biner yang berbeda.
Jim Pivarski

8

3. Hentikan pelaksanaan program dan laporkan kepada pengguna kesalahan parah terjadi.

[Pilihan ini] tidak praktis ...

Tentu saja itu praktis: Adalah tanggung jawab programmer untuk menulis sebuah program yang benar-benar masuk akal. Membagi dengan 0 tidak masuk akal. Oleh karena itu, jika programmer melakukan pembagian, itu juga merupakan tanggung jawabnya untuk memverifikasi sebelumnya bahwa pembagi tidak sama dengan 0. Jika programmer gagal melakukan pemeriksaan validasi, maka ia harus menyadari kesalahan itu segera setelah mungkin, dan hasil perhitungan dinormalisasi (NaN) atau salah (0) tidak akan membantu dalam hal itu.

Opsi 3 kebetulan yang saya akan merekomendasikan kepada Anda, btw, untuk menjadi yang paling mudah, jujur, dan benar secara matematis.


4

Sepertinya ide yang buruk bagi saya untuk menjalankan tugas penting (yaitu; "nightly cron") di lingkungan di mana kesalahan diabaikan. Ide yang buruk untuk menjadikan ini fitur. Ini mengesampingkan opsi 1 dan 2.

Opsi 3 adalah satu-satunya solusi yang dapat diterima. Pengecualian tidak harus menjadi bagian dari bahasa, tetapi mereka adalah bagian dari kenyataan. Pesan penghentian Anda harus sespesifik dan se informatif mungkin tentang kesalahan tersebut.


3

IEEE 754 sebenarnya memiliki solusi yang didefinisikan dengan baik untuk masalah Anda. Penanganan pengecualian tanpa menggunakan exceptions http://en.wikipedia.org/wiki/IEEE_floating_point#Exception_handling

1/0  = Inf
-1/0 = -Inf
0/0  = NaN

dengan cara ini semua operasi Anda masuk akal secara matematis.

\ lim_ {x \ hingga 0} 1 / x = Inf

Menurut pendapat saya mengikuti IEEE 754 paling masuk akal karena memastikan bahwa perhitungan Anda sama benarnya dengan di komputer dan Anda juga konsisten dengan perilaku bahasa pemrograman lainnya.

Satu-satunya masalah yang muncul adalah Inf dan NaN akan mencemari hasil Anda dan pengguna Anda tidak akan tahu persis dari mana masalah itu berasal. Lihatlah bahasa seperti Julia yang melakukan ini dengan cukup baik.

julia> 1/0
Inf

julia> -1/0
-Inf

julia> 0/0
NaN

julia> a = [1,1,1] ./ [2,1,0]
3-element Array{Float64,1}:
   0.5
   1.0
 Inf

julia> sum(a)
Inf

julia> a = [1,1,0] ./ [2,1,0]
3-element Array{Float64,1}:
   0.5
   1.0
 NaN

julia> sum(a)
NaN

Kesalahan pembagian diperbanyak dengan benar melalui operasi matematika tetapi pada akhirnya pengguna tidak perlu tahu dari mana operasi berasal dari kesalahan tersebut.

edit:Saya tidak melihat bagian kedua dari jawaban oleh Jim Pivarski yang pada dasarnya adalah apa yang saya katakan di atas. Salahku.


2

SQL, bahasa yang paling mudah digunakan oleh non-programmer, tidak # 3, untuk apa pun itu layak. Dalam pengalaman saya mengamati dan membantu non-programmer menulis SQL, perilaku ini umumnya dipahami dengan baik dan mudah dikompensasi (dengan pernyataan kasus atau sejenisnya). Ini membantu bahwa pesan kesalahan yang Anda peroleh cenderung menjadi sangat langsung misalnya di Postgres 9 Anda mendapatkan "GALAT: pembagian dengan nol".


2

Saya pikir masalahnya adalah "ditargetkan untuk pengguna pemula. -> Jadi tidak ada dukungan untuk ..."

Mengapa Anda berpikir bahwa penanganan pengecualian bermasalah bagi pengguna pemula?

Apa yang lebih buruk? Punya fitur "sulit" atau tidak tahu mengapa sesuatu terjadi? Apa yang bisa lebih membingungkan? Kecelakaan dengan dump inti atau "Fatal error: Divide by Zero"?

Sebaliknya, saya pikir JAUH lebih baik untuk membidik kesalahan pesan HEBAT. Jadi lakukan sebagai gantinya: "Perhitungan buruk, Bagi 0/0" (yaitu: Selalu tunjukkan DATA yang menyebabkan masalah, bukan hanya jenis masalah). Lihatlah bagaimana PostgreSql melakukan kesalahan pesan, itu adalah IMHO yang hebat.

Namun, Anda dapat melihat cara lain untuk bekerja dengan pengecualian seperti:

http://dlang.org/exception-safe.html

Saya juga punya mimpi membangun bahasa, dan dalam hal ini saya berpikir bahwa mencampur Mungkin / Opsional dengan Pengecualian normal bisa menjadi yang terbaik:

def openFile(fileName): File | Exception
    if not(File.Exist(fileName)):
        raise FileNotExist(fileName)
    else:
        return File.Open()

#This cause a exception:

theFile = openFile('not exist')

# But this, not:

theFile | err = openFile('not exist')

1

Dalam pandangan saya bahasa Anda harus menyediakan mekanisme umum untuk mendeteksi dan menangani kesalahan. Kesalahan pemrograman harus dideteksi pada waktu kompilasi (atau sedini mungkin) dan biasanya mengarah pada penghentian program. Kesalahan yang dihasilkan dari data yang tidak terduga atau salah, atau dari kondisi eksternal yang tidak terduga, harus dideteksi dan tersedia untuk tindakan yang sesuai, tetapi memungkinkan program untuk melanjutkan bila memungkinkan.

Tindakan yang masuk akal termasuk (a) mengakhiri (b) meminta pengguna untuk tindakan (c) mencatat kesalahan (d) mengganti nilai yang diperbaiki (e) menetapkan indikator untuk diuji dalam kode (f) meminta rutinitas penanganan kesalahan. Manakah dari ini yang Anda sediakan dan dengan cara apa saja pilihan yang harus Anda buat.

Dari pengalaman saya, kesalahan data umum seperti konversi yang salah, bagi dengan nol, luapan dan nilai di luar rentang jinak dan secara default harus ditangani dengan mengganti nilai yang berbeda dan menetapkan bendera kesalahan. (Non-programmer) yang menggunakan bahasa ini akan melihat data yang salah dan dengan cepat memahami kebutuhan untuk memeriksa kesalahan dan menanganinya.

[Sebagai contoh, pertimbangkan spreadsheet Excel. Excel tidak menghentikan spreadsheet Anda karena angka meluap atau apa pun. Sel mendapat nilai aneh dan Anda mencari tahu mengapa dan memperbaikinya.]

Jadi untuk menjawab pertanyaan Anda: Anda tentu tidak harus berhenti. Anda mungkin mengganti NaN tetapi Anda tidak harus membuatnya terlihat, pastikan saja perhitungannya selesai dan menghasilkan nilai tinggi yang aneh. Dan atur flag kesalahan sehingga pengguna yang membutuhkannya dapat menentukan bahwa kesalahan terjadi.

Pengungkapan: Saya menciptakan implementasi bahasa (Powerflex) dan mengatasi masalah ini (dan banyak lainnya) pada 1980-an. Ada sedikit atau tidak ada kemajuan pada bahasa untuk non-programmer dalam 20 tahun terakhir, dan Anda akan menarik banyak kritik karena mencoba, tetapi saya sangat berharap Anda berhasil.


1

Saya menyukai operator ternary di mana Anda memberikan nilai alternatif jika penyebutnya 0.

Satu lagi gagasan yang tidak saya lihat adalah menghasilkan nilai "tidak valid" umum. Umum "variabel ini tidak memiliki nilai karena program melakukan sesuatu yang buruk", yang membawa jejak tumpukan penuh dengan dirinya sendiri. Lalu, jika Anda pernah menggunakan nilai itu di mana saja, hasilnya sekali lagi tidak valid, dengan operasi baru dicoba di atas (yaitu jika nilai tidak valid pernah muncul dalam ekspresi, seluruh ekspresi menghasilkan tidak valid dan tidak ada panggilan fungsi yang dicoba; pengecualian akan menjadi operator boolean - benar atau tidak benar benar dan salah dan tidak valid salah - mungkin ada pengecualian lain untuk itu). Setelah nilai itu tidak lagi direferensikan di mana saja, Anda mencatat deskripsi panjang yang bagus dari seluruh rantai di mana segala sesuatu salah dan melanjutkan bisnis seperti biasa. Mungkin mengirim email jejak ke pimpinan proyek atau sesuatu.

Sesuatu seperti monad Maybe pada dasarnya. Ini akan bekerja dengan hal lain yang dapat gagal juga, dan Anda dapat memungkinkan orang untuk membangun cacat mereka sendiri. Dan program akan terus berjalan selama kesalahannya tidak terlalu dalam, yang sebenarnya diinginkan di sini, saya pikir.


1

Ada dua alasan mendasar untuk membagi dengan nol.

  1. Dalam model yang tepat (seperti bilangan bulat), Anda mendapatkan pembagian dengan nol DBZ karena input salah. Ini adalah jenis DBZ yang sebagian besar dari kita pikirkan.
  2. Dalam model yang tidak tepat (seperti floating pt), Anda mungkin mendapatkan DBZ karena kesalahan pembulatan meskipun inputnya valid. Inilah yang biasanya tidak kita pikirkan.

Untuk 1. Anda harus berkomunikasi kembali kepada pengguna bahwa mereka melakukan kesalahan karena merekalah yang bertanggung jawab dan merekalah yang paling tahu bagaimana memperbaiki situasi.

Untuk 2. Ini bukan kesalahan pengguna, Anda dapat menunjuk ke algoritme, implementasi perangkat keras, dll. Tapi ini bukan kesalahan pengguna sehingga Anda tidak boleh menghentikan program atau bahkan melempar pengecualian (jika diizinkan yang tidak dalam kasus ini). Jadi solusi yang masuk akal adalah melanjutkan operasi dengan cara yang masuk akal.

Saya dapat melihat orang yang mengajukan pertanyaan ini menanyakan kasus 1. Jadi, Anda perlu berkomunikasi kembali dengan pengguna. Menggunakan standar floating point apa pun, Inf, -Inf, Nan, IEEE tidak cocok dalam situasi ini. Strategi yang secara fundamental salah.


0

Tolak dalam bahasa. Dengan kata lain, larang membagi dengan angka sampai terbukti tidak nol, biasanya dengan mengujinya terlebih dahulu. Yaitu.

int div = random(0,100);
int b = 10000 / div; // Error E0000: div might be zero

Untuk melakukan ini, Anda memerlukan tipe numerik baru, bilangan alami, dan bukan bilangan bulat. Itu bisa ... sulit ... untuk dihadapi.
Servy

@Ervy: Tidak, kamu tidak akan. Mengapa kamu akan? Anda memang membutuhkan logika di kompiler untuk menentukan nilai yang mungkin, tetapi Anda tetap menginginkannya (untuk alasan pengoptimalan).
MSalters

Jika Anda tidak memiliki tipe yang berbeda, satu untuk nol dan satu untuk nilai bukan nol, maka Anda tidak akan dapat menyelesaikan masalah dalam kasus umum. Anda akan memiliki positif palsu, dan memaksa pengguna untuk memeriksa nol jauh lebih sering daripada yang seharusnya, atau Anda akan membuat situasi di mana mereka masih dapat membaginya dengan nol.
Servy

@Ervy: Anda salah: kompiler dapat melacak keadaan itu tanpa memerlukan jenis seperti itu, dan misalnya GCC sudah melakukannya. Misalnya, tipe C intmemungkinkan nilai nol, tetapi GCC masih dapat menentukan di mana dalam kode int tertentu tidak boleh nol.
MSalters

2
Tetapi hanya dalam kasus-kasus tertentu; tidak dapat melakukannya, dengan akurasi 100%, dalam semua kasus. Anda akan memiliki positif palsu atau negatif palsu. Ini terbukti benar. Misalnya, saya dapat membuat potongan kode yang mungkin atau bahkan tidak lengkap . Jika kompiler bahkan tidak bisa tahu apakah sudah selesai, bagaimana mungkin ia tahu jika int yang dihasilkan adalah nol? Ini dapat menangkap kasus-kasus sederhana yang jelas, tetapi tidak semua kasus.
Servy

0

Saat Anda menulis bahasa pemrograman, Anda harus mengambil keuntungan dari fakta dan mewajibkan untuk memasukkan tindakan untuk rancangan dengan keadaan nol. a <= n / c: 0 div-by-zero-action

Saya tahu apa yang saya sarankan pada dasarnya adalah menambahkan 'goto' ke PL Anda.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.