Deze vraag klinkt misschien stom, maar waarom evalueert 0
tot false
en elke andere [integer] waarde naar true
zijn de meeste programmeertalen?
Stringvergelijking
Aangezien de vraag een een beetje te simpel, ik zal mezelf wat meer uitleggen: allereerst lijkt het voor elke programmeur vanzelfsprekend, maar waarom zou er geen programmeertaal zijn – misschien wel, maar niet een die ik gebruikte – waar 0
evalueert naar true
en alle andere [integer] waarden naar false
? Die ene opmerking lijkt misschien willekeurig, maar ik heb een paar voorbeelden waar het misschien een goed idee was. Laten we eerst het voorbeeld nemen van een driewegvergelijking van strings. Ik neem C “s strcmp
als voorbeeld: elke programmeur die C als zijn eerste taal probeert, kan in de verleiding komen om de volgende code te schrijven:
if (strcmp(str1, str2)) { // Do something... }
Aangezien strcmp
retourneert 0
wat resulteert in false
wanneer de strings gelijk zijn, mislukt wat de beginnende programmeur probeerde te doen jammerlijk en hij begrijpt in eerste instantie niet waarom. Als 0
geëvalueerd was naar true
, dan had deze functie kunnen worden gebruikt in de meest eenvoudige uitdrukking – de bovenstaande – bij het vergelijken voor gelijkheid, en de juiste controles voor -1
en 1
zouden alleen zijn uitgevoerd als dat nodig was. We zouden het retourtype meestal hebben beschouwd als bool
(in onze gedachten bedoel ik) meestal.
Laten we bovendien een nieuw type introduceren, sign
, dat accepteert alleen waarden -1
, 0
en 1
. Dat kan best handig zijn. Stel je voor dat er een ruimteschipoperator in C ++ is en we willen deze voor std::string
(nou ja, er is al de functie compare
, maar ruimteschipoperator is leuker). De declaratie zou momenteel de volgende zijn:
sign operator<=>(const std::string& lhs, const std::string& rhs);
0
geëvalueerd naar true
, de ruimteschipoperator zou “niet eens bestaan, en we hadden operator==
op die manier kunnen verklaren:
sign operator==(const std::string& lhs, const std::string& rhs);
Deze operator==
zou hebben de driewegvergelijking in één keer afgehandeld en kunnen nog steeds worden gebruikt om de volgende controle uit te voeren terwijl u nog steeds kunt controleren welke string lexicografisch superieur is aan de andere wanneer dat nodig is:
if (str1 == str2) { // Do something... }
Afhandeling van oude fouten
We hebben nu uitzonderingen, dus dit deel is alleen van toepassing op de oude talen waar zoiets niet bestaat bestaan (C bijvoorbeeld). Als we kijken naar de standaardbibliotheek van C (en POSIX ook een), kunnen we zeker zien dat maaaaany-functies 0
retourneren als ze succesvol zijn en elk geheel getal anders. Ik heb helaas een aantal mensen gezien doe dit soort dingen:
#define TRUE 0 // ... if (some_function() == TRUE) { // Here, TRUE would mean success... // Do something }
Als we nadenken over hoe we denken in programmeren, hebben we vaak het volgende redeneringspatroon:
Do something Did it work? Yes -> That"s ok, one case to handle No -> Why? Many cases to handle
Als we nadenken over nogmaals, het zou logisch zijn geweest om de enige neutrale waarde, 0
, in yes
te zetten (en dat is hoe C functies werken), terwijl alle andere waarden aanwezig kunnen zijn om de vele gevallen van de no
op te lossen. In alle programmeertalen die ik ken (behalve misschien enkele experimentele esotherische talen), dat yes
evalueert naar false
in een if
voorwaarde, wh ile alle no
gevallen evalueren naar true
. Er zijn veel situaties waarin “het werkt” één geval vertegenwoordigt, terwijl “het werkt niet” veel waarschijnlijke oorzaken vertegenwoordigt. Als we er op die manier over nadenken, laat 0
evalueren naar true
en de rest naar false
zou veel logischer zijn geweest.
Conclusie
Mijn conclusie is in wezen mijn oorspronkelijke vraag: waarom hebben we talen ontworpen waar 0
false
en de andere waarden zijn true
, rekening houdend met mijn paar voorbeelden hierboven en misschien wat meer waar ik niet aan dacht?
Follow-up: Het is leuk om te zien dat er veel antwoorden zijn met veel ideeën en zoveel mogelijke redenen dat het zo is. Ik hou ervan hoe gepassioneerd je erover lijkt te zijn.Ik heb deze vraag oorspronkelijk uit verveling gesteld, maar omdat je zo gepassioneerd lijkt, besloot ik een beetje verder te gaan en te vragen naar de grondgedachte achter de Booleaanse keuze voor 0 en 1 op Math.SE 🙂
Reacties
Antwoord
0
is false
omdat ze allebei zijn nul gemeenschappelijke elementen semirings . Hoewel het verschillende gegevenstypen zijn, is het intuïtief zinvol om tussen deze typen te converteren, omdat ze tot isomorfe algebraïsche structuren behoren.
-
0
is de identiteit voor optellen en nul voor vermenigvuldiging. Dit geldt voor gehele getallen en rationale getallen, maar niet IEEE-754 drijvende-kommagetallen:0.0 * NaN = NaN
en0.0 * Infinity = NaN
. -
false
is de identiteit voor Boolean xor (⊻) en nul voor Boolean en (∧). Als Booleans worden weergegeven als {0, 1} —de verzameling gehele getallen modulo 2 — kunt u ⊻ zien als optellen zonder carry en ∧ als vermenigvuldiging. -
""
en[]
zijn identiteiten voor aaneenschakeling, maar er zijn verschillende bewerkingen waarvoor ze zinvol zijn als nul. Herhaling is er één, maar herhaling en aaneenschakeling verspreiden zich niet, dus deze bewerkingen vormen geen semire.
Dergelijke impliciete conversies zijn nuttig in kleine programmas, maar in de grote kan programmas moeilijker maken om over te redeneren. Slechts een van de vele afwegingen in taalontwerp.
Opmerkingen
- Leuk dat je lijsten hebt genoemd. (Tussen haakjes,
nil
is zowel de lege lijst[]
als defalse
waarde in Common Lisp ; is er een neiging om identiteiten van verschillende gegevenstypen samen te voegen?) Je moet nog steeds uitleggen waarom het natuurlijk is om false te beschouwen als een additieve identiteit en true als een multiplicatieve identiteit en niet andersom. Is niet ‘ mogelijktrue
te beschouwen als de identificatie voorAND
en nul voorOR
? - +1 voor verwijzen naar vergelijkbare identiteiten. Eindelijk een antwoord dat niet ‘ t gewoon neerkomt op ” conventie, behandel het “.
- +1 voor het geven van details van een concrete en zeer oude wiskunde waarin dit is gevolgd en lang zinvol was
- Dit antwoord heeft geen ‘ t logisch.
true
is ook de identiteit en het nulpunt van semirings (Booleaans en / of). Volgens afspraak is er geen reden om aan te nemen datfalse
dichter bij 0 ligt dantrue
. - @TonioElGringo: Het verschil tussen true en false is het verschil tussen XOR en XNOR. Men kan isomorfe ringen vormen met AND / XOR, waarbij true de multiplicatieve identiteit is en false de additieve, of met OR en XNOR, waarbij false de multiplicatieve identiteit is en true de additieve, maar XNOR wordt meestal niet als een gemeenschappelijke fundamentele werking zoals XOR is.
Antwoord
Omdat de wiskunde werkt.
FALSE OR TRUE is TRUE, because 0 | 1 is 1. ... insert many other examples here.
Traditioneel hebben C-programmas voorwaarden zoals
if (someFunctionReturningANumber())
in plaats van
if (someFunctionReturningANumber() != 0)
omdat het concept dat nul gelijk is aan false, goed begrepen wordt.
Opmerkingen
- De talen zijn zo ontworpen omdat de wiskunde logisch is. Dat kwam eerst.
- @Morwenn, het gaat terug tot de 19e eeuw en George Boole. Mensen stellen False al langer voor als 0 en True als! 0 dan dat er computers zijn.
- Ik begrijp niet ‘ waarom de wiskunde niet ‘ werkt niet andersom als je alleen alle definities wijzigt zodat AND is + en OR is *.
- Precies: de wiskunde werkt in twee richtingen en het antwoord op deze vraag lijkt puur conventioneel te zijn.
- @Robert Het ‘ zou geweldig zijn als je de ” wiskundige onderbouwing ” in uw bericht.
Antwoord
Zoals anderen al hebben gezegd, kwam de wiskunde op de eerste plaats. Dit is waarom 0 is false
en 1 is true
.
Over welke wiskunde hebben we het? Booleaanse algebras die dateren uit het midden van de 19e eeuw, lang voordat digitale computers op de markt kwamen.
Je zou ook kunnen zeggen dat de conventie voortkwam uit propositionele logica , die zelfs ouder is dan booleaanse algebras. Dit is de formalisering van veel van de logische resultaten die programmeurs kennen en waarderen (false || x
is gelijk aan x
, true && x
is gelijk aan x
enzovoort).
In feite hebben we het over rekenen op een set met twee elementen. Denk aan tellen in binair getal. Booleaanse algebras zijn de oorsprong van dit concept en de theoretische onderbouwing ervan. De conventies van talen zoals C zijn slechts een eenvoudige toepassing.
Opmerkingen
- Je zou kunnen , zeker. Maar het houden van de ” standaard ” manier past goed bij algemene rekenkunde (0 + 1 = 1, niet 0 + 1 = 0).
- Ja, maar je zou waarschijnlijk AND schrijven met + en OR met * als je de definities ook zou omdraaien.
- De wiskunde deed niet ‘ komt niet op de eerste plaats. Math herkende dat 0 en 1 een veld vormen, waarin AND is als vermenigvuldigen en OR als optellen.
- @ Kaz: Maar {0, 1} met OR en AND vormt geen veld.
- Het stoort me een beetje dat meer antwoorden en commentaren zeggen dat
true = 1
. Dat ‘ is niet helemaal exact, wanttrue != 0
is niet precies hetzelfde. Een reden (niet de enige) waarom men vergelijkingen zou moeten vermijden, zoalsif(something == true) { ... }
.
Antwoord
Ik dacht dat dit te maken had met de “overerving” van elektronica, en ook met booleaanse algebra, waarbij
-
0
=off
,negative
,no
,false
-
1
=on
,positive
,yes
,true
strcmp geeft 0 terug als strings gelijk zijn, heeft te maken met de implementatie ervan, aangezien het feitelijk de “afstand” tussen de twee strings berekent. Dat 0 toevallig ook als onwaar wordt beschouwd, is gewoon toeval.
retourneren 0 bij succes is logisch omdat 0 in dit geval wordt gebruikt om geen fout te betekenen en elk ander nummer een foutcode zou zijn. Het gebruik van een ander nummer voor succes zou minder logisch zijn, aangezien u slechts één succescode heeft, terwijl u meerdere foutcodes kunt hebben. U gebruikt “Werkte het?” omdat de uitdrukking if statement en say 0 = yes logischer zou zijn, maar de uitdrukking is correcter “Is er iets misgegaan?” en dan zie je dat 0 = nee heel logisch is. Denken aan false/true
heeft hier geen zin, aangezien het eigenlijk no error code/error code
is.
Reacties
- Haha, jij bent de eerste die de retourfoutvraag expliciet vermeldt. Ik wist al dat ik het op mijn eigen manier interpreteerde en het zou ook de andere kant op kunnen, maar jij ‘ bent de eerste die het expliciet uitdrukt (uit de vele antwoorden en commentaren).Eigenlijk zou ik niet ‘ zeggen dat de ene of de andere manier nergens op slaat, maar meer dat beide op verschillende manieren logisch zijn 🙂
- Eigenlijk heb ik ‘ d say
0
wantsuccess/no error
is het enige dat logisch is wanneer andere gehele getallen foutcodes vertegenwoordigen . Dat0
toevallig ookfalse
vertegenwoordigt in andere gevallen doet ‘ er niet toe, aangezien we zijn niet ‘ praten hier helemaal niet over waar of niet waar;) - Ik had hetzelfde idee, dus ik heb het verbeterd
- Je punt over
strcmp()
het berekenen van de afstand is redelijk goed. Als hetstrdiff()
was genoemd, dan zouif (!strdiff())
erg logisch zijn. - ” elektronica […] waarbij 0 = […] false, 1 = […] true ” – zelfs in elektronica is dit slechts een conventie , en isn ‘ t de enige. We noemen dit positieve logica, maar je kunt ook negatieve logica gebruiken, waarbij een positieve spanning false aangeeft en negatief true aangeeft. Vervolgens wordt het circuit dat u ‘ gebruikt voor AND OR, OR wordt AND, enzovoort. Door de wet van De Morgan ‘ wordt alles gelijkwaardig. Soms vind je ‘ een deel van een elektronisch circuit voor het gemak geïmplementeerd in negatieve logica, op welk punt de namen van de signalen in dat deel worden genoteerd met een balk erboven.
Antwoord
Zoals uitgelegd in dit artikel moeten de waarden false
en true
niet worden verward met de gehele getallen 0 en 1, maar kunnen worden geïdentificeerd met de elementen van het Galois-veld (eindig veld) van twee elementen (zie hier ).
Een veld is een set met twee bewerkingen die aan bepaalde axiomas voldoen.
De symbolen 0 en 1 worden conventioneel gebruikt om de additieve en vermenigvuldigende identiteiten van een veld aan te duiden, omdat de reële getallen ook een veld zijn (maar niet een eindig) waarvan de identiteiten de getallen 0 en 1 zijn.
De additieve identiteit is het element 0 van het veld, zodat voor alle x:
x + 0 = 0 + x = x
en de multiplicatieve identiteit is het element 1 van het veld, zodat voor alle x:
x * 1 = 1 * x = x
Het eindige veld van twee elementen heeft alleen deze twee elementen, namelijk de additieve identiteit 0 (of false
), en de multiplicatieve identiteit 1 (of true
). De twee bewerkingen van dit veld zijn de logische XOR (+) en de logische AND (*).
Opmerking. Als je de bewerkingen omdraait (XOR is de vermenigvuldiging en AND is de optelling), dan is de vermenigvuldiging niet distributief over de optelling en heb je geen veld meer. In dat geval heb je geen reden om de twee elementen 0 en 1 te noemen (in willekeurige volgorde). Merk ook op dat je niet de bewerking OR kunt kiezen in plaats van XOR: ongeacht hoe je OR / AND interpreteert als optellen / vermenigvuldigen, de resulterende structuur is geen veld (niet alle inverse elementen bestaan zoals vereist door de veldaxiomas).
Met betrekking tot de C-functies:
- Veel functies retourneren een geheel getal dat een foutcode is. 0 betekent GEEN FOUT.
- Intuïtief berekent de functie
strcmp
het verschil tussen twee strings. 0 betekent dat er geen verschil is tussen twee strings, dat wil zeggen dat twee strings gelijk zijn.
De bovenstaande intuïtieve uitleg kan helpen om de interpretatie van de geretourneerde waarden te onthouden, maar het is nog gemakkelijker om kijk maar in de bibliotheekdocumentatie.
Opmerkingen
- +1 om te laten zien dat als je deze willekeurig verwisselt, de wiskunde niet langer lukt.
- Omgedraaid: gegeven een veld met twee elementen en bewerkingen * en +, identificeren we True met 0 en False met 1. We identificeren OR met * en XOR met +.
- Je zult zien dat beide van deze identificaties worden over hetzelfde veld gedaan en beide zijn consistent met de regels van de Booleaanse logica. Uw opmerking is helaas onjuist 🙂
- Als u aanneemt dat True = 0, en XOR is +, dan moet True de identiteit voor XOR zijn. Maar het is niet omdat True XOR True = False. Tenzij u de bewerking XOR op True opnieuw definieert, zodat True XOR True = True. Dan werkt je constructie natuurlijk omdat je zojuist dingen hebt hernoemd (in elke wiskundige structuur kun je altijd met succes een naampermutatie maken en een isomorfe structuur krijgen). Aan de andere kant, als je True, False en XOR hun gebruikelijke betekenis laat hebben, dan kunnen True XOR True = False en True niet de additieve identiteit zijn, d.w.z. True kan niet 0 zijn.
- @Giorgio: ik heb mijn constructie gecorrigeerd volgens uw opmerking in mijn laatste opmerking …
Antwoord
Bedenk dat alternatieve systemen ook acceptabele ontwerpbeslissingen kunnen zijn.
Shells: 0 exit-status is waar, niet-nul is false
Het voorbeeld van shells die een 0 behandelen exit-status als true is al genoemd.
$ ( 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
De grondgedachte is dat er is één manier om te slagen, maar er zijn vele manieren om te falen, dus het gebruik van 0 als de speciale waarde die “geen fouten” betekent, is pragmatisch.
Ruby: 0 is net als elk ander getal
Onder “normale” programmeertalen zijn er enkele uitschieters, zoals Ruby, die 0 als een echte waarde behandelen.
$ irb irb(main):001:0> 0 ? "0 is true" : "0 is false" => "0 is true"
De grondgedachte is dat alleen false
en nil
false moeten zijn. Voor veel Ruby-nieuwelingen is het “een gotcha. In sommige gevallen is het echter prettig dat 0 net als elk ander getal wordt behandeld.
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"
Maar , werkt zon systeem alleen in een taal die booleans als een apart type van getallen kan onderscheiden. In de vroege dagen van het computergebruik hadden programmeurs die met assembleertaal of onbewerkte machinetaal werkten niet zulke luxe. Het is waarschijnlijk heel normaal om 0 te behandelen als de “blanco” toestand, en een bit in te stellen op 1 als een vlag wanneer de code detecteerde dat er iets gebeurde. Bij uitbreiding ontwikkelde de conventie dat nul werd behandeld als onwaar, en niet-nulwaarden werden behandeld als waar. Het hoeft echter niet zo te zijn.
Java: getallen kunnen helemaal niet als booleans worden behandeld
In Java true
en false
zijn de enige booleaanse waarden. Getallen zijn geen booleaanse waarden en kunnen zelfs niet in booleans worden gegoten ( Java-taalspecificatie, Sec 4.2.2 ):
Er zijn geen casts tussen integrale typen en het type
boolean
.
Die regel vermijdt gewoon de vraag helemaal – alle booleaanse uitdrukkingen moeten expliciet in de code worden geschreven.
Opmerkingen
- Rebol en Red behandelen beide 0-gewaardeerde INTEGER! -waarden als waar, en hebben een afzonderlijk NONE! -type (met slechts één waarde, NONE) behandeld als voorwaardelijk false naast LOGIC! false. Ik ‘ heb veel frustratie ondervonden bij het schrijven van JavaScript-code die 0 als false behandelt; het is een incr eetbaar onhandige beslissing voor een dynamisch getypeerde taal. Als je iets wilt testen dat null of 0 kan zijn, moet je
if (thing === 0)
schrijven, dat is gewoon niet cool. - @HostileFork Ik don ‘ weet het niet. Ik vind dat het logisch is dat
0
true
is (zoals elk ander geheel getal) in een dynamische taal. Soms ving ik een0
op wanneer ikNone
probeerde te vangen in Python, en dat kan soms behoorlijk moeilijk te herkennen zijn. - Ruby is geen uitbijter. Ruby neemt dit over van Lisp (Ruby wordt zelfs in het geheim ” MatzLisp ” genoemd). Lisp is een gangbare taal in de informatica. Nul is ook gewoon een echte waarde in de POSIX-shell, omdat het ‘ een stuk tekst is:
if [ 0 ] ; then echo this executes ; fi
. De waarde van de valse gegevens is een lege tekenreeks en een testbare onwaarheid is een mislukte beëindigingsstatus van een opdracht, die wordt weergegeven door een niet -zero.
Antwoord
Voordat we het algemene geval bespreken, kunnen we uw tegenvoorbeelden bespreken.
String-vergelijkingen
Hetzelfde geldt eigenlijk voor veel soorten vergelijkingen. Dergelijke vergelijkingen berekenen een afstand tussen twee objecten. Als de objecten gelijk zijn, is de afstand minimaal. Dus als de “vergelijking slaagt”, is de waarde 0. Maar echt, de geretourneerde waarde van strcmp
is niet een booleaanse waarde, het is een afstand, en dat wat onbewuste programmeurs vasthoudt die if (strcmp(...)) do_when_equal() else do_when_not_equal()
doen.
In C ++ zouden we strcmp
kunnen herontwerpen om een Distance
-object, dat operator bool()
overschrijft om true te retourneren als 0 (maar je zou dan gebeten worden door een andere reeks problemen). Of gebruik in gewone C gewoon een streq
-functie die 1 retourneert als strings gelijk zijn en 0 anders.
API-aanroepen / programma-afsluitcode
Hier geeft u om de reden waarom er iets fout is gegaan, omdat dit de beslissingen bij fouten zal verhogen. Als het lukt, wil je niets speciaals weten – je bedoeling wordt gerealiseerd. De geretourneerde waarde moet daarom deze informatie overbrengen.Het is niet een booleaanse waarde, het is een foutcode. De speciale foutwaarde 0 betekent “geen fout”. De rest van het bereik vertegenwoordigt lokaal betekenisvolle fouten waarmee je te maken hebt (inclusief 1, wat vaak “niet-gespecificeerde fout” betekent).
Algemeen geval
Dit laat ons met de vraag achter: waarom zijn booleaanse waarden True
en False
gewoonlijk weergegeven met respectievelijk 1 en 0?
Nou, naast het subjectieve zo voelt het beter-argument, zijn hier een paar (ook subjectieve) redenen die ik kan bedenken:
-
analogie van het elektrische circuit. De stroom is 1 sec AAN en 0 sec UIT. Ik vind het leuk om (1, Yes, True, On) samen te hebben, en (0, No, False, Off), in plaats van een andere mix
-
geheugeninitialisaties. Als ik
memset(0)
een aantal variabelen (of het nu ints, floats, bools zijn) wil ik dat hun waarde overeenkomt met de meest conservatieve aannames. Bijv. mijn som is aanvankelijk 0, het predikaat is False, enz.
Misschien zijn al deze redenen verbonden met mijn opleiding – als mij was geleerd om 0 te associëren met Waar vanuit de te beginnen, zou ik andersom gaan.
Reacties
- Eigenlijk is er tenminste één programmeertaal die 0 als waar behandelt. De unix-shell.
- +1 voor het aanpakken van het echte probleem: de meeste van Morwenn ‘ s vraag is niet ‘ t ongeveer
bool
. - @ dan04 Dat is het. Het hele bericht gaat over de grondgedachte achter de keuze van de cast van
int
totbool
in veel programmeertalen. De vergelijking en foutbewegingen zijn slechts voorbeelden van plaatsen waar het op een andere manier wordt gecast dan degene die het ‘ s dat momenteel is uitgevoerd, zinvol zou zijn.
Answer
Op hoog niveau heb je het over drie behoorlijk verschillende gegevenstypen:
-
Een booleaanse waarde. De wiskundige conventie in Booleaanse algebra is om 0 te gebruiken voor
false
en 1 voortrue
, dus het is logisch om die conventie te volgen. Ik denk dat deze manier ook intuïtiever logischer is. -
Het resultaat van de vergelijking. Dit heeft drie waarden:
<
,=
en>
(merk op dat geen van hentrue
). Voor hen is het logisch om de waarden -1, 0 en 1 te gebruiken (of, meer in het algemeen, een negatieve waarde, nul en een positieve waarde).Als u wilt controleren op gelijkheid a En als je alleen een functie hebt die een algemene vergelijking uitvoert, denk ik dat je het expliciet moet maken door iets te gebruiken als
strcmp(str1, str2) == 0
. Ik vind het gebruik van!
in deze situatie verwarrend, omdat het een niet-booleaanse waarde behandelt alsof het een booleaanse waarde is.Houd ook rekening met die vergelijking en gelijkheid hoeft niet hetzelfde te zijn. Als u mensen bijvoorbeeld rangschikt op geboortedatum, moet
Compare(me, myTwin)
retourneren0
, maarEquals(me, myTwin)
zoufalse
moeten teruggeven. -
Het succes of falen van een functie , mogelijk ook met details over dat succes of falen. Als je het over Windows hebt, dan heet dit type
HRESULT
en een niet-nulwaarde betekent niet noodzakelijkerwijs een mislukking. In feite duidt een negatieve waarde op een mislukking en een niet-negatief succes. De succeswaarde is vaakS_OK = 0
, maar het kan ook bijvoorbeeldS_FALSE = 1
zijn, of andere waarden.
De verwarring komt voort uit het feit die drie logischerwijs heel verschillende gegevenstypen worden feitelijk weergegeven als een enkel gegevenstype (een geheel getal) in C en sommige andere talen en dat u integer kunt gebruiken in een voorwaarde. Maar ik denk niet dat het zinvol is om boolean opnieuw te definiëren om het gebruik van sommige niet-booleaanse typen in voorwaarden eenvoudiger te maken.
Overweeg ook een ander type dat vaak wordt gebruikt in een voorwaarde in C: een pointer . Daar is het normaal om een NULL
-pointer (die wordt weergegeven als 0
) te behandelen als false
. Het opvolgen van je suggestie zou het werken met pointers dus ook moeilijker maken. (Hoewel ik persoonlijk liever pointers vergelijk met NULL
, in plaats van ze als booleans te behandelen.)
Antwoord
Nul kan onwaar zijn omdat de meeste CPUs een ZERO-vlag hebben die kan worden gebruikt om te vertakken. Het bespaart een vergelijkingsoperatie.
Laten we eens kijken waarom.
Sommige psuedocode, aangezien het publiek waarschijnlijk geen assembly leest
c-source simple loop roept 10 keer wibble aan
for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */ { wibble(); }
een of andere nep-assembly daarvoor
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-source nog een simpele loop roept wibble 10 keer aan
for (int foo =0; foo<10; foo-- ) /* up count loop is longer */ { wibble(); }
een of andere alsof assembly voor dit geval
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
nog wat c bron
int foo=10; if ( foo ) wibble()
en de assembly
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
zie hoe kort dat is?
nog wat c source
int foo=10; if ( foo==0 ) wibble()
en de assembly (laten we aannemen dat een marginaal slimme compiler == 0 kan vervangen zonder )
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
Laten we nu de conventie true = 1 proberen
wat meer c source #define TRUE 1 int foo = TRUE; if (foo == WAAR) wibble ()
en de assembly
0x1000 ld a 0x1 0x1002 cmp a 0x01 0x1004 jz 0x3 0x1006 call 0x1234 0x1009
zie hoe kort de case met niet-nul true is?
Echt waar vroege CPUs hadden kleine sets vlaggen die aan de accumulator waren gekoppeld.
Om te controleren of a> b of a = b over het algemeen een vergelijkingsinstructie accepteert.
- Tenzij B is ofwel NUL – in welk geval de vlag ZERO is ingesteld Geïmplementeerd als een eenvoudige logische NOR of alle bits in de Accumulator.
- Of NEGATIEF waarin alleen het “tekenbit” wordt gebruikt, dwz het meest significante bit van de Accumulator als u rekenkunde met twee complementen gebruikt. (Meestal doen we dat)
Laten we dit herhalen. Op sommige oudere CPUs hoefde je geen vergelijkingsinstructie te gebruiken voor accumulator gelijk aan NUL, of accumulator kleiner dan nul.
Zie je nu waarom nul onwaar zou kunnen zijn?
Let op: dit is psuedo-code en geen echte instructieset ziet er zo uit. Als je assembly kent, weet je dat ik de dingen hier veel vereenvoudig. Als je iets weet over het ontwerp van een compiler, hoef je dit antwoord niet te lezen. Iedereen die iets weet over het uitrollen van een lus of het voorspellen van vertakkingen, de gevorderde klas is verderop in kamer 203.
Opmerkingen
- Uw punt is hier niet goed gemaakt, omdat bijvoorbeeld
if (foo)
enif (foo != 0)
zou dezelfde code moeten genereren, en ten tweede laat je ‘ zien dat de assembleertaal die je ‘ gebruikt in feite expliciet booleaanse operanden en tests ervoor.jz
betekent bijvoorbeeldjump if zero
. Met andere woordenif (a == 0) goto target;
. En de hoeveelheid wordt niet eens rechtstreeks getest; de voorwaarde is geconverteerd naar een booleaanse vlag die wordt opgeslagen in een speciaal machinewoord. Het ‘ lijkt eigenlijk meer opcpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
- Geen Kaz, de oudere CPU ‘ s werkte niet zo. T hij jz / jnz kan worden uitgevoerd zonder een vergelijkingsinstructie uit te voeren. Dat was eigenlijk het punt van mijn hele bericht.
- Ik heb ‘ niets geschreven over een vergelijkingsinstructie.
- Kun je een processor noemen die een
jz
instructie heeft maar geenjnz
? (of een andere asymmetrische set van voorwaardelijke instructies)
Antwoord
Er zijn veel antwoorden die suggereren dat overeenstemming tussen 1 en true is vereist door een of andere wiskundige eigenschap. Ik kan zon eigenschap niet vinden en suggereer dat het een puur historische afspraak is.
Gegeven een veld met twee elementen, hebben we twee bewerkingen: optellen en vermenigvuldigen. We kunnen Booleaanse bewerkingen op dit veld op twee manieren in kaart brengen :
Traditioneel identificeren we True met 1 en False met 0. We identificeren AND met * en XOR met +. OR is dus verzadigende optelling.
We zouden echter net zo goed kunnen identificeren True met 0 en False met 1. Vervolgens identificeren we OR met * en XNOR met +. AND is dus verzadigende optelling.
Opmerkingen
- Als als je de link op wikipedia had gevolgd, had je kunnen ontdekken dat het concept van een booleaanse algebra gesloten is gerelateerd aan dat van een Galois-veld met twee elementen ( en.wikipedia.org/wiki / GF% 282% 29 ). De symbolen 0 en 1 worden conventioneel gebruikt om respectievelijk de additieve en multiplicatieve identiteiten aan te duiden, omdat de reële getallen ook een veld zijn waarvan de identiteiten de getallen 0 en 1 zijn.
- @NeilG Ik denk dat Giorgio het probeert te zeggen dat ‘ meer is dan alleen een conventie. 0 en 1 in booleaanse algebra zijn in principe hetzelfde als 0 en 1 in GF (2), die zich bijna hetzelfde gedragen als 0 en 1 in reële getallen met betrekking tot optellen en vermenigvuldigen.
- @svick: Nee , omdat u eenvoudigweg de naam van vermenigvuldiging en verzadiging kunt wijzigen in OR en EN en vervolgens de labels omdraaien zodat 0 waar is en 1 onwaar.Giorgio zegt dat het een conventie was van Booleaanse logica, die werd aangenomen als een conventie van de informatica.
- @Neil G: Nee, je kunt + en * en 0 en 1 niet omdraaien omdat een veld distributiviteit vereist van vermenigvuldiging boven optellen (zie en.wikipedia.org/wiki/Field_%28mathematics%29 ), maar als je +: = AND en *: = XOR instelt , je krijgt T XOR (T AND F) = T XOR F = T, terwijl (T XOR T) AND (T XOR F) = F AND T = F.Daarom heb je door de bewerkingen en de identiteiten om te draaien geen veld meer. Dus IMO die 0 en 1 definieert als de identiteiten van een geschikt veld, lijkt vals en waar vrij getrouw vast te leggen.
- @giorgio: ik heb het antwoord bewerkt om duidelijk te maken wat er aan de hand is.
Antwoord
Vreemd genoeg is nul niet altijd onwaar.
In het bijzonder de Unix- en Posix-conventie is om EXIT_SUCCESS
te definiëren als 0 (en EXIT_FAILURE
als 1). Eigenlijk is het zelfs een standaard C-conventie !
Dus voor Posix-shells en exit (2) syscalls, 0 betekent “succesvol”, wat intuïtief meer waar dan onwaar is.
In het bijzonder wil de shell “s if
een proces retourneert EXIT_SUCCESS
(dat is 0) om zijn “then” -tak te volgen!
In schema (maar niet in Common Lisp of in MELT ) 0 en nul (dwz ()
in Scheme) zijn waar, aangezien de enige valse waarde #f
Ik ga akkoord, ik ben aan het muggenzifterij!
Antwoord
C wordt gebruikt voor programmering op laag niveau in de buurt van hardware, een gebied waarin u soms moet schakelen tussen bitsgewijze en logische bewerkingen, op dezelfde gegevens. Als u een numerieke uitdrukking moet converteren naar booleaans om een test uit te voeren, zou dit rommelig worden de code.
U kunt dingen schrijven als:
if (modemctrl & MCTRL_CD) { /* carrier detect is on */ }
in plaats van
if ((modemctrl & MCTRL_CD) != 0) { /* carrier detect is on */ }
In een op zichzelf staand voorbeeld is het niet zo erg, maar het zal vervelend worden om dat te moeten doen.
Evenzo, omgekeerde bewerkingen. Het is handig voor het resultaat van een booleaanse bewerking, zoals een vergelijking, om gewoon een 0 of 1 te produceren: stel dat we het derde bit van een woord willen instellen op basis van of modemctrl
heeft de carrier-detectiebit:
flags |= ((modemctrl & MCTRL_CD) != 0) << 2;
Hier moeten we de != 0
, om het resultaat van de biwise &
-expressie te verkleinen tot 0
of 1
, maar omdat het resultaat slechts een geheel getal is, hoeven we geen vervelende cast toe te voegen om de boolean verder om te zetten in een geheel getal.
Ook al heeft de moderne C nu een bool
type, het behoudt nog steeds de geldigheid van code zoals deze, zowel omdat het “een goede zaak is, als vanwege de enorme breuk met achterwaartse compatibiliteit die anders zou worden veroorzaakt.
Nog een voorbeeld waarin C gelikt is: twee booleaanse voorwaarden testen als een vierwegschakelaar:
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; }
Je zou dit niet zonder slag of stoot van de C-programmeur kunnen afnemen!
Ten slotte dient C soms als een soort assembleertaal op hoog niveau. In assembleertalen hebben we ook geen booleaanse typen. Een booleaanse waarde is gewoon een bit of een nul versus een niet-nulwaarde in een geheugenlocatie of register. Een geheel getal nul, booleaanse nul en het adres nul worden allemaal op dezelfde manier getest in assembleertaalinstructiesets (en misschien zelfs drijvende komma nul). De overeenkomst tussen C en assembleertaal is handig, bijvoorbeeld wanneer C wordt gebruikt als de doeltaal voor het compileren van een andere taal (zelfs een taal die sterk getypte booleans heeft!)
Antwoord
Een booleaanse waarde of waarheidswaarde heeft slechts 2 waarden. Waar en niet waar.
Deze moeten niet worden weergegeven als gehele getallen, maar als bits (0 en 1 ).
Het zeggen van een ander geheel getal naast 0 of 1 is niet onwaar, is een verwarrende bewering. Waarheidstabellen gaan over waarheidswaarden, niet over gehele getallen.
Vanuit een prospectieve waarheidswaarde zouden -1 of 2 alle waarheidstabellen breken en elke booleaanse logica die daarmee verband houdt.
- 0 EN -1 ==?!
- 0 OF 2 ==?!
De meeste talen hebben meestal een boolean
type dat bij cast naar een getalsoort zoals integer onthult dat false wordt gecast als een integerwaarde van 0.
Reacties
- 0 EN -1 == welke booleaanse waarde je ze ook cast. Dat ‘ is waar mijn vraag over gaat, waarom ze naar
TRUE
ofFALSE
casten.Nooit heb ik gezegd – misschien wel, maar het was niet de bedoeling – gehele getallen waren waar of onwaar, ik vroeg waarom ze evalueren naar welke dan ook wanneer ze naar boolean worden gecast.
Antwoord
Uiteindelijk heb je het over het breken van de kerntaal omdat sommige APIs waardeloos zijn. Slechte APIs zijn niet nieuw, en je kunt ze niet repareren door de taal te breken. Het is een wiskundig feit dat 0 onwaar is en 1 waar, en elke taal die dit niet respecteert, is fundamenteel verbroken. De drievoudige vergelijking is niche en heeft geen zaken om het resultaat impliciet te converteren naar bool
aangezien het drie mogelijke resultaten oplevert. De oude C APIs hebben gewoon een vreselijke foutafhandeling, en zijn ook verlamd omdat C niet de nodige taalkenmerken heeft om geen vreselijke interfaces te hebben.
Merk op dat ik dit niet zeg voor talen die geen impliciete integer-> booleaanse conversie.
Reacties
- ” Het is een wiskundig feit dat 0 onwaar is en 1 is waar ” Erm.
- Kunt u een referentie noemen voor uw ” wiskundig feit dat 0 niet waar is en 1 is waar “? Je antwoord klinkt gevaarlijk als een tirade.
- Het ‘ is geen wiskundig feit, maar het is ‘ een wiskundige conventie sinds de 19e eeuw.
- Booleaanse algebra wordt weergegeven door een eindig veld waarin 0 en 1 de identiteitselementen zijn voor bewerkingen die lijken op optellen en vermenigvuldigen. Die bewerkingen zijn respectievelijk OR en AND. Booleaanse algebra wordt in feite net als normale algebra geschreven, waarbij juxtapositie AND aangeeft en het symbool
+
OR aangeeft. Dus bijvoorbeeldabc + a'b'c
betekent(a and b and c) or (a and (not b) and (not c))
.
strcmp()
is geen goed voorbeeld voor waar of false, aangezien het 3 verschillende waarden retourneert. En je zult verrast zijn als je een shell gaat gebruiken, waarbij 0 waar betekent en al het andere onwaar betekent.if true ; then ... ; fi
, waarbijtrue
een commando is dat nul retourneert en dit verteltif
om...
uit te voeren.bool
-type, maar vergelijkingen / if-voorwaarden etc. kunnen elke retourwaarde hebben.