【问题标题】:How to get truth table of function (( c + ~d ) * b ) * ~( d + a * e )如何获得函数的真值表 (( c + ~d ) * b ) * ~( d + a * e )
【发布时间】:2021-02-07 02:09:05
【问题描述】:

所以我有等式 (( c + ~d ) * b ) * ~( d + a * e ) 我试图生成一个真值表,但我不确定我什至如何开始程序根据真值表计算变量是否应该等于真或假。关于如何做到这一点的任何建议?提前谢谢你。

#include<iostream>

using namespace std;

bool checkBoolTF(int a){
    bool TF;
    if(a == 0){
        TF = false;
    }
    else{
        TF = true;
    }
    return TF;
}

int main()
{
  int a,b,c,d,e;
  bool aBool, bBool, cBool, dBool, eBool;

  string equation = "(( c + ~d ) * b ) * ~( d + a * e )";
  bool equationTF;


  //LOOP TO TRUTH TABLE - FINAL VALUES
  cout << "----------------------------------------------------------------------" << endl;
  cout << "|  a  |  b  |  c  |  d  |  e  |  " << equation << "  |" << endl;
  cout << "----------------------------------------------------------------------" << endl;
    for(a=0;a<=1;a++){
        checkBoolTF(a);
            for(b=0;b<=1;b++){
                checkBoolTF(b);
                    for(c=0;c<=1;c++){
                        checkBoolTF(c);
                            for(d=0;d<=1;d++){
                                checkBoolTF(d);
                                    for(e=0;e<=1;e++){
                                        checkBoolTF(e);
                                        cout << "|  " << a << "  |  " << b <<  "  |  " << c <<  "  |  " << d <<  "  |  " << e << "  |                   "  << equationTF << "                |" << endl;
                                        cout << "----------------------------------------------------------------------" << endl;
                                    }
                            }
                    }
            }
    }
    return 0;
}

【问题讨论】:

  • 你必须解析字符串(( c + ~d ) * b ) * ~( d + a * e )吗?或者是否允许通过一些转换对公式进行硬编码以将其用作 C++ 表达式?
  • 它必须被解析。可悲的是不能硬编码。
  • + 和 * 分别表示 OR 和 AND 吗?
  • 是的@Eugene
  • @RonBaker 是的,解析树比数学表达式所需的要复杂得多。查找调车场算法。它提供了一种将表达式从中缀表示法(我们在输入字符串中看到的)转换为一种后缀表示法的方法,例如c d ~ + b * d a e * + ~ *(如果我输入正确,它与您指定的表达式相同),其中后缀输入的形式更容易评估

标签: c++ truthtable


【解决方案1】:

我想展示一个额外的、已经存在的解决方案。它的结构和评论都很好。它在 github 上发布。请看here

该程序的预期目的是计算 MCDC 测试对。但它当然也可以满足您的所有需求。我不建议复制和粘贴,但您可以阅读并学习如何进行实施。

此代码准确读取您指定的字符串。它还创建了一个真值表。但这只是整个功能的一小部分。

因此,您需要做的是,将字符串编译为可以作为布尔表达式进行评估的内容。

为此,我首先定义了输入字母和语言,由语法描述。然后,我创建了一个编译器,由扫描器(词法分析器)、解析器和代码生成器组成。实际上我创建了 2 个编译器,具有相同的前端和 2 个不同的后端。因此,有 2 个不同的代码生成器。一,对于可以评估输入变量的任何组合的布尔表达式的虚拟机。并且,第二个后端将创建一个抽象语法树,我用它评估所有可能的 MCDC 测试对。

如前所述,第一个代码生成器为虚拟机创建 Op 代码。使用这台机器,计算真值表和所有最小项。然后使用 Quine 和 McCluskey(2 种不同的实现)来最小化布尔表达式。最后,利用优化后的Petricks方法求解单覆盖问题,识别最小质蕴涵集。

MCDC 部分可能有点过于复杂,无法在这里解释。

但主要信息是,您首先需要解析字符串并将其转换为可执行文件。

然后你可以评估任何你想要的。

【讨论】:

    【解决方案2】:

    第 1 步:标记化。

    enum class TokenType {
      bracket, binop, binaryop, var, literal
    };
    struct Token {
      TokenType type;
      char value;
     };
    

    将字符串转换为token的向量。

    您还没有使用literal:它是值 0 或 1。稍后您将使用它。

    编写漂亮地打印标记向量的代码。

    第 2 步:制作一棵简单的树。

    struct Tree {
      bool is_token=true;
      Token token;
      std::vector<Tree> tree;
    };
    

    更改您的第一个代码以生成包含标记向量的树。

    编写漂亮的打印代码。测试。

    第 3 步:减少树

    第 3a 步:括号

    现在做一个归约步骤;遍历树的向量并生成一个。它会盲目地将不是括号的所有内容复制到输出中。如果它看到 (,它会将所有内容复制到 匹配 )(计数打开和关闭)到子树中,然后将该子树复制到输出中。

    它需要"a ( b c )" 并使其成为a 然后b c 在子树中。

    编写可以漂亮地打印子树的代码。测试。

    步骤 3b:嵌套括号

    接下来,对你创建的子树进行递归,因此它的嵌套括号也被放入子树中。

    第 3c 步:运算符

    接下来,研究运算符。 ~ 很简单:它吞​​下向量中的下一棵树。由于+* 绑定失败者,因此为每个+ 创建两个子树;一个用于之前的一切,一个用于之后的一切。然后对* 执行相同的传递。

    在这一切之后,你转身

    a+(b+c)*~(d+e)
    

    进入

    +  (a , ( * (+ (b, c), ~(+(d,e))))
    

    第 4 步:替换

    映射一个将变量映射到一个值的std::map。获取一棵树的副本,然后遍历它,用与其值相等的文字替换每个变量。

    第 5 步:评估

    对于每个运算符,评估子树然后应用运算符。

    结果应该是 0 或 1。

    4 和 5 可以独立完成,以文字表达式开头。

    【讨论】:

      【解决方案3】:

      所以我有一个个人程序,它为带有表单的字符串实现这一点 "Ab|c(d|E)|fa"

      我的完整源代码完全是一团糟,并且包含我正在尝试同时做的几件事(未能通过圈出 kmaps 和其他东西来简化表达式)

      但是,如果有帮助,我可以逐步完成我所做的事情

      它的设置对我来说更容易解析,大写字母代表正数,小写字母代表否定/非 () 代表子表达式,[] 代表否定子表达式 所以输入字符串 `"ABC(DEF)G(HI(KK)S[as][ge])S" 被转换成这个 .repr() 结构

      AND(
        A
        B
        C
        AND( D E F )
        G
        AND(
          H
          I
          AND( K K )
          S
          NAND( !A !S )
          NAND( !G !E )
        )
        S
      )
      

      "Ab|cb" 这样的东西是

      OR(
        AND( A !B )
        AND( !C !B )
      )
      

      我有一个对象(我称之为表达式),其中包含有关其类型的信息,存储在以下内容中

      namespace xpr { //expression types
      enum typ {
          identity_,
          negation_,
          and_,
          or_,
          nand_,
          nor_
      };
      }
      
      
      class expression{
      ...
      
          xpr::typ type = xpr::identity_;
          char value = ' ';
          std::vector<expression> sub_expressions;
      ...
      };
      

      以及作为其值的 char 或表达式向量。 (and or nor nand 表达式)

      将其解析为这种表达式形式是通过嵌套构造函数完成的,这些构造函数不断传递字符串中的当前位置及其级别。

      终于回答你的问题了

      std::vector<char> vars = trackUsed();
          // equivalent to a set but more efficent to do the sort/unique at the end one time.
      removeDuplicates(vars);
      
      const auto truth_table_width = vars.size();
      const auto truth_table_size = (size_t)std::pow((size_t)2, truth_table_width); // 2^width
      expression::test_type test; // abc through !a!b!c
      test.reserve(truth_table_width);
      for ( const auto &v : vars ) {
          // value_type is value: 6, sign: 2 so character has to fit in 6bits and sign in 2.
          // minus 'A' to make A-Z 0-26
          test.emplace_back(v - 'A', xpr::negative);
      }   
      
      for ( size_t i = 0; i < truth_table_size; i++ ) {
          for ( size_t j = 0; j < truth_table_width; j++ ) {
              // converts 0 to negative and 1 to positive
              test[j].sign = (xpr::sign_type)((i >> j) & 0x1);
          }
          bool valid = testValues(test);
          if ( valid ) {
              sum_of_products.push_back(test);
          }
      }
      

      我通过提取所有用于删除重复的字符并对它们进行排序来建立一个真值表。制作一个矢量> 将一个值增加到最大真值表宽度并使用该值的符号位来填充真值表 - 0 = [0, 0, ... 1 = [1, 0, ... 2 = [0, 1, ... 等等 然后循环遍历外部向量并将内部向量发送到专门针对每种表达式类型的“testValues”成员函数

      // given A true B true C true see if whole expression evaluates to true. 
      bool expression::testValues(const potion::test_type& values) const {
          if ( this->is_simple() ) {
              auto val = std::lower_bound(values.begin(), values.end(),
                                          this->value,
                                          [ ](potion::val_type lhs, char rhs) -> bool {return lhs < rhs; }
              );
              if ( type == xpr::identity_ ) return (*val).sign;
              if ( type == xpr::negation_ ) return !(*val).sign;
          }
          if ( type == xpr::and_ || type == xpr::nand_ ) {
              const bool is_and = type == xpr::and_; //used to combine and and nand expressions and return the oposite val for nand
              for ( const auto& e : sub_expressions ) {
                  if ( e.testValues(values) == false ) return !is_and; // short circuit- if b is false then abc is false
              }
              return is_and;
          }
          if ( type == xpr::or_ || type == xpr::nor_ ) {
              const bool is_or = type == xpr::or_; //used to combine or and nor and return the oposite val for nor
              for ( const auto& e : sub_expressions ) {
                  if ( e.testValues(values) == true ) return is_or; // short circuit- if b is true then a|b|c is true
              }
              return !is_or;
          }
          throw std::runtime_error("Expression can't be simplified. Type not valid"); //should never happen
          return false;
      }
      

      显然有很多样板代码/解析代码可能不是最好的。如果您想使用“自定义语言”解析字符串,您正在定义“((c + ~d)* b)*~(d + a * e)” 那么解析代码显然会有很大的不同。

      无论如何,我希望这对您的项目有所帮助。 TLDR:实施起来可能比您最初想象的要难一些。尽管我所做的一切都是功能性的,但代码并不是最干净的,并且对于我的特定情况而言,它的设置很繁重——仅获取具有正数的真值表条目并将它们存储在可以进一步处理的产品总和中。

      【讨论】:

        【解决方案4】:

        首先,您可以将 checkBoolTF 函数简化为:

        bool checkBoolTF (int a)
        {
            return !(a==0);
        }
        

        其次,似乎在 for 循环中,此函数返回的值没有分配给任何东西,因此丢失了。所以你可能想定义一个辅助变量:

        bool auxA = checkBoolTF(a);
        

        等等..

        【讨论】:

          猜你喜欢
          • 2012-01-27
          • 2013-06-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-23
          相关资源
          最近更新 更多