Den här frågan kanske låter dum, men varför utvärderas 0
till false
och vilket annat [heltal] -värde som helst till true
är de flesta programmeringsspråk?
Strängjämförelse
Eftersom frågan verkar vara lite för enkelt, jag kommer att förklara mig lite mer: först och främst kan det verka uppenbart för alla programmerare, men varför skulle det inte finnas ett programmeringsspråk – det kan faktiskt finnas, men inte något jag använde – där 0
utvärderas till true
och alla andra [heltal] värden till false
? kan verka slumpmässigt, men jag har några exempel där det kan ha varit en bra idé. Först och främst, låt oss ta exemplet på strängar trevägs jämförelse, jag tar C ”s strcmp
som exempel: alla programmerare som försöker C som sitt första språk kan vara frestade att skriva följande kod:
if (strcmp(str1, str2)) { // Do something... }
Eftersom strcmp
returnerar 0
som utvärderas till false
när strängarna är lika, misslyckas vad den första programmeraren försökte göra och han förstår generellt inte varför först. Hade 0
istället utvärderats till true
, kunde den här funktionen ha använts i sitt enklaste uttryck – den ovan – när man jämför för jämlikhet, och de korrekta kontrollerna av -1
och 1
skulle ha gjorts bara när det behövs. Vi skulle ha betraktat returtypen som bool
(i våra tankar menar jag) för det mesta.
Dessutom ska vi introducera en ny typ, sign
, som bara tar värden -1
, 0
och 1
. Det kan vara ganska praktiskt. Tänk dig att det finns en rymdskeppsoperatör i C ++ och vi vill ha den för std::string
(ja, det finns redan compare
-funktionen, men rymdskeppsoperatören är roligare). Deklarationen skulle för närvarande vara följande:
sign operator<=>(const std::string& lhs, const std::string& rhs);
Hade 0
utvärderats till true
, rymdskeppsoperatören skulle inte ens existera, och vi kunde ha förklarat operator==
på det sättet:
sign operator==(const std::string& lhs, const std::string& rhs);
Detta operator==
skulle har hanterat trevägsjämförelse på en gång och kan fortfarande användas för att utföra följande kontroll medan du fortfarande kan kontrollera vilken sträng som är lexikografiskt överlägsen den andra vid behov:
if (str1 == str2) { // Do something... }
Gammal felhantering
Vi har nu undantag, så denna del gäller bara de gamla språken där inget sådant finns existerar (C till exempel). Om vi tittar på C: s standardbibliotek (och POSIX en också) kan vi med säkerhet se att maaaaany-funktioner returnerar 0
när de lyckas och annat heltal annars. Jag har tyvärr sett några människor gör den här typen av saker:
#define TRUE 0 // ... if (some_function() == TRUE) { // Here, TRUE would mean success... // Do something }
Om vi tänker på hur vi tänker i programmering har vi ofta följande resonemangsmönster:
Do something Did it work? Yes -> That"s ok, one case to handle No -> Why? Many cases to handle
Om vi tänker på det igen, det skulle ha varit vettigt att sätta det enda neutrala värdet, 0
, till yes
(och så är det hur C ”s funktioner fungerar), medan alla andra värden kan finnas där för att lösa de många fall av no
. Men i alla programmeringsspråk jag känner (utom kanske några experimentella esoteriska språk), som yes
utvärderas till false
i ett if
-villkor, wh ile alla no
fall utvärderas till true
. Det finns många situationer när ”det fungerar” representerar ett fall medan ”det fungerar inte” representerar många möjliga orsaker. Om vi tänker på det på det sättet att ha 0
utvärdera till true
och resten till false
skulle ha gjort mycket mer vettigt.
Slutsats
Min slutsats är i huvudsak min ursprungliga fråga: varför designade vi språk där 0
är false
och de andra värdena är true
, med hänsyn till mina få exempel ovan och kanske några fler som jag inte tänkte på?
Uppföljning: Det är trevligt att se att det finns många svar med många idéer och så många möjliga skäl för att det ska vara så. Jag älskar hur passionerad du verkar vara om det.Jag ställde den här frågan ursprungligen av tristess, men eftersom du verkar så passionerad bestämde jag mig för att gå lite längre och fråga om bakom det booleska valet för 0 och 1 på Math.SE 🙂
Kommentarer
Svar
0
är false
eftersom de båda är noll element gemensamt semirings . Även om de är distinkta datatyper är det meningsfullt att konvertera mellan dem eftersom de tillhör isomorfa algebraiska strukturer.
-
0
är identiteten för addition och noll för multiplikation. Detta gäller för heltal och rationella, men inte IEEE-754 flytpunktsnummer:0.0 * NaN = NaN
och0.0 * Infinity = NaN
. -
false
är identiteten för Boolean xor (⊻) och noll för Boolean och (∧). Om booléer representeras som {0, 1} – uppsättningen heltal modulo 2 – kan du tänka på ⊻ som tillägg utan bärande och ∧ som multiplikation. -
""
och[]
är identitet för sammankoppling, men det finns flera operationer för vilka de är meningsfulla som noll. Upprepning är en, men upprepning och sammankoppling distribuerar inte, så dessa operationer bildar inte en semiring.
Sådana implicita konverteringar är till hjälp i små program, men i stora kan göra program svårare att resonera om. Bara en av de många avvägningarna inom språkdesign.
Kommentarer
- Trevligt att du nämnde listor. (BTW,
nil
är både den tomma listan[]
ochfalse
i Common Lisp ; finns det en tendens att slå samman identiteter från olika datatyper?) Du måste fortfarande förklara varför det är naturligt att betrakta falskt som en additiv identitet och sant som en multiplikativ identitet och inte tvärtom. Är inte ’ t möjligt att betraktatrue
som identifieringen förAND
och noll förOR
? - +1 för att hänvisa till liknande identiteter. Slutligen ett svar som inte ’ t bara kokar ner till ” konvention, hantera det ”.
- +1 för att ge detaljer om en konkret och mycket gammal matematik där detta har följts och länge varit vettigt
- Detta svar inte ’ t meningsfullt.
true
är också identiteten och nollan av semirings (booleska och / eller). Det finns ingen anledning, enligt konventionen, att överväga attfalse
är närmare 0 äntrue
. - @TonioElGringo: Skillnaden mellan sant och falskt är skillnaden mellan XOR och XNOR. Man kan bilda isomorfiska ringar med AND / XOR, där true är multiplikativ identitet och falsk additiv, eller med OR och XNOR, där false är multiplikativ identitet och true är additiv, men XNOR betraktas vanligtvis inte som en vanlig grundläggande funktion som XOR är.
Svar
Eftersom matematiken fungerar.
FALSE OR TRUE is TRUE, because 0 | 1 is 1. ... insert many other examples here.
Traditionellt har C-program villkor som
if (someFunctionReturningANumber())
snarare än
if (someFunctionReturningANumber() != 0)
eftersom begreppet noll motsvarar falskt är välförstått.
Kommentarer
- Språken är utformade så för att matematiken är vettig. Det kom först.
- @Morwenn, det går tillbaka till 1800-talet och George Boole. Människor har representerat False som 0 och True as! 0 längre än det har funnits datorer.
- Jag förstår inte ’ varför matematiken inte ’ t fungerar åt andra hållet om du bara ändrar alla definitioner så att AND är + och OR är *.
- Exakt: matematiken fungerar åt båda hållen och svaret på den här frågan verkar vara att den är rent konventionell.
- @Robert Det ’ d skulle vara jättebra om du kunde stava ut ” matematiska underlag ” i ditt inlägg.
Svar
Som andra har sagt kom matematiken först. Det är därför 0 är false
och 1 är true
.
Vilken matematik pratar vi om? Booleska algebra som dateras från mitten av 1800-talet, långt innan digitala datorer kom.
Man kan också säga att konventionen kom ur propositionslogik , som ännu äldre än booleska algebraer. Detta är formaliseringen av många av de logiska resultat som programmerare känner och älskar (false || x
är lika med x
, true && x
är lika med x
och så vidare).
I grund och botten talar vi om aritmetik på en uppsättning med två element. Tänk på att räkna i binär. Booleska algebraer är ursprunget till detta koncept och dess teoretiska grund. Konventionerna för språk som C är bara en enkel applikation.
Kommentarer
- Du kan säkert. Men att hålla det ” standard ” passar bra med allmän aritmetik (0 + 1 = 1, inte 0 + 1 = 0).
- Ja, men du skulle förmodligen skriva OCH med + och ELLER med * om du också vänder om definitionerna.
- Matematiken gjorde inte ’ kommer inte först. Matematik kände igen att 0 och 1 bildar ett fält där AND är som multiplikation och OR är som addition.
- @ Kaz: Men {0, 1} med OR och AND bildar inte ett fält.
- Det stör mig lite att fler svar och kommentarer säger att
true = 1
. Att ’ inte är helt exakt, eftersomtrue != 0
vilket inte är exakt detsamma. En anledning (inte den enda) varför man bör undvika jämförelser somif(something == true) { ... }
.
Svar
Jag trodde att detta hade att göra med ”arvet” från elektronik, och även boolesk algebra, där
-
0
=off
,negative
,no
,false
-
1
=on
,positive
,yes
,true
strcmp returnerar 0 när strängarna är lika har att göra med dess implementering, eftersom det faktiskt gör är att beräkna ”avståndet” mellan de två strängarna. Att 0 också råkar betraktas som falskt är bara en slump.
Att returnera 0 på framgång är vettigt eftersom 0 i detta fall används för att betyda inget fel och något annat nummer skulle vara en felkod. Att använda vilket annat nummer som helst för att lyckas skulle vara mindre meningsfullt eftersom du bara har en enda framgångskod, medan du kan ha flera felkoder. Du använder ”Fungerade det?” som om uttrycksuttryck och säg 0 = ja skulle vara meningsfullare, men uttrycket är mer korrekt ”Gick något fel?” och då ser du att 0 = nej är mycket meningsfullt. Att tänka på false/true
är inte riktigt vettigt här, eftersom det faktiskt är no error code/error code
.
Kommentarer
- Haha, du är den första som uttryckligen anger frågan om returfel. Jag visste redan att jag tolkade det på mitt eget sätt och och det kunde jag fråga på andra hållet, men du ’ är den första som uttryckligen uttrycker det (av de många svar och kommentarer).Egentligen skulle jag ’ inte säga att det ena eller det andra sättet inte är meningsfullt, men mer att båda är vettiga på olika sätt 🙂
- Egentligen ’ d säger
0
försuccess/no error
är det enda som är vettigt när andra heltal representerar felkoder . Att0
råkar representerafalse
i andra fall spelar ingen roll ’, eftersom vi talar ’ alls inte om sant eller falskt;) - Jag hade samma idé så jag uppade
- Din poäng om
strcmp()
att beräkna avståndet är ganska bra. Om det hade kallatsstrdiff()
så skulleif (!strdiff())
vara mycket logiskt. - ” elektronik […] där 0 = […] falskt, 1 = […] sant ” – även i elektronik är detta bara en konvention , och är inte ’ t den enda. Vi kallar detta positiv logik, men du kan också använda negativ logik, där en positiv spänning indikerar falsk och negativ indikerar sant. Sedan blir kretsen som du ’ använder för AND till OR, ELLER blir AND, och så vidare. På grund av De Morgan ’ s lag, blir det hela lika mycket. Ibland hittar du ’ en del av en elektronisk krets implementerad i negativ logik för enkelhets skull, vid vilken tidpunkt namnen på signalerna i den delen noteras med en stapel ovanför dem.
Svar
Som förklaras i den här artikeln , bör värdena false
och true
inte förväxlas med heltal 0 och 1 utan kan identifieras med elementen i Galois-fältet (ändligt fält) av två element (se här ).
Ett fält är en uppsättning med två operationer som uppfyller vissa axiom.
Symbolerna 0 och 1 används konventionellt för att beteckna ett fälts additiva och multiplikativa identiteter eftersom de reella siffrorna också är ett fält (men inte ett ändligt) vars identitet är siffrorna 0 och 1.
Additividentiteten är elementet 0 i fältet, så att för alla x:
x + 0 = 0 + x = x
och den multiplikativa identiteten är elementet 1 i fältet, så att för alla x:
x * 1 = 1 * x = x
Det ändliga fältet med två element har bara dessa två element, nämligen additividentitet 0 (eller false
) och multiplikationsidentiteten 1 (eller true
). De två operationerna i detta fält är den logiska XOR (+) och den logiska AND (*).
Obs. Om du vänder på operationerna (XOR är multiplikationen och AND är tillägget) så är multiplikationen inte fördelande över addition och du har inget fält längre. I ett sådant fall har du ingen anledning att kalla de två elementen 0 och 1 (i vilken ordning som helst). Observera också att du inte kan välja operation ELLER i stället för XOR: oavsett hur du tolkar OR / AND som addition / multiplikation är den resulterande strukturen inte ett fält (inte alla inversa element finns som krävs av fältaxiomen).
När det gäller C-funktionerna:
- Många funktioner returnerar ett heltal som är en felkod. 0 betyder INGET FEL.
- Intuitivt beräknar funktionen
strcmp
skillnaden mellan två strängar. 0 betyder att det inte finns någon skillnad mellan två strängar, dvs att två strängar är lika.
Ovanstående intuitiva förklaringar kan hjälpa till att komma ihåg tolkningen av returvärdena, men det är ännu lättare att kolla bara i biblioteksdokumentationen.
Kommentarer
- +1 för att visa att om du godtyckligt byter dessa fungerar inte matematiken längre.
- Vänd: Med ett fält med två element och operationer * och + identifierar vi True med 0 och False med 1. Vi identifierar OR med * och XOR med +.
- Du kommer att upptäcka att båda av dessa identifieringar görs över samma fält och båda överensstämmer med reglerna för boolesk logik. Din anteckning är tyvärr felaktig 🙂
- Om du antar att True = 0 och XOR är + måste True vara identiteten för XOR. Men det beror inte på att True XOR True = False. Om du inte omdefinierar operationen XOR på True så att True XOR True = True. Då fungerar naturligtvis din konstruktion för att du precis har bytt namn på saker (i vilken matematisk struktur som helst kan du alltid framgångsrikt göra ett namn permutation och få en isomorf struktur). Å andra sidan, om du låter sant, falskt och XOR ha sin vanliga betydelse, så kan sant XOR sant = falskt och sant inte vara additividentiteten, dvs. sant kan inte vara 0.
- @Giorgio: Jag korrigerade min konstruktion enligt din kommentar i min senaste kommentar …
Svar
Du bör överväga att alternativa system också kan vara acceptabla designbeslut.
Skal: 0 utgångsstatus är sant, icke-noll är falskt
Exemplet med skal som behandlar en 0 utgångsstatus som sant har redan nämnts.
$ ( 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
Motivet där är att det finns ett sätt att lyckas, men många sätt att misslyckas, så att använda 0 som specialvärdet som betyder ”inga fel” är pragmatiskt.
Ruby: 0 är precis som alla andra siffror
Bland ”normala” programmeringsspråk finns det några avvikelser, som Ruby, som behandlar 0 som ett verkligt värde.
$ irb irb(main):001:0> 0 ? "0 is true" : "0 is false" => "0 is true"
motiveringen är att endast false
och nil
ska vara falska. För många Ruby-nybörjare är det ”sa gotcha. I vissa fall är det dock trevligt att 0 behandlas precis som alla andra nummer.
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"
Men , ett sådant system fungerar bara på ett språk som kan skilja booléer som en separat typ från siffror. Under de tidigare datorerna hade datorprogrammerare som arbetade med monteringsspråk eller råmaskinspråk ingen sådan lyx. Det är förmodligen helt naturligt att behandla 0 som ”tomt” tillstånd och ställa in lite till 1 som en flagga när koden upptäckte att något hände. I förlängningen utvecklades konventionen att noll behandlades som falskt och att värden som inte var noll behandlades som sanna. Det behöver dock inte vara så.
Java: Tal kan inte behandlas som booléer alls
I Java, true
och false
är de enda booleska värdena. Siffrorna är inte booléer och kan inte ens kastas till booléer ( Java Language Specification, Sec 4.2.2 ):
Det finns inga kast mellan integraltyper och typen
boolean
.
Denna regel undviker bara frågan helt och hållet – alla booleska uttryck måste uttryckligen skrivas i koden.
Kommentarer
- Rebol och Red behandlar båda 0-värderade INTEGER! -värden som sanna och har en separat NONE! -typ (med endast ett värde, INGEN) behandlas som villkorligt falsk utöver LOGIC! false. Jag ’ har hittat betydande frustration när jag försöker skriva JavaScript-kod som behandlar 0 som falskt; det är en inkr ätbart klumpigt beslut för ett dynamiskt typat språk. Om du vill testa något som kan vara noll eller 0 måste du skriva
if (thing === 0)
, det är inte coolt. - @HostileFork Jag don ’ vet inte. Jag tycker att det är vettigt att
0
ärtrue
(som alla andra heltal) i ett dynamiskt språk. Jag råkade ibland fånga en0
när jag försökte fångaNone
i Python, och det kan ibland vara ganska svårt att upptäcka. - Ruby är inte en outlier. Ruby tar detta från Lisp (Ruby kallas till och med i hemlighet ” MatzLisp ”). Lisp är ett vanligt språk inom datavetenskap. Noll är också bara ett verkligt värde i POSIX-skalet, eftersom det ’ är en text:
if [ 0 ] ; then echo this executes ; fi
. Det falska datavärdet är en tom sträng, och en testbar falskhet är en misslyckad avslutningsstatus för ett kommando, vilket representeras av ett non -noll.
Svar
Innan vi behandlar det allmänna fallet kan vi diskutera dina motexempel.
Strängjämförelser
Detsamma gäller för många slags jämförelser, faktiskt. Sådana jämförelser beräknar ett avstånd mellan två objekt. När objekten är lika är avståndet minimalt. Så när ”jämförelsen lyckas” är värdet 0. Men egentligen är returvärdet för strcmp
inte en boolean, det är ett avstånd och att det som fångar omedvetna programmerare som gör if (strcmp(...)) do_when_equal() else do_when_not_equal()
.
I C ++ kan vi redesigna strcmp
för att returnera en Distance
objekt, som åsidosätter operator bool()
för att returnera true när 0 (men du skulle då bli biten av en annan uppsättning problem). Eller i vanlig C har du bara en streq
-funktion som returnerar 1 när strängarna är lika och 0 annars.
API-samtal / programutgångskod
Här bryr du dig om orsaken till att något gick fel, eftersom detta kommer att göra besluten felaktiga. När saker lyckas vill du inte veta något särskilt – din avsikt realiseras. Avkastningsvärdet måste därför förmedla denna information.Det är inte en boolean, det är en felkod. Det speciella felvärdet 0 betyder ”inget fel”. Resten av intervallet representerar lokalt meningsfulla fel du måste hantera (inklusive 1, vilket ofta betyder ”ospecificerat fel”).
Allmänt fall
Detta lämnar oss med frågan: varför är booleska värden True
och False
vanligtvis representerad med 1 respektive 0?
Tja, förutom det subjektiva ”det känns bättre så här” argumentet, här är några skäl (subjektivt också) jag kan tänka på:
-
analog kretsanalys. Strömmen är PÅ för 1s och OFF för 0s. Jag gillar att ha (1, Ja, Sann, På) tillsammans och (0, Nej, Falsk, Av), snarare än en annan mix
-
minnesinitialiseringar. När jag
memset(0)
en massa variabler (vare sig de är inter, floats, bools) vill jag att deras värde ska matcha de mest konservativa antagandena. T.ex. min summa är initialt 0, predikatet är falskt osv.
Kanske är alla dessa skäl knutna till min utbildning – om jag hade lärt mig att associera 0 med True från från början skulle jag gå tvärtom.
Kommentarer
- Det finns faktiskt minst ett programmeringsspråk som behandlar 0 som sant. Unix-skalet.
- +1 för att ta itu med den verkliga frågan: De flesta av Morwenn ’ s fråga är inte ’ t om
bool
alls. - @ dan04 Det är det. Hela inlägget handlar om motivet bakom valet av rollerna från
int
tillbool
på många programmeringsspråk. Jämförelsen och felet är bara exempel på platser där det kan vara meningsfullt att kasta det på ett annat sätt än det det ’ gör för närvarande.
Svar
Ur ett högt perspektiv talar du om tre ganska olika datatyper:
-
En boolean. Den matematiska konventionen i Boolesk algebra är att använda 0 för
false
och 1 förtrue
, så det är vettigt att följa den konventionen. Jag tror att det här sättet också ger mer mening intuitivt. -
Resultatet av jämförelsen. Detta har tre värden:
<
,=
och>
(märker att ingen av dem ärtrue
). För dem är det vettigt att använda värdena -1, 0 respektive 1 (eller, mer generellt, ett negativt värde, noll och ett positivt värde).Om du vill kontrollera jämställdhet a och du har bara en funktion som utför generell jämförelse, jag tycker att du borde göra det tydligt genom att använda något som
strcmp(str1, str2) == 0
. Jag tycker att det är förvirrande att använda!
i denna situation, eftersom det behandlar ett icke-booleskt värde som om det var ett booleskt.Tänk också på att jämförelse och jämlikhet behöver inte vara samma sak. Om du till exempel beställer människor efter deras födelsedatum ska
Compare(me, myTwin)
returnera0
, menEquals(me, myTwin)
ska returnerafalse
. -
Framgång eller misslyckande för en funktion , möjligen också med detaljer om den framgången eller misslyckandet. Om du pratar om Windows kallas den här typen
HRESULT
och ett värde som inte är noll betyder inte nödvändigtvis misslyckande. Faktum är att ett negativt värde indikerar misslyckande och icke-negativ framgång. Framgångsvärdet är mycket oftaS_OK = 0
, men det kan till exempel varaS_FALSE = 1
eller andra värden.
Förvirringen kommer från det faktum det tre logiskt ganska olika datatyper representeras faktiskt som en enda datatyp (ett heltal) i C och vissa andra språk och att du kan använda heltal i ett tillstånd. Men jag tror inte att det vore vettigt att omdefiniera booleska för att använda vissa icke-booleska typer under enklare förhållanden.
Tänk också på en annan typ som ofta används i ett tillstånd i C: en pekare . Där är det naturligt att behandla en NULL
-pekare (som representeras som 0
) som false
. Så att följa ditt förslag skulle också göra det svårare att arbeta med pekare. (Men personligen föredrar jag att jag uttryckligen jämför pekare med NULL
istället för att behandla dem som booleaner.)
Svar
Noll kan vara falskt eftersom de flesta processorer har en NOLL-flagga som kan användas för att förgrena sig. Det sparar en jämförelse.
Låt oss se varför.
En del psuedokod, eftersom publiken antagligen inte läser församlingen
c- källa enkla slingor kallar wibble 10 gånger
for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */ { wibble(); }
någon låtsas församling för det
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- källa till en annan enkel loop kallar wibble tio gånger
for (int foo =0; foo<10; foo-- ) /* up count loop is longer */ { wibble(); }
några låtsas församling för detta fall
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
lite mer c-källa
int foo=10; if ( foo ) wibble()
och enheten
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
se hur kort det är?
lite mer c källa
int foo=10; if ( foo==0 ) wibble()
och enheten (kan anta en marginellt smart kompilator som kan ersätta == 0 utan jämförelse )
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
Låt oss nu testa en konvention av true = 1
lite mer c källa #define TRUE 1 int foo = TRUE; if (foo == SANT) wibble ()
och församlingen
0x1000 ld a 0x1 0x1002 cmp a 0x01 0x1004 jz 0x3 0x1006 call 0x1234 0x1009
se hur kort är fallet med icke-noll sant?
Verkligen tidiga processorer hade små uppsättningar flaggor anslutna till ackumulatorn.
För att kontrollera om a> b eller a = b generellt tar en jämförelseinstruktion.
- Om inte B är antingen ZERO – i vilket fall NOLL-flaggan är inställd Implementerad som en enkel logisk NOR eller alla bitar i ackumulatorn.
- Eller NEGATIV där du bara använder ”signbit” dvs den viktigaste biten i Ackumulator om du använder två komplement aritmetik. (För det mesta gör vi det)
Låt oss återupprepa detta. På vissa äldre processorer behövde du inte använda en jämförelseinstruktion för ackumulator lika med ZERO eller ackumulator mindre än noll.
Ser du nu varför noll kan vara falskt?
Observera att detta är psuedo-kod och ingen riktig instruktionsuppsättning ser ut så här. Om du vet montering vet du att jag förenklar sakerna mycket här. Om du vet något om kompilerdesign, behövde du inte läsa det här svaret. Den som vet något om looprullning eller grenförutsägelse, den avancerade klassen är nere i korridoren i rum 203.
Kommentarer
- Din poäng är inte bra här eftersom för en sak
if (foo)
ochif (foo != 0)
ska generera samma kod, och för det andra visar du ’ att det samlingsspråk du ’ faktiskt använder har uttryckligt booleska operander och tester för dem. Till exempeljz
betyderjump if zero
. Med andra ordif (a == 0) goto target;
Och kvantiteten testas inte ens direkt, villkoret omvandlas till en boolesk flagga som lagras i ett speciellt maskinord. Det ’ är faktiskt mer somcpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
- Nej Kaz, den äldre processorn ’ fungerade inte så. T he jz / jnz kan utföras utan att göra en jämförelseinstruktion. Vilket var verkligen poängen med hela mitt inlägg.
- Jag skrev inte ’ om en jämförelseinstruktion.
- Kan du citera en processor som har en
jz
instruktion men ingenjnz
? (eller någon annan asymmetrisk uppsättning villkorliga instruktioner)
Svar
Det finns många svar som tyder på att överensstämmelse mellan 1 och sant krävs av någon matematisk egenskap. Jag kan inte hitta någon sådan egenskap och föreslå att det är en rent historisk konvention.
Med tanke på ett fält med två element har vi två operationer: addition och multiplikation. Vi kan kartlägga booleska operationer på detta fält på två sätt :
Traditionellt identifierar vi True med 1 och False med 0. Vi identifierar AND med * och XOR med +. Således är OR mättande tillägg.
Vi kunde dock lika lätt identifiera True med 0 och False med 1. Sedan identifierar vi OR med * och XNOR med +. Således är AND mättande tillägg.
Kommentarer
- Om du hade följt länken på wikipedia kunde du ha funnit att begreppet boolesk algebra är stängd relaterat till begreppet Galoisfält med två element ( en.wikipedia.org/wiki / GF% 282% 29 ). Symbolerna 0 och 1 används konventionellt för att beteckna tillsats- och multiplikationsidentiteterna, eftersom de reella siffrorna också är ett fält vars identitet är siffrorna 0 och 1.
- @NeilG Jag tror att Giorgio försöker säga att det ’ är mer än bara en konvention. 0 och 1 i boolesk algebra är i princip samma som 0 och 1 i GF (2), som uppträder nästan lika som 0 och 1 i reella tal med avseende på addition och multiplikation.
- @svick: Nej eftersom du helt enkelt kan byta namn på multiplikation och mättnadstillägg för att vara OR och AND och sedan vända på etiketterna så att 0 är sant och 1 är falskt.Giorgio säger att det var en konvention av boolesk logik, som antogs som en konvention för datavetenskap.
- @Neil G: Nej, du kan inte vända + och * och 0 och 1 eftersom ett fält kräver distribution multiplikation över tillägg (se en.wikipedia.org/wiki/Field_%28mathematics%29 ), men om du ställer in +: = AND och *: = XOR får du T XOR (T OCH F) = T XOR F = T, medan (T XOR T) OCH (T XOR F) = F OCH T = F. Därför har du inte ett fält genom att vända operationerna och identiteterna längre. Så IMO som definierar 0 och 1 som identiteten för ett lämpligt fält verkar fånga falskt och sant ganska troget.
- @giorgio: Jag har redigerat svaret för att göra det uppenbart vad som händer.
Svar
Konstigt nog är noll inte alltid falskt.
I synnerhet konventionen Unix och Posix är att definiera EXIT_SUCCESS
som 0 (och EXIT_FAILURE
som 1). Egentligen är det till och med en standard C-konvention !
Så för Posix-skal och exit (2) syscalls, 0 betyder ”lyckad” vilket intuitivt är mer sant än falskt.
I synnerhet vill skalet ”s if
processen returnerar EXIT_SUCCESS
(det vill säga 0) för att följa dess ”då” gren!
I schemat (men inte i Common Lisp eller i MELT ) 0 och noll (dvs. ()
i Schema) är sanna, eftersom det enda falska värdet är #f
Jag håller med om det, jag nitar!
Svar
C används för programmering på låg nivå nära hårdvara, ett område där du ibland behöver växla mellan bitvis och logisk operation, på samma data. Om du måste konvertera ett numeriskt uttryck till booleskt bara för att utföra ett test skulle det vara rörigt koden.
Du kan skriva saker som:
if (modemctrl & MCTRL_CD) { /* carrier detect is on */ }
snarare än
if ((modemctrl & MCTRL_CD) != 0) { /* carrier detect is on */ }
I ett isolerat exempel är det inte så illa, men att behöva göra det blir irriterande.
Likaså, samtala operationer. Det är användbart för resultatet av en boolesk operation, som en jämförelse, att bara producera ett 0 eller 1: Antag att vi vill ställa in den tredje biten av något ord baserat på om modemctrl
har bärarens detekteringsbit:
flags |= ((modemctrl & MCTRL_CD) != 0) << 2;
Här måste vi ha != 0
, för att minska resultatet av biwise &
uttryck till 0
eller 1
, men eftersom resultatet bara är ett heltal, sparas vi från att behöva lägga till några irriterande cast för att ytterligare konvertera booleska till heltal.
Även om modern C nu har en bool
typ, det bevarar fortfarande giltigheten för koden så här, både för att den är en bra sak och på grund av den massiva brottet med bakåtkompatibilitet som annars skulle orsakas.
Ytterligare en exmapel där C är smidig: testar två booleska förhållanden som en fyrvägsomkopplare:
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; }
Du kunde inte ta bort detta från C-programmeraren utan en kamp!
Slutligen serverar C ibland som ett slags monteringsspråk på hög nivå. På monteringsspråk har vi inte heller booleska typer. Ett booleskt värde är bara en bit eller ett noll kontra icke-nollvärde i en minnesplats eller ett register. Ett heltal noll, boolesk noll och adressen noll testas alla på samma sätt i instruktionsuppsättningar för monteringsspråk (och kanske till och med flytpunkt noll). Likhet mellan C och monteringsspråk är användbart, till exempel när C används som målspråk för att kompilera ett annat språk (även ett som har starkt skrivit booleaner!)
Svar
Ett booleskt eller sanningsvärde har bara två värden. Sann och falsk.
Dessa bör inte representeras som heltal utan som bitar (0 och 1 ).
Att säga något annat heltal bredvid 0 eller 1 är inte falskt är ett förvirrande uttalande. Sanningstabeller handlar om sanningsvärden, inte heltal.
Från ett sanningsvärde kan potentiellt -1 eller 2 bryta alla sanningstabeller och all boolesk logik som associeras med dem.
- 0 OCH -1 ==?!
- 0 ELLER 2 ==?!
De flesta språk har vanligtvis en boolean
typ som vid gjutning till en nummertyp som heltal avslöjar falskt att gjutas som ett heltal värde 0.
Kommentarer
- 0 OCH -1 == vilket booleskt värde du kastar dem till. Att ’ är vad min fråga handlar om, varför kasta dem till
TRUE
ellerFALSE
.Aldrig sa jag – kanske gjorde jag det, men det var inte avsett – heltal var sanna eller falska, jag frågade om varför de utvärderar till vilket som helst när de kastas till booleska.
Svar
I slutändan pratar du om att bryta kärnspråket eftersom vissa API är skit. Crappy API: er är inte nya, och du kan inte fixa dem genom att bryta språket. Det är ett matematiskt faktum att 0 är falskt och 1 är sant, och alla språk som inte respekterar detta är i grunden trasiga. Trevägsjämförelsen är nisch och har inget företag som har resultatet att konvertera implicit till bool
eftersom det ger tre möjliga resultat. De gamla C API: erna har helt enkelt fruktansvärd felhantering och är också hämmade eftersom C inte har de språkfunktioner som krävs för att inte ha hemska gränssnitt.
Observera att jag inte säger det för språk som inte har implicita heltal-> boolesk konvertering.
Kommentarer
- ” Det är ett matematiskt faktum att 0 är falskt och 1 är sant ” Erm.
- Kan du citera en referens för ditt ” matematiska faktum att 0 är falskt och 1 är sant ”? Ditt svar låter farligt som en rant.
- Det ’ är inte ett matematiskt faktum, men det ’ har varit en matematisk konvention sedan 1800-talet.
- Boolesk algebra representeras av ett ändligt fält där 0 och 1 är identitetselementen för operationer som liknar additon och multiplikation. Dessa operationer är respektive OR och AND. I själva verket skrivs boolesk algebra ungefär som normal algebra där sammansättning betecknar AND och
+
symbolen betecknar OR. Så till exempel betyderabc + a'b'c
(a and b and c) or (a and (not b) and (not c))
.
strcmp()
är inget bra exempel för sant eller falsk, eftersom den returnerar 3 olika värden. Och du kommer att bli förvånad när du börjar använda ett skal, där 0 betyder sant och allt annat betyder falskt.if true ; then ... ; fi
, därtrue
är ett kommando som returnerar noll och detta sägerif
för att köra...
.bool
-typ men jämförelser / om villkor etc. kan ha något returvärde.