1 /*==========================================================================
2   functioninfo
3   ------------
4   Copyright: Juha Nieminen, Joel Yliluoma
5   This program (functioninfo) is distributed under the terms of the
6   GNU General Public License (GPL) version 3.
7   See gpl.txt for the license text.
8 ============================================================================*/
9 
10 static const char* const kVersionNumber = "1.2.0.4";
11 
12 #include "fparser.hh"
13 #include "fparser_mpfr.hh"
14 #include "fparser_gmpint.hh"
15 #include "extrasrc/fpaux.hh"
16 #include <iostream>
17 #include <iomanip>
18 #include <vector>
19 #include <set>
20 #include <string>
21 #include <cstring>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <ctime>
25 #include <cmath>
26 #include <sstream>
27 #include <cassert>
28 #include <algorithm>
29 
30 #define SEPARATOR \
31 "----------------------------------------------------------------------------"
32 
33 namespace
34 {
35     template<typename Value_t>
36     struct TimingConst
37     {
38         static const unsigned kParseLoopsPerUnit = 100000;
39         static const unsigned kEvalLoopsPerUnit = 300000;
40         static const unsigned kOptimizeLoopsPerUnit = 1000;
41     };
42 
43 #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
44     template<>
45     struct TimingConst<MpfrFloat>
46     {
47         static const unsigned kParseLoopsPerUnit = 100000;
48         static const unsigned kEvalLoopsPerUnit = 10000;
49         static const unsigned kOptimizeLoopsPerUnit = 500;
50     };
51 #endif
52 
53     const unsigned kTestTime = 250; // In milliseconds
54     const bool kPrintTimingProgress = false;
55 
56     const unsigned kMaxVarValueSetsAmount = 10000;
57     const double kVarValuesUpperLimit = 100000.0;
58     const double kVarValuesInitialDelta = 0.1;
59     const double kVarValuesDeltaFactor1 = 1.25;
60     const double kVarValuesDeltaFactor2 = 10.0;
61     const double kVarValuesDeltaFactor2Threshold = 10.0;
62 
63     bool gPrintByteCodeExpressions = true;
64 
epsilon()65     template<typename Value_t> Value_t epsilon() { return Value_t(1e-9); }
epsilon()66     template<> inline float epsilon<float>() { return 1e-5F; }
67     //template<> inline long epsilon<long>() { return 0; }
68 
69 #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
epsilon()70     template<> inline MpfrFloat epsilon<MpfrFloat>()
71     { return MpfrFloat::someEpsilon(); }
72 #endif
73 
74 //#ifdef FP_SUPPORT_GMP_INT_TYPE
75     //template<> inline GmpInt epsilon<GmpInt>() { return 0; }
76 //#endif
77 
78     template<typename Value_t>
Sqr(const Value_t * p)79     Value_t Sqr(const Value_t* p)
80     {
81         return p[0]*p[0];
82     }
83 
84     template<typename Value_t>
Sub(const Value_t * p)85     Value_t Sub(const Value_t* p)
86     {
87         return p[0]-p[1];
88     }
89 
90     template<typename Value_t>
Value(const Value_t *)91     Value_t Value(const Value_t*)
92     {
93         return Value_t(10);
94     }
95 
96     template<typename Value_t>
97     class InitializableParser: public FunctionParserBase<Value_t>
98     {
99      public:
InitializableParser(const char * function,const char * vars)100         InitializableParser(const char* function, const char* vars)
101         {
102             assert(FunctionParserBase<Value_t>::Parse(function, vars) < 0);
103         }
104     };
105 
106 
107     template<typename Value_t>
108     class ParserWithConsts: public FunctionParserBase<Value_t>
109     {
110      public:
ParserWithConsts()111         ParserWithConsts()
112         {
113             typedef FunctionParserBase<Value_t> b;
114             b::AddConstant("pi", Value_t(3.14159265358979323846));
115             b::AddConstant("e", Value_t(2.71828182845904523536));
116             b::AddUnit("k", Value_t(1000));
117             b::AddUnit("M", Value_t(1000000));
118             b::AddUnit("dozen", Value_t(12));
119             b::AddUnit("dozens", Value_t(12));
120 
121             b::AddFunction("sqr", Sqr<Value_t>, 1);
122             b::AddFunction("sub", Sub<Value_t>, 2);
123             b::AddFunction("value", Value<Value_t>, 0);
124 
125             static InitializableParser<Value_t> SqrFun("x*x", "x");
126             static InitializableParser<Value_t> SubFun("x-y", "x,y");
127             static InitializableParser<Value_t> ValueFun("5", "");
128 
129             b::AddFunction("psqr", SqrFun);
130             b::AddFunction("psub", SubFun);
131             b::AddFunction("pvalue", ValueFun);
132         }
133 
134         // Publicize fparser's parsing functions
135         using FunctionParserBase<Value_t>::ParseLiteral;
136         using FunctionParserBase<Value_t>::ParseIdentifier;
137     };
138 
139     struct TimingInfo
140     {
141         double mMicroSeconds;
142         unsigned mLoopsPerSecond;
143     };
144 
145     template<typename Value_t>
146     struct FunctionInfo
147     {
148         std::string mFunctionString;
149         ParserWithConsts<Value_t> mParser;
150         std::vector<Value_t> mValidVarValues;
151 
152         TimingInfo mParseTiming;
153         TimingInfo mEvalTiming;
154         TimingInfo mOptimizeTiming;
155         TimingInfo mDoubleOptimizeTiming;
156         TimingInfo mOptimizedEvalTiming;
157         TimingInfo mDoubleOptimizedEvalTiming;
158     };
159 
160 
161     template<typename Value_t>
162     struct ParserData
163     {
164         static ParserWithConsts<Value_t> gParser, gAuxParser;
165         static std::vector<std::vector<Value_t> > gVarValues;
166         static const Value_t* gEvalParameters;
167     };
168 
169     template<typename Value_t>
170     ParserWithConsts<Value_t> ParserData<Value_t>::gParser;
171 
172     template<typename Value_t>
173     ParserWithConsts<Value_t> ParserData<Value_t>::gAuxParser;
174 
175     template<typename Value_t>
176     std::vector<std::vector<Value_t> > ParserData<Value_t>::gVarValues;
177 
178     template<typename Value_t>
179     const Value_t* ParserData<Value_t>::gEvalParameters = 0;
180 
181 
182     std::string gFunctionString, gVarString;
183     bool gUseDegrees = false;
184 
185     template<typename Value_t>
doParse()186     inline void doParse()
187     {
188         ParserData<Value_t>::gParser.Parse
189             (gFunctionString, gVarString, gUseDegrees);
190     }
191 
192     template<typename Value_t>
doEval()193     inline void doEval()
194     {
195         ParserData<Value_t>::gParser.Eval
196             (ParserData<Value_t>::gEvalParameters);
197     }
198 
199     template<typename Value_t>
doOptimize()200     inline void doOptimize()
201     {
202         ParserData<Value_t>::gAuxParser = ParserData<Value_t>::gParser;
203         ParserData<Value_t>::gAuxParser.Optimize();
204     }
205 
206     template<void(*Function)(), unsigned loopsPerUnit>
getTimingInfo()207     TimingInfo getTimingInfo()
208     {
209         unsigned loopUnitsPerformed = 0;
210         unsigned totalMilliseconds;
211         std::clock_t iClock = std::clock();
212         do
213         {
214             for(unsigned i = 0; i < loopsPerUnit; ++i)
215                 Function();
216             ++loopUnitsPerformed;
217             totalMilliseconds = unsigned(
218                 (std::clock() - iClock) * 1000 / CLOCKS_PER_SEC );
219         }
220         while(totalMilliseconds < kTestTime);
221         //std::cout << loopUnitsPerformed << "\n";
222 
223         const double totalSeconds = totalMilliseconds / 1000.0;
224         const double totalLoops =
225             double(loopUnitsPerformed) * double(loopsPerUnit);
226 
227         TimingInfo info;
228         info.mMicroSeconds = totalSeconds * 1e6 / totalLoops;
229         info.mLoopsPerSecond = unsigned(totalLoops / totalSeconds + 0.5);
230 
231         return info;
232     }
233 
234     unsigned gTimingCounter = 0;
235     std::size_t gTimingTotalCount;
236 
printTimingInfo()237     void printTimingInfo()
238     {
239         if(!kPrintTimingProgress) return;
240         std::cout << "Timing " << gTimingCounter * 100 / gTimingTotalCount
241                   << "%\r" << std::flush;
242         ++gTimingCounter;
243     }
244 
245     template<typename Value_t>
getTimingInfo(FunctionInfo<Value_t> & info)246     void getTimingInfo(FunctionInfo<Value_t>& info)
247     {
248         gFunctionString = info.mFunctionString;
249         ParserData<Value_t>::gEvalParameters = &info.mValidVarValues[0];
250 
251         printTimingInfo();
252         info.mParseTiming =
253             getTimingInfo
254             <doParse<Value_t>, TimingConst<Value_t>::kParseLoopsPerUnit>();
255 
256         printTimingInfo();
257         info.mEvalTiming =
258             getTimingInfo
259             <doEval<Value_t>, TimingConst<Value_t>::kEvalLoopsPerUnit>();
260 
261         printTimingInfo();
262         info.mOptimizeTiming = // optimizing a non-optimized func
263             getTimingInfo
264             <doOptimize<Value_t>,
265             TimingConst<Value_t>::kOptimizeLoopsPerUnit>();
266 
267         printTimingInfo();
268         ParserData<Value_t>::gParser.Optimize();
269         info.mDoubleOptimizeTiming = // optimizing an already-optimized func
270             getTimingInfo<doOptimize<Value_t>,
271             TimingConst<Value_t>::kOptimizeLoopsPerUnit>();
272 
273         printTimingInfo();
274         info.mOptimizedEvalTiming = // evaluating an optimized func
275             getTimingInfo
276             <doEval<Value_t>, TimingConst<Value_t>::kEvalLoopsPerUnit>();
277 
278         printTimingInfo();
279         ParserData<Value_t>::gParser.Optimize();
280         info.mDoubleOptimizedEvalTiming = // evaluating a twice-optimized func
281             getTimingInfo
282             <doEval<Value_t>, TimingConst<Value_t>::kEvalLoopsPerUnit>();
283     }
284 
285     template<typename Value_t>
valueIsOk(Value_t value)286     inline bool valueIsOk(Value_t value)
287     {
288         return !(value < -1e14 || value > 1e14);
289     }
290 
291     template<>
valueIsOk(long)292     inline bool valueIsOk<long>(long) { return true; }
293 
294 #ifdef FP_SUPPORT_GMP_INT_TYPE
295     template<>
valueIsOk(GmpInt)296     inline bool valueIsOk<GmpInt>(GmpInt) { return true; }
297 #endif
298 
299 #ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
300     template<>
valueIsOk(std::complex<double>)301     inline bool valueIsOk<std::complex<double> > (std::complex<double>)
302     {
303         return true;
304     }
305 #endif
306 
307 #ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
308     template<>
valueIsOk(std::complex<float>)309     inline bool valueIsOk<std::complex<float> > (std::complex<float>)
310     {
311         return true;
312     }
313 #endif
314 
315 #ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
316     template<>
valueIsOk(std::complex<long double>)317     inline bool valueIsOk<std::complex<long double> > (std::complex<long double>)
318     {
319         return true;
320     }
321 #endif
322 
323     template<typename Value_t>
findImmeds(const std::vector<FunctionInfo<Value_t>> & functions)324     std::vector<Value_t> findImmeds(const std::vector<FunctionInfo<Value_t> >& functions)
325     {
326         std::vector<Value_t> result;
327 
328         for(std::size_t a=0; a<functions.size(); ++a)
329         {
330             const std::string& functionString = functions[a].mFunctionString;
331             const ParserWithConsts<Value_t>& parser = functions[a].mParser;
332             const char* function = functionString.c_str();
333             std::size_t len = functionString.size();
334 
335             for(std::size_t pos=0; pos<len; )
336             {
337                 std::pair<const char*, Value_t>
338                     literal = parser.ParseLiteral(function+pos);
339                 if(literal.first != (function+pos))
340                 {
341                     result.push_back(literal.second);
342                     result.push_back(-literal.second);
343                     pos = literal.first - function;
344                     continue;
345                 }
346                 unsigned identifier = parser.ParseIdentifier(function);
347 
348                 unsigned skip_length = identifier & 0xFFFF;
349                 if(skip_length == 0) skip_length = 1;
350                 pos += skip_length;
351             }
352         }
353 
354         std::sort(result.begin(), result.end(), FUNCTIONPARSERTYPES::fp_less<Value_t> );
355         result.erase(std::unique(result.begin(), result.end()), result.end());
356         return result;
357     }
358 
359     template<typename Value_t>
makeDoubleFrom(const Value_t & v)360     double makeDoubleFrom(const Value_t& v)
361     {
362         /* FIXME: Why is this function needed?
363          * Why does findValidVarValues() use "double" datatype?
364          */
365         return double(v);
366     }
367 
368 #ifdef FP_SUPPORT_GMP_INT_TYPE
369     template<>
makeDoubleFrom(const GmpInt & v)370     double makeDoubleFrom(const GmpInt& v)
371     {
372         return v.toInt();
373     }
374 #endif
375 
376 #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
377     template<>
makeDoubleFrom(const MpfrFloat & v)378     double makeDoubleFrom(const MpfrFloat& v)
379     {
380         return v.toDouble();
381     }
382 #endif
383 
384     template<typename Value_t>
parseUserGivenVarValues(const std::string & str)385     std::vector<Value_t> parseUserGivenVarValues(const std::string& str)
386     {
387         std::vector<Value_t> values;
388         std::istringstream is(str);
389         Value_t value;
390         while(is >> value) values.push_back(value);
391         return values;
392     }
393 
394     template<typename Value_t>
parseUserGivenVarValuesFromSpecialClass(const std::string & str)395     std::vector<Value_t> parseUserGivenVarValuesFromSpecialClass
396     (const std::string& str)
397     {
398         std::vector<Value_t> values;
399         const char* ptr = str.c_str();
400         char* endptr = 0;
401         while(true)
402         {
403             Value_t value = Value_t::parseString(ptr, &endptr);
404             if(endptr == ptr) break;
405             values.push_back(value);
406             ptr += endptr - ptr;
407         }
408         return values;
409     }
410 
411 #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
412     template<>
parseUserGivenVarValues(const std::string & str)413     std::vector<MpfrFloat> parseUserGivenVarValues<MpfrFloat>
414     (const std::string& str)
415     {
416         return parseUserGivenVarValuesFromSpecialClass<MpfrFloat>(str);
417     }
418 #endif
419 
420 #ifdef FP_SUPPORT_GMP_INT_TYPE
421     template<>
parseUserGivenVarValues(const std::string & str)422     std::vector<GmpInt> parseUserGivenVarValues<GmpInt>
423     (const std::string& str)
424     {
425         return parseUserGivenVarValuesFromSpecialClass<GmpInt>(str);
426     }
427 #endif
428 
429     template<typename Value_t
430 #ifdef FP_SUPPORT_COMPLEX_NUMBERS
431      , bool IsComplexType=FUNCTIONPARSERTYPES::IsComplexType<Value_t>::result
432 #endif
433             >
434     struct findValidVarValuesAux
435     {
find__anon3f10ec800111::findValidVarValuesAux436         static bool find(std::vector<FunctionInfo<Value_t> >& functions,
437                          const std::string& userGivenVarValuesString)
438         {
439             unsigned varsAmount = 1;
440             for(std::size_t i = 0; i < gVarString.length(); ++i)
441                 if(gVarString[i] == ',')
442                     ++varsAmount;
443 
444             std::vector<Value_t> userGivenVarValues;
445             if(!userGivenVarValuesString.empty())
446             {
447                 userGivenVarValues =
448                     parseUserGivenVarValues<Value_t>(userGivenVarValuesString);
449                 if(userGivenVarValues.size() != varsAmount)
450                 {
451                     std::cout << "Warning: Wrong amount of values specified with "
452                         "-varValues. Ignoring." << std::endl;
453                     userGivenVarValues.clear();
454                 }
455             }
456 
457             std::vector<Value_t> varValues(varsAmount, Value_t());
458             std::vector<double> doubleValues(varsAmount, 0);
459             std::vector<double> deltas(varsAmount, kVarValuesInitialDelta);
460 
461             std::vector<Value_t> immedList = findImmeds(functions);
462 
463             if(userGivenVarValues.empty())
464             {
465                 for(std::size_t i = 0; i < functions.size(); ++i)
466                     functions[i].mValidVarValues = varValues;
467             }
468             else
469             {
470                 for(std::size_t i = 0; i < functions.size(); ++i)
471                     functions[i].mValidVarValues = userGivenVarValues;
472                 ParserData<Value_t>::gVarValues.push_back(userGivenVarValues);
473             }
474 
475             std::vector<std::size_t> immedCounter(varsAmount, 0);
476 
477             while(true)
478             {
479                 for(unsigned i = 0; i < varsAmount; ++i)
480                     varValues[i] = Value_t(doubleValues[i]);
481 
482                 bool wasOk = false;
483                 for(std::size_t i = 0; i < functions.size(); ++i)
484                 {
485                     Value_t value = functions[i].mParser.Eval(&varValues[0]);
486                     if(functions[i].mParser.EvalError() == 0 && valueIsOk(value))
487                     {
488                         if(userGivenVarValues.empty())
489                             functions[i].mValidVarValues = varValues;
490                         wasOk = true;
491                     }
492                 }
493 
494                 if(wasOk)
495                 {
496                     ParserData<Value_t>::gVarValues.push_back(varValues);
497                     if(ParserData<Value_t>::gVarValues.size() >=
498                        kMaxVarValueSetsAmount)
499                         return true;
500                 }
501 
502                 std::size_t varIndex = 0;
503                 while(true)
504                 {
505                     if(immedCounter[varIndex] == 0)
506                     {
507                         doubleValues[varIndex] = -doubleValues[varIndex];
508                         if(doubleValues[varIndex] < 0.0)
509                             break;
510 
511                         doubleValues[varIndex] += deltas[varIndex];
512                         if(deltas[varIndex] < kVarValuesDeltaFactor2Threshold)
513                             deltas[varIndex] *= kVarValuesDeltaFactor1;
514                         else
515                             deltas[varIndex] *= kVarValuesDeltaFactor2;
516 
517                         if(doubleValues[varIndex] <= kVarValuesUpperLimit)
518                             break;
519                     }
520 
521                     if(immedCounter[varIndex] < immedList.size())
522                     {
523                         std::size_t& i = immedCounter[varIndex];
524                         doubleValues[varIndex] =
525                             makeDoubleFrom (immedList[i] );
526                         i += 1;
527                         break;
528                     }
529 
530                     immedCounter[varIndex] = 0;
531                     doubleValues[varIndex] = 0.0;
532                     deltas[varIndex] = kVarValuesInitialDelta;
533                     if(++varIndex == doubleValues.size())
534                     {
535                         if(ParserData<Value_t>::gVarValues.empty())
536                         {
537                             ParserData<Value_t>::gVarValues.push_back
538                                 (std::vector<Value_t>(varsAmount, Value_t()));
539                             return false;
540                         }
541                         return true;
542                     }
543                 }
544             }
545         }
546     };
547 
548 #ifdef FP_SUPPORT_COMPLEX_NUMBERS
549     template<typename Value_t>
550     struct findValidVarValuesAux<Value_t, true>
551     {
552         /* Same as above, but for complex numbers */
553 
makeDouble1From__anon3f10ec800111::findValidVarValuesAux554         static double makeDouble1From(const Value_t& v)
555         {
556             return makeDoubleFrom(v.real());
557         }
makeDouble2From__anon3f10ec800111::findValidVarValuesAux558         static double makeDouble2From(const Value_t& v)
559         {
560             return makeDoubleFrom(v.imag());
561         }
562 
find__anon3f10ec800111::findValidVarValuesAux563         static bool find(std::vector<FunctionInfo<Value_t> >& functions,
564                          const std::string& userGivenVarValuesString)
565         {
566             unsigned varsAmount = 1;
567             for(std::size_t i = 0; i < gVarString.length(); ++i)
568                 if(gVarString[i] == ',')
569                     ++varsAmount;
570 
571             std::vector<Value_t> userGivenVarValues;
572             if(!userGivenVarValuesString.empty())
573             {
574                 userGivenVarValues =
575                     parseUserGivenVarValues<Value_t>(userGivenVarValuesString);
576                 if(userGivenVarValues.size() != varsAmount)
577                 {
578                     std::cout << "Warning: Wrong amount of values specified with "
579                         "-varValues. Ignoring." << std::endl;
580                     userGivenVarValues.clear();
581                 }
582             }
583 
584             const unsigned valuesAmount = varsAmount*2;
585 
586             std::vector<Value_t> varValues(varsAmount, 0);
587             std::vector<double> doubleValues(valuesAmount, 0);
588             std::vector<double> deltas(valuesAmount, kVarValuesInitialDelta);
589 
590             std::vector<Value_t> immedList = findImmeds(functions);
591 
592             if(userGivenVarValues.empty())
593             {
594                 for(std::size_t i = 0; i < functions.size(); ++i)
595                     functions[i].mValidVarValues = varValues;
596             }
597             else
598             {
599                 for(std::size_t i = 0; i < functions.size(); ++i)
600                     functions[i].mValidVarValues = userGivenVarValues;
601                 ParserData<Value_t>::gVarValues.push_back(userGivenVarValues);
602             }
603 
604             std::vector<std::size_t> immedCounter(valuesAmount, 0);
605 
606             while(true)
607             {
608                 for(unsigned i = 0; i < varsAmount; ++i)
609                     varValues[i] = Value_t(
610                         doubleValues[i*2+0],
611                         doubleValues[i*2+1]
612                     );
613 
614                 bool wasOk = false;
615                 for(std::size_t i = 0; i < functions.size(); ++i)
616                 {
617                     Value_t value = functions[i].mParser.Eval(&varValues[0]);
618                     if(functions[i].mParser.EvalError() == 0 && valueIsOk(value))
619                     {
620                         if(userGivenVarValues.empty())
621                             functions[i].mValidVarValues = varValues;
622                         wasOk = true;
623                     }
624                 }
625 
626                 if(wasOk)
627                 {
628                     ParserData<Value_t>::gVarValues.push_back(varValues);
629                     if(ParserData<Value_t>::gVarValues.size() >=
630                        kMaxVarValueSetsAmount)
631                         return true;
632                 }
633 
634                 std::size_t valueIndex = 0;
635                 while(true)
636                 {
637                     if(immedCounter[valueIndex] == 0)
638                     {
639                         doubleValues[valueIndex] = -doubleValues[valueIndex];
640                         if(doubleValues[valueIndex] < 0.0)
641                             break;
642 
643                         doubleValues[valueIndex] += deltas[valueIndex];
644                         if(deltas[valueIndex] < kVarValuesDeltaFactor2Threshold)
645                             deltas[valueIndex] *= kVarValuesDeltaFactor1;
646                         else
647                             deltas[valueIndex] *= kVarValuesDeltaFactor2;
648 
649                         if(doubleValues[valueIndex] <= kVarValuesUpperLimit)
650                             break;
651                     }
652 
653                     if(immedCounter[valueIndex] < immedList.size())
654                     {
655                         std::size_t& i = immedCounter[valueIndex];
656                         doubleValues[valueIndex] =
657                             (valueIndex & 1)
658                                 ? makeDouble2From( immedList[i] )
659                                 : makeDouble1From( immedList[i] );
660                         i += 1;
661                         break;
662                     }
663 
664                     immedCounter[valueIndex] = 0;
665                     doubleValues[valueIndex] = 0.0;
666                     deltas[valueIndex] = kVarValuesInitialDelta;
667                     if(++valueIndex == doubleValues.size())
668                     {
669                         if(ParserData<Value_t>::gVarValues.empty())
670                         {
671                             ParserData<Value_t>::gVarValues.push_back
672                                 (std::vector<Value_t>(varsAmount, Value_t()));
673                             return false;
674                         }
675                         return true;
676                     }
677                 }
678             }
679         }
680     };
681 #endif
682 
683     template<typename Value_t>
findValidVarValues(std::vector<FunctionInfo<Value_t>> & functions,const std::string & userGivenVarValuesString)684     bool findValidVarValues(std::vector<FunctionInfo<Value_t> >& functions,
685                             const std::string& userGivenVarValuesString)
686     {
687         return findValidVarValuesAux<Value_t>
688             ::find(functions, userGivenVarValuesString);
689     }
690 
691     template<typename Value_t>
scaledDiff(Value_t v1,Value_t v2)692     inline Value_t scaledDiff(Value_t v1, Value_t v2)
693     {
694         using namespace FUNCTIONPARSERTYPES;
695         const Value_t scale =
696             fp_pow(Value_t(10), fp_floor(fp_log10(fp_abs(v1))));
697         const Value_t sv1 =
698             fp_abs(v1) < epsilon<Value_t>() ? 0 : v1/scale;
699         const Value_t sv2 =
700             fp_abs(v2) < epsilon<Value_t>() ? 0 : v2/scale;
701         return sv2 - sv1;
702     }
703 
704     template<>
scaledDiff(long v1,long v2)705     inline long scaledDiff<long>(long v1, long v2)
706     {
707         return v2 - v1;
708     }
709 
710 #ifdef FP_SUPPORT_GMP_INT_TYPE
711     template<>
scaledDiff(GmpInt v1,GmpInt v2)712     inline GmpInt scaledDiff<GmpInt>(GmpInt v1, GmpInt v2)
713     {
714         return v2 - v1;
715     }
716 #endif
717 
718     template<typename Value_t>
notEqual(Value_t v1,Value_t v2)719     inline bool notEqual(Value_t v1, Value_t v2)
720     {
721         using namespace FUNCTIONPARSERTYPES;
722         return fp_abs(scaledDiff(v1, v2)) > epsilon<Value_t>();
723     }
724 
725     template<>
notEqual(long v1,long v2)726     inline bool notEqual<long>(long v1, long v2)
727     {
728         return v1 != v2;
729     }
730 
731 #ifdef FP_SUPPORT_GMP_INT_TYPE
732     template<>
notEqual(GmpInt v1,GmpInt v2)733     inline bool notEqual<GmpInt>(GmpInt v1, GmpInt v2)
734     {
735         return v1 != v2;
736     }
737 #endif
738 
739     template<typename Value_t>
compareFunctions(std::size_t function1Index,std::size_t function2Index,ParserWithConsts<Value_t> & parser1,const char * parser1Type,ParserWithConsts<Value_t> & parser2,const char * parser2Type)740     bool compareFunctions(std::size_t function1Index,
741                           std::size_t function2Index,
742                           ParserWithConsts<Value_t>& parser1,
743                           const char* parser1Type,
744                           ParserWithConsts<Value_t>& parser2,
745                           const char* parser2Type)
746     {
747         const std::size_t varsAmount =
748             ParserData<Value_t>::gVarValues[0].size();
749         for(std::size_t varSetInd = 0;
750             varSetInd < ParserData<Value_t>::gVarValues.size();
751             ++varSetInd)
752         {
753             const Value_t* values =
754                 &ParserData<Value_t>::gVarValues[varSetInd][0];
755             const Value_t v1 = parser1.Eval(values);
756             const Value_t v2 = parser2.Eval(values);
757 
758             if(notEqual(v1, v2))
759             {
760                 if(parser1.EvalError() && parser1Type[0] == 'n')
761                 {
762                     // If the source expression returns an error,
763                     // ignore this "failure"
764                     continue;
765                 }
766 
767                 using namespace FUNCTIONPARSERTYPES;
768                 std::cout << SEPARATOR << "\n******* For variable values (";
769                 for(std::size_t i = 0; i < varsAmount; ++i)
770                 {
771                     if(i > 0) std::cout << ",";
772                     std::cout << values[i];
773                 }
774                 std::cout << ")\n";
775                 std::cout << "******* function " << function1Index+1
776                           << " (" << parser1Type << ") returned ";
777                 if(parser1.EvalError())
778                     std::cout << "error " << parser1.EvalError();
779                 else
780                     std::cout << std::setprecision(18) << v1;
781                 std::cout << "\n";
782                 std::cout << "******* function " << function2Index+1
783                           << " (" << parser2Type << ") returned ";
784                 if(parser2.EvalError())
785                     std::cout << "error " << parser2.EvalError();
786                 else
787                     std::cout << std::setprecision(18) << v2;
788                 std::cout << "\n******* (Difference: " << (v2-v1)
789                           << ", scaled diff: "
790                           << std::setprecision(18) << scaledDiff(v1, v2)
791                           << ")" << std::endl;
792                 return false;
793             }
794         }
795         return true;
796     }
797 
798     bool had_double_optimization_problems = false;
799 
800     template<typename Value_t>
checkEquality(const std::vector<FunctionInfo<Value_t>> & functions)801     bool checkEquality(const std::vector<FunctionInfo<Value_t> >& functions)
802     {
803         static const char not_optimized[] = "not optimized";
804         static const char optimized[]     = "optimized";
805         static const char optimized2[]    = "double-optimized";
806         static const char* const optimize_labels[3] =
807             { not_optimized, optimized, optimized2 };
808 
809         ParserWithConsts<Value_t> parser1, parser2, parser3;
810 
811         bool errors = false;
812         for(std::size_t ind1 = 0; ind1 < functions.size(); ++ind1)
813         {
814             parser1.Parse
815                 (functions[ind1].mFunctionString, gVarString, gUseDegrees);
816             parser2.Parse
817                 (functions[ind1].mFunctionString, gVarString, gUseDegrees);
818             // parser 1 is not optimized
819 
820             // Printing the bytecode right _here_ is useful
821             // for debugging situations where fparser crashes
822             // before printByteCodes() is reached, such as
823             // within Optimize() or Eval().
824 
825             ////std::cout << "Not optimized:\n"; parser2.PrintByteCode(std::cout);
826             parser2.Optimize(); // parser 2 is optimized once
827 
828             ////std::cout << "Is optimized:\n"; parser2.PrintByteCode(std::cout);
829 
830             if(!compareFunctions(ind1, ind1, parser1, not_optimized,
831                                  parser2, optimized))
832                 errors = true;
833 
834             parser2.Optimize(); // parser 2 is optimized twice
835             ////std::cout << "Twice optimized:\n"; parser2.PrintByteCode(std::cout);
836 
837             if(!compareFunctions(ind1, ind1, parser1, not_optimized,
838                                  parser2, optimized2))
839                 errors = had_double_optimization_problems = true;
840 
841             parser1.Optimize(); // parser 1 is optimized once
842             if(!compareFunctions(ind1, ind1, parser1, optimized,
843                                  parser2, optimized2))
844                 errors = had_double_optimization_problems = true;
845 
846             for(std::size_t ind2 = ind1+1; ind2 < functions.size(); ++ind2)
847             {
848                 parser1.Parse(functions[ind1].mFunctionString, gVarString,
849                               gUseDegrees);
850                 for(int n_optimizes1 = 0; n_optimizes1 <= 2; ++n_optimizes1)
851                 {
852                     if(errors) break;
853                     if(n_optimizes1 > 0) parser1.Optimize();
854 
855                     parser2.Parse(functions[ind2].mFunctionString, gVarString,
856                                   gUseDegrees);
857 
858                     for(int n_optimizes2 = 0; n_optimizes2 <= 2; ++n_optimizes2)
859                     {
860                         if(n_optimizes2 > 0) parser2.Optimize();
861                         bool ok = compareFunctions(ind1, ind2,
862                             parser1, optimize_labels[n_optimizes1],
863                             parser2, optimize_labels[n_optimizes2]);
864                         if(!ok)
865                         {
866                             errors = true;
867                             if(n_optimizes1 > 1 || n_optimizes2 > 1)
868                                 had_double_optimization_problems = true;
869                             break;
870                         }
871                     }
872                 }
873             }
874         }
875         return !errors;
876     }
877 
wrapLine(std::string & line,std::size_t cutter,std::string & wrap_buf,bool always_cut=false)878     void wrapLine(std::string& line, std::size_t cutter, std::string& wrap_buf,
879                   bool always_cut = false)
880     {
881         if(line.size() <= cutter)
882             line.resize(cutter, ' ');
883         else
884         {
885             if(!always_cut)
886             {
887                 for(std::size_t wrap_at = cutter; wrap_at > 0; --wrap_at)
888                 {
889                     char c = line[wrap_at-1];
890                     if(c == '*' || c == '+' || c == '/' || c == '('
891                     || c == ')' || c == '^' || c == ',' || c == '&'
892                     || c == '|' || c == '-')
893                     {
894                         wrap_buf = std::string(20, ' ');
895                         wrap_buf += line.substr(wrap_at);
896                         line.erase(line.begin()+wrap_at, line.end());
897                         line.resize(cutter, ' ');
898                         return;
899                     }
900                 }
901             }
902 
903             line.resize(cutter, ' ');
904             line[cutter-1] = '~';
905         }
906     }
907 
908     enum PrintMode { print_wrap, print_cut, print_no_cut_or_wrap };
909 
910     template<typename Value_t>
printByteCodes(const std::vector<FunctionInfo<Value_t>> & functions,PrintMode mode=print_no_cut_or_wrap)911     void printByteCodes(const std::vector<FunctionInfo<Value_t> >& functions,
912                         PrintMode mode = print_no_cut_or_wrap)
913     {
914 #ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
915         ParserWithConsts<Value_t> parser;
916         const char* const wall =
917             (mode == print_no_cut_or_wrap)
918                 ? "\33[0m| "
919                 : "| ";
920         const char* const newline =
921             (mode == print_no_cut_or_wrap)
922                 ? "\33[0m\n"
923                 : "\n";
924         const char* colors[3] = { "\33[37m", "\33[36m", "\33[32m" };
925         if(mode != print_no_cut_or_wrap)
926             colors[0] = colors[1] = colors[2] = "";
927 
928         for(std::size_t i = 0; i < functions.size(); ++i)
929         {
930             std::cout << SEPARATOR << std::endl;
931 
932             std::stringstream streams[3];
933 
934             parser.Parse(functions[i].mFunctionString, gVarString, gUseDegrees);
935 
936             std::size_t one_column  = 38;
937             std::size_t two_columns = one_column * 2 + 2;
938 
939             streams[0] <<
940                 "Function " << i+1 << " original\n"
941                 "-------------------\n";
942             parser.PrintByteCode(streams[0], gPrintByteCodeExpressions);
943 
944             streams[1] <<
945                 "Optimized\n"
946                 "---------\n";
947             parser.Optimize();
948             {
949                 std::ostringstream streams2_bytecodeonly;
950                 parser.PrintByteCode(streams2_bytecodeonly,
951                                      gPrintByteCodeExpressions);
952                 streams[1] << streams2_bytecodeonly.str();
953 
954                 parser.Optimize();
955                 {
956                     std::ostringstream streams3_bytecodeonly;
957                     parser.PrintByteCode(streams3_bytecodeonly,
958                                          gPrintByteCodeExpressions);
959 
960                     if(had_double_optimization_problems ||
961                        streams2_bytecodeonly.str() !=
962                        streams3_bytecodeonly.str())
963                     {
964                         streams[2] <<
965                             "Double-optimized\n"
966                             "----------------\n";
967                         streams[2] << streams3_bytecodeonly.str();
968                         //one_column  = 24;
969                         //two_columns = one_column * 2 + 2;
970                     }
971                 }
972             }
973 
974             #if 0
975             std::cout << "Code 0\n" << streams[0].str() << std::endl;
976             std::cout << "Code 1\n" << streams[1].str() << std::endl;
977             std::cout << "Code 2\n" << streams[2].str() << std::endl;
978             #else
979             std::string streams_wrap_buf[3];
980             std::string lines[3];
981             while(true)
982             {
983                 bool all_empty = true;
984                 for(int p=0; p<3; ++p)
985                 {
986                     if(!streams_wrap_buf[p].empty())
987                     {
988                         lines[p].clear();
989                         lines[p].swap( streams_wrap_buf[p] );
990                     }
991                     else if(streams[p])
992                         std::getline(streams[p], lines[p]);
993                     else
994                         lines[p].clear();
995                     if(!lines[p].empty()) all_empty = false;
996                 }
997                 if(all_empty) break;
998 
999                 if(mode != print_no_cut_or_wrap)
1000                 {
1001                     if(!lines[1].empty())
1002                         wrapLine(lines[0], one_column, streams_wrap_buf[0],
1003                                  mode == print_cut);
1004                     else if(!lines[2].empty())
1005                         wrapLine(lines[0], two_columns, streams_wrap_buf[0],
1006                                  mode == print_cut);
1007                     if(!lines[2].empty() && !lines[1].empty())
1008                         wrapLine(lines[1], one_column, streams_wrap_buf[1],
1009                                  mode == print_cut);
1010                 }
1011                 else
1012                 {
1013                     bool wrap0 = false;
1014                     if(!lines[1].empty())
1015                     {
1016                         if(lines[0].size() >= one_column) wrap0 = true;
1017                         else lines[0].resize(one_column, ' ');
1018                     }
1019                     else if(!lines[2].empty())
1020                     {
1021                         if(lines[0].size() >= two_columns) wrap0 = true;
1022                         else lines[0].resize(two_columns, ' ');
1023                     }
1024 
1025                     if(wrap0)
1026                     {
1027                         lines[1].swap(streams_wrap_buf[1]);
1028                         if(!lines[2].empty() && lines[0].size() >= two_columns)
1029                             lines[2].swap(streams_wrap_buf[2]);
1030                         else if(lines[0].size() < two_columns)
1031                             lines[0].resize(two_columns, ' ');
1032                     }
1033 
1034                     bool wrap1 = false;
1035                     if(!lines[2].empty() && !lines[1].empty())
1036                     {
1037                         if(lines[1].size() >= one_column) wrap1 = true;
1038                         else lines[1].resize(one_column, ' ');
1039                     }
1040 
1041                     if(wrap1 && !lines[2].empty())
1042                     {
1043                         lines[2].swap(streams_wrap_buf[2]);
1044                     }
1045                 }
1046 
1047                 std::cout << colors[0] << lines[0];
1048                 if(!lines[1].empty())
1049                     std::cout << wall << colors[1] << lines[1];
1050                 if(!lines[2].empty())
1051                     std::cout << wall << colors[2] << lines[2];
1052                 std::cout << newline;
1053             }
1054             #endif
1055         }
1056 #endif
1057     }
1058 
1059     template<typename Value_t>
printFunctionTimings(std::vector<FunctionInfo<Value_t>> & functions)1060     void printFunctionTimings(std::vector<FunctionInfo<Value_t> >& functions)
1061     {
1062         std::printf
1063         ("    ,------------------------------------------------------------------------,\n"
1064          "    |      Parse |      Eval |  Eval (O) | Eval (O2) |  Optimize |  Repeat O.|\n"
1065          ",---+------------+-----------+-----------+-----------+-----------+-----------+\n");
1066         for(std::size_t i = 0; i < functions.size(); ++i)
1067         {
1068             getTimingInfo(functions[i]);
1069             std::printf
1070                 ("|%2u | %10.3f |%10.3f |%10.3f |%10.3f |%10.1f |%10.1f |\n",
1071                  unsigned(i+1),
1072                  functions[i].mParseTiming.mMicroSeconds,
1073                  functions[i].mEvalTiming.mMicroSeconds,
1074                  functions[i].mOptimizedEvalTiming.mMicroSeconds,
1075                  functions[i].mDoubleOptimizedEvalTiming.mMicroSeconds,
1076                  functions[i].mOptimizeTiming.mMicroSeconds,
1077                  functions[i].mDoubleOptimizeTiming.mMicroSeconds
1078                  );
1079         }
1080         std::printf
1081         ("'----------------------------------------------------------------------------'\n");
1082     }
1083 
1084     template<typename Value_t>
checkFunctionValidity(FunctionInfo<Value_t> & info)1085     bool checkFunctionValidity(FunctionInfo<Value_t>& info)
1086     {
1087         int result = info.mParser.Parse(info.mFunctionString, gVarString,
1088                                         gUseDegrees);
1089         if(result >= 0)
1090         {
1091             std::cerr << "\"" << info.mFunctionString << "\"\n"
1092                       << std::string(result+1, ' ')
1093                       << "^ " << info.mParser.ErrorMsg() << std::endl;
1094             if(info.mParser.GetParseErrorType() ==
1095                FunctionParserBase<Value_t>::INVALID_VARS)
1096                 std::cerr << "Vars: \"" << gVarString << "\"" << std::endl;
1097             return false;
1098         }
1099         return true;
1100     }
1101 
1102     template<typename Value_t>
deduceVariables(const std::vector<FunctionInfo<Value_t>> & functions)1103     void deduceVariables(const std::vector<FunctionInfo<Value_t> >& functions)
1104     {
1105         typedef std::set<std::string> StrSet;
1106         StrSet varNames;
1107         ParserWithConsts<Value_t> parser;
1108 
1109         for(std::size_t funcInd = 0; funcInd < functions.size(); ++funcInd)
1110         {
1111             const std::string funcStr = functions[funcInd].mFunctionString;
1112             int oldIndex = -1;
1113 
1114             while(true)
1115             {
1116                 gVarString.clear();
1117                 for(StrSet::iterator iter = varNames.begin();
1118                     iter != varNames.end();
1119                     ++iter)
1120                 {
1121                     if(iter != varNames.begin()) gVarString += ",";
1122                     gVarString += *iter;
1123                 }
1124 
1125                 int index = parser.Parse(funcStr, gVarString, gUseDegrees);
1126                 if(index < 0) break;
1127                 if(index == oldIndex) return;
1128 
1129                 int index2 = index;
1130                 if(index2 < int(funcStr.length()) &&
1131                    (std::isalpha(funcStr[index2]) || funcStr[index2] == '_'))
1132                 {
1133                     while(index2 < int(funcStr.length()) &&
1134                           (std::isalnum(funcStr[index2]) ||
1135                            funcStr[index2] == '_'))
1136                         ++index2;
1137                 }
1138 
1139                 if(index2 == index)
1140                     return;
1141 
1142                 varNames.insert(funcStr.substr(index, index2-index));
1143                 oldIndex = index;
1144             }
1145         }
1146     }
1147 
printHelp(const char * programName)1148     int printHelp(const char* programName)
1149     {
1150         std::cerr <<
1151             "FunctionParser functioninfo utility " << kVersionNumber <<
1152             "\n\nUsage: " << programName <<
1153             " [<options] <function1> [<function2> ...]\n\n"
1154             "Options:\n"
1155             "  -f                  : Use FunctionParser_f.\n"
1156             "  -ld                 : Use FunctionParser_ld.\n"
1157             "  -mpfr               : Use FunctionParser_mpfr.\n"
1158             "  -mpfr_bits <bits>   : MpfrFloat mantissa bits (default 80).\n"
1159             "  -li                 : Use FunctionParser_li.\n"
1160             "  -gi                 : Use FunctionParser_gmpint.\n"
1161             "  -cd                 : Use FunctionParser_cd.\n"
1162             "  -cf                 : Use FunctionParser_cf.\n"
1163             "  -cld                : Use FunctionParser_cld.\n"
1164             "  -vars <string>      : Specify a var string.\n"
1165             "  -nt                 : No timing measurements.\n"
1166             "  -ntd                : No timing if functions differ.\n"
1167             "  -deg                : Use degrees for trigonometry.\n"
1168             "  -noexpr             : Don't print byte code expressions.\n"
1169             "  -varValues <values> : Space-separated variable values to use.\n";
1170         return 1;
1171     }
1172 }
1173 
1174 template<typename Value_t>
functionInfo(const char * const parserTypeString,const std::vector<std::string> & functionStrings,bool measureTimings,bool noTimingIfEqualityErrors,const std::string & userGivenVarValues)1175 int functionInfo(const char* const parserTypeString,
1176                  const std::vector<std::string>& functionStrings,
1177                  bool measureTimings, bool noTimingIfEqualityErrors,
1178                  const std::string& userGivenVarValues)
1179 {
1180     std::vector<FunctionInfo<Value_t> > functions(functionStrings.size());
1181     for(std::size_t i = 0; i < functions.size(); ++i)
1182         functions[i].mFunctionString = functionStrings[i];
1183 
1184     if(gVarString.empty())
1185         deduceVariables(functions);
1186 
1187     for(std::size_t i = 0; i < functions.size(); ++i)
1188     {
1189         if(!checkFunctionValidity(functions[i]))
1190             return 1;
1191     }
1192 
1193     const bool validVarValuesFound =
1194         findValidVarValues(functions, userGivenVarValues);
1195 
1196     std::cout << SEPARATOR << std::endl
1197               << "Parser type: " << parserTypeString << std::endl;
1198     for(std::size_t i = 0; i < functions.size(); ++i)
1199         std::cout << "- Function " << i+1 << ": \""
1200                   << functions[i].mFunctionString << "\"\n";
1201     const std::size_t varsAmount = ParserData<Value_t>::gVarValues[0].size();
1202     const std::size_t varValueSetsAmount = ParserData<Value_t>::gVarValues.size();
1203     std::cout << "- Var string: \"" << gVarString << "\" ("
1204               << ParserData<Value_t>::gVarValues[0].size()
1205               << (varsAmount == 1 ? " var" : " vars")
1206               << ") (using " << varValueSetsAmount << " set"
1207               << (varValueSetsAmount == 1 ? ")\n" : "s)\n");
1208 
1209 #if 0
1210     std::cout << SEPARATOR << "\nTesting with variable values:\n";
1211     for(std::size_t i = 0; i < ParserData<Value_t>::gVarValues.size(); ++i)
1212     {
1213         if(i > 0) std::cout << (i%5==0 ? "\n" : " ");
1214         std::cout << "(";
1215         for(std::size_t j = 0; j < ParserData<Value_t>::gVarValues[i].size(); ++j)
1216         {
1217             if(j > 0) std::cout << ",";
1218             using namespace FUNCTIONPARSERTYPES;
1219             std::cout << ParserData<Value_t>::gVarValues[i][j];
1220         }
1221         std::cout << ")";
1222     }
1223     if(!validVarValuesFound)
1224         std::cout << " [no valid variable values were found...]";
1225     std::cout << "\n" << SEPARATOR << std::endl;
1226 #else
1227     if(!validVarValuesFound)
1228         std::cout << SEPARATOR
1229                   << "\nWarning: No valid variable values were found."
1230                   << " Using (0,0)." << std::endl;
1231 #endif
1232 
1233     const bool equalityErrors = checkEquality(functions) == false;
1234 
1235     printByteCodes(functions);
1236 
1237     if(noTimingIfEqualityErrors && equalityErrors)
1238         measureTimings = false;
1239 
1240     if(measureTimings)
1241     {
1242         gTimingTotalCount = functions.size() * 4;
1243         printFunctionTimings(functions);
1244     }
1245 
1246     return 0;
1247 }
1248 
main(int argc,char * argv[])1249 int main(int argc, char* argv[])
1250 {
1251     if(argc < 2) return printHelp(argv[0]);
1252 
1253     enum ParserType { FP_D, FP_F, FP_LD, FP_MPFR, FP_LI, FP_GI, FP_CD, FP_CF, FP_CLD };
1254 
1255     std::vector<std::string> functionStrings;
1256     bool measureTimings = true, noTimingIfEqualityErrors = false;
1257     ParserType parserType = FP_D;
1258     unsigned long mantissaBits = 80;
1259     std::string userGivenVarValues;
1260 
1261     for(int i = 1; i < argc; ++i)
1262     {
1263         if(std::strcmp(argv[i], "-f") == 0) parserType = FP_F;
1264         else if(std::strcmp(argv[i], "-ld") == 0) parserType = FP_LD;
1265         else if(std::strcmp(argv[i], "-mpfr") == 0) parserType = FP_MPFR;
1266         else if(std::strcmp(argv[i], "-li") == 0) parserType = FP_LI;
1267         else if(std::strcmp(argv[i], "-gi") == 0) parserType = FP_GI;
1268         else if(std::strcmp(argv[i], "-cd") == 0) parserType = FP_CD;
1269         else if(std::strcmp(argv[i], "-cf") == 0) parserType = FP_CF;
1270         else if(std::strcmp(argv[i], "-cld") == 0) parserType = FP_CLD;
1271         else if(std::strcmp(argv[i], "-vars") == 0)
1272         {
1273             if(++i == argc) return printHelp(argv[0]);
1274             gVarString = argv[i];
1275         }
1276         else if(std::strcmp(argv[i], "-nt") == 0)
1277             measureTimings = false;
1278         else if(std::strcmp(argv[i], "-ntd") == 0)
1279             noTimingIfEqualityErrors = true;
1280         else if(std::strcmp(argv[i], "-deg") == 0)
1281             gUseDegrees = true;
1282         else if(std::strcmp(argv[i], "-mpfr_bits") == 0)
1283         {
1284             if(++i == argc) return printHelp(argv[0]);
1285             mantissaBits = std::atol(argv[i]);
1286         }
1287         else if(std::strcmp(argv[i], "-noexpr") == 0)
1288             gPrintByteCodeExpressions = false;
1289         else if(std::strcmp(argv[i], "-varValues") == 0)
1290         {
1291             if(++i == argc) return printHelp(argv[0]);
1292             userGivenVarValues = argv[i];
1293         }
1294         else if(std::strcmp(argv[i], "--help") == 0
1295              || std::strcmp(argv[i], "-help") == 0
1296              || std::strcmp(argv[i], "-h") == 0
1297              || std::strcmp(argv[i], "/?") == 0)
1298             printHelp(argv[0]);
1299         else
1300             functionStrings.push_back(argv[i]);
1301     }
1302 
1303     if(functionStrings.empty()) return printHelp(argv[0]);
1304 
1305     const char* notCompiledParserType = 0;
1306 
1307     switch(parserType)
1308     {
1309       case FP_D:
1310 #ifndef FP_DISABLE_DOUBLE_TYPE
1311           return functionInfo<double>
1312               ("double", functionStrings,
1313                measureTimings, noTimingIfEqualityErrors,
1314                userGivenVarValues);
1315 #else
1316           notCompiledParserType = "double";
1317           break;
1318 #endif
1319 
1320       case FP_F:
1321 #ifdef FP_SUPPORT_FLOAT_TYPE
1322           return functionInfo<float>
1323               ("float", functionStrings,
1324                measureTimings, noTimingIfEqualityErrors,
1325                userGivenVarValues);
1326 #else
1327           notCompiledParserType = "float";
1328           break;
1329 #endif
1330 
1331       case FP_LD:
1332 #ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
1333           return functionInfo<long double>
1334               ("long double", functionStrings,
1335                measureTimings, noTimingIfEqualityErrors,
1336                userGivenVarValues);
1337 #else
1338           notCompiledParserType = "long double";
1339           break;
1340 #endif
1341 
1342       case FP_MPFR:
1343 #ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
1344           {
1345               MpfrFloat::setDefaultMantissaBits(mantissaBits);
1346               std::ostringstream typeName;
1347               typeName << "MpfrFloat(" << mantissaBits << ")";
1348               return functionInfo<MpfrFloat>
1349                   (typeName.str().c_str(), functionStrings,
1350                    measureTimings, noTimingIfEqualityErrors,
1351                    userGivenVarValues);
1352           }
1353 #else
1354           notCompiledParserType = "MpfrFloat";
1355           break;
1356 #endif
1357 
1358       case FP_LI:
1359 #ifdef FP_SUPPORT_LONG_INT_TYPE
1360           return functionInfo<long int>
1361               ("long int", functionStrings,
1362                measureTimings, noTimingIfEqualityErrors,
1363                userGivenVarValues);
1364 #else
1365           notCompiledParserType = "long int";
1366           break;
1367 #endif
1368 
1369       case FP_GI:
1370 #ifdef FP_SUPPORT_GMP_INT_TYPE
1371           return functionInfo<GmpInt>
1372               ("GmpInt", functionStrings,
1373                measureTimings, noTimingIfEqualityErrors,
1374                userGivenVarValues);
1375 #else
1376           notCompiledParserType = "GmpInt";
1377           break;
1378 #endif
1379 
1380       case FP_CD:
1381 #ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
1382           return functionInfo<std::complex<double> >
1383               ("std::complex<double>", functionStrings,
1384                measureTimings, noTimingIfEqualityErrors,
1385                userGivenVarValues);
1386 #else
1387           notCompiledParserType = "std::complex<double>";
1388           break;
1389 #endif
1390 
1391       case FP_CF:
1392 #ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
1393           return functionInfo<std::complex<float> >
1394               ("std::complex<float>", functionStrings,
1395                measureTimings, noTimingIfEqualityErrors,
1396                userGivenVarValues);
1397 #else
1398           notCompiledParserType = "std::complex<float>";
1399           break;
1400 #endif
1401 
1402       case FP_CLD:
1403 #ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
1404           return functionInfo<std::complex<long double> >
1405               ("std::complex<long double>", functionStrings,
1406                measureTimings, noTimingIfEqualityErrors,
1407                userGivenVarValues);
1408 #else
1409           notCompiledParserType = "std::complex<long double>";
1410           break;
1411 #endif
1412     }
1413 
1414     if(notCompiledParserType)
1415     {
1416         std::cout << "Error: Support for type " << notCompiledParserType
1417                   << " was not compiled in." << std::endl;
1418         return 1;
1419     }
1420     return 0;
1421 }
1422