从自然语言到 C++ 表达式
Posted
技术标签:
【中文标题】从自然语言到 C++ 表达式【英文标题】:From natural language to C++ expression 【发布时间】:2020-03-29 01:09:38 【问题描述】:作业:
将以下自然语言表达式转换为 C++ 表达式。假设所有变量都是非负数或布尔值(值为真或假)。
自然语言:
a 和 b 都为假或 c 为真,但不能同时为真。
我的解决方案:
(a==0 && b==0)xor(c==1)
教授解决方案:
(!a && !b) != c
问题:
我想我稍微理解了第一个括号,通过说“not-a”和“not-b”,我认为 a 和 b 肯定是错误的,前提是假设 a开始。正确的?
但是说“不等于 c”的部分呢?
我不明白教授的解决方案,谁能帮我分解一下?
感谢您的帮助!
【问题讨论】:
一般来说,我会小心将口语布尔表达式转换为代码。一个常见的错误是将“A 等于 B 或 C”翻译成a == b or c
而不是 a == b or a ==c
。问题是口语不准确,实际上两种解释都可能有效
【参考方案1】:
我假设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++ 代码。
第一个小问题是类型的使用。当您将布尔值与数字进行比较或使用xor
时,您的解决方案依赖于int
和bool
之间的转换,这也是作用于int
s 的“按位异或”运算符。在现代 C++ 中,使用正确类型的值而不依赖于此类转换更受赞赏,因为它们有时不太清楚且难以推理。对于bool
,这些值分别是true
和false
,而不是1
和0
。 !=
也比 xor
更合适,因为虽然从技术上讲 bool
s 存储为数字,但从语义上讲,您没有任何数字,只有逻辑值。
第二个问题也是关于惯用语。它就在这里:a == 0
。将布尔表达式与布尔常量进行比较并不是一种好的做法。如您所知,a == true
完全等同于a
,而a == false
只是!a
或not a
(我更喜欢后者)。要了解这种比较不好的原因,只需比较两个代码 sn-ps 并做出决定,这更清楚:
if (str.empty() == false) ...
对
if (not str.empty()) ...
【讨论】:
虽然在技术上是正确的,但这个答案完全避免谈论类型和惯用的 C++,这可能是本练习的重点。 @KonradRudolph,哦,是的,我完全忘了提到这一点。也许我会编辑我的答案,谢谢【参考方案2】:考虑布尔值,而不是位
总而言之,您教授的解决方案更好(但严格来说仍然是错误的,请往下看),因为它使用布尔运算符而不是按位运算符,并将布尔值视为整数。表示“c 为真”的表达式c==1
是不正确的,因为如果 c 可能是一个数字(根据所述赋值),那么 c 的任何非零值都将被视为表示 true
。
请参阅this question,了解为什么最好不要将布尔值与 0 或 1 进行比较,即使这样做是安全的。
不使用xor
的一个很好的理由是这是按位 异或运算。它恰好在您的示例中起作用,因为左侧和右侧都是转换为 1 或 0 的布尔表达式(再次参见 1)。
布尔异或实际上是!=
。
分解表达式
为了更好地理解教授的解决方案,最简单的方法是将布尔运算符替换为“替代标记”等价物,这会将其变成更好的可红色(恕我直言)和完全等效的 C++ 代码: 使用 'not' 代表 '!' 'and' 代表 '&&' 你会得到
(not a and not b) != c
不幸的是,除了not_eq
之外,没有逻辑上的exclusive_or
运算符,这在这种情况下没有帮助。
如果我们分解自然语言表达式:
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。如果有的话非 0 的数字代表true
,按照惯例,那么下面的代码会产生令人惊讶的answer:
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);
【讨论】:
希望a
、b
和c
被声明为bool
,在这种情况下c == 1
是正确,尽管代码很糟糕。无论如何,这就是我会写的答案:OP 的代码可能和教授的代码是等价的,但它是糟糕的 C++。
@KonradRudolph 来自 OP 的作业文本:variables are non-negative numbers or boolean
。因此,我向@dhavenith +1 以捕捉这里大多数其他人错过的细节(包括我,最初)。
太好了,Isee。谢谢!但是你能不能给我解释一下我教授的解决方案,因为我不明白。
我为您教授的解决方案添加了另一种拼写。这应该有助于澄清表达式。对于更详细的解释,我认为@YuriKovalenko 答案中的真值表是处理表达式的最佳方法。【参考方案3】:
我将尝试用更多的词来解释:数字可以隐式转换为布尔值:
值零(对于整数、浮点和无范围枚举)以及空指针和指向成员的空指针值变为假。所有其他值都变为 true。
Source on cppreference
由此得出以下结论:
a == 0
与!a
相同,因为a
被转换为布尔值然后反转,等于!(a != 0)
。 b也是一样。
c==1
仅在c
等于 1. 使用转换(bool)c
将在c != 0
时产生true
而不仅仅是在c == 1
时。所以它可以工作,因为人们通常使用值 1 来表示true
,但并不保证。
a != b
在 a
和 b
是布尔表达式时与 a xor b
相同。这是真的,当一个值或另一个为真时,但不是两者兼而有之。在这种情况下,左侧(a==0 && b==0)
是布尔值,因此右侧c
也被转换为布尔值,因此两边都被解释为布尔表达式,因此!=
与xor
在此相同案例。
您可以使用其他答案提供的真值表自行检查所有这些。
【讨论】:
【参考方案4】:从真值表中我们可以看出:
!
(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 |
【讨论】:
以上是关于从自然语言到 C++ 表达式的主要内容,如果未能解决你的问题,请参考以下文章
最新110G超强C语言和C++编程0基础从入门到精通自学教程免费送!!!