从自然语言到 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】:

我假设abcbool

让我们画一些真值表:

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

如您所见,aa==1 是等价的,!aa==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 时,您的解决方案依赖于intbool 之间的转换,这也是作用于ints 的“按位异或”运算符。在现代 C++ 中,使用正确类型的值而不依赖于此类转换更受赞赏,因为它们有时不太清楚且难以推理。对于bool,这些值分别是truefalse,而不是10!= 也比 xor 更合适,因为虽然从技术上讲 bools 存储为数字,但从语义上讲,您没有任何数字,只有逻辑值。

第二个问题也是关于惯用语。它就在这里:a == 0。将布尔表达式与布尔常量进行比较并不是一种好的做法。如您所知,a == true 完全等同于a,而a == false 只是!anot 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);

【讨论】:

希望abc 被声明为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 != bab 是布尔表达式时与 a xor b 相同。这是真的,当一个值或另一个为真时,但不是两者兼而有之。在这种情况下,左侧(a==0 &amp;&amp; b==0) 是布尔值,因此右侧c 也被转换为布尔值,因此两边都被解释为布尔表达式,因此!=xor 在此相同案例。

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

【讨论】:

【参考方案4】:

从真值表中我们可以看出:

!(not) 和 ==0 给出相同的结果。 !=xor 给出相同的结果。 c==1c 相同

所以一个在另一个之下,说明为什么这两个表达式给出相同的结果:

(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++ 表达式的主要内容,如果未能解决你的问题,请参考以下文章

怎么从C语言过渡到C++

最新110G超强C语言和C++编程0基础从入门到精通自学教程免费送!!!

从硬件到语言,详解C++的内存对齐(memory alignment)

从C语言到C++

详解C++正则表达式,掌握后极大提高开发效率

从C到C++