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