Esta pregunta puede parecer tonta, pero ¿por qué 0
se evalúa como false
y cualquier otro valor [entero] para true
¿es la mayoría de lenguajes de programación?
Comparación de cadenas
Dado que la pregunta parece una un poco demasiado simple, me explicaré un poco más: en primer lugar, puede parecer evidente para cualquier programador, pero ¿por qué no habría un lenguaje de programación? Puede que en realidad lo haya, pero no uno que yo use, donde 0
se evalúa como true
y todos los demás valores [integer] como false
? Ese comentario puede parecer aleatorio, pero tengo algunos ejemplos en los que pudo haber sido una buena idea. En primer lugar, tomemos el ejemplo de la comparación de cadenas de tres vías, tomaré C «s strcmp
como ejemplo: cualquier programador que pruebe C como su primer idioma puede tener la tentación de escribir el siguiente código:
if (strcmp(str1, str2)) { // Do something... }
Dado que strcmp
devuelve 0
que se evalúa como false
cuando las cadenas son iguales, lo que el programador principiante intentó hacer falla estrepitosamente y generalmente no entiende por qué al principio. Si 0
se hubiera evaluado como true
en su lugar, esta función podría haberse utilizado en su expresión más simple, la anterior, al comparar la igualdad, y las comprobaciones adecuadas para -1
y 1
se habrían realizado solo cuando fuera necesario. Habríamos considerado el tipo de retorno como bool
(en nuestras mentes quiero decir) la mayor parte del tiempo.
Además, introduzcamos un nuevo tipo, sign
, que solo toma los valores -1
, 0
y 1
. Eso puede ser bastante útil. Imagina que hay un operador de nave espacial en C ++ y lo queremos para std::string
(bueno, ya existe la función compare
, pero el operador de nave espacial es más divertido). La declaración actualmente sería la siguiente:
sign operator<=>(const std::string& lhs, const std::string& rhs);
¿Se ha evaluado 0
a true
, el operador de la nave espacial «ni siquiera existiría, y podríamos haber declarado operator==
de esa manera:
sign operator==(const std::string& lhs, const std::string& rhs);
Este operator==
han manejado la comparación de tres vías a la vez, y aún podrían usarse para realizar la siguiente verificación y al mismo tiempo poder verificar qué cadena es lexicográficamente superior a la otra cuando sea necesario:
if (str1 == str2) { // Do something... }
Manejo de errores antiguos
Ahora tenemos excepciones, por lo que esta parte solo se aplica a los lenguajes antiguos donde no existe tal cosa existen (C por ejemplo). Si miramos la biblioteca estándar de C (y POSIX también), podemos ver con seguridad que muchas funciones devuelven 0
cuando tienen éxito y cualquier número entero en caso contrario. Lamentablemente, he visto a algunas personas haga este tipo de cosas:
#define TRUE 0 // ... if (some_function() == TRUE) { // Here, TRUE would mean success... // Do something }
Si pensamos en cómo pensamos en programación, a menudo tenemos el siguiente patrón de razonamiento:
Do something Did it work? Yes -> That"s ok, one case to handle No -> Why? Many cases to handle
Si pensamos en de nuevo, habría tenido sentido poner el único valor neutral, 0
, en yes
(y así es como C «s funciones funcionan), mientras que todos los demás valores pueden estar ahí para resolver los muchos casos de no
. Sin embargo, en todos los lenguajes de programación que conozco (excepto quizás algunos lenguajes esotéricos experimentales), que yes
se evalúa como false
en una if
condición, wh Todos los no
casos se evalúan como true
. Hay muchas situaciones en las que «funciona» representa un caso, mientras que «no funciona» representa muchas causas probables. Si lo pensamos de esa manera, tener 0
evaluar a true
y el resto a false
hubiera tenido mucho más sentido.
Conclusión
Mi conclusión es esencialmente mi pregunta original: ¿por qué diseñamos lenguajes donde 0
es false
y los otros valores son true
, teniendo en cuenta mis pocos ejemplos anteriores y tal vez algunos más en los que no pensé.
Seguimiento: Es bueno ver que hay muchas respuestas con muchas ideas y tantas razones posibles para que sea así. Me encanta lo apasionado que pareces ser al respecto.Originalmente hice esta pregunta por aburrimiento, pero como pareces tan apasionado, decidí ir un poco más lejos y preguntar sobre la razón detrás de la elección booleana de 0 y 1 en Math.SE 🙂
Comentarios
Respuesta
0
es false
porque ambos son cero elementos en semirrings comunes. Aunque son tipos de datos distintos, tiene sentido intuitivo convertir entre ellos porque pertenecen a estructuras algebraicas isomorfas.
-
0
es la identidad para la suma y el cero para la multiplicación. Esto es cierto para números enteros y racionales, pero no números de punto flotante IEEE-754:0.0 * NaN = NaN
y0.0 * Infinity = NaN
. -
false
es la identidad para booleano xor (⊻) y cero para booleano y (∧). Si los valores booleanos se representan como {0, 1}, el conjunto de números enteros módulo 2, puede pensar en ⊻ como una suma sin acarreo y en ∧ como una multiplicación. -
""
y[]
son identidades para la concatenación, pero hay varias operaciones para las que tienen sentido como cero. La repetición es una, pero la repetición y la concatenación no se distribuyen, por lo que estas operaciones no forman un semiring.
Tales conversiones implícitas son útiles en programas pequeños, pero en grandes puede hacer que los programas sean más difíciles de razonar. Solo una de las muchas compensaciones en el diseño de lenguajes.
Comentarios
- Es bueno que hayas mencionado listas. (Por cierto,
nil
es tanto la lista vacía[]
como el valorfalse
en Common Lisp ¿Existe una tendencia a fusionar identidades de diferentes tipos de datos?) Aún tiene que explicar por qué es natural considerar falso como una identidad aditiva y verdadero como una identidad multiplicativa y no al revés. ¿Es ‘ t posible considerartrue
como la identificación deAND
y cero paraOR
? - +1 para hacer referencia a identidades similares. Finalmente, una respuesta que no ‘ t simplemente se reduzca a la » convención, trata con ella «.
- +1 para dar detalles de una matemática concreta y muy antigua en la que esto se ha seguido y tiene sentido durante mucho tiempo
- Esta respuesta no ‘ t tiene sentido.
true
también es la identidad y el cero de semirings (booleanos y / o). No hay ninguna razón, aparte de la convención, para considerar quefalse
está más cerca de 0 quetrue
. - @TonioElGringo: La diferencia entre verdadero y falso es la diferencia entre XOR y XNOR. Se pueden formar anillos isomorfos usando AND / XOR, donde verdadero es la identidad multiplicativa y falso el aditivo, o con OR y XNOR, donde falso es la identidad multiplicativa y verdadero es el aditivo, pero XNOR no se suele considerar como un común. operación fundamental como lo es XOR.
Respuesta
Porque las matemáticas funcionan.
FALSE OR TRUE is TRUE, because 0 | 1 is 1. ... insert many other examples here.
Tradicionalmente, los programas C tienen condiciones como
if (someFunctionReturningANumber())
en lugar de
if (someFunctionReturningANumber() != 0)
porque el concepto de que cero es equivalente a falso es bien entendido.
Comentarios
- Los lenguajes están diseñados así porque las matemáticas tienen sentido. Eso fue primero.
- @Morwenn, se remonta al siglo XIX y George Boole. La gente ha estado representando False como 0 y True como! 0 durante más tiempo que las computadoras.
- No ‘ no veo por qué las matemáticas no ‘ No funciona al revés si simplemente cambia todas las definiciones para que AND sea + y OR sea *.
- Exactamente: las matemáticas funcionan en ambos sentidos y la respuesta a esta pregunta parece ser puramente convencional.
- @Robert Sería ‘ genial si pudiera deletrear el » fundamentos matemáticos » en su publicación.
Respuesta
Como han dicho otros, las matemáticas fueron lo primero. Por eso, 0 es false
y 1 es true
.
¿De qué matemáticas estamos hablando? Álgebras booleanas que datan de mediados del siglo XIX, mucho antes de que aparecieran las computadoras digitales.
También se podría decir que la convención surgió de la lógica proposicional , que es incluso más antigua que las álgebras booleanas. Esta es la formalización de muchos de los resultados lógicos que los programadores conocen y aman (false || x
es igual a x
, true && x
es igual a x
y así sucesivamente).
Básicamente, estamos hablando de aritmética en un conjunto con dos elementos. Piense en contar en binario. Las álgebras booleanas son el origen de este concepto y su base teórica. Las convenciones de lenguajes como C son solo una aplicación sencilla.
Comentarios
- Podrías , seguro. Pero mantenerlo en la forma » estándar » encaja bien con la aritmética general (0 + 1 = 1, no 0 + 1 = 0).
- Sí, pero presumiblemente escribiría AND con + y OR con * si también invirtiera las definiciones.
- Las matemáticas no ‘ t viene primero. Las matemáticas reconocieron que 0 y 1 forman un campo, en el que Y es como multiplicación y OR es como suma.
- @ Kaz: Pero {0, 1} con OR y AND no forman un campo.
- Me molesta un poco que más respuestas y comentarios digan que
true = 1
. Eso ‘ no es del todo exacto, porquetrue != 0
que no es exactamente lo mismo. Una razón (no la única) por la que se deben evitar comparaciones comoif(something == true) { ... }
.
Respuesta
Pensé que esto tenía que ver con la «herencia» de la electrónica, y también con el álgebra booleana, donde
-
0
=off
,negative
,no
,false
-
1
=on
,positive
,yes
,true
strcmp devuelve 0 cuando las cadenas son iguales tiene que ver con su implementación, ya que lo que realmente hace es calcular la «distancia» entre las dos cadenas. Que 0 también se considere falso es solo una coincidencia.
devolver 0 en caso de éxito tiene sentido porque 0 en este caso se usa para significar sin error y cualquier otro número sería un código de error. Usar cualquier otro número para el éxito tendría menos sentido ya que solo tiene un único código de éxito, mientras que puede tener varios códigos de error. Utiliza «¿Funcionó?» ya que la expresión de la instrucción if y decir 0 = sí tendría más sentido, pero la expresión es más correcta «¿Algo salió mal?» y luego ves que 0 = no tiene mucho sentido. Pensar en false/true
no tiene mucho sentido aquí, ya que en realidad es no error code/error code
.
Comentarios
- Jaja, eres el primero en declarar explícitamente la pregunta de retorno de error. Ya sabía que lo interpreté a mi manera y podría preguntarlo al revés, pero tú ‘ eres el primero en expresarlo explícitamente (de las muchas respuestas y comentarios).En realidad, yo no ‘ t diría que una u otra forma no tiene sentido, sino que ambas tienen sentido de diferentes formas 🙂
- En realidad, yo ‘ d say
0
parasuccess/no error
es lo único que tiene sentido cuando otros números enteros representan códigos de error . Que0
también representefalse
en otros casos no ‘ realmente importa, ya que no estamos ‘ t hablando de verdadero o falso aquí;) - Tuve la misma idea, así que subí
- Tu punto sobre
strcmp()
calcular la distancia es bastante bueno. Si se hubiera llamadostrdiff()
,if (!strdiff())
sería muy lógico. - » electrónica […] donde 0 = […] falso, 1 = […] verdadero » – incluso en electrónica, esto es solo un convención , y no es ‘ t el único. A esto lo llamamos lógica positiva, pero también puede usar lógica negativa, donde un voltaje positivo indica falso y negativo indica verdadero. Luego, el circuito que ‘ usaría para AND se convierte en OR, OR se convierte en AND, y así sucesivamente. Debido a la ley de De Morgan ‘, todo termina siendo equivalente. A veces, ‘ encontrará parte de un circuito electrónico implementado en lógica negativa por conveniencia, momento en el que los nombres de las señales en esa parte se indican con una barra encima de ellos.
Responder
Como se explica en este artículo , los valores false
y true
no deben confundirse con los enteros 0 y 1, pero pueden identificarse con los elementos del campo de Galois (campo finito) de dos elementos (ver aquí ).
Un campo es un conjunto con dos operaciones que satisfacen ciertos axiomas.
Los símbolos 0 y 1 se usan convencionalmente para denotar las identidades aditivas y multiplicativas de un campo porque los números reales también son un campo (pero no finito) cuyas identidades son los números 0 y 1.
La identidad aditiva es el elemento 0 del campo, de modo que para todo x:
x + 0 = 0 + x = x
y la identidad multiplicativa es el elemento 1 del campo, de modo que para todo x:
x * 1 = 1 * x = x
El campo finito de dos elementos tiene solo estos dos elementos, a saber, el identidad aditiva 0 (o false
) y la identidad multiplicativa 1 (o true
). Las dos operaciones de este campo son el XOR lógico (+) y el Y lógico (*).
Nota. Si invierte las operaciones (XOR es la multiplicación y Y es la suma) entonces la multiplicación no es distributiva sobre la suma y ya no tiene un campo. En tal caso, no tiene ninguna razón para llamar a los dos elementos 0 y 1 (en cualquier orden). Tenga en cuenta también que no puede elegir la operación O en lugar de XOR: no importa cómo interprete O / Y como suma / multiplicación, la estructura resultante no es un campo (no todos los elementos inversos existen como lo requieren los axiomas del campo).
Con respecto a las funciones C:
- Muchas funciones devuelven un número entero que es un código de error. 0 significa SIN ERROR.
- Intuitivamente, la función
strcmp
calcula la diferencia entre dos cadenas. 0 significa que no hay diferencia entre dos cadenas, es decir, que dos cadenas son iguales.
Las explicaciones intuitivas anteriores pueden ayudar a recordar la interpretación de los valores devueltos, pero es aún más fácil solo revisa la documentación de la biblioteca.
Comentarios
- +1 para mostrar que si los intercambias arbitrariamente, las matemáticas ya no funcionan.
- Volteado: Dado un campo con dos elementos y operaciones * y +, identificamos Verdadero con 0 y Falso con 1. Identificamos OR con * y XOR con +.
- Encontrará que ambos de estas identificaciones se realizan sobre el mismo campo y ambas son consistentes con las reglas de la lógica booleana. Desafortunadamente, su nota es incorrecta 🙂
- Si asume que True = 0, y XOR es +, entonces True debe ser la identidad de XOR. Pero no es porque True XOR True = False. A menos que redefina la operación XOR en True para que True XOR True = True. Entonces, por supuesto, su construcción funciona porque acaba de cambiar el nombre de las cosas (en cualquier estructura matemática siempre puede hacer una permutación de nombre y obtener una estructura isomórfica). Por otro lado, si deja que Verdadero, Falso y XOR tengan su significado habitual, entonces Verdadero XOR Verdadero = Falso y Verdadero no pueden ser la identidad aditiva, es decir, Verdadero no puede ser 0.
- @Giorgio: Corregí mi construcción según su comentario en mi último comentario …
Responder
Debe tener en cuenta que los sistemas alternativos también pueden ser decisiones de diseño aceptables.
Shells: el estado de salida 0 es verdadero, distinto de cero es falso
El ejemplo de shells que tratan un 0 El estado de salida como verdadero ya se ha mencionado.
$ ( 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 razón es que hay una forma de tener éxito, pero muchas formas de fallar, por lo que usar 0 como valor especial que significa «sin errores» es pragmático.
Ruby: 0 es como cualquier otro número
Entre los lenguajes de programación «normales», hay algunos valores atípicos, como Ruby, que tratan 0 como un valor verdadero.
$ irb irb(main):001:0> 0 ? "0 is true" : "0 is false" => "0 is true"
El el fundamento es que solo false
y nil
deben ser falsos. Para muchos principiantes de Ruby, es un problema. Sin embargo, en algunos casos, es bueno que el 0 se trate como cualquier otro número.
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"
Sin embargo , dicho sistema solo funciona en un lenguaje que pueda distinguir los booleanos como un tipo separado de los números. En los primeros días de la informática, los programadores que trabajaban con lenguaje ensamblador o lenguaje de máquina en bruto no tenían esos lujos. Probablemente sea natural tratar 0 como el estado «en blanco» y establecer un bit en 1 como una bandera cuando el código detecta que algo sucedió. Por extensión, la convención desarrolló que el cero se trataba como falso y los valores distintos de cero se trataban como verdaderos. Sin embargo, no tiene por qué ser así.
Java: los números no se pueden tratar como booleanos en absoluto
En Java, true
y false
son los únicos valores booleanos. Los números no son booleanos y ni siquiera se pueden convertir en booleanos ( Java Language Specification, Sec 4.2.2 ):
No hay conversiones entre los tipos integrales y el tipo
boolean
.
Esa regla simplemente evita la pregunta por completo: todas las expresiones booleanas deben escribirse explícitamente en el código.
Comentarios
- Rebol y Red tratan los valores INTEGER! con valor 0 como verdaderos y tienen un tipo NONE! separado (con un solo valor, NINGUNO) tratado como condicional falso además de LOGIC! false. ‘ he encontrado una frustración significativa al intentar escribir código JavaScript que trata 0 como falso; es un incr decisión comestiblemente torpe para un lenguaje escrito dinámicamente. Si quieres probar algo que puede ser nulo o 0, terminas teniendo que escribir
if (thing === 0)
, eso no está bien. - @HostileFork I don ‘ No lo sé. Creo que tiene sentido que
0
seatrue
(como cualquier otro número entero) en un lenguaje dinámico. A veces me pasaba a coger un0
al intentar capturarNone
en Python, y eso a veces puede ser bastante difícil de detectar. - Ruby no es un valor atípico. Ruby toma esto de Lisp (Ruby incluso se llama secretamente » MatzLisp «). Lisp es un lenguaje corriente en informática. Cero también es solo un valor real en el shell POSIX, porque ‘ es un fragmento de texto:
if [ 0 ] ; then echo this executes ; fi
. El valor de datos falsos es una cadena vacía, y una falsedad comprobable es un estado de terminación fallida de un comando, que está representado por un distinto de -zero.
Respuesta
Antes de abordar el caso general, podemos discutir sus contraejemplos.
Comparaciones de cadenas
En realidad, lo mismo se aplica a muchos tipos de comparaciones. Estas comparaciones calculan una distancia entre dos objetos. Cuando los objetos son iguales, la distancia es mínima. Entonces, cuando la «comparación se realiza correctamente», el valor es 0. Pero, en realidad, el valor de retorno de strcmp
es no un valor booleano, es una distancia y que lo que atrapa a los programadores desprevenidos haciendo if (strcmp(...)) do_when_equal() else do_when_not_equal()
.
En C ++ podríamos rediseñar strcmp
para devolver un Distance
objeto, que anula operator bool()
para devolver verdadero cuando 0 (pero luego sería mordido por un conjunto diferente de problemas). O en C simple, simplemente tenga una función streq
que devuelva 1 cuando las cadenas son iguales y 0 en caso contrario.
Llamadas a la API / código de salida del programa
Aquí le interesa la razón por la que algo salió mal, porque esto provocará que las decisiones se vuelvan erróneas. Cuando las cosas tienen éxito, no desea saber nada en particular, su intención se realiza. Por lo tanto, el valor de retorno debe transmitir esta información. no es un booleano, es un código de error. El valor de error especial 0 significa «sin error». El resto del rango representa errores localmente significativos con los que tiene que lidiar (incluido 1, que a menudo significa «error no especificado»).
Caso general
Esto nos deja con la pregunta: ¿por qué los valores booleanos son True
y False
comúnmente representado con 1 y 0, respectivamente?
Bueno, además del argumento subjetivo «se siente mejor de esta manera», aquí hay algunas razones (subjetivas también) que puedo pensar:
-
analogía del circuito eléctrico. La corriente está activada durante 1 s y desactivada durante 0 s. Me gusta tener (1, Sí, Verdadero, Activado) juntos y (0, No, Falso, Desactivado), en lugar de otra combinación
-
inicializaciones de memoria. Cuando
memset(0)
un montón de variables (ya sean ints, floats, bools) quiero que su valor coincida con las suposiciones más conservadoras. P.ej. mi suma es inicialmente 0, el predicado es Falso, etc.
Quizás todas estas razones estén ligadas a mi educación, si me hubieran enseñado a asociar 0 con Verdadero de la Al principio, iría al revés.
Comentarios
- En realidad, hay al menos un lenguaje de programación que trata el 0 como verdadero. El shell de Unix.
- +1 para abordar el problema real: La mayor parte de la ‘ pregunta de Morwenn no es ‘ t sobre
bool
en absoluto. - @ dan04 Lo es. Toda la publicación trata sobre el fundamento de la elección del elenco de
int
abool
en muchos lenguajes de programación. Las cosas de comparación y gestión de errores son solo ejemplos de lugares en los que lanzarlo de una manera diferente a la que ‘ está haciendo actualmente tendría sentido.
Respuesta
Desde una perspectiva de alto nivel, estás hablando de tres tipos de datos bastante diferentes:
-
Un booleano. La convención matemática en álgebra booleana es usar 0 para
false
y 1 paratrue
, por lo que tiene sentido seguir esa convención. Creo que de esta manera también tiene más sentido intuitivamente. -
El resultado de la comparación. Esto tiene tres valores:
<
,=
y>
(observe que ninguno de ellos estrue
). Para ellos tiene sentido usar los valores de -1, 0 y 1, respectivamente (o, más generalmente, un valor negativo, cero y un valor positivo).Si desea verificar la igualdad, Si solo tiene una función que realiza una comparación general, creo que debería hacerlo explícito usando algo como
strcmp(str1, str2) == 0
. Me parece confuso el uso de!
en esta situación, porque trata un valor no booleano como si fuera un booleano.Además, tenga en cuenta que la comparación y la igualdad no tiene que ser lo mismo. Por ejemplo, si ordena a las personas por su fecha de nacimiento,
Compare(me, myTwin)
debe devolver0
, peroEquals(me, myTwin)
debería devolverfalse
. -
El éxito o el fracaso de una función , posiblemente también con detalles sobre el éxito o el fracaso. Si está hablando de Windows, este tipo se llama
HRESULT
y un valor distinto de cero no necesariamente indica un error. De hecho, un valor negativo indica un error y un éxito no negativo. El valor de éxito suele serS_OK = 0
, pero también puede ser, por ejemplo,S_FALSE = 1
, u otros valores.
La confusión proviene del hecho que tres lógicamente tipos de datos bastante diferentes se representan en realidad como un solo tipo de datos (un número entero) en C y algunos otros lenguajes y que puede usar un número entero en una condición. Pero no creo que tenga sentido redefinir booleanos para simplificar el uso de algunos tipos no booleanos en condiciones.
Además, considere otro tipo que se usa a menudo en una condición en C: un puntero . Allí, es natural tratar un NULL
-punta (que se representa como 0
) como false
. Por lo tanto, seguir tu sugerencia también dificultaría más el trabajo con punteros (aunque, personalmente, prefiero comparar explícitamente punteros con NULL
, en lugar de tratarlos como booleanos).
Respuesta
Cero puede ser falso porque la mayoría de las CPU tienen un indicador CERO que se puede usar para bifurcar. Guarda una operación de comparación.
Veamos por qué.
Algunos psuedocode, ya que la audiencia probablemente no lee el ensamblaje
c- source simple loop llama a wibble 10 veces
for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */ { wibble(); }
algunos pretenden ensamblar para eso
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- fuente otro simple bucle llama a wibble 10 veces
for (int foo =0; foo<10; foo-- ) /* up count loop is longer */ { wibble(); }
algo de montaje simulado para este 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
más fuente de c
int foo=10; if ( foo ) wibble()
y el ensamblaje
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
¿Ves lo corto que es?
algo más de fuente c
int foo=10; if ( foo==0 ) wibble()
y el ensamblaje (supongamos un compilador marginalmente inteligente que puede reemplazar == 0 sin comparar )
0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007
Ahora intentemos una convención de true = 1
c fuente más #define TRUE 1 int foo = TRUE; if (foo == VERDADERO) wibble ()
y el ensamblaje
0x1000 ld a 0x1 0x1002 cmp a 0x01 0x1004 jz 0x3 0x1006 call 0x1234 0x1009
¿Ves qué tan corto es el caso con true distinto de cero?
Realmente Las primeras CPU tenían pequeños conjuntos de indicadores adjuntos al acumulador.
Para verificar si a> bo a = b generalmente toma una instrucción de comparación.
- A menos que B sea ya sea CERO – en cuyo caso la bandera CERO se establece Implementado como un NOR lógico simple o todos los bits en el Acumulador.
- O NEGATIVO en el cual simplemente use el «bit de signo», es decir, el bit más significativo del Acumulador si está utilizando aritmética en complemento a dos. (Principalmente lo hacemos)
Vamos a reafirmar esto. En algunas CPU más antiguas, no tenía que usar una instrucción de comparación para un acumulador igual a CERO o un acumulador menor que cero.
¿Ahora ve por qué el cero podría ser falso?
Tenga en cuenta que este es un código psuedo y ningún conjunto de instrucciones real se parece a esto. Si conoce el ensamblaje, sabe que estoy simplificando mucho las cosas aquí. Si sabe algo sobre diseño de compiladores, no necesita leer esta respuesta. Cualquiera que sepa algo sobre desenrollado de bucles o predicción de ramas, la clase avanzada está al final del pasillo en la habitación 203.
Comentarios
- Su punto no está bien expresado aquí porque, en primer lugar,
if (foo)
yif (foo != 0)
debería generar el mismo código y, en segundo lugar, ‘ estás mostrando que el lenguaje ensamblador que ‘ estás usando de hecho tiene operandos booleanos y pruebas para ellos. Por ejemplo,jz
significajump if zero
. En otras palabras,if (a == 0) goto target;
. Y la cantidad ni siquiera se está probando directamente; la condición se convierte en una bandera booleana que se almacena en una palabra de máquina especial. Es ‘ en realidad más comocpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
- No Kaz, la CPU anterior ‘ s no funcionaba así. T El jz / jnz se puede ejecutar sin hacer una instrucción de comparación. Ese fue el punto de toda mi publicación.
- No ‘ no escribí nada sobre una instrucción de comparación.
- ¿Puedes citar un procesador que tiene una instrucción
jz
pero nojnz
? (o cualquier otro conjunto asimétrico de instrucciones condicionales)
Respuesta
Hay muchas respuestas que sugieren que la correspondencia entre 1 y verdadero es necesaria por alguna propiedad matemática. No puedo encontrar ninguna propiedad de este tipo y sugerir que es una convención puramente histórica.
Dado un campo con dos elementos, tenemos dos operaciones: suma y multiplicación. Podemos mapear operaciones booleanas en este campo de dos maneras :
Tradicionalmente, identificamos Verdadero con 1 y Falso con 0. Identificamos Y con * y XOR con +. Por lo tanto, OR es una adición saturante.
Sin embargo, podríamos con la misma facilidad identificamos Verdadero con 0 y Falso con 1. Luego identificamos OR con * y XNOR con +. Por lo tanto, Y es una adición saturante.
Comentarios
- Si si hubiera seguido el enlace en wikipedia, podría haber encontrado que el concepto de álgebra booleana está relacionado con el de un campo de Galois de dos elementos ( en.wikipedia.org/wiki / GF% 282% 29 ). Los símbolos 0 y 1 se utilizan convencionalmente para denotar las identidades aditiva y multiplicativa, respectivamente, porque los números reales también son un campo cuyas identidades son los números 0 y 1.
- @NeilG Creo que Giorgio está intentando decirlo ‘ s más que una simple convención. 0 y 1 en álgebra booleana son básicamente lo mismo que 0 y 1 en GF (2), que se comportan casi igual que 0 y 1 en números reales con respecto a la suma y la multiplicación.
- @svick: No , porque simplemente puede cambiar el nombre de la multiplicación y la adición de saturación para que sean O y Y y luego voltear las etiquetas para que 0 sea Verdadero y 1 sea Falso.Giorgio está diciendo que era una convención de lógica booleana, que fue adoptada como una convención de la informática.
- @Neil G: No, no se puede cambiar + y * y 0 y 1 porque un campo requiere distributividad de multiplicación sobre suma (consulte en.wikipedia.org/wiki/Field_%28mathematics%29 ), pero si establece +: = AND y *: = XOR , obtienes T XOR (T AND F) = T XOR F = T, mientras que (T XOR T) AND (T XOR F) = F AND T = F. Por lo tanto, al cambiar las operaciones y las identidades no tienes un campo nunca más. Entonces, en mi opinión, definir 0 y 1 como las identidades de un campo apropiado parece capturar lo falso y lo verdadero con bastante fidelidad.
- @giorgio: He editado la respuesta para que sea obvio lo que está sucediendo.
Respuesta
Curiosamente, el cero no siempre es falso.
En particular, la convención de Unix y Posix es definir EXIT_SUCCESS
como 0 (y EXIT_FAILURE
como 1). En realidad, es incluso una convención C estándar.
Así que para los shells Posix y salir (2) syscalls, 0 significa «exitoso», que intuitivamente es más verdadero que falso.
En particular, el shell «s if
quiere un el proceso devuelve EXIT_SUCCESS
(que es 0) para seguir su rama «luego»!
En Scheme (pero no en Common Lisp o en MELT ) 0 y nil (es decir, ()
en Scheme) son verdaderas, ya que el único valor falso es #f
¡Estoy de acuerdo, soy quisquilloso!
Responder
C se utiliza para la programación de bajo nivel cerca del hardware, un área en la que a veces es necesario cambiar entre operaciones lógicas y bit a bit, en los mismos datos. Ser necesario convertir una expresión numérica a booleana solo para realizar una prueba sería desordenado el código.
Puede escribir cosas como:
if (modemctrl & MCTRL_CD) { /* carrier detect is on */ }
en lugar de
if ((modemctrl & MCTRL_CD) != 0) { /* carrier detect is on */ }
En un ejemplo aislado no es tan malo, pero tener que hacer eso se volverá molesto.
Del mismo modo, las operaciones inversas. Es útil para el resultado de una operación booleana, como una comparación, producir un 0 o un 1: supongamos que queremos establecer el tercer bit de una palabra en función de si modemctrl
tiene el bit de detección de portadora:
flags |= ((modemctrl & MCTRL_CD) != 0) << 2;
Aquí tenemos que tener el != 0
, para reducir el resultado de la expresión &
biwise a 0
o 1
, pero debido a que el resultado es solo un número entero, nos ahorramos tener que agregar algunas conversiones molestas para convertir booleano en entero.
Aunque el C moderno ahora tiene un bool
tipo, aún conserva la validez de código como este, tanto porque «es algo bueno, como por la rotura masiva de compatibilidad con versiones anteriores que se causaría de otra manera.
Otro ejemplo en el que C es hábil: probar dos condiciones booleanas como un interruptor de cuatro direcciones:
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; }
¡No podrías quitarle esto al programador de C sin luchar!
Por último, C a veces sirve como una especie de lenguaje ensamblador de alto nivel. En los lenguajes ensambladores, tampoco tenemos tipos booleanos. Un valor booleano es solo un bit o un valor cero versus un valor distinto de cero en una ubicación de memoria o registro. Un cero entero, un cero booleano y la dirección cero se prueban de la misma manera en conjuntos de instrucciones en lenguaje ensamblador (y quizás incluso en coma flotante cero). La semejanza entre C y el lenguaje ensamblador es útil, por ejemplo, cuando se usa C como el lenguaje de destino para compilar otro lenguaje (¡incluso uno que tenga booleanos fuertemente tipados!)
Respuesta
Un valor booleano o verdadero solo tiene 2 valores. Verdadero y falso.
Estos deben no representarse como enteros, sino como bits (0 y 1 ).
Decir que cualquier otro entero además de 0 o 1 no es falso es una afirmación confusa. Las tablas de verdad tratan con valores de verdad, no con números enteros.
De un valor de verdad prospectivo, -1 o 2 rompería todas las tablas de verdad y cualquier lógica booleana asociada con ellas.
- 0 Y -1 ==?!
- 0 O 2 ==?!
La mayoría de los idiomas suelen tener un boolean
tipo que cuando se envía a un tipo de número, como entero, revela falso para ser lanzado como un valor entero de 0.
Comentarios
- 0 AND -1 == cualquier valor booleano al que los envíe. De eso ‘ trata mi pregunta, por qué enviarlos a
TRUE
oFALSE
Nunca dije, tal vez lo hice, pero no era mi intención, los números enteros eran verdaderos o falsos, pregunté por qué se evalúan a cualquiera cuando se convierten en booleanos.
Respuesta
En última instancia, estás hablando de romper el lenguaje principal porque algunas API son malas. Las API de mierda no son nuevas y no se pueden arreglar rompiendo el lenguaje. Es un hecho matemático que 0 es falso y 1 es verdadero, y cualquier lenguaje que no respete esto está fundamentalmente roto. La comparación de tres vías es nicho y no tiene por qué hacer que su resultado se convierta implícitamente a bool
ya que devuelve tres resultados posibles. Las antiguas API de C simplemente tienen un manejo de errores terrible, y también están paralizadas porque C no tiene las características de lenguaje necesarias para no tener interfaces terribles.
Tenga en cuenta que no estoy diciendo eso para los lenguajes que no tienen integer-> conversión booleana.
Comentarios
- » Es un hecho matemático que 0 es falso y 1 es verdadero » Erm.
- ¿Puede citar una referencia para su » hecho matemático de que 0 es falso y 1 es verdadero «? Tu respuesta suena peligrosamente como una perorata.
- No es ‘ un hecho matemático, pero ‘ ha sido una convención matemática desde el siglo 19.
- El álgebra booleana está representada por un campo finito en el que 0 y 1 son los elementos de identidad para operaciones que se asemejan a la suma y la multiplicación. Esas operaciones son, respectivamente, OR y AND. De hecho, el álgebra booleana se escribe de manera muy similar al álgebra normal, donde la yuxtaposición denota Y, y el símbolo
+
denota OR. Entonces, por ejemplo,abc + a'b'c
significa(a and b and c) or (a and (not b) and (not c))
.
strcmp()
no es un buen ejemplo de verdadero o falso, ya que devuelve 3 valores diferentes. Y se sorprenderá cuando comience a usar un shell, donde 0 significa verdadero y cualquier otra cosa significa falso.if true ; then ... ; fi
, dondetrue
es un comando que devuelve cero y esto le dice aif
para ejecutar...
.bool
pero las comparaciones / condiciones, etc. pueden tener algún valor de retorno.