Questa domanda può sembrare stupida, ma perché 0
restituisce false
e qualsiasi altro valore [intero] di true
è la maggior parte dei linguaggi di programmazione?
Confronto di stringhe
Poiché la domanda sembra una un po troppo semplice, mi spiego un po di più: prima di tutto, può sembrare evidente a qualsiasi programmatore, ma perché non dovrebbe esserci un linguaggio di programmazione – potrebbe effettivamente esserci, ma non quello che ho usato – dove 0
restituisce true
e tutti gli altri valori [integer] a false
? Quella osservazione può sembrare casuale, ma ho alcuni esempi in cui potrebbe essere stata una buona idea. Prima di tutto, prendiamo lesempio del confronto a tre stringhe, prenderò C “s strcmp
come esempio: qualsiasi programmatore che provi C come prima lingua potrebbe essere tentato di scrivere il seguente codice:
if (strcmp(str1, str2)) { // Do something... }
Poiché strcmp
restituisce 0
che restituisce false
quando le stringhe sono uguali, ciò che il programmatore principiante ha cercato di fare fallisce miseramente e generalmente non capisce perché allinizio. Se 0
fosse stato valutato come true
, questa funzione avrebbe potuto essere utilizzata nella sua espressione più semplice, quella sopra, quando si confronta luguaglianza, e i controlli appropriati per -1
e 1
sarebbero stati eseguiti solo quando necessario. Avremmo considerato il tipo di ritorno come bool
(nella nostra mente intendo) la maggior parte delle volte.
Inoltre, introduciamo un nuovo tipo, sign
, che accetta solo i valori -1
, 0
e 1
. Può essere molto utile. Immagina che ci sia un operatore di astronave in C ++ e lo vogliamo per std::string
(beh, esiste già la funzione compare
, ma loperatore di astronave è più divertente). La dichiarazione al momento sarebbe la seguente:
sign operator<=>(const std::string& lhs, const std::string& rhs);
0
era stato valutato come true
, loperatore astronave non sarebbe nemmeno esistito e avremmo potuto dichiarare operator==
in questo modo:
sign operator==(const std::string& lhs, const std::string& rhs);
Questo operator==
sarebbe hanno gestito il confronto a tre in una volta, e potrebbe ancora essere utilizzato per eseguire il seguente controllo pur essendo ancora in grado di controllare quale stringa è lessicograficamente superiore allaltra quando necessario:
if (str1 == str2) { // Do something... }
Gestione dei vecchi errori
Ora abbiamo delle eccezioni, quindi questa parte si applica solo alle vecchie lingue in cui non esiste nulla di simile esistono (C per esempio). Se guardiamo la libreria standard di C (e anche quella POSIX), possiamo vedere con certezza che le funzioni maaaaany restituiscono 0
quando hanno successo e qualsiasi numero intero altrimenti. Ho visto tristemente alcune persone fare questo genere di cose:
#define TRUE 0 // ... if (some_function() == TRUE) { // Here, TRUE would mean success... // Do something }
Se pensiamo a come pensiamo programmazione, spesso abbiamo il seguente modello di ragionamento:
Do something Did it work? Yes -> That"s ok, one case to handle No -> Why? Many cases to handle
Se pensiamo a ancora una volta, avrebbe avuto senso mettere lunico valore neutro, 0
, a yes
(e questo è “come C” funzioni), mentre tutti gli altri valori possono essere lì per risolvere i molti casi di no
. Tuttavia, in tutti i linguaggi di programmazione che conosco (tranne forse alcuni linguaggi esoterici sperimentali), che yes
restituisce false
in una if
condizione, wh ile tutti i no
casi restituiscono true
. Ci sono molte situazioni in cui “funziona” rappresenta un caso mentre “non funziona” rappresenta molte cause probabili. Se la pensiamo in questo modo, 0
restituisce true
e il resto false
avrebbe avuto molto più senso.
Conclusione
La mia conclusione è essenzialmente la mia domanda originale: perché abbiamo progettato linguaggi in cui 0
è false
e gli altri valori sono true
, tenendo conto dei miei pochi esempi sopra e forse altri a cui non avevo pensato?
Follow-up: È bello vedere che ci sono molte risposte con molte idee e tanti possibili motivi perché sia così. Adoro quanto sembri appassionato al riguardo.Inizialmente ho posto questa domanda per noia, ma dal momento che sembri così appassionato, ho deciso di andare un po oltre e chiedere la logica alla base della scelta booleana per 0 e 1 on Math.SE 🙂
Commenti
Risposta
0
è false
perché sono entrambi zero elementi in semirimensioni . Anche se sono tipi di dati distinti, ha senso intuitivo convertirli tra loro perché appartengono a strutture algebriche isomorfe.
-
0
è lidentità per laddizione e lo zero per la moltiplicazione. Questo è vero per numeri interi e razionali, ma non IEEE-754 numeri a virgola mobile:0.0 * NaN = NaN
e0.0 * Infinity = NaN
. -
false
è lidentità per booleano xor (⊻) e zero per booleano e (∧). Se i valori booleani sono rappresentati come {0, 1}, linsieme di numeri interi modulo 2, puoi pensare a ⊻ come addizione senza riporto e ∧ come moltiplicazione. -
""
e[]
sono identità per la concatenazione, ma ci sono diverse operazioni per le quali hanno senso come zero. La ripetizione è una, ma la ripetizione e la concatenazione non vengono distribuite, quindi queste operazioni non formano un semirimorchio.
Tali conversioni implicite sono utili nei piccoli programmi, ma nel grande può rendere i programmi più difficili da ragionare. Solo uno dei tanti compromessi nella progettazione del linguaggio.
Commenti
- Bello che tu abbia menzionato gli elenchi. (A proposito,
nil
è sia lelenco vuoto[]
e il valorefalse
in Common Lisp ; cè una tendenza a fondere identità da diversi tipi di dati?) Devi ancora spiegare perché è naturale considerare falso come identità additiva e vero come identità moltiplicativa e non il contrario. Non è ‘ possibile consideraretrue
come lidentificativo diAND
e zero perOR
? - +1 per fare riferimento a identità simili. Infine una risposta che ‘ non si riduce alla ” convenzione, gestirla “.
- +1 per aver fornito dettagli di una matematica concreta e molto vecchia in cui è stata seguita e ha avuto senso a lungo
- Questa risposta non ‘ t ha senso.
true
è anche lidentità e lo zero delle semirimensioni (booleano e / o). Non cè motivo, a parte la convenzione, per considerarefalse
è più vicino a 0 ditrue
. - @TonioElGringo: La differenza tra vero e falso è la differenza tra XOR e XNOR. Si possono formare anelli isomorfici usando AND / XOR, dove true è lidentità moltiplicativa e false quella additiva, o con OR e XNOR, dove false è lidentità moltiplicativa e true è quella additiva, ma XNOR non è solitamente considerato come un comune operazione fondamentale come è XOR.
Risposta
Perché la matematica funziona.
FALSE OR TRUE is TRUE, because 0 | 1 is 1. ... insert many other examples here.
Tradizionalmente, i programmi C hanno condizioni come
if (someFunctionReturningANumber())
invece di
if (someFunctionReturningANumber() != 0)
perché il concetto di zero equivalente a falso è ben compreso.
Commenti
- Le lingue sono progettate in questo modo perché la matematica ha senso. È venuto prima.
- @Morwenn, risale al XIX secolo e a George Boole. Le persone hanno rappresentato False come 0 e True come! 0 da più tempo di quanto non esistano i computer.
- Non ‘ non capisco perché la matematica non ‘ t funziona in un altro modo se modifichi semplicemente tutte le definizioni in modo che AND sia + e OR sia *.
- Esatto: la matematica funziona in entrambi i modi e la risposta a questa domanda sembra essere puramente convenzionale.
- @Robert It ‘ sarebbe fantastico se potessi precisare il ” basi matematiche ” nel tuo post.
Risposta
Come altri hanno detto, la matematica viene prima di tutto. Questo è il motivo per cui 0 è false
e 1 è true
.
Di quale matematica stiamo parlando? algebre booleane che risalgono alla metà del 1800, molto prima che arrivassero i computer digitali.
Si potrebbe anche dire che la convenzione deriva dalla logica proposizionale , che è anche più vecchia delle algebre booleane. Questa è la formalizzazione di molti dei risultati logici che i programmatori conoscono e amano (false || x
è uguale a x
, true && x
è uguale a x
e così via).
Fondamentalmente stiamo parlando di aritmetica su un insieme di due elementi. Pensa al conteggio in binario. Le algebre booleane sono lorigine di questo concetto e la sua base teorica. Le convenzioni di linguaggi come il C sono solo unapplicazione semplice.
Commenti
- Potresti , di sicuro. Ma mantenerlo lo ” standard ” si adatta bene allaritmetica generale (0 + 1 = 1, non 0 + 1 = 0).
- Sì, ma presumibilmente scriveresti AND con + e OR con * se invertissi anche le definizioni.
- La matematica non ‘ t viene prima. Math ha riconosciuto che 0 e 1 formano un campo, in cui AND è come la moltiplicazione e OR è come laddizione.
- @ Kaz: Ma {0, 1} con OR e AND non forma un campo.
- Mi dà un po fastidio che più risposte e commenti dicano che
true = 1
. Questo ‘ non è del tutto esatto, perchétrue != 0
non è esattamente lo stesso. Una ragione (non lunica) per cui si dovrebbero evitare confronti comeif(something == true) { ... }
.
Risposta
Pensavo che questo avesse a che fare con l “eredità” dallelettronica e anche con lalgebra booleana, dove
-
0
=off
,negative
,no
,false
-
1
=on
,positive
,yes
,true
strcmp restituisce 0 quando le stringhe sono uguali ha a che fare con la sua implementazione, poiché ciò che in realtà fa è calcolare la “distanza” tra le due stringhe. Che anche 0 sia considerato falso è solo una coincidenza.
restituire 0 in caso di successo ha senso perché 0 in questo caso viene utilizzato per indicare nessun errore e qualsiasi altro numero sarebbe un codice di errore. Luso di qualsiasi altro numero per il successo avrebbe meno senso poiché hai un solo codice di successo, mentre puoi avere diversi codici di errore. Usi “Ha funzionato?” come lespressione dellistruzione if e dire 0 = yes avrebbe più senso, ma lespressione è più corretta “È andato storto qualcosa?” e poi vedi che 0 = no ha molto senso. Pensare a false/true
non ha “davvero senso qui, poiché in realtà è no error code/error code
.
Commenti
- Ahah, sei il primo a dichiarare esplicitamente la domanda di errore di ritorno. Sapevo già di averlo interpretato a modo mio e potevo chiedere in un altro modo, ma ‘ sei il primo ad esprimerlo esplicitamente (tra le tante risposte e commenti).In realtà, non vorrei ‘ dire che luno o laltro modo non ha senso, ma più che entrambi hanno senso in modi diversi 🙂
- In realtà io ‘ d say
0
persuccess/no error
è lunica cosa che ha senso quando altri numeri interi rappresentano codici di errore . Questo0
rappresenta anchefalse
in altri casi ‘ non ha molta importanza, poiché qui ‘ non stiamo affatto parlando di vero o falso;) - Avevo la stessa idea, quindi ho sollevato
- il tuo punto di vista
strcmp()
il calcolo della distanza è abbastanza buono. Se fosse stato chiamatostrdiff()
,if (!strdiff())
sarebbe molto logico. - ” elettronica […] dove 0 = […] false, 1 = […] true ” – anche in elettronica, questo è solo un convenzione e ‘ è lunico. Chiamiamo questa logica positiva, ma puoi anche usare la logica negativa, dove una tensione positiva indica falso e negativo indica vero. Quindi, il circuito che ‘ usi per AND diventa OR, OR diventa AND e così via. A causa della legge di De Morgan ‘, tutto finisce per essere equivalente. A volte, ‘ troverai parte di un circuito elettronico implementato in logica negativa per comodità, a quel punto i nomi dei segnali in quella parte sono annotati con una barra sopra di essi.
Risposta
Come spiegato in questo articolo , i valori false
e true
non devono essere confusi con i numeri interi 0 e 1, ma possono essere identificati con gli elementi del campo Galois (campo finito) di due elementi (vedere qui ).
Un campo è un insieme con due operazioni che soddisfano determinati assiomi.
I simboli 0 e 1 sono convenzionalmente usati per denotare le identità additive e moltiplicative di un campo perché i numeri reali sono anche un campo (ma non finito) le cui identità sono i numeri 0 e 1.
Lidentità additiva è lelemento 0 del campo, tale che per tutti gli x:
x + 0 = 0 + x = x
e lidentità moltiplicativa è lelemento 1 del campo, tale che per ogni x:
x * 1 = 1 * x = x
Il campo finito di due elementi ha solo questi due elementi, vale a dire il identità additiva 0 (o false
) e identità moltiplicativa 1 (o true
). Le due operazioni di questo campo sono XOR logico (+) e AND logico (*).
Nota. Se capovolgi le operazioni (XOR è la moltiplicazione e AND è laddizione) allora la moltiplicazione non è distributiva sulladdizione e non hai più un campo. In tal caso non hai motivo di chiamare i due elementi 0 e 1 (in qualsiasi ordine). Nota anche che non puoi scegliere loperazione OR invece di XOR: non importa come interpreti OR / AND come addizione / moltiplicazione, la struttura risultante non è un campo (non tutti gli elementi inversi esistono come richiesto dagli assiomi del campo).
Riguardo alle funzioni C:
- Molte funzioni restituiscono un numero intero che è un codice di errore. 0 significa NESSUN ERRORE.
- Intuitivamente, la funzione
strcmp
calcola la differenza tra due stringhe. 0 significa che non cè differenza tra due stringhe, cioè che due stringhe sono uguali.
Le spiegazioni intuitive sopra possono aiutare a ricordare linterpretazione dei valori restituiti, ma è ancora più facile da basta controllare la documentazione della libreria.
Commenti
- +1 per mostrare che se li scambi arbitrariamente, i calcoli non funzionano più.
- Capovolto: dato un campo con due elementi e operazioni * e +, identifichiamo True con 0 e False con 1. Identifichiamo OR con * e XOR con +.
- Scoprirai che entrambi di queste identificazioni vengono eseguite sullo stesso campo ed entrambe sono coerenti con le regole della logica booleana. La tua nota purtroppo non è corretta 🙂
- Se presumi che True = 0 e XOR sia +, allora True deve essere lidentità di XOR. Ma non è perché True XOR True = False. A meno che non si ridefinisca loperazione XOR su True in modo che True XOR True = True. Quindi ovviamente la tua costruzione funziona perché hai appena rinominato le cose (in qualsiasi struttura matematica puoi sempre fare con successo una permutazione del nome e ottenere una struttura isomorfa). Daltra parte, se lasci che True, False e XOR abbiano il loro significato abituale, allora True XOR True = False e True non possono essere lidentità additiva, cioè True non può essere 0.
- @Giorgio: ho corretto la mia costruzione in base al tuo commento nel mio ultimo commento …
Risposta
Dovresti considerare che anche i sistemi alternativi possono essere decisioni di progettazione accettabili.
Shell: 0 lo stato di uscita è vero, diverso da zero è falso
Lesempio di shell che trattano uno 0 lo stato di uscita come true è già stato menzionato.
$ ( 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
La logica è che cè un modo per avere successo, ma molti modi per fallire, quindi usare 0 come valore speciale che significa “nessun errore” è pragmatico.
Ruby: 0 è proprio come qualsiasi altro numero
Tra i linguaggi di programmazione “normali”, ci sono alcuni valori anomali, come Ruby, che trattano 0 come un valore vero.
$ irb irb(main):001:0> 0 ? "0 is true" : "0 is false" => "0 is true"
Il logica è che solo false
e nil
dovrebbero essere false. Per molti principianti di Ruby, è “un trucchetto. Tuttavia, in alcuni casi, è bello che 0 sia trattato come qualsiasi altro numero.
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"
Tuttavia , un tale sistema funziona solo in un linguaggio in grado di distinguere i booleani come un tipo separato dai numeri. Nei primi tempi dellinformatica, i programmatori che lavoravano con il linguaggio assembly o il linguaggio macchina grezzo non avevano tali lussi. Probabilmente è semplicemente naturale trattare 0 come lo stato “vuoto” e impostare un po su 1 come flag quando il codice rileva che è successo qualcosa. Per estensione, la convenzione ha sviluppato che lo zero era considerato falso e i valori diversi da zero venivano considerati veri. Tuttavia, non deve essere così.
Java: i numeri non possono essere trattati affatto come booleani
In Java, true
e false
sono gli unici valori booleani. I numeri non sono booleani e non possono nemmeno essere espressi in booleani ( Java Language Specification, Sec 4.2.2 ):
non sono presenti cast tra i tipi integrali e il tipo
boolean
.
Questa regola evita del tutto la domanda: tutte le espressioni booleane devono essere scritte esplicitamente nel codice.
Commenti
- Rebol e Red trattano entrambi i valori INTEGER! con valori 0 come veri e hanno un tipo NONE! separato (con un solo valore, NONE) trattato come falso condizionale oltre a LOGIC! false. ‘ ho riscontrato una notevole frustrazione nel tentativo di scrivere codice JavaScript che tratta 0 come falso; è un incr decisione commestibilmente goffa per un linguaggio digitato dinamicamente. Se vuoi testare qualcosa che può essere nullo o 0, finisci per dover scrivere
if (thing === 0)
, semplicemente non va bene. - @HostileFork I don ‘ non so. Trovo che abbia senso che
0
siatrue
(come ogni altro numero intero) in un linguaggio dinamico. A volte mi è capitato di rilevare un0
quando cercavo di catturareNone
in Python, e a volte può essere piuttosto difficile da individuare. - Ruby non è un valore anomalo. Ruby lo prende da Lisp (Ruby è anche segretamente chiamato ” MatzLisp “). Lisp è un linguaggio mainstream nellinformatica. Lo zero è anche solo un valore vero nella shell POSIX, perché ‘ è un pezzo di testo:
if [ 0 ] ; then echo this executes ; fi
. Il valore dei dati falsi è una stringa vuota e una falsità verificabile è uno stato di terminazione non riuscita di un comando, rappresentato da un diverso -zero.
Risposta
Prima di affrontare il caso generale, possiamo discutere i tuoi contro esempi.
Confronti di stringhe
Lo stesso vale per molti tipi di confronti, in realtà. Tali confronti calcolano una distanza tra due oggetti. Quando gli oggetti sono uguali, la distanza è minima. Quindi, quando il “confronto riesce”, il valore è 0. In realtà, il valore restituito di strcmp
non è booleano, è una distanza e questo è ciò che intrappola i programmatori inconsapevoli che fanno if (strcmp(...)) do_when_equal() else do_when_not_equal()
.
In C ++ potremmo riprogettare strcmp
per restituire un Distance
, che sostituisce operator bool()
per restituire true quando 0 (ma verresti morso da un diverso insieme di problemi). Oppure in C semplice basta avere una streq
funzione che restituisce 1 quando le stringhe sono uguali e 0 altrimenti.
Chiamate API / codice di uscita del programma
Qui ti interessa il motivo per cui qualcosa è andato storto, perché questo porterà le decisioni in errore. Quando le cose hanno successo, non vuoi sapere niente in particolare – il tuo intento è realizzato. Il valore di ritorno deve quindi trasmettere queste informazioni. non è un booleano, è un codice di errore. Il valore di errore speciale 0 significa “nessun errore”. Il resto dellintervallo rappresenta gli errori significativi a livello locale che devi affrontare (incluso 1, che spesso significa “errore non specificato”).
Caso generale
Questo ci lascia con la domanda: perché i valori booleani sono True
e False
comunemente rappresentato rispettivamente con 1 e 0?
Bene, oltre allargomento soggettivo “è meglio così”, ecco alcune ragioni (anche soggettive) a cui posso pensare:
-
analogia del circuito elettrico. La corrente è ON per 1s e OFF per 0s. Mi piace avere (1, Yes, True, On) insieme e (0, No, False, Off), piuttosto che un altro mix di inizializzazioni di memoria
-
. Quando
memset(0)
un gruppo di variabili (siano esse int, float, bool) voglio che il loro valore corrisponda alle ipotesi più conservative. Per esempio. la mia somma è inizialmente 0, il predicato è False, ecc.
Forse tutte queste ragioni sono legate alla mia educazione, se mi fosse stato insegnato ad associare 0 con True dal Allinizio, vorrei fare il contrario.
Commenti
- In realtà cè almeno un linguaggio di programmazione che tratta 0 come vero. La shell unix.
- +1 per aver risolto il problema reale: la maggior parte della ‘ domanda di Morwenn non è ‘ t su
bool
. - @ dan04 Lo è. Lintero post riguarda la logica alla base della scelta del cast da
int
abool
in molti linguaggi di programmazione. Il confronto e la gestione degli errori sono solo esempi di luoghi in cui trasmettere in un modo diverso da quello che ‘ è attualmente fatto avrebbe avuto senso.
Risposta
Da una prospettiva di alto livello, stai parlando di tre tipi di dati abbastanza diversi:
-
Un booleano. La convenzione matematica in algebra booleana è di utilizzare 0 per
false
e 1 pertrue
, quindi ha senso seguire questa convenzione. Penso che in questo modo abbia anche più senso intuitivamente. -
Il risultato del confronto. Questo ha tre valori:
<
,=
e>
(nota che nessuno di essi ètrue
). Per loro ha senso usare rispettivamente i valori -1, 0 e 1 (o, più in generale, un valore negativo, zero e un valore positivo).Se vuoi verificare luguaglianza a nd hai solo una funzione che esegue il confronto generale, penso che dovresti renderla esplicita usando qualcosa come
strcmp(str1, str2) == 0
. Trovo che luso di!
in questa situazione sia fonte di confusione, perché tratta un valore non booleano come se fosse un booleano.Inoltre, tieni presente questo confronto e luguaglianza non deve essere la stessa cosa. Ad esempio, se ordini le persone in base alla data di nascita,
Compare(me, myTwin)
dovrebbe restituire0
, maEquals(me, myTwin)
dovrebbe restituirefalse
. -
Il successo o il fallimento di una funzione , possibilmente anche con i dettagli su tale successo o fallimento. Se stai parlando di Windows, questo tipo si chiama
HRESULT
e un valore diverso da zero non indica necessariamente un fallimento. Infatti, un valore negativo indica un errore e un successo non negativo. Il valore di successo è molto spessoS_OK = 0
, ma può anche essere ad esempioS_FALSE = 1
o altri valori.
La confusione deriva dal fatto che tre logicamente tipi di dati abbastanza diversi sono in realtà rappresentati come un singolo tipo di dati (un numero intero) in C e in alcuni altri linguaggi e che è possibile utilizzare intero in una condizione. Ma non credo che avrebbe senso ridefinire booleano per rendere più semplice luso di alcuni tipi non booleani in condizioni.
Inoltre, considera un altro tipo che è spesso usato in una condizione in C: un puntatore . Lì, è naturale trattare un NULL
puntatore (che è rappresentato come 0
) come false
. Quindi, seguire il tuo suggerimento renderebbe anche più difficile lavorare con i puntatori (anche se, personalmente, preferisco confrontare esplicitamente i puntatori con NULL
, invece di trattarli come booleani.)
Risposta
Zero può essere falso perché la maggior parte delle CPU ha un flag ZERO che può essere usato per diramare. Salva unoperazione di confronto.
Vediamo perché.
Alcuni psuedocode, poiché il pubblico probabilmente non legge lassembly
c- source simple loop chiama wibble 10 volte
for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */ { wibble(); }
qualche finta assemblea per questo
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- fonte un altro semplice loop chiama wibble 10 volte
for (int foo =0; foo<10; foo-- ) /* up count loop is longer */ { wibble(); }
un po di finto assemblaggio per questo caso
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
qualche altra fonte c
int foo=10; if ( foo ) wibble()
e lassembly
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
vedi quanto è breve?
ancora un po di c source
int foo=10; if ( foo==0 ) wibble()
e lassembly (supponiamo un compilatore marginalmente intelligente che può sostituire == 0 senza confronto )
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
Ora proviamo una convenzione di true = 1
un po più di c source #define TRUE 1 int foo = TRUE; if (foo == TRUE) wibble ()
e lassembly
0x1000 ld a 0x1 0x1002 cmp a 0x01 0x1004 jz 0x3 0x1006 call 0x1234 0x1009
vedi quanto è breve il caso con vero diverso da zero?
Davvero le prime CPU avevano piccoli set di flag attaccati allaccumulatore.
Per controllare se a> b o a = b generalmente richiede unistruzione di confronto.
- A meno che B non sia ZERO – nel qual caso il flag ZERO è impostato Implementato come un semplice NOR logico o tutti i bit nellAccumulatore.
- O NEGATIVO in cui basta usare il “bit di segno” cioè il bit più significativo dellAccumulatore se stai usando laritmetica in complemento a due. (Per lo più lo facciamo)
Ripetiamo questo. Su alcune CPU meno recenti non era necessario utilizzare unistruzione di confronto per accumulatore uguale a ZERO o accumulatore minore di zero.
Ora capisci perché zero potrebbe essere falso?
Per favore nota che questo è codice psuedo e nessun vero set di istruzioni assomiglia a questo.Se conosci lassemblaggio sai che sto semplificando molto le cose qui. Se sai qualcosa sulla progettazione del compilatore, non hai bisogno di leggere questa risposta. Chiunque sappia qualcosa sullo srotolamento del loop o sulla previsione dei rami, la classe avanzata è in fondo al corridoio nella stanza 203.
Commenti
- Il tuo punto di vista qui non è ben espresso perché per prima cosa
if (foo)
eif (foo != 0)
dovrebbe generare lo stesso codice e, in secondo luogo, ‘ stai dimostrando che il linguaggio assembly che ‘ stai utilizzando in realtà è esplicito operandi booleani e verifica per essi. Ad esempiojz
significajump if zero
. In altre paroleif (a == 0) goto target;
. E la quantità non viene nemmeno testata direttamente; la condizione viene convertita è un flag booleano memorizzato in una parola macchina speciale. ‘ in realtà è più simile acpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
- No Kaz, la vecchia CPU ‘ non funzionava così. T jz / jnz può essere eseguito senza eseguire unistruzione di confronto. Che era davvero il punto di tutto il mio post.
- Non ‘ ho scritto nulla su unistruzione di confronto.
- Puoi citare un processore che dispone di unistruzione
jz
ma non dijnz
? (o qualsiasi altro insieme asimmetrico di istruzioni condizionali)
Risposta
Ci sono molte risposte che suggeriscono che la corrispondenza tra 1 e true è resa necessaria da alcune proprietà matematiche. Non riesco a trovare alcuna proprietà di questo tipo e suggerisco che sia puramente una convenzione storica.
Dato un campo con due elementi, abbiamo due operazioni: addizione e moltiplicazione. Possiamo mappare le operazioni booleane su questo campo in due modi :
Tradizionalmente, identifichiamo True con 1 e False con 0. Identifichiamo AND con * e XOR con +. Quindi OR è addizione saturante.
Tuttavia, potremmo altrettanto facilmente identifichiamo True con 0 e False con 1. Quindi identifichiamo OR con * e XNOR con +. Quindi AND sta saturando laddizione.
Commenti
- Se se avessi seguito il link su wikipedia avresti potuto scoprire che il concetto di algebra booleana è chiuso in relazione con quello di un campo di Galois di due elementi ( en.wikipedia.org/wiki / GF% 282% 29 ). I simboli 0 e 1 sono convenzionalmente usati per denotare le identità additiva e moltiplicativa, rispettivamente, perché i numeri reali sono anche un campo le cui identità sono i numeri 0 e 1.
- @NeilG Penso che Giorgio stia cercando di dire che ‘ è più di una semplice convenzione. 0 e 1 in algebra booleana sono sostanzialmente uguali a 0 e 1 in GF (2), che si comportano quasi come 0 e 1 in numeri reali per quanto riguarda laddizione e la moltiplicazione.
- @svick: No , perché puoi semplicemente rinominare la moltiplicazione e laggiunta di saturazione in OR e AND e quindi capovolgere le etichette in modo che 0 sia Vero e 1 sia Falso.Giorgio sta dicendo che era una convenzione della logica booleana, adottata come convenzione dellinformatica.
- @Neil G: No, non puoi capovolgere + e * e 0 e 1 perché un campo richiede distributività di moltiplicazione su addizione (vedi en.wikipedia.org/wiki/Field_%28mathematics%29 ), ma se imposti +: = AND e *: = XOR , ottieni T XOR (T AND F) = T XOR F = T, mentre (T XOR T) AND (T XOR F) = F AND T = F.Quindi capovolgendo le operazioni e le identità non hai un campo più. Quindi IMO definendo 0 e 1 come le identità di un campo appropriato sembra catturare il falso e il vero abbastanza fedelmente.
- @giorgio: ho modificato la risposta per rendere ovvio cosa sta succedendo.
Risposta
Stranamente, zero non è sempre falso.
In particolare, le convenzioni Unix e Posix è definire EXIT_SUCCESS
come 0 (e EXIT_FAILURE
come 1). In realtà è anche una convenzione C standard!
Quindi per le shell Posix e exit (2) syscalls, 0 significa “riuscito” che intuitivamente è più vero che falso.
In particolare, la shell “s if
vuole un process return EXIT_SUCCESS
(ovvero 0) per seguire il suo ramo “then”!
In Scheme (ma non in Common Lisp o in MELT ) 0 e nil (ovvero ()
nello schema) sono veri, poiché lunico valore falso è #f
Accetto, sto pignolo!
Risposta
C viene utilizzato per la programmazione di basso livello vicino allhardware, unarea in cui a volte è necessario passare da operazioni bit per bit a operazioni logiche, sugli stessi dati. La necessità di convertire unespressione numerica in booleana solo per eseguire un test sarebbe ingombrante il codice.
Puoi scrivere cose come:
if (modemctrl & MCTRL_CD) { /* carrier detect is on */ }
anziché
if ((modemctrl & MCTRL_CD) != 0) { /* carrier detect is on */ }
In un esempio isolato non è così male, ma doverlo fare diventerà fastidioso.
Allo stesso modo, le operazioni inverse. È utile per il risultato di unoperazione booleana, come un confronto, produrre solo uno 0 o 1: supponiamo di voler impostare il terzo bit di una parola in base al fatto che modemctrl
ha il bit di rilevamento della portante:
flags |= ((modemctrl & MCTRL_CD) != 0) << 2;
Qui dobbiamo avere il != 0
, per ridurre il risultato dellespressione &
biwise a 0
o 1
, ma poiché il risultato è solo un intero, ci viene risparmiato di dover aggiungere qualche fastidioso cast per convertire ulteriormente il booleano in intero.
Anche se il C moderno ora ha un bool
, conserva ancora la validità del codice come questo, sia perché “è una buona cosa, sia a causa della massiccia interruzione con la retrocompatibilità che sarebbe causata altrimenti.
Un altro esempio in cui C è perfetto: testare due condizioni booleane come un interruttore a quattro vie:
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; }
Non potresti toglierlo al programmatore C senza combattere!
Infine, C a volte serve come una sorta di linguaggio assembly di alto livello. Nei linguaggi assembly, inoltre, non abbiamo tipi booleani. Un valore booleano è solo un bit o uno zero rispetto a un valore diverso da zero in una posizione di memoria o in un registro. Un intero zero, uno zero booleano e un indirizzo zero vengono testati tutti allo stesso modo nei set di istruzioni in linguaggio assembly (e forse anche zero in virgola mobile). La somiglianza tra C e il linguaggio assembly è utile, ad esempio quando C viene utilizzato come lingua di destinazione per la compilazione di un altro linguaggio (anche uno con booleani fortemente tipizzati!)
Risposta
Un valore booleano o di verità ha solo 2 valori. Vero e falso.
Questi dovrebbero non essere rappresentati come numeri interi, ma come bit (0 e 1 ).
Dire che qualsiasi altro numero intero oltre a 0 o 1 non è falso è unaffermazione confusa. Le tabelle di verità trattano i valori di verità, non i numeri interi.
Da una prospettiva di valore di verità, -1 o 2 infrangerebbe tutte le tabelle di verità e qualsiasi logica booleana ad esse associata.
- 0 AND -1 ==?!
- 0 OR 2 ==?!
La maggior parte delle lingue di solito ha un boolean
tipo che quando viene convertito in un tipo di numero come intero rivela che false viene espresso come un valore intero di 0.
Commenti
- 0 AND -1 == qualunque valore booleano a cui li lanci. Questo è ‘ su cosa si tratta della mia domanda, perché trasmetterli a
TRUE
oFALSE
.Non ho mai detto – forse lho fatto, ma non era inteso – i numeri interi erano veri o falsi, ho chiesto perché valgono a seconda di quale quando vengono espressi come booleano.
Rispondi
In definitiva, stai parlando di rompere il linguaggio di base perché alcune API sono schifose. Le API scadenti non sono nuove e non puoi risolverle rompendo la lingua. È un fatto matematico che 0 è falso e 1 è vero, e qualsiasi linguaggio che non lo rispetti è fondamentalmente rotto. Il confronto a tre è di nicchia e non ha attività commerciali che il risultato venga convertito implicitamente in bool
poiché restituisce tre possibili risultati. Le vecchie API C hanno semplicemente una terribile gestione degli errori e sono anche ostacolate perché C non ha le caratteristiche del linguaggio necessarie per non avere interfacce terribili.
Si noti che non lo sto dicendo per i linguaggi che non hanno intero-> conversione booleana.
Commenti
- ” È un fatto matematico che 0 è falso e 1 è vero ” Ehm.
- Puoi citare un riferimento per il tuo ” fatto matematico che 0 è falso e 1 è vero “? La tua risposta suona pericolosamente come uno sproloquio.
- ‘ non è un fatto matematico, ma ‘ è stato una convenzione matematica sin dal XIX secolo.
- Lalgebra booleana è rappresentata da un campo finito in cui 0 e 1 sono gli elementi di identità per operazioni che assomigliano a addizione e moltiplicazione. Queste operazioni sono, rispettivamente, OR e AND. In effetti, lalgebra booleana è scritta in modo molto simile allalgebra normale, dove la giustapposizione indica AND e il simbolo
+
indica OR. Ad esempio,abc + a'b'c
significa(a and b and c) or (a and (not b) and (not c))
.
strcmp()
non è un buon esempio di vero o false, poiché restituisce 3 valori diversi. E sarai sorpreso quando inizierai a usare una shell, dove 0 significa vero e qualsiasi altra cosa significa falso.if true ; then ... ; fi
, dovetrue
è un comando che restituisce zero e questo indicaif
per eseguire...
.bool
ma i confronti / condizioni if ecc. Possono avere qualsiasi valore di ritorno.