Da linguagem natural à expressão C ++

9

Tarefa:

Traduza as seguintes expressões de linguagem natural para expressões C ++. Suponha que todas as variáveis ​​sejam números não negativos ou booleanos (com valor verdadeiro ou falso).

Linguagem Natural:

A e b são ambos falsos ou c é verdadeiro, mas não ambos.

Minha solução:

(a==0 && b==0)xor(c==1)

Solução para professores:

(!a && !b) != c

Questões:

  1. Acho que entendi um pouco o primeiro colchete, dizendo "não-a" e "não-b". Acho que aeb deve estar errado, desde que ab seja assumido como zero no começo. Direita?

  2. Mas e a parte que diz "desigual para c"?

  3. Não entendo a solução dos professores, alguém pode me explicar?

Obrigado pela ajuda!

limonada
fonte
em geral, eu seria cuidadoso ao traduzir expressões booleanas da linguagem falada em código. Um erro comum é traduzir "A é igual a B ou C" para em a == b or cvez de a == b or a ==c. O problema é que lanuage falada é impreciso e, na verdade, ambas as interpretações poderiam ser válido
idclev 463035818

Respostas:

5

Eu vou assumir isso a, be csão bool.

Vamos desenhar algumas tabelas da verdade:

| a | !a | a==1 | a==0 |
| 0 |  1 |   0  |   1  |
| 1 |  0 |   1  |   0  |

Como você pode ver, ae a==1são equivalentes, e !ae a==0também são equivalentes, de modo que podemos reescrever (a==0 && b==0)xor(c==1)como (!a && !b) xor c.

Agora, mais algumas tabelas de verdade:

| a | b | a xor b | a != b |
| 0 | 0 |    0    |    0   |
| 0 | 1 |    1    |    1   |
| 1 | 0 |    1    |    1   |
| 1 | 1 |    0    |    0   |

Então, a!=bé equivalente a a xor b, para que possamos reescrever (!a && !b) xor cpara (!a && !b)!=c. Como você vê, suas soluções são totalmente equivalentes, apenas escritas com diferentes 'sinais'.


UPD : Esqueci de mencionar. Existem razões pelas quais a solução do professor parece exatamente dessa maneira.

A solução do professor é mais idiomática. Embora sua solução esteja tecnicamente correta, não é um código C ++ idiomático.

O primeiro pequeno problema é o uso de tipos. Sua solução depende da conversão entre inte boolquando você compara o valor booleano com um número ou uso xor, que é um operador 'bit-wise exclusive ou' atuando sobre ints também. Em um C ++ moderno, é muito mais apreciado usar valores dos tipos corretos e não confiar nessas conversões, pois às vezes elas não são tão claras e difíceis de raciocinar. Para booltais valores são truee em falsevez de 1e 0respectivamente. Também !=é mais apropriado do que xorporque, enquanto tecnicamente, bools são armazenados como números, mas sematicamente você não possui números, apenas valores lógicos.

A segunda questão também é sobre a idiomia. Encontra-se aqui: a == 0. Não é considerado uma boa prática comparar expressões booleanas com constantes booleanas. Como você já sabe, a == trueé totalmente equivalente a apenas a, e a == falseé apenas !aou not a(eu prefiro o último). Para entender o motivo pelo qual essa comparação não é boa, basta comparar dois trechos de código e decidir, o que é mais claro:

if (str.empty() == false) { ... }

vs

if (not str.empty()) { ... }
Yuri Kovalenko
fonte
11
Embora tecnicamente correta, essa resposta evita completamente falar sobre tipos e C ++ idiomático, que foram, presumivelmente, o objetivo deste exercício.
Konrad Rudolph
@ KonradRudolph, oh, sim, eu esqueci completamente de mencionar isso. Talvez eu vou editar a minha resposta, graças
Yuri Kovalenko
3

Pense booleanos, não bits

Em resumo, a solução do professor é melhor (mas ainda está errada, a rigor, veja mais adiante) porque ela usa operadores booleanos em vez de operadores bit a bit e trata os booleanos como números inteiros. A expressão c==1para representar "c é verdadeira" está incorreta porque se c pode ser um número (de acordo com a atribuição declarada), qualquer valor diferente de zero de c deve ser considerado como representando true.

Veja esta pergunta sobre por que é melhor não comparar booleanos com 0 ou 1, mesmo quando é seguro fazê-lo.

Uma boa razão para não usar xoré que esta é a operação ou exclusiva em termos de bits . Isso funciona no seu exemplo, porque o lado esquerdo e o lado direito são expressões booleanas que se convertem em 1 ou 0 (consulte novamente 1 ).

O booleano exclusivo - ou é de fato !=.

Quebrando a expressão

Para entender melhor a solução do professor, é mais fácil substituir os operadores booleanos por seus equivalentes "token alternativo", que o transformam em código C ++ melhor redable (imho) e completamente equivalente: Usando 'not' for '!' e 'e' para '&&' você obtém

    (not a and not b) != c

Infelizmente, não há exclusive_oroutro operador lógico not_eqque não seja útil nesse caso.

Se quebrarmos a expressão da linguagem natural:

A e b são ambos falsos ou c é verdadeiro, mas não ambos.

primeiro em uma frase sobre as proposições booleanas A e B:

A ou B, mas não ambos.

isso se traduz em A != B(apenas para booleanos, não para qualquer tipo A e B).

Então a proposição A foi

aeb são ambos falsos

que pode ser indicado como

a é falso eb é falso

que se traduz em (not a and not b), e finalmente

c é verdade

O que simplesmente se traduz em c. Combinando eles, você obtém novamente (not a and not b) != c.

Para mais explicações sobre como essa expressão funciona, eu refiro às tabelas da verdade que outros deram em suas respostas.

Vocês dois estão errados

E se eu puder nitpick: A atribuição original afirmou que a, bec podem ser números não negativos, mas não declarou inequivocamente que, se fossem números, deveriam ser limitados aos valores 0 e 1. Se houver um número que seja not 0 representa true, como é habitual, o código a seguir produziria uma resposta surpreendente :

    auto c = 2; // "true" in some way
    auto a = 0; // "false"
    auto b = 0; // "false"

    std::cout << ((!a && !b) != c);

// this will output: 1 (!)
// fix by making sure that != compares booleans:

    std::cout << ((!a && !b) != (bool)c);
dhavenith
fonte
Bem a, esperançosamente , be csão declarados como bool, nesse caso, c == 1está correto , embora código atroz. Enfim, esta é a resposta que eu teria escrito: o código do OP pode ser equivalente ao do professor, mas é ruim em C ++.
Konrad Rudolph
11
@KonradRudolph Do texto de atribuição do OP: variables are non-negative numbers or boolean. Então, marque +1 em @dhavenith por capturar um detalhe que a maioria das pessoas aqui perdeu (incluindo eu, inicialmente).
Frodyne
Ótimo, entendi. Obrigado! Mas você pode me explicar a solução do meu professor porque eu não a entendo.
limonade
Adicionei uma ortografia alternativa para a solução do seu professor. Isso deve ajudar a esclarecer a expressão. Para explicações mais detalhadas, acho que as tabelas da verdade na resposta de @YuriKovalenko são a melhor maneira de abordar a expressão.
Dhavenith 5/12/19
2

Vou tentar explicar com mais algumas palavras: Os números podem ser implicitamente convertidos em valores booleanos:

O valor zero (para enumeração integral, de ponto flutuante e sem escopo) e o ponteiro nulo e os valores de ponteiro nulo para membro tornam-se falsos. Todos os outros valores se tornam verdadeiros.

Fonte sobre cppreference

Isso leva às seguintes conclusões:

  • a == 0é o mesmo que !a, porque aé convertido em um booleano e depois invertido, o que é igual a !(a != 0). O mesmo vale para b.

  • c==1só será verdadeiro quando for c igual a 1. O uso da conversão (bool)crenderia truequando c != 0não apenas se c == 1. Portanto, pode funcionar, porque geralmente se usa o valor 1 para representar true, mas não é garantido.

  • a != bé o mesmo que a xor bquando ae bsão expressões booleanas. É verdade, quando um valor ou outro é verdadeiro, mas não ambos. Nesse caso, o lado esquerdo (a==0 && b==0)é booleano; portanto, o lado direito também cé convertido em booleano; portanto, ambos os lados são interpretados como expressões booleanas; portanto, !=é o mesmo que xorneste caso.

Você pode verificar tudo isso sozinho com as tabelas da verdade fornecidas pelas outras respostas.

churill
fonte
2

Como podemos ver nas tabelas da verdade:

  • !( not) e ==0dê os mesmos resultados.
  • !=e xordê os mesmos resultados.
  • c==1 é o mesmo que apenas c

Então, um sob o outro, mostra por que essas duas expressões dão o mesmo resultado:

(a==0 && b==0) xor (c==1)
(!a   && !b)   !=   c

Tabelas da verdade:

Não

    |   | ! |
    | 0 | 1 |
    | 1 | 0 |

== 0

    |   |==0|
    | 0 | 1 |
    | 1 | 0 |

== 1

    |   |==1|
    | 0 | 0 |
    | 1 | 1 |

E

   | a | b | && |
   | 0 | 0 |  0 |
   | 0 | 1 |  0 |
   | 1 | 0 |  0 |
   | 1 | 1 |  1 |

Não igual

   | a | b | != |
   | 0 | 0 |  0 |
   | 0 | 1 |  1 |
   | 1 | 0 |  1 |
   | 1 | 1 |  0 |

XOR

   | a | b |xor|
   | 0 | 0 | 0 |
   | 0 | 1 | 1 |
   | 1 | 0 | 1 |
   | 1 | 1 | 0 |
Robert Andrzejuk
fonte