Od języka naturalnego do wyrażenia w C ++

9

Zadanie:

Przetłumacz następujące wyrażenia języka naturalnego na wyrażenia C ++. Załóżmy, że wszystkie zmienne są liczbami nieujemnymi lub wartością logiczną (o wartości true lub false).

Język naturalny:

Albo a i b są fałszywe, lub c jest prawdą, ale nie jedno i drugie.

Moje rozwiązanie:

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

Rozwiązanie dla profesorów:

(!a && !b) != c

Pytania:

  1. Myślę, że lekko rozumiem pierwszą nawias, mówiąc „nie-a” i „nie-b”. Myślę, że aib muszą być wtedy błędne, pod warunkiem, że ab na początku przyjmuje się, że nie jest zero. Dobrze?

  2. Ale co z częścią, która mówi „nierówne do c”?

  3. Nie rozumiem rozwiązania dla profesorów, czy ktoś może to dla mnie rozbić?

Dziękuję za pomoc!

limonada
źródło
generalnie będę ostrożny w tłumaczeniu wyrażeń logicznych na język mówiony na kod. Częstym błędem jest tłumaczenie „A równa się B lub C” na a == b or czamiast a == b or a ==c. Problem polega na tym, że mówiony język jest nieprecyzyjny i faktycznie obie interpretacje mogą być poprawne
idclev 463035818

Odpowiedzi:

5

Będę zakładać, że a, bi cbool.

Narysujmy kilka tabel prawdy:

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

Jak widać ai a==1są równoważne, !ai a==0są również równoważne, więc możemy przepisać (a==0 && b==0)xor(c==1)jako (!a && !b) xor c.

Teraz jeszcze kilka tabel prawdy:

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

Więc a!=bjest równoważne a xor b, więc możemy przepisać (!a && !b) xor cdo (!a && !b)!=c. Jak widzisz, twoje rozwiązania są w pełni równoważne, tylko napisane różnymi „znakami”.


UPD : Zapomniałem wspomnieć. Istnieją powody, dla których rozwiązanie profesora wygląda dokładnie w ten sposób.

Rozwiązanie profesora jest bardziej idiotyczne. Chociaż Twoje rozwiązanie jest technicznie poprawne, nie jest to idiomatyczny kod C ++.

Pierwszym małym problemem jest użycie typów. Twoje rozwiązanie opiera się na konwersji pomiędzy inti boolpodczas porównywania wartości logicznej z liczbą lub zastosowaniem xor, co jest „wyłącznym bitem” lub operatorem działającym również na ints. W nowoczesnym języku C ++ o wiele bardziej doceniane jest stosowanie wartości poprawnych typów i nie poleganie na takich konwersjach, ponieważ czasami nie są one tak jasne i trudne do uzasadnienia. Dla booltakich wartości są truei falsezamiast 1i 0odpowiednio. !=Jest to również bardziej odpowiednie niż to, xorże chociaż technicznie bools są przechowywane jako liczby, ale sematycznie nie masz żadnych liczb, tylko wartości logiczne.

Drugi problem dotyczy także idiomii. Leży tutaj: a == 0. Porównywanie wyrażeń boolowskich ze stałymi boolowskimi nie jest uważane za dobrą praktykę. Jak już wiesz, a == truejest w pełni równoważny z just ai a == falsejest sprawiedliwy !alub not a(wolę ten drugi). Aby zrozumieć powód, dla którego to porównanie nie jest dobre, po prostu porównaj dwa fragmenty kodu i zdecyduj, co jest jaśniejsze:

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

vs

if (not str.empty()) { ... }
Jurij Kowalalenko
źródło
1
Chociaż technicznie poprawne, ta odpowiedź całkowicie unika mówienia o typach i idiomatycznym C ++, które prawdopodobnie były celem tego ćwiczenia.
Konrad Rudolph,
@KonradRudolph, o tak, zupełnie zapomniałem o tym wspomnieć. Może zedytuję odpowiedź, dzięki
Jurij Kowalenko,
3

Myśl booleany, a nie bity

Podsumowując, rozwiązanie twojego profesora jest lepsze (ale nadal błędne, ściśle mówiąc, patrz dalej w dół), ponieważ używa operatorów logicznych zamiast operatorów bitowych i traktuje logiczne jako liczby całkowite. Wyrażenie c==1reprezentujące „c jest prawdą” jest niepoprawne, ponieważ jeśli c może być liczbą (zgodnie z podanym przypisaniem), wówczas każdą niezerową wartość c należy traktować jako reprezentującą true.

Zobacz pytanie, dlaczego lepiej nie porównywać boolanów z 0 lub 1, nawet jeśli jest to bezpieczne.

Jednym z bardzo dobrych powodów, aby nie używać, xorjest to, że jest to nieco wykluczająca operacja. Zdarza się, że działa w twoim przykładzie, ponieważ zarówno lewa strona, jak i prawa strona są wyrażeniami logicznymi, które są konwertowane na 1 lub 0 (zobacz ponownie 1 ).

Wartość logiczna wyłączna - lub w rzeczywistości jest !=.

Podział wyrazu

Aby lepiej zrozumieć rozwiązanie twojego profesora, najłatwiej jest zastąpić operatory logiczne ich ekwiwalentami „alternatywnego tokena”, co czyni go lepszym do redable (imho) i całkowicie równoważnym kodem C ++: Używanie „nie” dla ”!” oraz „i” za „&&”

    (not a and not b) != c

Niestety nie ma innego exclusive_oroperatora logicznego niż not_eq, co w tym przypadku nie jest pomocne.

Jeśli rozbimy naturalne wyrażenie językowe:

Albo a i b są fałszywe, lub c jest prawdą, ale nie jedno i drugie.

najpierw do zdania o zdaniach boolowskich A i B:

Albo A albo B, ale nie oba.

przekłada się to na A != B(tylko dla booleanów, nie dla żadnego typu A i B).

Wtedy była twierdzenie A.

oba a i b są fałszywe

które można określić jako

a jest fałszem, a b jest fałszem

co przekłada się na (not a and not b)i wreszcie

c jest prawdą

Co po prostu przekłada się na c. Łącząc je otrzymujesz ponownie (not a and not b) != c.

W celu dalszego wyjaśnienia, jak to wyrażenie działa, odsyłam do tabel prawdy, które inni podali w swoich odpowiedziach.

Oboje się mylicie

I jeśli mogę wytropić: Pierwotny przydział stwierdził, że a, b i c mogą być liczbami nieujemnymi, ale nie stwierdził jednoznacznie, że jeśli byłyby liczbami, powinny być ograniczone do wartości 0 i 1. Jeśli dowolna liczba, która jest nie 0 oznacza true, jak zwykle, następujący kod dałby zaskakującą odpowiedź :

    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
źródło
Mam nadzieję a, że bi csą zadeklarowane jako bool, w którym c == 1to przypadku jest poprawny , choć okropny kod. W każdym razie jest to odpowiedź, którą napisałbym: kod OP może być równoważny kodowi profesora, ale jest to zły C ++.
Konrad Rudolph
1
@KonradRudolph Z tekstu przypisania OP: variables are non-negative numbers or boolean. Od +1 do @dhavenith ode mnie za uchwycenie szczegółów, których większość innych tutaj tęskniło (w tym mnie początkowo).
Frodyne,
Świetnie, Isee. Dziękuję Ci! Ale czy możesz mi wyjaśnić rozwiązanie mojego profesora, ponieważ go nie rozumiem.
limonada,
Dodałem alternatywną pisownię do rozwiązania twojego profesora. To powinno pomóc w wyjaśnieniu wyrażenia. Aby uzyskać bardziej szczegółowe wyjaśnienia, myślę, że tabele prawdy w odpowiedzi @YuriKovalenko są najlepszym sposobem na zbliżenie się do wyrażenia.
dhavenith
2

Spróbuję wyjaśnić jeszcze kilkoma słowami: Liczby można domyślnie przekonwertować na wartości logiczne:

Wartość zero (dla wyliczenia całkowego, zmiennoprzecinkowego i nieskalowanego) oraz wskaźnik zerowy i wartości zerowego wskaźnika do elementu stają się fałszem. Wszystkie pozostałe wartości stają się prawdziwe.

Źródło na temat preferencji

Prowadzi to do następujących wniosków:

  • a == 0jest taki sam jak !a, ponieważ ajest konwertowany na wartość logiczną, a następnie odwrócony, co jest równe !(a != 0). To samo dotyczy b.

  • c==1stanie się prawdą tylko wtedy, gdy będzie c równa 1. Użycie konwersji (bool)cdałoby wynik, truegdy c != 0nie tylko, jeśli c == 1. Może więc działać, ponieważ zwykle używa się wartości 1 do reprezentowania true, ale nie jest ona gwarantowana.

  • a != bjest taka sama jak a xor bpodczas ai bar wyrażeń logicznych. To prawda, gdy jedna lub druga wartość jest prawdziwa, ale nie obie. W tym przypadku lewa strona (a==0 && b==0)jest wartością logiczną, więc prawa strona również cjest konwertowana na wartość logiczną, więc obie strony są interpretowane jako wyrażenia boolowskie, a zatem !=są takie same jak xorw tym przypadku.

Możesz to wszystko sprawdzić samodzielnie z tabelami prawdy, które podały inne odpowiedzi.

churill
źródło
2

Jak widać z tabel prawdy:

  • !( not) i ==0dać te same wyniki.
  • !=i xordać te same wyniki.
  • c==1 jest taki sam jak sprawiedliwy c

Tak więc jedno pod drugim pokazuje, dlaczego te 2 wyrażenia dają ten sam wynik:

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

Tabele prawdy:

Nie

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

== 0

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

== 1

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

I

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

Nie równe

   | 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
źródło