Dal linguaggio naturale all'espressione C ++


9

Incarico:

Traduci le seguenti espressioni in linguaggio naturale in espressioni C ++. Supponiamo che tutte le variabili siano numeri non negativi o booleani (di valore vero o falso).

Linguaggio naturale:

O aeb sono entrambi falsi oppure c è vero, ma non entrambi.

La mia soluzione:

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

Soluzione per i professori:

(!a && !b) != c

Domande:

  1. Penso di comprendere leggermente la prima parentesi, dicendo "non-a" e "non-b" Penso che aeb debbano quindi essere sbagliati, a condizione che all'inizio si supponga che non sia zero. Giusto?

  2. Ma per quanto riguarda la parte che dice "disuguale a c"?

  3. Non capisco la soluzione dei professori, qualcuno può romperlo per me?

Grazie per l'aiuto!


in generale starei attento a tradurre espressioni booleane di lingua parlata in codice. Un errore comune è tradurre "A è uguale a B o C" a == b or canziché a == b or a ==c. Il problema è che il linguaggio parlato è impreciso e in realtà entrambe le interpretazioni potrebbero essere valide
— idclev 463035818

Risposte:


5

Darò per scontato che a, be csono bool.

Disegniamo alcune tabelle di verità:

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

Come si può vedere, ae a==1sono equivalenti, e !aed a==0è anche equivalente, in modo che possiamo riscrivere (a==0 && b==0)xor(c==1)come (!a && !b) xor c.

Ora alcune altre tabelle di verità:

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

Quindi, a!=bè equivalente a a xor b, in modo che possiamo riscrivere (!a && !b) xor ca (!a && !b)!=c. Come vedi, le tue soluzioni sono completamente equivalenti, scritte solo con diversi "segni".


UPD : Ho dimenticato di menzionare. Ci sono ragioni per cui la soluzione del professore appare esattamente in quel modo.

La soluzione del professore è più idiomatica. Sebbene la tua soluzione sia tecnicamente corretta, non è un codice C ++ idiomatico.

Il primo piccolo problema è l'uso dei tipi. La tua soluzione si basa sulla conversione tra inte boolquando confronti il ​​valore booleano con un numero o un uso xor, che è un "bit-saggio esclusivo" o un operatore che agisce anche su ints. In un moderno C ++ è molto più apprezzato usare valori di tipi corretti e non fare affidamento su conversioni di questo tipo, a volte non così chiare e difficili da ragionare. Per booltali valori sono truee falseinvece di 1e 0rispettivamente. Inoltre !=è più appropriato rispetto al xorfatto che mentre tecnicamente i bools sono memorizzati come numeri, ma semestralmente non hai numeri, solo valori logici.

Il secondo numero riguarda anche l'idioma. Si trova qui: a == 0. Non è considerata una buona pratica confrontare espressioni booleane con costanti booleane. Come già sapete, a == trueè del tutto equivalente a just a, ed a == falseè giusto !ao not a(preferisco quest'ultimo). Per capire il motivo per cui quel confronto non è buono, confronta due frammenti di codice e decidi, che è più chiaro:

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

vs

if (not str.empty()) { ... }

1
Sebbene tecnicamente corretta, questa risposta evita completamente di parlare di tipi e di C ++ idiomatico, che erano presumibilmente il punto di questo esercizio.
— Konrad Rudolph,

@KonradRudolph, oh, sì, ho completamente dimenticato di menzionarlo. Forse modificherò la mia risposta, grazie
— Yuri Kovalenko il

3

Pensa ai booleani, non ai bit

In sintesi, la soluzione del tuo professore è migliore (ma è ancora sbagliata, a rigor di termini, vedi più in basso) perché utilizza operatori booleani invece di operatori bit a bit e tratta i valori booleani come numeri interi. L'espressione c==1per rappresentare "c è vera" non è corretta perché se c può essere un numero (secondo l'assegnazione dichiarata), qualsiasi valore diverso da zero di c deve essere considerato rappresentativo true.

Vedi questa domanda sul perché è meglio non confrontare i valori booleani con 0 o 1, anche quando è sicuro farlo.

Un ottimo motivo per non usare xorè che si tratta dell'esclusiva o dell'operazione bit-saggia . Succede nel tuo esempio perché sia ​​il lato sinistro che il lato destro sono espressioni booleane che vengono convertite in 1 o 0 (vedi di nuovo 1 ).

L'esclusiva booleana, o in effetti lo è !=.

Abbattere l'espressione

Per comprendere meglio la soluzione del tuo professore, è più semplice sostituire gli operatori booleani con i loro equivalenti "token alternativi", che lo trasformano in un codice C ++ redable (imho) e completamente equivalente: usando 'not' for '!' e 'e' per '&&' ottieni

    (not a and not b) != c

Sfortunatamente, non esiste un exclusive_oroperatore logico diverso da quello not_eq, il che non è utile in questo caso.

Se suddividiamo l'espressione del linguaggio naturale:

O aeb sono entrambi falsi oppure c è vero, ma non entrambi.

prima in una frase sulle proposizioni booleane A e B:

A o B, ma non entrambi.

questo si traduce in A != B(solo per i booleani, non per qualsiasi tipo A e B).

Quindi la proposizione A fu

aeb sono entrambi falsi

che può essere dichiarato come

a è falso e b è falso

che si traduce in (not a and not b), e infine

c è vero

Che si traduce semplicemente in c. Combinandoli si ottiene di nuovo (not a and not b) != c.

Per ulteriori spiegazioni su come funziona questa espressione, rimando alle tabelle di verità che altri hanno fornito nelle loro risposte.

Sbagli entrambi

E se potessi puntualizzare: l'assegnazione originale affermava che a, bec possono essere numeri non negativi, ma non affermava in modo inequivocabile che se fossero numeri, dovrebbero essere limitati ai valori 0 e 1. Se qualsiasi numero che è non 0 rappresenta true, come è consuetudine, quindi il seguente codice darebbe una risposta sorprendente :

    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);

Beh a, si spera , be csono dichiarati come bool, nel qual caso c == 1è corretto , anche se codice atroce. Comunque, questa è la risposta che avrei scritto: il codice di OP potrebbe essere equivalente a quello del professore, ma è un C ++ negativo.
— Konrad Rudolph,

1
@KonradRudolph Dal testo assegnazione di OP: variables are non-negative numbers or boolean. Quindi +1 a @dhavenith da parte mia per aver catturato un dettaglio che la maggior parte degli altri qui ha perso (incluso me, inizialmente).
— Frodyne,

Ottimo, Isee. Grazie! Ma puoi spiegarmi la soluzione del mio professore perché non la capisco.
— limonade,

Ho aggiunto un'ortografia alternativa per la soluzione del tuo professore. Ciò dovrebbe aiutare a chiarire l'espressione. Per spiegazioni più dettagliate, penso che le tabelle di verità nella risposta di @YuriKovalenko siano il modo migliore per avvicinarsi all'espressione.
— Dhavenith,

2

Proverò a spiegare con qualche altra parola: i numeri possono essere implicitamente convertiti in valori booleani:

Il valore zero (per l'enumerazione integrale, in virgola mobile e senza ambito) e il puntatore null e i valori null puntatore-membro diventano falsi. Tutti gli altri valori diventano veri.

Fonte su cppreference

Ciò porta alle seguenti conclusioni:

  • a == 0è lo stesso di !a, perché aviene convertito in un valore booleano e quindi invertito, che equivale a !(a != 0). Lo stesso vale per b.

  • c==1diventerà vero solo quando è c uguale a 1. L'uso della conversione (bool)cprodurrebbe truequando c != 0non solo se c == 1. Quindi può funzionare, perché di solito si utilizza il valore 1 per rappresentare true, ma non è garantito.

  • a != bè lo stesso di a xor bquando ae le bespressioni booleane. È vero, quando un valore o l'altro è vero, ma non entrambi. In questo caso il lato sinistro (a==0 && b==0)è booleano, quindi anche il lato destro cviene convertito in booleano, quindi entrambi i lati vengono interpretati come espressioni booleane, quindi !=è lo stesso xordi questo caso.

Puoi controllare tutto questo da solo con le verità fornite dalle altre risposte.


2

Come possiamo vedere dalle tabelle di verità:

  • !( not) e ==0dare gli stessi risultati.
  • !=e xordare gli stessi risultati.
  • c==1 è lo stesso di solo c

Quindi uno sotto l'altro, mostra perché queste 2 espressioni danno lo stesso risultato:

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

Tabelle della verità:

Non

    |   | ! |
    | 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 |

Non uguale

   | 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 |
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.