C++通过逻辑函数生成真值表

Wednesday, March 1, 2023
本文共775字
2分钟阅读时长

⚠️本文是作者P3troL1er原创,首发于https://peterliuzhi.top/posts/c++%E9%80%9A%E8%BF%87%E9%80%BB%E8%BE%91%E5%87%BD%E6%95%B0%E7%94%9F%E6%88%90%E7%9C%9F%E5%80%BC%E8%A1%A8/。商业转载请联系作者获得授权,非商业转载请注明出处!

Yesterday is history. Tomorrow is a mystery. And today? Today is a gift. That is why we call it the present. — Babatunde Olatunji

引入

手写真值表极其繁琐又无聊,于是我想着能不能用C++生成一个可读性高的真值表

使用了库GitHub - p-ranav/tabulate: Table Maker for Modern C++,这是一个header-only的库,源代码全部写在头文件里面,不用单独编译。

具体的教程可以看下面两篇:

总之只需要引入single_include/tabulate/tabulate.hpp就能直接用了

具体代码

传入一个函数指针来表示逻辑函数,可以用make_basic_func来跳过一些繁琐的数据处理,直接写逻辑表达式:

#include <functional>
#include <initializer_list>
#include <stdint.h>
#include <string>

#include "tabulate.hpp"

typedef std::function<bool(uint64_t, char)> FUNC;
typedef std::function<bool(std::vector<bool>)> BINARY_EXPRESSION;

inline bool ImplicationForm(bool var1, bool var2)
{
    return (!var1 || var2);
}

inline bool XNOR(bool var1, bool var2)
{
    return !(var1 ^ var2);
}

inline bool EquivalentForm(bool var1, bool var2)
{
    // 相当于同或
    return XNOR(var1, var2);
}

inline bool NAND(bool var1, bool var2)
{
    // 与非联结词
    return !(var1 && var2);
}

inline bool NOR(bool var1, bool var2)
{
    // 或非联结词
    return !(var1 || var2);
}

tabulate::Table func_to_truth_table(const std::initializer_list<FUNC>& func_list, const std::initializer_list<std::string>& vars)
{
    const auto var_size = vars.end() - vars.begin();
    if (var_size > 63) {
        std::cerr << "无法处理超过63个变量!" << std::endl;
        return tabulate::Table();
    }

    tabulate::Table table;
    // 插入头部
    tabulate::Table::Row_t header;
    header.insert(header.end(), vars.begin(), vars.end());
    for (int i = 0; i < func_list.end() - func_list.begin(); i++) {
        header.push_back("Result" + std::to_string(i));
    }
    table.add_row(header);
    for (auto& cell : table[0]) {
        cell.format()
            .font_color(tabulate::Color::blue)
            .font_style({ tabulate::FontStyle::bold, tabulate::FontStyle::underline })
            .font_align(tabulate::FontAlign::center);
    }
    uint64_t var_truth = 0;
    uint64_t max_size = (uint64_t)0x1 << var_size;
    for (uint64_t i = 0; i < max_size; i++) {
        tabulate::Table::Row_t onerow;
        for (char j = (var_size - 1); j >= 0; j--) {
            onerow.push_back(std::to_string((var_truth >> j) & 0x1));
        }
        for (auto& f : func_list) {
            onerow.push_back(std::to_string((int)f(var_truth, (char)var_size)));
        }
        ++var_truth;
        table.add_row(onerow);
        for (auto& cell : table[i + 1]) {
            cell.format()
                .font_align(tabulate::FontAlign::center);
        }
    }
    for (int i = 0; i < func_list.end() - func_list.begin(); i++) {
        for (auto& cell : table.column(var_size + i)) {
            cell.format()
                .font_style({ tabulate::FontStyle::bold });
        }
    }
    return table;
}

tabulate::Table func_to_truth_table(const FUNC f, const std::initializer_list<std::string>& vars)
{
    return func_to_truth_table({ f }, vars);
}

FUNC make_basic_func(BINARY_EXPRESSION f)
{
    std::function<bool(uint64_t, char)> ret = [f](uint64_t truth, char length) -> bool {
        bool val = truth & 0x1;
        std::vector<bool> val_list;
        for (int i = length - 1; i >= 1; i--) {
            val_list.push_back((truth >> i) & 0x1);
        }
        val_list.push_back(val);
        return f(val_list);
    };
    return ret;
}

int main(int argc, char const* argv[])
{
    // ∨∧→↔┐
    std::cout << "p ∧ r ∧ ┐(q → p):" << std::endl;
    std::cout << func_to_truth_table(make_basic_func([](std::vector<bool> val_list) -> bool {
        return val_list[0] && val_list[2] && (!ImplicationForm(val_list[1], val_list[0]));
    }),
        { "p", "q", "r" })
              << std::endl;
    std::initializer_list<FUNC> func_list {
        make_basic_func([](std::vector<bool> val_list) -> bool {
            return val_list[0] && val_list[2] && (!ImplicationForm(val_list[1], val_list[0]));
        }),
        make_basic_func([](std::vector<bool> val_list) -> bool {
            return ImplicationForm(ImplicationForm(val_list[0], val_list[1]), ImplicationForm(!val_list[1], !val_list[0])) || val_list[2];
        }),
        make_basic_func([](std::vector<bool> val_list) -> bool {
            return EquivalentForm(ImplicationForm(val_list[0], val_list[1]), ImplicationForm(val_list[0], val_list[2]));
        })
    };

    func_to_truth_table(func_list, { "p", "q", "r" }).print(std::cout);
    return 0;
}

效果:

文内图片

不知道是什么原因,下划线和粗体在Windows上都无法生效(博主还没在Linux上测试过),但是效果海星(至少够用