我创建了以下代码来计算逻辑门的结果(AND,OR,NOT)。该功能将用于电路仿真中,从网表文件中读取电路。一个电路最多可以包含50000个逻辑门。
基于这个函数通常在仿真过程中被调用的事实,我想知道它是否可以以其他方式实现,从而使生成的机器代码更高效?
一个逻辑门可能有两个以上的输入(除了不是只有一个输入),但是大多数逻辑门只有两个。因此,我考虑过测试两个输入,然后编写如下内容:return input->predecessors[0]->result && return input->predecessors[1]->result;
和return input->predecessors[0]->result || return input->predecessors[1]->result;
,但这可能会引入新的分支。输入的数量可以直接存储在Node
中,以防止调用size()
方法。
#include <vector>
enum class NodeType { NOT, AND, OR };
struct Node {
NodeType type;
bool result;
std::vector<Node *> predecessors;
};
bool evaluate(Node *input) {
switch (input->type) {
case NodeType::NOT: {
return !input->predecessors[0]->result;
}
case NodeType::AND: {
bool result = true;
for (const auto &node : input->predecessors) {
result = result && node->result;
}
return result;
}
case NodeType::OR: {
bool result = false;
for (const auto &node : input->predecessors) {
result = result || node->result;
}
return result;
}
};
};
答案 0 :(得分:1)
我很想获得第一个输入并将其状态合并到switch()
中;喜欢:
bool result = input->predecessors[0];
switch((input->type << 1) | result) {
case (NodeType::NOT << 1) | false:
return true;
case (NodeType::NOT << 1) | true:
return false;
case (NodeType::AND << 1) | false:
return false;
case (NodeType::OR << 1) | true:
return true;
case (NodeType::AND << 1) | true: {
for (const auto &node : input->predecessors) { // Note: Can skip 1st iteration
result = result && node->result;
if(result == false) {
return false;
}
}
return true;
}
case (NodeType::OR << 1) | false:
for (const auto &node : input->predecessors) { // Note: Can skip 1st iteration
result = result || node->result;
if(result == true) {
return true;
}
}
return false;
}
希望编译器能够将其转换为跳转表(例如,一条“ jmp [table+rax*8]
”指令代替所有switch()
和一半的代码)。
警告:要执行此操作,必须确保input->predecessors[0]
为“ true”使用1(并且没有其他值用于true)。如果这是一个潜在的问题;您可以使用bool result = !!input->predecessors[0];
答案 1 :(得分:0)
看起来好像您正在做的是一个界面。
struct Node {
std::vector<Node *> predecessors;
virtual bool evaluate() const;
};
struct NodeNot : Node {
bool evaluate() const {
return !input->predecessors[0]->result;
}
};
struct NodeAnd : Node {
bool evaluate() const {
for (const auto &node : input->predecessors) {
if(!node->result) {
// there is no need to accumulate the result
// fail fast
return false;
}
}
return true;
}
};
struct NodeOr : Node {
bool evaluate() const {
for (const auto &node : input->predecessors) {
if (node->result) {
return true;
}
}
return false;
}
};
这样一来,您完全无需使用switch
,只需一次virtual
调用就可以达到相同的结果。它可能比switch
更快或更慢,它实际上取决于许多因素以及您在Node::result
成员中缓存结果的良好程度。分析您的代码,以确保最有效。
答案 2 :(得分:0)
我正在考虑使用std::variant
。还是有点骇人听闻,因为我使用的是空指针...清理它的任何帮助都很好
#include <tuple>
#include <variant>
#include <stdexcept>
#include <assert.h>
using vcpc = void const* const;
struct NOT { vcpc ptr; };
struct OR { vcpc ptr1; vcpc ptr2; };
struct AND { vcpc ptr1; vcpc ptr2; };
using Node = std::variant<NOT, OR, AND, bool>;
// from https://en.cppreference.com/w/cpp/utility/variant/visit
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
using Ncpc = Node const* const;
constexpr bool evaluate(Ncpc input) {
return std::visit(overloaded{
[](NOT const& arg) { return !evaluate((Ncpc)arg.ptr); },
[](OR const& arg) { return evaluate((Ncpc)arg.ptr1) || evaluate((Ncpc)arg.ptr2); },
[](AND const& arg) { return evaluate((Ncpc)arg.ptr1) && evaluate((Ncpc)arg.ptr2); },
[](bool arg) { return arg; },
}, *input);
}
int main() {
Node const isTrue{ true };
Node const invTrue{ NOT{&isTrue} };
assert(evaluate(&invTrue) == false);
Node const andTrueFalse{ AND{&isTrue, &invTrue} };
assert(evaluate(&andTrueFalse) == false);
Node const orTrueFalse{ OR{&isTrue, &andTrueFalse} };
assert(evaluate(&orTrueFalse) == true);
}