server/libpoly/src/Poly.cc
2022-03-05 12:44:06 +02:00

932 lines
17 KiB
C++

#include <string>
#include "Poly.h"
#include "Constants.h"
#include <cmath>
#include <cctype>
#include <cstdlib>
using namespace std;
double _random()
{
#ifndef __WIN32__
return random() / (2147483648.0);
#else
return rand() / (2147483648.0);
#endif
}
int CPoly::my_irandom(double start, double end)
{
// Make range as inclusive-exclusive
int is = int(start + 0.5);
int ie = int(end - start + 0.5) + 1;
return int(_random() * ie + is);
}
double CPoly::my_frandom(double start, double end)
{
return _random() * (end - start) + start;
}
CPoly::CPoly()
: iToken(0), iNumToken(0), iLookAhead(0), iErrorPos(0), ErrorOccur(true),
uiLookPos(0), STSize(0)
{
lSymbol.clear();
lSymbol.reserve(50);
init();
}
CPoly::~CPoly()
{
Clear();
}
void CPoly::SetStr(const string & str)
{
strData = str;
}
double CPoly::Eval()
{
int stNow;
double save[MAXSTACK],t;
int iSp=0;
if (ErrorOccur)
{
/*THROW(new CEvalException("Evaluate Error"));*/
return 0;
}
//TEST
//list<int>::iterator pos = tokenBase.begin();
//list<double>::iterator posn = numBase.begin();
vector<int>::iterator pos = tokenBase.begin();
vector<double>::iterator posn = numBase.begin();
while (pos != tokenBase.end())
{
stNow=*pos;
++pos;
switch (stNow)
{
case NUM:
save[iSp++]=*posn++; break;
case ID:
save[iSp++]=
lSymbol[ *pos ]->dVal;
pos++;
break;
//case '+':
case PLU:
iSp--;
save[iSp-1]+=save[iSp]; break;
//case '-':
case MIN:
iSp--;
save[iSp-1]-=save[iSp]; break;
//case '*':
case MUL:
iSp--;
save[iSp-1]*=save[iSp]; break;
//case '%':
case MOD:
iSp--;
if (save[iSp]==0)
{
//THROW(new CEvalException("Divide by 0"));
return 0;
}
save[iSp-1]=fmod(save[iSp-1],save[iSp]); break;
//case '/':
case DIV:
iSp--;
if (save[iSp]==0)
{
//THROW(new CEvalException("Divide by 0"));
return 0;
}
save[iSp-1]/=save[iSp]; break;
//case '^':
case POW:
iSp--;
save[iSp-1]=pow(save[iSp-1],save[iSp]); break;
case ROOT:
if (save[iSp-1]<0)
{
//THROW(new CEvalException("Negative in root"));
return 0;
}
save[iSp-1]=sqrt(save[iSp-1]); break;
case COS:
save[iSp-1]=cos(save[iSp-1]); break;
case SIN:
save[iSp-1]=sin(save[iSp-1]); break;
case SIGN:
if (save[iSp-1] == 0.0) save[iSp-1] = 0.0;
else if (save[iSp-1] < 0.0) save[iSp-1] = -1.0;
else save[iSp-1] = 1.0f;
break;
case TAN:
if (!(t=cos(save[iSp-1])))
{
//THROW (new CEvalException("Divide by 0"));
return 0;
}
save[iSp-1]=tan(save[iSp-1]); break;
case CSC:
if (!(t=sin(save[iSp-1])))
{
//THROW(new CEvalException("Divide by 0"));
return 0;
}
save[iSp-1]=1/t; break;
case SEC:
if (!(t=cos(save[iSp-1])))
{
//THROW(new CEvalException("Divide by 0"));
return 0;
}
save[iSp-1]=1/t; break;
case COT:
if (!(t=sin(save[iSp-1])))
{
//THROW(new CEvalException("Divide by 0"));
return 0;
}
save[iSp-1]=cos(save[iSp-1])/t; break;
case LN:
if (save[iSp-1]<=0)
{
//THROW( new CEvalException("Call Log with minus number"));
return 0;
}
save[iSp-1]=log(save[iSp-1]); break;
case LOG10:
if (save[iSp-1]<=0)
{
//THROW( new CEvalException("Call Log with minus number"));
return 0;
}
save[iSp-1]=log10(save[iSp-1]); break;
case LOG:
if (save[iSp-1]<=0)
{
//THROW( new CEvalException("Call Log with minus number"));
return 0;
}
if (save[iSp-2]<=0 || save[iSp-2]==1)
{
//THROW( new CEvalException("Call Log with minus number"));
return 0;
}
save[iSp-2]=log(save[iSp-1])/log(save[iSp-2]);
iSp--;
break;
case ABS: save[iSp-1]=fabs(save[iSp-1]); break;
case FLOOR: save[iSp-1]=floor(save[iSp-1]); break;
case IRAND:
save[iSp-2]=my_irandom(save[iSp-2],save[iSp-1]);
iSp--;
break;
case FRAND:
save[iSp-2]=my_frandom(save[iSp-2],save[iSp-1]);
iSp--;
break;
case MINF:
save[iSp-2]=(save[iSp-2]<save[iSp-1])?save[iSp-2]:save[iSp-1];
iSp--;
break;
case MAXF:
save[iSp-2]=(save[iSp-2]>save[iSp-1])?save[iSp-2]:save[iSp-1];
iSp--;
break;
/*case MOD:
save[iSp-2]=fmod(save[iSp-2],save[iSp-1]);
iSp--;
break;*/
default:
return 0;
//THROW(new CEvalException("Token Error"));
}
}
return save[iSp-1];
}
int CPoly::Analyze(const char * pszStr)
{
if (pszStr)
SetStr(pszStr);
if (0 == strData.length())
return true;
//DisposeList();
ErrorOccur = false;
uiLookPos = 0;
iLookAhead = lexan();
expr();
if (tokenBase.empty())
{
//THROW(new CParseException("No Data"));
return false;
}
return !ErrorOccur;
}
void CPoly::Clear()
{
int i;
//while (!tokenBase.IsEmpty()) listBase.RemoveTail();
//while (!numBase.IsEmpty()) numBase.RemoveTail();
tokenBase.clear();
numBase.clear();
for (i = 0;i < STSize; ++i)
{
if (lSymbol[i]) delete lSymbol[i];
lSymbol[i]=NULL;
}
//lSymbol.FreeExtra();
lSymbol.clear();
SymbolIndex.clear();
STSize=0;
}
void CPoly::expr()
{
int t;
switch (iLookAhead)
{
case '+':
case '-':
uiLookPos--;
iLookAhead = NUM;
iNumToken = iToken = 0;
}
term();
while (!ErrorOccur)
{
switch (iLookAhead)
{
case '+':
case '-':
t=iLookAhead;
match(t);
term();
emit(t,NONE);
continue;
case EOS: case ')': case ',': return;
default:
error();
//THROW( new CParseException("Error Parsing"));
return;
}
}
}
void CPoly::error()
{
iErrorPos=uiLookPos;
ErrorOccur=true;
}
int CPoly::lexan()
{
int t;
double tt;
while (uiLookPos < strData.size())
{
if (strData[uiLookPos] == ' ' || strData[uiLookPos] == '\t')
;
else if (isdigit(strData[uiLookPos]))
{
t = 0;
for (;uiLookPos<strData.size();uiLookPos++)
{
if (isdigit(strData[uiLookPos]))
t = t * 10 + strData[uiLookPos] - '0';
else
break;
}
iToken=t;
tt=0.1;
iNumToken=0;
if (uiLookPos<strData.size() && strData[uiLookPos]=='.')
{
uiLookPos++;
for (;uiLookPos<strData.size();uiLookPos++,tt*=0.1)
{
if (isdigit(strData[uiLookPos]))
iNumToken+=tt*(strData[uiLookPos]-'0');
else
break;
}
}
iNumToken+=iToken;
return NUM;
}
else if (isalpha(strData[uiLookPos]))
{
string localSymbol("");
while (uiLookPos<strData.size() && isalpha(strData[uiLookPos]))
{
localSymbol+=strData[uiLookPos];
uiLookPos++;
}
iToken= find(localSymbol);
if (iToken==-1)
{
iToken=insert(localSymbol,ID);
}
return lSymbol[(/*FindIndex*/(iToken))]->token;
}
else
{
iToken=0;
return strData[uiLookPos++];
}
uiLookPos++;
}
return EOS;
}
void CPoly::term()
{
int t;
factor();
while (!ErrorOccur)
{
switch (iLookAhead)
{
case '*':
case '/':
case '%':
t=iLookAhead;
match(t);
factor();
emit(t,NONE);
continue;
default:
return;
}
}
}
void CPoly::factor()
{
int t;
expo();
while (!ErrorOccur)
{
switch (iLookAhead)
{
case '^':
t=iLookAhead;
match(t);
expo();
emit(t,NONE);
continue;
default:
return;
}
}
}
void CPoly::expo()
{
int t;
switch (iLookAhead)
{
case '(':
match('('); expr(); match(')'); break;
case NUM:
emit(NUM, iToken); match(NUM); break;
case ID:
emit(ID,(int)/*FindIndex*/(iToken)); match(ID); break;
case ROOT:
case SIN:
case COT:
case TAN:
case CSC:
case SEC:
case LN:
case LOG10:
case COS:
case ABS:
case FLOOR:
case SIGN:
t=iLookAhead;
match(iLookAhead); match('('); expr(); match(')'); emit(t,iToken);
break;
case LOG:
case MINF:
case MAXF:
case IRAND:
case FRAND:
case MOD:
t=iLookAhead;
match(iLookAhead); match('('); expr(); match(','); expr(); match(')'); emit(t,iToken);
break;
case EOS:
break;
default:
error();
//THROW( new CParseException("Error Parsing"));
}
}
void CPoly::match(int t)
{
if (iLookAhead==t) iLookAhead=lexan(); else error();
}
void CPoly::emit(int t, int tval)
{
switch (t)
{
case '+':
tokenBase.push_back(PLU);
break;
case '-':
tokenBase.push_back(MIN);
break;
case '*':
tokenBase.push_back(MUL);
break;
case '/':
tokenBase.push_back(DIV);
break;
case '%':
tokenBase.push_back(MOD);
break;
case '^':
tokenBase.push_back(POW);
break;
case ROOT:
case SIN:
case TAN:
case COT:
case COS:
case CSC:
case SEC:
case LOG:
case LN:
case LOG10:
case ABS:
case MINF:
case MAXF:
case IRAND:
case FRAND:
case MOD:
case FLOOR:
case SIGN:
tokenBase.push_back(t);
break;
case NUM:
tokenBase.push_back(t);
numBase.push_back(iNumToken);
break;
case ID:
tokenBase.push_back(t);
tokenBase.push_back(tval); break;
default:
error();
Clear();
//THROW( new CParseException("Error Parsing"));
return;
}
}
int CPoly::find(const string & s)
{
int l, m, r;
l = 0;
r = STSize - 1;
while (l <= r)
{
m = (l + r) >> 1;
if (lSymbol[SymbolIndex[m]]->strlex == s)
return SymbolIndex[m];
else if (lSymbol[SymbolIndex[m]]->strlex < s)
l = m + 1;
else
r = m - 1;
}
return -1;
}
int CPoly::insert(const string & s, int tok)
{
int i;
bool bAdded=false;
//s.MakeLower();
//transform(s.begin(),s.end(),s.begin(),std::tolower);
//lSymbol.SetAtGrow(STSize,new CSymTable(tok,s));
lSymbol.push_back(new CSymTable(tok,s));
for (i=0;i<STSize;i++)
{
if (s<lSymbol[SymbolIndex[i]]->strlex)
{
SymbolIndex.insert(SymbolIndex.begin()+i,STSize);
bAdded=true;
break;
}
}
if (!bAdded)
{
//SymbolIndex.SetAtGrow(STSize,STSize);
SymbolIndex.push_back(STSize);
}
STSize++;
return STSize-1;
}
int CPoly::SetVar(const string & strName, double dVar)
{
//transform(strName.begin(),strName.end(),s.begin(),std::tolower);
if (ErrorOccur) return false;
int index = find(strName);
if (index == -1) return false;
CSymTable * stVar = lSymbol[(/*FindIndex*/(index))];
stVar->dVal = dVar;
return true;
}
double CPoly::GetVar(const std::string & strName)
{
if (ErrorOccur) return false;
int index = find(strName);
if (index == -1) return false;
CSymTable * stVar = lSymbol[(/*FindIndex*/(index))];
if(!stVar)
return -1;
return stVar->dVal;
}
void CPoly::init()
{
insert("min",MINF);
insert("max",MAXF);
insert("number", IRAND);
insert("irandom", IRAND);
insert("irand", IRAND);
insert("frandom",FRAND);
insert("frand",FRAND);
insert("rt",ROOT);
insert("sqrt",ROOT);
insert("cos",COS);
insert("sin",SIN);
insert("tan",TAN);
insert("cot",COT);
insert("csc",CSC);
insert("cosec",COSEC);
insert("sec",SEC);
insert("pi",PI);
SetVar("pi",3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068);
insert("e",EXP);
SetVar("e",2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427);
insert("log",LOG);
insert("ln",LN);
insert("log10",LOG10);
insert("abs",ABS);
insert("mod",MOD);
insert("floor", FLOOR);
insert("sign",SIGN);
}
/*
void CPoly::AddSymTable(CPtrList* ns)
{
int i, len = ns->GetCount();
CSymTable* a, *b;
int index;
POSITION pos;
pos = ns->GetHeadPosition();
for (i=0;i<len;i++)
{
a = ((CSymTable*)ns->GetNext(pos));
if ((index=find(a->strlex))==-1)
{
lSymbol[insert(a->strlex,a->token)]->dVal = a->dVal;
//lSymbol.SetAtGrow(STSize,b);
//STSize++;
}
else
{
(lSymbol.GetAt(FindIndex(index)))->dVal = a->dVal;
}
}
}
*/
/*
void CPoly::Diff(CString& str)
{
int stNow, cc;
int i;
CString* mstr,*bstr;
if (ErrorOccur) //THROW(new CEvalException("Diff Error"));
return;
mstr = new CString[tokenBase.GetCount()];
bstr = new CString[tokenBase.GetCount()];
POSITION pos = tokenBase.GetHeadPosition();
POSITION posn = numBase.GetHeadPosition();
cc=0;
while (pos != NULL)
{
stNow=tokenBase.GetNext(pos);
switch (stNow)
{
case NUM:
//save[iSp++]=numBase.GetNext(posn);
mstr[cc]="0";bstr[cc].Format("%f",numBase.GetNext(posn));
for (i=bstr[cc].GetLength()-1;i>=0;i--)
if (bstr[cc][i] != '0')
break;
if (i>0)
bstr[cc]=bstr[cc].Left(i+1);
i=bstr[cc].GetLength()-1;
if (bstr[cc][i]=='.')
{
bstr[cc]=bstr[cc].Left(i);
}
cc++; break;
case ID:
////save[iSp++]=
//lSymbol.GetAt(
//lSymbol.FindIndex(
//(POSITION )tokenBase.GetNext(pos)
// )
//)->dVal;
bstr[cc] = lSymbol.GetAt(tokenBase.GetNext(pos))->strlex;
if (bstr[cc] != "x") mstr[cc]="0";
else mstr[cc] = "1";
cc++;
break;
case '+':
cc--;
if (bstr[cc-1]=="0")
{
if (bstr[cc]=="0")
bstr[cc-1]="0";
else
bstr[cc-1]="("+bstr[cc]+")";
}
else if (bstr[cc]=="0")
{
bstr[cc-1]="("+bstr[cc-1]+")";
}
else
bstr[cc-1]="("+bstr[cc-1]+"+"+bstr[cc]+")";
bstr[cc]="";
if (mstr[cc-1]=="0")
{
if (mstr[cc]=="0")
mstr[cc-1]="0";
else
mstr[cc-1]="("+mstr[cc]+")";
}
else if (mstr[cc]=="0")
{
mstr[cc-1]="("+mstr[cc-1]+")";
}
else
mstr[cc-1]="("+mstr[cc-1]+"+"+mstr[cc]+")";
mstr[cc]="";
break;
case '-':
cc--;
if (bstr[cc-1]=="0")
{
if (bstr[cc]=="0")
bstr[cc-1]="0";
else
bstr[cc-1]="(-"+bstr[cc]+")";
}
else if (bstr[cc]=="0")
{
bstr[cc-1]="("+bstr[cc-1]+")";
}
else
bstr[cc-1]="("+bstr[cc-1]+"-"+bstr[cc]+")";
bstr[cc]="";
if (mstr[cc-1]=="0")
{
if (mstr[cc]=="0")
mstr[cc-1]="0";
else
mstr[cc-1]="(-"+mstr[cc]+")";
}
else if (mstr[cc]=="0")
{
mstr[cc-1]="("+mstr[cc-1]+")";
}
else
mstr[cc-1]="("+mstr[cc-1]+"-"+mstr[cc]+")";
mstr[cc]="";
break;
case '*':
cc--;
if (mstr[cc-1]=="0" || bstr[cc]=="0")
{
if (mstr[cc]=="0" || bstr[cc-1]=="0")
{
mstr[cc-1]="0";
}
else
{
mstr[cc-1]="("+ mstr[cc] + "*" +bstr[cc-1] +")";
}
}
else if (mstr[cc]=="0" || bstr[cc-1]=="0")
{
mstr[cc-1] = "("+mstr[cc-1] + "*" + bstr[cc] + ")";
}
else
mstr[cc-1] = "(("+mstr[cc-1] + "*" + bstr[cc] + ")+(" +mstr[cc] + "*" +bstr[cc-1] +"))";
if (bstr[cc-1]=="0" || bstr[cc]=="0")
{
bstr[cc-1]="0";
}
else
bstr[cc-1]="("+bstr[cc-1]+"*"+bstr[cc]+")";
mstr[cc]=""; bstr[cc]="";
break;
case '/':
cc--;
if (bstr[cc]=="0") THROW(new CEvalException("Divide by Zero"));
if (mstr[cc-1]=="0"||bstr[cc]=="0")
{
if (mstr[cc]=="0" || bstr[cc-1]=="0")
{
mstr[cc-1]="0";
}
else
mstr[cc-1]="((-" +mstr[cc]+"*"+bstr[cc-1]+ ")/("+bstr[cc]+")^2)";
}
else if (mstr[cc]=="0"||bstr[cc-1]=="0")
{
mstr[cc-1]="((" +mstr[cc-1]+"*"+bstr[cc] + ")/("+bstr[cc]+")^2)";
}
else
mstr[cc-1]="((" +mstr[cc-1]+"*"+bstr[cc]+ "-" +mstr[cc]+"*"+bstr[cc-1]+ ")/("+bstr[cc]+")^2)";
if (bstr[cc-1]=="0")
bstr[cc-1]="0";
else
bstr[cc-1]="("+bstr[cc-1]+")/("+bstr[cc]+")";
break;
case '^':
cc--;
if (mstr[cc-1]=="0")
{
if (mstr[cc]=="0")
{
mstr[cc-1]="0";
mstr[cc]="";
}
else
{
mstr[cc-1]="ln("+bstr[cc-1]+")*("+bstr[cc-1]+")^("+bstr[cc]+")*("+mstr[cc]+")";
mstr[cc]="";
}
}
else if (mstr[cc]=="0")
{
mstr[cc-1]="("+bstr[cc]+")*("+bstr[cc-1]+")^("+bstr[cc]+"-1)*("+mstr[cc-1]+")";
mstr[cc]="";
}
else
{
mstr[cc-1]="(ln("+bstr[cc-1]+")*("+bstr[cc-1]+")^("+bstr[cc]+")*("+mstr[cc]+")+("+bstr[cc]+")*("+bstr[cc-1]+")^("+bstr[cc]+"-1)*("+mstr[cc-1]+"))";
mstr[cc]="";
}
if (bstr[cc-1]=="0")
{
bstr[cc-1]="0";
}
else if (bstr[cc-1]=="1")
{
bstr[cc-1]="1";
}
else if (bstr[cc]=="1")
{
}
else if (bstr[cc]=="0")
{
bstr[cc-1]="0";
}
else
bstr[cc-1]="("+bstr[cc-1]+")^("+bstr[cc]+")";
bstr[cc]="";
break;
case ROOT:
cc--;
if (mstr[cc]=="0")
mstr[cc]="0";
else
mstr[cc]="("+mstr[cc]+"/2/rt("+bstr[cc]+"))";
bstr[cc]="rt("+bstr[cc] +")";
cc++;
break;
case COS:
cc--;
mstr[cc]="(-"+mstr[cc]+"*sin("+bstr[cc]+"))";
bstr[cc]="cos("+bstr[cc]+")";
cc++;
break;
case SIN:
cc--;
mstr[cc]="("+mstr[cc]+"*cos("+bstr[cc]+"))";
bstr[cc]="sin("+bstr[cc]+")";
cc++;
break;
case TAN:
cc--;
mstr[cc]="(sec("+bstr[cc]+")^2*"+mstr[cc]+")";
bstr[cc]="tan("+bstr[cc]+")";
cc++;
break;
case CSC:
cc--;
mstr[cc]="(-csc("+bstr[cc]+")*cot("+bstr[cc]+")*"+mstr[cc]+")";
bstr[cc]="csc("+bstr[cc]+")";
cc++;
break;
case SEC:
cc--;
mstr[cc]="(sec("+bstr[cc]+")*tan("+bstr[cc]+")*"+mstr[cc]+")";
bstr[cc]="sec("+bstr[cc]+")";
cc++;
break;
case COT:
cc--;
mstr[cc]="(-csc("+bstr[cc]+")^2*"+mstr[cc]+")";
bstr[cc]="cot("+bstr[cc]+")";
cc++;
case LN:
cc--;
mstr[cc]="("+mstr[cc]+"/"+bstr[cc]+")";
bstr[cc]="ln("+bstr[cc]+")";
cc++;
break;
case LOG10:
cc--;
mstr[cc]="("+mstr[cc]+"/"+bstr[cc]+"/ln(10))";
bstr[cc]="log10("+bstr[cc]+")";
cc++;
break;
case LOG:
cc--;
mstr[cc-1]="("+mstr[cc]+"/"+bstr[cc]+"/ln("+bstr[cc-1]+")-ln("+bstr[cc]+")*"+mstr[cc-1]+"/ln("+bstr[cc-1]+")^2/"+bstr[cc-1]+")";
bstr[cc-1]="log("+bstr[cc-1]+","+bstr[cc]+")";
mstr[cc]="";
bstr[cc]="";
break;
default:
//THROW(new CEvalException("Out of Case"));
break;
}
}
str=mstr[cc-1];
delete[] mstr;
delete[] bstr;
}*/
/*int CPoly::FindIndex(int tval)
{
return tval;
}
*/