Această întrebare poate părea prostă, dar de ce 0
se evaluează la false
și orice altă valoare [întreg] la true
este cea mai mare parte a limbajelor de programare?
Comparație șir
Deoarece întrebarea pare o un pic prea simplu, mă voi explica un pic mai mult: în primul rând, poate părea evident pentru orice programator, dar de ce nu ar exista un limbaj de programare – poate exista de fapt, dar nu orice am folosit – unde 0
evaluează la true
și toate celelalte valori [întregi] la false
? Acea remarcă poate părea aleatoriu, dar am câteva exemple în care ar fi putut fi o idee bună. În primul rând, să luăm exemplul comparării în trei direcții a șirurilor, voi lua C „s strcmp
ca exemplu: orice programator care încearcă C ca primă limbă poate fi tentat să scrie următorul cod:
if (strcmp(str1, str2)) { // Do something... }
Deoarece strcmp
returnează 0
care se evaluează la false
când șirurile sunt egale, ceea ce a încercat să facă programatorul inițial eșuează lamentabil și, în general, nu înțelege de ce la început. 0
evaluat la true
în schimb, această funcție ar fi putut fi utilizată în cea mai simplă expresie – cea de mai sus – atunci când se compară pentru egalitate, iar verificările corespunzătoare pentru -1
și 1
s-ar fi făcut numai atunci când este necesar. Am fi considerat tipul de returnare ca bool
(în mintea noastră vreau să spun) de cele mai multe ori.
Mai mult, să introducem un nou tip, sign
, care doar ia valori -1
, 0
și 1
. Asta poate fi destul de la îndemână. Imaginați-vă că există un operator de navă spațială în C ++ și îl dorim pentru std::string
(bine, există deja funcția compare
, dar operatorul navei spațiale este mai distractiv). Declarația ar fi în prezent următoarea:
sign operator<=>(const std::string& lhs, const std::string& rhs);
0
fusese evaluat la true
, operatorul navei spațiale „nici măcar nu ar exista și am fi putut spune operator==
în acest fel:
sign operator==(const std::string& lhs, const std::string& rhs);
Acest operator==
au gestionat o comparație în trei direcții simultan și ar putea fi încă folosită pentru a efectua următoarea verificare, în timp ce puteți verifica ce șir este lexicografic superior celuilalt atunci când este necesar:
if (str1 == str2) { // Do something... }
Tratarea erorilor vechi
Acum avem excepții, deci această parte se aplică doar limbilor vechi unde nu există așa ceva exista (C de exemplu). Dacă ne uităm la biblioteca standard a lui C (și la POSIX una), putem vedea cu siguranță că funcțiile maaaaany returnează 0
atunci când reușesc și orice număr întreg altfel. faceți astfel de lucruri:
#define TRUE 0 // ... if (some_function() == TRUE) { // Here, TRUE would mean success... // Do something }
Dacă ne gândim la modul în care gândim în programare, avem adesea următorul model de raționament:
Do something Did it work? Yes -> That"s ok, one case to handle No -> Why? Many cases to handle
Dacă ne gândim la din nou, ar fi avut sens să punem singura valoare neutră, 0
, la yes
(și așa „s cum C” s funcțiile funcționează), în timp ce toate celelalte valori pot fi acolo pentru a rezolva numeroasele cazuri ale no
. Cu toate acestea, în toate limbajele de programare pe care le cunosc (cu excepția poate a unor limbaje ezoterice experimentale) că yes
se evaluează la false
într-o condiție if
, wh ile toate no
cazurile sunt evaluate la true
. Există multe situații în care „funcționează” reprezintă un caz în timp ce „nu funcționează” reprezintă multe cauze probabile. Dacă ne gândim la asta, având 0
evaluat la true
, iar restul la false
ar fi avut mult mai mult sens.
Concluzie
Concluzia mea este în esență întrebarea mea inițială: de ce am proiectat limbaje unde 0
este false
și celelalte valori sunt true
, ținând cont de câteva exemple de mai sus și poate de altele la care nu m-am gândit?
Urmărire: Este plăcut să vezi că există multe răspunsuri cu multe idei și cât mai multe motive posibile pentru ca acesta să fie așa. Îmi place cât de pasionat pare să fii în legătură cu asta.Am pus inițial această întrebare din plictiseală, dar, din moment ce pari atât de pasionat, am decis să merg puțin mai departe și să întreb despre rațiunea din spatele alegerii booleene pentru 0 și 1 pe Math.SE 🙂
Comentarii
Răspuns
0
este false
deoarece ambele sunt zero elemente în comun semirings . Chiar dacă sunt tipuri de date distincte, are sens intuitiv să se convertească între ele deoarece aparțin structurilor algebrice izomorfe.
-
0
este identitatea pentru adunare și zero pentru multiplicare. Acest lucru este valabil pentru numere întregi și raționale, dar nu IEEE-754 numere în virgulă mobilă:0.0 * NaN = NaN
și0.0 * Infinity = NaN
. -
false
este identitatea pentru boolean xor (⊻) și zero pentru boolean și (∧). Dacă booleenii sunt reprezentați ca {0, 1} – setul de numere întregi modulo 2 – vă puteți gândi la ⊻ ca adunare fără carry și ∧ ca multiplicare. -
""
și[]
sunt identitate pentru concatenare, dar există mai multe operații pentru care au sens ca zero. Repetarea este una, dar repetarea și concatenarea nu se distribuie, astfel încât aceste operații nu formează un semiremâncare.
Astfel de conversii implicite sunt utile în programele mici, dar în cele mari poate face programele mai dificil de raționat. Doar unul dintre numeroasele avantaje în proiectarea limbajului.
Comentarii
- Îmi pare bine că ai menționat liste. (BTW,
nil
este atât lista goală[]
, cât și valoareafalse
în Common Lisp ; există o tendință de a fuziona identități din diferite tipuri de date?) Trebuie totuși să explicați de ce este firesc să considerați fals ca o identitate aditivă și adevărat ca o identitate multiplicativă și nu invers. ‘ nu este posibil să se consideretrue
ca identificare pentruAND
și zero pentruOR
? - +1 pentru referire la identități similare. În cele din urmă, un răspuns care nu ‘ se rezumă doar la convenția „, tratează-l „.
- +1 pentru a oferi detalii despre o matematică concretă și foarte veche în care acest lucru a fost urmat și a avut sens de multă vreme
- Acest răspuns nu ‘ t are sens.
true
este, de asemenea, identitatea și zero semirings (boolean și / sau). Nu există niciun motiv, convenția apart, pentru a considerafalse
mai aproape de 0 decâttrue
. - @TonioElGringo: Diferența dintre adevărat și fals este diferența dintre XOR și XNOR. Se pot forma inele izomorfe folosind AND / XOR, unde adevărat este identitatea multiplicativă și fals aditiv, sau cu OR și XNOR, unde fals este identitatea multiplicativă și adevărat este aditiv, dar XNOR nu este de obicei considerat ca fiind un operație fundamentală așa cum este XOR.
Răspuns
Deoarece matematica funcționează.
FALSE OR TRUE is TRUE, because 0 | 1 is 1. ... insert many other examples here.
În mod tradițional, programele C au condiții precum
if (someFunctionReturningANumber())
mai degrabă decât
if (someFunctionReturningANumber() != 0)
deoarece conceptul de zero fiind echivalent cu fals este bine înțeles.
Comentarii
- Limbile sunt concepute astfel, deoarece matematica are sens. A venit primul.
- @Morwenn, datează din secolul al XIX-lea și George Boole. Oamenii reprezintă False ca 0 și True ca! 0 de mai mult timp decât au existat computere.
- Nu ‘ nu văd de ce matematica nu ‘ nu funcționează în sens invers dacă pur și simplu schimbați toate definițiile astfel încât AND este + și OR este *.
- Exact: matematica funcționează în ambele sensuri și răspunsul la această întrebare pare a fi că este pur convențională.
- @Robert ‘ ar fi extraordinar dacă ai putea spune ” temeiuri matematice ” în postarea dvs.
Răspuns
După cum au spus alții, matematica a venit pe primul loc. Acesta este motivul pentru care 0 este false
și 1 este true
.
Despre ce matematică vorbim? Algebre booleene care datează de la mijlocul anilor 1800, cu mult înainte de apariția computerelor digitale.
Ați putea spune, de asemenea, că convenția a ieșit din logică propozițională , care chiar mai veche decât algebrele booleene. Aceasta este formalizarea multor rezultate logice pe care programatorii le cunosc și le iubesc (false || x
este egal cu x
, true && x
este egal cu x
și așa mai departe).
Practic vorbim despre aritmetică pe un set cu două elemente. Gândiți-vă la numărarea în binar. Algebrele booleene sunt originea acestui concept și fundamentul său teoretic. Convențiile limbajelor precum C sunt doar o aplicație simplă.
Comentarii
- Ați putea , cu siguranță. Dar păstrându-l, modul ” standard ” se potrivește bine cu aritmetica generală (0 + 1 = 1, nu 0 + 1 = 0).
- Da, dar probabil că ați scrie ȘI cu + și SAU cu * dacă ați inversat și definițiile.
- Matematica nu ‘ nu sunt pe primul loc. Math a recunoscut că 0 și 1 formează un câmp, în care ȘI este ca multiplicarea și SAU este ca adunarea.
- @ Kaz: Dar {0, 1} cu OR și AND nu formează un câmp.
- Mă deranjează puțin că mai multe răspunsuri și comentarii spun că
true = 1
. ‘ nu este exact, deoarecetrue != 0
ceea ce nu este exact același. Un motiv (nu singurul) pentru care ar trebui evitate comparații precumif(something == true) { ... }
.
Răspuns
Am crezut că acest lucru are legătură cu „moștenirea” de la electronică și, de asemenea, algebra booleană, unde
-
0
=off
,negative
,no
,false
-
1
=on
,positive
,yes
,true
strcmp returnează 0 când șirurile sunt egale are legătură cu implementarea sa, deoarece ceea ce face de fapt este să calculeze „distanța” dintre cele două șiruri. Faptul că 0 se consideră fals este doar o coincidență.
returnând 0 succesul are sens deoarece 0 în acest caz este folosit pentru a însemna fără eroare și orice alt număr ar fi un cod de eroare. Utilizarea oricărui alt număr pentru succes ar avea mai puțin sens, deoarece aveți doar un singur cod de succes, în timp ce puteți avea mai multe coduri de eroare. Folosiți „A funcționat?” ca expresia dacă afirmația și spune 0 = da ar avea mai mult sens, dar expresia este mai corect „A greșit ceva?” și atunci vezi că 0 = nu are mult sens. Gândirea la false/true
nu are sens aici, întrucât este de fapt no error code/error code
.
Comentarii
- Haha, tu ești primul care afirmă în mod explicit întrebarea privind eroarea de returnare. Știam deja că l-am interpretat în felul meu și aș putea să-l întreb pe alt mod, dar tu ‘ ești primul care l-ai exprimat în mod explicit (din numeroasele răspunsuri și comentarii).De fapt, nu aș spune ‘ că nu spun că unul sau altul nu are sens, ci mai mult că ambele au sens în moduri diferite 🙂
- De fapt, eu ‘ spune
0
pentrusuccess/no error
este singurul lucru care are sens atunci când alte numere întregi reprezintă coduri de eroare . Că0
se întâmplă, de asemenea, să reprezintefalse
în alte cazuri, nu contează cu adevărat ‘, deoarece ‘ nu vorbim deloc despre adevărat sau fals aici;) - Am avut aceeași idee, așa că am susținut
- Punctul tău despre
strcmp()
calcularea distanței este destul de bună. Dacă ar fi fost numitstrdiff()
atunciif (!strdiff())
ar fi foarte logic. - ” electronică […] unde 0 = […] fals, 1 = […] adevărat ” – chiar și în electronică, acesta este doar un convenție și nu este singura ‘ Numim această logică pozitivă, dar puteți utiliza și logică negativă, unde o tensiune pozitivă indică fals și negativ indică adevărat. Apoi, circuitul pe care ‘ l utilizați pentru ȘI devine SAU, SAU devine ȘI și așa mai departe. Datorită legii lui De Morgan ‘, totul ajunge să fie echivalent. Uneori, ‘ veți găsi o parte a unui circuit electronic implementat în logică negativă pentru comoditate, moment în care numele semnalelor din acea parte sunt notate cu o bară deasupra lor.
Răspuns
După cum se explică în acest articol , valorile false
și true
nu trebuie confundate cu numerele întregi 0 și 1, dar pot fi identificate cu elementele câmpului Galois (câmp finit) a două elemente (vezi aici ).
Un câmp este un set cu două operații care satisfac anumite axiome.
Simbolurile 0 și 1 sunt utilizate în mod convențional pentru a desemna identitățile aditive și multiplicative ale unui câmp deoarece numerele reale sunt, de asemenea, un câmp (dar nu unul finit) ale cărui identități sunt numerele 0 și 1.
Identitatea aditivă este elementul 0 al câmpului, astfel încât pentru toate x:
x + 0 = 0 + x = x
și identitatea multiplicativă este elementul 1 al câmpului, astfel încât pentru toate x:
x * 1 = 1 * x = x
Câmpul finit al două elemente are doar aceste două elemente, și anume identitatea aditivă 0 (sau false
) și identitatea multiplicativă 1 (sau true
). Cele două operații ale acestui câmp sunt XOR logice (+) și AND logice (*).
Notă. Dacă răsturnați operațiile (XOR este înmulțirea și ȘI este adunarea) atunci înmulțirea nu este distribuitoare peste adunare și nu mai aveți un câmp. Într-un astfel de caz, nu aveți niciun motiv să numiți cele două elemente 0 și 1 (în orice ordine). Rețineți, de asemenea, că nu puteți alege operația SAU în loc de XOR: indiferent de modul în care interpretați OR / ȘI ca adunare / multiplicare, structura rezultată nu este un câmp (nu toate elementele inverse există așa cum este cerut de axiomele câmpului). >
În ceea ce privește funcțiile C:
- Multe funcții returnează un număr întreg care este un cod de eroare. 0 înseamnă FĂRĂ EROARE.
- Intuitiv, funcția
strcmp
calculează diferența dintre două șiruri. 0 înseamnă că nu există nicio diferență între două șiruri, adică două șiruri sunt egale.
Explicațiile intuitive de mai sus vă pot ajuta să vă amintiți interpretarea valorilor returnate, dar este și mai ușor să verificați doar documentația bibliotecii.
Comentarii
- +1 pentru a arăta că dacă le schimbați în mod arbitrar, matematica nu mai funcționează.
- Flipped: Având în vedere un câmp cu două elemente și operații * și +, identificăm True cu 0 și False cu 1. Identificăm SAU cu * și XOR cu +.
- Veți găsi că ambele dintre aceste identificări se fac pe același câmp și ambele sunt în concordanță cu regulile logicii booleene. Din păcate, nota dvs. este incorectă 🙂
- Dacă presupuneți că True = 0 și XOR este +, atunci True trebuie să fie identitatea pentru XOR. Dar nu pentru că True XOR True = False. Dacă nu redefiniți operația XOR pe True, astfel încât True XOR True = True. Apoi, bineînțeles, construcția dvs. funcționează pentru că tocmai ați redenumit lucrurile (în orice structură matematică puteți face întotdeauna cu succes o permutare a numelui și puteți obține o structură izomorfă). Pe de altă parte, dacă lăsați True, False și XOR să aibă semnificația lor obișnuită, atunci True XOR True = False și True nu poate fi identitatea aditivă, adică True nu poate fi 0.
- @Giorgio: mi-am corectat construcția în funcție de comentariul dvs. din ultimul meu comentariu …
Răspuns
Ar trebui să considerați că sistemele alternative pot fi, de asemenea, decizii de proiectare acceptabile.
Shells: 0 starea de ieșire este adevărată, non-zero este falsă
Exemplul shell-urilor care tratează un starea de ieșire ca adevărată a fost deja menționată.
$ ( 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
Rațiunea este că există o modalitate de a reuși, dar multe modalități de a eșua, deci utilizarea 0 ca valoare specială care înseamnă „fără erori” este pragmatică.
Ruby: 0 este la fel ca orice alt număr
Printre limbajele de programare „normale”, există unele valori aberante, cum ar fi Ruby, care tratează 0 ca pe o adevărată valoare.
$ irb irb(main):001:0> 0 ? "0 is true" : "0 is false" => "0 is true"
rațiunea este că numai false
și nil
ar trebui să fie false. Pentru mulți novici Ruby, „este bine. Totuși, în unele cazuri, este bine că 0 este tratat la fel ca orice alt număr.
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"
Cu toate acestea , un astfel de sistem funcționează numai într-un limbaj care este capabil să distingă booleenii ca un tip separat de numere. În primele zile de calcul, programatorii care lucrau cu limbaj de asamblare sau limbaj brut al mașinii nu aveau astfel de luxuri. Probabil că este firesc să tratezi 0 ca starea „necompletată” și să setezi un pic la 1 ca steag atunci când codul a detectat că s-a întâmplat ceva. Prin extensie, convenția a dezvoltat că zero a fost tratat ca fals, iar valorile non-zero au ajuns să fie tratate ca adevărate. Cu toate acestea, nu trebuie să fie așa.
Java: Numerele nu pot fi tratate deloc ca booleeni
În Java, true
și false
sunt singurele valori booleene. Numerele nu sunt booleene și nici măcar nu pot fi aruncate în booleeni ( Specificația limbii Java, sec. 4.2.2 ):
Nu există exprimări între tipurile integrale și tipul
boolean
.
Această regulă evită cu totul întrebarea – toate expresiile booleene trebuie scrise în mod explicit în cod.
Comentarii
- Rebol și Red tratează ambele valori INTEGER! cu valoare 0 ca fiind adevărate și au un tip NONE! separat (cu o singură valoare, NICIUL) tratat ca fals condițional în plus față de LOGIC! false. Am ‘ am găsit o frustrare semnificativă în încercarea de a scrie cod JavaScript care tratează 0 ca fiind fals; este un incr decizie greșit comestibilă pentru un limbaj tipat dinamic. Dacă doriți să testați ceva care poate fi nul sau 0, trebuie să scrieți
if (thing === 0)
, nu este deloc interesant. - @HostileFork Eu nu ‘ nu știu. Constat că are sens că
0
estetrue
(ca orice alt număr întreg) într-un limbaj dinamic. Uneori s-a întâmplat să prind un0
când încerc să prindNone
în Python, iar asta uneori poate fi destul de greu de observat. - Ruby nu este o valoare anterioară. Ruby ia acest lucru de la Lisp (Ruby este numit chiar în secret ” MatzLisp „). Lisp este un limbaj principal în informatică. Zero este, de asemenea, doar o adevărată valoare în shell-ul POSIX, deoarece este ‘ o bucată de text:
if [ 0 ] ; then echo this executes ; fi
. Valoarea de date false este un șir gol, iar o falsitate testabilă este o stare de terminare eșuată a unei comenzi, care este reprezentată de un non -zero.
Răspuns
Înainte de a aborda cazul general, putem discuta despre exemplele dvs. contra.
Comparații de șiruri
De fapt, același lucru este valabil pentru multe tipuri de comparații. Astfel de comparații calculează o distanță între două obiecte. Când obiectele sunt egale, distanța este minimă. Deci, atunci când „comparația reușește”, valoarea este 0. Dar într-adevăr, valoarea returnată a strcmp
nu este nu un boolean, este o distanță și că ceea ce captează programatorii care nu conștientizează if (strcmp(...)) do_when_equal() else do_when_not_equal()
.
În C ++ am putea reproiecta strcmp
pentru a returna un Distance
, care suprascrie operator bool()
pentru a reveni adevărat atunci când 0 (dar ai fi mușcat de un set diferit de probleme). Sau în C simplu aveți doar o funcție streq
care returnează 1 când șirurile sunt egale și 0 în caz contrar.
Apeluri API / cod de ieșire a programului
Aici îți pasă de motivul pentru care ceva nu a funcționat corect, deoarece acest lucru va duce la deciziile de eroare. Când lucrurile reușesc, nu vrei să știi nimic în special – intenția ta este realizată. Prin urmare, valoarea returnată trebuie să transmită aceste informații.Nu este nu un boolean, este un cod de eroare. Valoarea de eroare specială 0 înseamnă „fără eroare”. Restul intervalului reprezintă erori semnificative la nivel local cu care trebuie să vă confruntați (inclusiv 1, ceea ce înseamnă adesea „eroare nespecificată”).
Caz general
Aceasta ne lasă întrebarea: de ce sunt valorile booleene True
și False
reprezentat în mod obișnuit cu 1 și respectiv 0?
Ei bine, pe lângă argumentul subiectiv „se simte mai bine așa”, iată câteva motive (și subiective) la care mă pot gândi:
-
analogia circuitului electric. Curentul este PORNIT pentru 1s și OFF pentru 0s. Îmi place să am (1, Yes, True, On) împreună și (0, No, False, Off), mai degrabă decât un alt mix
-
inițializări de memorie. Când
memset(0)
o grămadă de variabile (fie ele ints, floats, bools) vreau ca valoarea lor să se potrivească cu ipotezele cele mai conservatoare. De exemplu. suma mea este inițial 0, predicatul este fals etc.
Poate că toate aceste motive sunt legate de educația mea – dacă aș fi fost învățat să asociez 0 cu adevărat din la început, aș merge în sens invers.
Comentarii
- De fapt, există cel puțin un limbaj de programare care tratează 0 ca fiind adevărat. Shell-ul unix.
- +1 pentru soluționarea problemei reale: majoritatea întrebărilor lui Morwenn ‘ nu sunt ‘ t despre
bool
deloc. - @ dan04 Este. Întreaga postare se referă la rațiunea din spatele alegerii distribuției de la
int
labool
în multe limbaje de programare. Compararea și gestionarea erorilor sunt doar exemple de locuri în care ar avea sens să le aruncați într-un alt mod decât cel pe care ‘ îl face în prezent.
Răspuns
Dintr-o perspectivă la nivel înalt, vorbești despre trei tipuri de date destul de diferite:
-
Un boolean. Convenția matematică din Algebra booleană este de a folosi 0 pentru
false
și 1 pentrutrue
, deci are sens să respectați această convenție. Cred că acest mod are și mai mult sens intuitiv. -
Rezultatul comparației. trei valori:
<
,=
și>
(observați că niciuna dintre ele nu estetrue
). Pentru ei este logic să se utilizeze valorile -1, 0 și respectiv 1 (sau, mai general, o valoare negativă, zero și o valoare pozitivă).Dacă doriți să verificați egalitatea a dacă aveți doar o funcție care efectuează o comparație generală, cred că ar trebui să o faceți explicită utilizând ceva de genul
strcmp(str1, str2) == 0
. Consider că utilizarea!
în această situație este confuză, deoarece tratează o valoare non-booleană ca și cum ar fi o booleană.De asemenea, rețineți această comparație și egalitatea nu trebuie să fie același lucru. De exemplu, dacă comandați oamenii după data lor de naștere,
Compare(me, myTwin)
ar trebui să returneze0
, darEquals(me, myTwin)
ar trebui să returnezefalse
. -
Succesul sau eșecul unei funcții , eventual și cu detalii despre acel succes sau eșec. Dacă vorbiți despre Windows, atunci acest tip se numește
HRESULT
și o valoare diferită de zero nu indică neapărat eșec. De fapt, o valoare negativă indică eșec și succes non-negativ. Valoarea succesului este foarte desS_OK = 0
, dar poate fi și de exempluS_FALSE = 1
sau alte valori.
Confuzia provine din faptul că că trei în mod logic tipuri de date destul de diferite sunt de fapt reprezentate ca un singur tip de date (un număr întreg) în C și în alte limbi și pe care le puteți utiliza întreg într-o condiție. Dar nu cred că ar avea sens să redefinim booleanul pentru a simplifica utilizarea unor tipuri non-booleene în condiții.
De asemenea, luăm în considerare un alt tip care este adesea folosit într-o stare în C: un pointer . Acolo, este firesc să tratezi un NULL
-pointer (care este reprezentat ca 0
) ca false
. Prin urmare, urmarea sugestiei dvs. ar face și mai dificilă lucrul cu indicii. (Deși, personal, prefer să compar în mod explicit indicii cu NULL
, în loc să-i tratez ca pe booleni.)
Răspuns
Zero poate fi fals deoarece majoritatea CPU-urilor au un steag ZERO care poate fi folosit pentru a ramifica. Se salvează o operațiune de comparare.
Să vedem de ce.
Unele psuedocode, deoarece publicul probabil nu citește ansamblul
c- surse simple de buclă apelează de 10 ori
for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */ { wibble(); }
unele pretind asamblare pentru acel
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- sursă alt simplu apeluri de buclă wibble de 10 ori
for (int foo =0; foo<10; foo-- ) /* up count loop is longer */ { wibble(); }
unele asamblări pretinde pentru acest caz
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
încă o sursă c
int foo=10; if ( foo ) wibble()
și ansamblul
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
vezi cât de scurt este?
mai multă sursă c
int foo=10; if ( foo==0 ) wibble()
și ansamblul (să presupunem un compilator marginal inteligent care poate înlocui == 0 fără comparație )
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
Acum să încercăm o convenție de adevărat = 1
încă o sursă c #define TRUE 1 int foo = TRUE; dacă (foo == ADEVĂRAT) wibble ()
și ansamblul
0x1000 ld a 0x1 0x1002 cmp a 0x01 0x1004 jz 0x3 0x1006 call 0x1234 0x1009
vezi cât de scurt este cazul cu diferit de zero?
Într-adevăr CPU-urile anterioare aveau seturi mici de semnalizări atașate la acumulator.
Pentru a verifica dacă a> b sau a = b, în general, necesită o instrucțiune de comparare. fie ZERO – caz în care semnalizatorul ZERO este setat Implementat ca o simplă NOR logică sau ca toți biții din acumulator.
Să redactăm acest lucru. Pe unele CPU mai vechi, nu a trebuit să utilizați o instrucțiune de comparare pentru acumulator egal cu ZERO sau acumulator mai mic decât zero.
Acum vedeți de ce zero ar putea fi fals?
Vă rugăm să rețineți că acesta este cod psuedo și niciun set de instrucțiuni reale nu arată așa. Dacă știți asamblarea, știți că simplific lucrurile aici. Dacă știți ceva despre proiectarea compilatorului, nu trebuia să citiți acest răspuns. Oricine știe ceva despre derularea buclei sau predicția ramurilor, clasa avansată se află pe holul din camera 203.
Comentarii
- Punctul dvs. nu este bine făcut aici, deoarece pentru un lucru
if (foo)
șiif (foo != 0)
ar trebui să genereze același cod și, în al doilea rând, arătați ‘ afișând că limbajul de asamblare pe care ‘ îl utilizați de fapt are explicit operanzi booleeni și teste pentru aceștia. De exemplu,jz
înseamnăjump if zero
. Cu alte cuvinte,if (a == 0) goto target;
. Și cantitatea nici măcar nu este testată direct; condiția este convertită într-un steag boolean care este stocat într-un cuvânt special de mașină. ‘ seamănă mai degrabă cucpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
- Nu Kaz, CPU mai vechi ‘ nu a funcționat așa. T el jz / jnz poate fi efectuat fără a face o instrucțiune de comparație. Care a fost într-adevăr un punct al întregii mele postări.
- Nu ‘ nu am scris nimic despre o instrucțiune de comparație.
- Poți citați un procesor care are o instrucțiune
jz
, dar nujnz
? (sau orice alt set asimetric de instrucțiuni condiționate)
Răspuns
Există o mulțime de răspunsuri care sugerează că corespondența dintre 1 și adevărat este necesară de o anumită proprietate matematică. Nu pot găsi o astfel de proprietate și sugerez că este o convenție pur istorică.
Având în vedere un câmp cu două elemente, avem două operații: adunare și înmulțire. Putem mapa operațiile booleene pe acest câmp în două moduri. :
În mod tradițional, identificăm Adevărat cu 1 și Fals cu 0. Identificăm ȘI cu * și XOR cu +. Astfel OR este o adunare saturată.
Cu toate acestea, am putea la fel de ușor identificăm Adevărat cu 0 și Fals cu 1. Apoi identificăm SAU cu * și XNOR cu +. Astfel ȘI este o adunare saturată.
Comentarii
- Dacă ați urmărit linkul de pe Wikipedia, ați fi putut constata că conceptul de algebră booleană este închis în legătură cu cel al unui câmp Galois cu două elemente ( en.wikipedia.org/wiki / GF% 282% 29 ). Simbolurile 0 și 1 sunt utilizate în mod convențional pentru a indica identitățile aditive și respectiv multiplicative, deoarece numerele reale sunt, de asemenea, un câmp ale cărui identități sunt numerele 0 și 1.
- @NeilG Cred că Giorgio încearcă să spună că ‘ este mai mult decât o convenție. 0 și 1 în algebra booleană sunt practic aceleași cu 0 și 1 în GF (2), care se comportă aproape la fel ca 0 și 1 în număr real în ceea ce privește adunarea și multiplicarea.
- @svick: Nu , deoarece puteți redenumi pur și simplu multiplicarea și adunarea saturată pentru a fi OR și ȘI apoi răsturnați etichetele astfel încât 0 să fie adevărat și 1 să fie fals.Giorgio spune că a fost o convenție de logică booleană, care a fost adoptată ca o convenție de informatică.
- @ Neil G: Nu, nu puteți flip + și * și 0 și 1 deoarece un câmp necesită distributivitate de multiplicare peste adunare (consultați en.wikipedia.org/wiki/Field_%28mathematics%29 ), dar dacă setați +: = ȘI și *: = XOR , obțineți T XOR (T ȘI F) = T XOR F = T, în timp ce (T XOR T) ȘI (T XOR F) = F ȘI T = F. Prin urmare, prin răsturnarea operațiilor și identităților nu aveți un câmp mai mult. Așadar, IMO care definește 0 și 1 ca identități ale unui câmp adecvat pare să capteze fals și adevărat destul de fidel.
- @giorgio: Am editat răspunsul pentru a face evident ce se întâmplă.
Răspuns
În mod ciudat, zero nu este întotdeauna fals.
În special, convenția Unix și Posix este de a defini EXIT_SUCCESS
ca 0 (și EXIT_FAILURE
ca 1). De fapt, este chiar o convenție standard C !
Deci pentru shell-urile Posix și (2) syscalls, 0 înseamnă „reușit”, ceea ce intuitiv este mai adevărat decât fals.
În special, shell-ul „s if
dorește un return proces EXIT_SUCCESS
(adică 0) pentru a-și urma ramura „apoi”!
În schemă (dar nu în Common Lisp sau în MELT ) 0 și zero (adică ()
în Scheme) sunt adevărate, deoarece singura valoare falsă este #f
Sunt de acord, mă descurc!
Răspunde
C este folosit pentru programarea la nivel scăzut apropiat de hardware, o zonă în care uneori trebuie să treceți între operațiile logice și bit, pe aceleași date. Fiind necesar să convertiți o expresie numerică în boolean doar pentru a efectua un test, s-ar aglomera codul.
Puteți scrie lucruri precum:
if (modemctrl & MCTRL_CD) { /* carrier detect is on */ }
mai degrabă decât
if ((modemctrl & MCTRL_CD) != 0) { /* carrier detect is on */ }
Într-un exemplu izolat, nu este atât de rău, dar trebuie să faci asta va deveni deranjant.
La fel, operațiile de conversare. Este util pentru rezultatul unei operații booleene, ca o comparație, să producem doar 0 sau 1: Să presupunem că dorim să setăm cel de-al treilea bit al unui cuvânt în funcție de modemctrl
are operatorul de detectare a bitului:
flags |= ((modemctrl & MCTRL_CD) != 0) << 2;
Aici trebuie să avem != 0
, pentru a reduce rezultatul expresiei biwise &
la 0
sau 1
, dar pentru că rezultatul este doar un întreg, suntem scutiți de faptul că trebuie să adăugăm o distribuție enervantă pentru a converti în continuare booleanul în întreg.
Chiar dacă modernul C are acum un bool
, păstrează în continuare valabilitatea codului ca acesta, atât pentru că este un lucru bun, cât și din cauza ruperii masive cu compatibilitate inversă care ar fi cauzată altfel.
Un alt exemplu în care C este slick: testarea a două condiții booleene ca un comutator cu patru căi:
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; }
Nu ați putea lua acest lucru de la programatorul C fără o luptă!
În cele din urmă, C servește uneori ca un fel de limbaj de asamblare la nivel înalt. În limbile de asamblare, de asemenea, nu avem tipuri booleene. O valoare booleană este doar un pic sau o valoare zero față de zero într-o locație sau registru de memorie. Un zero întreg, zero boolean și adresa zero sunt toate testate la fel în seturile de instrucțiuni ale limbajului de asamblare (și poate chiar cu virgulă mobilă zero). Asemănarea dintre C și limbajul de asamblare este utilă, de exemplu atunci când C este folosit ca limbă țintă pentru compilarea unei alte limbi (chiar și una care a introdus booleenii puternic!)
Răspuns
O valoare booleană sau adevărată are doar 2 valori. Adevărat și fals.
Acestea ar trebui nu să fie reprezentate ca numere întregi, ci ca biți (0 și 1 ).
Spunerea oricărui alt număr întreg lângă 0 sau 1 nu este falsă este o afirmație confuză. Tabelele adevărului se referă la valori de adevăr, nu la numere întregi.
Din perspectiva unei valori de adevăr, -1 sau 2 ar rupe toate tabelele de adevăr și orice logică booleană asociată cu acestea.
- 0 ȘI -1 ==?!
- 0 SAU 2 ==?!
Majoritatea limbilor au de obicei un boolean
tastați care, atunci când este aruncat la un tip de număr, cum ar fi întregul, arată fals pentru a fi aruncat ca valoare întreagă de 0.
Comentarii
- 0 ȘI -1 == orice valoare booleană le-ați aruncat. Aceasta este ‘ despre ce este întrebarea mea, de ce să le trimit la
TRUE
sauFALSE
.Nu am spus niciodată – poate că am făcut-o, dar nu a fost intenționat – numerele întregi erau adevărate sau false, am întrebat de ce evaluează în funcție de oricare dintre acestea, atunci când sunt aruncate în boolean.
Răspuns
În cele din urmă, vorbiți despre ruperea limbajului de bază, deoarece unele API-uri sunt nenorocite. API-urile neplăcute nu sunt noi și nu le puteți remedia rupând limba. Este un fapt matematic că 0 este fals și 1 este adevărat, iar orice limbaj care nu respectă acest lucru este fundamental rupt. Comparația în trei direcții este de nișă și nu are nicio afacere care să aibă rezultatul implicit convertit în bool
, deoarece returnează trei rezultate posibile. Vechile API-uri C pur și simplu au o manipulare teribilă a erorilor și sunt, de asemenea, blocate, deoarece C nu are caracteristicile de limbaj necesare pentru a nu avea interfețe teribile.
Rețineți că nu spun asta pentru limbile care nu au implicit integer-> conversie booleană.
Comentarii
- ” Este un fapt matematic că 0 este fals și 1 este adevărat ” Erm.
- Puteți cita o referință pentru ” faptul matematic că 0 este fals și 1 este adevărat „? Răspunsul dvs. sună în mod periculos ca o descărcare.
- Nu ‘ nu este un fapt matematic, ci ‘ a fost o convenție matematică începând cu secolul al XIX-lea.
- Algebra booleană este reprezentată de un câmp finit în care 0 și 1 sunt elemente de identitate pentru operații care seamănă cu additon și multiplicare. Acele operații sunt, respectiv, SAU ȘI ȘI. De fapt, algebra booleană este scrisă la fel ca algebra normală în care juxtapunerea indică ȘI, iar simbolul
+
denotă SAU. De exemplu,abc + a'b'c
înseamnă(a and b and c) or (a and (not b) and (not c))
.
strcmp()
nu este un exemplu bun pentru adevărat sau fals, deoarece returnează 3 valori diferite. Și vei fi surprins când vei începe să folosești un shell, unde 0 înseamnă adevărat și orice altceva înseamnă fals.if true ; then ... ; fi
, undetrue
este o comandă care returnează zero și aceasta spuneif
pentru a rula...
.bool
, dar comparațiile / dacă condițiile etc. pot avea orice valoare de returnare.