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:
CPhysConst m_PhysConst;
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 ) ;
double RAD(double x );
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();
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.0123
nErrorPosition
gives back the error position in the string
strErrortext
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
const double _c = 2.99792458E8;
const double _h = 6.6260755E-34;
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:
BOOL IsPhysConst(CString str);
double GetPhysConstValue(const CString str);
CString GetEachPhysConst(int i);
void SetPhysConstOrder();
private:
CStringArray m_strPhysConst;
};
like this:
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
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.
Ralf is the programmer of the well-known programs SimplexNumerica and SimplexParser. He's been programming since 1986 since he was at the Fraunhofer Institute for Laser Technology (ILT) in Aachen/Germany. His preferred programming language is Visual C++ with MFC/ATL and GFA Basic. Ralf was born near Gerolstein/Germany. He went to Aachen University where he obtained a Diploma of technical physics. He works as a senior design engineer for a fairly large, international company.