Por que 0 é falso?

Esta pergunta pode parecer idiota, mas por que 0 avalia como false e qualquer outro valor [inteiro] para true é a maioria das linguagens de programação?

Comparação de strings

Já que a pergunta parece uma um pouco simples demais, vou me explicar um pouco mais: em primeiro lugar, pode parecer evidente para qualquer programador, mas por que não haveria uma linguagem de programação – pode realmente haver, mas não qualquer que eu usei – onde 0 avalia como true e todos os outros valores [integer] como false? Essa observação pode parecer aleatório, mas eu tenho alguns exemplos em que pode ter sido uma boa ideia. Em primeiro lugar, vejamos o exemplo da comparação de strings de três vias, pegarei C “s strcmp como exemplo: qualquer programador tentando C como sua primeira linguagem pode ser tentado a escrever o seguinte código:

Já que strcmp retorna 0 que avalia como false quando as strings são iguais, o que o programador iniciante tentou fazer falha terrivelmente e ele geralmente não entende o porquê no início. Se 0 tivesse sido avaliada para true em vez disso, esta função poderia ter sido usada em sua expressão mais simples – a acima – ao comparar a igualdade, e as verificações adequadas para -1 e 1 teriam sido feitas somente quando necessário. Teríamos considerado o tipo de retorno como bool (em nossas mentes, quero dizer) na maioria das vezes.

Além disso, vamos apresentar um novo tipo, sign, que assume apenas valores -1, 0 e 1. Isso pode ser muito útil. Imagine que exista um operador de espaçonave em C ++ e o queremos para std::string (bem, já existe a função compare, mas o operador de nave é mais divertido). A declaração atualmente seria a seguinte:

 sign operator<=>(const std::string& lhs, const std::string& rhs);  

Tinha 0 avaliado para true, o operador da nave espacial nem existiria, e poderíamos ter declarado operator== dessa forma:

 sign operator==(const std::string& lhs, const std::string& rhs);  

Isso operator== iria trataram de comparação de três vias de uma vez, e ainda podem ser usados para realizar a seguinte verificação enquanto ainda podem verificar qual string é lexicograficamente superior à outra quando necessário:

 if (str1 == str2) { // Do something... }  

Tratamento de erros antigos

Agora temos exceções, então esta parte se aplica apenas às linguagens antigas onde não existe tal coisa existem (C por exemplo). Se olharmos para a biblioteca padrão do C (e POSIX também), podemos ver com certeza que as funções maaaaany retornam 0 quando bem-sucedidas e qualquer inteiro caso contrário. Infelizmente, vi algumas pessoas faça este tipo de coisas:

 #define TRUE 0 // ... if (some_function() == TRUE) { // Here, TRUE would mean success... // Do something }  

Se pensarmos em como pensamos em programação, geralmente temos o seguinte padrão de raciocínio:

 Do something Did it work? Yes -> That"s ok, one case to handle No -> Why? Many cases to handle  

Se pensarmos sobre novamente, faria sentido colocar o único valor neutro, 0, em yes (e é assim que C “s funcionam), enquanto todos os outros valores podem estar lá para resolver os muitos casos de no. No entanto, em todas as linguagens de programação que conheço (exceto talvez algumas linguagens esotéricas experimentais), que yes avalia para false em uma if condição, wh ile todos os no casos avaliados como true. Existem muitas situações em que “funciona” representa um caso, enquanto “não funciona” representa muitas causas prováveis. Se pensarmos dessa forma, 0 avalie para true e o resto para false faria muito mais sentido.

Conclusão

Minha conclusão é essencialmente minha pergunta original: por que criamos linguagens onde 0 é false e os outros valores são true, levando em consideração meus poucos exemplos acima e talvez mais alguns nos quais não pensei?

Acompanhamento: É bom ver que há muitas respostas com muitas ideias e tantos motivos possíveis para que seja assim. Eu amo o quão apaixonado você parece ser sobre isso.Originalmente, fiz essa pergunta por tédio, mas como você parece tão apaixonado, decidi ir um pouco mais além e perguntar sobre o fundamento lógico por trás da escolha booleana de 0 e 1 em Math.SE 🙂

Comentários

  • strcmp() não é um bom exemplo de verdadeiro ou falso, pois retorna 3 valores diferentes. E você ficará surpreso quando começar a usar um shell, onde 0 significa verdadeiro e qualquer outra coisa significa falso.
  • @ ott–: Em shells Unix, 0 significa sucesso e não -zero significa falha – não exatamente a mesma coisa que ” true ” e ” false “.
  • @KeithThompson: No Bash (e outros shells), ” sucesso ” e ” falha ” realmente são iguais a ” true ” e ” false “. Considere, por exemplo, a instrução if true ; then ... ; fi, onde true é um comando que retorna zero e informa if para executar ....
  • Não há booleanos em hardware, apenas números binários, e na maioria dos ISAs históricos um número diferente de zero é considerado como ” true ” em todas as instruções de ramificação condicional (a menos que ‘ estejam usando sinalizadores em vez de). Portanto, as linguagens de baixo nível são obrigadas a seguir as propriedades de hardware subjacentes.
  • @MasonWheeler Ter um tipo booleano não ‘ não implica em nada. Por exemplo, python não tem um bool tipo, mas comparações / se as condições etc. podem ter qualquer valor de retorno.

Resposta

0 é false porque são ambos zero elementos em semirings comuns. Embora sejam tipos de dados distintos, faz sentido intuitivamente converter entre eles porque pertencem a estruturas algébricas isomórficas.

  • 0 é a identidade para adição e zero para multiplicação. Isso é verdadeiro para inteiros e racionais, mas não números de ponto flutuante IEEE-754: 0.0 * NaN = NaN e 0.0 * Infinity = NaN .

  • false é a identidade do booleano xor (⊻) e zero do booleano e (∧). Se os booleanos forem representados como {0, 1} —o conjunto de inteiros módulo 2 — você pode pensar em ⊻ como adição sem transporte e ∧ como multiplicação.

  • "" e [] são identidade para concatenação, mas existem várias operações para as quais fazem sentido como zero. A repetição é uma, mas a repetição e a concatenação não se distribuem, então essas operações não formam uma semirreção.

Essas conversões implícitas são úteis em programas pequenos, mas em grandes pode dificultar o raciocínio dos programas. Apenas uma das muitas desvantagens no design de linguagem.

Comentários

  • Bom que você mencionou listas. (A propósito, nil é a lista vazia [] e o valor false em Common Lisp ; existe uma tendência de mesclar identidades de diferentes tipos de dados?) Você ainda precisa explicar por que é natural considerar falso como uma identidade aditiva e verdadeiro como uma identidade multiplicativa e não o contrário. Não é ‘ possível considerar true como a identificação para AND e zero para OR?
  • +1 para se referir a identidades semelhantes. Finalmente, uma resposta que ‘ não se resume a ” convenção, trata disso “.
  • +1 para dar detalhes de uma matemática concreta e muito antiga na qual isso foi seguido e há muito fazia sentido
  • Esta resposta não ‘ t faz sentido. true também é a identidade e o zero dos semirings (booleano e / ou). Não há razão, convenção appart, para considerar que false está mais próximo de 0 do que true.
  • @TonioElGringo: A diferença entre verdadeiro e falso é a diferença entre XOR e XNOR. Pode-se formar anéis isomórficos usando AND / XOR, onde verdadeiro é a identidade multiplicativa e falso o aditivo, ou com OR e XNOR, onde falso é a identidade multiplicativa e verdadeiro é o aditivo, mas XNOR não é geralmente considerado como um comum operação fundamental da maneira que XOR é.

Resposta

Porque a matemática funciona.

FALSE OR TRUE is TRUE, because 0 | 1 is 1. ... insert many other examples here. 

Tradicionalmente, os programas C têm condições como

 if (someFunctionReturningANumber())  

em vez de

 if (someFunctionReturningANumber() != 0)  

porque o conceito de zero sendo equivalente a falso é bem compreendido.

Comentários

  • As linguagens são projetadas assim porque a matemática faz sentido. Isso veio primeiro.
  • @Morwenn, remonta ao século 19 e George Boole. As pessoas têm representado Falso como 0 e Verdadeiro como! 0 por mais tempo do que os computadores.
  • Não ‘ não vejo por que a matemática não ‘ t funcione de outra maneira se você simplesmente alterar todas as definições para que AND seja + e OR seja *.
  • Exatamente: a matemática funciona dos dois modos e a resposta para esta pergunta parece ser puramente convencional.
  • @Robert It ‘ d seria ótimo se você pudesse soletrar ” fundamentos matemáticos ” em sua postagem.

Resposta

Como já foi dito, a matemática vem primeiro. É por isso que 0 é false e 1 é true.

De que matemática estamos falando? Álgebras booleanas que datam de meados de 1800, muito antes do surgimento dos computadores digitais.

Você também pode dizer que a convenção saiu da lógica proposicional , que é ainda mais antiga do que as álgebras booleanas. Esta é a formalização de muitos dos resultados lógicos que os programadores conhecem e amam (false || x é igual a x, true && x é igual a x e assim por diante).

Basicamente, estamos falando sobre aritmética em um conjunto com dois elementos. Pense em contar em binário. Álgebras booleanas são a origem deste conceito e sua base teórica. As convenções de linguagens como C são apenas uma aplicação direta.

Comentários

  • Você poderia , com certeza. Mas mantê-lo da forma ” padrão ” se encaixa bem na aritmética geral (0 + 1 = 1, não 0 + 1 = 0).
  • Sim, mas você provavelmente escreveria AND com + e OR com * se também revertesse as definições.
  • A matemática não ‘ vêm primeiro. O Math reconheceu que 0 e 1 formam um campo, no qual AND é como multiplicação e OR é como adição.
  • @ Kaz: Mas {0, 1} com OR e AND não forma um campo.
  • Me incomoda um pouco que mais respostas e comentários digam que true = 1. Isso ‘ não é muito exato, porque true != 0 que não é exatamente o mesmo. Uma razão (não a única) pela qual se deve evitar comparações como if(something == true) { ... }.

Resposta

Achei que isso tivesse a ver com a “herança” da eletrônica e também com a álgebra booleana, onde

  • 0 = off, negative, no, false
  • 1 = on, positive, yes, true

strcmp retorna 0 quando as strings são iguais tem a ver com sua implementação, já que o que ele realmente faz é calcular a “distância” entre as duas strings. Que 0 também seja considerado falso é apenas uma coincidência.

retornar 0 no sucesso faz sentido porque 0, neste caso, é usado para significar nenhum erro e qualquer outro número seria um código de erro. Usar qualquer outro número para obter sucesso faria menos sentido, pois você tem apenas um único código de sucesso, embora possa ter vários códigos de erro. Você usa “Funcionou?” já que a expressão da instrução if e dizer 0 = sim faria mais sentido, mas a expressão é mais correta “Alguma coisa deu errado?” e então você vê que 0 = não faz muito sentido. Pensar em false/true realmente não faz sentido aqui, pois na verdade é no error code/error code.

Comentários

  • Haha, você é o primeiro a declarar explicitamente a questão do erro de retorno. Eu já sabia que interpretava minha própria maneira e poderia perguntar de outra forma, mas você ‘ é o primeiro a expressá-lo explicitamente (dentre as muitas respostas e comentários).Na verdade, eu não ‘ diria que uma ou outra forma não faz sentido, mas sim que ambas fazem sentido de maneiras diferentes 🙂
  • Na verdade, eu ‘ d diga 0 para success/no error é a única coisa que faz sentido quando outros inteiros representam códigos de erro . Que 0 também represente false em outros casos, ‘ realmente importa, uma vez que não estamos ‘ falando sobre verdadeiro ou falso aqui;)
  • Tive a mesma idéia, então aumentei
  • Seu ponto de vista sobre strcmp() calcular a distância é muito bom. Se tivesse sido chamado strdiff(), então if (!strdiff()) seria muito lógico.
  • ” eletrônicos […] onde 0 = […] falso, 1 = […] verdadeiro ” – mesmo em eletrônicos, é apenas um convenção e não ‘ t o único. Chamamos isso de lógica positiva, mas você também pode usar a lógica negativa, onde uma voltagem positiva indica falso e negativo indica verdadeiro. Então, o circuito que você ‘ d usar para AND torna-se OR, OR torna-se AND e assim por diante. Devido à lei de De Morgan ‘, tudo acaba sendo equivalente. Às vezes, você ‘ encontrará parte de um circuito eletrônico implementado em lógica negativa por conveniência, no ponto em que os nomes dos sinais nessa parte são anotados com uma barra acima deles.

Resposta

Conforme explicado neste artigo , os valores false e true não devem ser confundidos com os inteiros 0 e 1, mas podem ser identificados com os elementos do campo de Galois (campo finito) de dois elementos (veja aqui ).

Um campo é um conjunto com duas operações que satisfazem certos axiomas.

Os símbolos 0 e 1 são convencionalmente usados para denotar as identidades aditivas e multiplicativas de um campo porque os números reais também são um campo (mas não finito) cujas identidades são os números 0 e 1.

A identidade aditiva é o elemento 0 do campo, de modo que para todos os x:

x + 0 = 0 + x = x 

e a identidade multiplicativa é o elemento 1 do campo, de modo que para todo x:

x * 1 = 1 * x = x 

O campo finito de dois elementos tem apenas esses dois elementos, a saber, o identidade aditiva 0 (ou false) e a identidade multiplicativa 1 (ou true). As duas operações deste campo são o XOR lógico (+) e o lógico AND (*).

Nota. Se você inverter as operações (XOR é a multiplicação e AND é a adição), então a multiplicação não é distributiva sobre a adição e você não tem mais um campo. Nesse caso, você não tem razão para chamar os dois elementos de 0 e 1 (em qualquer ordem). Observe também que você não pode escolher a operação OR em vez de XOR: não importa como você interpreta OR / AND como adição / multiplicação, a estrutura resultante não é um campo (nem todos os elementos inversos existem conforme exigido pelos axiomas do campo).

Em relação às funções C:

  • Muitas funções retornam um número inteiro que é um código de erro. 0 significa NENHUM ERRO.
  • Intuitivamente, a função strcmp calcula a diferença entre duas strings. 0 significa que não há diferença entre duas strings, ou seja, que duas strings são iguais.

As explicações intuitivas acima podem ajudar a lembrar a interpretação dos valores de retorno, mas é ainda mais fácil basta verificar a documentação da biblioteca.

Comentários

  • +1 para mostrar que se você trocá-los arbitrariamente, a matemática não funcionará mais.
  • Invertido: dado um campo com dois elementos e operações * e +, identificamos True com 0 e False com 1. Identificamos OR com * e XOR com +.
  • Você verá que ambos dessas identificações são feitas no mesmo campo e ambas são consistentes com as regras da lógica booleana. Sua nota infelizmente está incorreta 🙂
  • Se você assumir que True = 0 e XOR é +, True deve ser a identidade de XOR. Mas não é porque True XOR True = False. A menos que você redefina a operação XOR em True para que True XOR True = True. Então, é claro, sua construção funciona porque você acabou de renomear as coisas (em qualquer estrutura matemática você sempre pode fazer uma permutação de nome com sucesso e obter uma estrutura isomórfica). Por outro lado, se você permitir que True, False e XOR tenham seus significados normais, True XOR True = False e True não podem ser a identidade aditiva, ou seja, True não pode ser 0.
  • @Giorgio: Corrigi minha construção de acordo com seu comentário em meu último comentário…

Resposta

Você deve considerar que sistemas alternativos também podem ser decisões de projeto aceitáveis.

Shells: 0 status de saída é verdadeiro, diferente de zero é falso

O exemplo de shells tratando um 0 o status de saída como verdadeiro já foi 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  

A razão é que existe uma maneira de ter sucesso, mas muitas maneiras de falhar, então usar 0 como o valor especial que significa “sem erros” é pragmático.

Ruby: 0 é como qualquer outro número

Entre as linguagens de programação “normais”, existem alguns outliers, como Ruby, que tratam 0 como um valor verdadeiro.

$ irb irb(main):001:0> 0 ? "0 is true" : "0 is false" => "0 is true" 

O o fundamento é que apenas false e nil devem ser falsos. Para muitos novatos em Ruby, é uma pegadinha. No entanto, em alguns casos, é bom que 0 seja tratado como qualquer outro 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" 

No entanto , tal sistema só funciona em uma linguagem capaz de distinguir booleanos como um tipo separado de números. Nos primeiros dias da computação, os programadores que trabalhavam com linguagem assembly ou linguagem de máquina bruta não tinham esses luxos. É provavelmente natural tratar 0 como o estado “em branco” e definir um bit como 1 como um sinalizador quando o código detecta que algo aconteceu. Por extensão, a convenção desenvolveu que zero foi tratado como falso e valores diferentes de zero passaram a ser tratados como verdadeiros. No entanto, não precisa ser assim.

Java: os números não podem ser tratados como booleanos

Em Java, true e false são os únicos valores booleanos. Os números não são booleanos e nem podem ser convertidos em booleanos ( Especificação da linguagem Java, Sec 4.2.2 ):

Não há conversões entre os tipos integrais e o tipo boolean .

Essa regra apenas evita a questão – todas as expressões booleanas devem ser explicitamente escritas no código.

Comentários

  • Rebol e Red tratam valores INTEGER! de valor 0 como verdadeiros e têm um tipo NONE! separado (com apenas um valor, NONE) tratado como falso condicional além de LOGIC! false. Eu ‘ encontrei uma frustração significativa ao tentar escrever um código JavaScript que trata 0 como falso; é um incr decisão edivelmente desajeitada para uma linguagem digitada dinamicamente. Se você quiser testar algo que pode ser nulo ou 0, você terá que escrever if (thing === 0), isso não é legal.
  • @HostileFork I don ‘ Não sei. Acho que faz sentido que 0 seja true (como qualquer outro número inteiro) em uma linguagem dinâmica. Às vezes eu pegava um 0 ao tentar capturar None em Python, e isso às vezes pode ser muito difícil de detectar.
  • Ruby não é um outlier. Ruby obtém isso do Lisp (o Ruby é até mesmo secretamente chamado de ” MatzLisp “). Lisp é uma linguagem dominante na ciência da computação. Zero também é apenas um valor verdadeiro no shell POSIX, porque ‘ é um pedaço de texto: if [ 0 ] ; then echo this executes ; fi. O valor de dados falsos é uma string vazia e uma falsidade testável é um status de finalização com falha de um comando, que é representado por um não -zero.

Resposta

Antes de abordar o caso geral, podemos discutir seus exemplos de contador.

Comparações de strings

O mesmo se aplica a muitos tipos de comparações, na verdade. Essas comparações calculam uma distância entre dois objetos. Quando os objetos são iguais, a distância é mínima. Portanto, quando a “comparação for bem-sucedida”, o valor será 0. Mas, na verdade, o valor de retorno de strcmp não um booleano, é uma distância e isso é o que aprisiona programadores desavisados fazendo if (strcmp(...)) do_when_equal() else do_when_not_equal().

Em C ++, poderíamos reprojetar strcmp para retornar um Distance objeto, que sobrescreve operator bool() para retornar verdadeiro quando 0 (mas você seria picado por um conjunto diferente de problemas). Ou em C simples, apenas tenha uma função streq que retorna 1 quando as strings são iguais e 0 caso contrário.

Chamadas de API / código de saída do programa

Aqui, você se preocupa com o motivo pelo qual algo deu errado, porque isso levará as decisões até o erro. Quando as coisas são bem-sucedidas, você não quer saber de nada em particular – sua intenção é realizada. O valor de retorno deve, portanto, transmitir essa informação. não um booleano, é um código de erro. O valor de erro especial 0 significa “nenhum erro”. O restante do intervalo representa erros localmente significativos com os quais você deve lidar (incluindo 1, que geralmente significa “erro não especificado”).

Caso geral

Isso nos deixa com a pergunta: por que os valores booleanos são True e False comumente representado por 1 e 0, respectivamente?

Bem, além do argumento subjetivo “é melhor assim”, aqui estão algumas razões (subjetivas também) que posso pensar em:

  • analogia do circuito elétrico. A corrente é ON por 1s e OFF por 0s. Gosto de ter (1, Sim, Verdadeiro, Ligado) juntos e (0, Não, Falso, Desligado), em vez de outra combinação

  • inicializações de memória. Quando eu memset(0) um monte de variáveis (sejam elas ints, floats, bools), quero que seus valores correspondam às suposições mais conservadoras. Por exemplo. minha soma é inicialmente 0, o predicado é Falso, etc.

Talvez todos esses motivos estejam ligados à minha educação – se eu tivesse aprendido a associar 0 com Verdadeiro do começando, eu faria o contrário.

Comentários

  • Na verdade, há pelo menos uma linguagem de programação que trata 0 como verdadeiro. O shell do Unix.
  • +1 para abordar o problema real: a maior parte da ‘ s questão de Morwenn é ‘ t sobre bool em tudo.
  • @ dan04 É. A postagem inteira é sobre a razão por trás da escolha do elenco de int a bool em muitas linguagens de programação. As coisas de comparação e gestão de erros são apenas exemplos de lugares onde fazer um lançamento diferente daquela que ‘ está fazendo atualmente faria sentido.

Resposta

De uma perspectiva de alto nível, você está falando sobre três tipos de dados bastante diferentes:

  1. Um booleano. A convenção matemática em álgebra booleana é usar 0 para false e 1 para true, então faz sentido seguir essa convenção. Acho que esta forma também faz mais sentido intuitivamente.

  2. O resultado da comparação. Isso tem três valores: <, = e > (observe que nenhum deles é true). Para eles, faz sentido usar os valores de -1, 0 e 1, respectivamente (ou, mais geralmente, um valor negativo, zero e um valor positivo).

    Se você deseja verificar a igualdade de a nd você só tem uma função que executa comparação geral, acho que você deve torná-la explícita usando algo como strcmp(str1, str2) == 0. Acho que usar ! nesta situação é confuso, porque trata um valor não booleano como se fosse um booleano.

    Além disso, tenha em mente que a comparação e igualdade não precisa ser a mesma coisa. Por exemplo, se você ordenar as pessoas pela data de nascimento, Compare(me, myTwin) deve retornar 0 , mas Equals(me, myTwin) deve retornar false.

  3. O sucesso ou falha de uma função , possivelmente também com detalhes sobre o sucesso ou falha. Se você estiver falando sobre o Windows, esse tipo é chamado de HRESULT e um valor diferente de zero não indicam necessariamente falha. Na verdade, um valor negativo indica falha e sucesso não negativo. O valor de sucesso é muitas vezes S_OK = 0, mas também pode ser, por exemplo, S_FALSE = 1 ou outros valores.

A confusão vem do fato aqueles três logicamente tipos de dados bastante diferentes são realmente representados como um único tipo de dados (um inteiro) em C e em algumas outras linguagens e que você pode usar inteiro em uma condição. Mas não acho que faria sentido redefinir booleano para tornar o uso de alguns tipos não booleanos em condições mais simples.

Além disso, considere outro tipo que é frequentemente usado em uma condição em C: um ponteiro . Lá, é “natural tratar um NULL -pointer (que é representado como 0) como false. Portanto, seguir sua sugestão também tornaria o trabalho com ponteiros mais difícil. (Embora, pessoalmente, eu prefira comparar ponteiros explicitamente com NULL, em vez de tratá-los como booleanos.)

Resposta

Zero pode ser falso porque a maioria das CPUs tem um sinalizador ZERO que pode ser usado para ramificar. Ele salva uma operação de comparação.

Vamos ver por quê.

Algum psuedocode, já que o público provavelmente não lê o assembly

c- chamadas de loop simples de origem wibble 10 vezes

 for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */ { wibble(); }  

alguma montagem fingida para isso

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- source outro simples chamadas de loop wibble 10 vezes

 for (int foo =0; foo<10; foo-- ) /* up count loop is longer */ { wibble(); }  

alguma montagem simulada 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 

um pouco mais de fonte c

 int foo=10; if ( foo ) wibble()  

e a montagem

0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007 

veja como isso é curto?

mais algumas fontes c

 int foo=10; if ( foo==0 ) wibble()  

e o assembly (vamos supor um compilador marginalmente inteligente que pode substituir == 0 sem comparação )

0x1000 ld a 0x10 0x1002 jz 0x3 0x1004 call 0x1234 0x1007 

Agora vamos tentar uma convenção de verdadeiro = 1

mais alguma fonte c #define TRUE 1 int foo = TRUE; se (foo == TRUE) wibble ()

e o assembly

0x1000 ld a 0x1 0x1002 cmp a 0x01 0x1004 jz 0x3 0x1006 call 0x1234 0x1009 

veja como é curto o caso com verdadeiro diferente de zero?

Realmente CPU “s iniciais tinham pequenos conjuntos de sinalizadores anexados ao Acumulador.

Para verificar se a> b ou a = b geralmente leva uma instrução de comparação.

  • A menos que B seja ou ZERO – neste caso o sinalizador ZERO é definido Implementado como um NOR lógico simples ou todos os bits no acumulador.
  • Ou NEGATIVO em que apenas use o “bit de sinal”, ou seja, o bit mais significativo do acumulador. se você estiver usando aritmética de complemento de dois. (Geralmente fazemos)

Vamos reafirmar isso. Em algumas CPU “s mais antigas, você não precisava usar uma instrução de comparação para o acumulador igual a ZERO, ou acumulador menor que zero.

Agora você vê por que zero pode ser falso?

Observe que este é um código psuedo e nenhum conjunto de instruções real se parece com isso. Se você conhece o assembly, sabe que estou simplificando muito as coisas aqui. Se você sabe alguma coisa sobre design de compilador, não precisa ler esta resposta. Qualquer pessoa que saiba alguma coisa sobre desenrolamento de loop ou previsão de ramificação, a aula avançada fica no final do corredor, na sala 203.

Comentários

  • Seu ponto não foi bem fundamentado aqui porque, para começar, if (foo) e if (foo != 0) deve gerar o mesmo código e, em segundo lugar, você ‘ está mostrando que a linguagem assembly que você ‘ está usando de fato tem operandos booleanos e testes para eles. Por exemplo, jz significa jump if zero. Em outras palavras, if (a == 0) goto target; . E a quantidade nem mesmo está sendo testada diretamente; a condição é convertida em um sinalizador booleano que é armazenado em uma palavra de máquina especial. Na verdade, ‘ é mais parecido com cpu.flags.zero = (a == 0); if (cpu.flags.zero) goto target;
  • Não, Kaz, a CPU mais antiga ‘ s não funcionava assim. T O jz / jnz pode ser executado sem fazer uma instrução de comparação. Esse foi o ponto principal de toda a minha postagem.
  • Eu não ‘ não escrevi nada sobre uma instrução de comparação.
  • Você pode cite um processador que tenha uma instrução jz, mas nenhuma jnz? (ou qualquer outro conjunto assimétrico de instruções condicionais)

Resposta

Existem muitas respostas que sugerem que a correspondência entre 1 e verdadeiro é necessária por alguma propriedade matemática. Não consigo encontrar nenhuma propriedade desse tipo e sugerir que seja puramente convenção histórica.

Dado um campo com dois elementos, temos duas operações: adição e multiplicação. Podemos mapear operações booleanas neste campo de duas maneiras :

Tradicionalmente, identificamos Verdadeiro com 1 e Falso com 0. Identificamos AND com * e XOR com +. Portanto, OR é uma adição saturante.

No entanto, poderíamos facilmente identifique Verdadeiro com 0 e Falso com 1. Então identificamos OR com * e XNOR com +. Assim, AND é adição saturante.

Comentários

  • Se você seguiu o link da wikipedia, pode ter descoberto que o conceito de álgebra booleana está intimamente relacionado com o de um campo de Galois de dois elementos ( en.wikipedia.org/wiki / GF% 282% 29 ). Os símbolos 0 e 1 são convencionalmente usados para denotar as identidades aditiva e multiplicativa, respectivamente, porque os números reais também são um campo cujas identidades são os números 0 e 1.
  • @NeilG Acho que Giorgio está tentando dizer que ‘ é mais do que apenas uma convenção. 0 e 1 em álgebra booleana são basicamente iguais a 0 e 1 em GF (2), que se comportam quase da mesma forma que 0 e 1 em números reais em relação à adição e multiplicação.
  • @svick: Não , porque você pode simplesmente renomear a multiplicação e a adição de saturação para OR e AND e, em seguida, inverter os rótulos para que 0 seja Verdadeiro e 1 seja Falso.Giorgio está dizendo que era uma convenção da lógica booleana, que foi adotada como uma convenção da ciência da computação.
  • @Neil G: Não, você não pode inverter + e * e 0 e 1 porque um campo requer distributividade de multiplicação sobre adição (consulte en.wikipedia.org/wiki/Field_%28mathematics%29 ), mas se você definir +: = AND e *: = XOR , você obtém T XOR (T AND F) = T XOR F = T, enquanto (T XOR T) AND (T XOR F) = F AND T = F. Portanto, invertendo as operações e as identidades, você não tem um campo mais. Portanto, a IMO definindo 0 e 1 como as identidades de um campo apropriado parece capturar o falso e o verdadeiro com bastante fidelidade.
  • @giorgio: Eu editei a resposta para tornar óbvio o que está acontecendo.

Resposta

Estranhamente, zero nem sempre é falso.

Em particular, a convenção Unix e Posix é definir EXIT_SUCCESS como 0 (e EXIT_FAILURE como 1). Na verdade, é até uma convenção C padrão!

Então, para shells Posix e saída (2) syscalls, 0 significa “bem-sucedido” que intuitivamente é mais verdadeiro do que falso.

Em particular, o shell “s if quer um o processo retorna EXIT_SUCCESS (ou seja 0) para seguir sua ramificação “then”!

Em Scheme (mas não em Common Lisp ou em MELT ) 0 e nil (ou seja, () no Esquema) são verdadeiros, pois o único valor falso é #f

Concordo, estou criticando!

Resposta

C é usado para programação de baixo nível perto de hardware, uma área em que às vezes você precisa alternar entre operações bit a bit e lógicas, nos mesmos dados. A necessidade de converter uma expressão numérica em booleana apenas para realizar um teste pode complicar o código.

Você pode escrever coisas como:

 if (modemctrl & MCTRL_CD) { /* carrier detect is on */ }  

em vez de

 if ((modemctrl & MCTRL_CD) != 0) { /* carrier detect is on */ }  

Em um exemplo isolado, não é tão ruim, mas ter que fazer isso vai ser enfadonho.

Da mesma forma, operações inversas. É útil para o resultado de uma operação booleana, como uma comparação, produzir apenas 0 ou 1: suponha que desejemos definir o terceiro bit de alguma palavra com base em modemctrl tem o bit de detecção de portadora:

 flags |= ((modemctrl & MCTRL_CD) != 0) << 2;  

Aqui temos que ter o != 0, para reduzir o resultado da expressão biwise & para 0 ou 1, mas como o resultado é apenas um número inteiro, somos poupados de ter que adicionar um elenco irritante para converter booleano em inteiro.

Mesmo que o C moderno agora tenha um bool tipo, ainda preserva a validade do código como este, tanto porque é “uma coisa boa, quanto por causa da grande quebra de compatibilidade com versões anteriores que seria causada de outra forma.

Outro exemplo onde C é habilidoso: testando duas condições booleanas como uma chave de quatro vias:

Você não poderia tirar isso do programador C sem lutar!

Por último, C às vezes serve como uma espécie de linguagem assembly de alto nível. Em linguagens assembly, também não temos tipos booleanos. Um valor booleano é apenas um bit ou zero versus valor diferente de zero em um local de memória ou registro. Um zero inteiro, zero booleano e o endereço zero são todos testados da mesma forma em conjuntos de instruções em assembly (e talvez até mesmo zero de ponto flutuante). A semelhança entre C e linguagem assembly é útil, por exemplo, quando C é usada como linguagem-alvo para compilar outra linguagem (mesmo uma que tenha booleanos fortemente tipados!)

Resposta

Um valor booleano ou verdadeiro tem apenas 2 valores. Verdadeiro e falso.

Estes devem não ser representados como inteiros, mas como bits (0 e 1 ).

Dizer qualquer outro número inteiro além de 0 ou 1 não é falso é uma afirmação confusa. As tabelas verdade lidam com valores verdade, não inteiros.

De uma perspectiva de valor verdade, -1 ou 2 quebraria todas as tabelas verdade e qualquer lógica booleana associada a elas.

  • 0 AND -1 ==?!
  • 0 OR 2 ==?!

A maioria dos idiomas geralmente tem um boolean tipo que, quando convertido para um tipo de número, como inteiro, revela falso para ser convertido como um valor inteiro de 0.

Comentários

  • 0 E -1 == qualquer valor booleano para o qual você os converte. Minha pergunta é ‘, por que colocá-los em TRUE ou FALSE.Nunca eu disse – talvez tenha dito, mas não era a intenção – inteiros eram verdadeiros ou falsos, perguntei por que eles avaliam qualquer quando convertidos em booleano.

Resposta

No final das contas, você está falando sobre quebrar a linguagem principal porque algumas APIs são ruins. APIs ruins não são novas, e você não pode corrigi-las quebrando a linguagem. É um fato matemático que 0 é falso e 1 é verdadeiro, e qualquer linguagem que não respeite isso está fundamentalmente quebrada. A comparação de três vias é nicho e não tem por que ter seu resultado convertido implicitamente em bool, uma vez que retorna três resultados possíveis. As APIs C antigas simplesmente têm um tratamento de erros terrível e também são prejudicadas porque C não tem os recursos de linguagem necessários para não ter interfaces terríveis.

Observe que não estou dizendo isso para linguagens que não têm implícito inteiro-> conversão booleana.

Comentários

  • ” É um fato matemático que 0 é falso e 1 é verdadeiro ” Erm.
  • Você pode citar uma referência para o seu ” fato matemático de que 0 é falso e 1 é verdadeiro “? Sua resposta soa perigosamente como um discurso retórico.
  • ‘ não é um fato matemático, mas ‘ foi uma convenção matemática desde o século 19.
  • A álgebra booleana é representada por um corpo finito no qual 0 e 1 são os elementos de identidade para operações que se assemelham a adição e multiplicação. Essas operações são, respectivamente, OR e AND. Na verdade, a álgebra booleana é escrita como a álgebra normal, onde a justaposição denota AND, e o símbolo + denota OR. Portanto, por exemplo, abc + a'b'c significa (a and b and c) or (a and (not b) and (not c)).

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *