От естественного языка к выражению C ++

9

Назначение:

Переведите следующие выражения на естественном языке в выражения C ++. Предположим, что все переменные являются неотрицательными числами или логическими (со значением true или false).

Естественный язык:

Либо a, либо b оба имеют значение false, либо c соответствует true, но не оба.

Мое решение:

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

Решение профессора:

(!a && !b) != c

Вопросов:

  1. Я думаю, что немного понимаю первую скобку, говоря «not-a» и «not-b». Я думаю, что тогда a и b должны быть неправильными, если предположить, что ab изначально ненулевые. Правильно?

  2. Но как насчет части, которая говорит "неравный с"?

  3. Я не понимаю решение профессора, кто-нибудь может сломать его для меня?

Спасибо вам за помощь!

лимонад
источник
в общем, я буду осторожен с переводом логических выражений разговорного языка в код. Распространенной ошибкой является перевод «A равно B или C» a == b or cвместо a == b or a ==c. Проблема в том, что разговорный язык является неточным, и фактически обе интерпретации могут быть действительными
idclev 463035818

Ответы:

5

Я предполагаю , что a, bи cесть bool.

Давайте нарисуем некоторые таблицы истинности:

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

Как видите, aи a==1эквивалентны, и !aи a==0также эквивалентны, поэтому мы можем переписать (a==0 && b==0)xor(c==1)как (!a && !b) xor c.

Теперь еще несколько таблиц правды:

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

Так что a!=bэквивалентно a xor b, так что мы можем переписать (!a && !b) xor cв (!a && !b)!=c. Как видите, ваши решения полностью эквивалентны, просто написаны с разными «знаками».


UPD : забыл упомянуть. Есть причины, по которым решение профессора выглядит именно так.

Решение профессора более идиоматично. Хотя ваше решение технически правильно, это не идиоматический код C ++.

Первая небольшая проблема - использование типов. Ваше решение основывается на преобразовании между intи boolкогда вы сравниваете логическое значение с числом или использованием xor, которое является «побитовым эксклюзивным или» оператором, действующим также на ints. В современном C ++ гораздо ценнее использовать значения правильных типов и не полагаться на такие преобразования, поскольку они иногда не так ясны и трудны для рассуждения. Для boolтаких значений есть trueи falseвместо 1и 0соответственно. Это также !=более уместно, чем xorпотому, что, хотя технически boolони хранятся в виде чисел, но с точки зрения семантики у вас нет никаких чисел, только логические значения.

Второй вопрос касается идиоматизма. Он находится здесь: a == 0. Не рекомендуется сравнивать логические выражения с логическими константами. Как вы уже знаете, a == trueэто полностью эквивалентно справедливому aи a == falseявляется справедливым !aили not a(я предпочитаю последнее). Чтобы понять причину, по которой это сравнение не подходит, просто сравните два фрагмента кода и решите, что более понятно:

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

против

if (not str.empty()) { ... }
Юрий Коваленко
источник
1
Будучи технически правильным, этот ответ полностью избегает разговоров о типах и идиоматическом C ++, которые, по-видимому, были целью этого упражнения.
Конрад Рудольф
@KonradRudolph, о да, я совсем забыла об этом упомянуть. Может быть, я отредактирую свой ответ, спасибо
Юрий Коваленко
3

Думай логически, а не бит

Таким образом, решение вашего профессора лучше (но все же неправильно, строго говоря, смотрите далее), потому что оно использует логические операторы вместо побитовых операторов и рассматривает логические операторы как целые числа. Выражение c==1для представления «c является истинным» является неправильным, потому что, если c может быть числом (в соответствии с заявленным присваиванием), тогда любое ненулевое значение c следует рассматривать как представляющее true.

Посмотрите на этот вопрос, почему лучше не сравнивать логические значения с 0 или 1, даже если это безопасно.

Одна очень веская причина не использовать xorэто то, что это побитовое исключение или операция. Это работает в вашем примере, потому что и левая, и правая части являются логическими выражениями, которые преобразуются в 1 или 0 (см. Снова 1 ).

Булево исключение - или есть на самом деле !=.

Разбивая выражение

Чтобы лучше понять решение вашего преподавателя, проще всего заменить логические операторы их эквивалентами «альтернативного токена», что превращает его в более читаемый (imho) и полностью эквивалентный код C ++: использование «not» для «!» и 'и' для '&&' вы получаете

    (not a and not b) != c

К сожалению, нет логического exclusive_orоператора, кроме not_eq, который не помогает в этом случае.

Если мы разобьем выражение на естественном языке:

Либо a, либо b оба имеют значение false, либо c соответствует true, но не оба.

сначала в предложении о булевых предложениях A и B:

Либо А, либо Б, но не оба.

это переводится в A != B(только для логических значений, а не для любых типов A и B).

Тогда предложение А было

а и б оба ложные

который может быть заявлен как

а ложь и б ложь

который переводит в (not a and not b), и, наконец,

с правда

Который просто переводит на c. Объединяя их, вы получаете снова (not a and not b) != c.

Для дальнейшего объяснения того, как тогда работает это выражение, я приведу таблицы истинности, которые другие дали в своих ответах.

Вы оба не правы

И если я могу придираться: в первоначальном присваивании говорилось, что a, b и c могут быть неотрицательными числами, но не однозначно указывалось, что если бы они были числами, они должны быть ограничены значениями 0 и 1. Если любое число является не 0 представляет true, как обычно, тогда следующий код даст неожиданный ответ :

    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
источник
Ну , надеюсь a, bи cобъявлены как bool, в этом случае c == 1является правильным , хотя и зверского кода. В любом случае, это ответ, который я бы написал: код OP может быть эквивалентен коду профессора, но это плохо на C ++.
Конрад Рудольф
1
@KonradRudolph Из текста присваивания OP в: variables are non-negative numbers or boolean. Так что +1 к @dhavenith от меня за то, что я уловил детали, которые пропустили большинство других здесь (включая меня, изначально).
Фродин
Отлично, я вижу. Спасибо! Но можете ли вы тогда объяснить мне решение моего профессора, потому что я не понимаю его.
лимонада
Я добавил альтернативное правописание для решения вашего профессора. Это должно помочь уточнить выражение. Для более подробных объяснений, я думаю, что таблицы истинности в ответе @YuriKovalenko - лучший способ приблизиться к выражению.
19
2

Я попытаюсь объяснить с помощью еще нескольких слов: числа могут быть неявно преобразованы в логические значения:

Нулевое значение (для целочисленного значения, перечисления с плавающей точкой и перечисления с незаданной областью), а также нулевой указатель и нулевые значения указателя на член становятся ложными. Все остальные ценности становятся правдой.

Источник на cppreference

Это приводит к следующим выводам:

  • a == 0так же, как !a, потому что aпреобразуется в логическое значение, а затем инвертируется, что равно !(a != 0). То же самое касается б.

  • c==1станет истинным только при c равенстве 1. Использование преобразования (bool)cдаст результат, trueа c != 0не только если c == 1. Так что это может работать, потому что обычно для представления используется значение 1 true, но это не гарантируется.

  • a != bто же самое, что a xor bкогда aи bar булевы выражения. Это правда, когда одно значение или другое верно, но не оба. В этом случае левая часть (a==0 && b==0)является логической, поэтому правая часть также cпреобразуется в логическую, поэтому обе стороны интерпретируются как логические выражения, таким образом !=, то же самое, что и xorв этом случае.

Вы можете проверить все это самостоятельно с помощью правдивых таблиц, предоставленных другими ответами.

churill
источник
2

Как мы видим из таблиц истинности:

  • !( not) и ==0дают одинаковые результаты.
  • !=и xorдать те же результаты.
  • c==1 так же, как просто c

Так одно под другим показывает, почему эти два выражения дают одинаковый результат:

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

Таблицы правды:

Не

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

== 0

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

== 1

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

А также

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

Не равный

   | 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 |
Роберт Анджейюк
источник