#include #include "Poly.h" #include "Constants.h" #include #include #include 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::iterator pos = tokenBase.begin(); //list::iterator posn = numBase.begin(); vector::iterator pos = tokenBase.begin(); vector::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 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 (;uiLookPostoken; } 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;istrlex) { 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;iGetNext(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; } */