diff options
author | 2019-10-31 21:53:50 +0100 | |
---|---|---|
committer | 2019-10-31 21:53:50 +0100 | |
commit | c6b281685d16c02b83b1b0c89acae392ecf851ff (patch) | |
tree | 2cd979f919b39e1feeffbde0b22462db59a6492a /src/lib/netlist/plib/pfunction.cpp | |
parent | 6c075e602cf83b379b8fa2c981694134b679a538 (diff) |
netlist: Compile with float/double floating point. [Couriersud]
Added ability to compile using float instead of double. Specifically the
the solver as well as the infrastructure now can have their own floating
point type. Currently this is only an academic exercise since
numerically demanding circuits like kidniki only work with double/double
support. Using float here is pushing numerical stability over the
limits.
The long term design goal is too have the matrix type (double/float)
being a parameter.
Diffstat (limited to 'src/lib/netlist/plib/pfunction.cpp')
-rw-r--r-- | src/lib/netlist/plib/pfunction.cpp | 350 |
1 files changed, 179 insertions, 171 deletions
diff --git a/src/lib/netlist/plib/pfunction.cpp b/src/lib/netlist/plib/pfunction.cpp index e4ea2d57163..44254706636 100644 --- a/src/lib/netlist/plib/pfunction.cpp +++ b/src/lib/netlist/plib/pfunction.cpp @@ -16,207 +16,215 @@ namespace plib { -void pfunction::compile(const std::vector<pstring> &inputs, const pstring &expr) -{ - if (plib::startsWith(expr, "rpn:")) - compile_postfix(inputs, expr.substr(4)); - else - compile_infix(inputs, expr); -} - -void pfunction::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr) -{ - std::vector<pstring> cmds(plib::psplit(expr, " ")); - compile_postfix(inputs, cmds, expr); -} - -void pfunction::compile_postfix(const std::vector<pstring> &inputs, - const std::vector<pstring> &cmds, const pstring &expr) -{ - m_precompiled.clear(); - int stk = 0; - - for (const pstring &cmd : cmds) + template <typename NT> + void pfunction<NT>::compile(const std::vector<pstring> &inputs, const pstring &expr) { - rpn_inst rc; - if (cmd == "+") - { rc.m_cmd = ADD; stk -= 1; } - else if (cmd == "-") - { rc.m_cmd = SUB; stk -= 1; } - else if (cmd == "*") - { rc.m_cmd = MULT; stk -= 1; } - else if (cmd == "/") - { rc.m_cmd = DIV; stk -= 1; } - else if (cmd == "pow") - { rc.m_cmd = POW; stk -= 1; } - else if (cmd == "sin") - { rc.m_cmd = SIN; stk -= 0; } - else if (cmd == "cos") - { rc.m_cmd = COS; stk -= 0; } - else if (cmd == "trunc") - { rc.m_cmd = TRUNC; stk -= 0; } - else if (cmd == "rand") - { rc.m_cmd = RAND; stk += 1; } + if (plib::startsWith(expr, "rpn:")) + compile_postfix(inputs, expr.substr(4)); else + compile_infix(inputs, expr); + } + + template <typename NT> + void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs, const pstring &expr) + { + std::vector<pstring> cmds(plib::psplit(expr, " ")); + compile_postfix(inputs, cmds, expr); + } + + template <typename NT> + void pfunction<NT>::compile_postfix(const std::vector<pstring> &inputs, + const std::vector<pstring> &cmds, const pstring &expr) + { + m_precompiled.clear(); + int stk = 0; + + for (const pstring &cmd : cmds) { - for (std::size_t i = 0; i < inputs.size(); i++) + rpn_inst rc; + if (cmd == "+") + { rc.m_cmd = ADD; stk -= 1; } + else if (cmd == "-") + { rc.m_cmd = SUB; stk -= 1; } + else if (cmd == "*") + { rc.m_cmd = MULT; stk -= 1; } + else if (cmd == "/") + { rc.m_cmd = DIV; stk -= 1; } + else if (cmd == "pow") + { rc.m_cmd = POW; stk -= 1; } + else if (cmd == "sin") + { rc.m_cmd = SIN; stk -= 0; } + else if (cmd == "cos") + { rc.m_cmd = COS; stk -= 0; } + else if (cmd == "trunc") + { rc.m_cmd = TRUNC; stk -= 0; } + else if (cmd == "rand") + { rc.m_cmd = RAND; stk += 1; } + else { - if (inputs[i] == cmd) + for (std::size_t i = 0; i < inputs.size(); i++) + { + if (inputs[i] == cmd) + { + rc.m_cmd = PUSH_INPUT; + rc.m_param = static_cast<double>(i); + stk += 1; + break; + } + } + if (rc.m_cmd != PUSH_INPUT) { - rc.m_cmd = PUSH_INPUT; - rc.m_param = static_cast<double>(i); + rc.m_cmd = PUSH_CONST; + bool err(false); + rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err); + if (err) + throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); stk += 1; - break; } } - if (rc.m_cmd != PUSH_INPUT) - { - rc.m_cmd = PUSH_CONST; - bool err(false); - rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err); - if (err) - throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr)); - stk += 1; - } + if (stk < 1) + throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr)); + m_precompiled.push_back(rc); } - if (stk < 1) - throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr)); - m_precompiled.push_back(rc); + if (stk != 1) + throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr)); } - if (stk != 1) - throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr)); -} - -static int get_prio(const pstring &v) -{ - if (v == "(" || v == ")") - return 1; - else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") - return 0; - else if (v == "*" || v == "/") - return 20; - else if (v == "+" || v == "-") - return 10; - else if (v == "^") - return 30; - else - return -1; -} - -static pstring pop_check(std::stack<pstring> &stk, const pstring &expr) -{ - if (stk.size() == 0) - throw plib::pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr)); - pstring res = stk.top(); - stk.pop(); - return res; -} - -void pfunction::compile_infix(const std::vector<pstring> &inputs, const pstring &expr) -{ - // Shunting-yard infix parsing - std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"}; - std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep)); - std::stack<pstring> opstk; - std::vector<pstring> postfix; - - for (std::size_t i = 0; i < sexpr.size(); i++) + + static int get_prio(const pstring &v) { - pstring &s = sexpr[i]; - if (s=="(") - opstk.push(s); - else if (s==")") - { - pstring x = pop_check(opstk, expr); - while (x != "(") - { - postfix.push_back(x); - x = pop_check(opstk, expr); - } - if (opstk.size() > 0 && get_prio(opstk.top()) == 0) - postfix.push_back(pop_check(opstk, expr)); - } - else if (s==",") + if (v == "(" || v == ")") + return 1; + else if (plib::left(v, 1) >= "a" && plib::left(v, 1) <= "z") + return 0; + else if (v == "*" || v == "/") + return 20; + else if (v == "+" || v == "-") + return 10; + else if (v == "^") + return 30; + else + return -1; + } + + static pstring pop_check(std::stack<pstring> &stk, const pstring &expr) + { + if (stk.size() == 0) + throw plib::pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr)); + pstring res = stk.top(); + stk.pop(); + return res; + } + + template <typename NT> + void pfunction<NT>::compile_infix(const std::vector<pstring> &inputs, const pstring &expr) + { + // Shunting-yard infix parsing + std::vector<pstring> sep = {"(", ")", ",", "*", "/", "+", "-", "^"}; + std::vector<pstring> sexpr(plib::psplit(plib::replace_all(expr, " ", ""), sep)); + std::stack<pstring> opstk; + std::vector<pstring> postfix; + + for (std::size_t i = 0; i < sexpr.size(); i++) { - pstring x = pop_check(opstk, expr); - while (x != "(") + pstring &s = sexpr[i]; + if (s=="(") + opstk.push(s); + else if (s==")") { - postfix.push_back(x); - x = pop_check(opstk, expr); + pstring x = pop_check(opstk, expr); + while (x != "(") + { + postfix.push_back(x); + x = pop_check(opstk, expr); + } + if (opstk.size() > 0 && get_prio(opstk.top()) == 0) + postfix.push_back(pop_check(opstk, expr)); } - opstk.push(x); - } - else { - int p = get_prio(s); - if (p>0) + else if (s==",") { - if (opstk.size() == 0) - opstk.push(s); - else + pstring x = pop_check(opstk, expr); + while (x != "(") { - if (get_prio(opstk.top()) >= get_prio(s)) - postfix.push_back(pop_check(opstk, expr)); - opstk.push(s); + postfix.push_back(x); + x = pop_check(opstk, expr); } + opstk.push(x); } - else if (p == 0) // Function or variable - { - if (sexpr[i+1] == "(") - opstk.push(s); + else { + int p = get_prio(s); + if (p>0) + { + if (opstk.size() == 0) + opstk.push(s); + else + { + if (get_prio(opstk.top()) >= get_prio(s)) + postfix.push_back(pop_check(opstk, expr)); + opstk.push(s); + } + } + else if (p == 0) // Function or variable + { + if (sexpr[i+1] == "(") + opstk.push(s); + else + postfix.push_back(s); + } else postfix.push_back(s); } - else - postfix.push_back(s); } + while (opstk.size() > 0) + { + postfix.push_back(opstk.top()); + opstk.pop(); + } + compile_postfix(inputs, postfix, expr); } - while (opstk.size() > 0) - { - postfix.push_back(opstk.top()); - opstk.pop(); - } - compile_postfix(inputs, postfix, expr); -} -#define ST1 stack[ptr] -#define ST2 stack[ptr-1] + #define ST1 stack[ptr] + #define ST2 stack[ptr-1] -#define OP(OP, ADJ, EXPR) \ -case OP: \ - ptr-= (ADJ); \ - stack[ptr-1] = (EXPR); \ - break; + #define OP(OP, ADJ, EXPR) \ + case OP: \ + ptr-= (ADJ); \ + stack[ptr-1] = (EXPR); \ + break; -double pfunction::evaluate(const std::vector<double> &values) noexcept -{ - std::array<double, 20> stack = { 0 }; - unsigned ptr = 0; - stack[0] = 0.0; - for (auto &rc : m_precompiled) + template <typename NT> + NT pfunction<NT>::evaluate(const std::vector<NT> &values) noexcept { - switch (rc.m_cmd) + std::array<NT, 20> stack = { 0 }; + unsigned ptr = 0; + stack[0] = 0.0; + for (auto &rc : m_precompiled) { - OP(ADD, 1, ST2 + ST1) - OP(MULT, 1, ST2 * ST1) - OP(SUB, 1, ST2 - ST1) - OP(DIV, 1, ST2 / ST1) - OP(POW, 1, std::pow(ST2, ST1)) - OP(SIN, 0, std::sin(ST2)) - OP(COS, 0, std::cos(ST2)) - OP(TRUNC, 0, std::trunc(ST2)) - case RAND: - stack[ptr++] = lfsr_random(); - break; - case PUSH_INPUT: - stack[ptr++] = values[static_cast<unsigned>(rc.m_param)]; - break; - case PUSH_CONST: - stack[ptr++] = rc.m_param; - break; + switch (rc.m_cmd) + { + OP(ADD, 1, ST2 + ST1) + OP(MULT, 1, ST2 * ST1) + OP(SUB, 1, ST2 - ST1) + OP(DIV, 1, ST2 / ST1) + OP(POW, 1, std::pow(ST2, ST1)) + OP(SIN, 0, std::sin(ST2)) + OP(COS, 0, std::cos(ST2)) + OP(TRUNC, 0, std::trunc(ST2)) + case RAND: + stack[ptr++] = lfsr_random(); + break; + case PUSH_INPUT: + stack[ptr++] = values[static_cast<unsigned>(rc.m_param)]; + break; + case PUSH_CONST: + stack[ptr++] = rc.m_param; + break; + } } + return stack[ptr-1]; } - return stack[ptr-1]; -} + + template struct pfunction<float>; + template struct pfunction<double>; } // namespace plib |