寻找可以简化的过于复杂的布尔表达式的工具?

发布于 2024-12-04 09:36:33 字数 1539 浏览 0 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

二智少女 2024-12-11 09:36:35

虽然它不能直接在 C/C++ 布尔表达式上工作,但我发现对于简化复杂布尔逻辑非常有用的一个工具是 Logic Friday 。不幸的是它仅适用于 Windows,但幸运的是它是免费的。

Although it doesn't work directly on C/C++ boolean expressions, one tool I've found very useful for simplifying complex boolean logic is Logic Friday. Unfortunately it's Windows-only, but fortunately it's free.

逆流 2024-12-11 09:36:35

您可以通过减少需要检查的“if”数量来提高代码效率。但更简化和更好的可读性并不能自动实现。

You can make the code more efficient by reducing the number of "if"s its need to check. but more simplified and better readability can't be made automatically.

岁月静好 2024-12-11 09:36:35

http://www.freewarepalm.com/educational/booleanfunctionsimplificationtool.shtml

可能值得一试尝试。

然而,通常最好自己做 - 因为可读性和可理解性更重要 - 并让编译器进行简化。

http://www.freewarepalm.com/educational/booleanfunctionsimplificationtool.shtml

might be worth a try.

However it is usually better to do you for yourself - as readability and understandability is more important - and let the compiler do the simplification.

如此安好 2024-12-11 09:36:35

这是一个糟糕的主意!程序员编写的代码反映了他们的思维过程。因此,人类编写的布尔表达式已经自动优化以供人类理解。任何以编程方式改进这一点的尝试都注定会失败。唯一可能有意义的上下文是工具生成的源代码的后处理。

This is such a bad idea! Programmers write code that reflects their thought processes. So boolean expressions as written by humans are already automatically optimised for human comprehension. Any attempt to improve on this programatically is doomed to failure. The only context in which it might make sense is post-processing of tool-generated source code.

揽月 2024-12-11 09:36:35

您需要的是一个可以解析 C++、确定其符号的含义、挑选出布尔方程并对它们应用不违反语义的布尔简化规则的工具。

可以做到这一点的工具是我们的 DMS Software Reengineering Toolkit 及其 C++ 前端。 DMS 旨在对代码进行程序分析和源到源转换。使用 C++ 前端,它可以将 C++ 解析为 AST、构建符号表、推断表达式的类型以及应用重写规则。

人们可以用代码重写这样的规则:

domain Cpp.  -- tell DMS to use the C++ front end

rule factor_common_and_term(e1: condition, e2:condition, e3: condition):
        disjunctive_expression -> disjunctive_expression =
 " \e1 && \e2 ||  \e1 && \e3 " ->  " \e1 && ( \e2 || \e3 ) "
 if no_side_effects(e1) /\ no_side_effects(e2);

分解出一个常见的条件。该规则的名称为“factor_common_and_term”,以将其与人们可能编写的数百个其他规则(例如“distribute_term”等)区分开来。 e1、e2、e3 是表示任意子表达式(根据语法规则属于“条件”类型)的元变量。重写仅对 disjunction_expressions 进行操作;您可以将其设为“只是表达式”,但这样您就不会在其他条件表达式中嵌套析取。重写有一个模式(左)和一个替换(右),两者都用元引号 " 括起来,以区分模式中的 C++ 代码和围绕它的规则语言语法。 \e1 是 C++ 语法的转义,表示元变量可以匹配相应类别的任何语法,因此 \e1 可以是任意复杂的“条件”。事实是e1 在模式中被提及两次,迫使出现的情况相同。

我们可以编写一组重写规则来编码有关简化任意复杂布尔方程的知识;我们已经将这些规则应用于非系统。 - 具有数十万项的 C++ 布尔方程,以及 C 和 C++ 预处理器条件

对于 C++,您需要检查重写是否安全,但如果 e1 有副作用,则不安全。或 e2 有副作用。此检查是通过辅助函数调用进行的,该函数必须以保守的方式确定此答案。对于 C++ 来说,确定没有副作用实际上相当复杂:您必须知道表达式的所有元素是什么,并且它们都没有副作用。

人们可以使用 DMS 的属性语法(一种有组织的树爬行)来检查所有表达式元素。简单的常量和变量(为此需要符号表)不需要。函数调用(包括构造函数等)可以;必须找到它们的定义(同样需要符号表),并进行类似的处理。表达式元素有可能调用单独编译的函数;在这种情况下,保守的答案是“不知道”,因此“假设有副作用”。 DMS 实际上可以同时读取多个编译单元,因此如果您想做到这一点,可以找到、解析/符号解析和爬行单独编译的函数。

所以布尔重写部分非常简单;副作用分析则不然。

我们使用 DMS 对 C++ 代码进行了大量更改;我们经常通过对这样的复杂分析做出假设来作弊。通常我们会感到惊讶,就像程序员感到惊讶一样(“你的意思是,有副作用?”)。大多数情况下它工作得很好。我们对2500万行的C系统做了详细的副作用分析; C++ 还没有完全实现。

仅当某些子表达式可能被多次求值时,副作用分析才有意义。
评论中给出的OP示例不需要它们,可以通过以下规则处理:

rule not_on_disjunction(e1:condition, e2:condition):
    condition -> condition =
  " ! (\e1 || \e2) " ->  " !\e1 && !\e2";

rule double_not(e:condition):
    condition -> condition =
  " ! ! \e " -->  " \e ";

一个完整​​但简单的工作示例,具有更详细的描述是 这个传统代数和一些微积分的代数简化示例

关于特定的代码转换是否会使代码更具可读性,显然存在争议。恕我直言,那是因为代码的形状通常是一种艺术判断,而我们似乎对艺术都有不同意见。这与让其他人修改您的代码没有任何不同。

What you need is a tool that can parse C++, determine the meaning of its symbols, pick out boolean equations, and apply boolean simplification rules to them that don't violate the semantics.

A tool that can do this is our DMS Software Reengineering Toolkit with its C++ Front End. DMS is designed to carry out program analyses and source-to-source transformations on code. Using the C++ Front End, it can parse C++ to ASTs, build up symbol tables, and infer the type of an expression, and apply rewrite rules.

One can code rewrite rules like this:

domain Cpp.  -- tell DMS to use the C++ front end

rule factor_common_and_term(e1: condition, e2:condition, e3: condition):
        disjunctive_expression -> disjunctive_expression =
 " \e1 && \e2 ||  \e1 && \e3 " ->  " \e1 && ( \e2 || \e3 ) "
 if no_side_effects(e1) /\ no_side_effects(e2);

to factor out a common condition. The rule has name "factor_common_and_term" to distinguish it from the often hundreds of other rules one might write (e.g., "distribute_term", etc.). The e1,e2,e3 are metavariables representing arbitrary subexpressions (of type "condition" according to the grammar rules). The rewrite operates only on disjunction_expressions; you could make this be "just expression" but then you would not get disjunctions nested inside other conditional expressions. The rewrite has a pattern (left) and a replacement (right), both wrapped in meta-quotes " to distinguish the C++ code in the patterns from the rule-language syntax surrounding it. The \e1 are escapes from C++ syntax, and indicate where a metavariable can match. Metavariables match any syntax of the corresponding category, so where \e1 is seen can be an arbitrarily complicated "condition". The fact that e1 is mentioned twice in the pattern forces the occurences to be identical.

One can write a set of rewrite rules that encode knowledge about simplifying arbitrarily complex boolean equations; a few dozen rules sort of does it. We've applied these to systems of non-C++ boolean equations with hundreds of thousands of terms, and to C and C++ prepreprocessor conditionals.

For C++, you need a check that the rewrite is safe to do, which it is not if e1 has a side effect, or e2 has a side effect. This check is made with an auxiliary function call that has to determine this answer in a conservative way. The determination that there is no side effect is in fact pretty complex for C++: you have to know what all the elements of the expression are, and that none of them have side effects.

One can do this check with DMS's attribute grammar (an organized tree crawl) that inspects all expression elements. Simple constants and variables (need a symbol table for this) do not. Function calls (including constructors, etc.) may; their definition has to be found (again the need for a symbol table), and processed similarly. It is possible that an expression element calls a separately compiled function; the conservative answer in this case is "don't know" therefore "assume has side effect". DMS can actually read multiple compilation units at the same time, so a separately compiled function can be found, parse/symbol-resolved, and crawled if you want to go that far.

So the boolean rewrite part is pretty easy; the side effect analysis is not.

We've used DMS to carry out massive changes on C++ code; we often cheat a bit by making assumptions about complex analyses like this. Usually we get suprised the same ways programmers get surprised ("What do you mean, that has a side effect?"). Mostly it works pretty well. We have done side-effect analysis in detail on C systems of 25 million lines; not quite there for C++ yet.

The side effect analysis only matters if some subexpression might be evaluated more than once.
OP's example, given in a comment, doesn't need them, and can be handled by the following rules:

rule not_on_disjunction(e1:condition, e2:condition):
    condition -> condition =
  " ! (\e1 || \e2) " ->  " !\e1 && !\e2";

rule double_not(e:condition):
    condition -> condition =
  " ! ! \e " -->  " \e ";

A complete, but simple worked example with more detailed description is this example of algebraic simplification of conventional algebra and some calculus.

There's clearly controversy as to whether a particular code transformation will make code more readable. IMHO, that's because the shape of code is often an art judgement, and we all seem to disagree about art. This isn't any different than letting somebody else modify your code.

拧巴小姐 2024-12-11 09:36:34

人类。

你想要提高可读性,而由于可读性主要是人类的事情,所以应该由人类来教授。

请更有经验的开发人员检查您的表达方式并给出提示。

例如,请参阅我的答案:测试某个值是否落在阈值内的最佳方法(性能方面)是什么?

Humans.

You want to improve readability, and since readability is mostly a human thing it should be taught by a human.

Ask more experienced developers to review your expressions and give tips.

For example, see my answer here: What is the best way (performance-wise) to test whether a value falls within a threshold?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文