]> Shamusworld >> Repos - architektonas/commitdiff
Adding fparser v4.3...
authorShamus Hammons <jlhamm@acm.org>
Fri, 10 Sep 2010 21:50:44 +0000 (21:50 +0000)
committerShamus Hammons <jlhamm@acm.org>
Fri, 10 Sep 2010 21:50:44 +0000 (21:50 +0000)
21 files changed:
architektonas.pro
fparser/docs/fparser.html [new file with mode: 0644]
fparser/docs/gpl.txt [new file with mode: 0644]
fparser/docs/lgpl.txt [new file with mode: 0644]
fparser/docs/style.css [new file with mode: 0644]
fparser/examples/example.cc [new file with mode: 0644]
fparser/examples/example2.cc [new file with mode: 0644]
fparser/fp_identifier_parser.inc [new file with mode: 0644]
fparser/fp_opcode_add.inc [new file with mode: 0644]
fparser/fparser.cc [new file with mode: 0644]
fparser/fparser.hh [new file with mode: 0644]
fparser/fparser_gmpint.hh [new file with mode: 0644]
fparser/fparser_mpfr.hh [new file with mode: 0644]
fparser/fpaux.hh [new file with mode: 0644]
fparser/fpconfig.hh [new file with mode: 0644]
fparser/fpoptimizer.cc [new file with mode: 0644]
fparser/fptypes.hh [new file with mode: 0644]
fparser/mpfr/GmpInt.cc [new file with mode: 0644]
fparser/mpfr/GmpInt.hh [new file with mode: 0644]
fparser/mpfr/MpfrFloat.cc [new file with mode: 0644]
fparser/mpfr/MpfrFloat.hh [new file with mode: 0644]

index 39e1022ddfac0f0b55875696c9625266fc06ec83..a28d4a581d0175204b7136ecffbd312b922bb15e 100644 (file)
@@ -19,7 +19,7 @@ RCC_DIR     = obj
 UI_DIR      = obj
 
 INCLUDEPATH += \
-       fparser-4.3 \
+       fparser \
        dxflib/include \
        src/mainapp \
        src/actions \
@@ -28,7 +28,7 @@ INCLUDEPATH += \
        src/forms
 
 HEADERS = \
-       fparser-4.3/fparser.hh
+       fparser/fparser.hh
 
 HEADERS += \
        src/base/actioninterface.h \
@@ -109,8 +109,8 @@ HEADERS += \
        src/base/vectorsolutions.h
 
 SOURCES = \
-       fparser-4.3/fparser.cc \
-       fparser-4.3/fpoptimizer.cc
+       fparser/fparser.cc \
+       fparser/fpoptimizer.cc
 
 SOURCES += \
        src/base/actioninterface.cpp \
diff --git a/fparser/docs/fparser.html b/fparser/docs/fparser.html
new file mode 100644 (file)
index 0000000..1b10066
--- /dev/null
@@ -0,0 +1,1629 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <link href="style.css" rel="stylesheet" type="text/css" title="normal" media=screen>
+ <title>Function Parser for C++ v4.3    : Documentation</title>
+</head>
+
+<body>
+<h1>Function Parser for C++ v4.3    </h1>
+
+<p>Authors: Juha Nieminen
+(<a href="http://iki.fi/warp/">http://iki.fi/warp/</a>),
+Joel Yliluoma
+(<a href="http://iki.fi/bisqwit/">http://iki.fi/bisqwit/</a>).
+
+<p>The usage license of this library is located at the end of this file.
+
+<h2>Table of contents:</h2>
+
+<ul>
+ <li><a href="#whatsnew">What's new</a>
+ <li><a href="#preface">Preface</a>
+ <li><a href="#usage">Usage</a>
+     <ul>
+      <li><a href="#parsertypes">Parser types</a>
+      <li><a href="#configuring">Configuring the compilation</a>
+      <li><a href="#copyassignment">Copying and assignment</a>
+      <li><a href="#shortdesc">Short descriptions of FunctionParser methods</a>
+      <li><a href="#longdesc">Long descriptions of FunctionParser methods</a>
+       <ul>
+         <li><a href="#longdesc_Parse"><code>Parse()</code></a>
+         <li><a href="#longdesc_setDelimiterChar"><code>setDelimiterChar()</code></a>
+         <li><a href="#longdesc_ErrorMsg"><code>ErrorMsg()</code></a>
+         <li><a href="#longdesc_GetParseErrorType"><code>GetParseErrorType()</code></a>
+         <li><a href="#longdesc_Eval"><code>Eval()</code></a>
+         <li><a href="#longdesc_EvalError"><code>EvalError()</code></a>
+         <li><a href="#longdesc_Optimize"><code>Optimize()</code></a>
+         <li><a href="#longdesc_AddConstant"><code>AddConstant()</code></a>
+         <li><a href="#longdesc_AddUnit"><code>AddUnit()</code></a>
+         <li><a href="#longdesc_AddFunction1"><code>AddFunction()</code></a> (C++ function)
+         <li><a href="#longdesc_AddFunction2"><code>AddFunction()</code></a> (FunctionParser)
+         <li><a href="#longdesc_RemoveIdentifier"><code>RemoveIdentifier()</code></a>
+         <li><a href="#longdesc_ParseAndDeduceVariables"><code>ParseAndDeduceVariables()</code></a>
+        </ul>
+     </ul>
+ <li>Syntax
+   <ul>
+     <li><a href="#literals">Numeric literals</a>
+     <li><a href="#identifiers">Identifier names</a>
+     <li><a href="#functionsyntax">The function string syntax</a>
+     <li><a href="#inlinevars">Inline variables</a>
+     <li><a href="#whitespace">Whitespace</a>
+   </ul>
+ <li>Miscellaneous
+   <ul>
+     <li><a href="#evaluationchecks">About evaluation-time checks</a>
+     <li><a href="#threadsafety">About thread safety</a>
+     <li><a href="#tipsandtricks">Tips and tricks</a>
+     <li><a href="#contact">Contacting the author</a>
+   </ul>
+<!-- <li><a href="#algorithm">The algorithm used in the library</a> -->
+ <li><a href="#license">Usage license</a>
+</ul>
+
+<a name="whatsnew"></a>
+<h2>What's new</h2>
+
+<p>What's new in v4.3
+  <ul>
+    <li>Function syntax enhancement: Added possibility of defining new
+      variables in the function string itself. (See documentation for details.)
+    <li>Fixed some bugs in the optimizer (among others,
+      <code>"atan2(-x,-y)"</code> was being wrongly optimized into
+      <code>"atan2(x,y)"</code>
+  </ul>
+
+<p>What's new in v4.2
+  <ul>
+    <li>The <code>Optimize()</code> method now works also with the
+      <code>float</code> and <code>long double</code> versions of the library.
+    </li>
+    <li>Some new optimizations added.</li>
+    <li>There was a call to the C99/C++0x function <code>isinf()</code> in the
+      optimizer which made it not compile with some compilers. This call has
+      been removed.</li>
+  </ul>
+
+<p>What's new in v4.1
+  <ul>
+    <li>Official support for hexadecimal literals (for all the parser types).
+      Previously there was support only if the <code>strto...()</code> C
+      library functions happened to support them (which is a non-standard
+      extension of those functions). See documentation for details.</li>
+    <li>Significant amount of new optimizations performed by
+      <code>Parse()</code>.</li>
+    <li>Minor bugfixes.</li>
+  </ul>
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="preface"></a>
+<h2>Preface</h2>
+
+<p>This C++ library offers a class which can be used to parse and evaluate a
+mathematical function from a string (which might be eg. requested from the
+user). The syntax of the function string is similar to mathematical expressions
+written in C/C++ (the exact syntax is specified later in this document).
+The function can then be evaluated with different values of variables.
+
+<p>For example, a function like "<code>sin(sqrt(x*x+y*y))</code>" can be
+parsed from a string (either <code>std::string</code> or a C-style string)
+and then evaluated with different values of <code>x</code> and <code>y</code>.
+This library can be useful for evaluating user-inputted functions, or in
+some cases interpreting mathematical expressions in a scripting language.
+
+<p>This library aims for maximum speed in both parsing and evaluation, while
+keeping maximum portability. The library should compile and work with any
+standard-conforming C++ compiler.
+
+<p>Different numerical types are supported: <code>double</code>,
+  <code>float</code>, <code>long double</code>, <code>long int</code>,
+  multiple-precision floating point numbers using the MPFR library, and
+  arbitrary precision integers using the GMP library. (Note that it's
+  not necessary for these two libraries to exist in the system in order
+  to use the Function Parser library with the other numerical types. Support
+  for these libraries is optionally compiled in using preprocessor settings.)
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="usage"></a>
+<h2>Usage</h2>
+
+<p>To use the <code>FunctionParser</code> class, you have to include
+<code>"fparser.hh"</code> in your source code files which use the
+<code>FunctionParser</code> class.
+
+<p>If you are going to use the MPFR version of the library, you need to
+include <code>"fparser_mpfr.hh"</code>. If you are going to use the GMP
+version of the library, you need to include <code>"fparser_gmpint.hh"</code>.
+(Note that support for these special parser versions needs to be specified
+with preprocessor macros. See the <a href="#parsertypes">documentation
+below</a> for details.)
+
+<p>When compiling, you have to compile <code>fparser.cc</code> and
+<code>fpoptimizer.cc</code> and link them to the main program. In many
+developement environments it's enough to add those two files to your
+current project (usually header files don't have to be added to the
+project for the compilation to work).
+
+<p>If you are going to use the MPFR or the GMP versions of the library,
+you also need to add <code>mpfr/MpfrFloat.cc</code> or
+<code>mpfr/GmpInt.cc</code> files to your project, respectively. Otherwise
+they should not be added to the project.
+
+<p>Note that part of the library source code is inside several
+<code>.inc</code> files (these files contain auto-generated C++ code),
+provided in the library package. These files are used by
+<code>fparser.cc</code> and don't need to be added explicitly to the
+project in most IDEs (such as Visual Studio). Basically, you don't need
+to do anything with these files, other than keep them in the same directory
+as <code>fparser.cc</code>.
+
+<p>Simple usage example of the library:
+
+<pre>
+    FunctionParser fp;
+    fp.Parse("sqrt(x*x + y*y)", "x,y");
+    double variables[2] = { 1.5, 2.9 };
+    double result = fp.Eval(variables);
+</pre>
+
+<!-- -------------------------------------------------------------------- -->
+<a name="parsertypes"></a>
+<h3>Parser types</h3>
+
+<p>Different versions of the function parser class are supported, using
+  different floating point or integral types for function evaluation.
+
+<p>All the classes other than the default one, <code>FunctionParser</code>,
+  need to be enabled at compile time by defining a preprocessor macro
+  (specified below) either in the <code>fpconfig.hh</code> file or your
+  compiler settings. (The reason for this is that all the other parser types
+  use either C99 standard libraries not yet available in the official C++
+  standard or the third-party libraries GMP and MPFR. It also makes
+  compilation faster and the resulting binary smaller when unused classes
+  are not compiled in.).
+
+<p>Note that if you try to use the other class types without enabling them
+  with the correspondent preprocessor macro, you will get a linker error
+  (rather than a compiler error) because those classes will not have been
+  instantiated when the library was compiled.
+
+<p>Currently the <code>Optimize()</code> method works only for the
+  <code>FunctionParser</code>, <code>FunctionParser_f</code> and
+  <code>FunctionParser_ld</code> classes. For the other types it can be
+  called but it does nothing.
+
+<p>
+<dl>
+  <dt><p><code>FunctionParser</code></dt>
+  <dd>
+    <p>This is the default class, which uses <code>double</code> as its
+      numerical type. This is the only class enabled by default.
+    <p>If you use some other type than this one, and you don't want this
+      version of the class compiled into the library, you can define the
+      preprocessor macro <code>FP_DISABLE_DOUBLE_TYPE</code>.
+  </dd>
+
+  <dt><p><code>FunctionParser_f</code></dt>
+  <dd>
+    <p>This parser uses <code>float</code> as its numerical type.
+    <p>The <code>FP_SUPPORT_FLOAT_TYPE</code> preprocessor macro needs to be
+      defined for this class to be enabled.
+    <p>Note that this version of the class uses C99 standard math functions
+      not yet available in all C++ compilers. Also the <code>ld</code> version
+      of the class described below use such functions.
+  </dd>
+
+  <dt><p><code>FunctionParser_ld</code></dt>
+  <dd>
+    <p>This parser uses <code>long&nbsp;double</code> as its numerical type.
+    <p>The <code>FP_SUPPORT_LONG_DOUBLE_TYPE</code> preprocessor macro needs
+      to be defined for this class to be enabled.
+  </dd>
+
+  <dt><p><code>FunctionParser_li</code></dt>
+  <dd>
+    <p>This parser uses <code>long&nbsp;int</code> as its numerical type.
+    <p>The <code>FP_SUPPORT_LONG_INT_TYPE</code> preprocessor macro needs
+      to be defined for this class to be enabled.
+    <p>Note that this version of the class uses a reduced function syntax
+      with support only for functions which are feasible to be used with
+      integral types (namely <code>abs()</code>, <code>eval()</code>,
+      <code>if()</code>, <code>min()</code> and <code>max()</code>, besides
+      basic arithmetic operators, except for the power operator).
+  </dd>
+
+  <dt><p><code>FunctionParser_mpfr</code></dt>
+  <dd>
+    <p>This parser uses <code>MpfrFloat</code> as its numerical type.
+    <p>The <code>FP_SUPPORT_MPFR_FLOAT_TYPE</code> preprocessor macro needs
+      to be defined for this class to be enabled.
+    <p>Note that to use this version of the parser,
+      <code>"fparser_mpfr.hh"</code> needs to be included.
+    <p><code>MpfrFloat</code> is an auxiliary class which uses the MPFR
+      library for multiple-precision floating point numbers. The class
+      behaves largely like a floating point type, and is declared in the
+      <code>mpfr/MpfrFloat.hh</code> file (see that file for info about
+      the public interface of the class).
+    <p>If this class is enabled, <code>mpfr/MpfrFloat.cc</code>
+      needs to be compiled into the project, as well as the GMP and MPFR
+      libraries. (With the gcc compiler this means using the linker options
+      "<code>-lgmp -lmpfr</code>".)
+  </dd>
+
+  <dt><p><code>FunctionParser_gmpint</code></dt>
+  <dd>
+    <p>This parser uses <code>GmpInt</code> as its numerical type.
+    <p>The <code>FP_SUPPORT_GMP_INT_TYPE</code> preprocessor macro needs
+      to be defined for this class to be enabled.
+    <p>Note that to use this version of the parser,
+      <code>"fparser_gmpint.hh"</code> needs to be included.
+    <p><code>GmpInt</code> is an auxiliary class which uses the GMP
+      library for arbitrary-precision integer numbers. The class
+      behaves largely like an integer type, and is declared in the
+      <code>mpfr/GmpInt.hh</code> file (see that file for info about
+      the public interface of the class).
+    <p>If this class is enabled, <code>mpfr/GmpInt.cc</code>
+      needs to be compiled into the project, as well as the GMP library.
+    <p>This version of the class also uses a reduced version of the syntax,
+      like the <code>long int</code> version.
+    <p><b>Note:</b> Since there's no upper limit to the size of GMP
+      integers, this version of the class should be used with care in
+      situations where malicious users might be able to exploit it to
+      make the program run out of memory. An example of this would be
+      a server-side application usable through the WWW.
+  </dd>
+</dl>
+
+<p>Note that these different classes are completely independent and
+  instances of different classes cannot be given to each other using the
+  <code>AddFunction()</code> method. Only objects of the same type can
+  be given to that method.
+
+<p>The rest of the documentation assumes that <code>FunctionParser</code>
+  (which uses the <code>double</code> type) is used. The usage of the other
+  classes is identical except that <code>double</code> is replaced with the
+  correspondent type used by that class. (In other words, whenever the
+  rest of this documentation uses the type keyword '<code>double</code>',
+  the correspondent type should be used instead, when using another version
+  of the class.)
+
+<!-- -------------------------------------------------------------------- -->
+<a name="configuring"></a>
+<h3>Configuring the compilation</h3>
+
+<p>There is a set of precompiler options in the <code>fpconfig.hh</code> file
+which can be used for setting certain features on or off. All of these options
+can also be specified from the outside, using precompiler settings (eg. the
+<code>-D</code> option in gcc), and thus it's not necessary to modify this
+file.
+
+<dl>
+  <dt><p><code>FP_SUPPORT_TR1_MATH_FUNCS</code> : (Default off)</dt>
+  <dd><p>Define this precompiler constant to make the library use additional
+      math functions defined in the C99 standard and the C++ TR1 standard
+      proposal (but not yet in the official C++ standard). This can make
+      evaluation faster when these functions are involved.
+    <p>The C++ TR1 math functions in question are: <code>asinh()</code>,
+      <code>acosh()</code>, <code>atanh()</code>, <code>exp2()</code> and
+      <code>log2()</code>.
+  </dd>
+
+  <dt><p><code>FP_ENABLE_EVAL</code> : (Default off)</dt>
+  <dd><p>Even though the maximum recursion level of the <code>eval()</code>
+      function is limited, it is still possible to write functions which never
+      reach this maximum recursion level but take enormous amounts of
+      time to evaluate (this can be undesirable eg. in web server-side
+      applications). For this reason this function is disabled by default.
+      You can add support for the <code>eval()</code> function by
+      defining this precompiler constant.
+  </dd>
+
+  <dt><p><code>FP_EVAL_MAX_REC_LEVEL</code> : (Default 1000)</dt>
+  <dd><p>Sets the maximum recursion level allowed for <code>eval()</code>.
+  </dd>
+
+  <dt><p><code>FP_SUPPORT_OPTIMIZER</code> : (Default on)</dt>
+  <dd><p>If you are not going to use the <code>Optimize()</code> method, you
+      can comment this line out to speed-up the compilation a bit, as
+      well as making the binary a bit smaller. (<code>Optimize()</code> can
+      still be called, but it will not do anything.)
+
+    <p>You can also disable the optimizer by specifying the
+      <code>FP_NO_SUPPORT_OPTIMIZER</code> precompiler constant in your
+      compiler settings.
+  </dd>
+
+  <dt><p><code>FP_EPSILON</code> : (Default <code>1e-14</code>)</dt>
+  <dd><p>Epsilon value used in comparison operators.
+      If this line is commented out, then no epsilon will be used.
+  </dd>
+
+  <dt><p><code>FP_USE_THREAD_SAFE_EVAL</code> : (Default off)</dt>
+  <dd><p>Define this precompiler constant to make <code>Eval()</code>
+      thread-safe. Refer to the <a href="#threadsafety">thread safety
+       section</a> later in this document for more information.
+      Note that defining this may make <code>Eval()</code> slightly slower.
+    <p>Also note that the MPFR and GMP versions of the library cannot be
+      made thread-safe, and thus this setting has no effect on them.
+  </dd>
+
+  <dt><p><code>FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA</code> : (Default off)</dt>
+  <dd><p>This is like the previous, but makes <code>Eval()</code> use the
+      <code>alloca()</code> function (instead of <code>std::vector</code>).
+      This will make it faster, but the <code>alloca()</code>
+      function is not standard and thus not supported by all compilers.
+  </dd>
+
+  <dt><p><code>FP_NO_EVALUATION_CHECKS</code> : (Default off)</dt>
+  <dd><p>If this precompiler constant is defined, no evaluation-time checks
+      will be performed. This may give a slight boost in speed in certain
+      situations. Consult the <a href="#evaluationchecks">evaluation
+        checks section</a> below for more information on this subject.
+  </dd>
+</dl>
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="copyassignment"></a>
+<h3>Copying and assignment</h3>
+
+<p>The class implements a safe copy constructor and assignment operator.
+
+<p>It uses the copy-on-write technique for efficiency. This means that
+  when copying or assigning a FunctionParser instance, the internal data
+  (which in some cases can be quite lengthy) is not immediately copied
+  but only when the contents of the copy (or the original) are changed.
+
+<p>This means that copying/assigning is a very fast operation, and if
+  the copies are never modified then actual data copying never happens
+  either.
+
+<p>The <code>Eval()</code> and <code>EvalError()</code> methods of the
+copy can be called without the internal data being copied.
+
+<p>Calling <code>Parse()</code>, <code>Optimize()</code> or the user-defined
+constant/function adding methods will cause a deep-copy.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="shortdesc"></a>
+<h3>Short descriptions of FunctionParser methods</h3>
+
+<pre>
+int Parse(const std::string&amp; Function, const std::string&amp; Vars,
+          bool useDegrees = false);
+
+int Parse(const char* Function, const std::string&amp; Vars,
+          bool useDegrees = false);
+</pre>
+
+<p>Parses the given function and compiles it to internal format.
+    Return value is -1 if successful, else the index value to the location
+    of the error.
+
+<hr>
+<pre>
+void setDelimiterChar(char);
+</pre>
+
+<p>Sets an ending delimiter character for the function string. (See the
+    long description for more details.)
+
+<hr>
+<pre>
+const char* ErrorMsg(void) const;
+</pre>
+
+<p>Returns an error message corresponding to the error in
+<code>Parse()</code>, or an empty string if no such error occurred.
+
+<hr>
+<pre>
+ParseErrorType GetParseErrorType() const;
+</pre>
+
+<p>Returns the type of parsing error which occurred. Possible return types
+    are described in the long description.
+
+<hr>
+<pre>
+double Eval(const double* Vars);
+</pre>
+
+<p>Evaluates the function given to <code>Parse()</code>.
+
+<hr>
+<pre>
+int EvalError(void) const;
+</pre>
+
+<p>Returns <code>0</code> if no error happened in the previous call to
+<code>Eval()</code>, else an error code <code>&gt;0</code>.
+
+<hr>
+<pre>
+void Optimize();
+</pre>
+
+<p>Tries to optimize the bytecode for faster evaluation.
+
+<hr>
+<pre>
+bool AddConstant(const std::string&amp; name, double value);
+</pre>
+
+<p>Add a constant to the parser. Returns <code>false</code> if the name of
+the constant is invalid, else <code>true</code>.
+
+<hr>
+<pre>
+bool AddUnit(const std::string&amp; name, double value);
+</pre>
+
+<p>Add a new unit to the parser. Returns <code>false</code> if the name of
+the unit is invalid, else <code>true</code>.
+
+<hr>
+<pre>
+bool AddFunction(const std::string&amp; name,
+                 double (*functionPtr)(const double*),
+                 unsigned paramsAmount);
+</pre>
+
+<p>Add a user-defined function to the parser (as a function pointer).
+Returns <code>false</code> if the name of the function is invalid, else
+<code>true</code>.
+
+<hr>
+<pre>
+bool AddFunction(const std::string&amp; name, FunctionParser&amp;);
+</pre>
+
+<p>Add a user-defined function to the parser (as a <code>FunctionParser</code>
+instance). Returns <code>false</code> if the name of the function is invalid,
+else <code>true</code>.
+
+<hr>
+<pre>
+bool RemoveIdentifier(const std::string&amp; name);
+</pre>
+
+<p>Removes the constant, unit or user-defined function with the specified
+name from the parser.
+
+<hr>
+<pre>
+int ParseAndDeduceVariables(const std::string&amp; function,
+                            int* amountOfVariablesFound = 0,
+                            bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+                            std::string&amp; resultVarString,
+                            int* amountOfVariablesFound = 0,
+                            bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+                            std::vector&lt;std::string&gt;&amp; resultVars,
+                            bool useDegrees = false);
+</pre>
+
+<p>Like <code>Parse()</code>, but the variables in the function are deduced
+automatically. The amount of found variables and the variable names themselves
+are returned by the different versions of the function.
+
+<!-- -------------------------------------------------------------------- -->
+<a name="longdesc"></a>
+<h3>Long descriptions of FunctionParser methods</h3>
+
+<hr>
+<a name="longdesc_Parse"></a>
+<pre>
+int Parse(const std::string&amp; Function, const std::string&amp; Vars,
+          bool useDegrees = false);
+
+int Parse(const char* Function, const std::string&amp; Vars,
+          bool useDegrees = false);
+</pre>
+
+<p>Parses the given function (and compiles it to internal format).
+Destroys previous function. Following calls to <code>Eval()</code> will evaluate
+the given function.
+
+<p>The strings given as parameters are not needed anymore after parsing.
+
+<p>Parameters:
+
+<table border=2>
+ <tr>
+  <td><code>Function</code></td>
+  <td>String containing the function to parse.</td>
+ </tr><tr>
+  <td><code>Vars</code></td>
+  <td>String containing the variable names, separated by commas.<br>
+      Eg. <code>"x,y"</code>, <code>"VarX,VarY,VarZ,n"</code> or
+      <code>"x1,x2,x3,x4,__VAR__"</code>.
+ </tr><tr>
+  <td><code>useDegrees</code></td>
+  <td>(Optional.) Whether to use degrees or radians in
+        trigonometric functions. (Default: radians)</td>
+ </tr>
+</table>
+
+<p>If a <code>char*</code> is given as the <code>Function</code> parameter,
+it must be a null-terminated string.
+
+<p>Variables can have any size and they are case sensitive (ie.
+<code>"var"</code>, <code>"VAR"</code> and <code>"Var"</code> are
+<em>different</em> variable names). Letters, digits, underscores and
+UTF8-encoded characters can be used in variable names, but the name of
+a variable can't begin with a digit. Each variable name can appear only
+once in the '<code>Vars</code>' string. Function names are not legal
+variable names.
+
+<p>Using longer variable names causes no overhead whatsoever to the
+<code>Eval()</code> method, so it's completely safe to use variable names
+of any size.
+
+<p>The third, optional parameter specifies whether angles should be
+    interpreted as radians or degrees in trigonometrical functions.
+    If not specified, the default value is radians.
+
+<p>Return values:
+
+<ul>
+ <li>On success the function returns <code>-1</code>.
+ <li>On error the function returns an index to where the error was found
+     (<code>0</code> is the first character, <code>1</code> the second, etc).
+     If the error was not a parsing error returns an index to the end of the
+     string.
+</ul>
+
+<p>Example: <code>parser.Parse("3*x+y", "x,y");</code>
+
+
+<hr>
+<a name="longdesc_setDelimiterChar"></a>
+<pre>
+void setDelimiterChar(char);
+</pre>
+
+<p>By default the parser expects the entire function string to be valid
+(ie. the entire contents of the given <code>std::string</code>, or a C string
+ending in the null character <code>'\0'</code>).
+
+<p>If a delimiter character is specified with this function, then if it's
+encountered at the outermost parsing level by the <code>Parse()</code>
+function, and the input function has been valid so far, <code>Parse()</code>
+will return an index to this character inside the input string, but rather
+than set an error code, <code>FP_NO_ERROR</code> will be set.
+
+<p>The idea is that this can be used to more easily parse functions which
+are embedded inside larger strings, containing surrounding data, without
+having to explicitly extract the function to a separate string.
+
+<p>For example, suppose you are writing an interpreter for a scripting
+    language, which can have commands like this:
+
+<p><code>let MyFunction(x,y) = { sin(x*x+y*y) } // A 2-dimensional function</code>
+
+<p>Normally when parsing such a line you would have to extract the part
+inside the curly brackets into a separate string and parse it that way.
+With this feature what you can do instead is to set <code>'}'</code> as
+the delimiter character and then simply give a pointer to the character
+which comes after the <code>'{'</code>. If all goes well, the
+<code>Parse()</code> function will return an index to the <code>'}'</code>
+character (from the given starting point) and <code>GetParseErrorType()</code>
+will return <code>FP_NO_ERROR</code>. You can use the return
+value (if it's not <code>-1</code>) to jump forward in the string to the
+delimiter character.
+
+<p>Note that a null character (<code>'\0'</code>) or the end of the
+<code>std::string</code> (if one was given) will still be a valid end of
+the function string even if a delimiter character was specified. (In this
+case <code>Parse()</code> will return <code>-1</code> if there was no error,
+as usual.)
+
+<p>Also note that the delimiter character cannot be any valid operator
+or alphanumeric (including the underscore) character, nor the other
+characters defined in the function syntax. It must be a character not
+supported by the function parser (such as <code>'}'</code>,
+<code>'&quot;'</code>, <code>']'</code>, etc).
+
+
+<hr>
+<a name="longdesc_ErrorMsg"></a>
+<pre>
+const char* ErrorMsg(void) const;
+</pre>
+
+<p>Returns a pointer to an error message string corresponding to the error
+caused by <code>Parse()</code> (you can use this to print the proper error
+message to the user). If no such error has occurred, returns an empty string.
+
+
+<hr>
+<a name="longdesc_GetParseErrorType"></a>
+<pre>
+ParseErrorType GetParseErrorType() const;
+</pre>
+
+<p>Returns the type of parse error which occurred.
+
+<p>This method can be used to get the error type if <code>ErrorMsg()</code>
+is not enough for printing the error message. In other words, this can be
+used for printing customized error messages (eg. in another language).
+If the default error messages suffice, then this method doesn't need
+to be called.
+
+<code>FunctionParser::ParseErrorType</code> is an enumerated type inside
+the class (ie. its values are accessed like
+"<code>FunctionParser::SYNTAX_ERROR</code>").
+
+<p>The possible values for FunctionParser::ParseErrorType are listed below,
+along with their equivalent error message returned by the
+<code>ErrorMsg()</code> method:
+
+<p><table border=2>
+<tr>
+ <td><code>FP_NO_ERROR</code></td>
+ <td>If no error occurred in the previous call to <code>Parse()</code>.</td>
+</tr><tr>
+ <td><code>SYNTAX_ERROR</code></td>
+ <td>"Syntax error"</td>
+</tr><tr>
+ <td><code>MISM_PARENTH</code></td>
+ <td>"Mismatched parenthesis"</td>
+</tr><tr>
+ <td><code>MISSING_PARENTH</code></td>
+ <td>"Missing ')'"</td>
+</tr><tr>
+ <td><code>EMPTY_PARENTH</code></td>
+ <td>"Empty parentheses"</td>
+</tr><tr>
+ <td><code>EXPECT_OPERATOR</code></td>
+ <td>"Syntax error: Operator expected"</td>
+</tr><tr>
+ <td><code>OUT_OF_MEMORY</code></td>
+ <td>"Not enough memory"</td>
+</tr><tr>
+ <td><code>UNEXPECTED_ERROR</code></td>
+ <td>"An unexpected error occurred. Please make a full bug report to the
+      author"</td>
+</tr><tr>
+ <td><code>INVALID_VARS</code></td>
+ <td>"Syntax error in parameter 'Vars' given to FunctionParser::Parse()"</td>
+</tr><tr>
+ <td><code>ILL_PARAMS_AMOUNT</code></td>
+ <td>"Illegal number of parameters to function"</td>
+</tr><tr>
+ <td><code>PREMATURE_EOS</code></td>
+ <td>"Syntax error: Premature end of string"</td>
+</tr><tr>
+ <td><code>EXPECT_PARENTH_FUNC</code></td>
+ <td>"Syntax error: Expecting ( after function"</td>
+</tr><tr>
+ <td><code>UNKNOWN_IDENTIFIER</code></td>
+ <td>"Syntax error: Unknown identifier"</td>
+</tr><tr>
+ <td><code>NO_FUNCTION_PARSED_YET</code></td>
+ <td>"(No function has been parsed yet)"</td>
+</tr>
+</table>
+
+
+<hr>
+<a name="longdesc_Eval"></a>
+<pre>
+double Eval(const double* Vars);
+</pre>
+
+<p>Evaluates the function given to <code>Parse()</code>.
+The array given as parameter must contain the same amount of values as
+the amount of variables given to <code>Parse()</code>. Each value corresponds
+to each variable, in the same order.
+
+<p>Return values:
+<ul>
+ <li>On success returns the evaluated value of the function given to
+     <code>Parse()</code>.
+ <li>On error (such as division by 0) the return value is unspecified,
+     probably 0.
+</ul>
+
+<p>Example:
+
+<p><code>double Vars[] = {1, -2.5};</code><br>
+<code>double result = parser.Eval(Vars);</code>
+
+
+<hr>
+<a name="longdesc_EvalError"></a>
+<pre>
+int EvalError(void) const;
+</pre>
+
+<p>Used to test if the call to <code>Eval()</code> succeeded.
+
+<p>Return values:
+
+<p>If there was no error in the previous call to <code>Eval()</code>,
+returns <code>0</code>, else returns a positive value as follows:
+<ul>
+ <li>1: division by zero
+ <li>2: sqrt error (sqrt of a negative value)
+ <li>3: log error (logarithm of a negative value)
+ <li>4: trigonometric error (asin or acos of illegal value)
+ <li>5: maximum recursion level in <code>eval()</code> reached
+</ul>
+
+
+<hr>
+<a name="longdesc_Optimize"></a>
+<pre>
+void Optimize();
+</pre>
+
+<p>This method can be called after calling the <code>Parse()</code> method.
+It will try to simplify the internal bytecode so that it will evaluate faster
+(it tries to reduce the amount of opcodes in the bytecode).
+
+<p>For example, the bytecode for the function <code>"5+x*y-25*4/8"</code> will
+be reduced to a bytecode equivalent to the function <code>"x*y-7.5"</code> (the
+original 11 opcodes will be reduced to 5). Besides calculating constant
+expressions (like in the example), it also performs other types of
+simplifications with variable and function expressions.
+
+<p>This method is quite slow and the decision of whether to use it or
+not should depend on the type of application. If a function is parsed
+once and evaluated millions of times, then calling <code>Optimize()</code>
+may speed-up noticeably. However, if there are tons of functions to parse
+and each one is evaluated once or just a few times, then calling
+<code>Optimize()</code> will only slow down the program.
+
+<p>Also, if the original function is expected to be optimal, then calling
+<code>Optimize()</code> would be useless.
+
+<p>Note: Currently this method does not make any checks (like
+<code>Eval()</code> does) and thus things like <code>"1/0"</code> will cause
+undefined behaviour. (On the other hand, if such expression is given to the
+parser, <code>Eval()</code> will always give an error code, no matter what
+the parameters.) If caching this type of errors is important, a work-around
+is to call <code>Eval()</code> once before calling <code>Optimize()</code>
+and checking <code>EvalError()</code>.
+
+<p>If the destination application is not going to use this method,
+the compiler constant <code>FP_SUPPORT_OPTIMIZER</code> can be undefined in
+<code>fpconfig.hh</code> to make the library smaller (<code>Optimize()</code>
+can still be called, but it will not do anything).
+
+<p>(If you are interested in seeing how this method optimizes the opcode,
+you can call the <code>PrintByteCode()</code> method before and after the
+call to <code>Optimize()</code> to see the difference.)
+
+
+<hr>
+<a name="longdesc_AddConstant"></a>
+<pre>
+bool AddConstant(const std::string&amp; name, double value);
+</pre>
+
+<p>This method can be used to add constants to the parser. Syntactically
+    constants are identical to variables (ie. they follow the same naming
+    rules and they can be used in the function string in the same way as
+    variables), but internally constants are directly replaced with their
+    value at parse time.
+
+<p>Constants used by a function must be added before calling
+<code>Parse()</code> for that function. Constants are preserved between
+<code>Parse()</code> calls in the current FunctionParser instance, so
+they don't need to be added but once. (If you use the same constant in
+several instances of FunctionParser, you will need to add it to all the
+instances separately.)
+
+<p>Constants can be added at any time and the value of old constants can
+be changed, but new additions and changes will only have effect the next
+time <code>Parse()</code> is called. (That is, changing the value of a constant
+after calling <code>Parse()</code> and before calling <code>Eval()</code>
+will have no effect.)
+
+<p>The return value will be <code>false</code> if the '<code>name</code>' of
+the constant was illegal, else <code>true</code>. If the name was illegal,
+the method does nothing.
+
+<p>Example: <code>parser.AddConstant("pi", 3.1415926535897932);</code>
+
+<p>Now for example <code>parser.Parse("x*pi", "x");</code> will be identical
+to the call <code>parser.Parse("x*3.1415926535897932", "x");</code>
+
+
+<hr>
+<a name="longdesc_AddUnit"></a>
+<pre>
+bool AddUnit(const std::string&amp; name, double value);
+</pre>
+
+<p>In some applications it is desirable to have units of measurement.
+A typical example is an application which creates a page layout to be
+printed. When printing, distances are usually measured in points
+(defined by the resolution of the printer). However, it is often more
+useful for the user to be able to specify measurements in other units
+such as centimeters or inches.
+
+<p>A unit is simply a value by which the preceding element is multiplied.
+For example, if the printing has been set up to 300 DPI, one inch is
+then 300 points (dots). Thus saying eg. <code>"5in"</code> is the same as saying
+<code>"5*300"</code> or <code>"1500"</code> (assuming <code>"in"</code> has
+been added as a unit with the value 300).
+
+<p>Note that units are slightly different from a multiplication in
+that they have a higher precedence than any other operator (except
+parentheses). Thus for example <code>"5/2in"</code> is parsed as
+<code>"5/(2*300)"</code>.
+(If 5/2 inches is what one wants, it has to be written <code>"(5/2)in"</code>.)
+
+<p>You can use the <code>AddUnit()</code> method to add a new unit. The
+unit can then be used after any element in the function (and will work as
+a multiplier for that element). An element is a float literal, a constant,
+a variable, a function or any expression in parentheses. When the element
+is not a float literal nor an expression in parentheses, there has to naturally
+be at least one whitespace between the element and the unit (eg.
+<code>"x in"</code>). To change the value of a unit, call
+<code>AddUnit()</code> again with the same unit name and the new value.
+
+<p>Unit names share the same namespace as constants, functions and
+    variables, and thus should be distinct from those.
+
+<p>Example: <code>parser.AddUnit("in", 300);</code>
+
+<p>Now for example the function <code>"5in"</code> will be identical to
+<code>"(5*300)"</code>. Other usage examples include <code>"x in"</code>,
+<code>"3in+2"</code>, <code>"pow(x,2)in"</code>, <code>"(x+2)in"</code>.
+
+
+<hr>
+<a name="longdesc_AddFunction1"></a>
+<pre>
+bool AddFunction(const std::string&amp; name,
+                 double (*functionPtr)(const double*),
+                 unsigned paramsAmount);
+</pre>
+
+This method can be used to add new functions to the parser. For example,
+if you would like to add a function "<code>sqr(A)</code>" which squares the
+value of <code>A</code>, you can do it with this method (so that you don't
+need to touch the source code of the parser).
+
+<p>The method takes three parameters:
+
+<ul>
+ <li>The name of the function. The name follows the same naming conventions
+      as variable names.
+
+ <li>A C++ function, which will be called when evaluating the function
+      string (if the user-given function is called there). The C++ function
+      must have the form:
+      <p><code>double functionName(const double* params);</code>
+
+ <li>The number of parameters the function takes. 0 is a valid value
+      in which case the function takes no parameters (such function
+      should simply ignore the <code>double*</code> it gets as a parameter).
+</ul>
+
+<p>The return value will be <code>false</code> if the given name was invalid
+(either it did not follow the variable naming conventions, or the name was
+already reserved), else <code>true</code>. If the return value is
+<code>false</code>, nothing is added.
+
+<p>Example: Suppose we have a C++ function like this:
+
+<p><code>double Square(const double* p)</code><br>
+<code>{</code><br>
+<code>&nbsp;&nbsp;&nbsp;&nbsp;return p[0]*p[0];</code><br>
+<code>}</code>
+
+<p>Now we can add this function to the parser like this:
+
+<p><code>parser.AddFunction("sqr", Square, 1);</code><br>
+<code>parser.Parse("2*sqr(x)", "x");</code>
+
+<p>An example of a useful function taking no parameters is a function
+    returning a random value. For example:
+
+<p><code>double Rand(const double*)</code><br>
+<code>{</code><br>
+<code>&nbsp;&nbsp;&nbsp;&nbsp;return drand48();</code><br
+<code>}</code>
+
+<p><code>parser.AddFunction("rand", Rand, 0);</code>
+
+<p><em>Important note</em>: If you use the <code>Optimize()</code> method,
+it will assume that the user-given function has no side-effects, that is,
+it always returns the same value for the same parameters. The optimizer will
+optimize the function call away in some cases, making this assumption.
+(The <code>Rand()</code> function given as example above is one such
+problematic case.)
+
+
+<hr>
+<a name="longdesc_AddFunction2"></a>
+<pre>
+bool AddFunction(const std::string&amp; name, FunctionParser&amp;);
+</pre>
+
+<p>This method is almost identical to the previous <code>AddFunction()</code>,
+but instead of taking a C++ function, it takes another FunctionParser
+instance.
+
+<p>There are some important restrictions on making a FunctionParser instance
+    call another:
+
+<ul>
+ <li>The FunctionParser instance given as parameter must be initialized
+      with a <code>Parse()</code> call before giving it as parameter. That
+      is, if you want to use the parser <code>A</code> in the parser
+      <code>B</code>, you must call <code>A.Parse()</code> before you can
+      call <code>B.AddFunction("name", A)</code>.
+
+ <li>The amount of variables in the FunctionParser instance given as
+      parameter must not change after it has been given to the
+      <code>AddFunction()</code>
+      of another instance. Changing the number of variables will result in
+      malfunction.
+
+ <li><code>AddFunction()</code> will fail (ie. return <code>false</code>)
+      if a recursive loop is
+      formed. The method specifically checks that no such loop is built.
+
+ <li>The FunctionParser instance given as parameter will <em>not</em> be
+     copied internally, only referenced. Thus the FunctionParser instance
+     given as parameter must exist for as long as the other FunctionParser
+     instance uses it.
+</ul>
+
+<p>Example:
+
+<p><code>FunctionParser f1, f2;</code><br>
+<p><code>f1.Parse("x*x", "x");</code><br>
+<p><code>f2.AddFunction("sqr", f1);</code>
+
+<p>This version of the <code>AddFunction()</code> method can be useful to
+eg. chain user-given functions. For example, ask the user for a function F1,
+    and then ask the user another function F2, but now the user can
+    call F1 in this second function if he wants (and so on with a third
+    function F3, where he can call F1 and F2, etc).
+
+<hr>
+<a name="longdesc_RemoveIdentifier"></a>
+<pre>
+bool RemoveIdentifier(const std::string&amp; name);
+</pre>
+
+<p>If a constant, unit or user-defined function with the specified name
+exists in the parser, it will be removed and the return value will be
+<code>true</code>, else nothing will be done and the return value will be
+<code>false</code>.
+
+<p>(Note: If you want to remove <em>everything</em> from an existing
+FunctionParser instance, simply assign a fresh instance to it, ie. like
+"<code>parser&nbsp;=&nbsp;FunctionParser();</code>")
+
+<hr>
+<a name="longdesc_ParseAndDeduceVariables"></a>
+<pre>
+int ParseAndDeduceVariables(const std::string&amp; function,
+                            int* amountOfVariablesFound = 0,
+                            bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+                            std::string&amp; resultVarString,
+                            int* amountOfVariablesFound = 0,
+                            bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+                            std::vector&lt;std::string&gt;&amp; resultVars,
+                            bool useDegrees = false);
+</pre>
+
+<p>These functions work in the same way as the <code>Parse()</code> function,
+but the variables in the input function string are deduced automatically. The
+parameters are:
+
+<ul>
+ <li><code>function</code>: The input function string, as with
+   <code>Parse()</code>.
+ <li><code>amountOfVariablesFound</code>: If non-null, the amount of found
+   variables will be assigned here.
+ <li><code>resultVarString</code>: The found variables will be written to
+   this string, in the same format as accepted by the <code>Parse()</code>
+   function. The variable names will be sorted using the <code>&lt;</code>
+   operator of <code>std::string</code>.
+ <li><code>resultVars</code>: The found variables will be written to this
+   vector, each element being one variable name. They will be sorted using
+   the <code>&lt;</code> operator of <code>std::string</code>. (The amount
+   of found variables can be retrieved, rather obviously, with the
+   <code>size()</code> method of the vector.)
+ <li><code>useDegrees</code>: As with <code>Parse()</code>.
+</ul>
+
+<p>As with <code>Parse()</code>, the return value will be <code>-1</code> if
+the parsing succeeded, else an index to the location of the error. None of
+the specified return values will be modified in case of error.
+
+
+<!-- -------------------------------------------------------------------- -->
+<h2>Syntax</h2>
+
+<a name="literals"></a>
+<h3>Numeric literals</h3>
+
+<p>A numeric literal is a fixed numerical value in the input function string
+  (either a floating point value or an integer value, depending on the parser
+  type).
+
+<p>An integer literal can consist solely of numerical digits (possibly with
+  a preceding unary minus). For example, "<code>12345</code>".
+
+<p>If the literal is preceded by the characters "<code>0x</code>", it
+  will be interpreted as a hexadecimal literal, where digits can also include
+  the letters from '<code>A</code>' to '<code>F</code>' (in either uppercase
+  or lowercase). For example, "<code>0x89ABC</code>" (which corresponds to the
+  value 563900).
+
+<p>A floating point literal (only supported by the floating point type parsers)
+  may additionally include a decimal point followed by the decimal part of the
+  value, such as for example "<code>12.34</code>", optionally followed by a
+  decimal exponent.
+
+<p>A decimal exponent consists of an '<code>E</code>' or '<code>e</code>',
+  followed by an optional plus or minus sign, followed by decimal digits, and
+  indicates multiplication by a power of 10. For example, "<code>1.2e5</code>"
+  (which is equivalent to the value 120000).
+
+<p>If a floating point literal is preceded by the characters "<code>0x</code>"
+  it will be interpreted in hexadecimal. A hexadecimal floating point
+  literal consists of a hexadecimal value, with an optional decimal point,
+  followed optionally by a binary exponent in base 10 (in other words, the
+  exponent is not in hexadecimal).
+
+<p>A binary exponent has the same format as a decimal exponent, except that
+  '<code>P</code>' or '<code>p</code>' is used. A binary exponent indicates
+  multiplication by a power of 2. For example, "<code>0xA.Bp10</code>"
+  (which is equivalent to the value 10944).
+
+<a name="identifiers"></a>
+<h3>Identifier names</h3>
+
+<p>An identifier is the name of a function (internal or user-defined),
+  variable, constant or unit. New identifiers can be specified with the
+  functions described in the earlier subsections in this document.
+
+<p>The name of an identifier can use any alphanumeric characters, the
+  underscore character and any UTF8-encoded unicode character, excluding
+  those denoting whitespace.
+  The first character of the name cannot be a numeric digit, though.
+
+<p>All functions, variables, constants and units must use unique names.
+  It's not possible to add two different identifiers with the same name.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="functionsyntax"></a>
+<h3>The function string syntax</h3>
+
+<p>The function string understood by the class is very similar (but not
+completely identical in all aspects) to mathematical expressions in the
+C/C++ languages.
+Arithmetic float expressions can be created from float literals, variables
+or functions using the following operators in this order of precedence:
+
+<p><table border=2>
+ <tr>
+  <td><code>()</code></td>
+  <td>expressions in parentheses first</td>
+ </tr><tr>
+  <td><code>A unit</code></td>
+  <td>a unit multiplier (if one has been added)</td>
+ </tr><tr>
+  <td><code>A^B</code></td>
+  <td>exponentiation (A raised to the power B)</td>
+ </tr><tr>
+  <td><code>-A</code></td>
+  <td>unary minus</td>
+ </tr><tr>
+  <td><code>!A</code></td>
+  <td>unary logical not (result is 1 if <code>int(A)</code> is 0, else 0)</td>
+ </tr><tr>
+  <td><code>A*B  A/B  A%B</code></td>
+  <td>multiplication, division and modulo</td>
+ </tr><tr>
+  <td><code>A+B  A-B</code></td>
+  <td>addition and subtraction</td>
+ </tr><tr>
+  <td><code>A=B  A&lt;B  A&lt;=B<br>A!=B  A&gt;B  A&gt;=B</code></td>
+  <td>comparison between A and B (result is either 0 or 1)</td>
+ </tr><tr>
+  <td><code>A&amp;B</code></td>
+  <td>result is 1 if <code>int(A)</code> and <code>int(B)</code> differ from
+      0, else 0.<br>
+      Note: Regardless of the values, both operands are always
+      evaluated. However, if the expression is optimized, it may
+      be changed such that only one of the operands is evaluated,
+      according to standard shortcut logical operation semantics.</td>
+ </tr><tr>
+  <td><code>A|B</code></td>
+  <td>result is 1 if <code>int(A)</code> or <code>int(B)</code> differ from 0,
+      else 0.<br>
+      Note: Regardless of the values, both operands are always
+      evaluated. However, if the expression is optimized, it may
+      be changed such that only one of the operands is evaluated,
+      according to standard shortcut logical operation semantics.</td>
+ </tr>
+</table>
+
+<p>(Note that currently the exponentiation operator is not supported for
+  <code>FunctionParser_li</code> nor <code>FunctionParser_gmpint</code>.
+  With the former the result would very easily overflow, making its
+  usefulness questionable. With the latter it could be easily abused to
+  make the program run out of memory; think of a function like
+  "10^10^10^100000".)
+
+<p>Since the unary minus has higher precedence than any other operator, for
+  example the following expression is valid: <code>x*-y</code>
+
+<p>The comparison operators use an epsilon value, so expressions which may
+differ in very least-significant digits should work correctly. For example,
+<code>"0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 1"</code> should always
+return 1, and the same comparison done with "<code>&gt;</code>" or
+"<code>&lt;</code>" should always return 0. (The epsilon value can be
+configured in the <code>fpconfig.hh</code> file.)
+Without epsilon this comparison probably returns the wrong value.
+
+<p>The class supports these functions:
+
+<p><table border=2>
+<tr>
+ <td><code>abs(A)</code></td>
+ <td>Absolute value of A. If A is negative, returns -A otherwise returns A.</td>
+</tr><tr>
+  <td><code>acos(A)</code></td>
+  <td>Arc-cosine of A. Returns the angle, measured in radians, whose cosine
+      is A.</td>
+</tr><tr>
+  <td><code>acosh(A)</code></td>
+  <td>Same as acos() but for hyperbolic cosine.</td>
+</tr><tr>
+  <td><code>asin(A)</code></td>
+  <td>Arc-sine of A. Returns the angle, measured in radians, whose sine
+      is A.</td>
+</tr><tr>
+  <td><code>asinh(A)</code></td>
+  <td>Same as asin() but for hyperbolic sine.</td>
+</tr><tr>
+  <td><code>atan(A)</code></td>
+  <td>Arc-tangent of (A). Returns the angle, measured in radians,
+      whose tangent is (A).</td>
+</tr><tr>
+  <td><code>atan2(A,B)</code></td>
+  <td>Arc-tangent of A/B. The two main differences to atan() is
+      that it will return the right angle depending on the signs of
+      A and B (atan() can only return values betwen -pi/2 and pi/2),
+      and that the return value of pi/2 and -pi/2 are possible.</td>
+</tr><tr>
+  <td><code>atanh(A)</code></td>
+  <td>Same as atan() but for hyperbolic tangent.</td>
+</tr><tr>
+  <td><code>cbrt(A)</code></td>
+  <td>Cube root of A. Returns the value whose cube is A.</td>
+</tr><tr>
+  <td><code>ceil(A)</code></td>
+  <td>Ceiling of A. Returns the smallest integer not smaller than A.
+      Rounds up to the next higher integer. E.g. -2.9, -2.5 and -2.1 are
+    rounded to -2.0, and 2.9, 2.5 and 2.1 are rounded to 3.0.</td>
+</tr><tr>
+  <td><code>cos(A)</code></td>
+  <td>Cosine of A. Returns the cosine of the angle A, where A is
+      measured in radians.</td>
+</tr><tr>
+  <td><code>cosh(A)</code></td>
+  <td>Same as cos() but for hyperbolic cosine.</td>
+</tr><tr>
+  <td><code>cot(A)</code></td>
+  <td>Cotangent of A (equivalent to 1/tan(A)).</td>
+</tr><tr>
+  <td><code>csc(A)</code></td>
+  <td>Cosecant of A (equivalent to 1/sin(A)).</td>
+</tr><tr>
+  <td><code>eval(...)</code></td>
+  <td>This a recursive call to the function to be evaluated. The
+      number of parameters must be the same as the number of parameters
+      taken by the function. Must be called inside <code>if()</code> to avoid
+      infinite recursion.</td>
+</tr><tr>
+  <td><code>exp(A)</code></td>
+  <td>Exponential of A. Returns the value of e raised to the power
+      A where e is the base of the natural logarithm, i.e. the
+      non-repeating value approximately equal to 2.71828182846.</td>
+</tr><tr>
+  <td><code>floor(A)</code></td>
+  <td>Floor of A. Returns the largest integer not greater than A. Rounds
+      down to the next lower integer.
+      E.g. -2.9, -2.5 and -2.1 are rounded to -3.0,
+      and 2.9, 2.5 and 2.1 are rounded to 2.0.</td>
+</tr><tr>
+  <td><code>if(A,B,C)</code></td>
+  <td>If int(A) differs from 0, the return value of this function is B,
+      else C. Only the parameter which needs to be evaluated is
+      evaluated, the other parameter is skipped; this makes it safe to
+      use <code>eval()</code> in them.</td>
+</tr><tr>
+  <td><code>int(A)</code></td>
+  <td>Rounds A to the closest integer. Equidistant values are rounded up.
+    E.g. -2.9 is rounded to -3.0; -2.5 and -2.1 are rounded to -2.0,
+    and 2.9 and 2.5 are rounded to 3.0; 2.1 is rounded to 2.0.</td>
+</tr><tr>
+  <td><code>log(A)</code></td>
+  <td>Natural (base e) logarithm of A.</td>
+</tr><tr>
+  <td><code>log10(A)</code></td>
+  <td>Base 10 logarithm of A.</td>
+</tr><tr>
+  <td><code>max(A,B)</code></td>
+  <td>If A&gt;B, the result is A, else B.</td>
+</tr><tr>
+  <td><code>min(A,B)</code></td>
+  <td>If A&lt;B, the result is A, else B.</td>
+</tr><tr>
+  <td><code>pow(A,B)</code></td>
+  <td>Exponentiation (A raised to the power B).</td>
+</tr><tr>
+  <td><code>sec(A)</code></td>
+  <td>Secant of A (equivalent to 1/cos(A)).</td>
+</tr><tr>
+  <td><code>sin(A)</code></td>
+  <td>Sine of A. Returns the sine of the angle A, where A is
+      measured in radians.</td>
+</tr><tr>
+  <td><code>sinh(A)</code></td>
+  <td>Same as sin() but for hyperbolic sine.</td>
+</tr><tr>
+  <td><code>sqrt(A)</code></td>
+  <td>Square root of A. Returns the value whose square is A.</td>
+</tr><tr>
+  <td><code>tan(A)</code></td>
+  <td>Tangent of A. Returns the tangent of the angle A, where A
+      is measured in radians.</td>
+</tr><tr>
+  <td><code>tanh(A)</code></td>
+  <td>Same as tan() but for hyperbolic tangent.</td>
+</tr><tr>
+  <td><code>trunc(A)</code></td>
+  <td>Truncated value of A. Returns an integer corresponding to the value
+    of A without its fractional part.
+    E.g. -2.9, -2.5 and -2.1 are rounded to -2.0,
+    and 2.9, 2.5 and 2.1 are rounded to 2.0.</td>
+</tr>
+</table>
+
+<p>(Note that for <code>FunctionParser_li</code> and
+  <code>FunctionParser_gmpint</code> only the functions
+  <code>abs()</code>, <code>eval()</code>, <code>if()</code>,
+  <code>min()</code> and <code>max()</code> are supported.)
+
+<p>Examples of function string understood by the class:
+
+<p><code>"1+2"</code><br>
+<code>"x-1"</code><br>
+<code>"-sin(sqrt(x^2+y^2))"</code><br>
+<code>"sqrt(XCoord*XCoord + YCoord*YCoord)"</code><br>
+
+<p>An example of a recursive function is the factorial function:
+
+<code>"if(n>1, n*eval(n-1), 1)"</code>
+
+<p>Note that a recursive call has some overhead, which makes it a bit slower
+  than any other operation. It may be a good idea to avoid recursive functions
+  in very time-critical applications. Recursion also takes some memory, so
+  extremely deep recursions should be avoided (eg. millions of nested recursive
+  calls).
+
+<p>Also note that even though the maximum recursion level of
+<code>eval()</code> is limited, it is possible to write functions which
+never reach that level but still take enormous amounts of time to evaluate.
+This can sometimes be undesirable because it is prone to exploitation,
+which is why <code>eval()</code> is disabled by default. It can be enabled
+in the <code>fpconfig.hh</code> file.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="inlinevars"></a>
+<h3>Inline variables</h3>
+
+<p>The function syntax supports defining new variables inside the function
+string itself. This can be done with the following syntax:
+
+<p><code>"&lt;variable name&gt; := &lt;expression&gt;; &lt;function&gt;"</code>
+
+<p>For example:
+
+<p><code>"length := sqrt(x*x+y*y); 2*length*sin(length)"</code>
+
+<p>(Spaces around the '<code>:=</code>' operator are optional.)
+
+<p>The obvious benefit of this is that if a long expression needs to be
+used in the function several times, this allows writing it only once and
+using a named variable from that point forward.
+
+<p>The variable name must be an unused identifier (in other words, not an
+existing function, variable or unit name).
+
+<p>The <code>&lt;function&gt;</code> part can have further inline variable
+definitions, and thus it's possible to have any amount of them, for example:
+
+<p><code>"A := x^2; B := y^2; C := z^2; sqrt(A+B+C)"</code>
+
+<p>The expressions in subsequent inline variable definitions can use any
+of the previous inline variables. It is also possible to redefine an inline
+variable. For example:
+
+<p><code>"A := x^2; A := 2*A; sqrt(A)"</code>
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="whitespace"></a>
+<h3>Whitespace</h3>
+
+<p>Arbitrary amounts of whitespace can optionally be included between
+  elements in the function string.
+  The following unicode characters are interpreted as whitespace:
+<table>
+ <tr>
+  <th>Character number</th>
+  <th>Character name</th>
+  <th>UTF-8 byte sequence</th>
+ </tr>
+ <tr><td>U+0009</td><td>HORIZONTAL TABULATION    </td><td>09</td></tr>
+ <tr><td>U+000A</td><td>LINE FEED                </td><td>0A</td></tr>
+ <tr><td>U+000B</td><td>VERTICAL TABULATION      </td><td>0B</td></tr>
+ <tr><td>U+000D</td><td>CARRIAGE RETURN          </td><td>0D</td></tr>
+ <tr><td>U+0020</td><td>SPACE                    </td><td>20</td></tr>
+ <tr><td>U+00A0</td><td>NO-BREAK SPACE           </td><td>C2 A0</td></tr>
+ <tr><td>U+2000</td><td>EN QUAD                  </td><td>E2 80 80</td></tr>
+ <tr><td>U+2001</td><td>EM QUAD                  </td><td>E2 80 81</td></tr>
+ <tr><td>U+2002</td><td>EN SPACE                 </td><td>E2 80 82</td></tr>
+ <tr><td>U+2003</td><td>EM SPACE                 </td><td>E2 80 83</td></tr>
+ <tr><td>U+2004</td><td>THREE-PER-EM SPACE       </td><td>E2 80 84</td></tr>
+ <tr><td>U+2005</td><td>FOUR-PER-EM SPACE        </td><td>E2 80 85</td></tr>
+ <tr><td>U+2006</td><td>SIX-PER-EM SPACE         </td><td>E2 80 86</td></tr>
+ <tr><td>U+2007</td><td>FIGURE SPACE             </td><td>E2 80 87</td></tr>
+ <tr><td>U+2008</td><td>PUNCTUATION SPACE        </td><td>E2 80 88</td></tr>
+ <tr><td>U+2009</td><td>THIN SPACE               </td><td>E2 80 89</td></tr>
+ <tr><td>U+200A</td><td>HAIR SPACE               </td><td>E2 80 8A</td></tr>
+ <tr><td>U+200B</td><td>ZERO WIDTH SPACE         </td><td>E2 80 8B</td></tr>
+ <tr><td>U+202F</td><td>NARROW NO-BREAK SPACE    </td><td>E2 80 AF</td></tr>
+ <tr><td>U+205F</td><td>MEDIUM MATHEMATICAL SPACE</td><td>E2 81 9F</td></tr>
+ <tr><td>U+3000</td><td>IDEOGRAPHIC SPACE        </td><td>E3 80 80</td></tr>
+</table>
+
+
+<!-- -------------------------------------------------------------------- -->
+<h2>Miscellaneous</h2>
+
+<a name="evaluationchecks"></a>
+<h3>About evaluation-time checks</h3>
+
+<p>By default <code>FunctionParser::Eval()</code> will perform certain sanity
+checks before performing certain operations. For example, before calling the
+<code>sqrt</code> function, it will check if the parameter is negative, and
+if so, it will set the proper error code instead of calling the function.
+These checks include:
+
+<ul>
+ <li>Division by (the exact value of) zero.
+ <li>Square root of a negative value.
+ <li>Logarithm of a non-positive value.
+ <li>Arcsine or arccosine of a value not in the range [-1, 1]. (This includes
+   hyperbolic versions of the functions.)
+</ul>
+
+<p>However, the library <em>can not</em> guarantee that it will catch all
+possible floating point errors before performing them, because this is
+impossible to do with standard C++. For example, dividing a very large
+value by a value which is very close to zero, or calculating the logarithm
+of a very small value may overflow the result, as well as multiplying two
+very large values. Raising a negative number to a non-integral power may
+cause a <em>NaN</em> result, etc.
+
+<p>As a rule of thumb, the library will (by default) detect invalid operations
+if they are invalid for a range of values. For example, square root is undefined
+for all negative values, and arc sine is undefined only values outside the range
+[-1, 1]. In general, operations which are invalid for only one single value
+(rather than a contiguous range of values) will not be detected (division by
+the exact value of zero is an exception to this rule) nor will
+overflow/underflow situations.
+
+<p>The library cannot guarantee that floating point
+errors will never happen during evaluation. This can make the library to
+return the floating point values <em>inf</em> and <em>NaN</em>. Moreover,
+if floating point errors cause an interrupt in the target computer
+architecture and/or when using certain compiler settings, this library
+cannot guarantee that it will never happen.
+
+<p>Since not all error situations can be caught, and since the sanity checks
+only slow down the evaluation (although only very slightly), the precompiler
+constant <code>FP_NO_EVALUATION_CHECKS</code> can be used to turn all the
+checks off. This might make the evaluation slightly faster in certain
+situations.
+
+<p>Note that the optimizer never performs any sanity checks.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="threadsafety"></a>
+<h3>About thread safety</h3>
+
+<p>None of the member functions of the FunctionParser class are thread-safe.
+Most prominently, the <code>Eval()</code> function is not thread-safe.
+(In other words, the <code>Eval()</code> function of a single FunctionParser
+instance cannot be safely called simultaneously by two threads.)
+
+<p>There are ways to use this library in a thread-safe way, though. If each
+thread uses its own FunctionParser instance, no problems will obviously
+happen. Note, however, that if these instances need to be a copy of a given
+FunctionParser instance (eg. one where the user has entered a function),
+a deep copy of this instance has to be performed for each thread. By
+default FunctionParser uses shallow-copying (copy-on-write), which means
+that a simple assignment of copy construction will not copy the data itself.
+To force a deep copy you can all the <code>ForceDeepCopy()</code> function on
+each of the instances of each thread after the assignment or copying has been
+done.
+
+<p>Another possibility is to compile the FunctionParser library so that
+its <code>Eval()</code> function will be thread-safe. (This can be done by
+defining the <code>FP_USE_THREAD_SAFE_EVAL</code> or the
+<code>FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA</code>
+precompiler constant.) As long as only one thread calls the other functions
+of FunctionParser, the other threads can safely call the <code>Eval()</code>
+of this one instance.
+
+<p>Note, however, that compiling the library like this can make
+<code>Eval()</code> slightly slower. (The <code>alloca</code> version, if
+supported by the compiler, will not be as slow.)
+
+<p>Also note that the MPFR and GMP versions of the library cannot be
+  made thread-safe, and thus this setting has no effect on them.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="tipsandtricks"></a>
+<h3>Tips and tricks</h3>
+
+<h4>Add constants automatically to all parser objects</h4>
+
+<p>Often the same constants (such as <em>pi</em> and <em>e</em>) and other
+user-defined identifiers (such as units) are always used in all the
+<code>FunctionParser</code> objects throughout the program. It would be
+troublesome to always have to manually add these constants every time a
+new parser object is created.
+
+<p>There is, however, a simple way to always add these user-defined identifiers
+to all instances. Write a class like this:
+
+<pre>
+    class ParserWithConsts: public FunctionParser
+    {
+     public:
+        ParserWithConsts()
+        {
+            AddConstant("pi", 3.14159265358979323846);
+            AddConstant("e", 2.71828182845904523536);
+        }
+    };
+</pre>
+
+<p>Now instead of using <code>FunctionParser</code>, always use
+<code>ParserWithConsts</code>. It will behave identically except that the
+constants (and possibly other user-defined identifiers) will always be
+automatically defined. (Objects of this type even survive
+<a href="http://en.wikipedia.org/wiki/Object_slicing">slicing</a>, so
+they are completely safe to use anywhere.)
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="contact"></a>
+<h3>Contacting the author</h3>
+
+<p>Any comments, bug reports, etc. should be sent to warp@iki.fi
+
+
+<!-- -------------------------------------------------------------------- -->
+<!--
+<a name="algorithm"></a>
+<h2>The algorithm used in the library</h2>
+
+<p>The whole idea behind the algorithm is to convert the regular infix
+format (the regular syntax for mathematical operations in most languages,
+like C and the input of the library) to postfix format. The postfix format
+is also called stack arithmetic since an expression in postfix format
+can be evaluated using a stack and operating with the top of the stack.
+
+<p>For example:
+
+<p><table border=2>
+<tr><th>infix</th> <th>postfix</th></tr>
+<tr><td><code>2+3</code></td><td><code>2 3 +</code></td></tr>
+<tr><td><code>1+2+3</code></td><td><code>1 2 + 3 +</code></td></tr>
+<tr><td><code>5*2+8/2</code></td><td><code>5 2 * 8 2 / +</code></td></tr>
+<tr><td><code>(5+9)*3</code></td><td><code>5 9 + 3 *</code></td></tr>
+</table>
+
+<p>The postfix notation should be read in this way:
+
+<p>Let's take for example the expression: <code>5 2 * 8 2 / +</code>
+<ul>
+ <li>Put 5 on the stack
+ <li>Put 2 on the stack
+ <li>Multiply the two values on the top of the stack and put the result on
+    the stack (removing the two old values)
+ <li>Put 8 on the stack
+ <li>Put 2 on the stack
+ <li>Divide the two values on the top of the stack
+ <li>Add the two values on the top of the stack (which are in this case
+    the result of 5*2 and 8/2, that is, 10 and 4).
+</ul>
+
+<p>At the end there's only one value in the stack, and that value is the
+result of the expression.
+
+<p>Why stack arithmetic?
+
+<p>The last example above can give you a hint.
+  In infix format operators have precedence and we have to use parentheses to
+group operations with lower precedence to be calculated before operations
+with higher precedence.
+  This causes a problem when evaluating an infix expression, specially
+when converting it to byte code. For example in this kind of expression:
+    <code>(x+1)/(y+2)</code>
+we have to calculate first the two additions before we can calculate the
+division. We have to also keep counting parentheses, since there can be
+a countless amount of nested parentheses. This usually means that you
+have to do some type of recursion.
+
+<p>The simplest and mostefficient way of calculating this is to convert it
+to postfix notation.
+  The postfix notation has the advantage that you can make all operations
+in a straightforward way. You just evaluate the expression from left to
+right, applying each operation directly and that's it. There are no
+parentheses to worry about. You don't need recursion anywhere.
+  You have to keep a stack, of course, but that's extremely easily done.
+Also you just operate with the top of the stack, which makes it very easy.
+You never have to go deeper than 2 items in the stack.
+  And even better: Evaluating an expression in postfix format is never
+slower than in infix format. All the contrary, in many cases it's a lot
+faster (eg. because all parentheses are optimized away).
+  The above example could be expressed in postfix format:
+    <code>x 1 + y 2 + /</code>
+
+<p>The good thing about the postfix notation is also the fact that it can
+be extremely easily expressed in bytecode form.
+  You only need a byte value for each operation, for each variable and
+to push a constant to the stack.
+  Then you can interpret this bytecode straightforwardly. You just interpret
+it byte by byte, from the beginning to the end. You never have to go back,
+make loops or anything.
+
+<p>This is what makes byte-coded stack arithmetic so fast.
+-->
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="license"></a>
+<h2>Usage license</h2>
+
+<p>Copyright Â© 2003-2010 Juha Nieminen, Joel Yliluoma
+
+<p>This Library is distributed under the
+  <a href="http://www.gnu.org/copyleft/lesser.html">Lesser General Public
+    License</a> (LGPL) version 3.
+
+</body>
+</html>
diff --git a/fparser/docs/gpl.txt b/fparser/docs/gpl.txt
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/fparser/docs/lgpl.txt b/fparser/docs/lgpl.txt
new file mode 100644 (file)
index 0000000..cca7fc2
--- /dev/null
@@ -0,0 +1,165 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/fparser/docs/style.css b/fparser/docs/style.css
new file mode 100644 (file)
index 0000000..d5141d3
--- /dev/null
@@ -0,0 +1,80 @@
+html
+{
+  background-color: #E0E0E0;
+}
+
+body
+{
+  background-color: white;
+  margin-left: 7%;
+  margin-top: 16px;
+  margin-right: 7%;
+  padding-top: 2em;
+  padding-left: 7%;
+  padding-right: 7%;
+  padding-bottom: 2%;
+  border-color: black;
+  border: solid;
+  border-width: 1px;
+}
+
+h1
+{
+  text-align: center;
+  background-color: #FFEEBB;
+  padding-bottom: 0.2em;
+  padding-top: 0.1em;
+}
+
+h2
+{
+  background-color: #FFFFCC;
+  padding-left: 0.5em;
+}
+
+h3
+{
+  background-color: #FFFFEE;
+}
+
+blockquote
+{
+  padding-left: 2em;
+  padding-right: 2em;
+  font-style: italic;
+  background-color: #FFFAF0;
+}
+
+li
+{
+  padding-top: 0.3em;
+}
+
+pre
+{
+  background-color: #E8E8E8;
+  padding-left: 1em;
+  padding-top: 0.5em;
+  padding-bottom: 0.5em;
+}
+
+code
+{
+  font-family: monospace;
+  color: #900040;
+}
+
+.small
+{
+  font-size: 80%;
+}
+
+.codecomment
+{
+  color: green;
+}
+
+.highlight
+{
+  background: #C0D0FF;
+}
diff --git a/fparser/examples/example.cc b/fparser/examples/example.cc
new file mode 100644 (file)
index 0000000..b4ab5f4
--- /dev/null
@@ -0,0 +1,55 @@
+// Simple example file for the function parser\r
+// ===========================================\r
+\r
+/* When running the program, try for example with these values:\r
+\r
+f(x) = x^2\r
+min x: -5\r
+max x: 5\r
+step: 1\r
+\r
+*/\r
+\r
+#include "../fparser.hh"\r
+\r
+#include <iostream>\r
+#include <string>\r
+\r
+int main()\r
+{\r
+    std::string function;\r
+    double minx, maxx, step;\r
+    FunctionParser fparser;\r
+\r
+    fparser.AddConstant("pi", 3.1415926535897932);\r
+\r
+    while(true)\r
+    {\r
+        std::cout << "f(x) = ";\r
+        std::getline(std::cin, function);\r
+        if(std::cin.fail()) return 0;\r
+\r
+        int res = fparser.Parse(function, "x");\r
+        if(res < 0) break;\r
+\r
+        std::cout << std::string(res+7, ' ') << "^\n"\r
+                  << fparser.ErrorMsg() << "\n\n";\r
+    }\r
+\r
+    std::cout << "min x: ";\r
+    std::cin >> minx;\r
+    std::cout << "max x: ";\r
+    std::cin >> maxx;\r
+    std::cout << "step: ";\r
+    std::cin >> step;\r
+    if(std::cin.fail()) return 0;\r
+\r
+    double vals[] = { 0 };\r
+    for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)\r
+    {\r
+        std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)\r
+                  << std::endl;\r
+    }\r
+\r
+    return 0;\r
+}\r
diff --git a/fparser/examples/example2.cc b/fparser/examples/example2.cc
new file mode 100644 (file)
index 0000000..958b9a1
--- /dev/null
@@ -0,0 +1,85 @@
+// Simple example file for the function parser
+// ===========================================
+/* Note that the library has to be compiled with
+   FP_SUPPORT_FLOAT_TYPE, FP_SUPPORT_LONG_DOUBLE_TYPE and
+   FP_SUPPORT_LONG_INT_TYPE
+   preprocessor macros defined for this example to work.
+
+   Try with these input values with the different floating point parser
+   types to see the difference in accuracy:
+
+f(x) = x + 1.234567890123456789
+min x: 0
+max x: 2
+step: 1
+*/
+
+#include "../fparser.hh"
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+
+template<typename Parser>
+void runExample(const char* valueTypeName)
+{
+    typedef typename Parser::value_type Value_t;
+
+    std::cout << "Using " << valueTypeName << " parser." << std::endl;
+
+    Parser fparser;
+    std::string function;
+    Value_t minx, maxx, step;
+
+    fparser.AddConstant("pi", Value_t(3.1415926535897932));
+
+    std::cin.ignore();
+    while(true)
+    {
+        std::cout << "f(x) = ";
+        std::getline(std::cin, function);
+        if(std::cin.fail()) return;
+
+        int res = fparser.Parse(function, "x");
+        if(res < 0) break;
+
+        std::cout << std::string(res+7, ' ') << "^\n"
+                  << fparser.ErrorMsg() << "\n\n";
+    }
+
+    std::cout << "min x: ";
+    std::cin >> minx;
+    std::cout << "max x: ";
+    std::cin >> maxx;
+    std::cout << "step: ";
+    std::cin >> step;
+    if(std::cin.fail()) return;
+
+    Value_t vals[] = { 0 };
+    for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)
+    {
+        std::cout << std::setprecision(20);
+        std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)
+                  << std::endl;
+    }
+}
+
+int main()
+{
+    int choice = 0;
+    do
+    {
+        std::cout << "1 = double, 2 = float, 3 = long double, 4 = long int: ";
+        std::cin >> choice;
+    } while(choice < 1 || choice > 4);
+
+    switch(choice)
+    {
+      case 1: runExample<FunctionParser>("double"); break;
+      case 2: runExample<FunctionParser_f>("float"); break;
+      case 3: runExample<FunctionParser_ld>("long double"); break;
+      case 4: runExample<FunctionParser_li>("long int"); break;
+    }
+
+    return 0;
+}
diff --git a/fparser/fp_identifier_parser.inc b/fparser/fp_identifier_parser.inc
new file mode 100644 (file)
index 0000000..7a903c1
--- /dev/null
@@ -0,0 +1,415 @@
+/* NOTE:
+  Do not include this file in your project. The fparser.cc file #includes
+this file internally and thus you don't need to do anything (other than keep
+this file in the same directory as fparser.cc).
+
+  Part of this file is generated code (by using the make_function_name_parser
+utility, found in the development version of this library). It's not intended
+to be modified by hand.
+*/
+
+        unsigned nameLength = 0;
+        const unsigned maximumNameLength = 0x80000000U-8;
+        /*
+        Due to the manner the identifier lengths are returned from
+        the readOpcode() function, the maximum supported length for
+        identifiers is 0x7FFFFFFF bytes. We minus 8 here to add some
+        buffer, because of the multibyteness of UTF-8.
+        Function names are limited to 0xFFFF bytes instead, but because
+        function names that long just are not defined, the point is moot.
+        */
+        const unsigned char* const uptr = (const unsigned char*) input;
+        typedef signed char schar;
+        while(likely(nameLength < maximumNameLength))
+        {
+            unsigned char byte = uptr[nameLength+0];
+            /* Handle the common case of A-Za-z first */
+            if(byte >= 0x40)
+            {
+                if(byte < 0x80) // 0x40..0x7F - most common case
+                {
+                    // Valid characters in 40..7F: A-Za-z_
+                    // Valid bitmask for 40..5F: 01111111111111111111111111100001
+                    // Valid bitmask for 60..7F: 01111111111111111111111111100000
+                    if(sizeof(unsigned long) == 8)
+                    {
+                        const unsigned n = sizeof(unsigned long)*8-32;
+                        // ^ avoids compiler warning when not 64-bit
+                        unsigned long masklow6bits = 1UL << (byte & 0x3F);
+                        if(masklow6bits & ~((1UL << 0) | (0x0FUL << (0x1B  ))
+                                          | (1UL << n) | (0x1FUL << (0x1B+n))))
+                            { ++nameLength; continue; }
+                    }
+                    else
+                    {
+                        unsigned masklow5bits = 1 << (byte & 0x1F);
+                        if((masklow5bits & ~(1 | (0x1F << 0x1B))) || byte == '_')
+                            { ++nameLength; continue; }
+                    }
+                    break;
+                }
+                if(byte < 0xF0)
+                {
+                    if(byte < 0xE0)
+                    {
+                        if(byte < 0xC2) break; // 0x80..0xC1
+                        if(byte == 0xC2 && uptr[nameLength+1]==0xA0) break; // skip nbsp
+                        // C2-DF - next common case when >= 0x40
+                        // Valid sequence: C2-DF 80-BF
+                        if(schar(uptr[nameLength+1]) > schar(0xBF)) break;
+                        nameLength += 2;
+                        continue;
+                    }
+                    if(byte == 0xE0) // E0
+                    {
+                        // Valid sequence: E0 A0-BF 80-BF
+                        if((unsigned char)(uptr[nameLength+1] - 0xA0) > (0xBF-0xA0)) break;
+                    }
+                    else
+                    {
+                        if(byte == 0xED) break; // ED is invalid
+                        // Valid sequence: E1-EC 80-BF 80-BF
+                        //            And: EE-EF 80-BF 80-BF
+                        if(byte == 0xE2)
+                        {
+                            // break on various space characters
+                            if(uptr[nameLength+1] == 0x80
+                            && (schar(uptr[nameLength+2]) <= schar(0x8B)
+                            || (uptr[nameLength+2] == 0xAF))) break;
+                            if(uptr[nameLength+1] == 0x81
+                            && uptr[nameLength+2] == 0x9F) break;
+                        } else
+                        if(byte == 0xE3 && uptr[nameLength+1] == 0x80
+                        && uptr[nameLength+2] == 0x80) break; // this too
+
+                        if(schar(uptr[nameLength+1]) > schar(0xBF)) break;
+                    }
+                    if(schar(uptr[nameLength+2]) > schar(0xBF)) break;
+                    nameLength += 3;
+                    continue;
+                }
+                if(byte == 0xF0) // F0
+                {
+                    // Valid sequence: F0 90-BF 80-BF 80-BF
+                    if((unsigned char)(uptr[nameLength+1] - 0x90) > (0xBF-0x90)) break;
+                }
+                else
+                {
+                    if(byte > 0xF4) break; // F5-FF are invalid
+                    if(byte == 0xF4) // F4
+                    {
+                        // Valid sequence: F4 80-8F
+                        if(schar(uptr[nameLength+1]) > schar(0x8F)) break;
+                    }
+                    else
+                    {
+                        // F1-F3
+                        // Valid sequence: F1-F3 80-BF 80-BF 80-BF
+                        if(schar(uptr[nameLength+1]) > schar(0xBF)) break;
+                    }
+                }
+                if(schar(uptr[nameLength+2]) > schar(0xBF)) break;
+                if(schar(uptr[nameLength+3]) > schar(0xBF)) break;
+                nameLength += 4;
+                continue;
+            }
+            if(nameLength > 0)
+            {
+                if(sizeof(unsigned long) == 8)
+                {
+                    // Valid bitmask for 00..1F: 00000000000000000000000000000000
+                    // Valid bitmask for 20..3F: 00000000000000001111111111000000
+                    const unsigned n = sizeof(unsigned long)*8-32;
+                    // ^ avoids compiler warning when not 64-bit
+                    unsigned long masklow6bits = 1UL << byte;
+                    if(masklow6bits & (((1UL << 10)-1UL) << (16+n)))
+                        { ++nameLength; continue; }
+                }
+                else
+                {
+                    if(byte >= '0' && byte <= '9')
+                        { ++nameLength; continue; }
+                }
+            }
+            break;
+        }
+
+        /* This function generated with make_function_name_parser.cc */
+#define lN l7 lB
+#define lM l2 lB
+#define lL l3 lB
+#define lK if('i'l4
+#define lJ uptr
+#define lI l5 3]={
+#define lH 'n'l4
+#define lG l6 3;}lB
+#define lF return
+#define lE 0x80000003U:3;
+#define lD 0x80000005U:5;
+#define lC std::memcmp(lJ+
+#define lB case
+#define lA switch(
+#define l9 <<16)|
+#define l8 lC 1,tmp,
+#define l7 lD lF 5;}
+#define l6 default:lF
+#define l5 static const char tmp[
+#define l4 ==lJ[
+#define l3 lE lF 3;
+#define l2 0x80000004U:4;lF 4;
+#define l1 .enabled()?(
+#define l0 lF Functions[
+lA
+nameLength){lB
+2:lK
+0]&&'f'l4
+1])l0
+cIf]l1
+cIf
+l9
+0x80000002U:2;lF
+2;lB
+3:lA
+lJ[0]){lB'a':if('b'l4
+1]&&'s'l4
+2])l0
+cAbs]l1
+cAbs
+l9
+lL'c':lA
+lJ[1]){lB'o':lA
+lJ[2]){lB's':l0
+cCos]l1
+cCos
+l9
+lE
+lB't':l0
+cCot]l1
+cCot
+l9
+lE
+lG's':if('c'l4
+2])l0
+cCsc]l1
+cCsc
+l9
+l3
+lG'e':if('x'l4
+1]&&'p'l4
+2])l0
+cExp]l1
+cExp
+l9
+lL'i':if(lH
+1]&&'t'l4
+2])l0
+cInt]l1
+cInt
+l9
+lL'l':if('o'l4
+1]&&'g'l4
+2])l0
+cLog]l1
+cLog
+l9
+lL'm':lA
+lJ[1]){lB'a':if('x'l4
+2])l0
+cMax]l1
+cMax
+l9
+lL'i':if(lH
+2])l0
+cMin]l1
+cMin
+l9
+l3
+lG'p':if('o'l4
+1]&&'w'l4
+2])l0
+cPow]l1
+cPow
+l9
+lL's':lA
+lJ[1]){lB'e':if('c'l4
+2])l0
+cSec]l1
+cSec
+l9
+lL'i':if(lH
+2])l0
+cSin]l1
+cSin
+l9
+l3
+lG't':if('a'l4
+1]&&lH
+2])l0
+cTan]l1
+cTan
+l9
+l3
+lG
+4:lA
+lJ[0]){lB'a':lA
+lJ[1]){lB'c':if('o'l4
+2]&&'s'l4
+3])l0
+cAcos]l1
+cAcos
+l9
+lM's':lK
+2]&&lH
+3])l0
+cAsin]l1
+cAsin
+l9
+lM't':if('a'l4
+2]&&lH
+3])l0
+cAtan]l1
+cAtan
+l9
+l2
+l6
+4;}
+lB'c':lA
+lJ[1]){lB'b':if('r'l4
+2]&&'t'l4
+3])l0
+cCbrt]l1
+cCbrt
+l9
+lM'e':lK
+2]&&'l'l4
+3])l0
+cCeil]l1
+cCeil
+l9
+lM'o':if('s'l4
+2]&&'h'l4
+3])l0
+cCosh]l1
+cCosh
+l9
+l2
+l6
+4;}
+lB'e':lA
+lJ[1]){lB'v':if('a'l4
+2]&&'l'l4
+3])l0
+cEval]l1
+cEval
+l9
+lM'x':if('p'l4
+2]&&'2'l4
+3])l0
+cExp2]l1
+cExp2
+l9
+l2
+l6
+4;}
+lB'l':{lI'o','g','2'}
+;if(l8
+3)==0)l0
+cLog2]l1
+cLog2
+l9
+l2}
+lB's':lA
+lJ[1]){lB'i':if(lH
+2]&&'h'l4
+3])l0
+cSinh]l1
+cSinh
+l9
+lM'q':if('r'l4
+2]&&'t'l4
+3])l0
+cSqrt]l1
+cSqrt
+l9
+l2
+l6
+4;}
+lB't':{lI'a','n','h'}
+;if(l8
+3)==0)l0
+cTanh]l1
+cTanh
+l9
+l2}
+l6
+4;}
+lB
+5:lA
+lJ[0]){lB'a':lA
+lJ[1]){lB'c':{lI'o','s','h'}
+;if(lC
+2,tmp,3)==0)l0
+cAcosh]l1
+cAcosh
+l9
+lN's':{lI'i','n','h'}
+;if(lC
+2,tmp,3)==0)l0
+cAsinh]l1
+cAsinh
+l9
+lN't':if('a'l4
+2]){if(lH
+3]){lA
+lJ[4]){lB'2':l0
+cAtan2]l1
+cAtan2
+l9
+lD
+lB'h':l0
+cAtanh]l1
+cAtanh
+l9
+lD
+l6
+5;}
+}
+lF
+5;}
+lF
+5;l6
+5;}
+lB'f':{l5
+4]={'l','o','o','r'}
+;if(l8
+4)==0)l0
+cFloor]l1
+cFloor
+l9
+lN'h':{l5
+4]={'y','p','o','t'}
+;if(l8
+4)==0)l0
+cHypot]l1
+cHypot
+l9
+lN'l':{l5
+4]={'o','g','1','0'}
+;if(l8
+4)==0)l0
+cLog10]l1
+cLog10
+l9
+lN't':{l5
+4]={'r','u','n','c'}
+;if(l8
+4)==0)l0
+cTrunc]l1
+cTrunc
+l9
+l7
+l6
+5;}
+default:break;}
+lF
+nameLength;
\ No newline at end of file
diff --git a/fparser/fp_opcode_add.inc b/fparser/fp_opcode_add.inc
new file mode 100644 (file)
index 0000000..5b4b03d
--- /dev/null
@@ -0,0 +1,4214 @@
+/* Function Parser for C++ v4.3     
+
+  NOTE:
+  Do not include this file in your project. The fparser.cc file #includes
+this file internally and thus you don't need to do anything (other than keep
+this file in the same directory as fparser.cc).
+
+  This file contains generated code and is thus not intended to be to
+be modified by hand. It was generated by util/bytecoderules_parser, which
+is available in the development package.
+*/
+#define FP_TRACE_BYTECODE_OPTIMIZATION(srcline,from,to,with) \
+    /*std::cout << "Changing \"" from "\"\t(line " #srcline ")\n" \
+                   "    into \"" to "\"\n" with << std::flush*/
+#define FP_TRACE_OPCODENAME(op) \
+    (op < VarBegin \
+        ? FP_GetOpcodeName(OPCODE(op)) \
+        : findName(data->namePtrs,op,NameData<Value_t>::VARIABLE))
+#define FP_TRACE_BYTECODE_ADD(opcode) \
+    /*std::cout << "Adding opcode: " << FP_TRACE_OPCODENAME(opcode) \
+                << ", bytecode length " << data->ByteCode.size() \
+                << ", pointer is " << (void*)ByteCodePtr \
+                << ", code is " << (data->ByteCode.empty() \
+                                       ? (void*)0 \
+                                       : (void*)&data->ByteCode[0]) \
+                << std::endl*/
+#define q91 wR","aD
+#define q81 w5 wL aY
+#define q71 w5"x"wE
+#define q61 <<", C "oY
+#define q51 q21 aD
+#define q41 q21 wS q21 aF
+#define q31 wR","w9
+#define q21 <<","
+#define q11 wR","aF
+#define q01 "B[B>=VarBegin] "
+#define mZ "= "<<
+#define mY (y dF
+#define mX g0 3]
+#define mW wY" "
+#define mV );g6
+#define mU gU Lqc
+#define mT g8=q7;
+#define mS gU Lnn;
+#define mR x hI oW
+#define mQ cInv:oW
+#define mP "cTan "
+#define mO "cSec "
+#define mN "cCeil"
+#define mM "cDup"
+#define mL oH oW
+#define mK gN oW
+#define mJ "[-x] "
+#define mI "y"wB
+#define mH "y "
+#define mG (x mV
+#define mF ){oW
+#define mE dM>qY oW
+#define mD mT qG d1 g1
+#define mC qF hK:oW
+#define mB "cFloor"
+#define mA "cExp"
+#define m9 hH qC oW
+#define m8 wG wB w2
+#define m7 h1==gF){
+#define m6 wQ"cSub"
+#define m5 wX wB wG
+#define m4 "cSqrt"
+#define m3 "cLess"
+#define m2 wT" "
+#define m1 aX m4
+#define m0 "cMin"
+#define aZ "cMax"
+#define aY "cDiv"
+#define aX wG" "
+#define aW a9" "
+#define aV mA" "
+#define aU "[y*x]"
+#define aT "cPow"
+#define aS "cLog"
+#define aR "cGreater"
+#define aQ "A "wY wE
+#define aP "cCosh"
+#define aO "A[A>=VarBegin]"
+#define aN aO wE
+#define aM aO" "
+#define aL " "wJ"cInv"
+#define aK "cAbsNot"
+#define aJ " cNot"
+#define aI oK B==A mF
+#define aH "cLessOrEq"
+#define aG "cAbs"
+#define aF " "w0
+#define aE "    "wM
+#define aD " "wQ oY
+#define aC "[ y+x] "
+#define aB "cRDiv"wB w2
+#define aA " "aT
+#define a9 "cNeg"
+#define a8 =g8 oK qX oW
+#define a7 =g8 oK gK oW
+#define a6 q8 g1
+#define a5 "[-x]"w5
+#define a4 "cLog10"
+#define a3 "cNotNot"
+#define a2 "cLog2"
+#define a1 "cExp2"
+#define a0 "cGreaterOrEq"
+#define wZ "cEqual"
+#define wY "[x]"
+#define wX "cRSub"
+#define wW ==gF){h1 qC oW
+#define wV oC a8
+#define wU w5 aO
+#define wT "cSqr"
+#define wS wB mZ x
+#define wR " "oX
+#define wQ "B "
+#define wP aM aY
+#define wO "B[B==A] "
+#define wN "cNEqual"
+#define wM "with"w9
+#define wL "x[x!=Value_t(0)] "
+#define wK "B[B>=VarBegin] cSub"wB wG
+#define wJ mM" "
+#define wI "x[isInteger(x)]"aA
+#define wH "x[x>Value_t(0)]"
+#define wG "cAdd"
+#define wF wB"A[IsComparisonOpcode(A)]"
+#define wE " "w2
+#define wD "B[IsNeverNegativeValueOpcode(B)] "
+#define wC "x[x==Value_t(1)] "
+#define wB " x "
+#define wA <<"\n"
+#define w9 " A "oY
+#define w8 "B[IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "oZ
+#define w7 "A[IsNeverNegativeValueOpcode(A)] "
+#define w6 wR"\n"
+#define w5 wE" "
+#define w4 "A[A>=VarBegin&&mData->mByteCode.size()>2] "
+#define w3 "x[x==Value_t(0)] "
+#define w2 "cMul"
+#define w1 FP_TRACE_BYTECODE_ADD
+#define w0 mH mZ y wA
+#define oZ "A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "w3 w2
+#define oY mZ FP_TRACE_OPCODENAME
+#define oX "   with"wS<<
+#define oW FP_TRACE_BYTECODE_OPTIMIZATION
+#define oV cLog10
+#define oU cTanh:
+#define oT cSinh:
+#define oS cAbs){
+#define oR *x;qS
+#define oQ qH y*x
+#define oP qH x);
+#define oO qF gC
+#define oN oM gJ
+#define oM q5 Ldl;
+#define oL incStackPtr();g4
+#define oK ;if(
+#define oJ gE oK
+#define oI qO if(
+#define oH hH qO
+#define oG qB oH
+#define oF B h3){
+#define oE =q0 gQ
+#define oD oC oE
+#define oC g7 A
+#define oB tmp-->
+#define oA qD-1)&&x
+#define o9 qD 1)
+#define o8 qQ d1 g1
+#define o7 qH qD
+#define o6 hV gH
+#define o5 Lcf;
+#define o4 qA h4
+#define o3 2;qJ
+#define o2 cPow
+#define o1 cTan
+#define o0 Lap;
+#define dZ fp_pow(
+#define dY hB qS 3
+#define dX cGreater
+#define dW qN 3]qO
+#define dV cRDiv:
+#define dU qR A);
+#define dT cNEqual
+#define dS cLess:
+#define dR cEqual
+#define dQ gX 1)){
+#define dP h1 hM
+#define dO .size()
+#define dN cRSub
+#define dM if(x
+#define dL Default6
+#define dK Default5
+#define dJ Default2
+#define dI Default1
+#define dH mImmed
+#define dG fp_log(
+#define dF dD Lba;
+#define dE cGreaterOrEq
+#define dD ,x gU
+#define dC cExp2
+#define dB cNotNot
+#define dA fp_log10(
+#define d9 cAbs);
+#define d8 fp_abs(x)
+#define d7 gZ]qC
+#define d6 [0]=cDup;
+#define d5 qL cAdd);
+#define d4 cLessOrEq
+#define d3 qU 2){
+#define d2 cAbs:
+#define d1 gF);
+#define d0 fp_log2(
+#define hZ q7:gI
+#define hY h7 hZ
+#define hX cSinCos
+#define hW 0.5)){
+#define hV }if(
+#define hU 4 qR d1
+#define hT Default4;h7
+#define hS pop_back();
+#define hR mData->
+#define hQ switch(
+#define hP Value_t
+#define hO gZ gS
+#define hN qI q7 gU
+#define hM ==cDup){
+#define hL 3]hM
+#define hK cSqr
+#define hJ hV x==
+#define hI ==o9){
+#define hH qN 1]
+#define hG g5 y+x;qS
+#define hF TailCall_cTan
+#define hE TailCall_cSub
+#define hD TailCall_cNeg
+#define hC unsigned
+#define hB q9 2;oB 0;)
+#define hA q9 o3 q0-=2;
+#define h9 hO hI
+#define h8 dD o0
+#define h7 case
+#define h6 ,y gU Lba;
+#define h5 cAdd:
+#define h4 cDup:
+#define h3 >=VarBegin
+#define h2 isEvenInteger(
+#define h1 qN 2]
+#define h0 =q0[0]oK
+#define gZ if(q0[0
+#define gY oC h0
+#define gX hJ qD
+#define gW fp_const_deg_to_rad<hP>()){
+#define gV fp_const_rad_to_deg<hP>()){
+#define gU );q5
+#define gT ,y gU o0
+#define gS ]qC dM
+#define gR h7 gF:qN 1 gS>qY
+#define gQ [0];qV
+#define gP gO oF
+#define gO B=oJ
+#define gN gO B==A){
+#define gM gQ){qP h4 gN
+#define gL DegreesToRadians(x);
+#define gK IsLogicalOpcode(A)){
+#define gJ }break;
+#define gI y=q2[-1];
+#define gH IsUnaryOpcode(
+#define gG IsAlwaysIntegerOpcode(A)){
+#define gF cMul
+#define gE g0 2]
+#define gD hQ gE){h7
+#define gC cNeg:
+#define gB q2[0]=
+#define gA gB-x;
+#define g9 IsNeverNegativeValueOpcode(B)){
+#define g8 g0 1]
+#define g7 default:
+#define g6 return;
+#define g5 q2[-1]=
+#define g4 --mStackPtr;q5
+#define g3 &&!HasInvalidRangesOpcode(
+#define g2 hR mByteCode
+#define g1 opcode=
+#define g0 q0[-
+#define qZ FP_ReDefinePointers();
+#define qY qD 0)){
+#define qX IsNeverNegativeValueOpcode(A)){
+#define qW g2 q6 q5
+#define qV if(A h3
+#define qU &&g2 dO>
+#define qT hR dH q6
+#define qS qT q9
+#define qR ;oB q3 q1
+#define qQ q9 2 qR
+#define qP hQ g8){h7
+#define qO ==q7){gI
+#define qN if(g0
+#define qM if(!q0){q4
+#define qL AddFunctionOpcode(
+#define qK q5 Default0;
+#define qJ oB q3 hS
+#define qI g2.push_back(
+#define qH hR dH.push_back(
+#define qG g2.q1
+#define qF gJ h7
+#define qE }}qK
+#define qD hP(
+#define qC ==q7){x=q2[0];
+#define qB h7 q7:x=q2[0];
+#define qA hQ q0[0]){h7
+#define q9 for(hC tmp=
+#define q8 g2 q6 q0-=1;
+#define q7 cImmed
+#define q6 .hS
+#define q5 goto
+#define q4 q5 Laa;}h7
+#define q3 0;)g2.
+#define q2 ImmedPtr
+#define q1 hS qL
+#define q0 ByteCodePtr
+hC*q0;hP*q2;
+#define FP_ReDefinePointers() q0=!g2.empty()?&g2[0]+g2 dO-1:0;q2=!hR dH.empty()?&hR dH[0]+hR dH dO-1:0;
+qZ
+w1(opcode);
+#if(!FP_FLOAT_VERSION)
+hP
+x;hC
+A;hP
+y;hC
+B;hC
+C;hC
+D;hQ
+opcode){TailCall_cAbs:qM
+d2
+qA
+gC
+oW(246,aW
+aG,aG,);q5
+Lab;qB
+oW(48,"x "
+aG,"[fp_abs(x)]"
+,w6);q5
+Lac;gY
+qX
+oW(307,w7
+aG,"A"
+,aE(A)wA);g6
+qE
+TailCall_cAdd:qM
+h5
+o4
+qP
+h5
+dP
+oW(194,wJ
+aX
+wJ
+wG,"[Value_t(4)]"
+wE,);q5
+Lad;qF
+gF:h1==cAdd){qN
+hL
+oW(195,wJ
+wG
+w5
+wJ
+wG,w2" [Value_t(4)]"
+wE,);q5
+Lae;}
+gJ}
+q5
+dI;h7
+gF:hH
+qC
+dP
+oW(197,wJ"x"
+w5
+wG,"[x+Value_t(1)]"
+wE,w6);q5
+Laf;}
+}
+q5
+dI;h7
+gC
+oW(253,aW
+wG,"cSub"
+,);q5
+Lag;qB
+qP
+h5
+h1
+qO
+oW(187,mH
+wG
+wB
+wG,"[y+x] "
+wG,q11);q5
+Lah;qF
+dN:gD
+h5
+dW
+oW(129,mH
+aX
+m5,aC
+aX
+wX,q11);q5
+Lai;oO
+oW(130,aW
+m5,mJ
+aX
+wX,w6);q5
+Laj;hY
+oW(128,mH
+m5,aC
+wX,q11);q5
+Lak;qF
+cSub:gP
+hQ
+mX){h7
+h5
+qN
+4]qO
+oW(123,mH
+aX
+wK,aC
+aX
+m6,q91(B)q21
+aF);q5
+Lal;oO
+oW(124,aW
+wK,mJ
+aX
+m6,q91(B)wA);q5
+Lam;hY
+oW(122,mH
+wK,aC
+m6,q91(B)q21
+aF);q5
+Lan;}
+qF
+hZ
+oW(84,mI
+wG,"[y+x]"
+,q11);q5
+Lao;hJ
+qY
+oW(83,w3
+wG,,w6);q5
+o0
+gJ
+g7
+dI:;A
+oE){hH==dN){h1
+qC
+oW(121,"x "
+wX" "
+aM
+wG,"[DO_STACKPLUS1] A "
+mW
+aX
+wX,aE(A)q21
+wS
+wA);oL
+Laq;}
+oW(126,wX" "
+aM
+wG,"[DO_STACKPLUS1] A "
+aX
+wX,aE(A)wA);oL
+Lba;}
+qE
+TailCall_cAnd:qM
+cAnd:o4
+oW(426,wJ"cAnd"
+,a3,);q5
+Lbb;oG
+oW(177,mI"cAnd"
+,"[fp_and(x,y)]"
+,q11);q5
+Lbc;gJ}
+qK
+TailCall_cCos:qM
+cCos:A
+oE
+d3
+qP
+cSec:mK(434,wO
+mO
+w4"cCos"
+,wQ"cSec"
+aL,aE(A)q51(B)wA);q5
+Lbd;qF
+cSin:mK(428,wO"cSin "
+w4"cCos"
+,wQ"cSinCos"
+,aE(A)q51(B)wA);q5
+Lbe;gJ
+qE
+TailCall_cCot:qM
+cCot:A
+oE
+d3
+hH==o1){mK(432,wO
+mP
+w4"cCot"
+,wQ"cTan"
+aL,aE(A)q51(B)wA);q5
+Lbd;}
+qE
+TailCall_cCsc:qM
+cCsc:A
+oE
+d3
+hH==cSin){mK(430,wO"cSin "
+w4"cCsc"
+,wQ"cSin"
+aL,aE(A)q51(B)wA);q5
+Lbd;}
+qE
+TailCall_cDiv:qM
+cDiv:o4
+oW(167,wJ
+aY,"[Value_t(0)]"
+w5"[Value_t(1)] "
+wG,);q5
+Lbf;h7
+hX:oW(436,"cSinCos "
+aY,"cTan"
+,);q5
+Lbg;qB
+dM!=qY
+qP
+gC
+oW(185,aW
+wL
+aY,mJ
+aY,w6);q5
+Lbh;hY
+oW(81,mH
+wL
+aY,"[y/x]"
+,q11);q5
+Lbi;}
+dQ
+oW(80,wC
+aY,,w6);q5
+o0
+gJ}
+qK
+TailCall_cEqual:qM
+dR:h9
+A
+a7(335,"A[IsLogicalOpcode(A)] "
+wC
+wZ,"A"
+,q31(A)wA);q5
+o0}
+}
+mL(175,mI
+wZ,"[fp_equal(y,x)]"
+,q11);q5
+Lbj;hJ
+qY
+qP
+d2
+oW(265,aG" "
+w3
+wZ,mW
+wZ,w6);q5
+Lbk;h7
+hK:oW(267,m2
+w3
+wZ,mW
+wZ,w6);q5
+Lbk;}
+oW(325,w3
+wZ,"cNot"
+,w6);q5
+Lbl;qE
+TailCall_cGreater:qM
+dX:hO==qY
+qP
+d2
+oW(327,aG" "
+w3
+aR,a3,w6);q5
+Lbm;wV(331,w7
+w3
+aR,"A "
+a3,q31(A)wA);q5
+Lbn;}
+}
+}
+mL(173,mI
+aR,"[fp_less(x,y)]"
+,q11);q5
+Lbo;qE
+TailCall_cGreaterOrEq:qM
+dE:h9
+qP
+d2
+oW(328,aG" "
+wC
+a0,a3,w6);q5
+Lbm;wV(332,w7
+wC
+a0,"A "
+a3,q31(A)wA);q5
+Lbn;}
+}
+}
+mL(174,mI
+a0,"[fp_lessOrEq(x,y)]"
+,q11);q5
+Lbp;qE
+TailCall_cInv:qM
+cInv:qA
+cSqrt:oW(75,m4" cInv"
+,"cRSqrt"
+,);q5
+Lbq;qB
+dM!=qY
+oW(77,wL"cInv"
+,"[Value_t(1)/x]"
+,w6);q5
+Lca;gJ}
+qK
+TailCall_cLess:qM
+dS
+hO==qY
+A
+a8(132,w7
+w3
+m3,aQ,q31(A)wA);q5
+Lcb;}
+dQ
+qP
+d2
+oW(329,aG" "
+wC
+m3,"cNot"
+,w6);q5
+Lcc;wV(333,w7
+wC
+m3,"A"
+aJ,q31(A)wA);q5
+Lbl;}
+}
+}
+mL(171,mI
+m3,"[fp_less(y,x)]"
+,q11);q5
+Lcd;qE
+TailCall_cLessOrEq:qM
+d4:hO==qY
+qP
+d2
+oW(330,aG" "
+w3
+aH,"cNot"
+,w6);q5
+Lcc;wV(334,w7
+w3
+aH,"A"
+aJ,q31(A)wA);q5
+Lbl;}
+}
+}
+mL(172,mI
+aH,"[fp_lessOrEq(y,x)]"
+,q11);q5
+Lce;qE
+TailCall_cMax:qM
+cMax:o4
+oW(157,wJ
+aZ,,);q5
+o5
+oG
+oW(90,mI
+aZ,"[fp_max(x,y)]"
+,q11);q5
+Lcg;gJ
+oC=q0
+gM
+oW(159,wO
+wJ
+aM
+aZ,wQ
+mM,aE(A)q51(B)wA);q5
+o5
+qF
+cMax:mK(161,wO
+aZ" "
+aM
+aZ,wQ
+aZ,aE(A)q51(B)wA);q5
+o5
+gJ}
+qE
+TailCall_cMin:qM
+cMin:o4
+oW(156,wJ
+m0,,);q5
+o5
+oG
+oW(89,mI
+m0,"[fp_min(x,y)]"
+,q11);q5
+Lch;gJ
+oC=q0
+gM
+oW(158,wO
+wJ
+aM
+m0,wQ
+mM,aE(A)q51(B)wA);q5
+o5
+qF
+cMin:mK(160,wO
+m0" "
+aM
+m0,wQ
+m0,aE(A)q51(B)wA);q5
+o5
+gJ}
+qE
+TailCall_cMod:qM
+cMod:hO!=qY
+mL(82,mH
+wL"cMod"
+,"[fp_mod(y,x)]"
+,q11);q5
+Lci;}
+qE
+TailCall_cMul:qM
+gF:o4
+oW(402,mM
+wE,wT,);q5
+Lcj;h7
+gC
+qP
+h4
+oW(394,wJ
+a9
+wE,m2
+a9,);q5
+Lck;oC=g8;qV){m7
+B=mX
+aI(400,"B[B==A]"
+wU" "
+a9
+wE,wQ
+wT
+w5
+a9,aE(A)q51(B)wA);q5
+Lcl;}
+}
+}
+}
+q5
+dJ;h7
+o2:hH
+qC
+dP
+oW(198,mM
+wB
+aT
+wE,"[x+Value_t(1)]"
+aA,w6);q5
+Lcm;}
+}
+q5
+dJ;qB
+dM==qY
+qP
+gF:A=gE;qV
+mF(141,aO
+w5
+w3
+w2,wY
+wE,q31(A)wA);q5
+Lcn;}
+q5
+Default3;g7
+Default3:;A=g8
+oK
+IsBinaryOpcode(A)g3
+A)){gD
+hZ
+oW(140,mH
+oZ,wY
+wE,q31(A)q21
+aF);q5
+Lco;g7
+gO
+IsBinaryOpcode(B)g3
+B)){hQ
+mX){hY
+oW(144,mH
+w8,aQ,q31(A)q51(B)q21
+aF);q5
+Lcp;g7
+C=mX
+oK
+C
+h3
+mF(142,"C[C>=VarBegin] "
+w8,aQ,q31(A)q51(B)q61(C)wA);q5
+Lcq;o6
+C)g3
+C)mF(143,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+w8,wQ
+aQ,q31(A)q51(B)q61(C)wA);q5
+Lda;}
+}
+hV
+oF
+oW(138,q01
+oZ,wY
+wE,q31(A)q51(B)wA);q5
+Lcn;o6
+B)g3
+B)mF(139,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+oZ,aQ,q31(A)q51(B)wA);q5
+Ldb;}
+}
+}
+qV
+mF(136,aM
+w3
+w2,wY,q31(A)wA);q5
+Ldc;o6
+A)g3
+A)mF(137,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+w3
+w2,wY
+wE,q31(A)wA);q5
+Ldd;}
+}
+}
+qP
+h5
+gD
+h4
+oW(203,wJ
+m8,"[x+x]"
+wE,w6);q5
+Lde;h7
+gF:dW
+A=g0
+4];qV
+mF(292,aM"y"
+w5
+m8,wY
+w5"A "
+aU
+w5
+wG,wR", "
+mH
+mZ
+y
+q21
+w9(A)wA);q5
+Ldf;}
+qF
+hZ
+oW(291,mH
+m8,wY
+w5
+aU" "
+wG,q11);q5
+Ldg;qF
+gF:gD
+h5
+qN
+hL
+oW(205,wJ
+wG
+q71,w2" [x+x]"
+wE,w6);q5
+Ldh;qF
+hZ
+if(y*mR(192,"y[y*x==Value_t(1)]"
+q71,,q11);q5
+Ldi;}
+oW(193,"y"
+q71,aU
+wE,q11);q5
+Ldj;oO
+oW(182,a9
+wB
+w2,"[-x]"
+wE,w6);q5
+Ldk;h7
+cSub:m7
+dW
+A=g0
+4];qV
+mF(293,aM"y"
+w5"cSub"
+wB
+w2,wY
+w5"A "
+aU
+w5"cSub"
+,wR", "
+mH
+mZ
+y
+q21
+w9(A)wA);oM}
+}
+qF
+hZ
+oW(79,mI
+w2,aU,q11);q5
+Ldm;dQ
+oW(78,wC
+w2,,w6);q5
+o0
+gX
+2)mF(146,"x[x==Value_t(2)]"
+wE,wJ
+wG,w6);q5
+Ldn;gX-1)mF(184,"x[x==Value_t(-1)]"
+wE,a9,w6);q5
+Ldo;gJ
+g7
+dJ:;A
+oE){qP
+gF:gD
+gC
+B=mX
+aI(397,wO
+a9
+wU
+wE,wQ
+wT
+w5
+a9,aE(A)q51(B)wA);q5
+Lcl;}
+q5
+Default4;g7
+Default4:;mK(388,"B[B==A]"
+wU
+wE,wQ
+wT
+wE,aE(A)q51(B)wA);q5
+Ldp;}
+}
+q5
+dK;h7
+gC
+mK(391,wO
+aW
+aN,wQ
+m2
+a9,aE(A)q51(B)wA);q5
+Lck;}
+q5
+dK;g7
+dK:;B=g8
+aI(385,wO
+aN,wQ
+wT,aE(A)q51(B)wA);q5
+Lcj;}
+}
+o6
+A)){B=g8
+oK
+B
+h3
+qU
+1){m7
+C=mX
+oK
+C==A){D=g0
+4]oK
+D==B
+mF(408,"D[D==B] C[C==A]"
+w5"B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wE,"D C "
+wT
+wE,aE(A)q51(B)q61(C)<<", D "
+oY(D)wA);q5
+Ldq;}
+}
+}
+}
+qE
+TailCall_cNEqual:qM
+dT:h9
+A
+a7(336,"A[IsLogicalOpcode(A)] "
+wC
+wN,"A"
+aJ,q31(A)wA);q5
+Lbl;}
+}
+mL(176,mI
+wN,"[fp_nequal(y,x)]"
+,q11);q5
+Lea;hJ
+qY
+qP
+d2
+oW(266,aG" "
+w3
+wN,mW
+wN,w6);q5
+Leb;h7
+hK:oW(268,m2
+w3
+wN,mW
+wN,w6);q5
+Leb;}
+oW(326,w3
+wN,a3,w6);q5
+Lbn;qE
+hD:qM
+gC
+qA
+gF:m9(183,"x"
+w5
+a9,"[-x]"
+wE,w6);q5
+Lec;oO
+oW(248,aW
+a9,,);q5
+o5
+qB
+oW(76,"x "
+a9,"[-x]"
+,w6);q5
+Led;}
+qK
+TailCall_cNot:qM
+cNot:qA
+d2
+oW(296,aG
+aJ,"cNot"
+,);q5
+Lee;h7
+cAbsNot:A
+a7(303,"A[IsLogicalOpcode(A)] "
+aK
+aJ,"A"
+,aE(A)wA);q5
+o5
+hV
+A!=q7
+mF(304,"A[A!=cImmed] "
+aK
+aJ,"A cAbsNotNot"
+,aE(A)wA);q5
+Lef;}
+q5
+dL;h7
+cAbsNotNot:oW(299,"cAbsNotNot"
+aJ,aK,);q5
+Leg;h7
+h5
+m9(338,"x "
+wG
+aJ,mJ
+wZ,w6);q5
+Leh;}
+q5
+dL;h7
+dR:oW(262,wZ
+aJ,wN,);q5
+Lei;h7
+dX:oW(260,aR
+aJ,aH,);q5
+Lej;h7
+dE:oW(261,a0
+aJ,m3,);q5
+Lek;h7
+dS
+oW(258,m3
+aJ,a0,);q5
+Lel;h7
+d4:oW(259,aH
+aJ,aR,);q5
+Lem;h7
+dT:oW(263,wN
+aJ,wZ,);q5
+Len;h7
+gC
+oW(295,a9
+aJ,"cNot"
+,);q5
+Lee;h7
+cNot:oW(297,"cNot"
+aJ,a3,);q5
+Lbb;h7
+dB:oW(298,a3
+aJ,"cNot"
+,);q5
+Lee;qB
+oW(93,"x"
+aJ,"[fp_not(x)]"
+,w6);q5
+Leo;g7
+dL:;A
+h0
+qX
+oW(305,w7"cNot"
+,"A "
+aK,aE(A)wA);q5
+Lep;qE
+TailCall_cNotNot:qM
+dB:qA
+h5
+m9(337,"x "
+aX
+a3,mJ
+wN,w6);q5
+Leq;qF
+cNot:oW(300,"cNot "
+a3,"cNot"
+,);g6}
+qK
+TailCall_cOr:qM
+cOr:o4
+oW(425,wJ"cOr"
+,a3,);q5
+Lbb;oG
+oW(178,mI"cOr"
+,"[fp_or(x,y)]"
+,q11);q5
+Lfa;gJ}
+qK
+TailCall_cRDiv:qM
+dV
+qA
+hX:oW(437,"cSinCos cRDiv"
+,"cCot"
+,);q5
+Lfb;qB
+dM
+hI
+oW(99,wC"cRDiv"
+,"cInv"
+,w6);q5
+Lfc;gJ}
+qK
+TailCall_cRSub:qM
+dN:gZ]hM
+oW(200,wJ
+wX,"[Value_t(0)]"
+wE,);q5
+Lfd;}
+qK
+TailCall_cSec:qM
+cSec:A
+oE
+d3
+qP
+cCos:mK(431,wO"cCos "
+w4"cSec"
+,wQ"cCos"
+aL,aE(A)q51(B)wA);q5
+Lbd;qF
+cSin:mK(429,wO"cSin "
+w4"cSec"
+,wQ"cSinCos cInv"
+,aE(A)q51(B)wA);q5
+Lfe;gJ
+qE
+TailCall_cSin:qM
+cSin:A
+oE
+d3
+hH==cCsc){mK(433,wO"cCsc "
+w4"cSin"
+,wQ"cCsc"
+aL,aE(A)q51(B)wA);q5
+Lbd;}
+qE
+TailCall_cSqr:qM
+hK:qA
+d2
+oW(404,aG" "
+wT,wT,);q5
+Lff;h7
+gC
+oW(403,aW
+wT,wT,);q5
+Lff;}
+qK
+TailCall_cSqrt:qM
+cSqrt:gZ]==cAdd){hH==hK){A=gE;qV){qN
+3]==hK
+mF(439,m2
+aM
+m2
+m1,"A cHypot"
+,aE(A)wA);q5
+Lfg;}
+}
+gO
+gH
+B)){A=mX;qV){qN
+4]==hK
+mF(440,m2
+aM"B[IsUnaryOpcode(B)] "
+m2
+m1,"A "
+wQ"cHypot"
+,"    with"
+aD(B)q21
+w9(A)wA);q5
+Lfh;}
+}
+}
+qE
+hE:qM
+cSub:o4
+oW(199,wJ"cSub"
+,"[Value_t(0)]"
+wE,);q5
+Lfd;h7
+gC
+oW(254,aW"cSub"
+,wG,);q5
+Lfi;qB
+dM==qY
+oW(85,w3"cSub"
+,,w6);q5
+o0}
+mL(86,mI"cSub"
+,"[y-x]"
+,q11);q5
+Lfj;}
+oW(216,"x cSub"
+,mJ
+wG,w6);q5
+Lfk;oD){hH==dN){h1
+qC
+oW(120,"x "
+wX" "
+aM"cSub"
+,"A "
+aX
+mW
+wX,aE(A)q21
+wS
+wA);q5
+Lfl;}
+oW(127,wX" "
+aM"cSub"
+,"[DO_STACKPLUS1] A cSub "
+wX,aE(A)wA);oL
+Lfm;}
+qE
+hF:qM
+o1:A
+oE
+d3
+hH==cCot){mK(435,wO"cCot "
+w4"cTan"
+,wQ"cCot"
+aL,aE(A)q51(B)wA);q5
+Lbd;}
+qE
+g7
+Default0:;A=opcode
+oK
+IsComparisonOpcode(A)){d7
+qP
+h5
+h1
+qO
+oW(270,mH
+wG
+wF,"[x-y] A"
+,aE(A)q41);q5
+Lfn;oO
+oW(271,a9
+wF,mJ"{OppositeComparisonOpcode(A)}"
+,aE(A)q21
+wS
+wA);q5
+Lfo;}
+}
+}
+qV
+qU
+0){B
+h0
+B==A
+mF(406,wO"A[A>=VarBegin&&mData->mByteCode.size()>0]"
+,wQ
+mM,aE(A)q51(B)wA);q5
+Lfp;}
+o6
+A)){B
+h0
+B
+h3
+qU
+1){C=g8
+oK
+C==A){D=oJ
+D==B
+mF(407,"D[D==B] C[C==A] B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+,"D C "
+mM,aE(A)q51(B)q61(C)<<", D "
+oY(D)wA);q5
+Lfq;}
+}
+}
+}
+}
+q5
+Laa;Laa:qI
+opcode
+mV
+Lab:q8
+w1(cAbs);q5
+TailCall_cAbs;Lac:gB
+d8;g6
+Lad:o7
+4));gE=q7;hA
+Lga:g1
+gF;Lgb:qZ
+Lgc:w1(cMul);q5
+TailCall_cMul;Lae:q9
+hU
+o7
+4));hN
+Lga;Laf:gB
+x+o9;gE=q7;hA
+Lcb:g1
+gF;q5
+Lgc;Lag:a6
+cSub;Lgd:w1(cSub);q5
+hE;Lah:hG
+o3
+Lge:qZ
+Lgf:w1(cAdd);q5
+TailCall_cAdd;Lai:hG
+3;qJ
+Lgg:d5
+Lgh:g1
+dN;qZ
+w1(cRSub);q5
+TailCall_cRSub;Laj:gA
+gE=q7;q9
+o3
+q5
+Lgg;Lak:hG
+o3
+q5
+Lgh;Lal:hG
+4;qJ
+Lgi:d5
+Lgj:qL
+B);Lgk:g1
+cSub;qZ
+q5
+Lgd;Lam:gA
+mX=q7;q9
+3;qJ
+q5
+Lgi;Lan:hG
+3;qJ
+q5
+Lgj;Lao:g5
+y+x;Lap:qT
+Lcf:g2
+q6
+g6
+Laq:qS
+3
+dU
+oP
+hN
+Lgg;Lba:qQ
+A
+gU
+Lgg;Lbb:a6
+dB;Lgl:w1(cNotNot);q5
+TailCall_cNotNot;Lbc:g5
+fp_and(x
+gT
+Lbd:q0
+d6
+g1
+cInv;Lgm:w1(cInv);q5
+TailCall_cInv;Lbe:qQ
+hX
+mV
+Lbf:o7
+0));q0[0]=q7;qL
+d1
+o7
+1));Lgn:qI
+q7);Lgo:g1
+cAdd;q5
+Lge;Lbg:a6
+o1;w1(cTan);q5
+hF;Lbh:gA
+mT
+q8
+w1(cDiv);q5
+TailCall_cDiv;Lbi:g5
+y/x;q5
+o0
+Lbj:g5
+fp_equal(y
+h8
+Lbk:mT
+q8
+Lgp:w1(cEqual);q5
+TailCall_cEqual;Lbl:qT
+g2
+q6
+Lgq:g1
+cNot;qZ
+Lha:w1(cNot);q5
+TailCall_cNot;Lbm:qS
+o3
+Lhb:g1
+dB;qZ
+q5
+Lgl;Lbn:qT
+qW
+Lhb;Lbo:g5
+fp_less(x
+gT
+Lbp:g5
+fp_lessOrEq(x
+gT
+Lbq:qG
+cRSqrt
+mV
+Lca:gB
+o9/x;g6
+Lcc:qS
+o3
+q5
+Lgq;Lcd:g5
+fp_less(y
+h8
+Lce:g5
+fp_lessOrEq(y
+h8
+Lcg:g5
+fp_max(x
+gT
+Lch:g5
+fp_min(x
+gT
+Lci:g5
+fp_mod(y
+h8
+Lcj:a6
+hK;Lhc:w1(cSqr);q5
+TailCall_cSqr;Lck:qQ
+hK);Lhd:g1
+cNeg;qZ
+w1(cNeg);q5
+hD;Lcl:q9
+3
+qR
+hK);qL
+gF
+gU
+Lhd;Lcm:gB
+x+o9;gE=q7;qQ
+o2
+mV
+Lcn:gE=q7;hA
+q5
+Lgc;Lco:g5
+x;Lhe:qS
+o3
+q5
+Lgb;Lcp:hB
+qT
+Lhf:q9
+4;qJ
+Lhg:qL
+A);oP
+Lhh:hN
+Lgb;Lcq:qT
+q5
+Lhf;Lda:qS
+4
+qR
+B
+gU
+Lhg;Ldb:qS
+3;qJ
+q5
+Lhg;Ldc:mT
+q5
+o5
+Ldd:mT
+q8
+q5
+Lgc;Lde:gB
+x+x;q5
+Lcn;Ldf:g5
+x;g0
+4]=q7;qS
+hU
+qL
+A);oQ);qI
+q7);qL
+gF
+gU
+Lgo;Ldg:g5
+x;qT
+qQ
+d1
+oQ
+gU
+Lgn;Ldh:qS
+hU
+qH
+x+x
+gU
+Lhh;Ldi:dY;qJ
+g6
+Ldj:g5
+y*x;q5
+Lhe;Ldk:gA
+q5
+Ldd;Ldl:g5
+x;g0
+4]=q7;qS
+hU
+qL
+A);oQ);qI
+q7);qL
+gF
+gU
+Lgk;Ldm:g5
+y*x;q5
+o0
+Ldn:q0
+d6
+q2-=1;qT
+Lhi:g1
+cAdd;q5
+Lgf;Ldo:qT
+qW
+Lhd;Ldp:q9
+o3
+Lhj:qL
+hK
+gU
+Lgb;Ldq:q9
+3;qJ
+q5
+Lhj;Lea:g5
+fp_nequal(y
+h8
+Leb:mT
+q8
+Lhk:w1(cNEqual);q5
+TailCall_cNEqual;Lec:gA
+q8
+q5
+Lcb;Led:gA
+g6
+Lee:q8
+q5
+Lha;Lef:qG
+cAbsNotNot
+mV
+Leg:g2
+q6
+Lep:qL
+cAbsNot
+mV
+Leh:gA
+Len:a6
+dR;q5
+Lgp;Lei:a6
+dT;q5
+Lhk;Lej:a6
+d4;w1(cLessOrEq);q5
+TailCall_cLessOrEq;Lek:a6
+cLess;w1(cLess);q5
+TailCall_cLess;Lel:a6
+dE;w1(cGreaterOrEq);q5
+TailCall_cGreaterOrEq;Lem:a6
+dX;w1(cGreater);q5
+TailCall_cGreater;Leo:gB
+fp_not
+mG
+Leq:gA
+q5
+Lei;Lfa:g5
+fp_or(x
+gT
+Lfb:a6
+cCot;w1(cCot);q5
+TailCall_cCot;Lfc:qT
+g2
+q6
+Lhl:g1
+cInv;qZ
+q5
+Lgm;Lfd:o7
+0));q0[0]=q7;q5
+Lga;Lfe:qQ
+hX
+gU
+Lhl;Lff:q8
+q5
+Lhc;Lfg:q9
+4
+dU
+Lhm:qL
+cHypot
+mV
+Lfh:q9
+5
+dU
+qL
+B
+gU
+Lhm;Lfi:q8
+q5
+Lhi;Lfj:g5
+y-x;q5
+o0
+Lfk:gA
+q5
+Lhi;Lfl:qS
+3
+dU
+d5
+oP
+hN
+Lgh;Lfm:qQ
+A);qL
+cSub
+gU
+Lgh;Lfn:g5
+x-y;qT
+qQ
+A
+mV
+Lfo:gA
+mT
+qG
+OppositeComparisonOpcode(A)mV
+Lfp:qI
+cDup
+mV
+Lfq:q0
+d6
+g6
+g6
+q5
+TailCall_cAnd;q5
+TailCall_cCos;q5
+TailCall_cCsc;q5
+TailCall_cMax;q5
+TailCall_cMin;q5
+TailCall_cMod;q5
+hD;q5
+TailCall_cOr;q5
+TailCall_cRDiv;q5
+TailCall_cSec;q5
+TailCall_cSin;q5
+TailCall_cSqrt;q5
+hE;q5
+hF;
+#endif
+#if(FP_FLOAT_VERSION)
+hP
+x;hC
+A;hP
+y;hC
+B;hC
+C;hC
+D;hQ
+opcode){TailCall_cAbs:qM
+d2
+qA
+gC
+oW(246,aW
+aG,aG,);q5
+Lab;qB
+oW(48,"x "
+aG,"[fp_abs(x)]"
+,w6);q5
+Lac;gY
+qX
+oW(307,w7
+aG,"A"
+,aE(A)wA);g6
+qE
+TailCall_cAcos:qM
+cAcos:hO>=oA<=o9
+mF(52,"x[x>=Value_t(-1)&&x<=Value_t(1)] cAcos"
+,"[fp_acos(x)]"
+,w6);q5
+Lad;qE
+TailCall_cAcosh:qM
+cAcosh:hO>=o9
+mF(49,"x[x>=Value_t(1)] cAcosh"
+,"[fp_acosh(x)]"
+,w6);q5
+Lae;qE
+TailCall_cAdd:qM
+h5
+o4
+qP
+h5
+dP
+oW(194,wJ
+aX
+wJ
+wG,"[Value_t(4)]"
+wE,);q5
+Laf;qF
+gF:h1==cAdd){qN
+hL
+oW(195,wJ
+wG
+w5
+wJ
+wG,w2" [Value_t(4)]"
+wE,);q5
+Lag;}
+gJ}
+q5
+dI;h7
+gF:hH
+qC
+dP
+oW(197,wJ"x"
+w5
+wG,"[x+Value_t(1)]"
+wE,w6);q5
+Lah;}
+}
+q5
+dI;h7
+gC
+oW(253,aW
+wG,"cSub"
+,);q5
+Lai;qB
+qP
+h5
+h1
+qO
+oW(187,mH
+wG
+wB
+wG,"[y+x] "
+wG,q11);q5
+Laj;qF
+dN:gD
+h5
+dW
+oW(129,mH
+aX
+m5,aC
+aX
+wX,q11);q5
+Lak;oO
+oW(130,aW
+m5,mJ
+aX
+wX,w6);q5
+Lal;hY
+oW(128,mH
+m5,aC
+wX,q11);q5
+Lam;qF
+cSub:gP
+hQ
+mX){h7
+h5
+qN
+4]qO
+oW(123,mH
+aX
+wK,aC
+aX
+m6,q91(B)q21
+aF);q5
+Lan;oO
+oW(124,aW
+wK,mJ
+aX
+m6,q91(B)wA);q5
+Lao;hY
+oW(122,mH
+wK,aC
+m6,q91(B)q21
+aF);q5
+o0}
+qF
+hZ
+oW(84,mI
+wG,"[y+x]"
+,q11);q5
+Laq;hJ
+qY
+oW(83,w3
+wG,,w6);q5
+Lba;gJ
+g7
+dI:;A
+oE){hH==dN){h1
+qC
+oW(121,"x "
+wX" "
+aM
+wG,"[DO_STACKPLUS1] A "
+mW
+aX
+wX,aE(A)q21
+wS
+wA);oL
+Lbb;}
+oW(126,wX" "
+aM
+wG,"[DO_STACKPLUS1] A "
+aX
+wX,aE(A)wA);oL
+Lbc;}
+qE
+TailCall_cAnd:qM
+cAnd:o4
+oW(426,wJ"cAnd"
+,a3,);q5
+Lbd;oG
+oW(177,mI"cAnd"
+,"[fp_and(x,y)]"
+,q11);q5
+Lbe;gJ}
+qK
+TailCall_cAsin:qM
+cAsin:hO>=oA<=o9
+mF(53,"x[x>=Value_t(-1)&&x<=Value_t(1)] cAsin"
+,"[fp_asin(x)]"
+,w6);q5
+Lbf;qE
+TailCall_cAsinh:qM
+cAsinh:d7
+oW(50,"x cAsinh"
+,"[fp_asinh(x)]"
+,w6);q5
+Lbg;}
+qK
+TailCall_cAtan:qM
+cAtan:d7
+oW(54,"x cAtan"
+,"[fp_atan(x)]"
+,w6);q5
+Lbh;}
+qK
+TailCall_cAtan2:qM
+cAtan2:d7
+mL(91,mI"cAtan2"
+,"[fp_atan2(y,x)]"
+,q11);q5
+Lbi;qE
+TailCall_cAtanh:qM
+cAtanh:hO>oA<o9
+mF(51,"x[x>Value_t(-1)&&x<Value_t(1)] cAtanh"
+,"[fp_atanh(x)]"
+,w6);q5
+Lbj;qE
+TailCall_cCbrt:qM
+cCbrt:d7
+oW(55,"x cCbrt"
+,"[fp_cbrt(x)]"
+,w6);q5
+Lbk;}
+qK
+TailCall_cCeil:qM
+cCeil:qA
+gC
+oW(316,aW
+mN,mB" "
+a9,);q5
+Lbl;qB
+oW(56,"x "
+mN,"[fp_ceil(x)]"
+,w6);q5
+Lbm;gY
+gG
+oW(310,"A[IsAlwaysIntegerOpcode(A)] "
+mN,"A"
+,aE(A)wA);g6
+qE
+TailCall_cCos:qM
+cCos:qA
+d2
+oW(351,aG" cCos"
+,"cCos"
+,);q5
+Lbn;h7
+gC
+oW(353,aW"cCos"
+,"cCos"
+,);q5
+Lbn;qB
+oW(57,"x cCos"
+,"[fp_cos(x)]"
+,w6);q5
+Lbo;oD
+d3
+qP
+cSec:mK(434,wO
+mO
+w4"cCos"
+,wQ"cSec"
+aL,aE(A)q51(B)wA);q5
+Lbp;qF
+cSin:mK(428,wO"cSin "
+w4"cCos"
+,wQ"cSinCos"
+,aE(A)q51(B)wA);q5
+Lbq;gJ}
+qE
+TailCall_cCosh:qM
+cCosh:qA
+d2
+oW(352,aG" "
+aP,aP,);q5
+Lca;h7
+cAsinh:oW(365,"cAsinh "
+aP,"[DO_STACKPLUS1] "
+m2"[Value_t(1)] "
+m1,);oL
+Lcb;h7
+gC
+oW(354,aW
+aP,aP,);q5
+Lca;qB
+oW(58,"x "
+aP,"[fp_cosh(x)]"
+,w6);q5
+Lcc;}
+qK
+TailCall_cCot:qM
+cCot:A
+oE
+d3
+hH==o1){mK(432,wO
+mP
+w4"cCot"
+,wQ"cTan"
+aL,aE(A)q51(B)wA);q5
+Lbp;}
+qE
+TailCall_cCsc:qM
+cCsc:A
+oE
+d3
+hH==cSin){mK(430,wO"cSin "
+w4"cCsc"
+,wQ"cSin"
+aL,aE(A)q51(B)wA);q5
+Lbp;}
+qE
+TailCall_cDeg:qM
+cDeg:d7
+oW(73,"x cDeg"
+,"[RadiansToDegrees(x)]"
+,w6);q5
+Lcd;}
+qK
+TailCall_cDiv:qM
+cDiv:qA
+cCos:oW(368,"cCos "
+aY,"cSec"
+wE,);q5
+Lce;h7
+cCot:oW(372,"cCot "
+aY,"cTan"
+wE,);q5
+o5
+h7
+cCsc:oW(370,"cCsc "
+aY,"cSin"
+wE,);q5
+Lcg;h7
+h4
+oW(167,wJ
+aY,"[Value_t(0)]"
+w5"[Value_t(1)] "
+wG,);q5
+Lch;h7
+cExp:oW(322,aV
+aY,aW
+mA
+wE,);q5
+Lci;h7
+dC:oW(323,a1" "
+aY,aW
+a1
+wE,);q5
+Lcj;h7
+mQ(251,"cInv "
+aY,w2,);q5
+Lck;h7
+o2:oW(321,aT" "
+aY,a9
+aA
+wE,);q5
+Lcl;h7
+cSec:oW(371,mO
+aY,"cCos"
+wE,);q5
+Lcm;h7
+cSin:oW(367,"cSin "
+aY,"cCsc"
+wE,);q5
+Lcn;h7
+hX:oW(436,"cSinCos "
+aY,"cTan"
+,);q5
+Lco;h7
+o1:oW(369,mP
+aY,"cCot"
+wE,);q5
+Lcp;qB
+dM
+hI
+oW(80,wC
+aY,,w6);q5
+Lba;hV
+x!=qY
+qP
+gF:h1
+oI(y/x)==gV
+oW(207,"y[(y/x)==fp_const_rad_to_deg<Value_t>()]"
+q81,"cDeg"
+,q11);q5
+Lcq;hV(y/x)==gW
+oW(208,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]"
+q81,"cRad"
+,q11);q5
+Lda;}
+oW(209,"y"
+q81,"[y/x]"
+wE,q11);q5
+Ldb;oO
+oW(185,aW
+wL
+aY,mJ
+aY,w6);q5
+Ldc;hY
+oW(81,mH
+wL
+aY,"[y/x]"
+,q11);q5
+Ldd;}
+oW(211,wL
+aY,"[Value_t(1)/x]"
+wE,w6);q5
+Lde;gJ
+oD){qP
+cDiv:gP
+oW(102,q01
+aY" "
+wP,"[DO_STACKPLUS1] "
+wQ"A"
+w5
+aY,aE(A)q51(B)wA);oL
+Ldf;qF
+dV
+hQ
+gE){qB
+oW(97,"x cRDiv "
+wP,"A"
+w5
+mW"cRDiv"
+,aE(A)q21
+wS
+wA);q5
+Ldg;g7
+gP
+oW(96,"B[B>=VarBegin] cRDiv "
+wP,"A"
+w5
+wQ"cRDiv"
+,aE(A)q51(B)wA);q5
+Ldh;}
+gJ}
+qE
+TailCall_cEqual:qM
+dR:hO==qY
+qP
+d2
+oW(265,aG" "
+w3
+wZ,mW
+wZ,w6);q5
+Ldi;h7
+hK:oW(267,m2
+w3
+wZ,mW
+wZ,w6);q5
+Ldi;}
+}
+mL(175,mI
+wZ,"[fp_equal(y,x)]"
+,q11);q5
+Ldj;qE
+TailCall_cExp:qM
+cExp:qA
+h5
+m9(318,"x "
+aX
+mA,aV"[fp_exp(x)]"
+wE,w6);q5
+Ldk;qF
+cLog:A
+a8(231,w7
+aS" "
+mA,"A"
+,aE(A)wA);oN
+qB
+oW(59,"x "
+mA,"[fp_exp(x)]"
+,w6);q5
+Ldm;}
+qK
+TailCall_cExp2:qM
+dC:qA
+h5
+m9(319,"x "
+aX
+a1,a1" [fp_exp2(x)]"
+wE,w6);q5
+Ldn;qF
+cLog2:A
+a8(232,w7
+a2" "
+a1,"A"
+,aE(A)wA);oN
+qB
+oW(60,"x "
+a1,"[fp_exp2(x)]"
+,w6);q5
+Ldo;}
+oW(410,a1,"[DO_STACKPLUS1] [fp_log(Value_t(2))]"
+w5
+mA,);oL
+Ldp;TailCall_cFloor:qM
+cFloor:qA
+gC
+oW(315,aW
+mB,mN" "
+a9,);q5
+Ldq;qB
+oW(61,"x "
+mB,"[fp_floor(x)]"
+,w6);q5
+Lea;gY
+gG
+oW(309,"A[IsAlwaysIntegerOpcode(A)] "
+mB,"A"
+,aE(A)wA);g6
+qE
+TailCall_cGreater:qM
+dX:d7
+mL(173,mI
+aR,"[fp_less(x,y)]"
+,q11);q5
+Leb;gX-hW
+oW(345,"x[x==Value_t(-0.5)] "
+aR,aW
+aK,w6);q5
+Lec;qE
+TailCall_cGreaterOrEq:qM
+dE:hO!=qY
+hH==oS
+oW(341,aG" "
+wL
+a0,"[Value_t(0.5)/x]"
+w5
+a3,w6);q5
+Led;}
+}
+mL(174,mI
+a0,"[fp_lessOrEq(x,y)]"
+,q11);q5
+Lee;gX
+hW
+oW(344,"x[x==Value_t(0.5)] "
+a0,"cAbsNotNot"
+,w6);q5
+Lef;qE
+TailCall_cInt:qM
+cInt:qA
+q7:x=q2[0];oW(62,"x cInt"
+,"[fp_int(x)]"
+,w6);q5
+Leg;gY
+gG
+oW(311,"A[IsAlwaysIntegerOpcode(A)] cInt"
+,"A"
+,aE(A)wA);g6
+qE
+TailCall_cInv:qM
+cInv:qA
+cCos:oW(374,"cCos cInv"
+,"cSec"
+,);q5
+Leh;h7
+cCot:oW(378,"cCot cInv"
+,"cTan"
+,);q5
+Lco;h7
+cCsc:oW(376,"cCsc cInv"
+,"cSin"
+,);q5
+Lei;h7
+mQ(247,"cInv cInv"
+,,);oM
+h7
+o2:oW(249,aT" cInv"
+,a9
+aA,);q5
+Lej;h7
+cSec:oW(377,mO"cInv"
+,"cCos"
+,);q5
+Lek;h7
+cSin:oW(373,"cSin cInv"
+,"cCsc"
+,);q5
+Lel;h7
+cSqrt:oW(75,m4" cInv"
+,"cRSqrt"
+,);q5
+Lem;h7
+o1:oW(375,mP"cInv"
+,"cCot"
+,);q5
+Len;qB
+dM!=qY
+oW(77,wL"cInv"
+,"[Value_t(1)/x]"
+,w6);q5
+Leo;gJ}
+qK
+TailCall_cLess:qM
+dS
+hO==qY
+A
+a8(132,w7
+w3
+m3,aQ,q31(A)wA);q5
+Lep;}
+hV
+x!=qY
+hH==oS
+oW(340,aG" "
+wL
+m3,"[Value_t(0.5)/x]"
+w5"cNot"
+,w6);q5
+Leq;}
+}
+mL(171,mI
+m3,"[fp_less(y,x)]"
+,q11);q5
+Lfa;gX
+hW
+oW(343,"x[x==Value_t(0.5)] "
+m3,aK,w6);q5
+Lfb;qE
+TailCall_cLessOrEq:qM
+d4:d7
+mL(172,mI
+aH,"[fp_lessOrEq(y,x)]"
+,q11);q5
+Lfc;gX-hW
+oW(346,"x[x==Value_t(-0.5)] "
+aH,aW"cAbsNotNot"
+,w6);q5
+Lfd;qE
+TailCall_cLog:qM
+cLog:qA
+cExp:oW(234,aV
+aS,,);oM
+gR
+oW(422,wH
+w5
+aS,aS" [fp_log(x)] "
+wG,w6);q5
+Lfe;}
+mC(149,m2
+aS,aG" "
+aS" "
+wJ
+wG,);q5
+Lff;qB
+mE(63,wH" "
+aS,"[fp_log(x)]"
+,w6);q5
+Lfg;gJ}
+qK
+TailCall_cLog10:qM
+oV:qA
+cExp:oW(412,aV
+a4,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]"
+wE,);oL
+Lfh;gR
+oW(423,wH
+w5
+a4,a4" [fp_log10(x)] "
+wG,w6);q5
+Lfi;}
+mC(151,m2
+a4,aG" "
+a4" "
+wJ
+wG,);q5
+Lfj;qB
+mE(64,wH" "
+a4,"[fp_log10(x)]"
+,w6);q5
+Lfk;gJ}
+qK
+TailCall_cLog2:qM
+cLog2:qA
+cExp:oW(411,aV
+a2,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]"
+wE,);oL
+Lfl;h7
+dC:oW(235,a1" "
+a2,,);oM
+gR
+oW(421,wH
+w5
+a2,a2" [fp_log2(x)] "
+wG,w6);q5
+Lfm;}
+mC(150,m2
+a2,aG" "
+a2" "
+wJ
+wG,);q5
+Lfn;qB
+mE(65,wH" "
+a2,"[fp_log2(x)]"
+,w6);q5
+Lfo;gJ}
+qK
+TailCall_cMax:qM
+cMax:o4
+oW(157,wJ
+aZ,,);oM
+oG
+oW(90,mI
+aZ,"[fp_max(x,y)]"
+,q11);q5
+Lfp;gJ
+oC=q0
+gM
+oW(159,wO
+wJ
+aM
+aZ,wQ
+mM,aE(A)q51(B)wA);oM
+qF
+cMax:mK(161,wO
+aZ" "
+aM
+aZ,wQ
+aZ,aE(A)q51(B)wA);oN}
+qE
+TailCall_cMin:qM
+cMin:o4
+oW(156,wJ
+m0,,);oM
+oG
+oW(89,mI
+m0,"[fp_min(x,y)]"
+,q11);q5
+Lfq;gJ
+oC=q0
+gM
+oW(158,wO
+wJ
+aM
+m0,wQ
+mM,aE(A)q51(B)wA);oM
+qF
+cMin:mK(160,wO
+m0" "
+aM
+m0,wQ
+m0,aE(A)q51(B)wA);oN}
+qE
+TailCall_cMod:qM
+cMod:hO!=qY
+mL(82,mH
+wL"cMod"
+,"[fp_mod(y,x)]"
+,q11);q5
+Lga;}
+qE
+TailCall_cMul:qM
+gF:o4
+oW(402,mM
+wE,wT,);q5
+Lgb;h7
+mQ(252,"cInv"
+wE,aY,);q5
+Lgc;h7
+gC
+qP
+h4
+oW(394,wJ
+a9
+wE,m2
+a9,);q5
+Lgd;oC=g8;qV){m7
+B=mX
+aI(400,"B[B==A]"
+wU" "
+a9
+wE,wQ
+wT
+w5
+a9,aE(A)q51(B)wA);q5
+Lge;}
+}
+}
+}
+q5
+dJ;h7
+o2:hH
+qC
+dP
+oW(198,mM
+wB
+aT
+wE,"[x+Value_t(1)]"
+aA,w6);q5
+Lgf;}
+}
+q5
+dJ;qB
+dM==qY
+qP
+gF:A=gE;qV
+mF(141,aO
+w5
+w3
+w2,wY
+wE,q31(A)wA);q5
+Lgg;}
+q5
+Default3;g7
+Default3:;A=g8
+oK
+IsBinaryOpcode(A)g3
+A)){gD
+hZ
+oW(140,mH
+oZ,wY
+wE,q31(A)q21
+aF);q5
+Lgh;g7
+gO
+IsBinaryOpcode(B)g3
+B)){hQ
+mX){hY
+oW(144,mH
+w8,aQ,q31(A)q51(B)q21
+aF);q5
+Lgi;g7
+C=mX
+oK
+C
+h3
+mF(142,"C[C>=VarBegin] "
+w8,aQ,q31(A)q51(B)q61(C)wA);q5
+Lgj;o6
+C)g3
+C)mF(143,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+w8,wQ
+aQ,q31(A)q51(B)q61(C)wA);q5
+Lgk;}
+}
+hV
+oF
+oW(138,q01
+oZ,wY
+wE,q31(A)q51(B)wA);q5
+Lgg;o6
+B)g3
+B)mF(139,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+oZ,aQ,q31(A)q51(B)wA);q5
+Lgl;}
+}
+}
+qV
+mF(136,aM
+w3
+w2,wY,q31(A)wA);q5
+Lgm;o6
+A)g3
+A)mF(137,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+w3
+w2,wY
+wE,q31(A)wA);q5
+Lgn;}
+}
+}
+qP
+h5
+gD
+h4
+dM+mR(202,"cDup[x+x==Value_t(1)] "
+m8,,w6);q5
+Lgo;}
+oW(203,wJ
+m8,"[x+x]"
+wE,w6);q5
+Lgp;h7
+gF:dW
+A=g0
+4];qV
+mF(292,aM"y"
+w5
+m8,wY
+w5"A "
+aU
+w5
+wG,wR", "
+mH
+mZ
+y
+q21
+w9(A)wA);q5
+Lgq;}
+qF
+hZ
+oW(291,mH
+m8,wY
+w5
+aU" "
+wG,q11);q5
+Lha;qF
+cDeg:oW(152,"cDeg"
+wB
+w2,"[RadiansToDegrees(x)]"
+wE,w6);q5
+Lhb;h7
+cDiv:gP
+hQ
+mX){h7
+gF:qN
+4]qO
+oW(109,"y"
+w5
+q01
+aY
+wB
+w2,aU
+w5
+wQ
+aY,q91(B)q21
+aF);q5
+Lhc;oO
+oW(110,aW
+q01
+aY
+wB
+w2,a5
+wQ
+aY,q91(B)wA);q5
+Lhd;hY
+oW(108,mH
+q01
+aY
+wB
+w2,aU" "
+wQ
+aY,q91(B)q21
+aF);q5
+Lhe;}
+qF
+gF:gD
+h5
+qN
+hL
+dM+mR(204,"cDup[x+x==Value_t(1)] "
+wG
+q71,w2,w6);q5
+Lhf;}
+oW(205,wJ
+wG
+q71,w2" [x+x]"
+wE,w6);q5
+Lhg;qF
+hZ
+if((y*x)==gV
+oW(189,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]"
+q71,"cDeg"
+,q11);q5
+Lcq;hV(y*x)==gW
+oW(190,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]"
+q71,"cRad"
+,q11);q5
+Lda;hV
+y*mR(192,"y[y*x==Value_t(1)]"
+q71,,q11);q5
+Lhh;}
+oW(193,"y"
+q71,aU
+wE,q11);q5
+Lhi;oO
+oW(182,a9
+wB
+w2,"[-x]"
+wE,w6);q5
+Lhj;h7
+dV
+gD
+gF:dW
+oW(116,"y"
+w5
+aB,aU
+w5"cRDiv"
+,q11);q5
+Lhk;oO
+oW(117,aW
+aB,a5"cRDiv"
+,w6);q5
+Lhl;hY
+oW(115,mH
+aB,aU" cRDiv"
+,q11);q5
+Lhm;qF
+cRad:oW(153,"cRad"
+wB
+w2,"[DegreesToRadians(x)]"
+wE,w6);q5
+Lhn;h7
+cSub:m7
+dW
+A=g0
+4];qV
+mF(293,aM"y"
+w5"cSub"
+wB
+w2,wY
+w5"A "
+aU
+w5"cSub"
+,wR", "
+mH
+mZ
+y
+q21
+w9(A)wA);q5
+Lho;}
+}
+qF
+hZ
+oW(79,mI
+w2,aU,q11);q5
+Lhp;dQ
+oW(78,wC
+w2,,w6);q5
+Lba;gX
+2)mF(146,"x[x==Value_t(2)]"
+wE,wJ
+wG,w6);q5
+Lhq;hJ
+gV
+oW(147,"x[x==fp_const_rad_to_deg<Value_t>()]"
+wE,"cDeg"
+,w6);q5
+Lia;hJ
+gW
+oW(148,"x[x==fp_const_deg_to_rad<Value_t>()]"
+wE,"cRad"
+,w6);q5
+Lib;gX-1)mF(184,"x[x==Value_t(-1)]"
+wE,a9,w6);q5
+Lic;gJ
+g7
+dJ:;A
+oE){qP
+cDiv:gP
+oW(105,q01
+aY" "
+aN,"[DO_STACKPLUS1] A"
+w5
+wQ
+aY,aE(A)q51(B)wA);oL
+Lid;}
+q5
+hT
+gF:gD
+gC
+B=mX
+aI(397,wO
+a9
+wU
+wE,wQ
+wT
+w5
+a9,aE(A)q51(B)wA);q5
+Lge;}
+q5
+dK;g7
+dK:;mK(388,"B[B==A]"
+wU
+wE,wQ
+wT
+wE,aE(A)q51(B)wA);q5
+Lie;}
+}
+q5
+hT
+gC
+mK(391,wO
+aW
+aN,wQ
+m2
+a9,aE(A)q51(B)wA);q5
+Lgd;}
+q5
+hT
+dV
+h1
+qC
+oW(98,"x cRDiv "
+aN,"[DO_STACKPLUS1] A "
+wY
+w5"cRDiv"
+,aE(A)q21
+wS
+wA);oL
+Lif;}
+oW(112,"cRDiv "
+aN,"[DO_STACKPLUS1] A"
+w5"cRDiv"
+,aE(A)wA);oL
+Lig;g7
+Default4:;B=g8
+aI(385,wO
+aN,wQ
+wT,aE(A)q51(B)wA);q5
+Lgb;}
+}
+o6
+A)){B=g8
+oK
+B
+h3
+qU
+1){m7
+C=mX
+oK
+C==A){D=g0
+4]oK
+D==B
+mF(408,"D[D==B] C[C==A]"
+w5"B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wE,"D C "
+wT
+wE,aE(A)q51(B)q61(C)<<", D "
+oY(D)wA);q5
+Lih;}
+}
+}
+}
+qE
+TailCall_cNEqual:qM
+dT:hO==qY
+qP
+d2
+oW(266,aG" "
+w3
+wN,mW
+wN,w6);q5
+Lii;h7
+hK:oW(268,m2
+w3
+wN,mW
+wN,w6);q5
+Lii;}
+}
+mL(176,mI
+wN,"[fp_nequal(y,x)]"
+,q11);q5
+Lij;qE
+hD:qM
+gC
+qA
+gF:m9(183,"x"
+w5
+a9,"[-x]"
+wE,w6);q5
+Lik;oO
+oW(248,aW
+a9,,);oM
+h7
+cSin:hH
+wW(359,"x"
+w5"cSin "
+a9,a5"cSin"
+,w6);q5
+Lil;}
+qF
+oT
+hH
+wW(360,"x"
+w5"cSinh "
+a9,a5"cSinh"
+,w6);q5
+Lim;}
+qF
+o1:hH
+wW(361,"x"
+w5
+mP
+a9,a5"cTan"
+,w6);q5
+Lin;}
+qF
+oU
+hH
+wW(362,"x"
+w5"cTanh "
+a9,a5"cTanh"
+,w6);q5
+Lio;}
+gJ
+qB
+oW(76,"x "
+a9,"[-x]"
+,w6);q5
+Lip;}
+qK
+TailCall_cNot:qM
+cNot:qA
+d2
+oW(296,aG
+aJ,"cNot"
+,);q5
+Liq;h7
+cAbsNot:A
+a7(303,"A[IsLogicalOpcode(A)] "
+aK
+aJ,"A"
+,aE(A)wA);oM
+hV
+A!=q7
+mF(304,"A[A!=cImmed] "
+aK
+aJ,"A cAbsNotNot"
+,aE(A)wA);q5
+Lja;}
+q5
+dL;h7
+cAbsNotNot:oW(299,"cAbsNotNot"
+aJ,aK,);q5
+Ljb;h7
+dR:oW(262,wZ
+aJ,wN,);q5
+Ljc;h7
+dX:oW(260,aR
+aJ,aH,);q5
+Ljd;h7
+dE:oW(261,a0
+aJ,m3,);q5
+Lje;h7
+dS
+oW(258,m3
+aJ,a0,);q5
+Ljf;h7
+d4:oW(259,aH
+aJ,aR,);q5
+Ljg;h7
+dT:oW(263,wN
+aJ,wZ,);q5
+Ljh;h7
+gC
+oW(295,a9
+aJ,"cNot"
+,);q5
+Liq;h7
+cNot:oW(297,"cNot"
+aJ,a3,);q5
+Lbd;h7
+dB:oW(298,a3
+aJ,"cNot"
+,);q5
+Liq;qB
+oW(93,"x"
+aJ,"[fp_not(x)]"
+,w6);q5
+Lji;g7
+dL:;A
+h0
+qX
+oW(305,w7"cNot"
+,"A "
+aK,aE(A)wA);q5
+Ljj;qE
+TailCall_cNotNot:qM
+dB:gZ]==cNot
+mF(300,"cNot "
+a3,"cNot"
+,);g6}
+qK
+TailCall_cOr:qM
+cOr:o4
+oW(425,wJ"cOr"
+,a3,);q5
+Lbd;oG
+oW(178,mI"cOr"
+,"[fp_or(x,y)]"
+,q11);q5
+Ljk;gJ}
+qK
+TailCall_cPow:qM
+o2:d7
+if(!h2
+x+x)){hH==hK
+mF(22,m2"x[!isEvenInteger(x+x)]"
+aA,aG" [x+x]"
+aA,w6);q5
+Ljl;}
+hV
+isInteger(x)){qP
+cExp:oW(43,aV
+wI,wY
+w5
+mA,w6);q5
+Ljm;h7
+dC:oW(44,a1" "
+wI,wY
+w5
+a1,w6);q5
+Ljn;h7
+o2:h1
+oI!isInteger(y)mF(42,"y[!isInteger(y)]"
+aA" "
+wI,aU
+aA,q11);q5
+Ljo;}
+}
+oW(45,aT" "
+wI,wY
+w5
+aT,w6);q5
+Ljp;}
+hV
+h2
+x)){qP
+d2
+oW(348,aG" x[isEvenInteger(x)]"
+aA,wY
+aA,w6);q5
+Ljq;h7
+gF:h1==oS
+oW(349,aG
+w5"x[isEvenInteger(x)]"
+aA,w2" "
+wY
+aA,w6);q5
+Lka;gJ}
+hJ
+qY
+oW(169,w3
+aT,"[Value_t(0)]"
+w5"[Value_t(1)] "
+wG,w6);q5
+Lkb;gX
+hW
+oW(223,"x[x==Value_t(0.5)]"
+aA,m4,w6);q5
+Lkc;gX
+1)/qD
+3)mF(224,"x[x==Value_t(1)/Value_t(3)]"
+aA,"cCbrt"
+,w6);q5
+Lkd;gX
+1)/qD-3)mF(225,"x[x==Value_t(1)/Value_t(-3)]"
+aA,"cCbrt cInv"
+,w6);q5
+Lke;gX-hW
+oW(226,"x[x==Value_t(-0.5)]"
+aA,"cRSqrt"
+,w6);q5
+Lkf;gX-1)mF(227,"x[x==Value_t(-1)]"
+aA,"cInv"
+,w6);q5
+Lkg;}
+qP
+o2:h1
+oI
+h2
+y)&&!h2
+x*y)mF(21,"y[isEvenInteger(y)&&!isEvenInteger(x*y)]"
+aA
+wB
+aT,aG" "
+aU
+aA,q11);q5
+Lkh;}
+oW(221,"y"
+aA
+wB
+aT,aU
+aA,q11);q5
+Ljo;mC(46,wT
+wB
+aT,"[x+x]"
+aA,w6);q5
+Lki;hY
+if(y!=qD
+0)||x>=qY
+oW(92,"y[y!=Value_t(0)||x>=Value_t(0)]"
+wB
+aT,"[fp_pow(y,x)]"
+,q11);q5
+Lkj;gJ}
+oW(382,"x"
+aA,"[DO_POWI]"
+,w6)oK
+TryCompilePowi(x))g6}
+qK
+TailCall_cRDiv:qM
+dV
+qA
+hX:oW(437,"cSinCos cRDiv"
+,"cCot"
+,);q5
+Len;qB
+dM
+hI
+oW(99,wC"cRDiv"
+,"cInv"
+,w6);q5
+Lkg;gJ}
+qK
+TailCall_cRSub:qM
+dN:gZ]hM
+oW(200,wJ
+wX,"[Value_t(0)]"
+wE,);q5
+Lkk;}
+qK
+TailCall_cRad:qM
+cRad:qA
+gF:m9(154,"x"
+w5"cRad"
+,"[DegreesToRadians(x)]"
+wE,w6);q5
+Lkl;gJ
+qB
+oW(74,"x cRad"
+,"[DegreesToRadians(x)]"
+,w6);q5
+Lkm;}
+qK
+TailCall_cSec:qM
+cSec:A
+oE
+d3
+qP
+cCos:mK(431,wO"cCos "
+w4"cSec"
+,wQ"cCos"
+aL,aE(A)q51(B)wA);q5
+Lbp;qF
+cSin:mK(429,wO"cSin "
+w4"cSec"
+,wQ"cSinCos cInv"
+,aE(A)q51(B)wA);q5
+Lkn;gJ
+qE
+TailCall_cSin:qM
+cSin:qA
+gC
+oW(355,aW"cSin"
+,"cSin "
+a9,);q5
+Lko;qB
+oW(66,"x cSin"
+,"[fp_sin(x)]"
+,w6);q5
+Lkp;oD
+d3
+hH==cCsc){mK(433,wO"cCsc "
+w4"cSin"
+,wQ"cCsc"
+aL,aE(A)q51(B)wA);q5
+Lbp;}
+}
+qE
+TailCall_cSinh:qM
+oT
+qA
+cAcosh:oW(364,"cAcosh cSinh"
+,"[DO_STACKPLUS1] "
+m2"[Value_t(-1)] "
+m1,);oL
+Lkq;h7
+cAsinh:oW(240,"cAsinh cSinh"
+,,);oM
+h7
+gC
+oW(356,aW"cSinh"
+,"cSinh "
+a9,);q5
+Lla;qB
+oW(67,"x cSinh"
+,"[fp_sinh(x)]"
+,w6);q5
+Llb;}
+qK
+TailCall_cSqr:qM
+hK:qA
+d2
+oW(404,aG" "
+wT,wT,);q5
+Llc;h7
+gC
+oW(403,aW
+wT,wT,);q5
+Llc;h7
+cSqrt:A
+a8(229,w7
+m4" "
+wT,"A"
+,aE(A)wA);oN}
+qK
+TailCall_cSqrt:qM
+cSqrt:qA
+h5
+hH==hK){A=gE;qV){qN
+3]==hK
+mF(439,m2
+aM
+m2
+m1,"A cHypot"
+,aE(A)wA);q5
+Lld;}
+}
+gO
+gH
+B)){A=mX;qV){qN
+4]==hK
+mF(440,m2
+aM"B[IsUnaryOpcode(B)] "
+m2
+m1,"A "
+wQ"cHypot"
+,"    with"
+aD(B)q21
+w9(A)wA);q5
+Lle;}
+}
+}
+mC(23,m2
+m4,aG,);q5
+Llf;qB
+dM>=qY
+oW(68,"x[x>=Value_t(0)] "
+m4,"[fp_sqrt(x)]"
+,w6);q5
+Llg;gJ}
+qK
+hE:qM
+cSub:o4
+oW(199,wJ"cSub"
+,"[Value_t(0)]"
+wE,);q5
+Lkk;h7
+gC
+oW(254,aW"cSub"
+,wG,);q5
+Llh;qB
+dM==qY
+oW(85,w3"cSub"
+,,w6);q5
+Lba;}
+mL(86,mI"cSub"
+,"[y-x]"
+,q11);q5
+Lli;}
+oW(216,"x cSub"
+,mJ
+wG,w6);q5
+Llj;oD){hH==dN){h1
+qC
+oW(120,"x "
+wX" "
+aM"cSub"
+,"A "
+aX
+mW
+wX,aE(A)q21
+wS
+wA);q5
+Llk;}
+oW(127,wX" "
+aM"cSub"
+,"[DO_STACKPLUS1] A cSub "
+wX,aE(A)wA);oL
+Lll;}
+qE
+hF:qM
+o1:qA
+cAtan2:oW(245,"cAtan2 cTan"
+,aY,);q5
+Lgc;h7
+gC
+oW(357,aW"cTan"
+,mP
+a9,);q5
+Llm;qB
+oW(70,"x cTan"
+,"[fp_tan(x)]"
+,w6);q5
+Lln;oD
+d3
+hH==cCot){mK(435,wO"cCot "
+w4"cTan"
+,wQ"cCot"
+aL,aE(A)q51(B)wA);q5
+Lbp;}
+}
+qE
+TailCall_cTanh:qM
+oU
+qA
+gC
+oW(358,aW"cTanh"
+,"cTanh "
+a9,);q5
+Llo;qB
+oW(71,"x cTanh"
+,"[fp_tanh(x)]"
+,w6);q5
+Llp;}
+qK
+TailCall_cTrunc:qM
+cTrunc:qA
+q7:x=q2[0];oW(72,"x cTrunc"
+,"[fp_trunc(x)]"
+,w6);q5
+Llq;gY
+gG
+oW(308,"A[IsAlwaysIntegerOpcode(A)] cTrunc"
+,"A"
+,aE(A)wA);g6
+qE
+g7
+Default0:;A=opcode
+oK
+IsComparisonOpcode(A)){d7
+qP
+h5
+h1
+qO
+oW(270,mH
+wG
+wF,"[x-y] A"
+,aE(A)q41);q5
+Lma;qF
+cAtan:if(d8<fp_const_pi<hP>()*qD
+hW
+oW(286,"cAtan[fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)]"
+wF,"[fp_tan(x)] A"
+,aE(A)q21
+wS
+wA);q5
+Lmb;qF
+cExp:mE(276,"cExp[x>Value_t(0)]"
+wF,"[fp_log(x)] A"
+,aE(A)q21
+wS
+wA);q5
+Lmc;qF
+dC:mE(277,"cExp2[x>Value_t(0)]"
+wF,"[fp_log2(x)] A"
+,aE(A)q21
+wS
+wA);q5
+Lmd;qF
+cLog:gO
+g9
+oW(279,wD
+aS
+wF,wQ"[fp_exp(x)] A"
+,aE(A)q21
+wS
+q51(B)wA);q5
+Lme;qF
+oV:gO
+g9
+oW(281,wD
+a4
+wF,wQ"[fp_pow(Value_t(10),x)] A"
+,aE(A)q21
+wS
+q51(B)wA);q5
+Lmf;qF
+cLog2:gO
+g9
+oW(280,wD
+a2
+wF,wQ"[fp_exp2(x)] A"
+,aE(A)q21
+wS
+q51(B)wA);q5
+Lmg;qF
+gF:h1
+oI
+y>qY
+oW(272,"y[y>Value_t(0)]"
+w5"x A[IsComparisonOpcode(A)]"
+,"[x/y] A"
+,aE(A)q41);q5
+Lmh;hV
+y<qY
+oW(273,"y[y<Value_t(0)]"
+w5"x A[IsComparisonOpcode(A)]"
+,"[x/y] {OppositeComparisonOpcode(A)}"
+,aE(A)q41);q5
+Lmi;}
+oO
+oW(271,a9
+wF,mJ"{OppositeComparisonOpcode(A)}"
+,aE(A)q21
+wS
+wA);q5
+Lmj;h7
+o2:dM>qY
+h1
+oI
+y>qY
+oW(274,"y[y>Value_t(0)] cPow[x>Value_t(0)]"
+wF,"[fp_pow(x,1/y)] A"
+,aE(A)q41);q5
+Lmk;}
+}
+qF
+oT
+oW(287,"cSinh"
+wF,"[fp_asinh(x)] A"
+,aE(A)q21
+wS
+wA);q5
+Lml;h7
+hK:mE(275,"cSqr[x>Value_t(0)]"
+wF,aG" [fp_sqrt(x)] A"
+,aE(A)q21
+wS
+wA);q5
+Lmm;qF
+oU
+if(d8<o9
+mF(288,"cTanh[fp_abs(x)<Value_t(1)]"
+wF,"[fp_atanh(x)] A"
+,aE(A)q21
+wS
+wA);q5
+Lmn;gJ}
+}
+}
+qV
+qU
+0){B
+h0
+B==A
+mF(406,wO"A[A>=VarBegin&&mData->mByteCode.size()>0]"
+,wQ
+mM,aE(A)q51(B)wA);q5
+Lmo;}
+o6
+A)){B
+h0
+B
+h3
+qU
+1){C=g8
+oK
+C==A){D=oJ
+D==B
+mF(407,"D[D==B] C[C==A] B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+,"D C "
+mM,aE(A)q51(B)q61(C)<<", D "
+oY(D)wA);q5
+Lmp;}
+}
+}
+}
+}
+q5
+Laa;Laa:qI
+opcode
+mV
+Lab:q8
+Lmq:w1(cAbs);q5
+TailCall_cAbs;Lac:gB
+d8;g6
+Lad:gB
+fp_acos
+mG
+Lae:gB
+fp_acosh
+mG
+Laf:o7
+4));gE=q7;hA
+Lna:g1
+gF;Lnb:qZ
+Lnc:w1(cMul);q5
+TailCall_cMul;Lag:q9
+hU
+o7
+4));Lnd:hN
+Lna;Lah:gB
+x+o9;gE=q7;hA
+Lep:g1
+gF;q5
+Lnc;Lai:a6
+cSub;Lne:w1(cSub);q5
+hE;Laj:hG
+o3
+Lnf:qZ
+Lng:w1(cAdd);q5
+TailCall_cAdd;Lak:hG
+3;qJ
+Lnh:d5
+Lni:g1
+dN;qZ
+w1(cRSub);q5
+TailCall_cRSub;Lal:gA
+gE=q7;q9
+o3
+q5
+Lnh;Lam:hG
+o3
+q5
+Lni;Lan:hG
+4;qJ
+Lnj:d5
+Lnk:qL
+B);Lnl:g1
+cSub;qZ
+q5
+Lne;Lao:gA
+mX=q7;q9
+3;qJ
+q5
+Lnj;Lap:hG
+3;qJ
+q5
+Lnk;Laq:g5
+y+x;Lba:qT
+Ldl:g2
+q6
+g6
+Lbb:qS
+3
+dU
+oP
+hN
+Lnh;Lbc:qQ
+A
+gU
+Lnh;Lbd:a6
+dB;Lnm:w1(cNotNot);q5
+TailCall_cNotNot;Lbe:g5
+fp_and(x
+h6
+Lbf:gB
+fp_asin
+mG
+Lbg:gB
+fp_asinh
+mG
+Lbh:gB
+fp_atan
+mG
+Lbi:g5
+fp_atan2
+mY
+Lbj:gB
+fp_atanh
+mG
+Lbk:gB
+fp_cbrt
+mG
+Lbl:qG
+cFloor);Lnn:g1
+cNeg;qZ
+w1(cNeg);q5
+hD;Lbm:gB
+fp_ceil
+mG
+Lbn:q8
+Lno:w1(cCos);q5
+TailCall_cCos;Lbo:gB
+fp_cos
+mG
+Lbp:q0
+d6
+g1
+cInv;Lnp:w1(cInv);q5
+TailCall_cInv;Lbq:qQ
+hX
+mV
+Lca:q8
+w1(cCosh);q5
+TailCall_cCosh;Lcb:qG
+hK);o7
+1));Lnq:qI
+q7);d5
+Loa:g1
+cSqrt;qZ
+w1(cSqrt);q5
+TailCall_cSqrt;Lcc:gB
+fp_cosh
+mG
+Lcd:gB
+RadiansToDegrees
+mG
+Lce:qG
+cSec
+gU
+Lna;Lcf:qG
+o1
+gU
+Lna;Lcg:qG
+cSin
+gU
+Lna;Lch:o7
+0));q0[0]=q7;Lob:qL
+d1
+o7
+1));Loc:qI
+q7);Lod:g1
+cAdd;q5
+Lnf;Lci:qG
+cNeg);qL
+cExp
+gU
+Lna;Lcj:qG
+cNeg);qL
+dC
+gU
+Lna;Lck:q8
+q5
+Lep;Lcl:qG
+cNeg);qL
+o2
+gU
+Lna;Lcm:qG
+cCos
+gU
+Lna;Lcn:qG
+cCsc
+gU
+Lna;Lco:a6
+o1;Loe:w1(cTan);q5
+hF;Lcp:qG
+cCot
+gU
+Lna;Lcq:dY;qJ
+Lof:g1
+cDeg;qZ
+w1(cDeg);q5
+TailCall_cDeg;Lda:dY;qJ
+Log:g1
+cRad;qZ
+w1(cRad);q5
+TailCall_cRad;Ldb:g5
+y/x;qS
+o3
+q5
+Lna;Ldc:gA
+mT
+q8
+Loh:w1(cDiv);q5
+TailCall_cDiv;Ldd:g5
+y/x;q5
+Lba;Lde:gB
+o9/x;q5
+Lep;Ldf:qQ
+A);qL
+d1
+Loi:qZ
+q5
+Loh;Ldg:qS
+3
+dU
+qL
+d1
+oP
+qI
+q7);Loj:g1
+cRDiv;qZ
+w1(cRDiv);q5
+TailCall_cRDiv;Ldh:q9
+3
+dU
+qL
+d1
+qL
+B
+gU
+Loj;Ldi:mT
+q8
+Lok:w1(cEqual);q5
+TailCall_cEqual;Ldj:g5
+fp_equal
+mY
+Ldk:qT
+qQ
+cExp);qH
+fp_exp(x)gU
+Lnd;Ldm:gB
+fp_exp
+mG
+Ldn:qT
+qQ
+dC);qH
+fp_exp2(x)gU
+Lnd;Ldo:gB
+fp_exp2
+mG
+Ldp:qH
+dG
+qD
+2)));qI
+q7);Lol:qL
+d1
+g1
+cExp;qZ
+w1(cExp);q5
+TailCall_cExp;Ldq:qG
+cCeil
+mS
+Lea:gB
+fp_floor
+mG
+Leb:g5
+fp_less(x
+h6
+Lec:qT
+qG
+cNeg);Ljj:qL
+cAbsNot
+mV
+Led:gB
+qD
+0.5)/x;mD
+dB;qZ
+q5
+Lnm;Lee:g5
+fp_lessOrEq(x
+h6
+Lef:qT
+Lja:g2
+q6
+Lom:qL
+cAbsNotNot
+mV
+Leg:gB
+fp_int
+mG
+Leh:a6
+cSec;w1(cSec);q5
+TailCall_cSec;Lei:a6
+cSin;Lon:w1(cSin);q5
+TailCall_cSin;Lej:qG
+cNeg);g1
+o2;Loo:qZ
+Lop:w1(cPow);q5
+TailCall_cPow;Lek:a6
+cCos;q5
+Lno;Lel:a6
+cCsc;w1(cCsc);q5
+TailCall_cCsc;Lem:qG
+cRSqrt
+mV
+Len:a6
+cCot;w1(cCot);q5
+TailCall_cCot;Leo:gB
+o9/x;g6
+Leq:gB
+qD
+0.5)/x;mD
+cNot;qZ
+Loq:w1(cNot);q5
+TailCall_cNot;Lfa:g5
+fp_less
+mY
+Lfb:qT
+Ljb:qW
+Ljj;Lfc:g5
+fp_lessOrEq
+mY
+Lfd:qT
+qG
+cNeg
+gU
+Lom;Lfe:qT
+qQ
+cLog);qH
+dG
+x)gU
+Loc;Lff:qG
+d9
+qL
+cLog);Lpa:qI
+cDup
+gU
+Lod;Lfg:gB
+dG
+x
+mV
+Lfh:qH
+dA
+fp_const_e<hP>()));Lpb:q0[0]=q7;q5
+Lna;Lfi:qT
+qQ
+oV);qH
+dA
+x)gU
+Loc;Lfj:qG
+d9
+qL
+oV
+gU
+Lpa;Lfk:gB
+dA
+x
+mV
+Lfl:qH
+d0
+fp_const_e<hP>())gU
+Lpb;Lfm:qT
+qQ
+cLog2);qH
+d0
+x)gU
+Loc;Lfn:qG
+d9
+qL
+cLog2
+gU
+Lpa;Lfo:gB
+d0
+x
+mV
+Lfp:g5
+fp_max(x
+h6
+Lfq:g5
+fp_min(x
+h6
+Lga:g5
+fp_mod
+mY
+Lgb:a6
+hK;Lpc:w1(cSqr);q5
+TailCall_cSqr;Lgc:a6
+cDiv;q5
+Loh;Lgd:qQ
+hK
+mS
+Lge:q9
+3
+qR
+hK);qL
+gF
+mS
+Lgf:gB
+x+o9;gE=q7;hA
+g1
+o2;q5
+Lop;Lgg:gE=q7;hA
+q5
+Lnc;Lgh:g5
+x;Lpd:qS
+o3
+q5
+Lnb;Lgi:hB
+qT
+Lpe:q9
+4;qJ
+Lpf:qL
+A);oP
+Lpg:hN
+Lnb;Lgj:qT
+q5
+Lpe;Lgk:qS
+4
+qR
+B
+gU
+Lpf;Lgl:qS
+3;qJ
+q5
+Lpf;Lgm:mT
+oM
+Lgn:mT
+q8
+q5
+Lnc;Lgo:qT
+Lph:q9
+3;qJ
+g6
+Lgp:gB
+x+x;q5
+Lgg;Lgq:g5
+x;g0
+4]=q7;qS
+hU
+qL
+A);oQ);qI
+q7);qL
+gF
+gU
+Lod;Lha:g5
+x;qT
+qQ
+d1
+oQ
+gU
+Loc;Lhb:gB
+RadiansToDegrees(x
+gU
+Lgn;Lhc:g5
+y
+oR
+4;qJ
+Lpi:qL
+d1
+Lpj:qL
+B);g1
+cDiv;q5
+Loi;Lhd:gA
+mX=q7;q9
+3;qJ
+q5
+Lpi;Lhe:g5
+y
+oR
+3;qJ
+q5
+Lpj;Lhf:qS
+4;qJ
+q5
+Lnb;Lhg:qS
+hU
+qH
+x+x
+gU
+Lpg;Lhh:hB
+qT
+q5
+Lph;Lhi:g5
+y*x;q5
+Lpd;Lhj:gA
+q5
+Lgn;Lhk:g5
+y
+oR
+3;qJ
+Lpk:qL
+gF
+gU
+Loj;Lhl:gA
+gE=q7;q9
+o3
+q5
+Lpk;Lhm:g5
+y
+oR
+o3
+q5
+Loj;Lhn:gB
+gL
+q5
+Lgn;Lho:g5
+x;g0
+4]=q7;qS
+hU
+qL
+A);oQ);qI
+q7);qL
+gF
+gU
+Lnl;Lhp:g5
+y*x;q5
+Lba;Lhq:q0
+d6
+q2-=1;qT
+Lpl:g1
+cAdd;q5
+Lng;Lia:qT
+qW
+Lof;Lib:qT
+qW
+Log;Lic:qT
+qW
+Lnn;Lid:q9
+3
+qR
+A
+gU
+Lpi;Lie:q9
+o3
+Lpm:qL
+hK
+gU
+Lnb;Lif:qS
+3
+dU
+oP
+hN
+Lpk;Lig:qQ
+A
+gU
+Lpk;Lih:q9
+3;qJ
+q5
+Lpm;Lii:mT
+q8
+Lpn:w1(cNEqual);q5
+TailCall_cNEqual;Lij:g5
+fp_nequal
+mY
+Lik:gA
+q5
+Lck;Lil:gA
+o8
+cSin;qZ
+q5
+Lon;Lim:gA
+o8
+cSinh;qZ
+w1(cSinh);q5
+TailCall_cSinh;Lin:gA
+o8
+o1;qZ
+q5
+Loe;Lio:gA
+o8
+cTanh;qZ
+w1(cTanh);q5
+TailCall_cTanh;Lip:gA
+g6
+Liq:q8
+q5
+Loq;Ljc:a6
+dT;q5
+Lpn;Ljd:a6
+d4;w1(cLessOrEq);q5
+TailCall_cLessOrEq;Lje:a6
+cLess;w1(cLess);q5
+TailCall_cLess;Ljf:a6
+dE;w1(cGreaterOrEq);q5
+TailCall_cGreaterOrEq;Ljg:a6
+dX;w1(cGreater);q5
+TailCall_cGreater;Ljh:a6
+dR;q5
+Lok;Lji:gB
+fp_not
+mG
+Ljk:g5
+fp_or(x
+h6
+Ljl:qT
+qQ
+d9
+qH
+x+x);Lpo:hN
+Loo;Ljm:mT
+qW
+Lol;Ljn:mD
+dC;qZ
+w1(cExp2);q5
+TailCall_cExp2;Ljo:g5
+y
+oR
+o3
+q5
+Loo;Ljp:mT
+qG
+gF
+gU
+Loo;Ljq:mT
+q8
+q5
+Lop;Lka:qS
+3
+qR
+d1
+qH
+x
+gU
+Lpo;Lkb:gB
+qD
+0
+gU
+Lob;Lkc:qT
+qW
+Loa;Lkd:qT
+g2
+q6
+g1
+cCbrt;qZ
+w1(cCbrt);q5
+TailCall_cCbrt;Lke:qT
+qG
+cCbrt);Lpp:g1
+cInv;qZ
+q5
+Lnp;Lkf:qT
+q5
+Lem;Lkg:qT
+qW
+Lpp;Lkh:dY
+qR
+d9
+oQ
+gU
+Lpo;Lki:gB
+x+x;q5
+Ljq;Lkj:g5
+dZ
+y
+dF
+Lkk:o7
+0)gU
+Lpb;Lkl:gB
+gL
+q5
+Lck;Lkm:gB
+gL
+g6
+Lkn:qQ
+hX
+gU
+Lpp;Lko:qG
+cSin
+mS
+Lkp:gB
+fp_sin
+mG
+Lkq:qG
+hK);o7-1)gU
+Lnq;Lla:qG
+cSinh
+mS
+Llb:gB
+fp_sinh
+mG
+Llc:q8
+q5
+Lpc;Lld:q9
+4
+dU
+Lpq:qL
+cHypot
+mV
+Lle:q9
+5
+dU
+qL
+B
+gU
+Lpq;Llf:a6
+cAbs;q5
+Lmq;Llg:gB
+fp_sqrt
+mG
+Llh:q8
+q5
+Lpl;Lli:g5
+y-x;q5
+Lba;Llj:gA
+q5
+Lpl;Llk:qS
+3
+dU
+d5
+oP
+hN
+Lni;Lll:qQ
+A);qL
+cSub
+gU
+Lni;Llm:qG
+o1
+mS
+Lln:gB
+fp_tan
+mG
+Llo:qG
+cTanh
+mS
+Llp:gB
+fp_tanh
+mG
+Llq:gB
+fp_trunc
+mG
+Lma:g5
+x-y;Lqa:qS
+o3
+Lqb:qL
+A
+mV
+Lmb:gB
+fp_tan(x);Lqc:mT
+qW
+Lqb;Lmc:gB
+dG
+x
+mU;Lmd:gB
+d0
+x
+mU;Lme:gB
+fp_exp(x
+mU;Lmf:gB
+dZ
+qD
+10)dD
+Lqc;Lmg:gB
+fp_exp2(x
+mU;Lmh:g5
+x/y;q5
+Lqa;Lmi:g5
+x/y;qS
+o3
+Lqd:qL
+OppositeComparisonOpcode(A)mV
+Lmj:gA
+mT
+qW
+Lqd;Lmk:g5
+dZ
+x,1/y
+gU
+Lqa;Lml:gB
+fp_asinh(x
+mU;Lmm:qT
+qQ
+d9
+qH
+fp_sqrt(x));hN
+Lqb;Lmn:gB
+fp_atanh(x
+mU;Lmo:qI
+cDup
+mV
+Lmp:q0
+d6
+g6
+g6
+q5
+TailCall_cAcos;q5
+TailCall_cAcosh;q5
+TailCall_cAnd;q5
+TailCall_cAsin;q5
+TailCall_cAsinh;q5
+TailCall_cAtan;q5
+TailCall_cAtan2;q5
+TailCall_cAtanh;q5
+TailCall_cCeil;q5
+TailCall_cFloor;q5
+TailCall_cInt;q5
+TailCall_cLog;q5
+TailCall_cLog10;q5
+TailCall_cLog2;q5
+TailCall_cMax;q5
+TailCall_cMin;q5
+TailCall_cMod;q5
+TailCall_cOr;q5
+TailCall_cRDiv;q5
+TailCall_cRad;q5
+TailCall_cSec;q5
+TailCall_cSin;q5
+TailCall_cSinh;q5
+TailCall_cSqrt;q5
+hE;q5
+hF;q5
+TailCall_cTanh;q5
+TailCall_cTrunc;
+#endif
+#undef FP_ReDefinePointers
+#undef FP_TRACE_BYTECODE_OPTIMIZATION
+#undef FP_TRACE_OPCODENAME
diff --git a/fparser/fparser.cc b/fparser/fparser.cc
new file mode 100644 (file)
index 0000000..49e6ae0
--- /dev/null
@@ -0,0 +1,3482 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen, Joel Yliluoma                                 *|
+|*                                                                         *|
+|* This library is distributed under the terms of the                      *|
+|* GNU Lesser General Public License version 3.                            *|
+|* (See lgpl.txt and gpl.txt for the license text.)                        *|
+\***************************************************************************/
+
+#include "fpconfig.hh"
+#include "fparser.hh"
+
+#include <set>
+#include <cstdlib>
+#include <cstring>
+#include <cctype>
+#include <cmath>
+#include <cassert>
+#include <limits>
+using namespace std;
+
+#include "fptypes.hh"
+using namespace FUNCTIONPARSERTYPES;
+
+#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA
+#ifndef FP_USE_THREAD_SAFE_EVAL
+#define FP_USE_THREAD_SAFE_EVAL
+#endif
+#endif
+
+#ifdef __GNUC__
+# define likely(x)       __builtin_expect(!!(x), 1)
+# define unlikely(x)     __builtin_expect(!!(x), 0)
+#else
+# define likely(x)   (x)
+# define unlikely(x) (x)
+#endif
+
+
+//=========================================================================
+// Opcode analysis functions
+//=========================================================================
+// These functions are used by the Parse() bytecode optimizer (mostly from
+// code in fp_opcode_add.inc).
+
+bool FUNCTIONPARSERTYPES::IsLogicalOpcode(unsigned op)
+{
+    switch(op)
+    {
+      case cAnd: case cAbsAnd:
+      case cOr:  case cAbsOr:
+      case cNot: case cAbsNot:
+      case cNotNot: case cAbsNotNot:
+      case cEqual: case cNEqual:
+      case cLess: case cLessOrEq:
+      case cGreater: case cGreaterOrEq:
+          return true;
+      default: break;
+    }
+    return false;
+}
+
+bool FUNCTIONPARSERTYPES::IsComparisonOpcode(unsigned op)
+{
+    switch(op)
+    {
+      case cEqual: case cNEqual:
+      case cLess: case cLessOrEq:
+      case cGreater: case cGreaterOrEq:
+          return true;
+      default: break;
+    }
+    return false;
+}
+
+unsigned FUNCTIONPARSERTYPES::OppositeComparisonOpcode(unsigned op)
+{
+    switch(op)
+    {
+      case cLess: return cGreater;
+      case cGreater: return cLess;
+      case cLessOrEq: return cGreaterOrEq;
+      case cGreaterOrEq: return cLessOrEq;
+    }
+    return op;
+}
+
+bool FUNCTIONPARSERTYPES::IsNeverNegativeValueOpcode(unsigned op)
+{
+    switch(op)
+    {
+      case cAnd: case cAbsAnd:
+      case cOr:  case cAbsOr:
+      case cNot: case cAbsNot:
+      case cNotNot: case cAbsNotNot:
+      case cEqual: case cNEqual:
+      case cLess: case cLessOrEq:
+      case cGreater: case cGreaterOrEq:
+      case cSqrt: case cRSqrt: case cSqr:
+      case cHypot:
+      case cAbs:
+      case cAcos: case cCosh:
+          return true;
+      default: break;
+    }
+    return false;
+}
+
+bool FUNCTIONPARSERTYPES::IsAlwaysIntegerOpcode(unsigned op)
+{
+    switch(op)
+    {
+      case cAnd: case cAbsAnd:
+      case cOr:  case cAbsOr:
+      case cNot: case cAbsNot:
+      case cNotNot: case cAbsNotNot:
+      case cEqual: case cNEqual:
+      case cLess: case cLessOrEq:
+      case cGreater: case cGreaterOrEq:
+      case cInt: case cFloor: case cCeil: case cTrunc:
+          return true;
+      default: break;
+    }
+    return false;
+}
+
+bool FUNCTIONPARSERTYPES::IsUnaryOpcode(unsigned op)
+{
+    switch(op)
+    {
+      case cInv: case cNeg:
+      case cNot: case cAbsNot:
+      case cNotNot: case cAbsNotNot:
+      case cSqr: case cRSqrt:
+      case cDeg: case cRad:
+          return true;
+    }
+    return (op < FUNC_AMOUNT && Functions[op].params == 1);
+}
+
+bool FUNCTIONPARSERTYPES::IsBinaryOpcode(unsigned op)
+{
+    switch(op)
+    {
+      case cAdd: case cSub: case cRSub:
+      case cMul: case cDiv: case cRDiv:
+      case cMod:
+      case cEqual: case cNEqual: case cLess:
+      case cLessOrEq: case cGreater: case cGreaterOrEq:
+      case cAnd: case cAbsAnd:
+      case cOr: case cAbsOr:
+          return true;
+    }
+    return (op < FUNC_AMOUNT && Functions[op].params == 2);
+}
+
+bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op)
+{
+#ifndef FP_NO_EVALUATION_CHECKS
+    // Returns true, if the given opcode has a range of
+    // input values that gives an error.
+    switch(op)
+    {
+      case cAcos: // allowed range: |x| <= 1
+      case cAsin: // allowed range: |x| <= 1
+      case cAcosh: // allowed range: x >= 1
+      case cAtanh: // allowed range: |x| < 1
+          //case cCot: // note: no range, just separate values
+          //case cCsc: // note: no range, just separate values
+      case cLog: // allowed range: x > 0
+      case cLog2: // allowed range: x > 0
+      case cLog10: // allowed range: x > 0
+#ifdef FP_SUPPORT_OPTIMIZER
+      case cLog2by: // allowed range: x > 0
+#endif
+          //case cPow: // note: no range, just separate values
+          //case cSec: // note: no range, just separate values
+      case cSqrt: // allowed range: x >= 0
+      case cRSqrt: // allowed range: x > 0
+          //case cDiv: // note: no range, just separate values
+          //case cRDiv: // note: no range, just separate values
+          //case cInv: // note: no range, just separate values
+          return true;
+    }
+#endif
+    return false;
+}
+
+
+//=========================================================================
+// Mathematical template functions
+//=========================================================================
+/* fp_pow() is a wrapper for std::pow()
+ * that produces an identical value for
+ * exp(1) ^ 2.0  (0x4000000000000000)
+ * as exp(2.0)   (0x4000000000000000)
+ * - std::pow() on x86_64
+ * produces 2.0  (0x3FFFFFFFFFFFFFFF) instead!
+ * See comments below for other special traits.
+ */
+namespace
+{
+    template<typename ValueT>
+    inline ValueT fp_pow_with_exp_log(const ValueT& x, const ValueT& y)
+    {
+        // Exponentiation using exp(log(x)*y).
+        // See http://en.wikipedia.org/wiki/Exponentiation#Real_powers
+        // Requirements: x > 0.
+        return fp_exp(fp_log(x) * y);
+    }
+
+    template<typename ValueT>
+    inline ValueT fp_powi(ValueT x, unsigned long y)
+    {
+        // Fast binary exponentiation algorithm
+        // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring
+        // Requirements: y is non-negative integer.
+        ValueT result(1);
+        while(y != 0)
+        {
+            if(y & 1) { result *= x; y -= 1; }
+            else      { x *= x;      y /= 2; }
+        }
+        return result;
+    }
+}
+
+template<typename ValueT>
+ValueT FUNCTIONPARSERTYPES::fp_pow(const ValueT& x, const ValueT& y)
+{
+    if(x == ValueT(1)) return ValueT(1);
+    // y is now zero or positive
+    if(isLongInteger(y))
+    {
+        // Use fast binary exponentiation algorithm
+        if(y >= ValueT(0))
+            return fp_powi(x,              makeLongInteger(y));
+        else
+            return ValueT(1) / fp_powi(x, -makeLongInteger(y));
+    }
+    if(y >= ValueT(0))
+    {
+        // y is now positive. Calculate using exp(log(x)*y).
+        if(x > ValueT(0)) return fp_pow_with_exp_log(x, y);
+        if(x == ValueT(0)) return ValueT(0);
+        // At this point, y > 0.0 and x is known to be < 0.0,
+        // because positive and zero cases are already handled.
+        if(!isInteger(y*ValueT(16)))
+            return -fp_pow_with_exp_log(-x, y);
+        // ^This is not technically correct, but it allows
+        // functions such as cbrt(x^5), that is, x^(5/3),
+        // to be evaluated when x is negative.
+        // It is too complicated (and slow) to test whether y
+        // is a formed from a ratio of an integer to an odd integer.
+        // (And due to floating point inaccuracy, pointless too.)
+        // For example, x^1.30769230769... is
+        // actually x^(17/13), i.e. (x^17) ^ (1/13).
+        // (-5)^(17/13) gives us now -8.204227562330453.
+        // To see whether the result is right, we can test the given
+        // root: (-8.204227562330453)^13 gives us the value of (-5)^17,
+        // which proves that the expression was correct.
+        //
+        // The y*16 check prevents e.g. (-4)^(3/2) from being calculated,
+        // as it would confuse functioninfo when pow() returns no error
+        // but sqrt() does when the formula is converted into sqrt(x)*x.
+        //
+        // The errors in this approach are:
+        //     (-2)^sqrt(2) should produce NaN
+        //                  or actually sqrt(2)I + 2^sqrt(2),
+        //                  produces -(2^sqrt(2)) instead.
+        //                  (Impact: Neglible)
+        // Thus, at worst, we're changing a NaN (or complex)
+        // result into a negative real number result.
+    }
+    else
+    {
+        // y is negative. Utilize the x^y = 1/(x^-y) identity.
+        if(x > ValueT(0)) return fp_pow_with_exp_log(ValueT(1) / x, -y);
+        if(x < ValueT(0))
+        {
+            if(!isInteger(y*ValueT(-16)))
+                return -fp_pow_with_exp_log(ValueT(-1) / x, -y);
+            // ^ See comment above.
+        }
+        // Remaining case: 0.0 ^ negative number
+    }
+    // This is reached when:
+    //      x=0, and y<0
+    //      x<0, and y*16 is either positive or negative integer
+    // It is used for producing error values and as a safe fallback.
+    return fp_pow_base(x, y);
+}
+
+
+//=========================================================================
+// Elementary (atom) parsing functions
+//=========================================================================
+namespace
+{
+    /* Reads an UTF8-encoded sequence which forms a valid identifier name from
+       the given input string and returns its length. If bit 31 is set, the
+       return value also contains the internal function opcode (defined in
+       fptypes.hh) that matches the name.
+    */
+    unsigned readIdentifierForFloatType(const char* input)
+    {
+        /* Assuming unsigned = 32 bits:
+              76543210 76543210 76543210 76543210
+           Return value if built-in function:
+              1PPPPPPP PPPPPPPP LLLLLLLL LLLLLLLL
+                P = function opcode      (15 bits)
+                L = function name length (16 bits)
+           Return value if not built-in function:
+              0LLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL
+                L = identifier length (31 bits)
+           If unsigned has more than 32 bits, the other
+           higher order bits are to be assumed zero.
+        */
+#include "fp_identifier_parser.inc"
+        return 0;
+    }
+
+    inline unsigned readIdentifierForIntType(const char* input)
+    {
+        const unsigned value = readIdentifierForFloatType(input);
+        if((value & 0x80000000U) != 0 &&
+           !Functions[(value >> 16) & 0x7FFF].okForInt())
+            return value & 0xFFFF;
+        return value;
+    }
+
+    template<typename Value_t>
+    inline unsigned readIdentifier(const char* input)
+    {
+        return IsIntType<Value_t>::result
+                ? readIdentifierForIntType(input)
+                : readIdentifierForFloatType(input);
+    }
+
+    // Returns true if the entire string is a valid identifier
+    template<typename Value_t>
+    bool containsOnlyValidIdentifierChars(const std::string& name)
+    {
+        if(name.empty()) return false;
+        return readIdentifier<Value_t>(name.c_str()) == (unsigned) name.size();
+    }
+
+
+    // -----------------------------------------------------------------------
+    // Wrappers for strto... functions
+    // -----------------------------------------------------------------------
+    template<typename Value_t>
+    inline Value_t fp_parseLiteral(const char* str, char** endptr)
+    {
+        return strtod(str, endptr);
+    }
+
+#ifdef FP_SUPPORT_FLOAT_TYPE
+    template<>
+    inline float fp_parseLiteral<float>(const char* str, char** endptr)
+    {
+        return strtof(str, endptr);
+    }
+#endif
+
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+    template<>
+    inline long double fp_parseLiteral<long double>(const char* str,
+                                                    char** endptr)
+    {
+        return strtold(str, endptr);
+    }
+#endif
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+    template<>
+    inline long fp_parseLiteral<long>(const char* str, char** endptr)
+    {
+        return strtol(str, endptr, 10);
+    }
+#endif
+
+
+    // -----------------------------------------------------------------------
+    // Hexadecimal floating point literal parsing
+    // -----------------------------------------------------------------------
+    inline int testXdigit(unsigned c)
+    {
+        if((c-'0') < 10u) return c&15; // 0..9
+        if(((c|0x20)-'a') < 6u) return 9+(c&15); // A..F or a..f
+        return -1; // Not a hex digit
+    }
+
+    template<typename elem_t, unsigned n_limbs, unsigned limb_bits>
+    inline void addXdigit(elem_t* buffer, unsigned nibble)
+    {
+        for(unsigned p=0; p<n_limbs; ++p)
+        {
+            unsigned carry = unsigned( buffer[p] >> (elem_t)(limb_bits-4) );
+            buffer[p] = (buffer[p] << 4) | nibble;
+            nibble = carry;
+        }
+    }
+
+    template<typename Value_t>
+    Value_t parseHexLiteral(const char* str, char** endptr)
+    {
+        const unsigned bits_per_char = 8;
+
+        const int MantissaBits =
+            std::numeric_limits<Value_t>::radix == 2
+            ? std::numeric_limits<Value_t>::digits
+            : (((sizeof(Value_t) * bits_per_char) &~ 3) - 4);
+
+        typedef unsigned long elem_t;
+        const int ExtraMantissaBits = 4 + ((MantissaBits+3)&~3); // Store one digit more for correct rounding
+        const unsigned limb_bits = sizeof(elem_t) * bits_per_char;
+        const unsigned n_limbs   = (ExtraMantissaBits + limb_bits-1) / limb_bits;
+        elem_t mantissa_buffer[n_limbs] = { 0 };
+
+        int n_mantissa_bits = 0; // Track the number of bits
+        int exponent = 0; // The exponent that will be used to multiply the mantissa
+        // Read integer portion
+        while(true)
+        {
+            int xdigit = testXdigit(*str);
+            if(xdigit < 0) break;
+            addXdigit<elem_t,n_limbs,limb_bits> (mantissa_buffer, xdigit);
+            ++str;
+
+            n_mantissa_bits += 4;
+            if(n_mantissa_bits >= ExtraMantissaBits)
+            {
+                // Exhausted the precision. Parse the rest (until exponent)
+                // normally but ignore the actual digits.
+                for(; testXdigit(*str) >= 0; ++str)
+                    exponent += 4;
+                // Read but ignore decimals
+                if(*str == '.')
+                    for(++str; testXdigit(*str) >= 0; ++str)
+                        {}
+                goto read_exponent;
+            }
+        }
+        // Read decimals
+        if(*str == '.')
+            for(++str; ; )
+            {
+                int xdigit = testXdigit(*str);
+                if(xdigit < 0) break;
+                addXdigit<elem_t,n_limbs,limb_bits> (mantissa_buffer, xdigit);
+                ++str;
+
+                exponent -= 4;
+                n_mantissa_bits += 4;
+                if(n_mantissa_bits >= ExtraMantissaBits)
+                {
+                    // Exhausted the precision. Skip the rest
+                    // of the decimals, until the exponent.
+                    while(testXdigit(*str) >= 0)
+                        ++str;
+                    break;
+                }
+            }
+
+        // Read exponent
+    read_exponent:
+        if(*str == 'p' || *str == 'P')
+        {
+            const char* str2 = str+1;
+            long p_exponent = strtol(str2, (char**) &str2, 10);
+            if(str2 != str+1 && p_exponent == (long)(int)p_exponent)
+            {
+                exponent += (int)p_exponent;
+                str = str2;
+            }
+        }
+
+        if(endptr) *endptr = (char*) str;
+
+        Value_t result = ldexp(Value_t(mantissa_buffer[0]), exponent);
+        for(unsigned p=1; p<n_limbs; ++p)
+        {
+            exponent += limb_bits;
+            result += ldexp(Value_t(mantissa_buffer[p]), exponent);
+        }
+        return result;
+    }
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+    template<>
+    long parseHexLiteral<long>(const char* str, char** endptr)
+    {
+        return strtol(str, endptr, 16);
+    }
+#endif
+}
+
+//=========================================================================
+// Utility functions
+//=========================================================================
+namespace
+{
+    // -----------------------------------------------------------------------
+    // Add a new identifier to the specified identifier map
+    // -----------------------------------------------------------------------
+    // Return value will be false if the name already existed
+    template<typename Value_t>
+    bool addNewNameData(NamePtrsMap<Value_t>& namePtrs,
+                        std::pair<NamePtr, NameData<Value_t> >& newName,
+                        bool isVar)
+    {
+        typename NamePtrsMap<Value_t>::iterator nameIter =
+            namePtrs.lower_bound(newName.first);
+
+        if(nameIter != namePtrs.end() && newName.first == nameIter->first)
+        {
+            // redefining a var is not allowed.
+            if(isVar) return false;
+
+            // redefining other tokens is allowed, if the type stays the same.
+            if(nameIter->second.type != newName.second.type)
+                return false;
+
+            // update the data
+            nameIter->second = newName.second;
+            return true;
+        }
+
+        if(!isVar)
+        {
+            // Allocate a copy of the name (pointer stored in the map key)
+            // However, for VARIABLEs, the pointer points to VariableString,
+            // which is managed separately. Thusly, only done when !IsVar.
+            char* namebuf = new char[newName.first.nameLength];
+            memcpy(namebuf, newName.first.name, newName.first.nameLength);
+            newName.first.name = namebuf;
+        }
+
+        namePtrs.insert(nameIter, newName);
+        return true;
+    }
+}
+
+
+//=========================================================================
+// Data struct implementation
+//=========================================================================
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::Data():
+    mReferenceCounter(1),
+    mVariablesAmount(0),
+    mStackSize(0)
+{}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::Data(const Data& rhs):
+    mReferenceCounter(0),
+    mVariablesAmount(rhs.mVariablesAmount),
+    mVariablesString(rhs.mVariablesString),
+    mNamePtrs(),
+    mFuncPtrs(rhs.mFuncPtrs),
+    mFuncParsers(rhs.mFuncParsers),
+    mByteCode(rhs.mByteCode),
+    mImmed(rhs.mImmed),
+#ifndef FP_USE_THREAD_SAFE_EVAL
+    mStack(rhs.mStackSize),
+#endif
+    mStackSize(rhs.mStackSize)
+{
+    for(typename NamePtrsMap<Value_t>::const_iterator i = rhs.mNamePtrs.begin();
+        i != rhs.mNamePtrs.end();
+        ++i)
+    {
+        if(i->second.type == NameData<Value_t>::VARIABLE)
+        {
+            const size_t variableStringOffset =
+                i->first.name - rhs.mVariablesString.c_str();
+            std::pair<NamePtr, NameData<Value_t> > tmp
+                (NamePtr(&mVariablesString[variableStringOffset],
+                         i->first.nameLength),
+                 i->second);
+            mNamePtrs.insert(mNamePtrs.end(), tmp);
+        }
+        else
+        {
+            std::pair<NamePtr, NameData<Value_t> > tmp
+                (NamePtr(new char[i->first.nameLength], i->first.nameLength),
+                 i->second );
+            memcpy(const_cast<char*>(tmp.first.name), i->first.name,
+                   tmp.first.nameLength);
+            mNamePtrs.insert(mNamePtrs.end(), tmp);
+        }
+    }
+}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::~Data()
+{
+    for(typename NamePtrsMap<Value_t>::iterator i = mNamePtrs.begin();
+        i != mNamePtrs.end();
+        ++i)
+    {
+        if(i->second.type != NameData<Value_t>::VARIABLE)
+            delete[] i->first.name;
+    }
+}
+
+
+//=========================================================================
+// FunctionParser constructors, destructor and assignment
+//=========================================================================
+template<typename Value_t>
+FunctionParserBase<Value_t>::FunctionParserBase():
+    mDelimiterChar(0),
+    mParseErrorType(NO_FUNCTION_PARSED_YET), mEvalErrorType(0),
+    mData(new Data),
+    mUseDegreeConversion(false),
+    mEvalRecursionLevel(0),
+    mStackPtr(0), mErrorLocation(0)
+{
+}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::~FunctionParserBase()
+{
+    if(--(mData->mReferenceCounter) == 0)
+        delete mData;
+}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::FunctionParserBase(const FunctionParserBase& cpy):
+    mDelimiterChar(cpy.mDelimiterChar),
+    mParseErrorType(cpy.mParseErrorType),
+    mEvalErrorType(cpy.mEvalErrorType),
+    mData(cpy.mData),
+    mUseDegreeConversion(cpy.mUseDegreeConversion),
+    mEvalRecursionLevel(0),
+    mStackPtr(0), mErrorLocation(0)
+{
+    ++(mData->mReferenceCounter);
+}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>&
+FunctionParserBase<Value_t>::operator=(const FunctionParserBase& cpy)
+{
+    if(mData != cpy.mData)
+    {
+        if(--(mData->mReferenceCounter) == 0) delete mData;
+
+        mDelimiterChar = cpy.mDelimiterChar;
+        mParseErrorType = cpy.mParseErrorType;
+        mEvalErrorType = cpy.mEvalErrorType;
+        mData = cpy.mData;
+        mUseDegreeConversion = cpy.mUseDegreeConversion;
+        mEvalRecursionLevel = cpy.mEvalRecursionLevel;
+
+        ++(mData->mReferenceCounter);
+    }
+
+    return *this;
+}
+
+
+template<typename Value_t>
+void FunctionParserBase<Value_t>::setDelimiterChar(char c)
+{
+    mDelimiterChar = c;
+}
+
+
+//---------------------------------------------------------------------------
+// Copy-on-write method
+//---------------------------------------------------------------------------
+template<typename Value_t>
+void FunctionParserBase<Value_t>::CopyOnWrite()
+{
+    if(mData->mReferenceCounter > 1)
+    {
+        Data* oldData = mData;
+        mData = new Data(*oldData);
+        --(oldData->mReferenceCounter);
+        mData->mReferenceCounter = 1;
+    }
+}
+
+template<typename Value_t>
+void FunctionParserBase<Value_t>::ForceDeepCopy()
+{
+    CopyOnWrite();
+}
+
+
+//=========================================================================
+// User-defined identifier addition functions
+//=========================================================================
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::AddConstant(const std::string& name,
+                                              Value_t value)
+{
+    if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false;
+
+    CopyOnWrite();
+    std::pair<NamePtr, NameData<Value_t> > newName
+        (NamePtr(name.data(), unsigned(name.size())),
+         NameData<Value_t>(NameData<Value_t>::CONSTANT, value));
+
+    return addNewNameData(mData->mNamePtrs, newName, false);
+}
+
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::AddUnit(const std::string& name,
+                                          Value_t value)
+{
+    if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false;
+
+    CopyOnWrite();
+    std::pair<NamePtr, NameData<Value_t> > newName
+        (NamePtr(name.data(), unsigned(name.size())),
+         NameData<Value_t>(NameData<Value_t>::UNIT, value));
+    return addNewNameData(mData->mNamePtrs, newName, false);
+}
+
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::AddFunction
+(const std::string& name, FunctionPtr ptr, unsigned paramsAmount)
+{
+    if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false;
+
+    CopyOnWrite();
+    std::pair<NamePtr, NameData<Value_t> > newName
+        (NamePtr(name.data(), unsigned(name.size())),
+         NameData<Value_t>(NameData<Value_t>::FUNC_PTR,
+                           unsigned(mData->mFuncPtrs.size())));
+
+    const bool success = addNewNameData(mData->mNamePtrs, newName, false);
+    if(success)
+    {
+        mData->mFuncPtrs.push_back(typename Data::FuncPtrData());
+        mData->mFuncPtrs.back().mFuncPtr = ptr;
+        mData->mFuncPtrs.back().mParams = paramsAmount;
+    }
+    return success;
+}
+
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::CheckRecursiveLinking
+(const FunctionParserBase* fp) const
+{
+    if(fp == this) return true;
+    for(unsigned i = 0; i < fp->mData->mFuncParsers.size(); ++i)
+        if(CheckRecursiveLinking(fp->mData->mFuncParsers[i].mParserPtr))
+            return true;
+    return false;
+}
+
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::AddFunction(const std::string& name,
+                                              FunctionParserBase& fp)
+{
+    if(!containsOnlyValidIdentifierChars<Value_t>(name) ||
+       CheckRecursiveLinking(&fp))
+        return false;
+
+    CopyOnWrite();
+    std::pair<NamePtr, NameData<Value_t> > newName
+        (NamePtr(name.data(), unsigned(name.size())),
+         NameData<Value_t>(NameData<Value_t>::PARSER_PTR,
+                           unsigned(mData->mFuncParsers.size())));
+
+    const bool success = addNewNameData(mData->mNamePtrs, newName, false);
+    if(success)
+    {
+        mData->mFuncParsers.push_back(typename Data::FuncPtrData());
+        mData->mFuncParsers.back().mParserPtr = &fp;
+        mData->mFuncParsers.back().mParams = fp.mData->mVariablesAmount;
+    }
+    return success;
+}
+
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::RemoveIdentifier(const std::string& name)
+{
+    CopyOnWrite();
+
+    NamePtr namePtr(name.data(), unsigned(name.size()));
+
+    typename NamePtrsMap<Value_t>::iterator
+        nameIter = mData->mNamePtrs.find(namePtr);
+
+    if(nameIter != mData->mNamePtrs.end())
+    {
+        if(nameIter->second.type == NameData<Value_t>::VARIABLE)
+        {
+            // Illegal attempt to delete variables
+            return false;
+        }
+        delete[] nameIter->first.name;
+        mData->mNamePtrs.erase(nameIter);
+        return true;
+    }
+    return false;
+}
+
+
+//=========================================================================
+// Function parsing
+//=========================================================================
+namespace
+{
+    // Error messages returned by ErrorMsg():
+    const char* const ParseErrorMessage[]=
+    {
+        "Syntax error",                             // 0
+        "Mismatched parenthesis",                   // 1
+        "Missing ')'",                              // 2
+        "Empty parentheses",                        // 3
+        "Syntax error: Operator expected",          // 4
+        "Not enough memory",                        // 5
+        "An unexpected error occurred. Please make a full bug report "
+        "to the author",                            // 6
+        "Syntax error in parameter 'Vars' given to "
+        "FunctionParser::Parse()",                  // 7
+        "Illegal number of parameters to function", // 8
+        "Syntax error: Premature end of string",    // 9
+        "Syntax error: Expecting ( after function", // 10
+        "Syntax error: Unknown identifier",         // 11
+        "(No function has been parsed yet)",
+        ""
+    };
+
+    template<typename Value_t>
+    inline typename FunctionParserBase<Value_t>::ParseErrorType
+    noCommaError(char c)
+    {
+        return c == ')' ?
+            FunctionParserBase<Value_t>::ILL_PARAMS_AMOUNT :
+            FunctionParserBase<Value_t>::SYNTAX_ERROR;
+    }
+
+    template<typename Value_t>
+    inline typename FunctionParserBase<Value_t>::ParseErrorType
+    noParenthError(char c)
+    {
+        return c == ',' ?
+            FunctionParserBase<Value_t>::ILL_PARAMS_AMOUNT :
+            FunctionParserBase<Value_t>::MISSING_PARENTH;
+    }
+
+    template<unsigned offset>
+    struct IntLiteralMask
+    {
+        enum { mask =
+        //    (    1UL << ('-'-offset)) |
+            (0x3FFUL << ('0'-offset)) }; /* 0x3FF = 10 bits worth "1" */
+        // Note: If you change fparser to support negative numbers parsing
+        //       (as opposed to parsing them as cNeg followed by literal),
+        //       enable the '-' line above, and change the offset value
+        //       in BeginsLiteral() to '-' instead of '.'.
+    };
+
+    template<typename Value_t, unsigned offset>
+    struct LiteralMask
+    {
+        enum { mask =
+            (    1UL << ('.'-offset)) |
+            IntLiteralMask<offset>::mask };
+    };
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+    template<unsigned offset>
+    struct LiteralMask<long, offset>: public IntLiteralMask<offset>
+    {
+    };
+#endif
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+    template<unsigned offset>
+    struct LiteralMask<GmpInt, offset>: public IntLiteralMask<offset>
+    {
+    };
+#endif
+
+    template<unsigned offset>
+    struct SimpleSpaceMask
+    {
+        enum { mask =
+            (1UL << ('\r'-offset)) |
+            (1UL << ('\n'-offset)) |
+            (1UL << ('\v'-offset)) |
+            (1UL << ('\t'-offset)) |
+            (1UL << (' ' -offset)) };
+    };
+
+    template<typename Value_t>
+    inline bool BeginsLiteral(unsigned byte)
+    {
+        const unsigned n = sizeof(unsigned long)>=8 ? 0 : '.';
+        byte -= n;
+        if(byte > (unsigned char)('9'-n)) return false;
+        unsigned long shifted = 1UL << byte;
+        const unsigned long mask = LiteralMask<Value_t, n>::mask;
+        return (mask & shifted) != 0;
+    }
+
+    template<typename CharPtr>
+    inline void SkipSpace(CharPtr& function)
+    {
+/*
+        Space characters in unicode:
+U+0020  SPACE                      Depends on font, often adjusted (see below)
+U+00A0  NO-BREAK SPACE             As a space, but often not adjusted
+U+2000  EN QUAD                    1 en (= 1/2 em)
+U+2001  EM QUAD                    1 em (nominally, the height of the font)
+U+2002  EN SPACE                   1 en (= 1/2 em)
+U+2003  EM SPACE                   1 em
+U+2004  THREE-PER-EM SPACE         1/3 em
+U+2005  FOUR-PER-EM SPACE          1/4 em
+U+2006  SIX-PER-EM SPACE           1/6 em
+U+2007  FIGURE SPACE               Tabular width, the width of digits
+U+2008  PUNCTUATION SPACE          The width of a period .
+U+2009  THIN SPACE                 1/5 em (or sometimes 1/6 em)
+U+200A  HAIR SPACE                 Narrower than THIN SPACE
+U+200B  ZERO WIDTH SPACE           Nominally no width, but may expand
+U+202F  NARROW NO-BREAK SPACE      Narrower than NO-BREAK SPACE (or SPACE)
+U+205F  MEDIUM MATHEMATICAL SPACE  4/18 em
+U+3000  IDEOGRAPHIC SPACE          The width of ideographic (CJK) characters.
+        Also:
+U+000A  \n
+U+000D  \r
+U+0009  \t
+U+000B  \v
+        As UTF-8 sequences:
+            09
+            0A
+            0B
+            0D
+            20
+            C2 A0
+            E2 80 80-8B
+            E2 80 AF
+            E2 81 9F
+            E3 80 80
+*/
+        while(true)
+        {
+            const unsigned n = sizeof(unsigned long)>=8 ? 0 : '\t';
+            typedef signed char schar;
+            unsigned byte = (unsigned char)*function;
+            byte -= n;
+            // ^Note: values smaller than n intentionally become
+            //        big values here due to integer wrap. The
+            //        comparison below thus excludes them, making
+            //        the effective range 0x09..0x20 (32-bit)
+            //        or 0x00..0x20 (64-bit) within the if-clause.
+            if(byte <= (unsigned char)(' '-n))
+            {
+                unsigned long shifted = 1UL << byte;
+                const unsigned long mask = SimpleSpaceMask<n>::mask;
+                if(mask & shifted)
+                    { ++function; continue; } // \r, \n, \t, \v and space
+                break;
+            }
+            if(likely(byte < 0xC2-n)) break;
+
+            if(byte == 0xC2-n && function[1] == char(0xA0))
+                { function += 2; continue; } // U+00A0
+            if(byte == 0xE3-n &&
+               function[1] == char(0x80) && function[2] == char(0x80))
+                { function += 3; continue; } // U+3000
+            if(byte == 0xE2-n)
+            {
+                if(function[1] == char(0x81))
+                {
+                    if(function[2] != char(0x9F)) break;
+                    function += 3; // U+205F
+                    continue;
+                }
+                if(function[1] == char(0x80))
+                if(function[2] == char(0xAF) || // U+202F
+                   schar(function[2]) <= schar(0x8B) // U+2000..U+200B
+                  )
+                {
+                    function += 3;
+                    continue;
+                }
+            }
+            break;
+        } // while(true)
+    } // SkipSpace(CharPtr& function)
+}
+
+// ---------------------------------------------------------------------------
+// Return parse error message
+// ---------------------------------------------------------------------------
+template<typename Value_t>
+const char* FunctionParserBase<Value_t>::ErrorMsg() const
+{
+    return ParseErrorMessage[mParseErrorType];
+}
+
+
+// ---------------------------------------------------------------------------
+// Parse variables
+// ---------------------------------------------------------------------------
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::ParseVariables
+(const std::string& inputVarString)
+{
+    if(mData->mVariablesString == inputVarString) return true;
+
+    /* Delete existing variables from mNamePtrs */
+    for(typename NamePtrsMap<Value_t>::iterator i =
+            mData->mNamePtrs.begin();
+        i != mData->mNamePtrs.end(); )
+    {
+        if(i->second.type == NameData<Value_t>::VARIABLE)
+        {
+            typename NamePtrsMap<Value_t>::iterator j (i);
+            ++i;
+            mData->mNamePtrs.erase(j);
+        }
+        else ++i;
+    }
+    mData->mVariablesString = inputVarString;
+
+    const std::string& vars = mData->mVariablesString;
+    const unsigned len = unsigned(vars.size());
+
+    unsigned varNumber = VarBegin;
+
+    const char* beginPtr = vars.c_str();
+    const char* finalPtr = beginPtr + len;
+    while(beginPtr < finalPtr)
+    {
+        SkipSpace(beginPtr);
+        unsigned nameLength = readIdentifier<Value_t>(beginPtr);
+        if(nameLength == 0 || (nameLength & 0x80000000U)) return false;
+        const char* endPtr = beginPtr + nameLength;
+        SkipSpace(endPtr);
+        if(endPtr != finalPtr && *endPtr != ',') return false;
+
+        std::pair<NamePtr, NameData<Value_t> > newName
+            (NamePtr(beginPtr, nameLength),
+             NameData<Value_t>(NameData<Value_t>::VARIABLE, varNumber++));
+
+        if(!addNewNameData(mData->mNamePtrs, newName, true))
+        {
+            return false;
+        }
+
+        beginPtr = endPtr + 1;
+    }
+
+    mData->mVariablesAmount = varNumber - VarBegin;
+    return true;
+}
+
+// ---------------------------------------------------------------------------
+// Parse() public interface functions
+// ---------------------------------------------------------------------------
+template<typename Value_t>
+int FunctionParserBase<Value_t>::Parse(const char* Function,
+                                       const std::string& Vars,
+                                       bool useDegrees)
+{
+    CopyOnWrite();
+
+    if(!ParseVariables(Vars))
+    {
+        mParseErrorType = INVALID_VARS;
+        return int(strlen(Function));
+    }
+
+    return ParseFunction(Function, useDegrees);
+}
+
+template<typename Value_t>
+int FunctionParserBase<Value_t>::Parse(const std::string& Function,
+                                       const std::string& Vars,
+                                       bool useDegrees)
+{
+    CopyOnWrite();
+
+    if(!ParseVariables(Vars))
+    {
+        mParseErrorType = INVALID_VARS;
+        return int(Function.size());
+    }
+
+    return ParseFunction(Function.c_str(), useDegrees);
+}
+
+
+// ---------------------------------------------------------------------------
+// Main parsing function
+// ---------------------------------------------------------------------------
+template<typename Value_t>
+int FunctionParserBase<Value_t>::ParseFunction(const char* function,
+                                               bool useDegrees)
+{
+    mUseDegreeConversion = useDegrees;
+    mParseErrorType = FP_NO_ERROR;
+
+    mData->mInlineVarNames.clear();
+    mData->mByteCode.clear(); mData->mByteCode.reserve(128);
+    mData->mImmed.clear(); mData->mImmed.reserve(128);
+    mData->mStackSize = mStackPtr = 0;
+
+    mHasByteCodeFlags = false;
+
+    const char* ptr = Compile(function);
+    mData->mInlineVarNames.clear();
+
+    if(mHasByteCodeFlags)
+    {
+        for(unsigned i = unsigned(mData->mByteCode.size()); i-- > 0; )
+            mData->mByteCode[i] &= ~0x80000000U;
+    }
+
+    if(mParseErrorType != FP_NO_ERROR) return int(mErrorLocation - function);
+
+    assert(ptr); // Should never be null at this point. It's a bug otherwise.
+    if(*ptr)
+    {
+        if(mDelimiterChar == 0 || *ptr != mDelimiterChar)
+            mParseErrorType = EXPECT_OPERATOR;
+        return int(ptr - function);
+    }
+
+#ifndef FP_USE_THREAD_SAFE_EVAL
+    mData->mStack.resize(mData->mStackSize);
+#endif
+
+    return -1;
+}
+
+
+//=========================================================================
+// Parsing and bytecode compiling functions
+//=========================================================================
+template<typename Value_t>
+inline const char* FunctionParserBase<Value_t>::SetErrorType(ParseErrorType t,
+                                                             const char* pos)
+{
+    mParseErrorType = t;
+    mErrorLocation = pos;
+    return 0;
+}
+
+template<typename Value_t>
+inline void FunctionParserBase<Value_t>::incStackPtr()
+{
+    if(++mStackPtr > mData->mStackSize) ++(mData->mStackSize);
+}
+
+namespace
+{
+    const unsigned char powi_factor_table[128] =
+    {
+        0,1,0,0,0,0,0,0, 0, 0,0,0,0,0,0,3,/*   0 -  15 */
+        0,0,0,0,0,0,0,0, 0, 5,0,3,0,0,3,0,/*  16 -  31 */
+        0,0,0,0,0,0,0,3, 0, 0,0,0,0,5,0,0,/*  32 -  47 */
+        0,0,5,3,0,0,3,5, 0, 3,0,0,3,0,0,3,/*  48 -  63 */
+        0,0,0,0,0,0,0,0, 0, 0,0,3,0,0,3,0,/*  64 -  79 */
+        0,9,0,0,0,5,0,3, 0, 0,5,7,0,0,0,5,/*  80 -  95 */
+        0,0,0,3,5,0,3,0, 0, 3,0,0,3,0,5,3,/*  96 - 111 */
+        0,0,3,5,0,9,0,7, 3,11,0,3,0,5,3,0,/* 112 - 127 */
+    };
+
+    inline int get_powi_factor(long abs_int_exponent)
+    {
+        if(abs_int_exponent >= int(sizeof(powi_factor_table))) return 0;
+        return powi_factor_table[abs_int_exponent];
+    }
+
+#if 0
+    int EstimatePowiComplexity(int abs_int_exponent)
+    {
+        int cost = 0;
+        while(abs_int_exponent > 1)
+        {
+            int factor = get_powi_factor(abs_int_exponent);
+            if(factor)
+            {
+                cost += EstimatePowiComplexity(factor);
+                abs_int_exponent /= factor;
+                continue;
+            }
+            if(!(abs_int_exponent & 1))
+            {
+                abs_int_exponent /= 2;
+                cost += 3; // sqr
+            }
+            else
+            {
+                cost += 4; // dup+mul
+                abs_int_exponent -= 1;
+            }
+        }
+        return cost;
+    }
+#endif
+
+    bool IsEligibleIntPowiExponent(long int_exponent)
+    {
+        if(int_exponent == 0) return false;
+        long abs_int_exponent = int_exponent;
+    #if 0
+        int cost = 0;
+
+        if(abs_int_exponent < 0)
+        {
+            cost += 11;
+            abs_int_exponent = -abs_int_exponent;
+        }
+
+        cost += EstimatePowiComplexity(abs_int_exponent);
+
+        return cost < (10*3 + 4*4);
+    #else
+        if(abs_int_exponent < 0) abs_int_exponent = -abs_int_exponent;
+
+        return (abs_int_exponent >= 1)
+            && (abs_int_exponent <= 46 ||
+              (abs_int_exponent <= 1024 &&
+              (abs_int_exponent & (abs_int_exponent - 1)) == 0));
+    #endif
+    }
+
+#ifdef FP_EPSILON
+    const double EpsilonOrZero = FP_EPSILON;
+#else
+    const double EpsilonOrZero = 0.0;
+#endif
+
+}
+
+template<typename Value_t>
+inline void FunctionParserBase<Value_t>::AddImmedOpcode(Value_t value)
+{
+    mData->mImmed.push_back(value);
+    mData->mByteCode.push_back(cImmed);
+}
+
+template<typename Value_t>
+inline void FunctionParserBase<Value_t>::CompilePowi(long abs_int_exponent)
+{
+    int num_muls=0;
+    while(abs_int_exponent > 1)
+    {
+        long factor = get_powi_factor(abs_int_exponent);
+        if(factor)
+        {
+            CompilePowi(factor);
+            abs_int_exponent /= factor;
+            continue;
+        }
+        if(!(abs_int_exponent & 1))
+        {
+            abs_int_exponent /= 2;
+            mData->mByteCode.push_back(cSqr);
+            // ^ Don't put AddFunctionOpcode here,
+            //   it would slow down a great deal.
+        }
+        else
+        {
+            mData->mByteCode.push_back(cDup);
+            incStackPtr();
+            abs_int_exponent -= 1;
+            ++num_muls;
+        }
+    }
+    if(num_muls > 0)
+    {
+        mData->mByteCode.resize(mData->mByteCode.size()+num_muls, cMul);
+        mStackPtr -= num_muls;
+    }
+}
+
+template<typename Value_t>
+inline bool FunctionParserBase<Value_t>::TryCompilePowi(Value_t original_immed)
+{
+    Value_t changed_immed = original_immed;
+    for(int sqrt_count=0; /**/; ++sqrt_count)
+    {
+        long int_exponent = makeLongInteger(changed_immed);
+        if(isLongInteger(changed_immed) &&
+           IsEligibleIntPowiExponent(int_exponent))
+        {
+            long abs_int_exponent = int_exponent;
+            if(abs_int_exponent < 0)
+                abs_int_exponent = -abs_int_exponent;
+
+            mData->mImmed.pop_back(); mData->mByteCode.pop_back();
+            --mStackPtr;
+            // ^Though the above is accounted for by the procedure
+            // that generates cPow, we need it for correct cFetch
+            // indexes in CompilePowi().
+
+            while(sqrt_count > 0)
+            {
+                int opcode = cSqrt;
+                if(sqrt_count == 1 && int_exponent < 0)
+                {
+                    opcode = cRSqrt;
+                    int_exponent = -int_exponent;
+                }
+                mData->mByteCode.push_back(opcode);
+                --sqrt_count;
+            }
+            if((abs_int_exponent & 1) == 0)
+            {
+                // This special rule fixes the optimization
+                // shortcoming of (-x)^2 with minimal overhead.
+                AddFunctionOpcode(cSqr);
+                abs_int_exponent >>= 1;
+            }
+            CompilePowi(abs_int_exponent);
+            if(int_exponent < 0) mData->mByteCode.push_back(cInv);
+            ++mStackPtr; // Needed because cPow adding will assume this.
+            return true;
+        }
+        if(sqrt_count >= 4) break;
+        changed_immed += changed_immed;
+    }
+
+    // When we don't know whether x >= 0, we still know that
+    // x^y can be safely converted into exp(y * log(x))
+    // when y is _not_ integer, because we know that x >= 0.
+    // Otherwise either expression will give a NaN.
+    if(/*!isInteger(original_immed) ||*/
+       IsNeverNegativeValueOpcode(mData->mByteCode[mData->mByteCode.size()-2]))
+    {
+        mData->mImmed.pop_back();
+        mData->mByteCode.pop_back();
+        //--mStackPtr; - accounted for by the procedure that generates cPow
+        AddFunctionOpcode(cLog);
+        AddImmedOpcode(original_immed);
+        //incStackPtr(); - this and the next are redundant because...
+        AddFunctionOpcode(cMul);
+        //--mStackPtr;    - ...because the cImmed was popped earlier.
+        AddFunctionOpcode(cExp);
+        return true;
+    }
+    return false;
+}
+
+//#include "fpoptimizer/opcodename.hh"
+// ^ needed only if FP_TRACE_BYTECODE_OPTIMIZATION() is used
+
+template<typename Value_t>
+inline void FunctionParserBase<Value_t>::AddFunctionOpcode(unsigned opcode)
+{
+#define FP_FLOAT_VERSION 1
+#include "fp_opcode_add.inc"
+#undef FP_FLOAT_VERSION
+}
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+template<>
+inline void FunctionParserBase<long>::AddFunctionOpcode(unsigned opcode)
+{
+    typedef long Value_t;
+#define FP_FLOAT_VERSION 0
+#include "fp_opcode_add.inc"
+#undef FP_FLOAT_VERSION
+}
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+template<>
+inline void FunctionParserBase<GmpInt>::AddFunctionOpcode(unsigned opcode)
+{
+    typedef GmpInt Value_t;
+#define FP_FLOAT_VERSION 0
+#include "fp_opcode_add.inc"
+#undef FP_FLOAT_VERSION
+}
+#endif
+
+template<typename Value_t>
+unsigned
+FunctionParserBase<Value_t>::ParseIdentifier(const char* function)
+{
+    return readIdentifier<Value_t>(function);
+}
+
+template<typename Value_t>
+std::pair<const char*, Value_t>
+FunctionParserBase<Value_t>::ParseLiteral(const char* function)
+{
+    char* endptr;
+#if 0 /* Profile the hex literal parser */
+    if(function[0]=='0' && function[1]=='x')
+    {
+        // Parse hexadecimal literal if fp_parseLiteral didn't already
+        Value_t val = parseHexLiteral<Value_t>(function+2, &endptr);
+        if(endptr == function+2)
+            return std::pair<const char*,Value_t> (function, Value_t());
+        return std::pair<const char*, Value_t> (endptr, val);
+    }
+#endif
+    Value_t val = fp_parseLiteral<Value_t>(function, &endptr);
+
+    if(endptr == function+1 && function[0] == '0' && function[1] == 'x')
+    {
+        // Parse hexadecimal literal if fp_parseLiteral didn't already
+        val = parseHexLiteral<Value_t>(function+2, &endptr);
+        if(endptr == function+2)
+            return std::pair<const char*,Value_t> (function, Value_t());
+    }
+    else if(endptr == function)
+        return std::pair<const char*,Value_t> (function, Value_t());
+
+    return std::pair<const char*,Value_t> (endptr, val);
+}
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+template<>
+std::pair<const char*, MpfrFloat>
+FunctionParserBase<MpfrFloat>::ParseLiteral(const char* function)
+{
+    char* endPtr;
+    const MpfrFloat val = MpfrFloat::parseString(function, &endPtr);
+    if(endPtr == function)
+        return std::pair<const char*,MpfrFloat> (function, MpfrFloat());
+    return std::pair<const char*,MpfrFloat> (endPtr, val);
+}
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+template<>
+std::pair<const char*, GmpInt>
+FunctionParserBase<GmpInt>::ParseLiteral(const char* function)
+{
+    char* endPtr;
+    const GmpInt val = GmpInt::parseString(function, &endPtr);
+    if(endPtr == function)
+        return std::pair<const char*,GmpInt> (function, GmpInt());
+    return std::pair<const char*,GmpInt> (endPtr, val);
+}
+#endif
+
+
+template<typename Value_t>
+inline const char*
+FunctionParserBase<Value_t>::CompileLiteral(const char* function)
+{
+    std::pair<const char*, Value_t> result = ParseLiteral(function);
+
+    if(result.first == function)
+        return SetErrorType(SYNTAX_ERROR, result.first);
+
+    AddImmedOpcode(result.second);
+    incStackPtr();
+    SkipSpace(result.first);
+    return result.first;
+}
+
+template<typename Value_t>
+const char* FunctionParserBase<Value_t>::CompileIf(const char* function)
+{
+    if(*function != '(') return SetErrorType(EXPECT_PARENTH_FUNC, function);
+
+    function = CompileExpression(function+1);
+    if(!function) return 0;
+    if(*function != ',')
+        return SetErrorType(noCommaError<Value_t>(*function), function);
+
+    OPCODE opcode = cIf;
+    if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back();
+    if(IsNeverNegativeValueOpcode(mData->mByteCode.back()))
+    {
+        // If we know that the condition to be tested is always
+        // a positive value (such as when produced by "x<y"),
+        // we can use the faster opcode to evaluate it.
+        // cIf tests whether fabs(cond) >= 0.5,
+        // cAbsIf simply tests whether cond >= 0.5.
+        opcode = cAbsIf;
+    }
+
+    mData->mByteCode.push_back(opcode);
+    const unsigned curByteCodeSize = unsigned(mData->mByteCode.size());
+    PushOpcodeParam<false>(0); // Jump index; to be set later
+    PushOpcodeParam<true> (0); // Immed jump index; to be set later
+
+    --mStackPtr;
+
+    function = CompileExpression(function + 1);
+    if(!function) return 0;
+    if(*function != ',')
+        return SetErrorType(noCommaError<Value_t>(*function), function);
+
+    mData->mByteCode.push_back(cJump);
+    const unsigned curByteCodeSize2 = unsigned(mData->mByteCode.size());
+    const unsigned curImmedSize2 = unsigned(mData->mImmed.size());
+    PushOpcodeParam<false>(0); // Jump index; to be set later
+    PushOpcodeParam<true> (0); // Immed jump index; to be set later
+
+    --mStackPtr;
+
+    function = CompileExpression(function + 1);
+    if(!function) return 0;
+    if(*function != ')')
+        return SetErrorType(noParenthError<Value_t>(*function), function);
+
+    PutOpcodeParamAt<true> ( mData->mByteCode.back(), unsigned(mData->mByteCode.size()-1) );
+    // ^Necessary for guarding against if(x,1,2)+1 being changed
+    //  into if(x,1,3) by fp_opcode_add.inc
+
+    // Set jump indices
+    PutOpcodeParamAt<false>( curByteCodeSize2+1, curByteCodeSize );
+    PutOpcodeParamAt<false>( curImmedSize2,      curByteCodeSize+1 );
+    PutOpcodeParamAt<false>( unsigned(mData->mByteCode.size())-1, curByteCodeSize2);
+    PutOpcodeParamAt<false>( unsigned(mData->mImmed.size()),      curByteCodeSize2+1);
+
+    ++function;
+    SkipSpace(function);
+    return function;
+}
+
+template<typename Value_t>
+const char* FunctionParserBase<Value_t>::CompileFunctionParams
+(const char* function, unsigned requiredParams)
+{
+    if(*function != '(') return SetErrorType(EXPECT_PARENTH_FUNC, function);
+
+    if(requiredParams > 0)
+    {
+        const char* function_end = CompileExpression(function+1);
+        if(!function_end)
+        {
+            // If an error occurred, verify whether it was caused by ()
+            ++function;
+            SkipSpace(function);
+            if(*function == ')')
+                return SetErrorType(ILL_PARAMS_AMOUNT, function);
+            // Not caused by (), use the error message given by CompileExpression()
+            return 0;
+        }
+        function = function_end;
+
+        for(unsigned i = 1; i < requiredParams; ++i)
+        {
+            if(*function != ',')
+                return SetErrorType(noCommaError<Value_t>(*function), function);
+
+            function = CompileExpression(function+1);
+            if(!function) return 0;
+        }
+        // No need for incStackPtr() because each parse parameter calls it
+        mStackPtr -= requiredParams-1;
+    }
+    else
+    {
+        incStackPtr(); // return value of function is pushed onto the stack
+        ++function;
+        SkipSpace(function);
+    }
+
+    if(*function != ')')
+        return SetErrorType(noParenthError<Value_t>(*function), function);
+    ++function;
+    SkipSpace(function);
+    return function;
+}
+
+template<typename Value_t>
+const char* FunctionParserBase<Value_t>::CompileElement(const char* function)
+{
+    if(BeginsLiteral<Value_t>( (unsigned char) *function))
+        return CompileLiteral(function);
+
+    unsigned nameLength = readIdentifier<Value_t>(function);
+    if(nameLength == 0)
+    {
+        // No identifier found
+        if(*function == '(') return CompileParenthesis(function);
+        if(*function == ')') return SetErrorType(MISM_PARENTH, function);
+        return SetErrorType(SYNTAX_ERROR, function);
+    }
+
+    // Function, variable or constant
+    if(nameLength & 0x80000000U) // Function
+    {
+        OPCODE func_opcode = OPCODE( (nameLength >> 16) & 0x7FFF );
+        return CompileFunction(function + (nameLength & 0xFFFF), func_opcode);
+    }
+
+    NamePtr name(function, nameLength);
+    const char* endPtr = function + nameLength;
+    SkipSpace(endPtr);
+
+    typename NamePtrsMap<Value_t>::iterator nameIter =
+        mData->mNamePtrs.find(name);
+    if(nameIter == mData->mNamePtrs.end())
+    {
+        // Check if it's an inline variable:
+        for(typename Data::InlineVarNamesContainer::reverse_iterator iter =
+                mData->mInlineVarNames.rbegin();
+            iter != mData->mInlineVarNames.rend();
+            ++iter)
+        {
+            if(name == iter->mName)
+            {
+                if( iter->mFetchIndex+1 == mStackPtr)
+                {
+                    mData->mByteCode.push_back(cDup);
+                }
+                else
+                {
+                    mData->mByteCode.push_back(cFetch);
+                    PushOpcodeParam<true>(iter->mFetchIndex);
+                }
+                incStackPtr();
+                return endPtr;
+            }
+        }
+
+        return SetErrorType(UNKNOWN_IDENTIFIER, function);
+    }
+
+    const NameData<Value_t>* nameData = &nameIter->second;
+    switch(nameData->type)
+    {
+      case NameData<Value_t>::VARIABLE: // is variable
+          if(unlikely(!mData->mByteCode.empty() &&
+                      mData->mByteCode.back() == nameData->index))
+              mData->mByteCode.push_back(cDup);
+          else
+              mData->mByteCode.push_back(nameData->index);
+          incStackPtr();
+          return endPtr;
+
+      case NameData<Value_t>::CONSTANT: // is constant
+          AddImmedOpcode(nameData->value);
+          incStackPtr();
+          return endPtr;
+
+      case NameData<Value_t>::UNIT: // is unit (error if appears here)
+          break;
+
+      case NameData<Value_t>::FUNC_PTR: // is C++ function
+          function = CompileFunctionParams
+              (endPtr, mData->mFuncPtrs[nameData->index].mParams);
+          //if(!function) return 0;
+          mData->mByteCode.push_back(cFCall);
+          PushOpcodeParam<true>(nameData->index);
+          return function;
+
+      case NameData<Value_t>::PARSER_PTR: // is FunctionParser
+          function = CompileFunctionParams
+              (endPtr, mData->mFuncParsers[nameData->index].mParams);
+          //if(!function) return 0;
+          mData->mByteCode.push_back(cPCall);
+          PushOpcodeParam<true>(nameData->index);
+          return function;
+    }
+
+    // When it's an unit (or unrecognized type):
+    return SetErrorType(SYNTAX_ERROR, function);
+}
+
+template<typename Value_t>
+inline const char* FunctionParserBase<Value_t>::CompileFunction
+(const char* function, unsigned func_opcode)
+{
+    SkipSpace(function);
+    const FuncDefinition& funcDef = Functions[func_opcode];
+
+    if(func_opcode == cIf) // "if" is a special case
+        return CompileIf(function);
+
+    unsigned requiredParams = funcDef.params;
+#ifndef FP_DISABLE_EVAL
+    if(func_opcode == cEval)
+        requiredParams = mData->mVariablesAmount;
+#endif
+
+    function = CompileFunctionParams(function, requiredParams);
+    if(!function) return 0;
+
+    if(mUseDegreeConversion)
+    {
+        if(funcDef.flags & FuncDefinition::AngleIn)
+            AddFunctionOpcode(cRad);
+
+        AddFunctionOpcode(func_opcode);
+
+        if(funcDef.flags & FuncDefinition::AngleOut)
+            AddFunctionOpcode(cDeg);
+    }
+    else
+    {
+        AddFunctionOpcode(func_opcode);
+    }
+    return function;
+}
+
+template<typename Value_t>
+inline const char*
+FunctionParserBase<Value_t>::CompileParenthesis(const char* function)
+{
+    ++function; // Skip '('
+
+    SkipSpace(function);
+    if(*function == ')') return SetErrorType(EMPTY_PARENTH, function);
+    function = CompileExpression(function);
+    if(!function) return 0;
+
+    if(*function != ')') return SetErrorType(MISSING_PARENTH, function);
+    ++function; // Skip ')'
+
+    SkipSpace(function);
+    return function;
+}
+
+template<typename Value_t>
+const char*
+FunctionParserBase<Value_t>::CompilePossibleUnit(const char* function)
+{
+    unsigned nameLength = readIdentifier<Value_t>(function);
+    if(nameLength & 0x80000000U) return function; // built-in function name
+    if(nameLength != 0)
+    {
+        NamePtr name(function, nameLength);
+
+        typename NamePtrsMap<Value_t>::iterator nameIter =
+            mData->mNamePtrs.find(name);
+        if(nameIter != mData->mNamePtrs.end())
+        {
+            const NameData<Value_t>* nameData = &nameIter->second;
+            if(nameData->type == NameData<Value_t>::UNIT)
+            {
+                AddImmedOpcode(nameData->value);
+                incStackPtr();
+                AddFunctionOpcode(cMul);
+                --mStackPtr;
+
+                const char* endPtr = function + nameLength;
+                SkipSpace(endPtr);
+                return endPtr;
+            }
+        }
+    }
+
+    return function;
+}
+
+template<typename Value_t>
+inline const char*
+FunctionParserBase<Value_t>::CompilePow(const char* function)
+{
+    function = CompileElement(function);
+    if(!function) return 0;
+    function = CompilePossibleUnit(function);
+
+    if(*function == '^')
+    {
+        ++function;
+        SkipSpace(function);
+
+        unsigned op = cPow;
+        if(mData->mByteCode.back() == cImmed)
+        {
+            if(mData->mImmed.back() == fp_const_e<Value_t>())
+                { op = cExp;  mData->mByteCode.pop_back();
+                    mData->mImmed.pop_back(); --mStackPtr; }
+            else if(mData->mImmed.back() == Value_t(2))
+                { op = cExp2; mData->mByteCode.pop_back();
+                    mData->mImmed.pop_back(); --mStackPtr; }
+        }
+
+        function = CompileUnaryMinus(function);
+        if(!function) return 0;
+
+        // add opcode
+        AddFunctionOpcode(op);
+
+        if(op == cPow) --mStackPtr;
+    }
+    return function;
+}
+
+/* Currently the power operator is skipped for integral types because its
+   usefulness with them is questionable, and in the case of GmpIng, for safety
+   reasons.
+   - With long int almost any power, except for very small ones, would
+     overflow the result, so the usefulness of this is rather questionable.
+   - With GmpInt the power operator could be easily abused to make the program
+     run out of memory (think of a function like "10^10^10^10^1000000").
+*/
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+template<>
+inline const char*
+FunctionParserBase<long>::CompilePow(const char* function)
+{
+    function = CompileElement(function);
+    if(!function) return 0;
+    return CompilePossibleUnit(function);
+}
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+template<>
+inline const char*
+FunctionParserBase<GmpInt>::CompilePow(const char* function)
+{
+    function = CompileElement(function);
+    if(!function) return 0;
+    return CompilePossibleUnit(function);
+}
+#endif
+
+template<typename Value_t>
+inline const char*
+FunctionParserBase<Value_t>::CompileUnaryMinus(const char* function)
+{
+    char op = *function;
+    switch(op)
+    {
+        case '-':
+        case '!':
+            ++function;
+            SkipSpace(function);
+
+            function = CompileUnaryMinus(function);
+            if(!function) return 0;
+
+            AddFunctionOpcode(op=='-' ? cNeg : cNot);
+
+            return function;
+        default: break;
+    }
+    return CompilePow(function);
+}
+
+template<typename Value_t>
+inline const char*
+FunctionParserBase<Value_t>::CompileMult(const char* function)
+{
+    function = CompileUnaryMinus(function);
+    if(!function) return 0;
+
+    Value_t pending_immed(1);
+    #define FP_FlushImmed(do_reset) \
+        if(pending_immed != Value_t(1)) \
+        { \
+            unsigned op = cMul; \
+            if(!IsIntType<Value_t>::result && mData->mByteCode.back() == cInv) \
+            { \
+                /* (...) cInv 5 cMul -> (...) 5 cRDiv */ \
+                /*           ^               ^      | */ \
+                mData->mByteCode.pop_back(); \
+                op = cRDiv; \
+            } \
+            AddImmedOpcode(pending_immed); \
+            incStackPtr(); \
+            AddFunctionOpcode(op); \
+            --mStackPtr; \
+            if(do_reset) pending_immed = Value_t(1); \
+        }
+    while(true)
+    {
+        char c = *function;
+        if(c == '%')
+        {
+            FP_FlushImmed(true);
+            ++function;
+            SkipSpace(function);
+            function = CompileUnaryMinus(function);
+            if(!function) return 0;
+            AddFunctionOpcode(cMod);
+            --mStackPtr;
+            continue;
+        }
+        if(c != '*' && c != '/') break;
+
+        bool safe_cumulation = (c == '*' || !IsIntType<Value_t>::result);
+        if(!safe_cumulation)
+        {
+            FP_FlushImmed(true);
+        }
+
+        ++function;
+        SkipSpace(function);
+        if(mData->mByteCode.back() == cImmed
+        && (safe_cumulation
+         || mData->mImmed.back() == Value_t(1)))
+        {
+            // 5 (...) cMul --> (...)      ||| 5 cMul
+            // 5 (...) cDiv --> (...) cInv ||| 5 cMul
+            //  ^          |              ^
+            pending_immed *= mData->mImmed.back();
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            --mStackPtr;
+            function = CompileUnaryMinus(function);
+            if(!function) return 0;
+            if(c == '/')
+                AddFunctionOpcode(cInv);
+            continue;
+        }
+        if(safe_cumulation
+        && mData->mByteCode.back() == cMul
+        && mData->mByteCode[mData->mByteCode.size()-2] == cImmed)
+        {
+            // (:::) 5 cMul (...) cMul -> (:::) (...) cMul  ||| 5 cMul
+            // (:::) 5 cMul (...) cDiv -> (:::) (...) cDiv  ||| 5 cMul
+            //             ^                   ^
+            pending_immed *= mData->mImmed.back();
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            mData->mByteCode.pop_back();
+        }
+        // cDiv is not tested here because the bytecode
+        // optimizer will convert this kind of cDivs into cMuls.
+        bool lhs_inverted = false;
+        if(!IsIntType<Value_t>::result && c == '*'
+        && mData->mByteCode.back() == cInv)
+        {
+            // (:::) cInv (...) cMul -> (:::) (...) cRDiv
+            // (:::) cInv (...) cDiv -> (:::) (...) cMul cInv
+            //           ^                   ^            |
+            mData->mByteCode.pop_back();
+            lhs_inverted = true;
+        }
+        function = CompileUnaryMinus(function);
+        if(!function) return 0;
+        if(safe_cumulation
+        && mData->mByteCode.back() == cMul
+        && mData->mByteCode[mData->mByteCode.size()-2] == cImmed)
+        {
+            // (:::) (...) 5 cMul cMul -> (:::) (...) cMul  |||  5 Mul
+            // (:::) (...) 5 cMul cDiv -> (:::) (...) cDiv  ||| /5 Mul
+            //                   ^                        ^
+            if(c == '*')
+                pending_immed *= mData->mImmed.back();
+            else
+                pending_immed /= mData->mImmed.back();
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            mData->mByteCode.pop_back();
+        }
+        else
+        if(safe_cumulation
+        && mData->mByteCode.back() == cRDiv
+        && mData->mByteCode[mData->mByteCode.size()-2] == cImmed)
+        {
+            // (:::) (...) 5 cRDiv cMul -> (:::) (...) cDiv  |||  5 cMul
+            // (:::) (...) 5 cRDiv cDiv -> (:::) (...) cMul  ||| /5 cMul
+            //                    ^                   ^
+            if(c == '*')
+                { c = '/'; pending_immed *= mData->mImmed.back(); }
+            else
+                { c = '*'; pending_immed /= mData->mImmed.back(); }
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            mData->mByteCode.pop_back();
+        }
+        if(!lhs_inverted) // if (/x/y) was changed to /(x*y), add missing cInv
+        {
+            AddFunctionOpcode(c == '*' ? cMul : cDiv);
+            --mStackPtr;
+        }
+        else if(c == '*') // (/x)*y -> rdiv(x,y)
+        {
+            AddFunctionOpcode(cRDiv);
+            --mStackPtr;
+        }
+        else // (/x)/y -> /(x*y)
+        {
+            AddFunctionOpcode(cMul);
+            --mStackPtr;
+            AddFunctionOpcode(cInv);
+        }
+    }
+    FP_FlushImmed(false);
+    #undef FP_FlushImmed
+    return function;
+}
+
+template<typename Value_t>
+inline const char*
+FunctionParserBase<Value_t>::CompileAddition(const char* function)
+{
+    function = CompileMult(function);
+    if(!function) return 0;
+
+    Value_t pending_immed(0);
+    #define FP_FlushImmed(do_reset) \
+        if(pending_immed != Value_t(0)) \
+        { \
+            unsigned op = cAdd; \
+            if(mData->mByteCode.back() == cNeg) \
+            { \
+                /* (...) cNeg 5 cAdd -> (...) 5 cRSub */ \
+                /*           ^               ^      | */ \
+                mData->mByteCode.pop_back(); \
+                op = cRSub; \
+            } \
+            AddImmedOpcode(pending_immed); \
+            incStackPtr(); \
+            AddFunctionOpcode(op); \
+            --mStackPtr; \
+            if(do_reset) pending_immed = Value_t(0); \
+        }
+    while(true)
+    {
+        char c = *function;
+        if(c != '+' && c != '-') break;
+        ++function;
+        SkipSpace(function);
+        if(mData->mByteCode.back() == cImmed)
+        {
+            // 5 (...) cAdd --> (...)      ||| 5 cAdd
+            // 5 (...) cSub --> (...) cNeg ||| 5 cAdd
+            //  ^          |              ^
+            pending_immed += mData->mImmed.back();
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            --mStackPtr;
+            function = CompileMult(function);
+            if(!function) return 0;
+            if(c == '-')
+                AddFunctionOpcode(cNeg);
+            continue;
+        }
+        if(mData->mByteCode.back() == cAdd
+        && mData->mByteCode[mData->mByteCode.size()-2] == cImmed)
+        {
+            // (:::) 5 cAdd (...) cAdd -> (:::) (...) cAdd  ||| 5 cAdd
+            // (:::) 5 cAdd (...) cSub -> (:::) (...) cSub  ||| 5 cAdd
+            //             ^                   ^
+            pending_immed += mData->mImmed.back();
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            mData->mByteCode.pop_back();
+        }
+        // cSub is not tested here because the bytecode
+        // optimizer will convert this kind of cSubs into cAdds.
+        bool lhs_negated = false;
+        if(mData->mByteCode.back() == cNeg)
+        {
+            // (:::) cNeg (...) cAdd -> (:::) (...) cRSub
+            // (:::) cNeg (...) cSub -> (:::) (...) cAdd cNeg
+            //           ^                   ^            |
+            mData->mByteCode.pop_back();
+            lhs_negated = true;
+        }
+        function = CompileMult(function);
+        if(!function) return 0;
+        if(mData->mByteCode.back() == cAdd
+        && mData->mByteCode[mData->mByteCode.size()-2] == cImmed)
+        {
+            // (:::) (...) 5 cAdd cAdd -> (:::) (...) cAdd  |||  5 Add
+            // (:::) (...) 5 cAdd cSub -> (:::) (...) cSub  ||| -5 Add
+            //                   ^                        ^
+            if(c == '+')
+                pending_immed += mData->mImmed.back();
+            else
+                pending_immed -= mData->mImmed.back();
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            mData->mByteCode.pop_back();
+        }
+        else
+        if(mData->mByteCode.back() == cRSub
+        && mData->mByteCode[mData->mByteCode.size()-2] == cImmed)
+        {
+            // (:::) (...) 5 cRSub cAdd -> (:::) (...) cSub  |||  5 cAdd
+            // (:::) (...) 5 cRSub cSub -> (:::) (...) cAdd  ||| -5 cAdd
+            //                    ^                   ^
+            if(c == '+')
+                { c = '-'; pending_immed += mData->mImmed.back(); }
+            else
+                { c = '+'; pending_immed -= mData->mImmed.back(); }
+            mData->mImmed.pop_back();
+            mData->mByteCode.pop_back();
+            mData->mByteCode.pop_back();
+        }
+        if(!lhs_negated) // if (-x-y) was changed to -(x+y), add missing cNeg
+        {
+            AddFunctionOpcode(c == '+' ? cAdd : cSub);
+            --mStackPtr;
+        }
+        else if(c == '+') // (-x)+y -> rsub(x,y)
+        {
+            AddFunctionOpcode(cRSub);
+            --mStackPtr;
+        }
+        else // (-x)-y -> -(x+y)
+        {
+            AddFunctionOpcode(cAdd);
+            --mStackPtr;
+            AddFunctionOpcode(cNeg);
+        }
+    }
+    FP_FlushImmed(false);
+    #undef FP_FlushImmed
+    return function;
+}
+
+template<typename Value_t>
+inline const char*
+FunctionParserBase<Value_t>::CompileComparison(const char* function)
+{
+    unsigned op=0;
+    while(true)
+    {
+        function = CompileAddition(function);
+        if(!function) return 0;
+
+        if(op)
+        {
+            AddFunctionOpcode(op);
+            --mStackPtr;
+        }
+        switch(*function)
+        {
+          case '=':
+              ++function; op = cEqual; break;
+          case '!':
+              if(function[1] == '=')
+              { function += 2; op = cNEqual; break; }
+              // If '=' does not follow '!', a syntax error will
+              // be generated at the outermost parsing level
+              return function;
+          case '<':
+              if(function[1] == '=')
+              { function += 2; op = cLessOrEq; break; }
+              ++function; op = cLess; break;
+          case '>':
+              if(function[1] == '=')
+              { function += 2; op = cGreaterOrEq; break; }
+              ++function; op = cGreater; break;
+          default: return function;
+        }
+        SkipSpace(function);
+    }
+    return function;
+}
+
+template<typename Value_t>
+inline const char* FunctionParserBase<Value_t>::CompileAnd(const char* function)
+{
+    size_t param0end=0;
+    while(true)
+    {
+        function = CompileComparison(function);
+        if(!function) return 0;
+
+        if(param0end)
+        {
+            if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back();
+
+            AddFunctionOpcode(cAnd);
+            --mStackPtr;
+        }
+        if(*function != '&') break;
+        ++function;
+        SkipSpace(function);
+        param0end = mData->mByteCode.size();
+    }
+    return function;
+}
+
+template<typename Value_t>
+const char* FunctionParserBase<Value_t>::CompileExpression(const char* function)
+{
+    size_t param0end=0;
+    while(true)
+    {
+        SkipSpace(function);
+        function = CompileAnd(function);
+        if(!function) return 0;
+
+        if(param0end)
+        {
+            if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back();
+
+            AddFunctionOpcode(cOr);
+            --mStackPtr;
+        }
+        if(*function != '|') break;
+        ++function;
+        param0end = mData->mByteCode.size();
+    }
+    return function;
+}
+
+template<typename Value_t>
+const char* FunctionParserBase<Value_t>::Compile(const char* function)
+{
+    while(true)
+    {
+        // Check if an identifier appears as first token:
+        SkipSpace(function);
+        unsigned nameLength = readIdentifier<Value_t>(function);
+        if(nameLength > 0 && !(nameLength & 0x80000000U))
+        {
+            typename Data::InlineVariable inlineVar =
+                { NamePtr(function, nameLength), 0 };
+
+            // Check if it's an unknown identifier:
+            typename NamePtrsMap<Value_t>::iterator nameIter =
+                mData->mNamePtrs.find(inlineVar.mName);
+            if(nameIter == mData->mNamePtrs.end())
+            {
+                const char* function2 = function + nameLength;
+                SkipSpace(function2);
+
+                // Check if ":=" follows the unknown identifier:
+                if(function2[0] == ':' && function2[1] == '=')
+                {
+                    // Parse the expression that follows and create the
+                    // inline variable:
+                    function2 = CompileExpression(function2 + 2);
+                    if(!function2) return 0;
+                    if(*function2 != ';') return function2;
+
+                    inlineVar.mFetchIndex = mStackPtr - 1;
+                    mData->mInlineVarNames.push_back(inlineVar);
+
+                    // Continue with the expression after the ';':
+                    function = function2 + 1;
+                    continue;
+                }
+            }
+        }
+        break;
+    }
+
+    return CompileExpression(function);
+}
+
+template<typename Value_t> template<bool PutFlag>
+inline void FunctionParserBase<Value_t>::PushOpcodeParam
+    (unsigned value)
+{
+    mData->mByteCode.push_back(value | (PutFlag ? 0x80000000U : 0u));
+    if(PutFlag) mHasByteCodeFlags = true;
+}
+
+template<typename Value_t> template<bool PutFlag>
+inline void FunctionParserBase<Value_t>::PutOpcodeParamAt
+    (unsigned value, unsigned offset)
+{
+    mData->mByteCode[offset] = value | (PutFlag ? 0x80000000U : 0u);
+    if(PutFlag) mHasByteCodeFlags = true;
+}
+
+//===========================================================================
+// Function evaluation
+//===========================================================================
+template<typename Value_t>
+Value_t FunctionParserBase<Value_t>::Eval(const Value_t* Vars)
+{
+    if(mParseErrorType != FP_NO_ERROR) return Value_t(0);
+
+    const unsigned* const byteCode = &(mData->mByteCode[0]);
+    const Value_t* const immed = mData->mImmed.empty() ? 0 : &(mData->mImmed[0]);
+    const unsigned byteCodeSize = unsigned(mData->mByteCode.size());
+    unsigned IP, DP=0;
+    int SP=-1;
+
+#ifdef FP_USE_THREAD_SAFE_EVAL
+    /* If Eval() may be called by multiple threads simultaneously,
+     * then Eval() must allocate its own stack.
+     */
+#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA
+    /* alloca() allocates room from the hardware stack.
+     * It is automatically freed when the function returns.
+     */
+    Value_t* const Stack = (Value_t*)alloca(mData->mStackSize*sizeof(Value_t));
+#else
+    /* Allocate from the heap. Ensure that it is freed
+     * automatically no matter which exit path is taken.
+     */
+    struct AutoDealloc
+    {
+        Value_t* ptr;
+        ~AutoDealloc() { delete[] ptr; }
+    } AutoDeallocStack = { new Value_t[mData->mStackSize] };
+    Value_t*& Stack = AutoDeallocStack.ptr;
+#endif
+#else
+    /* No thread safety, so use a global stack. */
+    std::vector<Value_t>& Stack = mData->mStack;
+#endif
+
+    for(IP=0; IP<byteCodeSize; ++IP)
+    {
+        switch(byteCode[IP])
+        {
+// Functions:
+          case   cAbs: Stack[SP] = fp_abs(Stack[SP]); break;
+
+          case  cAcos:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1))
+              { mEvalErrorType=4; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_acos(Stack[SP]); break;
+
+          case cAcosh:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] < Value_t(1))
+              { mEvalErrorType=4; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_acosh(Stack[SP]); break;
+
+          case  cAsin:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1))
+              { mEvalErrorType=4; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_asin(Stack[SP]); break;
+
+          case cAsinh: Stack[SP] = fp_asinh(Stack[SP]); break;
+
+          case  cAtan: Stack[SP] = fp_atan(Stack[SP]); break;
+
+          case cAtan2: Stack[SP-1] = fp_atan2(Stack[SP-1], Stack[SP]);
+                       --SP; break;
+
+          case cAtanh:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] <= Value_t(-1) || Stack[SP] >= Value_t(1))
+              { mEvalErrorType=4; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_atanh(Stack[SP]); break;
+
+          case  cCbrt: Stack[SP] = fp_cbrt(Stack[SP]); break;
+
+          case  cCeil: Stack[SP] = fp_ceil(Stack[SP]); break;
+
+          case   cCos: Stack[SP] = fp_cos(Stack[SP]); break;
+
+          case  cCosh: Stack[SP] = fp_cosh(Stack[SP]); break;
+
+          case   cCot:
+              {
+                  const Value_t t = fp_tan(Stack[SP]);
+#               ifndef FP_NO_EVALUATION_CHECKS
+                  if(t == Value_t(0)) { mEvalErrorType=1; return Value_t(0); }
+#               endif
+                  Stack[SP] = Value_t(1)/t; break;
+              }
+
+          case   cCsc:
+              {
+                  const Value_t s = fp_sin(Stack[SP]);
+#               ifndef FP_NO_EVALUATION_CHECKS
+                  if(s == 0) { mEvalErrorType=1; return Value_t(0); }
+#               endif
+                  Stack[SP] = Value_t(1)/s; break;
+              }
+
+
+#       ifndef FP_DISABLE_EVAL
+          case  cEval:
+              {
+                  const unsigned varAmount = mData->mVariablesAmount;
+                  Value_t retVal = Value_t(0);
+                  if(mEvalRecursionLevel == FP_EVAL_MAX_REC_LEVEL)
+                  {
+                      mEvalErrorType = 5;
+                  }
+                  else
+                  {
+                      ++mEvalRecursionLevel;
+#                   ifndef FP_USE_THREAD_SAFE_EVAL
+                      /* Eval() will use mData->mStack for its storage.
+                       * Swap the current stack with an empty one.
+                       * This is the not-thread-safe method.
+                       */
+                      std::vector<Value_t> tmpStack(Stack.size());
+                      mData->mStack.swap(tmpStack);
+                      retVal = Eval(&tmpStack[SP - varAmount + 1]);
+                      mData->mStack.swap(tmpStack);
+#                   else
+                      /* Thread safety mode. We don't need to
+                       * worry about stack reusing here, because
+                       * each instance of Eval() will allocate
+                       * their own stack.
+                       */
+                      retVal = Eval(&Stack[SP - varAmount + 1]);
+#                   endif
+                      --mEvalRecursionLevel;
+                  }
+                  SP -= varAmount-1;
+                  Stack[SP] = retVal;
+                  break;
+              }
+#       endif
+
+          case   cExp: Stack[SP] = fp_exp(Stack[SP]); break;
+
+          case   cExp2: Stack[SP] = fp_exp2(Stack[SP]); break;
+
+          case cFloor: Stack[SP] = fp_floor(Stack[SP]); break;
+
+          case cHypot:
+              Stack[SP-1] = fp_hypot(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case    cIf:
+                  if(fp_truth(Stack[SP--]))
+                      IP += 2;
+                  else
+                  {
+                      const unsigned* buf = &byteCode[IP+1];
+                      IP = buf[0];
+                      DP = buf[1];
+                  }
+                  break;
+
+          case   cInt: Stack[SP] = fp_int(Stack[SP]); break;
+
+          case   cLog:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(!(Stack[SP] > Value_t(0)))
+              { mEvalErrorType=3; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_log(Stack[SP]); break;
+
+          case cLog10:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(!(Stack[SP] > Value_t(0)))
+              { mEvalErrorType=3; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_log10(Stack[SP]);
+              break;
+
+          case  cLog2:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(!(Stack[SP] > Value_t(0)))
+              { mEvalErrorType=3; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_log2(Stack[SP]);
+              break;
+
+          case   cMax: Stack[SP-1] = fp_max(Stack[SP-1], Stack[SP]);
+                       --SP; break;
+
+          case   cMin: Stack[SP-1] = fp_min(Stack[SP-1], Stack[SP]);
+                       --SP; break;
+
+          case   cPow:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              // x:Negative ^ y:NonInteger is failure,
+              // except when the reciprocal of y forms an integer
+              /*if(Stack[SP-1] < Value_t(0) &&
+                 !isInteger(Stack[SP]) &&
+                 !isInteger(1.0 / Stack[SP]))
+              { mEvalErrorType=3; return Value_t(0); }*/
+              // x:0 ^ y:negative is failure
+              if(Stack[SP-1] == Value_t(0) &&
+                 Stack[SP] < Value_t(0))
+              { mEvalErrorType=3; return Value_t(0); }
+#           endif
+              Stack[SP-1] = fp_pow(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case  cTrunc: Stack[SP] = fp_trunc(Stack[SP]); break;
+
+          case   cSec:
+              {
+                  const Value_t c = fp_cos(Stack[SP]);
+#               ifndef FP_NO_EVALUATION_CHECKS
+                  if(c == Value_t(0)) { mEvalErrorType=1; return Value_t(0); }
+#               endif
+                  Stack[SP] = Value_t(1)/c; break;
+              }
+
+          case   cSin: Stack[SP] = fp_sin(Stack[SP]); break;
+
+          case  cSinh: Stack[SP] = fp_sinh(Stack[SP]); break;
+
+          case  cSqrt:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] < Value_t(0)) { mEvalErrorType=2; return Value_t(0); }
+#           endif
+              Stack[SP] = fp_sqrt(Stack[SP]); break;
+
+          case   cTan: Stack[SP] = fp_tan(Stack[SP]); break;
+
+          case  cTanh: Stack[SP] = fp_tanh(Stack[SP]); break;
+
+
+// Misc:
+          case cImmed: Stack[++SP] = immed[DP++]; break;
+
+          case  cJump:
+              {
+                  const unsigned* buf = &byteCode[IP+1];
+                  IP = buf[0];
+                  DP = buf[1];
+                  break;
+              }
+
+// Operators:
+          case   cNeg: Stack[SP] = -Stack[SP]; break;
+          case   cAdd: Stack[SP-1] += Stack[SP]; --SP; break;
+          case   cSub: Stack[SP-1] -= Stack[SP]; --SP; break;
+          case   cMul: Stack[SP-1] *= Stack[SP]; --SP; break;
+
+          case   cDiv:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+#           else
+              if(IsIntType<Value_t>::result && Stack[SP] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+#           endif
+              Stack[SP-1] /= Stack[SP]; --SP; break;
+
+          case   cMod:
+              if(Stack[SP] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+              Stack[SP-1] = fp_mod(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case cEqual:
+              Stack[SP-1] = fp_equal(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case cNEqual:
+              Stack[SP-1] = fp_nequal(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case  cLess:
+              Stack[SP-1] = fp_less(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case  cLessOrEq:
+              Stack[SP-1] = fp_lessOrEq(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case cGreater:
+              Stack[SP-1] = fp_less(Stack[SP], Stack[SP-1]);
+              --SP; break;
+
+          case cGreaterOrEq:
+              Stack[SP-1] = fp_lessOrEq(Stack[SP], Stack[SP-1]);
+              --SP; break;
+
+          case   cNot: Stack[SP] = fp_not(Stack[SP]); break;
+
+          case cNotNot: Stack[SP] = fp_notNot(Stack[SP]); break;
+
+          case   cAnd:
+              Stack[SP-1] = fp_and(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+          case    cOr:
+              Stack[SP-1] = fp_or(Stack[SP-1], Stack[SP]);
+              --SP; break;
+
+// Degrees-radians conversion:
+          case   cDeg: Stack[SP] = RadiansToDegrees(Stack[SP]); break;
+          case   cRad: Stack[SP] = DegreesToRadians(Stack[SP]); break;
+
+// User-defined function calls:
+          case cFCall:
+              {
+                  unsigned index = byteCode[++IP];
+                  unsigned params = mData->mFuncPtrs[index].mParams;
+                  Value_t retVal =
+                      mData->mFuncPtrs[index].mFuncPtr(&Stack[SP-params+1]);
+                  SP -= int(params)-1;
+                  Stack[SP] = retVal;
+                  break;
+              }
+
+          case cPCall:
+              {
+                  unsigned index = byteCode[++IP];
+                  unsigned params = mData->mFuncParsers[index].mParams;
+                  Value_t retVal =
+                      mData->mFuncParsers[index].mParserPtr->Eval
+                      (&Stack[SP-params+1]);
+                  SP -= int(params)-1;
+                  Stack[SP] = retVal;
+                  const int error =
+                      mData->mFuncParsers[index].mParserPtr->EvalError();
+                  if(error)
+                  {
+                      mEvalErrorType = error;
+                      return 0;
+                  }
+                  break;
+              }
+
+
+          case   cFetch:
+              {
+                  unsigned stackOffs = byteCode[++IP];
+                  Stack[SP+1] = Stack[stackOffs]; ++SP;
+                  break;
+              }
+
+#ifdef FP_SUPPORT_OPTIMIZER
+          case   cPopNMov:
+              {
+                  unsigned stackOffs_target = byteCode[++IP];
+                  unsigned stackOffs_source = byteCode[++IP];
+                  Stack[stackOffs_target] = Stack[stackOffs_source];
+                  SP = stackOffs_target;
+                  break;
+              }
+
+          case  cLog2by:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP-1] <= Value_t(0))
+              { mEvalErrorType=3; return Value_t(0); }
+#           endif
+              Stack[SP-1] = fp_log2(Stack[SP-1]) * Stack[SP];
+              --SP;
+              break;
+
+          case cNop: break;
+#endif // FP_SUPPORT_OPTIMIZER
+
+          case cSinCos:
+              fp_sinCos(Stack[SP], Stack[SP+1], Stack[SP]);
+              ++SP;
+              break;
+
+          case cAbsNot:
+              Stack[SP] = fp_absNot(Stack[SP]); break;
+          case cAbsNotNot:
+              Stack[SP] = fp_absNotNot(Stack[SP]); break;
+          case cAbsAnd:
+              Stack[SP-1] = fp_absAnd(Stack[SP-1], Stack[SP]);
+              --SP; break;
+          case cAbsOr:
+              Stack[SP-1] = fp_absOr(Stack[SP-1], Stack[SP]);
+              --SP; break;
+          case cAbsIf:
+              if(fp_absTruth(Stack[SP--]))
+                  IP += 2;
+              else
+              {
+                  const unsigned* buf = &byteCode[IP+1];
+                  IP = buf[0];
+                  DP = buf[1];
+              }
+              break;
+
+          case   cDup: Stack[SP+1] = Stack[SP]; ++SP; break;
+
+          case   cInv:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+#           else
+              if(IsIntType<Value_t>::result && Stack[SP] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+#           endif
+              Stack[SP] = Value_t(1)/Stack[SP];
+              break;
+
+          case   cSqr:
+              Stack[SP] = Stack[SP]*Stack[SP];
+              break;
+
+          case   cRDiv:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP-1] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+#           else
+              if(IsIntType<Value_t>::result && Stack[SP-1] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+#           endif
+              Stack[SP-1] = Stack[SP] / Stack[SP-1]; --SP; break;
+
+          case   cRSub: Stack[SP-1] = Stack[SP] - Stack[SP-1]; --SP; break;
+
+          case   cRSqrt:
+#           ifndef FP_NO_EVALUATION_CHECKS
+              if(Stack[SP] == Value_t(0))
+              { mEvalErrorType=1; return Value_t(0); }
+#           endif
+              Stack[SP] = Value_t(1) / fp_sqrt(Stack[SP]); break;
+
+
+// Variables:
+          default:
+              Stack[++SP] = Vars[byteCode[IP]-VarBegin];
+        }
+    }
+
+    mEvalErrorType=0;
+    return Stack[SP];
+}
+
+
+//===========================================================================
+// Variable deduction
+//===========================================================================
+namespace
+{
+    template<typename Value_t>
+    int deduceVariables(FunctionParserBase<Value_t>& fParser,
+                        const char* funcStr,
+                        std::string& destVarString,
+                        int* amountOfVariablesFound,
+                        std::vector<std::string>* destVarNames,
+                        bool useDegrees)
+    {
+        typedef std::set<std::string> StrSet;
+        StrSet varNames;
+
+        int oldIndex = -1;
+
+        while(true)
+        {
+            destVarString.clear();
+            for(StrSet::iterator iter = varNames.begin();
+                iter != varNames.end();
+                ++iter)
+            {
+                if(iter != varNames.begin()) destVarString += ",";
+                destVarString += *iter;
+            }
+
+            const int index =
+                fParser.Parse(funcStr, destVarString, useDegrees);
+            if(index < 0) break;
+            if(index == oldIndex) return index;
+
+            unsigned nameLength = readIdentifier<Value_t>(funcStr + index);
+            if(nameLength & 0x80000000U) return index;
+            if(nameLength == 0) return index;
+
+            varNames.insert(std::string(funcStr + index, nameLength));
+            oldIndex = index;
+        }
+
+        if(amountOfVariablesFound)
+            *amountOfVariablesFound = int(varNames.size());
+
+        if(destVarNames)
+            destVarNames->assign(varNames.begin(), varNames.end());
+
+        return -1;
+    }
+}
+
+template<typename Value_t>
+int FunctionParserBase<Value_t>::ParseAndDeduceVariables
+(const std::string& function,
+ int* amountOfVariablesFound,
+ bool useDegrees)
+{
+    std::string varString;
+    return deduceVariables(*this, function.c_str(), varString,
+                           amountOfVariablesFound, 0, useDegrees);
+}
+
+template<typename Value_t>
+int FunctionParserBase<Value_t>::ParseAndDeduceVariables
+(const std::string& function,
+ std::string& resultVarString,
+ int* amountOfVariablesFound,
+ bool useDegrees)
+{
+    std::string varString;
+    const int index =
+        deduceVariables(*this, function.c_str(), varString,
+                        amountOfVariablesFound, 0, useDegrees);
+    if(index < 0) resultVarString = varString;
+    return index;
+}
+
+template<typename Value_t>
+int FunctionParserBase<Value_t>::ParseAndDeduceVariables
+(const std::string& function,
+ std::vector<std::string>& resultVars,
+ bool useDegrees)
+{
+    std::string varString;
+    std::vector<std::string> vars;
+    const int index =
+        deduceVariables(*this, function.c_str(), varString,
+                        0, &vars, useDegrees);
+    if(index < 0) resultVars.swap(vars);
+    return index;
+}
+
+
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+//===========================================================================
+// Bytecode injection
+//===========================================================================
+template<typename Value_t>
+void FunctionParserBase<Value_t>::InjectRawByteCode
+(const unsigned* bytecode, unsigned bytecodeAmount,
+ const Value_t* immed, unsigned immedAmount, unsigned stackSize)
+{
+    CopyOnWrite();
+
+    mData->mByteCode.assign(bytecode, bytecode + bytecodeAmount);
+    mData->mImmed.assign(immed, immed + immedAmount);
+    mData->mStackSize = stackSize;
+
+#ifndef FP_USE_THREAD_SAFE_EVAL
+    mData->mStack.resize(stackSize);
+#endif
+}
+
+//===========================================================================
+// Debug output
+//===========================================================================
+#include <iomanip>
+#include <sstream>
+namespace
+{
+    inline void printHex(std::ostream& dest, unsigned n)
+    {
+        std::ios::fmtflags flags = dest.flags();
+        dest.width(4); dest.fill('0'); std::hex(dest); //uppercase(dest);
+        dest << n;
+        dest.flags(flags);
+    }
+
+    void padLine(std::ostringstream& dest, unsigned destLength)
+    {
+        for(size_t currentLength = dest.str().length();
+            currentLength < destLength;
+            ++currentLength)
+        {
+            dest << ' ';
+        }
+    }
+
+    template<typename Value_t>
+    std::string findName(const NamePtrsMap<Value_t>& nameMap,
+                         unsigned index,
+                         typename NameData<Value_t>::DataType type)
+    {
+        for(typename NamePtrsMap<Value_t>::const_iterator
+                iter = nameMap.begin();
+            iter != nameMap.end();
+            ++iter)
+        {
+            if(iter->second.type == type && iter->second.index == index)
+                return std::string(iter->first.name,
+                                   iter->first.name + iter->first.nameLength);
+        }
+        return "?";
+    }
+
+    const struct PowiMuliType
+    {
+        unsigned opcode_square;
+        unsigned opcode_cumulate;
+        unsigned opcode_invert;
+        unsigned opcode_half;
+        unsigned opcode_invhalf;
+    } iseq_powi = {cSqr,cMul,cInv,cSqrt,cRSqrt},
+      iseq_muli = {~unsigned(0), cAdd,cNeg, ~unsigned(0),~unsigned(0) };
+
+    template<typename Value_t>
+    Value_t ParsePowiMuli(
+        const PowiMuliType& opcodes,
+        const std::vector<unsigned>& ByteCode, unsigned& IP,
+        unsigned limit,
+        size_t factor_stack_base,
+        std::vector<Value_t>& stack,
+        bool IgnoreExcess)
+    {
+        Value_t result = Value_t(1);
+        while(IP < limit)
+        {
+            if(ByteCode[IP] == opcodes.opcode_square)
+            {
+                if(!isInteger(result)) break;
+                result *= Value_t(2);
+                ++IP;
+                continue;
+            }
+            if(ByteCode[IP] == opcodes.opcode_invert)
+            {
+                if(result < Value_t(0)) break;
+                result = -result;
+                ++IP;
+                continue;
+            }
+            if(ByteCode[IP] == opcodes.opcode_half)
+            {
+                if(result > Value_t(0) && isEvenInteger(result))
+                    break;
+                if(isInteger(result * Value_t(0.5))) break;
+                result *= Value_t(0.5);
+                ++IP;
+                continue;
+            }
+            if(ByteCode[IP] == opcodes.opcode_invhalf)
+            {
+                if(result > Value_t(0) && isEvenInteger(result))
+                    break;
+                if(isInteger(result * Value_t(-0.5))) break;
+                result *= Value_t(-0.5);
+                ++IP;
+                continue;
+            }
+
+            unsigned dup_fetch_pos = IP;
+            Value_t lhs = Value_t(1);
+
+            if(ByteCode[IP] == cFetch)
+            {
+                unsigned index = ByteCode[++IP];
+                if(index < factor_stack_base
+                || size_t(index-factor_stack_base) >= stack.size())
+                {
+                    // It wasn't a powi-fetch after all
+                    IP = dup_fetch_pos;
+                    break;
+                }
+                lhs = stack[index - factor_stack_base];
+                // Note: ^This assumes that cFetch of recentmost
+                //        is always converted into cDup.
+                goto dup_or_fetch;
+            }
+
+            if(ByteCode[IP] == cDup)
+            {
+                lhs = result;
+                goto dup_or_fetch;
+
+            dup_or_fetch:
+                stack.push_back(result);
+                ++IP;
+                Value_t subexponent = ParsePowiMuli
+                    (opcodes,
+                     ByteCode, IP, limit,
+                     factor_stack_base, stack,
+                     IgnoreExcess);
+                if(IP >= limit && IgnoreExcess)
+                    return lhs*subexponent;
+                if(IP >= limit || ByteCode[IP] != opcodes.opcode_cumulate)
+                {
+                    // It wasn't a powi-dup after all
+                    IP = dup_fetch_pos;
+                    break;
+                }
+                ++IP; // skip opcode_cumulate
+                stack.pop_back();
+                result += lhs*subexponent;
+                continue;
+            }
+            break;
+        }
+        return result;
+    }
+
+    template<typename Value_t>
+    Value_t ParsePowiSequence(const std::vector<unsigned>& ByteCode,
+                              unsigned& IP, unsigned limit,
+                              size_t factor_stack_base,
+                              bool IgnoreExcess = false)
+    {
+        std::vector<Value_t> stack;
+        stack.push_back(Value_t(1));
+        return ParsePowiMuli(iseq_powi, ByteCode, IP, limit,
+                             factor_stack_base, stack,
+                             IgnoreExcess);
+    }
+
+    template<typename Value_t>
+    Value_t ParseMuliSequence(const std::vector<unsigned>& ByteCode,
+                              unsigned& IP, unsigned limit,
+                              size_t factor_stack_base,
+                              bool IgnoreExcess = false)
+    {
+        std::vector<Value_t> stack;
+        stack.push_back(Value_t(1));
+        return ParsePowiMuli(iseq_muli, ByteCode, IP, limit,
+                             factor_stack_base, stack,
+                             IgnoreExcess);
+    }
+
+    struct IfInfo
+    {
+        std::pair<int,std::string> condition;
+        std::pair<int,std::string> thenbranch;
+        unsigned endif_location;
+
+        IfInfo() : condition(), thenbranch(), endif_location() { }
+    };
+}
+
+template<typename Value_t>
+void FunctionParserBase<Value_t>::PrintByteCode(std::ostream& dest,
+                                                bool showExpression) const
+{
+    dest << "Size of stack: " << mData->mStackSize << "\n";
+
+    std::ostringstream outputBuffer;
+    std::ostream& output = (showExpression ? outputBuffer : dest);
+
+    const std::vector<unsigned>& ByteCode = mData->mByteCode;
+    const std::vector<Value_t>& Immed = mData->mImmed;
+
+    std::vector<std::pair<int,std::string> > stack;
+    std::vector<IfInfo> if_stack;
+
+    for(unsigned IP = 0, DP = 0; IP <= ByteCode.size(); ++IP)
+    {
+    after_powi_or_muli:;
+        std::string n;
+        bool out_params = false;
+        unsigned params = 2, produces = 1, opcode = 0;
+
+        if(showExpression && !if_stack.empty() &&
+          (   // Normal If termination rule:
+              if_stack.back().endif_location == IP
+              // This rule matches when cJumps are threaded:
+           || (IP < ByteCode.size() && ByteCode[IP] == cJump
+               && !if_stack.back().thenbranch.second.empty())
+          ))
+        {
+            printHex(output, IP);
+            if(if_stack.back().endif_location == IP)
+                output << ": ----- (phi)";
+            else
+                output << ": ----- (phi+)";
+
+            stack.resize(stack.size()+2);
+            std::swap(stack[stack.size()-3], stack[stack.size()-1]);
+            std::swap(if_stack.back().condition,  stack[stack.size()-3]);
+            std::swap(if_stack.back().thenbranch, stack[stack.size()-2]);
+            opcode = cIf;
+            params = 3;
+            --IP;
+            if_stack.pop_back();
+        }
+        else
+        {
+            if(IP >= ByteCode.size()) break;
+            opcode = ByteCode[IP];
+
+            if(showExpression && (
+                opcode == cSqr || opcode == cDup
+             || opcode == cInv
+             || opcode == cSqrt || opcode == cRSqrt
+             || opcode == cFetch
+            ))
+            {
+                unsigned changed_ip = IP;
+                Value_t exponent =
+                    ParsePowiSequence<Value_t>
+                    (ByteCode, changed_ip,
+                     if_stack.empty()
+                     ? (unsigned)ByteCode.size()
+                     : if_stack.back().endif_location,
+                     stack.size()-1);
+                std::string        operation_prefix;
+                std::ostringstream operation_value;
+                int prio = 0;
+                if(exponent == 1.0)
+                {
+                    if(opcode != cDup) goto not_powi_or_muli;
+                    Value_t factor =
+                        ParseMuliSequence<Value_t>
+                        (ByteCode, changed_ip,
+                         if_stack.empty()
+                         ? (unsigned)ByteCode.size()
+                         : if_stack.back().endif_location,
+                         stack.size()-1);
+                    if(factor == Value_t(1) || factor == Value_t(-1))
+                        goto not_powi_or_muli;
+                    operation_prefix = "*";
+                    operation_value << factor;
+                    prio = 3;
+                }
+                else
+                {
+                    prio = 2;
+                    operation_prefix = "^";
+                    operation_value << exponent;
+                }
+
+                //unsigned explanation_before = changed_ip-2;
+                unsigned explanation_before = changed_ip-1;
+
+                const char* explanation_prefix = "_";
+                for(const unsigned first_ip = IP; IP < changed_ip; ++IP)
+                {
+                    printHex(output, IP);
+                    output << ": ";
+
+                    const char* sep = "|";
+                    if(first_ip+1 == changed_ip)
+                    { sep = "="; explanation_prefix = " "; }
+                    else if(IP   == first_ip) sep = "\\";
+                    else if(IP+1 == changed_ip) sep = "/";
+                    else explanation_prefix = "=";
+
+                    switch(ByteCode[IP])
+                    {
+                        case cInv: output << "inv"; break;
+                        case cNeg: output << "neg"; break;
+                        case cDup: output << "dup"; break;
+                        case cSqr: output << "sqr"; break;
+                        case cMul: output << "mul"; break;
+                        case cAdd: output << "add"; break;
+                        case cCbrt: output << "cbrt"; break;
+                        case cSqrt: output << "sqrt"; break;
+                        case cRSqrt: output << "rsqrt"; break;
+                        case cFetch:
+                        {
+                            unsigned index = ByteCode[++IP];
+                            output << "cFetch(" << index << ")";
+                            break;
+                        }
+                        default: break;
+                    }
+                    padLine(outputBuffer, 20);
+                    output << sep;
+                    if(IP >= explanation_before)
+                    {
+                        explanation_before = (unsigned)ByteCode.size();
+                        output << explanation_prefix
+                               << '[' << (stack.size()-1) << ']';
+                        std::string last = stack.back().second;
+                        if(stack.back().first >= prio)
+                            last = "(" + last + ")";
+                        output << last;
+                        output << operation_prefix;
+                        output << operation_value.str();
+                    }
+                    else
+                    {
+                        unsigned p = first_ip;
+                        Value_t exp = operation_prefix=="^" ?
+                            ParsePowiSequence<Value_t>
+                            (ByteCode, p, IP+1, stack.size()-1, true) :
+                            ParseMuliSequence<Value_t>
+                            (ByteCode, p, IP+1, stack.size()-1, true);
+                        std::string last = stack.back().second;
+                        if(stack.back().first >= prio)
+                            last = "(" + last + ")";
+                        output << " ..." << last;
+                        output << operation_prefix;
+                        output << exp;
+                    }
+                    dest << outputBuffer.str() << std::endl;
+                    outputBuffer.str("");
+                }
+
+                std::string& last = stack.back().second;
+                if(stack.back().first >= prio)
+                    last = "(" + last + ")";
+                last += operation_prefix;
+                last += operation_value.str();
+                stack.back().first = prio;
+
+                goto after_powi_or_muli;
+            }
+        not_powi_or_muli:;
+            printHex(output, IP);
+            output << ": ";
+
+            switch(opcode)
+            {
+              case cIf:
+              {
+                  unsigned label = ByteCode[IP+1]+1;
+                  output << "jz ";
+                  printHex(output, label);
+                  params = 1;
+                  produces = 0;
+                  IP += 2;
+
+                  if_stack.resize(if_stack.size() + 1);
+                  std::swap( if_stack.back().condition, stack.back() );
+                  if_stack.back().endif_location = (unsigned) ByteCode.size();
+                  stack.pop_back();
+                  break;
+              }
+              case cAbsIf:
+              {
+                  unsigned dp    = ByteCode[IP+2];
+                  unsigned label = ByteCode[IP+1]+1;
+                  output << "jz_abs " << dp << ",";
+                  printHex(output, label);
+                  params = 1;
+                  produces = 0;
+                  IP += 2;
+
+                  if_stack.resize(if_stack.size() + 1);
+                  std::swap( if_stack.back().condition, stack.back() );
+                  if_stack.back().endif_location = (unsigned) ByteCode.size();
+                  stack.pop_back();
+                  break;
+              }
+
+              case cJump:
+              {
+                  unsigned dp    = ByteCode[IP+2];
+                  unsigned label = ByteCode[IP+1]+1;
+
+                  if(!if_stack.empty() && !stack.empty())
+                  {
+                      std::swap(if_stack.back().thenbranch, stack.back());
+                      if_stack.back().endif_location = label;
+                      stack.pop_back();
+                  }
+
+                  output << "jump " << dp << ",";
+                  printHex(output, label);
+                  params = 0;
+                  produces = 0;
+                  IP += 2;
+                  break;
+              }
+              case cImmed:
+              {
+                  if(showExpression)
+                  {
+                      std::ostringstream buf;
+                      buf.precision(8);
+                      buf << Immed[DP];
+                      stack.push_back( std::make_pair(0, buf.str()) );
+                  }
+                  output.precision(8);
+                  output << "push " << Immed[DP];
+                  ++DP;
+                  produces = 0;
+                  break;
+              }
+
+              case cFCall:
+                  {
+                      const unsigned index = ByteCode[++IP];
+                      params = mData->mFuncPtrs[index].mParams;
+                      static std::string name;
+                      name = "f:" + findName(mData->mNamePtrs, index,
+                                             NameData<Value_t>::FUNC_PTR);
+                      n = name.c_str();
+                      out_params = true;
+                      break;
+                  }
+
+              case cPCall:
+                  {
+                      const unsigned index = ByteCode[++IP];
+                      params = mData->mFuncParsers[index].mParams;
+                      static std::string name;
+                      name = "p:" + findName(mData->mNamePtrs, index,
+                                             NameData<Value_t>::PARSER_PTR);
+                      n = name.c_str();
+                      out_params = true;
+                      break;
+                  }
+
+              default:
+                  if(OPCODE(opcode) < VarBegin)
+                  {
+                      switch(opcode)
+                      {
+                        case cNeg: n = "neg"; params = 1; break;
+                        case cAdd: n = "add"; break;
+                        case cSub: n = "sub"; break;
+                        case cMul: n = "mul"; break;
+                        case cDiv: n = "div"; break;
+                        case cMod: n = "mod"; break;
+                        case cPow: n = "pow"; break;
+                        case cEqual: n = "eq"; break;
+                        case cNEqual: n = "neq"; break;
+                        case cLess: n = "lt"; break;
+                        case cLessOrEq: n = "le"; break;
+                        case cGreater: n = "gt"; break;
+                        case cGreaterOrEq: n = "ge"; break;
+                        case cAnd: n = "and"; break;
+                        case cOr: n = "or"; break;
+                        case cNot: n = "not"; params = 1; break;
+                        case cNotNot: n = "notnot"; params = 1; break;
+                        case cDeg: n = "deg"; params = 1; break;
+                        case cRad: n = "rad"; params = 1; break;
+
+    #ifndef FP_DISABLE_EVAL
+                        case cEval: n = "eval"; params = mData->mVariablesAmount;
+    #endif
+
+                        case cFetch:
+                        {
+                            unsigned index = ByteCode[++IP];
+                            if(showExpression && index < stack.size())
+                                stack.push_back(stack[index]);
+                            output << "cFetch(" << index << ")";
+                            produces = 0;
+                            break;
+                        }
+    #ifdef FP_SUPPORT_OPTIMIZER
+                        case cLog2by: n = "log2by"; params = 2; out_params = 1; break;
+                        case cPopNMov:
+                        {
+                            size_t a = ByteCode[++IP];
+                            size_t b = ByteCode[++IP];
+                            if(showExpression && b < stack.size())
+                            {
+                                std::pair<int, std::string> stacktop(0, "?");
+                                if(b < stack.size()) stacktop = stack[b];
+                                stack.resize(a);
+                                stack.push_back(stacktop);
+                            }
+                            output << "cPopNMov(" << a << ", " << b << ")";
+                            produces = 0;
+                            break;
+                        }
+                        case cNop:
+                            output << "nop"; params = 0; produces = 0;
+                            break;
+    #endif
+                        case cSinCos:
+                        {
+                            if(showExpression)
+                            {
+                                std::pair<int, std::string> sin = stack.back();
+                                std::pair<int, std::string> cos(
+                                    0, "cos(" + sin.second + ")");
+                                sin.first = 0;
+                                sin.second = "sin(" + sin.second + ")";
+                                stack.back() = sin;
+                                stack.push_back(cos);
+                            }
+                            output << "sincos";
+                            produces = 0;
+                            break;
+                        }
+                        case cAbsAnd: n = "abs_and"; break;
+                        case cAbsOr:  n = "abs_or"; break;
+                        case cAbsNot: n = "abs_not"; params = 1; break;
+                        case cAbsNotNot: n = "abs_notnot"; params = 1; break;
+                        case cDup:
+                        {
+                            if(showExpression)
+                                stack.push_back(stack.back());
+                            output << "dup";
+                            produces = 0;
+                            break;
+                        }
+                        case cInv: n = "inv"; params = 1; break;
+                        case cSqr: n = "sqr"; params = 1; break;
+                        case cRDiv: n = "rdiv"; break;
+                        case cRSub: n = "rsub"; break;
+                        case cRSqrt: n = "rsqrt"; params = 1; break;
+
+                        default:
+                            n = Functions[opcode-cAbs].name;
+                            params = Functions[opcode-cAbs].params;
+                            out_params = params != 1;
+                      }
+                  }
+                  else
+                  {
+                      if(showExpression)
+                      {
+                          stack.push_back(std::make_pair(0,
+                              (findName(mData->mNamePtrs, opcode,
+                                        NameData<Value_t>::VARIABLE))));
+                      }
+                      output << "push Var" << opcode-VarBegin;
+                      produces = 0;
+                  }
+            }
+        }
+        if(produces) output << n;
+        if(out_params) output << " (" << params << ")";
+        if(showExpression)
+        {
+            padLine(outputBuffer, 20);
+
+            if(produces > 0)
+            {
+                std::ostringstream buf;
+                const char *paramsep = ",", *suff = "";
+                int prio = 0; bool commutative = false;
+                switch(opcode)
+                {
+                  case cIf: buf << "if("; suff = ")";
+                      break;
+                  case cAbsIf: buf << "if("; suff = ")";
+                      break;
+                  case cOr:  prio = 6; paramsep = "|"; commutative = true;
+                      break;
+                  case cAnd: prio = 5; paramsep = "&"; commutative = true;
+                      break;
+                  case cAdd: prio = 4; paramsep = "+"; commutative = true;
+                      break;
+                  case cSub: prio = 4; paramsep = "-";
+                      break;
+                  case cMul: prio = 3; paramsep = "*"; commutative = true;
+                      break;
+                  case cDiv: prio = 3; paramsep = "/";
+                      break;
+                  case cPow: prio = 2; paramsep = "^";
+                      break;
+                  case cAbsOr:  prio = 6; paramsep = "|"; commutative = true;
+                      break;
+                  case cAbsAnd: prio = 5; paramsep = "&"; commutative = true;
+                      break;
+                  case cSqr: prio = 2; suff = "^2";
+                      break;
+                  case cNeg: buf << "(-("; suff = "))";
+                      break;
+                  case cNot: buf << "(!("; suff = "))";
+                      break;
+                  default: buf << n << '('; suff = ")";
+                }
+
+                const char* sep = "";
+                for(unsigned a=0; a<params; ++a)
+                {
+                    buf << sep;
+                    if(stack.size() + a < params)
+                        buf << "?";
+                    else
+                    {
+                        const std::pair<int,std::string>& prev =
+                            stack[stack.size() - params + a];
+                        if(prio > 0 && (prev.first > prio ||
+                                        (prev.first==prio && !commutative)))
+                            buf << '(' << prev.second << ')';
+                        else
+                            buf << prev.second;
+                    }
+                    sep = paramsep;
+                }
+                if(stack.size() >= params)
+                    stack.resize(stack.size() - params);
+                else
+                    stack.clear();
+                buf << suff;
+                stack.push_back(std::make_pair(prio, buf.str()));
+                //if(n.size() <= 4 && !out_params) padLine(outputBuffer, 20);
+            }
+            //padLine(outputBuffer, 20);
+            output << "= ";
+            if(((opcode == cIf || opcode == cAbsIf) && params != 3)
+              || opcode == cJump
+    #ifdef FP_SUPPORT_OPTIMIZER
+              || opcode == cNop
+    #endif
+                )
+                output << "(void)";
+            else if(stack.empty())
+                output << "[?] ?";
+            else
+                output << '[' << (stack.size()-1) << ']'
+                       << stack.back().second;
+        }
+
+        if(showExpression)
+        {
+            dest << outputBuffer.str() << std::endl;
+            outputBuffer.str("");
+        }
+        else
+            output << std::endl;
+    }
+    dest << std::flush;
+}
+#endif
+
+
+#ifndef FP_SUPPORT_OPTIMIZER
+template<typename Value_t>
+void FunctionParserBase<Value_t>::Optimize()
+{
+    // Do nothing if no optimizations are supported.
+}
+#endif
+
+FUNCTIONPARSER_INSTANTIATE_TYPES
diff --git a/fparser/fparser.hh b/fparser/fparser.hh
new file mode 100644 (file)
index 0000000..2157c3b
--- /dev/null
@@ -0,0 +1,179 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen, Joel Yliluoma                                 *|
+|*                                                                         *|
+|* This library is distributed under the terms of the                      *|
+|* GNU Lesser General Public License version 3.                            *|
+|* (See lgpl.txt and gpl.txt for the license text.)                        *|
+\***************************************************************************/
+
+#ifndef ONCE_FPARSER_H_
+#define ONCE_FPARSER_H_
+
+#include <string>
+#include <vector>
+
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+#include <iostream>
+#endif
+
+#ifdef _MSC_VER
+// Visual Studio's warning about missing definitions for the explicit
+// FunctionParserBase instantiations is irrelevant here.
+#pragma warning(disable : 4661)
+#endif
+
+namespace FPoptimizer_CodeTree { template<typename Value_t> class CodeTree; }
+
+template<typename Value_t>
+class FunctionParserBase
+{
+public:
+    enum ParseErrorType
+    {
+        SYNTAX_ERROR=0, MISM_PARENTH, MISSING_PARENTH, EMPTY_PARENTH,
+        EXPECT_OPERATOR, OUT_OF_MEMORY, UNEXPECTED_ERROR, INVALID_VARS,
+        ILL_PARAMS_AMOUNT, PREMATURE_EOS, EXPECT_PARENTH_FUNC,
+        UNKNOWN_IDENTIFIER,
+        NO_FUNCTION_PARSED_YET,
+        FP_NO_ERROR
+    };
+
+    typedef Value_t value_type;
+
+
+    int Parse(const char* Function, const std::string& Vars,
+              bool useDegrees = false);
+    int Parse(const std::string& Function, const std::string& Vars,
+              bool useDegrees = false);
+
+    void setDelimiterChar(char);
+
+    const char* ErrorMsg() const;
+    inline ParseErrorType GetParseErrorType() const { return mParseErrorType; }
+
+    Value_t Eval(const Value_t* Vars);
+    inline int EvalError() const { return mEvalErrorType; }
+
+    bool AddConstant(const std::string& name, Value_t value);
+    bool AddUnit(const std::string& name, Value_t value);
+
+    typedef Value_t (*FunctionPtr)(const Value_t*);
+
+    bool AddFunction(const std::string& name,
+                     FunctionPtr, unsigned paramsAmount);
+    bool AddFunction(const std::string& name, FunctionParserBase&);
+
+    bool RemoveIdentifier(const std::string& name);
+
+    void Optimize();
+
+
+    int ParseAndDeduceVariables(const std::string& function,
+                                int* amountOfVariablesFound = 0,
+                                bool useDegrees = false);
+    int ParseAndDeduceVariables(const std::string& function,
+                                std::string& resultVarString,
+                                int* amountOfVariablesFound = 0,
+                                bool useDegrees = false);
+    int ParseAndDeduceVariables(const std::string& function,
+                                std::vector<std::string>& resultVars,
+                                bool useDegrees = false);
+
+
+    FunctionParserBase();
+    ~FunctionParserBase();
+
+    // Copy constructor and assignment operator (implemented using the
+    // copy-on-write technique for efficiency):
+    FunctionParserBase(const FunctionParserBase&);
+    FunctionParserBase& operator=(const FunctionParserBase&);
+
+
+    void ForceDeepCopy();
+
+
+
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+    // For debugging purposes only.
+    // Performs no sanity checks or anything. If the values are wrong, the
+    // library will crash. Do not use unless you know what you are doing.
+    void InjectRawByteCode(const unsigned* bytecode, unsigned bytecodeAmount,
+                           const Value_t* immed, unsigned immedAmount,
+                           unsigned stackSize);
+
+    void PrintByteCode(std::ostream& dest, bool showExpression = true) const;
+#endif
+
+
+
+//========================================================================
+private:
+//========================================================================
+
+    friend class FPoptimizer_CodeTree::CodeTree<Value_t>;
+
+// Private data:
+// ------------
+    char mDelimiterChar;
+    ParseErrorType mParseErrorType;
+    int mEvalErrorType;
+
+    struct Data;
+    Data* mData;
+
+    bool mUseDegreeConversion;
+    bool mHasByteCodeFlags;
+    unsigned mEvalRecursionLevel;
+    unsigned mStackPtr;
+    const char* mErrorLocation;
+
+
+// Private methods:
+// ---------------
+    void CopyOnWrite();
+    bool CheckRecursiveLinking(const FunctionParserBase*) const;
+    bool NameExists(const char*, unsigned);
+    bool ParseVariables(const std::string&);
+    int ParseFunction(const char*, bool);
+    const char* SetErrorType(ParseErrorType, const char*);
+
+    void AddFunctionOpcode(unsigned);
+    void AddImmedOpcode(Value_t v);
+    void incStackPtr();
+    void CompilePowi(long);
+    bool TryCompilePowi(Value_t);
+
+    const char* CompileIf(const char*);
+    const char* CompileFunctionParams(const char*, unsigned);
+    const char* CompileElement(const char*);
+    const char* CompilePossibleUnit(const char*);
+    const char* CompilePow(const char*);
+    const char* CompileUnaryMinus(const char*);
+    const char* CompileMult(const char*);
+    const char* CompileAddition(const char*);
+    const char* CompileComparison(const char*);
+    const char* CompileAnd(const char*);
+    const char* CompileExpression(const char*);
+    inline const char* CompileFunction(const char*, unsigned);
+    inline const char* CompileParenthesis(const char*);
+    inline const char* CompileLiteral(const char*);
+    template<bool SetFlag>
+    inline void PushOpcodeParam(unsigned);
+    template<bool SetFlag>
+    inline void PutOpcodeParamAt(unsigned, unsigned offset);
+    const char* Compile(const char*);
+
+protected:
+    // Parsing utility functions
+    static std::pair<const char*, Value_t> ParseLiteral(const char*);
+    static unsigned ParseIdentifier(const char*);
+};
+
+class FunctionParser: public FunctionParserBase<double> {};
+class FunctionParser_f: public FunctionParserBase<float> {};
+class FunctionParser_ld: public FunctionParserBase<long double> {};
+class FunctionParser_li: public FunctionParserBase<long> {};
+
+#endif
diff --git a/fparser/fparser_gmpint.hh b/fparser/fparser_gmpint.hh
new file mode 100644 (file)
index 0000000..ba4f049
--- /dev/null
@@ -0,0 +1,15 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen                                                *|
+\***************************************************************************/
+
+#ifndef ONCE_FPARSER_GMPINT_H_
+#define ONCE_FPARSER_GMPINT_H_
+
+#include "fparser.hh"
+#include "mpfr/GmpInt.hh"
+
+class FunctionParser_gmpint: public FunctionParserBase<GmpInt> {};
+
+#endif
diff --git a/fparser/fparser_mpfr.hh b/fparser/fparser_mpfr.hh
new file mode 100644 (file)
index 0000000..8807847
--- /dev/null
@@ -0,0 +1,15 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen                                                *|
+\***************************************************************************/
+
+#ifndef ONCE_FPARSER_MPFR_H_
+#define ONCE_FPARSER_MPFR_H_
+
+#include "fparser.hh"
+#include "mpfr/MpfrFloat.hh"
+
+class FunctionParser_mpfr: public FunctionParserBase<MpfrFloat> {};
+
+#endif
diff --git a/fparser/fpaux.hh b/fparser/fpaux.hh
new file mode 100644 (file)
index 0000000..fe9dcd9
--- /dev/null
@@ -0,0 +1,796 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen, Joel Yliluoma                                 *|
+|*                                                                         *|
+|* This library is distributed under the terms of the                      *|
+|* GNU Lesser General Public License version 3.                            *|
+|* (See lgpl.txt and gpl.txt for the license text.)                        *|
+\***************************************************************************/
+
+// NOTE:
+// This file contains only internal types for the function parser library.
+// You don't need to include this file in your code. Include "fparser.hh"
+// only.
+
+#ifndef ONCE_FPARSER_AUX_H_
+#define ONCE_FPARSER_AUX_H_
+
+#include <cmath>
+#include <cstring>
+
+#include "fptypes.hh"
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+#include "mpfr/MpfrFloat.hh"
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+#include "mpfr/GmpInt.hh"
+#endif
+
+#ifdef ONCE_FPARSER_H_
+namespace FUNCTIONPARSERTYPES
+{
+    template<typename value_t>
+    struct IsIntType
+    {
+        enum { result = false };
+    };
+    template<>
+    struct IsIntType<long>
+    {
+        enum { result = true };
+    };
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+    template<>
+    struct IsIntType<GmpInt>
+    {
+        enum { result = true };
+    };
+#endif
+
+//==========================================================================
+// Math funcs
+//==========================================================================
+    template<typename ValueT>
+    ValueT fp_pow(const ValueT& x, const ValueT& y);
+
+    template<typename Value_t>
+    inline void fp_sinCos(Value_t& sin, Value_t& cos, const Value_t& a)
+    {
+        // Assuming that "cos" and "a" don't overlap, but "sin" and "a" may.
+        cos = fp_cos(a);
+        sin = fp_sin(a);
+    }
+
+    template<typename Value_t>
+    inline Value_t fp_hypot(Value_t x, Value_t y) { return fp_sqrt(x*x + y*y); }
+
+    template<typename Value_t>
+    inline Value_t fp_asinh(Value_t x)
+        { return fp_log(x + fp_sqrt(x*x + Value_t(1))); }
+    template<typename Value_t>
+    inline Value_t fp_acosh(Value_t x)
+        { return fp_log(x + fp_sqrt(x*x - Value_t(1))); }
+    template<typename Value_t>
+    inline Value_t fp_atanh(Value_t x)
+        { return fp_log( (Value_t(1)+x) / (Value_t(1)-x)) * Value_t(0.5); }
+
+
+    template<typename Value_t>
+    inline Value_t fp_const_pi() // CONSTANT_PI
+    {
+        return Value_t(3.1415926535897932384626433832795028841971693993751L);
+    }
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+    template<>
+    inline MpfrFloat fp_const_pi<MpfrFloat>() { return MpfrFloat::const_pi(); }
+#endif
+
+    template<typename Value_t>
+    inline Value_t fp_const_e() // CONSTANT_E
+    {
+        return Value_t(2.7182818284590452353602874713526624977572L);
+    }
+    template<typename Value_t>
+    inline Value_t fp_const_einv() // CONSTANT_EI
+    {
+        return Value_t(0.367879441171442321595523770161460867445811131L);
+    }
+    template<typename Value_t>
+    inline Value_t fp_const_log2() // CONSTANT_L2, CONSTANT_L2EI
+    {
+        return Value_t(0.69314718055994530941723212145817656807550013436025525412L);
+    }
+    template<typename Value_t>
+    inline Value_t fp_const_log10() // CONSTANT_L10, CONSTANT_L10EI
+    {
+        return Value_t(2.302585092994045684017991454684364207601101488628772976L);
+    }
+    template<typename Value_t>
+    inline Value_t fp_const_log2inv() // CONSTANT_L2I, CONSTANT_L2E
+    {
+        return Value_t(1.442695040888963407359924681001892137426645954L);
+    }
+    template<typename Value_t>
+    inline Value_t fp_const_log10inv() // CONSTANT_L10I, CONSTANT_L10E
+    {
+        return Value_t(0.434294481903251827651128918916605082294397L);
+    }
+
+    template<typename Value_t>
+    inline const Value_t& fp_const_deg_to_rad() // CONSTANT_DR
+    {
+        static const Value_t factor = fp_const_pi<Value_t>() / Value_t(180); // to rad from deg
+        return factor;
+    }
+
+    template<typename Value_t>
+    inline const Value_t& fp_const_rad_to_deg() // CONSTANT_RD
+    {
+        static const Value_t factor = Value_t(180) / fp_const_pi<Value_t>(); // to deg from rad
+        return factor;
+    }
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+    template<>
+    inline MpfrFloat fp_const_e<MpfrFloat>() { return MpfrFloat::const_e(); }
+
+    template<>
+    inline MpfrFloat fp_const_einv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_e(); }
+
+    template<>
+    inline MpfrFloat fp_const_log2<MpfrFloat>() { return MpfrFloat::const_log2(); }
+
+    /*
+    template<>
+    inline MpfrFloat fp_const_log10<MpfrFloat>() { return fp_log(MpfrFloat(10)); }
+
+    template<>
+    inline MpfrFloat fp_const_log2inv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_log2(); }
+
+    template<>
+    inline MpfrFloat fp_const_log10inv<MpfrFloat>() { return fp_log10(MpfrFloat::const_e()); }
+    */
+#endif
+
+
+// -------------------------------------------------------------------------
+// double
+// -------------------------------------------------------------------------
+    inline double fp_abs(double x) { return fabs(x); }
+    inline double fp_acos(double x) { return acos(x); }
+    inline double fp_asin(double x) { return asin(x); }
+    inline double fp_atan(double x) { return atan(x); }
+    inline double fp_atan2(double x, double y) { return atan2(x, y); }
+#ifdef FP_SUPPORT_CBRT
+    inline double fp_cbrt(double x) { return cbrt(x); }
+#else
+    inline double fp_cbrt(double x) { return x>0 ?  exp(log( x)/3.0)
+                                           : x<0 ? -exp(log(-x)/3.0)
+                                           : 0.0; }
+#endif
+    inline double fp_ceil(double x) { return ceil(x); }
+    inline double fp_cos(double x) { return cos(x); }
+    inline double fp_cosh(double x) { return cosh(x); }
+    inline double fp_exp(double x) { return exp(x); }
+    inline double fp_floor(double x) { return floor(x); }
+    inline double fp_int(double x) { return floor(x + .5); }
+    inline double fp_log(double x) { return log(x); }
+    inline double fp_log10(double x)
+    { return log(x) *
+            0.434294481903251827651128918916605082294397005803666566; }
+    inline double fp_mod(double x, double y) { return fmod(x, y); }
+    inline double fp_sin(double x) { return sin(x); }
+    inline double fp_sinh(double x) { return sinh(x); }
+    inline double fp_sqrt(double x) { return sqrt(x); }
+    inline double fp_tan(double x) { return tan(x); }
+    inline double fp_tanh(double x) { return tanh(x); }
+
+#ifdef FP_SUPPORT_ASINH
+    inline double fp_asinh(double x) { return asinh(x); }
+    inline double fp_acosh(double x) { return acosh(x); }
+    inline double fp_atanh(double x) { return atanh(x); }
+#endif // FP_SUPPORT_ASINH
+#ifdef FP_SUPPORT_HYPOT
+    inline double fp_hypot(double x, double y) { return hypot(x,y); }
+#endif
+
+    inline double fp_trunc(double x) { return x<0.0 ? ceil(x) : floor(x); }
+
+    inline double fp_pow_base(double x, double y) { return pow(x, y); }
+
+#ifndef FP_SUPPORT_LOG2
+    inline double fp_log2(double x)
+    { return log(x) * 1.4426950408889634073599246810018921374266459541529859; }
+#else
+    inline double fp_log2(double x) { return log2(x); }
+#endif // FP_SUPPORT_LOG2
+
+    inline double fp_exp2(double x) { return fp_pow(2.0, x); }
+
+#ifdef FP_EPSILON
+    template<typename Value_t>
+    inline Value_t fp_epsilon() { return FP_EPSILON; }
+#else
+    template<typename Value_t>
+    inline Value_t fp_epsilon() { return 0.0; }
+#endif
+
+  #ifdef _GNU_SOURCE
+    template<>
+    inline void fp_sinCos<double>(double& sin, double& cos, const double& a)
+    {
+        sincos(a, &sin, &cos);
+    }
+  #endif
+
+// -------------------------------------------------------------------------
+// float
+// -------------------------------------------------------------------------
+#ifdef FP_SUPPORT_FLOAT_TYPE
+    inline float fp_abs(float x) { return fabsf(x); }
+    inline float fp_acos(float x) { return acosf(x); }
+    inline float fp_asin(float x) { return asinf(x); }
+    inline float fp_atan(float x) { return atanf(x); }
+    inline float fp_atan2(float x, float y) { return atan2f(x, y); }
+#ifdef FP_SUPPORT_CBRT
+    inline float fp_cbrt(float x) { return cbrtf(x); }
+#else
+    inline float fp_cbrt(float x) { return x>0 ?  expf(logf( x)/3.0f)
+                                         : x<0 ? -expf(logf(-x)/3.0f)
+                                         : 0.0f; }
+#endif
+    inline float fp_ceil(float x) { return ceilf(x); }
+    inline float fp_cos(float x) { return cosf(x); }
+    inline float fp_cosh(float x) { return coshf(x); }
+    inline float fp_exp(float x) { return expf(x); }
+    inline float fp_floor(float x) { return floorf(x); }
+    inline float fp_int(float x) { return floorf(x + .5F); }
+    inline float fp_log(float x) { return logf(x); }
+    inline float fp_log10(float x)
+    { return logf(x) *
+            0.434294481903251827651128918916605082294397005803666566F; }
+    inline float fp_mod(float x, float y) { return fmodf(x, y); }
+    inline float fp_sin(float x) { return sinf(x); }
+    inline float fp_sinh(float x) { return sinhf(x); }
+    inline float fp_sqrt(float x) { return sqrtf(x); }
+    inline float fp_tan(float x) { return tanf(x); }
+    inline float fp_tanh(float x) { return tanhf(x); }
+
+#ifdef FP_SUPPORT_ASINH
+    inline float fp_asinh(float x) { return asinhf(x); }
+    inline float fp_acosh(float x) { return acoshf(x); }
+    inline float fp_atanh(float x) { return atanhf(x); }
+#endif // FP_SUPPORT_ASINH
+#ifdef FP_SUPPORT_HYPOT
+    inline float fp_hypot(float x, float y) { return hypotf(x,y); }
+#endif
+
+    inline float fp_trunc(float x) { return x<0.0F ? ceilf(x) : floorf(x); }
+
+    inline float fp_pow_base(float x, float y) { return powf(x, y); }
+
+#ifndef FP_SUPPORT_LOG2
+    inline float fp_log2(float x)
+    { return logf(x) *
+            1.4426950408889634073599246810018921374266459541529859F; }
+#else
+    inline float fp_log2(float x) { return log2f(x); }
+#endif // FP_SUPPORT_LOG2
+
+    inline float fp_exp2(float x) { return fp_pow(2.0F, x); }
+
+#ifdef FP_EPSILON
+    template<>
+    inline float fp_epsilon<float>() { return 1e-6F; }
+#else
+    template<>
+    inline float fp_epsilon<float>() { return 0.0F; }
+#endif
+
+#endif // FP_SUPPORT_FLOAT_TYPE
+  #ifdef _GNU_SOURCE
+    template<>
+    inline void fp_sinCos<float>(float& sin, float& cos, const float& a)
+    {
+        sincosf(a, &sin, &cos);
+    }
+  #endif
+
+
+
+// -------------------------------------------------------------------------
+// long double
+// -------------------------------------------------------------------------
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+    inline long double fp_abs(long double x) { return fabsl(x); }
+    inline long double fp_acos(long double x) { return acosl(x); }
+    inline long double fp_asin(long double x) { return asinl(x); }
+    inline long double fp_atan(long double x) { return atanl(x); }
+    inline long double fp_atan2(long double x, long double y)
+    { return atan2l(x, y); }
+#ifdef FP_SUPPORT_CBRT
+    inline long double fp_cbrt(long double x) { return cbrtl(x); }
+#else
+    inline long double fp_cbrt(long double x)
+        { return x>0 ?  expl(logl( x)/3.0l)
+               : x<0 ? -expl(logl(-x)/3.0l)
+               : 0.0l; }
+#endif
+    inline long double fp_ceil(long double x) { return ceill(x); }
+    inline long double fp_cos(long double x) { return cosl(x); }
+    inline long double fp_cosh(long double x) { return coshl(x); }
+    inline long double fp_exp(long double x) { return expl(x); }
+    inline long double fp_floor(long double x) { return floorl(x); }
+    inline long double fp_int(long double x) { return floorl(x + .5L); }
+    inline long double fp_log(long double x) { return logl(x); }
+    inline long double fp_log10(long double x)
+    { return logl(x) *
+            0.434294481903251827651128918916605082294397005803666566L; }
+    inline long double fp_mod(long double x, long double y)
+    { return fmodl(x, y); }
+    inline long double fp_sin(long double x) { return sinl(x); }
+    inline long double fp_sinh(long double x) { return sinhl(x); }
+    inline long double fp_sqrt(long double x) { return sqrtl(x); }
+    inline long double fp_tan(long double x) { return tanl(x); }
+    inline long double fp_tanh(long double x) { return tanhl(x); }
+
+#ifdef FP_SUPPORT_ASINH
+    inline long double fp_asinh(long double x) { return asinhl(x); }
+    inline long double fp_acosh(long double x) { return acoshl(x); }
+    inline long double fp_atanh(long double x) { return atanhl(x); }
+#endif // FP_SUPPORT_ASINH
+#ifdef FP_SUPPORT_HYPOT
+    inline long double fp_hypot(long double x, long double y) { return hypotl(x,y); }
+#endif
+
+    inline long double fp_trunc(long double x)
+    { return x<0.0L ? ceill(x) : floorl(x); }
+
+    inline long double fp_pow_base(long double x, long double y)
+    { return powl(x, y); }
+
+#ifndef FP_SUPPORT_LOG2
+    inline long double fp_log2(long double x)
+    { return fp_log(x) * 1.4426950408889634073599246810018921374266459541529859L; }
+#else
+    inline long double fp_log2(long double x) { return log2l(x); }
+#endif // FP_SUPPORT_LOG2
+
+    inline long double fp_exp2(long double x) { return fp_pow(2.0L, x); }
+
+#endif // FP_SUPPORT_LONG_DOUBLE_TYPE
+
+  #ifdef _GNU_SOURCE
+    template<>
+    inline void fp_sinCos<long double>(long double& sin, long double& cos, const long double& a)
+    {
+        sincosl(a, &sin, &cos);
+    }
+  #endif
+
+
+// -------------------------------------------------------------------------
+// Long int
+// -------------------------------------------------------------------------
+    inline long fp_abs(long x) { return x < 0 ? -x : x; }
+    inline long fp_acos(long) { return 0; }
+    inline long fp_asin(long) { return 0; }
+    inline long fp_atan(long) { return 0; }
+    inline long fp_atan2(long, long) { return 0; }
+    inline long fp_cbrt(long) { return 0; }
+    inline long fp_ceil(long x) { return x; }
+    inline long fp_cos(long) { return 0; }
+    inline long fp_cosh(long) { return 0; }
+    inline long fp_exp(long) { return 0; }
+    inline long fp_floor(long x) { return x; }
+    inline long fp_int(long x) { return x; }
+    inline long fp_log(long) { return 0; }
+    inline long fp_log10(long) { return 0; }
+    inline long fp_mod(long x, long y) { return x % y; }
+    inline long fp_pow(long, long) { return 0; }
+    inline long fp_sin(long) { return 0; }
+    inline long fp_sinh(long) { return 0; }
+    inline long fp_sqrt(long) { return 1; }
+    inline long fp_tan(long) { return 0; }
+    inline long fp_tanh(long) { return 0; }
+    inline long fp_asinh(long) { return 0; }
+    inline long fp_acosh(long) { return 0; }
+    inline long fp_atanh(long) { return 0; }
+    inline long fp_trunc(long x) { return x; }
+    inline long fp_pow_base(long, long) { return 0; }
+    inline long fp_log2(long) { return 0; }
+    inline long fp_exp2(long) { return 0; }
+
+    template<>
+    inline long fp_epsilon<long>() { return 0; }
+
+
+// -------------------------------------------------------------------------
+// MpfrFloat
+// -------------------------------------------------------------------------
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+    inline MpfrFloat fp_abs(const MpfrFloat& x) { return MpfrFloat::abs(x); }
+    inline MpfrFloat fp_acos(const MpfrFloat& x) { return MpfrFloat::acos(x); }
+    inline MpfrFloat fp_asin(const MpfrFloat& x) { return MpfrFloat::asin(x); }
+    inline MpfrFloat fp_atan(const MpfrFloat& x) { return MpfrFloat::atan(x); }
+    inline MpfrFloat fp_atan2(const MpfrFloat& x, const MpfrFloat& y)
+        { return MpfrFloat::atan2(x, y); }
+    inline MpfrFloat fp_cbrt(const MpfrFloat& x) { return MpfrFloat::cbrt(x); }
+    inline MpfrFloat fp_ceil(const MpfrFloat& x) { return MpfrFloat::ceil(x); }
+    inline MpfrFloat fp_cos(const MpfrFloat& x) { return MpfrFloat::cos(x); }
+    inline MpfrFloat fp_cosh(const MpfrFloat& x) { return MpfrFloat::cosh(x); }
+    inline MpfrFloat fp_exp(const MpfrFloat& x) { return MpfrFloat::exp(x); }
+    inline MpfrFloat fp_floor(const MpfrFloat& x) { return MpfrFloat::floor(x); }
+    inline MpfrFloat fp_hypot(const MpfrFloat& x, const MpfrFloat& y)
+        { return MpfrFloat::hypot(x, y); }
+    inline MpfrFloat fp_int(const MpfrFloat& x) { return MpfrFloat::round(x); }
+    inline MpfrFloat fp_log(const MpfrFloat& x) { return MpfrFloat::log(x); }
+    inline MpfrFloat fp_log10(const MpfrFloat& x) { return MpfrFloat::log10(x); }
+    inline MpfrFloat fp_mod(const MpfrFloat& x, const MpfrFloat& y) { return x % y; }
+    inline MpfrFloat fp_sin(const MpfrFloat& x) { return MpfrFloat::sin(x); }
+    inline MpfrFloat fp_sinh(const MpfrFloat& x) { return MpfrFloat::sinh(x); }
+    inline MpfrFloat fp_sqrt(const MpfrFloat& x) { return MpfrFloat::sqrt(x); }
+    inline MpfrFloat fp_tan(const MpfrFloat& x) { return MpfrFloat::tan(x); }
+    inline MpfrFloat fp_tanh(const MpfrFloat& x) { return MpfrFloat::tanh(x); }
+    inline MpfrFloat fp_asinh(const MpfrFloat& x) { return MpfrFloat::asinh(x); }
+    inline MpfrFloat fp_acosh(const MpfrFloat& x) { return MpfrFloat::acosh(x); }
+    inline MpfrFloat fp_atanh(const MpfrFloat& x) { return MpfrFloat::atanh(x); }
+    inline MpfrFloat fp_trunc(const MpfrFloat& x) { return MpfrFloat::trunc(x); }
+
+    inline MpfrFloat fp_pow(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); }
+    inline MpfrFloat fp_pow_base(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); }
+
+    inline MpfrFloat fp_log2(const MpfrFloat& x) { return MpfrFloat::log2(x); }
+    inline MpfrFloat fp_exp2(const MpfrFloat& x) { return MpfrFloat::exp2(x); }
+
+    template<>
+    inline void fp_sinCos<MpfrFloat>(MpfrFloat& sin, MpfrFloat& cos, const MpfrFloat& a)
+    {
+        MpfrFloat::sincos(a, sin, cos);
+    }
+
+    template<>
+    inline MpfrFloat fp_epsilon<MpfrFloat>() { return MpfrFloat::someEpsilon(); }
+#endif // FP_SUPPORT_MPFR_FLOAT_TYPE
+
+
+// -------------------------------------------------------------------------
+// GMP int
+// -------------------------------------------------------------------------
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+    inline GmpInt fp_abs(GmpInt x) { return GmpInt::abs(x); }
+    inline GmpInt fp_acos(GmpInt) { return 0; }
+    inline GmpInt fp_asin(GmpInt) { return 0; }
+    inline GmpInt fp_atan(GmpInt) { return 0; }
+    inline GmpInt fp_atan2(GmpInt, GmpInt) { return 0; }
+    inline GmpInt fp_cbrt(GmpInt) { return 0; }
+    inline GmpInt fp_ceil(GmpInt x) { return x; }
+    inline GmpInt fp_cos(GmpInt) { return 0; }
+    inline GmpInt fp_cosh(GmpInt) { return 0; }
+    inline GmpInt fp_exp(GmpInt) { return 0; }
+    inline GmpInt fp_floor(GmpInt x) { return x; }
+    inline GmpInt fp_hypot(GmpInt, GmpInt) { return 0; }
+    inline GmpInt fp_int(GmpInt x) { return x; }
+    inline GmpInt fp_log(GmpInt) { return 0; }
+    inline GmpInt fp_log10(GmpInt) { return 0; }
+    inline GmpInt fp_mod(GmpInt x, GmpInt y) { return x % y; }
+    inline GmpInt fp_pow(GmpInt, GmpInt) { return 0; }
+    inline GmpInt fp_sin(GmpInt) { return 0; }
+    inline GmpInt fp_sinh(GmpInt) { return 0; }
+    inline GmpInt fp_sqrt(GmpInt) { return 0; }
+    inline GmpInt fp_tan(GmpInt) { return 0; }
+    inline GmpInt fp_tanh(GmpInt) { return 0; }
+    inline GmpInt fp_asinh(GmpInt) { return 0; }
+    inline GmpInt fp_acosh(GmpInt) { return 0; }
+    inline GmpInt fp_atanh(GmpInt) { return 0; }
+    inline GmpInt fp_trunc(GmpInt x) { return x; }
+    inline GmpInt fp_pow_base(GmpInt, GmpInt) { return 0; }
+    inline GmpInt fp_log2(GmpInt) { return 0; }
+    inline GmpInt fp_exp2(GmpInt) { return 0; }
+
+    template<>
+    inline GmpInt fp_epsilon<GmpInt>() { return 0; }
+#endif // FP_SUPPORT_GMP_INT_TYPE
+
+
+// -------------------------------------------------------------------------
+// Comparison
+// -------------------------------------------------------------------------
+#ifdef FP_EPSILON
+    template<typename Value_t>
+    inline bool fp_equal(const Value_t& x, const Value_t& y)
+    { return IsIntType<Value_t>::result
+        ? (x == y)
+        : (fp_abs(x - y) <= fp_epsilon<Value_t>()); }
+
+    template<typename Value_t>
+    inline bool fp_nequal(const Value_t& x, const Value_t& y)
+    { return IsIntType<Value_t>::result
+        ? (x != y)
+        : (fp_abs(x - y) > fp_epsilon<Value_t>()); }
+
+    template<typename Value_t>
+    inline bool fp_less(const Value_t& x, const Value_t& y)
+    { return IsIntType<Value_t>::result
+        ? (x < y)
+        : (x < y - fp_epsilon<Value_t>()); }
+
+    template<typename Value_t>
+    inline bool fp_lessOrEq(const Value_t& x, const Value_t& y)
+    { return IsIntType<Value_t>::result
+        ? (x <= y)
+        : (x <= y + fp_epsilon<Value_t>()); }
+#else // FP_EPSILON
+    template<typename Value_t>
+    inline bool fp_equal(const Value_t& x, const Value_t& y) { return x == y; }
+
+    template<typename Value_t>
+    inline bool fp_nequal(const Value_t& x, const Value_t& y) { return x != y; }
+
+    template<typename Value_t>
+    inline bool fp_less(const Value_t& x, const Value_t& y) { return x < y; }
+
+    template<typename Value_t>
+    inline bool fp_lessOrEq(const Value_t& x, const Value_t& y) { return x <= y; }
+#endif // FP_EPSILON
+
+    template<typename Value_t>
+    inline bool fp_greater(const Value_t& x, const Value_t& y)
+    { return fp_less(y, x); }
+
+    template<typename Value_t>
+    inline bool fp_greaterOrEq(const Value_t& x, const Value_t& y)
+    { return fp_lessOrEq(y, x); }
+
+    template<typename Value_t>
+    inline bool fp_truth(const Value_t& d)
+    {
+        return IsIntType<Value_t>::result
+                ? d != 0
+                : fp_abs(d) >= Value_t(0.5);
+    }
+
+    template<typename Value_t>
+    inline bool fp_absTruth(const Value_t& abs_d)
+    {
+        return IsIntType<Value_t>::result
+                ? abs_d > 0
+                : abs_d >= Value_t(0.5);
+    }
+
+    template<typename Value_t>
+    inline const Value_t& fp_min(const Value_t& d1, const Value_t& d2)
+        { return d1<d2 ? d1 : d2; }
+
+    template<typename Value_t>
+    inline const Value_t& fp_max(const Value_t& d1, const Value_t& d2)
+        { return d1>d2 ? d1 : d2; }
+
+    template<typename Value_t>
+    inline const Value_t fp_not(const Value_t& b)
+        { return Value_t(!fp_truth(b)); }
+
+    template<typename Value_t>
+    inline const Value_t fp_notNot(const Value_t& b)
+        { return Value_t(fp_truth(b)); }
+
+    template<typename Value_t>
+    inline const Value_t fp_absNot(const Value_t& b)
+        { return Value_t(!fp_absTruth(b)); }
+
+    template<typename Value_t>
+    inline const Value_t fp_absNotNot(const Value_t& b)
+        { return Value_t(fp_absTruth(b)); }
+
+    template<typename Value_t>
+    inline const Value_t fp_and(const Value_t& a, const Value_t& b)
+        { return Value_t(fp_truth(a) && fp_truth(b)); }
+
+    template<typename Value_t>
+    inline const Value_t fp_or(const Value_t& a, const Value_t& b)
+        { return Value_t(fp_truth(a) || fp_truth(b)); }
+
+    template<typename Value_t>
+    inline const Value_t fp_absAnd(const Value_t& a, const Value_t& b)
+        { return Value_t(fp_absTruth(a) && fp_absTruth(b)); }
+
+    template<typename Value_t>
+    inline const Value_t fp_absOr(const Value_t& a, const Value_t& b)
+        { return Value_t(fp_absTruth(a) || fp_absTruth(b)); }
+
+    /////////////
+    /* Opcode analysis functions are used by fp_opcode_add.inc */
+    /* Moved here from fparser.cc because fp_opcode_add.inc
+     * is also now included by fpoptimizer.cc
+     */
+    bool IsLogicalOpcode(unsigned op);
+    bool IsComparisonOpcode(unsigned op);
+    unsigned OppositeComparisonOpcode(unsigned op);
+    bool IsNeverNegativeValueOpcode(unsigned op);
+    bool IsAlwaysIntegerOpcode(unsigned op);
+    bool IsUnaryOpcode(unsigned op);
+    bool IsBinaryOpcode(unsigned op);
+    bool HasInvalidRangesOpcode(unsigned op);
+
+    template<typename Value_t>
+    inline Value_t DegreesToRadians(Value_t degrees)
+    {
+        return degrees * fp_const_deg_to_rad<Value_t>();
+    }
+
+    template<typename Value_t>
+    inline Value_t RadiansToDegrees(Value_t radians)
+    {
+        return radians * fp_const_rad_to_deg<Value_t>();
+    }
+
+    template<typename Value_t>
+    inline bool isEvenInteger(Value_t value)
+    {
+        const Value_t halfValue = value * Value_t(0.5);
+        return fp_equal(halfValue, fp_floor(halfValue));
+    }
+
+    template<typename Value_t>
+    inline bool isInteger(Value_t value)
+    {
+        return fp_equal(value, fp_floor(value));
+    }
+
+    // Is value an integer that fits in "long" datatype?
+    template<typename Value_t>
+    inline bool isLongInteger(Value_t value)
+    {
+        return value == Value_t( makeLongInteger(value) );
+    }
+
+    template<typename Value_t>
+    inline long makeLongInteger(Value_t value)
+    {
+        return (long) fp_int(value);
+    }
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+    template<>
+    inline bool isEvenInteger(long value)
+    {
+        return value%2 == 0;
+    }
+
+    template<>
+    inline bool isInteger(long) { return true; }
+
+    template<>
+    inline bool isLongInteger(long) { return true; }
+
+    template<>
+    inline long makeLongInteger(long value)
+    {
+        return value;
+    }
+#endif
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+    template<>
+    inline bool isInteger(MpfrFloat value) { return value.isInteger(); }
+
+    template<>
+    inline bool isEvenInteger(MpfrFloat value)
+    {
+        return isInteger(value) && value%2 == 0;
+    }
+
+    template<>
+    inline long makeLongInteger(MpfrFloat value)
+    {
+        return (long) value.toInt();
+    }
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+    template<>
+    inline bool isEvenInteger(GmpInt value)
+    {
+        return value%2 == 0;
+    }
+
+    template<>
+    inline bool isInteger(GmpInt) { return true; }
+
+    template<>
+    inline long makeLongInteger(GmpInt value)
+    {
+        return (long) value.toInt();
+    }
+#endif
+
+    template<typename Value_t>
+    inline bool isOddInteger(Value_t value)
+    {
+        const Value_t halfValue = (value + Value_t(1)) * Value_t(0.5);
+        return fp_equal(halfValue, fp_floor(halfValue));
+    }
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+    template<>
+    inline bool isOddInteger(long value)
+    {
+        return value%2 != 0;
+    }
+#endif
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+    template<>
+    inline bool isOddInteger(MpfrFloat value)
+    {
+        return value.isInteger() && value%2 != 0;
+    }
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+    template<>
+    inline bool isOddInteger(GmpInt value)
+    {
+        return value%2 != 0;
+    }
+#endif
+} // namespace FUNCTIONPARSERTYPES
+
+#endif // ONCE_FPARSER_H_
+
+
+#ifndef FP_DISABLE_DOUBLE_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_D(g) g(double)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_D(g)
+#endif
+
+#ifdef FP_SUPPORT_FLOAT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_F(g) g(float)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_F(g)
+#endif
+
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_LD(g) g(long double)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_LD(g)
+#endif
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_LI(g) g(long)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_LI(g)
+#endif
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_MF(g) g(MpfrFloat)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_MF(g)
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_GI(g) g(GmpInt)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_GI(g)
+#endif
+
+/* Add 'FUNCTIONPARSER_INSTANTIATE_TYPES' at the end of all .cc files
+   containing FunctionParserBase implementations.
+ */
+#define FUNCTIONPARSER_INSTANTIATE_BASE(type) \
+    template class FunctionParserBase<type>;
+
+#define FUNCTIONPARSER_INSTANTIATE_TYPES \
+    FUNCTIONPARSER_INSTANTIATE_D(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_F(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_LD(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_LI(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_MF(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_GI(FUNCTIONPARSER_INSTANTIATE_BASE)
+
+#endif // ONCE_FPARSER_AUX_H_
diff --git a/fparser/fpconfig.hh b/fparser/fpconfig.hh
new file mode 100644 (file)
index 0000000..9607a79
--- /dev/null
@@ -0,0 +1,132 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen                                                *|
+|*                                                                         *|
+|* This library is distributed under the terms of the                      *|
+|* GNU Lesser General Public License version 3.                            *|
+|* (See lgpl.txt and gpl.txt for the license text.)                        *|
+\***************************************************************************/
+
+// Configuration file
+// ------------------
+
+/* NOTE:
+   This file is for the internal use of the function parser only.
+   You don't need to include this file in your source files, just
+   include "fparser.hh".
+*/
+
+
+/* Uncomment any of these lines or define them in your compiler settings
+   to enable the correspondent version of the parser. (These are disabled
+   by default because they rely on C99 functions, and non-standard libraries
+   in the case pf MPFR and GMP, and they make compiling needlessly slower
+   and the resulting binary needlessly larger if they are not used in the
+   program.)
+*/
+//#define FP_SUPPORT_FLOAT_TYPE
+//#define FP_SUPPORT_LONG_DOUBLE_TYPE
+//#define FP_SUPPORT_LONG_INT_TYPE
+//#define FP_SUPPORT_MPFR_FLOAT_TYPE
+//#define FP_SUPPORT_GMP_INT_TYPE
+
+/* Uncomment this line of define it in your compiler settings if you want
+   to disable compiling the basic double version of the library, in case
+   one of the above types is used but not the double type. (If the double
+   type is not used, then disabling it makes compiling faster and the
+   resulting binary smaller.)
+ */
+//#define FP_DISABLE_DOUBLE_TYPE
+
+/*
+ Note that these do not change what FunctionParser supports, they only
+ change how the function is evaluated, potentially making it faster when
+ these functions are involved.
+ These will make the source code use asinh(), acosh(), atanh(), exp2()
+ and log2().
+*/
+//#define FP_SUPPORT_TR1_MATH_FUNCS
+
+#ifdef FP_SUPPORT_TR1_MATH_FUNCS
+#define FP_SUPPORT_ASINH
+#define FP_SUPPORT_EXP2
+#define FP_SUPPORT_LOG2
+#define FP_SUPPORT_CBRT
+#define FP_SUPPORT_HYPOT
+#endif
+
+/*
+ Comment out the following line to enable the eval() function, which can
+ be used in the function string to recursively call the same function.
+ Note that enabling this function may be dangerous even if the maximum
+ recursion level is limited because it is still possible to write functions
+ using it which take enormous  amounts of time to evaluate even though the
+ maximum recursion is never reached. This may be undesirable in some
+ applications.
+ Alternatively you can define the FP_ENABLE_EVAL precompiler constant in
+ your compiler settings.
+*/
+#ifndef FP_ENABLE_EVAL
+#define FP_DISABLE_EVAL
+#endif
+
+
+/*
+ Maximum recursion level for eval() calls:
+*/
+#define FP_EVAL_MAX_REC_LEVEL 1000
+
+
+/*
+ Whether to use shortcut evaluation for the & and | operators:
+*/
+#ifndef FP_DISABLE_SHORTCUT_LOGICAL_EVALUATION
+#define FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#endif
+
+/*
+ Whether to enable optimizations that may ignore side effects
+ of if() calls, such as changing if(x,!y,0) into x&!y.
+ This is basically the polar opposite of "shortcut logical evaluation".
+ Disabled by default, because it makes eval() rather unsafe.
+*/
+#ifdef FP_ENABLE_IGNORE_IF_SIDEEFFECTS
+#endif
+
+/*
+ Comment out the following lines out if you are not going to use the
+ optimizer and want a slightly smaller library. The Optimize() method
+ can still be called, but it will not do anything.
+ If you are unsure, just leave it. It won't slow down the other parts of
+ the library.
+*/
+#ifndef FP_NO_SUPPORT_OPTIMIZER
+#define FP_SUPPORT_OPTIMIZER
+#endif
+
+
+/*
+ Epsilon value used with the comparison operators (must be non-negative):
+ (Comment it out if you don't want to use epsilon in comparisons. Might
+ lead to marginally faster evaluation of the comparison operators, but
+ can introduce inaccuracies in comparisons.)
+*/
+#define FP_EPSILON 1e-14
+
+
+/*
+ No member function of FunctionParser is thread-safe. Most prominently,
+ Eval() is not thread-safe. By uncommenting one of these lines the Eval()
+ function can be made thread-safe at the cost of a possible small overhead.
+ The second version requires that the compiler supports the alloca() function,
+ which is not standard, but is faster.
+ */
+//#define FP_USE_THREAD_SAFE_EVAL
+//#define FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA
+
+/*
+ Uncomment (or define in your compiler options) to disable evaluation checks.
+ (Consult the documentation for details.)
+ */
+//#define FP_NO_EVALUATION_CHECKS
diff --git a/fparser/fpoptimizer.cc b/fparser/fpoptimizer.cc
new file mode 100644 (file)
index 0000000..5245eb7
--- /dev/null
@@ -0,0 +1,10839 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Function optimizer                                                      *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Joel Yliluoma                                                *|
+|*                                                                         *|
+|* This library is distributed under the terms of the                      *|
+|* GNU Lesser General Public License version 3.                            *|
+|* (See lgpl.txt and gpl.txt for the license text.)                        *|
+\***************************************************************************/
+
+/* NOTE:
+ This file contains generated code (from the optimizer sources) and is
+ not intended to be modified by hand. If you want to modify the optimizer,
+ download the development version of the library.
+*/
+
+#include "fpconfig.hh"
+#ifdef FP_SUPPORT_OPTIMIZER
+#include "fparser.hh"
+#include "fptypes.hh"
+#define i43 nW1 a),
+#define i33 info.yH
+#define i23 ,cAtan2
+#define i13 =false;
+#define i03 cAbsIf
+#define tZ3 "Found "
+#define tY3 },{{2,
+#define tX3 {if(apos
+#define tW3 stackpos
+#define tV3 "dup(%u) "
+#define tU3 GetOpcode
+#define tT3 eR{assert
+#define tS3 "%d, cost "
+#define tR3 "immed "<<
+#define tQ3 mFuncParsers
+#define tP3 "PUSH ";xE3(
+#define tO3 stderr
+#define tN3 sep2=" "
+#define tM3 FPHASH_CONST
+#define tL3 cache_needed[
+#define tK3 fprintf
+#define tJ3 ::cout<<"Applying "
+#define tI3 ||tree.tU3
+#define tH3 HANDLE_UNARY_CONST_FUNC
+#define tG3 within,
+#define tF3 y21){if
+#define tE3 c_count
+#define tD3 s_count
+#define tC3 MaxOp
+#define tB3 2)lS 2*
+#define tA3 x11.cG3
+#define t93 l7 0,2,
+#define t83 <eS1(0)
+#define t73 );else{
+#define t63 (n6)nN3
+#define t53 b.Value)
+#define t43 b.Opcode
+#define t33 .nB synth
+#define t23 ].swap(
+#define t13 =synth.
+#define t03 codes[b
+#define eZ3 Value){
+#define eY3 whydump
+#define eX3 i01 eF2
+#define eW3 for(x53
+#define eV3 ;for yS{
+#define eU3 );synth
+#define eT3 info.SaveMatchedParamIndex(
+#define eS3 for(;a<
+#define eR3 nparams
+#define eQ3 first!=
+#define eP3 i03,
+#define eO3 l3 4,1,
+#define eN3 cTan,xJ
+#define eM3 cLog,xJ
+#define eL3 l3 0,1,
+#define eK3 cHypot,
+#define eJ3 nR 0,
+#define eI3 cAbs nR
+#define eH3 std::cO
+#define eG3 fp_pow(
+#define eF3 ,cM2 lD
+#define eE3 .second
+#define eD3 ]eE3
+#define eC3 ].first
+#define eB3 Ne_Mask
+#define eA3 Gt_Mask
+#define e93 Lt_Mask
+#define e83 {nL eS1(
+#define e73 131,4,1,
+#define e63 tC1 max
+#define e53 tU cMul);
+#define e43 131,8,1
+#define e33 FindPos
+#define e23 nN yL
+#define e13 public:
+#define e03 result xM
+#define cZ3 result))lA2
+#define cY3 result(
+#define cX3 {data->
+#define cW3 .eW1 n]
+#define cV3 eG cK1);
+#define cU3 eG yR1
+#define cT3 if(eY1==
+#define cS3 ),has_max(
+#define cR3 (count
+#define cQ3 .empty()
+#define cP3 .iH1 a);
+#define cO3 GetParamCount(nQ
+#define cN3 GetParamCount();
+#define cM3 ;}case
+#define cL3 pclone
+#define cK3 sim.x3
+#define cJ3 fpdata
+#define cI3 cCosh nR
+#define cH3 cCosh,
+#define cG3 Immeds
+#define cF3 l6 1,
+#define cE3 x8(tB2
+#define cD3 newpow
+#define cC3 change
+#define cB3 133,2,
+#define cA3 i01 x2
+#define c93 Params
+#define c83 Needs
+#define c73 byteCode
+#define c63 eT1&occ=
+#define c53 child)
+#define c43 AddFrom(
+#define c33 lT1 nE==
+#define c23 ;for xK2
+#define c13 tC1 lY1
+#define c03 factor_t
+#define yZ3 tree.xJ1
+#define yY3 yA tmp2)
+#define yX3 value1
+#define yW3 model.
+#define yV3 true;n31
+#define yU3 &&p0.max
+#define yT3 p2 eT ifp2
+#define yS3 yJ p2;p2
+#define yR3 cAbsNot
+#define yQ3 switch(tX
+#define yP3 tZ case
+#define yO3 IsNever
+#define yN3 }switch
+#define yM3 stackptr
+#define yL3 nN[++IP]
+#define yK3 const xH
+#define yJ3 yE cPow)
+#define yI3 default_function_handling
+#define yH3 cLog);x9
+#define yG3 ;sim.Push(
+#define yF3 eS1(0.5)
+#define yE3 iJ 1,
+#define yD3 [funcno].
+#define yC3 :start_at()
+#define yB3 Rehash(tT yA
+#define yA3 .size()
+#define y93 IsLogicalValue nW1
+#define y83 (tree))e5
+#define y73 stack[stack yA3-
+#define y63 stack yL
+#define y53 tmp yC 0))
+#define y43 ));tmp tU
+#define y33 ,(long tG1
+#define y23 );tmp2 yC
+#define y13 cMul);xK
+#define y03 1),eS1(1))
+#define xZ3 constvalue
+#define xY3 lD 0));
+#define xX3 )nG1 xK
+#define xW3 nN[IP]==
+#define xV3 opcodes
+#define xU3 did_muli
+#define xT3 switch(lF3.first iY2
+#define xS3 ;for iL1
+#define xR3 Ge0Lt1
+#define xQ3 &&p.max
+#define xP3 :tree.
+#define xO3 =y6 a));if(
+#define xN3 used[b]
+#define xM3 e8(),yG<
+#define xL3 size_t n
+#define xK3 sizeof(
+#define xJ3 cNotNot,
+#define xI3 cOr yF
+#define xH3 359463,
+#define xG3 2,7168,
+#define xF3 param.
+#define xE3 DumpTree
+#define xD3 Gt0Le1
+#define xC3 y21){eS1
+#define xB3 base,eS1
+#define xA3 ==cOr)l9
+#define x93 cAdd iU1
+#define x83 (cM2 lD
+#define x73 lD 2));
+#define x63 eT cond
+#define x53 iX2 0;b<
+#define x43 {}range(
+#define x33 .n_int_sqrt
+#define x23 ,cPow,xJ
+#define x13 ,{1,218,
+#define x03 lD 1))
+#define nZ3 tmp yA tree
+#define nY3 eS1(1)))
+#define nX3 iterator
+#define nW3 begin();
+#define nV3 TreeSet
+#define nU3 parent
+#define nT3 insert(i
+#define nS3 newrel
+#define nR3 eS1(2)));
+#define nQ3 {eS1 tmp
+#define nP3 iU.hash1
+#define nO3 (tree)!=
+#define nN3 )n5 lC
+#define nM3 break;}
+#define nL3 b_needed
+#define nK3 cachepos
+#define nJ3 half=
+#define nI3 src_pos
+#define nH3 reserve(
+#define nG3 treeptr
+#define nF3 iC2 size()
+#define nE3 .resize(
+#define nD3 eU1 void
+#define nC3 ImmedTag
+#define nB3 a,const
+#define nA3 RefCount
+#define n93 Birth();
+#define n83 mulgroup
+#define n73 template
+#define n63 cost_t
+#define n53 n72 nZ
+#define n43 middle
+#define n33 ))break;eS1
+#define n23 };enum
+#define n13 if(op==
+#define n03 (p1.xJ1
+#define lZ3 cLog2by);
+#define lY3 sqrt_cost
+#define lX3 const int
+#define lW3 mul_count
+#define lV3 maxValue1
+#define lU3 minValue1
+#define lT3 maxValue0
+#define lS3 minValue0
+#define lR3 ValueType
+#define lQ3 >(eS1(1),
+#define lP3 abs_mul
+#define lO3 pos_set
+#define lN3 goto e3
+#define lM3 nF1);}if(
+#define lL3 yE cAdd);
+#define lK3 subtree
+#define lJ3 invtree
+#define lI3 lV1=r.specs;if(r.found){
+#define lH3 ,lV1,info
+#define lG3 a;if(&t91
+#define lF3 parampair
+#define lE3 rulenumit
+#define lD3 cIf,l6 3,
+#define lC3 MakeEqual
+#define lB3 nH1,l4::
+#define lA3 nH1,{l4::
+#define l93 newbase
+#define l83 branch1op
+#define l73 branch2op
+#define l63 overlap
+#define l53 truth_a
+#define l43 ),Value(
+#define l33 );nW l4::
+#define l23 if nW1 0)
+#define l13 found_dup
+#define l03 &1)?(poly^(
+#define iZ2 (xF3
+#define iY2 ){case
+#define iX2 size_t b=
+#define iW2 i0 xQ3
+#define iV2 has_min
+#define iU2 Plan_Has(
+#define iT2 ;if(half
+#define iS2 ;}void
+#define iR2 )iS2
+#define iQ2 const nI2
+#define iP2 yV1 class
+#define iO2 namespace
+#define iN2 rhs.hash2;}
+#define iM2 rhs.hash1
+#define iL2 ::res,b8<
+#define iK2 inverted
+#define iJ2 has_max=
+#define iI2 has_max)
+#define iH2 iftree
+#define iG2 depcodes
+#define iF2 explicit
+#define iE2 VarBegin
+#define iD2 cM3 lZ2
+#define iC2 c93.
+#define iB2 ].data);
+#define iA2 y4)));nW
+#define i92 .what eX
+#define i82 ;if(fp_equal(
+#define i72 x02 yJ
+#define i62 begin(),
+#define i52 cond_add
+#define i42 cond_mul
+#define i32 cond_and
+#define i22 yG n91
+#define i12 bool e31
+#define i02 unsigned
+#define tZ2 costree
+#define tY2 sintree
+#define tX2 leaf_count
+#define tW2 =GetParam(
+#define tV2 sub_params
+#define tU2 printf(
+#define tT2 cbrt_count
+#define tS2 sqrt_count
+#define tR2 Finite
+#define tQ2 p1 eT ifp1
+#define tP2 pcall_tree
+#define tO2 after_powi
+#define tN2 grammar
+#define tM2 lE 0,1,
+#define tL2 cCos,xJ
+#define tK2 cEqual,
+#define tJ2 ,eO3 507 tS
+#define tI2 ,t71 l7 2,2,
+#define tH2 cLog nR
+#define tG2 l0 2,
+#define tF2 cPow,nU
+#define tE2 cAdd,xZ 2,
+#define tD2 cInv,xZ 1,
+#define tC2 cNeg,xZ 1,
+#define tB2 ),0},{
+#define tA2 x11.SubTrees
+#define t92 x11.Others
+#define t82 param=*i01
+#define t72 std::move(
+#define t62 nM3 switch(
+#define t52 constraints=
+#define t42 .constraints
+#define t32 data;data.
+#define t22 MakeNEqual
+#define t12 for yS eC1
+#define t02 yA mul)
+#define eZ2 Dump(std::
+#define eY2 isInteger(
+#define eX2 (cond.cI cA2
+#define eW2 yA3;++
+#define eV2 nG1 r;r tU
+#define eU2 Comparison
+#define eT2 needs_flip
+#define eS2 {data xB lM
+#define eR2 ,eQ,synth);
+#define eQ2 (half&63)-1;
+#define eP2 value]
+#define eO2 ));TriTruthValue
+#define eN2 );range.nN2
+#define eM2 ,2,1,4,1,2,
+#define eL2 >StackMax)
+#define eK2 ~size_t(0)
+#define eJ2 );t4=!t4;}
+#define eI2 ;}yV1 static
+#define eH2 info.lQ[b].
+#define eG2 const std::eO
+#define eF2 Rule&rule,
+#define eE2 .GetHash().
+#define eD2 (list.first
+#define eC2 ;iU.hash2+=
+#define eB2 ,xA1);lC
+#define eA2 ,const e1&
+#define e92 struct
+#define e82 cGreater,
+#define e72 tree lD 0)
+#define e62 const eS1&
+#define e52 mul_item
+#define e42 innersub
+#define e32 cbrt_cost
+#define e22 best_cost
+#define e12 )))l81 lH
+#define e02 result i0
+#define cZ2 fp_mod(m.
+#define cY2 Compare>
+#define cX2 (*x6)[a].info
+#define cW2 tree y21 yI
+#define cV2 tree nE==
+#define cU2 condition
+#define cT2 per_item
+#define cS2 item_type
+#define cR2 first2
+#define cQ2 ,l8 0,2,
+#define cP2 tS 396676
+#define cO2 Decision
+#define cN2 not_tree
+#define cM2 leaf1
+#define cL2 =tree lD
+#define cK2 group_by
+#define cJ2 ->second
+#define cI2 targetpos
+#define cH2 eat_count
+#define cG2 ParamSpec
+#define cF2 Forget()
+#define cE2 exponent
+#define cD2 ,bool abs){
+#define cC2 synth.Find(
+#define cB2 params
+#define cA2 &&cond eH))
+#define c92 source_tree
+#define c82 nE==cLog2&&
+#define c72 =lT1;bool iQ
+#define c62 <t8,n63>
+#define c52 p1_evenness
+#define c42 c32 i13 if(
+#define c32 tC1 iV2
+#define c22 isNegative(
+#define c12 n73 i5
+#define c02 neg_set
+#define yZ2 StackTopIs(
+#define yY2 cNop,cNop}}
+#define yX2 synth.PushImmed(
+#define yW2 FPoptimizer_ByteCode yU2
+#define yV2 FPoptimizer_ByteCode::
+#define yU2 ::ByteCodeSynth x8
+#define yT2 cTanh,cNop,
+#define yS2 matches
+#define yR2 goto fail;}
+#define yQ2 cSin,xJ
+#define yP2 cTan nR
+#define yO2 cCos nR
+#define yN2 negated
+#define yM2 i7,1,iX+1);
+#define yL2 CodeTree
+#define yK2 yL2 x8
+#define yJ2 ifdata
+#define yI2 best_score
+#define yH2 mulvalue
+#define yG2 pow_item
+#define yF2 nE==cPow&&tJ
+#define yE2 PowiResult
+#define yD2 maxValue
+#define yC2 minValue
+#define yB2 ;pow tU cPow);pow
+#define yA2 result cM3
+#define y92 fp_min(xA,
+#define y82 set_min_max(
+#define y72 div_tree
+#define y62 pow_tree
+#define y52 preserve
+#define y42 PullResult()
+#define y32 dup_or_fetch
+#define y22 nominator]
+#define y12 Rehash(false
+#define y02 test_order
+#define xZ2 lF3,
+#define xY2 .param_count
+#define xX2 shift(index)
+#define xW2 rulenumber
+#define xV2 cTanh nR
+#define xU2 (tree nE
+#define xT2 GetDepth()
+#define xS2 factor_immed
+#define xR2 changes
+#define xQ2 tU tree nE);
+#define xP2 tU cond nE
+#define xO2 Become nW1
+#define xN2 },0,0x1},{{1,
+#define xM2 ,lJ 0x7 tY3
+#define xL2 ;n41 eT y9 lD
+#define xK2 (size_t a=
+#define xJ2 ;}static yN1
+#define xI2 tree lD a)
+#define xH2 for(typename
+#define xG2 exp_diff
+#define xF2 ExponentInfo
+#define xE2 lower_bound(
+#define xD2 factor
+#define xC2 is_logical
+#define xB2 newrel_and
+#define xA2 Suboptimal
+#define x92 cW[c tO
+#define x82 IsAlways;if(
+#define x72 n73 nA1
+#define x62 res_stackpos
+#define x52 half_pos
+#define x42 ;}else{x6=new
+#define x32 )lS 3*
+#define x22 {e1 start_at;
+#define x12 ,(long double)
+#define x02 .Rehash()
+#define nZ2 )return
+#define nY2 );cK3 iJ 2,
+#define nX2 return false;}
+#define nW2 );nM3
+#define nV2 xD1 tA+1);
+#define nU2 ;i7.Remember(
+#define nT2 .match_tree
+#define nS2 l81 true;}
+#define nR2 nD OPCODE
+#define nQ2 yG x8&immed,
+#define nP2 >>1)):(
+#define nO2 CodeTreeData
+#define nN2 multiply(
+#define nM2 i0 i13
+#define nL2 .n73
+#define nK2 var_trees
+#define nJ2 cOr,lP 2,
+#define nI2 yL2&
+#define nH2 ::Optimize(){
+#define nG2 second eE3;
+#define nF2 second.first;
+#define nE2 log2_exponent
+#define nD2 tT.swap(tmp);
+#define nC2 Value(Value::
+#define nB2 dup_fetch_pos
+#define nA2 nN,size_t&l31
+#define n92 *)&*start_at;
+#define n82 yO3 yI lC
+#define n72 ,tree))
+#define n62 ContainsOtherCandidates(
+#define n52 ,cPow l7 2,2,
+#define n42 cSin nR
+#define n32 lK 2},0,iR 1,
+#define n22 lK 1},0,iR 1,
+#define n12 Value_EvenInt
+#define n02 Sign_Negative
+#define lZ2 SubFunction:{
+#define lY2 ParamHolder:{
+#define lX2 MakeFalse,{l4
+#define lW2 if(xW lD a)iA
+#define lV2 ConditionType
+#define lU2 SpecialOpcode
+#define lT2 synth_it
+#define lS2 fp_max(xA);
+#define lR2 assimilated
+#define lQ2 fraction
+#define lP2 0x12},{{
+#define lO2 DUP_BOTH();
+#define lN2 -1-offset].
+#define lM2 tU3()
+#define lL2 parent_opcode)
+#define lK2 TreeCounts
+#define lJ2 bool t4 i13
+#define lI2 SetOpcode(
+#define lH2 found_log2
+#define lG2 div_params
+#define lF2 .CopyOnWrite()
+#define lE2 immed_sum
+#define lD2 OPCODE(opcode)
+#define lC2 std::cout<<"POP "
+#define lB2 (stack yA3-
+#define lA2 break;result*=
+#define l92 FactorStack x8
+#define l82 IsAlways yI lC
+#define l72 l7 2,2,lB1
+#define l62 248024 tS
+#define l52 cAnd,lP 2,
+#define l42 cNot nR
+#define l32 cMul,xZ 2,
+#define l22 DumpHashesFrom
+#define l12 replacing_slot
+#define l02 RefParams
+#define iZ1 if_always[
+#define iY1 WhatDoWhenCase
+#define iX1 exponent_immed
+#define iW1 new_base_immed
+#define iV1 base_immed
+#define iU1 ||op1==
+#define iT1 (size_t a xX
+#define iS1 data[a eD3
+#define iR1 AddCollection(
+#define iQ1 if(newrel_or==
+#define iP1 DUP_ONE(apos);
+#define iO1 flipped
+#define iN1 .UseGetNeeded(
+#define iM1 e9 2,131,
+#define iL1 (i02
+#define iK1 OptimizedUsing
+#define iJ1 Var_or_Funcno
+#define iI1 iJ1;
+#define iH1 DelParam(
+#define iG1 typename nX1::nX3
+#define iF1 )nZ2 true
+#define iE1 GetParams(
+#define iD1 crc32_t
+#define iC1 fphash_value_t
+#define iB1 signed_chain
+#define iA1 IsDefined())
+#define i91 MinusInf
+#define i81 n_immeds
+#define i71 FindClone(xK
+#define i61 denominator]
+#define i51 needs_rehash
+#define i41 AnyWhere_Rec
+#define i31 minimum_need
+#define i21 ~i02(0)
+#define i11 tC1 min
+#define i01 (const
+#define tZ1 ,i01 void*)&
+#define tY1 41,42,43,44,
+#define tX1 constraints&
+#define tW1 tT.iH1
+#define tV1 p1_logical_b
+#define tU1 p0_logical_b
+#define tT1 p1_logical_a
+#define tS1 p0_logical_a
+#define tR1 ,PowiCache&i7,
+#define tQ1 synth.DoDup(
+#define tP1 else if(
+#define tO1 cache_needed
+#define tN1 e9 2,1,e9 2,
+#define tM1 treelist
+#define tL1 IsDescendantOf(
+#define tK1 has_bad_balance
+#define tJ1 (tree,std::cout)
+#define tI1 .SetParamsMove(
+#define tH1 c03 xD2
+#define tG1 double)cE2
+#define tF1 {case IsAlways:
+#define tE1 e02=false
+#define tD1 ;cE2.Rehash(
+#define tC1 result.
+#define tB1 range x8 result
+#define tA1 TopLevel)
+#define t91 *start_at){x6=(
+#define t81 (rule,tree,info
+#define t71 cNEqual
+#define t61 ,cEqual l7 2,2,
+#define t51 cAdd,AnyParams,
+#define t41 lP2 xG3
+#define t31 ,cNotNot nR
+#define t21 ,cLess l7 2,2,
+#define t11 Oneness_NotOne|
+#define t01 Value_IsInteger
+#define eZ1 iK1(
+#define eY1 reltype
+#define eX1 SequenceOpcodes
+#define eW1 sep_list[
+#define eV1 );eG n83);
+#define eU1 l02);
+#define eT1 TreeCountItem
+#define eS1 Value_t
+#define eR1 divgroup
+#define eQ1 ,eS1(-1)))xF
+#define eP1 set_min(fp_floor
+#define eO1 pihalf_limits
+#define eN1 y41 p0.min>=0.0)
+#define eM1 MaxChildDepth
+#define eL1 situation_flags&
+#define eK1 i02 opcode)
+#define eJ1 =yM|i02(nN yA3
+#define eI1 std::pair<It,It>
+#define eH1 eO3 483 tS
+#define eG1 ,l8 0,1,
+#define eF1 tG2 7168,
+#define eE1 Value_Logical
+#define eD1 new_factor_immed
+#define eC1 if(remaining[a])
+#define eB1 occurance_pos
+#define eA1 exponent_hash
+#define e91 exponent_list
+#define e81 CollectionSet x8
+#define e71 CollectMulGroup(
+#define e61 source_set
+#define e51 cE2,nV3
+#define e41 produce_count
+#define e31 operator
+#define e21 )yJ3;lC
+#define e11 back().thenbranch
+#define e01 ParamSpec_Extract
+#define cZ1 retry_anyparams_3
+#define cY1 retry_anyparams_2
+#define cX1 needlist_cached_t
+#define cW1 grammar_rules[*r]
+#define cV1 tF2 0x1 tY3
+#define cU1 CodeTreeImmed x8(
+#define cT1 GetParamCount()==
+#define cS1 by_float_exponent
+#define cR1 fp_equal(cE2
+#define cQ1 new_exp
+#define cP1 end()&&i->first==
+#define cO1 yB3 r);}
+#define cN1 return BecomeZero;
+#define cM1 return BecomeOne;
+#define cL1 if(lQ yA3<=n2)
+#define cK1 addgroup
+#define cJ1 found_log2by
+#define cI1 ())yE cMul);lC
+#define cH1 >=eS1(0)
+#define cG1 nE==yR3)
+#define cF1 ParsePowiMuli(
+#define cE1 branch1_backup
+#define cD1 branch2_backup
+#define cC1 exponent_map
+#define cB1 plain_set
+#define cA1 LightWeight(
+#define c91 }nM3 case
+#define c81 cN3++b)
+#define c71 synth.x5 1
+#define c61 ,i7 eR2
+#define c51 if(value
+#define c41 set_max(fp_ceil cY
+#define c31 e62 v,n7
+#define c21 {eS1 cE2=
+#define c11 should_regenerate=true;
+#define c01 should_regenerate,
+#define yZ1 Collection
+#define yY1 RelationshipResult
+#define yX1 Subdivide_Combine(
+#define yW1 long value
+#define yV1 n73 lT
+#define yU1 yV1 cA
+#define yT1 yV1 e92
+#define yS1 eP nE3 StackMax
+#define yR1 subgroup
+#define yQ1 best_sep_factor
+#define yP1 tP1!result
+#define yO1 needlist_cached
+#define yN1 inline i02
+#define yM1 221646 tS 24803
+#define yL1 Constness_Const
+#define yK1 opcode,bool pad
+#define yJ1 n_occurrences
+#define yI1 changed=true;
+#define yH1 iH1 a);}
+#define yG1 MakesInteger(
+#define yF1 e62 value
+#define yE1 best_sep_cost
+#define yD1 MultiplicationRange
+#define yC1 ;p1.yB3 p1
+#define yB1 yV1 eS1
+#define yA1 n_stacked
+#define y91 AnyParams_Rec
+#define y81 continue;
+#define y71 Become(value lD 0))
+#define y61 ,cGreater l7 2,2,
+#define y51 yV1 inline TriTruthValue
+#define y41 .iV2&&
+#define y31 ));n41 y3 op1 tT.DelParams(
+#define y21 .IsImmed()
+#define y11 =comp.AddItem(atree
+#define y01 needs_sincos
+#define xZ1 Recheck_RefCount_Div
+#define xY1 Recheck_RefCount_Mul
+#define xX1 n83.
+#define xW1 n83;n83 tU
+#define xV1 MultiplyAndMakeLong(
+#define xU1 cMul);y53;tmp
+#define xT1 covers_plus1
+#define xS1 lD2);
+#define xR1 if(synth.FindAndDup(
+#define xQ1 SynthesizeParam(
+#define xP1 public e8,public yG<
+#define xO1 grammar_func
+#define xN1 221426 tS 237795
+#define xM1 t93 165888 tS
+#define xL1 Modulo_Radians},
+#define xK1 tT.SetParam(
+#define xJ1 GetImmed()
+#define xI1 PositionType
+#define xH1 CollectionResult
+#define xG1 yV1 bool
+#define xF1 const_offset
+#define xE1 stacktop_desired
+#define xD1 SetStackTop(
+#define xC1 ,cLessOrEq l7 2,2,
+#define xB1 yV1 void
+#define xA1 cond_type
+#define x91 Recheck_RefCount_RDiv
+#define x81 static const range x8
+#define x71 fPExponentIsTooLarge(
+#define x61 CollectMulGroup_Item(
+#define x51 pair<eS1,nV3>
+#define x41 covers_full_cycle
+#define x31 AssembleSequence(
+#define x21 x8(rule.repl_param_list,
+#define x11 NeedList
+#define x01 )lF3 eE3
+#define nZ1 <<std::dec<<")";}
+#define nY1 &&IsLogicalValue(
+#define nX1 TreeCountType x8
+#define nW1 (tree lD
+#define nV1 <yK2>
+#define nU1 std::pair<T1,T2>&
+#define nT1 n73<typename
+#define nS1 has_good_balance_found
+#define nR1 Rehash();tV2 yL
+#define nQ1 found_log2_on_exponent
+#define nP1 covers_minus1
+#define nO1 needs_resynth
+#define nN1 immed_product
+#define nM1 }},{ProduceNewTree,2,1,
+#define nL1 ,2,1)nS if(found[data.
+#define nK1 t62 bitmask&
+#define nJ1 Sign_Positive
+#define nI1 {DataP slot_holder(xY[
+#define nH1 ::MakeTrue
+#define nG1 {yK2
+#define nF1 tree.iH1 a
+#define nE1 tree lD 1)y21&&
+#define nD1 },{l4::MakeNotP0,l4::
+#define nC1 SetParamMove(
+#define nB1 CodeTreeImmed(eS1(
+#define nA1 <i02 cY2 void
+#define n91 <yL2>&
+#define n81 yG<i02>&c73,
+#define n71 void ByteCodeSynth x8::
+#define n61 )const{return
+#define n51 rhs n61 hash1
+#define n41 changed_if
+#define n31 min=eS1(0);
+#define n21 opposite=
+#define n11 7168 tS 279818,
+#define n01 l81 xA2;
+#define lZ1 MatchResultType
+#define lY1 resulting_exponent
+#define lX1 Unknown:default:;}
+#define lW1 ,lE 2,1,
+#define lV1 (*x6)[a].start_at
+#define lU1 ,cAdd,SelectedParams,0},0,
+#define lT1 GetParam(a)
+#define lS1 inverse_nominator]
+#define lR1 void FunctionParserBase
+#define lQ1 ,nN,IP,limit,y1,stack);
+#define lP1 ByteCodeSynth x8&synth)
+#define lO1 xS3 a=0;a<xT;++a)
+#define lN1 ;std::cout<<
+#define lM1 const yK2
+#define lL1 const yG nV1
+#define lK1 synth.AddOperation(
+#define lJ1 tQ1 found[data.
+#define lI1 SetParams(iE1));
+#define lH1 o<<"("<<std::hex<<data.
+#define lG1 IfBalanceGood(
+#define lF1 n_as_tan_param
+#define lE1 changed_exponent
+#define lD1 retry_positionalparams_2
+#define lC1 i02 index
+#define lB1 463 tS 273436,
+#define lA1 l7 2,2,473304 tS
+#define l91 {l4::MakeNotP1,l4::
+#define l81 ;return
+#define l71 yO3 l81 Unknown;}
+#define l61 PlanNtimesCache(
+#define l51 AddFunctionOpcode_Float(
+#define l41 FPoptimizer_Grammar
+#define l31 IP,size_t limit,size_t y1
+#define l21 AddOperation(cInv,1,1)nS}
+#define l11 e92 ImmedHashGenerator
+#define l01 GetPositivityInfo nO3
+#define iZ tB2 eS1(
+#define iY CopyOnWrite();
+#define iX recursioncount
+#define iW ParamSpec_SubFunctionData
+#define iV inverse_denominator]
+#define iU NewHash
+#define iT tree.GetParamCount()
+#define iS PositionalParams_Rec
+#define iR 0x4},{{
+#define iQ needs_cow=GetRefCount()>1;
+#define iP );nC1 0,cE2);iH1 1);
+#define iO DumpTreeWithIndent(*this);
+#define iN switch(type iY2 cond_or:
+#define iM CalculateResultBoundaries(
+#define iL e62 v,eS1(lN
+#define iK AddFunctionOpcode_Integer(
+#define iJ sim.Eat(
+#define iI edited_powgroup
+#define iH has_unknown_max
+#define iG has_unknown_min
+#define iF if(keep_powi
+#define iE synthed_tree
+#define iD 356668 tS 24852
+#define iC +2]=yM|i02(Immed yA3);
+#define iB matched_params
+#define iA .IsIdenticalTo(
+#define i9 by_exponent
+#define i8 collections
+#define i7 cache
+#define i6 }inline
+#define i5 lT void range x8::
+#define i4 yA comp.cB1[a].value);
+#define i3 AnyParams,2},0,0x0},{{
+#define i2 cS1.data
+#define i1 iF2 nO2(
+#define i0 .has_max
+#define tZ goto ReplaceTreeWithZero;
+#define tY :goto ReplaceTreeWithOne;case
+#define tX GetLogicalValue nW1
+#define tW lN1 std::endl;DumpHashes(
+#define tV ;p2.yB3 p2);tH iH2 nE);e5}
+#define tU .lI2
+#define tT );tree
+#define tS ,{2,
+#define tR lZ 0x0},{{
+#define tQ yV1 nA
+#define tP MakeFalse,l4::
+#define tO ].relationship
+#define tN <=fp_const_negativezero x8())
+#define tM .hash1|=key;iC1 n9
+#define tL [n2 eC3=true;lQ[n2 eD3
+#define tK l41::Grammar*
+#define tJ powgroup lD
+#define tI ;pow tU cLog);tH cMul);
+#define tH tree tU
+#define tG eK2&&found[data.
+#define tF },{l4::MakeNotNotP1,l4::
+#define tE },{l4::MakeNotNotP0,l4::
+#define tD cN3 a-->0;)if(
+#define tC nB1(
+#define tB has_mulgroups_remaining
+#define tA StackTop
+#define t9 MatchInfo x8&
+#define t8 int_exponent_t
+#define t7 RootPowerTable x8::RootPowers[
+#define t6 MatchPositionSpec_AnyParams x8
+#define t5 iO2 FPoptimizer_ByteCode
+#define t4 is_signed
+#define t3 iE1));xX1 Rehash();
+#define t2 result_positivity
+#define t1 biggest_minimum
+#define t0 const iW
+#define eZ ParamSpec_NumConstant x8
+#define eY yK2&tree,std::ostream&o
+#define eX !=Unchanged)if(TestCase(
+#define eW cond_tree
+#define eV else_tree
+#define eU then_tree
+#define eT .AddParam(
+#define eS ;xE3(tree)lN1"\n";
+#define eR yK2&tree)
+#define eQ sequencing
+#define eP StackState
+#define eO string FP_GetOpcodeName(
+#define eN if_stack
+#define eM {return yK2(
+#define eL n_as_sin_param
+#define eK n_as_cos_param
+#define eJ PowiResolver::
+#define eI ];};extern"C"{
+#define eH .BalanceGood
+#define eG AddParamMove(
+#define eF valueType
+#define eE best_factor
+#define eD back().endif_location
+#define eC iC1(iJ1)
+#define eB iC1 key
+#define eA l8 2,1,
+#define e9 130,1,
+#define e8 MatchPositionSpecBase
+#define e7 iF2 yL2(
+#define e6 smallest_maximum
+#define e5 goto redo;
+#define e4 ++IP;y81}if(xW3 xV3.
+#define e3 ReplaceTreeWithParam0;
+#define e2 factor_needs_rehashing
+#define e1 MatchPositionSpecBaseP
+#define e0 nL eS1(-y03;
+#define cZ 79,112,113,117,118,123,124,127,128,
+#define cY )l81 m cM3
+#define cX e01 x8(nM.param_list,
+#define cW relationships
+#define cV 28,29,30,31,32,33,34,35,36,
+#define cU cIf,l0 3,
+#define cT lK 2},0,0x0},{{
+#define cS data.subfunc_opcode
+#define cR }if eD2.xJ1==eS1(
+#define cQ otherhalf
+#define cP :{AdoptChildrenWithSameOpcode(tree);
+#define cO map<fphash_t,std::set<std::string> >
+#define cN const SequenceOpCode x8
+#define cM =fp_cosh(m.min);m.max=fp_cosh(m.max);
+#define cL MatchPositionSpec_PositionalParams x8
+#define cK eS1(1.5)*fp_const_pi x8()
+#define cJ !=Unchanged nZ2 iZ1
+#define cI FoundChild
+#define cH CalculatePowiFactorCost(
+#define cG T1,typename T2>inline i12()(
+#define cF yK2 tmp;tmp tU
+#define cE has_nonlogical_values
+#define cD from_logical_context)
+#define cC for xK2 xW.cN3 a-->0;)
+#define cB POWI_CACHE_SIZE
+#define cA static inline yK2
+#define c9 BalanceResultType
+#define c8 cIf,eL3
+#define c7 nA3(0),Opcode(
+#define c6 const{return data->
+#define c5 +=fp_const_twopi x8();
+#define c4 .AddOperation(lM2,
+#define c3 for xK2 0;a<cN3++a){if(
+#define c2 static void MakeHash(nD fphash_t&iU,
+#define c1 l2 2,
+#define c0 MatchPositionSpec_AnyWhere
+#define yZ if iZ2 data.match_type==
+#define yY }PACKED_GRAMMAR_ATTRIBUTE;
+#define yX ,cGreaterOrEq l7 2,2,
+#define yW void OutFloatHex(std::ostream&o,
+#define yV yV1 x72 range x8::
+#define yU b;}};n73<>e92 Comp<
+#define yT eT CodeTreeImmed(
+#define yS xK2 0;a<iT;++a)
+#define yR t93 115824 tS 122999,
+#define yQ t93 129136 tS 128123,
+#define yP t93 472176 tS 24699,
+#define yO ,typename yK2::
+#define yN AssembleSequence_Subdivide(
+#define yM 0x80000000u
+#define yL .push_back(
+#define yK !=eK2){lJ1
+#define yJ ;yK2
+#define yI nZ2 false;
+#define yH paramholder_matches
+#define yG std::vector
+#define yF ,AnyParams,0 l1 0,1,
+#define yE ;iJ 2,
+#define yD for(lE3 r=range.first;r!=range eE3;++r){
+#define yC eT tree lD
+#define yB ComparisonSetBase::
+#define yA .eG
+#define y9 branch2
+#define y8 fp_const_twopi x8());if(
+#define y7 n73 set_min_max_if<cGreater>(eS1(0),
+#define y6 iM tree lD
+#define y5 =y6 0));range x8
+#define y4 tree lD 1).xJ1
+#define y3 x02;tH
+#define y2 lX&&tree lD 1)y21
+#define y1 factor_stack_base
+#define y0 cPow,l6 2,
+#define xZ GroupFunction,0},n0{{
+#define xY data->c93
+#define xX =0;a<nU3.cN3++a)if(
+#define xW branch1
+#define xV {lK2.erase(i);y81}
+#define xU xK2 iT;a-->0;)
+#define xT nM xY2
+#define xS i02 c;i02 char l[
+#define xR 158,167,168,169,178,179,191,195,203,207,215,227,229,232,233,234,235,236,239,240,241,242,245,246,247,248,250,251}};}e92
+#define xQ using iO2 FUNCTIONPARSERTYPES;
+#define xP const eY=std::cout
+#define xO IsIdenticalTo(leaf2 lD
+#define xN FPOPT_autoptr
+#define xM +=result l81 result;}yV1 inline eS1
+#define xL int_exponent
+#define xK newnode
+#define xJ l3 2,1,
+#define xI ParamSpec_SubFunction
+#define xH ParamSpec_ParamHolder
+#define xG has_highlevel_opcodes
+#define xF {if(needs_cow){iY goto
+#define xE ;if(fp_nequal(tmp,eS1(0)))lL eS1(1)/tmp)n5}lC
+#define xD },{l4::Unchanged,l4::Never},{l4::Unchanged,l4::Never}}
+#define xC best_selected_sep
+#define xB ->Recalculate_Hash_NoRecursion();}
+#define xA fp_sin(min),fp_sin(max))
+#define x9 sim.AddConst(
+#define x8 <eS1>
+#define x7 :nG1 tmp,tmp2;tmp2 tU
+#define x6 position
+#define x5 GetStackTop()-
+#define x4 for yS{range x8
+#define x3 SwapLastTwoInStack();
+#define x2 FPoptimizer_CodeTree::yK2&tree
+#define x1 SetParam(0,iH2 lD 0))yJ p1;p1 tU
+#define x0 TestImmedConstraints(param t42,tree)yI
+#define nZ {tree.FixIncompleteHashes();}
+#define nY {yE3 cInv nW2 x9-1 e21
+#define nX paramholder_index
+#define nW return true;case
+#define nV occurance_counts
+#define nU PositionalParams,0},0,
+#define nT xQ xD1 tA-1);
+#define nS ;synth.yZ2*this)l81;}
+#define nR ,l0 1,
+#define nQ );a-->0;){lM1&powgroup=lT1;if(powgroup
+#define nP ;a<iT;++a)if(ApplyGrammar(tN2,xI2,
+#define nO lK 1},0,0x0},{{
+#define nN ByteCode
+#define nM model_tree
+#define nL return range x8(
+#define nK yG nV1&l02
+#define nJ ConstantFolding_LogicCommon(tree,yB
+#define nI eS1>p xO3 p.
+#define nH nT1 Ref>inline void xN<Ref>::
+#define nG ;tmp2 yC 0 y43 cInv);tmp yY3 l81
+#define nF ):data(new nO2 x8(
+#define nE .lM2
+#define nD FUNCTIONPARSERTYPES::
+#define nC iJ1(),c93(),Hash(),Depth(1),eZ1 0){}
+#define nB SynthesizeByteCode(synth);
+#define nA nO2 x8::nO2(
+#define n9 crc=(key>>10)|(key<<(64-10))eC2((~iC1(crc))*3)^1234567;}};
+#define n8 GetIntegerInfo nW1 0))==IsAlways)lN3
+#define n7 eS1(*const func)(eS1),range x8 model){
+#define n6 e72.xJ1
+#define n5 ;goto do_return;}
+#define n4 while(ApplyGrammar(i01 Grammar&)
+#define n3 DumpParams x8 iZ2 data.param_list,xF3 data xY2,o);
+#define n2 restholder_index
+#define n1 yK2 cE2;cE2 e53 cE2 eT
+#define n0 yL1,0x0},
+#define lZ t51 1},0,
+#define lY ;tree yA n41)nS2
+#define lX l23 y21
+#define lW eG pow x03;pow.iH1 1);pow.Rehash(tT.nC1 0,pow);goto NowWeAreMulGroup;}
+#define lV {cF cPow);y53;tmp yT eS1(
+#define lU :if(ParamComparer x8()(c93[1],c93[0])){std::swap(c93[0],c93[1]);Opcode=
+#define lT <typename eS1>
+#define lS ,eS1(1)/eS1(
+#define lR SetParam(0,e72 lD 0)xK1 1,CodeTreeImmed(
+#define lQ restholder_matches
+#define lP SelectedParams,0},0,0x0},{{
+#define lO n41;n41 xQ2 n41 yA e72);n41 eT xW lD
+#define lN *const func)(eS1),range x8 model=range x8());
+#define lM yV1 yK2::yL2(
+#define lL {tree.ReplaceWithImmed(
+#define lK cMul,AnyParams,
+#define lJ cMul,SelectedParams,0},0,
+#define lI cPow,l0 2
+#define lH iM tmp)cM3
+#define lG :cC3=comp.AddRelationship(atree lD 0),atree lD 1),yB
+#define lF typename eS1>i12()i01 eS1&a,e62 b){return a
+#define lE t51 0 l1
+#define lD .GetParam(
+#define lC break;case
+#define lB {range x8 m=y6 0));
+#define lA xB1 yK2::
+#define l9 ?0:1))yJ n41;n41 xQ2 n41 tI1 tree.iE1));n41 y3
+#define l8 lK 0 l1
+#define l7 ,PositionalParams,0 l1
+#define l6 nU iR
+#define l5 cAdd,lP 2,
+#define l4 RangeComparisonData
+#define l3 PositionalParams,0}},{ProduceNewTree,
+#define l2 lJ 0x0},{{
+#define l1 }},{ReplaceParams,
+#define l0 nU 0x0},{{
+#ifdef _MSC_VER
+typedef
+i02
+int
+iD1;
+#else
+#include <stdint.h>
+typedef
+uint_least32_t
+iD1;
+#endif
+iO2
+crc32{enum{startvalue=0xFFFFFFFFUL,poly=0xEDB88320UL}
+;n73<iD1
+crc>e92
+b8{enum{b1=(crc
+l03
+crc
+nP2
+crc>>1),b2=(b1
+l03
+b1
+nP2
+b1>>1),b3=(b2
+l03
+b2
+nP2
+b2>>1),b4=(b3
+l03
+b3
+nP2
+b3>>1),b5=(b4
+l03
+b4
+nP2
+b4>>1),b6=(b5
+l03
+b5
+nP2
+b5>>1),b7=(b6
+l03
+b6
+nP2
+b6>>1),res=(b7
+l03
+b7
+nP2
+b7>>1)}
+;}
+;inline
+iD1
+update(iD1
+crc,i02
+b){
+#define B4(n) b8<n>iL2 n+1>iL2 n+2>iL2 n+3>::res
+#define R(n) B4(n),B4(n+4),B4(n+8),B4(n+12)
+static
+const
+iD1
+table[256]={R(0x00),R(0x10),R(0x20),R(0x30),R(0x40),R(0x50),R(0x60),R(0x70),R(0x80),R(0x90),R(0xA0),R(0xB0),R(0xC0),R(0xD0),R(0xE0),R(0xF0)}
+;
+#undef R
+#undef B4
+return((crc>>8))^table[(crc^b)&0xFF];i6
+iD1
+calc_upd(iD1
+c,const
+i02
+char*buf,size_t
+size){iD1
+value=c;for(size_t
+p=0;p<size;++p)value=update(value,buf[p])l81
+value;i6
+iD1
+calc
+i01
+i02
+char*buf,size_t
+size){return
+calc_upd(startvalue,buf,size);}
+}
+#ifndef FPOptimizerAutoPtrHH
+#define FPOptimizerAutoPtrHH
+nT1
+Ref>class
+xN{e13
+xN():p(0){}
+xN(Ref*b):p(b){n93}
+xN
+i01
+xN&b):p(b.p){n93
+i6
+Ref&e31*(n61*p;i6
+Ref*e31->(n61
+p;}
+xN&e31=(Ref*b){Set(b)l81*this;}
+xN&e31=i01
+xN&b){Set(b.p)l81*this;}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+xN(xN&&b):p(b.p){b.p=0;}
+xN&e31=(xN&&b){if(p!=b.p){cF2;p=b.p;b.p=0;}
+return*this;}
+#endif
+~xN(){cF2
+iS2
+UnsafeSetP(Ref*newp){p=newp
+iS2
+swap(xN<Ref>&b){Ref*tmp=p;p=b.p;b.p=tmp;}
+private:inline
+static
+void
+Have(Ref*p2);inline
+void
+cF2;inline
+void
+n93
+inline
+void
+Set(Ref*p2);private:Ref*p;}
+;nH
+cF2{if(!p
+nZ2;p->nA3-=1;if(!p->nA3)delete
+p;}
+nH
+Have(Ref*p2){if(p2)++(p2->nA3);}
+nH
+Birth(){Have(p);}
+nH
+Set(Ref*p2){Have(p2);cF2;p=p2;}
+#endif
+#include <utility>
+e92
+Compare2ndRev{nT1
+T>inline
+i12()i01
+T&nB3
+T&b
+n61
+a
+eE3>b
+eE3;}
+}
+;e92
+Compare1st{nT1
+cG
+const
+nU1
+nB3
+nU1
+b
+n61
+a.first<b.first;}
+nT1
+cG
+const
+nU1
+a,T1
+b
+n61
+a.first<b;}
+nT1
+cG
+T1
+nB3
+nU1
+b
+n61
+a<b.first;}
+}
+;
+#ifndef FPoptimizerHashHH
+#define FPoptimizerHashHH
+#ifdef _MSC_VER
+typedef
+i02
+long
+long
+iC1;
+#define FPHASH_CONST(x) x##ULL
+#else
+#include <stdint.h>
+typedef
+uint_fast64_t
+iC1;
+#define FPHASH_CONST(x) x##ULL
+#endif
+iO2
+FUNCTIONPARSERTYPES{e92
+fphash_t{iC1
+hash1,hash2;fphash_t():hash1(0),hash2(0){}
+fphash_t
+i01
+iC1&nB3
+iC1&b):hash1(a),hash2(b){}
+i12==i01
+fphash_t&n51==iM2&&hash2==iN2
+i12!=i01
+fphash_t&n51!=iM2||hash2!=iN2
+i12<i01
+fphash_t&n51!=iM2?hash1<iM2:hash2<iN2}
+;}
+#endif
+#ifndef FPOptimizer_CodeTreeHH
+#define FPOptimizer_CodeTreeHH
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <vector>
+#include <utility>
+iO2
+l41{e92
+Grammar;}
+t5{iP2
+ByteCodeSynth;}
+iO2
+FPoptimizer_CodeTree{iP2
+yL2;yT1
+nO2;iP2
+yL2{typedef
+xN<nO2
+x8>DataP;DataP
+data;e13
+yL2();~yL2();e92
+OpcodeTag{}
+;e7
+nR2
+o,OpcodeTag);e92
+FuncOpcodeTag{}
+;e7
+nR2
+o,i02
+f,FuncOpcodeTag);e92
+nC3{}
+;e7
+e62
+v,nC3);
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+e7
+eS1&&v,nC3);
+#endif
+e92
+VarTag{}
+;e7
+i02
+varno,VarTag);e92
+CloneTag{}
+;e7
+iQ2
+b,CloneTag);void
+GenerateFrom
+i01
+n81
+const
+nQ2
+const
+typename
+FunctionParserBase
+x8::Data&data,bool
+keep_powi=false);void
+GenerateFrom
+i01
+n81
+const
+nQ2
+const
+typename
+FunctionParserBase
+x8::Data&data,const
+i22
+nK2,bool
+keep_powi=false);void
+SynthesizeByteCode(n81
+nQ2
+size_t&stacktop_max);void
+SynthesizeByteCode(yW2&synth,bool
+MustPopTemps=true)const;size_t
+SynthCommonSubExpressions(yV2
+lP1
+const;void
+SetParams
+i01
+i22
+nD3
+SetParamsMove(i22
+eU1
+yL2
+GetUniqueRef();
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+void
+SetParams(yG<yL2>&&eU1
+#endif
+void
+SetParam(size_t
+which,iQ2
+b);void
+nC1
+size_t
+which,nI2
+b);void
+AddParam
+i01
+nI2
+param);void
+eG
+nI2
+param);void
+AddParams
+i01
+i22
+nD3
+AddParamsMove(i22
+nD3
+AddParamsMove(i22
+l02,size_t
+l12);void
+iH1
+size_t
+index);void
+DelParams();void
+Become
+i01
+nI2
+b);inline
+size_t
+GetParamCount(n61
+iE1)yA3;i6
+nI2
+GetParam(xL3){return
+iE1)[n];i6
+iQ2
+GetParam(xL3
+n61
+iE1)[n];i6
+void
+lI2
+nR2
+o)cX3
+Opcode=o;i6
+nR2
+lM2
+c6
+Opcode;i6
+nD
+fphash_t
+GetHash()c6
+Hash;i6
+const
+i22
+iE1
+n61
+xY;i6
+i22
+iE1){return
+xY;i6
+size_t
+xT2
+c6
+Depth;i6
+e62
+xJ1
+c6
+Value;i6
+i02
+GetVar()c6
+iI1
+i6
+i02
+GetFuncNo()c6
+iI1
+i6
+bool
+IsDefined(n61
+lM2!=nD
+cNop;i6
+bool
+IsImmed(n61
+lM2==nD
+cImmed;i6
+bool
+IsVar(n61
+lM2==nD
+iE2;i6
+i02
+GetRefCount()c6
+nA3
+iS2
+ReplaceWithImmed
+i01
+eS1&i);void
+Rehash(bool
+constantfolding=true);void
+Sort();inline
+void
+Mark_Incompletely_Hashed()cX3
+Depth=0;i6
+bool
+Is_Incompletely_Hashed()c6
+Depth==0;i6
+const
+tK
+GetOptimizedUsing()c6
+iK1;i6
+void
+SetOptimizedUsing
+i01
+tK
+g)cX3
+iK1=g;}
+bool
+RecreateInversionsAndNegations(bool
+prefer_base2=false);void
+FixIncompleteHashes();void
+swap(nI2
+b){data.swap(b.data);}
+bool
+IsIdenticalTo
+i01
+nI2
+b)const;void
+iY}
+;yT1
+nO2{int
+nA3;nR2
+Opcode;eS1
+Value;i02
+iI1
+yG
+nV1
+c93;nD
+fphash_t
+Hash;size_t
+Depth;const
+tK
+iK1;nO2();nO2
+i01
+nO2&b);i1
+nR2
+o);i1
+nR2
+o,i02
+f);i1
+e62
+i);
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+i1
+eS1&&i);nO2(nO2&&b);
+#endif
+bool
+IsIdenticalTo
+i01
+nO2&b)const;void
+Sort();void
+Recalculate_Hash_NoRecursion();private:void
+e31=i01
+nO2&b);}
+;yU1
+CodeTreeImmed
+i01
+eS1&i)eM
+i
+yO
+nC3());}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+yU1
+CodeTreeImmed(eS1&&i)eM
+t72
+i)yO
+nC3());}
+#endif
+yU1
+CodeTreeOp(nR2
+opcode)eM
+opcode
+yO
+OpcodeTag());}
+yU1
+CodeTreeFuncOp(nR2
+opcode,i02
+f)eM
+opcode,f
+yO
+FuncOpcodeTag());}
+yU1
+CodeTreeVar
+iL1
+varno)eM
+varno
+yO
+VarTag());}
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+xB1
+DumpHashes(xP);xB1
+xE3(xP);xB1
+DumpTreeWithIndent(xP,const
+std::string&indent="\\"
+);
+#endif
+}
+#endif
+#endif
+#ifndef FPOPT_NAN_CONST
+#include <iostream>
+#define FPOPT_NAN_CONST (-1712345.25)
+iO2
+FPoptimizer_CodeTree{iP2
+yL2;}
+iO2
+l41{enum
+ImmedConstraint_Value{ValueMask=0x07,Value_AnyNum=0x0,n12=0x1,Value_OddInt=0x2,t01=0x3,Value_NonInteger=0x4,eE1=0x5
+n23
+ImmedConstraint_Sign{SignMask=0x18,Sign_AnySign=0x00,nJ1=0x08,n02=0x10,Sign_NoIdea=0x18
+n23
+ImmedConstraint_Oneness{OnenessMask=0x60,Oneness_Any=0x00,Oneness_One=0x20,Oneness_NotOne=0x40
+n23
+ImmedConstraint_Constness{ConstnessMask=0x180,Constness_Any=0x00,yL1=0x80,Constness_NotConst=0x100
+n23
+Modulo_Mode{Modulo_None=0,Modulo_Radians=1
+n23
+Situation_Flags{LogicalContextOnly=0x01,NotForIntegers=0x02,OnlyForIntegers=0x04
+n23
+lU2{NumConstant,ParamHolder,SubFunction
+n23
+ParamMatchingType{PositionalParams,SelectedParams,AnyParams,GroupFunction
+n23
+RuleType{ProduceNewTree,ReplaceParams}
+;
+#ifdef __GNUC__
+# define PACKED_GRAMMAR_ATTRIBUTE __attribute__((packed))
+#else
+# define PACKED_GRAMMAR_ATTRIBUTE
+#endif
+typedef
+std::pair<lU2,const
+void*>cG2;yV1
+cG2
+e01
+iL1
+paramlist,lC1);xG1
+ParamSpec_Compare
+i01
+void*nB3
+void*b,lU2
+type);i02
+ParamSpec_GetDepCode
+i01
+cG2&b);e92
+xH{lC1:8;i02
+constraints:9;i02
+depcode:15;yY
+yT1
+ParamSpec_NumConstant{eS1
+xZ3;i02
+modulo;yY
+e92
+iW{i02
+param_count:2;i02
+param_list:30;nR2
+subfunc_opcode:8;ParamMatchingType
+match_type:3;i02
+n2:5;yY
+e92
+xI{iW
+data;i02
+constraints:9;i02
+depcode:7;yY
+e92
+Rule{RuleType
+ruletype:2;i02
+situation_flags:3;i02
+repl_param_count:2+11;i02
+repl_param_list:30;iW
+match_tree;yY
+e92
+Grammar{i02
+rule_count;i02
+char
+rule_list[999
+eI
+extern
+const
+Rule
+grammar_rules[];}
+xB1
+DumpParam
+i01
+cG2&p,std::ostream&o=std::cout);xB1
+DumpParams
+iL1
+paramlist,i02
+count,std::ostream&o=std::cout);}
+#endif
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795
+#endif
+#define CONSTANT_POS_INF HUGE_VAL
+#define CONSTANT_NEG_INF (-HUGE_VAL)
+iO2
+FUNCTIONPARSERTYPES{yV1
+inline
+eS1
+fp_const_pihalf(){return
+fp_const_pi
+x8()*yF3;}
+yV1
+inline
+eS1
+fp_const_twopi(){eS1
+cY3
+fp_const_pi
+x8());e03
+fp_const_twoe(){eS1
+cY3
+fp_const_e
+x8());e03
+fp_const_twoeinv(){eS1
+cY3
+fp_const_einv
+x8());e03
+fp_const_negativezero(){
+#ifdef FP_EPSILON
+return-fp_epsilon
+x8();
+#else
+return
+eS1(-1e-14);
+#endif
+}
+}
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <vector>
+#include <utility>
+#include <iostream>
+iO2
+FPoptimizer_Optimize{using
+iO2
+l41;using
+iO2
+FPoptimizer_CodeTree;xQ
+iP2
+MatchInfo{e13
+yG<std::pair<bool,yG
+nV1> >lQ;yG
+nV1
+yH;yG<i02>iB;e13
+MatchInfo():lQ(),yH(),iB(){}
+e13
+bool
+SaveOrTestRestHolder
+iL1
+n2,lL1&tM1){cL1{lQ
+nE3
+n2+1);lQ
+tL=tM1
+nS2
+if(lQ[n2
+eC3==false){lQ
+tL=tM1
+nS2
+lL1&found=lQ[n2
+eD3;if(tM1
+yA3!=found
+yA3
+yI
+for
+xK2
+0;a<tM1
+eW2
+a)if(!tM1[a]iA
+found[a])yI
+return
+true
+iS2
+SaveRestHolder
+iL1
+n2,yG
+nV1&tM1){cL1
+lQ
+nE3
+n2+1);lQ
+tL.swap(tM1);}
+bool
+SaveOrTestParamHolder
+iL1
+nX,lM1&nG3){if(yH
+yA3<=nX){yH.nH3
+nX+1);yH
+nE3
+nX);yH
+yL
+nG3)nS2
+if(!yH[nX].iA1{yH[nX]=nG3
+nS2
+return
+nG3
+iA
+yH[nX]iR2
+SaveMatchedParamIndex(lC1){iB
+yL
+index);}
+lM1&GetParamHolderValueIfFound
+iL1
+nX)const{static
+lM1
+dummytree;if(yH
+yA3<=nX
+nZ2
+dummytree
+l81
+yH[nX];}
+lM1&GetParamHolderValue
+iL1
+nX
+n61
+yH[nX];}
+bool
+HasRestHolder
+iL1
+n2
+n61
+lQ
+yA3>n2&&lQ[n2
+eC3==true;}
+lL1&GetRestHolderValues
+iL1
+n2)const{static
+lL1
+empty_result;cL1
+return
+empty_result
+l81
+lQ[n2
+eD3;}
+const
+yG<i02>&GetMatchedParamIndexes(n61
+iB
+iS2
+swap(t9
+b){lQ.swap(b.lQ);yH.swap(b.yH);iB.swap(b.iB);}
+t9
+e31=i01
+t9
+b){lQ=b.lQ;yH=b.yH;iB=b.iB
+l81*this;}
+}
+;class
+e8;typedef
+xN<e8>e1;class
+e8{e13
+int
+nA3;e13
+e8():nA3(0){}
+virtual~e8(){}
+}
+;e92
+lZ1{bool
+found;e1
+specs;lZ1(bool
+f):found(f),specs(){}
+lZ1(bool
+f
+eA2
+s):found(f),specs(s){}
+}
+;xB1
+SynthesizeRule
+eX3
+yK2&tree,t9
+info);yV1
+lZ1
+TestParam
+i01
+cG2&xZ2
+lM1&tree
+eA2
+start_at,t9
+info);yV1
+lZ1
+TestParams(t0&nM,lM1&tree
+eA2
+start_at,t9
+info,bool
+tA1;xG1
+ApplyGrammar
+i01
+Grammar&tN2,x2,bool
+from_logical_context=false);xB1
+ApplyGrammars(x2);xG1
+IsLogisticallyPlausibleParamsMatch(t0&cB2,const
+eR;}
+iO2
+l41{xB1
+DumpMatch
+eX3
+const
+x2,const
+FPoptimizer_Optimize::t9
+info,bool
+DidMatch,std::ostream&o=std::cout);xB1
+DumpMatch
+eX3
+const
+x2,const
+FPoptimizer_Optimize::t9
+info,const
+char*eY3,std::ostream&o=std::cout);}
+#endif
+#include <string>
+eG2
+l41::lU2
+yK1=false);eG2
+nR2
+yK1=false);
+#include <string>
+#include <sstream>
+#include <assert.h>
+#include <iostream>
+using
+iO2
+l41;xQ
+eG2
+l41::lU2
+yK1){
+#if 1
+const
+char*p=0;switch(opcode
+iY2
+NumConstant:p="NumConstant"
+;lC
+ParamHolder:p="ParamHolder"
+;lC
+SubFunction:p="SubFunction"
+;nM3
+std::ostringstream
+tmp;assert(p);tmp<<p;if(pad)while(tmp.str()yA3<12)tmp<<' 'l81
+tmp.str();
+#else
+std::ostringstream
+tmp;tmp<<opcode;if(pad)while(tmp.str()yA3<5)tmp<<' 'l81
+tmp.str();
+#endif
+}
+eG2
+nR2
+yK1){
+#if 1
+const
+char*p=0;switch(opcode
+iY2
+cAbs:p="cAbs"
+;lC
+cAcos:p="cAcos"
+;lC
+cAcosh:p="cAcosh"
+;lC
+cAsin:p="cAsin"
+;lC
+cAsinh:p="cAsinh"
+;lC
+cAtan:p="cAtan"
+;lC
+cAtan2:p="cAtan2"
+;lC
+cAtanh:p="cAtanh"
+;lC
+cCbrt:p="cCbrt"
+;lC
+cCeil:p="cCeil"
+;lC
+cCos:p="cCos"
+;lC
+cCosh:p="cCosh"
+;lC
+cCot:p="cCot"
+;lC
+cCsc:p="cCsc"
+;lC
+cEval:p="cEval"
+;lC
+cExp:p="cExp"
+;lC
+cExp2:p="cExp2"
+;lC
+cFloor:p="cFloor"
+;lC
+cHypot:p="cHypot"
+;lC
+cIf:p="cIf"
+;lC
+cInt:p="cInt"
+;lC
+cLog:p="cLog"
+;lC
+cLog2:p="cLog2"
+;lC
+cLog10:p="cLog10"
+;lC
+cMax:p="cMax"
+;lC
+cMin:p="cMin"
+;lC
+cPow:p="cPow"
+;lC
+cSec:p="cSec"
+;lC
+cSin:p="cSin"
+;lC
+cSinh:p="cSinh"
+;lC
+cSqrt:p="cSqrt"
+;lC
+cTan:p="cTan"
+;lC
+cTanh:p="cTanh"
+;lC
+cTrunc:p="cTrunc"
+;lC
+cImmed:p="cImmed"
+;lC
+cJump:p="cJump"
+;lC
+cNeg:p="cNeg"
+;lC
+cAdd:p="cAdd"
+;lC
+cSub:p="cSub"
+;lC
+cMul:p="cMul"
+;lC
+cDiv:p="cDiv"
+;lC
+cMod:p="cMod"
+;lC
+cEqual:p="cEqual"
+;lC
+t71:p="cNEqual"
+;lC
+cLess:p="cLess"
+;lC
+cLessOrEq:p="cLessOrEq"
+;lC
+cGreater:p="cGreater"
+;lC
+cGreaterOrEq:p="cGreaterOrEq"
+;lC
+cNot:p="cNot"
+;lC
+cAnd:p="cAnd"
+;lC
+cOr:p="cOr"
+;lC
+cDeg:p="cDeg"
+;lC
+cRad:p="cRad"
+;lC
+cFCall:p="cFCall"
+;lC
+cPCall:p="cPCall"
+;break;
+#ifdef FP_SUPPORT_OPTIMIZER
+case
+cFetch:p="cFetch"
+;lC
+cPopNMov:p="cPopNMov"
+;lC
+cLog2by:p="cLog2by"
+;lC
+cNop:p="cNop"
+;break;
+#endif
+case
+cSinCos:p="cSinCos"
+;lC
+yR3:p="cAbsNot"
+;lC
+cAbsNotNot:p="cAbsNotNot"
+;lC
+cAbsAnd:p="cAbsAnd"
+;lC
+cAbsOr:p="cAbsOr"
+;lC
+i03:p="cAbsIf"
+;lC
+cDup:p="cDup"
+;lC
+cInv:p="cInv"
+;lC
+cSqr:p="cSqr"
+;lC
+cRDiv:p="cRDiv"
+;lC
+cRSub:p="cRSub"
+;lC
+cNotNot:p="cNotNot"
+;lC
+cRSqrt:p="cRSqrt"
+;lC
+iE2:p="VarBegin"
+;nM3
+std::ostringstream
+tmp;assert(p);tmp<<p;if(pad)while(tmp.str()yA3<12)tmp<<' 'l81
+tmp.str();
+#else
+std::ostringstream
+tmp;tmp<<opcode;if(pad)while(tmp.str()yA3<5)tmp<<' 'l81
+tmp.str();
+#endif
+}
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <vector>
+#include <utility>
+#ifndef FP_GENERATING_POWI_TABLE
+enum{MAX_POWI_BYTECODE_LENGTH=20}
+;
+#else
+enum{MAX_POWI_BYTECODE_LENGTH=999}
+;
+#endif
+enum{MAX_MULI_BYTECODE_LENGTH=3}
+;t5{iP2
+ByteCodeSynth{e13
+ByteCodeSynth():nN(),Immed(),eP(),tA(0),StackMax(0){nN.nH3
+64);Immed.nH3
+8);eP.nH3
+16
+iR2
+Pull(yG<i02>&bc,yG
+x8&imm,size_t&StackTop_max){for
+iL1
+a=0;a<nN
+eW2
+a){nN[a]&=~yM;}
+nN.swap(bc);Immed.swap(imm);StackTop_max=StackMax;}
+size_t
+GetByteCodeSize(n61
+nN
+yA3;}
+size_t
+GetStackTop(n61
+tA
+iS2
+PushVar
+iL1
+varno){e23
+varno);nV2}
+void
+PushImmed(eS1
+immed){xQ
+e23
+cImmed);Immed
+yL
+immed);nV2}
+void
+StackTopIs
+cA3,int
+offset=0){if((int)tA>offset){eP[tA
+lN2
+first=true;eP[tA
+lN2
+second=tree;}
+}
+bool
+IsStackTop
+cA3,int
+offset=0
+n61(int)tA>offset&&eP[tA
+lN2
+first&&eP[tA
+lN2
+second
+iA
+tree);i6
+void
+EatNParams
+iL1
+cH2){tA-=cH2
+iS2
+ProducedNParams
+iL1
+e41){xD1
+tA+e41
+iR2
+AddOperation
+iL1
+opcode,i02
+cH2,i02
+e41=1){EatNParams(cH2);xQ
+AddFunctionOpcode(opcode);ProducedNParams(e41
+iR2
+DoPopNMov(size_t
+cI2,size_t
+srcpos){xQ
+e23
+cPopNMov);e23
+yM|iL1)cI2);e23
+yM|iL1)srcpos);xD1
+srcpos+1);eP[cI2]=eP[srcpos];xD1
+cI2+1
+iR2
+DoDup(size_t
+nI3){xQ
+if(nI3==tA-1){e23
+cDup);}
+else{e23
+cFetch);e23
+yM|iL1)nI3);}
+nV2
+eP[tA-1]=eP[nI3];}
+size_t
+e33
+cA3)const{for
+xK2
+tA;a-->0;)if(eP[a
+eC3&&eP[a
+eD3
+iA
+tree)nZ2
+a
+l81
+eK2;}
+bool
+Find
+cA3
+n61
+e33
+nO3
+eK2;}
+bool
+FindAndDup
+cA3){size_t
+pos=e33(tree);if(pos!=eK2){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<tZ3"duplicate at ["
+<<pos<<"]: "
+;xE3(tree)lN1" -- issuing cDup or cFetch\n"
+;
+#endif
+DoDup(pos)nS2
+nX2
+e92
+IfData{size_t
+ofs;}
+;void
+SynthIfStep1(IfData&yJ2,nR2
+op){nT
+yJ2.ofs=nN
+yA3;e23
+op);e23
+yM);e23
+yM
+iR2
+SynthIfStep2(IfData&yJ2){nT
+nN[yJ2.ofs+1]eJ1+2);nN[yJ2.ofs
+iC
+yJ2.ofs=nN
+yA3;e23
+cJump);e23
+yM);e23
+yM
+iR2
+SynthIfStep3(IfData&yJ2){nT
+nN.back()|=yM;nN[yJ2.ofs+1]eJ1-1);nN[yJ2.ofs
+iC
+nV2
+for
+xK2
+0;a<yJ2.ofs;++a){if(nN[a]==cJump&&nN[a+1]==(yM|(yJ2.ofs-1))){nN[a+1]eJ1-1);nN[a
+iC
+yN3(nN[a]iY2
+i03:case
+cIf:case
+cJump:case
+cPopNMov:a+=2;lC
+cFCall:case
+cPCall:case
+cFetch:a+=1;break;default:nM3}
+}
+protected:void
+xD1
+size_t
+value){tA=value;if(tA
+eL2{StackMax=tA;yS1);}
+}
+void
+l51
+eK1;void
+iK
+eK1;void
+AddFunctionOpcode(eK1;private:yG<i02>nN;yG
+x8
+Immed;yG<std::pair<bool,FPoptimizer_CodeTree::yK2> >eP;size_t
+tA;size_t
+StackMax;}
+;yT1
+SequenceOpCode;yT1
+eX1{static
+cN
+AddSequence;static
+cN
+MulSequence;}
+;xB1
+x31
+long
+count,cN&eQ,lP1;}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+t5{yT1
+SequenceOpCode{eS1
+basevalue;i02
+op_flip;i02
+op_normal,op_normal_flip;i02
+op_inverse,op_inverse_flip;}
+;yV1
+cN
+eX1
+x8::AddSequence={eS1(0),cNeg,cAdd,cAdd,cSub,cRSub}
+;yV1
+cN
+eX1
+x8::MulSequence={eS1(1),cInv,cMul,cMul,cDiv,cRDiv}
+;yV1
+n71
+l51
+eK1{int
+mStackPtr=0;
+#define incStackPtr() do{if(tA+2 eL2 yS1=tA+2);}while(0)
+#define findName(a,b,c) "var"
+#define TryCompilePowi(o) false
+#define mData this
+#define mByteCode nN
+#define mImmed Immed
+# define FP_FLOAT_VERSION 1
+# include "fp_opcode_add.inc"
+# undef FP_FLOAT_VERSION
+#undef mImmed
+#undef mByteCode
+#undef mData
+#undef TryCompilePowi
+#undef incStackPtr
+}
+yV1
+n71
+iK
+eK1{int
+mStackPtr=0;
+#define incStackPtr() do{if(tA+2 eL2 yS1=tA+2);}while(0)
+#define findName(a,b,c) "var"
+#define TryCompilePowi(o) false
+#define mData this
+#define mByteCode nN
+#define mImmed Immed
+# define FP_FLOAT_VERSION 0
+# include "fp_opcode_add.inc"
+# undef FP_FLOAT_VERSION
+#undef mImmed
+#undef mByteCode
+#undef mData
+#undef TryCompilePowi
+#undef incStackPtr
+}
+yV1
+n71
+AddFunctionOpcode(eK1{if(IsIntType
+x8::result)iK
+opcode);else
+l51
+opcode);}
+}
+using
+t5;
+#define POWI_TABLE_SIZE 256
+#define POWI_WINDOW_SIZE 3
+t5{
+#ifndef FP_GENERATING_POWI_TABLE
+extern
+const
+i02
+char
+powi_table[POWI_TABLE_SIZE];const
+#endif
+i02
+char
+powi_table[POWI_TABLE_SIZE]={0,1,1,1,2,1
+eM2
+1,4,1,2,e43
+eM2
+1,8,cB3
+e73
+15,1,16,1
+eM2
+e43,2,1,4,cB3
+1,16,1,25,e73
+27,5,8,3,2,1,30,1,31,3,32,1
+eM2
+1,8,1,2,e73
+39,1,16,137,2,1,4,cB3
+e43,45,135,4,31,2,5,32,1,2,131,50,1,51,1,8,3,2,1,54,1,55,3,16,1,57,133,4,137,2,135,60,1,61,3,62,133,63,1,tN1
+131,tN1
+139,iM1
+e9
+30,1,130,137,2,31,iM1
+e9
+e9
+130,cB3
+1,e9
+e9
+2,1,130,133,tN1
+61,130,133,62,139,130,137,e9
+iM1
+e9
+e9
+tN1
+131,e9
+e9
+130,131,2,133,iM1
+130,141,e9
+130,cB3
+1,e9
+5,135,e9
+iM1
+e9
+iM1
+130,133,130,141,130,131,e9
+e9
+2,131}
+;}
+static
+lX3
+cB=256;
+#define FPO(x)
+iO2{class
+PowiCache{private:int
+i7[cB];int
+tO1[cB];e13
+PowiCache():i7(),tO1(){i7[1]=1;}
+bool
+Plan_Add(yW1,int
+count){c51>=cB
+yI
+tO1[eP2+=count
+l81
+i7[eP2!=0
+iS2
+iU2
+yW1){c51<cB)i7[eP2=1
+iS2
+Start(size_t
+value1_pos){for(int
+n=2;n<cB;++n)i7[n]=-1;Remember(1,value1_pos);DumpContents();}
+int
+Find(yW1)const{c51<cB){if(i7[eP2>=0){FPO(tK3(tO3,"* I found %ld from cache (%u,%d)\n",value,(unsigned)cache[value],tL3 value]))l81
+i7[eP2;}
+}
+return-1
+iS2
+Remember(yW1,size_t
+tW3){c51>=cB
+nZ2;FPO(tK3(tO3,"* Remembering that %ld can be found at %u (%d uses remain)\n",value,(unsigned)tW3,tL3 value]));i7[eP2=(int)tW3
+iS2
+DumpContents()const{FPO(for(int a=1;a<POWI_CACHE_SIZE;++a)if(cache[a]>=0||tL3 a]>0){tK3(tO3,"== cache: sp=%d, val=%d, needs=%d\n",cache[a],a,tL3 a]);})}
+int
+UseGetNeeded(yW1){c51>=0&&value<cB
+nZ2--tO1[eP2
+l81
+0;}
+}
+;yV1
+size_t
+yN
+long
+count
+tR1
+cN&eQ,lP1;xB1
+yX1
+size_t
+apos,long
+aval,size_t
+bpos,long
+bval
+tR1
+i02
+cumulation_opcode,i02
+cimulation_opcode_flip,lP1;void
+l61
+yW1
+tR1
+int
+need_count,int
+iX=0){c51<1
+nZ2;
+#ifdef FP_GENERATING_POWI_TABLE
+if(iX>32)throw
+false;
+#endif
+if(i7.Plan_Add(value,need_count)nZ2;long
+nJ3
+1;c51<POWI_TABLE_SIZE){nJ3
+powi_table[eP2
+iT2&128){half&=127
+iT2&64)nJ3-eQ2
+FPO(tK3(tO3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,value/half));l61
+half,yM2
+i7.iU2
+half)l81;}
+tP1
+half&64){nJ3-eQ2}
+}
+else
+c51&1)nJ3
+value&((1<<POWI_WINDOW_SIZE)-1);else
+nJ3
+value/2;long
+cQ=value-half
+iT2>cQ||half<0)std::swap(half,cQ);FPO(tK3(tO3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,otherhalf))iT2==cQ){l61
+half,i7,2,iX+1);}
+else{l61
+half,yM2
+l61
+cQ>0?cQ:-cQ,yM2}
+i7.iU2
+value);}
+yV1
+size_t
+yN
+yW1
+tR1
+cN&eQ,lP1{int
+nK3=i7.Find(value);if(nK3>=0){return
+nK3;}
+long
+nJ3
+1;c51<POWI_TABLE_SIZE){nJ3
+powi_table[eP2
+iT2&128){half&=127
+iT2&64)nJ3-eQ2
+FPO(tK3(tO3,"* I want %ld, my plan is %ld * %ld\n",value,half,value/half));size_t
+x52=yN
+half
+c61
+if(i7
+iN1
+half)>0||x52!=c71){tQ1
+x52)nU2
+half,c71);}
+x31
+value/half
+eR2
+size_t
+tW3=c71
+nU2
+value,tW3);i7.DumpContents()l81
+tW3;}
+tP1
+half&64){nJ3-eQ2}
+}
+else
+c51&1)nJ3
+value&((1<<POWI_WINDOW_SIZE)-1);else
+nJ3
+value/2;long
+cQ=value-half
+iT2>cQ||half<0)std::swap(half,cQ);FPO(tK3(tO3,"* I want %ld, my plan is %ld + %ld\n",value,half,value-half))iT2==cQ){size_t
+x52=yN
+half
+c61
+yX1
+x52,half,x52,half,i7,eQ.op_normal,eQ.op_normal_flip,synth);}
+else{long
+part1=half;long
+part2=cQ>0?cQ:-cQ;size_t
+part1_pos=yN
+part1
+c61
+size_t
+part2_pos=yN
+part2
+c61
+FPO(tK3(tO3,"Subdivide(%ld: %ld, %ld)\n",value,half,otherhalf));yX1
+part1_pos,part1,part2_pos,part2,i7,cQ>0?eQ.op_normal:eQ.op_inverse,cQ>0?eQ.op_normal_flip:eQ.op_inverse_flip,synth);}
+size_t
+tW3=c71
+nU2
+value,tW3);i7.DumpContents()l81
+tW3;}
+xB1
+yX1
+size_t
+apos,long
+aval,size_t
+bpos,long
+bval
+tR1
+i02
+cumulation_opcode,i02
+cumulation_opcode_flip,lP1{int
+a_needed=i7
+iN1
+aval);int
+nL3=i7
+iN1
+bval);bool
+iO1
+i13
+#define DUP_BOTH() do tX3<bpos){size_t tmp=apos;apos=bpos;bpos=tmp;iO1=!iO1;}FPO(tK3(tO3,"-> "tV3 tV3"op\n",(unsigned)apos,(unsigned)bpos));tQ1 apos);tQ1 apos==bpos?c71:bpos);}while(0)
+#define DUP_ONE(p) do{FPO(tK3(tO3,"-> "tV3"op\n",(unsigned)p));tQ1 p);}while(0)
+if(a_needed>0){if(nL3>0){lO2}
+else{if(bpos!=c71)lO2
+else{iP1
+iO1=!iO1;}
+}
+}
+tP1
+nL3>0)tX3!=c71)lO2
+else
+DUP_ONE(bpos);}
+else
+tX3==bpos&&apos==c71)iP1
+tP1
+apos==c71&&bpos==synth.x5
+2){FPO(tK3(tO3,"-> op\n"));iO1=!iO1;}
+tP1
+apos==synth.x5
+2&&bpos==c71)FPO(tK3(tO3,"-> op\n"));tP1
+apos==c71)DUP_ONE(bpos);tP1
+bpos==c71){iP1
+iO1=!iO1;}
+else
+lO2}
+lK1
+iO1?cumulation_opcode_flip:cumulation_opcode,2);}
+xB1
+cA1
+long
+count,cN&eQ,lP1{while
+cR3<256){int
+nJ3
+yV2
+powi_table[count]iT2&128){half&=127;cA1
+half
+eR2
+count/=half;}
+else
+nM3
+if
+cR3==1
+nZ2;if(!cR3&1)){lK1
+cSqr,1);cA1
+count/2
+eR2}
+else{tQ1
+c71);cA1
+count-1
+eR2
+lK1
+cMul,2);}
+}
+}
+t5{xB1
+x31
+long
+count,cN&eQ,lP1{if
+cR3==0)yX2
+eQ.basevalue
+t73
+bool
+eT2
+i13
+if
+cR3<0){eT2=true;count=-count;}
+if(false)cA1
+count
+eR2
+tP1
+count>1){PowiCache
+i7;l61
+count,i7,1);size_t
+xE1
+t13
+GetStackTop();i7.Start(c71);FPO(tK3(tO3,"Calculating result for %ld...\n",count));size_t
+x62=yN
+count
+c61
+size_t
+n_excess
+t13
+x5
+xE1;if(n_excess>0||x62!=xE1-1){synth.DoPopNMov(xE1-1,x62);}
+}
+if(eT2)lK1
+eQ.op_flip,1);}
+}
+}
+#endif
+#ifndef FPOptimizer_RangeEstimationHH
+#define FPOptimizer_RangeEstimationHH
+iO2
+FPoptimizer_CodeTree{enum
+TriTruthValue{IsAlways,yO3,Unknown}
+;yT1
+range{eS1
+min,max;bool
+iV2,has_max;range():min(),max(),iV2(false
+cS3
+false)x43
+eS1
+mi,eS1
+ma):min(mi),max(ma),iV2(true
+cS3
+true)x43
+bool,eS1
+ma):min(),max(ma),iV2(false
+cS3
+true)x43
+eS1
+mi,bool):min(mi),max(),iV2(true
+cS3
+false){}
+void
+set_abs();void
+set_neg();x72
+set_min_max_if(iL
+x72
+set_min_if(iL
+x72
+set_max_if(iL
+void
+set_min(eS1(lN
+void
+set_max(eS1(lN
+void
+y82
+eS1(lN}
+;yV1
+inline
+bool
+IsLogicalTrueValue
+i01
+range
+x8&p
+cD2
+if(p
+y41
+p.min>=0.5
+nZ2
+true;if(!abs&&p
+iW2<=-0.5
+nZ2
+true
+l81
+false;}
+yV1
+inline
+bool
+IsLogicalFalseValue
+i01
+range
+x8&p
+cD2
+if(abs
+nZ2
+p
+iW2<0.5;else
+return
+p
+y41
+p
+i0&&p.min>-0.5
+xQ3<0.5;}
+yV1
+range
+x8
+iM
+const
+eR;xG1
+IsLogicalValue
+i01
+eR;yV1
+TriTruthValue
+GetIntegerInfo
+i01
+eR;y51
+GetEvennessInfo
+i01
+eR{if(!tree
+y21
+nZ2
+Unknown;yF1=yZ3;if(isEvenInteger(value)nZ2
+x82
+isOddInteger(value)nZ2
+l71
+y51
+GetPositivityInfo
+i01
+eR{range
+x8
+p=iM
+tree);if(p
+y41
+p.min
+cH1
+nZ2
+x82
+p
+iW2
+t83
+nZ2
+l71
+y51
+GetLogicalValue(lM1&tree
+cD2
+range
+x8
+p=iM
+tree);if(IsLogicalTrueValue(p,abs)nZ2
+x82
+IsLogicalFalseValue(p,abs)nZ2
+l71}
+#endif
+#ifndef FPOptimizer_ConstantFoldingHH
+#define FPOptimizer_ConstantFoldingHH
+iO2
+FPoptimizer_CodeTree{xB1
+ConstantFolding(eR;}
+#endif
+iO2{xQ
+using
+iO2
+FPoptimizer_CodeTree;e92
+ComparisonSetBase{enum{e93=0x1,Eq_Mask=0x2,Le_Mask=0x3,eA3=0x4,eB3=0x5,Ge_Mask=0x6}
+;static
+int
+Swap_Mask(int
+m){return(m&Eq_Mask)|((m&e93)?eA3:0)|((m&eA3)?e93:0);}
+enum
+yY1{Ok,BecomeZero,BecomeOne,xA2
+n23
+lV2{cond_or,i32,i42,i52}
+;}
+;yT1
+ComparisonSet:public
+ComparisonSetBase{e92
+eU2
+nG1
+a
+yJ
+b;int
+relationship;eU2():a(),b(),relationship(){}
+}
+;yG<eU2>cW;e92
+Item
+nG1
+value;bool
+yN2;Item():value(),yN2(false){}
+}
+;yG<Item>cB1;int
+xF1;ComparisonSet():cW(),cB1(),xF1(0){}
+yY1
+AddItem(lM1&a,bool
+yN2,lV2
+type){for(size_t
+c=0;c<cB1
+eW2
+c)if(cB1[c].value
+iA
+a)){if(yN2!=cB1[c].yN2){iN
+cM1
+case
+i52:cB1.erase(cB1.begin()+c);xF1+=1
+n01
+case
+i32:case
+i42:cN1}
+}
+return
+xA2;}
+Item
+pole;pole.value=a;pole.yN2=yN2;cB1
+yL
+pole)l81
+Ok;}
+yY1
+AddRelationship(yK2
+a,yK2
+b,int
+eY1,lV2
+type){iN
+cT3
+7)cM1
+lC
+i52:cT3
+7){xF1+=1
+n01}
+lC
+i32:case
+i42:cT3
+0)cN1
+nM3
+if(!(a.GetHash()<b.GetHash())){a.swap(b);eY1=Swap_Mask(eY1);}
+for(size_t
+c=0;c<cW
+eW2
+c){if(cW[c].a
+iA
+a)&&cW[c].b
+iA
+b)){iN{int
+nS3=x92|eY1;if(nS3==7)cM1
+x92=nS3;nM3
+case
+i32:case
+i42:{int
+nS3=x92&eY1;if(nS3==0)cN1
+x92=nS3;nM3
+case
+i52:{int
+newrel_or=x92|eY1;int
+xB2=x92&eY1;iQ1
+5&&xB2==0){x92=eB3
+n01}
+iQ1
+7&&xB2==0){xF1+=1;cW.erase(cW.begin()+c)n01}
+iQ1
+7&&xB2==Eq_Mask){x92=Eq_Mask;xF1+=1
+n01}
+y81}
+}
+return
+xA2;}
+}
+eU2
+comp;comp.a=a;comp.b=b;comp.relationship=eY1;cW
+yL
+comp)l81
+Ok;}
+}
+;nT1
+eS1,typename
+CondType>bool
+ConstantFolding_LogicCommon(yK2&tree,CondType
+xA1,bool
+xC2){bool
+should_regenerate
+i13
+ComparisonSet
+x8
+comp
+eV3
+typename
+yB
+yY1
+cC3=yB
+Ok;lM1&atree=xI2;switch(atree
+nE
+iY2
+cEqual
+lG
+Eq_Mask
+eB2
+t71
+lG
+eB3
+eB2
+cLess
+lG
+e93
+eB2
+cLessOrEq
+lG
+Le_Mask
+eB2
+cGreater
+lG
+eA3
+eB2
+cGreaterOrEq
+lG
+Ge_Mask
+eB2
+cNot:cC3
+y11
+lD
+0),true
+eB2
+cNotNot:cC3
+y11
+lD
+0),false,xA1);break;default:if(xC2||IsLogicalValue(atree))cC3
+y11,false,xA1);yN3(cC3){ReplaceTreeWithZero
+xP3
+ReplaceWithImmed(0)l81
+true;ReplaceTreeWithOne
+xP3
+ReplaceWithImmed(1);nW
+yB
+Ok:lC
+yB
+BecomeZero:yP3
+yB
+BecomeOne
+tY
+yB
+xA2:c11
+nM3}
+if(should_regenerate){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantFolding_LogicCommon: "
+eS
+#endif
+if(xC2){tree.DelParams();}
+else{for
+xU{lM1&atree=xI2;if(IsLogicalValue(atree))nF1);}
+}
+for
+xK2
+0;a<comp.cB1
+eW2
+a){if(comp.cB1[a].yN2)eV2
+cNot);r
+i4
+r.cO1
+tP1!xC2)eV2
+cNotNot);r
+i4
+r.cO1
+else
+tree
+i4}
+for
+xK2
+0;a<comp.cW
+eW2
+a)eV2
+cNop);switch(comp.cW[a
+tO
+iY2
+yB
+e93:r
+tU
+cLess);lC
+yB
+Eq_Mask:r
+tU
+cEqual);lC
+yB
+eA3:r
+tU
+cGreater);lC
+yB
+Le_Mask:r
+tU
+cLessOrEq);lC
+yB
+eB3:r
+tU
+t71);lC
+yB
+Ge_Mask:r
+tU
+cGreaterOrEq
+nW2
+r
+yA
+comp.cW[a].a);r
+yA
+comp.cW[a].b);r.cO1
+if(comp.xF1!=0)tree
+yT
+eS1(comp.xF1)));
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantFolding_LogicCommon: "
+eS
+#endif
+return
+true;}
+nX2
+xG1
+ConstantFolding_AndLogic(tT3(tree.tU3()==cAnd
+tI3()==cAbsAnd)l81
+nJ
+i32,true);}
+xG1
+ConstantFolding_OrLogic(tT3(tree.tU3()==cOr
+tI3()==cAbsOr)l81
+nJ
+cond_or,true);}
+xG1
+ConstantFolding_AddLogicItems(tT3(tree.tU3()==cAdd)l81
+nJ
+i52,false);}
+xG1
+ConstantFolding_MulLogicItems(tT3(tree.tU3()==cMul)l81
+nJ
+i42,false);}
+}
+#include <vector>
+#include <map>
+#include <algorithm>
+iO2{xQ
+using
+iO2
+FPoptimizer_CodeTree;e92
+CollectionSetBase{enum
+xH1{Ok,xA2}
+;}
+;yT1
+CollectionSet:public
+CollectionSetBase{e92
+yZ1
+nG1
+value
+yJ
+xD2;bool
+e2;yZ1():value(),xD2(),e2(false){}
+yZ1(lM1&v,lM1&f):value(v),xD2(f),e2(false){}
+}
+;std::multimap<fphash_t,yZ1>i8;typedef
+typename
+std::multimap<fphash_t,yZ1>::nX3
+xI1;CollectionSet():i8(){}
+xI1
+FindIdenticalValueTo(lM1&value){fphash_t
+hash=value.GetHash();for(xI1
+i=i8.xE2
+hash);i!=i8.cP1
+hash;++i){c51
+iA
+i
+cJ2.value)nZ2
+i;}
+return
+i8.end();}
+bool
+Found
+i01
+xI1&b){return
+b!=i8.end();}
+xH1
+AddCollectionTo(lM1&xD2,const
+xI1&into_which){yZ1&c=into_which
+cJ2;if(c.e2)c.xD2
+eT
+xD2);else
+nG1
+add;add
+tU
+cAdd);add
+yA
+c.xD2);add
+eT
+xD2);c.xD2.swap(add);c.e2=true;}
+return
+xA2;}
+xH1
+iR1
+lM1&value,lM1&xD2){const
+fphash_t
+hash=value.GetHash();xI1
+i=i8.xE2
+hash);for(;i!=i8.cP1
+hash;++i){if(i
+cJ2.value
+iA
+value)nZ2
+AddCollectionTo(xD2,i);}
+i8.nT3,std::make_pair(hash,yZ1(value,xD2)))l81
+Ok;}
+xH1
+iR1
+lM1&a){return
+iR1
+a,nB1
+1)));}
+}
+;yT1
+ConstantExponentCollection{typedef
+yG
+nV1
+nV3;typedef
+std::x51
+xF2;yG<xF2>data;ConstantExponentCollection():data(){}
+void
+MoveToSet_Unique
+i01
+eS1&e51&e61){data
+yL
+std::x51(e51()));data.back()eE3.swap(e61
+iR2
+MoveToSet_NonUnique
+i01
+eS1&e51&e61){typename
+yG<xF2>::nX3
+i=std::xE2
+data.i62
+data.end(),cE2,Compare1st());if(i!=data.cP1
+cE2){i
+cJ2.nT3
+cJ2.end(),e61.i62
+e61.end());}
+else{data.nT3,std::x51(cE2,e61));}
+}
+bool
+Optimize(){bool
+changed
+i13
+std::sort(data.i62
+data.end(),Compare1st());redo:for
+xK2
+0;a<data
+eW2
+a){eS1
+exp_a=data[a
+eC3
+i82
+exp_a,nY3
+y81
+for(iX2
+a+1;b<data
+eW2
+b){eS1
+exp_b=data[b
+eC3;eS1
+xG2=exp_b-exp_a;if(xG2>=fp_abs(exp_a
+n33
+exp_diff_still_probable_integer=xG2*eS1(16);if(eY2
+exp_diff_still_probable_integer)&&!(eY2
+exp_b)&&!eY2
+xG2))){nV3&a_set=iS1;nV3&b_set=data[b
+eD3;
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantExponentCollection iteration:\n"
+;eZ2
+cout);
+#endif
+if(isEvenInteger(exp_b)&&!isEvenInteger(xG2+exp_a))nG1
+tmp2;tmp2
+e53
+tmp2
+tI1
+b_set);tmp2
+i72
+tmp;tmp
+tU
+cAbs);tmp
+yY3;tmp
+x02;b_set
+nE3
+1);b_set[0
+t23
+tmp);}
+a_set.insert(a_set.end(),b_set.i62
+b_set.end());nV3
+b_copy=b_set;data.erase(data.begin()+b);MoveToSet_NonUnique(xG2,b_copy);yI1
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantExponentCollection iteration:\n"
+;eZ2
+cout);
+#endif
+e5}
+}
+}
+return
+changed;}
+#ifdef DEBUG_SUBSTITUTIONS
+void
+eZ2
+ostream&out){for
+xK2
+0;a<data
+eW2
+a){out.precision(12);out<<data[a
+eC3<<": "
+;eW3
+iS1
+eW2
+b){if(b>0)out<<'*';xE3(iS1[b],out);}
+out<<std::endl;}
+}
+#endif
+}
+;yV1
+static
+yK2
+x61
+yK2&value,bool&xG){switch(value
+nE
+iY2
+cPow:nG1
+cE2=value
+lD
+1);value.y71
+l81
+cE2
+cM3
+cRSqrt:value.y71;xG=true
+l81
+nB1-0.5));case
+cInv:value.y71;xG=true
+l81
+nB1-1));default:nM3
+return
+nB1
+1))eI2
+void
+e71
+e81&mul,lM1&tree,lM1&xD2,bool&c01
+bool&xG){for
+yS
+nG1
+value
+nW1
+a))yJ
+cE2(x61
+value,xG));if(!xD2
+y21||xD2.xJ1!=1.0)nG1
+cQ1;cQ1
+e53
+cQ1
+eT
+cE2);cQ1
+eT
+xD2);cQ1
+x02;cE2.swap(cQ1);}
+#if 0 /* FIXME: This does not work */
+c51
+nE==cMul){if(1){bool
+exponent_is_even=cE2
+y21&&isEvenInteger(cE2.xJ1);eW3
+value.c81{bool
+tmp=false
+yJ
+val(value
+lD
+b))yJ
+exp(x61
+val,tmp));if(exponent_is_even||(exp
+y21&&isEvenInteger(exp.xJ1)))nG1
+cQ1;cQ1
+e53
+cQ1
+eT
+cE2);cQ1
+yA
+exp);cQ1.ConstantFolding();if(!cQ1
+y21||!isEvenInteger(cQ1.xJ1)){goto
+cannot_adopt_mul;}
+}
+}
+}
+e71
+mul,value,cE2,c01
+xG);}
+else
+cannot_adopt_mul:
+#endif
+{if(mul.iR1
+value,cE2)==CollectionSetBase::xA2)c11}
+}
+}
+xG1
+ConstantFolding_MulGrouping(eR{bool
+xG
+i13
+bool
+should_regenerate
+i13
+e81
+mul;e71
+mul,tree,nB1
+1)),c01
+xG);typedef
+std::pair<yK2,yG
+nV1>e91;typedef
+std::multimap<fphash_t,e91>cC1;cC1
+i9;xH2
+e81::xI1
+j=mul.i8.nW3
+j!=mul.i8.end();++j)nG1&value=j
+cJ2.value
+yJ&cE2=j
+cJ2.xD2;if(j
+cJ2.e2)cE2
+x02;const
+fphash_t
+eA1=cE2.GetHash();typename
+cC1::nX3
+i=i9.xE2
+eA1);for(;i!=i9.cP1
+eA1;++i)if(i
+cJ2.first
+iA
+cE2)){if(!cE2
+y21||!cR1.xJ1,nY3
+c11
+i
+cJ2
+eE3
+yL
+value);goto
+skip_b;}
+i9.nT3,std::make_pair(eA1,std::make_pair(cE2,yG
+nV1(size_t(1),value))));skip_b:;}
+#ifdef FP_MUL_COMBINE_EXPONENTS
+ConstantExponentCollection
+x8
+cS1;xH2
+cC1::nX3
+j,i=i9.nW3
+i!=i9.end();i=j){j=i;++j;e91&list=i
+cJ2;if
+eD2
+y21)c21
+list.first.xJ1;if(!(cE2==eS1(0)))cS1.MoveToSet_Unique(cE2,list
+eE3);i9.erase(i);}
+}
+if(cS1.Optimize())c11
+#endif
+if(should_regenerate)nG1
+before=tree;before.iY
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantFolding_MulGrouping: "
+;xE3(before)lN1"\n"
+;
+#endif
+tree.DelParams();xH2
+cC1::nX3
+i=i9.nW3
+i!=i9.end();++i){e91&list=i
+cJ2;
+#ifndef FP_MUL_COMBINE_EXPONENTS
+if
+eD2
+y21)c21
+list.first.xJ1;if(cE2==eS1(0))y81
+if(cR1,nY3{tree.AddParamsMove(list
+eE3);y81}
+}
+#endif
+yK2
+mul;mul
+e53
+mul
+tI1
+list
+eE3);mul
+x02;if(xG&&list.first
+tF3
+eD2.xJ1==eS1(1)/eS1(3))nG1
+cbrt;cbrt
+tU
+cCbrt);cbrt
+t02;cbrt.yB3
+cbrt);y81
+cR
+0.5))nG1
+sqrt;sqrt
+tU
+cSqrt);sqrt
+t02;sqrt.yB3
+sqrt);y81
+cR-0.5))nG1
+rsqrt;rsqrt
+tU
+cRSqrt);rsqrt
+t02;rsqrt.yB3
+rsqrt);y81
+cR-1))nG1
+inv;inv
+tU
+cInv);inv
+t02;inv.yB3
+inv);y81}
+}
+yK2
+pow
+yB2
+t02;pow
+yA
+list.first);pow.yB3
+pow);}
+#ifdef FP_MUL_COMBINE_EXPONENTS
+i9.clear()c23
+0;a<i2
+eW2
+a)c21
+i2[a
+eC3;if(cR1,nY3{tree.AddParamsMove(i2[a
+eD3);y81}
+yK2
+mul;mul
+e53
+mul
+tI1
+i2[a
+eD3);mul
+i72
+pow
+yB2
+t02;pow
+yT
+cE2));pow.yB3
+pow);}
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantFolding_MulGrouping: "
+eS
+#endif
+return!tree
+iA
+before);}
+nX2
+xG1
+ConstantFolding_AddGrouping(eR{bool
+should_regenerate
+i13
+e81
+add
+eV3
+if
+nW1
+a)nE==cMul)y81
+if(add.AddCollection
+nW1
+a))==CollectionSetBase::xA2)c11}
+yG<bool>remaining(iT);size_t
+tB=0
+eV3
+lM1&n83=xI2;if(n83
+nE==cMul){eW3
+xX1
+c81{if(n83
+lD
+b)y21)y81
+typename
+e81::xI1
+c=add.FindIdenticalValueTo(n83
+lD
+b));if(add.Found(c))nG1
+tmp(n83
+yO
+CloneTag());tmp.iH1
+b);tmp
+x02;add.AddCollectionTo(tmp,c);c11
+goto
+done_a;}
+}
+remaining[a]=true;tB+=1;done_a:;}
+}
+if(tB>0){if(tB>1){yG<std::pair<yK2,size_t> >nV;std::multimap<fphash_t,size_t>eB1;bool
+l13
+i13
+t12{eW3
+xI2.c81{lM1&p=xI2
+lD
+b);const
+fphash_t
+p_hash=p.GetHash();for(std::multimap<fphash_t,size_t>::const_iterator
+i=eB1.xE2
+p_hash);i!=eB1.cP1
+p_hash;++i){if(nV[i
+cJ2
+eC3
+iA
+p)){nV[i
+cJ2
+eD3+=1;l13=true;goto
+found_mulgroup_item_dup;}
+}
+nV
+yL
+std::make_pair(p,size_t(1)));eB1.insert(std::make_pair(p_hash,nV
+yA3-1));found_mulgroup_item_dup:;}
+}
+if(l13)nG1
+cK2;{size_t
+max=0;for(size_t
+p=0;p<nV
+eW2
+p)if(nV[p
+eD3<=1)nV[p
+eD3=0;else{nV[p
+eD3*=nV[p
+eC3.xT2;if(nV[p
+eD3>max){cK2=nV[p
+eC3;max=nV[p
+eD3;}
+}
+}
+yK2
+group_add;group_add
+tU
+cAdd);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Duplicate across some trees: "
+;xE3(cK2)lN1" in "
+eS
+#endif
+t12
+eW3
+xI2.c81
+if(cK2
+iA
+xI2
+lD
+b)))nG1
+tmp
+nW1
+a)yO
+CloneTag());tmp.iH1
+b);tmp
+x02;group_add
+yA
+tmp);remaining[a]i13
+nM3
+group_add
+i72
+group;group
+e53
+group
+yA
+cK2);group
+yA
+group_add);group
+x02;add.iR1
+group);c11}
+}
+t12{if(add.AddCollection
+nW1
+a))==CollectionSetBase::xA2)c11}
+}
+if(should_regenerate){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantFolding_AddGrouping: "
+eS
+#endif
+tree.DelParams();xH2
+e81::xI1
+j=add.i8.nW3
+j!=add.i8.end();++j)nG1&value=j
+cJ2.value
+yJ&coeff=j
+cJ2.xD2;if(j
+cJ2.e2)coeff
+x02;if(coeff
+tF3(fp_equal(coeff.xJ1,eS1(0)))y81
+if(fp_equal(coeff.xJ1,nY3{tree
+yA
+value);y81}
+}
+yK2
+mul;mul
+e53
+mul
+yA
+value);mul
+yA
+coeff);mul.Rehash(tT
+t02;}
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantFolding_AddGrouping: "
+eS
+#endif
+return
+true;}
+nX2}
+iO2{xQ
+using
+iO2
+FPoptimizer_CodeTree;xG1
+ConstantFolding_IfOperations(tT3(tree.tU3()==cIf
+tI3()==i03);for(;;){l23
+nE==cNot){tH
+cIf
+tT
+lD
+0).xO2
+0)lD
+0)tT
+lD
+1).swap
+nW1
+2));}
+else
+l23
+cG1{tH
+i03
+tT
+lD
+0).xO2
+0)lD
+0)tT
+lD
+1).swap
+nW1
+2));}
+else
+t62
+tX
+0),cV2
+i03))tF1
+tree.xO2
+1));nW
+yO3
+xP3
+xO2
+2));nW
+lX1
+l23
+nE==cIf||e72
+nE==i03)nG1
+cond
+cL2
+0)yJ
+l53;l53
+xP2==cIf?cNotNot:cAbsNotNot);l53
+x63
+x03;ConstantFolding(l53)yJ
+truth_b;truth_b
+xP2==cIf?cNotNot:cAbsNotNot);truth_b
+x63
+x73
+ConstantFolding(truth_b);if(l53
+y21||truth_b
+y21)nG1
+eU;eU
+xP2);eU
+x63
+x03;eU
+yC
+1));eU
+yC
+2));eU
+i72
+eV;eV
+xP2);eV
+x63
+x73
+eV
+yC
+1));eV
+yC
+2));eV
+y3
+cond
+nE
+xK1
+0,cond
+lD
+0)tT.nC1
+1,eU
+tT.nC1
+2,eV)nS2}
+if
+nW1
+1)nE==tree
+lD
+2)nE&&nW1
+1)nE==cIf||tree
+lD
+1)nE==i03))nG1&cM2
+cL2
+1)yJ&leaf2
+cL2
+2);if
+x83
+0).xO
+0))&&x83
+1).xO
+1))||cM2
+lD
+2).xO
+2))))nG1
+eU;eU
+xQ2
+eU
+yC
+0));eU
+eT
+cM2
+x03;eU
+eT
+leaf2
+x03;eU
+i72
+eV;eV
+xQ2
+eV
+yC
+0));eV
+eT
+cM2
+x73
+eV
+eT
+leaf2
+x73
+eV
+y3
+cM2
+nE
+xK1
+0
+eF3
+0)tT.nC1
+1,eU
+tT.nC1
+2,eV)nS2
+if
+x83
+1).xO
+1))&&cM2
+lD
+2).xO
+2)))nG1
+eW;eW
+xQ2
+eW
+yA
+e72);eW
+eT
+cM2
+xY3
+eW
+eT
+leaf2
+xY3
+eW
+y3
+cM2
+nE
+tT.nC1
+0,eW
+xK1
+2
+eF3
+2)xK1
+1,cM2
+x03
+nS2
+if
+x83
+1).xO
+2))&&cM2
+lD
+2).xO
+1)))nG1
+cN2;cN2
+tU
+leaf2
+nE==cIf?cNot:yR3);cN2
+eT
+leaf2
+xY3
+cN2
+i72
+eW;eW
+xQ2
+eW
+yA
+e72);eW
+eT
+cM2
+xY3
+eW
+yA
+cN2);eW
+y3
+cM2
+nE
+tT.nC1
+0,eW
+xK1
+2
+eF3
+2)xK1
+1,cM2
+x03
+nS2}
+yK2&xW
+cL2
+1)yJ&y9
+cL2
+2);if(xW
+iA
+y9)){tree.xO2
+1))nS2
+const
+OPCODE
+op1=xW
+nE;const
+OPCODE
+op2=y9
+nE;if(op1==op2){if(xW.cT1
+1)nG1
+lO
+0))xL2
+0
+y31)lY
+if(xW.cT1
+2&&y9.cT1
+2){if(xW
+lD
+0)iA
+y9
+lD
+0)))nG1
+param0=xW
+lD
+0)yJ
+lO
+1))xL2
+1
+y31
+tT
+yA
+param0)lY
+if(xW
+lD
+1)iA
+y9
+x03)nG1
+param1=xW
+lD
+1)yJ
+lO
+0))xL2
+0
+y31
+tT
+yA
+n41
+tT
+yA
+param1)nS2}
+if(op1==x93
+cMul
+iU1
+cAnd
+iU1
+cOr
+iU1
+cAbsAnd
+iU1
+cAbsOr
+iU1
+cMin
+iU1
+cMax){yG
+nV1
+l63;cC{for(iX2
+y9.cN3
+b-->0;){lW2
+y9
+lD
+b))){if(l63
+cQ3){xW.iY
+y9.iY}
+l63
+yL
+xW
+lD
+a));y9.iH1
+b);xW.iH1
+a
+nW2}
+}
+if(!l63
+cQ3){xW
+x02;y9
+i72
+n41;n41
+xQ2
+n41
+tI1
+tree.iE1));n41
+y3
+op1
+tT
+tI1
+l63)lY}
+}
+if(op1==x93
+cMul||(op1==cAnd
+nY1
+y9))||(op1==cOr
+nY1
+y9))){cC
+lW2
+y9)){xW.iY
+xW
+cP3
+xW
+i72
+cD1=y9;y9=tC
+op1==x93
+cOr)l9
+op1
+tT
+yA
+cD1)lY}
+if((op1==cAnd
+iU1
+cOr)&&op2==cNotNot)nG1&l73=y9
+lD
+0);cC
+lW2
+l73)){xW.iY
+xW
+cP3
+xW
+i72
+cD1=l73;y9=tC
+op1
+xA3
+op1
+tT
+yA
+cD1)lY}
+if(op2==cAdd||op2==cMul||(op2==cAnd
+nY1
+xW))||(op2==cOr
+nY1
+xW))){for
+xK2
+y9.tD
+y9
+lD
+a)iA
+xW)){y9.iY
+y9
+cP3
+y9
+i72
+cE1=xW;xW=tC
+op2==cAdd||op2
+xA3
+op2
+tT
+yA
+cE1)lY}
+if((op2==cAnd||op2==cOr)&&op1==cNotNot)nG1&l83=xW
+lD
+0)c23
+y9.tD
+y9
+lD
+a)iA
+l83)){y9.iY
+y9
+cP3
+y9
+i72
+cE1=l83;xW=tC
+op2
+xA3
+op2
+tT
+yA
+cE1)lY}
+nX2}
+#include <limits>
+iO2{xQ
+using
+iO2
+FPoptimizer_CodeTree;yV1
+int
+maxFPExponent(){return
+std::numeric_limits
+x8::max_exponent;}
+xG1
+x71
+eS1
+xB3
+cE2){if(base<eS1(0
+iF1
+i82
+xB3(0))||fp_equal(xB3(1))yI
+return
+cE2>=eS1(maxFPExponent
+x8())/fp_log2(base);}
+xG1
+ConstantFolding_PowOperations(tT3(tree.tU3()==cPow);y2){eS1
+const_value=eG3
+n6,y4
+tT.ReplaceWithImmed(const_value)l81
+false;}
+if(nE1
+fp_equal(y4,nY3{tree.xO2
+0))nS2
+lX&&fp_equal(n6,nY3
+lL
+1)l81
+false;}
+lX&&tree
+lD
+1)nE==cMul){bool
+xR2
+i13
+eS1
+iV1=n6
+yJ
+n83
+cL2
+1)c23
+xX1
+tD
+n83
+lD
+a)xC3
+imm=n83
+lD
+a).xJ1;{if(x71
+iV1,imm
+n33
+iW1=eG3
+iV1,imm)i82
+iW1,eS1(0)))break;if(!xR2){xR2=true;xX1
+iY}
+iV1=iW1;xX1
+iH1
+a
+nW2}
+if(xR2){xX1
+Rehash();
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before pow-mul change: "
+eS
+#endif
+e72.Become(cU1
+iV1)tT
+lD
+1).Become(n83);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After pow-mul change: "
+eS
+#endif
+}
+}
+if(nE1
+e72
+nE==cMul){eS1
+iX1=y4;eS1
+xS2=1.0;bool
+xR2=false
+yJ&n83
+cL2
+0)c23
+xX1
+tD
+n83
+lD
+a)xC3
+imm=n83
+lD
+a).xJ1;{if(x71
+imm,iX1
+n33
+eD1=eG3
+imm,iX1)i82
+eD1,eS1(0)))break;if(!xR2){xR2=true;xX1
+iY}
+xS2*=eD1;xX1
+iH1
+a
+nW2}
+if(xR2){xX1
+Rehash()yJ
+cD3;cD3
+tU
+cPow);cD3
+tI1
+tree.iE1));cD3.y12);tH
+cMul
+tT
+yA
+cD3
+tT
+eT
+cU1
+xS2))nS2}
+l23
+nE==cPow&&nE1
+e72
+lD
+1)xC3
+a
+cL2
+0)lD
+1).xJ1;eS1
+b=y4;eS1
+c=a*b;if(isEvenInteger(a)&&!isEvenInteger(c))nG1
+l93;l93
+tU
+cAbs);l93
+yC
+0)xY3
+l93.Rehash(tT.nC1
+0,l93);}
+else
+tree.SetParam(0,e72
+lD
+0)xK1
+1,cU1
+c));}
+nX2}
+iO2{xQ
+using
+iO2
+FPoptimizer_CodeTree;e92
+l4{enum
+cO2{MakeFalse=0,MakeTrue=1,t22=2,lC3=3,MakeNotNotP0=4,MakeNotNotP1=5,MakeNotP0=6,MakeNotP1=7,Unchanged=8
+n23
+iY1{Never=0,Eq0=1,Eq1=2,xD3=3,xR3=4}
+;cO2
+if_identical;cO2
+iZ1
+4];e92{cO2
+what:4;iY1
+when:4;}
+tS1,tT1,tU1,tV1;yV1
+cO2
+Analyze(lM1&a,lM1&b)const{if(a
+iA
+b)nZ2
+if_identical;range
+x8
+p0=iM
+a);range
+x8
+p1=iM
+b);if(p0
+i0&&p1.iV2){if(p0.max<p1.min&&iZ1
+0]cJ
+0];if(p0.max<=p1.min&&iZ1
+1]cJ
+1];}
+if(p0
+y41
+p1
+i0){if(p0.min>p1.max&&iZ1
+2]cJ
+2];if(p0.min>=p1.max&&iZ1
+3]cJ
+3];}
+if(IsLogicalValue(a)){if(tS1
+i92
+tS1.when,p1)nZ2
+tS1.what;if(tU1
+i92
+tU1.when,p1)nZ2
+tU1.what;}
+if(IsLogicalValue(b)){if(tT1
+i92
+tT1.when,p0)nZ2
+tT1.what;if(tV1
+i92
+tV1.when,p0)nZ2
+tV1.what;}
+return
+Unchanged
+eI2
+bool
+TestCase(iY1
+when,const
+range
+x8&p){if(!p.iV2||!p
+i0
+yI
+switch(when
+iY2
+Eq0:return
+p.min==0.0
+xQ3==p.min;case
+Eq1:return
+p.min==1.0
+xQ3==p.max;case
+xD3:return
+p.min>0
+xQ3<=1;case
+xR3:return
+p.min>=0
+xQ3<1;default:;}
+nX2}
+;iO2
+RangeComparisonsData{static
+const
+l4
+Data[6]={{l4
+lA3
+tP
+Unchanged,l4::tP
+Unchanged
+tE
+Eq1
+tF
+Eq1
+nD1
+Eq0}
+,l91
+Eq0}
+}
+,{l4::lX2
+lB3
+Unchanged,l4
+lB3
+Unchanged
+tE
+Eq0
+tF
+Eq0
+nD1
+Eq1}
+,l91
+Eq1}
+}
+,{l4::lX2
+lB3
+t22,l4::tP
+MakeFalse
+nD1
+xD3
+tF
+xR3
+xD,{l4
+lA3
+Unchanged,l4
+lB3
+tP
+lC3
+nD1
+xR3
+tF
+xD3
+xD,{l4::lX2::tP
+tP
+MakeTrue,l4::t22
+tE
+xR3}
+,l91
+xD3
+xD,{l4
+lA3
+tP
+lC3,l4::Unchanged,l4
+nH1
+tE
+xD3}
+,l91
+xR3
+xD}
+;}
+xG1
+ConstantFolding_Comparison(eR{using
+iO2
+RangeComparisonsData;assert(tree.tU3()>=cEqual&&tree.tU3()<=cGreaterOrEq);switch(Data[tree
+nE-cEqual].Analyze
+nW1
+0),tree
+x03
+iY2
+l4::MakeFalse
+xP3
+ReplaceWithImmed(0);nW
+l4
+nH1
+xP3
+ReplaceWithImmed(1
+l33
+lC3:tH
+cEqual
+l33
+t22:tH
+t71
+l33
+MakeNotNotP0:tH
+cNotNot
+tW1
+1
+l33
+MakeNotNotP1:tH
+cNotNot
+tW1
+0
+l33
+MakeNotP0:tH
+cNot
+tW1
+1
+l33
+MakeNotP1:tH
+cNot
+tW1
+0
+l33
+Unchanged:;}
+if
+nW1
+1)y21)switch
+nW1
+0)nE
+iY2
+cAsin
+xP3
+lR
+fp_sin(iA2
+cAcos
+xP3
+lR
+fp_cos(y4)));tH
+cV2
+cLess?cGreater:cV2
+cLessOrEq?cGreaterOrEq:cV2
+cGreater?cLess:cV2
+cGreaterOrEq?cLessOrEq:tree
+nE);nW
+cAtan
+xP3
+lR
+fp_tan(iA2
+cLog
+xP3
+lR
+fp_exp(iA2
+cSinh
+xP3
+lR
+fp_asinh(iA2
+cTanh:if(fp_less(fp_abs(y4),nY3{tree.lR
+fp_atanh(y4)))nS2
+break;default:nM3
+nX2}
+#include <list>
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+iO2{
+#ifdef DEBUG_SUBSTITUTIONS
+yW
+double
+d){union{double
+d;uint_least64_t
+h;}
+t32
+d=d;lH1
+h
+nZ1
+#ifdef FP_SUPPORT_FLOAT_TYPE
+yW
+float
+f){union{float
+f;uint_least32_t
+h;}
+t32
+f=f;lH1
+h
+nZ1
+#endif
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+yW
+long
+double
+ld){union{long
+double
+ld;e92{uint_least64_t
+a;i02
+short
+b;}
+s;}
+t32
+ld=ld;lH1
+s.b<<data.s.a
+nZ1
+#endif
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+yW
+long
+ld){o<<"("
+<<std::hex<<ld
+nZ1
+#endif
+#endif
+}
+iO2
+FPoptimizer_CodeTree{lM
+nF)){}
+lM
+e62
+i
+yO
+nC3
+nF
+i)){data
+xB
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+lM
+eS1&&i
+yO
+nC3
+nF
+t72
+i))){data
+xB
+#endif
+lM
+i02
+v
+yO
+VarTag
+nF
+iE2,v))eS2
+nR2
+o
+yO
+OpcodeTag
+nF
+o))eS2
+nR2
+o,i02
+f
+yO
+FuncOpcodeTag
+nF
+o,f))eS2
+lM1&b
+yO
+CloneTag
+nF*b.data)){}
+yV1
+yK2::~yL2(){}
+lA
+ReplaceWithImmed
+i01
+eS1&i){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Replacing "
+;xE3(*this);if(IsImmed())OutFloatHex(std::cout,xJ1)lN1" with const value "
+<<i;OutFloatHex(std::cout,i)lN1"\n"
+;
+#endif
+data=new
+nO2
+x8(i);}
+yT1
+ParamComparer{i12()(lM1&a,lM1&b)const{if(a.xT2!=b.xT2
+nZ2
+a.xT2<b.xT2
+l81
+a.GetHash()<b.GetHash();}
+}
+;xB1
+nO2
+x8::Sort(){switch(Opcode
+iY2
+cAdd:case
+cMul:case
+cMin:case
+cMax:case
+cAnd:case
+cAbsAnd:case
+cOr:case
+cAbsOr:case
+cHypot:case
+cEqual:case
+t71:std::sort(iC2
+i62
+iC2
+end(),ParamComparer
+x8());lC
+cLess
+lU
+cGreater;}
+lC
+cLessOrEq
+lU
+cGreaterOrEq;}
+lC
+cGreater
+lU
+cLess;}
+lC
+cGreaterOrEq
+lU
+cLessOrEq;}
+break;default:nM3}
+lA
+AddParam(lM1&param){xY
+yL
+param);}
+lA
+eG
+yK2&param){xY
+yL
+yK2());xY.back().swap(param);}
+lA
+SetParam(size_t
+which,lM1&b)nI1
+which
+iB2
+xY[which]=b;}
+lA
+nC1
+size_t
+which,yK2&b)nI1
+which
+iB2
+xY[which
+t23
+b);}
+lA
+AddParams
+i01
+nK){xY.insert(xY.end(),l02.i62
+l02.end());}
+lA
+AddParamsMove(nK){size_t
+endpos=xY
+yA3,added=l02
+yA3;xY
+nE3
+endpos+added,yK2());for(size_t
+p=0;p<added;++p)xY[endpos+p
+t23
+l02[p]);}
+lA
+AddParamsMove(nK,size_t
+l12)nI1
+l12
+iB2
+iH1
+l12);AddParamsMove(eU1}
+lA
+SetParams
+i01
+nK){yG
+nV1
+tmp(eU1
+xY.swap(tmp);}
+lA
+SetParamsMove(nK){xY.swap(eU1
+l02.clear();}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+lA
+SetParams(yG
+nV1&&l02){SetParamsMove(eU1}
+#endif
+lA
+iH1
+size_t
+index){yG
+nV1&c93=xY;
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+iC2
+erase(iC2
+begin()+index);
+#else
+c93[index].data=0;for(size_t
+p=index;p+1<c93
+eW2
+p)c93[p].data.UnsafeSetP(&*c93[p+1
+iB2
+c93[nF3-1].data.UnsafeSetP(0);iC2
+resize(nF3-1);
+#endif
+}
+lA
+DelParams(){xY.clear();}
+xG1
+yK2::IsIdenticalTo(lM1&b)const{if(&*data==&*b.data
+nZ2
+true
+l81
+data->IsIdenticalTo(*b.data);}
+xG1
+nO2
+x8::IsIdenticalTo
+i01
+nO2
+x8&b)const{if(Hash!=b.Hash
+yI
+if(Opcode!=t43
+yI
+switch(Opcode
+iY2
+cImmed:return
+fp_equal(Value,t53;case
+iE2:return
+iJ1==b.iI1
+case
+cFCall:case
+cPCall:if(iJ1!=b.iJ1
+yI
+break;default:nM3
+if(nF3!=b.nF3
+yI
+for
+xK2
+0;a<c93
+eW2
+a){if(!c93[a]iA
+b.c93[a])yI}
+return
+true;}
+lA
+Become(lM1&b){if(&b!=this&&&*data!=&*b.data){DataP
+tmp=b.data;iY
+data.swap(tmp);}
+}
+lA
+CopyOnWrite(){if(GetRefCount()>1)data=new
+nO2
+x8(*data);}
+yV1
+yK2
+yK2::GetUniqueRef(){if(GetRefCount()>1
+nZ2
+yK2(*this,CloneTag())l81*this;}
+tQ):c7
+cNop
+l43),nC
+tQ
+const
+nO2&b):c7
+t43
+l43
+t53,iJ1(b.iJ1),c93(b.c93),Hash(b.Hash),Depth(b.Depth),eZ1
+b.iK1){}
+tQ
+e62
+i):c7
+cImmed
+l43
+i),nC
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+tQ
+nO2
+x8&&b):c7
+t43
+l43
+t72
+t53),iJ1(b.iJ1),c93(t72
+b.c93)),Hash(b.Hash),Depth(b.Depth),eZ1
+b.iK1){}
+tQ
+eS1&&i):c7
+cImmed
+l43
+t72
+i)),nC
+#endif
+tQ
+nR2
+o):c7
+o
+l43),nC
+tQ
+nR2
+o,i02
+f):c7
+o
+l43),iJ1(f),c93(),Hash(),Depth(1),eZ1
+0){}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <sstream>
+#include <string>
+#include <map>
+#include <set>
+#include <iostream>
+xQ
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+iO2{xB1
+l22
+cA3,eH3&done,std::ostream&o){for
+yS
+l22
+i43
+done,o);std::ostringstream
+buf;xE3(tree,buf);done[tree.GetHash()].insert(buf.str());}
+}
+#endif
+iO2
+FPoptimizer_CodeTree{
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+xB1
+DumpHashes
+i01
+eY){eH3
+done;l22(tree,done,o);for(eH3::const_iterator
+i=done.nW3
+i!=done.end();++i){const
+std::set<std::string>&flist=i
+cJ2;if(flist
+yA3!=1)o<<"ERROR - HASH COLLISION?\n"
+;for(std::set<std::string>::const_iterator
+j=flist.nW3
+j!=flist.end();++j){o<<'['<<std::hex<<i->first.hash1<<','<<i->first.hash2<<']'<<std::dec;o<<": "
+<<*j<<"\n"
+;}
+}
+}
+xB1
+xE3
+i01
+eY){const
+char*tN3;switch
+xU2
+iY2
+cImmed:o<<yZ3
+l81;case
+iE2:o<<"Var"
+<<(tree.GetVar()-iE2)l81;case
+cAdd:tN3"+"
+;lC
+cMul:tN3"*"
+;lC
+cAnd:tN3"&"
+;lC
+cOr:tN3"|"
+;lC
+cPow:tN3"^"
+;break;default:tN3;o<<FP_GetOpcodeName
+xU2);if
+xU2==cFCall||cV2
+cPCall)o<<':'<<tree.GetFuncNo();}
+o<<'(';if(iT<=1&&sep2[1])o<<(sep2+1)<<' 'eV3
+if(a>0)o<<' ';xE3
+i43
+o);if(a+1<iT)o<<sep2;}
+o<<')';}
+xB1
+DumpTreeWithIndent
+i01
+eY,const
+std::string&indent){o<<'['<<std::hex<<(void*)(&tree.iE1))<<std::dec<<','<<tree.GetRefCount()<<']';o<<indent<<'_';switch
+xU2
+iY2
+cImmed:o<<"cImmed "
+<<yZ3;o<<'\n'l81;case
+iE2:o<<"VarBegin "
+<<(tree.GetVar()-iE2);o<<'\n'l81;default:o<<FP_GetOpcodeName
+xU2);if
+xU2==cFCall||cV2
+cPCall)o<<':'<<tree.GetFuncNo();o<<'\n';}
+for
+yS{std::string
+ind=indent;for(size_t
+p=0;p<ind
+yA3;p+=2)if(ind[p]=='\\')ind[p]=' ';ind+=(a+1<iT)?" |"
+:" \\"
+;DumpTreeWithIndent
+i43
+o,ind);}
+o<<std::flush;}
+#endif
+}
+#endif
+using
+iO2
+l41;xQ
+#include <cctype>
+iO2
+l41{xG1
+ParamSpec_Compare
+i01
+void*aa,const
+void*bb,lU2
+type){switch(type
+iY2
+lY2
+xH&a=*(xH*)aa;xH&b=*(xH*)bb
+l81
+a
+t42==b
+t42&&a.index==b.index&&a.depcode==b.depcode
+cM3
+NumConstant:{eZ&a=*(eZ*)aa;eZ&b=*(eZ*)bb
+l81
+fp_equal(a.xZ3,b.xZ3)&&a.modulo==b.modulo
+iD2
+xI&a=*(xI*)aa;xI&b=*(xI*)bb
+l81
+a
+t42==b
+t42&&a.cS==b.cS&&a.data.match_type==b.data.match_type&&a.data
+xY2==b.data
+xY2&&a.data.param_list==b.data.param_list&&a.data.n2==b.data.n2&&a.depcode==b.depcode;}
+}
+return
+true;}
+i02
+ParamSpec_GetDepCode
+i01
+cG2&b){switch(b.first
+iY2
+lY2
+yK3*s=i01
+xH*)b
+eE3
+l81
+s->depcode
+iD2
+const
+xI*s=i01
+xI*)b
+eE3
+l81
+s->depcode;}
+default:nM3
+return
+0;}
+xB1
+DumpParam
+i01
+cG2&xZ2
+std::ostream&o){static
+const
+char
+ParamHolderNames[][2]={"%"
+,"&"
+,"x"
+,"y"
+,"z"
+,"a"
+,"b"
+,"c"
+}
+;i02
+t52
+0;xT3
+NumConstant:{const
+eZ&t82
+eZ*x01;o.precision(12);o<<xF3
+xZ3;nM3
+case
+lY2
+yK3&t82
+xH*x01;o<<ParamHolderNames[xF3
+index];t52
+param
+t42;break
+iD2
+const
+xI&t82
+xI*x01;t52
+param
+t42;yZ
+GroupFunction){if
+iZ2
+cS==cNeg){o<<"-"
+;n3}
+tP1
+xF3
+cS==cInv){o<<"/"
+;n3}
+else{std::string
+opcode=FP_GetOpcodeName((nR2)xF3
+cS).substr(1)c23
+0;a<opcode
+eW2
+a)opcode[a]=(char)std::toupper(opcode[a]);o<<opcode<<"( "
+;n3
+o<<" )"
+;}
+}
+else{o<<'('<<FP_GetOpcodeName((nR2)xF3
+cS)<<' ';yZ
+PositionalParams)o<<'[';yZ
+SelectedParams)o<<'{';n3
+if
+iZ2
+data.n2!=0)o<<" <"
+<<xF3
+data.n2<<'>';yZ
+PositionalParams)o<<"]"
+;yZ
+SelectedParams)o<<"}"
+;o<<')';}
+nM3
+yN3(ImmedConstraint_Value(tX1
+ValueMask)iY2
+ValueMask:lC
+Value_AnyNum:lC
+n12:o<<"@E"
+;lC
+Value_OddInt:o<<"@O"
+;lC
+t01:o<<"@I"
+;lC
+Value_NonInteger:o<<"@F"
+;lC
+eE1:o<<"@L"
+;t62
+ImmedConstraint_Sign(tX1
+SignMask)iY2
+SignMask:lC
+Sign_AnySign:lC
+nJ1:o<<"@P"
+;lC
+n02:o<<"@N"
+;t62
+ImmedConstraint_Oneness(tX1
+OnenessMask)iY2
+OnenessMask:lC
+Oneness_Any:lC
+Oneness_One:o<<"@1"
+;lC
+Oneness_NotOne:o<<"@M"
+;t62
+ImmedConstraint_Constness(tX1
+ConstnessMask)iY2
+ConstnessMask:lC
+yL1:if(lF3.first==ParamHolder){yK3&t82
+xH*x01;if
+iZ2
+index<2)nM3
+o<<"@C"
+;lC
+Constness_NotConst:o<<"@V"
+;lC
+Oneness_Any:nM3}
+xB1
+DumpParams
+iL1
+paramlist,i02
+count,std::ostream&o){for
+iL1
+a=0;a<count;++a){if(a>0)o<<' ';const
+cG2&param=e01
+x8(paramlist,a);DumpParam
+x8(param,o);i02
+depcode=ParamSpec_GetDepCode(param);if(depcode!=0)o<<"@D"
+<<depcode;}
+}
+}
+#include <algorithm>
+using
+iO2
+l41;xQ
+iO2{yK3
+plist_p[36]={{2,0,0x0}
+tS
+0,0x4}
+tS
+nJ1,0x0}
+tS
+n02|Constness_NotConst,0x0}
+tS
+Sign_NoIdea,0x0}
+tS
+eE1,0x0}
+,{3,Sign_NoIdea,0x0}
+,{3,0,0x0}
+,{3,eE1,0x0}
+,{3,0,0x8}
+,{3,Value_OddInt,0x0}
+,{3,Value_NonInteger,0x0}
+,{3,n12,0x0}
+,{3,nJ1,0x0}
+,{0,n02|n0{0,n0{0,nJ1|n0{0,n12|n0{0,yL1,0x1}
+,{0,t01|nJ1|n0{0,t11
+yL1,0x1}
+,{0,t11
+n0{0,Oneness_One|n0{0,eE1|n0{1,n0{1,n12|n0{1,t11
+n0{1,t01|n0{1,nJ1|n0{6,0,0x0}
+,{4,0,0x0}
+,{4,t01,0x0}
+,{4,n0{4,0,0x16}
+,{5,0,0x0}
+,{5,n0}
+;yT1
+plist_n_container{static
+const
+eZ
+plist_n[19];}
+;yV1
+const
+eZ
+plist_n_container
+x8::plist_n[19]={{eS1(-2
+iZ-1
+iZ-0.5
+iZ
+0
+tB2
+fp_const_deg_to_rad
+cE3
+fp_const_einv
+cE3
+fp_const_log10inv
+x8(iZ
+0.5
+tB2
+fp_const_log2
+x8(iZ
+1
+tB2
+fp_const_log2inv
+x8(iZ
+2
+tB2
+fp_const_log10
+cE3
+fp_const_e
+cE3
+fp_const_rad_to_deg
+cE3-fp_const_pihalf
+x8(),xL1{eS1(0),xL1{fp_const_pihalf
+x8(),xL1{fp_const_pi
+x8(),xL1}
+;const
+xI
+plist_s[464]={{{1,15,tC2
+15,cNeg,GroupFunction,0}
+,yL1,0x1}
+,{{1,422,tC2
+423,tC2
+15,tD2
+24,tD2
+410,tD2
+411,cInv,xZ
+2,301330,cAdd,tG2
+271397
+lU1
+0x5
+tY3
+271397,l5
+45
+lU1
+iR
+2,58413,l5
+140333,l5
+194605
+lU1
+0x1
+tY3
+224301,l5
+270373,l5
+270381,l5
+271405,l5
+271405
+lU1
+0x5
+tY3
+140341,l5
+223285,l5
+286757,l5
+286765,l5
+322605,l5
+232501,l5
+7168,l5
+30727,l5
+141312,l5
+179207,l5
+58383,l5
+59407,l5
+285718
+lU1
+iR
+2,59416,l5
+29726,l5
+34823,l5
+18597,l5
+46264,l5
+15764,l5
+57509,l5
+293049,l5
+292026,l5
+161979,l5
+161980,l5
+172265,l5
+173308,l5
+243951,l5
+247024,l5
+38152,l5
+46344,l5
+293147,l5
+1332,l5
+24980,l5
+183473,l5
+183570,l5
+418001,l5
+420248,cAdd,lP
+0,0,tR
+0,0,cAdd,i3
+1,43,tR
+1,51,tR
+1,52,tR
+1,53,tR
+1,54,tR
+1,0,lZ
+iR
+1,0,t51
+2}
+,0,iR
+1,0,tR
+1,21,tR
+1,15,tR
+1,26,tR
+1,24,cAdd,i3
+2,56344,cAdd,i3
+1,219,tR
+1,230,cAdd,i3
+1,245,lZ
+0x16}
+,{{1,329,lZ
+0x16}
+,{{1,399,lZ
+iR
+1,401,lZ
+iR
+0,0,t51
+1}
+,nJ1,0x0
+tY3
+46095,tE2
+24591,tE2
+32783,tE2
+37,c1
+7205,c1
+114725,c1
+288805,lJ
+0x6
+tY3
+347173,lJ
+0x6
+tY3
+331813,c1
+350245,c1
+372773,c1
+377893,c1
+378917,c1
+383013,c1
+388133,c1
+439333,c1
+442405,c1
+447525,c1
+450597,c1
+459813,c1
+468005,c1
+305201,l2
+3,61910016,c1
+7168,c1
+114688,c1
+512000,l2
+3,45508608,c1
+15,c1
+30727,c1
+71695,c1
+130063,c1
+286735,lJ
+0x1
+tY3
+29726,c1
+34823,c1
+115736,c1
+114712,c1
+299008,c1
+288783
+xM2
+300032,c1
+347151
+xM2
+357376,l2
+3,65425438,c1
+420864,c1
+280611,c1
+358407,c1
+301088,c1
+55,c1
+38143,c1
+38143,lJ
+iR
+2,38145,lJ
+iR
+2,38152,c1
+38171,c1
+15631,c1
+15711,c1
+56671,c1
+38262,lJ
+iR
+2,60820,c1
+38325,lJ
+iR
+3,15777143,c1
+37303,c1
+48505,l2
+3,15777207,c1
+347191
+xM2
+48571,c1
+103714,c1
+104739,c1
+266538,c1
+307547,c1
+304475,c1
+353627,c1
+48490,c1
+310338,c1
+376173,lJ
+lP2
+3,39173485,lJ
+lP2
+2,436589,lJ
+lP2
+2,7578,c1
+376232,lJ
+lP2
+2,436648,lJ
+lP2
+3,39233901,lJ
+lP2
+3,39233960,lJ
+lP2
+2,7651,c1
+7675,l2
+0,0,nO
+0,0,cT
+1,37,nO
+1,37,cT
+1,2,n22
+2,n32
+3,n22
+3,n32
+0,nO
+1,0,n32
+0,cT
+1,14,nO
+1,16,nO
+1,16,lK
+1
+xN2
+21,nO
+1,15,nO
+1,24,cT
+2,24591,nO
+1,55,nO
+1,55,lK
+2
+xN2
+275,n22
+278,n32
+284,cT
+1,287,nO
+1,288,nO
+1,289,cT
+1,462,cT
+2,413757,lK
+1
+xN2
+295,nO
+1,329,cT
+2,414025,lK
+1}
+,0,0x16}
+,{{1,351,nO
+1,404,nO
+1,410,nO
+2,60459,l32
+44047,l32
+24591,l32
+32783,l32
+44056,l32
+41,lI,41,y0
+49,lI,49,y0
+365609,lI,222257,lI,365617,lI,366633,lI,366641,lI,48128,lI,15,lI,15,cV1
+16,lI,10240,lI,11264,lI,7170,lI,7168,lI,7168,y0
+7183,cV1
+17408,lI,19456,lI,16384,lI,15360,lI,27648,lI,30720,lI,30722,lI,24,tF2
+0x6
+tY3
+24,lI,7192,lI,68608,lI,83968,lI,86040,lI,87040,lI,88064,lI,90112,lI,432128,lI,433152,lI,37895,lI,14342,lI,25607,lI,7183,lI,56327,lI,114703,lI,114718,lI,257024,lI,419840,lI,260103,lI,37953,tF2
+0x5
+tY3
+37956,y0
+37961,tF2
+0x5
+tY3
+38105,lI,38114,y0
+38984,y0
+44103,y0
+44104,y0
+38991,lI,44111,lI,44135,lI,44124,y0
+44136,lI,48240,lI,60693,lI,38253,y0
+38253,lI,38259,tF2
+0x5
+tY3
+38260,cV1
+38262,y0
+38262,lI,48493,y0
+48493,lI,15734,y0
+137590,lI,38264,tF2
+0x5
+tY3
+38292,lI,38294,lI,38300,lI,38301,lI,38312,y0
+38325,y0
+38332,y0
+38332,lI,38341,lI,38341,y0
+38343,lI,60,lI,60,tF2
+0x6
+tY3
+48552,y0
+48552,lI,257198,lI,260274,lI,24792,lI,7172,cPow,PositionalParams,0}
+,nJ1,0x0
+tY3
+24591,cPow,xZ
+2,60440,cPow,xZ
+2,60451,cPow,xZ
+2,61472,cPow,xZ
+1,0,eI3
+7,eI3
+157,eI3
+0,cAcos
+eJ3
+cAcosh
+eJ3
+cAsin
+eJ3
+cAsinh
+nR
+112,cAsinh
+eJ3
+cAtan,eF1
+cAtan2,tG2
+303104
+i23
+eJ3
+cAtanh
+eJ3
+cCeil,cF3
+216,cCeil
+eJ3
+yO2
+0,cCos,cF3
+7,yO2
+81,yO2
+83,yO2
+112,yO2
+180,yO2
+234,yO2
+0,cH3
+cF3
+0,cI3
+176,cI3
+180,cI3
+409,cI3
+0,cFloor,cF3
+216,cFloor,tG2
+308523,eK3
+tG2
+352555,eK3
+tG2
+352599,eK3
+l0
+3,31464448,cU
+507534336,cU
+508566528,cU
+33579008,cU
+30443520,lD3
+31464448,lD3
+7836672,cU
+24612864,cU
+93415424,cU
+142744576,cU
+174234624,cU
+265547776,cU
+435585024,cU
+439783424,cU
+519553024,cU
+526900224,cU
+58739160,cU
+58739160,lD3
+58739166,cU
+58739166,cIf,cF3
+112,cInt
+eJ3
+tH2
+7,tH2
+30,tH2
+157,tH2
+216,tH2
+282,tH2
+15,cLog,xZ
+1,24,cLog,xZ
+1,0,cLog10
+eJ3
+cLog2,eF1
+cMax,tG2
+29726,cMax,tG2
+34823,cMax
+eJ3
+cMax,AnyParams,1}
+,0,iR
+xG3
+cMin,tG2
+29726,cMin,tG2
+34823,cMin
+eJ3
+cMin,AnyParams,1}
+,0,iR
+2,46095,cMin,xZ
+2,24591,cMin,xZ
+1,0,n42
+0,cSin,cF3
+7,n42
+81,n42
+83,n42
+112,n42
+139,n42
+161,cSin,nU
+0x5}
+,{{1,216,n42
+227,n42
+231,cSin,nU
+0x1}
+,{{1,234,n42
+0,cSinh,cF3
+0,cSinh
+nR
+161,cSinh,nU
+0x5}
+,{{1,176,cSinh
+nR
+216,cSinh
+nR
+227,cSinh
+nR
+234,cSinh
+nR
+409,cSinh
+eJ3
+yP2
+0,cTan,cF3
+75,cTan,cF3
+76,yP2
+161,yP2
+216,yP2
+231,yP2
+227,yP2
+234,yP2
+0,xV2
+0,cTanh,cF3
+160,xV2
+161,xV2
+216,xV2
+227,xV2
+234,xV2
+0,cTrunc,tG2
+15384,cSub,xZ
+2,15384,cDiv,xZ
+2,420251,cDiv,xZ
+xG3
+tK2
+nU
+t41
+tK2
+tG2
+30720,tK2
+nU
+0x20
+tY3
+30727,tK2
+nU
+0x24
+tY3
+30727,tK2
+tG2
+114743,tK2
+tG2
+114743,t71,tG2
+39936,cLess,l6
+2,39936,cLess,tG2
+7,cLess,eF1
+cLess,nU
+t41
+cLessOrEq,tG2
+256216,cLessOrEq,tG2
+39936,e82
+l6
+2,39936,e82
+tG2
+7,e82
+eF1
+e82
+nU
+t41
+cGreaterOrEq,tG2
+256216,cGreaterOrEq
+eJ3
+l42
+7,l42
+15,l42
+30,l42
+156,l42
+494,l42
+497,l42
+498,l42
+501,l42
+504,l42
+505,cNot,eF1
+l52
+29726,l52
+34823,l52
+394270,l52
+398366,l52
+7651,cAnd,lP
+0,0,cAnd,AnyParams,1}
+,0,0x0}
+,{{xG3
+nJ2
+29726,nJ2
+34823,nJ2
+394270,nJ2
+398366,nJ2
+7651,cOr,lP
+1,0
+t31
+81
+t31
+121
+t31
+156
+t31
+159
+t31
+216,cDeg
+nR
+216,cRad,eF1
+cAbsAnd,lP
+xG3
+cAbsOr,lP
+1,0,yR3
+eJ3
+cAbsNotNot,l0
+3,31464448,eP3
+nU
+0x0}
+,}
+;}
+iO2
+l41{const
+Rule
+grammar_rules[253]={{ProduceNewTree,1,1,0,{1,0,cAbs,xJ
+361,{1,172,cAtan,xJ
+354
+tS
+1337
+i23,xJ
+356
+tS
+320513
+i23
+l7
+2,2,222424
+tS
+226524
+i23
+l7
+2,2,224474
+tS
+228574
+i23,xJ
+148
+x13
+cCeil,xJ
+435,{1,80,tL2
+429,{1,115,tL2
+430,{1,117,tL2
+146,{1,118,tL2
+370,{1,116,tL2
+0,{1,354,cCos
+l7
+2,1,0,{1,351,cCos
+l7
+2,1,216
+x13
+tL2
+314,{1,357,cCosh
+l7
+2,1,0,{1,351,cCosh
+l7
+2,1,216
+x13
+cH3
+xJ
+144
+x13
+cFloor,xJ
+403,{1,114,cFloor,eL3
+214,{3,7379968,c8
+518,{3,31464450,c8
+499,{3,8428544,c8
+501,{3,8434688,c8
+215,{3,40901632,c8
+494,{3,40902656,c8
+507,{3,40940544,c8
+506,{3,47194112,c8
+483,{3,47225856,c8
+414,{3,1058266,c8
+418,{3,1058272,c8
+418,{3,9438682,c8
+414,{3,9438688,c8
+460,{3,396733911,c8
+460,{3,381020637,cIf
+l7
+0,3,31492569,{3,35682779,cIf
+l7
+0,3,31492575,{3,35682785,cIf,xJ
+111,{1,228,eM3
+110,{1,244,eM3
+355,{1,106,eM3
+204,{1,205,cLog
+l7
+0,1,395
+cP2,cMax
+yF
+0
+tS
+431105,cMax
+yF
+396
+cP2,cMin
+yF
+0
+tS
+427009,cMin,AnyParams,0}
+}
+,{ProduceNewTree,0,1,203
+tS
+24804,cPow,eL3
+203
+tS
+25827,cPow,eL3
+202
+tS
+126991,cPow
+xM1
+30988,cPow
+xM1
+30989,cPow
+xM1
+30990,cPow
+t93
+166239
+tS
+31066,cPow
+xM1
+32015,cPow
+t93
+7168
+tS
+12639,cPow
+t93
+7392
+tS
+12535
+x23
+380
+tS
+44095
+x23
+381
+tS
+44141
+x23
+382
+tS
+44140
+x23
+201
+tS
+109583
+x23
+200
+tS
+132129
+x23
+155
+tS
+133153
+n52
+419840
+tS
+413711
+n52
+254976
+tS
+253967
+n52
+221184
+tS
+251937
+n52
+221184
+tS
+248850
+x23
+150
+x13
+yQ2
+372,{1,80,yQ2
+146,{1,115,yQ2
+370,{1,117,yQ2
+149,{1,118,yQ2
+429,{1,116,yQ2
+0,{1,356,yQ2
+152
+x13
+cSinh,xJ
+312,{1,355,cSinh,xJ
+153
+x13
+eN3
+0,{1,359,eN3
+170,{1,360,eN3
+154
+x13
+cTanh
+l7
+0,1,392
+tS
+395279,tM2
+391
+cP2,tM2
+199
+tS
+242924,tM2
+198
+tS
+230636,tM2
+164
+tS
+240869,tM2
+163
+tS
+240660,t51
+0
+nM1
+263,{1,311,t51
+1
+nM1
+262,{1,310,t51
+1
+l1
+2,1,261
+tS
+1333
+lW1
+259
+tS
+1331
+lW1
+407
+tS
+415124
+lW1
+45
+tS
+331093
+lW1
+324
+tS
+146477
+lW1
+342
+tS
+145453
+lW1
+427
+tS
+213202
+lW1
+428
+tS
+217298
+lW1
+368
+tS
+216270
+lW1
+145
+tS
+216271
+lW1
+369
+tS
+218318
+lW1
+197
+tS
+144665
+lW1
+194
+tS
+348441
+lW1
+193
+tS
+348300
+lW1
+195
+tS
+200875
+lW1
+192
+tS
+177323
+lW1
+257
+tS
+446837
+lW1
+181
+tS
+446653
+lW1
+151
+tS
+187765
+lW1
+147
+tS
+187828
+lW1
+255
+tS
+195957
+lW1
+374
+tS
+264383
+lW1
+437
+tS
+264381
+lW1
+437
+tS
+186741
+lW1
+374
+tS
+262580
+lW1
+151
+tS
+262333,tM2
+98
+tS
+1155
+eG1
+97
+tS
+1156
+eG1
+305
+tS
+1330
+eG1
+99
+tS
+24704
+eG1
+100
+tS
+24698
+eG1
+394
+tS
+395279
+eG1
+393
+cP2
+eG1
+353
+tS
+360799
+eG1
+96
+tS
+89360
+eG1
+105
+tS
+80155
+eG1
+95
+tS
+79131
+cQ2
+56671
+tS
+1424
+cQ2
+15711
+tS
+1426
+cQ2
+107535
+tS
+93467
+cQ2
+97295
+tS
+96539,l8
+1,1,0,{1,351,l8
+1,1,55,{1,14,lK
+0
+nM1
+93
+tS
+70674,cMul,SelectedParams,0
+nM1
+512,{1,50,lK
+1
+nM1
+513,{1,40,lK
+1
+l1
+2,1,435
+tS
+443429,eA
+442
+tS
+451621,eA
+336
+tS
+382285,eA
+437
+tS
+382406,eA
+374
+tS
+446801,eA
+365
+tS
+435534,eA
+444
+tS
+325033,eA
+318
+tS
+340413,eA
+335
+tS
+375116,eA
+424
+tS
+375229,eA
+45
+tS
+456126,eA
+450
+tS
+328114,eA
+45
+tS
+460223,eA
+452
+tS
+461861,eA
+453
+tS
+329140,eA
+322
+tS
+341446,eA
+456
+tS
+335286,eA
+448
+tS
+327087,eA
+459
+tS
+469029,eA
+455
+tS
+311360,eA
+338
+tS
+309322,eA
+412
+tS
+43412,eA
+330
+tS
+49480,eA
+413
+tS
+47508,eA
+331
+tS
+45384,l8
+2,2,334277
+tS
+333236
+cQ2
+39936
+tS
+xH3
+cEqual
+yP
+cEqual
+yQ
+cEqual
+yR
+cEqual
+lA1
+24807
+t61
+iD
+t61
+l62
+237799
+t61
+n11
+cEqual
+l72
+tK2
+eH1
+39,tK2
+eO3
+0
+tS
+5165,cEqual
+t93
+39936
+tS
+xH3
+t71
+yP
+t71
+yQ
+t71
+yR
+t71
+lA1
+24807
+tI2
+iD
+tI2
+l62
+237799
+tI2
+n11
+t71
+l72
+t71
+tJ2
+39,t71,eH1
+5165,t71
+yP
+cLess
+yQ
+cLess
+yR
+cLess,xJ
+516
+tS
+44032,cLess
+lA1
+24804
+t21
+yM1
+t21
+iD
+t21
+l62
+237796
+t21
+xN1
+t21
+n11
+cLess
+l72
+cLess
+tJ2
+xH3
+cLess
+yP
+cLessOrEq
+yQ
+cLessOrEq
+yR
+cLessOrEq,xJ
+510
+tS
+359439,cLessOrEq
+lA1
+24804
+xC1
+yM1
+xC1
+iD
+xC1
+l62
+237796
+xC1
+xN1
+xC1
+n11
+cLessOrEq
+l72
+cLessOrEq
+tJ2
+359469,cLessOrEq
+yP
+cGreater
+yQ
+cGreater
+yR
+e82
+xJ
+487
+tS
+359439,cGreater
+lA1
+24804
+y61
+yM1
+y61
+iD
+y61
+l62
+237796
+y61
+xN1
+y61
+n11
+cGreater
+l72
+e82
+eH1
+359469,cGreater
+yP
+cGreaterOrEq
+yQ
+cGreaterOrEq
+yR
+cGreaterOrEq,xJ
+517
+tS
+44032
+yX
+473304
+tS
+24804
+yX
+yM1
+yX
+iD
+yX
+l62
+237796
+yX
+xN1
+yX
+7168
+tS
+279818
+yX
+lB1
+cGreaterOrEq,eH1
+xH3
+cGreaterOrEq,eL3
+516,{1,2,cNot,eO3
+469,{1,123,cNot,eL3
+511,{1,5,cAnd,AnyParams,1
+l1
+0,1,514
+tS
+13314,cAnd
+yF
+397
+cP2,cAnd
+yF
+491
+tS
+496099,cAnd
+yF
+492
+tS
+399846,cAnd
+yF
+493
+tS
+393702,cAnd,AnyParams,0
+l1
+0,2,479697,{3,489115088,cAnd
+yF
+515
+tS
+13314,xI3
+508
+tS
+8197,xI3
+398
+cP2,xI3
+488
+tS
+496099,xI3
+489
+tS
+399846,xI3
+490
+tS
+393702,xI3
+509
+tS
+136197,cOr,AnyParams,0}
+}
+,{ProduceNewTree,0,1,517,{1,2,xJ3
+l3
+1,1,0,{1,0,xJ3
+eO3
+470,{1,123,xJ3
+xJ
+482,{1,228,cAbsNotNot,AnyParams,0
+nM1
+476,{1,227,cAbsNotNot,AnyParams,0}
+}
+,{ProduceNewTree,0,1,383,{3,31464955,eP3
+eL3
+517,{3,40940544,eP3
+eL3
+516,{3,47225856,i03
+l7
+0,3,31492569,{3,35682779,eP3
+PositionalParams,0}
+}
+,}
+;e92
+grammar_optimize_abslogical_type{xS
+9
+eI
+grammar_optimize_abslogical_type
+grammar_optimize_abslogical={9,{21,183,219,228,231,237,244,249,252}
+}
+;}
+e92
+grammar_optimize_ignore_if_sideeffects_type{xS
+59
+eI
+grammar_optimize_ignore_if_sideeffects_type
+grammar_optimize_ignore_if_sideeffects={59,{0,20,22,23,24,25,26,27,cV
+tY1
+78,cZ
+xR
+grammar_optimize_nonshortcut_logical_evaluation_type{xS
+56
+eI
+grammar_optimize_nonshortcut_logical_evaluation_type
+grammar_optimize_nonshortcut_logical_evaluation={56,{0,26,cV
+tY1
+78,cZ
+158,167,168,169,178,179,191,195,203,207,215,227,229,230,232,233,234,235,236,238,239,240,241,242,243,245,246,247,248,250,251}
+}
+;}
+e92
+grammar_optimize_round1_type{xS
+118
+eI
+grammar_optimize_round1_type
+grammar_optimize_round1={118,{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,18,26,cV
+37,38,tY1
+45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,63,64,65,66,67,68,69,70,71,78,79,80,81,82,83,88,89,90,91,92,93,94,95,96,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,132,xR
+grammar_optimize_round2_type{xS
+100
+eI
+grammar_optimize_round2_type
+grammar_optimize_round2={100,{0,15,16,17,26,cV
+39,40,tY1
+45,46,47,48,49,50,51,52,53,54,59,60,72,73,78,79,84,85,86,87,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,117,118,119,120,121,122,123,124,125,126,127,128,133,157,xR
+grammar_optimize_round3_type{xS
+79
+eI
+grammar_optimize_round3_type
+grammar_optimize_round3={79,{74,75,76,77,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,159,160,161,162,163,164,165,166,170,171,172,173,174,175,176,177,180,181,182,184,185,186,187,188,189,190,192,193,194,196,197,198,199,200,201,202,204,205,206,208,209,210,211,212,213,214,216,217,218,220,221,222,223,224,225,226}
+}
+;}
+e92
+grammar_optimize_round4_type{xS
+10
+eI
+grammar_optimize_round4_type
+grammar_optimize_round4={10,{19,55,56,57,130,131,153,154,155,156}
+}
+;}
+e92
+grammar_optimize_shortcut_logical_evaluation_type{xS
+53
+eI
+grammar_optimize_shortcut_logical_evaluation_type
+grammar_optimize_shortcut_logical_evaluation={53,{0,26,cV
+tY1
+78,cZ
+158,167,168,169,178,179,191,195,203,207,215,227,229,232,233,234,235,236,239,240,241,242,245,246,247,248,250,251}
+}
+;}
+}
+iO2
+l41{yV1
+cG2
+e01
+iL1
+paramlist,lC1){index=(paramlist>>(index*10))&1023;if(index>=55
+nZ2
+cG2(SubFunction
+tZ1
+plist_s[index-55]);if(index>=36
+nZ2
+cG2(NumConstant
+tZ1
+plist_n_container
+x8::plist_n[index-36])l81
+cG2(ParamHolder
+tZ1
+plist_p[index]);}
+}
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <stdio.h>
+#include <algorithm>
+#include <map>
+#include <sstream>
+xQ
+using
+iO2
+l41;using
+iO2
+FPoptimizer_CodeTree;using
+iO2
+FPoptimizer_Optimize;iO2{nT1
+It,typename
+T,typename
+Comp>eI1
+MyEqualRange(It
+first,It
+last,const
+T&val,Comp
+comp){size_t
+len=last-first;while(len>0){size_t
+nJ3
+len/2;It
+n43(first);n43+=half;if(comp(*n43,val)){first=n43;++first;len=len-half-1;}
+tP1
+comp(val,*n43)){len=half;}
+else{It
+left(first);{It&cR2=left;It
+last2(n43);size_t
+len2=last2-cR2;while(len2>0){size_t
+half2=len2/2;It
+middle2(cR2);middle2+=half2;if(comp(*middle2,val)){cR2=middle2;++cR2;len2=len2-half2-1;}
+else
+len2=half2;}
+}
+first+=len;It
+right(++n43);{It&cR2=right;It&last2=first;size_t
+len2=last2-cR2;while(len2>0){size_t
+half2=len2/2;It
+middle2(cR2);middle2+=half2;if(comp(val,*middle2))len2=half2;else{cR2=middle2;++cR2;len2=len2-half2-1;}
+}
+}
+return
+eI1(left,right);}
+}
+return
+eI1(first,first);}
+yT1
+OpcodeRuleCompare{i12()(lM1&tree,i02
+xW2)const{const
+Rule&rule=grammar_rules[xW2]l81
+tree
+nE<rule
+nT2.subfunc_opcode;}
+i12()iL1
+xW2,const
+eR
+const{const
+Rule&rule=grammar_rules[xW2]l81
+rule
+nT2.subfunc_opcode<tree
+nE;}
+}
+;xG1
+TestRuleAndApplyIfMatch
+eX3
+yK2&tree,bool
+cD{MatchInfo
+x8
+info;lZ1
+found(false,e1());if((rule.eL1
+LogicalContextOnly)&&!cD{yR2
+if(nD
+IsIntType
+x8::result){if(rule.eL1
+NotForIntegers)yR2
+else{if(rule.eL1
+OnlyForIntegers)yR2
+for(;;){
+#ifdef DEBUG_SUBSTITUTIONS
+#endif
+found=TestParams(rule
+nT2,tree,found.specs,info,true);if(found.found)break;if(!&*found.specs){fail:;
+#ifdef DEBUG_SUBSTITUTIONS
+DumpMatch
+t81,false);
+#endif
+nX2}
+#ifdef DEBUG_SUBSTITUTIONS
+DumpMatch
+t81,true);
+#endif
+SynthesizeRule
+t81)nS2}
+iO2
+FPoptimizer_Optimize{xG1
+ApplyGrammar
+i01
+Grammar&tN2,yK2&tree,bool
+cD{if(tree.GetOptimizedUsing()==&tN2){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Already optimized:  "
+;xE3(tree)lN1"\n"
+<<std::flush;
+#endif
+nX2
+if(true){bool
+changed
+i13
+switch
+xU2
+iY2
+cNot:case
+cNotNot:case
+cAnd:case
+cOr:for
+xK2
+0
+nP
+true))yI1
+lC
+cIf:case
+i03:if(ApplyGrammar(tN2,e72,cV2
+cIf))yI1
+for
+xK2
+1
+nP
+cD)yI1
+break;default:for
+xK2
+0
+nP
+false))yI1}
+if(changed){tree.Mark_Incompletely_Hashed()nS2}
+typedef
+const
+i02
+char*lE3;std::pair<lE3,lE3>range=MyEqualRange(tN2.rule_list,tN2.rule_list+tN2.rule_count,tree,OpcodeRuleCompare
+x8());if(range.eQ3
+range
+eE3){
+#ifdef DEBUG_SUBSTITUTIONS
+yG<i02
+char>rules;rules.nH3
+range
+eE3-range.first);yD
+if(IsLogisticallyPlausibleParamsMatch(cW1
+nT2
+n72
+rules
+yL*r);}
+range.first=&rules[0];range
+eE3=&rules[rules
+yA3-1]+1;if(range.eQ3
+range
+eE3){std::cout<<"Input ("
+<<FP_GetOpcodeName
+xU2)<<")["
+<<iT<<"]"
+;if(cD
+std::cout<<"(Logical)"
+;i02
+first=i21,prev=i21;const
+char*sep=", rules "
+;yD
+if(first==i21)first=prev=*r;tP1*r==prev+1)prev=*r;else{std::cout<<sep<<first;sep=","
+;if(prev!=first)std::cout<<'-'<<prev;first=prev=*r;}
+}
+if(eQ3
+i21){std::cout<<sep<<first;if(prev!=first)std::cout<<'-'<<prev;}
+std::cout<<": "
+;xE3(tree)lN1"\n"
+<<std::flush;}
+#endif
+bool
+changed
+i13
+yD
+#ifndef DEBUG_SUBSTITUTIONS
+if(!IsLogisticallyPlausibleParamsMatch(cW1
+nT2
+n72
+y81
+#endif
+if(TestRuleAndApplyIfMatch(cW1,tree,cD){yI1
+nM3}
+if(changed){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Changed."
+<<std::endl
+lN1"Output: "
+;xE3(tree)lN1"\n"
+<<std::flush;
+#endif
+tree.Mark_Incompletely_Hashed()nS2}
+tree.SetOptimizedUsing(&tN2)l81
+false;}
+xB1
+ApplyGrammars(x2){
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_round1\n"
+;
+#endif
+n4
+grammar_optimize_round1
+n53
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_round2\n"
+;
+#endif
+n4
+grammar_optimize_round2
+n53
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_round3\n"
+;
+#endif
+n4
+grammar_optimize_round3
+n53
+#ifndef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_nonshortcut_logical_evaluation\n"
+;
+#endif
+n4
+grammar_optimize_nonshortcut_logical_evaluation
+n53
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_round4\n"
+;
+#endif
+n4
+grammar_optimize_round4
+n53
+#ifdef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_shortcut_logical_evaluation\n"
+;
+#endif
+n4
+grammar_optimize_shortcut_logical_evaluation
+n53
+#endif
+#ifdef FP_ENABLE_IGNORE_IF_SIDEEFFECTS
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_ignore_if_sideeffects\n"
+;
+#endif
+n4
+grammar_optimize_ignore_if_sideeffects
+n53
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+std
+tJ3"grammar_optimize_abslogical\n"
+;
+#endif
+n4
+grammar_optimize_abslogical
+n53
+#undef C
+}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <algorithm>
+#include <assert.h>
+#include <cstring>
+#include <cmath>
+#include <memory> /* for auto_ptr */
+xQ
+using
+iO2
+l41;using
+iO2
+FPoptimizer_CodeTree;using
+iO2
+FPoptimizer_Optimize;iO2{xG1
+TestImmedConstraints
+iL1
+bitmask,const
+eR{switch(bitmask&ValueMask
+iY2
+Value_AnyNum:case
+ValueMask:lC
+n12:if(GetEvennessInfo
+nO3
+l82
+Value_OddInt:if(GetEvennessInfo
+nO3
+n82
+t01:if(GetIntegerInfo
+nO3
+l82
+Value_NonInteger:if(GetIntegerInfo
+nO3
+n82
+eE1:if(!IsLogicalValue(tree)yI
+nK1
+SignMask
+iY2
+Sign_AnySign:lC
+nJ1:if(l01
+l82
+n02:if(l01
+n82
+Sign_NoIdea:if(l01
+Unknown
+yI
+nK1
+OnenessMask
+iY2
+Oneness_Any:case
+OnenessMask:lC
+Oneness_One:if(!cW2
+if(!fp_equal(fp_abs(yZ3),eS1(1))yI
+lC
+Oneness_NotOne:if(!cW2
+if(fp_equal(fp_abs(yZ3),eS1(1))yI
+nK1
+ConstnessMask
+iY2
+Constness_Any:lC
+yL1:if(!cW2
+lC
+Constness_NotConst:if(cW2
+nM3
+return
+true;}
+n73<i02
+extent,i02
+nbits,typename
+cS2=i02
+int>e92
+nbitmap{private:static
+const
+i02
+bits_in_char=8;static
+const
+i02
+cT2=(xK3
+cS2)*bits_in_char)/nbits;cS2
+data[(extent+cT2-1)/cT2];e13
+void
+inc(lC1,int
+by=1){data[pos(index)]+=by*cS2(1<<xX2);i6
+void
+dec(lC1){inc(index,-1);}
+int
+get(lC1
+n61(data[pos(index)]>>xX2)&mask()xJ2
+pos(lC1){return
+index/cT2
+xJ2
+shift(lC1){return
+nbits*(index%cT2)xJ2
+mask(){return(1<<nbits)-1
+xJ2
+mask(lC1){return
+mask()<<xX2;}
+}
+;e92
+c83{int
+SubTrees:8;int
+Others:8;int
+i31:8;int
+cG3:8;nbitmap<iE2,2>SubTreesDetail;c83(){std::memset(this,0,xK3*this));}
+c83
+i01
+c83&b){std::memcpy(this,&b,xK3
+b));}
+c83&e31=i01
+c83&b){std::memcpy(this,&b,xK3
+b))l81*this;}
+}
+;yV1
+c83
+CreateNeedList_uncached(t0&cB2){c83
+x11
+xS3
+a=0;a<cB2
+xY2;++a){const
+cG2&lF3=e01
+x8(cB2.param_list,a);xT3
+lZ2
+const
+xI&t82
+xI*x01;yZ
+GroupFunction)++tA3;else{++tA2;assert(param.data.subfunc_opcode<VarBegin);x11.SubTreesDetail.inc
+iZ2
+cS);}
+++x11.i31;nM3
+case
+NumConstant:case
+ParamHolder:++t92;++x11.i31;nM3}
+return
+x11;}
+yV1
+c83&CreateNeedList(t0&cB2){typedef
+std::map<t0*,c83>cX1;static
+cX1
+yO1;cX1::nX3
+i=yO1.xE2&cB2);if(i!=yO1.cP1&cB2
+nZ2
+i
+cJ2
+l81
+yO1.nT3,std::make_pair(&cB2,CreateNeedList_uncached
+x8(cB2)))cJ2;}
+yV1
+yK2
+CalculateGroupFunction
+i01
+cG2&xZ2
+const
+t9
+info){xT3
+NumConstant:{const
+eZ&t82
+eZ*x01
+l81
+CodeTreeImmed
+iZ2
+xZ3)cM3
+lY2
+yK3&t82
+xH*x01
+l81
+info.GetParamHolderValueIfFound
+iZ2
+index)iD2
+const
+xI&t82
+xI*x01
+yJ
+result;result
+tU
+xF3
+cS);tC1
+iE1).reserve
+iZ2
+data
+xY2)xS3
+a=0;a<xF3
+data
+xY2;++a)nG1
+tmp(CalculateGroupFunction(e01
+x8
+iZ2
+data.param_list,a),info));result
+yA
+tmp);}
+tC1
+Rehash()l81
+result;}
+}
+return
+yK2();}
+}
+iO2
+FPoptimizer_Optimize{xG1
+IsLogisticallyPlausibleParamsMatch(t0&cB2,const
+eR{c83
+x11(CreateNeedList
+x8(cB2));size_t
+eR3=iT;if(eR3<size_t(x11.i31)){nX2
+for
+xK2
+0;a<eR3;++a){i02
+opcode=xI2
+nE;switch(opcode
+iY2
+cImmed:if(tA3>0)--tA3;else--t92;lC
+iE2:case
+cFCall:case
+cPCall:--t92;break;default:assert(opcode<VarBegin);if(tA2>0&&x11.SubTreesDetail.get(opcode)>0){--tA2;x11.SubTreesDetail.dec(opcode);}
+else--t92;}
+}
+if(tA3>0||tA2>0||t92>0){nX2
+if(cB2.match_type!=AnyParams){if(0||tA2<0||t92<0){nX2}
+return
+true;}
+yV1
+lZ1
+TestParam
+i01
+cG2&xZ2
+lM1&tree
+eA2
+start_at,t9
+info){xT3
+NumConstant:{const
+eZ&t82
+eZ*x01;if(!cW2
+eS1
+imm=yZ3;switch
+iZ2
+modulo
+iY2
+Modulo_None:lC
+Modulo_Radians:imm=fp_mod(imm,y8
+imm<0)imm
+c5
+if(imm>fp_const_pi
+x8())imm-=fp_const_twopi
+x8(nW2
+return
+fp_equal(imm,xF3
+xZ3)cM3
+lY2
+yK3&t82
+xH*x01;if(!x0
+return
+info.SaveOrTestParamHolder
+iZ2
+index,tree)iD2
+const
+xI&t82
+xI*x01;yZ
+GroupFunction){if(!x0
+yK2
+xO1=CalculateGroupFunction(xZ2
+info);
+#ifdef DEBUG_SUBSTITUTIONS
+DumpHashes(xO1)lN1*i01
+void**)&xO1.xJ1
+lN1"\n"
+lN1*i01
+void**)&yZ3
+lN1"\n"
+;DumpHashes(tree)lN1"Comparing "
+;xE3(xO1)lN1" and "
+;xE3(tree)lN1": "
+lN1(xO1
+iA
+tree)?"true"
+:"false"
+)lN1"\n"
+;
+#endif
+return
+xO1
+iA
+tree);}
+else{if(!&*start_at){if(!x0
+if
+xU2!=xF3
+cS
+yI}
+return
+TestParams
+iZ2
+data,tree,start_at,info,false);}
+}
+}
+nX2
+yT1
+iS
+x22
+MatchInfo
+x8
+info;iS()yC3,info(){}
+}
+;iP2
+MatchPositionSpec_PositionalParams:xP1
+iS
+x8>{e13
+iF2
+MatchPositionSpec_PositionalParams(xL3):xM3
+iS
+x8>(n){}
+}
+;e92
+i41
+x22
+i41()yC3{}
+}
+;class
+c0:xP1
+i41>{e13
+i02
+trypos;iF2
+c0(xL3):xM3
+i41>(n),trypos(0){}
+}
+;yV1
+lZ1
+TestParam_AnyWhere
+i01
+cG2&xZ2
+lM1&tree
+eA2
+start_at,t9
+info,yG<bool>&used,bool
+tA1{xN<c0>x6;i02
+lG3
+c0
+n92
+a=x6->trypos;goto
+retry_anywhere_2
+x42
+c0(iT);a=0;}
+eS3
+iT;++a){if(used[a])y81
+retry_anywhere:{lZ1
+r=TestParam(xZ2
+xI2
+lH3);lI3
+used[a]=true;if(tA1
+eT3
+a);x6->trypos=a
+l81
+lZ1(true,&*x6);}
+}
+retry_anywhere_2:if(&*lV1){goto
+retry_anywhere;}
+}
+nX2
+yT1
+y91
+x22
+MatchInfo
+x8
+info;yG<bool>used;iF2
+y91(size_t
+eR3)yC3,info(),used(eR3){}
+}
+;iP2
+MatchPositionSpec_AnyParams:xP1
+y91
+x8>{e13
+iF2
+MatchPositionSpec_AnyParams(xL3,size_t
+m):xM3
+y91
+x8>(n,y91
+x8(m)){}
+}
+;yV1
+lZ1
+TestParams(t0&nM,lM1&tree
+eA2
+start_at,t9
+info,bool
+tA1{if(nM.match_type!=AnyParams){if(xT!=iT
+yI}
+if(!IsLogisticallyPlausibleParamsMatch(nM
+n72{nX2
+switch(nM.match_type
+iY2
+PositionalParams:{xN<cL>x6;i02
+lG3
+cL
+n92
+a=xT-1;goto
+lD1
+x42
+cL(xT);a=0;}
+eS3
+xT;++a){cX2=info;retry_positionalparams:{lZ1
+r=TestParam(cX
+a),xI2
+lH3);lI3
+y81}
+}
+lD1:if(&*lV1){info=cX2;goto
+retry_positionalparams;}
+if(a>0){--a;goto
+lD1;}
+info=(*x6)[0].info
+l81
+false;}
+if(tA1
+for
+iL1
+a=0;a<xT;++a)eT3
+a)l81
+lZ1(true,&*x6)cM3
+SelectedParams:case
+AnyParams:{xN<t6>x6;yG<bool>used(iT);yG<i02>iG2(xT);yG<i02>y02(xT)lO1{const
+cG2
+lF3=cX
+a);iG2[a]=ParamSpec_GetDepCode(lF3);}
+{i02
+b=0
+lO1
+if(iG2[a]!=0)y02[b++]=a
+lO1
+if(iG2[a]==0)y02[b++]=a;}
+i02
+lG3
+t6
+n92
+if(xT==0){a=0;goto
+retry_anyparams_4;}
+a=xT-1;goto
+cY1
+x42
+t6(xT,iT);a=0;if(xT!=0){(*x6)[0].info=info;(*x6)[0].used=used;}
+}
+eS3
+xT;++a){if(a>0){cX2=info;(*x6)[a].used=used;}
+retry_anyparams:{lZ1
+r=TestParam_AnyWhere
+x8(cX
+y02[a]),tree
+lH3,used,tA1;lI3
+y81}
+}
+cY1:if(&*lV1){info=cX2;used=(*x6)[a].used;goto
+retry_anyparams;}
+cZ1:if(a>0){--a;goto
+cY1;}
+info=(*x6)[0].info
+l81
+false;}
+retry_anyparams_4:if(nM.n2!=0){if(!TopLevel||!info.HasRestHolder(nM.n2)){yG
+nV1
+yS2;yS2.nH3
+iT)xS3
+b=0;b<iT;++b){if(xN3)y81
+yS2
+yL
+tree
+lD
+b));xN3=true;if(tA1
+eT3
+b);}
+if(!info.SaveOrTestRestHolder(nM.n2,yS2)){goto
+cZ1;}
+}
+else{lL1&yS2=info.GetRestHolderValues(nM.n2)c23
+0;a<yS2
+eW2
+a){bool
+found=false
+xS3
+b=0;b<iT;++b){if(xN3)y81
+if(yS2[a]iA
+tree
+lD
+b))){xN3=true;if(tA1
+eT3
+b);found=true;nM3}
+if(!found){goto
+cZ1;}
+}
+}
+}
+return
+lZ1(true,xT?&*x6:0)cM3
+GroupFunction:nM3
+nX2}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <algorithm>
+#include <assert.h>
+using
+iO2
+FPoptimizer_CodeTree;using
+iO2
+FPoptimizer_Optimize;iO2{yV1
+yK2
+xQ1
+const
+cG2&xZ2
+t9
+info,bool
+inner=true){xT3
+NumConstant:{const
+eZ&t82
+eZ*x01
+l81
+CodeTreeImmed
+iZ2
+xZ3)cM3
+lY2
+yK3&t82
+xH*x01
+l81
+info.GetParamHolderValue
+iZ2
+index)iD2
+const
+xI&t82
+xI*x01
+yJ
+tree;tH
+xF3
+cS)xS3
+a=0;a<xF3
+data
+xY2;++a)nG1
+nparam=xQ1
+e01
+x8
+iZ2
+data.param_list,a),info,true
+tT
+yA
+nparam);}
+if
+iZ2
+data.n2!=0){yG
+nV1
+trees(info.GetRestHolderValues
+iZ2
+data.n2)tT.AddParamsMove(trees);if(iT==1){assert(tree.tU3()==cAdd tI3()==cMul tI3()==cMin tI3()==cMax tI3()==cAnd tI3()==cOr tI3()==cAbsAnd tI3()==cAbsOr);tree.xO2
+0));}
+tP1
+iT==0){switch
+xU2
+iY2
+cAdd:case
+cOr:tree=nB1
+0));lC
+cMul:case
+cAnd:tree=nB1
+1));default:nM3}
+}
+if(inner)tree
+x02
+l81
+tree;}
+}
+return
+yK2();}
+}
+iO2
+FPoptimizer_Optimize{xB1
+SynthesizeRule
+eX3
+yK2&tree,t9
+info){switch(rule.ruletype
+iY2
+ProduceNewTree:{tree.Become(xQ1
+e01
+x21
+0),info,false)nW2
+case
+ReplaceParams:default:{yG<i02>list=info.GetMatchedParamIndexes();std::sort(list.i62
+list.end())c23
+list
+yA3;a-->0;)tree.iH1
+list[a])xS3
+a=0;a<rule.repl_param_count;++a)nG1
+nparam=xQ1
+e01
+x21
+a),info,true
+tT
+yA
+nparam);}
+nM3}
+}
+}
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+#include <sstream>
+#include <cstring>
+xQ
+using
+iO2
+l41;using
+iO2
+FPoptimizer_CodeTree;using
+iO2
+FPoptimizer_Optimize;iO2
+l41{xB1
+DumpMatch
+eX3
+lM1&tree,const
+t9
+info,bool
+DidMatch,std::ostream&o){DumpMatch
+t81,DidMatch?tZ3"match"
+:tZ3"mismatch"
+,o);}
+xB1
+DumpMatch
+eX3
+lM1&tree,const
+t9
+info,const
+char*eY3,std::ostream&o){static
+const
+char
+ParamHolderNames[][2]={"%"
+,"&"
+,"x"
+,"y"
+,"z"
+,"a"
+,"b"
+,"c"
+}
+;o<<eY3<<" (rule "
+<<(&rule-grammar_rules)<<")"
+<<":\n  Pattern    : "
+;{cG2
+tmp;tmp.first=SubFunction;xI
+tmp2;tmp2.data=rule
+nT2;tmp
+eE3=i01
+void*)&tmp2;DumpParam
+x8(tmp,o);}
+o<<"\n  Replacement: "
+;DumpParams
+x21
+rule.repl_param_count,o);o<<"\n"
+;o<<"  Tree       : "
+;xE3(tree,o);o<<"\n"
+;if(!std::strcmp(eY3,tZ3"match"
+))DumpHashes(tree,o)c23
+0;a<i33
+eW2
+a){if(!i33[a].iA1
+y81
+o<<"           "
+<<ParamHolderNames[a]<<" = "
+;xE3(i33[a],o);o<<"\n"
+;}
+eW3
+info.lQ
+eW2
+b){if(!eH2
+first)y81
+for
+xK2
+0;a<eH2
+second
+eW2
+a){o<<"         <"
+<<b<<"> = "
+;xE3(eH2
+second[a],o);o<<std::endl;}
+}
+o<<std::flush;}
+}
+#endif
+#include <list>
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+iO2{xG1
+MarkIncompletes(x2){if(tree.Is_Incompletely_Hashed(iF1;bool
+i51
+i13
+for
+yS
+i51|=MarkIncompletes
+nW1
+a));if(i51)tree.Mark_Incompletely_Hashed()l81
+i51;}
+xB1
+FixIncompletes(x2){if(tree.Is_Incompletely_Hashed()){for
+yS
+FixIncompletes
+nW1
+a)tT
+x02;}
+}
+}
+iO2
+FPoptimizer_CodeTree{lA
+Sort()cX3
+Sort();}
+lA
+Rehash(bool
+constantfolding){if(constantfolding)ConstantFolding(*this);else
+Sort();data
+xB
+yV1
+l11{c2
+e62
+eZ3
+nP3=0;
+#if 0
+long
+double
+value=Value;eB=crc32::calc(i01
+i02
+char*)&value,xK3
+value));key^=(key<<24);
+#elif 0
+union{e92{i02
+char
+filler1[16];eS1
+v;i02
+char
+filler2[16];}
+buf2;e92{i02
+char
+filler3[xK3
+eS1)+16-x
+K3
+iC1)];eB;}
+buf1;}
+data;memset(&data,0,xK3
+data));data.buf2.v=Value;eB=data.buf1.key;
+#else
+int
+cE2;eS1
+lQ2=std::frexp(Value,&cE2);eB=iL1(cE2+0x8000)&0xFFFF);if(lQ2<0){lQ2=-lQ2;key=key^0xFFFF;}
+else
+key+=0x10000;lQ2-=yF3;key<<=39;key|=iC1((lQ2+lQ2)*eS1(1u<<31))<<8;
+#endif
+iU
+tM
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+n73<>l11<long>{c2
+long
+eZ3
+eB=Value;iU
+tM
+#endif
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+n73<>l11<GmpInt>{c2
+const
+GmpInt&eZ3
+eB=Value.toInt();iU
+tM
+#endif
+xB1
+nO2
+x8::Recalculate_Hash_NoRecursion(){fphash_t
+iU(iC1(Opcode)<<56,Opcode*tM3(0x1131462E270012B));Depth=1;switch(Opcode
+iY2
+cImmed:{ImmedHashGenerator
+x8::MakeHash(iU,Value
+nW2
+case
+iE2:{nP3|=eC<<48
+eC2((eC)*11)^tM3(0x3A83A83A83A83A0);nM3
+case
+cFCall:case
+cPCall:{nP3|=eC<<48
+eC2((~eC)*7)^3456789;}
+default:{size_t
+eM1=0
+c23
+0;a<c93
+eW2
+a){if(c93[a].xT2>eM1)eM1=c93[a].xT2;nP3+=((c93[a]eE2
+hash1*(a+1))>>12)eC2
+c93[a]eE2
+hash1
+eC2(3)*tM3(0x9ABCD801357);iU.hash2*=tM3(0xECADB912345)eC2(~c93[a]eE2
+hash2)^4567890;}
+Depth+=eM1;}
+}
+if(Hash!=iU){Hash=iU;iK1=0;}
+}
+lA
+FixIncompleteHashes(){MarkIncompletes(*this);FixIncompletes(*this);}
+}
+#endif
+#include <cmath>
+#include <list>
+#include <cassert>
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+iO2{using
+iO2
+FPoptimizer_CodeTree;xG1
+x31
+lM1&tree,long
+count,const
+yV2
+SequenceOpCode
+x8&eQ,yW2&synth,size_t
+max_bytecode_grow_length);static
+const
+e92
+SinCosTanDataType{OPCODE
+whichopcode;OPCODE
+inverse_opcode;enum{nominator,denominator,inverse_nominator,inverse_denominator}
+;OPCODE
+codes[4];}
+SinCosTanData[12]={{cTan,cCot,{cSin,cCos,cCsc,cSec}
+}
+,{cCot,cCot,{cCos,cSin,cSec,cCsc}
+}
+,{cCos,cSec,{cSin,cTan,cCsc,cCot}
+}
+,{cSec,cCos,{cTan,cSin,cCot,cCsc}
+}
+,{cSin,cCsc,{cCos,cCot,cSec,cTan}
+}
+,{cCsc,cSin,{cCot,cCos,cTan,cSec}
+}
+,{yT2{cSinh,cH3
+yY2,{cSinh,cNop,{yT2
+cNop,cCosh}
+}
+,{cH3
+cNop,{cSinh,yT2
+cNop}
+}
+,{cNop,cTanh,{cH3
+cSinh,yY2,{cNop,cSinh,{cNop,cTanh,cH3
+cNop}
+}
+,{cNop,cH3{cTanh,cSinh,yY2}
+;}
+iO2
+FPoptimizer_CodeTree{lA
+SynthesizeByteCode(yG<i02>&nN,yG
+x8&Immed,size_t&stacktop_max){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Making bytecode for:\n"
+;iO
+#endif
+while(RecreateInversionsAndNegations()){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"One change issued, produced:\n"
+;iO
+#endif
+FixIncompleteHashes();}
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Actually synthesizing, after recreating inv/neg:\n"
+;iO
+#endif
+yW2
+synth;SynthesizeByteCode(synth,false
+eU3.Pull(nN,Immed,stacktop_max);}
+lA
+SynthesizeByteCode(yW2&synth,bool
+MustPopTemps)const{xR1*this)){return;}
+for
+xK2
+0;a<12;++a){const
+SinCosTanDataType&data=SinCosTanData[a];if(data.whichopcode!=cNop){if(lM2!=data.whichopcode)y81
+yL2
+lJ3;lJ3.lI1
+lJ3
+tU
+data.inverse_opcode);lJ3.y12);xR1
+lJ3)){synth.l21
+else{if(lM2!=cInv)y81
+if(GetParam(0)nE!=data.inverse_opcode)y81
+xR1
+GetParam(0))){synth.l21
+size_t
+found[4];eW3
+4;++b){yL2
+tree;if(data.t03]==cNop){tH
+cInv);yL2
+lK3;lK3.lI1
+lK3
+tU
+data.t03^2]);lK3.y12
+tT
+yA
+lK3);}
+else{tree.lI1
+tH
+data.t03]);}
+tree.y12);found[b]t13
+e33(tree);}
+if(found[data.y22!=tG
+i61
+yK
+y22);lJ1
+i61);lK1
+cDiv
+nL1
+y22!=tG
+iV
+yK
+y22);lJ1
+iV);lK1
+cMul
+nL1
+lS1!=tG
+iV
+yK
+lS1);lJ1
+iV);lK1
+cRDiv
+nL1
+lS1!=tG
+i61
+yK
+lS1);lJ1
+i61);lK1
+cMul,2,1
+eU3.l21
+size_t
+n_subexpressions_synthesized=SynthCommonSubExpressions(synth);switch(lM2
+iY2
+iE2:synth.PushVar(GetVar());lC
+cImmed:yX2
+xJ1);lC
+cAdd:case
+cMul:case
+cMin:case
+cMax:case
+cAnd:case
+cOr:case
+cAbsAnd:case
+cAbsOr:{if(lM2==cMul){bool
+xU3
+i13
+c3
+lT1
+y21&&isLongInteger(lT1.xJ1)){yW1=makeLongInteger(lT1.xJ1);yL2
+tmp(*this,typename
+yL2::CloneTag());tmp
+cP3
+tmp
+x02;if(x31
+tmp,value,yV2
+eX1
+x8::AddSequence,synth,MAX_MULI_BYTECODE_LENGTH)){xU3=true;nM3}
+}
+if(xU3)nM3
+int
+yA1=0;yG<bool>done(GetParamCount(),false);yL2
+iE;iE
+tU
+lM2);for(;;){bool
+found
+i13
+c3
+done[a])y81
+if(synth.IsStackTop(lT1)){found=true;done[a]=true;lT1.nB
+iE
+eT
+lT1);if(++yA1>1){synth
+c4
+2);iE.y12
+eU3.yZ2
+iE);yA1=yA1-2+1;}
+}
+}
+if(!found)nM3
+c3
+done[a])y81
+lT1.nB
+iE
+eT
+lT1);if(++yA1>1){synth
+c4
+2);iE.y12
+eU3.yZ2
+iE);yA1=yA1-2+1;}
+}
+if(yA1==0){switch(lM2
+iY2
+cAdd:case
+cOr:case
+cAbsOr:yX2
+0);lC
+cMul:case
+cAnd:case
+cAbsAnd:yX2
+1);lC
+cMin:case
+cMax:yX2
+0);break;default:nM3++yA1;}
+assert(n_stacked==1);nM3
+case
+cPow:{iQ2
+p0
+tW2
+0);iQ2
+p1
+tW2
+1);if(!p1
+y21||!isLongInteger
+n03)||!x31
+p0,makeLongInteger
+n03),yV2
+eX1
+x8::MulSequence,synth,MAX_POWI_BYTECODE_LENGTH)){p0.nB
+p1
+t33
+c4
+2);c91
+cIf:case
+i03:{typename
+yW2::IfData
+yJ2;GetParam(0)t33.SynthIfStep1(yJ2,lM2);GetParam(1)t33.SynthIfStep2(yJ2);GetParam(2)t33.SynthIfStep3(yJ2
+nW2
+case
+cFCall:case
+cPCall:{for
+xK2
+0;a<cN3++a)lT1
+t33
+c4
+iL1)GetParamCount());lK1
+yM|GetFuncNo(),0,0
+nW2
+default:{for
+xK2
+0;a<cN3++a)lT1
+t33
+c4
+iL1)GetParamCount()nW2}
+synth.yZ2*this);if(MustPopTemps&&n_subexpressions_synthesized>0){size_t
+top
+t13
+GetStackTop(eU3.DoPopNMov(top-1-n_subexpressions_synthesized,top-1);}
+}
+}
+iO2{xG1
+x31
+lM1&tree,long
+count,const
+yV2
+SequenceOpCode
+x8&eQ,yW2&synth,size_t
+max_bytecode_grow_length){if
+cR3!=0){yW2
+backup=synth;tree.nB
+size_t
+bytecodesize_backup
+t13
+GetByteCodeSize();yV2
+x31
+count
+eR2
+size_t
+bytecode_grow_amount
+t13
+GetByteCodeSize()-bytecodesize_backup;if(bytecode_grow_amount>max_bytecode_grow_length){synth=backup
+l81
+false;}
+return
+true;}
+else{yV2
+x31
+count,eQ,synth)nS2}
+}
+#endif
+#include <cmath>
+#include <cassert>
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+iO2{using
+iO2
+FPoptimizer_CodeTree;
+#define FactorStack yG
+const
+e92
+PowiMuliType{i02
+opcode_square;i02
+opcode_cumulate;i02
+opcode_invert;i02
+opcode_half;i02
+opcode_invhalf;}
+iseq_powi={cSqr,cMul,cInv,cSqrt,cRSqrt}
+,iseq_muli={i21,cAdd,cNeg,i21,i21}
+;yB1
+cF1
+const
+PowiMuliType&xV3,const
+yG<i02>&nA2,l92&stack){eS1
+cY3
+1);while(IP<limit){if(xW3
+xV3.opcode_square){if(!eY2
+cZ3
+2;e4
+opcode_invert){result=-result;e4
+opcode_half){if(result>eS1(0)&&isEvenInteger(cZ3
+yF3;e4
+opcode_invhalf){if(result>eS1(0)&&isEvenInteger(cZ3
+eS1(-0.5);++IP;y81}
+size_t
+nB2=IP;eS1
+lhs(1);if(xW3
+cFetch){lC1=yL3;if(index<y1||size_t(index-y1)>=stack
+yA3){IP=nB2;nM3
+lhs=stack[index-y1];goto
+y32;}
+if(xW3
+cDup){lhs=result;goto
+y32;y32:y63
+result);++IP;eS1
+subexponent=cF1
+xV3
+lQ1
+if(IP>=limit||nN[IP]!=xV3.opcode_cumulate){IP=nB2;nM3++IP;stack.pop_back();result+=lhs*subexponent;y81}
+nM3
+return
+result;}
+yB1
+ParsePowiSequence
+i01
+yG<i02>&nA2){l92
+stack;y63
+eS1(1))l81
+cF1
+iseq_powi
+lQ1}
+yB1
+ParseMuliSequence
+i01
+yG<i02>&nA2){l92
+stack;y63
+eS1(1))l81
+cF1
+iseq_muli
+lQ1}
+iP2
+CodeTreeParserData{e13
+iF2
+CodeTreeParserData(bool
+k_powi):stack(),clones(),keep_powi(k_powi){}
+void
+Eat(size_t
+eR3,OPCODE
+opcode
+xX3;xK
+tU
+opcode);yG
+nV1
+cB2=Pop(eR3);xK
+tI1
+cB2);if(!keep_powi)switch(opcode
+iY2
+cTanh:nG1
+sinh,cosh;sinh
+tU
+cSinh);sinh
+eT
+xK
+xY3
+sinh
+x02;cosh
+tU
+cCosh);cosh
+yA
+xK
+xY3
+cosh
+i72
+pow
+yB2
+yA
+cosh);pow
+yT
+eS1(-1)));pow
+x02;xK
+tU
+y13.nC1
+0,sinh);xK
+yA
+pow
+nW2
+case
+cTan:nG1
+sin,cos;sin
+tU
+cSin);sin
+eT
+xK
+xY3
+sin
+x02;cos
+tU
+cCos);cos
+yA
+xK
+xY3
+cos
+i72
+pow
+yB2
+yA
+cos);pow
+yT
+eS1(-1)));pow
+x02;xK
+tU
+y13.nC1
+0,sin);xK
+yA
+pow
+nW2
+case
+cPow:{lM1&p0=xK
+lD
+0);lM1&p1=xK
+lD
+1);if(p1
+nE==cAdd){yG
+nV1
+n83(p1.GetParamCount())c23
+0;a<p1.cN3++a)nG1
+pow
+yB2
+eT
+p0);pow
+eT
+p1
+lD
+a));pow
+x02;n83[a
+t23
+pow);}
+xK
+tU
+y13
+tI1
+n83);}
+nM3
+default:nM3
+xK.Rehash(!keep_powi);i71,false);
+#ifdef DEBUG_SUBSTITUTIONS
+lC2<<eR3<<", "
+<<FP_GetOpcodeName(opcode)<<"->"
+<<FP_GetOpcodeName(xK
+nE)<<": "
+tP3
+xK)tW
+xK);
+#endif
+y63
+xK
+iR2
+EatFunc(size_t
+eR3,OPCODE
+opcode,i02
+funcno
+xX3=CodeTreeFuncOp
+x8(opcode,funcno);yG
+nV1
+cB2=Pop(eR3);xK
+tI1
+cB2);xK.y12);
+#ifdef DEBUG_SUBSTITUTIONS
+lC2<<eR3<<", "
+tP3
+xK)tW
+xK);
+#endif
+i71);y63
+xK
+iR2
+AddConst(yF1
+xX3=CodeTreeImmed(value);i71);Push(xK
+iR2
+AddVar
+iL1
+varno
+xX3=CodeTreeVar
+x8(varno);i71);Push(xK
+iR2
+SwapLastTwoInStack(){y73
+1
+t23
+y73
+2]iR2
+Dup(){Fetch
+lB2
+1
+iR2
+Fetch(size_t
+which){Push(stack[which]);}
+nT1
+T>void
+Push(T
+tree){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<tP3
+tree)tW
+tree);
+#endif
+y63
+tree
+iR2
+PopNMov(size_t
+target,size_t
+source){stack[target]=stack[source];stack
+nE3
+target+1);}
+yK2
+y42{clones.clear()yJ
+cY3
+stack.back());stack.resize
+lB2
+1)l81
+result;}
+yG
+nV1
+Pop(size_t
+n_pop){yG
+nV1
+cY3
+n_pop)xS3
+n=0;n<n_pop;++n)result[n
+t23
+y73
+n_pop+n]);
+#ifdef DEBUG_SUBSTITUTIONS
+for(xL3=n_pop;n-->0;){lC2;xE3(result[n])tW
+result[n]);}
+#endif
+stack.resize
+lB2
+n_pop)l81
+result;}
+size_t
+GetStackTop(n61
+stack
+yA3;}
+private:void
+FindClone(yK2&,bool=true){return;}
+private:yG
+nV1
+stack;std::multimap<fphash_t,yK2>clones;bool
+keep_powi;private:CodeTreeParserData
+i01
+CodeTreeParserData&);CodeTreeParserData&e31=i01
+CodeTreeParserData&);}
+;yT1
+IfInfo
+nG1
+cU2
+yJ
+thenbranch;size_t
+endif_location;IfInfo():cU2(),thenbranch(),endif_location(){}
+}
+;}
+iO2
+FPoptimizer_CodeTree{lA
+GenerateFrom
+i01
+yG<i02>&nN,const
+yG
+x8&Immed,const
+typename
+FunctionParserBase
+x8::Data&cJ3,bool
+keep_powi){yG
+nV1
+nK2;nK2.nH3
+cJ3.mVariablesAmount)xS3
+n=0;n<cJ3.mVariablesAmount;++n){nK2
+yL
+CodeTreeVar
+x8(n+iE2));}
+GenerateFrom(nN,Immed,cJ3,nK2,keep_powi);}
+lA
+GenerateFrom
+i01
+yG<i02>&nN,const
+yG
+x8&Immed,const
+typename
+FunctionParserBase
+x8::Data&cJ3,const
+i22
+nK2,bool
+keep_powi){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"ENTERS GenerateFrom()\n"
+;
+#endif
+CodeTreeParserData
+x8
+sim(keep_powi);yG<IfInfo
+x8>eN;for(size_t
+IP=0,DP=0;;++IP){tO2:while(!eN
+cQ3&&(eN.eD==IP||(IP<nN
+yA3&&xW3
+cJump&&eN.e11.iA1)){yL2
+elsebranch=sim.y42
+yG3
+eN.back().cU2)yG3
+eN.e11)yG3
+elsebranch);iJ
+3,cIf);eN.pop_back();}
+if(IP>=nN
+yA3)break;i02
+opcode=nN[IP];if((opcode==cSqr||opcode==cDup||(opcode==cInv&&!IsIntType
+x8::result)||opcode==cNeg||opcode==cSqrt||opcode==cRSqrt||opcode==cFetch)){size_t
+was_ip=IP;eS1
+cE2=ParsePowiSequence
+x8(nN,IP,eN
+cQ3?nN
+yA3:eN.eD,sim.x5
+1);if(cE2!=1.0){x9
+cE2)yJ3;goto
+tO2;}
+if(opcode==cDup||opcode==cFetch||opcode==cNeg){eS1
+xD2=ParseMuliSequence
+x8(nN,IP,eN
+cQ3?nN
+yA3:eN.eD,sim.x5
+1);if(xD2!=1.0){x9
+xD2)yE
+cMul);goto
+tO2;}
+}
+IP=was_ip;}
+if(lD2>=iE2){sim.Push(nK2[opcode-iE2]);}
+else{switch(lD2
+iY2
+cIf:case
+i03:{eN
+nE3
+eN
+yA3+1);yL2
+res(sim.y42);eN.back().cU2.swap(res);eN.eD=nN
+yA3;IP+=2;y81}
+case
+cJump:{yL2
+res(sim.y42);eN.e11.swap(res);eN.eD=nN[IP+1]+1;IP+=2;y81}
+case
+cImmed:x9
+Immed[DP++]);lC
+cDup:sim.Dup();lC
+cNop:lC
+cFCall:{i02
+funcno=yL3;assert(funcno<fpdata.mFuncPtrs.size());i02
+cB2=cJ3.mFuncPtrs
+yD3
+mParams;sim.EatFunc(cB2,lD2,funcno
+nW2
+case
+cPCall:{i02
+funcno=yL3;assert(funcno<fpdata.tQ3.size());const
+FunctionParserBase
+x8&p=*cJ3.tQ3
+yD3
+mParserPtr;i02
+cB2=cJ3.tQ3
+yD3
+mParams;yG<yL2>paramlist=sim.Pop(cB2);yL2
+tP2;tP2.GenerateFrom(p.mData->mByteCode,p.mData->mImmed,*p.mData,paramlist)yG3
+tP2
+nW2
+case
+cInv:x9
+1
+nY2
+cDiv);lC
+cNeg:yE3
+cNeg);break;x9
+0
+nY2
+cSub);lC
+cSqr:x9
+2
+e21
+cSqrt:x9
+yF3
+e21
+cRSqrt:x9
+eS1(-0.5)e21
+cCbrt:x9
+eS1(1)/eS1(3)e21
+cDeg:x9
+fp_const_rad_to_deg
+x8
+cI1
+cRad:x9
+fp_const_deg_to_rad
+x8
+cI1
+cExp:iF)goto
+yI3;x9
+fp_const_e
+x8()nY2
+cPow);lC
+cExp2:iF)goto
+yI3;x9
+2.0
+nY2
+cPow);lC
+cCot:yE3
+cTan);iF)nY
+cCsc:yE3
+cSin);iF)nY
+cSec:yE3
+cCos);iF)nY
+cInt:
+#ifndef __x86_64
+iF){yE3
+cInt
+nW2
+#endif
+x9
+yF3)lL3
+yE3
+cFloor);lC
+cLog10:yE3
+yH3
+fp_const_log10inv
+x8
+cI1
+cLog2:yE3
+yH3
+fp_const_log2inv
+x8
+cI1
+cLog2by:cK3
+yE3
+yH3
+fp_const_log2inv
+x8());iJ
+3,cMul);lC
+cHypot:x9
+2)yJ3;cK3
+x9
+2)yJ3
+lL3
+x9
+yF3
+e21
+cSinCos:sim.Dup();yE3
+cSin);cK3
+yE3
+cCos);lC
+cRSub:cK3
+case
+cSub:iF){iJ
+2,cSub
+nW2
+x9-1)yE
+cMul)lL3
+lC
+cRDiv:cK3
+case
+cDiv:iF||IsIntType
+x8::result){iJ
+2,cDiv
+nW2
+x9-1)yJ3
+yE
+cMul);lC
+cAdd:case
+cMul:case
+cMod:case
+cPow:case
+cEqual:case
+cLess:case
+cGreater:case
+t71:case
+cLessOrEq:case
+cGreaterOrEq:case
+cAnd:case
+cOr:case
+cAbsAnd:case
+cAbsOr:iJ
+2,xS1
+lC
+cNot:case
+cNotNot:case
+yR3:case
+cAbsNotNot:yE3
+xS1
+lC
+cFetch:sim.Fetch(yL3);lC
+cPopNMov:{i02
+stackOffs_target=yL3;i02
+stackOffs_source=yL3;sim.PopNMov(stackOffs_target,stackOffs_source
+nW2
+#ifndef FP_DISABLE_EVAL
+case
+cEval:{size_t
+paramcount=cJ3.mVariablesAmount;iJ
+paramcount,xS1
+nM3
+#endif
+default:yI3:;i02
+funcno=opcode-cAbs;assert(funcno<FUNC_AMOUNT);const
+FuncDefinition&func=Functions[funcno];iJ
+func.cB2,xS1
+nM3}
+}
+Become(sim.y42);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Produced tree:\n"
+;iO
+#endif
+}
+}
+#endif
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <assert.h>
+#define FP_MUL_COMBINE_EXPONENTS
+iO2{xQ
+using
+iO2
+FPoptimizer_CodeTree;yV1
+static
+void
+AdoptChildrenWithSameOpcode(eR{
+#ifdef DEBUG_SUBSTITUTIONS
+bool
+lR2
+i13
+#endif
+for
+xU
+if
+nW1
+a)nE==tree
+nE){
+#ifdef DEBUG_SUBSTITUTIONS
+if(!lR2){std::cout<<"Before assimilation: "
+eS
+lR2=true;}
+#endif
+tree.AddParamsMove
+nW1
+a).GetUniqueRef().iE1),a);}
+#ifdef DEBUG_SUBSTITUTIONS
+if(lR2){std::cout<<"After assimilation:   "
+eS}
+#endif
+}
+}
+iO2
+FPoptimizer_CodeTree{xB1
+ConstantFolding(eR{tree.Sort();
+#ifdef DEBUG_SUBSTITUTIONS
+void*yM3=0
+lN1"["
+<<(&yM3)<<"]Runs ConstantFolding for: "
+eS
+DumpHashes(tree);
+#endif
+if(false){redo:;tree.Sort();
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"["
+<<(&yM3)<<"]Re-runs ConstantFolding: "
+eS
+DumpHashes(tree);
+#endif
+}
+if
+xU2!=cImmed){range
+x8
+p=iM
+tree);if(p
+y41
+p
+i0&&p.min==p.max)lL
+p.min)n5}
+if(false){ReplaceTreeWithOne
+xP3
+ReplaceWithImmed(eS1(1));goto
+do_return;ReplaceTreeWithZero
+xP3
+ReplaceWithImmed(eS1(0));goto
+do_return;ReplaceTreeWithParam0:
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before replace: "
+lN1
+std::hex<<'['<<tree
+eE2
+hash1<<','<<tree
+eE2
+hash2<<']'<<std::dec
+eS
+#endif
+tree.xO2
+0));
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After replace: "
+lN1
+std::hex<<'['<<tree
+eE2
+hash1<<','<<tree
+eE2
+hash2<<']'<<std::dec
+eS
+#endif
+e5
+yN3
+xU2
+iY2
+cImmed:lC
+iE2:lC
+cAnd:case
+cAbsAnd
+cP
+bool
+cE
+i13
+for
+xU{if(!y93
+a)))cE=true;yQ3
+a),cV2
+cAbsAnd)iY2
+yO3:yP3
+IsAlways:nF1);lC
+lX1
+yN3(iT
+iY2
+0
+tY
+1:tH
+cV2
+cAnd?cNotNot:cAbsNotNot);e5
+default:if
+xU2==cAnd||!cE)if(ConstantFolding_AndLogic
+y83
+c91
+cOr:case
+cAbsOr
+cP
+bool
+cE
+i13
+for
+xU{if(!y93
+a)))cE=true;yQ3
+a),cV2
+cAbsOr)iY2
+IsAlways
+tY
+yO3:nF1);lC
+lX1
+yN3(iT
+iY2
+0:yP3
+1:tH
+cV2
+cOr?cNotNot:cAbsNotNot);e5
+default:if
+xU2==cOr||!cE)if(ConstantFolding_OrLogic
+y83
+c91
+cNot:case
+yR3:{i02
+n21
+0;switch
+nW1
+0)nE
+iY2
+cEqual:n21
+t71;lC
+t71:n21
+cEqual;lC
+cLess:n21
+cGreaterOrEq;lC
+cGreater:n21
+cLessOrEq;lC
+cLessOrEq:n21
+cGreater;lC
+cGreaterOrEq:n21
+cLess;lC
+cNotNot:n21
+cNot;lC
+cNot:n21
+cNotNot;lC
+yR3:n21
+cAbsNotNot;lC
+cAbsNotNot:n21
+yR3;break;default:nM3
+if(opposite){tH
+OPCODE(opposite)tT.SetParamsMove
+nW1
+0).GetUniqueRef().iE1));e5
+yN3(tX
+0),tree
+cG1)tF1
+yP3
+yO3
+tY
+lX1
+if
+xU2==cNot&&GetPositivityInfo
+nW1
+0))==IsAlways)tH
+yR3);l23
+nE==cIf||e72
+nE==i03)nG1
+iH2
+cL2
+0);lM1&ifp1=iH2
+lD
+1);lM1&ifp2=iH2
+lD
+2);if(ifp1
+nE==cNot||ifp1
+cG1{tree.x1
+ifp1
+nE==cNot?cNotNot:cAbsNotNot);tQ2
+lD
+0))yC1)yS3
+xQ2
+yT3)tV
+if(ifp2
+nE==cNot||ifp2
+cG1{tree.x1
+tree
+nE);tQ2)yC1)yS3
+tU
+ifp2
+nE==cNot?cNotNot:cAbsNotNot);yT3
+lD
+0))tV
+c91
+cNotNot:case
+cAbsNotNot:{if(y93
+0)))lN3
+yQ3
+0),cV2
+cAbsNotNot)iY2
+yO3:yP3
+IsAlways
+tY
+lX1
+if
+xU2==cNotNot&&GetPositivityInfo
+nW1
+0))==IsAlways)tH
+cAbsNotNot);l23
+nE==cIf||e72
+nE==i03)nG1
+iH2
+cL2
+0);lM1&ifp1=iH2
+lD
+1);lM1&ifp2=iH2
+lD
+2);if(ifp1
+nE==cNot||ifp1
+cG1{tree.SetParam(0,iH2
+lD
+0)tT
+eT
+ifp1)yS3
+xQ2
+yT3)tV
+if(ifp2
+nE==cNot||ifp2
+cG1{tree.x1
+tree
+nE);tQ2)yC1
+tT
+eT
+ifp2);tH
+iH2
+nE);e5}
+c91
+cIf:case
+i03:{if(ConstantFolding_IfOperations
+y83
+nM3
+case
+cMul:{NowWeAreMulGroup:;AdoptChildrenWithSameOpcode(tree);eS1
+nN1=eS1(1);size_t
+i81=0;bool
+nO1=false
+eV3
+if(!xI2
+y21)y81
+eS1
+immed=xI2.xJ1;if(immed==eS1(0))tZ
+nN1*=immed;++i81;}
+if(i81>1||(i81==1&&fp_equal(nN1,nY3)nO1=true;if(nO1){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"cMul: Will add new "
+tR3
+nN1<<"\n"
+;
+#endif
+for
+xU
+if
+nW1
+a)y21){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<" - For that, deleting "
+tR3
+xI2.xJ1
+lN1"\n"
+;
+#endif
+lM3!fp_equal(nN1,nY3
+tree
+eT
+cU1
+nN1));yN3(iT
+iY2
+0
+tY
+1:lN3
+default:if(ConstantFolding_MulGrouping
+y83
+if(ConstantFolding_MulLogicItems
+y83
+c91
+cAdd
+cP
+eS1
+lE2=0.0;size_t
+i81=0;bool
+nO1=false
+eV3
+if(!xI2
+y21)y81
+eS1
+immed=xI2.xJ1;lE2+=immed;++i81;}
+if(i81>1||(i81==1&&lE2==0.0))nO1=true;if(nO1){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"cAdd: Will add new "
+tR3
+lE2<<"\n"
+lN1"In: "
+eS
+#endif
+for
+xU
+if
+nW1
+a)y21){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<" - For that, deleting "
+tR3
+xI2.xJ1
+lN1"\n"
+;
+#endif
+lM3!(lE2==0.0))tree
+eT
+cU1
+lE2));yN3(iT
+iY2
+0:yP3
+1:lN3
+default:if(ConstantFolding_AddGrouping
+y83
+if(ConstantFolding_AddLogicItems
+y83
+c91
+cMin
+cP
+size_t
+y52=0;range
+x8
+e6
+eV3
+while(a+1<iT&&xI2
+iA
+tree
+lD
+a+1)))nF1+1);range<nI
+has_max&&(!e6
+i0||(p.max)<e6.max)){e6.max=p.max;e6
+i0=true;y52=a;}
+}
+if(e6
+i0)for
+xU{range<nI
+iV2&&a!=y52&&p.min>=e6.max)lM3
+iT==1){lN3
+c91
+cMax
+cP
+size_t
+y52=0;range
+x8
+t1
+eV3
+while(a+1<iT&&xI2
+iA
+tree
+lD
+a+1)))nF1+1);range<nI
+iV2&&(!t1.iV2||p.min>t1.min)){t1.min=p.min;t1.iV2=true;y52=a;}
+}
+if(t1.iV2){for
+xU{range<nI
+has_max&&a!=y52&&(p.max)<t1.min){nF1);}
+}
+}
+if(iT==1){lN3
+c91
+cEqual:case
+t71:case
+cLess:case
+cGreater:case
+cLessOrEq:case
+cGreaterOrEq:if(ConstantFolding_Comparison
+y83
+lC
+cAbs:{range
+x8
+p0=y6
+0));if(p0
+eN1
+lN3
+if(p0
+i0
+yU3
+tN{tH
+cMul
+tT
+yT
+nY3;goto
+NowWeAreMulGroup;}
+l23
+nE==cMul){lM1&p
+cL2
+0);yG
+nV1
+lO3;yG
+nV1
+c02
+c23
+0;a<p.cN3++a){p0=iM
+p
+lD
+a));if(p0
+eN1{lO3
+yL
+p
+lD
+a));}
+if(p0
+i0
+yU3
+tN{c02
+yL
+p
+lD
+a));}
+}
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Abs: mul group has "
+<<lO3
+yA3<<" pos, "
+<<c02
+yA3<<"neg\n"
+;
+#endif
+if(!lO3
+cQ3||!c02
+cQ3){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"AbsReplace-Before: "
+;xE3(tree)lN1"\n"
+<<std::flush;DumpHashes
+tJ1;
+#endif
+yK2
+cL3;cL3
+tU
+cMul)c23
+0;a<p.cN3++a){p0=iM
+p
+lD
+a));if((p0
+eN1||(p0
+i0
+yU3
+tN){}
+else
+cL3
+eT
+p
+lD
+a));}
+cL3
+i72
+lP3;lP3
+tU
+cAbs);lP3
+yA
+cL3);lP3
+i72
+xW1
+cMul);n83
+yA
+lP3);xX1
+AddParamsMove(lO3);if(!c02
+cQ3){if(c02
+yA3%2)n83
+yT
+eS1(-1)));xX1
+AddParamsMove(c02);}
+tree.Become(n83);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"AbsReplace-After: "
+;xE3
+tJ1
+lN1"\n"
+<<std::flush;DumpHashes
+tJ1;
+#endif
+goto
+NowWeAreMulGroup;}
+}
+nM3
+#define HANDLE_UNARY_CONST_FUNC(funcname) lX)lL funcname(n6))n5
+case
+cLog:tH3(fp_log);l23
+nE==cPow)nG1
+pow
+cL2
+0);if(GetPositivityInfo(pow
+lD
+0))==IsAlways){pow
+lF2
+tI
+tree.lW
+if(GetEvennessInfo(pow
+x03==IsAlways){pow
+lF2
+yJ
+abs;abs
+tU
+cAbs);abs
+yA
+pow
+xY3
+abs
+x02
+tI
+pow.nC1
+0,abs
+tT.lW}
+else
+l23
+nE==cAbs)nG1
+pow
+cL2
+0)lD
+0);if(pow
+nE==cPow){pow
+lF2
+yJ
+abs;abs
+tU
+cAbs);abs
+yA
+pow
+xY3
+abs
+x02
+tI
+pow.nC1
+0,abs
+tT.lW}
+lC
+cAcosh:tH3(fp_acosh);lC
+cAsinh:tH3(fp_asinh);lC
+cAtanh:tH3(fp_atanh);lC
+cAcos:tH3(fp_acos);lC
+cAsin:tH3(fp_asin);lC
+cAtan:tH3(fp_atan);lC
+cCosh:tH3(fp_cosh);lC
+cSinh:tH3(fp_sinh);lC
+cTanh:tH3(fp_tanh);lC
+cSin:tH3(fp_sin);lC
+cCos:tH3(fp_cos);lC
+cTan:tH3(fp_tan);lC
+cCeil:if(n8
+tH3(fp_ceil);lC
+cTrunc:if(n8
+tH3(fp_trunc);lC
+cFloor:if(n8
+tH3(fp_floor);lC
+cInt:if(n8
+tH3(fp_int);lC
+cCbrt:tH3(fp_cbrt);lC
+cSqrt:tH3(fp_sqrt);lC
+cExp:tH3(fp_exp);lC
+cLog2:tH3(fp_log2);lC
+cLog10:tH3(fp_log10);lC
+cLog2by:y2)lL
+fp_log2(n6)*y4
+nN3
+cMod:y2)lL
+fp_mod(n6,y4)nN3
+cAtan2:{range
+x8
+p0
+y5
+p1=y6
+1));lX&&fp_equal(n6,eS1(0))){if(p1
+i0&&(p1.max)<0)lL
+fp_const_pi
+x8())n5
+if(p1
+y41
+p1.min>=0.0)lL
+eS1(0))n5}
+if(nE1
+fp_equal(y4,eS1(0))){if(p0
+i0&&(p0.max)<0)lL-fp_const_pihalf
+x8())n5
+if(p0
+y41
+p0.min>0)lL
+fp_const_pihalf
+x8())n5}
+y2)lL
+fp_atan2(n6,y4))n5
+if((p1
+y41
+p1.min>0.0)||(p1
+i0&&(p1.max)<fp_const_negativezero
+x8()))nG1
+y62;y62
+tU
+cPow);y62
+yA
+tree
+x03;y62
+yT
+eS1(-1)));y62
+i72
+y72;y72
+e53
+y72
+yA
+e72);y72
+yA
+y62);y72
+y3
+cAtan
+tT.nC1
+0,y72
+tW1
+1);c91
+cPow:{if(ConstantFolding_PowOperations
+y83
+nM3
+case
+cDiv:y2&&y4!=0.0)lL
+n6/y4
+nN3
+cInv:lX&&n6!=0.0)lL
+eS1(1)/n6
+nN3
+cSub:y2)lL
+n6-y4
+nN3
+cNeg:lX)lL-n6
+nN3
+cRad:lX)lL
+RadiansToDegrees
+t63
+cDeg:lX)lL
+DegreesToRadians
+t63
+cSqr:lX)lL
+n6*n6
+nN3
+cExp2:tH3(fp_exp2);lC
+cRSqrt:lX)lL
+eS1(1)/fp_sqrt
+t63
+cCot:lX)nQ3=fp_tan(n6)xE
+cSec:lX)nQ3=fp_cos(n6)xE
+cCsc:lX)nQ3=fp_sin(n6)xE
+cHypot:y2)lL
+fp_hypot(n6,y4)nN3
+cRDiv:case
+cRSub:case
+cDup:case
+cFetch:case
+cPopNMov:case
+cSinCos:case
+cNop:case
+cJump:lC
+cPCall:case
+cFCall:case
+cEval:nM3
+do_return:;
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"["
+<<(&yM3)<<"]Done ConstantFolding, result: "
+eS
+DumpHashes(tree);
+#endif
+}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+using
+iO2
+FPoptimizer_CodeTree;iO2{n73<i02
+cY2
+e92
+Comp{}
+;n73<>e92
+Comp<cLess>{n73<lF<yU
+cLessOrEq>{n73<lF<=yU
+cGreater>{n73<lF>yU
+cGreaterOrEq>{n73<lF>=yU
+cEqual>{n73<lF==yU
+t71>{n73<lF!=b;}
+}
+;}
+iO2
+FPoptimizer_CodeTree{c12
+set_abs(){if(!iV2&&!iI2{iV2=yV3}
+tP1!iV2&&max
+t83){iV2=true;min=-max;iJ2
+false;}
+tP1!iV2){iV2=yV3
+iJ2
+false;}
+tP1
+min
+cH1
+nZ2;tP1!iI2{iV2=yV3}
+tP1
+max
+t83)nQ3(-max);max=-min;min=tmp;}
+tP1-min>=max){max=-min;n31}
+else{n31}
+}
+c12
+set_neg(){std::swap(iV2,iI2;std::swap(min,max);min=-min;max=-max;}
+yV
+set_min_if(c31
+if(iV2&&Comp<cY2()(min,v))min=func(min
+t73
+iV2=yW3
+iV2;min=yW3
+min;}
+}
+yV
+set_max_if(c31
+if(has_max&&Comp<cY2()(max,v))max=func(max
+t73
+iJ2
+model
+i0;max=yW3
+max;}
+}
+yV
+set_min_max_if(c31
+set_min_if<cY2(v,func,model);set_max_if<cY2(v,func,model);}
+c12
+set_min(n7
+if(iV2)min=func(min
+t73
+iV2=yW3
+iV2;min=yW3
+min;}
+}
+c12
+set_max(n7
+if(iI2
+max=func(max
+t73
+iJ2
+model
+i0;max=yW3
+max;}
+}
+c12
+y82
+n7
+set_min(func,model);set_max(func,model);}
+yV1
+range
+x8
+iM
+const
+eR
+#ifdef DEBUG_SUBSTITUTIONS_extra_verbose
+{range
+x8
+tmp=CalculateResultBoundaries_do(tree)lN1"Estimated boundaries: "
+;if(tmp.iV2)std::cout<<tmp.min;else
+std::cout<<"-inf"
+lN1" .. "
+;if(tmp
+i0)std::cout<<tmp.max;else
+std::cout<<"+inf"
+lN1": "
+;xE3(tree)lN1
+std::endl
+l81
+tmp;}
+yV1
+range
+x8
+yK2::CalculateResultBoundaries_do
+i01
+eR
+#endif
+{x81
+eO1(-fp_const_pihalf
+x8(),fp_const_pihalf
+x8());x81
+pi_limits(-fp_const_pi
+x8(),fp_const_pi
+x8());x81
+abs_pi_limits(eS1(0),fp_const_pi
+x8());using
+iO2
+std;switch
+xU2
+iY2
+cImmed:nL
+yZ3,yZ3);case
+cAnd:case
+cAbsAnd:case
+cOr:case
+cAbsOr:case
+cNot:case
+yR3:case
+cNotNot:case
+cAbsNotNot:case
+cEqual:case
+t71:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:e83
+0),eS1(1))cM3
+cAbs:lB
+m.set_abs(cY
+cLog:lB
+m.y7
+fp_log
+cY
+cLog2:lB
+m.y7
+fp_log2
+cY
+cLog10:lB
+m.y7
+fp_log10
+cY
+cAcosh:lB
+m
+nL2
+set_min_max_if<cGreaterOrEq
+lQ3
+fp_acosh
+cY
+cAsinh:lB
+m.y82
+fp_asinh
+cY
+cAtanh:lB
+m
+nL2
+set_min_if<cGreater>(eS1(-1),fp_atanh);m
+nL2
+set_max_if<cLess
+lQ3
+fp_atanh
+cY
+cAcos:lB
+nL(m
+i0&&(m.max)<eS1(1))?fp_acos(m.max):eS1(0),(m
+y41(m.min)>=eS1(-1))?fp_acos(m.min):fp_const_pi
+x8())cM3
+cAsin:lB
+m
+nL2
+set_min_if<cGreater>(eS1(-1),fp_asin,eO1);m
+nL2
+set_max_if<cLess
+lQ3
+fp_asin,eO1
+cY
+cAtan:lB
+m.y82
+fp_atan,eO1
+cY
+cAtan2:{range
+x8
+p0
+y5
+p1=y6
+1));lX&&fp_equal(n6,eS1(0))){return
+abs_pi_limits;}
+if(nE1
+fp_equal(y4,eS1(0))){return
+eO1;}
+return
+pi_limits
+cM3
+cSin:lB
+bool
+x41=!m.iV2||!m
+i0||(m.max-m.min)>=(y8
+x41)e0
+eS1
+min=cZ2
+min,y8
+min
+t83)min
+c5
+eS1
+max=cZ2
+max,y8
+max
+t83)max
+c5
+if(max<min)max
+c5
+bool
+xT1=(min<=fp_const_pihalf
+x8()&&max>=fp_const_pihalf
+x8());bool
+nP1=(min<=cK&&max>=cK);if(xT1&&nP1)e0
+if(nP1)nL
+eS1(-1),lS2
+if(xT1)nL
+y92
+eS1(1));nL
+y92
+lS2}
+case
+cCos:lB
+if(m.iV2)m.min+=fp_const_pihalf
+x8();if(m
+i0)m.max+=fp_const_pihalf
+x8();bool
+x41=!m.iV2||!m
+i0||(m.max-m.min)>=(y8
+x41)e0
+eS1
+min=cZ2
+min,y8
+min
+t83)min
+c5
+eS1
+max=cZ2
+max,y8
+max
+t83)max
+c5
+if(max<min)max
+c5
+bool
+xT1=(min<=fp_const_pihalf
+x8()&&max>=fp_const_pihalf
+x8());bool
+nP1=(min<=cK&&max>=cK);if(xT1&&nP1)e0
+if(nP1)nL
+eS1(-1),lS2
+if(xT1)nL
+y92
+eS1(1));nL
+y92
+lS2}
+case
+cTan:{nL)cM3
+cCeil:lB
+m.c41
+cFloor:lB
+m.eP1
+cY
+cTrunc:lB
+m.eP1);m.c41
+cInt:lB
+m.eP1);m.c41
+cSinh:lB
+m.y82
+fp_sinh
+cY
+cTanh:lB
+m.y82
+fp_tanh,range
+x8(eS1(-y03
+cY
+cCosh:lB
+if(m.iV2){if(m
+i0){if(m.min
+cH1&&m.max
+cH1){m.min
+cM}
+tP1(m.min)t83&&m.max
+cH1)nQ3
+cM
+if(tmp>m.max)m.max=tmp;m.min=eS1(1);}
+else{m.min
+cM
+std::swap(m.min,m.max);}
+}
+else{if(m.min
+cH1){m
+nM2
+m.min=fp_cosh(m.min);}
+else{m
+nM2
+m.min=eS1(1);}
+}
+}
+else{m.iV2=true;m.min=eS1(1);if(m
+i0){m.min=fp_cosh(m.max);m
+nM2}
+else
+m
+nM2}
+return
+m
+cM3
+cIf:case
+i03:{range
+x8
+res1=y6
+1));range
+x8
+res2=y6
+2));if(!res2.iV2)res1.iV2
+i13
+tP1
+res1
+y41(res2.min)<res1.min)res1.min=res2.min;if(!res2
+i0)res1
+nM2
+tP1
+res1
+i0&&(res2.max)>res1.max)res1.max=res2.max
+l81
+res1
+cM3
+cMin:{bool
+iG
+i13
+bool
+iH
+i13
+tB1;x4
+m
+xO3!m.iV2)iG=true;yP1.iV2||(m.min)<i11)i11=m.min;if(!m
+i0)iH=true;yP1
+i0||(m.max)<e63)e63=m.max;}
+if(iG)c42
+iH)tE1
+l81
+yA2
+cMax:{bool
+iG
+i13
+bool
+iH
+i13
+tB1;x4
+m
+xO3!m.iV2)iG=true;yP1.iV2||m.min>i11)i11=m.min;if(!m
+i0)iH=true;yP1
+i0||m.max>e63)e63=m.max;}
+if(iG)c42
+iH)tE1
+l81
+yA2
+cAdd:{tB1(eS1(0),eS1(0));x4
+item
+xO3
+item.iV2)i11+=item.min;else
+c42
+item
+i0)e63+=item.max;else
+tE1;if(!result
+y41!e02)nM3
+if(result
+y41
+e02&&i11>e63)std::swap(i11,e63)l81
+yA2
+cMul:{e92
+Value{enum
+lR3{tR2,i91,PlusInf}
+;lR3
+eF;eS1
+value;Value(lR3
+t):eF(t),value(0){}
+Value(eS1
+v):eF(tR2),value(v){}
+bool
+c22
+n61
+eF==i91||(eF==tR2&&value
+t83
+iR2
+e31*=i01
+Value&rhs){if(eF==tR2&&rhs.eF==tR2)value*=rhs.value;else
+eF=(c22)!=rhs.c22)?i91:PlusInf);}
+i12<i01
+Value&rhs
+n61(eF==i91&&rhs.eF!=i91)||(eF==tR2&&(rhs.eF==PlusInf||(rhs.eF==tR2&&value<rhs.value)));}
+}
+;e92
+yD1{Value
+yC2,yD2;yD1():yC2(Value::PlusInf),yD2(Value::i91){}
+void
+nN2
+Value
+yX3,const
+Value&value2){yX3*=value2;if(yX3<yC2)yC2=yX3;if(yD2<yX3)yD2=yX3;}
+}
+;tB1(eS1(y03;x4
+item
+xO3!item
+y41!item
+i0)nL);Value
+lS3=c32?Value(i11):nC2
+i91);Value
+lT3=e02?Value(e63):nC2
+PlusInf);Value
+lU3=item.iV2?Value(item.min):nC2
+i91);Value
+lV3=item
+i0?Value(item.max):nC2
+PlusInf);yD1
+range;range.nN2
+lS3,lU3
+eN2
+lS3,lV3
+eN2
+lT3,lU3
+eN2
+lT3,lV3);if(range.yC2.eF==Value::tR2)i11=range.yC2.value;else
+c42
+range.yD2.eF==Value::tR2)e63=range.yD2.value;else
+tE1;if(!result
+y41!e02)nM3
+if(result
+y41
+e02&&i11>e63)std::swap(i11,e63)l81
+yA2
+cMod:{range
+x8
+x
+y5
+y=y6
+1));if(y
+i0){if(y.max
+cH1){if(!x.iV2||(x.min)<0)nL-y.max,y.max);else
+nL
+eS1(0),y.max);}
+else{if(!x
+i0||(x.max)>=0)nL
+y.max,-y.max);else
+nL
+y.max,fp_const_negativezero
+x8());}
+}
+else
+nL)cM3
+cPow:{if(nE1
+y4==eS1(0))e83
+y03;}
+lX&&n6==eS1(0))e83
+0),eS1(0));}
+lX&&fp_equal(n6,nY3
+e83
+y03;}
+if(nE1
+y4>0&&GetEvennessInfo
+nW1
+1))==IsAlways)c21
+y4;range
+x8
+tmp
+y5
+result;c32=true;i11=0;if(tmp
+y41
+tmp.min>=0)i11=eG3
+tmp.min,cE2);tP1
+tmp
+i0&&tmp.max<=0)i11=eG3
+tmp.max,cE2);tE1;if(tmp
+y41
+tmp
+i0){e02=true;e63=std::max(fp_abs(tmp.min),fp_abs(tmp.max));e63=eG3
+e63,cE2);}
+return
+result;}
+range
+x8
+p0
+y5
+p1=y6
+1
+eO2
+p0_positivity=(p0
+y41(p0.min)cH1)?IsAlways:(p0
+i0&&(p0.max)t83?yO3:Unknown);TriTruthValue
+c52=GetEvennessInfo
+nW1
+1
+eO2
+t2=Unknown;switch(p0_positivity)tF1
+t2=IsAlways;lC
+yO3:{t2=c52;nM3
+default:switch(c52)tF1
+t2=IsAlways;lC
+yO3:lC
+Unknown:{if(nE1!eY2
+y4)&&y4
+cH1){t2=IsAlways;}
+nM3}
+yN3(t2)tF1{eS1
+n31
+if(p0
+y41
+p1.iV2){min=eG3
+p0.min,p1.min);if(p0.min
+t83&&(!p1
+i0||p1.max
+cH1)&&min
+cH1)n31}
+if(p0
+y41
+p0.min
+cH1&&p0
+i0&&p1
+i0){eS1
+max=eG3
+p0.max,p1.max);if(min>max)std::swap(min,max);nL
+min,max);}
+nL
+min,false)cM3
+yO3:{nL
+false,fp_const_negativezero
+x8());}
+default:{nM3
+c91
+cNeg:lB
+m.set_neg(cY
+cSub
+x7
+cNeg
+y23
+1
+y43
+cAdd);y53;tmp
+yY3
+l81
+lH
+cInv:lV-1
+e12
+cDiv
+x7
+cInv
+y23
+1
+y43
+xU1
+yY3
+l81
+lH
+cRad:{cF
+xU1
+yT
+fp_const_rad_to_deg
+x8(e12
+cDeg:{cF
+xU1
+yT
+fp_const_deg_to_rad
+x8(e12
+cSqr:lV
+2
+e12
+cExp:{cF
+cPow);tmp
+yT
+fp_const_e
+x8()));y53
+l81
+lH
+cExp2:{cF
+cPow);tmp
+yT
+nR3
+y53
+l81
+lH
+cCbrt:lB
+m.y82
+fp_cbrt
+cY
+cSqrt:lB
+if(m.iV2)m.min=(m.min)<0?0:fp_sqrt(m.min);if(m
+i0)m.max=(m.max)<0?0:fp_sqrt(m.max
+cY
+cRSqrt:lV-0.5
+e12
+cHypot:nG1
+xsqr,ysqr,add,sqrt;xsqr
+yC
+0));xsqr
+yT
+nR3
+ysqr
+yC
+1));ysqr
+yT
+nR3
+xsqr
+tU
+cPow);ysqr
+tU
+cPow);add
+yA
+xsqr);add
+yA
+ysqr);add
+tU
+cAdd);sqrt
+yA
+add);sqrt
+tU
+cSqrt)l81
+iM
+sqrt)cM3
+cLog2by
+x7
+cLog2
+y23
+0
+y43
+cMul);tmp
+yY3;tmp
+yC
+1))l81
+lH
+cCot
+x7
+cTan)nG
+lH
+cSec
+x7
+cCos)nG
+lH
+cCsc
+x7
+cSin)nG
+iM
+tmp);}
+lC
+cRDiv:case
+cRSub:case
+cDup:case
+cFetch:case
+cPopNMov:case
+cSinCos:case
+cNop:case
+cJump:case
+iE2:lC
+cPCall:lC
+cFCall:lC
+cEval:nM3
+nL);}
+yV1
+TriTruthValue
+GetIntegerInfo
+i01
+eR{switch
+xU2
+iY2
+cImmed:return
+eY2
+yZ3)?IsAlways:yO3;case
+cFloor:case
+cCeil:case
+cTrunc:case
+cInt:return
+IsAlways;case
+cAnd:case
+cOr:case
+cNot:case
+cNotNot:case
+cEqual:case
+t71:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:return
+IsAlways;case
+cIf:{TriTruthValue
+a=GetIntegerInfo
+nW1
+1
+eO2
+b=GetIntegerInfo
+nW1
+2));if(a==b
+nZ2
+a
+l81
+Unknown
+cM3
+cAdd:case
+cMul:{for
+xU
+if(GetIntegerInfo
+nW1
+a))!=IsAlways
+nZ2
+Unknown
+l81
+IsAlways;}
+default:nM3
+return
+Unknown;}
+xG1
+IsLogicalValue
+i01
+eR{switch
+xU2
+iY2
+cImmed:return
+fp_equal(yZ3,eS1(0))||fp_equal(yZ3,eS1(1));case
+cAnd:case
+cOr:case
+cNot:case
+cNotNot:case
+cAbsAnd:case
+cAbsOr:case
+yR3:case
+cAbsNotNot:case
+cEqual:case
+t71:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:nW
+cMul:{for
+xU
+if(!y93
+a))yI
+return
+true
+cM3
+cIf:case
+i03:{return
+y93
+1))&&y93
+2));}
+default:nM3
+nX2}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+#if defined(__x86_64) || !defined(FP_SUPPORT_CBRT)
+# define CBRT_IS_SLOW
+#endif
+#if defined(DEBUG_POWI) || defined(DEBUG_SUBSTITUTIONS)
+#include <cstdio>
+#endif
+t5{extern
+const
+i02
+char
+powi_table[256];}
+iO2{using
+iO2
+FPoptimizer_CodeTree;xG1
+IsOptimizableUsingPowi(long
+immed,long
+penalty=0){yW2
+synth;synth.PushVar(iE2);size_t
+bytecodesize_backup
+t13
+GetByteCodeSize();yV2
+x31
+immed,yV2
+eX1
+x8::MulSequence,synth);size_t
+bytecode_grow_amount
+t13
+GetByteCodeSize()-bytecodesize_backup
+l81
+bytecode_grow_amount<size_t(MAX_POWI_BYTECODE_LENGTH-penalty);}
+xB1
+ChangeIntoRootChain(yK2&tree,bool
+iK2,long
+tS2,long
+tT2){while(tT2>0){cF
+cCbrt);nZ3);tmp.Rehash(nD2--tT2;}
+while(tS2>0){cF
+cSqrt);if(iK2){tmp
+tU
+cRSqrt);iK2
+i13}
+nZ3);tmp.Rehash(nD2--tS2;}
+if(iK2){cF
+cInv);nZ3
+nD2}
+}
+yT1
+RootPowerTable{static
+const
+eS1
+RootPowers[(1+4)*(1+3)];}
+;yV1
+const
+eS1
+t7(1+4)*(1+3)]={eS1(1)lS
+tB3
+tB3
+2*tB3
+2*2*2)lS
+3
+x32
+2
+x32
+2*2
+x32
+2*2*2
+x32
+2*2*2*2
+x32
+3
+x32
+3*2
+x32
+3*2*2
+x32
+3*2*2*2
+x32
+3*2*2*2*2
+x32
+3*3
+x32
+3*3*2
+x32
+3*3*2*2
+x32
+3*3*2*2*2
+x32
+3*3*2*2*2*2)}
+;e92
+PowiResolver{static
+const
+i02
+MaxSep=4;static
+lX3
+tC3=5;typedef
+int
+c03;typedef
+long
+n63;typedef
+long
+t8;e92
+yE2{yE2():n_int_sqrt(0),n_int_cbrt(0),sep_list(),lY1(0){}
+int
+n_int_sqrt;int
+n_int_cbrt;int
+eW1
+MaxSep];t8
+lY1;}
+;yV1
+static
+yE2
+CreatePowiResult(eS1
+cE2){yE2
+result;c03
+eE=FindIntegerFactor(cE2);if(eE==0){
+#ifdef DEBUG_POWI
+tU2"no factor found for %Lg\n"
+y33);
+#endif
+return
+result;}
+c13=xV1
+cE2,eE);n63
+e22=EvaluateFactorCost(eE,0,0,0)+cH
+c13);int
+tD3=0;int
+tE3=0;int
+lW3=0;
+#ifdef DEBUG_POWI
+tU2"orig = %Lg\n"
+y33);tU2"plain factor = "
+tS3"%ld\n"
+,(int)eE,(long)e22);
+#endif
+for
+iL1
+n_s=0;n_s<MaxSep;++n_s){int
+xC=0;n63
+yE1=e22;c03
+yQ1=eE;for(int
+s=1;s<tC3*4;++s){
+#ifdef CBRT_IS_SLOW
+if(s>=tC3)break;
+#endif
+int
+n_sqrt=s%tC3;int
+n_cbrt=s/tC3;if(n_sqrt+n_cbrt>4)y81
+eS1
+lE1=cE2;lE1-=t7
+s];tH1=FindIntegerFactor(lE1);if(xD2!=0){t8
+xL=xV1
+lE1,xD2);n63
+cost=EvaluateFactorCost(xD2,tD3+n_sqrt,tE3+n_cbrt,lW3+1)+cH
+xL);
+#ifdef DEBUG_POWI
+tU2"Candidate sep %u (%d*sqrt %d*cbrt)factor = "
+tS3"%ld (for %Lg to %ld)\n"
+,s,n_sqrt,n_cbrt,xD2,(long)cost
+x12
+lE1,(long)xL);
+#endif
+if(cost<yE1){xC=s;yQ1=xD2;yE1=cost;}
+}
+}
+if(!xC)break;
+#ifdef DEBUG_POWI
+tU2"CHOSEN sep %u (%d*sqrt %d*cbrt)factor = "
+tS3"%ld, exponent %Lg->%Lg\n"
+,xC,xC%tC3,xC/tC3,yQ1,yE1
+x12(cE2)x12(cE2-t7
+xC]));
+#endif
+tC1
+eW1
+n_s]=xC;cE2-=t7
+xC];tD3+=xC%tC3;tE3+=xC/tC3;e22=yE1;eE=yQ1;lW3+=1;}
+c13=xV1
+cE2,eE);
+#ifdef DEBUG_POWI
+tU2"resulting exponent is %ld (from exponent=%Lg, best_factor=%Lg)\n"
+,c13
+y33
+x12
+eE);
+#endif
+while(eE%2==0){++tC1
+n_int_sqrt;eE/=2;}
+while(eE%3==0){++tC1
+n_int_cbrt;eE/=3;}
+return
+result;}
+private:static
+n63
+cH
+t8
+xL){static
+std::map
+c62
+i7;if(xL<0){n63
+cost=22
+l81
+cost+cH-xL);}
+std::map
+c62::nX3
+i=i7.xE2
+xL);if(i!=i7.cP1
+xL
+nZ2
+i
+cJ2;std::pair
+c62
+cY3
+xL,0.0);n63&cost=tC1
+second;while(xL>1){int
+xD2=0;if(xL<256){xD2=yV2
+powi_table[xL];if(xD2&128)xD2&=127;else
+xD2=0;if(xD2&64)xD2=-(xD2&63)-1;}
+if(xD2){cost+=cH
+xD2);xL/=xD2;y81}
+if(!(xL&1)){xL/=2;cost+=6;}
+else{cost+=7;xL-=1;}
+}
+i7.nT3,result)l81
+cost
+eI2
+t8
+xV1
+yF1,tH1){return
+makeLongInteger(value*eS1(xD2))eI2
+bool
+yG1
+yF1,tH1){eS1
+v=value*eS1(xD2)l81
+isLongInteger(v)eI2
+c03
+FindIntegerFactor(yF1){tH1=(2*2*2*2);
+#ifdef CBRT_IS_SLOW
+#else
+xD2*=(3*3*3);
+#endif
+c03
+result=0;if(yG1
+value,xD2)){result=xD2;while((xD2%2)==0&&yG1
+value,xD2/2))result=xD2/=2;while((xD2%3)==0&&yG1
+value,xD2/3))result=xD2/=3;}
+#ifdef CBRT_IS_SLOW
+if(result==0){if(yG1
+value,3)nZ2
+3;}
+#endif
+return
+result;}
+static
+int
+EvaluateFactorCost(int
+xD2,int
+s,int
+c,int
+nmuls){lX3
+lY3=6;
+#ifdef CBRT_IS_SLOW
+lX3
+e32=25;
+#else
+lX3
+e32=8;
+#endif
+int
+result=s*lY3+c*e32;while(xD2%2==0){xD2/=2;result+=lY3;}
+while(xD2%3==0){xD2/=3;result+=e32;}
+result+=nmuls
+l81
+result;}
+}
+;}
+iO2
+FPoptimizer_CodeTree{xG1
+yK2::RecreateInversionsAndNegations(bool
+prefer_base2){bool
+changed=false
+c23
+0;a<cN3++a)if(lT1.RecreateInversionsAndNegations(prefer_base2))yI1
+if(changed){exit_changed:Mark_Incompletely_Hashed()nS2
+switch(lM2
+iY2
+cMul:{yG
+nV1
+lG2
+yJ
+lH2,cJ1;if(true){bool
+nQ1
+i13
+eS1
+nE2=0
+c23
+cO3
+yF2
+0)c82
+tJ
+1)y21){nQ1=true;nE2=tJ
+1).xJ1;nM3}
+if(nQ1){eS1
+immeds=1.0
+c23
+cO3
+y21){immeds*=powgroup.xJ1;yH1}
+for
+xK2
+cN3
+a-->0;)nG1&powgroup=lT1;if(powgroup
+yF2
+0)c82
+tJ
+1)y21)nG1&log2=tJ
+0);log2.iY
+log2
+tU
+lZ3
+log2
+yT
+eG3
+immeds,eS1(1)/nE2)));log2.Rehash(nW2}
+}
+}
+for
+xK2
+cO3
+yF2
+1)y21){lM1&exp_param=tJ
+1);eS1
+cE2=exp_param.xJ1;if(cR1,eS1(-1))){iY
+lG2
+yL
+lT1
+xY3
+yH1
+tP1
+cE2<0&&eY2
+cE2))nG1
+iI;iI
+tU
+cPow);iI
+eT
+tJ
+0));iI
+yT-cE2));iI
+x02;lG2
+yL
+iI);iY
+yH1}
+tP1
+powgroup
+c82!lH2.iA1{lH2=tJ
+0);iY
+yH1
+tP1
+powgroup
+nE==cLog2by&&!cJ1.iA1{cJ1=powgroup;iY
+yH1}
+if(!lG2
+cQ3){changed=true
+yJ
+eR1;eR1
+e53
+eR1
+tI1
+lG2);eR1
+i72
+xW1
+cMul);xX1
+SetParamsMove(t3
+if(xX1
+IsImmed()&&fp_equal(xX1
+xJ1,nY3{lI2
+cInv);eG
+eR1);}
+else{if(xX1
+xT2>=eR1.xT2){lI2
+cDiv
+eV1
+eG
+eR1);}
+else{lI2
+cRDiv);eG
+eR1
+eV1}
+}
+}
+if(lH2.iA1
+nG1
+xW1
+lM2);xX1
+SetParamsMove(t3
+while(xX1
+RecreateInversionsAndNegations(prefer_base2))xX1
+FixIncompleteHashes();lI2
+lZ3
+eG
+lH2
+eV1
+yI1}
+if(cJ1.iA1
+nG1
+xW1
+cMul);n83
+yA
+cJ1
+x03;xX1
+AddParamsMove(t3
+while(xX1
+RecreateInversionsAndNegations(prefer_base2))xX1
+FixIncompleteHashes();DelParams();lI2
+lZ3
+eG
+cJ1
+lD
+0)eV1
+yI1
+c91
+cAdd:{yG
+nV1
+tV2
+c23
+tD
+c33
+cMul){lJ2
+xY1:yJ&n83
+c72
+for(iX2
+xX1
+cN3
+b-->0;){if(n83
+lD
+b)xC3
+xD2=n83
+lD
+b).xJ1
+i82
+xD2
+eQ1
+xY1;}
+xX1
+iY
+xX1
+iH1
+b
+eJ2
+tP1
+fp_equal(xD2,eS1(-2)))xF
+xY1;}
+xX1
+iY
+xX1
+iH1
+b);n83
+yT
+eS1(2))eJ2}
+}
+if(t4){xX1
+nR1
+n83);yH1}
+tP1
+c33
+cDiv&&!IsIntType
+x8::result){lJ2
+xZ1:yJ&eR1
+c72
+if(eR1
+lD
+0)tF3(fp_equal(eR1
+lD
+0).xJ1
+eQ1
+xZ1;}
+eR1.iY
+eR1.iH1
+0);eR1
+tU
+cInv
+eJ2}
+if(t4)xF
+xZ1;}
+eR1.nR1
+eR1);yH1}
+tP1
+c33
+cRDiv&&!IsIntType
+x8::result){lJ2
+x91:yJ&eR1
+c72
+if(eR1
+lD
+1)tF3(fp_equal(eR1
+lD
+1).xJ1
+eQ1
+x91;}
+eR1.iY
+eR1.iH1
+1);eR1
+tU
+cInv
+eJ2}
+if(t4)xF
+x91;}
+eR1.nR1
+eR1);yH1}
+if(!tV2
+cQ3){
+#ifdef DEBUG_SUBSTITUTIONS
+tU2"Will make a Sub conversion in:\n"
+);fflush(stdout);iO
+#endif
+yK2
+yR1;yR1
+tU
+cAdd);yR1
+tI1
+tV2);yR1
+i72
+cK1;cK1
+tU
+cAdd);cK1
+tI1
+iE1));cK1
+x02;if(cK1
+y21&&fp_equal(cK1.xJ1,eS1(0))){lI2
+cNeg);cU3);}
+else{if(cK1.xT2==1){lI2
+cRSub);cU3);cV3}
+tP1
+yR1
+nE==cAdd){lI2
+cSub);cV3
+cU3
+xY3
+for
+xK2
+1;a<yR1.cN3++a)nG1
+e42;e42
+tU
+cSub);e42
+tI1
+iE1));e42.y12);eG
+e42);cU3
+lD
+a));}
+}
+else{lI2
+cSub);cV3
+cU3);}
+}
+#ifdef DEBUG_SUBSTITUTIONS
+tU2"After Sub conversion:\n"
+);fflush(stdout);iO
+#endif
+c91
+cPow:{lM1&p0
+tW2
+0);lM1&p1
+tW2
+1);if(p1
+tF3
+n03!=eS1(0)&&!eY2
+p1.xJ1)){eJ
+yE2
+r=eJ
+CreatePowiResult(fp_abs
+n03));if(r.lY1!=0){bool
+iB1
+i13
+if
+n03<0&&r.eW1
+0]==0&&r
+x33>0){iB1=true;}
+#ifdef DEBUG_POWI
+tU2"Will resolve powi %Lg as powi(chain(%d,%d),%ld)"
+x12
+fp_abs
+n03),r
+x33,r.n_int_cbrt,r.lY1)xS3
+n=0;n<eJ
+MaxSep;++n){if(r
+cW3==0)break;int
+n_sqrt=r
+cW3%eJ
+tC3;int
+n_cbrt=r
+cW3/eJ
+tC3;tU2"*chain(%d,%d)"
+,n_sqrt,n_cbrt);}
+tU2"\n"
+);
+#endif
+yK2
+c92
+tW2
+0)yJ
+yG2=c92;yG2.iY
+ChangeIntoRootChain(yG2,iB1,r
+x33,r.n_int_cbrt);yG2
+i72
+pow;if(r.lY1!=1){pow
+tU
+cPow);pow
+yA
+yG2);pow
+yT
+eS1(r.lY1)));}
+else
+pow.swap(yG2)yJ
+mul;mul
+e53
+mul
+yA
+pow)xS3
+n=0;n<eJ
+MaxSep;++n){if(r
+cW3==0)break;int
+n_sqrt=r
+cW3%eJ
+tC3;int
+n_cbrt=r
+cW3/eJ
+tC3
+yJ
+e52=c92;e52.iY
+ChangeIntoRootChain(e52,false,n_sqrt,n_cbrt);e52
+x02;mul
+yA
+e52);}
+if
+n03<0&&!iB1){mul
+x02;lI2
+cInv);nC1
+0,mul);iH1
+1);}
+else{lI2
+cMul);SetParamsMove(mul.iE1));}
+#ifdef DEBUG_POWI
+iO
+#endif
+yI1
+nM3}
+}
+if(lM2==cPow&&(!p1
+y21||!isLongInteger
+n03)||!IsOptimizableUsingPowi
+x8(makeLongInteger
+n03)))){if(p0
+y21&&p0.xJ1>0.0){if(prefer_base2){eS1
+yH2=fp_log2(p0.xJ1)i82
+yH2,nY3{iH1
+0);}
+else{n1
+cU1
+yH2));cE2
+eT
+p1)tD1
+iP}
+lI2
+cExp2);yI1}
+else{eS1
+yH2=fp_log(p0.xJ1)i82
+yH2,nY3{iH1
+0);}
+else{n1
+cU1
+yH2));cE2
+eT
+p1)tD1
+iP}
+lI2
+cExp);yI1}
+}
+tP1
+GetPositivityInfo(p0)==IsAlways){if(prefer_base2)nG1
+log;log
+tU
+cLog2);log
+eT
+p0);log
+x02;n1
+p1);cE2
+yA
+log)tD1);lI2
+cExp2
+iP
+yI1}
+else
+nG1
+log;log
+tU
+cLog);log
+eT
+p0);log
+x02;n1
+p1);cE2
+yA
+log)tD1);lI2
+cExp
+iP
+yI1}
+}
+c91
+cDiv:{if(GetParam(0)y21&&fp_equal(GetParam(0).xJ1,nY3{lI2
+cInv);iH1
+0);}
+nM3
+default:nM3
+if(changed)goto
+exit_changed
+l81
+changed;}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+xQ
+iO2{using
+iO2
+FPoptimizer_CodeTree;class
+eT1{size_t
+yJ1;size_t
+eK;size_t
+eL;size_t
+lF1;e13
+eT1():yJ1(0),eK(0),eL(0),lF1(0){}
+void
+c43
+OPCODE
+op){yJ1+=1;n13
+cCos)++eK;n13
+cSin)++eL;n13
+cSec)++eK;n13
+cCsc)++eL;n13
+cTan)++lF1;n13
+cCot)++lF1;}
+size_t
+GetCSEscore()const{size_t
+result=yJ1
+l81
+result;}
+int
+NeedsSinCos()const{bool
+always_sincostan=(yJ1==(eK+eL+lF1));if((lF1&&(eL||eK))||(eL&&eK)){if(always_sincostan
+nZ2
+1
+l81
+2;}
+return
+0;}
+size_t
+MinimumDepth()const{size_t
+n_sincos=std::min(eK,eL);if(n_sincos==0
+nZ2
+2
+l81
+1;}
+}
+;iP2
+TreeCountType:public
+std::multimap<fphash_t,std::pair<eT1,yK2> >{}
+;xB1
+FindTreeCounts(nX1&lK2,lM1&tree,OPCODE
+lL2{iG1
+i=lK2.xE2
+tree.GetHash());bool
+found
+i13
+for(;i!=lK2.cP1
+tree.GetHash();++i){if(tree
+iA
+i
+cJ2
+eE3)){i
+cJ2.first.c43
+lL2;found=true;nM3}
+if(!found){eT1
+count;count.c43
+lL2;lK2.nT3,std::make_pair(tree.GetHash(),std::make_pair
+cR3
+n72);}
+for
+yS
+FindTreeCounts(lK2,xI2,tree
+nE);}
+e92
+c9{bool
+BalanceGood;bool
+cI;}
+;yV1
+c9
+lG1
+lM1&root,lM1&c53{if(root
+iA
+c53){c9
+result={true,true}
+l81
+result;}
+c9
+result={true,false}
+;if(root
+nE==cIf||root
+nE==i03){c9
+cond=lG1
+root
+lD
+0),c53;c9
+xW=lG1
+root
+lD
+1),c53;c9
+y9=lG1
+root
+lD
+2),c53;if(cond.cI||xW.cI||y9.cI){tC1
+cI=true;}
+result
+eH=((xW.cI==y9.cI)||eX2&&(cond
+eH||(xW.cI&&y9.cI))&&(xW
+eH||eX2&&(y9
+eH||eX2;}
+else{bool
+tK1
+i13
+bool
+nS1
+i13
+for(iX2
+root.GetParamCount(),a=0;a<b;++a){c9
+tmp=lG1
+root
+lD
+a),c53;if(tmp.cI)tC1
+cI=true;if(tmp
+eH==false)tK1=true;tP1
+tmp.cI)nS1=true;}
+if(tK1&&!nS1)result
+eH
+i13}
+return
+result;}
+xG1
+n62
+lM1&tG3
+lM1&tree,const
+yW2&synth,const
+nX1&lK2){for(iX2
+iT,a=0;a<b;++a){lM1&leaf=xI2;iG1
+lT2;xH2
+nX1::const_iterator
+i=lK2.nW3
+i!=lK2.end();++i){if(i->eQ3
+leaf.GetHash())y81
+const
+c63
+i->nF2
+size_t
+score=occ.GetCSEscore();lM1&candidate=i->nG2
+if(cC2
+candidate))y81
+if(leaf.xT2<occ.MinimumDepth())y81
+if(score<2)y81
+if(lG1
+tG3
+leaf)eH==false)continue
+nS2
+if(n62
+tG3
+leaf,synth,lK2
+iF1;}
+nX2
+xG1
+tL1
+lM1&nU3,lM1&expr){for
+iT1
+nU3
+lD
+a)iA
+expr
+iF1;for
+iT1
+tL1
+nU3
+lD
+a),expr
+iF1
+l81
+false;}
+xG1
+GoodMomentForCSE(lM1&nU3,lM1&expr){if(nU3
+nE==cIf
+nZ2
+true;for
+iT1
+nU3
+lD
+a)iA
+expr
+iF1;size_t
+tX2=0;for
+iT1
+tL1
+nU3
+lD
+a),expr))++tX2
+l81
+tX2!=1;}
+}
+iO2
+FPoptimizer_CodeTree{yV1
+size_t
+yK2::SynthCommonSubExpressions(yV2
+lP1
+const{size_t
+stacktop_before
+t13
+GetStackTop();nX1
+lK2;FindTreeCounts(lK2,*this,lM2);
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+DumpHashes(*this);
+#endif
+for(;;){size_t
+yI2=0;iG1
+lT2;for(iG1
+j,i=lK2.nW3
+i!=lK2.end();i=j){j=i;++j;const
+c63
+i->nF2
+size_t
+score=occ.GetCSEscore();lM1&tree=i->nG2
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+std::cout<<"Score "
+<<score<<":\n"
+;DumpTreeWithIndent(tree);
+#endif
+if(cC2
+tree))xV
+if(tree.xT2<occ.MinimumDepth())xV
+if(score<2)xV
+if(lG1*this,tree)eH==false)xV
+if(n62*this,tree,synth,lK2)){y81}
+if(!GoodMomentForCSE(*this
+n72
+xV
+score*=tree.xT2;if(score>yI2){yI2=score;lT2=i;}
+}
+if(yI2<=0)break;const
+c63
+lT2->nF2
+lM1&tree=lT2->nG2
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+std::cout<<tZ3"Common Subexpression:"
+;xE3
+x8(tree)lN1"\n"
+;
+#endif
+int
+y01=occ.NeedsSinCos()yJ
+tY2,tZ2;if(y01){tY2
+eT
+tree);tY2
+tU
+cSin);tY2
+x02;tZ2
+eT
+tree);tZ2
+tU
+cCos);tZ2
+x02;if(cC2
+tY2)||cC2
+tZ2)){if(y01==2){lK2.erase(lT2);y81}
+y01=0;}
+}
+tree.SynthesizeByteCode(synth,false);lK2.erase(lT2);
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+std::cout<<"Done with Common Subexpression:"
+;xE3
+x8(tree)lN1"\n"
+;
+#endif
+if(y01){if(y01==2){tQ1
+c71);}
+lK1
+cSinCos,1,2
+eU3.yZ2
+tY2,1
+eU3.yZ2
+tZ2,0);}
+}
+return
+synth.x5
+stacktop_before;}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+yV1
+lR1
+x8
+nH2
+using
+iO2
+FPoptimizer_CodeTree;CopyOnWrite()yJ
+tree;tree.GenerateFrom(mData->mByteCode,mData->mImmed,*mData);FPoptimizer_Optimize::ApplyGrammars(tree);yG<i02>c73;yG
+x8
+immed;size_t
+stacktop_max=0;tree.SynthesizeByteCode(c73,immed,stacktop_max);if(mData->mStackSize!=stacktop_max){mData->mStackSize=i02(stacktop_max);
+#if !defined(FP_USE_THREAD_SAFE_EVAL) && \
+    !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA)
+mData->mStack
+nE3
+stacktop_max);
+#endif
+}
+mData->mByteCode.swap(c73);mData->mImmed.swap(immed);}
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+n73<>lR1<MpfrFloat>nH2}
+#endif
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+n73<>lR1<GmpInt>nH2}
+#endif
+FUNCTIONPARSER_INSTANTIATE_TYPES
+#endif
+
+#endif
diff --git a/fparser/fptypes.hh b/fparser/fptypes.hh
new file mode 100644 (file)
index 0000000..ef6357e
--- /dev/null
@@ -0,0 +1,282 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.3                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen, Joel Yliluoma                                 *|
+|*                                                                         *|
+|* This library is distributed under the terms of the                      *|
+|* GNU Lesser General Public License version 3.                            *|
+|* (See lgpl.txt and gpl.txt for the license text.)                        *|
+\***************************************************************************/
+
+// NOTE:
+// This file contains only internal types for the function parser library.
+// You don't need to include this file in your code. Include "fparser.hh"
+// only.
+
+#ifndef ONCE_FPARSER_TYPES_H_
+#define ONCE_FPARSER_TYPES_H_
+
+#include "fpconfig.hh"
+#include <cstring>
+
+#ifdef ONCE_FPARSER_H_
+#include <map>
+#endif
+
+namespace FUNCTIONPARSERTYPES
+{
+    enum OPCODE
+    {
+// The order of opcodes in the function list must
+// match that which is in the Functions[] array.
+        cAbs,
+        cAcos, cAcosh,
+        cAsin, cAsinh,
+        cAtan, cAtan2, cAtanh,
+        cCbrt, cCeil,
+        cCos, cCosh, cCot, cCsc,
+        cEval,
+        cExp, cExp2, cFloor, cHypot,
+        cIf, cInt, cLog, cLog10, cLog2, cMax, cMin,
+        cPow, cSec, cSin, cSinh, cSqrt, cTan, cTanh,
+        cTrunc,
+
+// These do not need any ordering:
+// Except that if you change the order of {eq,neq,lt,le,gt,ge}, you
+// must also change the order in ConstantFolding_ComparisonOperations().
+        cImmed, cJump,
+        cNeg, cAdd, cSub, cMul, cDiv, cMod,
+        cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq,
+        cNot, cAnd, cOr,
+        cNotNot, /* Protects the double-not sequence from optimizations */
+
+        cDeg, cRad, /* Multiplication and division by 180 / pi */
+
+        cFCall, cPCall,
+
+#ifdef FP_SUPPORT_OPTIMIZER
+        cPopNMov, /* cPopNMov(x,y) moves [y] to [x] and deletes anything
+                   * above [x]. Used for disposing of temporaries.
+                   */
+        cLog2by, /* log2by(x,y) = log2(x) * y */
+        cNop,    /* Used by fpoptimizer internally; should not occur in bytecode */
+#endif
+        cSinCos, /* sin(x) followed by cos(x) (two values are pushed to stack) */
+        cAbsAnd,    /* As cAnd,       but assume both operands are absolute values */
+        cAbsOr,     /* As cOr,        but assume both operands are absolute values */
+        cAbsNot,    /* As cAbsNot,    but assume the operand is an absolute value */
+        cAbsNotNot, /* As cAbsNotNot, but assume the operand is an absolute value */
+        cAbsIf,     /* As cAbsIf,     but assume the 1st operand is an absolute value */
+
+        cDup,   /* Duplicates the last value in the stack: Push [Stacktop] */
+        cFetch, /* Same as Dup, except with absolute index
+                 * (next value is index) */
+        cInv,   /* Inverts the last value in the stack (x = 1/x) */
+        cSqr,   /* squares the last operand in the stack, no push/pop */
+        cRDiv,  /* reverse division (not x/y, but y/x) */
+        cRSub,  /* reverse subtraction (not x-y, but y-x) */
+        cRSqrt, /* inverse square-root (1/sqrt(x)) */
+
+        VarBegin
+    };
+
+#ifdef ONCE_FPARSER_H_
+    struct FuncDefinition
+    {
+        enum FunctionFlags
+        {
+            Enabled  = 0x01,
+            AngleIn  = 0x02,
+            AngleOut = 0x04,
+            OkForInt = 0x08
+        };
+
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+        const char name[8];
+#else
+        struct name { } name;
+#endif
+        unsigned params : 8;
+        unsigned flags  : 8;
+
+        inline bool enabled() const { return flags != 0; }
+        inline bool okForInt() const { return (flags & OkForInt) != 0; }
+    };
+
+#ifndef FP_DISABLE_EVAL
+# define FP_EVAL_FUNCTION_ENABLED \
+    FuncDefinition::Enabled | FuncDefinition::OkForInt
+#else
+# define FP_EVAL_FUNCTION_ENABLED 0
+#endif
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+# define FP_FNAME(n) n
+#else
+# define FP_FNAME(n) {}
+#endif
+// This list must be in the same order as that in OPCODE enum,
+// because the opcode value is used to index this array, and
+// the pointer to array element is used for generating the opcode.
+    const FuncDefinition Functions[]=
+    {
+        /*cAbs  */ { FP_FNAME("abs"),   1,
+                     FuncDefinition::Enabled | FuncDefinition::OkForInt },
+        /*cAcos */ { FP_FNAME("acos"),  1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleOut },
+        /*cAcosh*/ { FP_FNAME("acosh"), 1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleOut },
+        /*cAsin */ { FP_FNAME("asin"),  1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleOut },
+        /*cAsinh*/ { FP_FNAME("asinh"), 1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleOut },
+        /*cAtan */ { FP_FNAME("atan"),  1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleOut },
+        /*cAtan2*/ { FP_FNAME("atan2"), 2,
+                     FuncDefinition::Enabled | FuncDefinition::AngleOut },
+        /*cAtanh*/ { FP_FNAME("atanh"), 1, FuncDefinition::Enabled },
+        /*cCbrt */ { FP_FNAME("cbrt"),  1, FuncDefinition::Enabled },
+        /*cCeil */ { FP_FNAME("ceil"),  1, FuncDefinition::Enabled },
+        /*cCos  */ { FP_FNAME("cos"),   1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cCosh */ { FP_FNAME("cosh"),  1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cCot  */ { FP_FNAME("cot"),   1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cCsc  */ { FP_FNAME("csc"),   1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cEval */ { FP_FNAME("eval"),  0, FP_EVAL_FUNCTION_ENABLED },
+        /*cExp  */ { FP_FNAME("exp"),   1, FuncDefinition::Enabled },
+        /*cExp2 */ { FP_FNAME("exp2"),  1, FuncDefinition::Enabled },
+        /*cFloor*/ { FP_FNAME("floor"), 1, FuncDefinition::Enabled },
+        /*cHypot*/ { FP_FNAME("hypot"), 2, FuncDefinition::Enabled },
+        /*cIf   */ { FP_FNAME("if"),    0,
+                     FuncDefinition::Enabled | FuncDefinition::OkForInt },
+        /*cInt  */ { FP_FNAME("int"),   1, FuncDefinition::Enabled },
+        /*cLog  */ { FP_FNAME("log"),   1, FuncDefinition::Enabled },
+        /*cLog10*/ { FP_FNAME("log10"), 1, FuncDefinition::Enabled },
+        /*cLog2 */ { FP_FNAME("log2"),  1, FuncDefinition::Enabled },
+        /*cMax  */ { FP_FNAME("max"),   2,
+                     FuncDefinition::Enabled | FuncDefinition::OkForInt },
+        /*cMin  */ { FP_FNAME("min"),   2,
+                     FuncDefinition::Enabled | FuncDefinition::OkForInt },
+        /*cPow  */ { FP_FNAME("pow"),   2, FuncDefinition::Enabled },
+        /*cSec  */ { FP_FNAME("sec"),   1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cSin  */ { FP_FNAME("sin"),   1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cSinh */ { FP_FNAME("sinh"),  1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cSqrt */ { FP_FNAME("sqrt"),  1,
+                     FuncDefinition::Enabled },
+        /*cTan  */ { FP_FNAME("tan"),   1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cTanh */ { FP_FNAME("tanh"),  1,
+                     FuncDefinition::Enabled | FuncDefinition::AngleIn },
+        /*cTrunc*/ { FP_FNAME("trunc"), 1,
+                     FuncDefinition::Enabled }
+    };
+#undef FP_FNAME
+
+    struct NamePtr
+    {
+        const char* name;
+        unsigned nameLength;
+
+        NamePtr(const char* n, unsigned l): name(n), nameLength(l) {}
+
+        inline bool operator==(const NamePtr& rhs) const
+        {
+            return nameLength == rhs.nameLength
+                && std::memcmp(name, rhs.name, nameLength) == 0;
+        }
+        inline bool operator<(const NamePtr& rhs) const
+        {
+            for(unsigned i = 0; i < nameLength; ++i)
+            {
+                if(i == rhs.nameLength) return false;
+                const char c1 = name[i], c2 = rhs.name[i];
+                if(c1 < c2) return true;
+                if(c2 < c1) return false;
+            }
+            return nameLength < rhs.nameLength;
+        }
+    };
+
+    template<typename Value_t>
+    struct NameData
+    {
+        enum DataType { CONSTANT, UNIT, FUNC_PTR, PARSER_PTR, VARIABLE };
+        DataType type;
+        unsigned index;
+        Value_t value;
+
+        NameData(DataType t, unsigned v) : type(t), index(v), value() { }
+        NameData(DataType t, Value_t v) : type(t), index(), value(v) { }
+        NameData() { }
+    };
+
+    template<typename Value_t>
+    class NamePtrsMap: public
+    std::map<FUNCTIONPARSERTYPES::NamePtr,
+             FUNCTIONPARSERTYPES::NameData<Value_t> >
+    {
+    };
+
+    const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]);
+#endif // ONCE_FPARSER_H_
+}
+
+#ifdef ONCE_FPARSER_H_
+#include <vector>
+
+template<typename Value_t>
+struct FunctionParserBase<Value_t>::Data
+{
+    unsigned mReferenceCounter;
+
+    unsigned mVariablesAmount;
+    std::string mVariablesString;
+    FUNCTIONPARSERTYPES::NamePtrsMap<Value_t> mNamePtrs;
+
+    struct InlineVariable
+    {
+        FUNCTIONPARSERTYPES::NamePtr mName;
+        unsigned mFetchIndex;
+    };
+
+    typedef std::vector<InlineVariable> InlineVarNamesContainer;
+    InlineVarNamesContainer mInlineVarNames;
+
+    struct FuncPtrData
+    {
+        union
+        {
+            FunctionPtr mFuncPtr;
+            FunctionParserBase<Value_t>* mParserPtr;
+        };
+        unsigned mParams;
+    };
+
+    std::vector<FuncPtrData> mFuncPtrs;
+    std::vector<FuncPtrData> mFuncParsers;
+
+    std::vector<unsigned> mByteCode;
+    std::vector<Value_t> mImmed;
+#if !defined(FP_USE_THREAD_SAFE_EVAL) && \
+    !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA)
+    std::vector<Value_t> mStack;
+    // Note: When mStack exists,
+    //       mStack.size() and mStackSize are mutually redundant.
+#endif
+    unsigned mStackSize;
+
+    Data();
+    Data(const Data&);
+    Data& operator=(const Data&); // not implemented on purpose
+    ~Data();
+};
+#endif
+
+#include "fpaux.hh"
+
+#endif
diff --git a/fparser/mpfr/GmpInt.cc b/fparser/mpfr/GmpInt.cc
new file mode 100644 (file)
index 0000000..490add4
--- /dev/null
@@ -0,0 +1,710 @@
+#include "GmpInt.hh"
+#include <gmp.h>
+#include <deque>
+#include <vector>
+#include <cstring>
+#include <cctype>
+
+//===========================================================================
+// Shared data
+//===========================================================================
+namespace
+{
+    unsigned long gIntDefaultNumberOfBits = 256;
+
+    std::vector<char>& intString()
+    {
+        static std::vector<char> str;
+        return str;
+    }
+}
+
+//===========================================================================
+// Auxiliary structs
+//===========================================================================
+struct GmpInt::GmpIntData
+{
+    unsigned mRefCount;
+    GmpIntData* nextFreeNode;
+    mpz_t mInteger;
+
+    GmpIntData(): mRefCount(1), nextFreeNode(0) {}
+};
+
+class GmpInt::GmpIntDataContainer
+{
+    std::deque<GmpInt::GmpIntData> mData;
+    GmpInt::GmpIntData* mFirstFreeNode;
+    GmpInt::GmpIntData* mConst_0;
+
+ public:
+    GmpIntDataContainer(): mFirstFreeNode(0), mConst_0(0) {}
+
+    ~GmpIntDataContainer()
+    {
+        for(size_t i = 0; i < mData.size(); ++i)
+            mpz_clear(mData[i].mInteger);
+    }
+
+    GmpInt::GmpIntData* allocateGmpIntData(unsigned long numberOfBits,
+                                           bool initToZero)
+    {
+        if(mFirstFreeNode)
+        {
+            GmpInt::GmpIntData* node = mFirstFreeNode;
+            mFirstFreeNode = node->nextFreeNode;
+            if(initToZero) mpz_set_si(node->mInteger, 0);
+            ++(node->mRefCount);
+            return node;
+        }
+
+        mData.push_back(GmpInt::GmpIntData());
+        if(numberOfBits > 0)
+            mpz_init2(mData.back().mInteger, numberOfBits);
+        else
+            mpz_init(mData.back().mInteger);
+        return &mData.back();
+    }
+
+    void releaseGmpIntData(GmpIntData* data)
+    {
+        if(--(data->mRefCount) == 0)
+        {
+            data->nextFreeNode = mFirstFreeNode;
+            mFirstFreeNode = data;
+        }
+    }
+
+    GmpInt::GmpIntData* const_0()
+    {
+        if(!mConst_0)
+            mConst_0 = allocateGmpIntData(gIntDefaultNumberOfBits, true);
+        return mConst_0;
+    }
+};
+
+
+GmpInt::GmpIntDataContainer& GmpInt::gmpIntDataContainer()
+{
+    static GmpIntDataContainer container;
+    return container;
+}
+
+//===========================================================================
+// Auxiliary functions
+//===========================================================================
+void GmpInt::setDefaultNumberOfBits(unsigned long value)
+{
+    gIntDefaultNumberOfBits = value;
+}
+
+unsigned long GmpInt::getDefaultNumberOfBits()
+{
+    return gIntDefaultNumberOfBits;
+}
+
+inline void GmpInt::copyIfShared()
+{
+    if(mData->mRefCount > 1)
+    {
+        --(mData->mRefCount);
+        GmpIntData* oldData = mData;
+        mData = gmpIntDataContainer().allocateGmpIntData(0, false);
+        mpz_set(mData->mInteger, oldData->mInteger);
+    }
+}
+
+
+//===========================================================================
+// Constructors, destructor, assignment
+//===========================================================================
+GmpInt::GmpInt(DummyType):
+    mData(gmpIntDataContainer().allocateGmpIntData(0, false))
+{}
+
+GmpInt::GmpInt()
+{
+    mData = gmpIntDataContainer().const_0();
+    ++(mData->mRefCount);
+}
+
+GmpInt::GmpInt(long value)
+{
+    if(value == 0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_si(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(unsigned long value)
+{
+    if(value == 0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_ui(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(int value)
+{
+    if(value == 0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_si(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(double value)
+{
+    const double absValue = value >= 0.0 ? value : -value;
+    if(absValue < 1.0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_d(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(long double value)
+{
+    const long double absValue = value >= 0.0L ? value : -value;
+    if(absValue < 1.0L)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_d(mData->mInteger, double(value));
+    }
+}
+
+GmpInt::GmpInt(const GmpInt& rhs):
+    mData(rhs.mData)
+{
+    ++(mData->mRefCount);
+}
+
+GmpInt& GmpInt::operator=(const GmpInt& rhs)
+{
+    if(mData != rhs.mData)
+    {
+        gmpIntDataContainer().releaseGmpIntData(mData);
+        mData = rhs.mData;
+        ++(mData->mRefCount);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator=(signed long value)
+{
+    if(value == 0)
+    {
+        gmpIntDataContainer().releaseGmpIntData(mData);
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        if(mData->mRefCount > 1)
+        {
+            --(mData->mRefCount);
+            mData = gmpIntDataContainer().allocateGmpIntData
+                (gIntDefaultNumberOfBits, false);
+        }
+        mpz_set_si(mData->mInteger, value);
+    }
+    return *this;
+}
+
+GmpInt::~GmpInt()
+{
+    gmpIntDataContainer().releaseGmpIntData(mData);
+}
+
+
+//===========================================================================
+// Data getters
+//===========================================================================
+template<>
+void GmpInt::get_raw_mpfr_data<mpz_t>(mpz_t& dest_mpz_t)
+{
+    std::memcpy(&dest_mpz_t, mData->mInteger, sizeof(mpz_t));
+}
+
+const char* GmpInt::getAsString(int base) const
+{
+    intString().resize(mpz_sizeinbase(mData->mInteger, base) + 2);
+    return mpz_get_str(&intString()[0], base, mData->mInteger);
+}
+
+long GmpInt::toInt() const
+{
+    return mpz_get_si(mData->mInteger);
+}
+
+
+//===========================================================================
+// Modifying operators
+//===========================================================================
+GmpInt& GmpInt::operator+=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_add(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator+=(long value)
+{
+    copyIfShared();
+    if(value >= 0)
+        mpz_add_ui(mData->mInteger, mData->mInteger, value);
+    else
+        mpz_sub_ui(mData->mInteger, mData->mInteger, -value);
+    return *this;
+}
+
+GmpInt& GmpInt::operator-=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_sub(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator-=(long value)
+{
+    copyIfShared();
+    if(value >= 0)
+        mpz_sub_ui(mData->mInteger, mData->mInteger, value);
+    else
+        mpz_add_ui(mData->mInteger, mData->mInteger, -value);
+    return *this;
+}
+
+GmpInt& GmpInt::operator*=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_mul(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator*=(long value)
+{
+    copyIfShared();
+    mpz_mul_si(mData->mInteger, mData->mInteger, value);
+    return *this;
+}
+
+GmpInt& GmpInt::operator/=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_tdiv_q(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator/=(long value)
+{
+    copyIfShared();
+    if(value >= 0)
+        mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, value);
+    else
+    {
+        mpz_neg(mData->mInteger, mData->mInteger);
+        mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, -value);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator%=(const GmpInt& rhs)
+{
+    copyIfShared();
+    if(operator<(0))
+    {
+        negate();
+        mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+        negate();
+    }
+    else
+    {
+        mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator%=(long value)
+{
+    copyIfShared();
+    if(value < 0) value = -value;
+    if(operator<(0))
+    {
+        negate();
+        mpz_mod_ui(mData->mInteger, mData->mInteger, value);
+        negate();
+    }
+    else
+    {
+        mpz_mod_ui(mData->mInteger, mData->mInteger, value);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator<<=(unsigned long bits)
+{
+    copyIfShared();
+    mpz_mul_2exp(mData->mInteger, mData->mInteger, bits);
+    return *this;
+}
+
+GmpInt& GmpInt::operator>>=(unsigned long bits)
+{
+    copyIfShared();
+    mpz_tdiv_q_2exp(mData->mInteger, mData->mInteger, bits);
+    return *this;
+}
+
+
+//===========================================================================
+// Modifying functions
+//===========================================================================
+void GmpInt::addProduct(const GmpInt& value1, const GmpInt& value2)
+{
+    copyIfShared();
+    mpz_addmul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
+}
+
+void GmpInt::addProduct(const GmpInt& value1, unsigned long value2)
+{
+    copyIfShared();
+    mpz_addmul_ui(mData->mInteger, value1.mData->mInteger, value2);
+}
+
+void GmpInt::subProduct(const GmpInt& value1, const GmpInt& value2)
+{
+    copyIfShared();
+    mpz_submul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
+}
+
+void GmpInt::subProduct(const GmpInt& value1, unsigned long value2)
+{
+    copyIfShared();
+    mpz_submul_ui(mData->mInteger, value1.mData->mInteger, value2);
+}
+
+void GmpInt::negate()
+{
+    copyIfShared();
+    mpz_neg(mData->mInteger, mData->mInteger);
+}
+
+void GmpInt::abs()
+{
+    copyIfShared();
+    mpz_abs(mData->mInteger, mData->mInteger);
+}
+
+GmpInt GmpInt::abs(const GmpInt& value)
+{
+    GmpInt retval(kNoInitialization);
+    mpz_abs(retval.mData->mInteger, value.mData->mInteger);
+    return retval;
+}
+
+
+//===========================================================================
+// Non-modifying operators
+//===========================================================================
+GmpInt GmpInt::operator+(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_add(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator+(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value >= 0)
+        mpz_add_ui(retval.mData->mInteger, mData->mInteger, value);
+    else
+        mpz_sub_ui(retval.mData->mInteger, mData->mInteger, -value);
+    return retval;
+}
+
+GmpInt GmpInt::operator-(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_sub(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator-(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value >= 0)
+        mpz_sub_ui(retval.mData->mInteger, mData->mInteger, value);
+    else
+        mpz_add_ui(retval.mData->mInteger, mData->mInteger, -value);
+    return retval;
+}
+
+GmpInt GmpInt::operator*(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_mul(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator*(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_mul_si(retval.mData->mInteger, mData->mInteger, value);
+    return retval;
+}
+
+GmpInt GmpInt::operator/(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_tdiv_q(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator/(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value >= 0)
+        mpz_tdiv_q_ui(retval.mData->mInteger, mData->mInteger, value);
+    else
+    {
+        mpz_neg(retval.mData->mInteger, mData->mInteger);
+        mpz_tdiv_q_ui(retval.mData->mInteger, retval.mData->mInteger, -value);
+    }
+    return retval;
+}
+
+GmpInt GmpInt::operator%(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    if(operator<(0))
+    {
+        mpz_neg(retval.mData->mInteger, mData->mInteger);
+        mpz_mod(retval.mData->mInteger,
+                retval.mData->mInteger, rhs.mData->mInteger);
+        retval.negate();
+    }
+    else
+    {
+        mpz_mod(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    }
+    return retval;
+}
+
+GmpInt GmpInt::operator%(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value < 0) value = -value;
+    if(operator<(0))
+    {
+        mpz_neg(retval.mData->mInteger, mData->mInteger);
+        mpz_mod_ui(retval.mData->mInteger, retval.mData->mInteger, value);
+        retval.negate();
+    }
+    else
+    {
+        mpz_mod_ui(retval.mData->mInteger, mData->mInteger, value);
+    }
+    return retval;
+}
+
+GmpInt GmpInt::operator-() const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_neg(retval.mData->mInteger, mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator<<(unsigned long bits) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_mul_2exp(retval.mData->mInteger, mData->mInteger, bits);
+    return retval;
+}
+
+GmpInt GmpInt::operator>>(unsigned long bits) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_tdiv_q_2exp(retval.mData->mInteger, mData->mInteger, bits);
+    return retval;
+}
+
+
+//===========================================================================
+// Comparison operators
+//===========================================================================
+bool GmpInt::operator<(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) < 0;
+}
+
+bool GmpInt::operator<(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) < 0;
+}
+
+bool GmpInt::operator<=(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) <= 0;
+}
+
+bool GmpInt::operator<=(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) <= 0;
+}
+
+bool GmpInt::operator>(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) > 0;
+}
+
+bool GmpInt::operator>(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) > 0;
+}
+
+bool GmpInt::operator>=(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) >= 0;
+}
+
+bool GmpInt::operator>=(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) >= 0;
+}
+
+bool GmpInt::operator==(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) == 0;
+}
+
+bool GmpInt::operator==(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) == 0;
+}
+
+bool GmpInt::operator!=(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) != 0;
+}
+
+bool GmpInt::operator!=(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) != 0;
+}
+
+void GmpInt::parseValue(const char* value)
+{
+    mpz_set_str(mData->mInteger, value, 10);
+}
+
+void GmpInt::parseValue(const char* value, char** endptr)
+{
+    static std::vector<char> str;
+
+    unsigned startIndex = 0;
+    while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex;
+    if(!value[startIndex]) { *endptr = const_cast<char*>(value); return; }
+
+    unsigned endIndex = startIndex;
+    if(value[endIndex] == '-') ++endIndex;
+    if(!std::isdigit(value[endIndex]))
+    { *endptr = const_cast<char*>(value); return; }
+    if(value[endIndex] == '0' && value[endIndex+1] == 'x')
+    {
+        endIndex += 1;
+        while(std::isxdigit(value[++endIndex])) {}
+    }
+    else
+    {
+        while(std::isdigit(value[++endIndex])) {}
+    }
+
+    str.reserve(endIndex - startIndex + 1);
+    str.assign(value + startIndex, value + endIndex);
+    str.push_back(0);
+
+    mpz_set_str(mData->mInteger, &str[0], 0);
+    *endptr = const_cast<char*>(value + endIndex);
+}
+
+GmpInt GmpInt::parseString(const char* str, char** endptr)
+{
+    GmpInt retval(kNoInitialization);
+    retval.parseValue(str, endptr);
+    return retval;
+}
+
+//===========================================================================
+// Operator functions
+//===========================================================================
+GmpInt operator+(long lhs, const GmpInt& rhs)
+{
+    GmpInt retval(GmpInt::kNoInitialization);
+    if(lhs >= 0)
+        mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs);
+    else
+        mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
+    return retval;
+}
+
+GmpInt operator-(long lhs, const GmpInt& rhs)
+{
+    GmpInt retval(GmpInt::kNoInitialization);
+    if(lhs >= 0)
+        mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger);
+    else
+    {
+        mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
+        mpz_neg(retval.mData->mInteger, retval.mData->mInteger);
+    }
+    return retval;
+}
+
+GmpInt operator*(long lhs, const GmpInt& rhs)
+{
+    return rhs * lhs;
+}
+
+GmpInt operator/(long lhs, const GmpInt& rhs)
+{
+    return GmpInt(lhs) / rhs;
+}
+
+GmpInt operator%(long lhs, const GmpInt& rhs)
+{
+    return GmpInt(lhs) % rhs;
+}
diff --git a/fparser/mpfr/GmpInt.hh b/fparser/mpfr/GmpInt.hh
new file mode 100644 (file)
index 0000000..1c1c171
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef ONCE_FP_GMP_INT_HH_
+#define ONCE_FP_GMP_INT_HH_
+
+#include <iostream>
+
+class GmpInt
+{
+ public:
+    /* A default of 256 bits will be used for all newly-instantiated GmpInt
+       objects. This default can be changed with the function below.
+    */
+    static void setDefaultNumberOfBits(unsigned long);
+    static unsigned long getDefaultNumberOfBits();
+
+    GmpInt();
+    GmpInt(long value);
+    GmpInt(unsigned long value);
+    GmpInt(int value);
+    GmpInt(double value);
+    GmpInt(long double value);
+
+    GmpInt(const GmpInt&);
+    GmpInt& operator=(const GmpInt&);
+    GmpInt& operator=(signed long value);
+
+    ~GmpInt();
+
+
+    /* This function can be used to retrieve the raw mpz_t data structure
+       used by this object. (The template trick is used to avoid a dependency
+       of this header file with <gmp.h>.)
+       In other words, it can be called like:
+
+         mpz_t raw_mpz_data;
+         intValue.get_raw_mpz_data(raw_mpz_data);
+
+       Note that the returned mpz_t should be considered as read-only and
+       not be modified from the outside because it may be shared among
+       several objects. If the calling code needs to modify the data, it
+       should copy it for itself first with the appropriate GMP library
+       functions.
+     */
+    template<typename Mpz_t>
+    void get_raw_mpfr_data(Mpz_t& dest_mpz_t);
+
+
+    // Note that the returned char* points to an internal (shared) buffer
+    // which will be valid until the next time this function is called
+    // (by any object).
+    const char* getAsString(int base = 10) const;
+    long toInt() const;
+
+    GmpInt& operator+=(const GmpInt&);
+    GmpInt& operator+=(long);
+    GmpInt& operator-=(const GmpInt&);
+    GmpInt& operator-=(long);
+    GmpInt& operator*=(const GmpInt&);
+    GmpInt& operator*=(long);
+    GmpInt& operator/=(const GmpInt&);
+    GmpInt& operator/=(long);
+    GmpInt& operator%=(const GmpInt&);
+    GmpInt& operator%=(long);
+
+    GmpInt& operator<<=(unsigned long);
+    GmpInt& operator>>=(unsigned long);
+
+    // Equivalent to "+= value1 * value2;"
+    void addProduct(const GmpInt& value1, const GmpInt& value2);
+    void addProduct(const GmpInt& value1, unsigned long value2);
+
+    // Equivalent to "-= value1 * value2;"
+    void subProduct(const GmpInt& value1, const GmpInt& value2);
+    void subProduct(const GmpInt& value1, unsigned long value2);
+
+    void negate();
+    void abs();
+    static GmpInt abs(const GmpInt&);
+
+    GmpInt operator+(const GmpInt&) const;
+    GmpInt operator+(long) const;
+    GmpInt operator-(const GmpInt&) const;
+    GmpInt operator-(long) const;
+    GmpInt operator*(const GmpInt&) const;
+    GmpInt operator*(long) const;
+    GmpInt operator/(const GmpInt&) const;
+    GmpInt operator/(long) const;
+    GmpInt operator%(const GmpInt&) const;
+    GmpInt operator%(long) const;
+
+    GmpInt operator-() const;
+
+    GmpInt operator<<(unsigned long) const;
+    GmpInt operator>>(unsigned long) const;
+
+    bool operator<(const GmpInt&) const;
+    bool operator<(long) const;
+    bool operator<=(const GmpInt&) const;
+    bool operator<=(long) const;
+    bool operator>(const GmpInt&) const;
+    bool operator>(long) const;
+    bool operator>=(const GmpInt&) const;
+    bool operator>=(long) const;
+    bool operator==(const GmpInt&) const;
+    bool operator==(long) const;
+    bool operator!=(const GmpInt&) const;
+    bool operator!=(long) const;
+
+    void parseValue(const char* value);
+    void parseValue(const char* value, char** endptr);
+    static GmpInt parseString(const char* str, char** endptr);
+
+
+ private:
+    struct GmpIntData;
+    class GmpIntDataContainer;
+
+    GmpIntData* mData;
+
+    enum DummyType { kNoInitialization };
+    GmpInt(DummyType);
+
+    void copyIfShared();
+    static GmpIntDataContainer& gmpIntDataContainer();
+
+    friend GmpInt operator+(long lhs, const GmpInt& rhs);
+    friend GmpInt operator-(long lhs, const GmpInt& rhs);
+};
+
+GmpInt operator+(long lhs, const GmpInt& rhs);
+GmpInt operator-(long lhs, const GmpInt& rhs);
+GmpInt operator*(long lhs, const GmpInt& rhs);
+GmpInt operator/(long lhs, const GmpInt& rhs);
+GmpInt operator%(long lhs, const GmpInt& rhs);
+
+inline bool operator<(long lhs, const GmpInt& rhs) { return rhs > lhs; }
+inline bool operator<=(long lhs, const GmpInt& rhs) { return rhs >= lhs; }
+inline bool operator>(long lhs, const GmpInt& rhs) { return rhs < lhs; }
+inline bool operator>=(long lhs, const GmpInt& rhs) { return rhs <= lhs; }
+inline bool operator==(long lhs, const GmpInt& rhs) { return rhs == lhs; }
+inline bool operator!=(long lhs, const GmpInt& rhs) { return rhs != lhs; }
+
+inline std::ostream& operator<<(std::ostream& os, const GmpInt& value)
+{
+    os << value.getAsString();
+    return os;
+}
+
+#endif
diff --git a/fparser/mpfr/MpfrFloat.cc b/fparser/mpfr/MpfrFloat.cc
new file mode 100644 (file)
index 0000000..387d1e8
--- /dev/null
@@ -0,0 +1,974 @@
+#include "MpfrFloat.hh"
+#include <stdio.h>
+#include <mpfr.h>
+#include <deque>
+#include <vector>
+#include <cstring>
+#include <cassert>
+
+//===========================================================================
+// Auxiliary structs
+//===========================================================================
+struct MpfrFloat::MpfrFloatData
+{
+    unsigned mRefCount;
+    MpfrFloatData* nextFreeNode;
+    mpfr_t mFloat;
+
+    MpfrFloatData(): mRefCount(1), nextFreeNode(0) {}
+};
+
+class MpfrFloat::MpfrFloatDataContainer
+{
+    unsigned long mDefaultPrecision;
+    std::deque<MpfrFloatData> mData;
+    MpfrFloatData* mFirstFreeNode;
+
+    MpfrFloatData
+    *mConst_0, *mConst_pi, *mConst_e, *mConst_log2, *mConst_epsilon;
+
+    void recalculateEpsilon()
+    {
+        mpfr_set_si(mConst_epsilon->mFloat, 1, GMP_RNDN);
+        mpfr_div_2ui(mConst_epsilon->mFloat, mConst_epsilon->mFloat,
+                     mDefaultPrecision*7/8 - 1, GMP_RNDN);
+    }
+
+ public:
+    MpfrFloatDataContainer():
+        mDefaultPrecision(256), mFirstFreeNode(0),
+        mConst_pi(0), mConst_e(0), mConst_log2(0), mConst_epsilon(0)
+    {}
+
+    ~MpfrFloatDataContainer()
+    {
+        for(size_t i = 0; i < mData.size(); ++i)
+            mpfr_clear(mData[i].mFloat);
+    }
+
+    MpfrFloatData* allocateMpfrFloatData(bool initToZero)
+    {
+        if(mFirstFreeNode)
+        {
+            MpfrFloatData* node = mFirstFreeNode;
+            mFirstFreeNode = node->nextFreeNode;
+            if(initToZero) mpfr_set_si(node->mFloat, 0, GMP_RNDN);
+            ++(node->mRefCount);
+            return node;
+        }
+
+        mData.push_back(MpfrFloatData());
+        mpfr_init2(mData.back().mFloat, mDefaultPrecision);
+        if(initToZero) mpfr_set_si(mData.back().mFloat, 0, GMP_RNDN);
+        return &mData.back();
+    }
+
+    void releaseMpfrFloatData(MpfrFloatData* data)
+    {
+        if(--(data->mRefCount) == 0)
+        {
+            data->nextFreeNode = mFirstFreeNode;
+            mFirstFreeNode = data;
+        }
+    }
+
+    void setDefaultPrecision(unsigned long bits)
+    {
+        if(bits != mDefaultPrecision)
+        {
+            mDefaultPrecision = bits;
+            for(size_t i = 0; i < mData.size(); ++i)
+                mpfr_prec_round(mData[i].mFloat, bits, GMP_RNDN);
+
+            if(mConst_pi) mpfr_const_pi(mConst_pi->mFloat, GMP_RNDN);
+            if(mConst_e)
+            {
+                mpfr_set_si(mConst_e->mFloat, 1, GMP_RNDN);
+                mpfr_exp(mConst_e->mFloat, mConst_e->mFloat, GMP_RNDN);
+            }
+            if(mConst_log2) mpfr_const_log2(mConst_log2->mFloat, GMP_RNDN);
+            if(mConst_epsilon) recalculateEpsilon();
+        }
+    }
+
+    unsigned long getDefaultPrecision() const
+    {
+        return mDefaultPrecision;
+    }
+
+    MpfrFloatData* const_0()
+    {
+        if(!mConst_0) mConst_0 = allocateMpfrFloatData(true);
+        return mConst_0;
+    }
+
+    MpfrFloat const_pi()
+    {
+        if(!mConst_pi)
+        {
+            mConst_pi = allocateMpfrFloatData(false);
+            mpfr_const_pi(mConst_pi->mFloat, GMP_RNDN);
+        }
+        return MpfrFloat(mConst_pi);
+    }
+
+    MpfrFloat const_e()
+    {
+        if(!mConst_e)
+        {
+            mConst_e = allocateMpfrFloatData(false);
+            mpfr_set_si(mConst_e->mFloat, 1, GMP_RNDN);
+            mpfr_exp(mConst_e->mFloat, mConst_e->mFloat, GMP_RNDN);
+        }
+        return MpfrFloat(mConst_e);
+    }
+
+    MpfrFloat const_log2()
+    {
+        if(!mConst_log2)
+        {
+            mConst_log2 = allocateMpfrFloatData(false);
+            mpfr_const_log2(mConst_log2->mFloat, GMP_RNDN);
+        }
+        return MpfrFloat(mConst_log2);
+    }
+
+    MpfrFloat const_epsilon()
+    {
+        if(!mConst_epsilon)
+        {
+            mConst_epsilon = allocateMpfrFloatData(false);
+            recalculateEpsilon();
+        }
+        return MpfrFloat(mConst_epsilon);
+    }
+};
+
+
+//===========================================================================
+// Shared data
+//===========================================================================
+// This should ensure that the container is not accessed by any MpfrFloat
+// instance before it has been constructed or after it has been destroyed
+// (which might otherwise happen if MpfrFloat is instantiated globally.)
+MpfrFloat::MpfrFloatDataContainer& MpfrFloat::mpfrFloatDataContainer()
+{
+    static MpfrFloat::MpfrFloatDataContainer container;
+    return container;
+}
+
+
+//===========================================================================
+// Auxiliary functions
+//===========================================================================
+void MpfrFloat::setDefaultMantissaBits(unsigned long bits)
+{
+    mpfrFloatDataContainer().setDefaultPrecision(bits);
+}
+
+unsigned long MpfrFloat::getCurrentDefaultMantissaBits()
+{
+    return mpfrFloatDataContainer().getDefaultPrecision();
+}
+
+inline void MpfrFloat::copyIfShared()
+{
+    if(mData->mRefCount > 1)
+    {
+        --(mData->mRefCount);
+        MpfrFloatData* oldData = mData;
+        mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        mpfr_set(mData->mFloat, oldData->mFloat, GMP_RNDN);
+    }
+}
+
+
+//===========================================================================
+// Constructors, destructor, assignment
+//===========================================================================
+MpfrFloat::MpfrFloat(DummyType):
+    mData(mpfrFloatDataContainer().allocateMpfrFloatData(false))
+{}
+
+MpfrFloat::MpfrFloat(MpfrFloatData* data):
+    mData(data)
+{
+    assert(data != 0);
+    ++(mData->mRefCount);
+}
+
+MpfrFloat::MpfrFloat():
+    mData(mpfrFloatDataContainer().const_0())
+{
+    ++(mData->mRefCount);
+}
+
+MpfrFloat::MpfrFloat(double value)
+{
+    if(value == 0.0)
+    {
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        mpfr_set_d(mData->mFloat, value, GMP_RNDN);
+    }
+}
+
+MpfrFloat::MpfrFloat(long double value)
+{
+    if(value == 0.0L)
+    {
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        mpfr_set_ld(mData->mFloat, value, GMP_RNDN);
+    }
+}
+
+MpfrFloat::MpfrFloat(long value)
+{
+    if(value == 0)
+    {
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        mpfr_set_si(mData->mFloat, value, GMP_RNDN);
+    }
+}
+
+MpfrFloat::MpfrFloat(int value)
+{
+    if(value == 0)
+    {
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        mpfr_set_si(mData->mFloat, value, GMP_RNDN);
+    }
+}
+
+MpfrFloat::MpfrFloat(const char* value, char** endptr):
+    mData(mpfrFloatDataContainer().allocateMpfrFloatData(false))
+{
+    mpfr_strtofr(mData->mFloat, value, endptr, 0, GMP_RNDN);
+}
+
+MpfrFloat::~MpfrFloat()
+{
+    mpfrFloatDataContainer().releaseMpfrFloatData(mData);
+}
+
+MpfrFloat::MpfrFloat(const MpfrFloat& rhs):
+    mData(rhs.mData)
+{
+    ++(mData->mRefCount);
+}
+
+MpfrFloat& MpfrFloat::operator=(const MpfrFloat& rhs)
+{
+    if(mData != rhs.mData)
+    {
+        mpfrFloatDataContainer().releaseMpfrFloatData(mData);
+        mData = rhs.mData;
+        ++(mData->mRefCount);
+    }
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator=(double value)
+{
+    if(value == 0.0)
+    {
+        mpfrFloatDataContainer().releaseMpfrFloatData(mData);
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        if(mData->mRefCount > 1)
+        {
+            --(mData->mRefCount);
+            mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        }
+        mpfr_set_d(mData->mFloat, value, GMP_RNDN);
+    }
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator=(long double value)
+{
+    if(value == 0.0L)
+    {
+        mpfrFloatDataContainer().releaseMpfrFloatData(mData);
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        if(mData->mRefCount > 1)
+        {
+            --(mData->mRefCount);
+            mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        }
+        mpfr_set_ld(mData->mFloat, value, GMP_RNDN);
+    }
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator=(long value)
+{
+    if(value == 0)
+    {
+        mpfrFloatDataContainer().releaseMpfrFloatData(mData);
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        if(mData->mRefCount > 1)
+        {
+            --(mData->mRefCount);
+            mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        }
+        mpfr_set_si(mData->mFloat, value, GMP_RNDN);
+    }
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator=(int value)
+{
+    if(value == 0)
+    {
+        mpfrFloatDataContainer().releaseMpfrFloatData(mData);
+        mData = mpfrFloatDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        if(mData->mRefCount > 1)
+        {
+            --(mData->mRefCount);
+            mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+        }
+        mpfr_set_si(mData->mFloat, value, GMP_RNDN);
+    }
+    return *this;
+}
+
+/*
+MpfrFloat& MpfrFloat::operator=(const char* value)
+{
+    if(mData->mRefCount > 1)
+    {
+        --(mData->mRefCount);
+        mData = mpfrFloatDataContainer().allocateMpfrFloatData(false);
+    }
+
+    mpfr_set_str(mData->mFloat, value, 10, GMP_RNDN);
+    return *this;
+}
+*/
+
+void MpfrFloat::parseValue(const char* value)
+{
+    copyIfShared();
+    mpfr_set_str(mData->mFloat, value, 10, GMP_RNDN);
+}
+
+void MpfrFloat::parseValue(const char* value, char** endptr)
+{
+    copyIfShared();
+    mpfr_strtofr(mData->mFloat, value, endptr, 0, GMP_RNDN);
+}
+
+
+//===========================================================================
+// Data getters
+//===========================================================================
+template<>
+void MpfrFloat::get_raw_mpfr_data<mpfr_t>(mpfr_t& dest_mpfr_t)
+{
+    std::memcpy(&dest_mpfr_t, mData->mFloat, sizeof(mpfr_t));
+}
+
+const char* MpfrFloat::getAsString(unsigned precision) const
+{
+#if(MPFR_VERSION_MAJOR < 2 || (MPFR_VERSION_MAJOR == 2 && MPFR_VERSION_MINOR < 4))
+    static const char* retval =
+        "[mpfr_snprintf() is not supported in mpfr versions prior to 2.4]";
+    return retval;
+#else
+    static std::vector<char> str;
+    str.resize(precision+30);
+    mpfr_snprintf(&(str[0]), precision+30, "%.*RNg", precision, mData->mFloat);
+    return &(str[0]);
+#endif
+}
+
+bool MpfrFloat::isInteger() const
+{
+    return mpfr_integer_p(mData->mFloat) != 0;
+}
+
+long MpfrFloat::toInt() const
+{
+    return mpfr_get_si(mData->mFloat, GMP_RNDN);
+}
+
+double MpfrFloat::toDouble() const
+{
+    return mpfr_get_d(mData->mFloat, GMP_RNDN);
+}
+
+
+//===========================================================================
+// Modifying operators
+//===========================================================================
+MpfrFloat& MpfrFloat::operator+=(const MpfrFloat& rhs)
+{
+    copyIfShared();
+    mpfr_add(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator+=(double value)
+{
+    copyIfShared();
+    mpfr_add_d(mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator-=(const MpfrFloat& rhs)
+{
+    copyIfShared();
+    mpfr_sub(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator-=(double value)
+{
+    copyIfShared();
+    mpfr_sub_d(mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator*=(const MpfrFloat& rhs)
+{
+    copyIfShared();
+    mpfr_mul(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator*=(double value)
+{
+    copyIfShared();
+    mpfr_mul_d(mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator/=(const MpfrFloat& rhs)
+{
+    copyIfShared();
+    mpfr_div(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator/=(double value)
+{
+    copyIfShared();
+    mpfr_div_d(mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return *this;
+}
+
+MpfrFloat& MpfrFloat::operator%=(const MpfrFloat& rhs)
+{
+    copyIfShared();
+    mpfr_fmod(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return *this;
+}
+
+
+//===========================================================================
+// Modifying functions
+//===========================================================================
+void MpfrFloat::negate()
+{
+    copyIfShared();
+    mpfr_neg(mData->mFloat, mData->mFloat, GMP_RNDN);
+}
+
+void MpfrFloat::abs()
+{
+    copyIfShared();
+    mpfr_abs(mData->mFloat, mData->mFloat, GMP_RNDN);
+}
+
+
+//===========================================================================
+// Non-modifying operators
+//===========================================================================
+MpfrFloat MpfrFloat::operator+(const MpfrFloat& rhs) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_add(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator+(double value) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_add_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator-(const MpfrFloat& rhs) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_sub(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator-(double value) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_sub_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator*(const MpfrFloat& rhs) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_mul(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator*(double value) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_mul_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator/(const MpfrFloat& rhs) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_div(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator/(double value) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_div_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator%(const MpfrFloat& rhs) const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_fmod(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::operator-() const
+{
+    MpfrFloat retval(kNoInitialization);
+    mpfr_neg(retval.mData->mFloat, mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+
+
+//===========================================================================
+// Comparison operators
+//===========================================================================
+bool MpfrFloat::operator<(const MpfrFloat& rhs) const
+{
+    return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) < 0;
+}
+
+bool MpfrFloat::operator<(double value) const
+{
+    return mpfr_cmp_d(mData->mFloat, value) < 0;
+}
+
+bool MpfrFloat::operator<=(const MpfrFloat& rhs) const
+{
+    return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) <= 0;
+}
+
+bool MpfrFloat::operator<=(double value) const
+{
+    return mpfr_cmp_d(mData->mFloat, value) <= 0;
+}
+
+bool MpfrFloat::operator>(const MpfrFloat& rhs) const
+{
+    return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) > 0;
+}
+
+bool MpfrFloat::operator>(double value) const
+{
+    return mpfr_cmp_d(mData->mFloat, value) > 0;
+}
+
+bool MpfrFloat::operator>=(const MpfrFloat& rhs) const
+{
+    return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) >= 0;
+}
+
+bool MpfrFloat::operator>=(double value) const
+{
+    return mpfr_cmp_d(mData->mFloat, value) >= 0;
+}
+
+bool MpfrFloat::operator==(const MpfrFloat& rhs) const
+{
+    return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) == 0;
+}
+
+bool MpfrFloat::operator==(double value) const
+{
+    return mpfr_cmp_d(mData->mFloat, value) == 0;
+}
+
+bool MpfrFloat::operator!=(const MpfrFloat& rhs) const
+{
+    return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) != 0;
+}
+
+bool MpfrFloat::operator!=(double value) const
+{
+    return mpfr_cmp_d(mData->mFloat, value) != 0;
+}
+
+
+//===========================================================================
+// Operator functions
+//===========================================================================
+MpfrFloat operator+(double lhs, const MpfrFloat& rhs)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_add_d(retval.mData->mFloat, rhs.mData->mFloat, lhs, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat operator-(double lhs, const MpfrFloat& rhs)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_d_sub(retval.mData->mFloat, lhs, rhs.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat operator*(double lhs, const MpfrFloat& rhs)
+{
+    return rhs * lhs;
+}
+
+MpfrFloat operator/(double lhs, const MpfrFloat& rhs)
+{
+    return MpfrFloat(lhs) / rhs;
+}
+
+MpfrFloat operator%(double lhs, const MpfrFloat& rhs)
+{
+    return MpfrFloat(lhs) % rhs;
+}
+
+std::ostream& operator<<(std::ostream& os, const MpfrFloat& value)
+{
+    os << value.getAsString(unsigned(os.precision()));
+    return os;
+}
+
+//===========================================================================
+// Static functions
+//===========================================================================
+MpfrFloat MpfrFloat::log(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_log(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::log2(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_log2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::log10(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_log10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::exp(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_exp(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::exp2(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_exp2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::exp10(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_exp10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::cos(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_cos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::sin(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_sin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::tan(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_tan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::sec(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_sec(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::csc(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_csc(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::cot(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_cot(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+void MpfrFloat::sincos(const MpfrFloat& value,
+                       MpfrFloat& sin,
+                       MpfrFloat& cos)
+{
+    mpfr_sin_cos(
+        sin.mData->mFloat, cos.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+}
+
+MpfrFloat MpfrFloat::acos(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_acos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::asin(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_asin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::atan(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_atan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::atan2(const MpfrFloat& value1, const MpfrFloat& value2)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_atan2(retval.mData->mFloat,
+               value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::hypot(const MpfrFloat& value1, const MpfrFloat& value2)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_hypot(retval.mData->mFloat,
+               value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::cosh(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_cosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::sinh(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_sinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::tanh(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_tanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::acosh(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_acosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::asinh(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_asinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::atanh(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_atanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::sqrt(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_sqrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::cbrt(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_cbrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::root(const MpfrFloat& value, unsigned long root)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_root(retval.mData->mFloat, value.mData->mFloat, root, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::pow(const MpfrFloat& value1, const MpfrFloat& value2)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_pow(retval.mData->mFloat,
+             value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::pow(const MpfrFloat& value, long exponent)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_pow_si(retval.mData->mFloat, value.mData->mFloat, exponent, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::abs(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_abs(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::dim(const MpfrFloat& value1, const MpfrFloat& value2)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_dim(retval.mData->mFloat,
+             value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::round(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_round(retval.mData->mFloat, value.mData->mFloat);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::ceil(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_ceil(retval.mData->mFloat, value.mData->mFloat);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::floor(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_floor(retval.mData->mFloat, value.mData->mFloat);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::trunc(const MpfrFloat& value)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_trunc(retval.mData->mFloat, value.mData->mFloat);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::parseString(const char* str, char** endptr)
+{
+    MpfrFloat retval(MpfrFloat::kNoInitialization);
+    mpfr_strtofr(retval.mData->mFloat, str, endptr, 0, GMP_RNDN);
+    return retval;
+}
+
+MpfrFloat MpfrFloat::const_pi()
+{
+    return mpfrFloatDataContainer().const_pi();
+}
+
+MpfrFloat MpfrFloat::const_e()
+{
+    return mpfrFloatDataContainer().const_e();
+}
+
+MpfrFloat MpfrFloat::const_log2()
+{
+    return mpfrFloatDataContainer().const_log2();
+}
+
+MpfrFloat MpfrFloat::someEpsilon()
+{
+    return mpfrFloatDataContainer().const_epsilon();
+}
diff --git a/fparser/mpfr/MpfrFloat.hh b/fparser/mpfr/MpfrFloat.hh
new file mode 100644 (file)
index 0000000..d455d24
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef ONCE_FP_MPFR_FLOAT_
+#define ONCE_FP_MPFR_FLOAT_
+
+#include <iostream>
+
+class MpfrFloat
+{
+ public:
+    /* A default of 256 bits will be used unless changed with this function.
+       Note that all existing and cached GMP objects will be resized to the
+       specified precision (which can be a somewhat heavy operation).
+    */
+    static void setDefaultMantissaBits(unsigned long bits);
+
+    static unsigned long getCurrentDefaultMantissaBits();
+
+    /* The default constructor initializes the object to the value 0.
+       It's efficient to instantiate such zero-initialized objects because
+       all of them will share the same mpfr data. (Also any object initialized
+       with or assigned the explicit value of zero will also share that one
+       mpfr data.) Thus multiple zero-initialized MpfrFloat instances won't
+       consume significant amounts of memory (until they are modified to
+       contain some other value, of course).
+
+       Important caveat:
+       ----------------
+       Note that initializing an MpfrFloat object with, for example, 0.1 will
+       suffer from accuracy problems (at least if the MpfrFloat object has
+       more mantissa bits than a double). The C++ double value 0.1 has only
+       53 mantissa bits, while the MpfrFloat object usually has more. If the
+       MpfrFloat object is initialized with a double, only that many bits of
+       accuracy will end up in the value of the MpfrFloat object. This can
+       create significant rounding/accuracy problems in some cases.
+       If you need to initialize the MpfrObject with some value (which cannot
+       be represented accurately by base-2 floating point numbers, eg. 0.1)
+       at full mantissa precision, you have to use parseValue("0.1") instead,
+       rather than relying on the constructor taking a double type value.
+    */
+    MpfrFloat();
+    MpfrFloat(double value);
+    MpfrFloat(long double value);
+    MpfrFloat(long value);
+    MpfrFloat(int value);
+    MpfrFloat(const char* value, char** endptr);
+
+    ~MpfrFloat();
+
+    MpfrFloat(const MpfrFloat&);
+
+    MpfrFloat& operator=(const MpfrFloat&);
+    MpfrFloat& operator=(double value);
+    MpfrFloat& operator=(long double value);
+    MpfrFloat& operator=(long value);
+    MpfrFloat& operator=(int value);
+    //MpfrFloat& operator=(const char* value);
+
+    void parseValue(const char* value);
+    void parseValue(const char* value, char** endptr);
+
+
+    /* This function can be used to retrieve the raw mpfr_t data structure
+       used by this object. (The template trick is used to avoid a dependency
+       of this header file with <mpfr.h>.)
+       In other words, it can be called like:
+
+         mpfr_t raw_mpfr_data;
+         floatValue.get_raw_mpfr_data(raw_mpfr_data);
+
+       Note that the returned mpfr_t should be considered as read-only and
+       not be modified from the outside because it may be shared among
+       several objects. If the calling code needs to modify the data, it
+       should copy it for itself first with the appropriate MPFR library
+       functions.
+     */
+    template<typename Mpfr_t>
+    void get_raw_mpfr_data(Mpfr_t& dest_mpfr_t);
+
+
+    /* Note that the returned char* points to an internal (shared) buffer
+       which will be valid until the next time this function is called
+       (by any object).
+    */
+    const char* getAsString(unsigned precision) const;
+
+    bool isInteger() const;
+    long toInt() const;
+    double toDouble() const;
+
+    MpfrFloat& operator+=(const MpfrFloat&);
+    MpfrFloat& operator+=(double);
+    MpfrFloat& operator-=(const MpfrFloat&);
+    MpfrFloat& operator-=(double);
+    MpfrFloat& operator*=(const MpfrFloat&);
+    MpfrFloat& operator*=(double);
+    MpfrFloat& operator/=(const MpfrFloat&);
+    MpfrFloat& operator/=(double);
+    MpfrFloat& operator%=(const MpfrFloat&);
+
+    void negate();
+    void abs();
+
+    MpfrFloat operator+(const MpfrFloat&) const;
+    MpfrFloat operator+(double) const;
+    MpfrFloat operator-(const MpfrFloat&) const;
+    MpfrFloat operator-(double) const;
+    MpfrFloat operator*(const MpfrFloat&) const;
+    MpfrFloat operator*(double) const;
+    MpfrFloat operator/(const MpfrFloat&) const;
+    MpfrFloat operator/(double) const;
+    MpfrFloat operator%(const MpfrFloat&) const;
+
+    MpfrFloat operator-() const;
+
+    bool operator<(const MpfrFloat&) const;
+    bool operator<(double) const;
+    bool operator<=(const MpfrFloat&) const;
+    bool operator<=(double) const;
+    bool operator>(const MpfrFloat&) const;
+    bool operator>(double) const;
+    bool operator>=(const MpfrFloat&) const;
+    bool operator>=(double) const;
+    bool operator==(const MpfrFloat&) const;
+    bool operator==(double) const;
+    bool operator!=(const MpfrFloat&) const;
+    bool operator!=(double) const;
+
+    static MpfrFloat log(const MpfrFloat&);
+    static MpfrFloat log2(const MpfrFloat&);
+    static MpfrFloat log10(const MpfrFloat&);
+    static MpfrFloat exp(const MpfrFloat&);
+    static MpfrFloat exp2(const MpfrFloat&);
+    static MpfrFloat exp10(const MpfrFloat&);
+    static MpfrFloat cos(const MpfrFloat&);
+    static MpfrFloat sin(const MpfrFloat&);
+    static MpfrFloat tan(const MpfrFloat&);
+    static MpfrFloat sec(const MpfrFloat&);
+    static MpfrFloat csc(const MpfrFloat&);
+    static MpfrFloat cot(const MpfrFloat&);
+    static void sincos(const MpfrFloat&, MpfrFloat& sin, MpfrFloat& cos);
+    static MpfrFloat acos(const MpfrFloat&);
+    static MpfrFloat asin(const MpfrFloat&);
+    static MpfrFloat atan(const MpfrFloat&);
+    static MpfrFloat atan2(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat hypot(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat cosh(const MpfrFloat&);
+    static MpfrFloat sinh(const MpfrFloat&);
+    static MpfrFloat tanh(const MpfrFloat&);
+    static MpfrFloat acosh(const MpfrFloat&);
+    static MpfrFloat asinh(const MpfrFloat&);
+    static MpfrFloat atanh(const MpfrFloat&);
+    static MpfrFloat sqrt(const MpfrFloat&);
+    static MpfrFloat cbrt(const MpfrFloat&);
+    static MpfrFloat root(const MpfrFloat&, unsigned long root);
+    static MpfrFloat pow(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat pow(const MpfrFloat&, long exponent);
+    static MpfrFloat abs(const MpfrFloat&);
+    static MpfrFloat dim(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat round(const MpfrFloat&);
+    static MpfrFloat ceil(const MpfrFloat&);
+    static MpfrFloat floor(const MpfrFloat&);
+    static MpfrFloat trunc(const MpfrFloat&);
+
+    static MpfrFloat parseString(const char* str, char** endptr);
+
+    // These values are cached (and recalculated every time the mantissa bits
+    // change), so it's efficient to call these repeatedly:
+    static MpfrFloat const_pi();
+    static MpfrFloat const_e();
+    static MpfrFloat const_log2();
+    static MpfrFloat someEpsilon();
+
+
+ private:
+    struct MpfrFloatData;
+    class MpfrFloatDataContainer;
+
+    MpfrFloatData* mData;
+
+    enum DummyType { kNoInitialization };
+    MpfrFloat(DummyType);
+    MpfrFloat(MpfrFloatData*);
+
+    void copyIfShared();
+    static MpfrFloatDataContainer& mpfrFloatDataContainer();
+
+    friend MpfrFloat operator+(double lhs, const MpfrFloat& rhs);
+    friend MpfrFloat operator-(double lhs, const MpfrFloat& rhs);
+};
+
+MpfrFloat operator+(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator-(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator*(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator/(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator%(double lhs, const MpfrFloat& rhs);
+
+inline bool operator<(double lhs, const MpfrFloat& rhs) { return rhs > lhs; }
+inline bool operator<=(double lhs, const MpfrFloat& rhs) { return rhs >= lhs; }
+inline bool operator>(double lhs, const MpfrFloat& rhs) { return rhs < lhs; }
+inline bool operator>=(double lhs, const MpfrFloat& rhs) { return rhs <= lhs; }
+inline bool operator==(double lhs, const MpfrFloat& rhs) { return rhs == lhs; }
+inline bool operator!=(double lhs, const MpfrFloat& rhs) { return rhs != lhs; }
+
+// This function takes into account the value of os.precision()
+std::ostream& operator<<(std::ostream& os, const MpfrFloat& value);
+
+#endif