从自然语言到C ++表达式


9

分配:

将以下自然语言表达式转换为C ++表达式。假定所有变量都是非负数或布尔值(值为true或false)。

自然语言:

a和b都为假,或者c为真,但不是两个都为真。

我的解决方案:

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

教授的解决方案:

(!a && !b) != c

问题:

  1. 我认为我稍微理解了第一个括号,通过说“ not-a”和“ not-b”,我认为a和b一定是错误的,只要ab在开始时就假定为非零。对?

  2. 但是说“不等于c”的部分呢?

  3. 我不了解教授的解决方案,有人可以为我分解一下吗?

感谢您的帮助!


通常,在将口语布尔表达式翻译为代码时,我会格外小心。一个常见的错误是把“A等于B或C”来a == b or c代替a == b or a ==c。问题在于口头语言不准确,实际上两种解释都可能是有效的
idclev 463035818

Answers:


5

我会以为ab并且cbool

让我们画一些真值表:

| 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 ++代码。

第一个小问题是类型的用法。您的解决方案依赖之间的转换intbool比较时,布尔值,数字或使用xor,这是作用于“按位异或”操作int太迟了。在现代C ++中,使用正确类型的值而不依赖于此类转换有时会更加令人赞赏,因为它们有时不那么清晰且难以推理。对于bool这样的值分别是truefalse而不是10。还!=比说更合适,xor因为从技术上来说,bools是作为数字存储的,但是在语义上您没有任何数字,只是逻辑值。

第二个问题也是关于成语的。它位于:a == 0。将布尔表达式与布尔常量进行比较不是一个好习惯。如您所知,a == true完全等于just a,并且a == false是just !anot a(我更喜欢后者)。要了解比较不佳的原因,只需比较两个代码段并确定,这更加清楚:

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

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

1
尽管从技术上讲是正确的,但该答案完全避免了谈论类型和惯用的C ++,这大概是本练习的重点。
康拉德·鲁道夫

@KonradRudolph,哦,是的,我完全忘记了这一点。也许我会编辑答案,谢谢
Yuri Kovalenko

3

考虑布尔值而不是位

总而言之,您教授的解决方案更好(但严格来说,还是错的,严格来说,请进一步了解),因为它使用布尔运算符而不是按位运算符并将布尔值视为整数。c==1表示“ c为真” 的表达式是错误的,因为如果c可以是数字(根据指定的赋值),则c的任何非零值都将被视为表示true

有关为什么最好不要比较布尔值与0或1的比较,请参见此问题

不使用的一个很好的理由xor是这是按异或运算。它在您的示例中确实起作用,因为左侧和右侧都是布尔表达式,它们都转换为1或0(再次参见1)。

布尔异或实际上是!=

分解表达

为了更好地理解您教授的解决方案,最简单的方法是将布尔运算符替换为等效的“替代令牌”,这将布尔运算符转换为更好的可重现(imho)和完全等效的C ++代码:对“!”使用“ not” 和'and'代表'&&'

    (not a and not b) != c

不幸的是,exclusive_or除之外没有其他逻辑运算符not_eq,在这种情况下这没有帮助。

如果我们分解自然语言表达:

a和b都为假,或者c为真,但不是两个都为真。

首先是关于布尔命题A和B的句子:

A或B,但不能两者都选。

转换为A != B(仅适用于布尔值,不适用于任何类型A和B)。

命题A是

a和b都是假的

可以说是

a为假b为假

转换成(not a and not b),最后

c是真的

简而言之就是c。结合它们,您会再次得到(not a and not b) != c

为了进一步解释此表达式的工作原理,我遵循其他人在其答案中给出的真值表。

你们都错了

而且,如果我可以挑剔:原始赋值指出a,b和c可以是非负数,但并未明确声明如果它们是数字,则应将其限制为值0和1。true按照惯例,如果不是0代表,那么下面的代码将给出一个令人惊讶的答案

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

希望很好ab并且c被声明为bool,在这种情况下c == 1正确的,尽管代码很糟糕。无论如何,这就是我要写的答案:OP的代码可能等同于教授的代码,但是C ++不好。
康拉德·鲁道夫

1
@KonradRudolph来自OP的作业文本:variables are non-negative numbers or boolean。因此,我向@dhavenith +1了,因为他捕捉到了这里大多数其他人(最初包括我)错过的细节。
Frodyne '19

很好,我知道。谢谢!但是您能不能向我解释我教授的解决方案,因为我不理解。
limonade

我为您的教授的解决方案添加了替代拼写。这应该有助于澄清表达。对于更详细的解释,我认为@YuriKovalenko答案中的真值表是处理该表达式的最佳方法。
dhavenith '19

2

我将尝试用更多的词来解释:数字可以隐式转换为布尔值:

零值(用于整数,浮点数和无作用域枚举)以及null指针和null指向成员的值将变为false。所有其他值都变为true。

cppreference的来源

这得出以下结论:

  • a == 0与相同!a,因为a转换为布尔值然后取反,等于!(a != 0)。b也是如此。

  • c==1当将成为唯一的真正c 等于 1.使用转换(bool)c将产生truec != 0不只是如果c == 1。这样就可以了,因为通常使用值1来表示true,但是并没有保证。

  • a != ba xor bwhen abar布尔表达式相同。是的,当一个值或另一个值是正确的,但不是两个都正确时。在这种情况下,左侧(a==0 && b==0)为布尔值,因此右侧也c被转换为布尔值,因此,两侧都被解释为布尔表达式,因此!=xor这种情况相同。

您可以使用其他答案提供的真值表亲自检查所有这些。


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 |

异或

   | a | b |xor|
   | 0 | 0 | 0 |
   | 0 | 1 | 1 |
   | 1 | 0 | 1 |
   | 1 | 1 | 0 |
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.