Mengapa 0 salah?

115

Pertanyaan ini mungkin terdengar bodoh, tetapi mengapa 0harus dievaluasi falsedan nilai [integer] lainnya truekebanyakan bahasa pemrograman?

Perbandingan string

Karena pertanyaannya tampak agak terlalu sederhana, saya akan menjelaskan diri saya sedikit lagi: pertama-tama, mungkin tampak jelas bagi setiap programmer, tetapi mengapa tidak akan ada bahasa pemrograman - mungkin sebenarnya ada, tetapi tidak ada Saya menggunakan - di mana 0mengevaluasi truedan semua nilai [integer] lainnya false? Satu komentar itu mungkin tampak acak, tapi saya punya beberapa contoh di mana itu mungkin ide yang bagus. Pertama-tama, mari kita ambil contoh perbandingan tiga arah string, saya akan mengambil C strcmpsebagai contoh: setiap programmer yang mencoba C karena bahasa pertamanya mungkin tergoda untuk menulis kode berikut:

if (strcmp(str1, str2)) { // Do something... }

Karena strcmppengembalian 0yang mengevaluasi falseketika string sama, apa yang coba dilakukan oleh programmer awal gagal total dan dia umumnya tidak mengerti mengapa pada awalnya. Telah 0dievaluasi untuk truesebaliknya, fungsi ini bisa digunakan dalam ekspresi yang paling sederhana - satu di atas - ketika membandingkan kesetaraan, dan pemeriksaan yang tepat untuk -1dan 1akan telah dilakukan hanya bila diperlukan. Kami akan menganggap tipe pengembalian sebagai bool(dalam pikiran kami maksud saya) sebagian besar waktu.

Selain itu, mari kita perkenalkan tipe baru sign,, yang hanya mengambil nilai -1, 0dan 1. Itu bisa sangat berguna. Bayangkan ada operator pesawat ruang angkasa di C ++ dan kami menginginkannya std::string(well, sudah ada comparefungsinya, tetapi operator pesawat ruang angkasa lebih menyenangkan). Deklarasi saat ini akan menjadi yang berikut:

sign operator<=>(const std::string& lhs, const std::string& rhs);

Telah 0dievaluasi true, operator pesawat ruang angkasa bahkan tidak ada, dan kami bisa menyatakan operator==seperti itu:

sign operator==(const std::string& lhs, const std::string& rhs);

Ini operator==akan menangani perbandingan tiga arah sekaligus, dan masih dapat digunakan untuk melakukan pemeriksaan berikut sambil masih dapat memeriksa string mana yang secara leksikografis lebih unggul dari yang lain ketika dibutuhkan:

if (str1 == str2) { // Do something... }

Penanganan kesalahan lama

Kami sekarang memiliki pengecualian, jadi bagian ini hanya berlaku untuk bahasa lama di mana tidak ada hal seperti itu (C misalnya). Jika kita melihat pustaka standar C (dan juga POSIX satu), kita dapat melihat dengan pasti bahwa fungsi maaaaany kembali 0ketika berhasil dan bilangan bulat apa pun sebaliknya. Saya sedih melihat beberapa orang melakukan hal-hal semacam ini:

#define TRUE 0
// ...
if (some_function() == TRUE)
{
    // Here, TRUE would mean success...
    // Do something
}

Jika kita memikirkan bagaimana kita berpikir dalam pemrograman, kita sering memiliki pola penalaran berikut:

Do something
Did it work?
Yes ->
    That's ok, one case to handle
No ->
    Why? Many cases to handle

Jika kita memikirkannya lagi, masuk akal untuk menempatkan satu-satunya nilai netral 0,, ke yes(dan begitulah fungsi C bekerja), sementara semua nilai lain dapat berada di sana untuk menyelesaikan banyak kasus no. Namun, dalam semua bahasa pemrograman saya tahu (kecuali mungkin beberapa bahasa esoterik eksperimental), yang yesmengevaluasi falsedalam suatu ifkondisi, sementara semua nokasus dievaluasi true. Ada banyak situasi ketika "itu berfungsi" mewakili satu kasus sementara "itu tidak berfungsi" mewakili banyak kemungkinan penyebab. Jika kita berpikir seperti itu, 0mengevaluasi truedan sisanya falseakan jauh lebih masuk akal.

Kesimpulan

Kesimpulan saya adalah pada dasarnya pertanyaan asli saya: mengapa kita merancang bahasa mana 0adalah falsedan nilai-nilai lain yang true, mengambil dalam account beberapa contoh saya di atas dan mungkin beberapa lagi saya tidak memikirkan?

Tindak lanjut: Sangat menyenangkan melihat ada banyak jawaban dengan banyak ide dan sebanyak mungkin alasan untuk menjadi seperti itu. Saya suka bagaimana Anda tampaknya bersemangat tentang hal itu. Saya awalnya mengajukan pertanyaan ini karena bosan, tetapi karena Anda tampak bersemangat, saya memutuskan untuk melangkah sedikit lebih jauh dan bertanya tentang alasan di balik pilihan Boolean untuk 0 dan 1 di Math.SE :)

Morwenn
sumber
32
strcmp()bukan contoh yang baik untuk benar atau salah, karena mengembalikan 3 nilai yang berbeda. Dan Anda akan terkejut ketika Anda mulai menggunakan shell, di mana 0 berarti benar dan yang lainnya berarti salah.
ott--
52
@ ott--: Dalam shell Unix, 0 berarti sukses dan bukan nol berarti kegagalan - tidak persis sama dengan "benar" dan "salah".
Keith Thompson
14
@KeithThompson: Di Bash (dan kerang lainnya), "sukses" dan "kegagalan" benar-benar sama dengan "benar" dan "salah". Pertimbangkan, misalnya, pernyataan if true ; then ... ; fi, di mana trueperintah yang mengembalikan nol dan ini memberitahu ifuntuk dijalankan ....
ruakh
13
Tidak ada boolean dalam perangkat keras apa pun, hanya angka biner, dan dalam sebagian besar ISA, angka bukan nol dianggap sebagai "benar" dalam semua instruksi percabangan bersyarat (kecuali jika mereka menggunakan flag sebagai gantinya). Jadi, bahasa tingkat rendah dengan segala cara wajib mengikuti properti perangkat keras yang mendasarinya.
SK-logic
2
@MasonWheeler Memiliki tipe boolean tidak menyiratkan apa pun. Sebagai contoh python memang memiliki booltipe tetapi perbandingan / jika kondisi dll dapat memiliki nilai balik.
Bakuriu

Jawaban:

98

0adalah falsekarena mereka berdua nol unsur kesamaan semirings . Meskipun mereka adalah tipe data yang berbeda, masuk akal secara intuitif untuk mengkonversi di antara mereka karena mereka milik struktur aljabar isomorfik.

  • 0adalah identitas untuk penjumlahan dan nol untuk perkalian. Ini berlaku untuk bilangan bulat dan rasional, tetapi tidak untuk angka floating-point IEEE-754: 0.0 * NaN = NaNdan 0.0 * Infinity = NaN.

  • falseadalah identitas untuk Boolean xor (⊻) dan nol untuk Boolean dan (∧). Jika Boolean direpresentasikan sebagai {0, 1} —set bilangan bulat modulo 2 — Anda dapat menganggap ⊻ sebagai tambahan tanpa carry dan ∧ sebagai perkalian.

  • ""dan []merupakan identitas untuk rangkaian, tetapi ada beberapa operasi yang masuk akal sebagai nol. Pengulangan adalah satu, tetapi pengulangan dan penyatuan tidak mendistribusikan, sehingga operasi ini tidak membentuk semiring.

Konversi tersirat semacam itu sangat membantu dalam program kecil, tetapi dalam jumlah besar dapat membuat program lebih sulit untuk dipikirkan. Hanya satu dari banyak pengorbanan dalam desain bahasa.

Jon Purdy
sumber
1
Senang bahwa Anda menyebutkan daftar. (BTW, nilapakah daftar kosong []dan falsenilai dalam Common Lisp; adakah kecenderungan untuk menggabungkan identitas dari tipe data yang berbeda?) Anda masih harus menjelaskan mengapa wajar untuk menganggap false sebagai identitas aditif dan benar sebagai identitas multiplikatif dan bukan sebaliknya. Apakah tidak mungkin dipertimbangkan truesebagai identifikasi untuk ANDdan nol untuk OR?
Giorgio
3
+1 untuk merujuk pada identitas yang serupa. Akhirnya jawaban yang tidak hanya bermuara pada "konvensi, atasi itu".
l0b0
5
+1 untuk memberikan detail matematika yang konkret dan sangat lama yang diikuti dan sudah masuk akal
Jimmy Hoffa
1
Jawaban ini tidak masuk akal. truejuga merupakan identitas dan nol semiring (Boolean dan / atau). Tidak ada alasan, konvensi appart, untuk mempertimbangkan falselebih dekat ke 0 daripada true.
TonioElGringo
1
@TonioElGringo: Perbedaan antara benar dan salah adalah perbedaan antara XOR dan XNOR. Seseorang dapat membentuk cincin isomorfik menggunakan AND / XOR, di mana true adalah identitas multiplikatif dan false sebagai aditif, atau dengan OR dan XNOR, di mana false adalah identitas multiplikatif dan true adalah aditif, tetapi XNOR biasanya tidak dianggap sebagai yang umum operasi mendasar seperti XOR.
supercat
74

Karena matematika berhasil.

FALSE OR TRUE is TRUE, because 0 | 1 is 1.

... insert many other examples here.

Secara tradisional, program C memiliki kondisi seperti

if (someFunctionReturningANumber())

daripada

if (someFunctionReturningANumber() != 0)

karena konsep nol yang setara dengan yang salah dipahami dengan baik.

Robert Harvey
sumber
21
Bahasa dirancang seperti itu karena matematika masuk akal. Itu yang lebih dulu.
Robert Harvey
26
@Morwenn, itu kembali ke abad ke-19 dan George Boole. Orang-orang telah mewakili False as 0 dan True as! 0 lebih lama dari yang ada komputer.
Charles E. Grant
11
Saya tidak melihat mengapa matematika tidak bekerja sebaliknya jika Anda hanya mengubah semua definisi sehingga AND adalah + dan OR adalah *.
Neil G
7
Tepatnya: matematika bekerja dua arah dan jawaban untuk pertanyaan ini tampaknya murni murni.
Neil G
6
@ Robert Akan lebih bagus jika Anda bisa mengeja "dasar matematika" di posting Anda.
phant0m
38

Seperti yang orang lain katakan, matematika lebih dulu. Inilah sebabnya 0 adalah falsedan 1 adalah true.

Matematika mana yang sedang kita bicarakan? Aljabar Boolean yang berasal dari pertengahan 1800-an, jauh sebelum komputer digital datang.

Anda juga bisa mengatakan bahwa konvensi tersebut keluar dari logika proposisional , yang bahkan lebih tua dari aljabar boolean. Ini adalah formalisasi dari banyak hasil logis yang diketahui dan cinta programmer ( false || xsama x, true && xsama xdan sebagainya).

Pada dasarnya kita berbicara tentang aritmatika pada set dengan dua elemen. Pikirkan tentang penghitungan dalam biner. Aljabar Boolean adalah asal dari konsep ini dan landasan teoretisnya. Konvensi bahasa seperti C hanyalah aplikasi sederhana.

joshin4colours
sumber
2
Anda pasti bisa. Tetapi menjaganya tetap "standar" cocok dengan aritmatika umum (0 +1 = 1, bukan 0 +1 = 0).
joshin4colours
2
Ya, tetapi Anda mungkin akan menulis DAN dengan + dan ATAU dengan * jika Anda membalikkan definisi juga.
Neil G
3
Matematika tidak diutamakan. Matematika mengakui bahwa 0 dan 1 membentuk bidang, di mana AND seperti perkalian dan OR seperti penambahan.
Kaz
1
@ Ka: Tapi {0, 1} dengan OR dan AND tidak membentuk bidang.
Giorgio
2
Saya sedikit terganggu karena lebih banyak jawaban dan komentar mengatakan itu true = 1. Itu tidak terlalu tepat, karena true != 0yang tidak persis sama. Salah satu alasan (bukan satu-satunya) mengapa seseorang harus menghindari perbandingan suka if(something == true) { ... }.
JensG
26

Saya pikir ini ada hubungannya dengan "warisan" dari elektronik, dan juga aljabar boolean, di mana

  • 0= off, negative, no,false
  • 1= on, positive, yes,true

strcmp mengembalikan 0 ketika string sama dengan hubungannya dengan implementasinya, karena apa yang sebenarnya dilakukannya adalah menghitung "jarak" antara dua string. Bahwa 0 juga dianggap salah hanyalah kebetulan.

mengembalikan 0 pada kesuksesan masuk akal karena 0 dalam hal ini digunakan berarti tidak ada kesalahan dan angka lainnya akan menjadi kode kesalahan. Menggunakan nomor lain untuk sukses akan kurang masuk akal karena Anda hanya memiliki satu kode sukses, sementara Anda dapat memiliki beberapa kode kesalahan. Anda menggunakan "Apakah itu berhasil?" sebagai pernyataan if statement dan mengatakan 0 = yes akan lebih masuk akal, tetapi ungkapan itu lebih tepat "Apakah ada yang salah?" dan kemudian Anda melihat bahwa 0 = tidak masuk akal. Berpikir false/truetidak masuk akal di sini, karena sebenarnya no error code/error code.

Svish
sumber
Haha, Anda adalah orang pertama yang menyatakan pertanyaan kesalahan pengembalian secara eksplisit. Saya sudah tahu saya menafsirkannya dengan cara saya sendiri dan dan itu bisa dengan menanyakannya dengan cara lain, tetapi Anda adalah orang pertama yang secara eksplisit mengungkapkannya (dari banyak jawaban dan komentar). Sebenarnya, saya tidak akan mengatakan bahwa satu atau lain cara tidak masuk akal, tetapi lebih dari keduanya masuk akal dengan cara yang berbeda :)
Morwenn
1
Sebenarnya saya akan mengatakan 0untuk success/no erroradalah satu-satunya hal yang masuk akal ketika bilangan bulat lainnya mewakili kode kesalahan. Itu 0juga terjadi untuk mewakili falsedalam kasus lain tidak terlalu penting, karena kita sama sekali tidak berbicara tentang benar atau salah;)
Svish
Saya punya ide yang sama jadi saya naik
user60812
1
Poin Anda tentang strcmp()menghitung jarak cukup baik. Jika sudah dipanggil strdiff()maka if (!strdiff())akan sangat logis.
Kevin Cox
"elektronik [...] di mana 0 = [...] salah, 1 = [...] benar" - bahkan dalam elektronik, ini hanya sebuah konvensi , dan bukan satu-satunya. Kami menyebutnya logika positif ini, tetapi Anda juga dapat menggunakan logika negatif, di mana tegangan positif menunjukkan false dan negatif menunjukkan true. Kemudian, sirkuit yang Anda gunakan untuk DAN menjadi ATAU, ATAU menjadi DAN, dan seterusnya. Karena hukum De Morgan, semuanya akhirnya menjadi setara. Kadang-kadang, Anda akan menemukan bagian dari rangkaian elektronik yang diimplementasikan dalam logika negatif untuk kenyamanan, di mana titik nama-nama sinyal di bagian itu dicatat dengan bilah di atasnya.
Jules
18

Sebagaimana dijelaskan dalam artikel ini , nilai-nilai falsedan truetidak boleh dikacaukan dengan bilangan bulat 0 dan 1, tetapi dapat diidentifikasi dengan unsur-unsur bidang Galois (bidang terbatas) dari dua elemen (lihat di sini ).

Field adalah himpunan dengan dua operasi yang memenuhi aksioma tertentu.

Simbol 0 dan 1 secara konvensional digunakan untuk menunjukkan identitas aditif dan multiplikatif dari suatu bidang karena bilangan real juga merupakan bidang (tetapi bukan yang terbatas) yang identitasnya adalah angka 0 dan 1.

Identitas aditif adalah elemen 0 bidang, sehingga untuk semua x:

x + 0 = 0 + x = x

dan identitas multiplikatif adalah elemen 1 dari bidang, sehingga untuk semua x:

x * 1 = 1 * x = x

Bidang terbatas dari dua elemen hanya memiliki dua elemen ini, yaitu identitas aditif 0 (atau false), dan identitas multiplikatif 1 (atau true). Dua operasi bidang ini adalah XOR logis (+) dan logika AND (*).

Catatan. Jika Anda membalik operasi (XOR adalah perkalian dan DAN adalah tambahan) maka perkalian tidak distributif atas penambahan dan Anda tidak memiliki bidang lagi. Dalam kasus seperti itu Anda tidak memiliki alasan untuk memanggil dua elemen 0 dan 1 (dalam urutan apa pun). Perhatikan juga bahwa Anda tidak dapat memilih operasi ATAU alih-alih XOR: tidak peduli bagaimana Anda mengartikan OR / DAN sebagai penambahan / perkalian, struktur yang dihasilkan bukan bidang (tidak semua elemen terbalik ada seperti yang dipersyaratkan oleh aksioma bidang).

Mengenai fungsi C:

  • Banyak fungsi mengembalikan integer yang merupakan kode kesalahan. 0 berarti TANPA KESALAHAN.
  • Secara intuitif, fungsi strcmpmenghitung perbedaan antara dua string. 0 berarti tidak ada perbedaan antara dua string, yaitu bahwa dua string sama.

Penjelasan intuitif di atas dapat membantu untuk mengingat interpretasi nilai-nilai pengembalian, tetapi bahkan lebih mudah untuk hanya memeriksa dokumentasi perpustakaan.

Giorgio
sumber
1
+1 untuk menunjukkan bahwa jika Anda menukar ini dengan sewenang-wenang, matematika tidak lagi berfungsi.
Jimmy Hoffa
2
Membalik: Diberikan bidang dengan dua elemen dan operasi * dan +, kami mengidentifikasi Benar dengan 0 dan Salah dengan 1. Kami mengidentifikasi OR dengan * dan XOR dengan +.
Neil G
1
Anda akan menemukan bahwa kedua identifikasi ini dilakukan di bidang yang sama dan keduanya konsisten dengan aturan logika Boolean. Sayangnya, catatan Anda salah :)
Neil G
1
Jika Anda berasumsi bahwa True = 0, dan XOR adalah +, maka True harus menjadi identitas untuk XOR. Tetapi itu bukan karena True XOR True = False. Kecuali Anda mendefinisikan ulang operasi XOR pada True sehingga True XOR True = True. Maka tentu saja konstruksi Anda berfungsi karena Anda baru saja mengganti nama hal-hal (dalam struktur matematika apa pun Anda selalu dapat berhasil membuat permutasi nama dan mendapatkan struktur isomorfik). Di sisi lain, jika Anda membiarkan Benar, Salah dan XOR memiliki makna seperti biasanya, maka True XOR Benar = Salah dan Benar tidak dapat menjadi identitas tambahan, yaitu Benar tidak boleh 0.
Giorgio
1
@Giorgio: Saya mengoreksi konstruksi saya per komentar Anda di komentar terakhir saya ...
Neil G
13

Anda harus mempertimbangkan bahwa sistem alternatif juga dapat menjadi keputusan desain yang dapat diterima.

Kerang: 0 status keluar benar, bukan nol salah

Contoh shell yang memperlakukan status keluar 0 sebagai true telah disebutkan.

$ ( exit 0 ) && echo "0 is true" || echo "0 is false"
0 is true
$ ( exit 1 ) && echo "1 is true" || echo "1 is false"
1 is false

Alasannya adalah bahwa ada satu cara untuk berhasil, tetapi banyak cara untuk gagal, jadi menggunakan 0 sebagai nilai khusus yang berarti "tidak ada kesalahan" adalah pragmatis.

Ruby: 0 sama seperti nomor lainnya

Di antara bahasa pemrograman "normal", ada beberapa pencilan, seperti Ruby, yang memperlakukan 0 sebagai nilai sebenarnya.

$ irb
irb(main):001:0> 0 ? '0 is true' : '0 is false'
=> "0 is true"

The pemikiran adalah bahwa hanya falsedan nilharus palsu. Bagi banyak pemula Ruby, ini adalah gotcha. Namun, dalam beberapa kasus, bagus bahwa 0 diperlakukan sama seperti nomor lainnya.

irb(main):002:0> (pos = 'axe' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 1"
irb(main):003:0> (pos = 'xyz' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 0"
irb(main):004:0> (pos = 'abc' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "x not found"

Namun, sistem seperti itu hanya berfungsi dalam bahasa yang mampu membedakan boolean sebagai tipe terpisah dari angka. Pada hari-hari awal komputasi, programmer yang bekerja dengan bahasa assembly atau bahasa mesin mentah tidak memiliki kemewahan seperti itu. Mungkin wajar untuk memperlakukan 0 sebagai keadaan "kosong", dan menetapkan sedikit ke 1 sebagai bendera ketika kode mendeteksi bahwa sesuatu terjadi. Dengan ekstensi, konvensi berkembang bahwa nol diperlakukan sebagai salah, dan nilai-nilai bukan nol kemudian dianggap benar. Namun, tidak harus seperti itu.

Java: Angka tidak bisa diperlakukan sebagai boolean sama sekali

Di Jawa, truedan falsemerupakan satu-satunya nilai boolean. Angka bukan boolean, dan bahkan tidak bisa dimasukkan ke boolean ( Spesifikasi Bahasa Jawa, Bagian 4.2.2 ):

Tidak ada gips antara tipe integral dan tipe boolean.

Aturan itu hanya menghindari pertanyaan sama sekali - semua ekspresi boolean harus ditulis secara eksplisit dalam kode.

200_sukses
sumber
1
Rebol dan Red sama-sama memperlakukan INTEGER bernilai 0! nilai sebagai true, dan memiliki NONE yang terpisah! ketik (dengan hanya satu nilai, NONE) diperlakukan sebagai conditional false di samping LOGIC! Salah. Saya telah menemukan frustrasi yang signifikan dalam mencoba menulis kode JavaScript yang memperlakukan 0 sebagai salah; itu adalah keputusan yang sangat kikuk untuk bahasa yang diketik secara dinamis. Jika Anda ingin menguji sesuatu yang bisa nol atau 0 Anda akhirnya harus menulis if (thing === 0), itu tidak keren.
HostileFork
@HostileFork Saya tidak tahu. Saya menemukan bahwa masuk akal bahwa 0adalah true(karena setiap bilangan bulat lainnya) dalam bahasa dinamis. Saya kadang-kadang menangkap 0ketika mencoba menangkap Nonedengan Python, dan itu kadang-kadang bisa sangat sulit dikenali.
Morwenn
2
Ruby bukan pencilan. Ruby mengambil ini dari Lisp (Ruby bahkan diam-diam disebut "MatzLisp"). Lisp adalah bahasa utama dalam ilmu komputer. Zero adalah juga hanya nilai sebenarnya dalam shell POSIX, karena itu sepotong teks: if [ 0 ] ; then echo this executes ; fi. Nilai data palsu adalah string kosong, dan kepalsuan yang dapat diuji adalah status pemutusan perintah yang gagal, yang diwakili oleh bukan- nol.
Kaz
8

Sebelum membahas kasus umum, kami dapat membahas contoh tanggapan Anda.

Perbandingan string

Hal yang sama berlaku untuk berbagai macam perbandingan, sebenarnya. Perbandingan semacam itu menghitung jarak antara dua objek. Ketika objek sama, jaraknya minimal. Jadi ketika "perbandingan berhasil", nilai adalah 0. Tapi sungguh, nilai kembali dari strcmpadalah tidak boolean, itu adalah jarak, dan bahwa apa perangkap programmer menyadari melakukan if (strcmp(...)) do_when_equal() else do_when_not_equal().

Dalam C ++ kita bisa mendesain ulang strcmpuntuk mengembalikan Distanceobjek, yang menimpa operator bool()untuk mengembalikan true ketika 0 (tetapi Anda kemudian akan digigit oleh serangkaian masalah yang berbeda). Atau dalam plain C hanya memiliki streqfungsi yang mengembalikan 1 ketika string sama, dan 0 sebaliknya.

Panggilan API / kode keluar program

Di sini Anda peduli tentang alasan ada yang tidak beres, karena ini akan membuat keputusan salah. Ketika semuanya berhasil, Anda tidak ingin tahu apa-apa khususnya - niat Anda terwujud. Nilai pengembalian karenanya harus menyampaikan informasi ini. Ini bukan boolean, ini adalah kode kesalahan. Nilai kesalahan khusus 0 berarti "tidak ada kesalahan". Sisa rentang mewakili kesalahan berarti secara lokal yang harus Anda tangani (termasuk 1, yang sering berarti "kesalahan yang tidak ditentukan").

Kasus umum

Ini meninggalkan kita dengan pertanyaan: mengapa nilai boolean Truedan Falsebiasanya direpresentasikan dengan 1 dan 0, masing-masing?

Nah, selain argumen subyektif "rasanya lebih baik begini", berikut adalah beberapa alasan (subyektif juga) yang dapat saya pikirkan:

  • analogi sirkuit listrik. Saat ini HIDUP untuk 1s, dan OFF untuk 0s. Saya suka memiliki (1, Ya, Benar, Aktif) bersama, dan (0, Tidak, Salah, Tidak Aktif), daripada campuran lainnya

  • inisialisasi memori. Ketika saya memset(0)banyak variabel (baik itu int, float, bools) saya ingin nilainya cocok dengan asumsi yang paling konservatif. Misalnya jumlah saya awalnya 0, predikat Salah, dll.

Mungkin semua alasan ini terkait dengan pendidikan saya - jika saya diajarkan untuk mengasosiasikan 0 dengan True dari awal, saya akan memilih sebaliknya.

pengguna44761
sumber
2
Sebenarnya setidaknya ada satu bahasa pemrograman yang memperlakukan 0 sebagai benar. Shell unix.
Jan Hudec
+1 untuk mengatasi masalah sebenarnya: Sebagian besar pertanyaan Morwenn boolsama sekali bukan tentang .
dan04
@ dan04 Ya. Seluruh posting adalah tentang alasan di balik pilihan pemain dari intke booldalam banyak bahasa pemrograman. Hal-hal perbandingan dan kesalahan gestion hanyalah contoh tempat di mana casting dengan cara lain daripada yang saat ini dilakukan akan masuk akal.
Morwenn
6

Dari perspektif tingkat tinggi, Anda berbicara tentang tiga tipe data yang sangat berbeda:

  1. Boolean. Konvensi matematika dalam aljabar Boolean adalah menggunakan 0 untuk falsedan 1 untuk true, sehingga masuk akal untuk mengikuti konvensi itu. Saya pikir cara ini juga lebih masuk akal secara intuitif.

  2. Hasil perbandingan. Ini memiliki tiga nilai: <, =dan >(perhatikan bahwa tidak satupun dari mereka adalah true). Bagi mereka masuk akal untuk menggunakan nilai -1, 0 dan 1, masing-masing (atau, lebih umum, nilai negatif, nol dan nilai positif).

    Jika Anda ingin memeriksa kesetaraan dan Anda hanya memiliki fungsi yang melakukan perbandingan umum, saya pikir Anda harus membuatnya eksplisit dengan menggunakan sesuatu seperti strcmp(str1, str2) == 0. Saya merasa menggunakan !dalam situasi ini membingungkan, karena memperlakukan nilai non-boolean seolah-olah itu adalah boolean.

    Juga, ingatlah bahwa perbandingan dan kesetaraan tidak harus sama. Misalnya, jika Anda memesan orang berdasarkan tanggal lahirnya, Compare(me, myTwin)harus kembali 0, tetapi Equals(me, myTwin)harus kembali false.

  3. Keberhasilan atau kegagalan suatu fungsi, mungkin juga dengan detail tentang keberhasilan atau kegagalan itu. Jika Anda berbicara tentang Windows, maka jenis ini disebut HRESULTdan nilai bukan nol tidak selalu menunjukkan kegagalan. Bahkan, nilai negatif menunjukkan kegagalan dan keberhasilan non-negatif. Nilai keberhasilan sangat sering S_OK = 0, tetapi bisa juga misalnya S_FALSE = 1, atau nilai-nilai lainnya.

Kebingungan datang dari fakta bahwa tiga tipe data yang sangat berbeda secara logis sebenarnya direpresentasikan sebagai tipe data tunggal (integer) dalam C dan beberapa bahasa lain dan bahwa Anda dapat menggunakan integer dalam suatu kondisi. Tapi saya pikir tidak masuk akal untuk mendefinisikan ulang boolean untuk menggunakan beberapa jenis non-boolean dalam kondisi yang lebih sederhana.

Juga, pertimbangkan tipe lain yang sering digunakan dalam kondisi di C: sebuah pointer. Di sana, itu wajar untuk memperlakukan NULL-pointer (yang diwakili sebagai 0) sebagai false. Jadi, mengikuti saran Anda juga akan membuat bekerja dengan pointer lebih sulit. (Meskipun, secara pribadi, saya lebih suka membandingkan pointer secara eksplisit NULL, daripada memperlakukannya sebagai boolean.)

svick
sumber
4

Nol bisa salah karena sebagian besar CPU memiliki bendera NOL yang dapat digunakan untuk bercabang. Ini menghemat operasi perbandingan.

Mari kita lihat alasannya.

Beberapa psuedocode, karena audiens mungkin tidak membaca majelis

c- sumber panggilan loop sederhana menggoyang 10 kali

for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */
{  
   wibble();
}

beberapa orang berpura-pura berkumpul untuk itu

0x1000 ld a 0x0a      'foo=10
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 jrnz -0x06      'jump back to 0x1000 if not zero
0x1008  

c- sumber panggilan loop sederhana lain menggeliat 10 kali

for (int foo =0; foo<10; foo-- ) /* up count loop is longer  */
{  
   wibble();
}

beberapa majelis berpura-pura untuk kasus ini

0x1000 ld a 0x00      'foo=0
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 cmp 0x0a       'compare foo to 10 ( like a subtract but we throw the result away)
0x1008 jrns -0x08      'jump back to 0x1000 if compare was negative
0x100a  

beberapa sumber c lagi

int foo=10;
if ( foo ) wibble()

dan majelis

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

lihat seberapa pendek itu?

beberapa sumber c lagi

int foo=10;
if ( foo==0 ) wibble()

dan perakitan (mari kita asumsikan kompiler yang sedikit pintar yang dapat mengganti == 0 tanpa perbandingan)

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

Sekarang mari kita coba konvensi true = 1

beberapa sumber c #define TRUE 1 int foo = TRUE; if (foo == TRUE) wibble ()

dan majelis

0x1000 ld a 0x1
0x1002 cmp a 0x01
0x1004 jz 0x3
0x1006 call 0x1234
0x1009 

lihat seberapa pendek kasus dengan nol benar?

CPU benar-benar awal memiliki set kecil bendera yang melekat pada Akumulator.

Untuk memeriksa apakah a> b atau a = b umumnya membutuhkan instruksi pembanding.

  • Kecuali B adalah ZERO - dalam hal ini flag ZERO diatur Diimplementasikan sebagai NOR logis sederhana atau semua bit dalam Accumulator.
  • Atau NEGATIF ​​di mana hanya menggunakan "tanda bit" yaitu bit yang paling signifikan dari Accumulator jika Anda menggunakan aritmatika komplemen dua. (Kebanyakan kita lakukan)

Mari kita nyatakan kembali ini. Pada beberapa CPU lama, Anda tidak harus menggunakan instruksi pembanding untuk akumulator yang sama dengan ZERO, atau akumulator yang kurang dari nol.

Sekarang apakah Anda tahu mengapa nol mungkin salah?

Harap dicatat ini adalah kode psuedo dan tidak ada set instruksi nyata yang terlihat seperti ini. Jika Anda tahu perakitan, Anda tahu saya menyederhanakan banyak hal di sini. Jika Anda tahu apa-apa tentang desain kompiler, Anda tidak perlu membaca jawaban ini. Siapa pun yang tahu apa-apa tentang loop membuka gulungan atau prediksi cabang, kelas lanjutan ada di ujung lorong di kamar 203.

Tim Williscroft
sumber
2
Maksud Anda tidak dibuat dengan baik di sini karena untuk satu hal if (foo)dan if (foo != 0)harus menghasilkan kode yang sama, dan kedua, Anda menunjukkan bahwa bahasa assembly yang Anda gunakan sebenarnya memiliki operan boolean eksplisit dan tes untuk mereka. Misalnya jzartinya jump if zero. Dengan kata lain if (a == 0) goto target;. Dan kuantitasnya bahkan tidak sedang diuji secara langsung; kondisi dikonversi dengan bendera boolean yang disimpan dalam kata mesin khusus. Sebenarnya lebih seperticpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
Kaz
Tidak Kaz, CPU yang lebih tua tidak berfungsi seperti itu. Jz / jnz dapat dilakukan tanpa melakukan instruksi perbandingan. Yang merupakan inti dari seluruh postingan saya.
Tim Williscroft
2
Saya tidak menulis apa pun tentang instruksi perbandingan.
Kaz
Bisakah Anda mengutip prosesor yang memiliki jzinstruksi tetapi tidak jnz? (atau serangkaian instruksi kondisional asimetris lainnya)
Toby Speight
3

Ada banyak jawaban yang menunjukkan bahwa korespondensi antara 1 dan true diperlukan oleh beberapa properti matematika. Saya tidak dapat menemukan properti seperti itu dan menyarankan itu murni konvensi sejarah.

Diberi bidang dengan dua elemen, kami memiliki dua operasi: penjumlahan dan perkalian. Kami dapat memetakan operasi Boolean di bidang ini dalam dua cara:

Secara tradisional, kami mengidentifikasi Benar dengan 1 dan Salah dengan 0. Kami mengidentifikasi DAN dengan * dan XOR dengan +. Jadi OR adalah penjenuhan.

Namun, kami dapat dengan mudah mengidentifikasi Benar dengan 0 dan Salah dengan 1. Kemudian kami mengidentifikasi OR dengan * dan XNOR dengan +. Jadi AND adalah penjenuhan tambahan.

Neil G
sumber
4
Jika Anda telah mengikuti tautan di wikipedia Anda bisa menemukan bahwa konsep aljabar boolean ditutup terkait dengan bidang Galois dari dua elemen ( en.wikipedia.org/wiki/GF%282%29 ). Simbol 0 dan 1 secara konvensional digunakan untuk menunjukkan identitas aditif dan multiplikatif, masing-masing, karena bilangan real juga merupakan bidang yang identitasnya adalah angka 0 dan 1.
Giorgio
1
@NeilG Saya pikir Giorgio berusaha mengatakan itu lebih dari sekedar konvensi. 0 dan 1 dalam aljabar boolean pada dasarnya sama dengan 0 dan 1 dalam GF (2), yang berperilaku hampir sama dengan 0 dan 1 dalam bilangan real berkaitan dengan penambahan dan perkalian.
svick
1
@svick: Tidak, karena Anda bisa mengubah nama penambahan perkalian dan penjenuhan menjadi OR dan AND lalu balikkan label sehingga 0 benar dan 1 salah. Giorgio mengatakan bahwa itu adalah konvensi logika Boolean, yang diadopsi sebagai konvensi ilmu komputer.
Neil G
1
@Neil G: Tidak, Anda tidak dapat membalik + dan * dan 0 dan 1 karena bidang membutuhkan distribusi multiplikasi daripada penambahan (lihat en.wikipedia.org/wiki/Field_%28mathematics%29 ), tetapi jika Anda menyetel +: = DAN dan *: = XOR, Anda mendapatkan T XOR (T AND F) = T XOR F = T, sedangkan (T XOR T) AND (T XOR F) = F AND T = F. Oleh karena itu dengan membalik operasi dan identitas Anda tidak memiliki bidang lagi. Jadi IMO mendefinisikan 0 dan 1 sebagai identitas bidang yang sesuai tampaknya menangkap salah dan benar cukup setia.
Giorgio
1
@giorgio: Saya telah mengedit jawaban untuk menjelaskan apa yang sedang terjadi.
Neil G
3

Anehnya, nol tidak selalu salah.

Secara khusus, konvensi Unix dan Posix adalah untuk mendefinisikan EXIT_SUCCESSsebagai 0 (dan EXIT_FAILUREsebagai 1). Sebenarnya itu bahkan konvensi standar C !

Jadi untuk kerang Posix dan keluar (2) syscalls, 0 berarti "berhasil" yang secara intuitif lebih benar daripada salah.

Secara khusus, shell ifingin proses kembali EXIT_SUCCESS(yaitu 0) untuk mengikuti cabang "lalu" nya!

Dalam Skema (tetapi tidak dalam Common Lisp atau dalam MELT ) 0 dan nil (yaitu ()dalam Skema) benar, karena satu-satunya nilai palsu adalah#f

Saya setuju, saya nitpicking!

Basile Starynkevitch
sumber
3

C digunakan untuk pemrograman tingkat rendah yang dekat dengan perangkat keras, area di mana Anda kadang-kadang perlu beralih antara operasi bitwise dan logis, pada data yang sama. Diperlukan untuk mengubah ekspresi numerik menjadi boolean hanya untuk melakukan tes akan mengacaukan kode.

Anda dapat menulis hal-hal seperti:

if (modemctrl & MCTRL_CD) {
   /* carrier detect is on */
}

daripada

if ((modemctrl & MCTRL_CD) != 0) {
    /* carrier detect is on */
}

Dalam satu contoh terisolasi itu tidak begitu buruk, tetapi harus melakukan itu akan menjengkelkan.

Demikian juga, operasi converse. Ini berguna untuk hasil operasi boolean, seperti perbandingan, untuk hanya menghasilkan 0 atau 1: Misalkan kita ingin mengatur bit ketiga dari beberapa kata berdasarkan pada apakah modemctrloperator mendeteksi bit:

flags |= ((modemctrl & MCTRL_CD) != 0) << 2;

Di sini kita harus memiliki != 0, untuk mengurangi hasil &ekspresi biwise menjadi 0atau 1, tetapi karena hasilnya hanya bilangan bulat, kita terhindar dari keharusan menambahkan beberapa pemeran yang mengganggu untuk selanjutnya mengubah boolean ke bilangan bulat.

Meskipun C modern sekarang memiliki booltipe, C tetap mempertahankan keabsahan kode seperti ini, baik karena itu adalah hal yang baik, dan karena kerusakan besar dengan kompatibilitas ke belakang yang akan disebabkan sebaliknya.

Exmaple lain di mana C adalah slick: menguji dua kondisi boolean sebagai saklar empat arah:

switch (foo << 1 | bar) {  /* foo and bar booleans are 0 or 1 */
case 0: /* !foo && !bar */
   break;
case 1: /* !foo && bar */
   break;
case 2: /* foo && !bar */
   break;
case 3: /* foo && bar */
   break;
}

Anda tidak bisa mengambil ini dari programmer C tanpa perlawanan!

Terakhir, C terkadang berfungsi sebagai sejenis bahasa rakitan tingkat tinggi. Dalam bahasa assembly, kami juga tidak memiliki tipe boolean. Nilai boolean hanya sedikit atau nol dibandingkan nilai bukan nol di lokasi memori atau register. Bilangan bulat nol, nol boolean, dan alamat nol semuanya diuji dengan cara yang sama dalam set instruksi bahasa assembly (dan mungkin bahkan floating point zero). Kemiripan antara C dan bahasa assembly berguna, misalnya ketika C digunakan sebagai bahasa target untuk mengkompilasi bahasa lain (bahkan yang memiliki boolean yang sangat diketik!)

Kaz
sumber
0

Nilai boolean atau kebenaran hanya memiliki 2 nilai. Benar dan salah.

Ini tidak boleh direpresentasikan sebagai bilangan bulat, tetapi sebagai bit (0 dan 1).

Mengatakan bilangan bulat lain selain 0 atau 1 tidak salah adalah pernyataan yang membingungkan. Tabel kebenaran berhubungan dengan nilai kebenaran, bukan bilangan bulat.

Dari nilai kebenaran prospektif, -1 atau 2 akan memecah semua tabel kebenaran dan logika boolean yang dikaitkan dengannya.

  • 0 DAN -1 ==?!
  • 0 ATAU 2 ==?!

Sebagian besar bahasa biasanya memiliki booleantipe yang ketika dilemparkan ke tipe angka seperti integer mengungkapkan false untuk dilemparkan sebagai nilai integer 0.

Jon Raynor
sumber
1
0 DAN -1 == nilai boolean apa pun yang Anda gunakan. Itulah yang menjadi pertanyaan saya, mengapa harus melemparkannya ke TRUEatau FALSE. Tidak pernah saya katakan - mungkin saya lakukan, tetapi itu tidak dimaksudkan - bilangan bulat itu benar atau salah, saya bertanya tentang mengapa mereka mengevaluasi ke mana saja ketika dilemparkan ke boolean.
Morwenn
-6

Pada akhirnya, Anda berbicara tentang melanggar bahasa inti karena beberapa API jelek. API jelek bukan hal baru, dan Anda tidak bisa memperbaikinya dengan melanggar bahasa. Ini adalah fakta matematika bahwa 0 salah dan 1 benar, dan bahasa apa pun yang tidak menghargai ini rusak secara fundamental. Perbandingan tiga arah adalah niche dan tidak memiliki bisnis yang hasilnya dikonversi secara implisit boolkarena menghasilkan tiga hasil yang mungkin. API C lama hanya memiliki penanganan kesalahan yang mengerikan, dan juga sembelih karena C tidak memiliki fitur bahasa yang diperlukan untuk tidak memiliki antarmuka yang mengerikan.

Perhatikan bahwa saya tidak mengatakan bahwa untuk bahasa yang tidak memiliki konversi boolean integer-> implisit.

DeadMG
sumber
11
"Ini adalah fakta matematika bahwa 0 salah dan 1 benar" Erm.
R. Martinho Fernandes
11
Bisakah Anda mengutip referensi untuk "fakta matematika bahwa 0 salah dan 1 benar"? Jawaban Anda terdengar seperti kata kasar.
Dan Pichelman
14
Ini bukan fakta matematika, tetapi sudah menjadi konvensi matematika sejak abad ke-19.
Charles E. Grant
1
Aljabar Boolean diwakili oleh bidang terbatas di mana 0 dan 1 adalah elemen identitas untuk operasi yang menyerupai penambahan dan perkalian. Operasi-operasi tersebut, masing-masing, OR dan AND. Bahkan, aljabar boolean ditulis seperti aljabar normal di mana penjajaran menunjukkan AND, dan +simbol menunjukkan OR. Jadi misalnya abc + a'b'cartinya (a and b and c) or (a and (not b) and (not c)).
Kaz