Seamly2D
Code documentation
qmuparser.cpp
Go to the documentation of this file.
1 /***************************************************************************************************
2  **
3  ** Copyright (C) 2013 Ingo Berg
4  **
5  ** Permission is hereby granted, free of charge, to any person obtaining a copy of this
6  ** software and associated documentation files (the "Software"), to deal in the Software
7  ** without restriction, including without limitation the rights to use, copy, modify,
8  ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9  ** permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  **
11  ** The above copyright notice and this permission notice shall be included in all copies or
12  ** substantial portions of the Software.
13  **
14  ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
15  ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16  ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17  ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  **
20  ******************************************************************************************************/
21 
22 #include "qmuparser.h"
23 
24 #include <QCoreApplication>
25 #include <QStaticStringData>
26 #include <QStringData>
27 #include <QStringDataPtr>
28 #include <QtGlobal>
29 #include <sstream>
30 #include <string>
31 
32 #include "qmuparserdef.h"
33 #include "qmuparsererror.h"
34 #include "../vmisc/vmath.h"
35 
36 /**
37  * @file
38  * @brief Implementation of the standard floating point QmuParser.
39  */
40 
41 /**
42  * @brief Namespace for mathematical applications.
43  */
44 namespace qmu
45 {
46 //---------------------------------------------------------------------------------------------------------------------
47 // Trigonometric function
48 qreal QmuParser::DegreeToRadian(qreal deg)
49 {
50  return qDegreesToRadians(deg);
51 }
52 
53 //---------------------------------------------------------------------------------------------------------------------
54 qreal QmuParser::RadianToDegree(qreal rad)
55 {
56  return qRadiansToDegrees(rad);
57 }
58 
59 //---------------------------------------------------------------------------------------------------------------------
60 qreal QmuParser::Sinh(qreal v)
61 {
62  return sinh(v);
63 }
64 
65 //---------------------------------------------------------------------------------------------------------------------
66 qreal QmuParser::ASinh(qreal v)
67 {
68  return log(v + qSqrt(v * v + 1));
69 }
70 
71 //---------------------------------------------------------------------------------------------------------------------
72 qreal QmuParser::Cosh(qreal v)
73 {
74  return cosh(v);
75 }
76 
77 //---------------------------------------------------------------------------------------------------------------------
78 qreal QmuParser::ACosh(qreal v)
79 {
80  return log(v + qSqrt(v * v - 1));
81 }
82 
83 //---------------------------------------------------------------------------------------------------------------------
84 qreal QmuParser::Tanh(qreal v)
85 {
86  return tanh(v);
87 }
88 
89 //---------------------------------------------------------------------------------------------------------------------
90 qreal QmuParser::ATanh(qreal v)
91 {
92  return (0.5 * log((1 + v) / (1 - v)));
93 }
94 
95 //---------------------------------------------------------------------------------------------------------------------
96 qreal QmuParser::SinD(qreal v)
97 {
98  return qSin(qDegreesToRadians(v));
99 }
100 
101 //---------------------------------------------------------------------------------------------------------------------
102 qreal QmuParser::ASinD(qreal v)
103 {
104  return qRadiansToDegrees(qAsin(v));
105 }
106 
107 //---------------------------------------------------------------------------------------------------------------------
108 qreal QmuParser::CosD(qreal v)
109 {
110  return qCos(qDegreesToRadians(v));
111 }
112 
113 //---------------------------------------------------------------------------------------------------------------------
114 qreal QmuParser::ACosD(qreal v)
115 {
116  return qRadiansToDegrees(qAcos(v));
117 }
118 
119 //---------------------------------------------------------------------------------------------------------------------
120 qreal QmuParser::TanD(qreal v)
121 {
122  return qTan(qDegreesToRadians(v));
123 }
124 
125 //---------------------------------------------------------------------------------------------------------------------
126 qreal QmuParser::ATanD(qreal v)
127 {
128  return qRadiansToDegrees(qAtan(v));
129 }
130 
131 //---------------------------------------------------------------------------------------------------------------------
132 // Logarithm functions
133 
134 //---------------------------------------------------------------------------------------------------------------------
135 // Logarithm base 2
136 qreal QmuParser::Log2(qreal v)
137 {
138 #ifdef MUP_MATH_EXCEPTIONS
139  if (v<=0)
140  {
141  throw QmuParserError(ecDOMAIN_ERROR, "Log2");
142  }
143 #endif
144  return log(v)/log(2.0);
145 }
146 
147 //---------------------------------------------------------------------------------------------------------------------
148 // Logarithm base 10
149 qreal QmuParser::Log10(qreal v)
150 {
151 #ifdef MUP_MATH_EXCEPTIONS
152  if (v<=0)
153  {
154  throw QmuParserError(ecDOMAIN_ERROR, "Log10");
155  }
156 #endif
157  return log10(v);
158 }
159 
160 //---------------------------------------------------------------------------------------------------------------------
161 // misc
162 qreal QmuParser::Abs(qreal v)
163 {
164  return qAbs(v);
165 }
166 
167 //---------------------------------------------------------------------------------------------------------------------
168 qreal QmuParser::Rint(qreal v)
169 {
170  return qFloor(v + 0.5);
171 }
172 
173 //---------------------------------------------------------------------------------------------------------------------
174 qreal QmuParser::Sign(qreal v)
175 {
176  return ((v<0) ? -1 : (v>0) ? 1 : 0);
177 }
178 
179 //---------------------------------------------------------------------------------------------------------------------
180 qreal QmuParser::FMod(qreal number, qreal denom)
181 {
182  return fmod(number, denom);
183 }
184 
185 //---------------------------------------------------------------------------------------------------------------------
186 /**
187  * @brief Callback for adding multiple values.
188  * @param [in] a_afArg Vector with the function arguments
189  * @param [in] a_iArgc The size of a_afArg
190  */
191 qreal QmuParser::Sum(const qreal *a_afArg, int a_iArgc)
192 {
193  if (a_iArgc == 0)
194  {
195  throw QmuParserError(QCoreApplication::translate("QmuParser", "too few arguments for function sum.",
196  "parser error message"));
197  }
198  qreal fRes=0;
199  for (int i=0; i<a_iArgc; ++i)
200  {
201  fRes += a_afArg[i];
202  }
203  return fRes;
204 }
205 
206 //---------------------------------------------------------------------------------------------------------------------
207 /**
208  * @brief Callback for averaging multiple values.
209  * @param [in] a_afArg Vector with the function arguments
210  * @param [in] a_iArgc The size of a_afArg
211  */
212 qreal QmuParser::Avg(const qreal *a_afArg, int a_iArgc)
213 {
214  if (a_iArgc == 0)
215  {
216  throw QmuParserError(QCoreApplication::translate("QmuParser", "too few arguments for function sum.",
217  "parser error message"));
218  }
219  qreal fRes=0;
220  for (int i=0; i<a_iArgc; ++i)
221  {
222  fRes += a_afArg[i];
223  }
224  return fRes/static_cast<qreal>(a_iArgc);
225 }
226 
227 //---------------------------------------------------------------------------------------------------------------------
228 /**
229  * @brief Callback for determining the minimum value out of a vector.
230  * @param [in] a_afArg Vector with the function arguments
231  * @param [in] a_iArgc The size of a_afArg
232  */
233 qreal QmuParser::Min(const qreal *a_afArg, int a_iArgc)
234 {
235  if (a_iArgc == 0)
236  {
237  throw QmuParserError(QCoreApplication::translate("QmuParser", "too few arguments for function min.",
238  "parser error message"));
239  }
240  qreal fRes=a_afArg[0];
241  for (int i=0; i<a_iArgc; ++i)
242  {
243  fRes = qMin(fRes, a_afArg[i]);
244  }
245  return fRes;
246 }
247 
248 //---------------------------------------------------------------------------------------------------------------------
249 /**
250  * @brief Callback for determining the maximum value out of a vector.
251  * @param [in] a_afArg Vector with the function arguments
252  * @param [in] a_iArgc The size of a_afArg
253  */
254 qreal QmuParser::Max(const qreal *a_afArg, int a_iArgc)
255 {
256  if (a_iArgc == 0)
257  {
258  throw QmuParserError(QCoreApplication::translate("QmuParser", "too few arguments for function min.",
259  "parser error message"));
260  }
261  qreal fRes=a_afArg[0];
262  for (int i=0; i<a_iArgc; ++i)
263  {
264  fRes = qMax(fRes, a_afArg[i]);
265  }
266  return fRes;
267 }
268 
269 //---------------------------------------------------------------------------------------------------------------------
270 /**
271 * @brief Default value recognition callback.
272 * @param [in] a_szExpr Pointer to the expression
273 * @param [in, out] a_iPos Pointer to an index storing the current position within the expression
274 * @param [out] a_fVal Pointer where the value should be stored in case one is found.
275 * @return 1 if a value was found 0 otherwise.
276 */
277 int QmuParser::IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const QLocale &locale, const QChar &decimal,
278  const QChar &thousand)
279 {
280  qreal fVal(0);
281 
282  const int pos = ReadVal(a_szExpr, fVal, locale, decimal, thousand);
283 
284  if (pos == -1)
285  {
286  return 0;
287  }
288 
289  *a_iPos += pos;
290  *a_fVal = fVal;
291  return 1;
292 }
293 
294 //---------------------------------------------------------------------------------------------------------------------
295 /**
296  * @brief Constructor.
297  *
298  * Call QmuParserBase class constructor and trigger Function, Operator and Constant initialization.
299  */
301 {
303 
304  InitCharSets();
305  InitFun();
306  InitConst();
307  InitOprt();
308 }
309 
310 //---------------------------------------------------------------------------------------------------------------------
311 /**
312  * @brief Define the character sets.
313  * @sa DefineNameChars, DefineOprtChars, DefineInfixOprtChars
314  *
315  * This function is used for initializing the default character sets that define
316  * the characters to be useable in function and variable names and operators.
317  */
319 {
320  DefineNameChars( QStringLiteral("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") );
321  DefineOprtChars( QStringLiteral("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+-*^/?<>=#!$%&|~'_{}") );
322  DefineInfixOprtChars( QStringLiteral("/+-*^?<>=#!$%&|~'_") );
323 }
324 
325 //---------------------------------------------------------------------------------------------------------------------
326 /**
327  * @brief Initialize the default functions.
328  */
330 {
331  // trigonometric helper functions
332  DefineFun("degTorad", DegreeToRadian);
333  DefineFun("radTodeg", RadianToDegree);
334 
335  // trigonometric functions
336  DefineFun("sin", qSin);
337  DefineFun("cos", qCos);
338  DefineFun("tan", qTan);
339  DefineFun("sinD", SinD);
340  DefineFun("cosD", CosD);
341  DefineFun("tanD", TanD);
342  // inverse functions
343  DefineFun("asin", qAsin);
344  DefineFun("acos", qAcos);
345  DefineFun("atan", qAtan);
346  DefineFun("atan2", qAtan2);
347  DefineFun("asinD", ASinD);
348  DefineFun("acosD", ACosD);
349  DefineFun("atanD", ATanD);
350  // hyperbolic functions
351  DefineFun("sinh", Sinh);
352  DefineFun("cosh", Cosh);
353  DefineFun("tanh", Tanh);
354  // inverse hyperbolic functions
355  DefineFun("asinh", ASinh);
356  DefineFun("acosh", ACosh);
357  DefineFun("atanh", ATanh);
358  // Logarithm functions
359  DefineFun("log2", Log2);
360  DefineFun("log10", Log10);
361  DefineFun("log", Log10);
362  DefineFun("ln", qLn);
363  // misc
364  DefineFun("exp", qExp);
365  DefineFun("sqrt", qSqrt);
366  DefineFun("sign", Sign);
367  DefineFun("rint", Rint);
368  DefineFun("abs", Abs);
369  DefineFun("fmod", FMod);
370  // Functions with variable number of arguments
371  DefineFun("sum", Sum);
372  DefineFun("avg", Avg);
373  DefineFun("min", Min);
374  DefineFun("max", Max);
375 }
376 
377 //---------------------------------------------------------------------------------------------------------------------
378 /**
379  * @brief Initialize constants.
380  *
381  * By default the QmuParser recognizes two constants. Pi ("pi") and the eulerian
382  * number ("_e").
383  */
385 {
386  DefineConst("_pi", static_cast<qreal>(M_PI));
387  DefineConst("_e", static_cast<qreal>(M_E));
388 }
389 
390 //---------------------------------------------------------------------------------------------------------------------
391 /**
392  * @brief Initialize operators.
393  *
394  * By default only the unary minus operator is added.
395  */
397 {
398  DefineInfixOprt(m_locale.negativeSign(), UnaryMinus);
399 }
400 
401 //---------------------------------------------------------------------------------------------------------------------
402 void QmuParser::OnDetectVar(const QString &pExpr, int &nStart, int &nEnd)
403 {
404  Q_UNUSED(pExpr)
405  Q_UNUSED(nStart)
406  Q_UNUSED(nEnd)
407  // this is just sample code to illustrate modifying variable names on the fly.
408  // I'm not sure anyone really needs such a feature...
409  /*
410 
411 
412  string sVar(pExpr->begin()+nStart, pExpr->begin()+nEnd);
413  string sRepl = std::string("_") + sVar + "_";
414 
415  int nOrigVarEnd = nEnd;
416  cout << "variable detected!\n";
417  cout << " Expr: " << *pExpr << "\n";
418  cout << " Start: " << nStart << "\n";
419  cout << " End: " << nEnd << "\n";
420  cout << " Var: \"" << sVar << "\"\n";
421  cout << " Repl: \"" << sRepl << "\"\n";
422  nEnd = nStart + sRepl.length();
423  cout << " End: " << nEnd << "\n";
424  pExpr->replace(pExpr->begin()+nStart, pExpr->begin()+nOrigVarEnd, sRepl);
425  cout << " New expr: " << *pExpr << "\n";
426  */
427 }
428 
429 //---------------------------------------------------------------------------------------------------------------------
430 /**
431  * @brief Numerically differentiate with regard to a variable.
432  * @param [in] a_Var Pointer to the differentiation variable.
433  * @param [in] a_fPos Position at which the differentiation should take place.
434  * @param [in] a_fEpsilon Epsilon used for the numerical differentiation.
435  *
436  * Numerical differentiation uses a 5 point operator yielding a 4th order
437  * formula. The default value for epsilon is 0.00074 which is
438  * numeric_limits<double>::epsilon() ^ (1/5) as suggested in the muQmuParser
439  * forum:
440  *
441  * http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843
442  */
443 // cppcheck-suppress unusedFunction
444 qreal QmuParser::Diff(qreal *a_Var, qreal a_fPos, qreal a_fEpsilon) const
445 {
446  qreal fRes(0),
447  fBuf(*a_Var),
448  f[4] = {0, 0, 0, 0},
449  fEpsilon(a_fEpsilon);
450 
451  // Backwards compatible calculation of epsilon inc case the user doesnt provide
452  // his own epsilon
453  if (qFuzzyIsNull(fEpsilon))
454  {
455  fEpsilon = qFuzzyIsNull(a_fPos) ? static_cast<qreal>(1e-10) : static_cast<qreal>(1e-7) * a_fPos;
456  }
457 
458  *a_Var = a_fPos+2 * fEpsilon; f[0] = Eval();
459  *a_Var = a_fPos+1 * fEpsilon; f[1] = Eval();
460  *a_Var = a_fPos-1 * fEpsilon; f[2] = Eval();
461  *a_Var = a_fPos-2 * fEpsilon; f[3] = Eval();
462  *a_Var = fBuf; // restore variable
463 
464  fRes = (-f[0] + 8*f[1] - 8*f[2] + f[3]) / (12*fEpsilon);
465  return fRes;
466 }
467 } // namespace qmu
Mathematical expressions parser (base parser engine).
Definition: qmuparserbase.h:66
void DefineOprtChars(const QString &a_szCharset)
Define the set of valid characters to be used in names of binary operators and postfix operators.
void DefineFun(const QString &a_strName, T a_pFun, bool a_bAllowOpt=true)
Define a parser function without arguments.
void DefineInfixOprtChars(const QString &a_szCharset)
Define the set of valid characters to be used in names of infix operators.
QLocale m_locale
The locale used by the parser.
qreal Eval() const
Calculate the result.
void AddValIdent(identfun_type a_pCallback)
Add a value parsing function.
void DefineConst(const QString &a_sName, qreal a_fVal)
Add a user defined constant.
void DefineInfixOprt(const QString &a_sName, fun_type1 a_pFun, int a_iPrec=prINFIX, bool a_bAllowOpt=true)
Add a user defined operator.
void DefineNameChars(const QString &a_szCharset)
Define the set of valid characters to be used in names of functions, variables, constants.
Error class of the parser.
virtual void InitOprt() Q_DECL_OVERRIDE
Initialize operators.
Definition: qmuparser.cpp:396
static qreal Min(const qreal *, int)
Callback for determining the minimum value out of a vector.
Definition: qmuparser.cpp:233
static qreal Rint(qreal)
Definition: qmuparser.cpp:168
virtual void InitFun() Q_DECL_OVERRIDE
Initialize the default functions.
Definition: qmuparser.cpp:329
static qreal RadianToDegree(qreal)
Definition: qmuparser.cpp:54
static qreal Sum(const qreal *, int)
Callback for adding multiple values.
Definition: qmuparser.cpp:191
static qreal ACosD(qreal)
Definition: qmuparser.cpp:114
static qreal UnaryMinus(qreal v)
Callback for the unary minus operator.
Definition: qmuparser.h:104
static qreal Sign(qreal)
Definition: qmuparser.cpp:174
static qreal Tanh(qreal)
Definition: qmuparser.cpp:84
virtual void InitConst() Q_DECL_OVERRIDE
Initialize constants.
Definition: qmuparser.cpp:384
static qreal ACosh(qreal)
Definition: qmuparser.cpp:78
static qreal ATanh(qreal)
Definition: qmuparser.cpp:90
static qreal Sinh(qreal)
Definition: qmuparser.cpp:60
static qreal DegreeToRadian(qreal)
Definition: qmuparser.cpp:48
QmuParser()
Constructor.
Definition: qmuparser.cpp:300
static qreal ATanD(qreal)
Definition: qmuparser.cpp:126
static qreal Abs(qreal)
Definition: qmuparser.cpp:162
static qreal FMod(qreal, qreal)
Definition: qmuparser.cpp:180
static int IsVal(const QString &a_szExpr, int *a_iPos, qreal *a_fVal, const QLocale &locale, const QChar &decimal, const QChar &thousand)
Default value recognition callback.
Definition: qmuparser.cpp:277
static qreal SinD(qreal)
Definition: qmuparser.cpp:96
static qreal ASinh(qreal)
Definition: qmuparser.cpp:66
static qreal Avg(const qreal *, int)
Callback for averaging multiple values.
Definition: qmuparser.cpp:212
virtual void OnDetectVar(const QString &pExpr, int &nStart, int &nEnd) Q_DECL_OVERRIDE
Definition: qmuparser.cpp:402
static qreal CosD(qreal)
Definition: qmuparser.cpp:108
static qreal TanD(qreal)
Definition: qmuparser.cpp:120
qreal Diff(qreal *a_Var, qreal a_fPos, qreal a_fEpsilon=0) const
Numerically differentiate with regard to a variable.
Definition: qmuparser.cpp:444
static qreal Log2(qreal)
Definition: qmuparser.cpp:136
static qreal ASinD(qreal)
Definition: qmuparser.cpp:102
virtual void InitCharSets() Q_DECL_OVERRIDE
Define the character sets.
Definition: qmuparser.cpp:318
static qreal Max(const qreal *, int)
Callback for determining the maximum value out of a vector.
Definition: qmuparser.cpp:254
static qreal Cosh(qreal)
Definition: qmuparser.cpp:72
static qreal Log10(qreal)
Definition: qmuparser.cpp:149
Namespace for mathematical applications.
@ ecDOMAIN_ERROR
catch division by zero, sqrt(-1), log(0) (currently unused)
int ReadVal(const QString &formula, qreal &val, const QLocale &locale, const QChar &decimal, const QChar &thousand)
Definition: qmudef.cpp:170
Definition of the standard floating point parser.
This file contains standard definitions used by the parser.
This file defines the error class used by the parser.
#define translate(context, source)
Definition: vcmdexport.cpp:41