为啥用析取范式表达代码很重要?

Posted

技术标签:

【中文标题】为啥用析取范式表达代码很重要?【英文标题】:Why is it important to express code in Disjunctive Normal Form?为什么用析取范式表达代码很重要? 【发布时间】:2011-07-04 18:26:33 【问题描述】:

在我工作的公司,最近有一项要求,所有“高度可见”的布尔逻辑必须以析取范式表示。

例如(尽管这个概念与语言无关),

#if (defined(A) || defined( B )) || (defined(C) && defined(D))

必须替换为:

#if defined(A) || (defined(C) && defined(D)) || defined(B)

要求必须以这种方式表达代码的动机是什么?有什么优势?

【问题讨论】:

两个表达式都在 DNF 中;第一个只是有一些多余的括号。这是您的编码指南中的实际示例吗? 该示例来自最近的一个电子邮件链,该电子邮件链要求基于 DNF 进行更改。为这个错误道歉,因为它确实是一个糟糕的例子。 【参考方案1】:

优势在于,在代码库中的任何地方以规范/规范化形式表达此类逻辑(理论上)将使程序员更容易理解和维护它。

如果没有这样的规则,一些程序员倾向于尝试“优化”一个表达式,这样维护者就很难解开它。此外,如果有必要,通用形式可以更轻松地编写新表达式。

(这些优势值得商榷。与任何风格准则一样,遵循一致的规则比选择一条规则而不是替代规则更重要。)

【讨论】:

【参考方案2】:

虽然你的例子很糟糕(两个表达式都在 DNF 中),但我明白为什么有人会强加这个政策。

任何范式的优点是所有表达式现在都具有相同的形式。在 DNF 中,该形式是子句/条件的列表,其中一个必须为真。子句依次是文字/条件列表,每个条件都必须为真。

DNF 特别有一个优势,在大多数语法中,and 的优先级高于 or,而 not 的优先级更高,所以 DNF需要的括号比 CNF 少,省略括号不是错误。

【讨论】:

【参考方案3】:

很多时候,您拥有的编码标准并不像始终如一地实施它们那么重要。始终如一地编写代码大大提高了可读性,而且很多时候,决定选择哪些代码的人是在行使个人偏好,而不是编码智慧。

假设您列出的标准确实有帮助。我想说大多数人没有意识到 && 运算符比 || 具有更高的运算符优先级。因此,在 && 运算符和操作数周围使用 () 有助于使事情更加明确。

请始终记住,在许多语言中,如果仅在计算其中一个操作数后可以确定表达式的值,则可能不会执行布尔表达式的两个操作数。如:

1: (trueMethod() || falseMethod())

2: (falseMethod() || trueMethod())

万一只有一个 trueMethod() 被执行。但在案例 2 中,两种方法都被执行。顺序可以产生很大的影响。

【讨论】:

以上是关于为啥用析取范式表达代码很重要?的主要内容,如果未能解决你的问题,请参考以下文章

利用真值表法求取主析取范式以及主合取范式的实现(C++)

将析取范式转化为主析取范式

将命题转化为主析取命范式和主合取范式

为啥我们将没有一个是肯定的文字的析取称为目标从句?

为啥替代品的顺序在正则表达式中很重要?

数理逻辑命题逻辑的等值演算与推理演算 ( 命题逻辑 | 等值演算 | 主合取 ( 析取 ) 范式 | 推理演算 ) ★★