Simple(x) Numerical Formula Parser






4.81/5 (25 votes)
Numerical Formula class from the SimplexParser freeware
Introduction
I'd like to set up my numerical formula class from SimplexParser in addition to my previous article about the date & time math parser (see here) also to the CodeProject site. With the class CFormulaParser
you can parse and evaluate numerical expressions and functions with variables given in a string. The class encapsulates also a useful mathematical parser for physical constants.
The demo project has the following simple input dialog for formula/function and variable/constants.
Sample Operations
The parser interprets editors code like:
Function: f(x) = y = sin(x)/x + a
whereby x is the main variable and a - h are the constants in the function. The result will be shown in the output window when you press the Enter button. That you can save and load the function and constants is in fact not so important here.
CFormulaParser
class
The following code shows the main methods from the CFormulaParser
class:
//... class CFormulaParser { private: // Physical Constants CPhysConst m_PhysConst; //Implementation CString m_strFormula; CString m_strFunction; CString m_strErrortext; static CString g_strF; double m_dFktValue; double m_dFunctionConstant[ANZFUNKTKONST]; CStringArray m_strStandardFunction; double SignFactor(int& nPosition, CString& strCharacter); double Expression(int& nPosition, CString& strCharacter); double SimpleExpression(int& nPosition, CString& strCharacter); double Term(int& nPosition, CString& strCharacter); double Factor(int& nPosition, CString& strCharacter); double Char_n(int& nPosition, CString& strCharacter); CString strChar_(BYTE DecimalZahl); CString GetNextToken(CString& strSrc, const CString strDelim); double SINQ(double Winkel_grad); double COSQ(double Winkel_grad); double DEG(double x /* rad */) ; double RAD(double x /* grad */); double cot(double x); long double signl(long double x); double ArSinh(double x); double ArCosh(double x); double ArTanh(double x); double ArCoth(double x); double sqr(double x); public: void StripFormula(CString& strFormula); CString GetFormula(); void SetFormula(CString Formula); void SetFunctConst(int index, double val); CFormulaParser(); virtual ~CFormulaParser(); //Interface double Calculation(CString strFormula, double xValue, int& nErrorPosition, CString& strErrortext, BOOL strip = true); }; //...
Using the code
The main method in CFormulaParser
for the evaluation is:
double Calculation(CString strFormula, double xValue, int& nErrorPosition, CString& strErrortext, BOOL strip = true);
where
strFormula
is the formula string, e.g. "b*sin(x)/x"xValue
is in this case x, e.g. 0.0123nErrorPosition
gives back the error position in the stringstrErrortext
gives back the corresponding error text
You can use this code as shown next:
//... void CSimplexParserDlg::OnEnter() { int ErrorPosition; char buffer[64]; CString strErrortext; strErrortext.Empty(); UpdateData(true); //___________________________ CFormulaParser FormulaParser; //___________________________ FormulaParser.SetFunctConst(1, m_dKonstA); FormulaParser.SetFunctConst(2, m_dKonstB); FormulaParser.SetFunctConst(3, m_dKonstC); FormulaParser.SetFunctConst(4, m_dKonstD); FormulaParser.SetFunctConst(5, m_dKonstE); FormulaParser.SetFunctConst(6, m_dKonstF); FormulaParser.SetFunctConst(7, m_dKonstG); FormulaParser.SetFunctConst(8, m_dKonstH); //______________________________________________ double retValue = FormulaParser.Calculation(m_strFormulainput, m_dKonstX, ErrorPosition, Errortext); //______________________________________________ CWnd* pWnd = GetDlgItem(IDC_FORMULAINPUT); pWnd->SetFocus(); if (nErrorPosition == 0) { if (strErrortext == "") { sprintf(buffer, "%f", retValue); m_strFormulaoutput = buffer; } else m_strFormulaoutput = "Error: " + Errortext; pWnd->SendMessage(EM_SETSEL,32767,32767); } else { m_strFormulaoutput = strErrortext; pWnd->SendMessage(EM_SETSEL,nErrorPosition - 1,nErrorPosition); } UpdateData(false); } //...
Physical Constants
The class encapsulates also a useful mathematical parser for physical constants. The implementation of the Physical Constants is very simple to use.
Define in the file PhysConst.h some additional constants like
// Velocity of light in vacuum (def) m/s const double _c = 2.99792458E8; // Planck constant (40)J s const double _h = 6.6260755E-34; // etc.
with a underline symbol in front (e.g. _abcd
). The name must be unique under the names.
Then fill in the constructor and member functions in the class CPhysConst
:
//... class CPhysConst { public: CPhysConst(); virtual ~CPhysConst(); public: //Functions BOOL IsPhysConst(CString str); double GetPhysConstValue(const CString str); CString GetEachPhysConst(int i); void SetPhysConstOrder(); private: // String Array CStringArray m_strPhysConst; }; //...
like this:
//... // constructor CPhysConst::CPhysConst() { // ... m_strPhysConst.Add(_T("_c")); m_strPhysConst.Add(_T("_h")); //...
and this:
//... BOOL CPhysConst::IsPhysConst(CString str) { if (stricmp(str, _T("_c")) == 0) return true; if (stricmp(str, _T("_h")) == 0) return true; //...
and finally this one:
//... double CPhysConst::GetPhysConstValue(const CString str) { if (stricmp(str, _T("_c")) == 0) return _c; if (stricmp(str, _T("_h")) == 0) return _h; //...
You can use this code as shown next:
//... CPhysConst m_PhysConst; //... else if (strFunctionUpper == "ARCOSH") { if (fabs(f) >= 1) f = ArCosh(f); else wError = -1; } else if (strFunctionUpper == "ARTANH") { if (fabs(f) <= 1) f = ArTanh(f); else wError = -1; } else if (double pc = m_PhysConst.GetPhysConstValue(strFunctionUpper)) { f = pc; } break; } //...
I hope that the code is reasonably obvious how to use. Look to the demo project for more details.
History
- 1.0 (25 April 2004) Initial Release
Acknowledgement
This would not have been possible without all the authors making their code freely available! So, thanks for that, SimplexParser will be available as freeware for all the time.