Neden 0 yanlış?


115

Bu soru dilsiz gelebilir, ama neden yok 0etmek değerlendirir falseve başka bir [tamsayı] değer trueprogramlama dillerinin en çok?

Dize karşılaştırması

Soru biraz fazla basit göründüğü için, kendimi biraz daha açıklayacağım: Her şeyden önce, herhangi bir programcıya açık gelebilir, ama neden bir programlama dili olmasaydı - aslında olabilir, ama hiçbiri Ben kullandım - ve diğer tüm [integer] değerlerini nerede 0değerlendirir ? Bu sözler rastlantısal görünebilir, ancak iyi bir fikir olabileceği birkaç örneğim var. Her şeyden önce, üç yollu karşılaştırma dizesini ele alalım, C'yi örnek alacağım : ilk dili olarak C'yi deneyen herhangi bir programcı aşağıdaki kodu yazmaya başlayabilir:truefalsestrcmp

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

Yana strcmpdöner 0sonucunu falsebaşlayan programcı yapmaya çalıştığım da buydu dizeleri eşit olduğunda, sefil başarısız olur ve o genellikle neden ilk anlamıyor. Bunun yerine 0değerlendirilmiş olsaydı true, bu işlev, eşitliği karşılaştırırken en basit ifadesinde - yukarıda belirtilen - kullanılmış olabilirdi -1ve 1yalnızca gerekli olduğunda uygun kontroller yapılıyordu. Dönüş türünü boolçoğu zaman (aklımızda demek istediğim) olarak kabul ederdik .

Dahası, signsadece değerleri alan yeni bir tür sunalım -1, 0ve 1. Bu oldukça kullanışlı olabilir. C ++ 'ta bir uzay gemisi operatörü olduğunu hayal edin ve bunun için istediğimizi std::string(iyi, zaten bir comparefonksiyon var, ancak uzay gemisi operatörü daha eğlenceli). Deklarasyon şu anda aşağıdaki olurdu:

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

Olsaydı 0hiç değerlendirilmemiştir true, uzay gemisi operatörü bile var olamazdı ve biz ilan olabilirdi operator==bu şekilde:

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

Bu operator==, bir kerede üç yönlü karşılaştırma yapmalıydı ve yine de, hangi dize gerektiğinde sözlükten daha üstün olduğunu kontrol edebiliyorken aşağıdaki kontrolü yapmak için de kullanılabilirdi:

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

Eski hata işlemesi

Şimdi istisnalarımız var, bu yüzden bu kısım sadece böyle bir şeyin olmadığı eski diller için geçerlidir (örneğin C). C'nin standart kütüphanesine bakarsak (ve POSIX bir tane de), maaaaany işlevlerinin 0başarılı olduğunda ve herhangi bir tamsayıda geri döndüğünden emin olabiliriz . Ne yazık ki bazı insanların böyle şeyler yaptığını gördüm:

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

Programlamada nasıl düşündüğümüzü düşünürsek, genellikle aşağıdaki akıl yürütme düzenine sahibiz:

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

Tekrar düşün, bu, sadece nötr değere koymak için mantıklı olurdu 0, hiç yes(ve bu C'nin fonksiyonları çalışır nasıl) tüm diğer değerler olabilir birçok durumda çözmek için ise, no. Ancak, tek bildiğim programlama dillerinde (belki bazı deneysel esotheric diller hariç), o yesolarak değerlendirilen falsebir in iftüm bunlar olurken, durumun novakalar için değerlendirmek true. “Çalışıyor” un bir vakayı temsil ettiği, “Çalışmıyor” un pek çok olası nedeni temsil ettiği birçok durum vardır. Bu şekilde düşünürsek, 0değerlendirmek trueve gerisini değerlendirmek falseçok daha anlamlı olurdu.

Sonuç

Nerede neden dilleri tasarladın: Benim sonuç aslında benim orijinal soru 0olduğunu falseve diğer değerlerdir truebenim birkaç örnek üzerinde ve belki biraz daha düşünmüyordu hesabında alarak?

Takip: Pek çok fikri olan birçok cevabı ve böyle olması için olası sebepleri görmek güzel. Ne kadar tutkulu olduğunuzu seviyorum. Orijinal olarak bu soruyu sıkıntıdan sordum, ama çok tutkulu göründüğünüz için biraz daha ileri gitmeye karar verdim ve Boolean'ın arkasındaki mantık hakkında 0 ve 1 Math.SE için sormaya karar verdim :)


32
strcmp()doğru veya yanlış için iyi bir örnek değildir, çünkü 3 farklı değer döndürür. Ve bir kabuk kullanmaya başladığınızda, 0'ın doğru ve başka bir şeyin yanlış olduğu anlamına geldiğinde şaşıracaksınız.
ott--

52
@ ott--: Unix kabuklarında 0, başarı anlamına gelir ve sıfır olmayan başarısızlık anlamına gelir - "doğru" ve "yanlış" ile aynı şey değildir.
Keith Thompson

14
@KeithThompson: Bash'de (ve diğer mermilerde) "başarı" ve "başarısızlık" gerçekten "doğru" ve "yanlış" ile aynıdır. Örneğin, deyim, düşünün if true ; then ... ; fi, nereye truesıfır döndüren bir komut ve bu söyler ifçalıştırmak için ....
ruakh

13
Donanımda hiçbir boole yok, sadece ikili sayılar var ve çoğu tarihi ISA’larda sıfır olmayan bir sayı tüm koşullu dallanma talimatlarında "true" olarak kabul edilir (bunun yerine bayrak kullanmıyorlarsa). Bu nedenle, düşük seviyeli diller elbette altta yatan donanım özelliklerini takip etmek zorundadır.
SK-mantık

2
@MasonWheeler Boole türüne sahip olmak hiçbir şey ifade etmez. Örneğin piton yapar bir sahip booltürü ancak karşılaştırmalar / koşullar vb olabilir varsa dönüş değeri.
Bakuriu

Yanıtlar:


98

0olduğu falseortak noktaları hem sıfır unsurları çünkü semirings . Farklı veri türleri olmalarına rağmen, izomorfik cebirsel yapılara ait oldukları için aralarında dönüşüm yapmak sezgiseldir.

  • 0ekleme için kimlik ve çarpma için sıfırdır. Bu tamsayılar ve rationals ama için de geçerlidir değil , IEEE-754 kayan nokta sayıları: 0.0 * NaN = NaNve 0.0 * Infinity = NaN.

  • falseBoolean xor (⊻) ve Boolean ve (∧) için sıfırdır . Boolean'ler {0, 1} olarak temsil edilirse - modulo 2 tamsayıları kümesi — carry taşımasız toplama ve and çarpma olarak düşünebilirsiniz.

  • ""ve []birleştirme için kimlikleri vardır, ancak sıfır olarak anlamlı oldukları birkaç işlem vardır. Tekrarlama birdir, fakat tekrarlama ve birleştirme dağıtılmaz, bu yüzden bu işlemler bir semiring oluşturmaz.

Bu tür örtük dönüşümler küçük programlarda yardımcı olur, ancak büyük programların akla gelmesini zorlaştırabilir. Dil tasarımındaki birçok travmadan sadece biri.


1
Listelerden bahsetmene sevindim. (BTW, nilboş liste hem []ve falsebunun çarpımsal kimlik olarak bir katkı kimlik olarak yanlış ve gerçek dikkate almak doğaldır neden hala açıklamak zorunda;? Farklı veri türlerinden kimlikleri birleştirmek için bir eğilim vardır Common Lisp değeri) ve tam tersi değil. İçin tanım ve sıfır trueolarak kabul etmek mümkün değil mi? ANDOR
Giorgio,

3
Benzer kimliklere atıfta bulunmak için +1. Sonunda, sadece "kongre, onunla ilgilen" konusuna değinmeyen bir cevap.
l0b0

5
İzlendiği ve uzun zaman önce anlaşıldığı somut ve çok eski bir matematiğin ayrıntılarını vermek için +1
Jimmy Hoffa

1
Bu cevap anlamlı değil. trueaynı zamanda, semirlerin kimliği ve sıfırıdır (Boolean ve / veya). Kabul etmek için hiçbir sebep yok, kongre düzenlemesi, false0'dan daha yakın true.
TonioElGringo

1
@TonioElGringo: Doğru ve yanlış arasındaki fark, XOR ve XNOR arasındaki farktır. Biri AND / XOR kullanarak izomorfik halkalar oluşturabilir; buradaki true, çarpma kimliğidir ve ilave olanı yanlıştır, ya da OR ve XNOR'dur, burada false, çarpma kimliğidir ve true, katkı olandır, ancak XNOR, genel olarak kabul edilmez. Temel işlem, XOR’un olduğu gibi.
supercat

74

Çünkü matematik çalışıyor.

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

... insert many other examples here.

Geleneksel olarak, C programları gibi koşullara sahiptir

if (someFunctionReturningANumber())

ziyade

if (someFunctionReturningANumber() != 0)

Çünkü sıfır'a eşdeğer olma kavramı iyi anlaşılmıştır.


21
Dil böyle tasarlanır çünkü matematik anlamlıdır. Bu ilk geldi.
Robert Harvey,

26
@Morwenn, 19. yüzyıla kadar uzanıyor ve George Boole. İnsanlar, bilgisayarlardan daha uzun süredir False'ı 0, True'i! 0 olarak temsil ediyorlar.
Charles E. Grant

11
Tüm tanımları yalnızca AND ile ve + ile VEYA * olarak değiştirirseniz, matematiğin neden diğer şekilde çalışmadığını anlamıyorum.
Neil G

7
Tam olarak: matematik her iki yönde de çalışır ve bu sorunun cevabı tamamen geleneksel görünüyor.
Neil G

6
@Robert Yazınızdaki "matematiksel temelleri" heceleyebilmeniz harika olurdu.
phant0m

38

Diğerlerinin dediği gibi matematik önce geldi. Bu yüzden 0 falseve 1'dir true.

Hangi matematikten bahsediyoruz? Dijital bilgisayarların ortaya çıkmasından çok önce, 1800'lerin ortalarından kalma Boole cebirleri .

Sözleşmenin , boolean cebirlerinden bile daha eski olan önermeci mantıktan çıktığını da söyleyebilirsiniz . Bu, programcıların bildiği ve sevdiği ( false || xeşit x, true && xeşittir xvb.) Mantıksal sonuçların birçoğunun biçimselleştirilmesidir .

Temel olarak iki elementli bir sette aritmetikten bahsediyoruz. İkili sayımı düşünün. Boolean cebirleri bu kavramın kökeni ve teorik temelini oluşturur. C gibi dillerin kuralları sadece basit bir uygulamadır.


2
Elbette yapabilirsin. Ancak "standart" şekilde tutmak, genel aritmetik işlemlere iyi uyum sağlar (0 + 1 = 1, 0 + 1 = 0 değil).
joshin4colours,

2
Evet, ancak tanımları tersine çevirirseniz büyük olasılıkla VE + ve VEYA ile * yazarsınız.
Neil G,

3
Matematik önce gelmedi. Math, 0 ve 1'in, AND'un çarpma ve VEYA toplama gibi olduğu bir alan oluşturduğunu kabul etti.
Kaz,

1
@Kaz: Ancak {0, 1} OR ve AND ile bir alan oluşturmaz.
Giorgio

2
Daha fazla cevap ve yorum söylemesi beni biraz rahatsız ediyor true = 1. Bu tam true != 0olarak doğru değil , çünkü tam olarak aynı değil. Bir neden (tek değil) neden böyle bir karşılaştırma yapmaktan kaçınmalı if(something == true) { ... }?
JensG

26

Bunun elektronikten gelen "miras" ve ayrıca boolean cebiriyle ilgisi olduğunu düşündüm.

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

Dizgelerin eşit olması durumunda strcmp 0 döndürür, çünkü gerçekte yaptığı şey iki dizgenin arasındaki "mesafeyi" hesaplamaktır. Ayrıca 0'ın yanlış olduğu düşünülürse, sadece bir tesadüf olur.

başarı durumunda 0 döndürmek anlamlıdır, çünkü bu durumda 0, hata olmadığı anlamına gelir ve başka herhangi bir sayı bir hata kodu olacaktır. Başarı için başka herhangi bir sayı kullanmak, yalnızca tek bir başarı koduna sahip olduğunuzdan daha az anlamlı olur, ancak birkaç hata koduna sahip olabilirsiniz. "İşe yaradı mı?" if ifadesi ve 0 = evet deyince daha anlamlı olur, ancak ifade daha doğrudur "Bir şeyler ters gitti mi?" ve sonra 0 = hayır'ın çok anlamlı olduğunu görüyorsunuz. Düşünmek, false/trueaslında olduğu gibi, burada gerçekten mantıklı değil no error code/error code.


Haha, açıkça dönüş hatası sorusunu bildiren ilk kişisin. Zaten kendi yolumla yorumladığımı ve diğer yoldan da sorabileceğimi biliyordum, ama açıkça ifade eden ilk kişi (birçok cevap ve yorumdan). Aslında, birinin ya da diğerinin hiçbir anlamı olmadığını söyleyemem, ama her ikisi de farklı şekillerde anlamlı olur :)
Morwenn

1
Aslında derdim 0için success/no errordiğer tamsayılar hata kodları temsil zaman mantıklı tek şeydir. Bu 0da temsil etmek olur false); biz hiç doğru ya da burada yanlış bahsetmiyoruz çünkü gerçekten önemli değil diğer durumlarda
Svish

Ben de aynı fikri vardı bu yüzden upped
user60812

1
strcmp()Mesafeyi hesaplama konusundaki amacınız oldukça iyi. Denir olsaydı strdiff()o zaman if (!strdiff())çok mantıklı olurdu.
Kevin Cox

"elektronik [...] 0 = [...] yanlış, 1 = [...] doğru" - elektronikte bile, bu yalnızca bir kuraldır ve tek değildir. Buna pozitif mantık diyoruz, ancak pozitif voltajın yanlış ve negatifin doğru olduğunu ifade ettiği negatif mantığı da kullanabilirsiniz. Daha sonra, AND için kullanacağınız devre VEYA, VEYA VEYA olur vb. De Morgan yasası gereği her şey eşdeğerdir. Bazen, uygunluk için negatif mantıkta uygulanan bir elektronik devrenin bir kısmını bulacaksınız, bu noktada o kısımdaki sinyallerin adları üstlerinde bir çubukla belirtilmiştir.
Jules

18

Bu makalede açıklandığı gibi , değerler falseve true0 ve 1 tam sayılarıyla karıştırılmamalıdır, ancak iki elementin Galois alanının (sonlu alan) öğeleriyle tanımlanabilir ( buraya bakın ).

Alan, belirli aksiyomları karşılayan iki işlemi olan bir kümedir.

0 ve 1 sembolleri geleneksel olarak bir alanın ek ve çarpımsal kimliklerini belirtmek için kullanılır, çünkü gerçek sayılar aynı zamanda kimlikleri 0 ve 1 olan bir alandır (ancak sonlu olmayan).

Ek kimlik, alanın 0 elemanıdır, öyle ki tüm x için:

x + 0 = 0 + x = x

ve çarpımsal kimlik, tüm x için olduğu gibi, alanın 1 elementidir:

x * 1 = 1 * x = x

İki elementin sonlu alanı sadece bu iki elemente sahiptir, yani ilave kimlik 0 (veya false) ve çarpımsal kimlik 1 (veya true). Bu alanın iki işlemi, mantıksal XOR (+) ve mantıksal AND (*) 'dır.

Not. İşlemleri çevirirseniz (XOR çarpımdır ve AND toplamadır) o zaman çarpma toplama üzerinde dağılmaz ve artık bir alanınız olmaz. Böyle bir durumda iki ve 0 elementlerini (herhangi bir sıra ile) çağırmak için hiçbir nedeniniz yoktur. Ayrıca XOR yerine VEYA işlemini seçemeyeceğinizi de unutmayın: OR / VE'yi toplama / çarpma olarak nasıl yorumladığınızdan bağımsız olarak, sonuçta elde edilen yapı bir alan değildir (alan aksiyomlarının gerektirdiği gibi tüm ters elemanlar mevcut değildir).

C fonksiyonlarıyla ilgili:

  • Birçok işlev, hata kodu olan bir tamsayı döndürür. 0 NO HATASI anlamına gelir.
  • Sezgisel olarak, işlev strcmpiki dize arasındaki farkı hesaplar. 0, iki dizi arasında bir fark olmadığı, yani iki dizenin eşit olduğu anlamına gelir.

Yukarıdaki sezgisel açıklamalar, dönüş değerlerinin yorumlanmasını hatırlamaya yardımcı olabilir, ancak kütüphane dokümantasyonunu kontrol etmek daha da kolaydır.


1
Bunları keyfi bir şekilde değiştirirseniz, matematiğin artık işe yaramadığını göstermek için +1.
Jimmy Hoffa,

2
Döndürülmüş: İki element ve işlem * ve + olan bir alan göz önüne alındığında, True ile 0 ile Yanlış ve 1 ile False değerini belirleriz.
Neil G

1
Bu tanımların her ikisinin de aynı alan üzerinde yapıldığını ve her ikisinin de Boole mantığı kuralları ile tutarlı olduğunu göreceksiniz. Notunuz maalesef yanlıştır :)
Neil G

1
True = 0 ve XOR değerinin + olduğunu varsayarsanız, True, XOR için kimlik olmalıdır. Ancak True XOR True = False olduğu için değildir. XOR işlemini True olarak tanımlamazsanız, True XOR True = True olur. O zaman elbette inşaatınız işe yarıyor, çünkü yeni şeyler yeniden adlandırdınız (herhangi bir matematiksel yapıda her zaman başarılı bir şekilde isim izni yapabilir ve izomorfik bir yapı elde edebilirsiniz). Öte yandan, True, False ve XOR'un normal anlamlarına sahip olmalarına izin verirseniz, True XOR True = False ve True ek kimlik olamaz, yani True 0 olamaz.
Giorgio

1
@Giorgio: Yaptığım yorumları yorumunuza göre son yorumumda düzelttim…
Neil G

13

Alternatif sistemlerin de kabul edilebilir tasarım kararları olabileceğini göz önünde bulundurmalısınız.

Kabuklar: 0 çıkış durumu doğru, sıfır olmayan yanlış

0 çıkış statüsünü true olarak kabul eden mermi örneği zaten belirtilmiştir.

$ ( 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

Buradaki mantık, başarılı olmanın bir yolu var, ancak başarısız olmanın pek çok yolu var, bu nedenle 0'ı "hata yok" anlamına gelen özel değer olarak kullanmak pratiktir.

Yakut: 0, başka herhangi bir sayı gibi

"Normal" programlama dilleri arasında, 0 gibi gerçek bir değer olarak değerlendiren Ruby gibi bazı aykırı değerler vardır.

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

Mantık bu sadece falseve nilyanlış olmalıdır. Birçok Ruby acemi için bir yakalama var. Bununla birlikte, bazı durumlarda, 0'a başka herhangi bir sayıdaki gibi davranılması çok hoş

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"

Bununla birlikte, böyle bir sistem sadece booleans'ı sayıdan ayrı bir tür olarak ayırabilen bir dilde çalışır. Bilgisayarın ilk günlerinde, assembly dili veya ham makine dili ile çalışan programcıların böyle bir lüksü yoktu. Muhtemelen 0'a "boş" durum olarak bakmak ve kodun bir şey olduğunu tespit ettiğinde bayrak olarak 1 olarak ayarlamak için biraz doğaldır. Ek olarak, sözleşme sıfıra yanlış olarak muamele etti ve sıfır olmayan değerlerin doğru olarak muamele edilmesine başlandı. Ancak, bu şekilde olmak zorunda değildir.

Java: Sayılar hiç bir şekilde boole olarak değerlendirilemez

Java'da trueve falsesadece boolean değerlerdir. Sayılar boolean değildir ve booleanlara bile dökülemezler ( Java Language Specification, Sec 4.2.2 ):

İntegral tipler ve tipler arasında boşluk yoktur boolean.

Bu kural sadece soruyu tamamen önler - tüm boolean ifadelerin açıkça kodda yazılması gerekir.


1
Hem Rebol hem de Red, 0 değerli INTEGER! değerleri doğru ve ayrı bir YOK var! LOGIC! 'e ek olarak koşullu yanlış olarak kabul edilen tür (yalnızca bir değer ile YOK) yanlış. 0 değerini yanlış olarak algılayan JavaScript kodu yazmaya çalışırken büyük hayal kırıklığı buldum; dinamik olarak yazılmış bir dil için inanılmaz derecede zor bir karar. Eğer boş ya da 0 olan bir şeyi test etmek istiyorsanız, yazmak zorunda kaldığınızda if (thing === 0), bu hiç de hoş değil.
HostileFork

@HostileFork Bilmiyorum. Ben mantıklı bulmak 0olduğunu truedinamik bir dilde (her tamsayı olarak). Bazen Python'da 0yakalamaya çalışırken bir tane yakaladım Noneve bu bazen tespit etmesi zor olabilir.
Morwenn

2
Ruby bir dışlayıcı değil. Ruby bunu Lisp'ten alır (Ruby bile gizlice "MatzLisp" olarak adlandırılır). Lisp bilgisayar bilimlerinde ana dildir. O metin parçasıdır çünkü Sıfır, ayrıca POSIX kabuğunda sadece gerçek bir değerdir: if [ 0 ] ; then echo this executes ; fi. Yanlış veri değer boş dize ve test edilebilir bir yanlışlık, temsil edilen bir komuta, bir başarısız sonlandırma durumudur olmayan -Zero.
Kaz

8

Genel olayı ele almadan önce, karşı örneklerinizi tartışabiliriz.

Dize karşılaştırmaları

Aynısı aslında birçok kıyaslama için de geçerlidir. Bu tür karşılaştırmalar iki nesne arasındaki mesafeyi hesaplar . Nesneler eşit olduğunda mesafe minimumdur. "Karşılaştırma başarılı" Yani, değer 0'dır Ama gerçekten, dönüş değeri strcmpolan değil bir boolean, bir mesafedir ve bu ne habersiz programcılar yapıyor hapseden if (strcmp(...)) do_when_equal() else do_when_not_equal().

C ++ ' da 0 olduğunda doğru döndürmeyi geçersiz kılan strcmpbir Distancenesneyi döndürmek için yeniden tasarlayabiliriz operator bool()(ancak daha sonra farklı bir sorun kümesi tarafından ısırılırsınız). Veya düz C'de streq, dizeler eşit olduğunda 1, aksi halde 0 döndüren bir işleve sahiptir.

API çağrıları / program çıkış kodu

Burada bir şeylerin yanlış olmasının nedenini önemsiyorsunuz, çünkü bu kararları yanlışlıkla alacaktır. İşler başarılı olduğunda, özel bir şey bilmek istemezsiniz - amacınız gerçekleşmiştir. Bu nedenle iade değeri bu bilgiyi iletmelidir. Öyle değil , bir hata kodu bir boolean. Özel hata değeri 0, "hata yok" anlamına gelir. Aralığın geri kalanı, başa çıkmanız gereken yerel olarak anlamlı hataları temsil eder (1 'i de içerir, bu genellikle "belirtilmemiş hata" anlamına gelir).

Genel dava

Bu bize şu soruyu bırakıyor: Neden boole değerleri Trueve Falsegenelde sırasıyla 1 ve 0 ile temsil ediliyorlar ?

Sübjektif "bu şekilde daha iyi hissettiriyor" argümanının yanı sıra, düşünebilmemin birkaç nedeni (öznel olarak):

  • elektrik devresi analojisi. Akım 1 saniye AÇIK, 0 saniye KAPALI. Başka bir karışım yerine (1, Evet, Doğru, Açık) birlikte (0, Hayır, Yanlış, Kapalı) olmasını seviyorum.

  • hafıza başlatma. Ben memset(0)bir sürü değişken olduğunda (bunlar ints, floats, bools olsunlar) değerlerinin en muhafazakar varsayımlara uymasını istiyorum. Örneğin, toplamım 0, belirti Yanlış, vb.

Belki de bütün bu nedenler eğitimime bağlı. Eğer 0 ile baştan başlamayı öğretmiş olsaydım, başından sonuna kadar giderdim.


2
Aslında 0'ı doğru olarak kabul eden en az bir programlama dili var. Unix kabuğu.
Jan Hudec

Asıl konuyu ele almak için + 1: Morwenn'ın sorusunun çoğu hiç de önemli değil bool.
dan04,

@ dan04 Öyle. Bütün yayının ait döküm seçimi ardındaki mantığı hakkındadır intiçin boolbirçok programlama dillerinde. Karşılaştırma ve hata belirten şeyler, şu anda yaptığı şeyden başka bir şekilde yapmanın bir anlam ifade edebileceği yerlerin örnekleridir.
Morwenn

6

Üst düzey bir bakış açısıyla, üç farklı veri tipinden bahsediyorsunuz:

  1. Bir boole. Boolean cebirindeki matematiksel kongre, 0 için falseve 1 için kullanmaktır true, bu nedenle bu konvansiyonu takip etmek mantıklıdır. Bence bu yol da sezgisel olarak daha mantıklı geliyor.

  2. Karşılaştırma sonucu. Bu üç değer vardır <, =ve >(bunların hiçbiri olduğunu haber true). Onlar için sırasıyla -1, 0 ve 1 değerlerini (veya daha genel olarak negatif, sıfır ve pozitif bir değer) kullanmak anlamlıdır.

    Eşitliği kontrol etmek istiyorsanız ve yalnızca genel karşılaştırma yapan bir işleve sahipseniz, bunun gibi bir şey kullanarak onu açık hale getirmeniz gerektiğini düşünüyorum strcmp(str1, str2) == 0. !Bu durumda kafa karıştırıcı buluyorum çünkü boolean olmayan bir değeri bir boolean gibi ele alıyor.

    Ayrıca, karşılaştırma ve eşitlik aynı şey olmak zorunda değildir. Örneğin, insanlara doğum tarihlerine göre sipariş verirseniz, Compare(me, myTwin)geri dönmelisiniz 0, ancak Equals(me, myTwin)geri dönmelisiniz false.

  3. Bir işlevin başarısı veya başarısızlığı, muhtemelen bu başarı veya başarısızlıkla ilgili ayrıntılar da. Windows hakkında konuşuyorsanız, o zaman bu tür çağrılır HRESULTve sıfır olmayan bir değer mutlaka başarısızlık olduğunu göstermez. Aslında, negatif bir değer başarısızlık ve negatif olmayan başarıyı gösterir. Başarı değeri çok sık S_OK = 0, ancak örneğin S_FALSE = 1veya başka değerler de olabilir.

Bu karışıklık, mantıksal olarak üç farklı veri tipinin aslında C ve diğer bazı dillerde tek bir veri tipi (tamsayı) olarak gösterilmesi ve tamsayıyı bir koşulda kullanabilmenizdir. Ancak, bazı Boole olmayan türlerin daha basit koşullarda kullanılması için booleni yeniden tanımlamanın mantıklı olacağını düşünmüyorum.

Ayrıca, C: imlecindeki bir durumda sıklıkla kullanılan başka bir türü de göz önünde bulundurun. Burada bir NULLişaretçiyi (olarak temsil edilir 0) olduğu gibi ele almak doğaldır false. Bu yüzden önerinizi takip etmek aynı zamanda işaretçilerle çalışmayı da zorlaştırır. (Her ne kadar kişisel olarak, işaretçileri açıkça NULLboolean olarak değerlendirmek yerine karşılaştırmayı tercih ederim .)


4

Sıfır hatalı olabilir çünkü çoğu CPU dalda kullanılabilecek bir SIFIR bayrağına sahiptir. Bir karşılaştırma işlemi kaydeder.

Nedenini görelim.

Bazı psuedocode, izleyiciler muhtemelen derleme okumadığı için

c- kaynak basit döngü 10 kez wibble çağırır

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

bunun için bazı taklit meclis

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- kaynak başka bir basit döngü 10 kez wibble çağırır

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

bu dava için bazı taklit meclisleri

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  

biraz daha c kaynağı

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

ve montaj

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

Bunun ne kadar kısa olduğunu gördün mü?

biraz daha c kaynağı

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

ve derleme (== 0 karşılaştırması olmadan değiştirebilen marjinal olarak akıllı bir derleyiciyi varsayalım)

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

Şimdi doğru bir kuralı deneyelim = 1

biraz daha c kaynağı #define TRUE 1 int foo = TRUE; if (foo == TRUE) wibble ()

ve montaj

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

Sıfır olmayan durumun ne kadar kısa olduğunu görüyor musunuz?

Gerçekten erkenci CPU'ların Akümülatöre takılı küçük bayrakları vardı.

A> b veya a = b olup olmadığını kontrol etmek için genellikle bir karşılaştırma talimatı kullanılır.

  • B ya SIFIR değilse - bu durumda SIFA bayrağı basit bir mantıksal NOR olarak veya Akümülatördeki tüm bitler olarak uygulanır.
  • Veya ikisinin tamamlayıcı aritmetiğini kullanıyorsanız, sadece "sign-bit" i kullanan, yani Akümülatörün en önemli biti olan NEGATİF. (Çoğunlukla yapıyoruz)

Bunu yeniden ifade edelim. Bazı eski CPU'larda, SIFIR'a eşit akümülatör için bir karşılaştırma talimatı kullanmanız veya sıfırdan düşük akümülatör kullanmanız gerekmez.

Sıfırın neden yanlış olabileceğini anladınız mı?

Lütfen bunun psuedo kod olduğunu ve hiçbir gerçek talimat setinin bu şekilde görünmediğini unutmayın. Eğer montajı biliyorsan, burada işleri çok basitleştirdiğimi biliyorsun. Derleyici tasarımı hakkında bir şey biliyorsanız, bu cevabı okumanıza gerek yoktu. Döngü açma veya dallanma tahmini hakkında bir şey bilen herhangi biri, ileri sınıf 203 numaralı odanın koridorundadır.


2
Demek istediğin iyi çünkü bir şey için burada yapılan edilmez if (foo)ve if (foo != 0)aynı kodu oluşturmak gerekir, ve ikinci olarak, size aslında kullandığınız çevirici dili açık boole işlenen ve onlar için testler sahip olduğunu gösteriyoruz. Mesela jzdemek jump if zero. Başka bir deyişle if (a == 0) goto target;. Ve miktar doğrudan test edilmiyor bile; Koşul, özel bir makine kelimesinde depolanan bir boolean bayrağına dönüştürülür. Aslında daha fazlası gibicpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
Kaz

Hayır Kaz, eski CPU böyle çalışmadı. Jz / jnz, bir karşılaştırma talimatı yapılmadan gerçekleştirilebilir. Bu da benim postumun bir nevi noktasıydı.
Tim Williscroft

2
Karşılaştırma talimatı hakkında hiçbir şey yazmadım.
Kaz

jzTalimatı olan ama olmayan bir işlemciyi alıntılayabilir misiniz jnz? (ya da diğer asimetrik koşullu talimatlar kümesi)
Toby Speight

3

Bazı matematiksel özelliklerin 1 ile doğru arasındaki karşılıklı eşleşmenin gerekli olduğunu gösteren birçok cevabı vardır. Böyle bir mülk bulamıyorum ve tamamen tarihi bir kongre olduğunu öne sürüyorum.

İki elementli bir alan göz önüne alındığında, iki işlemimiz var: toplama ve çarpma. Bu alandaki Boole işlemlerini iki yolla eşleştirebiliriz:

Geleneksel olarak, True değerini 1 ve False değerini 0 ile tanımlarız. AND ile * ve XOR ile + işaretini belirleriz. Bu nedenle, OR ilaveyi doyurur.

Ancak, True ile 0 ile False ve 1 ile False değerlerini kolayca tanımlayabiliriz. Sonra OR ile * ve XNOR ile + işaretlerini belirleriz. Bu yüzden AND, ilaveyi doyuruyor.


4
Vikipedi bağlantısını izlemiş olsaydınız, bir boolean cebiri kavramının iki elementli bir Galois alanıyla ilgili olarak kapalı olduğunu keşfedebiliyordunuz ( en.wikipedia.org/wiki/GF%282%29 ). Sırasıyla, 0 ve 1 sembolleri geleneksel olarak sırasıyla ek ve çarpımsal kimlikleri belirtmek için kullanılır, çünkü gerçek sayılar aynı zamanda kimlikleri 0 ve 1 olan bir alandır
Giorgio

1
@NeilG Bence Giorgio bir konvansiyondan öte bir şey demeye çalışıyor. Boolean cebirindeki 0 ve 1, temel olarak GF'de (2) 0 ve 1 ile aynıdır; toplama ve çarpma ile ilgili olarak neredeyse gerçek sayılarla 0 ve 1 ile aynı şekilde davranır.
svick

1
@svick: Hayır, çünkü çarpma ve doygunluk ilavesini OR ve AND olacak şekilde yeniden adlandırabilir ve ardından etiketleri 0, Doğru ve 1 False olacak şekilde çevirebilirsiniz. Giorgio, bunun bilgisayar bilimi kongresi olarak kabul edilen Boole mantığının bir sözleşmesi olduğunu söylüyor.
Neil G,

1
@Neil G: Hayır, + ve * ve 0 ve 1 sayılarını çeviremezsiniz çünkü bir alan toplama işleminde çarpma dağılımını gerektirir (bkz. En.wikipedia.org/wiki/Field_%28mathematics%29 ), ancak +: = AND ve *: = XOR, T XOR (T VE F) = T XOR F = T, oysa (T XOR T) VE (T XOR F) = F VE T = F olur. Bu nedenle işlemleri ve kimlikleri çevirerek Artık bir alan yok. Bu nedenle IMO, 0 ve 1'i uygun bir alanın kimlikleri olarak tanımlayan, yanlış ve doğru bir şekilde, sadakatle yakalamak gibi görünüyor.
Giorgio

1
@giorgio: Neler olduğunu netleştirmek için cevabı değiştirdim.
Neil G

3

Garip bir şekilde, sıfır her zaman yanlış değildir.

Özellikle, Unix ve Posix kuralı, EXIT_SUCCESS0 (ve EXIT_FAILURE1) olarak tanımlamak içindir . Aslında standart bir C sözleşmesi bile var !

Yani Posix kabukları ve çıkış (2) sistem çağrıları için 0, sezgisel olarak yanlış olandan daha doğru olan "başarılı" anlamına gelir.

Özellikle, kabuğun "o zaman" dalını takip etmek için ifbir işlem geri dönüşü EXIT_SUCCESS(bu 0'dır) istiyor !

Scheme'de (fakat Common Lisp'te veya MELT'de değil ) 0 ve nil (yani ()Scheme'de) doğrudur, çünkü tek yanlış değer#f

Katılıyorum, nitpicking ediyorum!


3

C, aynı veriler üzerinde bazen bitsel ve mantıksal işlemler arasında geçiş yapmanız gereken bir alan olan donanıma yakın düşük seviyeli programlama için kullanılır. Sayısal bir ifadeyi yalnızca bir test gerçekleştirmek için boole değerine dönüştürmek gerekliyse kodu bozar.

Gibi şeyler yazabilirsiniz:

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

ziyade

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

Bir izole edilmiş örnekte o kadar da kötü değil, ama bunu yapmak zorunda kalmak sıkıntılı olacak.

Aynı şekilde, işlemleri sohbet. Bir boolean işlemi sonucu, bir karşılaştırma gibi, sadece 0 veya 1 üretmek için kullanışlıdır: Sanırım modemctrl, taşıyıcının algılaması biti olup olmadığına bağlı olarak, bir kelimenin üçüncü bitini ayarlamak istediğimizi varsayalım :

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

Burada != 0, iki yönlü &ifadenin sonucunu azaltmak için 0veya buna sahip olmak zorundayız 1, ancak sonuç sadece bir tamsayı olduğundan , boolayı tam sayıya daha da dönüştürmek için can sıkıcı oyuncular eklemek zorunda kalmayız .

Şimdi modern C'nin bir booltürü olmasına rağmen , yine de böyle bir kodun geçerliliğini koruyor, çünkü her ikisi de iyi bir şey, ve aksi takdirde ortaya çıkacak olan geriye dönük uyumlulukta büyük kırılma nedeniyle.

C'nin kaygan olduğu bir başka örnek: iki boolean koşulu dört yollu anahtar olarak test etmek:

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;
}

Bunu C programlayıcısından dövüşmeden alamazdın!

Son olarak, C bazen bir tür üst düzey meclis dili görevi görür. Assembly dillerinde ayrıca boole türleri de yoktur. Bir boolean değeri, bir bellek konumunda veya kaydında sıfır olmayan değere karşı sadece biraz veya sıfırdır. Bir tamsayı sıfır, boolean sıfır ve sıfır adresinin hepsi assembly dili komut kümelerinde aynı şekilde test edilir (ve hatta belki kayan nokta sıfır). C ile assembly dili arasındaki benzerlik, örneğin C, başka bir dili derlemek için hedef dil olarak kullanıldığında yararlıdır (örneğin, güçlü bir şekilde yazılan booleanlar bile!)


0

Bir boole veya doğruluk değeri yalnızca 2 değer içerir. Doğru ve yanlış.

Bu gereken olmayan tamsayı olarak temsil ancak bit (0 ve 1) olarak hazırlanmıştır.

0 veya 1 dışında başka bir tamsayı söylemek yanlış değildir, kafa karıştırıcı bir ifadedir. Gerçek tabloları tamsayılarla değil gerçek değerlerle ilgilidir.

Potansiyel bir doğruluk değerinden, -1 veya 2, bütün doğruluk tablolarını ve bunlarla ilişkili olan tüm Boole mantıklarını kırar.

  • 0 VE -1 ==?!
  • 0 VEYA 2 ==?!

Çoğu dil, genellikle, booleantamsayı gibi bir sayı türüne basıldığında, 0'ın bir tamsayı değeri olarak atılmanın yanlış olduğunu gösteren bir türe sahiptir.


1
0 AND -1 == Onlara harcadığınız boolean değer ne olursa olsun. Sorum bu işte, neden TRUEya da neden oyuncuya FALSE. Asla demedim - belki yaptım, ama amaçlanmadı - tamsayılar doğru ya da yanlıştı, neden boolean'a atıldıklarında hangisini değerlendirdiklerini sordum.
Morwenn

-6

Sonuçta, bazı API'ler berbat olduğu için çekirdek dili kırmaktan bahsediyorsunuz. Crappy API'ler yeni değildir ve dili kırarak bunları düzeltemezsiniz. 0'ın yanlış, 1'in doğru olduğu ve buna saygı göstermeyen herhangi bir dilin temelde kırıldığı matematiksel bir gerçektir. Üç yönlü karşılaştırma niş ve boolüç olası sonuç döndürdüğü için sonucunu dolaylı olarak dönüştüren bir işi yok . Eski C API'leri basitçe hata işlemeye sahiptir ve C de korkunç arayüzlere sahip olmak için gerekli dil özelliklerine sahip olmadığından da hamstrung.

Örtülü tamsayı-> boolean dönüşümü olmayan diller için söylemiyorum.


11
“0'ın yanlış ve 1'in doğru olduğu matematiksel bir gerçektir” Erm.
R. Martinho Fernandes

11
"0'ın yanlış ve 1'in doğru olduğu matematiksel gerçeği" için bir referansınızı alıntılayabilir misiniz? Cevabınız tehlikeli bir rant gibi geliyor.
Dan Pichelman

14
Bu matematiksel bir gerçek değil, ancak 19. yüzyıldan beri matematiksel bir kongre oldu.
Charles E. Grant

1
Boolean cebiri, 0 ve 1'in toplama ve çarpma işlemlerine benzeyen işlemler için kimlik elemanları olduğu sınırlı bir alanla temsil edilir. Bu işlemler sırasıyla VEYA ve VE'dir. Aslında, boolean cebiri, yan yana konumlamanın VE'yi, +sembolün OR'yi ifade ettiği normal cebir gibi yazılır . Yani mesela abc + a'b'cdemek (a and b and c) or (a and (not b) and (not c)).
Kaz,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.