Perché 0 è falso?

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:

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

  • 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.
  • @ ott–: Nelle shell Unix, 0 significa successo e non -zero significa errore – non esattamente la stessa cosa di ” true ” e ” false “.
  • @KeithThompson: In Bash (e altre shell), ” success ” e ” fallimento ” sono davvero gli stessi di ” true ” e ” false “. Considera, ad esempio, listruzione if true ; then ... ; fi, dove true è un comando che restituisce zero e questo indica if per eseguire ....
  • Non ci sono booleani nellhardware, solo numeri binari e nella maggior parte degli ISA storici viene considerato un numero diverso da zero come ” true ” in tutte le istruzioni di diramazione condizionale (a meno che ‘ non stia utilizzando i flag anziché). Quindi, i linguaggi di basso livello sono assolutamente obbligati a seguire le proprietà hardware sottostanti.
  • @MasonWheeler Avere un tipo booleano non ‘ implica nulla. Ad esempio, python ha un tipo bool ma i confronti / condizioni if ecc. Possono avere qualsiasi valore di ritorno.

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 e 0.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 valore false 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 considerare true come lidentificativo di AND e zero per OR?
  • +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 considerare false è più vicino a 0 di true.
  • @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 come if(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 per success/no error è lunica cosa che ha senso quando altri numeri interi rappresentano codici di errore . Questo 0 rappresenta anche false 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 chiamato strdiff(), 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 sia true (come ogni altro numero intero) in un linguaggio dinamico. A volte mi è capitato di rilevare un 0 quando cercavo di catturare None 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 a bool 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:

  1. Un booleano. La convenzione matematica in algebra booleana è di utilizzare 0 per false e 1 per true, quindi ha senso seguire questa convenzione. Penso che in questo modo abbia anche più senso intuitivamente.

  2. 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 restituire 0 , ma Equals(me, myTwin) dovrebbe restituire false.

  3. 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 spesso S_OK = 0, ma può anche essere ad esempio S_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) e if (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 esempio jz significa jump if zero. In altre parole if (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 a cpu.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 di jnz? (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:

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 o FALSE.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)).

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *