tree changes
This commit is contained in:
1209
libs/main/math/pievaluator.cpp
Normal file
1209
libs/main/math/pievaluator.cpp
Normal file
@@ -0,0 +1,1209 @@
|
||||
/*
|
||||
PIP - Platform Independent Primitives
|
||||
Evaluator designed for stream computing
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pievaluator.h"
|
||||
|
||||
|
||||
/*! \class PIEvaluator
|
||||
* \brief This class provide mathematical evaluations of custom expression
|
||||
*
|
||||
* \section PIEvaluator_sec0 Synopsis
|
||||
* %PIEvaluator developed for stream evaluations of once set expression.
|
||||
* It`s create internal list of instructions on function \a check() and
|
||||
* executes very fast on function \a evaluate(). Once given expression
|
||||
* can be evaluated any times with different variable values. Evaluator
|
||||
* supports many common mathematic functions described below. Also it`s
|
||||
* automatic puts unnecessarily signs and bracets. Processed expression
|
||||
* can be obtains with function \a expression(). If there is an error
|
||||
* in expression you can get it with function \a error(). Last evaluated
|
||||
* result you can get with function \a lastResult().
|
||||
* \section PIEvaluator_sec1 Using
|
||||
* First you should set your variables with function \a setVariable().
|
||||
* Next give your expression with function \a check() and check for error
|
||||
* with functions \a isCorrect() and \a error(). If expression is correct
|
||||
* you can get processed expression with function \a expression() and
|
||||
* evaluate it with function \a evaluate(). You can change variable values
|
||||
* without rechecking expression.
|
||||
*
|
||||
* \section PIEvaluator_sec2 Functions
|
||||
* %PIEvaluator supports arithmetical operations with complex numbers, this
|
||||
* is their list in priority order:
|
||||
* * ^ (power)
|
||||
* * * (multiply)
|
||||
* * / (divide)
|
||||
* * % (residue)
|
||||
* * + (add)
|
||||
* * - (subtract)
|
||||
*
|
||||
* In addition there are compare and logical operations:
|
||||
* * == (equal)
|
||||
* * != (not equal)
|
||||
* * > (greater)
|
||||
* * < (smaller)
|
||||
* * >= (greater or equal)
|
||||
* * <= (smaller or equal)
|
||||
* * && (and)
|
||||
* * || (or)
|
||||
*
|
||||
* Compare and logical functions works with real operators part and returns 0 or 1.
|
||||
*
|
||||
* Mathematical functions:
|
||||
* * sin(x) - sine
|
||||
* * cos(x) - cosine
|
||||
* * tg(x) - tangent
|
||||
* * ctg(x) - cotangent
|
||||
* * arcsin(x) - arcsine
|
||||
* * arccos(x) - arccosine
|
||||
* * arctg(x) - arctangent
|
||||
* * arcctg(x) - arccotangent
|
||||
* * sh(x) - hyperbolical sine
|
||||
* * ch(x) - hyperbolical cosine
|
||||
* * th(x) - hyperbolical tangent
|
||||
* * cth(x) - hyperbolical cotangent
|
||||
* * sqr(x) - square
|
||||
* * sqrt(x) - square root
|
||||
* * abs(x) - absolute value
|
||||
* * sign(x) - sign of real part (-1 or 1)
|
||||
* * exp(x) - exponent
|
||||
* * pow(x, p) - x in power p
|
||||
* * ln(x) - natural logarithm
|
||||
* * lg(x) - decimal logarithm
|
||||
* * log(x, b) - logarithm of x with base b
|
||||
* * im(x) - imaginary part of complex number
|
||||
* * re(x) - real part of complex number
|
||||
* * arg(x) - argument of complex number
|
||||
* * len(x) - length of complex number
|
||||
* * conj(x) - length of complex number
|
||||
* * rad(x) - convert degrees to radians
|
||||
* * deg(x) - convert radians to degrees
|
||||
* * j0(x) - Bessel function first kind order 0
|
||||
* * j1(x) - Bessel function first kind order 1
|
||||
* * jn(x, n) - Bessel function first kind order n
|
||||
* * y0(x) - Bessel function second kind order 0
|
||||
* * y1(x) - Bessel function second kind order 1
|
||||
* * yn(x, n) - Bessel function second kind order n
|
||||
* * random(s, a) - regular random with shift s and amp a
|
||||
* * randomn(s, a) - normalize random with shift s and amp a
|
||||
* * min(x0, x1, ...) - minimum of x0, x1, ...
|
||||
* * max(x0, x1, ...) - maximum of x0, x1, ...
|
||||
* * clamp(x, a, b) - trim x on range [a, b]
|
||||
* * step(x, s) - 0 if x < s, else 1
|
||||
* * mix(x, a, b) - interpolate between a and b linear for x (a * (1 - x) + b * x)
|
||||
* * round(x) - round
|
||||
*
|
||||
* There are some built-in constans:
|
||||
* * i (imaginary 1)
|
||||
* * e
|
||||
* * pi
|
||||
*
|
||||
* All trigonometric functions takes angle in radians.
|
||||
*
|
||||
* \section PIEvaluator_sec3 Example
|
||||
* \snippet pievaluator.cpp main
|
||||
*/
|
||||
|
||||
using namespace PIEvaluatorTypes;
|
||||
|
||||
|
||||
PIEvaluatorContent::PIEvaluatorContent() {
|
||||
addFunction("arcsin", 1);
|
||||
addFunction("arccos", 1);
|
||||
addFunction("arctg", 1);
|
||||
addFunction("arcctg", 1);
|
||||
addFunction("random", 2);
|
||||
addFunction("randomn", 2);
|
||||
addFunction("sin", 1);
|
||||
addFunction("cos", 1);
|
||||
addFunction("ctg", 1);
|
||||
addFunction("tg", 1);
|
||||
addFunction("exp", 1);
|
||||
addFunction("cth", 1);
|
||||
addFunction("sh", 1);
|
||||
addFunction("ch", 1);
|
||||
addFunction("th", 1);
|
||||
addFunction("sqrt", 1);
|
||||
addFunction("sqr", 1);
|
||||
addFunction("pow", 2);
|
||||
addFunction("abs", 1);
|
||||
addFunction("ln", 1);
|
||||
addFunction("lg", 1);
|
||||
addFunction("log", 2);
|
||||
addFunction("im", 1);
|
||||
addFunction("re", 1);
|
||||
addFunction("arg", 1);
|
||||
addFunction("len", 1);
|
||||
addFunction("conj", 1);
|
||||
addFunction("sign", 1);
|
||||
addFunction("rad", 1);
|
||||
addFunction("deg", 1);
|
||||
addFunction("j0", 1);
|
||||
addFunction("j1", 1);
|
||||
addFunction("jn", 2);
|
||||
addFunction("y0", 1);
|
||||
addFunction("y1", 1);
|
||||
addFunction("yn", 2);
|
||||
addFunction("min", -2); // (x0,x1,...)
|
||||
addFunction("max", -2); // (x0,x1,...)
|
||||
addFunction("clamp", 3); // (x,a,b) = x < a ? a : (x > b ? b : x)
|
||||
addFunction("step", 2); // (x,s) = x >= s ? 1. : 0. (1 if 'x' >= 's', else 0)
|
||||
addFunction("mix", 3); // (x,a,b) = a*(1.-x) + b*x (interpolate between 'a' and 'b' linear for 'x')
|
||||
addFunction("defined", 1);
|
||||
addFunction("round", 1);
|
||||
clearCustomVariables();
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluatorContent::setVariableValue(int index, complexd new_value) {
|
||||
if (index < 0 || index >= variables.size_s()) return false;
|
||||
variables[index].value = new_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluatorContent::setVariableName(int index, const PIString & new_name) {
|
||||
if (index < 0 || index >= variables.size_s()) return false;
|
||||
variables[index].name = new_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluatorContent::clearCustomVariables() {
|
||||
variables.clear();
|
||||
addVariable("i", complexd_i);
|
||||
addVariable("pi", atan(1.) * 4.);
|
||||
addVariable("e", exp(1.));
|
||||
cv_count = variables.size();
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluatorContent::sortVariables() {
|
||||
for (uint i = 0; i < variables.size(); i++) {
|
||||
for (uint j = variables.size() - 1; j > i; j--) {
|
||||
if (variables[j].name.length() <= variables[i].name.length()) continue;
|
||||
piSwap<Variable>(variables[i], variables[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BaseFunctions PIEvaluatorContent::getBaseFunction(const PIString & name) {
|
||||
if (name == "sin") return bfSin;
|
||||
if (name == "cos") return bfCos;
|
||||
if (name == "tg") return bfTg;
|
||||
if (name == "ctg") return bfCtg;
|
||||
if (name == "arcsin") return bfArcsin;
|
||||
if (name == "arccos") return bfArccos;
|
||||
if (name == "arctg") return bfArctg;
|
||||
if (name == "arcctg") return bfArcctg;
|
||||
if (name == "exp") return bfExp;
|
||||
if (name == "random") return bfRandom;
|
||||
if (name == "randomn") return bfRandomn;
|
||||
if (name == "sh") return bfSh;
|
||||
if (name == "ch") return bfCh;
|
||||
if (name == "th") return bfTh;
|
||||
if (name == "cth") return bfCth;
|
||||
if (name == "sqrt") return bfSqrt;
|
||||
if (name == "sqr") return bfSqr;
|
||||
if (name == "pow") return bfPow;
|
||||
if (name == "abs") return bfAbs;
|
||||
if (name == "ln") return bfLn;
|
||||
if (name == "lg") return bfLg;
|
||||
if (name == "log") return bfLog;
|
||||
if (name == "im") return bfIm;
|
||||
if (name == "re") return bfRe;
|
||||
if (name == "arg") return bfArg;
|
||||
if (name == "len") return bfLen;
|
||||
if (name == "conj") return bfConj;
|
||||
if (name == "sign") return bfSign;
|
||||
if (name == "rad") return bfRad;
|
||||
if (name == "deg") return bfDeg;
|
||||
if (name == "j0") return bfJ0;
|
||||
if (name == "j1") return bfJ1;
|
||||
if (name == "jn") return bfJN;
|
||||
if (name == "y0") return bfY0;
|
||||
if (name == "y1") return bfY1;
|
||||
if (name == "yn") return bfYN;
|
||||
if (name == "min") return bfMin;
|
||||
if (name == "max") return bfMax;
|
||||
if (name == "clamp") return bfClamp;
|
||||
if (name == "step") return bfStep;
|
||||
if (name == "mix") return bfMix;
|
||||
if (name == "defined") return bfDefined;
|
||||
if (name == "round") return bfRound;
|
||||
return bfUnknown;
|
||||
}
|
||||
|
||||
|
||||
const PIString & PIEvaluator::prepare(const PIString & string) {
|
||||
currentString = string.trimmed();
|
||||
if (currentString.isEmpty()) currentString = "0";
|
||||
replaceOperators();
|
||||
removeSpaces();
|
||||
checkBrackets();
|
||||
while (fillElements()) checkBrackets();
|
||||
while (setSignes()) fillElements();
|
||||
removeJunk();
|
||||
findUnknownVariables();
|
||||
return currentString;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::removeSpaces() {
|
||||
PIString tmps = currentString;
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
if (tmps[i] == ' ' || tmps[i] == '\t') {
|
||||
tmps.remove(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
currentString = tmps;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::removeJunk() {
|
||||
PIChar cc;
|
||||
bool junk = true;
|
||||
int bcnt;
|
||||
while (junk) {
|
||||
if (currentString.left(1) != "(" || currentString.right(1) != ")") return;
|
||||
bcnt = 1;
|
||||
junk = false;
|
||||
for (int i = 1; i < currentString.length(); i++) {
|
||||
cc = currentString[i];
|
||||
if (cc == '(') bcnt++;
|
||||
if (cc == ')') bcnt--;
|
||||
if (bcnt == 0) {
|
||||
if (i == currentString.length() - 1) {
|
||||
currentString = currentString.mid(1, currentString.length() - 2);
|
||||
elements.pop_front();
|
||||
elements.pop_back();
|
||||
junk = true;
|
||||
break;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::replaceOperators() {
|
||||
currentString.replaceAll("==", "=");
|
||||
currentString.replaceAll("!=", ":");
|
||||
currentString.replaceAll(">=", "}");
|
||||
currentString.replaceAll("<=", "{");
|
||||
currentString.replaceAll("&&", "&");
|
||||
currentString.replaceAll("||", "|");
|
||||
currentString.replaceAll(PIString::fromUTF8("≠"), ":");
|
||||
currentString.replaceAll(PIString::fromUTF8("≥"), "}");
|
||||
currentString.replaceAll(PIString::fromUTF8("≤"), "{");
|
||||
currentString.replaceAll(PIString::fromUTF8("⋀"), "&");
|
||||
currentString.replaceAll(PIString::fromUTF8("⋁"), "|");
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::makeOutput(PIString & string) {
|
||||
string.replaceAll(":", PIString::fromUTF8("≠"));
|
||||
string.replaceAll("}", PIString::fromUTF8("≥"));
|
||||
string.replaceAll("{", PIString::fromUTF8("≤"));
|
||||
string.replaceAll("&", PIString::fromUTF8("⋀"));
|
||||
string.replaceAll("|", PIString::fromUTF8("⋁"));
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::findUnknownVariables() {
|
||||
PIString cvar;
|
||||
unknownVars.clear();
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
if (elements[i].var_num == -666) cvar += currentString[i];
|
||||
else {
|
||||
if (cvar.length() == 0) continue;
|
||||
unknownVars << cvar;
|
||||
cvar = "";
|
||||
}
|
||||
}
|
||||
if (cvar.length() > 0) unknownVars << cvar;
|
||||
unknownVars.removeDuplicates();
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::isSign(const PIChar & ch) {
|
||||
return ch == '+' || ch == '-' ||
|
||||
ch == '*' || ch == '/' ||
|
||||
ch == '%' || ch == '^' ||
|
||||
ch == '=' || ch == ':' ||
|
||||
ch == '>' || ch == '<' ||
|
||||
ch == '}' || ch == '{' ||
|
||||
ch == '&' || ch == '|';
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::checkBrackets() {
|
||||
PIString tmps = currentString;
|
||||
PIChar fc, sc;
|
||||
int bcnt = 0, bpos = 0, inserted = 0;
|
||||
currentString = tmps;
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
if (tmps[i] == '(') {
|
||||
if (bcnt == 0) bpos = i;
|
||||
bcnt++;
|
||||
}
|
||||
if (tmps[i] == ')') {
|
||||
if (bcnt == 0) {
|
||||
currentString.insert(bpos + inserted, "(");
|
||||
inserted++;
|
||||
} else bcnt--;
|
||||
}
|
||||
}
|
||||
if (bcnt > 0) currentString += PIString(bcnt, ')');
|
||||
tmps = currentString;
|
||||
for (int i = 0; i < tmps.length() - 1; i++) {
|
||||
fc = tmps[i].toLower();
|
||||
sc = tmps[i + 1].toLower();
|
||||
if ((fc == ')' && sc == '(') ||
|
||||
(fc == ')' && sc >= '0' && sc <= '9') ||
|
||||
(fc == ')' && sc >= 'a' && sc <= 'z') ) tmps.insert(++i, '*');
|
||||
}
|
||||
currentString = tmps;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::fillElements() {
|
||||
int fstart, flen, cnum = 0, cpart = 0, cfunc;
|
||||
PIChar cc, nc, pc, fc = '!';
|
||||
bool numFound = false;
|
||||
PIString curfind, tmps = currentString;
|
||||
elements.resize(tmps.length());
|
||||
for (uint i = 0; i < elements.size(); i++) {
|
||||
elements[i].type = etVariable;
|
||||
elements[i].var_num = -666;
|
||||
}
|
||||
currentVariables.clear();
|
||||
for (int i = 0; i < content.functionsCount(); i++) {
|
||||
curfind = content.function(i).identifier;
|
||||
cfunc = i;
|
||||
flen = curfind.length();
|
||||
fstart = 0;
|
||||
while (fstart >= 0) {
|
||||
fstart = tmps.find(curfind, fstart);
|
||||
if (fstart < 0) break;
|
||||
if (tmps[fstart + flen] != '(') {
|
||||
fstart++;
|
||||
continue;
|
||||
}
|
||||
for (int j = fstart; j < fstart + flen; j++) {
|
||||
elements[j].set(etFunction, cnum, cfunc);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
cnum++;
|
||||
}
|
||||
}
|
||||
cnum = 0;
|
||||
for (int i = 0; i < content.variablesCount(); i++) {
|
||||
curfind = content.variable(i).name;
|
||||
flen = curfind.length();
|
||||
fstart = 0;
|
||||
while (fstart >= 0) {
|
||||
fstart = tmps.find(curfind, fstart);
|
||||
if (fstart < 0) break;
|
||||
for (int j = fstart; j < fstart + flen; j++) {
|
||||
elements[j].set(etVariable, cnum, i);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
cnum++;
|
||||
}
|
||||
}
|
||||
curfind = "";
|
||||
cnum = 1;
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
cc = tmps[i];
|
||||
switch (cpart) {
|
||||
case 0:
|
||||
if ((cc >= '0' && cc <= '9')) {
|
||||
curfind += cc;
|
||||
cpart = 1;
|
||||
continue;
|
||||
}
|
||||
if (cc == '.') {
|
||||
curfind += cc;
|
||||
cpart = 2;
|
||||
continue;
|
||||
}
|
||||
if (cc == 'E') {
|
||||
curfind += cc;
|
||||
cpart = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (cc >= '0' && cc <= '9') {
|
||||
curfind += cc;
|
||||
continue;
|
||||
}
|
||||
if (cc == '.') {
|
||||
curfind += cc;
|
||||
cpart = 2;
|
||||
continue;
|
||||
}
|
||||
if (cc == 'E') {
|
||||
curfind += cc;
|
||||
cpart = 3;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
case 2:
|
||||
if (cc >= '0' && cc <= '9') {
|
||||
curfind += cc;
|
||||
continue;
|
||||
}
|
||||
if (cc == 'E') {
|
||||
curfind += cc;
|
||||
cpart = 3;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
case 3:
|
||||
if ((cc >= '0' && cc <= '9') || cc == '-' || cc == '+') {
|
||||
curfind += cc;
|
||||
cpart = 4;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
case 4:
|
||||
if (cc >= '0' && cc <= '9') {
|
||||
curfind += cc;
|
||||
continue;
|
||||
}
|
||||
numFound = true;
|
||||
break;
|
||||
}
|
||||
if (numFound) {
|
||||
currentVariables.push_back(Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble()));
|
||||
for (int j = i - curfind.length(); j < i; j++) {
|
||||
elements[j].set(etNumber, cnum, -cnum);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
curfind = "";
|
||||
cnum++;
|
||||
cpart = 0;
|
||||
numFound = false;
|
||||
}
|
||||
}
|
||||
if (cpart > 0) {
|
||||
currentVariables.push_back(Variable("tmp" + PIString::fromNumber(cnum), curfind.toDouble()));
|
||||
for (int j = tmps.length() - curfind.length(); j < tmps.length(); j++) {
|
||||
elements[j].set(etNumber, cnum, -cnum);
|
||||
tmps.replace(j, 1, fc);
|
||||
}
|
||||
}
|
||||
cc = nc = fc;
|
||||
for (int i = 0; i < tmps.length(); i++) {
|
||||
cc = tmps[i];
|
||||
if (i > 0) pc = tmps[i - 1];
|
||||
else pc = fc;
|
||||
if (i < tmps.length() - 1) nc = tmps[i + 1];
|
||||
else nc = fc;
|
||||
if (cc == '(' || cc == ')' || cc == ',') {
|
||||
elements[i].set(etOperator, -1);
|
||||
continue;
|
||||
}
|
||||
if (cc == '-' || cc == '+') {
|
||||
elements[i].set(etOperator, -1);
|
||||
if (i < tmps.length() - 1) if (elements[i + 1].type == etVariable ||
|
||||
elements[i + 1].type == etFunction) continue;
|
||||
if ((pc == '(' || isSign(pc) || i == 0) && i < tmps.length() - 1) {
|
||||
if (elements[i + 1].type != etOperator) {
|
||||
cnum = elements[i + 1].num;
|
||||
elements[i].set(etNumber, cnum);
|
||||
tmps.replace(i, 1, fc);
|
||||
///cout << "found sign " << cc << " :" << cnum - 1 << endl;
|
||||
if (cc == '-' && currentVariables.size_s() >= cnum)
|
||||
currentVariables[cnum - 1].value = -currentVariables[cnum - 1].value;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isSign(cc)) {
|
||||
elements[i].set(etOperator, -1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*cout << " ";
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
switch (elements[i].type) {
|
||||
case etFunction: cout << "f"; break;
|
||||
case etNumber: cout << "n"; break;
|
||||
case etOperator: cout << "o"; break;
|
||||
case etVariable: cout << "v"; break;
|
||||
}
|
||||
}
|
||||
cout << endl; */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::setSignes() {
|
||||
int inserted = 0, ni, pi = 0, needInsert = 0;
|
||||
PIChar fc, sc, pc;
|
||||
PIString tmps = currentString;
|
||||
for (int i = 0; i < tmps.length() - 1; i++) {
|
||||
needInsert = 0;
|
||||
ni = i + 1;
|
||||
if (i > 0) pi = i - 1;
|
||||
fc = tmps[i].toLower();
|
||||
sc = tmps[ni].toLower();
|
||||
pc = tmps[pi].toLower();
|
||||
if (fc == ',' || sc == ',') continue;
|
||||
if (elements[i].type == etOperator && elements[ni].type == etOperator) continue;
|
||||
if (fc == ')' && (elements[ni].type == etNumber || elements[ni].type == etVariable || elements[ni].type == etFunction)) needInsert = 1;
|
||||
if (sc == '(' && (elements[i].type == etNumber || elements[i].type == etVariable)) needInsert = 1;
|
||||
if (elements[i].type == etNumber && elements[ni].type == etNumber && elements[i].num != elements[ni].num) needInsert = 1;
|
||||
if (elements[i].type == etVariable && elements[ni].type == etVariable && elements[i].num != elements[ni].num) needInsert = 1;
|
||||
if ((elements[i].type == etNumber && elements[ni].type == etVariable) || (elements[i].type == etVariable && elements[ni].type == etNumber)) needInsert = 1;
|
||||
if ((elements[i].type == etNumber || elements[i].type == etVariable) && elements[ni].type == etFunction) needInsert = 1;
|
||||
if (elements[i].type == etFunction && elements[ni].type == etFunction && elements[i].num != elements[ni].num) needInsert = 2;
|
||||
if (elements[i].type == etFunction && elements[ni].type != etFunction && sc != '(') needInsert = 2;
|
||||
if (elements[pi].type == etOperator && (elements[ni].type == etFunction || elements[ni].type == etVariable) && fc == '-') needInsert = 3;
|
||||
switch (needInsert) {
|
||||
case 1:
|
||||
currentString.insert(ni + inserted, "*");
|
||||
elements.insert(ni + inserted, Element(etOperator, -1));
|
||||
return true;
|
||||
case 3:
|
||||
currentString.insert(ni + inserted, "1*");
|
||||
elements.insert(ni + inserted, Element(etOperator, -1));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::convert() {
|
||||
int j;
|
||||
Element ce, pe;
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
pe = elements[i];
|
||||
if (pe.type != etFunction) continue;
|
||||
j = i + 1;
|
||||
while (j < currentString.length()) {
|
||||
ce = elements[j];
|
||||
if (ce != pe) break;
|
||||
j++;
|
||||
}
|
||||
currentString.replace(i, j - i, " ");
|
||||
for (int k = i + 1; k < j; k++) elements.remove(i);
|
||||
}
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
pe = elements[i];
|
||||
if (pe.type != etNumber) continue;
|
||||
j = i + 1;
|
||||
while (j < currentString.length()) {
|
||||
ce = elements[j];
|
||||
if (ce != pe) break;
|
||||
j++;
|
||||
}
|
||||
currentString.replace(i, j - i, " ");
|
||||
for (int k = i + 1; k < j; k++) elements.remove(i);
|
||||
}
|
||||
for (int i = 0; i < currentString.length(); i++) {
|
||||
pe = elements[i];
|
||||
if (pe.type != etVariable) continue;
|
||||
j = i + 1;
|
||||
while (j < currentString.length()) {
|
||||
ce = elements[j];
|
||||
if (ce != pe) break;
|
||||
j++;
|
||||
}
|
||||
currentString.replace(i, j - i, " ");
|
||||
for (int k = i + 1; k < j; k++) elements.remove(i);
|
||||
}
|
||||
/*cout << " ";
|
||||
for (int i = 0; i < elements.size(); i++) {
|
||||
switch (elements[i].type) {
|
||||
case etFunction: cout << "f"; break;
|
||||
case etNumber: cout << "n"; break;
|
||||
case etOperator: cout << "o"; break;
|
||||
case etVariable: cout << "v"; break;
|
||||
}
|
||||
}
|
||||
cout << endl; */
|
||||
}
|
||||
|
||||
|
||||
|
||||
PIString PIEvaluator::preprocess(const PIString & string) {
|
||||
PIString ret;
|
||||
int lind;
|
||||
ret = prepare(string);
|
||||
convert();
|
||||
instructions.clear();
|
||||
variables = currentVariables;
|
||||
lind = parse(currentString);
|
||||
if (instructions.size() == 0) {
|
||||
variables.push_back(Variable());
|
||||
instructions.push_back(Instruction(oNone, PIVector<short>(1, lind), -variables.size_s()));
|
||||
}
|
||||
kvars = &(content.variables);
|
||||
/*cout << endl << "variables:" << endl;
|
||||
for (int i = 0; i < variables.size(); i++)
|
||||
cout << i << " value = " << variables[i].value << endl;
|
||||
|
||||
cout << endl << "instructions:" << endl;
|
||||
for (int i = 0; i < instructions.size(); i++) {
|
||||
cout << i << endl;
|
||||
cout << " operation " << instructions[i].operation << endl;
|
||||
cout << " operators: ";
|
||||
for (int j = 0; j < instructions[i].operators.size(); j++)
|
||||
cout << instructions[i].operators[j] << "; ";
|
||||
cout << endl << " function " << instructions[i].function << endl;
|
||||
cout << " out " << instructions[i].out << endl;
|
||||
} */
|
||||
makeOutput(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int PIEvaluator::parse(const PIString & string, int offset) {
|
||||
int slen = string.length(), /*facnt,*/ farg, bcnt, k;
|
||||
PIChar cc;
|
||||
Element ce;
|
||||
Function cfunc;
|
||||
PIString sbrackets, carg;
|
||||
PIVector<short> args, atmp;
|
||||
PIVector<Operation> opers;
|
||||
|
||||
//cout << " "; for (int i = 0; i < slen; i++) cout << preproc->elements[i + offset].type; cout << endl;
|
||||
for (int i = 0; i < slen; i++) {
|
||||
ce = elements[i + offset];
|
||||
cc = string[i];
|
||||
switch (ce.type) {
|
||||
case etNumber:
|
||||
args.push_back(ce.var_num);
|
||||
continue;
|
||||
case etVariable:
|
||||
args.push_back(ce.var_num);
|
||||
continue;
|
||||
case etFunction:
|
||||
i++;
|
||||
cfunc = content.function(ce.var_num);
|
||||
atmp.clear();
|
||||
bcnt = farg = 1;
|
||||
carg = "";
|
||||
k = i + 1;
|
||||
while (bcnt > 0) {
|
||||
cc = string[k];
|
||||
switch (cc.toAscii()) {
|
||||
case '(': bcnt++; break;
|
||||
case ')':
|
||||
bcnt--;
|
||||
if (bcnt == 0) {
|
||||
///qDebug() << "arument: " << carg;
|
||||
atmp.push_back(parse(carg, k + offset - carg.length()));
|
||||
k++;
|
||||
carg = "";
|
||||
if (atmp.size_s() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (bcnt == 1) {
|
||||
///qDebug() << "arument: " << carg;
|
||||
atmp.push_back(parse(carg, k + offset - carg.length()));
|
||||
k++;
|
||||
carg = "";
|
||||
if (atmp.size_s() > 0) if (atmp.back() < 0 && farg > 0) farg = atmp.back();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
carg += cc;
|
||||
k++;
|
||||
}
|
||||
i = k - 1;
|
||||
if (farg > 0) {
|
||||
variables.push_back(Variable());
|
||||
farg = -variables.size_s();
|
||||
}
|
||||
instructions.push_back(Instruction(oFunction, atmp, farg, ce.var_num));
|
||||
args.push_back(farg);
|
||||
//for (int i = 0; i < args.size_s(); i++) cout << preproc->currentVariables[-args[i]].value << endl;
|
||||
continue;
|
||||
case etOperator:
|
||||
if (cc == '(') {
|
||||
sbrackets = inBrackets(string.right(slen - i));
|
||||
args.push_back(parse(sbrackets, i + offset + 1));
|
||||
i += sbrackets.length() + 1;
|
||||
continue;
|
||||
}
|
||||
if (cc == '+') {opers.push_back(oAdd); continue;}
|
||||
if (cc == '-') {opers.push_back(oSubtract); continue;}
|
||||
if (cc == '*') {opers.push_back(oMultiply); continue;}
|
||||
if (cc == '/') {opers.push_back(oDivide); continue;}
|
||||
if (cc == '%') {opers.push_back(oResidue); continue;}
|
||||
if (cc == '^') {opers.push_back(oPower); continue;}
|
||||
if (cc == '=') {opers.push_back(oEqual); continue;}
|
||||
if (cc == ':') {opers.push_back(oNotEqual); continue;}
|
||||
if (cc == '}') {opers.push_back(oGreaterEqual); continue;}
|
||||
if (cc == '{') {opers.push_back(oSmallerEqual); continue;}
|
||||
if (cc == '>') {opers.push_back(oGreater); continue;}
|
||||
if (cc == '<') {opers.push_back(oSmaller); continue;}
|
||||
if (cc == '&') {opers.push_back(oAnd); continue;}
|
||||
if (cc == '|') {opers.push_back(oOr); continue;}
|
||||
}
|
||||
}
|
||||
/*cout << "stack: " << endl << "args: ";
|
||||
for (int i = 0; i < args.size_s(); i++) cout << args[i] << ", ";
|
||||
cout << endl << "opers: ";
|
||||
for (int i = 0; i < opers.size_s(); i++) cout << opers[i] << ", "; */
|
||||
if (opers.size_s() == 0) {
|
||||
if (args.size_s() > 0) return args.back();
|
||||
else return -666;
|
||||
}
|
||||
|
||||
int oprior = -1;
|
||||
PIVector<Operation> opv;
|
||||
while(1) {
|
||||
operationsByPriority(++oprior, opv);
|
||||
if (opv.isEmpty()) break;
|
||||
for (int j = 0; j < opers.size_s(); j++) {
|
||||
if (!opv.contains(opers[j])) continue;
|
||||
atmp.clear();
|
||||
if (j < args.size_s() && j >= 0) atmp.push_back(args[j]);
|
||||
else atmp.push_back(-666);
|
||||
if (j + 1 < args.size_s() && j >= -1) atmp.push_back(args[j + 1]);
|
||||
else atmp.push_back(-666);
|
||||
farg = 1;
|
||||
if (atmp[0] < 0) farg = atmp[0];
|
||||
else {
|
||||
if (atmp[1] < 0) farg = atmp[1];
|
||||
else {
|
||||
variables.push_back(Variable());
|
||||
farg = -variables.size_s();
|
||||
}
|
||||
}
|
||||
instructions.push_back(Instruction(opers[j], atmp, farg));
|
||||
if (j >= 0 && j < args.size_s()) {
|
||||
args.remove(j);
|
||||
if (j < args.size_s()) args[j] = farg;
|
||||
}
|
||||
opers.remove(j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
return instructions.back().out;
|
||||
//cout << endl;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::check() {
|
||||
Instruction ci;
|
||||
bool error;
|
||||
if (unknownVars.size_s() > 0) {
|
||||
lastError = "Unknown variables: \"" + unknownVars.join("\", \"") + "\"";
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < instructions.size_s(); i++) {
|
||||
error = false;
|
||||
ci = instructions[i];
|
||||
Function cf;
|
||||
int fac, gac;
|
||||
switch (ci.operation) {
|
||||
case oNone: break;
|
||||
case oFunction:
|
||||
cf = content.function(ci.function);
|
||||
fac = cf.arguments;
|
||||
gac = ci.operators.size_s();
|
||||
for (int j = 0; j < ci.operators.size_s(); j++) {
|
||||
if (ci.operators[j] == -666) {
|
||||
error = true;
|
||||
gac--;
|
||||
}
|
||||
}
|
||||
if (fac > 0) {
|
||||
if (gac != fac) {
|
||||
lastError = "Invalid arguments count for function \"" + cf.identifier +
|
||||
"\", expected " + PIString::fromNumber(fac) + " but " +
|
||||
PIString::fromNumber(gac) + " given";
|
||||
return false;
|
||||
}
|
||||
if (error) {
|
||||
lastError = "Invalid at least one of function \"" + cf.identifier + "\" argument";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fac < 0) {
|
||||
if (gac < -fac) {
|
||||
lastError = "Invalid arguments count for function \"" + cf.identifier +
|
||||
"\", expected at least " + PIString::fromNumber(-fac) + " but " +
|
||||
PIString::fromNumber(gac) + " given";
|
||||
return false;
|
||||
}
|
||||
if (error) {
|
||||
lastError = "Invalid at least one of function \"" + cf.identifier + "\" argument";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (ci.operators[0] == -666 || ci.operators[1] == -666) error = true;
|
||||
if (ci.operators.size_s() != 2 || error) {
|
||||
lastError = "Invalid arguments count for operation \" " + operationChar(ci.operation) + " \"";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ci.out < -variables.size_s()) {
|
||||
lastError = "Invalid variable index \"" + PIString::fromNumber(ci.out) + "\"";
|
||||
return false;
|
||||
}
|
||||
for (int j = 0; j < ci.operators.size_s(); j++) {
|
||||
if (ci.operators[j] < -variables.size_s() || ci.operators[j] >= kvars->size_s()) {
|
||||
lastError = "Invalid variable index \"" + PIString::fromNumber(ci.operators[j]) + "\"";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
PIString PIEvaluator::inBrackets(const PIString & string) {
|
||||
int slen = string.length(), bcnt = 0;
|
||||
PIChar cc;
|
||||
for (int i = 0; i < slen; i++) {
|
||||
cc = string[i];
|
||||
if (cc == '(') bcnt++;
|
||||
if (cc == ')') {
|
||||
bcnt--;
|
||||
if (bcnt == 0) return string.mid(1, i - 1);
|
||||
}
|
||||
}
|
||||
return PIString();
|
||||
}
|
||||
|
||||
|
||||
PIString PIEvaluator::operationChar(const Operation & operation) {
|
||||
switch (operation) {
|
||||
case oAdd: return "+";
|
||||
case oSubtract: return "-";
|
||||
case oMultiply: return "*";
|
||||
case oDivide: return "/";
|
||||
case oPower: return "^";
|
||||
case oResidue: return "%";
|
||||
case oEqual: return "=";
|
||||
case oNotEqual: return PIString::fromUTF8("≠");
|
||||
case oGreaterEqual: return PIString::fromUTF8("≥");
|
||||
case oSmallerEqual: return PIString::fromUTF8("≤");
|
||||
case oGreater: return ">";
|
||||
case oSmaller: return "<";
|
||||
case oAnd: return PIString::fromUTF8("⋀");
|
||||
case oOr: return PIString::fromUTF8("⋁");
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::operationsByPriority(int p, PIVector<Operation> & ret) {
|
||||
ret.clear();
|
||||
switch (p) {
|
||||
case 0: ret << oPower; break;
|
||||
case 1: ret << oMultiply << oDivide << oResidue; break;
|
||||
case 2: ret << oAdd << oSubtract; break;
|
||||
case 3: ret << oEqual << oNotEqual << oGreaterEqual << oSmallerEqual << oGreater << oSmaller; break;
|
||||
case 4: ret << oAnd; break;
|
||||
case 5: ret << oOr; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline complexd PIEvaluator::residue(const complexd & f, const complexd & s) {
|
||||
complexd ret;
|
||||
if (s.real() != 0.) ret = complexd(f.real() - ((int)(f.real() / s.real())) * s.real(), 0.);
|
||||
if (s.imag() != 0.) ret = complexd(ret.real(), f.imag() - ((int)(f.imag() / s.imag())) * s.imag());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
inline void PIEvaluator::execFunction(const Instruction & ci) {
|
||||
const Function & cfunc(content.function(ci.function));
|
||||
int oi = -ci.out - 1;
|
||||
complexd tmp, stmp, ttmp;
|
||||
switch (cfunc.type) {
|
||||
case bfSin:
|
||||
tmpvars[oi].value = sin(value(ci.operators[0]));
|
||||
break;
|
||||
case bfCos:
|
||||
tmpvars[oi].value = cos(value(ci.operators[0]));
|
||||
break;
|
||||
case bfTg:
|
||||
tmpvars[oi].value = tan(value(ci.operators[0]));
|
||||
break;
|
||||
case bfCtg:
|
||||
tmp = tan(value(ci.operators[0]));
|
||||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = complexd_1 / tmp;
|
||||
break;
|
||||
case bfArcsin:
|
||||
tmpvars[oi].value = asinc(value(ci.operators[0]));
|
||||
break;
|
||||
case bfArccos:
|
||||
tmpvars[oi].value = acosc(value(ci.operators[0]));
|
||||
break;
|
||||
case bfArctg:
|
||||
tmpvars[oi].value = atanc(value(ci.operators[0]));
|
||||
break;
|
||||
case bfArcctg:
|
||||
tmpvars[oi].value = atanc(-value(ci.operators[0])) + M_PI_2;
|
||||
break;
|
||||
case bfSh:
|
||||
tmpvars[oi].value = sinh(value(ci.operators[0]));
|
||||
break;
|
||||
case bfCh:
|
||||
tmpvars[oi].value = cosh(value(ci.operators[0]));
|
||||
break;
|
||||
case bfTh:
|
||||
tmpvars[oi].value = tanh(value(ci.operators[0]));
|
||||
break;
|
||||
case bfCth:
|
||||
tmp = tanh(value(ci.operators[0]));
|
||||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = complexd_1 / tmp;
|
||||
break;
|
||||
case bfAbs:
|
||||
tmpvars[oi].value = abs(value(ci.operators[0]));
|
||||
break;
|
||||
case bfSqrt:
|
||||
tmpvars[oi].value = sqrt(value(ci.operators[0]));
|
||||
break;
|
||||
case bfSqr:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[0]);
|
||||
break;
|
||||
case bfExp:
|
||||
tmpvars[oi].value = exp(value(ci.operators[0]));
|
||||
break;
|
||||
case bfPow:
|
||||
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
|
||||
break;
|
||||
case bfLn:
|
||||
tmpvars[oi].value = log(value(ci.operators[0]));
|
||||
break;
|
||||
case bfLg:
|
||||
tmpvars[oi].value = log10(value(ci.operators[0]));
|
||||
break;
|
||||
case bfLog:
|
||||
tmp = log(value(ci.operators[1]));
|
||||
if (tmp == complexd_0) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = log(value(ci.operators[0])) / tmp;
|
||||
break;
|
||||
case bfRe:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real();
|
||||
break;
|
||||
case bfIm:
|
||||
tmpvars[oi].value = value(ci.operators[0]).imag();
|
||||
break;
|
||||
case bfArg:
|
||||
tmpvars[oi].value = arg(value(ci.operators[0]));
|
||||
break;
|
||||
case bfLen:
|
||||
tmpvars[oi].value = abs(value(ci.operators[0]));
|
||||
break;
|
||||
case bfConj:
|
||||
tmpvars[oi].value = conj(value(ci.operators[0]));
|
||||
break;
|
||||
case bfSign:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() >= 0. ? complexd_1 : -complexd_1;
|
||||
break;
|
||||
case bfRad:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * complexd(deg2rad, 0.);
|
||||
break;
|
||||
case bfDeg:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * complexd(rad2deg, 0.);
|
||||
break;
|
||||
case bfJ0:
|
||||
tmpvars[oi].value = piJ0(value(ci.operators[0]).real());
|
||||
break;
|
||||
case bfJ1:
|
||||
tmpvars[oi].value = piJ1(value(ci.operators[0]).real());
|
||||
break;
|
||||
case bfJN:
|
||||
tmpvars[oi].value = piJn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real());
|
||||
break;
|
||||
case bfY0:
|
||||
tmpvars[oi].value = piY0(value(ci.operators[0]).real());
|
||||
break;
|
||||
case bfY1:
|
||||
tmpvars[oi].value = piY1(value(ci.operators[0]).real());
|
||||
break;
|
||||
case bfYN:
|
||||
tmpvars[oi].value = piYn(piRoundd(value(ci.operators[1]).real()), value(ci.operators[0]).real());
|
||||
break;
|
||||
case bfMin:
|
||||
tmp = value(ci.operators[0]);
|
||||
for (int i = 1; i < ci.operators.size_s(); ++i) {
|
||||
stmp = value(ci.operators[i]);
|
||||
tmp = complexd(piMind(tmp.real(), stmp.real()), piMind(tmp.imag(), stmp.imag()));
|
||||
}
|
||||
tmpvars[oi].value = tmp;
|
||||
break;
|
||||
case bfMax:
|
||||
tmp = value(ci.operators[0]);
|
||||
for (int i = 1; i < ci.operators.size_s(); ++i) {
|
||||
stmp = value(ci.operators[i]);
|
||||
tmp = complexd(piMaxd(tmp.real(), stmp.real()), piMaxd(tmp.imag(), stmp.imag()));
|
||||
}
|
||||
tmpvars[oi].value = tmp;
|
||||
break;
|
||||
case bfClamp:
|
||||
tmp = value(ci.operators[0]);
|
||||
stmp = value(ci.operators[1]);
|
||||
ttmp = value(ci.operators[2]);
|
||||
tmpvars[oi].value = complexd(piClampd(tmp.real(), stmp.real(), ttmp.real()), piClampd(tmp.imag(), stmp.imag(), ttmp.imag()));
|
||||
break;
|
||||
case bfStep:
|
||||
tmpvars[oi].value = complexd(value(ci.operators[0]).real() >= value(ci.operators[1]).real() ? complexld_1 : complexld_0);
|
||||
break;
|
||||
case bfMix:
|
||||
tmp = value(ci.operators[0]);
|
||||
stmp = value(ci.operators[1]);
|
||||
ttmp = value(ci.operators[2]);
|
||||
tmpvars[oi].value = stmp.real() * (1. - tmp.real()) + ttmp.real() * tmp.real();
|
||||
break;
|
||||
case bfDefined:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. ? complexd_1 : complexd_0;
|
||||
break;
|
||||
case bfRandom:
|
||||
tmpvars[oi].value = value(ci.operators[0]) + randomd() * value(ci.operators[1]);
|
||||
break;
|
||||
case bfRandomn:
|
||||
tmpvars[oi].value = randomn(value(ci.operators[0]).real(), value(ci.operators[1]).real());
|
||||
break;
|
||||
case bfRound:
|
||||
tmpvars[oi].value = piRoundd(value(ci.operators[0]).real());
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool PIEvaluator::execInstructions() {
|
||||
kvars = &(content.variables);
|
||||
int oi;
|
||||
complexd tmp;
|
||||
tmpvars = variables;
|
||||
//cout << "var count " << tmpvars.size_s() << endl;
|
||||
for (int i = 0; i < instructions.size_s(); i++) {
|
||||
const Instruction & ci(instructions[i]);
|
||||
oi = -ci.out - 1;
|
||||
//cout << value(ci.operators[0]) << operationChar(ci.operation) << value(ci.operators[1]) << ", " << oi << endl;
|
||||
switch (ci.operation) {
|
||||
case oAdd:
|
||||
tmpvars[oi].value = value(ci.operators[0]) + value(ci.operators[1]);
|
||||
break;
|
||||
case oSubtract:
|
||||
tmpvars[oi].value = value(ci.operators[0]) - value(ci.operators[1]);
|
||||
break;
|
||||
case oMultiply:
|
||||
tmpvars[oi].value = value(ci.operators[0]) * value(ci.operators[1]);
|
||||
break;
|
||||
case oDivide:
|
||||
tmp = value(ci.operators[1]);
|
||||
if (tmp == complexd(0., 0.)) tmpvars[oi].value = 0.;
|
||||
else tmpvars[oi].value = value(ci.operators[0]) / tmp;
|
||||
break;
|
||||
case oResidue:
|
||||
tmpvars[oi].value = residue(value(ci.operators[0]), value(ci.operators[1]));
|
||||
break;
|
||||
case oPower:
|
||||
tmpvars[oi].value = pow(value(ci.operators[0]), value(ci.operators[1]));
|
||||
break;
|
||||
case oEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]) == value(ci.operators[1]);
|
||||
break;
|
||||
case oNotEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]) != value(ci.operators[1]);
|
||||
break;
|
||||
case oGreaterEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() >= value(ci.operators[1]).real();
|
||||
break;
|
||||
case oSmallerEqual:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() <= value(ci.operators[1]).real();
|
||||
break;
|
||||
case oGreater:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > value(ci.operators[1]).real();
|
||||
break;
|
||||
case oSmaller:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() < value(ci.operators[1]).real();
|
||||
break;
|
||||
case oAnd:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. && value(ci.operators[1]).real() > 0.;
|
||||
break;
|
||||
case oOr:
|
||||
tmpvars[oi].value = value(ci.operators[0]).real() > 0. || value(ci.operators[1]).real() > 0.;
|
||||
break;
|
||||
case oFunction:
|
||||
execFunction(ci);
|
||||
break;
|
||||
case oNone:
|
||||
tmpvars[oi].value = value(ci.operators[0]);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (!instructions.isEmpty())
|
||||
out = value(instructions.back().out);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PIEvaluator::check(const PIString & string) {
|
||||
currentString = preprocess(string);
|
||||
correct = check();
|
||||
if (!correct) {
|
||||
instructions.clear();
|
||||
return false;
|
||||
}
|
||||
lastError = "Correct";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
complexd PIEvaluator::evaluate() {
|
||||
if (!execInstructions()) out = 0.;
|
||||
if (fabs(out.real()) < 1E-300) out = complexd(0., out.imag());
|
||||
if (fabs(out.imag()) < 1E-300) out = complexd(out.real(), 0.);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
PIByteArray PIEvaluator::save() const {
|
||||
PIByteArray ret;
|
||||
ret << content << currentVariables << unknownVars << instructions << currentString << lastError << out << correct;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void PIEvaluator::load(PIByteArray ba) {
|
||||
if (ba.size() <= 4) return;
|
||||
ba >> content >> currentVariables >> unknownVars >> instructions >> currentString >> lastError >> out >> correct;
|
||||
variables = currentVariables;
|
||||
}
|
||||
Reference in New Issue
Block a user