summaryrefslogtreecommitdiff
path: root/fparser
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2016-07-05 18:02:38 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2016-07-05 18:02:38 +0200
commitef962f6008f25ab7cbd4ca21bcc72b97a1e2d76f (patch)
tree8149bee93d1a3f91d4503bfb3853adac4af0a85e /fparser
Imported Upstream version 0.0.34
Diffstat (limited to 'fparser')
-rw-r--r--fparser/CMakeLists.txt29
-rw-r--r--fparser/docs/fparser.html1863
-rw-r--r--fparser/docs/gpl.txt674
-rw-r--r--fparser/docs/lgpl.txt165
-rw-r--r--fparser/docs/style.css80
-rw-r--r--fparser/examples/example.cc55
-rw-r--r--fparser/examples/example2.cc85
-rw-r--r--fparser/extrasrc/fp_identifier_parser.inc379
-rw-r--r--fparser/extrasrc/fp_opcode_add.inc7696
-rw-r--r--fparser/extrasrc/fpaux.hh1238
-rw-r--r--fparser/extrasrc/fptypes.hh288
-rw-r--r--fparser/fparser.cc3800
-rw-r--r--fparser/fparser.hh223
-rw-r--r--fparser/fparser.pro35
-rw-r--r--fparser/fparser_gmpint.hh15
-rw-r--r--fparser/fparser_mpfr.hh15
-rw-r--r--fparser/fpconfig.hh88
-rw-r--r--fparser/fpoptimizer.cc11745
-rw-r--r--fparser/mpfr/GmpInt.cc710
-rw-r--r--fparser/mpfr/GmpInt.hh148
-rw-r--r--fparser/mpfr/MpfrFloat.cc976
-rw-r--r--fparser/mpfr/MpfrFloat.hh206
22 files changed, 30513 insertions, 0 deletions
diff --git a/fparser/CMakeLists.txt b/fparser/CMakeLists.txt
new file mode 100644
index 0000000..434218a
--- /dev/null
+++ b/fparser/CMakeLists.txt
@@ -0,0 +1,29 @@
+
+# define build type
+SET( CMAKE_BUILD_TYPE Release )
+
+PROJECT(fparser CXX)
+
+cmake_minimum_required(VERSION 2.8)
+
+# default
+set(LIB_VERSION_MAJOR 4)
+set(LIB_VERSION_MINOR 5)
+set(LIB_VERSION_PATCH 1)
+set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH})
+
+set(VERSION "v${LIB_VERSION_STRING}")
+
+#set(HEADERS fparser.hh fpconfig.hh fptypes.hh)
+set(SOURCES fparser.cc fpoptimizer.cc)
+
+remove(CMAKE_CXX_FLAGS -Dfparser_EXPORTS)
+
+ADD_LIBRARY(fparser SHARED ${SOURCES})
+
+set_target_properties(fparser PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_MAJOR})
+
+INSTALL(TARGETS fparser DESTINATION lib${LIB_SUFFIX})
+
+INSTALL(FILES fparser.hh DESTINATION include)
+
diff --git a/fparser/docs/fparser.html b/fparser/docs/fparser.html
new file mode 100644
index 0000000..ffc73f4
--- /dev/null
+++ b/fparser/docs/fparser.html
@@ -0,0 +1,1863 @@
+<!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.5.1 : Documentation</title>
+</head>
+
+<body>
+<h1>Function Parser for C++ v4.5.1 </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_AddFunction3"><code>AddFunctionWrapper()</code></a>
+ <li><a href="#longdesc_RemoveIdentifier"><code>RemoveIdentifier()</code></a>
+ <li><a href="#longdesc_ParseAndDeduceVariables"><code>ParseAndDeduceVariables()</code></a>
+ </ul>
+ <li><a href="#functionobjects">Specialized function objects</a>
+ <li><a href="#base">FunctionParserBase</a>
+ </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="#fpaccuracy">About floating point accuracy</a>
+ <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.5.1
+ <ul>
+ <li>Reverted the automatic C++11 detection to a precompiler macro setting
+ (<code>FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS</code>) because not all
+ compilers yet fully support the C++11 math functions.
+ <li>Fixed a potential duplicate symbol problem that happens with explicit
+ template instantiations.
+ </ul>
+
+<p>What's new in v4.5
+ <ul>
+ <li>Removed support for the <code>"eval()"</code> function from the
+ supported syntax. (This function was too dangerous, too difficult to
+ maintain internally, not very useful, and more or less a gimmick in
+ the first place.)
+ <li>Removed several of the conditional compiling macro definitions, namely
+ <code>FP_SUPPORT_TR1_MATH</code>, <code>FP_ENABLE_EVAL</code>,
+ <code>FP_EVAL_MAX_REC_LEVEL</code>, <code>FP_NO_EVALUATION_CHECKS</code>
+ and <code>FP_EPSILON</code>.
+ <li>The epsilon value used in comparisons is now set with a member function
+ of FunctionParser (which allows setting different values for different
+ versions of the parser).
+ <li>The math functions previously turned on with
+ <code>FP_SUPPORT_TR1_MATH</code> are now automatically used if
+ <code>__cplusplus</code> indicates that C++11 is in use.
+ <li>Fixed some compilation problems with clang++.
+ </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>,
+ <code>std::complex</code> (of types <code>double</code>,
+ <code>float</code> and <code>long double</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 inside the <code>extrasrc</code> subdirectory
+(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 <code>extrasrc</code> subdirectory.
+
+<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 every parser that is
+ included in the compilation process will make the compilation slower
+ and increase the size of the executable, so they are compiled only on
+ demand. Also, the GMP and MPFR versions of the parser require for those
+ libraries to be available, which is often not the case.)
+
+<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.
+ </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.
+ <p>Note that the <code>FP_USE_STRTOLD</code> preprocessor macro should
+ also be defined when using this version of the parser if the compiler
+ supports the (C99) function <code>strtold()</code>. (See
+ <a href="#configuring">documentation</a> below.)
+ </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_cd</code>, <code>FunctionParser_cf</code>,
+ <code>FunctionParser_cld</code></dt>
+ <dd>
+ <p>These parsers use <code>std::complex&lt;double&gt;</code>,
+ <code>std::complex&lt;float&gt;</code> and
+ <code>std::complex&lt;long&nbsp;double&gt;</code> as their numerical type,
+ respectively.
+ <p>The preprocessor macros to enable them are
+ <code>FP_SUPPORT_COMPLEX_DOUBLE_TYPE</code>,
+ <code>FP_SUPPORT_COMPLEX_FLOAT_TYPE</code> and
+ <code>FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE</code>.
+ <p>If <code>FunctionParser_cld</code> is used, the
+ <code>FP_USE_STRTOLD</code> macro should also be defined if the compiler
+ supports the <code>strtold()</code> function.
+ </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_USE_STRTOLD</code> : (Default off)</dt>
+ <dd><p>If <code>FunctionParser_ld</code> or <code>FunctionParser_cld</code>
+ are used, this preprocessor macro should be defined if the compiler
+ supports the (C99) function <code>strtold()</code>. If not, then numeric
+ literals will be parsed with double precision only, which in most
+ systems is less accurate than long double precision, which will cause
+ small rounding errors. (This setting has no effect on the other parser
+ types.) Note that <code>strtold()</code> will also be automatically used
+ if <code>__cplusplus</code> indicates that C++11 is in use.
+ </dd>
+
+ <dt><p><code>FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS</code> : (Default off)</dt>
+ <dd><p>Use C++11 math functions where applicable. (These are ostensibly
+ faster than the equivalent formulas using C++98 math functions.) Note
+ that not all compilers support these functions (even if they otherwise
+ support C++11.)
+
+ <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_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>
+</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>
+static double epsilon();
+static void setEpsilon(double);
+</pre>
+
+<p>Setter and getter for the epsilon value used with comparison operators.
+
+<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_Epsilon"></a>
+<pre>
+static double epsilon();
+static void setEpsilon(double);
+</pre>
+
+<p>Comparison operators (for the non-integral versions of the parser) use an
+epsilon value to account for floating point calculation rounding errors.
+This epsilon value can be set and read with these functions. (Note that the
+specified value will be used by all instances of FunctionParser.) If not
+specified, the default values are:
+
+<ul>
+ <li>double: 1e-12
+ <li>float: 1e-5
+ <li>long double: 1e-14
+ <li>MpfrFloat: The value of MpfrFloat::someEpsilon()
+</ul>
+
+
+<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_AddFunction3"></a>
+<pre>
+template&lt;typename DerivedWrapper&gt;
+bool AddFunctionWrapper(const std::string& name, const DerivedWrapper&,
+ unsigned paramsAmount);
+</pre>
+
+<p>See section on <a href="#functionobjects">specialized function objects</a>.
+
+<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.
+
+<!-- -------------------------------------------------------------------- -->
+<a name="functionobjects"></a>
+<h3>Specialized function objects</h3>
+
+<p>The <code>AddFunction()</code> method can be used to add a new user-defined
+function to the parser, its implementation being called through a C++ function
+pointer. Sometimes this might not be enough, though. For example, one might
+want to use <code>boost::function</code> or other similar specialized stateful
+function objects instead of raw function pointers. This library provides a
+mechanism to achieve this.
+
+<h4>Creating and adding a specialized function object</h4>
+
+<p>In order to create a specialized function object, create a class derived
+from the <code>FunctionParser::FunctionWrapper</code> class. This class
+declares a virtual function named <code>callFunction</code> that the derived
+class must implement. For example:
+
+<pre>
+class MyFunctionWrapper:
+ public FunctionParser::FunctionWrapper
+{
+ public:
+ virtual double callFunction(const double* values)
+ {
+ // Perform the actual function call here, like:
+ return someFunctionSomewhere(values);
+
+ // In principle the result could also be
+ // calculated here, like for example:
+ return values[0] * values[0];
+ }
+};
+</pre>
+
+<p>You can then add an instance of this class to <code>FunctionParser</code>
+using the <code>AddFunctionWrapper()</code> method, which works like
+<code>AddFunction()</code>, but takes a wrapper object instead of a function
+pointer as parameter. For example:
+
+<pre>
+MyFunctionWrapper wrapper;
+parser.AddFunctionWrapper("funcName", wrapper, 1);
+</pre>
+
+<p>Note that <code>FunctionParser</code> will internally create a copy of
+the wrapper object, managing the lifetime of this copy, and thus the object
+given as parameter does not need to exist for as long as the
+<code>FunctionParser</code> instance. Hence the above could also be written as:
+
+<pre>
+parser.AddFunctionWrapper("funcName", MyFunctionWrapper(), 1);
+</pre>
+
+<p>Note that this also means that the wrapper class must have a working
+copy constructor.
+
+<p>Also note that if the <code>FunctionParser</code> instance is copied, all
+the copies will share the same function wrapper objects given to the original.
+
+<h4>Retrieving specialized function objects</h4>
+
+<p>As noted, the library will internally make a copy of the wrapper object,
+and thus it will be separate from the one which was given as parameter to
+<code>AddFunctionWrapper()</code>. In some cases it may be necessary to
+retrieve this wrapper object (for example to read or change its state).
+This can be done with the <code>GetFunctionWrapper()</code> method, which
+takes the name of the function and returns a pointer to the wrapper object,
+or null if no such object exists with that name.
+
+<p>Note that the returned pointer will be of type
+<code>FunctionParser::FunctionWrapper</code>. In order to get a pointer to
+the actual derived type, the calling code should perform a
+<code>dynamic_cast</code>, for example like this:
+
+<pre>
+MyFunctionWrapper* wrapper =
+ dynamic_cast&lt;MyFunctionWrapper*&gt;
+ (parser.GetFunctionWrapper("funcName"));
+
+if(!wrapper) { /* oops, the retrieval failed */ }
+else ...
+</pre>
+
+<p>(Using dynamic cast rather than a static cast adds safety because if you
+accidentally try to downcast to the wrong type, the pointer will become null.)
+
+<p>The calling code is free to modify the object in any way it wants, but it
+must not delete it (because <code>FunctionParser</code> itself handles this).
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="base"></a>
+<h3>FunctionParserBase</h3>
+
+<p>All the different parser types are derived from a templated base class
+named <code>FunctionParserBase</code>. In normal use it's not necessary to
+directly refer to this base class in the calling code. However, if the calling
+code also needs to be templated (with respect to the numerical type), then
+using <code>FunctionParserBase</code> directly is the easiest way to achieve
+this.
+
+<p>For example, if you want to make a function that handles more than one
+type of parser, it can be done like this:
+
+<pre>
+template&lt;typename Value_t&gt;
+void someFunction(FunctionParserBase&lt;Value_t&gt& parser)
+{
+ // do something with 'parser' here
+}
+</pre>
+
+<p>Now it's convenient to call that function with more than one type of
+parser, for example:
+
+<pre>
+FunctionParser realParser;
+FunctionParser_cd complexParser;
+
+someFunction(realParser);
+someFunction(complexParser);
+</pre>
+
+<p>Another example is a class that inherits from <code>FunctionParser</code>
+which also wants to support different numerical types. Such class can be
+declared as:
+
+<pre>
+template&lt;typename Value_t&gt;
+class SpecializedParser: public FunctionParserBase&lt;Value_t&gt;
+{
+ ...
+};
+</pre>
+
+
+<!-- -------------------------------------------------------------------- -->
+<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).
+
+<p>With the complex versions of the library, the imaginary part of a numeric
+ literal is written as a regular numeric literal with an '<code>i</code>'
+ appended, for example "<code>5i</code>". Note that when also specifying
+ the real part of a complex literal, parentheses should be used to avoid
+ precedence problems. (For example, "<code>(2+5i)&nbsp;*&nbsp;x</code>"
+ is not the same thing as "<code>2+5i&nbsp;*&nbsp;x</code>". The latter
+ would be equivalent to "<code>2 + (5i&nbsp;*&nbsp;x)</code>".)
+
+<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 (magnitude) of A.
+ With real numbers, if A is negative, returns -A otherwise returns A.
+ With complex numbers, equivalent to <code>hypot(real(x),imag(x))</code>.</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>arg(A)</code></td>
+ <td>Phase angle of complex number A. Equivalent to <code>atan2(imag(x),real(x))</code>.</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>Principal arc-tangent of A/B, using the signs of the
+ two arguments to determine the quadrant of the result.
+ Returns the solution to the two expressions
+ hypot(A,B)*sin(x)=A, hypot(A,B)*cos(x)=B.
+ The return value is in range -pi to pi, inclusive.</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 a solution to expression pow(x,3)=A.</td>
+</tr><tr>
+ <td><code>conj(A)</code></td>
+ <td>Complex conjugate of A. Equivalent to <code>real(x) - 1i*imag(x)</code> or <code>polar(abs(x),-arg(x))</code>.</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 <code>1/tan(A)</code>.</td>
+</tr><tr>
+ <td><code>csc(A)</code></td>
+ <td>Cosecant of A. Equivalent to <code>1/sin(A)</code>.</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>exp2(A)</code></td>
+ <td>Base 2 exponential of A. Equivalent to <code>pow(2,A)</code>.</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>hypot(A,B)</code></td>
+ <td>Euclidean distance function. Equivalent to <code>sqrt(A^2+B^2)</code>.</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>imag(A)</code></td>
+ <td>Return the imaginary part of complex number A. Equivalent to <code>abs(A)*sin(arg(A))</code>.</td>
+</tr><tr>
+ <td><code>int(A)</code></td>
+ <td>Rounds A to the closest integer. Equidistant values are rounded away from
+ zero. E.g. -2.9 and -2.5 are rounded to -3.0; -2.1 is 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. Returns the solution to expression exp(x)=A.</td>
+</tr><tr>
+ <td><code>log2(A)</code></td>
+ <td>Base 2 logarithm of A. Equivalent to <code>log(A)/log(2)</code>.</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>polar(A,B)</code></td>
+ <td>Returns a complex number from magnitude A, phase angle B (in radians).
+ Equivalent to <code>real(A)*(cos(real(B))+1i*sin(real(B)))</code>.</td>
+</tr><tr>
+ <td><code>pow(A,B)</code></td>
+ <td>Exponentiation (A raised to the power B).</td>
+</tr><tr>
+ <td><code>real(A)</code></td>
+ <td>Return the real part of complex number A. Equivalent to <code>abs(A)*cos(arg(A))</code>.</td>
+</tr><tr>
+ <td><code>sec(A)</code></td>
+ <td>Secant of A. Equivalent to <code>1/cos(A)</code>.</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 a solution to expression pow(x,2)=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="fpaccuracy"></a>
+<h3>About floating point accuracy</h3>
+
+<p>Note that if you are using <code>FunctionParser_ld</code> or
+<code>FunctionParser_cld</code> and you want calculations to be as accurate
+as the <code>long double</code> type allows, you should pay special attention
+to floating point literals in your own code. For example, this is a very
+typical mistake:
+
+<pre>FunctionParser_ld parser;
+parser.AddConstant("pi", 3.14159265358979323846);</pre>
+
+<p>The mistake might not be immediately apparent. The mistake is that a
+literal of type <code>double</code> is passed to the <code>AddConstant()</code>
+function even though it expects a value of type <code>long&nbsp;double</code>.
+In most systems the latter has more bits of precision than the former, which
+means that the value will have its least-significant bits clipped,
+introducing a rounding error. The proper way of making the above calls is:
+
+<pre>FunctionParser_ld parser;
+parser.AddConstant("pi", 3.14159265358979323846L);</pre>
+
+<p>The same principle should be used everywhere in your own code, if you are
+using the <code>long&nbsp;double</code> type.
+
+<p>This is especially important if you are using the <code>MpfrFloat</code>
+type (in which case its string-parsing constructor or its
+<code>ParseValue()</code> or <code>parseString()</code> member functions
+should be used instead of using numerical literals).
+
+<a name="evaluationchecks"></a>
+<h3>About evaluation-time checks</h3>
+
+<p><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>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-2011 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
index 0000000..94a9ed0
--- /dev/null
+++ b/fparser/docs/gpl.txt
@@ -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
index 0000000..cca7fc2
--- /dev/null
+++ b/fparser/docs/lgpl.txt
@@ -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
index 0000000..d5141d3
--- /dev/null
+++ b/fparser/docs/style.css
@@ -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
index 0000000..b4ab5f4
--- /dev/null
+++ b/fparser/examples/example.cc
@@ -0,0 +1,55 @@
+// Simple example file for the function parser
+// ===========================================
+
+/* When running the program, try for example with these values:
+
+f(x) = x^2
+min x: -5
+max x: 5
+step: 1
+
+*/
+
+#include "../fparser.hh"
+
+#include <iostream>
+#include <string>
+
+int main()
+{
+ std::string function;
+ double minx, maxx, step;
+ FunctionParser fparser;
+
+ fparser.AddConstant("pi", 3.1415926535897932);
+
+ while(true)
+ {
+ std::cout << "f(x) = ";
+ std::getline(std::cin, function);
+ if(std::cin.fail()) return 0;
+
+ 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 0;
+
+ double vals[] = { 0 };
+ for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)
+ {
+ std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)
+ << std::endl;
+ }
+
+ return 0;
+}
diff --git a/fparser/examples/example2.cc b/fparser/examples/example2.cc
new file mode 100644
index 0000000..958b9a1
--- /dev/null
+++ b/fparser/examples/example2.cc
@@ -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/extrasrc/fp_identifier_parser.inc b/fparser/extrasrc/fp_identifier_parser.inc
new file mode 100644
index 0000000..7489fd0
--- /dev/null
+++ b/fparser/extrasrc/fp_identifier_parser.inc
@@ -0,0 +1,379 @@
+/* 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 lO l3 lH
+#define lN switch(
+#define lM l4 lH
+#define lL if('i' l5
+#define lK 'n' l5
+#define lJ 0x80000003U;
+#define lI l1 3]={
+#define lH case
+#define lG 0x80000005U;
+#define lF )==0)l0(
+#define lE l8 3;}lH
+#define lD std::memcmp(uptr+
+#define lC l2 3 lF
+#define lB lA 1]){lH
+#define lA :lN uptr[
+#define l9 'a' lB
+#define l8 default:l0
+#define l7 lG l0 5;}lH
+#define l6 <<16)|
+#define l5 ==uptr[
+#define l4 lJ l0 3;
+#define l3 0x80000004U;l0 4;
+#define l2 lD 1,tmp,
+#define l1 static const char tmp[
+#define l0 return
+lN
+nameLength){lH
+2:lL
+0]&&'f' l5
+1])l0(cIf
+l6
+0x80000002U;l0
+2;lH
+3
+lA
+0]){lH
+l9'b':if('s' l5
+2])l0(cAbs
+l6
+lM'r':if('g' l5
+2])l0(cArg
+l6
+l4
+lE'c' lB'o' lA
+2]){lH's':l0(cCos
+l6
+lJ
+lH't':l0(cCot
+l6
+lJ
+lE's':if('c' l5
+2])l0(cCsc
+l6
+l4
+lE'e':if('x' l5
+1]&&'p' l5
+2])l0(cExp
+l6
+lM'i':if(lK
+1]&&'t' l5
+2])l0(cInt
+l6
+lM'l':if('o' l5
+1]&&'g' l5
+2])l0(cLog
+l6
+lM'm' lB'a':if('x' l5
+2])l0(cMax
+l6
+lM'i':if(lK
+2])l0(cMin
+l6
+l4
+lE'p':if('o' l5
+1]&&'w' l5
+2])l0(cPow
+l6
+lM's' lB'e':if('c' l5
+2])l0(cSec
+l6
+lM'i':if(lK
+2])l0(cSin
+l6
+l4
+lE't':if('a' l5
+1]&&lK
+2])l0(cTan
+l6
+l4
+lE
+4
+lA
+0]){lH
+l9'c':if('o' l5
+2]&&'s' l5
+3])l0(cAcos
+l6
+lO's':lL
+2]&&lK
+3])l0(cAsin
+l6
+lO't':if('a' l5
+2]&&lK
+3])l0(cAtan
+l6
+l3
+l8
+4;}
+lH'c' lB'b':if('r' l5
+2]&&'t' l5
+3])l0(cCbrt
+l6
+lO'e':lL
+2]&&'l' l5
+3])l0(cCeil
+l6
+lO'o' lA
+2]){lH'n':if('j' l5
+3])l0(cConj
+l6
+lO's':if('h' l5
+3])l0(cCosh
+l6
+l3
+l8
+4;}
+l8
+4;}
+lH'e':{lI'x','p','2'}
+;if(lC
+cExp2
+l6
+l3}
+lH'i':{lI'm','a','g'}
+;if(lC
+cImag
+l6
+l3}
+lH'l':{lI'o','g','2'}
+;if(lC
+cLog2
+l6
+l3}
+lH'r':{lI'e','a','l'}
+;if(lC
+cReal
+l6
+l3}
+lH's' lB'i':if(lK
+2]&&'h' l5
+3])l0(cSinh
+l6
+lO'q':if('r' l5
+2]&&'t' l5
+3])l0(cSqrt
+l6
+l3
+l8
+4;}
+lH't':{lI'a','n','h'}
+;if(lC
+cTanh
+l6
+l3}
+l8
+4;}
+lH
+5
+lA
+0]){lH
+l9'c':{lI'o','s','h'}
+;if(lD
+2,tmp,3
+lF
+cAcosh
+l6
+l7's':{lI'i','n','h'}
+;if(lD
+2,tmp,3
+lF
+cAsinh
+l6
+l7't':if('a' l5
+2]){if(lK
+3]){lN
+uptr[4]){lH'2':l0(cAtan2
+l6
+lG
+lH'h':l0(cAtanh
+l6
+lG
+l8
+5;}
+}
+l0
+5;}
+l0
+5;l8
+5;}
+lH'f':{l1
+4]={'l','o','o','r'}
+;if(l2
+4
+lF
+cFloor
+l6
+l7'h':{l1
+4]={'y','p','o','t'}
+;if(l2
+4
+lF
+cHypot
+l6
+l7'l':{l1
+4]={'o','g','1','0'}
+;if(l2
+4
+lF
+cLog10
+l6
+l7'p':{l1
+4]={'o','l','a','r'}
+;if(l2
+4
+lF
+cPolar
+l6
+l7't':{l1
+4]={'r','u','n','c'}
+;if(l2
+4
+lF
+cTrunc
+l6
+lG
+l0
+5;}
+l8
+5;}
+default:break;}
+l0
+nameLength;
diff --git a/fparser/extrasrc/fp_opcode_add.inc b/fparser/extrasrc/fp_opcode_add.inc
new file mode 100644
index 0000000..ed05b22
--- /dev/null
+++ b/fparser/extrasrc/fp_opcode_add.inc
@@ -0,0 +1,7696 @@
+/* Function Parser for C++ v4.5.1
+
+ 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 HasInvalidRangesOpcode HasInvalidRangesOpcode<IsComplexType<Value_t>::result>
+#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(mData->mNamePtrs,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 qH1 " B" mF
+#define qG1 gT y*x;
+#define qF1 hV 2;qI
+#define qE1 <<"," aD
+#define qD1 <<"," aB
+#define qC1 "cNeg"
+#define qB1 wA"," aD
+#define qA1 "x[x!=Value_t(0)] "
+#define q91 <<"," a8
+#define q81 wA"," a1
+#define q71 );qW q6
+#define q61 "cPow "
+#define q51 "cSqrt"
+#define q41 "cSqr "
+#define q31 " cExp2"
+#define q21 "cExp "
+#define q11 ){hD wB
+#define q01 "cCeil"
+#define mZ "cImag"
+#define mY "cConj"
+#define mX "cDup "
+#define mW hO wB
+#define mV "cAbs"
+#define mU wQ wH" "
+#define mT qS w2 wB
+#define mS "cFloor"
+#define mR "cTan"
+#define mQ " cDup"
+#define mP "cSin"
+#define mO (y hX;
+#define mN "[ y+x]"
+#define mM hV 2 gC
+#define mL " cExp"
+#define mK "A " wX
+#define mJ "cLess"
+#define mI "[-x]" wH
+#define mH "cDiv" a7
+#define mG "cLog"
+#define mF " cDiv"
+#define mE " " a6
+#define mD " " aF
+#define mC "cMin"
+#define mB "cMax"
+#define mA aY"x "
+#define m9 gN wB
+#define m8 "x cPow"
+#define m7 g1 oG wB
+#define m6 (x);gJ
+#define m5 "B cSqr"
+#define m4 oH dE wB
+#define m3 "[y*x]" wH
+#define m2 "cGreater"
+#define m1 mV" " wL
+#define m0 "cNeg "
+#define aZ " cAdd"
+#define aY "y "
+#define aX "B[IsVarOpcode(B)] "
+#define aW " cSub"
+#define aV gY if(dO wB
+#define aU "cInv"
+#define aT mX aU
+#define aS "cAbsNot"
+#define aR "cLessOrEq"
+#define aQ "cAdd " q51
+#define aP "[y*x] cPow"
+#define aO "cCos"
+#define aN "cLog2"
+#define aM "cCosh"
+#define aL "cLog10"
+#define aK "B[B==A]"
+#define aJ "cNotNot"
+#define aI " " a2
+#define aH "cDup" aZ
+#define aG "cGreaterOrEq"
+#define aF "x" aZ
+#define aE "cEqual"
+#define aD " " aC
+#define aC "A" wY
+#define aB " " wU
+#define aA " cNeg"
+#define a9 " cRDiv"
+#define a8 " B" wY
+#define a7 " x" wH
+#define a6 "cRSub"
+#define a5 "A[IsVarOpcode(A)]"
+#define a4 "x[x!=Value_t()] "
+#define a3 " " a5" "
+#define a2 " with" aD
+#define a1 " " wG
+#define a0 " cNot"
+#define wZ "x[x==Value_t()]" wH
+#define wY " " wC
+#define wX "[x]" wH
+#define wW "cNEqual"
+#define wV a5 mF
+#define wU "x = "<<x
+#define wT "x[isInteger(x)] cPow"
+#define wS a5 wH
+#define wR "x[x!=Value_t(0)]" mF
+#define wQ "x[x>Value_t(0)]"
+#define wP "B[IsNeverNegativeValueOpcode(B)] "
+#define wO "x[x==Value_t(1)] "
+#define wN wA"\n"
+#define wM <<"\n"
+#define wL "x[x==Value_t(0)] "
+#define wK "B[IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " wD
+#define wJ "A[IsNeverNegativeValueOpcode(A)] "
+#define wI "A[IsVarOpcode(A)&&mData->mByteCode.size()>2] "
+#define wH " cMul"
+#define wG aY"= "<<y wM
+#define wF " x A[IsComparisonOpcode(A)]"
+#define wE FP_TRACE_BYTECODE_ADD
+#define wD "A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " wZ
+#define wC "= "<<FP_TRACE_OPCODENAME
+#define wB FP_TRACE_BYTECODE_OPTIMIZATION
+#define wA " with" aB<<
+#define w9 qT q6:
+#define w8 cEqual
+#define w7 Lbd gY
+#define w6 Lcb gY
+#define w5 opcode
+#define w4 B==A){
+#define w3 q5 q4
+#define w2 cExp:
+#define w1 qO A qP
+#define w0 qO h2
+#define oZ qF g1
+#define oY if dC
+#define oX fp_pow(
+#define oW fp_log(
+#define oV 3 gC A
+#define oU x==g1 oG
+#define oT gX Lml;
+#define oS q4 Lbo
+#define oR 3 gH
+#define oQ cSinh:
+#define oP g1 0)
+#define oO 0.5)){
+#define oN Ldn;qT
+#define oM ]==h3){
+#define oL qY g8 0
+#define oK .size()
+#define oJ );qE
+#define oI A oJ dU
+#define oH g7 A=
+#define oG 1)){
+#define oF qU hI
+#define oE Lbo oF
+#define oD qT hM hB
+#define oC qL 3]
+#define oB :hC qQ oC
+#define oA cSub oB d3 hJ
+#define o9 q7=-x
+#define o8 gX Loi;
+#define o7 );qF
+#define o6 qE A o7
+#define o5 h3 d4 qL
+#define o4 fp_log2(
+#define o3 ==cSqr){
+#define o2 qT cSqr:
+#define o1 cGreater
+#define o0 Default6
+#define dZ Default5
+#define dY Default2
+#define dX Default1
+#define dW ImmedPtr
+#define dV gA qZ qC
+#define dU h3);
+#define dT gC dU
+#define dS cNotNot
+#define dR fp_log10(
+#define dQ cAbs);
+#define dP fp_abs(x)
+#define dO x>oP){
+#define dN mImmed
+#define dM qE h3 gX
+#define dL qK dJ w3
+#define dK cGreaterOrEq
+#define dJ =q6;
+#define dI qK dJ g6
+#define dH Value_t
+#define dG q8 2 gH q4
+#define dF q0[0]
+#define dE qK qR qX
+#define dD qK qR IsLogicalOpcode(h2
+#define dC (qK==
+#define dB hB oY
+#define dA qY g8 oG
+#define d9 pop_back()
+#define d8 q6;q1 h3 gI
+#define d7 q8 2 gC
+#define d6 hR Lba;
+#define d5 Default4 qU
+#define d4 :if(
+#define d3 qV hS d4 qL
+#define d2 h3 gM if
+#define d1 IsVarOpcode(
+#define d0 mData->
+#define hZ ]qR w4
+#define hY gX Llq
+#define hX ,x gX Lap
+#define hW gT y+x;q8
+#define hV for qA
+#define hU gQ cAbs:
+#define hT unsigned
+#define hS cAdd
+#define hR ,y gX
+#define hQ qL 3 hZ
+#define hP y=q3-1]qR
+#define hO y gO
+#define hN qY if(dP
+#define hM q6:qC
+#define hL :if gF
+#define hK qQ h9 hS hL
+#define hJ 4 qZ mW(292,aY"cAdd B[IsVarOpcode(B)]" aW mD,mN aZ" B" aW,wA"," a8(B)<<"," a1);q4
+#define hI cNeg:
+#define hH :qS cDup:
+#define hG hS hH hK h1 wB(310,aH" " aH,"[Value_t(4)]" wH,);q4
+#define hF (x!=g1
+#define hE qL 2]
+#define hD B g4 w4
+#define hC B=hE qO B)){
+#define hB if hF 0)){
+#define hA gX Lng;
+#define h9 qK qV
+#define h8 }break;
+#define h7 <dH>()){
+#define h6 hR Lap;
+#define h5 isEvenInteger(
+#define h4 DegreesToRadians(x
+#define h3 cMul
+#define h2 A)){
+#define h1 ]==cDup){
+#define h0 hI wB(201,m0 mV,mV,);q4 Lab qU qB
+#define gZ 3 h1 wB(311,aH wH" " aH,"cMul [Value_t(4)]" wH,);q4
+#define gY qU hM
+#define gX );q4
+#define gW y,x gX Lba;
+#define gV IsUnaryOpcode(
+#define gU g6 w5=
+#define gT q3-1]=
+#define gS gR qR IsAlwaysIntegerOpcode(h2
+#define gR ;oH dF
+#define gQ )){qQ h9
+#define gP break gR qO A gQ
+#define gO =q3-1];
+#define gN qJ hO
+#define gM :qJ qC
+#define gL d2(dO
+#define gK ]=q6 q9 2 gH
+#define gJ return;
+#define gI );w5=
+#define gH ;qI q5
+#define gG qL 2 gK q0-=2;
+#define gF (qL 2
+#define gE y;hT B;hT
+#define gD d0 mByteCode
+#define gC ;qI q1
+#define gB q9 2 gC h3 gI
+#define gA ){if gF
+#define g9 oY h3 dV
+#define g8 if(x==g1
+#define g7 default:
+#define g6 q5 q0-=1;
+#define g5 if(!q0){q2
+#define g4 =hE qR
+#define g3 B g4 IsNeverNegativeValueOpcode(B)){
+#define g2 &&!HasInvalidRangesOpcode(
+#define g1 dH(
+#define g0 FP_ReDefinePointers();
+#define qZ ]==q6){
+#define qY if(q0[0 qZ qC
+#define qX IsNeverNegativeValueOpcode(h2
+#define qW gD qD
+#define qV ){case
+#define qU ;case
+#define qT }break qU
+#define qS qQ dF qV
+#define qR ;if(
+#define qQ switch(
+#define qP )&&gD oK>
+#define qO qR d1
+#define qN dF w1 2){
+#define qM d0 dN.d9;
+#define qL q0[-
+#define qK qL 1]
+#define qJ oY q6){
+#define qI tmp-->0;)
+#define qH q4 Default0;
+#define qG }}qH
+#define qF d0 dN qD
+#define qE AddFunctionOpcode(
+#define qD .push_back(
+#define qC x=q7;
+#define qB hM wB(132,"x " mV,"[fp_abs(x)]",wN);q4 Lac;
+#define qA (hT tmp=
+#define q9 ;hV
+#define q8 d0 dN.d9 q9
+#define q7 q3 0]
+#define q6 cImmed
+#define q5 gD.d9;
+#define q4 goto
+#define q3 dW[
+#define q2 q4 Laa;}case
+#define q1 q5 qE
+#define q0 ByteCodePtr
+hT*q0;dH*dW;
+#define FP_ReDefinePointers() q0=!gD.empty()?&gD[0]+gD oK-1:0;dW=!d0 dN.empty()?&d0 dN[0]+d0 dN oK-1:0;
+g0
+wE(opcode);
+#if(!(FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION))
+dH
+x;hT
+A;dH
+gE
+C;hT
+D;qQ
+w5){TailCall_cAbs:g5
+cAbs:qS
+h0
+oH
+dF
+qR
+qX
+wB(393,wJ
+mV,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cAdd:g5
+hG
+Lad;qT
+h3
+hL]==hS){if(qL
+gZ
+Lae;}
+h8}
+q4
+dX
+qU
+d2
+gF
+h1
+wB(313,"cDup"
+a7
+aZ,"[x+Value_t(1)]"
+wH,wN);q4
+Laf;}
+}
+q4
+dX
+oF
+wB(199,qC1
+aZ,"cSub"
+,);q4
+Lag
+gY
+hK
+qZ
+mW(127,aY"cAdd"
+mD,"[y+x]"
+aZ,q81);q4
+Lah;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mW(298,aY"cAdd"
+mE
+mD,mN
+aZ
+mE,q81);q4
+Lai;qT
+hI
+wB(299,m0
+a6
+mD,"[-x]"
+aZ
+mE,wN);q4
+Laj
+qU
+q6:mW(297,aY
+a6
+mD,mN
+mE,q81);q4
+Lak;qT
+oA
+Lal;qT
+hI
+wB(293,m0"B[IsVarOpcode(B)]"
+aW
+mD,"[-x]"
+aZ" B"
+aW,wA","
+a8(B)wM);q4
+Lam
+qU
+q6:mW(291,aY"B[IsVarOpcode(B)]"
+aW
+mD,mN" B"
+aW,wA","
+a8(B)<<","
+a1);q4
+Lan;}
+w9
+mW(105,aY
+aF,"[y+x]"
+,q81);q4
+Lao;}
+g8)){wB(57,"x[x==Value_t()]"
+aZ,,wN);q4
+Lap;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x"
+mE
+a3"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aZ
+mE,aI(A)qD1
+wM);incStackPtr();--mStackPtr;q4
+Laq;}
+wB(295,a6
+a3"cAdd"
+,"[DO_STACKPLUS1] A"
+aZ
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lba;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mX"cAnd"
+,aJ,);q4
+Lbb
+gY
+m9(117,mA"cAnd"
+,"[fp_and(x,y)]"
+,q81);q4
+Lbc;h8}
+qH
+TailCall_cDiv:g5
+cDiv
+hH
+wB(78,"cDup"
+mF,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,);q4
+w7
+if
+hF
+gQ
+hI
+wB(125,m0
+a4"cDiv"
+,"[-x]"
+mF,wN);q4
+Lbe
+qU
+q6:mW(103,aY
+a4"cDiv"
+,"[y/x]"
+,q81);q4
+Lbf;}
+}
+g8
+oG
+wB(56,wO"cDiv"
+,,wN);q4
+Lap;h8}
+qH
+TailCall_cEqual:g5
+w8:dA
+A=dD
+wB(421,"A[IsLogicalOpcode(A)] "
+wO
+aE,"A"
+,qB1(A)wM);q4
+Lap;}
+}
+m9(115,mA
+aE,"[fp_equal(y,x)]"
+,q81);q4
+Lbg;}
+g8
+0
+hU
+wB(359,m1
+aE,"[x] "
+aE,wN);q4
+Lbh
+qU
+cSqr:wB(361,q41
+wL
+aE,"[x] "
+aE,wN);q4
+Lbh;}
+wB(411,wL
+aE,"cNot"
+,wN);q4
+Lbi;qG
+TailCall_cGreater:g5
+o1:oL
+hU
+wB(413,m1
+m2,aJ,wN);q4
+Lbj;m4(417,wJ
+wL
+m2,"A "
+aJ,qB1(A)wM);q4
+Lbk;}
+}
+}
+m9(113,mA
+m2,"[fp_less(x,y)]"
+,q81);q4
+Lbl;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+g8
+1
+hU
+wB(414,mV" "
+wO
+aG,aJ,wN);q4
+Lbj;m4(418,wJ
+wO
+aG,"A "
+aJ,qB1(A)wM);q4
+Lbk;}
+}
+}
+m9(114,mA
+aG,"[fp_lessOrEq(x,y)]"
+,q81);q4
+Lbm;qG
+TailCall_cInv:g5
+cInv:qY
+if
+hF)){wB(101,a4
+aU,"[Value_t(1)/x]"
+,wN);q4
+Lbn;qG
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mJ,mK,qB1(A)wM);oS;}
+}
+g8
+1
+hU
+wB(415,mV" "
+wO
+mJ,"cNot"
+,wN);q4
+Lbp;m4(419,wJ
+wO
+mJ,"A"
+a0,qB1(A)wM);q4
+Lbi;}
+}
+}
+m9(111,mA
+mJ,"[fp_less(y,x)]"
+,q81);q4
+Lbq;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:oL
+hU
+wB(416,m1
+aR,"cNot"
+,wN);q4
+Lbp;m4(420,wJ
+wL
+aR,"A"
+a0,qB1(A)wM);q4
+Lbi;}
+}
+}
+m9(112,mA
+aR,"[fp_lessOrEq(y,x)]"
+,q81);q4
+Lca;qG
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mX
+mB,,);q4
+w6
+m9(141,mA
+mB,"[fp_max(x,y)]"
+,q81);q4
+Lcc;}
+gP
+cDup:hD
+wB(66,aK
+mQ
+a3
+mB,"B"
+mQ,aI(A)q91(B)wM);q4
+Lcb;qT
+cMax:hD
+wB(68,aK" "
+mB
+a3
+mB,"B "
+mB,aI(A)q91(B)wM);q4
+Lcb;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mX
+mC,,);q4
+w6
+m9(140,mA
+mC,"[fp_min(x,y)]"
+,q81);q4
+Lcd;}
+gP
+cDup:hD
+wB(65,aK
+mQ
+a3
+mC,"B"
+mQ,aI(A)q91(B)wM);q4
+Lcb;qT
+cMin:hD
+wB(67,aK" "
+mC
+a3
+mC,"B "
+mC,aI(A)q91(B)wM);q4
+Lcb;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m9(104,aY
+a4"cMod"
+,"[fp_mod(y,x)]"
+,q81);q4
+Lce;}
+qG
+TailCall_cMul:g5
+h3
+hH
+wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lcf
+oF
+qQ
+h9
+cDup:wB(467,"cDup"
+aA
+wH,"cSqr"
+aA,);q4
+Lcg;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aK
+wH
+a3
+qC1
+wH,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lch;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mX
+m8
+wH,"[x+Value_t(1)] cPow"
+,wN);q4
+Lci;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wS" "
+wZ,wX,qB1(A)wM);q4
+Lcj;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mW(92,aY
+wD,wX,qB1(A)<<","
+a1);q4
+Lck;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mW(96,aY
+wK,mK,qB1(A)q91(B)<<","
+a1);q4
+Lcl;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lcm;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lcn;}
+}
+}
+if(d1
+B)){wB(90,aX
+wD,wX,qB1(A)q91(B)wM);q4
+Lcj;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mK,qB1(A)q91(B)wM);q4
+Lco;}
+}
+}
+if(d1
+h2
+wB(88,a5" "
+wZ,"[x]"
+,qB1(A)wM);q4
+Lcp;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wZ,wX,qB1(A)wM);q4
+Lcq;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup:wB(317,aH
+a7,"[x+x]"
+wH,wN);q4
+Lda
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,a5" y"
+wH
+aZ
+a7,wX" A "
+m3
+aZ,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Ldb;}
+w9
+mW(385,aY"cAdd"
+a7,wX" [y*x]"
+aZ,q81);q4
+Ldc;qT
+h3:qQ
+hE
+d3
+3
+h1
+wB(319,aH
+wH
+a7,"cMul [x+x]"
+wH,wN);q4
+Ldd;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+a7,,q81);q4
+Lde;}
+wB(128,"y"
+wH
+a7,m3,q81);q4
+Ldf;qT
+hI
+wB(122,qC1
+a7,mI,wN);q4
+Ldg
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,a5" y"
+wH
+aW
+a7,wX" A "
+m3
+aW,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Ldh;}
+}
+w9
+mW(102,"y"
+a7,"[y*x]"
+,q81);q4
+Ldi;}
+g8
+oG
+wB(55,"x[x==Value_t(1)]"
+wH,,wN);q4
+Lap;}
+g8-oG
+wB(124,"x[x==Value_t(-1)]"
+wH,qC1,wN);q4
+Ldj;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,aH,wN);q4
+Ldk;h8
+g7
+dY:;A=dF
+qO
+A
+gQ
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aK
+aA
+wH" "
+wS,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lch;}
+q4
+Default4;g7
+Default4:;hD
+wB(461,aK
+wH" "
+wS,m5
+wH,aI(A)q91(B)wM);q4
+Ldl;}
+}
+q4
+dZ
+oF
+hD
+wB(464,aK
+aA" "
+wS,m5
+aA,aI(A)q91(B)wM);q4
+Lcg;}
+q4
+dZ;g7
+dZ:;B=qK
+qR
+w4
+wB(458,aK" "
+wS,m5,aI(A)q91(B)wM);q4
+Lcf;}
+}
+}
+if(gV
+h2
+B=qK
+qO
+B
+qP
+1
+gA
+oM
+C=oC
+qR
+C==A){D=qL
+4]qR
+D==B){wB(477,"D[D==B] C[C==A]"
+wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Ldm;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:dA
+A=dD
+wB(422,"A[IsLogicalOpcode(A)] "
+wO
+wW,"A"
+a0,qB1(A)wM);q4
+Lbi;}
+}
+m9(116,mA
+wW,"[fp_nequal(y,x)]"
+,q81);q4
+Ldn;}
+g8
+0
+hU
+wB(360,m1
+wW,"[x] "
+wW,wN);q4
+Ldo
+qU
+cSqr:wB(362,q41
+wL
+wW,"[x] "
+wW,wN);q4
+Ldo;}
+wB(412,wL
+wW,aJ,wN);q4
+Lbk;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+wH
+aA,mI,wN);q4
+Ldp;qT
+hI
+wB(61,qC1
+aA,,);q4
+w6
+wB(100,"x"
+aA,"[-x]"
+,wN);q4
+Ldq;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbs:wB(227,mV
+a0,"cNot"
+,);q4
+Lea
+qU
+cAbsNot:A=dD
+wB(389,"A[IsLogicalOpcode(A)] "
+aS
+a0,"A"
+,aI(A)wM);q4
+Lcb;}
+if(A!=q6){wB(390,"A[A!=cImmed] "
+aS
+a0,"A cAbsNotNot"
+,aI(A)wM);q4
+Leb;}
+q4
+o0
+qU
+cAbsNotNot:wB(231,"cAbsNotNot"
+a0,aS,);q4
+Lec
+qU
+hS
+gM
+wB(424,aF
+a0,"[-x] "
+aE,wN);q4
+Led;}
+q4
+o0
+qU
+w8:wB(220,aE
+a0,wW,);q4
+Lee
+qU
+o1:wB(218,m2
+a0,aR,);q4
+Lef
+qU
+dK:wB(219,aG
+a0,mJ,);q4
+Leg
+qU
+cLess:wB(216,mJ
+a0,aG,);q4
+Leh
+qU
+cLessOrEq:wB(217,aR
+a0,m2,);q4
+Lei
+qU
+cNEqual:wB(221,wW
+a0,aE,);q4
+Lej
+oF
+wB(226,qC1
+a0,"cNot"
+,);q4
+Lea
+qU
+cNot:wB(229,"cNot"
+a0,aJ,);q4
+Lbb
+qU
+dS:wB(230,aJ
+a0,"cNot"
+,);q4
+Lea
+gY
+wB(107,"x"
+a0,"[fp_not(x)]"
+,wN);q4
+Lek;g7
+o0:;A=dF
+qR
+qX
+wB(391,wJ"cNot"
+,"A "
+aS,aI(A)wM);q4
+Lel;qG
+TailCall_cNotNot:g5
+dS:qS
+hS
+gM
+wB(423,aF" "
+aJ,"[-x] "
+wW,wN);q4
+Lem;qT
+cNot:wB(232,"cNot "
+aJ,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mX"cOr"
+,aJ,);q4
+Lbb
+gY
+m9(118,mA"cOr"
+,"[fp_or(x,y)]"
+,q81);q4
+Len;h8}
+qH
+TailCall_cRDiv:g5
+cRDiv:dA
+wB(268,wO"cRDiv"
+,aU,wN);q4
+Leo;qG
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,"cDup"
+mE,"[Value_t()]"
+wH,);q4
+Lep;}
+qH
+TailCall_cSqr:g5
+cSqr:qS
+cAbs:wB(204,mV" cSqr"
+,"cSqr"
+,);q4
+Leq
+oF
+wB(203,m0"cSqr"
+,"cSqr"
+,);q4
+Leq;}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,"cDup"
+aW,"[Value_t()]"
+wH,);q4
+Lep
+oF
+wB(200,qC1
+aW,"cAdd"
+,);q4
+Lfa
+gY
+g8)){wB(58,"x[x==Value_t()]"
+aW,,wN);q4
+Lap;}
+m9(106,aY"x"
+aW,"[y-x]"
+,q81);q4
+Lfb;}
+wB(51,"x"
+aW,"[-x]"
+aZ,wN);q4
+Lfc
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x"
+mE
+a3"cSub"
+,"A"
+aZ" [x]"
+mE,aI(A)qD1
+wM);q4
+Lfd;}
+wB(296,a6
+a3"cSub"
+,"[DO_STACKPLUS1] A"
+aW
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lfe;}
+qG
+g7
+Default0:;A=w5
+qR
+IsComparisonOpcode(h2
+qY
+hK
+qZ
+mW(364,aY"cAdd"
+wF,"[x-y] A"
+,aI(A)qD1<<","
+a1);q4
+Lff;qT
+hI
+wB(365,qC1
+wF,"[-x] {OppositeComparisonOpcode(A)}"
+,aI(A)qD1
+wM);q4
+Lfg;}
+}
+}
+if(d1
+A
+qP
+0){B=q0[0
+hZ
+wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mQ,aI(A)q91(B)wM);q4
+Lfh;}
+}
+if(gV
+h2
+B=dF
+qO
+B
+qP
+1){C=qK
+qR
+C==A){D
+g4
+D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+,"D C"
+mQ,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Lfi;}
+}
+}
+}
+}
+q4
+Laa;Laa:qW
+w5);gJ
+Lab:g6
+wE(cAbs);q4
+TailCall_cAbs;Lac:q7=dP;gJ
+Lad:oZ
+4));gG
+Lfj:w5=h3;Lfk:g0
+Lfl:wE(cMul);q4
+TailCall_cMul;Lae:hV
+4
+dT
+oZ
+4)q71
+gX
+Lfj;Laf:q7=x+g1
+1);gG
+Lbo:w5=h3;q4
+Lfl;Lag:gU
+cSub;Lfm:wE(cSub);q4
+TailCall_cSub;Lah:hW
+2
+gH
+Lfn:g0
+Lfo:wE(cAdd);q4
+TailCall_cAdd;Lai:hW
+oR
+Lfp:qE
+hS);Lfq:w5=cRSub;g0
+wE(cRSub);q4
+TailCall_cRSub;Laj:o9;qL
+2
+gK
+q4
+Lfp;Lak:hW
+2
+gH
+q4
+Lfq;Lal:hW
+4
+gH
+Lga:qE
+hS);Lgb:qE
+B);Lgc:w5=cSub;g0
+q4
+Lfm;Lam:o9;oC=q6
+q9
+oR
+q4
+Lga;Lan:hW
+oR
+q4
+Lgb;Lao:gT
+y+x;Lap:qM
+Lcb:q5
+gJ
+Laq:q8
+oV
+o7
+x
+q71
+gX
+Lfp;Lba:mM
+A
+gX
+Lfp;Lbb:gU
+dS;Lgd:wE(cNotNot);q4
+TailCall_cNotNot;Lbc:gT
+fp_and(x
+h6
+Lbd:oZ));dF
+dJ
+qE
+dU
+oZ
+1));Lge:qW
+q6);Lgf:w5=hS;q4
+Lfn;Lbe:o9;dI
+wE(cDiv);q4
+TailCall_cDiv;Lbf:gT
+y/x;q4
+Lap;Lbg:gT
+fp_equal
+mO
+Lbh:dI
+Lgg:wE(cEqual);q4
+TailCall_cEqual;Lbi:qM
+q5
+Lgh:w5=cNot;g0
+Lgi:wE(cNot);q4
+TailCall_cNot;Lbj:q8
+2
+gH
+Lgj:w5=dS;g0
+q4
+Lgd;Lbk:qM
+w3
+Lgj;Lbl:gT
+fp_less(x
+h6
+Lbm:gT
+fp_lessOrEq(x
+h6
+Lbn:q7=g1
+1)/x;gJ
+Lbp:dG
+Lgh;Lbq:gT
+fp_less
+mO
+Lca:gT
+fp_lessOrEq
+mO
+Lcc:gT
+fp_max(x
+h6
+Lcd:gT
+fp_min(x
+h6
+Lce:gT
+fp_mod
+mO
+Lcf:gU
+cSqr;Lgk:wE(cSqr);q4
+TailCall_cSqr;Lcg:mM
+cSqr);Lgl:w5=cNeg;g0
+wE(cNeg);q4
+TailCall_cNeg;Lch:hV
+3
+gC
+cSqr);dM
+Lgl;Lci:q7=x+g1
+1);hE=q6
+q9
+2
+gC
+cPow);gJ
+Lcj:gG
+q4
+Lfl;Lck:gT
+x;Lgm:dG
+Lfk;Lcl:qF1
+qM
+Lgn:hV
+4
+gH
+Lgo:o6
+x);Lgp:qW
+q6
+gX
+Lfk;Lcm:qM
+q4
+Lgn;Lcn:q8
+4
+gC
+B
+gX
+Lgo;Lco:q8
+oR
+q4
+Lgo;Lcp:qK
+dJ
+q4
+Lcb;Lcq:dI
+q4
+Lfl;Lda:q7=x+x;q4
+Lcj;Ldb:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Lgf;Ldc:gT
+x;d7
+dU
+qF
+y*x
+gX
+Lge;Ldd:q8
+4
+dT
+qF
+x+x
+gX
+Lgp;Lde:qF1
+q8
+oR
+gJ
+Ldf:qG1
+q4
+Lgm;Ldg:o9;q4
+Lcq;Ldh:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Lgc;Ldi:qG1
+q4
+Lap;Ldj:qM
+w3
+Lgl;Ldk:dF=cDup;dW-=1;qM
+Lgq:w5=hS;q4
+Lfo;Ldl:hV
+2
+gH
+Lha:qE
+cSqr
+gX
+Lfk;Ldm:hV
+oR
+q4
+Lha;Ldn:gT
+fp_nequal
+mO
+Ldo:dI
+Lhb:wE(cNEqual);q4
+TailCall_cNEqual;Ldp:o9;g6
+oS;Ldq:o9;gJ
+Lea:g6
+q4
+Lgi;Leb:q1
+cAbsNotNot);gJ
+Lec:q5
+Lel:qE
+cAbsNot);gJ
+Led:o9;Lej:gU
+w8;q4
+Lgg;Lee:gU
+cNEqual;q4
+Lhb;Lef:gU
+cLessOrEq;wE(cLessOrEq);q4
+TailCall_cLessOrEq;Leg:gU
+cLess;wE(cLess);q4
+TailCall_cLess;Leh:gU
+dK;wE(cGreaterOrEq);q4
+TailCall_cGreaterOrEq;Lei:gU
+o1;wE(cGreater);q4
+TailCall_cGreater;Lek:q7=fp_not
+m6
+Lem:o9;q4
+Lee;Len:gT
+fp_or(x
+h6
+Leo:qM
+q5
+w5=cInv;g0
+wE(cInv);q4
+TailCall_cInv;Lep:oZ));dF
+dJ
+q4
+Lfj;Leq:g6
+q4
+Lgk;Lfa:g6
+q4
+Lgq;Lfb:gT
+y-x;q4
+Lap;Lfc:o9;q4
+Lgq;Lfd:q8
+oV
+oJ
+hS
+o7
+x
+q71
+gX
+Lfq;Lfe:mM
+A
+oJ
+cSub
+gX
+Lfq;Lff:gT
+x-y;d7
+A);gJ
+Lfg:o9;qK
+dJ
+q1
+OppositeComparisonOpcode(A));gJ
+Lfh:qW
+cDup);gJ
+Lfi:dF=cDup;gJ
+gJ
+q4
+TailCall_cAnd;q4
+TailCall_cMax;q4
+TailCall_cMin;q4
+TailCall_cMod;q4
+TailCall_cNeg;q4
+TailCall_cOr;q4
+TailCall_cRDiv;q4
+TailCall_cSub;
+#endif
+#if((FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION))
+dH
+x;dH
+gE
+A;hT
+C;hT
+D;qQ
+w5){TailCall_cAbs:g5
+cAbs:qS
+h0}
+qH
+TailCall_cAdd:g5
+hG
+Lad;qT
+h3
+hL]==hS){if(qL
+gZ
+Lae;}
+h8}
+q4
+dX
+qU
+d2
+gF
+h1
+wB(313,"cDup"
+a7
+aZ,"[x+Value_t(1)]"
+wH,wN);q4
+Laf;}
+}
+q4
+dX
+oF
+wB(199,qC1
+aZ,"cSub"
+,);q4
+Lag
+gY
+hK
+qZ
+mW(127,aY"cAdd"
+mD,"[y+x]"
+aZ,q81);q4
+Lah;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mW(298,aY"cAdd"
+mE
+mD,mN
+aZ
+mE,q81);q4
+Lai;qT
+hI
+wB(299,m0
+a6
+mD,"[-x]"
+aZ
+mE,wN);q4
+Laj
+qU
+q6:mW(297,aY
+a6
+mD,mN
+mE,q81);q4
+Lak;qT
+oA
+Lal;qT
+hI
+wB(293,m0"B[IsVarOpcode(B)]"
+aW
+mD,"[-x]"
+aZ" B"
+aW,wA","
+a8(B)wM);q4
+Lam
+qU
+q6:mW(291,aY"B[IsVarOpcode(B)]"
+aW
+mD,mN" B"
+aW,wA","
+a8(B)<<","
+a1);q4
+Lan;}
+w9
+mW(105,aY
+aF,"[y+x]"
+,q81);q4
+Lao;}
+g8)){wB(57,"x[x==Value_t()]"
+aZ,,wN);q4
+Lap;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x"
+mE
+a3"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aZ
+mE,aI(A)qD1
+wM);incStackPtr();--mStackPtr;q4
+Laq;}
+wB(295,a6
+a3"cAdd"
+,"[DO_STACKPLUS1] A"
+aZ
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lba;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mX"cAnd"
+,aJ,);q4
+Lbb
+gY
+m9(117,mA"cAnd"
+,"[fp_and(x,y)]"
+,q81);q4
+Lbc;h8}
+qH
+TailCall_cConj:g5
+cConj:qS
+cConj:wB(63,mY" "
+mY,,);q4
+w7
+wB(193,"x "
+mY,"[fp_conj(x)]"
+,wN);q4
+Lbe;}
+qH
+TailCall_cDiv:g5
+cDiv
+hH
+wB(78,"cDup"
+mF,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,);q4
+Lbf
+gY
+if
+hF
+gQ
+hI
+wB(125,m0
+a4"cDiv"
+,"[-x]"
+mF,wN);q4
+Lbg
+qU
+q6:mW(103,aY
+a4"cDiv"
+,"[y/x]"
+,q81);q4
+Lbh;}
+}
+g8
+oG
+wB(56,wO"cDiv"
+,,wN);q4
+Lap;h8}
+qH
+TailCall_cEqual:g5
+w8:dA
+A=dD
+wB(421,"A[IsLogicalOpcode(A)] "
+wO
+aE,"A"
+,qB1(A)wM);q4
+Lap;}
+}
+m9(115,mA
+aE,"[fp_equal(y,x)]"
+,q81);q4
+Lbi;}
+g8
+0
+hU
+wB(359,m1
+aE,"[x] "
+aE,wN);q4
+Lbj
+qU
+cSqr:wB(361,q41
+wL
+aE,"[x] "
+aE,wN);q4
+Lbj;}
+wB(411,wL
+aE,"cNot"
+,wN);q4
+Lbk;qG
+TailCall_cGreater:g5
+o1:qY
+m9(113,mA
+m2,"[fp_less(x,y)]"
+,q81);q4
+Lbl;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+m9(114,mA
+aG,"[fp_lessOrEq(x,y)]"
+,q81);q4
+Lbm;qG
+TailCall_cImag:g5
+cImag:qS
+cAbs:wB(81,mV" "
+mZ,"[Value_t()]"
+wH,);q4
+Lbn
+qU
+cReal:wB(80,"cReal "
+mZ,"[Value_t()]"
+wH,);q4
+Lbn
+gY
+wB(192,"x "
+mZ,"[fp_imag(x)]"
+,wN);oS;}
+qH
+TailCall_cInv:g5
+cInv:qY
+if
+hF)){wB(101,a4
+aU,"[Value_t(1)/x]"
+,wN);q4
+Lbp;qG
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mJ,mK,qB1(A)wM);q4
+Lbq;}
+}
+m9(111,mA
+mJ,"[fp_less(y,x)]"
+,q81);q4
+Lca;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:qY
+m9(112,mA
+aR,"[fp_lessOrEq(y,x)]"
+,q81);q4
+Lcb;qG
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mX
+mB,,);q4
+w7
+m9(141,mA
+mB,"[fp_max(x,y)]"
+,q81);q4
+Lcc;}
+gP
+cDup:hD
+wB(66,aK
+mQ
+a3
+mB,"B"
+mQ,aI(A)q91(B)wM);q4
+Lbd;qT
+cMax:hD
+wB(68,aK" "
+mB
+a3
+mB,"B "
+mB,aI(A)q91(B)wM);q4
+Lbd;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mX
+mC,,);q4
+w7
+m9(140,mA
+mC,"[fp_min(x,y)]"
+,q81);q4
+Lcd;}
+gP
+cDup:hD
+wB(65,aK
+mQ
+a3
+mC,"B"
+mQ,aI(A)q91(B)wM);q4
+Lbd;qT
+cMin:hD
+wB(67,aK" "
+mC
+a3
+mC,"B "
+mC,aI(A)q91(B)wM);q4
+Lbd;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m9(104,aY
+a4"cMod"
+,"[fp_mod(y,x)]"
+,q81);q4
+Lce;}
+qG
+TailCall_cMul:g5
+h3
+hH
+wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lcf
+oF
+qQ
+h9
+cDup:wB(467,"cDup"
+aA
+wH,"cSqr"
+aA,);q4
+Lcg;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aK
+wH
+a3
+qC1
+wH,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lch;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mX
+m8
+wH,"[x+Value_t(1)] cPow"
+,wN);q4
+Lci;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wS" "
+wZ,wX,qB1(A)wM);q4
+Lcj;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mW(92,aY
+wD,wX,qB1(A)<<","
+a1);q4
+Lck;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mW(96,aY
+wK,mK,qB1(A)q91(B)<<","
+a1);q4
+Lcl;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lcm;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lcn;}
+}
+}
+if(d1
+B)){wB(90,aX
+wD,wX,qB1(A)q91(B)wM);q4
+Lcj;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mK,qB1(A)q91(B)wM);q4
+Lco;}
+}
+}
+if(d1
+h2
+wB(88,a5" "
+wZ,"[x]"
+,qB1(A)wM);q4
+Lcp;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wZ,wX,qB1(A)wM);q4
+Lcq;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup:wB(317,aH
+a7,"[x+x]"
+wH,wN);q4
+Lda
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,a5" y"
+wH
+aZ
+a7,wX" A "
+m3
+aZ,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Ldb;}
+w9
+mW(385,aY"cAdd"
+a7,wX" [y*x]"
+aZ,q81);q4
+Ldc;qT
+h3:qQ
+hE
+d3
+3
+h1
+wB(319,aH
+wH
+a7,"cMul [x+x]"
+wH,wN);q4
+Ldd;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+a7,,q81);q4
+Lde;}
+wB(128,"y"
+wH
+a7,m3,q81);q4
+Ldf;qT
+hI
+wB(122,qC1
+a7,mI,wN);q4
+Ldg
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,a5" y"
+wH
+aW
+a7,wX" A "
+m3
+aW,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Ldh;}
+}
+w9
+mW(102,"y"
+a7,"[y*x]"
+,q81);q4
+Ldi;}
+g8
+oG
+wB(55,"x[x==Value_t(1)]"
+wH,,wN);q4
+Lap;}
+g8-oG
+wB(124,"x[x==Value_t(-1)]"
+wH,qC1,wN);q4
+Ldj;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,aH,wN);q4
+Ldk;h8
+g7
+dY:;A=dF
+qO
+A
+gQ
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aK
+aA
+wH" "
+wS,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lch;}
+q4
+Default4;g7
+Default4:;hD
+wB(461,aK
+wH" "
+wS,m5
+wH,aI(A)q91(B)wM);q4
+Ldl;}
+}
+q4
+dZ
+oF
+hD
+wB(464,aK
+aA" "
+wS,m5
+aA,aI(A)q91(B)wM);q4
+Lcg;}
+q4
+dZ;g7
+dZ:;B=qK
+qR
+w4
+wB(458,aK" "
+wS,m5,aI(A)q91(B)wM);q4
+Lcf;}
+}
+}
+if(gV
+h2
+B=qK
+qO
+B
+qP
+1
+gA
+oM
+C=oC
+qR
+C==A){D=qL
+4]qR
+D==B){wB(477,"D[D==B] C[C==A]"
+wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Ldm;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:dA
+A=dD
+wB(422,"A[IsLogicalOpcode(A)] "
+wO
+wW,"A"
+a0,qB1(A)wM);q4
+Lbk;}
+}
+m9(116,mA
+wW,"[fp_nequal(y,x)]"
+,q81);q4
+Ldn;}
+g8
+0
+hU
+wB(360,m1
+wW,"[x] "
+wW,wN);q4
+Ldo
+qU
+cSqr:wB(362,q41
+wL
+wW,"[x] "
+wW,wN);q4
+Ldo;}
+wB(412,wL
+wW,aJ,wN);q4
+Ldp;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+wH
+aA,mI,wN);q4
+Ldq;qT
+hI
+wB(61,qC1
+aA,,);q4
+w7
+wB(100,"x"
+aA,"[-x]"
+,wN);q4
+Lea;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbsNotNot:wB(231,"cAbsNotNot"
+a0,aS,);q4
+Leb
+qU
+hS
+gM
+wB(424,aF
+a0,"[-x] "
+aE,wN);q4
+Lec;qT
+w8:wB(220,aE
+a0,wW,);q4
+Led
+qU
+o1:wB(218,m2
+a0,aR,);q4
+Lee
+qU
+dK:wB(219,aG
+a0,mJ,);q4
+Lef
+qU
+cLess:wB(216,mJ
+a0,aG,);q4
+Leg
+qU
+cLessOrEq:wB(217,aR
+a0,m2,);q4
+Leh
+qU
+cNEqual:wB(221,wW
+a0,aE,);q4
+Lei
+qU
+cNot:wB(229,"cNot"
+a0,aJ,);q4
+Lbb
+qU
+dS:wB(230,aJ
+a0,"cNot"
+,);q4
+Lej
+gY
+wB(107,"x"
+a0,"[fp_not(x)]"
+,wN);q4
+Lek;}
+qH
+TailCall_cNotNot:g5
+dS:qS
+hS
+gM
+wB(423,aF" "
+aJ,"[-x] "
+wW,wN);q4
+Lel;qT
+cNot:wB(232,"cNot "
+aJ,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mX"cOr"
+,aJ,);q4
+Lbb
+gY
+m9(118,mA"cOr"
+,"[fp_or(x,y)]"
+,q81);q4
+Lem;h8}
+qH
+TailCall_cRDiv:g5
+cRDiv:dA
+wB(268,wO"cRDiv"
+,aU,wN);q4
+Len;qG
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,"cDup"
+mE,"[Value_t()]"
+wH,);q4
+Lbn;}
+qH
+TailCall_cReal:g5
+cReal:qY
+wB(191,"x cReal"
+,"[fp_real(x)]"
+,wN);q4
+Leo;}
+qH
+TailCall_cSqr:g5
+cSqr:qS
+cAbs:wB(204,mV" cSqr"
+,"cSqr"
+,);q4
+Lep
+oF
+wB(203,m0"cSqr"
+,"cSqr"
+,);q4
+Lep;}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,"cDup"
+aW,"[Value_t()]"
+wH,);q4
+Lbn
+oF
+wB(200,qC1
+aW,"cAdd"
+,);q4
+Leq
+gY
+g8)){wB(58,"x[x==Value_t()]"
+aW,,wN);q4
+Lap;}
+m9(106,aY"x"
+aW,"[y-x]"
+,q81);q4
+Lfa;}
+wB(51,"x"
+aW,"[-x]"
+aZ,wN);q4
+Lfb
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x"
+mE
+a3"cSub"
+,"A"
+aZ" [x]"
+mE,aI(A)qD1
+wM);q4
+Lfc;}
+wB(296,a6
+a3"cSub"
+,"[DO_STACKPLUS1] A"
+aW
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lfd;}
+qG
+g7
+Default0:;A=w5
+w1
+0){B=q0[0
+hZ
+wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mQ,aI(A)q91(B)wM);q4
+Lfe;}
+}
+if(gV
+h2
+B=dF
+qO
+B
+qP
+1){C=qK
+qR
+C==A){D
+g4
+D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+,"D C"
+mQ,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Lff;}
+}
+}
+}
+}
+q4
+Laa;Laa:qW
+w5);gJ
+Lab:g6
+wE(cAbs);q4
+TailCall_cAbs;Lac:q7=dP;gJ
+Lad:oZ
+4));gG
+Lfg:w5=h3;Lfh:g0
+Lfi:wE(cMul);q4
+TailCall_cMul;Lae:hV
+4
+dT
+oZ
+4)q71
+gX
+Lfg;Laf:q7=x+g1
+1);gG
+Lbq:w5=h3;q4
+Lfi;Lag:gU
+cSub;Lfj:wE(cSub);q4
+TailCall_cSub;Lah:hW
+2
+gH
+Lfk:g0
+Lfl:wE(cAdd);q4
+TailCall_cAdd;Lai:hW
+oR
+Lfm:qE
+hS);Lfn:w5=cRSub;g0
+wE(cRSub);q4
+TailCall_cRSub;Laj:o9;qL
+2
+gK
+q4
+Lfm;Lak:hW
+2
+gH
+q4
+Lfn;Lal:hW
+4
+gH
+Lfo:qE
+hS);Lfp:qE
+B);Lfq:w5=cSub;g0
+q4
+Lfj;Lam:o9;oC=q6
+q9
+oR
+q4
+Lfo;Lan:hW
+oR
+q4
+Lfp;Lao:gT
+y+x;Lap:qM
+Lbd:q5
+gJ
+Laq:q8
+oV
+o7
+x
+q71
+gX
+Lfm;Lba:mM
+A
+gX
+Lfm;Lbb:gU
+dS;Lga:wE(cNotNot);q4
+TailCall_cNotNot;Lbc:gT
+fp_and(x
+h6
+Lbe:q7=fp_conj
+m6
+Lbf:oZ));dF
+dJ
+qE
+dU
+oZ
+1));Lgb:qW
+q6);Lgc:w5=hS;q4
+Lfk;Lbg:o9;dI
+wE(cDiv);q4
+TailCall_cDiv;Lbh:gT
+y/x;q4
+Lap;Lbi:gT
+fp_equal
+mO
+Lbj:dI
+Lgd:wE(cEqual);q4
+TailCall_cEqual;Lbk:qM
+q5
+w5=cNot;g0
+Lge:wE(cNot);q4
+TailCall_cNot;Lbl:gT
+fp_less(x
+h6
+Lbm:gT
+fp_lessOrEq(x
+h6
+Lbn:oZ));dF
+dJ
+q4
+Lfg;Lbo:q7=fp_imag
+m6
+Lbp:q7=g1
+1)/x;gJ
+Lca:gT
+fp_less
+mO
+Lcb:gT
+fp_lessOrEq
+mO
+Lcc:gT
+fp_max(x
+h6
+Lcd:gT
+fp_min(x
+h6
+Lce:gT
+fp_mod
+mO
+Lcf:gU
+cSqr;Lgf:wE(cSqr);q4
+TailCall_cSqr;Lcg:mM
+cSqr);Lgg:w5=cNeg;g0
+wE(cNeg);q4
+TailCall_cNeg;Lch:hV
+3
+gC
+cSqr);dM
+Lgg;Lci:q7=x+g1
+1);hE=q6
+q9
+2
+gC
+cPow);gJ
+Lcj:gG
+q4
+Lfi;Lck:gT
+x;Lgh:dG
+Lfh;Lcl:qF1
+qM
+Lgi:hV
+4
+gH
+Lgj:o6
+x);Lgk:qW
+q6
+gX
+Lfh;Lcm:qM
+q4
+Lgi;Lcn:q8
+4
+gC
+B
+gX
+Lgj;Lco:q8
+oR
+q4
+Lgj;Lcp:qK
+dJ
+q4
+Lbd;Lcq:dI
+q4
+Lfi;Lda:q7=x+x;q4
+Lcj;Ldb:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Lgc;Ldc:gT
+x;d7
+dU
+qF
+y*x
+gX
+Lgb;Ldd:q8
+4
+dT
+qF
+x+x
+gX
+Lgk;Lde:qF1
+q8
+oR
+gJ
+Ldf:qG1
+q4
+Lgh;Ldg:o9;q4
+Lcq;Ldh:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Lfq;Ldi:qG1
+q4
+Lap;Ldj:qM
+w3
+Lgg;Ldk:dF=cDup;dW-=1;qM
+Lgl:w5=hS;q4
+Lfl;Ldl:hV
+2
+gH
+Lgm:qE
+cSqr
+gX
+Lfh;Ldm:hV
+oR
+q4
+Lgm;Ldn:gT
+fp_nequal
+mO
+Ldo:dI
+Lgn:wE(cNEqual);q4
+TailCall_cNEqual;Ldp:qM
+q5
+w5=dS;g0
+q4
+Lga;Ldq:o9;g6
+q4
+Lbq;Lea:o9;gJ
+Leb:q1
+cAbsNot);gJ
+Lec:o9;Lei:gU
+w8;q4
+Lgd;Led:gU
+cNEqual;q4
+Lgn;Lee:gU
+cLessOrEq;wE(cLessOrEq);q4
+TailCall_cLessOrEq;Lef:gU
+cLess;wE(cLess);q4
+TailCall_cLess;Leg:gU
+dK;wE(cGreaterOrEq);q4
+TailCall_cGreaterOrEq;Leh:gU
+o1;wE(cGreater);q4
+TailCall_cGreater;Lej:g6
+q4
+Lge;Lek:q7=fp_not
+m6
+Lel:o9;q4
+Led;Lem:gT
+fp_or(x
+h6
+Len:qM
+q5
+w5=cInv;g0
+wE(cInv);q4
+TailCall_cInv;Leo:q7=fp_real
+m6
+Lep:g6
+q4
+Lgf;Leq:g6
+q4
+Lgl;Lfa:gT
+y-x;q4
+Lap;Lfb:o9;q4
+Lgl;Lfc:q8
+oV
+oJ
+hS
+o7
+x
+q71
+gX
+Lfn;Lfd:mM
+A
+oJ
+cSub
+gX
+Lfn;Lfe:qW
+cDup);gJ
+Lff:dF=cDup;gJ
+gJ
+q4
+TailCall_cAnd;q4
+TailCall_cConj;q4
+TailCall_cImag;q4
+TailCall_cMax;q4
+TailCall_cMin;q4
+TailCall_cMod;q4
+TailCall_cNeg;q4
+TailCall_cOr;q4
+TailCall_cRDiv;q4
+TailCall_cReal;q4
+TailCall_cSub;
+#endif
+#if((FP_FLOAT_VERSION) && !(FP_COMPLEX_VERSION))
+dH
+x;hT
+A;dH
+gE
+C;hT
+D;qQ
+w5){TailCall_cAbs:g5
+cAbs:qS
+h0
+oH
+dF
+qR
+qX
+wB(393,wJ
+mV,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cAcos:g5
+cAcos:hN<=m7(148,"x[fp_abs(x)<=Value_t(1)] cAcos"
+,"[fp_acos(x)]"
+,wN);q4
+Lad;qG
+TailCall_cAcosh:g5
+cAcosh:qY
+if(x>=m7(145,"x[x>=Value_t(1)] cAcosh"
+,"[fp_acosh(x)]"
+,wN);q4
+Lae;qG
+TailCall_cAdd:g5
+hG
+Laf;qT
+h3
+hL]==hS){if(qL
+gZ
+Lag;}
+h8}
+q4
+dX
+qU
+d2
+gF
+h1
+wB(313,"cDup"
+a7
+aZ,"[x+Value_t(1)]"
+wH,wN);q4
+Lah;}
+}
+q4
+dX
+oF
+wB(199,qC1
+aZ,"cSub"
+,);q4
+Lai
+gY
+hK
+qZ
+mW(127,aY"cAdd"
+mD,"[y+x]"
+aZ,q81);q4
+Laj;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mW(298,aY"cAdd"
+mE
+mD,mN
+aZ
+mE,q81);q4
+Lak;qT
+hI
+wB(299,m0
+a6
+mD,"[-x]"
+aZ
+mE,wN);q4
+Lal
+qU
+q6:mW(297,aY
+a6
+mD,mN
+mE,q81);q4
+Lam;qT
+oA
+Lan;qT
+hI
+wB(293,m0"B[IsVarOpcode(B)]"
+aW
+mD,"[-x]"
+aZ" B"
+aW,wA","
+a8(B)wM);q4
+Lao
+qU
+q6:mW(291,aY"B[IsVarOpcode(B)]"
+aW
+mD,mN" B"
+aW,wA","
+a8(B)<<","
+a1);q4
+Lap;}
+w9
+mW(105,aY
+aF,"[y+x]"
+,q81);q4
+Laq;}
+g8)){wB(57,"x[x==Value_t()]"
+aZ,,wN);q4
+Lba;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x"
+mE
+a3"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aZ
+mE,aI(A)qD1
+wM);incStackPtr();--mStackPtr;q4
+Lbb;}
+wB(295,a6
+a3"cAdd"
+,"[DO_STACKPLUS1] A"
+aZ
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lbc;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mX"cAnd"
+,aJ,);q4
+w7
+m9(117,mA"cAnd"
+,"[fp_and(x,y)]"
+,q81);q4
+Lbe;h8}
+qH
+TailCall_cAsin:g5
+cAsin:hN<=m7(149,"x[fp_abs(x)<=Value_t(1)] cAsin"
+,"[fp_asin(x)]"
+,wN);q4
+Lbf;qG
+TailCall_cAsinh:g5
+cAsinh:qY
+wB(146,"x cAsinh"
+,"[fp_asinh(x)]"
+,wN);q4
+Lbg;}
+qH
+TailCall_cAtan:g5
+cAtan:qY
+wB(150,"x cAtan"
+,"[fp_atan(x)]"
+,wN);q4
+Lbh;}
+qH
+TailCall_cAtan2:g5
+cAtan2:qY
+m9(139,mA"cAtan2"
+,"[fp_atan2(y,x)]"
+,q81);q4
+Lbi;qG
+TailCall_cAtanh:g5
+cAtanh:hN<m7(147,"x[fp_abs(x)<Value_t(1)] cAtanh"
+,"[fp_atanh(x)]"
+,wN);q4
+Lbj;qG
+TailCall_cCbrt:g5
+cCbrt:qY
+wB(151,"x cCbrt"
+,"[fp_cbrt(x)]"
+,wN);q4
+Lbk;}
+qH
+TailCall_cCeil:g5
+cCeil:qS
+hI
+wB(402,m0
+q01,mS
+aA,);q4
+Lbl
+gY
+wB(135,"x "
+q01,"[fp_ceil(x)]"
+,wN);q4
+Lbm
+gS
+wB(396,"A[IsAlwaysIntegerOpcode(A)] "
+q01,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cCos:g5
+cCos:qS
+cAbs:wB(235,mV" "
+aO,aO,);q4
+Lbn
+oF
+wB(238,m0
+aO,aO,);q4
+Lbn
+gY
+wB(152,"x "
+aO,"[fp_cos(x)]"
+,wN);oS;oH
+qN
+qQ
+h9
+cSec:hD
+wB(500,aK" cSec "
+wI
+aO,"B cSec "
+aT,aI(A)q91(B)wM);q4
+Lbp;qT
+cSin:hD
+wB(494,aK" "
+mP" "
+wI
+aO,"B cSinCos"
+,aI(A)q91(B)wM);q4
+Lbq;h8}
+qG
+TailCall_cCosh:g5
+cCosh:qS
+cAbs:wB(236,mV" "
+aM,aM,);q4
+Lca
+qU
+cAsinh:wB(450,"cAsinh "
+aM,"[DO_STACKPLUS1] "
+q41"[Value_t(1)] "
+aQ,);incStackPtr();--mStackPtr;q4
+Lcb
+oF
+wB(239,m0
+aM,aM,);q4
+Lca
+gY
+wB(153,"x "
+aM,"[fp_cosh(x)]"
+,wN);q4
+Lcc;oH
+qN
+oY
+cSinh
+q11(507,aK" cSinh "
+wI
+aM,"B cSinhCosh"
+,aI(A)q91(B)wM);q4
+Lcd;}
+}
+qG
+TailCall_cCot:g5
+cCot:A=qN
+oY
+cTan
+q11(498,aK" "
+mR" "
+wI"cCot"
+,"B "
+mR" "
+aT,aI(A)q91(B)wM);q4
+Lbp;}
+qG
+TailCall_cCsc:g5
+cCsc:A=qN
+oY
+cSin
+q11(496,aK" "
+mP" "
+wI"cCsc"
+,"B "
+mP" "
+aT,aI(A)q91(B)wM);q4
+Lbp;}
+qG
+TailCall_cDeg:g5
+cDeg:qY
+wB(133,"x cDeg"
+,"[RadiansToDegrees(x)]"
+,wN);q4
+Lce;}
+qH
+TailCall_cDiv:g5
+cDiv:qS
+cCos:wB(250,aO
+mF,"cSec"
+wH,);q4
+Lcf
+qU
+cCot:wB(254,"cCot"
+mF,mR
+wH,);q4
+Lcg
+qU
+cCsc:wB(252,"cCsc"
+mF,mP
+wH,);q4
+Lch
+qU
+cDup:wB(78,"cDup"
+mF,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,);q4
+Lci
+qU
+w2
+wB(408,"cExp"
+mF,m0"cExp"
+wH,);q4
+Lcj
+qU
+cExp2:wB(409,"cExp2"
+mF,m0"cExp2"
+wH,);q4
+Lck
+qU
+cInv:wB(213,aU
+mF,"cMul"
+,);q4
+Lcl
+qU
+cPow:wB(407,"cPow"
+mF,m0"cPow"
+wH,);q4
+Lcm
+qU
+cSec:wB(253,"cSec"
+mF,aO
+wH,);q4
+Lcn
+qU
+cSin:wB(249,mP
+mF,"cCsc"
+wH,);q4
+Lco
+qU
+cSinCos:wB(502,"cSinCos"
+mF,mR,);q4
+Lcp
+qU
+cSinhCosh:wB(509,"cSinhCosh"
+mF,"cTanh"
+,);q4
+Lcq
+qU
+cTan:wB(251,mR
+mF,"cCot"
+wH,);q4
+Lda
+gY
+if
+hF
+gQ
+hI
+wB(125,m0
+a4"cDiv"
+,"[-x]"
+mF,wN);q4
+Ldb
+qU
+q6:mW(103,aY
+a4"cDiv"
+,"[y/x]"
+,q81);q4
+Ldc;}
+}
+g8
+oG
+wB(56,wO"cDiv"
+,,wN);q4
+Lba;}
+dB
+h3
+gA
+qZ
+hP(y/x)==fp_const_rad_to_deg
+h7
+wB(321,"y[(y/x)==fp_const_rad_to_deg<Value_t>()]"
+wH" "
+wR,"cDeg"
+,q81);q4
+Ldd;}
+if((y/x)==fp_const_deg_to_rad
+h7
+wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]"
+wH" "
+wR,"cRad"
+,q81);q4
+Lde;}
+wB(323,"y"
+wH" "
+wR,"[y/x]"
+wH,q81);q4
+Ldf;}
+}
+wB(325,wR,"[Value_t(1)/x]"
+wH,wN);q4
+Ldg;}
+gP
+cDiv:hC
+wB(271,aX"cDiv "
+wV,"[DO_STACKPLUS1] B A"
+wH
+mF,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4
+Ldh;qT
+cRDiv:qQ
+hE
+qV
+hM
+wB(266,"x"
+a9" "
+wV,"A"
+wH" [x]"
+a9,aI(A)qD1
+wM);q4
+Ldi;g7
+hC
+wB(265,"B[IsVarOpcode(B)]"
+a9" "
+wV,"A"
+wH" B"
+a9,aI(A)q91(B)wM);q4
+Ldj;}
+h8}
+qG
+TailCall_cEqual:g5
+w8:oL
+hU
+wB(359,m1
+aE,"[x] "
+aE,wN);q4
+Ldk
+qU
+cSqr:wB(361,q41
+wL
+aE,"[x] "
+aE,wN);q4
+Ldk;}
+}
+m9(115,mA
+aE,"[fp_equal(y,x)]"
+,q81);q4
+Ldl;qG
+TailCall_cExp:g5
+w2
+qS
+hS
+gM
+wB(404,aF
+mL,q21"[fp_exp(x)]"
+wH,wN);q4
+Ldm;qT
+cLog:A=dE
+wB(340,wJ
+mG
+mL,"A"
+,aI(A)wM);q4
+oN
+hM
+wB(154,"x"
+mL,"[fp_exp(x)]"
+,wN);q4
+Ldo;}
+qH
+TailCall_cExp2:g5
+cExp2:qS
+hS
+gM
+wB(405,aF
+q31,"cExp2 [fp_exp2(x)]"
+wH,wN);q4
+Ldp;qT
+cLog2:A=dE
+wB(341,wJ
+aN
+q31,"A"
+,aI(A)wM);q4
+oN
+hM
+wB(155,"x"
+q31,"[fp_exp2(x)]"
+,wN);q4
+Ldq;}
+wB(479,"cExp2"
+,"[DO_STACKPLUS1] [fp_log(Value_t(2))]"
+wH
+mL,);incStackPtr();--mStackPtr;q4
+Lea;TailCall_cFloor:g5
+cFloor:qS
+hI
+wB(401,m0
+mS,q01
+aA,);q4
+Leb
+gY
+wB(136,"x "
+mS,"[fp_floor(x)]"
+,wN);q4
+Lec
+gS
+wB(395,"A[IsAlwaysIntegerOpcode(A)] "
+mS,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cGreater:g5
+o1:qY
+m9(113,mA
+m2,"[fp_less(x,y)]"
+,q81);q4
+Led;}
+g8-oO
+wB(431,"x[x==Value_t(-0.5)] "
+m2,m0
+aS,wN);q4
+Lee;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+dB
+cAbs){wB(427,mV" x[x!=Value_t(0)] "
+aG,"[Value_t(0.5)/x]"
+wH" "
+aJ,wN);q4
+Lef;}
+}
+m9(114,mA
+aG,"[fp_lessOrEq(x,y)]"
+,q81);q4
+Leg;}
+g8
+oO
+wB(430,"x[x==Value_t(0.5)] "
+aG,"cAbsNotNot"
+,wN);q4
+Leh;qG
+TailCall_cHypot:g5
+cHypot
+d4
+dF==cSinCos){wB(84,"cSinCos cHypot"
+,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,);q4
+Lci;}
+qH
+TailCall_cInt:g5
+cInt:qS
+hM
+wB(137,"x cInt"
+,"[fp_int(x)]"
+,wN);q4
+Lei
+gS
+wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt"
+,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cInv:g5
+cInv:qS
+cCos:wB(256,aO" "
+aU,"cSec"
+,);q4
+Lej
+qU
+cCot:wB(260,"cCot "
+aU,mR,);q4
+Lcp
+qU
+cCsc:wB(258,"cCsc "
+aU,mP,);q4
+Lek
+qU
+cInv:wB(62,aU" "
+aU,,);q4
+Ldn
+qU
+cPow:wB(355,q61
+aU,m0"cPow"
+,);q4
+Lel
+qU
+cSec:wB(259,"cSec "
+aU,aO,);q4
+Lem
+qU
+cSin:wB(255,mP" "
+aU,"cCsc"
+,);q4
+Len
+qU
+cSqrt:wB(206,q51" "
+aU,"cRSqrt"
+,);q4
+Leo
+qU
+cTan:wB(257,mR" "
+aU,"cCot"
+,);q4
+Lep
+gY
+if
+hF)){wB(101,a4
+aU,"[Value_t(1)/x]"
+,wN);q4
+Leq;h8}
+qH
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mJ,mK,qB1(A)wM);q4
+Lfa;}
+}
+dB
+cAbs){wB(426,mV" x[x!=Value_t(0)] "
+mJ,"[Value_t(0.5)/x]"
+wH
+a0,wN);q4
+Lfb;}
+}
+m9(111,mA
+mJ,"[fp_less(y,x)]"
+,q81);q4
+Lfc;}
+g8
+oO
+wB(429,"x[x==Value_t(0.5)] "
+mJ,aS,wN);q4
+Lfd;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:qY
+m9(112,mA
+aR,"[fp_lessOrEq(y,x)]"
+,q81);q4
+Lfe;}
+g8-oO
+wB(432,"x[x==Value_t(-0.5)] "
+aR,m0"cAbsNotNot"
+,wN);q4
+Lff;qG
+TailCall_cLog:g5
+cLog:mT(343,q21
+mG,,);q4
+Ldn
+qU
+gL
+wB(491,mU
+mG,mG" [fp_log(x)]"
+aZ,wN);q4
+Lfg;}
+o2
+wB(303,q41
+mG,mV" "
+mG" "
+aH,);q4
+Lfh
+aV(156,wQ" "
+mG,"[fp_log(x)]"
+,wN);q4
+Lfi;h8}
+qH
+TailCall_cLog10:g5
+cLog10:mT(481,q21
+aL,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfj
+qU
+gL
+wB(492,mU
+aL,aL" [fp_log10(x)]"
+aZ,wN);q4
+Lfk;}
+o2
+wB(305,q41
+aL,mV" "
+aL" "
+aH,);q4
+Lfl
+aV(157,wQ" "
+aL,"[fp_log10(x)]"
+,wN);q4
+Lfm;h8}
+qH
+TailCall_cLog2:g5
+cLog2:mT(480,q21
+aN,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfn
+qU
+cExp2:wB(344,"cExp2 "
+aN,,);q4
+Ldn
+qU
+gL
+wB(490,mU
+aN,aN" [fp_log2(x)]"
+aZ,wN);q4
+Lfo;}
+o2
+wB(304,q41
+aN,mV" "
+aN" "
+aH,);q4
+Lfp
+aV(158,wQ" "
+aN,"[fp_log2(x)]"
+,wN);q4
+Lfq;h8}
+qH
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mX
+mB,,);q4
+Ldn
+gY
+m9(141,mA
+mB,"[fp_max(x,y)]"
+,q81);q4
+Lga;}
+gP
+cDup:hD
+wB(66,aK
+mQ
+a3
+mB,"B"
+mQ,aI(A)q91(B)wM);q4
+oN
+cMax:hD
+wB(68,aK" "
+mB
+a3
+mB,"B "
+mB,aI(A)q91(B)wM);q4
+Ldn;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mX
+mC,,);q4
+Ldn
+gY
+m9(140,mA
+mC,"[fp_min(x,y)]"
+,q81);q4
+Lgb;}
+gP
+cDup:hD
+wB(65,aK
+mQ
+a3
+mC,"B"
+mQ,aI(A)q91(B)wM);q4
+oN
+cMin:hD
+wB(67,aK" "
+mC
+a3
+mC,"B "
+mC,aI(A)q91(B)wM);q4
+Ldn;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m9(104,aY
+a4"cMod"
+,"[fp_mod(y,x)]"
+,q81);q4
+Lgc;}
+qG
+TailCall_cMul:g5
+h3:qS
+cCsc:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(508,aK" "
+aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc"
+wH,"B cCot"
+,aI(A)q91(B)wM);q4
+Lgd;}
+}
+}
+q4
+dY
+qU
+cDup:wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lge
+qU
+cInv:wB(214,aU
+wH,"cDiv"
+,);q4
+Lgf
+oF
+qQ
+h9
+cDup:wB(467,"cDup"
+aA
+wH,"cSqr"
+aA,);q4
+Lgg;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aK
+wH
+a3
+qC1
+wH,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lgh;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mX
+m8
+wH,"[x+Value_t(1)] cPow"
+,wN);q4
+Lgi;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wS" "
+wZ,wX,qB1(A)wM);q4
+Lgj;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mW(92,aY
+wD,wX,qB1(A)<<","
+a1);q4
+Lgk;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mW(96,aY
+wK,mK,qB1(A)q91(B)<<","
+a1);q4
+Lgl;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lgm;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lgn;}
+}
+}
+if(d1
+B)){wB(90,aX
+wD,wX,qB1(A)q91(B)wM);q4
+Lgj;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mK,qB1(A)q91(B)wM);q4
+Lgo;}
+}
+}
+if(d1
+h2
+wB(88,a5" "
+wZ,"[x]"
+,qB1(A)wM);q4
+Lgp;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wZ,wX,qB1(A)wM);q4
+Lgq;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup
+d4
+x+oU
+wB(316,"cDup[x+x==Value_t(1)]"
+aZ
+a7,,wN);q4
+Lha;}
+wB(317,aH
+a7,"[x+x]"
+wH,wN);q4
+Lhb
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,a5" y"
+wH
+aZ
+a7,wX" A "
+m3
+aZ,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Lhc;}
+w9
+mW(385,aY"cAdd"
+a7,wX" [y*x]"
+aZ,q81);q4
+Lhd;qT
+cDeg:wB(209,"cDeg"
+a7,"[RadiansToDegrees(x)]"
+wH,wN);q4
+Lhe
+qU
+cDiv
+oB
+qV
+o5
+4
+qZ
+mW(278,"y"
+wH" "
+aX
+mH,m3
+qH1,wA","
+a8(B)<<","
+a1);q4
+Lhf;qT
+hI
+wB(279,m0
+aX
+mH,mI
+qH1,wA","
+a8(B)wM);q4
+Lhg
+qU
+q6:mW(277,aY
+aX
+mH,"[y*x] B"
+mF,wA","
+a8(B)<<","
+a1);q4
+Lhh;}
+qT
+h3:qQ
+hE
+d3
+3
+h1
+if(x+oU
+wB(318,"cDup[x+x==Value_t(1)]"
+aZ
+wH
+a7,"cMul"
+,wN);q4
+Lhi;}
+wB(319,aH
+wH
+a7,"cMul [x+x]"
+wH,wN);q4
+Lhj;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+a7,,q81);q4
+Lhk;}
+if((y*x)==fp_const_rad_to_deg
+h7
+wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]"
+wH
+a7,"cDeg"
+,q81);q4
+Ldd;}
+if((y*x)==fp_const_deg_to_rad
+h7
+wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]"
+wH
+a7,"cRad"
+,q81);q4
+Lde;}
+wB(128,"y"
+wH
+a7,m3,q81);q4
+Lhl;qT
+hI
+wB(122,qC1
+a7,mI,wN);q4
+Lhm
+qU
+cRDiv:qQ
+hE
+qV
+o5
+3
+qZ
+mW(285,"y"
+wH
+a9
+a7,m3
+a9,q81);q4
+Lhn;qT
+hI
+wB(286,qC1
+a9
+a7,mI
+a9,wN);q4
+Lho
+qU
+q6:mW(284,"y"
+a9
+a7,"[y*x]"
+a9,q81);q4
+Lhp;qT
+cRad:wB(210,"cRad"
+a7,"[DegreesToRadians(x)]"
+wH,wN);q4
+Lhq
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,a5" y"
+wH
+aW
+a7,wX" A "
+m3
+aW,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Lia;}
+}
+w9
+mW(102,"y"
+a7,"[y*x]"
+,q81);q4
+Lib;}
+g8
+oG
+wB(55,"x[x==Value_t(1)]"
+wH,,wN);q4
+Lba;}
+g8-oG
+wB(124,"x[x==Value_t(-1)]"
+wH,qC1,wN);q4
+Lic;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,aH,wN);q4
+Lid;}
+if(x==fp_const_rad_to_deg
+h7
+wB(207,"x[x==fp_const_rad_to_deg<Value_t>()]"
+wH,"cDeg"
+,wN);q4
+Lie;}
+if(x==fp_const_deg_to_rad
+h7
+wB(208,"x[x==fp_const_deg_to_rad<Value_t>()]"
+wH,"cRad"
+,wN);q4
+Lif;h8
+g7
+dY:;A=dF
+qO
+A
+gQ
+cDiv:hC
+wB(274,aX"cDiv "
+wS,"[DO_STACKPLUS1] A"
+wH
+qH1,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4
+Lig;}
+q4
+d5
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aK
+aA
+wH" "
+wS,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lgh;}
+q4
+dZ;g7
+dZ:;hD
+wB(461,aK
+wH" "
+wS,m5
+wH,aI(A)q91(B)wM);q4
+Lih;}
+}
+q4
+d5
+hI
+hD
+wB(464,aK
+aA" "
+wS,m5
+aA,aI(A)q91(B)wM);q4
+Lgg;}
+q4
+d5
+cRDiv
+hL
+qZ
+qC
+wB(267,"x"
+a9" "
+wS,"[DO_STACKPLUS1] "
+mK
+a9,aI(A)qD1
+wM);incStackPtr();--mStackPtr;q4
+Lii;}
+wB(281,"cRDiv "
+wS,"[DO_STACKPLUS1] A"
+wH
+a9,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lij;g7
+Default4:;B=qK
+qR
+w4
+wB(458,aK" "
+wS,m5,aI(A)q91(B)wM);q4
+Lge;}
+}
+}
+if(gV
+h2
+B=qK
+qO
+B
+qP
+1
+gA
+oM
+C=oC
+qR
+C==A){D=qL
+4]qR
+D==B){wB(477,"D[D==B] C[C==A]"
+wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Lik;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:oL
+hU
+wB(360,m1
+wW,"[x] "
+wW,wN);q4
+Lil
+qU
+cSqr:wB(362,q41
+wL
+wW,"[x] "
+wW,wN);q4
+Lil;}
+}
+m9(116,mA
+wW,"[fp_nequal(y,x)]"
+,q81);q4
+Lim;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+wH
+aA,mI,wN);q4
+Lin;qT
+hI
+wB(61,qC1
+aA,,);q4
+Ldn
+qU
+cSin:g9
+wB(244,"x"
+wH" "
+mP
+aA,mI" "
+mP,wN);q4
+Lio;}
+qT
+oQ
+g9
+wB(245,"x"
+wH" cSinh"
+aA,mI" cSinh"
+,wN);q4
+Lip;}
+qT
+cTan:g9
+wB(246,"x"
+wH" "
+mR
+aA,mI" "
+mR,wN);q4
+Liq;}
+qT
+cTanh:g9
+wB(247,"x"
+wH" cTanh"
+aA,mI" cTanh"
+,wN);q4
+Lja;}
+qT
+hM
+wB(100,"x"
+aA,"[-x]"
+,wN);q4
+Ljb;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbs:wB(227,mV
+a0,"cNot"
+,);q4
+Ljc
+qU
+cAbsNot:A=dD
+wB(389,"A[IsLogicalOpcode(A)] "
+aS
+a0,"A"
+,aI(A)wM);q4
+Ldn;}
+if(A!=q6){wB(390,"A[A!=cImmed] "
+aS
+a0,"A cAbsNotNot"
+,aI(A)wM);q4
+Ljd;}
+q4
+o0
+qU
+cAbsNotNot:wB(231,"cAbsNotNot"
+a0,aS,);q4
+Lje
+qU
+w8:wB(220,aE
+a0,wW,);q4
+Ljf
+qU
+o1:wB(218,m2
+a0,aR,);q4
+Ljg
+qU
+dK:wB(219,aG
+a0,mJ,);q4
+Ljh
+qU
+cLess:wB(216,mJ
+a0,aG,);q4
+Lji
+qU
+cLessOrEq:wB(217,aR
+a0,m2,);q4
+Ljj
+qU
+cNEqual:wB(221,wW
+a0,aE,);q4
+Ljk
+oF
+wB(226,qC1
+a0,"cNot"
+,);q4
+Ljc
+qU
+cNot:wB(229,"cNot"
+a0,aJ,);q4
+Lbd
+qU
+dS:wB(230,aJ
+a0,"cNot"
+,);q4
+Ljc
+gY
+wB(107,"x"
+a0,"[fp_not(x)]"
+,wN);q4
+Ljl;g7
+o0:;A=dF
+qR
+qX
+wB(391,wJ"cNot"
+,"A "
+aS,aI(A)wM);q4
+Ljm;qG
+TailCall_cNotNot:g5
+dS
+d4
+dF==cNot){wB(232,"cNot "
+aJ,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mX"cOr"
+,aJ,);q4
+w7
+m9(118,mA"cOr"
+,"[fp_or(x,y)]"
+,q81);q4
+Ljn;h8}
+qH
+TailCall_cPow:g5
+cPow:qY
+if(!h5
+x+x)){oY
+cSqr){wB(22,q41"x[!isEvenInteger(x+x)] cPow"
+,mV" [x+x] cPow"
+,wN);q4
+Ljo;}
+}
+if(isInteger(x
+gQ
+w2
+wB(43,q21
+wT,wX
+mL,wN);q4
+Ljp
+qU
+cExp2:wB(44,"cExp2 "
+wT,wX
+q31,wN);q4
+Ljq
+qU
+cPow
+hL
+qZ
+hP!isInteger(y)){wB(42,"y[!isInteger(y)] "
+q61
+wT,aP,q81);q4
+Lka;}
+}
+wB(45,q61
+wT,wX" cPow"
+,wN);q4
+Lkb;}
+}
+if(h5
+x
+hU
+wB(434,mV" x[isEvenInteger(x)] cPow"
+,"[x] cPow"
+,wN);q4
+Lkc
+qU
+h3
+hL]==cAbs){wB(435,mV
+wH" x[isEvenInteger(x)] cPow"
+,"cMul [x] cPow"
+,wN);q4
+Lkd;h8}
+}
+g8)){wB(83,"x[x==Value_t()] cPow"
+,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,wN);q4
+Lke;}
+g8
+oO
+wB(332,"x[x==Value_t(0.5)] cPow"
+,q51,wN);q4
+Lkf;}
+g8
+1)/g1
+3)){wB(333,"x[x==Value_t(1)/Value_t(3)] cPow"
+,"cCbrt"
+,wN);q4
+Lkg;}
+g8
+1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)] cPow"
+,"cCbrt "
+aU,wN);q4
+Lkh;}
+g8-oO
+wB(335,"x[x==Value_t(-0.5)] cPow"
+,"cRSqrt"
+,wN);q4
+Lki;}
+g8-oG
+wB(336,"x[x==Value_t(-1)] cPow"
+,aU,wN);q4
+Lkj;}
+qQ
+h9
+cPow
+hL
+qZ
+hP
+h5
+y)&&!h5
+x*y)){wB(21,"y[isEvenInteger(y)&&!isEvenInteger(x*y)] "
+q61
+m8,mV" "
+aP,q81);q4
+Lkk;}
+wB(330,aY
+q61
+m8,aP,q81);q4
+Lka;o2
+wB(46,q41
+m8,"[x+x] cPow"
+,wN);q4
+Lkl
+qU
+q6:hP
+y!=oP||x>=oP){wB(165,"y[y!=Value_t(0)||x>=Value_t(0)] "
+m8,"[fp_pow(y,x)]"
+,q81);q4
+Lkm;h8}
+wB(455,m8,"[DO_POWI]"
+,wN)qR
+TryCompilePowi(x))gJ}
+qH
+TailCall_cRDiv:g5
+cRDiv:qS
+cSinCos:wB(503,"cSinCos"
+a9,"cCot"
+,);q4
+Lep
+qU
+cSinhCosh:wB(510,"cSinhCosh"
+a9,"cTanh "
+aU,);q4
+Lkn
+gY
+g8
+oG
+wB(268,wO"cRDiv"
+,aU,wN);q4
+Lkj;h8}
+qH
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,"cDup"
+mE,"[Value_t()]"
+wH,);q4
+Lko;}
+qH
+TailCall_cRad:g5
+cRad:qS
+h3
+gM
+wB(211,"x"
+wH" cRad"
+,"[DegreesToRadians(x)]"
+wH,wN);q4
+Lkp;qT
+hM
+wB(134,"x cRad"
+,"[DegreesToRadians(x)]"
+,wN);q4
+Lkq;}
+qH
+TailCall_cSec:g5
+cSec:A=qN
+qQ
+h9
+cCos:hD
+wB(497,aK" "
+aO" "
+wI"cSec"
+,"B "
+aO" "
+aT,aI(A)q91(B)wM);q4
+Lbp;qT
+cSin:hD
+wB(495,aK" "
+mP" "
+wI"cSec"
+,"B cSinCos "
+aU,aI(A)q91(B)wM);q4
+Lla;h8
+qG
+TailCall_cSin:g5
+cSin:qS
+hI
+wB(240,m0
+mP,mP
+aA,);q4
+Llb
+gY
+wB(159,"x "
+mP,"[fp_sin(x)]"
+,wN);q4
+Llc;oH
+qN
+oY
+cCsc
+q11(499,aK" cCsc "
+wI
+mP,"B cCsc "
+aT,aI(A)q91(B)wM);q4
+Lbp;}
+}
+qG
+TailCall_cSinh:g5
+oQ
+qS
+cAcosh:wB(437,"cAcosh cSinh"
+,"[DO_STACKPLUS1] "
+q41"[Value_t(-1)] "
+aQ,);incStackPtr();--mStackPtr;q4
+Lld
+qU
+cAsinh:wB(349,"cAsinh cSinh"
+,,);q4
+Ldn
+oF
+wB(241,m0"cSinh"
+,"cSinh"
+aA,);q4
+Lle
+gY
+wB(160,"x cSinh"
+,"[fp_sinh(x)]"
+,wN);q4
+Llf;}
+qH
+TailCall_cSqr:g5
+cSqr:qS
+cAbs:wB(204,mV" cSqr"
+,"cSqr"
+,);q4
+Llg
+oF
+wB(203,m0"cSqr"
+,"cSqr"
+,);q4
+Llg
+qU
+cSqrt:A=dE
+wB(338,wJ
+q51" cSqr"
+,"A"
+,aI(A)wM);q4
+Ldn;h8}
+qH
+TailCall_cSqrt:g5
+cSqrt:qS
+hS
+d4
+qK
+o3
+A=hE
+w0
+if(oC
+o3
+wB(512,"cSqr"
+a3
+q41
+aQ,"A cHypot"
+,aI(A)wM);q4
+Llh;}
+}
+B
+g4
+gV
+B)){A=oC
+w0
+if(qL
+4]o3
+wB(513,"cSqr"
+a3"B[IsUnaryOpcode(B)] "
+q41
+aQ,"A B cHypot"
+," with"
+a8(B)qE1(A)wM);q4
+Lli;}
+}
+}
+o2
+wB(23,q41
+q51,mV,);q4
+Llj
+gY
+if(x>=oP){wB(161,"x[x>=Value_t(0)] "
+q51,"[fp_sqrt(x)]"
+,wN);q4
+Llk;h8}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,"cDup"
+aW,"[Value_t()]"
+wH,);q4
+Lko
+oF
+wB(200,qC1
+aW,"cAdd"
+,);q4
+Lll
+gY
+g8)){wB(58,"x[x==Value_t()]"
+aW,,wN);q4
+Lba;}
+m9(106,aY"x"
+aW,"[y-x]"
+,q81);q4
+Llm;}
+wB(51,"x"
+aW,"[-x]"
+aZ,wN);q4
+Lln
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x"
+mE
+a3"cSub"
+,"A"
+aZ" [x]"
+mE,aI(A)qD1
+wM);q4
+Llo;}
+wB(296,a6
+a3"cSub"
+,"[DO_STACKPLUS1] A"
+aW
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Llp;}
+qG
+TailCall_cTan:g5
+cTan:qS
+cAtan2:wB(354,"cAtan2 "
+mR,"cDiv"
+,);q4
+Lgf
+oF
+wB(242,m0
+mR,mR
+aA,);q4
+Llq
+gY
+wB(163,"x "
+mR,"[fp_tan(x)]"
+,wN);q4
+Lma;oH
+qN
+oY
+cCot
+q11(501,aK" cCot "
+wI
+mR,"B cCot "
+aT,aI(A)q91(B)wM);q4
+Lbp;}
+}
+qG
+TailCall_cTanh:g5
+cTanh:qS
+hI
+wB(243,m0"cTanh"
+,"cTanh"
+aA,);q4
+Lmb
+gY
+wB(164,"x cTanh"
+,"[fp_tanh(x)]"
+,wN);q4
+Lmc;}
+qH
+TailCall_cTrunc:g5
+cTrunc:qS
+hM
+wB(138,"x cTrunc"
+,"[fp_trunc(x)]"
+,wN);q4
+Lmd
+gS
+wB(394,"A[IsAlwaysIntegerOpcode(A)] cTrunc"
+,"A"
+,aI(A)wM);gJ
+qG
+g7
+Default0:;A=w5
+qR
+IsComparisonOpcode(h2
+qY
+hK
+qZ
+mW(364,aY"cAdd"
+wF,"[x-y] A"
+,aI(A)qD1<<","
+a1);q4
+Lme;qT
+cAtan
+d4
+dP<fp_const_pi<dH>()*g1
+oO
+wB(380,"cAtan[fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)]"
+wF,"[fp_tan(x)] A"
+,aI(A)qD1
+wM);q4
+Lmf;qT
+cExp
+d4
+dO
+wB(370,"cExp[x>Value_t(0)]"
+wF,"[fp_log(x)] A"
+,aI(A)qD1
+wM);q4
+Lmg;qT
+cExp2
+d4
+dO
+wB(371,"cExp2[x>Value_t(0)]"
+wF,"[fp_log2(x)] A"
+,aI(A)qD1
+wM);q4
+Lmh;qT
+cLog:g3
+wB(373,wP
+mG
+wF,"B [fp_exp(x)] A"
+,aI(A)qD1
+q91(B)wM);q4
+Lmi;qT
+cLog10:g3
+wB(375,wP
+aL
+wF,"B [fp_pow(Value_t(10),x)] A"
+,aI(A)qD1
+q91(B)wM);q4
+Lmj;qT
+cLog2:g3
+wB(374,wP
+aN
+wF,"B [fp_exp2(x)] A"
+,aI(A)qD1
+q91(B)wM);q4
+Lmk;qT
+h3
+hL
+qZ
+hP
+y>oP){wB(366,"y[y>Value_t(0)]"
+wH
+wF,"[x/y] A"
+,aI(A)qD1<<","
+a1);q4
+Lml;}
+if(y<oP){wB(367,"y[y<Value_t(0)]"
+wH
+wF,"[x/y] {OppositeComparisonOpcode(A)}"
+,aI(A)qD1<<","
+a1);q4
+Lmm;}
+qT
+hI
+wB(365,qC1
+wF,"[-x] {OppositeComparisonOpcode(A)}"
+,aI(A)qD1
+wM);q4
+Lmn
+qU
+cPow
+d4
+x>oP
+gA
+qZ
+hP
+y>oP){wB(368,"y[y>Value_t(0)] cPow[x>Value_t(0)]"
+wF,"[fp_pow(x,Value_t(1)/y)] A"
+,aI(A)qD1<<","
+a1);q4
+Lmo;}
+}
+qT
+oQ
+wB(381,"cSinh"
+wF,"[fp_asinh(x)] A"
+,aI(A)qD1
+wM);q4
+Lmp
+qU
+cSqr
+d4
+dO
+wB(369,"cSqr[x>Value_t(0)]"
+wF,mV" [fp_sqrt(x)] A"
+,aI(A)qD1
+wM);q4
+Lmq;qT
+cTanh
+d4
+dP<m7(382,"cTanh[fp_abs(x)<Value_t(1)]"
+wF,"[fp_atanh(x)] A"
+,aI(A)qD1
+wM);q4
+Lna;h8}
+}
+}
+if(d1
+A
+qP
+0){B=q0[0
+hZ
+wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mQ,aI(A)q91(B)wM);q4
+Lnb;}
+}
+if(gV
+h2
+B=dF
+qO
+B
+qP
+1){C=qK
+qR
+C==A){D
+g4
+D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+,"D C"
+mQ,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Lnc;}
+}
+}
+}
+C=w5
+qR
+IsCommutativeOrParamSwappableBinaryOpcode(C)){qS
+cSin:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(505,aK" "
+aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] "
+mP" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinCos {GetParamSwappedBinaryOpcode(C)}"
+," with C"
+wY(C)qE1(A)q91(B)wM);q4
+Lnd;}
+}
+qT
+oQ
+A=qK
+w1
+3
+gA]==cCosh){B=hQ
+wB(506,aK" "
+aM" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}"
+," with C"
+wY(C)qE1(A)q91(B)wM);q4
+Lne;}
+}
+h8}
+}
+}
+q4
+Laa;Laa:qW
+w5);gJ
+Lab:g6
+Lnf:wE(cAbs);q4
+TailCall_cAbs;Lac:q7=dP;gJ
+Lad:q7=fp_acos
+m6
+Lae:q7=fp_acosh
+m6
+Laf:oZ
+4));gG
+Lng:w5=h3;Lnh:g0
+Lni:wE(cMul);q4
+TailCall_cMul;Lag:hV
+4
+dT
+oZ
+4));Lnj:qW
+q6
+hA
+Lah:q7=x+g1
+1);gG
+Lfa:w5=h3;q4
+Lni;Lai:gU
+cSub;Lnk:wE(cSub);q4
+TailCall_cSub;Laj:hW
+2
+gH
+Lnl:g0
+Lnm:wE(cAdd);q4
+TailCall_cAdd;Lak:hW
+oR
+Lnn:qE
+hS);Lno:w5=cRSub;g0
+wE(cRSub);q4
+TailCall_cRSub;Lal:o9;qL
+2
+gK
+q4
+Lnn;Lam:hW
+2
+gH
+q4
+Lno;Lan:hW
+4
+gH
+Lnp:qE
+hS);Lnq:qE
+B);Loa:w5=cSub;g0
+q4
+Lnk;Lao:o9;oC=q6
+q9
+oR
+q4
+Lnp;Lap:hW
+oR
+q4
+Lnq;Laq:gT
+y+x;Lba:qM
+Ldn:q5
+gJ
+Lbb:q8
+oV
+o7
+x
+q71
+gX
+Lnn;Lbc:mM
+A
+gX
+Lnn;Lbd:gU
+dS;Lob:wE(cNotNot);q4
+TailCall_cNotNot;Lbe:gT
+fp_and(x
+d6
+Lbf:q7=fp_asin
+m6
+Lbg:q7=fp_asinh
+m6
+Lbh:q7=fp_atan
+m6
+Lbi:gT
+fp_atan2(gW
+Lbj:q7=fp_atanh
+m6
+Lbk:q7=fp_cbrt
+m6
+Lbl:q1
+cFloor);Loc:w5=cNeg;g0
+wE(cNeg);q4
+TailCall_cNeg;Lbm:q7=fp_ceil
+m6
+Lbn:g6
+Lod:wE(cCos);q4
+TailCall_cCos;Lbo:q7=fp_cos
+m6
+Lbp:dF=cDup;w5=cInv;Loe:wE(cInv);q4
+TailCall_cInv;Lbq:mM
+cSinCos);gJ
+Lca:g6
+wE(cCosh);q4
+TailCall_cCosh;Lcb:q1
+cSqr
+o7
+g1
+1));Lof:qW
+q6
+oJ
+hS);Log:w5=cSqrt;g0
+wE(cSqrt);q4
+TailCall_cSqrt;Lcc:q7=fp_cosh
+m6
+Lcd:mM
+cSinhCosh);gJ
+Lce:q7=RadiansToDegrees
+m6
+Lcf:q1
+cSec
+hA
+Lcg:q1
+cTan
+hA
+Lch:q1
+cSin
+hA
+Lci:oZ));dF
+dJ
+Loh:qE
+dU
+oZ
+1));Loi:qW
+q6);Loj:w5=hS;q4
+Lnl;Lcj:q1
+cNeg
+oJ
+cExp
+hA
+Lck:q1
+cNeg
+oJ
+cExp2
+hA
+Lcl:g6
+q4
+Lfa;Lcm:q1
+cNeg
+oJ
+cPow
+hA
+Lcn:q1
+cCos
+hA
+Lco:q1
+cCsc
+hA
+Lcp:gU
+cTan;Lok:wE(cTan);q4
+TailCall_cTan;Lcq:gU
+cTanh;Lol:wE(cTanh);q4
+TailCall_cTanh;Lda:q1
+cCot
+hA
+Ldb:o9;dI
+Lom:wE(cDiv);q4
+TailCall_cDiv;Ldc:gT
+y/x;q4
+Lba;Ldd:qF1
+q8
+oR
+Lon:w5=cDeg;g0
+wE(cDeg);q4
+TailCall_cDeg;Lde:qF1
+q8
+oR
+Loo:w5=cRad;g0
+wE(cRad);q4
+TailCall_cRad;Ldf:gT
+y/x;dG
+Lng;Ldg:q7=g1
+1)/x;q4
+Lfa;Ldh:mM
+oI
+Lop:g0
+q4
+Lom;Ldi:q8
+3
+gC
+oI
+qF
+x
+q71);Loq:w5=cRDiv;g0
+wE(cRDiv);q4
+TailCall_cRDiv;Ldj:hV
+3
+gC
+oI
+qE
+B
+gX
+Loq;Ldk:dI
+Lpa:wE(cEqual);q4
+TailCall_cEqual;Ldl:gT
+fp_equal(gW
+Ldm:d7
+cExp
+o7
+fp_exp(x)gX
+Lnj;Ldo:q7=fp_exp
+m6
+Ldp:d7
+cExp2
+o7
+fp_exp2(x)gX
+Lnj;Ldq:q7=fp_exp2
+m6
+Lea:qF
+oW
+g1
+2))q71);Lpb:qE
+h3
+gI
+cExp;g0
+wE(cExp);q4
+TailCall_cExp;Leb:q1
+cCeil
+gX
+Loc;Lec:q7=fp_floor
+m6
+Led:gT
+fp_less(x
+d6
+Lee:qM
+q1
+cNeg);Ljm:qE
+cAbsNot);gJ
+Lef:q7=g1
+0.5)/x;qK=d8
+dS;g0
+q4
+Lob;Leg:gT
+fp_lessOrEq(x
+d6
+Leh:qM
+Ljd:q5
+Lpc:qE
+cAbsNotNot);gJ
+Lei:q7=fp_int
+m6
+Lej:gU
+cSec;wE(cSec);q4
+TailCall_cSec;Lek:gU
+cSin;Lpd:wE(cSin);q4
+TailCall_cSin;Lel:q1
+cNeg
+gI
+cPow;Lpe:g0
+Lpf:wE(cPow);q4
+TailCall_cPow;Lem:gU
+cCos;q4
+Lod;Len:gU
+cCsc;wE(cCsc);q4
+TailCall_cCsc;Leo:q1
+cRSqrt);gJ
+Lep:g6
+Lpg:w5=cCot;wE(cCot);q4
+TailCall_cCot;Leq:q7=g1
+1)/x;gJ
+Lfb:q7=g1
+0.5)/x;qK=d8
+cNot;g0
+Lph:wE(cNot);q4
+TailCall_cNot;Lfc:gT
+fp_less(gW
+Lfd:qM
+Lje:w3
+Ljm;Lfe:gT
+fp_lessOrEq(gW
+Lff:qM
+q1
+cNeg
+gX
+Lpc;Lfg:d7
+cLog
+o7
+oW
+x)o8
+Lfh:q1
+dQ
+qE
+cLog);Lpi:qW
+cDup
+gX
+Loj;Lfi:q7=oW
+x);gJ
+Lfj:qF
+dR
+fp_const_e<dH>()));Lpj:dF
+dJ
+q4
+Lng;Lfk:d7
+cLog10
+o7
+dR
+x)o8
+Lfl:q1
+dQ
+qE
+cLog10
+gX
+Lpi;Lfm:q7=dR
+x);gJ
+Lfn:qF
+o4
+fp_const_e<dH>())gX
+Lpj;Lfo:d7
+cLog2
+o7
+o4
+x)o8
+Lfp:q1
+dQ
+qE
+cLog2
+gX
+Lpi;Lfq:q7=o4
+x);gJ
+Lga:gT
+fp_max(x
+d6
+Lgb:gT
+fp_min(x
+d6
+Lgc:gT
+fp_mod(gW
+Lgd:hV
+oR
+q0-=3;q4
+Lpg;Lge:gU
+cSqr;Lpk:wE(cSqr);q4
+TailCall_cSqr;Lgf:gU
+cDiv;q4
+Lom;Lgg:mM
+cSqr
+gX
+Loc;Lgh:hV
+3
+gC
+cSqr);dM
+Loc;Lgi:q7=x+g1
+1);gG
+w5=cPow;q4
+Lpf;Lgj:gG
+q4
+Lni;Lgk:gT
+x;Lpl:dG
+Lnh;Lgl:qF1
+qM
+Lpm:hV
+4
+gH
+Lpn:o6
+x);Lpo:qW
+q6
+gX
+Lnh;Lgm:qM
+q4
+Lpm;Lgn:q8
+4
+gC
+B
+gX
+Lpn;Lgo:q8
+oR
+q4
+Lpn;Lgp:qK
+dJ
+q4
+Ldn;Lgq:dI
+q4
+Lni;Lha:qM
+Lpp:hV
+oR
+gJ
+Lhb:q7=x+x;q4
+Lgj;Lhc:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Loj;Lhd:gT
+x;d7
+dU
+qF
+y*x
+o8
+Lhe:q7=RadiansToDegrees(x
+gX
+Lgq;Lhf:qG1
+q8
+4
+gH
+Lpq:qE
+dU
+Lqa:qE
+B
+gI
+cDiv;q4
+Lop;Lhg:o9;oC=q6
+q9
+oR
+q4
+Lpq;Lhh:qG1
+q8
+oR
+q4
+Lqa;Lhi:q8
+4
+gH
+q4
+Lnh;Lhj:q8
+4
+dT
+qF
+x+x
+gX
+Lpo;Lhk:qF1
+qM
+q4
+Lpp;Lhl:qG1
+q4
+Lpl;Lhm:o9;q4
+Lgq;Lhn:qG1
+q8
+oR
+Lqb:dM
+Loq;Lho:o9;qL
+2
+gK
+q4
+Lqb;Lhp:qG1
+dG
+Loq;Lhq:q7=h4
+gX
+Lgq;Lia:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Loa;Lib:qG1
+q4
+Lba;Lic:qM
+w3
+Loc;Lid:dF=cDup;dW-=1;qM
+Lqc:w5=hS;q4
+Lnm;Lie:qM
+w3
+Lon;Lif:qM
+w3
+Loo;Lig:hV
+oV
+gX
+Lpq;Lih:hV
+2
+gH
+Lqd:qE
+cSqr
+gX
+Lnh;Lii:q8
+oV
+o7
+x
+q71
+gX
+Lqb;Lij:mM
+A
+gX
+Lqb;Lik:hV
+oR
+q4
+Lqd;Lil:dI
+Lqe:wE(cNEqual);q4
+TailCall_cNEqual;Lim:gT
+fp_nequal(gW
+Lin:o9;q4
+Lcl;Lio:o9
+gB
+cSin;g0
+q4
+Lpd;Lip:o9
+gB
+cSinh;g0
+wE(cSinh);q4
+TailCall_cSinh;Liq:o9
+gB
+cTan;g0
+q4
+Lok;Lja:o9
+gB
+cTanh;g0
+q4
+Lol;Ljb:o9;gJ
+Ljc:g6
+q4
+Lph;Ljf:gU
+cNEqual;q4
+Lqe;Ljg:gU
+cLessOrEq;wE(cLessOrEq);q4
+TailCall_cLessOrEq;Ljh:gU
+cLess;wE(cLess);q4
+TailCall_cLess;Lji:gU
+dK;wE(cGreaterOrEq);q4
+TailCall_cGreaterOrEq;Ljj:gU
+o1;wE(cGreater);q4
+TailCall_cGreater;Ljk:gU
+w8;q4
+Lpa;Ljl:q7=fp_not
+m6
+Ljn:gT
+fp_or(x
+d6
+Ljo:d7
+dQ
+qF
+x+x);Lqf:qW
+q6
+gX
+Lpe;Ljp:dL
+Lpb;Ljq:qK=d8
+cExp2;g0
+wE(cExp2);q4
+TailCall_cExp2;Lka:qG1
+dG
+Lpe;Lkb:qK
+dJ
+q1
+h3
+gX
+Lpe;Lkc:dI
+q4
+Lpf;Lkd:q8
+3
+dT
+qF
+x
+gX
+Lqf;Lke:q7=g1
+gX
+Loh;Lkf:qM
+w3
+Log;Lkg:qM
+q5
+w5=cCbrt;g0
+wE(cCbrt);q4
+TailCall_cCbrt;Lkh:qM
+q1
+cCbrt);Lqg:w5=cInv;g0
+q4
+Loe;Lki:qM
+q4
+Leo;Lkj:qM
+w3
+Lqg;Lkk:qF1
+q8
+3
+gC
+dQ
+qF
+y*x
+gX
+Lqf;Lkl:q7=x+x;q4
+Lkc;Lkm:gT
+oX
+gW
+Lkn:q1
+cTanh
+gX
+Lqg;Lko:oZ)gX
+Lpj;Lkp:q7=h4
+gX
+Lcl;Lkq:q7=h4);gJ
+Lla:mM
+cSinCos
+gX
+Lqg;Llb:q1
+cSin
+gX
+Loc;Llc:q7=fp_sin
+m6
+Lld:q1
+cSqr
+o7
+g1-1)gX
+Lof;Lle:q1
+cSinh
+gX
+Loc;Llf:q7=fp_sinh
+m6
+Llg:g6
+q4
+Lpk;Llh:hV
+4
+gC
+A);Lqh:w5=cHypot;g0
+wE(cHypot);q4
+TailCall_cHypot;Lli:hV
+5
+gC
+A
+oJ
+B
+gX
+Lqh;Llj:gU
+cAbs;q4
+Lnf;Llk:q7=fp_sqrt
+m6
+Lll:g6
+q4
+Lqc;Llm:gT
+y-x;q4
+Lba;Lln:o9;q4
+Lqc;Llo:q8
+oV
+oJ
+hS
+o7
+x
+q71
+gX
+Lno;Llp:mM
+A
+oJ
+cSub
+gX
+Lno;Llq:q1
+cTan
+gX
+Loc;Lma:q7=fp_tan
+m6
+Lmb:q1
+cTanh
+gX
+Loc;Lmc:q7=fp_tanh
+m6
+Lmd:q7=fp_trunc
+m6
+Lme:gT
+x-y;Lqi:q8
+2
+gH
+Lqj:qE
+A);gJ
+Lmf:q7=fp_tan(x);Lqk:dL
+Lqj;Lmg:q7=oW
+x
+gX
+Lqk;Lmh:q7=o4
+x
+gX
+Lqk;Lmi:q7=fp_exp(x
+gX
+Lqk;Lmj:q7=oX
+g1
+10),x
+gX
+Lqk;Lmk:q7=fp_exp2(x
+gX
+Lqk;Lml:gT
+x/y;q4
+Lqi;Lmm:gT
+x/y;q8
+2
+gH
+Lql:qE
+OppositeComparisonOpcode(A));gJ
+Lmn:o9;dL
+Lql;Lmo:gT
+oX
+x,g1
+1)/y
+gX
+Lqi;Lmp:q7=fp_asinh(x
+gX
+Lqk;Lmq:d7
+dQ
+qF
+fp_sqrt(x)q71
+gX
+Lqj;Lna:q7=fp_atanh(x
+gX
+Lqk;Lnb:qW
+cDup);gJ
+Lnc:dF=cDup;gJ
+Lnd:hV
+3
+gC
+cSinCos);Lqm:qE
+GetParamSwappedBinaryOpcode(C));gJ
+Lne:hV
+3
+gC
+cSinhCosh
+gX
+Lqm;gJ
+q4
+TailCall_cAcos;q4
+TailCall_cAcosh;q4
+TailCall_cAnd;q4
+TailCall_cAsin;q4
+TailCall_cAsinh;q4
+TailCall_cAtan;q4
+TailCall_cAtan2;q4
+TailCall_cAtanh;q4
+TailCall_cCeil;q4
+TailCall_cFloor;q4
+TailCall_cInt;q4
+TailCall_cLog;q4
+TailCall_cLog10;q4
+TailCall_cLog2;q4
+TailCall_cMax;q4
+TailCall_cMin;q4
+TailCall_cMod;q4
+TailCall_cOr;q4
+TailCall_cRDiv;q4
+TailCall_cRad;q4
+TailCall_cSec;q4
+TailCall_cSin;q4
+TailCall_cSinh;q4
+TailCall_cSqrt;q4
+TailCall_cSub;q4
+TailCall_cTan;q4
+TailCall_cTanh;q4
+TailCall_cTrunc;
+#endif
+#if((FP_COMPLEX_VERSION) && (FP_FLOAT_VERSION))
+dH
+x;dH
+gE
+A;hT
+C;hT
+D;qQ
+w5){TailCall_cAbs:g5
+cAbs:qS
+h0}
+qH
+TailCall_cAcos:g5
+cAcos:qY
+wB(172,"x cAcos"
+,"[fp_acos(x)]"
+,wN);q4
+Lad;}
+qH
+TailCall_cAcosh:g5
+cAcosh:qY
+wB(169,"x cAcosh"
+,"[fp_acosh(x)]"
+,wN);q4
+Lae;}
+qH
+TailCall_cAdd:g5
+hG
+Laf;qT
+h3
+hL]==hS){if(qL
+gZ
+Lag;}
+h8}
+q4
+dX
+qU
+d2
+gF
+h1
+wB(313,"cDup"
+a7
+aZ,"[x+Value_t(1)]"
+wH,wN);q4
+Lah;}
+}
+q4
+dX
+oF
+wB(199,qC1
+aZ,"cSub"
+,);q4
+Lai
+gY
+hK
+qZ
+mW(127,aY"cAdd"
+mD,"[y+x]"
+aZ,q81);q4
+Laj;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mW(298,aY"cAdd"
+mE
+mD,mN
+aZ
+mE,q81);q4
+Lak;qT
+hI
+wB(299,m0
+a6
+mD,"[-x]"
+aZ
+mE,wN);q4
+Lal
+qU
+q6:mW(297,aY
+a6
+mD,mN
+mE,q81);q4
+Lam;qT
+oA
+Lan;qT
+hI
+wB(293,m0"B[IsVarOpcode(B)]"
+aW
+mD,"[-x]"
+aZ" B"
+aW,wA","
+a8(B)wM);q4
+Lao
+qU
+q6:mW(291,aY"B[IsVarOpcode(B)]"
+aW
+mD,mN" B"
+aW,wA","
+a8(B)<<","
+a1);q4
+Lap;}
+w9
+mW(105,aY
+aF,"[y+x]"
+,q81);q4
+Laq;}
+g8)){wB(57,"x[x==Value_t()]"
+aZ,,wN);q4
+Lba;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x"
+mE
+a3"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aZ
+mE,aI(A)qD1
+wM);incStackPtr();--mStackPtr;q4
+Lbb;}
+wB(295,a6
+a3"cAdd"
+,"[DO_STACKPLUS1] A"
+aZ
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lbc;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mX"cAnd"
+,aJ,);q4
+w7
+m9(117,mA"cAnd"
+,"[fp_and(x,y)]"
+,q81);q4
+Lbe;h8}
+qH
+TailCall_cArg:g5
+cArg:qY
+wB(190,"x cArg"
+,"[fp_arg(x)]"
+,wN);q4
+Lbf;}
+qH
+TailCall_cAsin:g5
+cAsin:qY
+wB(173,"x cAsin"
+,"[fp_asin(x)]"
+,wN);q4
+Lbg;}
+qH
+TailCall_cAsinh:g5
+cAsinh:qY
+wB(170,"x cAsinh"
+,"[fp_asinh(x)]"
+,wN);q4
+Lbh;}
+qH
+TailCall_cAtan:g5
+cAtan:qY
+if(g1
+x.real(),fp_abs(x.imag()))!=g1
+0,oG
+wB(174,"x[Value_t(x.real(),fp_abs(x.imag()))!=Value_t(0,1)] cAtan"
+,"[fp_atan(x)]"
+,wN);q4
+Lbi;qG
+TailCall_cAtan2:g5
+cAtan2:qY
+m9(139,mA"cAtan2"
+,"[fp_atan2(y,x)]"
+,q81);q4
+Lbj;qG
+TailCall_cAtanh:g5
+cAtanh:qY
+if(g1
+fp_abs(x.real()),x.imag())!=g1
+1,0)){wB(171,"x[Value_t(fp_abs(x.real()),x.imag())!=Value_t(1,0)] cAtanh"
+,"[fp_atanh(x)]"
+,wN);q4
+Lbk;qG
+TailCall_cCbrt:g5
+cCbrt:qY
+wB(175,"x cCbrt"
+,"[fp_cbrt(x)]"
+,wN);q4
+Lbl;}
+qH
+TailCall_cCeil:g5
+cCeil:qS
+hI
+wB(402,m0
+q01,mS
+aA,);q4
+Lbm
+gY
+wB(135,"x "
+q01,"[fp_ceil(x)]"
+,wN);q4
+Lbn
+gS
+wB(396,"A[IsAlwaysIntegerOpcode(A)] "
+q01,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cConj:g5
+cConj:qS
+cConj:wB(63,mY" "
+mY,,);oS
+gY
+wB(193,"x "
+mY,"[fp_conj(x)]"
+,wN);q4
+Lbp;}
+qH
+TailCall_cCos:g5
+cCos:qS
+cAcos:wB(346,"cAcos "
+aO,,);q4
+oE
+wB(238,m0
+aO,aO,);q4
+Lbq
+gY
+wB(176,"x "
+aO,"[fp_cos(x)]"
+,wN);q4
+Lca;oH
+qN
+qQ
+h9
+cSec:hD
+wB(500,aK" cSec "
+wI
+aO,"B cSec "
+aT,aI(A)q91(B)wM);q4
+Lcb;qT
+cSin:hD
+wB(494,aK" "
+mP" "
+wI
+aO,"B cSinCos"
+,aI(A)q91(B)wM);q4
+Lcc;h8}
+qG
+TailCall_cCosh:g5
+cCosh:qS
+cAsinh:wB(450,"cAsinh "
+aM,"[DO_STACKPLUS1] "
+q41"[Value_t(1)] "
+aQ,);incStackPtr();--mStackPtr;q4
+Lcd
+oF
+wB(239,m0
+aM,aM,);q4
+Lce
+gY
+wB(177,"x "
+aM,"[fp_cosh(x)]"
+,wN);q4
+Lcf;oH
+qN
+oY
+cSinh
+q11(507,aK" cSinh "
+wI
+aM,"B cSinhCosh"
+,aI(A)q91(B)wM);q4
+Lcg;}
+}
+qG
+TailCall_cCot:g5
+cCot:A=qN
+oY
+cTan
+q11(498,aK" "
+mR" "
+wI"cCot"
+,"B "
+mR" "
+aT,aI(A)q91(B)wM);q4
+Lcb;}
+qG
+TailCall_cCsc:g5
+cCsc:A=qN
+oY
+cSin
+q11(496,aK" "
+mP" "
+wI"cCsc"
+,"B "
+mP" "
+aT,aI(A)q91(B)wM);q4
+Lcb;}
+qG
+TailCall_cDeg:g5
+cDeg:qY
+wB(133,"x cDeg"
+,"[RadiansToDegrees(x)]"
+,wN);q4
+Lch;}
+qH
+TailCall_cDiv:g5
+cDiv:qS
+cCos:wB(250,aO
+mF,"cSec"
+wH,);q4
+Lci
+qU
+cCot:wB(254,"cCot"
+mF,mR
+wH,);q4
+Lcj
+qU
+cCsc:wB(252,"cCsc"
+mF,mP
+wH,);q4
+Lck
+qU
+cDup:wB(78,"cDup"
+mF,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,);q4
+Lcl
+qU
+w2
+wB(408,"cExp"
+mF,m0"cExp"
+wH,);q4
+Lcm
+qU
+cExp2:wB(409,"cExp2"
+mF,m0"cExp2"
+wH,);q4
+Lcn
+qU
+cInv:wB(213,aU
+mF,"cMul"
+,);q4
+Lco
+qU
+cPow:wB(407,"cPow"
+mF,m0"cPow"
+wH,);q4
+Lcp
+qU
+cSec:wB(253,"cSec"
+mF,aO
+wH,);q4
+Lcq
+qU
+cSin:wB(249,mP
+mF,"cCsc"
+wH,);q4
+Lda
+qU
+cSinCos:wB(502,"cSinCos"
+mF,mR,);q4
+Ldb
+qU
+cSinhCosh:wB(509,"cSinhCosh"
+mF,"cTanh"
+,);q4
+Ldc
+qU
+cTan:wB(251,mR
+mF,"cCot"
+wH,);q4
+Ldd
+gY
+if
+hF
+gQ
+hI
+wB(125,m0
+a4"cDiv"
+,"[-x]"
+mF,wN);q4
+Lde
+qU
+q6:mW(103,aY
+a4"cDiv"
+,"[y/x]"
+,q81);q4
+Ldf;}
+}
+g8
+oG
+wB(56,wO"cDiv"
+,,wN);q4
+Lba;}
+dB
+h3
+gA
+qZ
+hP(y/x)==fp_const_rad_to_deg
+h7
+wB(321,"y[(y/x)==fp_const_rad_to_deg<Value_t>()]"
+wH" "
+wR,"cDeg"
+,q81);q4
+Ldg;}
+if((y/x)==fp_const_deg_to_rad
+h7
+wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]"
+wH" "
+wR,"cRad"
+,q81);q4
+Ldh;}
+wB(323,"y"
+wH" "
+wR,"[y/x]"
+wH,q81);q4
+Ldi;}
+}
+wB(325,wR,"[Value_t(1)/x]"
+wH,wN);q4
+Ldj;}
+gP
+cDiv:hC
+wB(271,aX"cDiv "
+wV,"[DO_STACKPLUS1] B A"
+wH
+mF,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4
+Ldk;qT
+cRDiv:qQ
+hE
+qV
+hM
+wB(266,"x"
+a9" "
+wV,"A"
+wH" [x]"
+a9,aI(A)qD1
+wM);q4
+Ldl;g7
+hC
+wB(265,"B[IsVarOpcode(B)]"
+a9" "
+wV,"A"
+wH" B"
+a9,aI(A)q91(B)wM);q4
+Ldm;}
+h8}
+qG
+TailCall_cEqual:g5
+w8:oL
+hU
+wB(359,m1
+aE,"[x] "
+aE,wN);q4
+Ldn
+qU
+cSqr:wB(361,q41
+wL
+aE,"[x] "
+aE,wN);q4
+Ldn;}
+}
+m9(115,mA
+aE,"[fp_equal(y,x)]"
+,q81);q4
+Ldo;qG
+TailCall_cExp:g5
+w2
+qS
+hS
+gM
+wB(404,aF
+mL,q21"[fp_exp(x)]"
+wH,wN);q4
+Ldp;qT
+cLog:A=dE
+wB(340,wJ
+mG
+mL,"A"
+,aI(A)wM);oS;qT
+hM
+wB(178,"x"
+mL,"[fp_exp(x)]"
+,wN);q4
+Ldq;}
+qH
+TailCall_cExp2:g5
+cExp2:qS
+hS
+gM
+wB(405,aF
+q31,"cExp2 [fp_exp2(x)]"
+wH,wN);q4
+Lea;qT
+cLog2:A=dE
+wB(341,wJ
+aN
+q31,"A"
+,aI(A)wM);oS;qT
+hM
+wB(179,"x"
+q31,"[fp_exp2(x)]"
+,wN);q4
+Leb;}
+wB(479,"cExp2"
+,"[DO_STACKPLUS1] [fp_log(Value_t(2))]"
+wH
+mL,);incStackPtr();--mStackPtr;q4
+Lec;TailCall_cFloor:g5
+cFloor:qS
+hI
+wB(401,m0
+mS,q01
+aA,);q4
+Led
+gY
+wB(136,"x "
+mS,"[fp_floor(x)]"
+,wN);q4
+Lee
+gS
+wB(395,"A[IsAlwaysIntegerOpcode(A)] "
+mS,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cGreater:g5
+o1:qY
+m9(113,mA
+m2,"[fp_less(x,y)]"
+,q81);q4
+Lef;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+m9(114,mA
+aG,"[fp_lessOrEq(x,y)]"
+,q81);q4
+Leg;qG
+TailCall_cHypot:g5
+cHypot
+d4
+dF==cSinCos){wB(84,"cSinCos cHypot"
+,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,);q4
+Lcl;}
+qH
+TailCall_cImag:g5
+cImag:qS
+cAbs:wB(81,mV" "
+mZ,"[Value_t()]"
+wH,);q4
+Leh
+qU
+cReal:wB(80,"cReal "
+mZ,"[Value_t()]"
+wH,);q4
+Leh
+gY
+wB(192,"x "
+mZ,"[fp_imag(x)]"
+,wN);q4
+Lei;}
+qH
+TailCall_cInt:g5
+cInt:qS
+hM
+wB(137,"x cInt"
+,"[fp_int(x)]"
+,wN);q4
+Lej
+gS
+wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt"
+,"A"
+,aI(A)wM);gJ
+qG
+TailCall_cInv:g5
+cInv:qS
+cCos:wB(256,aO" "
+aU,"cSec"
+,);q4
+Lek
+qU
+cCot:wB(260,"cCot "
+aU,mR,);q4
+Ldb
+qU
+cCsc:wB(258,"cCsc "
+aU,mP,);q4
+Lel
+qU
+cInv:wB(62,aU" "
+aU,,);oS
+qU
+cPow:wB(355,q61
+aU,m0"cPow"
+,);q4
+Lem
+qU
+cSec:wB(259,"cSec "
+aU,aO,);q4
+Len
+qU
+cSin:wB(255,mP" "
+aU,"cCsc"
+,);q4
+Leo
+qU
+cSqrt:wB(206,q51" "
+aU,"cRSqrt"
+,);q4
+Lep
+qU
+cTan:wB(257,mR" "
+aU,"cCot"
+,);q4
+Leq
+gY
+if
+hF)){wB(101,a4
+aU,"[Value_t(1)/x]"
+,wN);q4
+Lfa;h8}
+qH
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mJ,mK,qB1(A)wM);q4
+Lfb;}
+}
+m9(111,mA
+mJ,"[fp_less(y,x)]"
+,q81);q4
+Lfc;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:qY
+m9(112,mA
+aR,"[fp_lessOrEq(y,x)]"
+,q81);q4
+Lfd;qG
+TailCall_cLog:g5
+cLog:mT(343,q21
+mG,,);oS
+qU
+gL
+wB(491,mU
+mG,mG" [fp_log(x)]"
+aZ,wN);q4
+Lfe;}
+oD
+wB(180,qA1
+mG,"[fp_log(x)]"
+,wN);q4
+Lff;h8}
+qH
+TailCall_cLog10:g5
+cLog10:mT(481,q21
+aL,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfg
+qU
+gL
+wB(492,mU
+aL,aL" [fp_log10(x)]"
+aZ,wN);q4
+Lfh;}
+oD
+wB(181,qA1
+aL,"[fp_log10(x)]"
+,wN);q4
+Lfi;h8}
+qH
+TailCall_cLog2:g5
+cLog2:mT(480,q21
+aN,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfj
+qU
+cExp2:wB(344,"cExp2 "
+aN,,);oS
+qU
+gL
+wB(490,mU
+aN,aN" [fp_log2(x)]"
+aZ,wN);q4
+Lfk;}
+oD
+wB(182,qA1
+aN,"[fp_log2(x)]"
+,wN);q4
+Lfl;h8}
+qH
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mX
+mB,,);oS
+gY
+m9(141,mA
+mB,"[fp_max(x,y)]"
+,q81);q4
+Lfm;}
+gP
+cDup:hD
+wB(66,aK
+mQ
+a3
+mB,"B"
+mQ,aI(A)q91(B)wM);oS;qT
+cMax:hD
+wB(68,aK" "
+mB
+a3
+mB,"B "
+mB,aI(A)q91(B)wM);oS;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mX
+mC,,);oS
+gY
+m9(140,mA
+mC,"[fp_min(x,y)]"
+,q81);q4
+Lfn;}
+gP
+cDup:hD
+wB(65,aK
+mQ
+a3
+mC,"B"
+mQ,aI(A)q91(B)wM);oS;qT
+cMin:hD
+wB(67,aK" "
+mC
+a3
+mC,"B "
+mC,aI(A)q91(B)wM);oS;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m9(104,aY
+a4"cMod"
+,"[fp_mod(y,x)]"
+,q81);q4
+Lfo;}
+qG
+TailCall_cMul:g5
+h3:qS
+cCsc:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(508,aK" "
+aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc"
+wH,"B cCot"
+,aI(A)q91(B)wM);q4
+Lfp;}
+}
+}
+q4
+dY
+qU
+cDup:wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lfq
+qU
+cInv:wB(214,aU
+wH,"cDiv"
+,);q4
+Lga
+oF
+qQ
+h9
+cDup:wB(467,"cDup"
+aA
+wH,"cSqr"
+aA,);q4
+Lgb;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aK
+wH
+a3
+qC1
+wH,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lgc;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mX
+m8
+wH,"[x+Value_t(1)] cPow"
+,wN);q4
+Lgd;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wS" "
+wZ,wX,qB1(A)wM);q4
+Lge;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mW(92,aY
+wD,wX,qB1(A)<<","
+a1);q4
+Lgf;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mW(96,aY
+wK,mK,qB1(A)q91(B)<<","
+a1);q4
+Lgg;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lgh;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mK,qB1(A)q91(B)<<", C"
+wY(C)wM);q4
+Lgi;}
+}
+}
+if(d1
+B)){wB(90,aX
+wD,wX,qB1(A)q91(B)wM);q4
+Lge;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mK,qB1(A)q91(B)wM);q4
+Lgj;}
+}
+}
+if(d1
+h2
+wB(88,a5" "
+wZ,"[x]"
+,qB1(A)wM);q4
+Lgk;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wZ,wX,qB1(A)wM);q4
+Lgl;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup
+d4
+x+oU
+wB(316,"cDup[x+x==Value_t(1)]"
+aZ
+a7,,wN);q4
+Lgm;}
+wB(317,aH
+a7,"[x+x]"
+wH,wN);q4
+Lgn
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,a5" y"
+wH
+aZ
+a7,wX" A "
+m3
+aZ,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Lgo;}
+w9
+mW(385,aY"cAdd"
+a7,wX" [y*x]"
+aZ,q81);q4
+Lgp;qT
+cDeg:wB(209,"cDeg"
+a7,"[RadiansToDegrees(x)]"
+wH,wN);q4
+Lgq
+qU
+cDiv
+oB
+qV
+o5
+4
+qZ
+mW(278,"y"
+wH" "
+aX
+mH,m3
+qH1,wA","
+a8(B)<<","
+a1);q4
+Lha;qT
+hI
+wB(279,m0
+aX
+mH,mI
+qH1,wA","
+a8(B)wM);q4
+Lhb
+qU
+q6:mW(277,aY
+aX
+mH,"[y*x] B"
+mF,wA","
+a8(B)<<","
+a1);q4
+Lhc;}
+qT
+h3:qQ
+hE
+d3
+3
+h1
+if(x+oU
+wB(318,"cDup[x+x==Value_t(1)]"
+aZ
+wH
+a7,"cMul"
+,wN);q4
+Lhd;}
+wB(319,aH
+wH
+a7,"cMul [x+x]"
+wH,wN);q4
+Lhe;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+a7,,q81);q4
+Lhf;}
+if((y*x)==fp_const_rad_to_deg
+h7
+wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]"
+wH
+a7,"cDeg"
+,q81);q4
+Ldg;}
+if((y*x)==fp_const_deg_to_rad
+h7
+wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]"
+wH
+a7,"cRad"
+,q81);q4
+Ldh;}
+wB(128,"y"
+wH
+a7,m3,q81);q4
+Lhg;qT
+hI
+wB(122,qC1
+a7,mI,wN);q4
+Lhh
+qU
+cRDiv:qQ
+hE
+qV
+o5
+3
+qZ
+mW(285,"y"
+wH
+a9
+a7,m3
+a9,q81);q4
+Lhi;qT
+hI
+wB(286,qC1
+a9
+a7,mI
+a9,wN);q4
+Lhj
+qU
+q6:mW(284,"y"
+a9
+a7,"[y*x]"
+a9,q81);q4
+Lhk;qT
+cRad:wB(210,"cRad"
+a7,"[DegreesToRadians(x)]"
+wH,wN);q4
+Lhl
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,a5" y"
+wH
+aW
+a7,wX" A "
+m3
+aW,wA", "
+aY"= "
+<<y
+qE1(A)wM);q4
+Lhm;}
+}
+w9
+mW(102,"y"
+a7,"[y*x]"
+,q81);q4
+Lhn;}
+g8
+oG
+wB(55,"x[x==Value_t(1)]"
+wH,,wN);q4
+Lba;}
+g8-oG
+wB(124,"x[x==Value_t(-1)]"
+wH,qC1,wN);q4
+Lho;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,aH,wN);q4
+Lhp;}
+if(x==fp_const_rad_to_deg
+h7
+wB(207,"x[x==fp_const_rad_to_deg<Value_t>()]"
+wH,"cDeg"
+,wN);q4
+Lhq;}
+if(x==fp_const_deg_to_rad
+h7
+wB(208,"x[x==fp_const_deg_to_rad<Value_t>()]"
+wH,"cRad"
+,wN);q4
+Lia;h8
+g7
+dY:;A=dF
+qO
+A
+gQ
+cDiv:hC
+wB(274,aX"cDiv "
+wS,"[DO_STACKPLUS1] A"
+wH
+qH1,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4
+Lib;}
+q4
+d5
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aK
+aA
+wH" "
+wS,m5
+wH
+aA,aI(A)q91(B)wM);q4
+Lgc;}
+q4
+dZ;g7
+dZ:;hD
+wB(461,aK
+wH" "
+wS,m5
+wH,aI(A)q91(B)wM);q4
+Lic;}
+}
+q4
+d5
+hI
+hD
+wB(464,aK
+aA" "
+wS,m5
+aA,aI(A)q91(B)wM);q4
+Lgb;}
+q4
+d5
+cRDiv
+hL
+qZ
+qC
+wB(267,"x"
+a9" "
+wS,"[DO_STACKPLUS1] "
+mK
+a9,aI(A)qD1
+wM);incStackPtr();--mStackPtr;q4
+Lid;}
+wB(281,"cRDiv "
+wS,"[DO_STACKPLUS1] A"
+wH
+a9,aI(A)wM);incStackPtr();--mStackPtr;q4
+Lie;g7
+Default4:;B=qK
+qR
+w4
+wB(458,aK" "
+wS,m5,aI(A)q91(B)wM);q4
+Lfq;}
+}
+}
+if(gV
+h2
+B=qK
+qO
+B
+qP
+1
+gA
+oM
+C=oC
+qR
+C==A){D=qL
+4]qR
+D==B){wB(477,"D[D==B] C[C==A]"
+wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Lif;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:oL
+hU
+wB(360,m1
+wW,"[x] "
+wW,wN);q4
+Lig
+qU
+cSqr:wB(362,q41
+wL
+wW,"[x] "
+wW,wN);q4
+Lig;}
+}
+m9(116,mA
+wW,"[fp_nequal(y,x)]"
+,q81);q4
+Lih;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+wH
+aA,mI,wN);q4
+Lii;qT
+hI
+wB(61,qC1
+aA,,);oS
+qU
+cSin:g9
+wB(244,"x"
+wH" "
+mP
+aA,mI" "
+mP,wN);q4
+Lij;}
+qT
+oQ
+g9
+wB(245,"x"
+wH" cSinh"
+aA,mI" cSinh"
+,wN);q4
+Lik;}
+qT
+cTan:g9
+wB(246,"x"
+wH" "
+mR
+aA,mI" "
+mR,wN);q4
+Lil;}
+qT
+cTanh:g9
+wB(247,"x"
+wH" cTanh"
+aA,mI" cTanh"
+,wN);q4
+Lim;}
+qT
+hM
+wB(100,"x"
+aA,"[-x]"
+,wN);q4
+Lin;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbsNotNot:wB(231,"cAbsNotNot"
+a0,aS,);q4
+Lio
+qU
+w8:wB(220,aE
+a0,wW,);q4
+Lip
+qU
+o1:wB(218,m2
+a0,aR,);q4
+Liq
+qU
+dK:wB(219,aG
+a0,mJ,);q4
+Lja
+qU
+cLess:wB(216,mJ
+a0,aG,);q4
+Ljb
+qU
+cLessOrEq:wB(217,aR
+a0,m2,);q4
+Ljc
+qU
+cNEqual:wB(221,wW
+a0,aE,);q4
+Ljd
+qU
+cNot:wB(229,"cNot"
+a0,aJ,);q4
+Lbd
+qU
+dS:wB(230,aJ
+a0,"cNot"
+,);q4
+Lje
+gY
+wB(107,"x"
+a0,"[fp_not(x)]"
+,wN);q4
+Ljf;}
+qH
+TailCall_cNotNot:g5
+dS
+d4
+dF==cNot){wB(232,"cNot "
+aJ,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mX"cOr"
+,aJ,);q4
+w7
+m9(118,mA"cOr"
+,"[fp_or(x,y)]"
+,q81);q4
+Ljg;h8}
+qH
+TailCall_cPolar:g5
+cPolar
+d4
+q0[0
+qZ
+y=q7;qJ
+x
+gO
+wB(194,"x "
+aY"cPolar"
+,"[fp_polar(x,y)]"
+," with "
+aY"= "
+<<y
+qD1
+wM);q4
+Ljh;qG
+TailCall_cPow:g5
+cPow:qY
+if(isInteger(x
+gQ
+w2
+wB(43,q21
+wT,wX
+mL,wN);q4
+Lji
+qU
+cExp2:wB(44,"cExp2 "
+wT,wX
+q31,wN);q4
+Ljj
+qU
+cPow
+hL
+qZ
+hP!isInteger(y)){wB(42,"y[!isInteger(y)] "
+q61
+wT,aP,q81);q4
+Ljk;}
+}
+wB(45,q61
+wT,wX" cPow"
+,wN);q4
+Ljl;}
+}
+g8)){wB(83,"x[x==Value_t()] cPow"
+,"[Value_t()]"
+wH" [Value_t(1)]"
+aZ,wN);q4
+Ljm;}
+g8
+oO
+wB(332,"x[x==Value_t(0.5)] cPow"
+,q51,wN);q4
+Ljn;}
+g8
+1)/g1
+3)){wB(333,"x[x==Value_t(1)/Value_t(3)] cPow"
+,"cCbrt"
+,wN);q4
+Ljo;}
+g8
+1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)] cPow"
+,"cCbrt "
+aU,wN);q4
+Ljp;}
+g8-oO
+wB(335,"x[x==Value_t(-0.5)] cPow"
+,"cRSqrt"
+,wN);q4
+Ljq;}
+g8-oG
+wB(336,"x[x==Value_t(-1)] cPow"
+,aU,wN);q4
+Lka;}
+qQ
+h9
+cPow
+hL
+qZ
+mW(330,aY
+q61
+m8,aP,q81);q4
+Ljk;o2
+wB(46,q41
+m8,"[x+x] cPow"
+,wN);q4
+Lkb
+qU
+q6:mW(189,aY
+m8,"[fp_pow(y,x)]"
+,q81);q4
+Lkc;}
+wB(455,m8,"[DO_POWI]"
+,wN)qR
+TryCompilePowi(x))gJ}
+qH
+TailCall_cRDiv:g5
+cRDiv:qS
+cSinCos:wB(503,"cSinCos"
+a9,"cCot"
+,);q4
+Leq
+qU
+cSinhCosh:wB(510,"cSinhCosh"
+a9,"cTanh "
+aU,);q4
+Lkd
+gY
+g8
+oG
+wB(268,wO"cRDiv"
+,aU,wN);q4
+Lka;h8}
+qH
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,"cDup"
+mE,"[Value_t()]"
+wH,);q4
+Leh;}
+qH
+TailCall_cRad:g5
+cRad:qS
+h3
+gM
+wB(211,"x"
+wH" cRad"
+,"[DegreesToRadians(x)]"
+wH,wN);q4
+Lke;qT
+hM
+wB(134,"x cRad"
+,"[DegreesToRadians(x)]"
+,wN);q4
+Lkf;}
+qH
+TailCall_cReal:g5
+cReal:qY
+wB(191,"x cReal"
+,"[fp_real(x)]"
+,wN);q4
+Lkg;}
+qH
+TailCall_cSec:g5
+cSec:A=qN
+qQ
+h9
+cCos:hD
+wB(497,aK" "
+aO" "
+wI"cSec"
+,"B "
+aO" "
+aT,aI(A)q91(B)wM);q4
+Lcb;qT
+cSin:hD
+wB(495,aK" "
+mP" "
+wI"cSec"
+,"B cSinCos "
+aU,aI(A)q91(B)wM);q4
+Lkh;h8
+qG
+TailCall_cSin:g5
+cSin:qS
+cAsin:wB(345,"cAsin "
+mP,,);q4
+oE
+wB(240,m0
+mP,mP
+aA,);q4
+Lki
+gY
+wB(183,"x "
+mP,"[fp_sin(x)]"
+,wN);q4
+Lkj;oH
+qN
+oY
+cCsc
+q11(499,aK" cCsc "
+wI
+mP,"B cCsc "
+aT,aI(A)q91(B)wM);q4
+Lcb;}
+}
+qG
+TailCall_cSinh:g5
+oQ
+qS
+cAcosh:wB(437,"cAcosh cSinh"
+,"[DO_STACKPLUS1] "
+q41"[Value_t(-1)] "
+aQ,);incStackPtr();--mStackPtr;q4
+Lkk
+qU
+cAsinh:wB(349,"cAsinh cSinh"
+,,);q4
+oE
+wB(241,m0"cSinh"
+,"cSinh"
+aA,);q4
+Lkl
+gY
+wB(184,"x cSinh"
+,"[fp_sinh(x)]"
+,wN);q4
+Lkm;}
+qH
+TailCall_cSqr:g5
+cSqr:qS
+cAbs:wB(204,mV" cSqr"
+,"cSqr"
+,);q4
+Lkn
+oF
+wB(203,m0"cSqr"
+,"cSqr"
+,);q4
+Lkn
+qU
+cSqrt:A=dE
+wB(338,wJ
+q51" cSqr"
+,"A"
+,aI(A)wM);oS;h8}
+qH
+TailCall_cSqrt:g5
+cSqrt:qS
+hS
+d4
+qK
+o3
+A=hE
+w0
+if(oC
+o3
+wB(512,"cSqr"
+a3
+q41
+aQ,"A cHypot"
+,aI(A)wM);q4
+Lko;}
+}
+B
+g4
+gV
+B)){A=oC
+w0
+if(qL
+4]o3
+wB(513,"cSqr"
+a3"B[IsUnaryOpcode(B)] "
+q41
+aQ,"A B cHypot"
+," with"
+a8(B)qE1(A)wM);q4
+Lkp;}
+}
+}
+o2
+wB(23,q41
+q51,mV,);q4
+Lkq
+gY
+wB(185,"x "
+q51,"[fp_sqrt(x)]"
+,wN);q4
+Lla;}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,"cDup"
+aW,"[Value_t()]"
+wH,);q4
+Leh
+oF
+wB(200,qC1
+aW,"cAdd"
+,);q4
+Llb
+gY
+g8)){wB(58,"x[x==Value_t()]"
+aW,,wN);q4
+Lba;}
+m9(106,aY"x"
+aW,"[y-x]"
+,q81);q4
+Llc;}
+wB(51,"x"
+aW,"[-x]"
+aZ,wN);q4
+Lld
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x"
+mE
+a3"cSub"
+,"A"
+aZ" [x]"
+mE,aI(A)qD1
+wM);q4
+Lle;}
+wB(296,a6
+a3"cSub"
+,"[DO_STACKPLUS1] A"
+aW
+mE,aI(A)wM);incStackPtr();--mStackPtr;q4
+Llf;}
+qG
+TailCall_cTan:g5
+cTan:qS
+cAtan2:wB(354,"cAtan2 "
+mR,"cDiv"
+,);q4
+Lga
+oF
+wB(242,m0
+mR,mR
+aA,);q4
+Llg
+gY
+wB(187,"x "
+mR,"[fp_tan(x)]"
+,wN);q4
+Llh;oH
+qN
+oY
+cCot
+q11(501,aK" cCot "
+wI
+mR,"B cCot "
+aT,aI(A)q91(B)wM);q4
+Lcb;}
+}
+qG
+TailCall_cTanh:g5
+cTanh:qS
+cAtanh:wB(352,"cAtanh cTanh"
+,,);q4
+oE
+wB(243,m0"cTanh"
+,"cTanh"
+aA,);q4
+Lli
+gY
+wB(188,"x cTanh"
+,"[fp_tanh(x)]"
+,wN);q4
+Llj;}
+qH
+TailCall_cTrunc:g5
+cTrunc:qS
+hM
+wB(138,"x cTrunc"
+,"[fp_trunc(x)]"
+,wN);q4
+Llk
+gS
+wB(394,"A[IsAlwaysIntegerOpcode(A)] cTrunc"
+,"A"
+,aI(A)wM);gJ
+qG
+g7
+Default0:;A=w5
+w1
+0){B=q0[0
+hZ
+wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mQ,aI(A)q91(B)wM);q4
+Lll;}
+}
+if(gV
+h2
+B=dF
+qO
+B
+qP
+1){C=qK
+qR
+C==A){D
+g4
+D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+,"D C"
+mQ,aI(A)q91(B)<<", C"
+wY(C)<<", D"
+wY(D)wM);q4
+Llm;}
+}
+}
+}
+C=w5
+qR
+IsCommutativeOrParamSwappableBinaryOpcode(C)){qS
+cSin:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(505,aK" "
+aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] "
+mP" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinCos {GetParamSwappedBinaryOpcode(C)}"
+," with C"
+wY(C)qE1(A)q91(B)wM);q4
+Lln;}
+}
+qT
+oQ
+A=qK
+w1
+3
+gA]==cCosh){B=hQ
+wB(506,aK" "
+aM" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}"
+," with C"
+wY(C)qE1(A)q91(B)wM);q4
+Llo;}
+}
+h8}
+}
+}
+q4
+Laa;Laa:qW
+w5);gJ
+Lab:g6
+Llp:wE(cAbs);q4
+TailCall_cAbs;Lac:q7=dP;gJ
+Lad:q7=fp_acos
+m6
+Lae:q7=fp_acosh
+m6
+Laf:oZ
+4));gG
+Llq:w5=h3;Lma:g0
+Lmb:wE(cMul);q4
+TailCall_cMul;Lag:hV
+4
+dT
+oZ
+4));Lmc:qW
+q6
+hY;Lah:q7=x+g1
+1);gG
+Lfb:w5=h3;q4
+Lmb;Lai:gU
+cSub;Lmd:wE(cSub);q4
+TailCall_cSub;Laj:hW
+2
+gH
+Lme:g0
+Lmf:wE(cAdd);q4
+TailCall_cAdd;Lak:hW
+oR
+Lmg:qE
+hS);Lmh:w5=cRSub;g0
+wE(cRSub);q4
+TailCall_cRSub;Lal:o9;qL
+2
+gK
+q4
+Lmg;Lam:hW
+2
+gH
+q4
+Lmh;Lan:hW
+4
+gH
+Lmi:qE
+hS);Lmj:qE
+B);Lmk:w5=cSub;g0
+q4
+Lmd;Lao:o9;oC=q6
+q9
+oR
+q4
+Lmi;Lap:hW
+oR
+q4
+Lmj;Laq:gT
+y+x;Lba:qM
+Lbo:q5
+gJ
+Lbb:q8
+oV
+o7
+x
+q71
+gX
+Lmg;Lbc:mM
+A
+gX
+Lmg;Lbd:gU
+dS;wE(cNotNot);q4
+TailCall_cNotNot;Lbe:gT
+fp_and(x
+d6
+Lbf:q7=fp_arg
+m6
+Lbg:q7=fp_asin
+m6
+Lbh:q7=fp_asinh
+m6
+Lbi:q7=fp_atan
+m6
+Lbj:gT
+fp_atan2(gW
+Lbk:q7=fp_atanh
+m6
+Lbl:q7=fp_cbrt
+m6
+Lbm:q1
+cFloor);Lml:w5=cNeg;g0
+wE(cNeg);q4
+TailCall_cNeg;Lbn:q7=fp_ceil
+m6
+Lbp:q7=fp_conj
+m6
+Lbq:g6
+Lmm:wE(cCos);q4
+TailCall_cCos;Lca:q7=fp_cos
+m6
+Lcb:dF=cDup;w5=cInv;Lmn:wE(cInv);q4
+TailCall_cInv;Lcc:mM
+cSinCos);gJ
+Lcd:q1
+cSqr
+o7
+g1
+1));Lmo:qW
+q6
+oJ
+hS);Lmp:w5=cSqrt;g0
+wE(cSqrt);q4
+TailCall_cSqrt;Lce:g6
+wE(cCosh);q4
+TailCall_cCosh;Lcf:q7=fp_cosh
+m6
+Lcg:mM
+cSinhCosh);gJ
+Lch:q7=RadiansToDegrees
+m6
+Lci:q1
+cSec
+hY;Lcj:q1
+cTan
+hY;Lck:q1
+cSin
+hY;Lcl:oZ));dF
+dJ
+Lmq:qE
+dU
+oZ
+1));Lna:qW
+q6);Lnb:w5=hS;q4
+Lme;Lcm:q1
+cNeg
+oJ
+cExp
+hY;Lcn:q1
+cNeg
+oJ
+cExp2
+hY;Lco:g6
+q4
+Lfb;Lcp:q1
+cNeg
+oJ
+cPow
+hY;Lcq:q1
+cCos
+hY;Lda:q1
+cCsc
+hY;Ldb:gU
+cTan;Lnc:wE(cTan);q4
+TailCall_cTan;Ldc:gU
+cTanh;Lnd:wE(cTanh);q4
+TailCall_cTanh;Ldd:q1
+cCot
+hY;Lde:o9;dI
+Lne:wE(cDiv);q4
+TailCall_cDiv;Ldf:gT
+y/x;q4
+Lba;Ldg:qF1
+q8
+oR
+Lnf:w5=cDeg;g0
+wE(cDeg);q4
+TailCall_cDeg;Ldh:qF1
+q8
+oR
+Lng:w5=cRad;g0
+wE(cRad);q4
+TailCall_cRad;Ldi:gT
+y/x;dG
+Llq;Ldj:q7=g1
+1)/x;q4
+Lfb;Ldk:mM
+oI
+Lnh:g0
+q4
+Lne;Ldl:q8
+3
+gC
+oI
+qF
+x
+q71);Lni:w5=cRDiv;g0
+wE(cRDiv);q4
+TailCall_cRDiv;Ldm:hV
+3
+gC
+oI
+qE
+B
+gX
+Lni;Ldn:dI
+Lnj:wE(cEqual);q4
+TailCall_cEqual;Ldo:gT
+fp_equal(gW
+Ldp:d7
+cExp
+o7
+fp_exp(x)gX
+Lmc;Ldq:q7=fp_exp
+m6
+Lea:d7
+cExp2
+o7
+fp_exp2(x)gX
+Lmc;Leb:q7=fp_exp2
+m6
+Lec:qF
+oW
+g1
+2))q71);Lnk:qE
+h3
+gI
+cExp;g0
+wE(cExp);q4
+TailCall_cExp;Led:q1
+cCeil
+oT
+Lee:q7=fp_floor
+m6
+Lef:gT
+fp_less(x
+d6
+Leg:gT
+fp_lessOrEq(x
+d6
+Leh:oZ));Lnl:dF
+dJ
+q4
+Llq;Lei:q7=fp_imag
+m6
+Lej:q7=fp_int
+m6
+Lek:gU
+cSec;wE(cSec);q4
+TailCall_cSec;Lel:gU
+cSin;Lnm:wE(cSin);q4
+TailCall_cSin;Lem:q1
+cNeg
+gI
+cPow;Lnn:g0
+Lno:wE(cPow);q4
+TailCall_cPow;Len:gU
+cCos;q4
+Lmm;Leo:gU
+cCsc;wE(cCsc);q4
+TailCall_cCsc;Lep:q1
+cRSqrt);gJ
+Leq:g6
+Lnp:w5=cCot;wE(cCot);q4
+TailCall_cCot;Lfa:q7=g1
+1)/x;gJ
+Lfc:gT
+fp_less(gW
+Lfd:gT
+fp_lessOrEq(gW
+Lfe:d7
+cLog
+o7
+oW
+x)gX
+Lna;Lff:q7=oW
+x);gJ
+Lfg:qF
+dR
+fp_const_e<dH>())gX
+Lnl;Lfh:d7
+cLog10
+o7
+dR
+x)gX
+Lna;Lfi:q7=dR
+x);gJ
+Lfj:qF
+o4
+fp_const_e<dH>())gX
+Lnl;Lfk:d7
+cLog2
+o7
+o4
+x)gX
+Lna;Lfl:q7=o4
+x);gJ
+Lfm:gT
+fp_max(x
+d6
+Lfn:gT
+fp_min(x
+d6
+Lfo:gT
+fp_mod(gW
+Lfp:hV
+oR
+q0-=3;q4
+Lnp;Lfq:gU
+cSqr;Lnq:wE(cSqr);q4
+TailCall_cSqr;Lga:gU
+cDiv;q4
+Lne;Lgb:mM
+cSqr
+oT
+Lgc:hV
+3
+gC
+cSqr);dM
+Lml;Lgd:q7=x+g1
+1);gG
+w5=cPow;q4
+Lno;Lge:gG
+q4
+Lmb;Lgf:gT
+x;Loa:dG
+Lma;Lgg:qF1
+qM
+Lob:hV
+4
+gH
+Loc:o6
+x);Lod:qW
+q6
+gX
+Lma;Lgh:qM
+q4
+Lob;Lgi:q8
+4
+gC
+B
+gX
+Loc;Lgj:q8
+oR
+q4
+Loc;Lgk:qK
+dJ
+oS;Lgl:dI
+q4
+Lmb;Lgm:qM
+Loe:hV
+oR
+gJ
+Lgn:q7=x+x;q4
+Lge;Lgo:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Lnb;Lgp:gT
+x;d7
+dU
+qF
+y*x
+gX
+Lna;Lgq:q7=RadiansToDegrees(x
+gX
+Lgl;Lha:qG1
+q8
+4
+gH
+Lof:qE
+dU
+Log:qE
+B
+gI
+cDiv;q4
+Lnh;Lhb:o9;oC=q6
+q9
+oR
+q4
+Lof;Lhc:qG1
+q8
+oR
+q4
+Log;Lhd:q8
+4
+gH
+q4
+Lma;Lhe:q8
+4
+dT
+qF
+x+x
+gX
+Lod;Lhf:qF1
+qM
+q4
+Loe;Lhg:qG1
+q4
+Loa;Lhh:o9;q4
+Lgl;Lhi:qG1
+q8
+oR
+Loh:dM
+Lni;Lhj:o9;qL
+2
+gK
+q4
+Loh;Lhk:qG1
+dG
+Lni;Lhl:q7=h4
+gX
+Lgl;Lhm:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q71);dM
+Lmk;Lhn:qG1
+q4
+Lba;Lho:qM
+w3
+Lml;Lhp:dF=cDup;dW-=1;qM
+Loi:w5=hS;q4
+Lmf;Lhq:qM
+w3
+Lnf;Lia:qM
+w3
+Lng;Lib:hV
+oV
+gX
+Lof;Lic:hV
+2
+gH
+Loj:qE
+cSqr
+gX
+Lma;Lid:q8
+oV
+o7
+x
+q71
+gX
+Loh;Lie:mM
+A
+gX
+Loh;Lif:hV
+oR
+q4
+Loj;Lig:dI
+Lok:wE(cNEqual);q4
+TailCall_cNEqual;Lih:gT
+fp_nequal(gW
+Lii:o9;q4
+Lco;Lij:o9
+gB
+cSin;g0
+q4
+Lnm;Lik:o9
+gB
+cSinh;g0
+wE(cSinh);q4
+TailCall_cSinh;Lil:o9
+gB
+cTan;g0
+q4
+Lnc;Lim:o9
+gB
+cTanh;g0
+q4
+Lnd;Lin:o9;gJ
+Lio:q1
+cAbsNot);gJ
+Lip:gU
+cNEqual;q4
+Lok;Liq:gU
+cLessOrEq;wE(cLessOrEq);q4
+TailCall_cLessOrEq;Lja:gU
+cLess;wE(cLess);q4
+TailCall_cLess;Ljb:gU
+dK;wE(cGreaterOrEq);q4
+TailCall_cGreaterOrEq;Ljc:gU
+o1;wE(cGreater);q4
+TailCall_cGreater;Ljd:gU
+w8;q4
+Lnj;Lje:g6
+wE(cNot);q4
+TailCall_cNot;Ljf:q7=fp_not
+m6
+Ljg:gT
+fp_or(x
+d6
+Ljh:gT
+fp_polar(x
+d6
+Lji:dL
+Lnk;Ljj:qK=d8
+cExp2;g0
+wE(cExp2);q4
+TailCall_cExp2;Ljk:qG1
+dG
+Lnn;Ljl:qK
+dJ
+q1
+h3
+gX
+Lnn;Ljm:q7=g1
+gX
+Lmq;Ljn:qM
+w3
+Lmp;Ljo:qM
+q5
+w5=cCbrt;g0
+wE(cCbrt);q4
+TailCall_cCbrt;Ljp:qM
+q1
+cCbrt);Lol:w5=cInv;g0
+q4
+Lmn;Ljq:qM
+q4
+Lep;Lka:qM
+w3
+Lol;Lkb:q7=x+x;dI
+q4
+Lno;Lkc:gT
+oX
+gW
+Lkd:q1
+cTanh
+gX
+Lol;Lke:q7=h4
+gX
+Lco;Lkf:q7=h4);gJ
+Lkg:q7=fp_real
+m6
+Lkh:mM
+cSinCos
+gX
+Lol;Lki:q1
+cSin
+oT
+Lkj:q7=fp_sin
+m6
+Lkk:q1
+cSqr
+o7
+g1-1)gX
+Lmo;Lkl:q1
+cSinh
+oT
+Lkm:q7=fp_sinh
+m6
+Lkn:g6
+q4
+Lnq;Lko:hV
+4
+gC
+A);Lom:w5=cHypot;g0
+wE(cHypot);q4
+TailCall_cHypot;Lkp:hV
+5
+gC
+A
+oJ
+B
+gX
+Lom;Lkq:gU
+cAbs;q4
+Llp;Lla:q7=fp_sqrt
+m6
+Llb:g6
+q4
+Loi;Llc:gT
+y-x;q4
+Lba;Lld:o9;q4
+Loi;Lle:q8
+oV
+oJ
+hS
+o7
+x
+q71
+gX
+Lmh;Llf:mM
+A
+oJ
+cSub
+gX
+Lmh;Llg:q1
+cTan
+oT
+Llh:q7=fp_tan
+m6
+Lli:q1
+cTanh
+oT
+Llj:q7=fp_tanh
+m6
+Llk:q7=fp_trunc
+m6
+Lll:qW
+cDup);gJ
+Llm:dF=cDup;gJ
+Lln:hV
+3
+gC
+cSinCos);Lon:qE
+GetParamSwappedBinaryOpcode(C));gJ
+Llo:hV
+3
+gC
+cSinhCosh
+gX
+Lon;gJ
+q4
+TailCall_cAcos;q4
+TailCall_cAcosh;q4
+TailCall_cAnd;q4
+TailCall_cArg;q4
+TailCall_cAsin;q4
+TailCall_cAsinh;q4
+TailCall_cAtan;q4
+TailCall_cAtan2;q4
+TailCall_cAtanh;q4
+TailCall_cCeil;q4
+TailCall_cConj;q4
+TailCall_cFloor;q4
+TailCall_cImag;q4
+TailCall_cInt;q4
+TailCall_cLog;q4
+TailCall_cLog10;q4
+TailCall_cLog2;q4
+TailCall_cMax;q4
+TailCall_cMin;q4
+TailCall_cMod;q4
+TailCall_cOr;q4
+TailCall_cPolar;q4
+TailCall_cRDiv;q4
+TailCall_cRad;q4
+TailCall_cReal;q4
+TailCall_cSec;q4
+TailCall_cSin;q4
+TailCall_cSinh;q4
+TailCall_cSqrt;q4
+TailCall_cSub;q4
+TailCall_cTan;q4
+TailCall_cTanh;q4
+TailCall_cTrunc;
+#endif
+#undef FP_ReDefinePointers
+#undef FP_TRACE_BYTECODE_OPTIMIZATION
+#undef FP_TRACE_OPCODENAME
diff --git a/fparser/extrasrc/fpaux.hh b/fparser/extrasrc/fpaux.hh
new file mode 100644
index 0000000..fe2011c
--- /dev/null
+++ b/fparser/extrasrc/fpaux.hh
@@ -0,0 +1,1238 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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 "fptypes.hh"
+
+#include <cmath>
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+#include "mpfr/MpfrFloat.hh"
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+#include "mpfr/GmpInt.hh"
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+#include <complex>
+#endif
+
+#ifdef ONCE_FPARSER_H_
+namespace FUNCTIONPARSERTYPES
+{
+ template<typename>
+ 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
+
+ template<typename>
+ struct IsComplexType
+ {
+ enum { result = false };
+ };
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+ template<typename T>
+ struct IsComplexType<std::complex<T> >
+ {
+ enum { result = true };
+ };
+#endif
+
+
+//==========================================================================
+// Constants
+//==========================================================================
+ template<typename Value_t>
+ inline Value_t fp_const_pi() // CONSTANT_PI
+ {
+ return Value_t(3.1415926535897932384626433832795028841971693993751L);
+ }
+
+ 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_pi<MpfrFloat>() { return MpfrFloat::const_pi(); }
+
+ 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
+
+
+//==========================================================================
+// Generic math functions
+//==========================================================================
+ template<typename Value_t>
+ inline Value_t fp_abs(const Value_t& x) { return std::fabs(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_acos(const Value_t& x) { return std::acos(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_asin(const Value_t& x) { return std::asin(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_atan(const Value_t& x) { return std::atan(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_atan2(const Value_t& x, const Value_t& y)
+ { return std::atan2(x, y); }
+
+ template<typename Value_t>
+ inline Value_t fp_ceil(const Value_t& x) { return std::ceil(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_cos(const Value_t& x) { return std::cos(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_cosh(const Value_t& x) { return std::cosh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_exp(const Value_t& x) { return std::exp(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_floor(const Value_t& x) { return std::floor(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_log(const Value_t& x) { return std::log(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_mod(const Value_t& x, const Value_t& y)
+ { return std::fmod(x, y); }
+
+ template<typename Value_t>
+ inline Value_t fp_sin(const Value_t& x) { return std::sin(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_sinh(const Value_t& x) { return std::sinh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_sqrt(const Value_t& x) { return std::sqrt(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_tan(const Value_t& x) { return std::tan(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_tanh(const Value_t& x) { return std::tanh(x); }
+
+#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+ template<typename Value_t>
+ inline Value_t fp_asinh(const Value_t& x) { return std::asinh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_acosh(const Value_t& x) { return std::acosh(x); }
+
+ template<typename Value_t>
+ inline Value_t fp_atanh(const Value_t& x) { return std::atanh(x); }
+#else
+ template<typename Value_t>
+ inline Value_t fp_asinh(const Value_t& x)
+ { return fp_log(x + fp_sqrt(x*x + Value_t(1))); }
+
+ template<typename Value_t>
+ inline Value_t fp_acosh(const Value_t& x)
+ { return fp_log(x + fp_sqrt(x*x - Value_t(1))); }
+
+ template<typename Value_t>
+ inline Value_t fp_atanh(const Value_t& x)
+ {
+ return fp_log( (Value_t(1)+x) / (Value_t(1)-x)) * Value_t(0.5);
+ // Note: x = +1 causes division by zero
+ // x = -1 causes log(0)
+ // Thus, x must not be +-1
+ }
+#endif // FP_SUPPORT_ASINH
+
+#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+ template<typename Value_t>
+ inline Value_t fp_hypot(const Value_t& x, const Value_t& y)
+ { return std::hypot(x,y); }
+#else
+ template<typename Value_t>
+ inline Value_t fp_hypot(const Value_t& x, const Value_t& y)
+ { return fp_sqrt(x*x + y*y); }
+#endif
+
+ template<typename Value_t>
+ inline Value_t fp_pow_base(const Value_t& x, const Value_t& y)
+ { return std::pow(x, y); }
+
+#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+ template<typename Value_t>
+ inline Value_t fp_log2(const Value_t& x) { return std::log2(x); }
+#else
+ template<typename Value_t>
+ inline Value_t fp_log2(const Value_t& x)
+ {
+ return fp_log(x) * fp_const_log2inv<Value_t>();
+ }
+#endif // FP_SUPPORT_LOG2
+
+ template<typename Value_t>
+ inline Value_t fp_log10(const Value_t& x)
+ {
+ return fp_log(x) * fp_const_log10inv<Value_t>();
+ }
+
+ template<typename Value_t>
+ inline Value_t fp_trunc(const Value_t& x)
+ {
+ return x < Value_t() ? fp_ceil(x) : fp_floor(x);
+ }
+
+ template<typename Value_t>
+ inline Value_t fp_int(const Value_t& x)
+ {
+ return x < Value_t() ?
+ fp_ceil(x - Value_t(0.5)) : fp_floor(x + Value_t(0.5));
+ }
+
+ template<typename Value_t>
+ inline void fp_sinCos(Value_t& sinvalue, Value_t& cosvalue,
+ const Value_t& param)
+ {
+ // Assuming that "cosvalue" and "param" do not
+ // overlap, but "sinvalue" and "param" may.
+ cosvalue = fp_cos(param);
+ sinvalue = fp_sin(param);
+ }
+
+ template<typename Value_t>
+ inline void fp_sinhCosh(Value_t& sinhvalue, Value_t& coshvalue,
+ const Value_t& param)
+ {
+ const Value_t ex(fp_exp(param)), emx(fp_exp(-param));
+ sinhvalue = Value_t(0.5)*(ex-emx);
+ coshvalue = Value_t(0.5)*(ex+emx);
+ }
+
+ template<typename Value_t>
+ struct Epsilon
+ {
+ static Value_t value;
+ static Value_t defaultValue() { return 0; }
+ };
+
+ template<> inline double Epsilon<double>::defaultValue() { return 1E-12; }
+ template<> inline float Epsilon<float>::defaultValue() { return 1E-5F; }
+ template<> inline long double Epsilon<long double>::defaultValue() { return 1E-14L; }
+
+ template<> inline std::complex<double>
+ Epsilon<std::complex<double> >::defaultValue() { return 1E-12; }
+
+ template<> inline std::complex<float>
+ Epsilon<std::complex<float> >::defaultValue() { return 1E-5F; }
+
+ template<> inline std::complex<long double>
+ Epsilon<std::complex<long double> >::defaultValue() { return 1E-14L; }
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+ template<> inline MpfrFloat
+ Epsilon<MpfrFloat>::defaultValue() { return MpfrFloat::someEpsilon(); }
+#endif
+
+ template<typename Value_t> Value_t Epsilon<Value_t>::value =
+ Epsilon<Value_t>::defaultValue();
+
+
+#ifdef _GNU_SOURCE
+ inline void fp_sinCos(double& sin, double& cos, const double& a)
+ {
+ sincos(a, &sin, &cos);
+ }
+ inline void fp_sinCos(float& sin, float& cos, const float& a)
+ {
+ sincosf(a, &sin, &cos);
+ }
+ inline void fp_sinCos(long double& sin, long double& cos,
+ const long double& a)
+ {
+ sincosl(a, &sin, &cos);
+ }
+#endif
+
+
+// -------------------------------------------------------------------------
+// Long int
+// -------------------------------------------------------------------------
+ inline long fp_abs(const long& x) { return x < 0 ? -x : x; }
+ inline long fp_acos(const long&) { return 0; }
+ inline long fp_asin(const long&) { return 0; }
+ inline long fp_atan(const long&) { return 0; }
+ inline long fp_atan2(const long&, const long&) { return 0; }
+ inline long fp_cbrt(const long&) { return 0; }
+ inline long fp_ceil(const long& x) { return x; }
+ inline long fp_cos(const long&) { return 0; }
+ inline long fp_cosh(const long&) { return 0; }
+ inline long fp_exp(const long&) { return 0; }
+ inline long fp_exp2(const long&) { return 0; }
+ inline long fp_floor(const long& x) { return x; }
+ inline long fp_log(const long&) { return 0; }
+ inline long fp_log2(const long&) { return 0; }
+ inline long fp_log10(const long&) { return 0; }
+ inline long fp_mod(const long& x, const long& y) { return x % y; }
+ inline long fp_pow(const long&, const long&) { return 0; }
+ inline long fp_sin(const long&) { return 0; }
+ inline long fp_sinh(const long&) { return 0; }
+ inline long fp_sqrt(const long&) { return 1; }
+ inline long fp_tan(const long&) { return 0; }
+ inline long fp_tanh(const long&) { return 0; }
+ inline long fp_asinh(const long&) { return 0; }
+ inline long fp_acosh(const long&) { return 0; }
+ inline long fp_atanh(const long&) { return 0; }
+ inline long fp_pow_base(const long&, const long&) { return 0; }
+ inline void fp_sinCos(long&, long&, const long&) {}
+ inline void fp_sinhCosh(long&, long&, const long&) {}
+
+ //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_acosh(const MpfrFloat& x) { return MpfrFloat::acosh(x); }
+ inline MpfrFloat fp_asin(const MpfrFloat& x) { return MpfrFloat::asin(x); }
+ inline MpfrFloat fp_asinh(const MpfrFloat& x) { return MpfrFloat::asinh(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_atanh(const MpfrFloat& x) { return MpfrFloat::atanh(x); }
+ 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_exp2(const MpfrFloat& x) { return MpfrFloat::exp2(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_log2(const MpfrFloat& x) { return MpfrFloat::log2(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_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 void fp_sinCos(MpfrFloat& sin, MpfrFloat& cos, const MpfrFloat& a)
+ {
+ MpfrFloat::sincos(a, sin, cos);
+ }
+
+ inline void fp_sinhCosh(MpfrFloat& sinhvalue, MpfrFloat& coshvalue,
+ const MpfrFloat& param)
+ {
+ const MpfrFloat paramCopy = param;
+ sinhvalue = fp_sinh(paramCopy);
+ coshvalue = fp_cosh(paramCopy);
+ }
+#endif // FP_SUPPORT_MPFR_FLOAT_TYPE
+
+
+// -------------------------------------------------------------------------
+// GMP int
+// -------------------------------------------------------------------------
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+ inline GmpInt fp_abs(const GmpInt& x) { return GmpInt::abs(x); }
+ inline GmpInt fp_acos(const GmpInt&) { return 0; }
+ inline GmpInt fp_acosh(const GmpInt&) { return 0; }
+ inline GmpInt fp_asin(const GmpInt&) { return 0; }
+ inline GmpInt fp_asinh(const GmpInt&) { return 0; }
+ inline GmpInt fp_atan(const GmpInt&) { return 0; }
+ inline GmpInt fp_atan2(const GmpInt&, const GmpInt&) { return 0; }
+ inline GmpInt fp_atanh(const GmpInt&) { return 0; }
+ inline GmpInt fp_cbrt(const GmpInt&) { return 0; }
+ inline GmpInt fp_ceil(const GmpInt& x) { return x; }
+ inline GmpInt fp_cos(const GmpInt&) { return 0; }
+ inline GmpInt fp_cosh(const GmpInt&) { return 0; }
+ inline GmpInt fp_exp(const GmpInt&) { return 0; }
+ inline GmpInt fp_exp2(const GmpInt&) { return 0; }
+ inline GmpInt fp_floor(const GmpInt& x) { return x; }
+ inline GmpInt fp_hypot(const GmpInt&, const GmpInt&) { return 0; }
+ inline GmpInt fp_int(const GmpInt& x) { return x; }
+ inline GmpInt fp_log(const GmpInt&) { return 0; }
+ inline GmpInt fp_log2(const GmpInt&) { return 0; }
+ inline GmpInt fp_log10(const GmpInt&) { return 0; }
+ inline GmpInt fp_mod(const GmpInt& x, const GmpInt& y) { return x % y; }
+ inline GmpInt fp_pow(const GmpInt&, const GmpInt&) { return 0; }
+ inline GmpInt fp_sin(const GmpInt&) { return 0; }
+ inline GmpInt fp_sinh(const GmpInt&) { return 0; }
+ inline GmpInt fp_sqrt(const GmpInt&) { return 0; }
+ inline GmpInt fp_tan(const GmpInt&) { return 0; }
+ inline GmpInt fp_tanh(const GmpInt&) { return 0; }
+ inline GmpInt fp_trunc(const GmpInt& x) { return x; }
+ inline GmpInt fp_pow_base(const GmpInt&, const GmpInt&) { return 0; }
+ inline void fp_sinCos(GmpInt&, GmpInt&, const GmpInt&) {}
+ inline void fp_sinhCosh(GmpInt&, GmpInt&, const GmpInt&) {}
+#endif // FP_SUPPORT_GMP_INT_TYPE
+
+
+#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+ template<typename Value_t>
+ inline Value_t fp_cbrt(const Value_t& x) { return std::cbrt(x); }
+#else
+ template<typename Value_t>
+ inline Value_t fp_cbrt(const Value_t& x)
+ {
+ return (x > Value_t() ? fp_exp(fp_log( x) / Value_t(3)) :
+ x < Value_t() ? -fp_exp(fp_log(-x) / Value_t(3)) :
+ Value_t());
+ }
+#endif
+
+// -------------------------------------------------------------------------
+// Synthetic functions and fallbacks for when an optimized
+// implementation or a library function is not available
+// -------------------------------------------------------------------------
+ template<typename Value_t> inline Value_t fp_arg(const Value_t& x);
+ template<typename Value_t> inline Value_t fp_exp2(const Value_t& x);
+ template<typename Value_t> inline Value_t fp_int(const Value_t& x);
+ template<typename Value_t> inline Value_t fp_trunc(const Value_t& x);
+ template<typename Value_t>
+ inline void fp_sinCos(Value_t& , Value_t& , const Value_t& );
+ template<typename Value_t>
+ inline void fp_sinhCosh(Value_t& , Value_t& , const Value_t& );
+
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+ /* NOTE: Complex multiplication of a and b can be done with:
+ tmp = b.real * (a.real + a.imag)
+ result.real = tmp - a.imag * (b.real + b.imag)
+ result.imag = tmp + a.real * (b.imag - b.real)
+ This has fewer multiplications than the standard
+ algorithm. Take note, if you support mpfr complex one day.
+ */
+
+ template<typename T>
+ struct FP_ProbablyHasFastLibcComplex
+ { enum { result = false }; };
+ /* The generic sqrt() etc. implementations in libstdc++
+ * are very plain and non-optimized; however, it contains
+ * callbacks to libc complex math functions where possible,
+ * and I suspect that those may actually be well optimized.
+ * So we use std:: functions when we suspect they may be fast,
+ * and otherwise we use our own optimized implementations.
+ */
+#ifdef __GNUC__
+ template<> struct FP_ProbablyHasFastLibcComplex<float>
+ { enum { result = true }; };
+ template<> struct FP_ProbablyHasFastLibcComplex<double>
+ { enum { result = true }; };
+ template<> struct FP_ProbablyHasFastLibcComplex<long double>
+ { enum { result = true }; };
+#endif
+
+ template<typename T>
+ inline const std::complex<T> fp_make_imag(const std::complex<T>& v)
+ {
+ return std::complex<T> ( T(), v.real() );
+ }
+
+ template<typename T>
+ inline std::complex<T> fp_real(const std::complex<T>& x)
+ {
+ return x.real();
+ }
+ template<typename T>
+ inline std::complex<T> fp_imag(const std::complex<T>& x)
+ {
+ return x.imag();
+ }
+ template<typename T>
+ inline std::complex<T> fp_arg(const std::complex<T>& x)
+ {
+ return std::arg(x);
+ }
+ template<typename T>
+ inline std::complex<T> fp_conj(const std::complex<T>& x)
+ {
+ return std::conj(x);
+ }
+ template<typename T, bool>
+ inline std::complex<T> fp_polar(const T& x, const T& y)
+ {
+ T si, co; fp_sinCos(si, co, y);
+ return std::complex<T> (x*co, x*si);
+ }
+ template<typename T>
+ inline std::complex<T> fp_polar(const std::complex<T>& x, const std::complex<T>& y)
+ {
+ // x * cos(y) + i * x * sin(y) -- arguments are supposed to be REAL numbers
+ return fp_polar<T,true> (x.real(), y.real());
+ //return std::polar(x.real(), y.real());
+ //return x * (fp_cos(y) + (std::complex<T>(0,1) * fp_sin(y));
+ }
+
+ // These provide fallbacks in case there's no library function
+ template<typename T>
+ inline std::complex<T> fp_floor(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_floor(x.real()), fp_floor(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_trunc(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_trunc(x.real()), fp_trunc(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_int(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_int(x.real()), fp_int(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_ceil(const std::complex<T>& x)
+ {
+ return std::complex<T> (fp_ceil(x.real()), fp_ceil(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_abs(const std::complex<T>& x)
+ {
+ return std::abs(x);
+ //T extent = fp_max(fp_abs(x.real()), fp_abs(x.imag()));
+ //if(extent == T()) return x;
+ //return extent * fp_hypot(x.real() / extent, x.imag() / extent);
+ }
+ template<typename T>
+ inline std::complex<T> fp_exp(const std::complex<T>& x)
+ {
+ if(FP_ProbablyHasFastLibcComplex<T>::result)
+ return std::exp(x);
+ return fp_polar<T,true>(fp_exp(x.real()), x.imag());
+ }
+ template<typename T>
+ inline std::complex<T> fp_log(const std::complex<T>& x)
+ {
+ if(FP_ProbablyHasFastLibcComplex<T>::result)
+ return std::log(x);
+ // log(abs(x)) + i*arg(x)
+ // log(Xr^2+Xi^2)*0.5 + i*arg(x)
+ if(x.imag()==T())
+ return std::complex<T>( fp_log(fp_abs(x.real())),
+ fp_arg(x.real()) ); // Note: Uses real-value fp_arg() here!
+ return std::complex<T>(
+ fp_log(std::norm(x)) * T(0.5),
+ fp_arg(x).real() );
+ }
+ template<typename T>
+ inline std::complex<T> fp_sqrt(const std::complex<T>& x)
+ {
+ if(FP_ProbablyHasFastLibcComplex<T>::result)
+ return std::sqrt(x);
+ return fp_polar<T,true> (fp_sqrt(fp_abs(x).real()),
+ T(0.5)*fp_arg(x).real());
+ }
+ template<typename T>
+ inline std::complex<T> fp_acos(const std::complex<T>& x)
+ {
+ // -i * log(x + i * sqrt(1 - x^2))
+ const std::complex<T> i (T(), T(1));
+ return -i * fp_log(x + i * fp_sqrt(T(1) - x*x));
+ // Note: Real version of acos() cannot handle |x| > 1,
+ // because it would cause sqrt(negative value).
+ }
+ template<typename T>
+ inline std::complex<T> fp_asin(const std::complex<T>& x)
+ {
+ // -i * log(i*x + sqrt(1 - x^2))
+ const std::complex<T> i (T(), T(1));
+ return -i * fp_log(i*x + fp_sqrt(T(1) - x*x));
+ // Note: Real version of asin() cannot handle |x| > 1,
+ // because it would cause sqrt(negative value).
+ }
+ template<typename T>
+ inline std::complex<T> fp_atan(const std::complex<T>& x)
+ {
+ // 0.5i * (log(1-i*x) - log(1+i*x))
+ // -0.5i * log( (1+i*x) / (1-i*x) )
+ const std::complex<T> i (T(), T(1));
+ return (T(-0.5)*i) * fp_log( (T(1)+i*x) / (T(1)-i*x) );
+ // Note: x = -1i causes division by zero
+ // x = +1i causes log(0)
+ // Thus, x must not be +-1i
+ }
+ template<typename T>
+ inline std::complex<T> fp_cos(const std::complex<T>& x)
+ {
+ return std::cos(x);
+ // // (exp(i*x) + exp(-i*x)) / (2)
+ // //const std::complex<T> i (T(), T(1));
+ // //return (fp_exp(i*x) + fp_exp(-i*x)) * T(0.5);
+ // // Also: cos(Xr)*cosh(Xi) - i*sin(Xr)*sinh(Xi)
+ // return std::complex<T> (
+ // fp_cos(x.real())*fp_cosh(x.imag()),
+ // -fp_sin(x.real())*fp_sinh(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_sin(const std::complex<T>& x)
+ {
+ return std::sin(x);
+ // // (exp(i*x) - exp(-i*x)) / (2i)
+ // //const std::complex<T> i (T(), T(1));
+ // //return (fp_exp(i*x) - fp_exp(-i*x)) * (T(-0.5)*i);
+ // // Also: sin(Xr)*cosh(Xi) + cos(Xr)*sinh(Xi)
+ // return std::complex<T> (
+ // fp_sin(x.real())*fp_cosh(x.imag()),
+ // fp_cos(x.real())*fp_sinh(x.imag()));
+ }
+ template<typename T>
+ inline void fp_sinCos(
+ std::complex<T>& sinvalue,
+ std::complex<T>& cosvalue,
+ const std::complex<T>& x)
+ {
+ //const std::complex<T> i (T(), T(1)), expix(fp_exp(i*x)), expmix(fp_exp((-i)*x));
+ //cosvalue = (expix + expmix) * T(0.5);
+ //sinvalue = (expix - expmix) * (i*T(-0.5));
+ // The above expands to the following:
+ T srx, crx; fp_sinCos(srx, crx, x.real());
+ T six, cix; fp_sinhCosh(six, cix, x.imag());
+ sinvalue = std::complex<T>(srx*cix, crx*six);
+ cosvalue = std::complex<T>(crx*cix, -srx*six);
+ }
+ template<typename T>
+ inline void fp_sinhCosh(
+ std::complex<T>& sinhvalue,
+ std::complex<T>& coshvalue,
+ const std::complex<T>& x)
+ {
+ T srx, crx; fp_sinhCosh(srx, crx, x.real());
+ T six, cix; fp_sinCos(six, cix, x.imag());
+ sinhvalue = std::complex<T>(srx*cix, crx*six);
+ coshvalue = std::complex<T>(crx*cix, srx*six);
+ }
+ template<typename T>
+ inline std::complex<T> fp_tan(const std::complex<T>& x)
+ {
+ return std::tan(x);
+ //std::complex<T> si, co;
+ //fp_sinCos(si, co, x);
+ //return si/co;
+ // // (i-i*exp(2i*x)) / (exp(2i*x)+1)
+ // const std::complex<T> i (T(), T(1)), exp2ix=fp_exp((2*i)*x);
+ // return (i-i*exp2ix) / (exp2ix+T(1));
+ // // Also: sin(x)/cos(y)
+ // // return fp_sin(x)/fp_cos(x);
+ }
+ template<typename T>
+ inline std::complex<T> fp_cosh(const std::complex<T>& x)
+ {
+ return std::cosh(x);
+ // // (exp(x) + exp(-x)) * 0.5
+ // // Also: cosh(Xr)*cos(Xi) + i*sinh(Xr)*sin(Xi)
+ // return std::complex<T> (
+ // fp_cosh(x.real())*fp_cos(x.imag()),
+ // fp_sinh(x.real())*fp_sin(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_sinh(const std::complex<T>& x)
+ {
+ return std::sinh(x);
+ // // (exp(x) - exp(-x)) * 0.5
+ // // Also: sinh(Xr)*cos(Xi) + i*cosh(Xr)*sin(Xi)
+ // return std::complex<T> (
+ // fp_sinh(x.real())*fp_cos(x.imag()),
+ // fp_cosh(x.real())*fp_sin(x.imag()));
+ }
+ template<typename T>
+ inline std::complex<T> fp_tanh(const std::complex<T>& x)
+ {
+ return std::tanh(x);
+ //std::complex<T> si, co;
+ //fp_sinhCosh(si, co, x);
+ //return si/co;
+ // // (exp(2*x)-1) / (exp(2*x)+1)
+ // // Also: sinh(x)/tanh(x)
+ // const std::complex<T> exp2x=fp_exp(x+x);
+ // return (exp2x-T(1)) / (exp2x+T(1));
+ }
+
+#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+ template<typename T>
+ inline std::complex<T> fp_acosh(const std::complex<T>& x)
+ { return fp_log(x + fp_sqrt(x*x - std::complex<T>(1))); }
+ template<typename T>
+ inline std::complex<T> fp_asinh(const std::complex<T>& x)
+ { return fp_log(x + fp_sqrt(x*x + std::complex<T>(1))); }
+ template<typename T>
+ inline std::complex<T> fp_atanh(const std::complex<T>& x)
+ { return fp_log( (std::complex<T>(1)+x) / (std::complex<T>(1)-x))
+ * std::complex<T>(0.5); }
+#endif
+ template<typename T>
+ inline std::complex<T> fp_pow(const std::complex<T>& x, const std::complex<T>& y)
+ {
+ // return std::pow(x,y);
+
+ // With complex numbers, pow(x,y) can be solved with
+ // the general formula: exp(y*log(x)). It handles
+ // all special cases gracefully.
+ // It expands to the following:
+ // A)
+ // t1 = log(x)
+ // t2 = y * t1
+ // res = exp(t2)
+ // B)
+ // t1.r = log(x.r * x.r + x.i * x.i) * 0.5 \ fp_log()
+ // t1.i = atan2(x.i, x.r) /
+ // t2.r = y.r*t1.r - y.i*t1.i \ multiplication
+ // t2.i = y.r*t1.i + y.i*t1.r /
+ // rho = exp(t2.r) \ fp_exp()
+ // theta = t2.i /
+ // res.r = rho * cos(theta) \ fp_polar(), called from
+ // res.i = rho * sin(theta) / fp_exp(). Uses sincos().
+ // Aside from the common "norm" calculation in atan2()
+ // and in the log parameter, both of which are part of fp_log(),
+ // there does not seem to be any incentive to break this
+ // function down further; it would not help optimizing it.
+ // However, we do handle the following special cases:
+ //
+ // When x is real (positive or negative):
+ // t1.r = log(abs(x.r))
+ // t1.i = x.r<0 ? -pi : 0
+ // When y is real:
+ // t2.r = y.r * t1.r
+ // t2.i = y.r * t1.i
+ const std::complex<T> t =
+ (x.imag() != T())
+ ? fp_log(x)
+ : std::complex<T> (fp_log(fp_abs(x.real())),
+ fp_arg(x.real())); // Note: Uses real-value fp_arg() here!
+ return y.imag() != T()
+ ? fp_exp(y * t)
+ : fp_polar<T,true> (fp_exp(y.real()*t.real()), y.real()*t.imag());
+ }
+ template<typename T>
+ inline std::complex<T> fp_cbrt(const std::complex<T>& x)
+ {
+ // For real numbers, prefer giving a real solution
+ // rather than a complex solution.
+ // For example, cbrt(-3) has the following three solutions:
+ // A) 0.7211247966535 + 1.2490247864016i
+ // B) 0.7211247966535 - 1.2490247864016i
+ // C) -1.442249593307
+ // exp(log(x)/3) gives A, but we prefer to give C.
+ if(x.imag() == T()) return fp_cbrt(x.real());
+ const std::complex<T> t(fp_log(x));
+ return fp_polar<T,true> (fp_exp(t.real() / T(3)), t.imag() / T(3));
+ }
+
+ template<typename T>
+ inline std::complex<T> fp_exp2(const std::complex<T>& x)
+ {
+ // pow(2, x)
+ // polar(2^Xr, Xi*log(2))
+ return fp_polar<T,true> (fp_exp2(x.real()), x.imag()*fp_const_log2<T>());
+ }
+ template<typename T>
+ inline std::complex<T> fp_mod(const std::complex<T>& x, const std::complex<T>& y)
+ {
+ // Modulo function is probably not defined for complex numbers.
+ // But we do our best to calculate it the same way as it is done
+ // with real numbers, so that at least it is in some way "consistent".
+ if(y.imag() == 0) return fp_mod(x.real(), y.real()); // optimization
+ std::complex<T> n = fp_trunc(x / y);
+ return x - n * y;
+ }
+
+ /* libstdc++ already defines a streaming operator for complex values,
+ * but we redefine our own that it is compatible with the input
+ * accepted by fparser. I.e. instead of (5,3) we now get (5+3i),
+ * and instead of (-4,0) we now get -4.
+ */
+ template<typename T>
+ inline std::ostream& operator<<(std::ostream& os, const std::complex<T>& value)
+ {
+ if(value.imag() == T()) return os << value.real();
+ if(value.real() == T()) return os << value.imag() << 'i';
+ if(value.imag() < T())
+ return os << '(' << value.real() << "-" << -value.imag() << "i)";
+ else
+ return os << '(' << value.real() << "+" << value.imag() << "i)";
+ }
+
+ /* Less-than or greater-than operators are not technically defined
+ * for Complex types. However, in fparser and its tool set, these
+ * operators are widely required to be present.
+ * Our implementation here is based on converting the complex number
+ * into a scalar and the doing a scalar comparison on the value.
+ * The means by which the number is changed into a scalar is based
+ * on the following principles:
+ * - Does not introduce unjustified amounts of extra inaccuracy
+ * - Is transparent to purely real values
+ * (this disqualifies something like x.real() + x.imag())
+ * - Does not ignore the imaginary value completely
+ * (this may be relevant especially in testbed)
+ * - Is not so complicated that it would slow down a great deal
+ *
+ * Basically our formula here is the same as std::abs(),
+ * except that it keeps the sign of the original real number,
+ * and it does not do a sqrt() calculation that is not really
+ * needed because we are only interested in the relative magnitudes.
+ *
+ * Equality and nonequality operators must not need to be overloaded.
+ * They are already implemented in standard, and we must
+ * not introduce flawed equality assumptions.
+ */
+ template<typename T>
+ inline T fp_complexScalarize(const std::complex<T>& x)
+ {
+ T res(std::norm(x));
+ if(x.real() < T()) res = -res;
+ return res;
+ }
+ template<typename T>
+ inline T fp_realComplexScalarize(const T& x)
+ {
+ T res(x*x);
+ if(x < T()) res = -res;
+ return res;
+ }
+ // { return x.real() * (T(1.0) + fp_abs(x.imag())); }
+ #define d(op) \
+ template<typename T> \
+ inline bool operator op (const std::complex<T>& x, T y) \
+ { return fp_complexScalarize(x) op fp_realComplexScalarize(y); } \
+ template<typename T> \
+ inline bool operator op (const std::complex<T>& x, const std::complex<T>& y) \
+ { return fp_complexScalarize(x) op \
+ fp_complexScalarize(y); } \
+ template<typename T> \
+ inline bool operator op (T x, const std::complex<T>& y) \
+ { return fp_realComplexScalarize(x) op fp_complexScalarize(y); }
+ d( < ) d( <= ) d( > ) d( >= )
+ #undef d
+#endif
+
+ template<typename Value_t>
+ inline Value_t fp_real(const Value_t& x) { return x; }
+ template<typename Value_t>
+ inline Value_t fp_imag(const Value_t& ) { return Value_t(); }
+ template<typename Value_t>
+ inline Value_t fp_arg(const Value_t& x)
+ { return x < Value_t() ? -fp_const_pi<Value_t>() : Value_t(); }
+ template<typename Value_t>
+ inline Value_t fp_conj(const Value_t& x) { return x; }
+ template<typename Value_t>
+ inline Value_t fp_polar(const Value_t& x, const Value_t& y)
+ { return x * fp_cos(y); } // This is of course a meaningless function.
+
+ template<typename Value_t>
+ inline std::complex<Value_t> fp_atan2(const std::complex<Value_t>& y,
+ const std::complex<Value_t>& x)
+ {
+ if(y == Value_t()) return fp_arg(x);
+ if(x == Value_t()) return fp_const_pi<Value_t>() * Value_t(-0.5);
+ // 2*atan(y / (sqrt(x^2+y^2) + x) )
+ // 2*atan( (sqrt(x^2+y^2) - x) / y)
+ std::complex<Value_t> res( fp_atan(y / (fp_hypot(x,y) + x)) );
+ return res+res;
+ }
+
+// -------------------------------------------------------------------------
+// Comparison
+// -------------------------------------------------------------------------
+ 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) <= Epsilon<Value_t>::value); }
+
+ 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) > Epsilon<Value_t>::value); }
+
+ 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 - Epsilon<Value_t>::value); }
+
+ 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 + Epsilon<Value_t>::value); }
+
+
+ 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 != Value_t()
+ : 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 > Value_t()
+ : 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)); }
+
+ template<typename Value_t>
+ inline const Value_t fp_make_imag(const Value_t& ) // Imaginary 1. In real mode, always zero.
+ {
+ return Value_t();
+ }
+
+ /////////////
+ /* 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 IsVarOpcode(unsigned op);
+ bool IsCommutativeOrParamSwappableBinaryOpcode(unsigned op);
+ unsigned GetParamSwappedBinaryOpcode(unsigned op);
+
+ template<bool ComplexType>
+ bool HasInvalidRangesOpcode(unsigned op);
+
+ template<typename Value_t>
+ inline Value_t DegreesToRadians(const Value_t& degrees)
+ {
+ return degrees * fp_const_deg_to_rad<Value_t>();
+ }
+
+ template<typename Value_t>
+ inline Value_t RadiansToDegrees(const Value_t& radians)
+ {
+ return radians * fp_const_rad_to_deg<Value_t>();
+ }
+
+ template<typename Value_t>
+ inline long makeLongInteger(const Value_t& value)
+ {
+ return (long) fp_int(value);
+ }
+
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+ template<typename T>
+ inline long makeLongInteger(const std::complex<T>& value)
+ {
+ return (long) fp_int( std::abs(value) );
+ }
+#endif
+
+ // Is value an integer that fits in "long" datatype?
+ template<typename Value_t>
+ inline bool isLongInteger(const Value_t& value)
+ {
+ return value == Value_t( makeLongInteger(value) );
+ }
+
+ template<typename Value_t>
+ inline bool isOddInteger(const Value_t& value)
+ {
+ const Value_t halfValue = (value + Value_t(1)) * Value_t(0.5);
+ return fp_equal(halfValue, fp_floor(halfValue));
+ }
+
+ template<typename Value_t>
+ inline bool isEvenInteger(const 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(const Value_t& value)
+ {
+ return fp_equal(value, fp_floor(value));
+ }
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+ template<>
+ inline bool isEvenInteger(const long& value)
+ {
+ return value%2 == 0;
+ }
+
+ template<>
+ inline bool isInteger(const long&) { return true; }
+
+ template<>
+ inline bool isLongInteger(const long&) { return true; }
+
+ template<>
+ inline long makeLongInteger(const long& value)
+ {
+ return value;
+ }
+#endif
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+ template<>
+ inline bool isInteger(const MpfrFloat& value) { return value.isInteger(); }
+
+ template<>
+ inline bool isEvenInteger(const MpfrFloat& value)
+ {
+ return isInteger(value) && value%2 == 0;
+ }
+
+ template<>
+ inline long makeLongInteger(const MpfrFloat& value)
+ {
+ return (long) value.toInt();
+ }
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+ template<>
+ inline bool isEvenInteger(const GmpInt& value)
+ {
+ return value%2 == 0;
+ }
+
+ template<>
+ inline bool isInteger(const GmpInt&) { return true; }
+
+ template<>
+ inline long makeLongInteger(const GmpInt& value)
+ {
+ return (long) value.toInt();
+ }
+#endif
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+ template<>
+ inline bool isOddInteger(const long& value)
+ {
+ return value%2 != 0;
+ }
+#endif
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+ template<>
+ inline bool isOddInteger(const MpfrFloat& value)
+ {
+ return value.isInteger() && value%2 != 0;
+ }
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+ template<>
+ inline bool isOddInteger(const GmpInt& value)
+ {
+ return value%2 != 0;
+ }
+#endif
+
+
+// -------------------------------------------------------------------------
+// fp_pow
+// -------------------------------------------------------------------------
+ // Commented versions in fparser.cc
+ template<typename Value_t>
+ inline Value_t fp_pow_with_exp_log(const Value_t& x, const Value_t& y)
+ {
+ return fp_exp(fp_log(x) * y);
+ }
+
+ template<typename Value_t>
+ inline Value_t fp_powi(Value_t x, unsigned long y)
+ {
+ Value_t result(1);
+ while(y != 0)
+ {
+ if(y & 1) { result *= x; y -= 1; }
+ else { x *= x; y /= 2; }
+ }
+ return result;
+ }
+
+ template<typename Value_t>
+ Value_t fp_pow(const Value_t& x, const Value_t& y)
+ {
+ if(x == Value_t(1)) return Value_t(1);
+ if(isLongInteger(y))
+ {
+ if(y >= Value_t(0))
+ return fp_powi(x, makeLongInteger(y));
+ else
+ return Value_t(1) / fp_powi(x, -makeLongInteger(y));
+ }
+ if(y >= Value_t(0))
+ {
+ if(x > Value_t(0)) return fp_pow_with_exp_log(x, y);
+ if(x == Value_t(0)) return Value_t(0);
+ if(!isInteger(y*Value_t(16)))
+ return -fp_pow_with_exp_log(-x, y);
+ }
+ else
+ {
+ if(x > Value_t(0)) return fp_pow_with_exp_log(Value_t(1) / x, -y);
+ if(x < Value_t(0))
+ {
+ if(!isInteger(y*Value_t(-16)))
+ return -fp_pow_with_exp_log(Value_t(-1) / x, -y);
+ }
+ }
+ return fp_pow_base(x, y);
+ }
+
+ template<typename Value_t>
+ inline Value_t fp_exp2(const Value_t& x)
+ {
+ return fp_pow(Value_t(2), x);
+ }
+} // namespace FUNCTIONPARSERTYPES
+
+#endif // ONCE_FPARSER_H_
+#endif // ONCE_FPARSER_AUX_H_
diff --git a/fparser/extrasrc/fptypes.hh b/fparser/extrasrc/fptypes.hh
new file mode 100644
index 0000000..159903b
--- /dev/null
+++ b/fparser/extrasrc/fptypes.hh
@@ -0,0 +1,288 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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,
+ cArg, /* get the phase angle of a complex value */
+ cAsin, cAsinh,
+ cAtan, cAtan2, cAtanh,
+ cCbrt, cCeil,
+ cConj, /* get the complex conjugate of a complex value */
+ cCos, cCosh, cCot, cCsc,
+ cExp, cExp2, cFloor, cHypot,
+ cIf,
+ cImag, /* get imaginary part of a complex value */
+ cInt, cLog, cLog10, cLog2, cMax, cMin,
+ cPolar, /* create a complex number from polar coordinates */
+ cPow,
+ cReal, /* get real part of a complex value */
+ 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) */
+ cSinhCosh, /* hyperbolic equivalent of sincos */
+ 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,
+ ComplexOnly = 0x10
+ };
+
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+ const char name[8];
+#else
+ struct name { } name;
+#endif
+ unsigned params : 8;
+ unsigned flags : 8;
+
+ inline bool okForInt() const { return (flags & OkForInt) != 0; }
+ inline bool complexOnly() const { return (flags & ComplexOnly) != 0; }
+ };
+
+#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::OkForInt },
+ /*cAcos */ { FP_FNAME("acos"), 1, FuncDefinition::AngleOut },
+ /*cAcosh*/ { FP_FNAME("acosh"), 1, FuncDefinition::AngleOut },
+ /*cArg */ { FP_FNAME("arg"), 1, FuncDefinition::AngleOut | FuncDefinition::ComplexOnly },
+ /*cAsin */ { FP_FNAME("asin"), 1, FuncDefinition::AngleOut },
+ /*cAsinh*/ { FP_FNAME("asinh"), 1, FuncDefinition::AngleOut },
+ /*cAtan */ { FP_FNAME("atan"), 1, FuncDefinition::AngleOut },
+ /*cAtan2*/ { FP_FNAME("atan2"), 2, FuncDefinition::AngleOut },
+ /*cAtanh*/ { FP_FNAME("atanh"), 1, 0 },
+ /*cCbrt */ { FP_FNAME("cbrt"), 1, 0 },
+ /*cCeil */ { FP_FNAME("ceil"), 1, 0 },
+ /*cConj */ { FP_FNAME("conj"), 1, FuncDefinition::ComplexOnly },
+ /*cCos */ { FP_FNAME("cos"), 1, FuncDefinition::AngleIn },
+ /*cCosh */ { FP_FNAME("cosh"), 1, FuncDefinition::AngleIn },
+ /*cCot */ { FP_FNAME("cot"), 1, FuncDefinition::AngleIn },
+ /*cCsc */ { FP_FNAME("csc"), 1, FuncDefinition::AngleIn },
+ /*cExp */ { FP_FNAME("exp"), 1, 0 },
+ /*cExp2 */ { FP_FNAME("exp2"), 1, 0 },
+ /*cFloor*/ { FP_FNAME("floor"), 1, 0 },
+ /*cHypot*/ { FP_FNAME("hypot"), 2, 0 },
+ /*cIf */ { FP_FNAME("if"), 0, FuncDefinition::OkForInt },
+ /*cImag */ { FP_FNAME("imag"), 1, FuncDefinition::ComplexOnly },
+ /*cInt */ { FP_FNAME("int"), 1, 0 },
+ /*cLog */ { FP_FNAME("log"), 1, 0 },
+ /*cLog10*/ { FP_FNAME("log10"), 1, 0 },
+ /*cLog2 */ { FP_FNAME("log2"), 1, 0 },
+ /*cMax */ { FP_FNAME("max"), 2, FuncDefinition::OkForInt },
+ /*cMin */ { FP_FNAME("min"), 2, FuncDefinition::OkForInt },
+ /*cPolar */{ FP_FNAME("polar"), 2, FuncDefinition::ComplexOnly | FuncDefinition::AngleIn },
+ /*cPow */ { FP_FNAME("pow"), 2, 0 },
+ /*cReal */ { FP_FNAME("real"), 1, FuncDefinition::ComplexOnly },
+ /*cSec */ { FP_FNAME("sec"), 1, FuncDefinition::AngleIn },
+ /*cSin */ { FP_FNAME("sin"), 1, FuncDefinition::AngleIn },
+ /*cSinh */ { FP_FNAME("sinh"), 1, FuncDefinition::AngleIn },
+ /*cSqrt */ { FP_FNAME("sqrt"), 1, 0 },
+ /*cTan */ { FP_FNAME("tan"), 1, FuncDefinition::AngleIn },
+ /*cTanh */ { FP_FNAME("tanh"), 1, FuncDefinition::AngleIn },
+ /*cTrunc*/ { FP_FNAME("trunc"), 1, 0 }
+ };
+#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;
+
+ char mDelimiterChar;
+ ParseErrorType mParseErrorType;
+ int mEvalErrorType;
+ bool mUseDegreeConversion;
+ bool mHasByteCodeFlags;
+ const char* mErrorLocation;
+
+ 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 FuncWrapperPtrData
+ {
+ /* Only one of the pointers will point to a function, the other
+ will be null. (The raw function pointer could be implemented
+ as a FunctionWrapper specialization, but it's done like this
+ for efficiency.) */
+ FunctionPtr mRawFuncPtr;
+ FunctionWrapper* mFuncWrapperPtr;
+ unsigned mParams;
+
+ FuncWrapperPtrData();
+ ~FuncWrapperPtrData();
+ FuncWrapperPtrData(const FuncWrapperPtrData&);
+ FuncWrapperPtrData& operator=(const FuncWrapperPtrData&);
+ };
+
+ struct FuncParserPtrData
+ {
+ FunctionParserBase<Value_t>* mParserPtr;
+ unsigned mParams;
+ };
+
+ std::vector<FuncWrapperPtrData> mFuncPtrs;
+ std::vector<FuncParserPtrData> 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/fparser.cc b/fparser/fparser.cc
new file mode 100644
index 0000000..11fa09e
--- /dev/null
+++ b/fparser/fparser.cc
@@ -0,0 +1,3800 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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>
+
+#include "extrasrc/fptypes.hh"
+#include "extrasrc/fpaux.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::IsVarOpcode(unsigned op)
+{
+ // See comment in declaration of FP_ParamGuardMask
+ return int(op) >= VarBegin;
+}
+
+bool FUNCTIONPARSERTYPES::IsCommutativeOrParamSwappableBinaryOpcode(unsigned op)
+{
+ switch(op)
+ {
+ case cAdd:
+ case cMul:
+ case cEqual: case cNEqual:
+ case cAnd: case cAbsAnd:
+ case cOr: case cAbsOr:
+ case cMin: case cMax: case cHypot:
+ return true;
+ case cDiv: case cSub: case cRDiv: case cRSub:
+ return true;
+ case cLess: case cGreater:
+ case cLessOrEq: case cGreaterOrEq: return true;
+ }
+ return false;
+}
+
+unsigned FUNCTIONPARSERTYPES::GetParamSwappedBinaryOpcode(unsigned op)
+{
+ switch(op)
+ {
+ case cAdd:
+ case cMul:
+ case cEqual: case cNEqual:
+ case cAnd: case cAbsAnd:
+ case cOr: case cAbsOr:
+ case cMin: case cMax: case cHypot:
+ return op;
+ case cDiv: return cRDiv;
+ case cSub: return cRSub;
+ case cRDiv: return cDiv;
+ case cRSub: return cSub;
+ case cLess: return cGreater;
+ case cGreater: return cLess;
+ case cLessOrEq: return cGreaterOrEq;
+ case cGreaterOrEq: return cLessOrEq;
+ }
+ return op; // Error
+}
+
+template<bool ComplexType>
+bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op)
+{
+ // Returns true, if the given opcode has a range of
+ // input values that gives an error.
+ if(ComplexType)
+ {
+ // COMPLEX:
+ switch(op)
+ {
+ case cAtan: // allowed range: x != +-1i
+ case cAtanh: // allowed range: x != +-1
+ //case cCot: // allowed range: tan(x) != 0
+ //case cCsc: // allowed range: sin(x) != 0
+ 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: // allowed when: x != 0 or y != 0
+ //case cSec: // allowed range: cos(x) != 0
+ //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2)
+ //case cTanh: // allowed range: log(x) != -1 --> x != +-(pi/2)i
+ case cRSqrt: // allowed range: x != 0
+ //case cDiv: // allowed range: y != 0
+ //case cRDiv: // allowed range: x != 0
+ //case cInv: // allowed range: x != 0
+ return true;
+ }
+ }
+ else
+ {
+ // REAL:
+ 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: // allowed range: tan(x) != 0
+ //case cCsc: // allowed range: sin(x) != 0
+ 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: // allowed when: x > 0 or (x = 0 and y != 0) or (x<0)
+ // Technically, when (x<0 and y is not integer),
+ // it is not allowed, but we allow it anyway
+ // in order to make nontrivial roots work.
+ //case cSec: // allowed range: cos(x) != 0
+ case cSqrt: // allowed range: x >= 0
+ case cRSqrt: // allowed range: x > 0
+ //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2)
+ //case cDiv: // allowed range: y != 0
+ //case cRDiv: // allowed range: x != 0
+ //case cInv: // allowed range: x != 0
+ return true;
+ }
+ }
+ return false;
+}
+
+template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode<false>(unsigned op);
+template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode<true>(unsigned op);
+
+
+#if(0) // Implementation moved to fpaux.hh due to linker problems
+//=========================================================================
+// 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);
+}
+#endif
+
+
+//=========================================================================
+// Elementary (atom) parsing functions
+//=========================================================================
+namespace
+{
+ const unsigned FP_ParamGuardMask = 1U << (sizeof(unsigned) * 8u - 1u);
+ // ^ This mask is used to prevent cFetch/other opcode's parameters
+ // from being confused into opcodes or variable indices within the
+ // bytecode optimizer. Because the way it is tested in bytecoderules.dat
+ // for speed reasons, it must also be the sign-bit of the "int" datatype.
+ // Perhaps an "assert(IsVarOpcode(X | FP_ParamGuardMask) == false)"
+ // might be justified to put somewhere in the code, just in case?
+
+
+ /* 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 readIdentifierCommon(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 "extrasrc/fp_identifier_parser.inc"
+ return 0;
+ }
+
+ template<typename Value_t>
+ inline unsigned readIdentifier(const char* input)
+ {
+ const unsigned value = readIdentifierCommon(input);
+ if( (value & 0x80000000U) != 0) // Function?
+ {
+ // Verify that the function actually exists for this datatype
+ if(IsIntType<Value_t>::result
+ && !Functions[(value >> 16) & 0x7FFF].okForInt())
+ {
+ // If it does not exist, return it as an identifier instead
+ return value & 0xFFFFu;
+ }
+ if(!IsComplexType<Value_t>::result
+ && Functions[(value >> 16) & 0x7FFF].complexOnly())
+ {
+ // If it does not exist, return it as an identifier instead
+ return value & 0xFFFFu;
+ }
+ }
+ return value;
+ }
+
+ // 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 std::strtod(str, endptr);
+ }
+
+#if defined(FP_USE_STRTOLD) || defined(FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS)
+ template<>
+ inline long double fp_parseLiteral<long double>(const char* str,
+ char** endptr)
+ {
+ using namespace std; // Just in case strtold() is not inside std::
+ return strtold(str, endptr);
+ }
+#endif
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+ template<>
+ inline long fp_parseLiteral<long>(const char* str, char** endptr)
+ {
+ return std::strtol(str, endptr, 10);
+ }
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+ template<typename T>
+ inline std::complex<T> fp_parseComplexLiteral(const char* str,
+ char** endptr)
+ {
+ T result = fp_parseLiteral<T> (str,endptr);
+ const char* end = *endptr;
+ if( (*end == 'i' || *end == 'I')
+ && !std::isalnum(end[1]) )
+ {
+ ++*endptr;
+ return std::complex<T> (T(), result);
+ }
+ return std::complex<T> (result, T());
+ }
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+ template<>
+ inline std::complex<double> fp_parseLiteral<std::complex<double> >
+ (const char* str, char** endptr)
+ {
+ return fp_parseComplexLiteral<double> (str,endptr);
+ }
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+ template<>
+ inline std::complex<float> fp_parseLiteral<std::complex<float> >
+ (const char* str, char** endptr)
+ {
+ return fp_parseComplexLiteral<float> (str,endptr);
+ }
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+ template<>
+ inline std::complex<long double> fp_parseLiteral<std::complex<long double> >
+ (const char* str, char** endptr)
+ {
+ return fp_parseComplexLiteral<long double> (str,endptr);
+ }
+#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, const_cast<char**> (&str2), 10);
+ if(str2 != str+1 && p_exponent == (long)(int)p_exponent)
+ {
+ exponent += (int)p_exponent;
+ str = str2;
+ }
+ }
+
+ if(endptr) *endptr = const_cast<char*> (str);
+
+ Value_t result = std::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 std::strtol(str, endptr, 16);
+ }
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+ template<>
+ std::complex<double>
+ parseHexLiteral<std::complex<double> >(const char* str, char** endptr)
+ {
+ return parseHexLiteral<double> (str, endptr);
+ }
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+ template<>
+ std::complex<float>
+ parseHexLiteral<std::complex<float> >(const char* str, char** endptr)
+ {
+ return parseHexLiteral<float> (str, endptr);
+ }
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+ template<>
+ std::complex<long double>
+ parseHexLiteral<std::complex<long double> >(const char* str, char** endptr)
+ {
+ return parseHexLiteral<long double> (str, endptr);
+ }
+#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),
+ mDelimiterChar(0),
+ mParseErrorType(NO_FUNCTION_PARSED_YET),
+ mEvalErrorType(0),
+ mUseDegreeConversion(false),
+ mErrorLocation(0),
+ mVariablesAmount(0),
+ mStackSize(0)
+{}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::Data(const Data& rhs):
+ mReferenceCounter(0),
+ mDelimiterChar(rhs.mDelimiterChar),
+ mParseErrorType(rhs.mParseErrorType),
+ mEvalErrorType(rhs.mEvalErrorType),
+ mUseDegreeConversion(rhs.mUseDegreeConversion),
+ mErrorLocation(rhs.mErrorLocation),
+ 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 std::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;
+ }
+}
+
+template<typename Value_t>
+void FunctionParserBase<Value_t>::incFuncWrapperRefCount
+(FunctionWrapper* wrapper)
+{
+ ++wrapper->mReferenceCount;
+}
+
+template<typename Value_t>
+unsigned FunctionParserBase<Value_t>::decFuncWrapperRefCount
+(FunctionWrapper* wrapper)
+{
+ return --wrapper->mReferenceCount;
+}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::FuncWrapperPtrData():
+ mRawFuncPtr(0), mFuncWrapperPtr(0), mParams(0)
+{}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::~FuncWrapperPtrData()
+{
+ if(mFuncWrapperPtr &&
+ FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0)
+ delete mFuncWrapperPtr;
+}
+
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::FuncWrapperPtrData
+(const FuncWrapperPtrData& rhs):
+ mRawFuncPtr(rhs.mRawFuncPtr),
+ mFuncWrapperPtr(rhs.mFuncWrapperPtr),
+ mParams(rhs.mParams)
+{
+ if(mFuncWrapperPtr)
+ FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr);
+}
+
+template<typename Value_t>
+typename FunctionParserBase<Value_t>::Data::FuncWrapperPtrData&
+FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::operator=
+(const FuncWrapperPtrData& rhs)
+{
+ if(&rhs != this)
+ {
+ if(mFuncWrapperPtr &&
+ FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0)
+ delete mFuncWrapperPtr;
+ mRawFuncPtr = rhs.mRawFuncPtr;
+ mFuncWrapperPtr = rhs.mFuncWrapperPtr;
+ mParams = rhs.mParams;
+ if(mFuncWrapperPtr)
+ FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr);
+ }
+ return *this;
+}
+
+
+//=========================================================================
+// FunctionParser constructors, destructor and assignment
+//=========================================================================
+template<typename Value_t>
+FunctionParserBase<Value_t>::FunctionParserBase():
+ mData(new Data),
+ mStackPtr(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):
+ mData(cpy.mData),
+ mStackPtr(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;
+
+ mData = cpy.mData;
+ ++(mData->mReferenceCounter);
+ }
+ return *this;
+}
+
+template<typename Value_t>
+typename FunctionParserBase<Value_t>::Data*
+FunctionParserBase<Value_t>::getParserData()
+{
+ return mData;
+}
+
+template<typename Value_t>
+void FunctionParserBase<Value_t>::setDelimiterChar(char c)
+{
+ mData->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();
+}
+
+
+//=========================================================================
+// Epsilon
+//=========================================================================
+template<typename Value_t>
+Value_t FunctionParserBase<Value_t>::epsilon()
+{
+ return Epsilon<Value_t>::value;
+}
+
+template<typename Value_t>
+void FunctionParserBase<Value_t>::setEpsilon(Value_t value)
+{
+ Epsilon<Value_t>::value = value;
+}
+
+
+//=========================================================================
+// 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::FuncWrapperPtrData());
+ mData->mFuncPtrs.back().mRawFuncPtr = ptr;
+ mData->mFuncPtrs.back().mParams = paramsAmount;
+ }
+ return success;
+}
+
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::addFunctionWrapperPtr
+(const std::string& name, FunctionWrapper* wrapper, unsigned paramsAmount)
+{
+ if(!AddFunction(name, FunctionPtr(0), paramsAmount)) return false;
+ mData->mFuncPtrs.back().mFuncWrapperPtr = wrapper;
+ return true;
+}
+
+template<typename Value_t>
+typename FunctionParserBase<Value_t>::FunctionWrapper*
+FunctionParserBase<Value_t>::GetFunctionWrapper(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() &&
+ nameIter->second.type == NameData<Value_t>::FUNC_PTR)
+ {
+ return mData->mFuncPtrs[nameIter->second.index].mFuncWrapperPtr;
+ }
+ return 0;
+}
+
+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::FuncParserPtrData());
+ 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)
+ {
+ enum { 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)
+ {
+ enum { 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[mData->mParseErrorType];
+}
+
+template<typename Value_t>
+typename FunctionParserBase<Value_t>::ParseErrorType
+FunctionParserBase<Value_t>::GetParseErrorType() const
+{
+ return mData->mParseErrorType;
+}
+
+template<typename Value_t>
+int FunctionParserBase<Value_t>::EvalError() const
+{
+ return mData->mEvalErrorType;
+}
+
+
+// ---------------------------------------------------------------------------
+// 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))
+ {
+ mData->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))
+ {
+ mData->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)
+{
+ mData->mUseDegreeConversion = useDegrees;
+ mData->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;
+
+ mData->mHasByteCodeFlags = false;
+
+ const char* ptr = Compile(function);
+ mData->mInlineVarNames.clear();
+
+ if(mData->mHasByteCodeFlags)
+ {
+ for(unsigned i = unsigned(mData->mByteCode.size()); i-- > 0; )
+ mData->mByteCode[i] &= ~FP_ParamGuardMask;
+ }
+
+ if(mData->mParseErrorType != FP_NO_ERROR)
+ return int(mData->mErrorLocation - function);
+
+ assert(ptr); // Should never be null at this point. It's a bug otherwise.
+ if(*ptr)
+ {
+ if(mData->mDelimiterChar == 0 || *ptr != mData->mDelimiterChar)
+ mData->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)
+{
+ mData->mParseErrorType = t;
+ mData->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
+ }
+
+ /* Needed by fp_opcode_add.inc if tracing is enabled */
+ 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 "?";
+ }
+}
+
+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
+#define FP_COMPLEX_VERSION 0
+#include "extrasrc/fp_opcode_add.inc"
+#undef FP_COMPLEX_VERSION
+#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
+#define FP_COMPLEX_VERSION 0
+#include "extrasrc/fp_opcode_add.inc"
+#undef FP_COMPLEX_VERSION
+#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
+#define FP_COMPLEX_VERSION 0
+#include "extrasrc/fp_opcode_add.inc"
+#undef FP_COMPLEX_VERSION
+#undef FP_FLOAT_VERSION
+}
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+template<>
+inline void FunctionParserBase<std::complex<double> >::AddFunctionOpcode(unsigned opcode)
+{
+ typedef std::complex<double> Value_t;
+#define FP_FLOAT_VERSION 1
+#define FP_COMPLEX_VERSION 1
+#include "extrasrc/fp_opcode_add.inc"
+#undef FP_COMPLEX_VERSION
+#undef FP_FLOAT_VERSION
+}
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+template<>
+inline void FunctionParserBase<std::complex<float> >::AddFunctionOpcode(unsigned opcode)
+{
+ typedef std::complex<float> Value_t;
+#define FP_FLOAT_VERSION 1
+#define FP_COMPLEX_VERSION 1
+#include "extrasrc/fp_opcode_add.inc"
+#undef FP_COMPLEX_VERSION
+#undef FP_FLOAT_VERSION
+}
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+template<>
+inline void FunctionParserBase<std::complex<long double> >::AddFunctionOpcode(unsigned opcode)
+{
+ typedef std::complex<long double> Value_t;
+#define FP_FLOAT_VERSION 1
+#define FP_COMPLEX_VERSION 1
+#include "extrasrc/fp_opcode_add.inc"
+#undef FP_COMPLEX_VERSION
+#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;
+
+ function = CompileFunctionParams(function, requiredParams);
+ if(!function) return 0;
+
+ if(mData->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 GmpInt, 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)
+{
+ std::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)
+{
+ std::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 ? FP_ParamGuardMask : 0u));
+ if(PutFlag) mData->mHasByteCodeFlags = true;
+}
+
+template<typename Value_t> template<bool PutFlag>
+inline void FunctionParserBase<Value_t>::PutOpcodeParamAt
+ (unsigned value, unsigned offset)
+{
+ mData->mByteCode[offset] = value | (PutFlag ? FP_ParamGuardMask : 0u);
+ if(PutFlag) mData->mHasByteCodeFlags = true;
+}
+
+//===========================================================================
+// Function evaluation
+//===========================================================================
+template<typename Value_t>
+Value_t FunctionParserBase<Value_t>::Eval(const Value_t* Vars)
+{
+ if(mData->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:
+ if(IsComplexType<Value_t>::result == false
+ && (Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1)))
+ { mData->mEvalErrorType=4; return Value_t(0); }
+ Stack[SP] = fp_acos(Stack[SP]); break;
+
+ case cAcosh:
+ if(IsComplexType<Value_t>::result == false
+ && Stack[SP] < Value_t(1))
+ { mData->mEvalErrorType=4; return Value_t(0); }
+ Stack[SP] = fp_acosh(Stack[SP]); break;
+
+ case cAsin:
+ if(IsComplexType<Value_t>::result == false
+ && (Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1)))
+ { mData->mEvalErrorType=4; return Value_t(0); }
+ 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:
+ if(IsComplexType<Value_t>::result
+ ? (Stack[SP] == Value_t(-1) || Stack[SP] == Value_t(1))
+ : (Stack[SP] <= Value_t(-1) || Stack[SP] >= Value_t(1)))
+ { mData->mEvalErrorType=4; return Value_t(0); }
+ 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]);
+ if(t == Value_t(0))
+ { mData->mEvalErrorType=1; return Value_t(0); }
+ Stack[SP] = Value_t(1)/t; break;
+ }
+
+ case cCsc:
+ {
+ const Value_t s = fp_sin(Stack[SP]);
+ if(s == Value_t(0))
+ { mData->mEvalErrorType=1; return Value_t(0); }
+ Stack[SP] = Value_t(1)/s; break;
+ }
+
+
+ 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:
+ if(IsComplexType<Value_t>::result
+ ? Stack[SP] == Value_t(0)
+ : !(Stack[SP] > Value_t(0)))
+ { mData->mEvalErrorType=3; return Value_t(0); }
+ Stack[SP] = fp_log(Stack[SP]); break;
+
+ case cLog10:
+ if(IsComplexType<Value_t>::result
+ ? Stack[SP] == Value_t(0)
+ : !(Stack[SP] > Value_t(0)))
+ { mData->mEvalErrorType=3; return Value_t(0); }
+ Stack[SP] = fp_log10(Stack[SP]);
+ break;
+
+ case cLog2:
+ if(IsComplexType<Value_t>::result
+ ? Stack[SP] == Value_t(0)
+ : !(Stack[SP] > Value_t(0)))
+ { mData->mEvalErrorType=3; return Value_t(0); }
+ 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:
+ // x:Negative ^ y:NonInteger is failure,
+ // except when the reciprocal of y forms an integer
+ /*if(IsComplexType<Value_t>::result == false
+ && 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))
+ { mData->mEvalErrorType=3; return Value_t(0); }
+ 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]);
+ if(c == Value_t(0))
+ { mData->mEvalErrorType=1; return Value_t(0); }
+ 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:
+ if(IsComplexType<Value_t>::result == false &&
+ Stack[SP] < Value_t(0))
+ { mData->mEvalErrorType=2; return Value_t(0); }
+ 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:
+ if(Stack[SP] == Value_t(0))
+ { mData->mEvalErrorType=1; return Value_t(0); }
+ Stack[SP-1] /= Stack[SP]; --SP; break;
+
+ case cMod:
+ if(Stack[SP] == Value_t(0))
+ { mData->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:
+ {
+ const unsigned index = byteCode[++IP];
+ const unsigned params = mData->mFuncPtrs[index].mParams;
+ const Value_t retVal =
+ mData->mFuncPtrs[index].mRawFuncPtr ?
+ mData->mFuncPtrs[index].mRawFuncPtr(&Stack[SP-params+1]) :
+ mData->mFuncPtrs[index].mFuncWrapperPtr->callFunction
+ (&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)
+ {
+ mData->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:
+ if(IsComplexType<Value_t>::result
+ ? Stack[SP-1] == Value_t(0)
+ : !(Stack[SP-1] > Value_t(0)))
+ { mData->mEvalErrorType=3; return Value_t(0); }
+ 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 cSinhCosh:
+ fp_sinhCosh(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:
+ if(Stack[SP] == Value_t(0))
+ { mData->mEvalErrorType=1; return Value_t(0); }
+ Stack[SP] = Value_t(1)/Stack[SP];
+ break;
+
+ case cSqr:
+ Stack[SP] = Stack[SP]*Stack[SP];
+ break;
+
+ case cRDiv:
+ if(Stack[SP-1] == Value_t(0))
+ { mData->mEvalErrorType=1; return Value_t(0); }
+ Stack[SP-1] = Stack[SP] / Stack[SP-1]; --SP; break;
+
+ case cRSub: Stack[SP-1] = Stack[SP] - Stack[SP-1]; --SP; break;
+
+ case cRSqrt:
+ if(Stack[SP] == Value_t(0))
+ { mData->mEvalErrorType=1; return Value_t(0); }
+ Stack[SP] = Value_t(1) / fp_sqrt(Stack[SP]); break;
+
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+ case cReal: Stack[SP] = fp_real(Stack[SP]); break;
+ case cImag: Stack[SP] = fp_imag(Stack[SP]); break;
+ case cArg: Stack[SP] = fp_arg(Stack[SP]); break;
+ case cConj: Stack[SP] = fp_conj(Stack[SP]); break;
+ case cPolar:
+ Stack[SP-1] = fp_polar(Stack[SP-1], Stack[SP]);
+ --SP; break;
+#endif
+
+
+// Variables:
+ default:
+ Stack[++SP] = Vars[byteCode[IP]-VarBegin];
+ }
+ }
+
+ mData->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(std::size_t currentLength = dest.str().length();
+ currentLength < destLength;
+ ++currentLength)
+ {
+ dest << ' ';
+ }
+ }
+
+ 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,
+ std::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
+ || std::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,
+ std::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,
+ std::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 == Value_t(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(IsVarOpcode(opcode))
+ {
+ if(showExpression)
+ {
+ stack.push_back(std::make_pair(0,
+ (findName(mData->mNamePtrs, opcode,
+ NameData<Value_t>::VARIABLE))));
+ }
+ output << "push Var" << opcode-VarBegin;
+ produces = 0;
+ }
+ else
+ {
+ switch(OPCODE(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;
+
+ 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:
+ {
+ std::size_t a = ByteCode[++IP];
+ std::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 cSinhCosh:
+ {
+ if(showExpression)
+ {
+ std::pair<int, std::string> sinh = stack.back();
+ std::pair<int, std::string> cosh(
+ 0, "cosh(" + sinh.second + ")");
+ sinh.first = 0;
+ sinh.second = "sinh(" + sinh.second + ")";
+ stack.back() = sinh;
+ stack.push_back(cosh);
+ }
+ output << "sinhcosh";
+ 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;
+ }
+ }
+ }
+ }
+ 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
+
+
+#define FUNCTIONPARSER_INSTANTIATE_CLASS(type) \
+ template class FunctionParserBase< type >;
+
+#ifndef FP_DISABLE_DOUBLE_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(double)
+#endif
+
+#ifdef FP_SUPPORT_FLOAT_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(float)
+#endif
+
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(long double)
+#endif
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(long)
+#endif
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(MpfrFloat)
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(GmpInt)
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<double>)
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<float>)
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<long double>)
+#endif
diff --git a/fparser/fparser.hh b/fparser/fparser.hh
new file mode 100644
index 0000000..282e9b5
--- /dev/null
+++ b/fparser/fparser.hh
@@ -0,0 +1,223 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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);
+
+ static Value_t epsilon();
+ static void setEpsilon(Value_t);
+
+ const char* ErrorMsg() const;
+ ParseErrorType GetParseErrorType() const;
+
+ Value_t Eval(const Value_t* Vars);
+ int EvalError() const;
+
+ 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&);
+
+ class FunctionWrapper;
+
+ template<typename DerivedWrapper>
+ bool AddFunctionWrapper(const std::string& name, const DerivedWrapper&,
+ unsigned paramsAmount);
+
+ FunctionWrapper* GetFunctionWrapper(const std::string& name);
+
+ 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
+
+
+
+//========================================================================
+ protected:
+//========================================================================
+ // A derived class can implement its own evaluation logic by using
+ // the parser data (found in fptypes.hh).
+ struct Data;
+ Data* getParserData();
+
+
+//========================================================================
+ private:
+//========================================================================
+
+ friend class FPoptimizer_CodeTree::CodeTree<Value_t>;
+
+// Private data:
+// ------------
+ Data* mData;
+ unsigned mStackPtr;
+
+
+// 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*);
+
+ bool addFunctionWrapperPtr(const std::string&, FunctionWrapper*, unsigned);
+ static void incFuncWrapperRefCount(FunctionWrapper*);
+ static unsigned decFuncWrapperRefCount(FunctionWrapper*);
+
+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> {};
+
+#include <complex>
+class FunctionParser_cd: public FunctionParserBase<std::complex<double> > {};
+class FunctionParser_cf: public FunctionParserBase<std::complex<float> > {};
+class FunctionParser_cld: public FunctionParserBase<std::complex<long double> > {};
+
+
+
+template<typename Value_t>
+class FunctionParserBase<Value_t>::FunctionWrapper
+{
+ unsigned mReferenceCount;
+ friend class FunctionParserBase<Value_t>;
+
+ public:
+ FunctionWrapper(): mReferenceCount(1) {}
+ FunctionWrapper(const FunctionWrapper&): mReferenceCount(1) {}
+ virtual ~FunctionWrapper() {}
+ FunctionWrapper& operator=(const FunctionWrapper&) { return *this; }
+
+ virtual Value_t callFunction(const Value_t*) = 0;
+};
+
+template<typename Value_t>
+template<typename DerivedWrapper>
+bool FunctionParserBase<Value_t>::AddFunctionWrapper
+(const std::string& name, const DerivedWrapper& wrapper, unsigned paramsAmount)
+{
+ return addFunctionWrapperPtr
+ (name, new DerivedWrapper(wrapper), paramsAmount);
+}
+#endif
diff --git a/fparser/fparser.pro b/fparser/fparser.pro
new file mode 100644
index 0000000..3b2e7b7
--- /dev/null
+++ b/fparser/fparser.pro
@@ -0,0 +1,35 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Tue Mar 10 07:42:54 2009
+######################################################################
+
+CONFIG -= qt
+TEMPLATE = lib
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+VERSION = 4.5.1
+
+# Input
+HEADERS += fparser.hh fpconfig.hh fptypes.hh
+SOURCES += fparser.cc fpoptimizer.cc
+
+#
+# INSTALL
+#
+isEmpty(PREFIX) {
+ PREFIX = /usr/local
+}
+install.target = install
+install.commands = mkdir -p \"$$PREFIX/lib$$LIB_SUFFIX\"
+install.commands += && mkdir -p \"$$PREFIX/include\"
+unix:!macx {
+ install.commands += && cp -at \"$$PREFIX/include/\" fparser.hh
+ install.commands += && cp -at \"$$PREFIX/lib$$LIB_SUFFIX/\" libfparser.so*
+}
+win32:install.commands += && cp -at \"$$PREFIX/lib$$LIB_SUFFIX/\" release/fparser4.dll
+macx {
+ install.commands += && cp fparser.hh \"$$PREFIX/include/\"
+ install.commands += && cp libfparser*.dylib \"$$PREFIX/lib$$LIB_SUFFIX/\"
+}
+
+QMAKE_EXTRA_TARGETS += install
diff --git a/fparser/fparser_gmpint.hh b/fparser/fparser_gmpint.hh
new file mode 100644
index 0000000..6254a4e
--- /dev/null
+++ b/fparser/fparser_gmpint.hh
@@ -0,0 +1,15 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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
index 0000000..1eb772f
--- /dev/null
+++ b/fparser/fparser_mpfr.hh
@@ -0,0 +1,15 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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/fpconfig.hh b/fparser/fpconfig.hh
new file mode 100644
index 0000000..1a8a55f
--- /dev/null
+++ b/fparser/fpconfig.hh
@@ -0,0 +1,88 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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
+//#define FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+//#define FP_SUPPORT_COMPLEX_FLOAT_TYPE
+//#define FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+
+/* If you are using FunctionParser_ld or FunctionParser_cld and your compiler
+ supports the strtold() function, you should uncomment the following line.
+ */
+//#define FP_USE_STRTOLD
+
+
+/* Uncomment this line or 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
+
+/* Uncomment this line or define it in your compiler settings to make the
+ parser use C++11 math functions. (Note that these may not be supported
+ by all compilers.)
+*/
+//#define FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS
+
+/*
+ Whether to use shortcut evaluation for the & and | operators:
+*/
+#ifndef FP_DISABLE_SHORTCUT_LOGICAL_EVALUATION
+#define FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#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
+
+#if defined(FP_SUPPORT_COMPLEX_DOUBLE_TYPE) || defined(FP_SUPPORT_COMPLEX_FLOAT_TYPE) || defined(FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE)
+#define FP_SUPPORT_COMPLEX_NUMBERS
+#endif
+
+
+/*
+ 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
diff --git a/fparser/fpoptimizer.cc b/fparser/fpoptimizer.cc
new file mode 100644
index 0000000..4eab746
--- /dev/null
+++ b/fparser/fpoptimizer.cc
@@ -0,0 +1,11745 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5.1 *|
+|*-------------------------------------------------------------------------*|
+|* 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 "extrasrc/fptypes.hh"
+#include "extrasrc/fpaux.hh"
+#define l14 {Value_t
+#define l04 ),info,
+#define iZ3 {data->
+#define iY3 ==cNot||
+#define iX3 "Found "
+#define iW3 info.lQ[b
+#define iV3 ;o<<"\n";
+#define iU3 )yR 2,cPow
+#define iT3 ;}static yU1
+#define iS3 (tree)!=
+#define iR3 ),Value(
+#define iQ3 stackpos
+#define iP3 minValue0
+#define iO3 "dup(%u) "
+#define iN3 =true;iO1
+#define iM3 eR{assert
+#define iL3 "%d, cost "
+#define iK3 "PUSH " iL2
+#define iJ3 "immed "<<
+#define iI3 mFuncParsers
+#define iH3 param.data
+#define iG3 stderr
+#define iF3 sep2=" "
+#define iE3 FPHASH_CONST
+#define iD3 cache_needed[
+#define iC3 fprintf
+#define iB3 "Applying "
+#define iA3 FUNCTIONPARSER_INSTANTIATE_OPTIMIZE
+#define i93 FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE
+#define i83 HANDLE_UNARY_CONST_FUNC
+#define i73 {if(n11
+#define i63 second;
+#define i53 within,
+#define i43 AddFrom(
+#define i33 tH3==
+#define i23 c_count
+#define i13 MaxOp
+#define i03 else nM
+#define tZ3 =tZ cL3
+#define tY3 .nJ 0));
+#define tX3 .nJ 1));
+#define tW3 lD m.
+#define tV3 ;a<tree.xB
+#define tU3 iZ);}if
+#define tT3 cS ifp2
+#define tS3 sim.xB1
+#define tR3 );tO tL1
+#define tQ3 ].swap(
+#define tP3 codes[b
+#define tO3 whydump
+#define tN3 for lS1
+#define tM3 for(;a<
+#define tL3 nparams
+#define tK3 281856,
+#define tJ3 cTan i7
+#define tI3 l2 2,2,
+#define tH3 ;if(op
+#define tG3 l4 0,1,
+#define tF3 0x12 nH
+#define tE3 FixIncompleteHashes()
+#define tD3 cSinh,
+#define tC3 ,cTan nS
+#define tB3 ,iX 1,
+#define tA3 nS 0,
+#define t93 cAbs nS
+#define t83 ;case
+#define t73 i1 t83
+#define t63 Params[
+#define t53 Params(
+#define t43 &&p nL3
+#define t33 fp_pow(
+#define t23 false;}
+#define t13 lD1 y4.
+#define t03 cAbsIf)
+#define eZ3 l91++b)
+#define eY3 lX1 nC==
+#define eX3 ;exponent
+#define eW3 =false;
+#define eV3 tN cS1);
+#define eU3 .empty()
+#define eT3 nS3))n92
+#define eS3 (opcode==
+#define eR3 <data eJ3;++
+#define eQ3 l14 nS3(
+#define eP3 ByteCodeSynth xF
+#define eO3 std xM3<
+#define eN3 middle2
+#define eM3 std::string
+#define eL3 SetOpcode(
+#define eK3 ;for iZ1
+#define eJ3 .size()
+#define eI3 ].second
+#define eH3 ].first
+#define eG3 return p
+#define eF3 TreeCountItem
+#define eE3 }return
+#define eD3 Ne_Mask
+#define eC3 Gt_Mask
+#define eB3 Lt_Mask
+#define eA3 const eK
+#define e93 .n7 synth.
+#define e83 range nE3
+#define e73 eK3 a=
+#define e63 ,eQ,c92
+#define e53 eO|lT1)
+#define e43 public:
+#define e33 Rehash(
+#define e23 switch(
+#define e13 pclone
+#define e03 cOr,l6
+#define cZ3 newpow
+#define cY3 change
+#define cX3 (Value_t
+#define cW3 (count
+#define cV3 133,2,
+#define cU3 ,tree
+#define cT3 byteCode
+#define cS3 child)
+#define cR3 (p1 x41)
+#define cQ3 cLog2by
+#define cP3 long iD1
+#define cO3 factor_t
+#define cN3 (p0 yI&&
+#define cM3 value1
+#define cL3 a));if(!
+#define cK3 fp_mod(
+#define cJ3 else{if(
+#define cI3 )min.set(
+#define cH3 xF());nD
+#define cG3 max.known
+#define cF3 known&&
+#define cE3 tX p2;p2
+#define cD3 {tree.x4
+#define cC3 cAbsNot
+#define cB3 ,x53 l8
+#define cA3 e23 lY1
+#define c93 xW 0)nC
+#define c83 IsLogicalValue(xW
+#define c73 }switch
+#define c63 stackptr
+#define c53 cLog);xG
+#define c43 l8 0));
+#define c33 opcodes
+#define c23 did_muli
+#define c13 &Value){
+#define c03 yD const
+#define yZ3 (param.
+#define yY3 ){e23
+#define yX3 :if(&*lE1){
+#define yW3 :{n31 r=
+#define yV3 xY3 e23
+#define yU3 param=*(
+#define yT3 cAbsIf,
+#define yS3 cNotNot,
+#define yR3 l4 16,1,
+#define yQ3 yO3 info
+#define yP3 lE1=r.specs;if(r.found){
+#define yO3 *x8)[a].
+#define yN3 cLess,cH
+#define yM3 default_function_handling
+#define yL3 l4 20,1,
+#define yK3 l4 4,1,
+#define yJ3 450998,
+#define yI3 cExp2 nS
+#define yH3 lJ 2},0,
+#define yG3 )lS 3*3*2*2
+#define yF3 default:
+#define yE3 range<nV
+#define yD3 range xF
+#define yC3 Ge0Lt1
+#define yB3 Gt0Le1
+#define yA3 cAdd lV2
+#define y93 if(op1==
+#define y83 iterator
+#define y73 begin();
+#define y63 TreeSet
+#define y53 parent
+#define y43 insert(i
+#define y33 newrel
+#define y23 y03 xX3 xO2
+#define y13 y03 iF2;if(
+#define y03 ))return
+#define xZ3 ;if(half
+#define xY3 break;}
+#define xX3 IsNever
+#define xW3 e62 eO1
+#define xV3 synth.xH
+#define xU3 b_needed
+#define xT3 cachepos
+#define xS3 ,lE1,info
+#define xR3 half=
+#define xQ3 131,4,1,
+#define xP3 131,8,1,
+#define xO3 ,iM,1,lC1+1);
+#define xN3 4,1,2,1,
+#define xM3 ::vector
+#define xL3 1 y5 n41
+#define xK3 FindPos(
+#define xJ3 src_pos
+#define xI3 xM1 xQ+
+#define xH3 reserve(
+#define xG3 treeptr
+#define xF3 .resize(
+#define xE3 tO1 void
+#define xD3 ImmedTag
+#define xC3 a,const
+#define xB3 RefCount
+#define xA3 Birth();
+#define x93 typename
+#define x83 unsigned
+#define x73 template
+#define x63 7168,
+#define x53 leaf1
+#define x43 cost_t
+#define x33 fpdata
+#define x23 middle
+#define x13 sqrt_cost
+#define x03 const int
+#define nZ3 mul_count
+#define nY3 );nZ l5::
+#define nX3 e62 2)));
+#define nW3 maxValue1
+#define nV3 minValue1
+#define nU3 maxValue0
+#define nT3 ValueType
+#define nS3 result
+#define nR3 nS3;}case
+#define nQ3 nS3.tL
+#define nP3 ::res,b8<
+#define nO3 eG3 yM
+#define nN3 .what nS1
+#define nM3 e62 1),e62 1));
+#define nL3 .max.val
+#define nK3 nS3 yM2
+#define nJ3 nS3 e61
+#define nI3 nS3 yI
+#define nH3 nS3 nL3
+#define nG3 nS3 tG1
+#define nF3 nS3 yM
+#define nE3 xF nS3
+#define nD3 tO n3 0),
+#define nC3 i8);nD lC
+#define nB3 abs_mul
+#define nA3 xM3<x83>&e71
+#define n93 l8 a));
+#define n83 pos_set
+#define n73 goto e1
+#define n63 p1.lT2 p1
+#define n53 [funcno].
+#define n43 eN1[++IP]
+#define n33 sim.x2 1,
+#define n23 {sim.Eat(
+#define n13 eN1[IP]==
+#define n03 subtree
+#define lZ3 invtree
+#define lY3 MakeHash(
+#define lX3 parampair
+#define lW3 rulenumit
+#define lV3 cAnd l3
+#define lU3 ,cMul l3
+#define lT3 cAnd,l6
+#define lS3 x9 lT 2,
+#define lR3 },{{1,
+#define lQ3 cEqual,
+#define lP3 lQ3 lA
+#define lO3 t01},{{3,
+#define lN3 MakeEqual
+#define lM3 nC1,l5::
+#define lL3 nC1,{l5::
+#define lK3 newbase
+#define lJ3 fp_equal(
+#define lI3 branch1op
+#define lH3 branch2op
+#define lG3 if(lJ3
+#define lF3 l8 a)xI
+#define lE3 overlap
+#define lD3 truth_b
+#define lC3 truth_a
+#define lB3 found_dup
+#define lA3 nQ r;r iH
+#define l93 void set(
+#define l83 {tP1 lE
+#define l73 rangeutil
+#define l63 Plan_Has(
+#define l53 StackMax)
+#define l43 i1 true;}
+#define l33 namespace
+#define l23 (cond yX
+#define l13 inverted
+#define l03 xX3:
+#define iZ2 iftree
+#define iY2 depcodes
+#define iX2 explicit
+#define iW2 cCosh nS
+#define iV2 t01 nH
+#define iU2 VarBegin
+#define iT2 t63 a]
+#define iS2 iR2 size()
+#define iR2 Params.
+#define iQ2 ].data);
+#define iP2 i8)));nZ
+#define iO2 yQ1.SubTrees
+#define iN2 yQ1.Others
+#define iM2 );synth
+#define iL2 ;DumpTree(
+#define iK2 ;Value_t
+#define iJ2 begin(),
+#define iI2 cond_add
+#define iH2 cond_mul
+#define iG2 cond_and
+#define iF2 IsAlways
+#define iE2 func lQ1
+#define iD2 bool eM1
+#define iC2 Forget()
+#define iB2 .second);
+#define iA2 Optimize()
+#define i92 costree
+#define i82 sintree
+#define i72 leaf_count
+#define i62 &&cond eD)
+#define i52 .tT1 n]
+#define i42 =GetParam(
+#define i32 sub_params
+#define i22 nC==cLog2&&
+#define i12 nC==cPow&&
+#define i02 printf(
+#define tZ2 cbrt_count
+#define tY2 sqrt_count
+#define tX2 cPow i7
+#define tW2 ,cPow,
+#define tV2 ,cGreater
+#define tU2 exponent);
+#define tT2 Finite
+#define tS2 min.n3 0),
+#define tR2 p1 cS ifp1
+#define tQ2 yR 2,cAdd)
+#define tP2 pcall_tree
+#define tO2 after_powi
+#define tN2 GetHash().
+#define tM2 yP t23
+#define tL2 params)
+#define tK2 grammar
+#define tJ2 cEqual t11
+#define tI2 cLog nS
+#define tH2 cNeg,lT 1,
+#define tG2 ),0},{
+#define tF2 std::move(
+#define tE2 iH cond nC
+#define tD2 tree iH
+#define tC2 ){eL3
+#define tB2 tree))cJ
+#define tA2 );t0=!t0;}
+#define t92 tmp c91 tree
+#define t82 nQ tmp;tmp iH
+#define t72 tree nC
+#define t62 MakeNEqual
+#define t52 )?0:1))l7
+#define t42 isInteger(
+#define t32 Comparison
+#define t22 needs_flip
+#define t12 (half&63)-1;
+#define t02 value]
+#define eZ2 lT1 opcode
+#define eY2 )lS 3*3*3*2
+#define eX2 cS tree);
+#define eW2 mul_item
+#define eV2 innersub
+#define eU2 cbrt_cost
+#define eT2 best_cost
+#define eS2 condition
+#define eR2 nominator
+#define eQ2 per_item
+#define eP2 item_type
+#define eO2 first2
+#define eN2 l4 18,1,
+#define eM2 cIf,iX 3,
+#define eL2 lJ 1},0,
+#define eK2 tJ 1},0,
+#define eJ2 Decision
+#define eI2 not_tree
+#define eH2 (mulgroup
+#define eG2 (lR));nD lC
+#define eF2 Become(xW
+#define eE2 group_by
+#define eD2 exponent=
+#define eC2 ->second
+#define eB2 targetpos
+#define eA2 ParamSpec
+#define e92 rhs.hash2;}
+#define e82 rhs.hash1
+#define e72 struct
+#define e62 Value_t(
+#define e52 .n_int_sqrt
+#define e42 const std::eP
+#define e32 const char*
+#define e22 nT 409641,
+#define e12 ,xF1);lC
+#define e02 );xY3
+#define cZ2 if(t72==
+#define cY2 eO3 bool>
+#define cX2 ,(long double)
+#define cW2 ContainsOtherCandidates
+#define cV2 std::cout
+#define cU2 source_tree
+#define cT2 GetParam eS
+#define cS2 <tP,x43>
+#define cR2 p1_evenness
+#define cQ2 isNegative(
+#define cP2 neg_set
+#define cO2 }else{x8=new
+#define cN2 );}void
+#define cM2 cNop,cNop}}
+#define cL2 cTanh,cNop,
+#define cK2 NewHash
+#define cJ2 >e72 cB<
+#define cI2 matches
+#define cH2 {cV2<<
+#define cG2 iS1 void*)&
+#define cF2 cGreater,cH
+#define cE2 cSin i7
+#define cD2 cCos nS
+#define cC2 ,t21 0x1 nH
+#define cB2 +=1 i1 n91;
+#define cA2 negated
+#define c92 synth);
+#define c82 Specializer
+#define c72 ifdata.ofs
+#define c62 (IfData&ifdata
+#define c52 .push_back(
+#define c42 ;}data;data.
+#define c32 );sim.x2 2,
+#define c22 nP)l14 tmp=
+#define c12 (*x8)[0].info
+#define c02 CodeTree
+#define yZ2 c02 xF
+#define yY2 coshtree
+#define yX2 sinhtree
+#define yW2 best_score
+#define yV2 mulvalue
+#define yU2 pow_item
+#define yT2 subgroup
+#define yS2 PowiResult
+#define yR2 .match_tree
+#define yQ2 )l43
+#define yP2 0));yD3
+#define yO2 maxValue
+#define yN2 minValue
+#define yM2 yI eW3 if(
+#define yL2 fp_min(yL,
+#define yK2 div_tree
+#define yJ2 pow_tree
+#define yI2 preserve
+#define yH2 ,cCos i7
+#define yG2 (rule cU3,info
+#define yF2 e62 0.5)
+#define yE2 PullResult()
+#define yD2 dup_or_fetch
+#define yC2 e33 false
+#define yB2 test_order
+#define yA2 lX3,
+#define y92 .param_count
+#define y82 shift(index)
+#define y72 rulenumber
+#define y62 cTanh nS
+#define y52 cSinh nS
+#define y42 cInv,lT 1,
+#define y32 constraints=
+#define y22 factor_immed
+#define y12 changes
+#define y02 n81 cS y4 l8
+#define xZ2 cS leaf2 l8
+#define xY2 cS x53 l8
+#define xX2 cS cond l8
+#define xW2 exp_diff
+#define xV2 ExponentInfo
+#define xU2 lower_bound(
+#define xT2 factor
+#define xS2 is_logical
+#define xR2 newrel_and
+#define xQ2 tH[c eE
+#define xP2 ;iM.Remember(
+#define xO2 i1 Unknown;}
+#define xN2 res_stackpos
+#define xM2 half_pos
+#define xL2 >>1)):(
+#define xK2 CodeTreeData
+#define xJ2 multiply(
+#define xI2 tO known)
+#define xH2 var_trees
+#define xG2 erase(cs_it);
+#define xF2 parent_opcode
+#define xE2 log2_exponent
+#define xD2 yB swap(tmp);
+#define xC2 Value(Value::
+#define xB2 dup_fetch_pos
+#define xA2 a;if(eK1){x8=
+#define x92 {cZ start_at;
+#define x82 xX3 cQ lC
+#define x72 cSin nS
+#define x62 Value_EvenInt
+#define x52 )){data xC
+#define x42 MakeFalse,{l5
+#define x32 if(list.first
+#define x22 AddCollection
+#define x12 ConditionType
+#define x02 DUP_ONE(apos)
+#define nZ2 SpecialOpcode
+#define nY2 =i eC2.
+#define nX2 IsDefined()
+#define nW2 fp_max(yL);
+#define nV2 (tree,cV2
+#define nU2 e62-1)
+#define nT2 assimilated
+#define nS2 denominator
+#define nR2 fraction
+#define nQ2 l2 18,2,
+#define nP2 .GetDepth()
+#define nO2 iH t72)
+#define nN2 xI leaf2 l8
+#define nM2 DUP_BOTH();
+#define nL2 x73 lL
+#define nK2 -1-offset].
+#define nJ2 tree.GetHash()
+#define nI2 TreeCounts
+#define nH2 ,e62 1))){
+#define nG2 bool t0 eW3
+#define nF2 found_log2
+#define nE2 div_params
+#define nD2 immed_sum
+#define nC2 :sim.Eat(1,
+#define nB2 OPCODE(opcode)
+#define nA2 ;sim.Push(
+#define n92 break;nS3*=
+#define n82 FactorStack xF
+#define n72 iF2 cQ lC
+#define n62 cLessOrEq,
+#define n52 282870 nT
+#define n42 cNotNot nS
+#define n32 cNot nS
+#define n22 replacing_slot
+#define n12 RefParams
+#define n02 if_always[
+#define lZ2 WhatDoWhenCase
+#define lY2 exponent_immed
+#define lX2 new_base_immed
+#define lW2 base_immed
+#define lV2 ||op1==
+#define lU2 remaining
+#define lT2 Rehash t8
+#define lS2 data[a eI3
+#define lR2 lT2 r);}
+#define lQ2 if(newrel_or==
+#define lP2 .UseGetNeeded(
+#define lO2 e7 2,131,
+#define lN2 Immed eJ3);
+#define lM2 OptimizedUsing
+#define lL2 Var_or_Funcno
+#define lK2 lL2;
+#define lJ2 GetParams(
+#define lI2 crc32_t
+#define lH2 signed_chain
+#define lG2 MinusInf
+#define lF2 synth.Find(
+#define lE2 );cV2<<
+#define lD2 return true;
+#define lC2 n_immeds
+#define lB2 stack eJ3
+#define lA2 FindClone(xM
+#define l92 GetOpcode())
+#define l82 needs_rehash
+#define l72 AnyWhere_Rec
+#define l62 minimum_need
+#define l52 ~x83(0)
+#define l42 41,42,43,44,
+#define l32 p1_logical_b
+#define l22 p0_logical_b
+#define l12 p1_logical_a
+#define l02 p0_logical_a
+#define iZ1 (size_t
+#define iY1 )e73
+#define iX1 TopLevel)
+#define iW1 .e33)
+#define iV1 {pow.CopyOnWrite
+#define iU1 nB OPCODE
+#define iT1 const yZ2
+#define iS1 (const
+#define iR1 iS1 yZ2&
+#define iQ1 ,PowiCache&iM,
+#define iP1 else if(
+#define iO1 iP1!nS3
+#define iN1 synth.DoDup(
+#define iM1 cache_needed
+#define iL1 e7 2,1,e7 2,
+#define iK1 [c72+
+#define iJ1 treelist
+#define iI1 IsDescendantOf(
+#define iH1 has_bad_balance
+#define iG1 )tN mulgroup)
+#define iF1 .SetParamsMove(
+#define iE1 cO3 xT2
+#define iD1 double)exponent
+#define iC1 {if(GetOpcode()
+#define iB1 cV2<<std::y11
+#define iA1 cV2<<"POP "
+#define i91 DelParam(
+#define i81 set(fp_ceil);tK
+#define i71 fp_abs(max.val))
+#define i61 fp_abs(min.val)
+#define i51 cNEqual
+#define i41 },0,0x0},{{
+#define i31 tJ 2 i41
+#define i21 Oneness_NotOne|
+#define i11 Value_IsInteger
+#define i01 Constness_Const
+#define tZ1 DumpHashesFrom(
+#define tY1 reltype
+#define tX1 const Value_t&i)
+#define tW1 const c02&
+#define tV1 const Value_t&v
+#define tU1 SequenceOpcodes
+#define tT1 sep_list[
+#define tS1 ;else_tree
+#define tR1 goto fail;}
+#define tQ1 l1 0x4 nH
+#define tP1 x73<
+#define tO1 n12);
+#define tN1 ){case iF2:
+#define tM1 grammar_rules[*r]
+#define tL1 x73 set_if<
+#define tK1 x73 lX
+#define tJ1 TreeCountType xF
+#define tI1 GetParamCount(nX
+#define tH1 >(e62 1),
+#define tG1 nL3)
+#define tF1 )lX3.second
+#define tE1 e62 0.0)){nU
+#define tD1 .IsImmed()
+#define tC1 a)tD1)
+#define tB1 nB2);
+#define tA1 stack[lB2-
+#define t91 stack c52
+#define t81 )eX3 iW1;
+#define t71 synth.PushImmed(
+#define t61 MaxChildDepth
+#define t51 repl_param_list,
+#define t41 const Rule&rule,
+#define t31 std::pair<It,It>
+#define t21 cPow,lA
+#define t11 ,l0 2,
+#define t01 ,l1 0x12
+#define eZ1 Sign_Negative
+#define eY1 Value_Logical
+#define eX1 yZ2&b
+#define eW1 new_factor_immed
+#define eV1 occurance_pos
+#define eU1 exponent_hash
+#define eT1 exponent_list
+#define eS1 CollectionSet xF
+#define eR1 CollectMulGroup(
+#define eQ1 source_set
+#define eP1 exponent,y63
+#define eO1 *const func)(
+#define eN1 ByteCode
+#define eM1 operator
+#define eL1 FindAndDup(tree);
+#define eK1 &*start_at
+#define eJ1 <<nJ2.
+#define eI1 xW 1)tD1&&
+#define eH1 retry_anyparams_3
+#define eG1 retry_anyparams_2
+#define eF1 e6(),eO3
+#define eE1 needlist_cached_t
+#define eD1 yH3 0x4 lR3
+#define eC1 eL2 0x4 lR3
+#define eB1 ),lM2(
+#define eA1 CodeTreeImmed xF(
+#define e91 GetParamCount()==
+#define e81 .back().thenbranch
+#define e71 eN1,size_t&IP,size_t limit,size_t y2
+#define e61 .cG3
+#define e51 (lR,xW i8));nD
+#define e41 ;flipped=!flipped;}
+#define e31 ,l1 0x0},{{3,
+#define e21 }xY3 case
+#define e11 for iZ1 b=0;b<
+#define e01 by_float_exponent
+#define cZ1 lJ3 exponent
+#define cY1 new_exp
+#define cX1 end()&&i->first==
+#define cW1 return BecomeZero;
+#define cV1 =comp.AddItem(atree
+#define cU1 return BecomeOne;
+#define cT1 if(lQ eJ3<=n1)
+#define cS1 addgroup
+#define cR1 found_log2by
+#define cQ1 nC==cC3)
+#define cP1 ParsePowiMuli(
+#define cO1 lL2)
+#define cN1 eL 529654 nT
+#define cM1 branch1_backup
+#define cL1 branch2_backup
+#define cK1 exponent_map
+#define cJ1 plain_set
+#define cI1 rangehalf
+#define cH1 LightWeight(
+#define cG1 xV3 1
+#define cF1 divgroup
+#define cE1 ,iM e63
+#define cD1 if(value
+#define cC1 tK1 c0
+#define cB1 tK1 static
+#define cA1 mulgroup.
+#define c91 .AddParamMove(
+#define c81 yB AddParamMove(
+#define c71 ;n81 cY op1 yB DelParams
+#define c61 should_regenerate=true;
+#define c51 should_regenerate,
+#define c41 Collection
+#define c31 RelationshipResult
+#define c21 Subdivide_Combine(
+#define c11 long value
+#define c01 )const yP
+#define yZ1 rhs c01 hash1
+#define yY1 for iZ1 a xY
+#define yX1 best_sep_factor
+#define yW1 SynthesizeParam
+#define yV1 needlist_cached
+#define yU1 inline x83
+#define yT1 opcode,bool pad
+#define yS1 changed=true;
+#define yR1 );xM iF1
+#define yQ1 NeedList
+#define yP1 tK1 bool
+#define yO1 ;tK1
+#define yN1 i91 a);}
+#define yM1 MakesInteger(
+#define yL1 const Value_t&value
+#define yK1 best_sep_cost
+#define yJ1 MultiplicationRange
+#define yI1 .min.set(fp_floor);
+#define yH1 pihalf_limits
+#define yG1 yR 2,cMul);lC
+#define yF1 n_stacked
+#define yE1 cK2.hash1
+#define yD1 AnyParams_Rec
+#define yC1 ;synth.StackTopIs(
+#define yB1 synth.AddOperation(
+#define yA1 continue;
+#define y91 Become(value l8 0))
+#define y81 }inline
+#define y71 PositionalParams,0}
+#define y61 always_sincostan
+#define y51 Recheck_RefCount_Div
+#define y41 Recheck_RefCount_Mul
+#define y31 MultiplyAndMakeLong(
+#define y21 covers_plus1
+#define y11 endl;DumpHashes(
+#define y01 if(synth.FindAndDup(
+#define xZ1 grammar_func
+#define xY1 tree tD1 cQ
+#define xX1 cOr l3 16,1,
+#define xW1 252421 nT 24830,
+#define xV1 l2 0,2,165888 nT
+#define xU1 Modulo_Radians},
+#define xT1 yB SetParam(
+#define xS1 PositionType
+#define xR1 CollectionResult
+#define xQ1 const_offset
+#define xP1 inline TriTruthValue
+#define xO1 stacktop_desired
+#define xN1 iU3);lC
+#define xM1 SetStackTop(
+#define xL1 tK1 void
+#define xK1 FPoptimizer_ByteCode
+#define xJ1 1)?(poly^(
+#define xI1 eP3&synth)
+#define xH1 e62 0)
+#define xG1 xH1)
+#define xF1 cond_type
+#define xE1 fphash_value_t
+#define xD1 Recheck_RefCount_RDiv
+#define xC1 cMul);tmp tY3 tmp.
+#define xB1 SwapLastTwoInStack();
+#define xA1 SetParams(lJ2)
+#define x91 fPExponentIsTooLarge(
+#define x81 CollectMulGroup_Item(
+#define x71 pair<Value_t,y63>
+#define x61 (x53 l8 1)nN2
+#define x51 for iZ1 a=0;a<yC++a)
+#define x41 .GetImmed()
+#define x31 {int mStackPtr=0;
+#define x21 nL xM1 xQ-1);
+#define x11 covers_full_cycle
+#define x01 AssembleSequence(
+#define nZ1 inverse_nominator
+#define nY1 252180 nT 281854,
+#define nX1 <<std::dec<<")";}
+#define nW1 {DataP slot_holder(y1[
+#define nV1 },{l5::MakeNotP1,l5::
+#define nU1 },{l5::MakeNotP0,l5::
+#define nT1 },{l5::MakeNotNotP1,l5::
+#define nS1 !=xJ)if(TestCase(
+#define nR1 AddFunctionOpcode
+#define nQ1 public e6,public eO3
+#define nP1 yZ2&tree,
+#define nO1 std::pair<T1,T2>&
+#define nN1 tP1 x93
+#define nM1 has_good_balance_found
+#define nL1 n_occurrences
+#define nK1 found_log2_on_exponent
+#define nJ1 covers_minus1
+#define nI1 needs_resynth
+#define nH1 immed_product
+#define nG1 l33 FPoptimizer_Optimize
+#define nF1 (ParamSpec_Extract xF(
+#define nE1 yV3 bitmask&
+#define nD1 Sign_Positive
+#define nC1 ::MakeTrue
+#define nB1 SetParamMove(
+#define nA1 CodeTreeImmed(e62
+#define n91 Suboptimal
+#define n81 changed_if
+#define n71 n_as_tanh_param
+#define n61 opposite=
+#define n51 xE1(
+#define n41 eN1 eJ3
+#define n31 MatchResultType
+#define n21 yP yZ2(
+#define n11 needs_sincos
+#define n01 resulting_exponent
+#define lZ1 Unknown:yF3;}
+#define lY1 GetLogicalValue(xW
+#define lX1 GetParam(a)
+#define lW1 cMul l3 0,1,
+#define lV1 IsImmed())l14
+#define lU1 void FunctionParserBase
+#define lT1 (x83
+#define lS1 lT1 a=0;a<xT;++a)
+#define lR1 o<<"("<<std::hex<<data.
+#define lQ1 (val);else*this=model;}
+#define lP1 IfBalanceGood(
+#define lO1 n_as_tan_param
+#define lN1 changed_exponent
+#define lM1 inverse_denominator
+#define lL1 ;cK2.hash2+=
+#define lK1 retry_positionalparams_2
+#define lJ1 x83 index
+#define lI1 situation_flags&
+#define lH1 518 nT 400412,
+#define lG1 data.subfunc_opcode
+#define lF1 },{l5::MakeNotNotP0,l5::
+#define lE1 (yO3 start_at
+#define lD1 CopyOnWrite();
+#define lC1 recursioncount
+#define lB1 PlanNtimesCache(
+#define lA1 FPoptimizer_Grammar
+#define l91 GetParamCount();
+#define l81 GetPositivityInfo iS3
+#define l71 ParamSpec_SubFunctionData
+#define l61 t43<e62
+#define l51 (tree.GetParamCount()
+#define l41 iZ1 a=yC a-->0;)
+#define l31 PositionalParams_Rec
+#define l21 DumpTreeWithIndent(*this);
+#define l11 e23 type){case cond_or:
+#define l01 tP1 x83 Compare>
+#define iZ tree.i91 a
+#define iY .l91 a-->0;)if(
+#define iX lA 0x4},{{
+#define iW lJ 2 i41 1,
+#define iV edited_powgroup
+#define iU has_unknown_max
+#define iT has_unknown_min
+#define iS static const yD3
+#define iR if(keep_powi
+#define iQ synthed_tree
+#define iP 7168 nT 401798,
+#define iO SelectedParams,0 i41
+#define iN collections
+#define iM cache
+#define iL ,cIf,l0 3,
+#define iK ,eN1,IP,limit,y2,stack);
+#define iJ by_exponent
+#define iI );p2.lT2 p2 yB eL3 iZ2 nC);cJ}
+#define iH .eL3
+#define iG mulgroup;mulgroup iH
+#define iF (p0 e61&&p0 nL3 i2
+#define iE cN3 p0 yM>=e62 0.0))
+#define iD goto ReplaceTreeWithOne t83
+#define iC !=xJ)return n02
+#define iB e01.data
+#define iA iX2 xK2(
+#define i9 needs_sinhcosh
+#define i8 1)x41
+#define i7 ,l4 2,1,
+#define i6 cAdd l3 0,
+#define i5 tG2 e62
+#define i4 tK1 n9
+#define i3 MakeFalse,l5::
+#define i2 <=fp_const_negativezero xF())
+#define i1 ;return
+#define i0 )i1 lH
+#define tZ CalculateResultBoundaries(xW
+#define tY p0=CalculateResultBoundaries(
+#define tX ;yZ2
+#define tW ,2,1 iM2.xR if(found[data.
+#define tV 408964 nT 24963,
+#define tU 528503 nT 24713,
+#define tT matched_params
+#define tS [n1 eH3=true;lQ[n1 eI3
+#define tR lA1::Grammar*
+#define tQ AddOperation(cInv,1,1 iM2.xR}
+#define tP int_exponent_t
+#define tO m.max.
+#define tN ;AddParamMove(
+#define tM nM nU2,e62 1));
+#define tL cG3 eW3
+#define tK return m;}case
+#define tJ x9 AnyParams,
+#define tI powgroup l8
+#define tH relationships
+#define tG ]!=~size_t(0)){synth.yT
+#define tF }},{ProduceNewTree,2,1,
+#define tE nA1(
+#define tD has_mulgroups_remaining
+#define tC MatchInfo xF&
+#define tB e33);i32 c52
+#define tA best_factor
+#define t9 RootPowerTable xF::RootPowers[
+#define t8 (c81
+#define t7 :goto ReplaceTreeWithZero t83
+#define t6 MatchPositionSpec_AnyParams xF
+#define t5 l33 FPoptimizer_CodeTree
+#define t4 n_as_sinh_param
+#define t3 n_as_cosh_param
+#define t2 ();pow iH cLog yB eL3 cMul
+#define t1 0,tU2 i91 1);
+#define t0 is_signed
+#define eZ result_positivity
+#define eY biggest_minimum
+#define eX const l71
+#define eW 122999 nT 139399,
+#define eV 142455 nT 141449,
+#define eU cond_tree
+#define eT then_tree
+#define eS (a);bool needs_cow=GetRefCount()>1;
+#define eR yZ2&tree)
+#define eQ sequencing
+#define eP string FP_GetOpcodeName(
+#define eO );eN1 c52 0x80000000u
+#define eN {if(needs_cow){lD1 goto
+#define eM (lJ2));cA1 e33);
+#define eL ,nQ2
+#define eK eO3 yZ2>
+#define eJ if_stack
+#define eI n_as_sin_param
+#define eH n_as_cos_param
+#define eG PowiResolver::
+#define eF cIf,tG3
+#define eE ].relationship
+#define eD .BalanceGood
+#define eC AddParamMove(yT2
+#define eB valueType
+#define eA back().endif_location
+#define e9 xE1 key
+#define e8 AddParamMove(mul);
+#define e7 130,1,
+#define e6 MatchPositionSpecBase
+#define e5 iX2 c02(
+#define e4 smallest_maximum
+#define e3 ]!=~size_t(0)&&found[data.
+#define e2 }PACKED_GRAMMAR_ATTRIBUTE;
+#define e1 ReplaceTreeWithParam0;
+#define e0 factor_needs_rehashing
+#define cZ MatchPositionSpecBaseP
+#define cY .e33 yB eL3
+#define cX x93 tJ1::y83
+#define cW ParamSpec_Extract xF(nN.param_list,
+#define cV }x32 x41==e62
+#define cU 243,244,245,246,249,250,251,253,255,256,257,258,259}};}
+#define cT ];};extern"C"{
+#define cS .AddParam(
+#define cR iL2 tree lE2"\n";
+#define cQ )return false;
+#define cP 79,122,123,160,161,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240,
+#define cO 27,28,29,30,31,32,33,35,36,
+#define cN const ParamSpec_SubFunction
+#define cM const ParamSpec_ParamHolder
+#define cL otherhalf
+#define cK :{AdoptChildrenWithSameOpcode(tree);
+#define cJ goto redo;
+#define cI StackState
+#define cH l2 16,2,
+#define cG const SequenceOpCode xF
+#define cF MatchPositionSpec_PositionalParams xF
+#define cE const nP1 std::ostream&o
+#define cD e62 1.5)*fp_const_pi xF()
+#define cC CalculatePowiFactorCost(
+#define cB ImmedHashGenerator
+#define cA paramholder_matches
+#define c9 ::map<fphash_t,std::set<eM3> >
+#define c8 ComparisonSetBase::
+#define c7 AddParamMove(comp.cJ1[a].value);
+#define c6 T1,x93 T2>inline iD2()(
+#define c5 has_nonlogical_values
+#define c4 from_logical_context)
+#define c3 AnyParams,0}},{ProduceNewTree,
+#define c2 for iZ1 a=xV.l91 a-->0;)
+#define c1 POWI_CACHE_SIZE
+#define c0 static inline yZ2
+#define yZ ++IP;yA1}if(n13 c33.
+#define yY },{l5::xJ,l5::Never},{l5::xJ,l5::Never}}
+#define yX .FoundChild
+#define yW BalanceResultType
+#define yV {yZ2 tmp;tmp iH
+#define yU yB1 GetOpcode(),
+#define yT DoDup(found[data.
+#define yS xB3(0),Opcode(
+#define yR ;sim.Eat(
+#define yQ );void nR1 eZ2,c82<
+#define yP {return
+#define yO const yP data->
+#define yN +=fp_const_twopi xF();
+#define yM .min.val
+#define yL fp_sin(min),fp_sin(max))
+#define yK fp_const_twopi xF());if(
+#define yJ {yZ2 tmp,tmp2;tmp2 iH
+#define yI .min.known
+#define yH for iZ1 a=0;a<l91++a){if(
+#define yG MatchPositionSpec_AnyWhere
+#define yF if yZ3 data.match_type==
+#define yE void OutFloatHex(std::ostream&o,
+#define yD {static void lY3 nB fphash_t&cK2,
+#define yC tree.l91
+#define yB );tree.
+#define yA AddParam(CodeTreeImmed(
+#define y9 cGreaterOrEq,
+#define y8 ,x93 yZ2::
+#define y7 xF model=cI1 xF()){if(known
+#define y6 AssembleSequence_Subdivide(
+#define y5 ]=0x80000000u|x83(
+#define y4 branch2
+#define y3 x83 c;x83 short l[
+#define y2 factor_stack_base
+#define y1 data->Params
+#define y0 (lW3 r=range.first;r!=range.i63++r){
+#define xZ {nI2.erase(i);yA1}
+#define xY =0;a<y53.l91++a)if(
+#define xX ,t21 0x4 nH
+#define xW tree l8
+#define xV branch1
+#define xU ,nU2))eN
+#define xT nN y92
+#define xS =fp_cosh(m yM);tO val=fp_cosh(tO val);
+#define xR StackTopIs(*this)i1;}
+#define xQ StackTop
+#define xP FPOPT_autoptr
+#define xO +=nS3 i1 nS3;}tK1 inline Value_t
+#define xN int_exponent
+#define xM newnode
+#define xL lJ 1 i41
+#define xK has_highlevel_opcodes
+#define xJ Unchanged
+#define xI .IsIdenticalTo(
+#define xH GetStackTop()-
+#define xG sim.AddConst(
+#define xF <Value_t>
+#define xE cE=cV2
+#define xD best_selected_sep
+#define xC ->Recalculate_Hash_NoRecursion();}
+#define xB l91++a)if(ApplyGrammar(tK2,xW a),
+#define xA lU3 2,1,
+#define x9 ,cAdd,
+#define x8 position
+#define x7 x51{yD3
+#define x6 ;tmp2 tY3 tmp iH cInv);tmp c91 tmp2)i1
+#define x5 eO3 c02>
+#define x4 SetParam(0,iZ2 l8 0))tX p1;p1 iH
+#define x3 TestImmedConstraints yZ3 constraints cU3)cQ
+#define x2 SwapLastTwoInStack()yR
+#define x1 n23 1,cInv e02 xG-1 xN1
+#define x0 paramholder_index
+#define nZ lD2 case
+#define nY occurance_counts
+#define nX );a-->0;){iT1&powgroup=lX1;if(powgroup
+#define nW )){tree.tE3;}
+#define nV Value_t>p=tZ a));if(p.
+#define nU tree.ReplaceWithImmed(
+#define nT ,{2,
+#define nS ,l0 1,
+#define nR ,cAdd l3 2,1,
+#define nQ ){yZ2
+#define nP if(xW 0)tD1
+#define nO const FPoptimizer_CodeTree::yZ2&tree
+#define nN model_tree
+#define nM return yD3(
+#define nL ){using l33 FUNCTIONPARSERTYPES;
+#define nK eK&n12
+#define nJ AddParam(xW
+#define nI ConstantFolding_LogicCommon(tree,c8
+#define nH },{{2,
+#define nG nN1 Ref>inline void xP<Ref>::
+#define nF AnyParams,1 i41
+#define nE ):data(new xK2 xF(
+#define nD goto do_return;}
+#define nC .GetOpcode()
+#define nB FUNCTIONPARSERTYPES::
+#define nA b;}};tP1>e72 Comp<nB
+#define n9 xK2 xF::xK2(
+#define n8 lL2(),t53),Hash(),Depth(1 eB1 0){}
+#define n7 SynthesizeByteCode(c92
+#define n6 while(ApplyGrammar(cG2
+#define n5 GetIntegerInfo(xW 0))==iF2)n73
+#define n4 ;tree c91 n81 yQ2
+#define n3 tL1 cGreater>(e62
+#define n2 DumpParams xF yZ3 data.param_list,iH3 y92,o);
+#define n1 restholder_index
+#define n0 yZ2 exponent eX3 iH cMul)eX3 cS
+#define lZ lR);if(fp_nequal(tmp,xG1){nU e62 1)/tmp);nD}lC
+#define lY :if(ParamComparer xF()(t63 1],t63 0])){std::swap(t63 0],t63 1]);Opcode=
+#define lX <x93 Value_t>
+#define lW xF tmp;tmp iH cPow);tmp tY3 tmp.yA e62
+#define lV i01,0x0},
+#define lU AddParamMove(pow l8 1));pow.i91 1);pow.e33 yB nB1 0,pow);goto NowWeAreMulGroup;}
+#define lT GroupFunction,0},lV{{
+#define lS ,e62 1)/e62
+#define lR xW 0)x41
+#define lQ restholder_matches
+#define lP yE1|=key;xE1 crc=(key>>10)|(key<<(64-10))lL1((~n51 crc))*3)^1234567;}};
+#define lO n81;n81 nO2;n81 c91 xW 0));n81 cS xV l8
+#define lN tK1 yZ2::c02(
+#define lM tree.SetParam(0,xW 0)l8 0)xT1 1,CodeTreeImmed(
+#define lL lX void eP3::nR1 eZ2,c82<
+#define lK cMul,lT 2,
+#define lJ cMul,AnyParams,
+#define lI (xW 0)tD1&&xW 1)tD1){nU
+#define lH CalculateResultBoundaries(tmp);}case
+#define lG :cY3=comp.AddRelationship(atree l8 0),atree l8 1),c8
+#define lF cPow,l0 2
+#define lE x93 Value_t>inline iD2()iS1 Value_t&xC3 Value_t&b)yP a
+#define lD {yD3 m=tZ 0));
+#define lC break t83
+#define lB xL1 yZ2::
+#define lA y71,0,
+#define l9 l1 0x0 nH
+#define l8 .GetParam(
+#define l7 tX n81;n81 nO2;n81 iF1 tree.lJ2));n81 cY
+#define l6 SelectedParams,0},0,0x0 nH
+#define l5 RangeComparisonData
+#define l4 y71},{ProduceNewTree,
+#define l3 ,AnyParams,0}},{ReplaceParams,
+#define l2 y71},{ReplaceParams,
+#define l1 cMul,SelectedParams,0},0,
+#define l0 lA 0x0},{{
+#ifdef _MSC_VER
+typedef
+x83
+int
+lI2;
+#else
+#include <stdint.h>
+typedef
+uint_least32_t
+lI2;
+#endif
+l33
+crc32{enum{startvalue=0xFFFFFFFFUL,poly=0xEDB88320UL}
+;tP1
+lI2
+crc>e72
+b8{enum{b1=(crc&xJ1
+crc
+xL2
+crc>>1),b2=(b1&xJ1
+b1
+xL2
+b1>>1),b3=(b2&xJ1
+b2
+xL2
+b2>>1),b4=(b3&xJ1
+b3
+xL2
+b3>>1),b5=(b4&xJ1
+b4
+xL2
+b4>>1),b6=(b5&xJ1
+b5
+xL2
+b5>>1),b7=(b6&xJ1
+b6
+xL2
+b6>>1),res=(b7&xJ1
+b7
+xL2
+b7>>1)}
+;}
+;inline
+lI2
+update(lI2
+crc,x83
+b){
+#define B4(n) b8<n>nP3 n+1>nP3 n+2>nP3 n+3>::res
+#define R(n) B4(n),B4(n+4),B4(n+8),B4(n+12)
+static
+const
+lI2
+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];y81
+lI2
+calc_upd(lI2
+c,const
+x83
+char*buf,size_t
+size){lI2
+value=c
+eK3
+p=0;p<size;++p)value=update(value,buf[p])i1
+value;y81
+lI2
+calc
+iS1
+x83
+char*buf,size_t
+size)yP
+calc_upd(startvalue,buf,size);}
+}
+#ifndef FPOptimizerAutoPtrHH
+#define FPOptimizerAutoPtrHH
+nN1
+Ref>class
+xP{e43
+xP():p(0){}
+xP(Ref*b):p(b){xA3}
+xP
+iS1
+xP&b):p(b.p){xA3
+y81
+Ref&eM1*(c01*p;y81
+Ref*eM1->(c01
+p;}
+xP&eM1=(Ref*b){Set(b)i1*this;}
+xP&eM1=iS1
+xP&b){Set(b.p)i1*this;}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+xP(xP&&b):p(b.p){b.p=0;}
+xP&eM1=(xP&&b){if(p!=b.p){iC2;p=b.p;b.p=0;eE3*this;}
+#endif
+~xP(){Forget(cN2
+UnsafeSetP(Ref*newp){p=newp;}
+void
+swap(xP<Ref>&b){Ref*tmp=p;p=b.p;b.p=tmp;}
+private:inline
+static
+void
+Have(Ref*p2);inline
+void
+iC2;inline
+void
+xA3
+inline
+void
+Set(Ref*p2);private:Ref*p;}
+;nG
+iC2{if(!p)return;p->xB3-=1;if(!p->xB3)delete
+p;}
+nG
+Have(Ref*p2){if(p2)++(p2->xB3);}
+nG
+Birth(){Have(p);}
+nG
+Set(Ref*p2){Have(p2);iC2;p=p2;}
+#endif
+#include <utility>
+e72
+Compare2ndRev{nN1
+T>inline
+iD2()iS1
+T&xC3
+T&b
+c01
+a.second>b.i63}
+}
+;e72
+Compare1st{nN1
+c6
+const
+nO1
+xC3
+nO1
+b
+c01
+a.first<b.first;}
+nN1
+c6
+const
+nO1
+a,T1
+b
+c01
+a.first<b;}
+nN1
+c6
+T1
+xC3
+nO1
+b
+c01
+a<b.first;}
+}
+;
+#ifndef FPoptimizerHashHH
+#define FPoptimizerHashHH
+#ifdef _MSC_VER
+typedef
+x83
+long
+long
+xE1;
+#define FPHASH_CONST(x) x##ULL
+#else
+#include <stdint.h>
+typedef
+uint_fast64_t
+xE1;
+#define FPHASH_CONST(x) x##ULL
+#endif
+l33
+FUNCTIONPARSERTYPES{e72
+fphash_t{xE1
+hash1,hash2;fphash_t():hash1(0),hash2(0){}
+fphash_t
+iS1
+xE1&xC3
+xE1&b):hash1(a),hash2(b){}
+iD2==iS1
+fphash_t&yZ1==e82&&hash2==e92
+iD2!=iS1
+fphash_t&yZ1!=e82||hash2!=e92
+iD2<iS1
+fphash_t&yZ1!=e82?hash1<e82:hash2<e92}
+;}
+#endif
+#ifndef FPOptimizer_CodeTreeHH
+#define FPOptimizer_CodeTreeHH
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <vector>
+#include <utility>
+l33
+lA1{e72
+Grammar;}
+l33
+xK1{tK1
+class
+ByteCodeSynth;}
+t5{tK1
+class
+c02
+yO1
+e72
+xK2
+yO1
+class
+c02{typedef
+xP<xK2
+xF>DataP;DataP
+data;e43
+c02();~c02();e72
+OpcodeTag{}
+;e5
+iU1
+o,OpcodeTag);e72
+FuncOpcodeTag{}
+;e5
+iU1
+o,x83
+f,FuncOpcodeTag);e72
+xD3{}
+;e5
+tV1,xD3);
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+e5
+Value_t&&v,xD3);
+#endif
+e72
+VarTag{}
+;e5
+x83
+varno,VarTag);e72
+CloneTag{}
+;e5
+tW1
+b,CloneTag);void
+GenerateFrom
+iS1
+x93
+FunctionParserBase
+xF::Data&data,bool
+keep_powi=false);void
+GenerateFrom
+iS1
+x93
+FunctionParserBase
+xF::Data&data,const
+x5&xH2,bool
+keep_powi=false);void
+SynthesizeByteCode(eO3
+x83>&cT3,std
+xM3
+xF&immed,size_t&stacktop_max);void
+SynthesizeByteCode(xK1::eP3&synth,bool
+MustPopTemps=true)const;size_t
+SynthCommonSubExpressions(xK1::xI1
+const;void
+SetParams
+iS1
+x5&xE3
+SetParamsMove(x5&tO1
+c02
+GetUniqueRef();
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+void
+SetParams(x5&&tO1
+#endif
+void
+SetParam
+iZ1
+which,tW1
+b);void
+nB1
+size_t
+which,c02&b);void
+AddParam(tW1
+param);void
+AddParamMove(c02&param);void
+AddParams
+iS1
+x5&xE3
+AddParamsMove(x5&xE3
+AddParamsMove(x5&n12,size_t
+n22);void
+i91
+size_t
+index);void
+DelParams();void
+Become(tW1
+b);inline
+size_t
+GetParamCount(c01
+lJ2)eJ3;y81
+c02&GetParam
+iZ1
+n)yP
+lJ2)[n];y81
+tW1
+GetParam
+iZ1
+n
+c01
+lJ2)[n];y81
+void
+eL3
+iU1
+o)iZ3
+Opcode=o;y81
+iU1
+GetOpcode()yO
+Opcode;y81
+nB
+fphash_t
+GetHash()yO
+Hash;y81
+const
+x5&lJ2
+c01
+y1;y81
+x5&lJ2)yP
+y1;y81
+size_t
+GetDepth()yO
+Depth;y81
+const
+Value_t&GetImmed()yO
+Value;y81
+x83
+GetVar()yO
+lK2
+y81
+x83
+GetFuncNo()yO
+lK2
+y81
+bool
+IsDefined(c01
+GetOpcode()!=nB
+cNop;y81
+bool
+IsImmed(c01
+GetOpcode()==nB
+cImmed;y81
+bool
+IsVar(c01
+GetOpcode()==nB
+iU2;y81
+x83
+GetRefCount()yO
+xB3;}
+void
+ReplaceWithImmed(tX1;void
+e33
+bool
+constantfolding=true);void
+Sort();inline
+void
+Mark_Incompletely_Hashed()iZ3
+Depth=0;y81
+bool
+Is_Incompletely_Hashed()yO
+Depth==0;y81
+const
+tR
+GetOptimizedUsing()yO
+lM2;y81
+void
+SetOptimizedUsing
+iS1
+tR
+g)iZ3
+lM2=g;}
+bool
+RecreateInversionsAndNegations(bool
+prefer_base2=false);void
+tE3;void
+swap(c02&b){data.swap(b.data);}
+bool
+IsIdenticalTo(tW1
+b)const;void
+lD1}
+yO1
+e72
+xK2{int
+xB3;iU1
+Opcode
+iK2
+Value;x83
+lK2
+eK
+Params;nB
+fphash_t
+Hash;size_t
+Depth;const
+tR
+lM2;xK2();xK2
+iS1
+xK2&b);iA
+iU1
+o);iA
+iU1
+o,x83
+f);iA
+tX1;
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+iA
+Value_t&&i);xK2(xK2&&b);
+#endif
+bool
+IsIdenticalTo
+iS1
+xK2&b)const;void
+Sort();void
+Recalculate_Hash_NoRecursion();private:void
+eM1=iS1
+xK2&b);}
+yO1
+c0
+CodeTreeImmed(tX1
+n21
+i
+y8
+xD3());}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+cC1
+CodeTreeImmed
+cX3&&i)n21
+tF2
+i)y8
+xD3());}
+#endif
+cC1
+CodeTreeOp(iU1
+opcode)n21
+opcode
+y8
+OpcodeTag());}
+cC1
+CodeTreeFuncOp(iU1
+opcode,x83
+f)n21
+opcode,f
+y8
+FuncOpcodeTag());}
+cC1
+CodeTreeVar
+lT1
+varno)n21
+varno
+y8
+VarTag());}
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+xL1
+DumpHashes(xE);xL1
+DumpTree(xE);xL1
+DumpTreeWithIndent(xE,const
+eM3&indent="\\"
+);
+#endif
+}
+#endif
+#endif
+#ifndef FPOptimizer_GrammarHH
+#define FPOptimizer_GrammarHH
+#include <iostream>
+t5{tK1
+class
+c02;}
+l33
+lA1{enum
+ImmedConstraint_Value{ValueMask=0x07,Value_AnyNum=0x0,x62=0x1,Value_OddInt=0x2,i11=0x3,Value_NonInteger=0x4,eY1=0x5}
+;enum
+ImmedConstraint_Sign{SignMask=0x18,Sign_AnySign=0x00,nD1=0x08,eZ1=0x10,Sign_NoIdea=0x18}
+;enum
+ImmedConstraint_Oneness{OnenessMask=0x60,Oneness_Any=0x00,Oneness_One=0x20,Oneness_NotOne=0x40}
+;enum
+ImmedConstraint_Constness{ConstnessMask=0x180,Constness_Any=0x00,i01=0x80,Constness_NotConst=0x100}
+;enum
+Modulo_Mode{Modulo_None=0,Modulo_Radians=1}
+;enum
+Situation_Flags{LogicalContextOnly=0x01,NotForIntegers=0x02,OnlyForIntegers=0x04,OnlyForComplex=0x08,NotForComplex=0x10}
+;enum
+nZ2{NumConstant,ParamHolder,SubFunction}
+;enum
+ParamMatchingType{PositionalParams,SelectedParams,AnyParams,GroupFunction}
+;enum
+RuleType{ProduceNewTree,ReplaceParams}
+;
+#ifdef __GNUC__
+# define PACKED_GRAMMAR_ATTRIBUTE __attribute__((packed))
+#else
+# define PACKED_GRAMMAR_ATTRIBUTE
+#endif
+typedef
+std::pair<nZ2,const
+void*>eA2
+yO1
+eA2
+ParamSpec_Extract
+lT1
+paramlist,lJ1)yO1
+bool
+ParamSpec_Compare
+iS1
+void*xC3
+void*b,nZ2
+type);x83
+ParamSpec_GetDepCode
+iS1
+eA2&b);e72
+ParamSpec_ParamHolder{lJ1:8;x83
+constraints:9;x83
+depcode:15;e2
+tK1
+e72
+ParamSpec_NumConstant
+l14
+constvalue;x83
+modulo;}
+;e72
+l71{x83
+param_count:2;x83
+param_list:30;iU1
+subfunc_opcode:8;ParamMatchingType
+match_type:3;x83
+n1:5;e2
+e72
+ParamSpec_SubFunction{l71
+data;x83
+constraints:9;x83
+depcode:7;e2
+e72
+Rule{RuleType
+ruletype:2;x83
+situation_flags:5;x83
+repl_param_count:2+9;x83
+repl_param_list:30;l71
+match_tree;e2
+e72
+Grammar{x83
+rule_count;x83
+short
+rule_list[999
+cT
+extern
+const
+Rule
+grammar_rules[];}
+xL1
+DumpParam
+iS1
+eA2&p,std::ostream&o=cV2);xL1
+DumpParams
+lT1
+paramlist,x83
+count,std::ostream&o=cV2);}
+#endif
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795
+#endif
+#define CONSTANT_POS_INF HUGE_VAL
+#define CONSTANT_NEG_INF (-HUGE_VAL)
+l33
+FUNCTIONPARSERTYPES{tK1
+inline
+Value_t
+fp_const_pihalf()yP
+fp_const_pi
+xF()*yF2;}
+tK1
+inline
+Value_t
+fp_const_twopi()eQ3
+fp_const_pi
+xF());nS3
+xO
+fp_const_twoe()eQ3
+fp_const_e
+xF());nS3
+xO
+fp_const_twoeinv()eQ3
+fp_const_einv
+xF());nS3
+xO
+fp_const_negativezero()yP-Epsilon
+xF::value;}
+}
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <vector>
+#include <utility>
+#include <iostream>
+nG1{using
+l33
+lA1;using
+t5;using
+l33
+FUNCTIONPARSERTYPES
+yO1
+class
+MatchInfo{e43
+eO3
+std::pair<bool,eK> >lQ;eK
+cA;eO3
+x83>tT;e43
+MatchInfo():lQ(),cA(),tT(){}
+e43
+bool
+SaveOrTestRestHolder
+lT1
+n1,eA3&iJ1){cT1{lQ
+xF3
+n1+1);lQ
+tS=iJ1
+l43
+if(lQ[n1
+eH3==false){lQ
+tS=iJ1
+l43
+eA3&found=lQ[n1
+eI3;if(iJ1
+eJ3!=found
+eJ3
+cQ
+for
+iZ1
+a=0;a<iJ1
+eJ3;++a)if(!iJ1[a]xI
+found[a])cQ
+lD2}
+void
+SaveRestHolder
+lT1
+n1,eK&iJ1){cT1
+lQ
+xF3
+n1+1);lQ
+tS.swap(iJ1);}
+bool
+SaveOrTestParamHolder
+lT1
+x0,iT1&xG3){if(cA
+eJ3<=x0){cA.xH3
+x0+1);cA
+xF3
+x0);cA
+c52
+xG3
+yQ2
+if(!cA[x0].nX2){cA[x0]=xG3
+l43
+return
+xG3
+xI
+cA[x0]cN2
+SaveMatchedParamIndex(lJ1){tT
+c52
+index);}
+iT1&GetParamHolderValueIfFound
+lT1
+x0)const{static
+iT1
+dummytree;if(cA
+eJ3<=x0)return
+dummytree
+i1
+cA[x0];}
+iT1&GetParamHolderValue
+lT1
+x0
+c01
+cA[x0];}
+bool
+HasRestHolder
+lT1
+n1
+c01
+lQ
+eJ3>n1&&lQ[n1
+eH3==true;}
+eA3&GetRestHolderValues
+lT1
+n1)const{static
+eA3
+empty_result;cT1
+return
+empty_result
+i1
+lQ[n1
+eI3;}
+const
+eO3
+x83>&GetMatchedParamIndexes(c01
+tT;}
+void
+swap(tC
+b){lQ.swap(b.lQ);cA.swap(b.cA);tT.swap(b.tT);}
+tC
+eM1=iS1
+tC
+b){lQ=b.lQ;cA=b.cA;tT=b.tT
+i1*this;}
+}
+;class
+e6;typedef
+xP<e6>cZ;class
+e6{e43
+int
+xB3;e43
+e6():xB3(0){}
+virtual~e6(){}
+}
+;e72
+n31{bool
+found;cZ
+specs;n31(bool
+f):found(f),specs(){}
+n31(bool
+f,const
+cZ&s):found(f),specs(s){}
+}
+;xL1
+SynthesizeRule(t41
+nP1
+tC
+info)yO1
+n31
+TestParam
+iS1
+eA2&yA2
+const
+nP1
+const
+cZ&start_at,tC
+info)yO1
+n31
+TestParams(eX&nN,const
+nP1
+const
+cZ&start_at,tC
+info,bool
+iX1
+yO1
+bool
+ApplyGrammar
+iS1
+Grammar&tK2,FPoptimizer_CodeTree::nP1
+bool
+from_logical_context=false);xL1
+ApplyGrammars(FPoptimizer_CodeTree::eR
+yO1
+bool
+IsLogisticallyPlausibleParamsMatch(eX&params,const
+eR;}
+l33
+lA1{xL1
+DumpMatch(t41
+nO,const
+FPoptimizer_Optimize::tC
+info,bool
+DidMatch,std::ostream&o=cV2);xL1
+DumpMatch(t41
+nO,const
+FPoptimizer_Optimize::tC
+info,e32
+tO3,std::ostream&o=cV2);}
+#endif
+#include <string>
+e42
+lA1::nZ2
+yT1=false);e42
+iU1
+yT1=false);
+#include <string>
+#include <sstream>
+#include <assert.h>
+#include <iostream>
+using
+l33
+lA1;using
+l33
+FUNCTIONPARSERTYPES;e42
+lA1::nZ2
+yT1){
+#if 1
+e32
+p=0;e23
+opcode){case
+NumConstant:p="NumConstant"
+;lC
+ParamHolder:p="ParamHolder"
+;lC
+SubFunction:p="SubFunction"
+;xY3
+std::ostringstream
+tmp;assert(p);tmp<<p;if(pad)while(tmp.str()eJ3<12)tmp<<' '
+i1
+tmp.str();
+#else
+std::ostringstream
+tmp;tmp<<opcode;if(pad)while(tmp.str()eJ3<5)tmp<<' '
+i1
+tmp.str();
+#endif
+}
+e42
+iU1
+yT1){
+#if 1
+e32
+p=0;e23
+opcode){case
+cAbs:p="cAbs"
+;lC
+cAcos:p="cAcos"
+;lC
+cAcosh:p="cAcosh"
+;lC
+cArg:p="cArg"
+;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
+cConj:p="cConj"
+;lC
+cCos:p="cCos"
+;lC
+cCosh:p="cCosh"
+;lC
+cCot:p="cCot"
+;lC
+cCsc:p="cCsc"
+;lC
+cExp:p="cExp"
+;lC
+cExp2:p="cExp2"
+;lC
+cFloor:p="cFloor"
+;lC
+cHypot:p="cHypot"
+;lC
+cIf:p="cIf"
+;lC
+cImag:p="cImag"
+;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
+cPolar:p="cPolar"
+;lC
+cPow:p="cPow"
+;lC
+cReal:p="cReal"
+;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
+i51: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
+cQ3:p="cLog2by"
+;lC
+cNop:p="cNop"
+;break;
+#endif
+case
+cSinCos:p="cSinCos"
+;lC
+cSinhCosh:p="cSinhCosh"
+;lC
+cC3:p="cAbsNot"
+;lC
+cAbsNotNot:p="cAbsNotNot"
+;lC
+cAbsAnd:p="cAbsAnd"
+;lC
+cAbsOr:p="cAbsOr"
+;lC
+cAbsIf: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
+iU2:p="VarBegin"
+;xY3
+std::ostringstream
+tmp;assert(p);tmp<<p;if(pad)while(tmp.str()eJ3<12)tmp<<' '
+i1
+tmp.str();
+#else
+std::ostringstream
+tmp;tmp<<opcode;if(pad)while(tmp.str()eJ3<5)tmp<<' '
+i1
+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}
+;l33
+xK1{tK1
+class
+ByteCodeSynth{e43
+ByteCodeSynth():eN1(),Immed(),cI(),xQ(0),StackMax(0){eN1.xH3
+64);Immed.xH3
+8);cI.xH3
+16
+cN2
+Pull(eO3
+x83>&bc,std
+xM3
+xF&imm,size_t&StackTop_max){for
+lT1
+a=0;a<n41;++a){eN1[a]&=~0x80000000u;}
+eN1.swap(bc);Immed.swap(imm);StackTop_max=StackMax;}
+size_t
+GetByteCodeSize(c01
+n41;}
+size_t
+GetStackTop(c01
+xQ;}
+void
+PushVar
+lT1
+varno){eN1
+c52
+varno);xI3
+1
+cN2
+PushImmed
+cX3
+immed
+nL
+eN1
+c52
+cImmed);Immed
+c52
+immed);xI3
+1
+cN2
+StackTopIs(nO,int
+offset=0){if((int)xQ>offset){cI[xQ
+nK2
+first=true;cI[xQ
+nK2
+second=tree;}
+}
+bool
+IsStackTop(nO,int
+offset=0
+c01(int)xQ>offset&&cI[xQ
+nK2
+first&&cI[xQ
+nK2
+second
+xI
+tree);y81
+void
+EatNParams
+lT1
+eat_count){xQ-=eat_count;}
+void
+ProducedNParams
+lT1
+produce_count){xI3
+produce_count
+cN2
+DoPopNMov
+iZ1
+eB2,size_t
+srcpos
+nL
+eN1
+c52
+cPopNMov
+e53
+eB2
+e53
+srcpos);xM1
+srcpos+1);cI[eB2]=cI[srcpos];xM1
+eB2+1
+cN2
+DoDup
+iZ1
+xJ3
+nL
+if(xJ3==xQ-1){eN1
+c52
+cDup);}
+else{eN1
+c52
+cFetch
+e53
+xJ3);}
+xI3
+1);cI[xQ-1]=cI[xJ3];}
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+tP1
+int>void
+Dump(){std::ostream&o=cV2;o<<"Stack state now("
+<<xQ<<"):\n"
+e73
+0;a<xQ;++a){o<<a<<": "
+;if(cI[a
+eH3){nO=cI[a
+eI3;o<<'['<<std::hex<<(void*)(&tree.lJ2))<<std::dec<<','<<tree.GetRefCount()<<']'
+iL2
+tree,o);}
+else
+o<<"?"
+iV3}
+o<<std::flush;}
+#endif
+size_t
+xK3
+nO)const{for
+iZ1
+a=xQ;a-->0;)if(cI[a
+eH3&&cI[a
+eI3
+xI
+tree
+y03
+a
+i1~size_t(0);}
+bool
+Find(nO
+c01
+xK3
+tree)!=~size_t(0);}
+bool
+FindAndDup(nO){size_t
+pos=xK3
+tree);if(pos!=~size_t(0)){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iX3"duplicate at ["
+<<pos<<"]: "
+iL2
+tree
+lE2" -- issuing cDup or cFetch\n"
+;
+#endif
+DoDup(pos
+yQ2
+return
+t23
+e72
+IfData{size_t
+ofs;}
+;void
+SynthIfStep1
+c62,iU1
+op
+x21
+c72=n41;eN1
+c52
+op
+eO
+eO
+cN2
+SynthIfStep2
+c62
+x21
+eN1
+iK1
+xL3+2);eN1
+iK1
+2
+y5
+lN2
+c72=n41;eN1
+c52
+cJump
+eO
+eO
+cN2
+SynthIfStep3
+c62
+x21
+eN1.back()|=0x80000000u;eN1
+iK1
+xL3-1);eN1
+iK1
+2
+y5
+lN2
+xI3
+1
+iY1
+0;a<c72;++a){if(eN1[a]==cJump&&eN1[a+1]==(0x80000000u|(c72-1))){eN1[a+xL3-1);eN1[a+2
+y5
+lN2
+c73(eN1[a]){case
+cAbsIf:case
+cIf:case
+cJump:case
+cPopNMov:a+=2;lC
+cFCall:case
+cPCall:case
+cFetch:a+=1;break;yF3
+xY3}
+}
+protected:void
+xM1
+size_t
+value){xQ=value;if(xQ>l53{StackMax=xQ;cI
+xF3
+l53;}
+}
+protected:eO3
+x83>eN1;std
+xM3
+xF
+Immed;eO3
+std::pair<bool,FPoptimizer_CodeTree::yZ2> >cI;size_t
+xQ;size_t
+StackMax;private:void
+incStackPtr(){if(xQ+2>l53
+cI
+xF3
+StackMax=xQ+2);}
+tP1
+bool
+IsIntType,bool
+IsComplexType>e72
+c82{}
+;e43
+void
+AddOperation
+eZ2,x83
+eat_count,x83
+produce_count=1){EatNParams(eat_count);nR1(opcode);ProducedNParams(produce_count
+cN2
+nR1
+eZ2,c82<false,false>yQ
+false,true>yQ
+true,false>yQ
+true,true>);inline
+void
+nR1
+eZ2){nR1(opcode,c82<bool(nB
+IsIntType
+xF::nS3),bool(nB
+IsComplexType
+xF::nS3)>());}
+}
+yO1
+e72
+SequenceOpCode
+yO1
+e72
+tU1{static
+cG
+AddSequence;static
+cG
+MulSequence;}
+;xL1
+x01
+long
+count,cG&eQ,xI1;}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;l33
+xK1{tK1
+e72
+SequenceOpCode
+l14
+basevalue;x83
+op_flip;x83
+op_normal,op_normal_flip;x83
+op_inverse,op_inverse_flip;}
+yO1
+cG
+tU1
+xF::AddSequence={xH1,cNeg
+x9
+cAdd,cSub,cRSub}
+yO1
+cG
+tU1
+xF::MulSequence={e62
+1),cInv,cMul,cMul,cDiv,cRDiv}
+;
+#define findName(a,b,c) "var"
+#define TryCompilePowi(o) false
+#define mData this
+#define mByteCode eN1
+#define mImmed Immed
+nL2
+false,false>)x31
+# define FP_FLOAT_VERSION 1
+# define FP_COMPLEX_VERSION 0
+# include "extrasrc/fp_opcode_add.inc"
+# undef FP_COMPLEX_VERSION
+# undef FP_FLOAT_VERSION
+}
+nL2
+true,false>)x31
+# define FP_FLOAT_VERSION 0
+# define FP_COMPLEX_VERSION 0
+# include "extrasrc/fp_opcode_add.inc"
+# undef FP_COMPLEX_VERSION
+# undef FP_FLOAT_VERSION
+}
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+nL2
+false,true>)x31
+# define FP_FLOAT_VERSION 1
+# define FP_COMPLEX_VERSION 1
+# include "extrasrc/fp_opcode_add.inc"
+# undef FP_COMPLEX_VERSION
+# undef FP_FLOAT_VERSION
+}
+nL2
+true,true>)x31
+# define FP_FLOAT_VERSION 0
+# define FP_COMPLEX_VERSION 1
+# include "extrasrc/fp_opcode_add.inc"
+# undef FP_COMPLEX_VERSION
+# undef FP_FLOAT_VERSION
+}
+#endif
+#undef findName
+#undef mImmed
+#undef mByteCode
+#undef mData
+#undef TryCompilePowi
+}
+using
+l33
+xK1;
+#define POWI_TABLE_SIZE 256
+#define POWI_WINDOW_SIZE 3
+l33
+xK1{
+#ifndef FP_GENERATING_POWI_TABLE
+extern
+const
+x83
+char
+powi_table[POWI_TABLE_SIZE];const
+#endif
+x83
+char
+powi_table[POWI_TABLE_SIZE]={0,1,1,1,2,1,2,1,xN3
+4,1,2,xP3
+2,1,xN3
+8,cV3
+xQ3
+15,1,16,1,2,1,4,1,2,xP3
+2,1,4,cV3
+1,16,1,25,xQ3
+27,5,8,3,2,1,30,1,31,3,32,1,2,1,xN3
+8,1,2,xQ3
+39,1,16,137,2,1,4,cV3
+xP3
+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,iL1
+131,iL1
+139,lO2
+e7
+30,1,130,137,2,31,lO2
+e7
+e7
+130,cV3
+1,e7
+e7
+2,1,130,133,iL1
+61,130,133,62,139,130,137,e7
+lO2
+e7
+e7
+iL1
+131,e7
+e7
+130,131,2,133,lO2
+130,141,e7
+130,cV3
+1,e7
+5,135,e7
+lO2
+e7
+lO2
+130,133,130,141,130,131,e7
+e7
+2,131}
+;}
+static
+x03
+c1=256;
+#define FPO(x)
+l33{class
+PowiCache{private:int
+iM[c1];int
+iM1[c1];e43
+PowiCache():iM(),iM1(){iM[1]=1;}
+bool
+Plan_Add(c11,int
+count){cD1>=c1
+cQ
+iM1[t02+=count
+i1
+iM[t02!=0;}
+void
+l63
+c11){cD1<c1)iM[t02=1;}
+void
+Start
+iZ1
+value1_pos){for(int
+n=2;n<c1;++n)iM[n]=-1;Remember(1,value1_pos);DumpContents();}
+int
+Find(c11)const{cD1<c1){if(iM[t02>=0){FPO(iC3(iG3,"* I found %ld from cache (%u,%d)\n",value,(unsigned)cache[value],iD3 value]))i1
+iM[t02;}
+eE3-1;}
+void
+Remember(c11,size_t
+iQ3){cD1>=c1)return;FPO(iC3(iG3,"* Remembering that %ld can be found at %u (%d uses remain)\n",value,(unsigned)iQ3,iD3 value]));iM[t02=(int)iQ3;}
+void
+DumpContents()const{FPO(for(int a=1;a<POWI_CACHE_SIZE;++a)if(cache[a]>=0||iD3 a]>0){iC3(iG3,"== cache: sp=%d, val=%d, needs=%d\n",cache[a],a,iD3 a]);})}
+int
+UseGetNeeded(c11){cD1>=0&&value<c1)return--iM1[t02
+i1
+0;}
+}
+yO1
+size_t
+y6
+long
+count
+iQ1
+cG&eQ,xI1;xL1
+c21
+size_t
+apos,long
+aval,size_t
+bpos,long
+bval
+iQ1
+x83
+cumulation_opcode,x83
+cimulation_opcode_flip,xI1;void
+lB1
+c11
+iQ1
+int
+need_count,int
+lC1=0){cD1<1)return;
+#ifdef FP_GENERATING_POWI_TABLE
+if(lC1>32)throw
+false;
+#endif
+if(iM.Plan_Add(value,need_count
+y03;long
+xR3
+1;cD1<POWI_TABLE_SIZE){xR3
+powi_table[t02
+xZ3&128){half&=127
+xZ3&64)xR3-t12
+FPO(iC3(iG3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,value/half));lB1
+half
+xO3
+iM.l63
+half)i1;}
+iP1
+half&64){xR3-t12}
+}
+else
+cD1&1)xR3
+value&((1<<POWI_WINDOW_SIZE)-1);else
+xR3
+value/2;long
+cL=value-half
+xZ3>cL||half<0)std::swap(half,cL);FPO(iC3(iG3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,otherhalf))xZ3==cL){lB1
+half,iM,2,lC1+1);}
+else{lB1
+half
+xO3
+lB1
+cL>0?cL:-cL
+xO3}
+iM.l63
+value);}
+tK1
+size_t
+y6
+c11
+iQ1
+cG&eQ,xI1{int
+xT3=iM.Find(value);if(xT3>=0)yP
+xT3;}
+long
+xR3
+1;cD1<POWI_TABLE_SIZE){xR3
+powi_table[t02
+xZ3&128){half&=127
+xZ3&64)xR3-t12
+FPO(iC3(iG3,"* I want %ld, my plan is %ld * %ld\n",value,half,value/half));size_t
+xM2=y6
+half
+cE1
+if(iM
+lP2
+half)>0||xM2!=cG1){iN1
+xM2)xP2
+half,cG1);}
+x01
+value/half
+e63
+size_t
+iQ3=cG1
+xP2
+value,iQ3);iM.DumpContents()i1
+iQ3;}
+iP1
+half&64){xR3-t12}
+}
+else
+cD1&1)xR3
+value&((1<<POWI_WINDOW_SIZE)-1);else
+xR3
+value/2;long
+cL=value-half
+xZ3>cL||half<0)std::swap(half,cL);FPO(iC3(iG3,"* I want %ld, my plan is %ld + %ld\n",value,half,value-half))xZ3==cL){size_t
+xM2=y6
+half
+cE1
+c21
+xM2,half,xM2,half,iM,eQ.op_normal,eQ.op_normal_flip,c92}
+else{long
+part1=half;long
+part2=cL>0?cL:-cL;size_t
+part1_pos=y6
+part1
+cE1
+size_t
+part2_pos=y6
+part2
+cE1
+FPO(iC3(iG3,"Subdivide(%ld: %ld, %ld)\n",value,half,otherhalf));c21
+part1_pos,part1,part2_pos,part2,iM,cL>0?eQ.op_normal:eQ.op_inverse,cL>0?eQ.op_normal_flip:eQ.op_inverse_flip,c92}
+size_t
+iQ3=cG1
+xP2
+value,iQ3);iM.DumpContents()i1
+iQ3;}
+xL1
+c21
+size_t
+apos,long
+aval,size_t
+bpos,long
+bval
+iQ1
+x83
+cumulation_opcode,x83
+cumulation_opcode_flip,xI1{int
+a_needed=iM
+lP2
+aval);int
+xU3=iM
+lP2
+bval);bool
+flipped
+eW3
+#define DUP_BOTH() do{if(apos<bpos){size_t tmp=apos;apos=bpos;bpos=tmp e41 FPO(iC3(iG3,"-> " iO3 iO3"op\n",(unsigned)apos,(unsigned)bpos));iN1 apos);iN1 apos==bpos?cG1:bpos);}while(0)
+#define DUP_ONE(p) do{FPO(iC3(iG3,"-> " iO3"op\n",(unsigned)p));iN1 p);}while(0)
+if(a_needed>0){if(xU3>0){nM2}
+cJ3
+bpos!=cG1)nM2
+else{x02
+e41}
+}
+iP1
+xU3>0){if(apos!=cG1)nM2
+else
+DUP_ONE(bpos);}
+cJ3
+apos==bpos&&apos==cG1)x02;iP1
+apos==cG1&&bpos==xV3
+2){FPO(iC3(iG3,"-> op\n"))e41
+iP1
+apos==xV3
+2&&bpos==cG1)FPO(iC3(iG3,"-> op\n"));iP1
+apos==cG1)DUP_ONE(bpos);iP1
+bpos==cG1){x02
+e41
+else
+nM2}
+yB1
+flipped?cumulation_opcode_flip:cumulation_opcode,2);}
+xL1
+cH1
+long
+count,cG&eQ,xI1{while
+cW3<256){int
+xR3
+xK1::powi_table[count]xZ3&128){half&=127;cH1
+half
+e63
+count/=half;}
+else
+xY3
+if
+cW3==1)return;if(!cW3&1)){yB1
+cSqr,1);cH1
+count/2
+e63}
+else{iN1
+cG1);cH1
+count-1
+e63
+yB1
+cMul,2);}
+}
+}
+l33
+xK1{xL1
+x01
+long
+count,cG&eQ,xI1{if
+cW3==0)t71
+eQ.basevalue);else{bool
+t22
+eW3
+if
+cW3<0){t22=true;count=-count;}
+if(false)cH1
+count
+e63
+iP1
+count>1){PowiCache
+iM;lB1
+count,iM,1);size_t
+xO1=synth.GetStackTop();iM.Start(cG1);FPO(iC3(iG3,"Calculating result for %ld...\n",count));size_t
+xN2=y6
+count
+cE1
+size_t
+n_excess=xV3
+xO1;if(n_excess>0||xN2!=xO1-1){synth.DoPopNMov(xO1-1,xN2);}
+}
+if(t22)yB1
+eQ.op_flip,1);}
+}
+}
+#endif
+#ifndef FPOptimizer_ValueRangeHH
+#define FPOptimizer_ValueRangeHH
+t5{l33
+l73{l01
+e72
+Comp{}
+;tP1>e72
+Comp<nB
+cLess>l83<nA
+cLessOrEq>l83<=nA
+cGreater>l83>nA
+cGreaterOrEq>l83>=nA
+cEqual>l83==nA
+i51>l83!=b;}
+}
+;}
+tK1
+e72
+cI1
+l14
+val;bool
+known;cI1():val(),known(false){}
+cI1(tV1):val(v),known(true){y81
+l93
+tV1){known=true;val=v;}
+l93
+xW3
+Value_t),cI1
+y7)val=iE2
+l93
+xW3
+const
+Value_t&),cI1
+y7)val=iE2
+l01
+void
+set_if
+cX3
+v,xW3
+Value_t),cI1
+y7&&l73::Comp<Compare>()(val,v))val=iE2
+l01
+void
+set_if(tV1,xW3
+const
+Value_t&),cI1
+y7&&l73::Comp<Compare>()(val,v))val=iE2}
+yO1
+e72
+range{cI1
+xF
+min,max;range():min(),max(){}
+range
+cX3
+mi,Value_t
+ma):min(mi),max(ma){}
+range(bool,Value_t
+ma):min(),max(ma){}
+range
+cX3
+mi,bool):min(mi),max(){}
+void
+set_abs();void
+set_neg();}
+yO1
+bool
+IsLogicalTrueValue
+iS1
+yD3&p,bool
+abs)yO1
+bool
+IsLogicalFalseValue
+iS1
+yD3&p,bool
+abs);}
+#endif
+#ifndef FPOptimizer_RangeEstimationHH
+#define FPOptimizer_RangeEstimationHH
+t5{enum
+TriTruthValue{iF2,xX3,Unknown}
+yO1
+yD3
+CalculateResultBoundaries
+iS1
+eR
+yO1
+bool
+IsLogicalValue
+iS1
+eR
+yO1
+TriTruthValue
+GetIntegerInfo
+iS1
+eR
+yO1
+xP1
+GetEvennessInfo
+iS1
+eR{if(!tree
+tD1)return
+Unknown;yL1=tree
+x41;if(nB
+isEvenInteger(value
+y13
+nB
+isOddInteger(value
+y23
+tK1
+xP1
+GetPositivityInfo
+iS1
+eR{yD3
+p=CalculateResultBoundaries(tree);if(p
+yI&&p
+yM>=e62
+y13
+p
+e61
+l61
+y23
+tK1
+xP1
+GetLogicalValue
+iS1
+nP1
+bool
+abs){yD3
+p=CalculateResultBoundaries(tree);if(IsLogicalTrueValue(p,abs
+y13
+IsLogicalFalseValue(p,abs
+y23}
+#endif
+#ifndef FPOptimizer_ConstantFoldingHH
+#define FPOptimizer_ConstantFoldingHH
+t5{xL1
+ConstantFolding(eR;}
+#endif
+l33{using
+l33
+FUNCTIONPARSERTYPES;using
+t5;e72
+ComparisonSetBase{enum{eB3=0x1,Eq_Mask=0x2,Le_Mask=0x3,eC3=0x4,eD3=0x5,Ge_Mask=0x6}
+;static
+int
+Swap_Mask(int
+m)yP(m&Eq_Mask)|((m&eB3)?eC3:0)|((m&eC3)?eB3:0);}
+enum
+c31{Ok,BecomeZero,BecomeOne,n91}
+;enum
+x12{cond_or,iG2,iH2,iI2}
+;}
+yO1
+e72
+ComparisonSet:public
+ComparisonSetBase{e72
+t32{yZ2
+a
+tX
+b;int
+relationship;t32():a(),b(),relationship(){}
+}
+;eO3
+t32>tH;e72
+Item{yZ2
+value;bool
+cA2;Item():value(),cA2(false){}
+}
+;eO3
+Item>cJ1;int
+xQ1;ComparisonSet():tH(),cJ1(),xQ1(0){}
+c31
+AddItem
+iR1
+a,bool
+cA2,x12
+type){for
+iZ1
+c=0;c<cJ1
+eJ3;++c)if(cJ1[c].value
+xI
+a)){if(cA2!=cJ1[c].cA2){l11
+cU1
+case
+iI2:cJ1.erase(cJ1.begin()+c);xQ1
+cB2
+case
+iG2:case
+iH2:cW1}
+eE3
+n91;}
+Item
+pole;pole.value=a;pole.cA2=cA2;cJ1
+c52
+pole)i1
+Ok;}
+c31
+AddRelationship(yZ2
+a,yZ2
+b,int
+tY1,x12
+type){l11
+if(tY1==7)cU1
+lC
+iI2:if(tY1==7){xQ1
+cB2}
+lC
+iG2:case
+iH2:if(tY1==0)cW1
+xY3
+if(!(a.GetHash()<b.GetHash())){a.swap(b);tY1=Swap_Mask(tY1);}
+for
+iZ1
+c=0;c<tH
+eJ3;++c){if(tH[c].a
+xI
+a)&&tH[c].b
+xI
+b)){l11{int
+y33=xQ2|tY1;if(y33==7)cU1
+xQ2=y33;xY3
+case
+iG2:case
+iH2:{int
+y33=xQ2&tY1;if(y33==0)cW1
+xQ2=y33;xY3
+case
+iI2:{int
+newrel_or=xQ2|tY1;int
+xR2=xQ2&tY1;lQ2
+5&&xR2==0){xQ2=eD3
+i1
+n91;}
+lQ2
+7&&xR2==0){xQ1+=1;tH.erase(tH.begin()+c)i1
+n91;}
+lQ2
+7&&xR2==Eq_Mask){xQ2=Eq_Mask;xQ1
+cB2}
+yA1}
+eE3
+n91;}
+}
+t32
+comp;comp.a=a;comp.b=b;comp.relationship=tY1;tH
+c52
+comp)i1
+Ok;}
+}
+;nN1
+Value_t,x93
+CondType>bool
+ConstantFolding_LogicCommon(nP1
+CondType
+xF1,bool
+xS2){bool
+should_regenerate
+eW3
+ComparisonSet
+xF
+comp;x51{x93
+c8
+c31
+cY3=c8
+Ok;iT1&atree=xW
+a);e23
+atree
+nC){case
+cEqual
+lG
+Eq_Mask
+e12
+i51
+lG
+eD3
+e12
+cLess
+lG
+eB3
+e12
+cLessOrEq
+lG
+Le_Mask
+e12
+cGreater
+lG
+eC3
+e12
+cGreaterOrEq
+lG
+Ge_Mask
+e12
+cNot:cY3
+cV1
+l8
+0),true
+e12
+cNotNot:cY3
+cV1
+l8
+0),false,xF1);break;yF3
+if(xS2||IsLogicalValue(atree))cY3
+cV1,false,xF1);c73(cY3){ReplaceTreeWithZero:nU
+0)i1
+true;ReplaceTreeWithOne:nU
+1);nZ
+c8
+Ok:lC
+c8
+BecomeZero
+t7
+c8
+BecomeOne:iD
+c8
+n91:c61
+xY3}
+if(should_regenerate){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Before ConstantFolding_LogicCommon: "
+cR
+#endif
+if(xS2){tree.DelParams();}
+else{for
+l41{iT1&atree=xW
+a);if(IsLogicalValue(atree))iZ);}
+}
+for
+iZ1
+a=0;a<comp.cJ1
+eJ3;++a){if(comp.cJ1[a].cA2
+lA3
+cNot);r.c7
+r.lR2
+iP1!xS2
+lA3
+cNotNot);r.c7
+r.lR2
+else
+tree.c7}
+for
+iZ1
+a=0;a<comp.tH
+eJ3;++a
+lA3
+cNop);e23
+comp.tH[a
+eE){case
+c8
+eB3:r
+iH
+cLess);lC
+c8
+Eq_Mask:r
+iH
+cEqual);lC
+c8
+eC3:r
+iH
+cGreater);lC
+c8
+Le_Mask:r
+iH
+cLessOrEq);lC
+c8
+eD3:r
+iH
+i51);lC
+c8
+Ge_Mask:r
+iH
+cGreaterOrEq
+e02
+r
+c91
+comp.tH[a].a);r
+c91
+comp.tH[a].b);r.lR2
+if(comp.xQ1!=0)tree.yA
+e62
+comp.xQ1)));
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"After ConstantFolding_LogicCommon: "
+cR
+#endif
+lD2
+eE3
+t23
+yP1
+ConstantFolding_AndLogic(iM3(tree.GetOpcode()==cAnd||tree.GetOpcode()==cAbsAnd)i1
+nI
+iG2,true);}
+yP1
+ConstantFolding_OrLogic(iM3(tree.GetOpcode()==cOr||tree.GetOpcode()==cAbsOr)i1
+nI
+cond_or,true);}
+yP1
+ConstantFolding_AddLogicItems(iM3(tree.GetOpcode()==cAdd)i1
+nI
+iI2,false);}
+yP1
+ConstantFolding_MulLogicItems(iM3(tree.GetOpcode()==cMul)i1
+nI
+iH2,false);}
+}
+#include <vector>
+#include <map>
+#include <algorithm>
+l33{using
+l33
+FUNCTIONPARSERTYPES;using
+t5;e72
+CollectionSetBase{enum
+xR1{Ok,n91}
+;}
+yO1
+e72
+CollectionSet:public
+CollectionSetBase{e72
+c41{yZ2
+value
+tX
+xT2;bool
+e0;c41():value(),xT2(),e0(false){}
+c41
+iR1
+v,iT1&f):value(v),xT2(f),e0(false){}
+}
+;std::multimap<fphash_t,c41>iN;typedef
+x93
+std::multimap<fphash_t,c41>::y83
+xS1;CollectionSet():iN(){}
+xS1
+FindIdenticalValueTo
+iR1
+value){fphash_t
+hash=value.GetHash();for(xS1
+i=iN.xU2
+hash);i!=iN.cX1
+hash;++i){cD1
+xI
+i
+eC2.value
+y03
+i;eE3
+iN.end();}
+bool
+Found
+iS1
+xS1&b)yP
+b!=iN.end();}
+xR1
+AddCollectionTo
+iR1
+xT2,const
+xS1&into_which){c41&c=into_which
+eC2;if(c.e0)c.xT2
+cS
+xT2);else{yZ2
+add;add
+iH
+cAdd);add
+c91
+c.xT2);add
+cS
+xT2);c.xT2.swap(add);c.e0=true;eE3
+n91;}
+xR1
+x22
+iR1
+value,iT1&xT2){const
+fphash_t
+hash=value.GetHash();xS1
+i=iN.xU2
+hash);for(;i!=iN.cX1
+hash;++i){if(i
+eC2.value
+xI
+value
+y03
+AddCollectionTo(xT2,i);}
+iN.y43,std::make_pair(hash,c41(value,xT2)))i1
+Ok;}
+xR1
+x22
+iR1
+a)yP
+x22(a,nA1
+1)));}
+}
+yO1
+e72
+ConstantExponentCollection{typedef
+eK
+y63;typedef
+std::x71
+xV2;eO3
+xV2>data;ConstantExponentCollection():data(){}
+void
+MoveToSet_Unique
+iS1
+Value_t&eP1&eQ1){data
+c52
+std::x71(eP1()));data.back().second.swap(eQ1
+cN2
+MoveToSet_NonUnique
+iS1
+Value_t&eP1&eQ1){x93
+eO3
+xV2>::y83
+i=std::xU2
+data.iJ2
+data.end(),exponent,Compare1st());if(i!=data.cX1
+exponent){i
+eC2.y43
+eC2.end(),eQ1.iJ2
+eQ1.end());}
+else{data.y43,std::x71(exponent,eQ1));}
+}
+bool
+iA2{bool
+changed
+eW3
+std::sort(data.iJ2
+data.end(),Compare1st());redo:for
+iZ1
+a=0;a
+eR3
+a)l14
+exp_a=data[a
+eH3;lG3
+exp_a,e62
+1)))yA1
+for
+iZ1
+b=a+1;b
+eR3
+b)l14
+exp_b=data[b
+eH3
+iK2
+xW2=exp_b-exp_a;if(xW2>=fp_abs(exp_a))break
+iK2
+exp_diff_still_probable_integer=xW2*e62
+16);if(t42
+exp_diff_still_probable_integer)&&!(t42
+exp_b)&&!t42
+xW2))){y63&a_set=lS2;y63&b_set=data[b
+eI3;
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Before ConstantExponentCollection iteration:\n"
+;Dump(cV2);
+#endif
+if(isEvenInteger(exp_b)&&!isEvenInteger(xW2+exp_a)nQ
+tmp2;tmp2
+iH
+cMul);tmp2
+iF1
+b_set);tmp2
+iW1
+tX
+tmp;tmp
+iH
+cAbs);tmp
+c91
+tmp2);tmp
+iW1;b_set
+xF3
+1);b_set[0
+tQ3
+tmp);}
+a_set.insert(a_set.end(),b_set.iJ2
+b_set.end());y63
+b_copy=b_set;data.erase(data.begin()+b);MoveToSet_NonUnique(xW2,b_copy);yS1
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"After ConstantExponentCollection iteration:\n"
+;Dump(cV2);
+#endif
+cJ}
+}
+eE3
+changed;}
+#ifdef DEBUG_SUBSTITUTIONS
+void
+Dump(std::ostream&out){for
+iZ1
+a=0;a
+eR3
+a){out.precision(12);out<<data[a
+eH3<<": "
+;e11
+lS2
+eJ3;++b){if(b>0)out<<'*'
+iL2
+lS2[b],out);}
+out<<std::endl;}
+}
+#endif
+}
+yO1
+static
+yZ2
+x81
+yZ2&value,bool&xK
+yY3
+value
+nC){case
+cPow:{yZ2
+eD2
+value
+l8
+1);value.y91
+i1
+exponent;}
+case
+cRSqrt:value.y91;xK=true
+i1
+nA1-0.5))t83
+cInv:value.y91;xK=true
+i1
+nA1-1));yF3
+xY3
+return
+nA1
+1));}
+cB1
+void
+eR1
+eS1&mul,const
+nP1
+iT1&xT2,bool&c51
+bool&xK){for
+iZ1
+a=0;a<yC++a
+nQ
+value(xW
+a))tX
+exponent(x81
+value,xK));if(!xT2
+tD1||xT2
+x41!=e62
+1.0)nQ
+cY1;cY1
+iH
+cMul);cY1
+cS
+tU2
+cY1
+cS
+xT2);cY1
+iW1
+eX3.swap(cY1);}
+#if 0 /* FIXME: This does not work */
+cD1
+nC==cMul){if(1){bool
+exponent_is_even=exponent
+tD1&&isEvenInteger(exponent
+x41);e11
+value.eZ3{bool
+tmp=false
+tX
+val(value
+l8
+b))tX
+exp(x81
+val,tmp));if(exponent_is_even||(exp
+tD1&&isEvenInteger(exp
+x41))nQ
+cY1;cY1
+iH
+cMul);cY1
+cS
+tU2
+cY1
+c91
+exp);cY1.ConstantFolding();if(!cY1
+tD1||!isEvenInteger(cY1
+x41)){goto
+cannot_adopt_mul;}
+}
+}
+}
+eR1
+mul,value,exponent,c51
+xK);}
+else
+cannot_adopt_mul:
+#endif
+{if(mul.x22(value,exponent)==CollectionSetBase::n91)c61}
+}
+}
+yP1
+ConstantFolding_MulGrouping(eR{bool
+xK
+eW3
+bool
+should_regenerate
+eW3
+eS1
+mul;eR1
+mul
+cU3,nA1
+1)),c51
+xK);typedef
+std::pair<yZ2,eK>eT1;typedef
+std::multimap<fphash_t,eT1>cK1;cK1
+iJ;for(x93
+eS1::xS1
+j=mul.iN.y73
+j!=mul.iN.end();++j
+nQ&value=j
+eC2.value
+tX&eD2
+j
+eC2.xT2;if(j
+eC2.e0)exponent
+iW1;const
+fphash_t
+eU1=exponent.GetHash();x93
+cK1::y83
+i=iJ.xU2
+eU1);for(;i!=iJ.cX1
+eU1;++i)if(i
+eC2.first
+xI
+exponent)){if(!exponent
+tD1||!cZ1
+x41,e62
+1)))c61
+i
+eC2.second
+c52
+value);goto
+skip_b;}
+iJ.y43,std::make_pair(eU1,std::make_pair(exponent,eK
+iZ1(1),value))));skip_b:;}
+#ifdef FP_MUL_COMBINE_EXPONENTS
+ConstantExponentCollection
+xF
+e01;for(x93
+cK1::y83
+j,i=iJ.y73
+i!=iJ.end();i=j){j=i;++j;eT1&list=i
+eC2;x32.lV1
+eD2
+list.first
+x41;if(!(exponent==xG1)e01.MoveToSet_Unique(exponent,list
+iB2
+iJ.erase(i);}
+}
+if(e01.iA2)c61
+#endif
+if(should_regenerate
+nQ
+before=tree;before.lD1
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Before ConstantFolding_MulGrouping: "
+iL2
+before
+lE2"\n"
+;
+#endif
+tree.DelParams();for(x93
+cK1::y83
+i=iJ.y73
+i!=iJ.end();++i){eT1&list=i
+eC2;
+#ifndef FP_MUL_COMBINE_EXPONENTS
+x32.lV1
+eD2
+list.first
+x41;if(exponent==xG1
+yA1
+if(cZ1
+nH2
+tree.AddParamsMove(list
+iB2
+yA1}
+}
+#endif
+yZ2
+mul;mul
+iH
+cMul);mul
+iF1
+list
+iB2
+mul
+iW1;if(xK&&list.first
+tD1){x32
+x41==e62
+1)/e62
+3)nQ
+cbrt;cbrt
+iH
+cCbrt);cbrt.e8
+cbrt.lT2
+cbrt);yA1
+cV
+0.5)nQ
+sqrt;sqrt
+iH
+cSqrt);sqrt.e8
+sqrt.lT2
+sqrt);yA1
+cV-0.5)nQ
+rsqrt;rsqrt
+iH
+cRSqrt);rsqrt.e8
+rsqrt.lT2
+rsqrt);yA1
+cV-1)nQ
+inv;inv
+iH
+cInv);inv.e8
+inv.lT2
+inv);yA1}
+}
+yZ2
+pow;pow
+iH
+cPow);pow.e8
+pow
+c91
+list.first);pow.lT2
+pow);}
+#ifdef FP_MUL_COMBINE_EXPONENTS
+iJ.clear(iY1
+0;a<iB
+eJ3;++a)l14
+eD2
+iB[a
+eH3;if(cZ1
+nH2
+tree.AddParamsMove(iB[a]iB2
+yA1}
+yZ2
+mul;mul
+iH
+cMul);mul
+iF1
+iB[a]iB2
+mul
+iW1
+tX
+pow;pow
+iH
+cPow);pow.e8
+pow.yA
+exponent));pow.lT2
+pow);}
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"After ConstantFolding_MulGrouping: "
+cR
+#endif
+return!tree
+xI
+before);eE3
+t23
+yP1
+ConstantFolding_AddGrouping(eR{bool
+should_regenerate
+eW3
+eS1
+add;x51{if(xW
+a)nC==cMul)yA1
+if(add.x22(xW
+a))==CollectionSetBase::n91)c61}
+cY2
+lU2
+l51);size_t
+tD=0;x51{iT1&mulgroup=xW
+a);if
+eH2
+nC==cMul){e11
+cA1
+eZ3{if
+eH2
+l8
+b)tD1)yA1
+x93
+eS1::xS1
+c=add.FindIdenticalValueTo
+eH2
+l8
+b));if(add.Found(c)nQ
+tmp
+eH2
+y8
+CloneTag());tmp.i91
+b);tmp
+iW1;add.AddCollectionTo(tmp,c);c61
+goto
+done_a;}
+}
+lU2[a]=true;tD+=1;done_a:;}
+}
+if(tD>0){if(tD>1){eO3
+std::pair<yZ2,size_t> >nY;std::multimap<fphash_t,size_t>eV1;bool
+lB3
+eW3
+x51
+if(lU2[a]){e11
+xW
+a).eZ3{iT1&p=xW
+a)l8
+b);const
+fphash_t
+p_hash=p.GetHash();for(std::multimap<fphash_t,size_t>::const_iterator
+i=eV1.xU2
+p_hash);i!=eV1.cX1
+p_hash;++i){if(nY[i
+eC2
+eH3
+xI
+p)){nY[i
+eC2
+eI3+=1;lB3=true;goto
+found_mulgroup_item_dup;}
+}
+nY
+c52
+std::make_pair(p,size_t(1)));eV1.insert(std::make_pair(p_hash,nY
+eJ3-1));found_mulgroup_item_dup:;}
+}
+if(lB3
+nQ
+eE2;{size_t
+max=0
+eK3
+p=0;p<nY
+eJ3;++p)if(nY[p
+eI3<=1)nY[p
+eI3=0;else{nY[p
+eI3*=nY[p
+eH3
+nP2;if(nY[p
+eI3>max){eE2=nY[p
+eH3;max=nY[p
+eI3;}
+}
+}
+yZ2
+group_add;group_add
+iH
+cAdd);
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Duplicate across some trees: "
+iL2
+eE2
+lE2" in "
+cR
+#endif
+x51
+if(lU2[a])e11
+xW
+a).eZ3
+if(eE2
+xI
+xW
+a)l8
+b))nQ
+tmp(xW
+a)y8
+CloneTag());tmp.i91
+b);tmp
+iW1;group_add
+c91
+tmp);lU2[a]eW3
+xY3
+group_add
+iW1
+tX
+group;group
+iH
+cMul);group
+c91
+eE2);group
+c91
+group_add);group
+iW1;add.x22(group);c61}
+}
+x51
+if(lU2[a]){if(add.x22(xW
+a))==CollectionSetBase::n91)c61}
+}
+if(should_regenerate){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Before ConstantFolding_AddGrouping: "
+cR
+#endif
+tree.DelParams();for(x93
+eS1::xS1
+j=add.iN.y73
+j!=add.iN.end();++j
+nQ&value=j
+eC2.value
+tX&coeff=j
+eC2.xT2;if(j
+eC2.e0)coeff
+iW1;if(coeff
+tD1){lG3
+coeff
+x41,xG1)yA1
+lG3
+coeff
+x41
+nH2
+tree
+c91
+value);yA1}
+}
+yZ2
+mul;mul
+iH
+cMul);mul
+c91
+value);mul
+c91
+coeff);mul.e33
+yB
+e8}
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"After ConstantFolding_AddGrouping: "
+cR
+#endif
+lD2
+eE3
+t23}
+l33{using
+l33
+FUNCTIONPARSERTYPES;using
+t5
+yO1
+bool
+ConstantFolding_IfOperations(iM3(tree.GetOpcode()==cIf||tree.GetOpcode()==cAbsIf);for(;;){if(c93==cNot){tD2
+cIf);xW
+0).eF2
+0)c43
+xW
+1).swap(xW
+2));}
+iP1
+xW
+0)cQ1{tD2
+t03;xW
+0).eF2
+0)c43
+xW
+1).swap(xW
+2));}
+else
+yV3
+lY1
+0),t72==t03
+tN1
+tree.eF2
+1));nZ
+l03
+tree.eF2
+2));nZ
+lZ1
+if(c93==cIf||c93==cAbsIf
+nQ
+cond=xW
+0)tX
+lC3;lC3
+tE2==cIf?cNotNot:cAbsNotNot);lC3
+xX2
+1));ConstantFolding(lC3)tX
+lD3;lD3
+tE2==cIf?cNotNot:cAbsNotNot);lD3
+xX2
+2));ConstantFolding(lD3);if(lC3
+tD1||lD3
+tD1
+nQ
+eT;eT
+tE2);eT
+xX2
+1));eT
+tX3
+eT.nJ
+2));eT
+iW1
+tX
+else_tree
+tS1
+tE2)tS1
+xX2
+2))tS1.nJ
+1))tS1.nJ
+2))tS1
+cY
+cond
+nC
+xT1
+0,cond
+l8
+0)yB
+nB1
+1,eT
+yB
+nB1
+2,else_tree
+yQ2}
+if(xW
+1)nC==xW
+2)nC&&(xW
+1)nC==cIf||xW
+1)nC==t03
+nQ&x53=xW
+1)tX&leaf2=xW
+2);if(x53
+l8
+0)nN2
+0))&&x61
+1))||x53
+l8
+2)nN2
+2)))nQ
+eT;eT
+nO2;eT
+tY3
+eT
+xY2
+1));eT
+xZ2
+1));eT
+iW1
+tX
+else_tree
+tS1
+nO2
+tS1.nJ
+0))tS1
+xY2
+2))tS1
+xZ2
+2))tS1
+cY
+x53
+nC
+xT1
+0
+cB3
+0)yB
+nB1
+1,eT
+yB
+nB1
+2,else_tree
+yQ2
+if
+x61
+1))&&x53
+l8
+2)nN2
+2))nQ
+eU;eU
+nO2;eU
+c91
+xW
+0));eU
+xY2
+0));eU
+xZ2
+0));eU
+cY
+x53
+nC
+yB
+nB1
+0,eU
+xT1
+2
+cB3
+2)xT1
+1
+cB3
+1)yQ2
+if
+x61
+2))&&x53
+l8
+2)nN2
+1))nQ
+eI2;eI2
+iH
+leaf2
+nC==cIf?cNot:cC3);eI2
+xZ2
+0));eI2
+iW1
+tX
+eU;eU
+nO2;eU
+c91
+xW
+0));eU
+xY2
+0));eU
+c91
+eI2);eU
+cY
+x53
+nC
+yB
+nB1
+0,eU
+xT1
+2
+cB3
+2)xT1
+1
+cB3
+1)yQ2}
+yZ2&xV=xW
+1)tX&y4=xW
+2);if(xV
+xI
+y4)){tree.eF2
+1)yQ2
+const
+OPCODE
+op1=xV
+nC;const
+OPCODE
+op2=y4
+nC;y93
+op2){if(xV.e91
+1
+nQ
+lO
+0));y02
+0))c71()n4
+if(xV.e91
+2&&y4.e91
+2){if(xV
+l8
+0)xI
+y4
+l8
+0))nQ
+param0=xV
+l8
+0)tX
+lO
+1));y02
+1))c71
+t8
+param0)n4
+if(xV
+l8
+1)xI
+y4
+l8
+1))nQ
+param1=xV
+l8
+1)tX
+lO
+0));y02
+0))c71
+t8
+n81
+c81
+param1
+yQ2}
+y93
+yA3
+cMul
+lV2
+cAnd
+lV2
+cOr
+lV2
+cAbsAnd
+lV2
+cAbsOr
+lV2
+cMin
+lV2
+cMax){eK
+lE3;c2{for
+iZ1
+b=y4.l91
+b-->0;){if(xV
+lF3
+y4
+l8
+b))){if(lE3
+eU3){xV.t13
+lD1}
+lE3
+c52
+xV
+n93
+y4.i91
+b);xV.i91
+a
+e02}
+}
+if(!lE3
+eU3){xV
+iW1;y4
+iW1
+l7
+op1
+yB
+SetParamsMove(lE3)n4}
+}
+y93
+yA3
+cMul||(op1==cAnd&&IsLogicalValue(y4))||(op1==cOr&&IsLogicalValue(y4))){c2
+if(xV
+lF3
+y4)){xV.lD1
+xV.i91
+a);xV
+iW1
+tX
+cL1=y4;y4=tE
+op1==yA3
+cOr
+t52
+op1
+c81
+cL1)n4}
+if((op1==cAnd
+lV2
+cOr)&&op2==cNotNot
+nQ&lH3=y4
+l8
+0);c2
+if(xV
+lF3
+lH3)){xV.lD1
+xV.i91
+a);xV
+iW1
+tX
+cL1=lH3;y4=tE
+op1==cOr
+t52
+op1
+c81
+cL1)n4}
+if(op2==cAdd||op2==cMul||(op2==cAnd&&IsLogicalValue(xV))||(op2==cOr&&IsLogicalValue(xV))){for
+iZ1
+a=y4
+iY
+y4
+lF3
+xV)){y4.t13
+i91
+a);y4
+iW1
+tX
+cM1=xV;xV=tE
+op2==cAdd||op2==cOr
+t52
+op2
+c81
+cM1)n4}
+if((op2==cAnd||op2==cOr)&&op1==cNotNot
+nQ&lI3=xV
+l8
+0
+iY1
+y4
+iY
+y4
+lF3
+lI3)){y4.t13
+i91
+a);y4
+iW1
+tX
+cM1=lI3;xV=tE
+op2==cOr
+t52
+op2
+c81
+cM1)n4
+eE3
+t23}
+#include <limits>
+l33{using
+l33
+FUNCTIONPARSERTYPES;using
+t5
+yO1
+int
+maxFPExponent()yP
+std::numeric_limits
+xF::max_exponent;}
+yP1
+x91
+Value_t
+base,Value_t
+exponent){if(base<xG1
+lD2
+lG3
+base,xG1||lJ3
+base,e62
+1))cQ
+return
+exponent>=e62
+maxFPExponent
+xF())/fp_log2(base);}
+yP1
+ConstantFolding_PowOperations(iM3(tree.GetOpcode()==cPow);nP&&xW
+1).lV1
+const_value=t33
+lR,xW
+i8);nU
+const_value)i1
+t23
+if(eI1
+lJ3
+xW
+i8
+nH2
+tree.eF2
+0)yQ2
+nP&&lJ3
+lR
+nH2
+nU
+1)i1
+t23
+nP&&xW
+1)nC==cMul){bool
+y12=false
+iK2
+lW2=lR
+tX
+mulgroup=xW
+1
+iY1
+mulgroup
+iY
+mulgroup
+l8
+a).lV1
+imm=mulgroup
+l8
+a)x41;{if(x91
+lW2,imm))break
+iK2
+lX2=t33
+lW2,imm);lG3
+lX2,xG1)break;if(!y12){y12=true;cA1
+lD1}
+lW2=lX2;cA1
+i91
+a
+e02}
+if(y12){cA1
+e33);
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Before pow-mul change: "
+cR
+#endif
+xW
+0).Become(eA1
+lW2));xW
+1).Become
+eH2);
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"After pow-mul change: "
+cR
+#endif
+}
+}
+if(eI1
+c93==cMul)l14
+lY2=xW
+i8
+iK2
+y22=1.0;bool
+y12=false
+tX&mulgroup=xW
+0
+iY1
+mulgroup
+iY
+mulgroup
+l8
+a).lV1
+imm=mulgroup
+l8
+a)x41;{if(x91
+imm,lY2))break
+iK2
+eW1=t33
+imm,lY2);lG3
+eW1,xG1)break;if(!y12){y12=true;cA1
+lD1}
+y22*=eW1;cA1
+i91
+a
+e02}
+if(y12){cA1
+e33)tX
+cZ3;cZ3
+iH
+cPow);cZ3
+iF1
+tree.lJ2));cZ3.yC2
+yB
+eL3
+cMul
+c81
+cZ3
+yB
+AddParam(eA1
+y22)yQ2}
+if(xW
+0)i12
+eI1
+xW
+0)l8
+1).lV1
+a=xW
+0)l8
+i8
+iK2
+b=xW
+i8
+iK2
+c=a*b;if(isEvenInteger(a)&&!isEvenInteger(c)nQ
+lK3;lK3
+iH
+cAbs);lK3.nJ
+0)c43
+lK3.e33
+yB
+nB1
+0,lK3);}
+else
+tree.SetParam(0,xW
+0)l8
+0)xT1
+1,eA1
+c));eE3
+t23}
+l33{using
+l33
+FUNCTIONPARSERTYPES;using
+t5;e72
+l5{enum
+eJ2{MakeFalse=0,MakeTrue=1,t62=2,lN3=3,MakeNotNotP0=4,MakeNotNotP1=5,MakeNotP0=6,MakeNotP1=7,xJ=8}
+;enum
+lZ2{Never=0,Eq0=1,Eq1=2,yB3=3,yC3=4}
+;eJ2
+if_identical;eJ2
+n02
+4];e72{eJ2
+what:4;lZ2
+when:4;}
+l02,l12,l22,l32
+yO1
+eJ2
+Analyze
+iR1
+xC3
+eX1)const{if(a
+xI
+b
+y03
+if_identical;yD3
+tY
+a);yD3
+p1=CalculateResultBoundaries(b);if(p0
+e61&&p1
+yI){if(p0
+nL3<p1
+yM&&n02
+0]iC
+0];if(p0
+nL3<=p1
+yM&&n02
+1]iC
+1];}
+if
+cN3
+p1
+e61){if(p0
+yM>p1
+nL3&&n02
+2]iC
+2];if(p0
+yM>=p1
+nL3&&n02
+3]iC
+3];}
+if(IsLogicalValue(a)){if(l02
+nN3
+l02.when,p1
+y03
+l02.what;if(l22
+nN3
+l22.when,p1
+y03
+l22.what;}
+if(IsLogicalValue(b)){if(l12
+nN3
+l12.when,p0
+y03
+l12.what;if(l32
+nN3
+l32.when,p0
+y03
+l32.what;eE3
+xJ;}
+cB1
+bool
+TestCase(lZ2
+when,const
+yD3&p){if(!p
+yI||!p
+e61
+cQ
+e23
+when){case
+Eq0:nO3==e62
+0.0)t43==p
+yM
+t83
+Eq1:nO3==e62
+1.0)t43==p
+nL3
+t83
+yB3:nO3>xH1
+t43<=e62
+1)t83
+yC3:nO3>=xH1
+l61
+1);yF3;eE3
+t23}
+;l33
+RangeComparisonsData{static
+const
+l5
+Data[6]={{l5
+lL3
+i3
+xJ,l5::i3
+xJ
+lF1
+Eq1
+nT1
+Eq1
+nU1
+Eq0
+nV1
+Eq0}
+}
+,{l5::x42
+lM3
+xJ,l5
+lM3
+xJ
+lF1
+Eq0
+nT1
+Eq0
+nU1
+Eq1
+nV1
+Eq1}
+}
+,{l5::x42
+lM3
+t62,l5::i3
+MakeFalse
+nU1
+yB3
+nT1
+yC3
+yY,{l5
+lL3
+xJ,l5
+lM3
+i3
+lN3
+nU1
+yC3
+nT1
+yB3
+yY,{l5::x42::i3
+i3
+MakeTrue,l5::t62
+lF1
+yC3
+nV1
+yB3
+yY,{l5
+lL3
+i3
+lN3,l5::xJ,l5
+nC1
+lF1
+yB3
+nV1
+yC3
+yY}
+;}
+yP1
+ConstantFolding_Comparison(eR{using
+l33
+RangeComparisonsData;assert(tree.GetOpcode()>=cEqual&&tree.GetOpcode()<=cGreaterOrEq);e23
+Data[t72-cEqual].Analyze(xW
+0),xW
+1))){case
+l5::MakeFalse:nU
+0);nZ
+l5
+nC1:nU
+1
+nY3
+lN3:tD2
+cEqual
+nY3
+t62:tD2
+i51
+nY3
+MakeNotNotP0:tD2
+cNotNot
+yB
+i91
+1
+nY3
+MakeNotNotP1:tD2
+cNotNot
+yB
+i91
+0
+nY3
+MakeNotP0:tD2
+cNot
+yB
+i91
+1
+nY3
+MakeNotP1:tD2
+cNot
+yB
+i91
+0
+nY3
+xJ:;}
+if(xW
+1)tD1)e23
+c93){case
+cAsin:lM
+fp_sin(xW
+iP2
+cAcos:lM
+fp_cos(xW
+i8))yB
+eL3
+t72==cLess?cGreater:t72==cLessOrEq?cGreaterOrEq:t72==cGreater?cLess:t72==cGreaterOrEq?cLessOrEq:t72);nZ
+cAtan:lM
+fp_tan(xW
+iP2
+cLog:lM
+fp_exp(xW
+iP2
+cSinh:lM
+fp_asinh(xW
+iP2
+cTanh:if(fp_less(fp_abs(xW
+i8)nH2
+lM
+fp_atanh(xW
+i8))yQ2
+break;yF3
+xY3
+return
+t23}
+#include <list>
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;l33{
+#ifdef DEBUG_SUBSTITUTIONS
+yE
+double
+d){union{double
+d;uint_least64_t
+h
+c42
+d=d;lR1
+h
+nX1
+#ifdef FP_SUPPORT_FLOAT_TYPE
+yE
+float
+f){union{float
+f;uint_least32_t
+h
+c42
+f=f;lR1
+h
+nX1
+#endif
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+yE
+long
+double
+ld){union{long
+double
+ld;e72{uint_least64_t
+a;x83
+short
+b;}
+s
+c42
+ld=ld;lR1
+s.b<<data.s.a
+nX1
+#endif
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+yE
+long
+ld){o<<"("
+<<std::hex<<ld
+nX1
+#endif
+#endif
+}
+t5{lN
+nE)){}
+lN
+const
+Value_t&i
+y8
+xD3
+nE
+i
+x52
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+lN
+Value_t&&i
+y8
+xD3
+nE
+tF2
+i)x52
+#endif
+lN
+x83
+v
+y8
+VarTag
+nE
+iU2,v
+x52
+lN
+iU1
+o
+y8
+OpcodeTag
+nE
+o
+x52
+lN
+iU1
+o,x83
+f
+y8
+FuncOpcodeTag
+nE
+o,f
+x52
+lN
+const
+eX1
+y8
+CloneTag
+nE*b.data)){}
+tK1
+yZ2::~c02(){}
+lB
+ReplaceWithImmed(tX1{
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Replacing "
+iL2*this);if(IsImmed())OutFloatHex(cV2,GetImmed()lE2" with const value "
+<<i;OutFloatHex(cV2,i
+lE2"\n"
+;
+#endif
+data=new
+xK2
+xF(i);}
+tK1
+e72
+ParamComparer{iD2()iR1
+xC3
+eX1)const{if(a
+nP2!=b
+nP2)return
+a
+nP2<b
+nP2
+i1
+a.GetHash()<b.GetHash();}
+}
+;xL1
+xK2
+xF::Sort(yY3
+Opcode){case
+cAdd:case
+cMul:case
+cMin:case
+cMax:case
+cAnd:case
+cAbsAnd:case
+cOr:case
+cAbsOr:case
+cHypot:case
+cEqual:case
+i51:std::sort(iR2
+iJ2
+iR2
+end(),ParamComparer
+xF());lC
+cLess
+lY
+cGreater;}
+lC
+cLessOrEq
+lY
+cGreaterOrEq;}
+lC
+cGreater
+lY
+cLess;}
+lC
+cGreaterOrEq
+lY
+cLessOrEq;}
+break;yF3
+xY3}
+lB
+AddParam
+iR1
+param){y1
+c52
+param);}
+lB
+AddParamMove(yZ2&param){y1
+c52
+yZ2());y1.back().swap(param);}
+lB
+SetParam
+iZ1
+which,const
+eX1)nW1
+which
+iQ2
+y1[which]=b;}
+lB
+nB1
+size_t
+which,eX1)nW1
+which
+iQ2
+y1[which
+tQ3
+b);}
+lB
+AddParams
+iS1
+nK){y1.insert(y1.end(),n12.iJ2
+n12.end());}
+lB
+AddParamsMove(nK){size_t
+endpos=y1
+eJ3,added=n12
+eJ3;y1
+xF3
+endpos+added,yZ2())eK3
+p=0;p<added;++p)y1[endpos+p
+tQ3
+n12[p]);}
+lB
+AddParamsMove(nK,size_t
+n22)nW1
+n22
+iQ2
+i91
+n22);AddParamsMove(tO1}
+lB
+SetParams
+iS1
+nK){eK
+tmp(tO1
+y1.swap(tmp);}
+lB
+SetParamsMove(nK){y1.swap(tO1
+n12.clear();}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+lB
+SetParams(eK&&n12){SetParamsMove(tO1}
+#endif
+lB
+i91
+size_t
+index){eK&Params=y1;
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+iR2
+erase(iR2
+begin()+index);
+#else
+t63
+index].data=0
+eK3
+p=index;p+1<iS2;++p)t63
+p].data.UnsafeSetP(&*t63
+p+1
+iQ2
+t63
+iS2-1].data.UnsafeSetP(0);iR2
+resize(iS2-1);
+#endif
+}
+lB
+DelParams(){y1.clear();}
+yP1
+yZ2::IsIdenticalTo
+iS1
+eX1)const{if(&*data==&*b.data)return
+true
+i1
+data->IsIdenticalTo(*b.data);}
+yP1
+xK2
+xF::IsIdenticalTo
+iS1
+xK2
+xF&b)const{if(Hash!=b.Hash
+cQ
+if(Opcode!=b.Opcode
+cQ
+e23
+Opcode){case
+cImmed:return
+lJ3
+Value,b.Value)t83
+iU2:return
+lL2==b.lK2
+case
+cFCall:case
+cPCall:if(lL2!=b.lL2
+cQ
+break;yF3
+xY3
+if(iS2!=b.iS2
+cQ
+for
+iZ1
+a=0;a<iS2;++a){if(!iT2
+xI
+b.iT2)cQ}
+lD2}
+lB
+Become
+iS1
+eX1){if(&b!=this&&&*data!=&*b.data){DataP
+tmp=b.data;lD1
+data.swap(tmp);}
+}
+lB
+CopyOnWrite(){if(GetRefCount()>1)data=new
+xK2
+xF(*data);}
+tK1
+yZ2
+yZ2::GetUniqueRef(){if(GetRefCount()>1)return
+yZ2(*this,CloneTag())i1*this;}
+i4):yS
+cNop
+iR3),n8
+i4
+const
+xK2&b):yS
+b.Opcode
+iR3
+b.Value),lL2(b.cO1,t53
+b.Params),Hash(b.Hash),Depth(b.Depth
+eB1
+b.lM2){}
+i4
+tX1:yS
+cImmed
+iR3
+i),n8
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+i4
+xK2
+xF&&b):yS
+b.Opcode
+iR3
+tF2
+b.Value)),lL2(b.cO1,t53
+tF2
+b.Params)),Hash(b.Hash),Depth(b.Depth
+eB1
+b.lM2){}
+i4
+Value_t&&i):yS
+cImmed
+iR3
+tF2
+i)),n8
+#endif
+i4
+iU1
+o):yS
+o
+iR3),n8
+i4
+iU1
+o,x83
+f):yS
+o
+iR3),lL2(f),t53),Hash(),Depth(1
+eB1
+0){}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <sstream>
+#include <string>
+#include <map>
+#include <set>
+#include <iostream>
+using
+l33
+FUNCTIONPARSERTYPES;
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+l33{xL1
+tZ1
+nO,std
+c9&done,std::ostream&o){x51
+tZ1
+xW
+a),done,o);std::ostringstream
+buf
+iL2
+tree,buf);done[nJ2].insert(buf.str());}
+}
+#endif
+t5{
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+xL1
+DumpHashes(cE){std
+c9
+done;tZ1
+tree,done,o);for(std
+c9::const_iterator
+i=done.y73
+i!=done.end();++i){const
+std::set<eM3>&flist=i
+eC2;if(flist
+eJ3!=1)o<<"ERROR - HASH COLLISION?\n"
+;for(std::set<eM3>::const_iterator
+j=flist.y73
+j!=flist.end();++j){o<<'['<<std::hex<<i->first.hash1<<','<<i->first.hash2<<']'<<std::dec;o<<": "
+<<*j<<"\n"
+;}
+}
+}
+xL1
+DumpTree(cE){e32
+iF3;e23
+t72){case
+cImmed:o<<tree
+x41
+t73
+iU2:o<<"Var"
+<<(tree.GetVar()-iU2)t73
+cAdd:iF3"+"
+;lC
+cMul:iF3"*"
+;lC
+cAnd:iF3"&"
+;lC
+cOr:iF3"|"
+;lC
+cPow:iF3"^"
+;break;yF3
+iF3;o<<FP_GetOpcodeName(t72);cZ2
+cFCall||t72==cPCall)o<<':'<<tree.GetFuncNo();}
+o<<'(';if
+l51<=1&&sep2[1])o<<(sep2+1)<<' ';x51{if(a>0)o<<' '
+iL2
+xW
+a),o);if(a+1<tree.GetParamCount())o<<sep2;}
+o<<')';}
+xL1
+DumpTreeWithIndent(cE,const
+eM3&indent){o<<'['<<std::hex<<(void*)(&tree.lJ2))<<std::dec<<','<<tree.GetRefCount()<<']';o<<indent<<'_';e23
+t72){case
+cImmed:o<<"cImmed "
+<<tree
+x41;o<<'\n'
+t73
+iU2:o<<"VarBegin "
+<<(tree.GetVar()-iU2);o<<'\n'
+i1;yF3
+o<<FP_GetOpcodeName(t72);cZ2
+cFCall||t72==cPCall)o<<':'<<tree.GetFuncNo();o<<'\n';}
+x51{eM3
+ind=indent
+eK3
+p=0;p<ind
+eJ3;p+=2)if(ind[p]=='\\')ind[p]=' ';ind+=(a+1<tree.GetParamCount())?" |"
+:" \\"
+;DumpTreeWithIndent(xW
+a),o,ind);}
+o<<std::flush;}
+#endif
+}
+#endif
+using
+l33
+lA1;using
+l33
+FUNCTIONPARSERTYPES;
+#include <cctype>
+l33
+lA1{x83
+ParamSpec_GetDepCode
+iS1
+eA2&b
+yY3
+b.first){case
+ParamHolder:{cM*s=(cM*)b.second
+i1
+s->depcode;}
+case
+SubFunction:{cN*s=(cN*)b.second
+i1
+s->depcode;}
+yF3
+xY3
+return
+0;}
+xL1
+DumpParam
+iS1
+eA2&yA2
+std::ostream&o){static
+const
+char
+ParamHolderNames[][2]={"%"
+,"&"
+,"x"
+,"y"
+,"z"
+,"a"
+,"b"
+,"c"
+}
+;x83
+y32
+0;e23
+lX3.first){case
+NumConstant:{const
+ParamSpec_NumConstant
+xF&param=*iS1
+ParamSpec_NumConstant
+xF*tF1;using
+l33
+FUNCTIONPARSERTYPES;o.precision(12);o<<param.constvalue;xY3
+case
+ParamHolder:{cM&yU3
+cM*tF1;o<<ParamHolderNames[param.index];y32
+param.constraints;xY3
+case
+SubFunction:{cN&yU3
+cN*tF1;y32
+param.constraints;yF
+GroupFunction){if
+yZ3
+lG1==cNeg){o<<"-"
+;n2}
+iP1
+param.lG1==cInv){o<<"/"
+;n2}
+else{eM3
+opcode=FP_GetOpcodeName((iU1)param.lG1).substr(1
+iY1
+0;a<opcode
+eJ3;++a)opcode[a]=(char)std::toupper(opcode[a]);o<<opcode<<"( "
+;n2
+o<<" )"
+;}
+}
+else{o<<'('<<FP_GetOpcodeName((iU1)param.lG1)<<' ';yF
+PositionalParams)o<<'[';yF
+SelectedParams)o<<'{';n2
+if
+yZ3
+data.n1!=0)o<<" <"
+<<iH3.n1<<'>';yF
+PositionalParams)o<<"]"
+;yF
+SelectedParams)o<<"}"
+;o<<')';}
+xY3
+c73(ImmedConstraint_Value(constraints&ValueMask)){case
+ValueMask:lC
+Value_AnyNum:lC
+x62:o<<"@E"
+;lC
+Value_OddInt:o<<"@O"
+;lC
+i11:o<<"@I"
+;lC
+Value_NonInteger:o<<"@F"
+;lC
+eY1:o<<"@L"
+;yV3
+ImmedConstraint_Sign(constraints&SignMask)){case
+SignMask:lC
+Sign_AnySign:lC
+nD1:o<<"@P"
+;lC
+eZ1:o<<"@N"
+;yV3
+ImmedConstraint_Oneness(constraints&OnenessMask)){case
+OnenessMask:lC
+Oneness_Any:lC
+Oneness_One:o<<"@1"
+;lC
+Oneness_NotOne:o<<"@M"
+;yV3
+ImmedConstraint_Constness(constraints&ConstnessMask)){case
+ConstnessMask:lC
+i01:if(lX3.first==ParamHolder){cM&yU3
+cM*tF1;if
+yZ3
+index<2)xY3
+o<<"@C"
+;lC
+Constness_NotConst:o<<"@V"
+;lC
+Oneness_Any:xY3}
+xL1
+DumpParams
+lT1
+paramlist,x83
+count,std::ostream&o){for
+lT1
+a=0;a<count;++a){if(a>0)o<<' ';const
+eA2&param=ParamSpec_Extract
+xF(paramlist,a);DumpParam
+xF(param,o);x83
+depcode=ParamSpec_GetDepCode(param);if(depcode!=0)o<<"@D"
+<<depcode;}
+}
+}
+#include <algorithm>
+using
+l33
+lA1;using
+l33
+FUNCTIONPARSERTYPES;l33{cM
+plist_p[37]={{2,0,0x0}
+nT
+0,0x4}
+nT
+nD1,0x0}
+nT
+eZ1|Constness_NotConst,0x0}
+nT
+Sign_NoIdea,0x0}
+nT
+eY1,0x0}
+,{3,Sign_NoIdea,0x0}
+,{3,0,0x0}
+,{3,eY1,0x0}
+,{3,0,0x8}
+,{3,Value_OddInt,0x0}
+,{3,Value_NonInteger,0x0}
+,{3,x62,0x0}
+,{3,nD1,0x0}
+,{0,eZ1|lV{0,lV{0,nD1|lV{0,x62|lV{0,i01,0x1}
+,{0,i11|nD1|lV{0,i21
+i01,0x1}
+,{0,i21
+lV{0,Oneness_One|lV{0,eY1|lV{1,lV{1,x62|lV{1,i21
+lV{1,i11|lV{1,nD1|lV{1,eZ1|lV{6,0,0x0}
+,{4,0,0x0}
+,{4,i11,0x0}
+,{4,lV{4,0,0x16}
+,{5,0,0x0}
+,{5,lV}
+yO1
+e72
+plist_n_container{static
+const
+ParamSpec_NumConstant
+xF
+plist_n[20];}
+yO1
+const
+ParamSpec_NumConstant
+xF
+plist_n_container
+xF::plist_n[20]={{e62-2
+i5-1
+i5-0.5
+i5-0.25
+i5
+0
+tG2
+fp_const_deg_to_rad
+xF(tG2
+fp_const_einv
+xF(tG2
+fp_const_log10inv
+xF(i5
+0.5
+tG2
+fp_const_log2
+xF(i5
+1
+tG2
+fp_const_log2inv
+xF(i5
+2
+tG2
+fp_const_log10
+xF(tG2
+fp_const_e
+xF(tG2
+fp_const_rad_to_deg
+xF(tG2-fp_const_pihalf
+xF(),xU1{xH1,xU1{fp_const_pihalf
+xF(),xU1{fp_const_pi
+xF(),xU1}
+;cN
+plist_s[517]={{{1,15,tH2
+398,tH2
+477,tH2
+15,cNeg,GroupFunction,0}
+,i01,0x1
+lR3
+15,y42
+24,y42
+465,y42
+466,y42
+498,cInv,lT
+2,327995
+x9
+l0
+2,48276
+x9
+l6
+260151
+x9
+l6
+470171
+x9
+l6
+169126
+x9
+l6
+48418
+x9
+l6
+1328
+x9
+l6
+283962
+x9
+l6
+169275
+x9
+l6
+39202
+x9
+l6
+283964
+x9
+l6
+283973
+x9
+l6
+476619
+x9
+l6
+296998
+x9
+l6
+47
+x9
+SelectedParams,0}
+,0,0x4
+nH
+161839
+x9
+l6
+25036
+x9
+l6
+35847
+x9
+l6
+60440
+x9
+l6
+30751
+x9
+l6
+270599
+x9
+l6
+60431
+x9
+l6
+259119
+x9
+l6
+183474
+x9
+l6
+332066
+x9
+l6
+7168
+x9
+l6
+197632
+x9
+l6
+291840
+x9
+l6
+283648
+x9
+l6
+238866
+x9
+l6
+239902
+x9
+l6
+31751
+x9
+l6
+244743
+x9
+l6
+384022
+x9
+SelectedParams,0}
+,0,0x4
+nH
+385262
+x9
+l6
+386086
+x9
+l6
+393254
+x9
+SelectedParams,0}
+,0,0x5
+nH
+393254
+x9
+l6
+386095
+x9
+l6
+387312
+x9
+l6
+18662
+x9
+l6
+61670
+x9
+l6
+387397
+x9
+l6
+247855
+x9
+SelectedParams,0}
+,0,0x1
+nH
+342063
+x9
+l6
+297007
+x9
+l6
+15820
+x9
+l6
+393263
+x9
+l6
+393263
+x9
+SelectedParams,0}
+,0,0x5
+nH
+161847
+x9
+l6
+258103
+x9
+l6
+249073
+x9
+l6
+249076
+x9
+iO
+0,0
+x9
+nF
+0,0
+i31
+1,45
+x9
+nF
+1,53
+x9
+nF
+1,54
+x9
+nF
+1,55
+x9
+nF
+1,56
+x9
+nF
+1,26
+x9
+nF
+1,259
+eK2
+0x16
+lR3
+253
+x9
+nF
+1,272
+i31
+1,323
+eK2
+0x16
+lR3
+0
+x9
+nF
+1,21
+x9
+nF
+1,447
+eK2
+0x4
+lR3
+449
+eK2
+0x4
+lR3
+0
+eK2
+0x4
+lR3
+0
+tJ
+2}
+,0,0x4
+lR3
+15
+x9
+nF
+1,24
+tJ
+2}
+,0,0x0
+nH
+58392
+i31
+0,0
+tJ
+1}
+,nD1,0x0
+nH
+24591
+lS3
+33807
+lS3
+48143
+lS3
+285720
+lS3
+290840
+lS3
+305152,l9
+312400,l9
+39202,l9
+121894,l9
+421926,l9
+429094,l9
+443430,l9
+317834,l9
+329098,l9
+7633,l9
+7706,l9
+7730,l9
+38,l9
+50587,l9
+406528,l9
+24583,l9
+31751,l9
+405511,l9
+321551
+iV2
+327713,l9
+322596,l9
+88361,l9
+335174,l9
+327050,l9
+493606,l9
+496678,l9
+503846,l9
+516134,l9
+7217,l9
+333875,l9
+336896,l9
+524326,l9
+509952,l9
+286727,l9
+90127,l9
+131087,l9
+296976,tQ1
+324623,l1
+0x14
+nH
+332815,l1
+0x10}
+,{{3,7340056,tQ1
+289092,l9
+92176
+iV2
+337935
+e31
+7340060
+lO3
+7340176,l9
+338959
+e31
+7340061
+iV2
+7206,l9
+x63
+l9
+357414,l9
+368678,l9
+370745,l1
+0x7}
+,{{3,7340177,l9
+39277,tQ1
+426398
+lO3
+40272286
+iV2
+490910
+lO3
+40336798
+iV2
+50600,l9
+426462
+iV2
+490974
+iV2
+370726,l1
+0x6
+nH
+371750,l1
+0x6
+nH
+428070
+e31
+40336862
+iV2
+38378,l9
+50671
+e31
+47662080,l9
+477184,l9
+568320,l9
+371727,l1
+0x7}
+,{{3,15779306,l9
+370703,l1
+0x7
+nH
+39277,l9
+39279,l1
+0x4}
+,{{3,15779238,l9
+39338,tQ1
+436262,l9
+508966,l9
+39409,tQ1
+296998,tQ1
+35847,l9
+15,tQ1
+377894,l9
+386063,l1
+0x1
+nH
+15,l9
+7192,l9
+122904,l9
+121880,l9
+30751,l9
+57,l9
+7456,l9
+15674
+e31
+67579935,l9
+39237,l9
+58768,l9
+62924,l9
+121856,l9
+15760
+e31
+64009216,l1
+0x0}
+,{{0,0,xL
+0,0,iW
+2,eC1
+2,eD1
+3,eC1
+3,eD1
+38,xL
+1,38,iW
+14,xL
+1,57,xL
+1,16,eL2
+0x0
+nH
+471103,eL2
+0x1
+lR3
+303,xL
+1,323,yH3
+0x0
+nH
+471363,eL2
+0x16
+lR3
+293,eC1
+294,eD1
+295,xL
+1,296,iW
+400,xL
+1,0,xL
+1,460,xL
+1,465,xL
+1,16,eL2
+0x1
+lR3
+57,yH3
+0x1
+lR3
+0,iW
+21,xL
+1,15,eL2
+0x0
+nH
+24591,xL
+1,24,iW
+517,yH3
+0x0
+nH
+46095,lK
+46104,lK
+15397,lK
+287789,lK
+66584,lK
+404763,lK
+62504,lK
+15409,lK
+39951,lK
+24591,lK
+33807,lK
+50200,lK
+62509,lK
+50176,lF,178176,t21
+tF3
+283648,lF,19456,lF,27648,lF,89088,lF,86016,lF,488448,lF,14342,lF,58375,lF,46147
+xX
+46151,lF,284679,lF,7183,lF,46159
+xX
+38993
+xX
+50265,lF,50249,lF,283808,lF,284835,lF,24822,lF,10240,lF,11264,lF,7170,lF,x63
+lF,17408,lF,164864,lF,237568,lF,242688,t21
+0x14
+nH
+476160,lF,25607,lF,121871,lF,50252,lF,39374,lF,50183,lF,7192,lF,121887,lF,252979,lF,46155,lF,38919,lF,50267,lF,50268,lF,50253,lF,46190,lF,50295,lF,7563,t21
+0x10
+nH
+416811,lF,416819,lF,40046,lF,46191
+xX
+415795,lF,40047
+xX
+415787,lF,39015,t21
+0x5
+nH
+39326
+xX
+39326,lF,39332,t21
+0x5
+nH
+39333
+cC2
+50590
+xX
+50590,lF,39338
+xX
+39338,lF,39335,t21
+0x5
+nH
+15786
+xX
+146858,lF,39372,lF,39379,lF,39380,lF,39390
+xX
+50654
+xX
+50654,lF,24,t21
+0x6
+nH
+62,lF,24,lF,62,t21
+0x6
+nH
+43,lF,43
+xX
+51,lF,51
+xX
+50269,lF,50176
+xX
+50270,lF,39159,lF,39183
+xX
+7168
+xX
+31744,lF,99328,lF,31746,lF,100376,lF,39409
+xX
+39411
+xX
+39411,lF,39420,lF,39420
+xX
+15,lF,39025,t21
+0x5
+nH
+39422,lF,16384,lF,62853,lF,15360,lF,15
+cC2
+16,lF,7183
+cC2
+7172
+tW2
+y71,nD1,0x0
+nH
+24591
+tW2
+lT
+2,50200
+tW2
+lT
+2,63521
+tW2
+lT
+2,62500
+tW2
+lT
+2,50453
+tW2
+lT
+2,62488
+tW2
+lT
+1,0,t93
+7,t93
+194,t93
+0,cAcos
+tA3
+cAcosh
+tA3
+cAsin
+tA3
+cAsinh
+nS
+119,cAsinh
+tA3
+cAtan
+t11
+306176,cAtan2
+t11
+x63
+cAtan2
+tA3
+cAtanh
+nS
+246,cCeil
+tA3
+cCeil
+tB3
+0,cD2
+0,cCos
+tB3
+7,cD2
+91,cD2
+92,cD2
+119,cD2
+236,cD2
+255,cD2
+214,iW2
+236,iW2
+464,iW2
+0,cCosh
+tB3
+0,iW2
+0,cExp
+nS
+7,cExp
+nS
+91,cExp
+tA3
+yI3
+7,yI3
+91,yI3
+246,cFloor
+tA3
+cFloor,lA
+0x4
+nH
+309540,cHypot
+t11
+316708,cHypot
+t11
+316724,cHypot,l0
+3,32513024,eM2
+34627584
+iL
+31493120,eM2
+89213952
+iL
+149042176
+iL
+246647808
+iL
+301234176
+iL
+494360576
+iL
+498558976
+iL
+62933520
+iL
+62933520,eM2
+62933526
+iL
+62933526,eM2
+24670208
+iL
+579378176
+iL
+573578240
+iL
+32513024
+iL
+566254592
+iL
+7900160
+iL
+588822528,cIf
+nS
+119,cInt
+nS
+246,tI2
+0,tI2
+7,tI2
+31,tI2
+194,tI2
+363,tI2
+15,cLog,lT
+1,24,cLog,lT
+1,0,cLog10
+tA3
+cLog2
+t11
+x63
+cMax
+t11
+35847,cMax
+t11
+30751,cMax
+tA3
+cMax,AnyParams,1}
+,0,0x4
+nH
+x63
+cMin
+t11
+35847,cMin
+t11
+30751,cMin
+tA3
+cMin,AnyParams,1}
+,0,0x4
+nH
+24591,cMin,lT
+1,0,x72
+7,x72
+91,x72
+92,x72
+119,x72
+149,x72
+231,cSin,lA
+0x5
+lR3
+246,x72
+255,x72
+254,x72
+0,cSin
+tB3
+273,cSin,lA
+0x1
+lR3
+214,y52
+231,tD3
+lA
+0x5
+lR3
+246,y52
+254,y52
+255,y52
+464,y52
+0,cSinh
+tB3
+0,y52
+15,cSqrt,lT
+1,0,cTan
+tA3
+cTan
+tB3
+115,cTan
+tB3
+116
+tC3
+231
+tC3
+246
+tC3
+273
+tC3
+254
+tC3
+255,cTan
+tA3
+y62
+0,cTanh
+tB3
+213,y62
+231,y62
+246,y62
+254,y62
+255,y62
+0,cTrunc
+t11
+15384,cSub,lT
+2,15384,cDiv,lT
+2,476626,cDiv,lT
+2,121913,tJ2
+x63
+lP3
+tF3
+x63
+tJ2
+31744,lP3
+0x20
+nH
+31751,lP3
+0x24
+nH
+31751,tJ2
+121913,i51
+t11
+x63
+cLess,lA
+tF3
+41984,cLess,lA
+0x4
+nH
+41984,cLess
+t11
+7,cLess
+t11
+x63
+cLessOrEq
+t11
+296182,cLessOrEq
+t11
+7168
+tV2,lA
+tF3
+41984
+tV2,lA
+0x4
+nH
+41984
+tV2
+t11
+7
+tV2
+t11
+x63
+y9
+l0
+2,296182,cGreaterOrEq
+tA3
+n32
+245,n32
+7,n32
+550,n32
+553,n32
+554,n32
+556,n32
+31,n32
+559,n32
+15,n32
+560,cNot
+t11
+7706,lT3
+x63
+lT3
+35847,lT3
+30751,lT3
+463903,lT3
+466975,cAnd,iO
+0,0,cAnd,nF
+2,x63
+e03
+7706,e03
+35847,e03
+463903,e03
+466975,e03
+30751,cOr,iO
+1,0,n42
+91,n42
+131,n42
+245,n42
+215,n42
+246,cDeg
+nS
+246,cRad
+t11
+x63
+cAbsAnd,l6
+x63
+cAbsOr,iO
+1,0,cC3
+tA3
+cAbsNotNot,l0
+3,32513024,yT3
+lA
+0x0}
+,}
+;}
+l33
+lA1{const
+Rule
+grammar_rules[262]={{ProduceNewTree,17,1,0,{1,0,cAbs,eN2
+409,{1,146,cAtan,eN2
+403
+nT
+1324,cAtan2,eN2
+405
+nT
+307201,cAtan2
+eL
+253174
+nT
+255224,cAtan2
+eL
+259324
+nT
+257274,cAtan2,eN2
+152,{1,252,cCeil
+i7
+486,{1,68
+yH2
+482,{1,122
+yH2
+483,{1,124
+yH2
+151,{1,125
+yH2
+419,{1,123
+yH2
+0,{1,403,cCos,l2
+2,1,246,{1,252,cCos,l2
+18,1,0,{1,400
+yH2
+301,{1,406,cCosh,l2
+2,1,246,{1,252,cCosh,l2
+18,1,0,{1,400,cCosh
+i7
+458,{1,121,cFloor,eN2
+150,{1,252,cFloor,tG3
+156,{3,7382016,eF
+549,{3,8430592,eF
+556,{3,8436736,eF
+157,{3,42998784,eF
+550,{3,42999808,eF
+562,{3,43039744,eF
+557,{3,49291264,eF
+538,{3,49325056,eF
+469,{3,1058318,eF
+473,{3,1058324,eF
+473,{3,9438734,eF
+469,{3,9438740,cIf,l2
+0,3,32542225,{3,36732434,cIf,l2
+0,3,32542231,{3,36732440,cIf,yR3
+573,{3,32513026,cIf,yR3
+515,{3,455505423,cIf,yR3
+515,{3,433506837,cIf
+i7
+78,{1,256,cLog
+i7
+69,{1,258,cLog
+i7
+404,{1,72,cLog
+i7
+159,{1,147,cLog,l2
+0,1,0
+nT
+487425,cMax
+l3
+16,1,445
+nT
+yJ3
+cMax
+l3
+0,1,0
+nT
+483329,cMin
+l3
+16,1,446
+nT
+yJ3
+cMin,c3
+0,1,153
+nT
+24832
+tW2
+tG3
+153
+nT
+25854
+tW2
+tG3
+154
+nT
+129039
+tW2
+xV1
+32055
+tW2
+xV1
+32056
+tW2
+xV1
+32057
+tW2
+l2
+0,2,166288
+nT
+32137
+tW2
+xV1
+33082
+tW2
+l2
+0,2,7168
+nT
+12688
+tW2
+l2
+0,2,7434
+nT
+12553,tX2
+435
+nT
+46146,tX2
+436
+nT
+46154,tX2
+437
+nT
+46150,tX2
+169
+nT
+83983,tX2
+168
+nT
+130082,tX2
+175
+nT
+133154
+tW2
+tI3
+476160
+nT
+471055
+tW2
+tI3
+274432
+nT
+273423
+tW2
+tI3
+251904
+nT
+266274
+tW2
+tI3
+251904
+nT
+263186,tX2
+171,{1,252,cE2
+421,{1,68,cE2
+151,{1,122,cE2
+419,{1,124,cE2
+170,{1,125,cE2
+482,{1,123,cE2
+0,{1,405,cE2
+172,{1,252,cSinh
+i7
+328,{1,404,cSinh
+i7
+173,{1,252,tJ3
+0,{1,408,tJ3
+176,{1,410,tJ3
+177,{1,252,cTanh,l2
+0,1,442
+nT
+449551,i6
+1,441
+nT
+yJ3
+i6
+1,167
+nT
+268549,i6
+1,181
+nT
+276749,i6
+1,180
+nT
+276500,i6
+2,190770
+nT
+189622,i6
+2,194748
+nT
+193723,i6
+2,202943
+nT
+196795,i6
+2,59699
+nT
+298148,i6
+2,59714
+nT
+325815,i6
+2,59724
+nT
+343224
+x9
+c3
+2,1,337,{1,333
+tJ
+1
+tF
+336,{1,338
+tJ
+1}
+}
+,{ReplaceParams,2,1,340
+nT
+1363
+nR
+342
+nT
+1365
+nR
+463
+nT
+472524
+nR
+47
+nT
+356711
+nR
+349
+nT
+200751
+nR
+360
+nT
+199727
+nR
+480
+nT
+207053
+nR
+481
+nT
+208077
+nR
+417
+nT
+211144
+nR
+209
+nT
+211145
+nR
+418
+nT
+215240
+nR
+212
+nT
+212329
+nR
+204
+nT
+373097
+nR
+211
+nT
+372944
+nR
+217
+nT
+201944
+nR
+221
+nT
+223448
+nR
+367
+nT
+508329
+nR
+219
+nT
+508126
+nR
+224
+nT
+225705
+nR
+223
+nT
+225776
+nR
+365
+nT
+230825
+nR
+426
+nT
+377057
+nR
+497
+nT
+377054
+nR
+497
+nT
+204201
+nR
+426
+nT
+375280
+nR
+224
+nT
+375006,cAdd
+l3
+2,2,407781
+nT
+233698,cAdd
+l3
+2,2,59763
+nT
+233842,i6
+1,372
+nT
+1397,lW1
+95
+nT
+24705,lW1
+96
+nT
+24708,lW1
+444
+nT
+449551,lW1
+443
+nT
+yJ3
+lW1
+100
+nT
+101750,lW1
+108
+nT
+106821,lW1
+105
+nT
+103749
+lU3
+0,2,110607
+nT
+108869
+lU3
+0,2,107535
+nT
+109893,lJ
+0
+tF
+112
+nT
+111634,cMul,SelectedParams,0
+tF
+567,{1,52,lJ
+1
+tF
+568,{1,42,lJ
+1}
+}
+,{ReplaceParams,2,1,467
+nT
+45516
+xA
+356
+nT
+51555
+xA
+468
+nT
+49612
+xA
+357
+nT
+47459
+xA
+429
+nT
+438699
+xA
+432
+nT
+441774
+xA
+486
+nT
+498726
+xA
+494
+nT
+504870
+xA
+382
+nT
+435579
+xA
+497
+nT
+435709
+xA
+426
+nT
+508287
+xA
+414
+nT
+500092
+xA
+499
+nT
+352744
+xA
+345
+nT
+367092
+xA
+381
+nT
+425318
+xA
+478
+nT
+425460
+xA
+47
+nT
+512501
+xA
+505
+nT
+355817
+xA
+47
+nT
+516598
+xA
+507
+nT
+518182
+xA
+508
+nT
+358896
+xA
+351
+nT
+388605
+xA
+511
+nT
+360939
+xA
+503
+nT
+354788
+xA
+514
+nT
+525350
+xA
+510
+nT
+394342
+xA
+386
+nT
+351346
+lU3
+2,2,363004
+nT
+361968
+lU3
+16,1,117
+nT
+1157
+lU3
+16,1,118
+nT
+1158
+lU3
+16,1,402
+nT
+411024
+lU3
+16,2,58768
+nT
+1472
+lU3
+16,2,15760
+nT
+1474
+lU3
+17,1,0,{1,400
+lU3
+17,1,57,{1,14,lJ
+0}
+}
+,{ProduceNewTree,4,1,538
+nT
+41,lQ3
+yK3
+0
+nT
+5167,lQ3
+cH
+41984
+e22
+lQ3
+cH
+tU
+lQ3
+cH
+eV
+lQ3
+cH
+eW
+cEqual
+cN1
+24849,cEqual
+eL
+tV
+cEqual
+eL
+n52
+281873,cEqual
+eL
+iP
+cEqual
+eL
+lH1
+lQ3
+yK3
+562
+nT
+41,i51,yK3
+538
+nT
+5167,i51,cH
+41984
+e22
+i51,cH
+tU
+i51,cH
+eV
+i51,cH
+eW
+i51
+cN1
+24849,i51
+eL
+tV
+i51
+eL
+n52
+281873,i51
+eL
+iP
+i51
+eL
+lH1
+i51,cH
+tU
+yN3
+eV
+yN3
+eW
+cLess,eN2
+571
+nT
+46080,cLess
+cN1
+24832,cLess
+eL
+xW1
+cLess
+eL
+tV
+cLess
+eL
+n52
+tK3
+cLess
+eL
+nY1
+cLess
+eL
+iP
+cLess
+eL
+lH1
+cLess,yL3
+562
+e22
+yN3
+tU
+n62
+cH
+eV
+n62
+cH
+eW
+n62
+eN2
+565
+nT
+409615,cLessOrEq
+cN1
+24832,cLessOrEq
+eL
+xW1
+cLessOrEq
+eL
+tV
+cLessOrEq
+eL
+n52
+tK3
+cLessOrEq
+eL
+nY1
+cLessOrEq
+eL
+iP
+cLessOrEq
+eL
+lH1
+n62
+yL3
+562
+nT
+409647,n62
+cH
+tU
+cF2
+eV
+cF2
+eW
+cGreater,eN2
+539
+nT
+409615
+tV2
+cN1
+24832
+tV2
+eL
+xW1
+cGreater
+eL
+tV
+cGreater
+eL
+n52
+281856
+tV2
+eL
+nY1
+cGreater
+eL
+iP
+cGreater
+eL
+lH1
+cGreater,yL3
+538
+nT
+409647,cF2
+tU
+y9
+cH
+eV
+y9
+cH
+eW
+y9
+eN2
+572
+nT
+46080,y9
+nQ2
+529654
+nT
+24832,y9
+nQ2
+xW1
+y9
+nQ2
+tV
+y9
+nQ2
+n52
+tK3
+y9
+nQ2
+nY1
+y9
+nQ2
+iP
+y9
+nQ2
+lH1
+y9
+yL3
+538
+e22
+y9
+yK3
+519,{1,137,cNot,yR3
+571,{1,2,cNot,l2
+0,1,452
+nT
+yJ3
+lV3
+0,2,537097,{3,547892744,cAnd,c3
+16,1,566,{1,5,cAnd,AnyParams,1}
+}
+,{ReplaceParams,16,1,569
+nT
+13314,lV3
+16,1,544
+nT
+553498,lV3
+16,1,546
+nT
+462369,lV3
+16,1,548
+nT
+466465,lV3
+0,1,457
+nT
+yJ3
+xX1
+570
+nT
+13314,xX1
+563
+nT
+8197,xX1
+541
+nT
+553498,xX1
+542
+nT
+462369,xX1
+543
+nT
+466465,xX1
+564
+nT
+143365,cOr,c3
+4,1,525,{1,137,yS3
+yR3
+572,{1,2,yS3
+l4
+17,1,0,{1,0,yS3
+eN2
+537,{1,256,cAbsNotNot,c3
+18,1,531,{1,254,cAbsNotNot,c3
+0,1,572,{3,43039744,yT3
+tG3
+571,{3,49325056,yT3
+yR3
+454,{3,32513586,yT3
+l2
+16,3,32542225,{3,36732434,yT3
+y71}
+,}
+;e72
+grammar_optimize_abslogical_type{y3
+9
+cT
+grammar_optimize_abslogical_type
+grammar_optimize_abslogical={9,{34,192,228,238,242,247,254,260,261}
+}
+;}
+e72
+grammar_optimize_ignore_if_sideeffects_type{y3
+59
+cT
+grammar_optimize_ignore_if_sideeffects_type
+grammar_optimize_ignore_if_sideeffects={59,{0,20,21,22,23,24,25,26,cO
+l42
+78,cP
+cU
+e72
+grammar_optimize_nonshortcut_logical_evaluation_type{y3
+56
+cT
+grammar_optimize_nonshortcut_logical_evaluation_type
+grammar_optimize_nonshortcut_logical_evaluation={56,{0,25,cO
+l42
+78,cP
+241,243,244,245,246,248,249,250,251,252,253,255,256,257,258,259}
+}
+;}
+e72
+grammar_optimize_recreate_type{y3
+22
+cT
+grammar_optimize_recreate_type
+grammar_optimize_recreate={22,{18,55,56,57,80,81,82,83,84,85,117,118,120,121,130,131,132,133,134,135,136,137}
+}
+;}
+e72
+grammar_optimize_round1_type{y3
+125
+cT
+grammar_optimize_round1_type
+grammar_optimize_round1={125,{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,19,25,cO
+37,38,l42
+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,84,85,86,87,88,93,94,95,96,97,98,99,100,101,117,118,119,120,121,122,123,124,125,126,127,128,129,138,160,161,162,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240,cU
+e72
+grammar_optimize_round2_type{y3
+103
+cT
+grammar_optimize_round2_type
+grammar_optimize_round2={103,{0,15,16,17,25,cO
+39,40,l42
+45,46,47,48,49,50,51,52,53,54,59,60,72,73,78,79,86,87,88,89,90,91,92,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,119,122,123,124,125,126,127,128,139,159,160,161,162,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240,cU
+e72
+grammar_optimize_round3_type{y3
+79
+cT
+grammar_optimize_round3_type
+grammar_optimize_round3={79,{74,75,76,77,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,170,171,172,173,174,175,176,177,181,182,183,184,185,186,187,188,189,190,191,193,194,195,196,197,198,199,201,202,203,205,206,207,208,209,210,211,213,214,215,217,218,219,220,221,222,223,225,226,227,229,230,231,232,233,234,235}
+}
+;}
+e72
+grammar_optimize_round4_type{y3
+12
+cT
+grammar_optimize_round4_type
+grammar_optimize_round4={12,{18,55,56,57,130,131,132,133,134,135,136,137}
+}
+;}
+e72
+grammar_optimize_shortcut_logical_evaluation_type{y3
+53
+cT
+grammar_optimize_shortcut_logical_evaluation_type
+grammar_optimize_shortcut_logical_evaluation={53,{0,25,cO
+l42
+78,cP
+cU}
+l33
+lA1{tK1
+eA2
+ParamSpec_Extract
+lT1
+paramlist,lJ1){index=(paramlist>>(index*10))&1023;if(index>=57)return
+eA2(SubFunction,cG2
+plist_s[index-57]);if(index>=37)return
+eA2(NumConstant,cG2
+plist_n_container
+xF::plist_n[index-37])i1
+eA2(ParamHolder,cG2
+plist_p[index]);}
+}
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <stdio.h>
+#include <algorithm>
+#include <map>
+#include <sstream>
+using
+l33
+FUNCTIONPARSERTYPES;using
+l33
+lA1;using
+t5;using
+nG1;l33{nN1
+It,x93
+T,x93
+Comp>t31
+MyEqualRange(It
+first,It
+last,const
+T&val,Comp
+comp){size_t
+len=last-first;while(len>0){size_t
+xR3
+len/2;It
+x23(first);x23+=half;if(comp(*x23,val)){first=x23;++first;len=len-half-1;}
+iP1
+comp(val,*x23)){len=half;}
+else{It
+left(first);{It&eO2=left;It
+last2(x23);size_t
+len2=last2-eO2;while(len2>0){size_t
+half2=len2/2;It
+eN3(eO2);eN3+=half2;if(comp(*eN3,val)){eO2=eN3;++eO2;len2=len2-half2-1;}
+else
+len2=half2;}
+}
+first+=len;It
+right(++x23);{It&eO2=right;It&last2=first;size_t
+len2=last2-eO2;while(len2>0){size_t
+half2=len2/2;It
+eN3(eO2);eN3+=half2;if(comp(val,*eN3))len2=half2;else{eO2=eN3;++eO2;len2=len2-half2-1;}
+}
+eE3
+t31(left,right);}
+eE3
+t31(first,first);}
+tK1
+e72
+OpcodeRuleCompare{iD2()iS1
+nP1
+x83
+y72)const{const
+Rule&rule=grammar_rules[y72]i1
+t72<rule
+yR2.subfunc_opcode;}
+iD2()lT1
+y72,const
+eR
+const{const
+Rule&rule=grammar_rules[y72]i1
+rule
+yR2.subfunc_opcode<t72;}
+}
+yO1
+bool
+TestRuleAndApplyIfMatch(t41
+nP1
+bool
+c4{MatchInfo
+xF
+info;n31
+found(false,cZ());if((rule.lI1
+LogicalContextOnly)&&!c4{tR1
+if(nB
+IsIntType
+xF::nS3){if(rule.lI1
+NotForIntegers)tR1
+cJ3
+rule.lI1
+OnlyForIntegers)tR1
+if(nB
+IsComplexType
+xF::nS3){if(rule.lI1
+NotForComplex)tR1
+cJ3
+rule.lI1
+OnlyForComplex)tR1
+for(;;){
+#ifdef DEBUG_SUBSTITUTIONS
+#endif
+found=TestParams(rule
+yR2
+cU3,found.specs,info,true);if(found.found)break;if(!&*found.specs){fail:;
+#ifdef DEBUG_SUBSTITUTIONS
+DumpMatch
+yG2,false);
+#endif
+return
+t23}
+#ifdef DEBUG_SUBSTITUTIONS
+DumpMatch
+yG2,true);
+#endif
+SynthesizeRule
+yG2
+yQ2}
+nG1{yP1
+ApplyGrammar
+iS1
+Grammar&tK2,nP1
+bool
+c4{if(tree.GetOptimizedUsing()==&tK2){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Already optimized: "
+iL2
+tree
+lE2"\n"
+<<std::flush;
+#endif
+return
+t23
+if(true){bool
+changed
+eW3
+e23
+t72){case
+cNot:case
+cNotNot:case
+cAnd:case
+cOr:for
+iZ1
+a=0
+tV3
+true))yS1
+lC
+cIf:case
+cAbsIf:if(ApplyGrammar(tK2,xW
+0),t72==cIf))yS1
+for
+iZ1
+a=1
+tV3
+c4)yS1
+break;yF3
+for
+iZ1
+a=0
+tV3
+false))yS1}
+if(changed){tree.Mark_Incompletely_Hashed(yQ2}
+typedef
+const
+x83
+short*lW3;std::pair<lW3,lW3>range=MyEqualRange(tK2.rule_list,tK2.rule_list+tK2.rule_count
+cU3,OpcodeRuleCompare
+xF());eO3
+x83
+short>rules;rules.xH3
+range.second-range.first);for
+y0
+if(IsLogisticallyPlausibleParamsMatch(tM1
+yR2
+cU3))rules
+c52*r);}
+range.first=!rules
+eU3?&rules[0]:0;range.second=!rules
+eU3?&rules[rules
+eJ3-1]+1:0;if(range.first!=range.second){
+#ifdef DEBUG_SUBSTITUTIONS
+if(range.first!=range.second)cH2"Input ("
+<<FP_GetOpcodeName(t72)<<")["
+<<tree.GetParamCount()<<"]"
+;if(c4
+cV2<<"(Logical)"
+;x83
+first=l52,prev=l52;e32
+sep=", rules "
+;for
+y0
+if(first==l52)first=prev=*r;iP1*r==prev+1)prev=*r;else
+cH2
+sep<<first;sep=","
+;if(prev!=first)cV2<<'-'<<prev;first=prev=*r;}
+}
+if(first!=l52)cH2
+sep<<first;if(prev!=first)cV2<<'-'<<prev;}
+cV2<<": "
+iL2
+tree
+lE2"\n"
+<<std::flush;}
+#endif
+bool
+changed
+eW3
+for
+y0
+#ifndef DEBUG_SUBSTITUTIONS
+if(!IsLogisticallyPlausibleParamsMatch(tM1
+yR2
+cU3))yA1
+#endif
+if(TestRuleAndApplyIfMatch(tM1
+cU3,c4){yS1
+xY3}
+if(changed){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Changed."
+<<std::endl;cV2<<"Output: "
+iL2
+tree
+lE2"\n"
+<<std::flush;
+#endif
+tree.Mark_Incompletely_Hashed(yQ2}
+tree.SetOptimizedUsing(&tK2)i1
+t23
+yP1
+ApplyGrammar
+iS1
+void*p,FPoptimizer_CodeTree::eR
+yP
+ApplyGrammar(*iS1
+Grammar*)p
+cU3);}
+xL1
+ApplyGrammars(FPoptimizer_CodeTree::eR{
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_round1\n"
+;
+#endif
+n6
+grammar_optimize_round1
+cU3
+nW
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_round2\n"
+;
+#endif
+n6
+grammar_optimize_round2
+cU3
+nW
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_round3\n"
+;
+#endif
+n6
+grammar_optimize_round3
+cU3
+nW
+#ifndef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_nonshortcut_logical_evaluation\n"
+;
+#endif
+n6
+grammar_optimize_nonshortcut_logical_evaluation
+cU3
+nW
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_round4\n"
+;
+#endif
+n6
+grammar_optimize_round4
+cU3
+nW
+#ifdef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_shortcut_logical_evaluation\n"
+;
+#endif
+n6
+grammar_optimize_shortcut_logical_evaluation
+cU3
+nW
+#endif
+#ifdef FP_ENABLE_IGNORE_IF_SIDEEFFECTS
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_ignore_if_sideeffects\n"
+;
+#endif
+n6
+grammar_optimize_ignore_if_sideeffects
+cU3
+nW
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iB3"grammar_optimize_abslogical\n"
+;
+#endif
+n6
+grammar_optimize_abslogical
+cU3
+nW
+#undef C
+}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <algorithm>
+#include <assert.h>
+#include <cstring>
+#include <cmath>
+#include <memory> /* for auto_ptr */
+using
+l33
+FUNCTIONPARSERTYPES;using
+l33
+lA1;using
+t5;using
+nG1;l33{yP1
+TestImmedConstraints
+lT1
+bitmask,const
+eR{e23
+bitmask&ValueMask){case
+Value_AnyNum:case
+ValueMask:lC
+x62:if(GetEvennessInfo
+iS3
+n72
+Value_OddInt:if(GetEvennessInfo
+iS3
+x82
+i11:if(GetIntegerInfo
+iS3
+n72
+Value_NonInteger:if(GetIntegerInfo
+iS3
+x82
+eY1:if(!IsLogicalValue(tree)cQ
+nE1
+SignMask){case
+Sign_AnySign:lC
+nD1:if(l81
+n72
+eZ1:if(l81
+x82
+Sign_NoIdea:if(l81
+Unknown
+cQ
+nE1
+OnenessMask){case
+Oneness_Any:case
+OnenessMask:lC
+Oneness_One:if(!xY1
+if(!lJ3
+fp_abs(tree
+x41),e62
+1))cQ
+lC
+Oneness_NotOne:if(!xY1
+lG3
+fp_abs(tree
+x41),e62
+1))cQ
+nE1
+ConstnessMask){case
+Constness_Any:lC
+i01:if(!xY1
+lC
+Constness_NotConst:if(xY1
+xY3
+lD2}
+tP1
+x83
+extent,x83
+nbits,x93
+eP2=x83
+int>e72
+nbitmap{private:static
+const
+x83
+bits_in_char=8;static
+const
+x83
+eQ2=(sizeof(eP2)*bits_in_char)/nbits;eP2
+data[(extent+eQ2-1)/eQ2];e43
+void
+inc(lJ1,int
+by=1){data[pos(index)]+=by*eP2(1<<y82);y81
+void
+dec(lJ1){inc(index,-1);}
+int
+get(lJ1
+c01(data[pos(index)]>>y82)&mask()iT3
+pos(lJ1)yP
+index/eQ2
+iT3
+shift(lJ1)yP
+nbits*(index%eQ2)iT3
+mask()yP(1<<nbits)-1
+iT3
+mask(lJ1)yP
+mask()<<y82;}
+}
+;e72
+Needs{int
+SubTrees:8;int
+Others:8;int
+l62:8;int
+Immeds:8;nbitmap<iU2,2>SubTreesDetail;Needs(){std::memset(this,0,sizeof(*this));}
+Needs
+iS1
+Needs&b){std::memcpy(this,&b,sizeof(b));}
+Needs&eM1=iS1
+Needs&b){std::memcpy(this,&b,sizeof(b))i1*this;}
+}
+yO1
+Needs
+CreateNeedList_uncached(eX&tL2{Needs
+yQ1;for
+lT1
+a=0;a<params
+y92;++a){const
+eA2&lX3=ParamSpec_Extract
+xF(params.param_list,a);e23
+lX3.first){case
+SubFunction:{cN&yU3
+cN*tF1;yF
+GroupFunction)++yQ1.Immeds;else{++iO2;assert(iH3.subfunc_opcode<VarBegin);yQ1.SubTreesDetail.inc
+yZ3
+lG1);}
+++yQ1.l62;xY3
+case
+NumConstant:case
+ParamHolder:++iN2;++yQ1.l62;xY3
+eE3
+yQ1;}
+tK1
+Needs&CreateNeedList(eX&tL2{typedef
+std::map<eX*,Needs>eE1;static
+eE1
+yV1;eE1::y83
+i=yV1.xU2&tL2;if(i!=yV1.cX1&tL2
+return
+i
+eC2
+i1
+yV1.y43,std::make_pair(&params,CreateNeedList_uncached
+xF(tL2))eC2;}
+tK1
+yZ2
+CalculateGroupFunction
+iS1
+eA2&yA2
+const
+tC
+info
+yY3
+lX3.first){case
+NumConstant:{const
+ParamSpec_NumConstant
+xF&param=*iS1
+ParamSpec_NumConstant
+xF*tF1
+i1
+CodeTreeImmed
+yZ3
+constvalue);}
+case
+ParamHolder:{cM&yU3
+cM*tF1
+i1
+info.GetParamHolderValueIfFound
+yZ3
+index);}
+case
+SubFunction:{cN&yU3
+cN*tF1
+tX
+nS3;nS3
+iH
+param.lG1);nS3.lJ2).xH3
+iH3
+y92);for
+lT1
+a=0;a<iH3
+y92;++a
+nQ
+tmp(CalculateGroupFunction
+nF1
+iH3.param_list,a),info));nS3
+c91
+tmp);}
+nS3
+iW1
+i1
+nS3;}
+eE3
+yZ2();}
+}
+nG1{yP1
+IsLogisticallyPlausibleParamsMatch(eX&params,const
+eR{Needs
+yQ1(CreateNeedList
+xF(tL2);size_t
+tL3=yC
+if(tL3<size_t(yQ1.l62))tM2
+for
+iZ1
+a=0;a<tL3;++a){x83
+opcode=xW
+a)nC;e23
+opcode){case
+cImmed:if(yQ1.Immeds>0)--yQ1.Immeds;else--iN2;lC
+iU2:case
+cFCall:case
+cPCall:--iN2;break;yF3
+assert(opcode<VarBegin);if(iO2>0&&yQ1.SubTreesDetail.get(opcode)>0){--iO2;yQ1.SubTreesDetail.dec(opcode);}
+else--iN2;}
+}
+if(yQ1.Immeds>0||iO2>0||iN2>0)tM2
+if(params.match_type!=AnyParams){if(0||iO2<0||iN2<0)tM2}
+lD2}
+tK1
+n31
+TestParam
+iS1
+eA2&yA2
+const
+nP1
+const
+cZ&start_at,tC
+info
+yY3
+lX3.first){case
+NumConstant:{const
+ParamSpec_NumConstant
+xF&param=*iS1
+ParamSpec_NumConstant
+xF*tF1;if(!xY1
+Value_t
+imm=tree
+x41;switch
+yZ3
+modulo){case
+Modulo_None:lC
+Modulo_Radians:imm=cK3
+imm,yK
+imm<xG1
+imm
+yN
+if(imm>fp_const_pi
+xF())imm-=fp_const_twopi
+xF(e02
+return
+lJ3
+imm,param.constvalue);}
+case
+ParamHolder:{cM&yU3
+cM*tF1;if(!x3
+return
+info.SaveOrTestParamHolder
+yZ3
+index
+cU3);}
+case
+SubFunction:{cN&yU3
+cN*tF1;yF
+GroupFunction){if(!x3
+yZ2
+xZ1=CalculateGroupFunction(yA2
+info);
+#ifdef DEBUG_SUBSTITUTIONS
+DumpHashes(xZ1
+lE2*iS1
+void**)&xZ1
+x41;cV2<<"\n"
+;cV2<<*iS1
+void**)&tree
+x41;cV2<<"\n"
+;DumpHashes(tree
+lE2"Comparing "
+iL2
+xZ1
+lE2" and "
+iL2
+tree
+lE2": "
+;cV2<<(xZ1
+xI
+tree)?"true"
+:"false"
+lE2"\n"
+;
+#endif
+return
+xZ1
+xI
+tree);}
+cJ3!eK1){if(!x3
+if(t72!=param.lG1
+cQ
+eE3
+TestParams
+yZ3
+data
+cU3,start_at,info,false);}
+}
+eE3
+t23
+tK1
+e72
+l31
+x92
+MatchInfo
+xF
+info;l31():start_at(),info(){}
+}
+yO1
+class
+MatchPositionSpec_PositionalParams:nQ1
+l31
+xF>{e43
+iX2
+MatchPositionSpec_PositionalParams
+iZ1
+n):eF1
+l31
+xF>(n){}
+}
+;e72
+l72
+x92
+l72():start_at(){}
+}
+;class
+yG:nQ1
+l72>{e43
+x83
+trypos;iX2
+yG
+iZ1
+n):eF1
+l72>(n),trypos(0){}
+}
+yO1
+n31
+TestParam_AnyWhere
+iS1
+eA2&yA2
+const
+nP1
+const
+cZ&start_at,tC
+info,cY2&used,bool
+iX1{xP<yG>x8;x83
+xA2(yG*)eK1;a=x8->trypos;goto
+retry_anywhere_2;cO2
+yG
+l51);a=0;}
+tM3
+yC++a){if(used[a])yA1
+retry_anywhere
+yW3
+TestParam(yA2
+xW
+a)xS3);yP3
+used[a]=true;if(iX1
+info.SaveMatchedParamIndex(a);x8->trypos=a
+i1
+n31(true,&*x8);}
+}
+retry_anywhere_2
+yX3
+goto
+retry_anywhere;}
+eE3
+t23
+tK1
+e72
+yD1
+x92
+MatchInfo
+xF
+info;cY2
+used;iX2
+yD1
+iZ1
+tL3):start_at(),info(),used(tL3){}
+}
+yO1
+class
+MatchPositionSpec_AnyParams:nQ1
+yD1
+xF>{e43
+iX2
+MatchPositionSpec_AnyParams
+iZ1
+n,size_t
+m):eF1
+yD1
+xF>(n,yD1
+xF(m)){}
+}
+yO1
+n31
+TestParams(eX&nN,const
+nP1
+const
+cZ&start_at,tC
+info,bool
+iX1{if(nN.match_type!=AnyParams){if(xT!=tree.GetParamCount()cQ}
+if(!IsLogisticallyPlausibleParamsMatch(nN
+cU3))tM2
+e23
+nN.match_type){case
+PositionalParams:{xP<cF>x8;x83
+xA2(cF*)eK1;a=xT-1;goto
+lK1;cO2
+cF(xT);a=0;}
+tM3
+xT;++a){(yQ3=info;retry_positionalparams
+yW3
+TestParam(cW
+a),xW
+a)xS3);yP3
+yA1}
+}
+lK1
+yX3
+info=(yQ3;goto
+retry_positionalparams;}
+if(a>0){--a;goto
+lK1;}
+info=c12
+i1
+t23
+if(iX1
+tN3
+info.SaveMatchedParamIndex(a)i1
+n31(true,&*x8);}
+case
+SelectedParams:case
+AnyParams:{xP<t6>x8;cY2
+used
+l51);eO3
+x83>iY2(xT);eO3
+x83>yB2(xT);tN3{const
+eA2
+lX3=cW
+a);iY2[a]=ParamSpec_GetDepCode(lX3);}
+{x83
+b=0;tN3
+if(iY2[a]!=0)yB2[b++]=a;tN3
+if(iY2[a]==0)yB2[b++]=a;}
+x83
+xA2(t6*)eK1;if(xT==0){a=0;goto
+retry_anyparams_4;}
+a=xT-1;goto
+eG1;cO2
+t6(xT
+cU3.GetParamCount());a=0;if(xT!=0){c12=info;(*x8)[0].used=used;}
+}
+tM3
+xT;++a){if(a>0){(yQ3=info;(yO3
+used=used;}
+retry_anyparams
+yW3
+TestParam_AnyWhere
+xF(cW
+yB2[a])cU3
+xS3,used,iX1;yP3
+yA1}
+}
+eG1
+yX3
+info=(yQ3;used=(yO3
+used;goto
+retry_anyparams;}
+eH1:if(a>0){--a;goto
+eG1;}
+info=c12
+i1
+t23
+retry_anyparams_4:if(nN.n1!=0){if(!TopLevel||!info.HasRestHolder(nN.n1)){eK
+cI2;cI2.reserve
+l51);for
+lT1
+b=0;b<yC++b){if(used[b])yA1
+cI2
+c52
+xW
+b));used[b]=true;if(iX1
+info.SaveMatchedParamIndex(b);}
+if(!info.SaveOrTestRestHolder(nN.n1,cI2)){goto
+eH1;}
+}
+else{eA3&cI2=info.GetRestHolderValues(nN.n1
+iY1
+0;a<cI2
+eJ3;++a){bool
+found
+eW3
+for
+lT1
+b=0;b<yC++b){if(used[b])yA1
+if(cI2[a]xI
+xW
+b))){used[b]=true;if(iX1
+info.SaveMatchedParamIndex(b);found=true;xY3}
+if(!found){goto
+eH1;}
+}
+}
+eE3
+n31(true,xT?&*x8:0);}
+case
+GroupFunction:xY3
+return
+t23}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <algorithm>
+#include <assert.h>
+using
+t5;using
+nG1;l33{tK1
+yZ2
+yW1
+iS1
+eA2&yA2
+tC
+info,bool
+inner=true
+yY3
+lX3.first){case
+NumConstant:{const
+ParamSpec_NumConstant
+xF&param=*iS1
+ParamSpec_NumConstant
+xF*tF1
+i1
+CodeTreeImmed
+yZ3
+constvalue);}
+case
+ParamHolder:{cM&yU3
+cM*tF1
+i1
+info.GetParamHolderValue
+yZ3
+index);}
+case
+SubFunction:{cN&yU3
+cN*tF1
+tX
+tree;tD2
+param.lG1);for
+lT1
+a=0;a<iH3
+y92;++a
+nQ
+nparam=yW1
+nF1
+iH3.param_list,a
+l04
+true
+c81
+nparam);}
+if
+yZ3
+data.n1!=0){eK
+trees(info.GetRestHolderValues
+yZ3
+data.n1)yB
+AddParamsMove(trees);if
+l51==1){assert(tree.GetOpcode()==cAdd||tree.GetOpcode()==cMul||tree.GetOpcode()==cMin||tree.GetOpcode()==cMax||tree.GetOpcode()==cAnd||tree.GetOpcode()==cOr||tree.GetOpcode()==cAbsAnd||tree.GetOpcode()==cAbsOr);tree.eF2
+0));}
+else
+if
+l51==0
+yY3
+t72){case
+cAdd:case
+cOr:tree=nA1
+0));lC
+cMul:case
+cAnd:tree=nA1
+1));yF3
+xY3}
+}
+if(inner)tree
+iW1
+i1
+tree;}
+eE3
+yZ2();}
+}
+nG1{xL1
+SynthesizeRule(t41
+nP1
+tC
+info
+yY3
+rule.ruletype){case
+ProduceNewTree:{tree.Become(yW1
+nF1
+rule.t51
+0
+l04
+false)e02
+case
+ReplaceParams:yF3{eO3
+x83>list=info.GetMatchedParamIndexes();std::sort(list.iJ2
+list.end()iY1
+list
+eJ3;a-->0;)tree.i91
+list[a]);for
+lT1
+a=0;a<rule.repl_param_count;++a
+nQ
+nparam=yW1
+nF1
+rule.t51
+a
+l04
+true
+c81
+nparam);}
+xY3}
+}
+}
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+#include <sstream>
+#include <cstring>
+using
+l33
+FUNCTIONPARSERTYPES;using
+l33
+lA1;using
+t5;using
+nG1;l33
+lA1{xL1
+DumpMatch(t41
+const
+nP1
+const
+tC
+info,bool
+DidMatch,std::ostream&o){DumpMatch
+yG2,DidMatch?iX3"match"
+:iX3"mismatch"
+,o);}
+xL1
+DumpMatch(t41
+const
+nP1
+const
+tC
+info,e32
+tO3,std::ostream&o){static
+const
+char
+ParamHolderNames[][2]={"%"
+,"&"
+,"x"
+,"y"
+,"z"
+,"a"
+,"b"
+,"c"
+}
+;o<<tO3<<" (rule "
+<<(&rule-grammar_rules)<<")"
+<<":\n Pattern : "
+;{eA2
+tmp;tmp.first=SubFunction;ParamSpec_SubFunction
+tmp2;tmp2.data=rule
+yR2;tmp.second=cG2
+tmp2;DumpParam
+xF(tmp,o);}
+o<<"\n Replacement: "
+;DumpParams
+xF(rule.t51
+rule.repl_param_count,o)iV3
+o<<" Tree : "
+iL2
+tree,o)iV3
+if(!std::strcmp(tO3,iX3"match"
+))DumpHashes(tree,o
+iY1
+0;a<info.cA
+eJ3;++a){if(!info.cA[a].nX2)yA1
+o<<" "
+<<ParamHolderNames[a]<<" = "
+iL2
+info.cA[a],o)iV3}
+e11
+info.lQ
+eJ3;++b){if(!iW3
+eH3)yA1
+for
+iZ1
+a=0;a<iW3
+eI3
+eJ3;++a){o<<" <"
+<<b<<"> = "
+iL2
+iW3
+eI3[a],o);o<<std::endl;}
+}
+o<<std::flush;}
+}
+#endif
+#include <list>
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;l33{yP1
+MarkIncompletes(FPoptimizer_CodeTree::eR{if(tree.Is_Incompletely_Hashed())lD2
+bool
+l82
+eW3
+x51
+l82|=MarkIncompletes(xW
+a));if(l82)tree.Mark_Incompletely_Hashed()i1
+l82;}
+xL1
+FixIncompletes(FPoptimizer_CodeTree::eR{if(tree.Is_Incompletely_Hashed()){x51
+FixIncompletes(xW
+a)yB
+e33);}
+}
+}
+t5{lB
+Sort()iZ3
+Sort();}
+lB
+e33
+bool
+constantfolding){if(constantfolding)ConstantFolding(*this);else
+Sort();data
+xC
+tK1
+e72
+cB
+c03
+Value_t
+c13
+yE1=0;
+#if 0
+long
+double
+value=Value;e9=crc32::calc(iS1
+x83
+char*)&value,sizeof(value));key^=(key<<24);
+#elif 0
+union{e72{x83
+char
+filler1[16]iK2
+v;x83
+char
+filler2[16];}
+buf2;e72{x83
+char
+filler3[sizeof
+cX3)+16-sizeof(xE1)];e9;}
+buf1;}
+data;memset(&data,0,sizeof(data));data.buf2.v=Value;e9=data.buf1.key;
+#else
+int
+exponent
+iK2
+nR2=std::frexp(Value,&tU2
+e9=lT1(exponent+0x8000)&0xFFFF);if(nR2<0){nR2=-nR2;key=key^0xFFFF;}
+else
+key+=0x10000;nR2-=yF2;key<<=39;key|=n51(nR2+nR2)*e62
+1u<<31))<<8;
+#endif
+lP
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+nN1
+T
+cJ2
+std::complex<T> >c03
+std::complex<T>c13
+cB<T>::lY3
+cK2,Value.real());nB
+fphash_t
+temp;cB<T>::lY3
+temp,Value.imag());yE1^=temp.hash2;cK2.hash2^=temp.hash1;}
+}
+;
+#endif
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+tP1
+cJ2
+long>yD
+long
+Value){e9=Value;lP
+#endif
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+tP1
+cJ2
+GmpInt>c03
+GmpInt
+c13
+e9=Value.toInt();lP
+#endif
+xL1
+xK2
+xF::Recalculate_Hash_NoRecursion(){fphash_t
+cK2(n51
+Opcode)<<56,Opcode*iE3(0x1131462E270012B));Depth=1;e23
+Opcode){case
+cImmed:{cB
+xF::lY3
+cK2,Value
+e02
+case
+iU2:{yE1|=n51
+cO1<<48
+lL1((n51
+cO1)*11)^iE3(0x3A83A83A83A83A0);xY3
+case
+cFCall:case
+cPCall:{yE1|=n51
+cO1<<48
+lL1((~n51
+cO1)*7)^3456789;}
+yF3{size_t
+t61=0
+e73
+0;a<iS2;++a){if(iT2
+nP2>t61)t61=iT2
+nP2;yE1+=((iT2.tN2
+hash1*(a+1))>>12)lL1
+iT2.tN2
+hash1
+lL1(3)*iE3(0x9ABCD801357);cK2.hash2*=iE3(0xECADB912345)lL1(~iT2.tN2
+hash2)^4567890;}
+Depth+=t61;}
+}
+if(Hash!=cK2){Hash=cK2;lM2=0;}
+}
+lB
+tE3{MarkIncompletes(*this);FixIncompletes(*this);}
+}
+#endif
+#include <cmath>
+#include <list>
+#include <cassert>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;l33{using
+t5
+yO1
+bool
+x01
+const
+nP1
+long
+count,const
+xK1::SequenceOpCode
+xF&eQ,xK1::eP3&synth,size_t
+max_bytecode_grow_length);static
+const
+e72
+SinCosTanDataType{OPCODE
+whichopcode;OPCODE
+inverse_opcode;enum{eR2,nS2,nZ1,lM1}
+;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}
+}
+,{cL2{tD3
+cCosh,cM2,{tD3
+cNop,{cL2
+cNop,cCosh}
+}
+,{cCosh,cNop,{tD3
+cL2
+cNop}
+}
+,{cNop,cTanh,{cCosh,tD3
+cM2,{cNop,tD3{cNop,cTanh,cCosh,cNop}
+}
+,{cNop,cCosh,{cTanh,tD3
+cM2}
+;}
+t5{lB
+SynthesizeByteCode(eO3
+x83>&eN1,std
+xM3
+xF&Immed,size_t&stacktop_max){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Making bytecode for:\n"
+;l21
+#endif
+while(RecreateInversionsAndNegations()){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"One change issued, produced:\n"
+;l21
+#endif
+tE3;using
+nG1;using
+l33
+lA1;const
+void*g=cG2
+grammar_optimize_recreate;while(ApplyGrammar(*iS1
+Grammar*)g,*this)){tE3;}
+}
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Actually synthesizing, after recreating inv/neg:\n"
+;l21
+#endif
+xK1::eP3
+synth;SynthesizeByteCode(synth,false
+iM2.Pull(eN1,Immed,stacktop_max);}
+lB
+SynthesizeByteCode(xK1::eP3&synth,bool
+MustPopTemps)const{y01*this))yP;}
+for
+iZ1
+a=0;a<12;++a){const
+SinCosTanDataType&data=SinCosTanData[a];if(data.whichopcode!=cNop)iC1!=data.whichopcode)yA1
+c02
+lZ3;lZ3.xA1);lZ3
+iH
+data.inverse_opcode);lZ3.yC2);y01
+lZ3)){synth.tQ
+else
+iC1!=cInv)yA1
+if(GetParam(0)nC!=data.inverse_opcode)yA1
+y01
+GetParam(0))){synth.tQ
+size_t
+found[4];e11
+4;++b){c02
+tree;if(data.tP3]==cNop){tD2
+cInv);c02
+n03;n03.xA1);n03
+iH
+data.tP3^2]);n03.yC2
+c81
+n03);}
+else{tree.xA1
+yB
+eL3
+data.tP3]);}
+tree.yC2);found[b]=synth.xK3
+tree);}
+if(found[data.eR2
+e3
+nS2
+tG
+eR2]iM2.yT
+nS2]);yB1
+cDiv
+tW
+eR2
+e3
+lM1
+tG
+eR2]iM2.yT
+lM1]);yB1
+cMul
+tW
+nZ1
+e3
+lM1
+tG
+nZ1]iM2.yT
+lM1]);yB1
+cRDiv
+tW
+nZ1
+e3
+nS2
+tG
+nZ1]iM2.yT
+nS2]);yB1
+cMul,2,1
+iM2.tQ
+size_t
+n_subexpressions_synthesized=SynthCommonSubExpressions(c92
+e23
+l92{case
+iU2:synth.PushVar(GetVar());lC
+cImmed:t71
+GetImmed());lC
+cAdd:case
+cMul:case
+cMin:case
+cMax:case
+cAnd:case
+cOr:case
+cAbsAnd:case
+cAbsOr:iC1==cMul){bool
+c23
+eW3
+yH
+lX1
+tD1&&isLongInteger(lX1
+x41)){c11=makeLongInteger(lX1
+x41);c02
+tmp(*this,x93
+c02::CloneTag());tmp.i91
+a);tmp
+iW1;if(x01
+tmp,value,xK1::tU1
+xF::AddSequence,synth,MAX_MULI_BYTECODE_LENGTH)){c23=true;xY3}
+}
+if(c23)xY3
+int
+yF1=0;cY2
+done(GetParamCount(),false);c02
+iQ;iQ
+iH
+l92;for(;;){bool
+found
+eW3
+yH
+done[a])yA1
+if(synth.IsStackTop(lX1)){found=true;done[a]=true;lX1.n7
+iQ
+cS
+lX1);if(++yF1>1){yU
+2);iQ.yC2)yC1
+iQ);yF1=yF1-2+1;}
+}
+}
+if(!found)xY3
+yH
+done[a])yA1
+lX1.n7
+iQ
+cS
+lX1);if(++yF1>1){yU
+2);iQ.yC2)yC1
+iQ);yF1=yF1-2+1;}
+}
+if(yF1==0
+yY3
+l92{case
+cAdd:case
+cOr:case
+cAbsOr:t71
+0);lC
+cMul:case
+cAnd:case
+cAbsAnd:t71
+1);lC
+cMin:case
+cMax:t71
+0);break;yF3
+xY3++yF1;}
+assert(n_stacked==1);xY3
+case
+cPow:{tW1
+p0
+i42
+0);tW1
+p1
+i42
+1);if(!p1
+tD1||!isLongInteger
+cR3||!x01
+p0,makeLongInteger
+cR3,xK1::tU1
+xF::MulSequence,synth,MAX_POWI_BYTECODE_LENGTH)){p0.n7
+p1.n7
+yU
+2);e21
+cIf:case
+cAbsIf:{x93
+xK1::eP3::IfData
+ifdata;GetParam(0)e93
+SynthIfStep1(ifdata,l92;GetParam(1)e93
+SynthIfStep2(ifdata);GetParam(2)e93
+SynthIfStep3(ifdata
+e02
+case
+cFCall:case
+cPCall:{for
+iZ1
+a=0;a<l91++a)lX1.n7
+yU
+lT1)GetParamCount());yB1
+0x80000000u|GetFuncNo(),0,0
+e02
+yF3{for
+iZ1
+a=0;a<l91++a)lX1.n7
+yU
+lT1)GetParamCount()e02}
+synth.StackTopIs(*this);if(MustPopTemps&&n_subexpressions_synthesized>0){size_t
+top=synth.GetStackTop(iM2.DoPopNMov(top-1-n_subexpressions_synthesized,top-1);}
+}
+}
+l33{yP1
+x01
+const
+nP1
+long
+count,const
+xK1::SequenceOpCode
+xF&eQ,xK1::eP3&synth,size_t
+max_bytecode_grow_length){if
+cW3!=0){xK1::eP3
+backup=synth;tree.n7
+size_t
+bytecodesize_backup=synth.GetByteCodeSize();xK1::x01
+count
+e63
+size_t
+bytecode_grow_amount=synth.GetByteCodeSize()-bytecodesize_backup;if(bytecode_grow_amount>max_bytecode_grow_length){synth=backup
+i1
+t23
+lD2}
+else{xK1::x01
+count,eQ,synth
+yQ2}
+}
+#endif
+#include <cmath>
+#include <cassert>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;l33{using
+t5;
+#define FactorStack std xM3
+const
+e72
+PowiMuliType{x83
+opcode_square;x83
+opcode_cumulate;x83
+opcode_invert;x83
+opcode_half;x83
+opcode_invhalf;}
+iseq_powi={cSqr,cMul,cInv,cSqrt,cRSqrt}
+,iseq_muli={l52
+x9
+cNeg,l52,l52}
+yO1
+Value_t
+cP1
+const
+PowiMuliType&c33,const
+std
+nA3,n82&stack)eQ3
+1);while(IP<limit){if(n13
+c33.opcode_square){if(!t42
+eT3
+2;yZ
+opcode_invert){nS3=-nS3;yZ
+opcode_half){if(nS3>xH1&&isEvenInteger(eT3
+yF2;yZ
+opcode_invhalf){if(nS3>xH1&&isEvenInteger(eT3
+e62-0.5);++IP;yA1}
+size_t
+xB2=IP
+iK2
+lhs(1);if(n13
+cFetch){lJ1=n43;if(index<y2||size_t(index-y2)>=lB2){IP=xB2;xY3
+lhs=stack[index-y2];goto
+yD2;}
+if(n13
+cDup){lhs=nS3;goto
+yD2;yD2:t91
+nS3);++IP
+iK2
+subexponent=cP1
+c33
+iK
+if(IP>=limit||eN1[IP]!=c33.opcode_cumulate){IP=xB2;xY3++IP;stack.pop_back();nS3+=lhs*subexponent;yA1}
+xY3
+return
+nS3;}
+tK1
+Value_t
+ParsePowiSequence
+iS1
+std
+nA3){n82
+stack;t91
+e62
+1))i1
+cP1
+iseq_powi
+iK}
+tK1
+Value_t
+ParseMuliSequence
+iS1
+std
+nA3){n82
+stack;t91
+e62
+1))i1
+cP1
+iseq_muli
+iK}
+tK1
+class
+CodeTreeParserData{e43
+iX2
+CodeTreeParserData(bool
+k_powi):stack(),clones(),keep_powi(k_powi){}
+void
+Eat
+iZ1
+tL3,OPCODE
+opcode
+nQ
+xM;xM
+iH
+opcode);eK
+params=Pop(tL3
+yR1
+tL2;if(!keep_powi)e23
+opcode){case
+cTanh:{yZ2
+sinh,cosh;sinh
+iH
+cSinh);sinh
+cS
+xM
+c43
+sinh
+iW1;cosh
+iH
+cCosh);cosh
+c91
+xM
+c43
+cosh
+iW1
+tX
+pow;pow
+iH
+cPow);pow
+c91
+cosh);pow.yA
+nU2));pow
+iW1;xM
+iH
+cMul);xM.nB1
+0,sinh);xM
+c91
+pow
+e02
+case
+cTan:{yZ2
+sin,cos;sin
+iH
+cSin);sin
+cS
+xM
+c43
+sin
+iW1;cos
+iH
+cCos);cos
+c91
+xM
+c43
+cos
+iW1
+tX
+pow;pow
+iH
+cPow);pow
+c91
+cos);pow.yA
+nU2));pow
+iW1;xM
+iH
+cMul);xM.nB1
+0,sin);xM
+c91
+pow
+e02
+case
+cPow:{iT1&p0=xM
+l8
+0);iT1&p1=xM
+l8
+1);if(p1
+nC==cAdd){eK
+mulgroup(p1.GetParamCount()iY1
+0;a<p1.l91++a
+nQ
+pow;pow
+iH
+cPow);pow
+cS
+p0);pow
+cS
+p1
+n93
+pow
+iW1;mulgroup[a
+tQ3
+pow);}
+xM
+iH
+cMul
+yR1
+mulgroup);}
+xY3
+yF3
+xY3
+xM.e33!keep_powi);lA2,false);
+#ifdef DEBUG_SUBSTITUTIONS
+iA1<<tL3<<", "
+<<FP_GetOpcodeName(opcode)<<"->"
+<<FP_GetOpcodeName(xM
+nC)<<": "
+iK3
+xM);iB1
+xM);
+#endif
+t91
+xM
+cN2
+EatFunc
+iZ1
+tL3,OPCODE
+opcode,x83
+funcno
+nQ
+xM=CodeTreeFuncOp
+xF(opcode,funcno);eK
+params=Pop(tL3
+yR1
+tL2;xM.yC2);
+#ifdef DEBUG_SUBSTITUTIONS
+iA1<<tL3<<", "
+iK3
+xM);iB1
+xM);
+#endif
+lA2);t91
+xM
+cN2
+AddConst(yL1
+nQ
+xM=CodeTreeImmed(value);lA2);Push(xM
+cN2
+AddVar
+lT1
+varno
+nQ
+xM=CodeTreeVar
+xF(varno);lA2);Push(xM
+cN2
+SwapLastTwoInStack(){tA1
+1
+tQ3
+tA1
+2]cN2
+Dup(){Fetch(lB2-1
+cN2
+Fetch
+iZ1
+which){Push(stack[which]);}
+nN1
+T>void
+Push(T
+tree){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<iK3
+tree);iB1
+tree);
+#endif
+t91
+tree
+cN2
+PopNMov
+iZ1
+target,size_t
+source){stack[target]=stack[source];stack
+xF3
+target+1);}
+yZ2
+yE2{clones.clear()tX
+nS3(stack.back());stack
+xF3
+lB2-1)i1
+nS3;}
+eK
+Pop
+iZ1
+n_pop){eK
+nS3(n_pop);for
+lT1
+n=0;n<n_pop;++n)nS3[n
+tQ3
+tA1
+n_pop+n]);
+#ifdef DEBUG_SUBSTITUTIONS
+for
+iZ1
+n=n_pop;n-->0;){iA1
+iL2
+nS3[n]);iB1
+nS3[n]);}
+#endif
+stack
+xF3
+lB2-n_pop)i1
+nS3;}
+size_t
+GetStackTop(c01
+lB2;}
+private:void
+FindClone(yZ2&,bool=true)yP;}
+private:eK
+stack;std::multimap<fphash_t,yZ2>clones;bool
+keep_powi;private:CodeTreeParserData
+iS1
+CodeTreeParserData&);CodeTreeParserData&eM1=iS1
+CodeTreeParserData&);}
+yO1
+e72
+IfInfo{yZ2
+eS2
+tX
+thenbranch;size_t
+endif_location;IfInfo():eS2(),thenbranch(),endif_location(){}
+}
+;}
+t5{lB
+GenerateFrom
+iS1
+x93
+FunctionParserBase
+xF::Data&x33,bool
+keep_powi){eK
+xH2;xH2.xH3
+x33.mVariablesAmount);for
+lT1
+n=0;n<x33.mVariablesAmount;++n){xH2
+c52
+CodeTreeVar
+xF(n+iU2));}
+GenerateFrom(x33,xH2,keep_powi);}
+lB
+GenerateFrom
+iS1
+x93
+FunctionParserBase
+xF::Data&x33,const
+x5&xH2,bool
+keep_powi){const
+eO3
+x83>&eN1=x33.mByteCode;const
+std
+xM3
+xF&Immed=x33.mImmed;
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"ENTERS GenerateFrom()\n"
+;
+#endif
+CodeTreeParserData
+xF
+sim(keep_powi);eO3
+IfInfo
+xF>eJ
+eK3
+IP=0,DP=0;;++IP){tO2:while(!eJ
+eU3&&(eJ.eA==IP||(IP<n41&&n13
+cJump&&eJ
+e81.nX2))){c02
+elsebranch=sim.yE2
+nA2
+eJ.back().eS2)nA2
+eJ
+e81)nA2
+elsebranch)yR
+3,cIf);eJ.pop_back();}
+if(IP>=n41)break;x83
+opcode=eN1[IP];if(eS3
+cSqr||opcode==cDup||eS3
+cInv&&!IsIntType
+xF::nS3)||opcode==cNeg||opcode==cSqrt||opcode==cRSqrt||opcode==cFetch)){size_t
+was_ip=IP
+iK2
+eD2
+ParsePowiSequence
+xF(eN1,IP,eJ
+eU3?n41:eJ.eA,sim.xH
+1);if(exponent!=e62
+1.0)){xG
+exponent
+iU3);goto
+tO2;}
+if
+eS3
+cDup||opcode==cFetch||opcode==cNeg)l14
+xT2=ParseMuliSequence
+xF(eN1,IP,eJ
+eU3?n41:eJ.eA,sim.xH
+1);if(xT2!=e62
+1.0)){xG
+xT2)yR
+2,cMul);goto
+tO2;}
+}
+IP=was_ip;}
+if(nB2>=iU2){lJ1=opcode-iU2
+nA2
+xH2[index]);}
+else{e23
+nB2){case
+cIf:case
+cAbsIf:{eJ
+xF3
+eJ
+eJ3+1);c02
+res(sim.yE2);eJ.back().eS2.swap(res);eJ.eA=n41;IP+=2;yA1}
+case
+cJump:{c02
+res(sim.yE2);eJ
+e81.swap(res);eJ.eA=eN1[IP+1]+1;IP+=2;yA1}
+case
+cImmed:xG
+Immed[DP++]);lC
+cDup:sim.Dup();lC
+cNop:lC
+cFCall:{x83
+funcno=n43;assert(funcno<fpdata.mFuncPtrs.size());x83
+params=x33.mFuncPtrs
+n53
+mParams;sim.EatFunc(params,nB2,funcno
+e02
+case
+cPCall:{x83
+funcno=n43;assert(funcno<fpdata.iI3.size());const
+FunctionParserBase
+xF&p=*x33.iI3
+n53
+mParserPtr;x83
+params=x33.iI3
+n53
+mParams;x5
+paramlist=sim.Pop(tL2;c02
+tP2;tP2.GenerateFrom(*p.mData,paramlist)nA2
+tP2
+e02
+case
+cInv:xG
+1
+c32
+cDiv);lC
+cNeg
+nC2
+cNeg);break;xG
+0
+c32
+cSub);lC
+cSqr:xG
+2
+xN1
+cSqrt:xG
+yF2
+xN1
+cRSqrt:xG
+e62-0.5)xN1
+cCbrt:xG
+e62
+1)/e62
+3)xN1
+cDeg:xG
+fp_const_rad_to_deg
+xF())yG1
+cRad:xG
+fp_const_deg_to_rad
+xF())yG1
+cExp:iR)goto
+yM3;xG
+fp_const_e
+xF()c32
+cPow);lC
+cExp2:iR)goto
+yM3;xG
+2.0
+c32
+cPow);lC
+cCot
+nC2
+cTan);iR)x1
+cCsc
+nC2
+cSin);iR)x1
+cSec
+nC2
+cCos);iR)x1
+cInt:
+#ifndef __x86_64
+iR)n23
+1,cInt
+e02
+#endif
+xG
+yF2)tQ2
+yR
+1,cFloor);lC
+cLog10
+nC2
+c53
+fp_const_log10inv
+xF())yG1
+cLog2
+nC2
+c53
+fp_const_log2inv
+xF())yG1
+cQ3:n33
+c53
+fp_const_log2inv
+xF())yR
+3,cMul);lC
+cHypot:xG
+2
+iU3);tS3
+xG
+2
+iU3)tQ2;xG
+yF2
+xN1
+cSinCos:sim.Dup()yR
+1,cSin);n33
+cCos);lC
+cSinhCosh:sim.Dup()yR
+1,cSinh);n33
+cCosh);lC
+cRSub:tS3
+case
+cSub:iR)n23
+2,cSub
+e02
+xG-1)yR
+2,cMul)tQ2;lC
+cRDiv:tS3
+case
+cDiv:iR||IsIntType
+xF::nS3)n23
+2,cDiv
+e02
+xG-1
+iU3)yG1
+cAdd:case
+cMul:case
+cMod:case
+cPow:case
+cEqual:case
+cLess:case
+cGreater:case
+i51:case
+cLessOrEq:case
+cGreaterOrEq:case
+cAnd:case
+cOr:case
+cAbsAnd:case
+cAbsOr:sim.Eat(2,tB1
+lC
+cNot:case
+cNotNot:case
+cC3:case
+cAbsNotNot
+nC2
+tB1
+lC
+cFetch:sim.Fetch(n43);lC
+cPopNMov:{x83
+stackOffs_target=n43;x83
+stackOffs_source=n43;sim.PopNMov(stackOffs_target,stackOffs_source
+e02
+yF3
+yM3:;x83
+funcno=opcode-cAbs;assert(funcno<FUNC_AMOUNT);const
+FuncDefinition&func=Functions[funcno]yR
+func.params,tB1
+xY3}
+}
+Become(sim.yE2);
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Produced tree:\n"
+;l21
+#endif
+}
+}
+#endif
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <assert.h>
+#define FP_MUL_COMBINE_EXPONENTS
+l33{using
+l33
+FUNCTIONPARSERTYPES;using
+t5
+yO1
+static
+void
+AdoptChildrenWithSameOpcode(eR{
+#ifdef DEBUG_SUBSTITUTIONS
+bool
+nT2
+eW3
+#endif
+for
+l41
+if(xW
+a)nC==t72){
+#ifdef DEBUG_SUBSTITUTIONS
+if(!nT2)cH2"Before assimilation: "
+cR
+nT2=true;}
+#endif
+tree.AddParamsMove(xW
+a).GetUniqueRef().lJ2),a);}
+#ifdef DEBUG_SUBSTITUTIONS
+if(nT2)cH2"After assimilation: "
+cR}
+#endif
+}
+}
+t5{xL1
+ConstantFolding(eR{tree.Sort();
+#ifdef DEBUG_SUBSTITUTIONS
+void*c63=0;cV2<<"["
+<<(&c63)<<"]Runs ConstantFolding for: "
+cR
+DumpHashes(tree
+lE2
+std::flush;
+#endif
+if(false){redo:;tree.Sort();
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"["
+<<(&c63)<<"]Re-runs ConstantFolding: "
+cR
+DumpHashes(tree);
+#endif
+}
+if(t72!=cImmed){yD3
+p=CalculateResultBoundaries(tree);if(p
+yI&&p
+e61&&p
+yM==p
+tG1{nU
+p
+yM);nD}
+if(false){ReplaceTreeWithOne:nU
+e62
+1));goto
+do_return;ReplaceTreeWithZero:nU
+xG1;goto
+do_return;ReplaceTreeWithParam0:
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Before replace: "
+;cV2<<std::hex<<'['
+eJ1
+hash1<<','
+eJ1
+hash2<<']'<<std::dec
+cR
+#endif
+tree.eF2
+0));
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"After replace: "
+;cV2<<std::hex<<'['
+eJ1
+hash1<<','
+eJ1
+hash2<<']'<<std::dec
+cR
+#endif
+cJ
+c73(t72){case
+cImmed:lC
+iU2:lC
+cAnd:case
+cAbsAnd
+cK
+bool
+c5
+eW3
+for
+l41{if(!c83
+a)))c5=true;cA3
+a),t72==cAbsAnd)){case
+xX3
+t7
+iF2:iZ);lC
+lZ1
+c73
+l51){case
+0:iD
+1:tD2
+t72==cAnd?cNotNot:cAbsNotNot);cJ
+yF3
+cZ2
+cAnd||!c5)if(ConstantFolding_AndLogic(tB2
+e21
+cOr:case
+cAbsOr
+cK
+bool
+c5
+eW3
+for
+l41{if(!c83
+a)))c5=true;cA3
+a),t72==cAbsOr)tN1
+iD
+l03
+iZ);lC
+lZ1
+c73
+l51){case
+0
+t7
+1:tD2
+t72==cOr?cNotNot:cAbsNotNot);cJ
+yF3
+cZ2
+cOr||!c5)if(ConstantFolding_OrLogic(tB2
+e21
+cNot:case
+cC3:{x83
+n61
+0;e23
+c93){case
+cEqual:n61
+i51;lC
+i51:n61
+cEqual;lC
+cLess:n61
+cGreaterOrEq;lC
+cGreater:n61
+cLessOrEq;lC
+cLessOrEq:n61
+cGreater;lC
+cGreaterOrEq:n61
+cLess;lC
+cNotNot:n61
+cNot;lC
+cNot:n61
+cNotNot;lC
+cC3:n61
+cAbsNotNot;lC
+cAbsNotNot:n61
+cC3;break;yF3
+xY3
+if(opposite){tD2
+OPCODE(opposite)yB
+SetParamsMove(xW
+0).GetUniqueRef().lJ2));cJ
+c73(lY1
+0)cU3
+cQ1){case
+iF2
+t7
+l03
+iD
+lZ1
+cZ2
+cNot&&GetPositivityInfo(xW
+0))==iF2)tD2
+cC3);if(c93==cIf||c93==cAbsIf
+nQ
+iZ2=xW
+0);iT1&ifp1=iZ2
+l8
+1);iT1&ifp2=iZ2
+l8
+2);if(ifp1
+nC
+iY3
+ifp1
+cQ1
+cD3
+ifp1
+nC==cNot?cNotNot:cAbsNotNot);tR2
+c43
+n63)cE3
+nO2;p2
+tT3
+iI
+if(ifp2
+nC
+iY3
+ifp2
+cQ1
+cD3
+t72);tR2);n63)cE3
+iH
+ifp2
+nC==cNot?cNotNot:cAbsNotNot);p2
+tT3
+l8
+0)iI
+e21
+cNotNot:case
+cAbsNotNot:{if(c83
+0)))n73
+cA3
+0),t72==cAbsNotNot)){case
+xX3
+t7
+iF2:iD
+lZ1
+cZ2
+cNotNot&&GetPositivityInfo(xW
+0))==iF2)tD2
+cAbsNotNot);if(c93==cIf||c93==cAbsIf
+nQ
+iZ2=xW
+0);iT1&ifp1=iZ2
+l8
+1);iT1&ifp2=iZ2
+l8
+2);if(ifp1
+nC
+iY3
+ifp1
+cQ1{tree.SetParam(0,iZ2
+l8
+0)yB
+AddParam(ifp1)cE3
+nO2;p2
+tT3
+iI
+if(ifp2
+nC
+iY3
+ifp2
+cQ1
+cD3
+t72);tR2);n63
+yB
+AddParam(ifp2
+yB
+eL3
+iZ2
+nC);cJ}
+e21
+cIf:case
+cAbsIf:{if(ConstantFolding_IfOperations(tB2
+xY3
+case
+cMul:{NowWeAreMulGroup:;AdoptChildrenWithSameOpcode(tree)iK2
+nH1=e62
+1);size_t
+lC2=0;bool
+nI1
+eW3
+x51{if(!xW
+tC1
+yA1
+Value_t
+immed=xW
+a)x41;if(immed==xG1
+goto
+ReplaceTreeWithZero;nH1*=immed;++lC2;}
+if(lC2>1||(lC2==1&&lJ3
+nH1,e62
+1))))nI1=true;if(nI1){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"cMul: Will add new "
+iJ3
+nH1<<"\n"
+;
+#endif
+for
+l41
+if(xW
+tC1{
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<" - For that, deleting "
+iJ3
+xW
+a)x41;cV2<<"\n"
+;
+#endif
+tU3(!lJ3
+nH1,e62
+1)))tree
+cS
+eA1
+nH1));c73
+l51){case
+0:iD
+1:n73
+yF3
+if(ConstantFolding_MulGrouping(tB2
+if(ConstantFolding_MulLogicItems(tB2
+e21
+cAdd
+cK
+Value_t
+nD2=0.0;size_t
+lC2=0;bool
+nI1
+eW3
+x51{if(!xW
+tC1
+yA1
+Value_t
+immed=xW
+a)x41;nD2+=immed;++lC2;}
+if(lC2>1||(lC2==1&&nD2==xG1)nI1=true;if(nI1){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"cAdd: Will add new "
+iJ3
+nD2<<"\n"
+;cV2<<"In: "
+cR
+#endif
+for
+l41
+if(xW
+tC1{
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<" - For that, deleting "
+iJ3
+xW
+a)x41;cV2<<"\n"
+;
+#endif
+tU3(!(nD2==e62
+0.0)))tree
+cS
+eA1
+nD2));c73
+l51){case
+0
+t7
+1:n73
+yF3
+if(ConstantFolding_AddGrouping(tB2
+if(ConstantFolding_AddLogicItems(tB2
+e21
+cMin
+cK
+size_t
+yI2=0;yD3
+e4;x51{while(a+1<tree.GetParamCount()&&xW
+a)xI
+xW
+a+1)))iZ+1);yE3
+max.cF3(!e4
+e61||(p
+tG1<e4
+tG1){e4
+nL3=p
+nL3;e4
+e61=true;yI2=a;}
+}
+if(e4
+e61)for
+l41{yE3
+min.cF3
+a!=yI2&&p
+yM>=e4
+tG1
+tU3
+l51==1){n73
+e21
+cMax
+cK
+size_t
+yI2=0;yD3
+eY;x51{while(a+1<tree.GetParamCount()&&xW
+a)xI
+xW
+a+1)))iZ+1);yE3
+min.cF3(!eY
+yI||p
+yM>eY
+yM)){eY
+yM=p
+yM;eY
+yI=true;yI2=a;}
+}
+if(eY
+yI){for
+l41{yE3
+max.cF3
+a!=yI2&&(p
+tG1<eY
+yM){iZ);}
+}
+}
+if
+l51==1){n73
+e21
+cEqual:case
+i51:case
+cLess:case
+cGreater:case
+cLessOrEq:case
+cGreaterOrEq:if(ConstantFolding_Comparison(tB2
+lC
+cAbs:{yD3
+tY
+xW
+0));if
+iE
+n73
+if
+iF{tD2
+cMul
+yB
+yA
+e62
+1)));goto
+NowWeAreMulGroup;}
+if(c93==cMul){iT1&p=xW
+0);eK
+n83;eK
+cP2
+e73
+0;a<p.l91++a){tY
+p
+n93
+if
+iE{n83
+c52
+p
+n93}
+if
+iF{cP2
+c52
+p
+n93}
+}
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"Abs: mul group has "
+<<n83
+eJ3<<" pos, "
+<<cP2
+eJ3<<"neg\n"
+;
+#endif
+if(!n83
+eU3||!cP2
+eU3){
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"AbsReplace-Before: "
+iL2
+tree
+lE2"\n"
+<<std::flush;DumpHashes
+nV2);
+#endif
+yZ2
+e13;e13
+iH
+cMul
+iY1
+0;a<p.l91++a){tY
+p
+n93
+if(iE||iF){}
+else
+e13
+cS
+p
+n93}
+e13
+iW1
+tX
+nB3;nB3
+iH
+cAbs);nB3
+c91
+e13);nB3
+iW1
+tX
+iG
+cMul);mulgroup
+c91
+nB3);cA1
+AddParamsMove(n83);if(!cP2
+eU3){if(cP2
+eJ3%2)cA1
+yA
+nU2));cA1
+AddParamsMove(cP2);}
+tree.Become
+eH2);
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"AbsReplace-After: "
+;DumpTree
+nV2
+lE2"\n"
+<<std::flush;DumpHashes
+nV2);
+#endif
+goto
+NowWeAreMulGroup;}
+}
+xY3
+#define HANDLE_UNARY_CONST_FUNC(funcname) nP){nU funcname(lR));nD
+case
+cLog:i83(fp_log);if(c93==cPow
+nQ
+pow=xW
+0);if(GetPositivityInfo(pow
+l8
+0))==iF2)iV1
+t2
+yB
+lU
+if(GetEvennessInfo(pow
+l8
+1))==iF2)iV1()tX
+abs;abs
+iH
+cAbs);abs
+c91
+pow
+c43
+abs.Rehash
+t2);pow.nB1
+0,abs
+yB
+lU}
+iP1
+c93==cAbs
+nQ
+pow=xW
+0)l8
+0);if(pow
+nC==cPow)iV1()tX
+abs;abs
+iH
+cAbs);abs
+c91
+pow
+c43
+abs.Rehash
+t2);pow.nB1
+0,abs
+yB
+lU}
+lC
+cAcosh:i83(fp_acosh);lC
+cAsinh:i83(fp_asinh);lC
+cAtanh:i83(fp_atanh);lC
+cAcos:i83(fp_acos);lC
+cAsin:i83(fp_asin);lC
+cAtan:i83(fp_atan);lC
+cCosh:i83(fp_cosh);lC
+cSinh:i83(fp_sinh);lC
+cTanh:i83(fp_tanh);lC
+cSin:i83(fp_sin);lC
+cCos:i83(fp_cos);lC
+cTan:i83(fp_tan);lC
+cCeil:if(n5
+i83(fp_ceil);lC
+cTrunc:if(n5
+i83(fp_trunc);lC
+cFloor:if(n5
+i83(fp_floor);lC
+cInt:if(n5
+i83(fp_int);lC
+cCbrt:i83(fp_cbrt);lC
+cSqrt:i83(fp_sqrt);lC
+cExp:i83(fp_exp);lC
+cLog2:i83(fp_log2);lC
+cLog10:i83(fp_log10);lC
+cQ3:if
+lI
+fp_log2(lR)*xW
+nC3
+cArg:i83(fp_arg);lC
+cConj:i83(fp_conj);lC
+cImag:i83(fp_imag);lC
+cReal:i83(fp_real);lC
+cPolar:if
+lI
+fp_polar
+e51
+lC
+cMod:if
+lI
+fp_mod
+e51
+lC
+cAtan2:{yD3
+tY
+xW
+yP2
+p1=tZ
+1));nP&&lJ3
+lR,xG1){if(p1
+e61&&(p1
+tG1<xG1{nU
+fp_const_pi
+cH3
+if(p1
+yI&&p1
+yM>=tE1
+xG1;nD}
+if(eI1
+lJ3
+xW
+i8,xG1){if(p0
+e61&&(p0
+tG1<xG1{nU-fp_const_pihalf
+cH3
+if
+cN3
+p0
+yM>xG1{nU
+fp_const_pihalf
+cH3}
+if
+lI
+fp_atan2
+e51
+if((p1
+yI&&p1
+yM>xG1||(p1
+e61&&(p1
+tG1<fp_const_negativezero
+xF())nQ
+yJ2;yJ2
+iH
+cPow);yJ2
+c91
+xW
+1));yJ2.yA
+nU2));yJ2
+iW1
+tX
+yK2;yK2
+iH
+cMul);yK2
+c91
+xW
+0));yK2
+c91
+yJ2);yK2
+cY
+cAtan
+yB
+nB1
+0,yK2
+yB
+i91
+1);e21
+cPow:{if(ConstantFolding_PowOperations(tB2
+xY3
+case
+cDiv:nP&&eI1
+xW
+i8!=tE1
+lR/xW
+nC3
+cInv:nP&&lR!=tE1
+e62
+1)/lR);nD
+lC
+cSub:if
+lI
+lR-xW
+nC3
+cNeg:nP){nU-lR);nD
+lC
+cRad:nP){nU
+RadiansToDegrees
+eG2
+cDeg:nP){nU
+DegreesToRadians
+eG2
+cSqr:nP){nU
+lR*lR);nD
+lC
+cExp2:i83(fp_exp2);lC
+cRSqrt:nP){nU
+e62
+1)/fp_sqrt
+eG2
+cCot:c22
+fp_tan(lZ
+cSec:c22
+fp_cos(lZ
+cCsc:c22
+fp_sin(lZ
+cHypot:if
+lI
+fp_hypot
+e51
+lC
+cRDiv:case
+cRSub:case
+cDup:case
+cFetch:case
+cPopNMov:case
+cSinCos:case
+cSinhCosh:case
+cNop:case
+cJump:lC
+cPCall:case
+cFCall:xY3
+do_return:;
+#ifdef DEBUG_SUBSTITUTIONS
+cV2<<"["
+<<(&c63)<<"]Done ConstantFolding, result: "
+cR
+DumpHashes(tree);
+#endif
+}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+t5{xL1
+yD3::set_abs(nL
+bool
+has_negative=!min.known||min.val<e62);bool
+has_positive=!cG3||max.val>e62);bool
+crosses_axis=has_negative&&has_positive;cI1
+xF
+newmax;if(min.cF3
+cG3)newmax.set(fp_max(i61,i71);if(crosses_axis
+cI3
+e62));cJ3
+min.cF3
+cG3
+cI3
+fp_min(i61,i71);iP1
+min.known
+cI3
+i61);else
+min.set(i71;}
+max=newmax;}
+xL1
+yD3::set_neg(){std::swap(min,max);min.val=-min.val;max.val=-max.val;}
+yP1
+IsLogicalTrueValue
+iS1
+yD3&p,bool
+abs){if(nB
+IsIntType
+xF::nS3){if(p
+yI&&p
+yM>=e62
+1))lD2
+if(!abs&&p
+e61
+t43<=nU2)lD2}
+cJ3
+p
+yI&&p
+yM>=yF2)lD2
+if(!abs&&p
+e61
+t43<=e62-0.5))lD2
+eE3
+t23
+yP1
+IsLogicalFalseValue
+iS1
+yD3&p,bool
+abs){if(nB
+IsIntType
+xF::nS3){if(abs)eG3
+e61
+l61
+1);else
+eG3
+yI&&p
+e61&&p
+yM>nU2
+l61
+1);}
+cJ3
+abs)eG3
+e61
+l61
+0.5);else
+eG3
+yI&&p
+e61&&p
+yM>e62-0.5)l61
+0.5);}
+}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;using
+t5;t5{tK1
+yD3
+CalculateResultBoundaries
+iS1
+eR
+#ifdef DEBUG_SUBSTITUTIONS_extra_verbose
+{using
+l33
+FUNCTIONPARSERTYPES;yD3
+tmp=CalculateResultBoundaries_do(tree
+lE2"Estimated boundaries: "
+;if(tmp
+yI)cV2<<tmp
+yM;else
+cV2<<"-inf"
+;cV2<<" .. "
+;if(tmp
+e61)cV2<<tmp
+nL3;else
+cV2<<"+inf"
+;cV2<<": "
+iL2
+tree
+lE2
+std::endl
+i1
+tmp;}
+tK1
+yD3
+yZ2::CalculateResultBoundaries_do
+iS1
+eR
+#endif
+{iS
+yH1(-fp_const_pihalf
+xF(),fp_const_pihalf
+xF());iS
+pi_limits(-fp_const_pi
+xF(),fp_const_pi
+xF());iS
+abs_pi_limits(xH1,fp_const_pi
+xF());iS
+plusminus1_limits(nU2,e62
+1));using
+l33
+std;e23
+t72){case
+cImmed:nM
+tree
+x41
+cU3
+x41)t83
+cAnd:case
+cAbsAnd:case
+cOr:case
+cAbsOr:case
+cNot:case
+cC3:case
+cNotNot:case
+cAbsNotNot:case
+cEqual:case
+i51:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:{nM
+xH1,e62
+1));}
+case
+cAbs:tW3
+set_abs();tK
+cLog:tW3
+tS2
+fp_log);nD3
+fp_log);tK
+cLog2:tW3
+tS2
+fp_log2);nD3
+fp_log2);tK
+cLog10:tW3
+tS2
+fp_log10);nD3
+fp_log10);tK
+cAcosh:tW3
+min.tL1
+cGreaterOrEq
+tH1
+fp_acosh
+tR3
+cGreaterOrEq
+tH1
+fp_acosh);tK
+cAsinh:tW3
+min.set(fp_asinh);tO
+set(fp_asinh);tK
+cAtanh:tW3
+min.n3-1),fp_atanh
+tR3
+cLess
+tH1
+fp_atanh);tK
+cAcos:lD
+nM(tO
+cF3(tO
+val)<e62
+1))?fp_acos(tO
+val):xH1,(m
+yI&&(m
+yM)>=nU2)?fp_acos(m
+yM):fp_const_pi
+xF());}
+case
+cAsin:tW3
+min.n3-1),fp_asin,yH1
+yM
+tR3
+cLess
+tH1
+fp_asin,yH1
+tG1;tK
+cAtan:tW3
+min.set(fp_atan,yH1
+yM);tO
+set(fp_atan,yH1
+tG1;tK
+cAtan2:{nP&&lJ3
+lR,xG1)yP
+abs_pi_limits;}
+if(eI1
+lJ3
+xW
+i8,xG1)yP
+yH1;eE3
+pi_limits;}
+case
+cSin:lD
+bool
+x11=!m
+yI||!tO
+known||(tO
+val-m
+yM)>=(yK
+x11)tM
+Value_t
+min=cK3
+m
+yM,yK
+min<xG1
+min
+yN
+Value_t
+max=cK3
+tO
+val,yK
+max<xG1
+max
+yN
+if(max<min)max
+yN
+bool
+y21=(min<=fp_const_pihalf
+xF()&&max>=fp_const_pihalf
+xF());bool
+nJ1=(min<=cD&&max>=cD);if(y21&&nJ1)tM
+if(nJ1)nM
+nU2,nW2
+if(y21)nM
+yL2
+e62
+1));nM
+yL2
+nW2}
+case
+cCos:lD
+if(m
+yI)m
+yM+=fp_const_pihalf
+xF();if(xI2
+tO
+val+=fp_const_pihalf
+xF();bool
+x11=!m
+yI||!tO
+known||(tO
+val-m
+yM)>=(yK
+x11)tM
+Value_t
+min=cK3
+m
+yM,yK
+min<xG1
+min
+yN
+Value_t
+max=cK3
+tO
+val,yK
+max<xG1
+max
+yN
+if(max<min)max
+yN
+bool
+y21=(min<=fp_const_pihalf
+xF()&&max>=fp_const_pihalf
+xF());bool
+nJ1=(min<=cD&&max>=cD);if(y21&&nJ1)tM
+if(nJ1)nM
+nU2,nW2
+if(y21)nM
+yL2
+e62
+1));nM
+yL2
+nW2}
+case
+cTan:{nM);}
+case
+cCeil:lD
+tO
+i81
+cFloor:lD
+m
+yI1
+tK
+cTrunc:lD
+m
+yI1
+tO
+i81
+cInt:lD
+m
+yI1
+tO
+i81
+cSinh:tW3
+min.set(fp_sinh);tO
+set(fp_sinh);tK
+cTanh:tW3
+min.set(fp_tanh,plusminus1_limits.min);tO
+set(fp_tanh,plusminus1_limits.max);tK
+cCosh:lD
+if(m
+yI){if(xI2{if(m
+yM>=xH1&&tO
+val>=xG1{m
+yM
+xS}
+iP1(m
+yM)<xH1&&tO
+val>=xG1
+l14
+tmp
+xS
+if(tmp>tO
+val)tO
+val=tmp;m
+yM=e62
+1);}
+else{m
+yM
+xS
+std::swap(m
+yM,tO
+val);}
+}
+cJ3
+m
+yM>=xG1{m.tL
+m
+yM=fp_cosh(m
+yM);}
+else{m.tL
+m
+yM=e62
+1);}
+}
+}
+else{m
+yI=true;m
+yM=e62
+1);if(xI2{m
+yM=fp_cosh(tO
+val);m.tL}
+else
+m.tL}
+tK
+cIf:case
+cAbsIf:{yD3
+res1=tZ
+1));yD3
+res2=tZ
+2));if(!res2
+yI)res1
+yI
+eW3
+iP1
+res1
+yI&&(res2
+yM)<res1
+yM)res1
+yM=res2
+yM;if(!res2
+e61)res1.tL
+iP1
+res1
+e61&&(res2
+tG1>res1
+tG1
+res1
+nL3=res2
+nL3
+i1
+res1;}
+case
+cMin:{bool
+iT
+eW3
+bool
+iU
+eW3
+e83;x7
+m
+tZ3
+m
+yI)iT
+iN3
+yI||(m
+yM)<nF3)nF3=m
+yM;if(!xI2
+iU
+iN3
+e61||(tO
+val)<nG3
+nH3=tO
+val;}
+if(iT)nK3
+iU)nQ3
+return
+nR3
+cMax:{bool
+iT
+eW3
+bool
+iU
+eW3
+e83;x7
+m
+tZ3
+m
+yI)iT
+iN3
+yI||m
+yM>nF3)nF3=m
+yM;if(!xI2
+iU
+iN3
+e61||tO
+val>nG3
+nH3=tO
+val;}
+if(iT)nK3
+iU)nQ3
+return
+nR3
+cAdd:{e83(xH1,xG1;x7
+item=tZ
+a));if(item
+yI)nF3+=item
+yM;else
+nK3
+item
+e61)nH3+=item
+nL3;else
+nQ3
+if(!nI3&&!nJ3)xY3
+if(nI3&&nJ3&&nF3>nG3
+std::swap(nF3,nG3
+i1
+nR3
+cMul:{e72
+Value{enum
+nT3{tT2,lG2,PlusInf}
+;nT3
+eB
+iK2
+value;Value(nT3
+t):eB(t),value(0){}
+Value
+cX3
+v):eB(tT2),value(v){}
+bool
+cQ2
+c01
+eB==lG2||(eB==tT2&&value<xG1;}
+void
+eM1*=iS1
+Value&rhs){if(eB==tT2&&rhs.eB==tT2)value*=rhs.value;else
+eB=(cQ2)!=rhs.cQ2)?lG2:PlusInf);}
+iD2<iS1
+Value&rhs
+c01(eB==lG2&&rhs.eB!=lG2)||(eB==tT2&&(rhs.eB==PlusInf||(rhs.eB==tT2&&value<rhs.value)));}
+}
+;e72
+yJ1{Value
+yN2,yO2;yJ1():yN2(Value::PlusInf),yO2(Value::lG2){}
+void
+xJ2
+Value
+cM3,const
+Value&value2){cM3*=value2;if(cM3<yN2)yN2=cM3;if(yO2<cM3)yO2=cM3;}
+}
+;e83(nM3
+x7
+item
+tZ3
+item
+yI&&!item
+e61)nM);Value
+iP3=nI3?Value(nF3):xC2
+lG2);Value
+nU3=nJ3?Value(nG3:xC2
+PlusInf);Value
+nV3=item
+yI?Value(item
+yM):xC2
+lG2);Value
+nW3=item
+e61?Value(item
+tG1:xC2
+PlusInf);yJ1
+range;range.xJ2
+iP3,nV3);range.xJ2
+iP3,nW3);range.xJ2
+nU3,nV3);range.xJ2
+nU3,nW3);if(range.yN2.eB==Value::tT2)nF3=range.yN2.value;else
+nK3
+range.yO2.eB==Value::tT2)nH3=range.yO2.value;else
+nQ3
+if(!nI3&&!nJ3)xY3
+if(nI3&&nJ3&&nF3>nG3
+std::swap(nF3,nG3
+i1
+nR3
+cMod:{yD3
+x=tZ
+yP2
+y=tZ
+1));if(y
+e61){if(y
+nL3>=xG1{if(!x
+yI||(x
+yM)<xG1
+nM-y
+nL3,y
+tG1;i03
+xH1,y
+tG1;}
+cJ3!x
+e61||(x
+tG1>=xG1
+nM
+y
+nL3,-y
+tG1;i03
+y
+nL3,fp_const_negativezero
+xF());}
+}
+i03);}
+case
+cPow:{if(eI1
+xW
+i8==xG1{nM
+nM3}
+nP&&lR==xG1{nM
+xH1,xG1;}
+nP&&lJ3
+lR
+nH2
+nM
+nM3}
+if(eI1
+xW
+i8>xH1&&GetEvennessInfo(xW
+1))==iF2)l14
+eD2
+xW
+i8;yD3
+tmp=tZ
+yP2
+nS3;nI3=true;nF3=0;if(tmp
+yI&&tmp
+yM>=xG1
+nF3=t33
+tmp
+yM,tU2
+iP1
+tmp
+e61&&tmp
+nL3<=xG1
+nF3=t33
+tmp
+nL3,tU2
+nQ3
+if(tmp
+yI&&tmp
+e61){nJ3=true;nH3=fp_max(fp_abs(tmp
+yM),fp_abs(tmp
+tG1);nH3=t33
+nH3,tU2
+eE3
+nS3;}
+yD3
+tY
+xW
+yP2
+p1=tZ
+1));TriTruthValue
+p0_positivity=cN3(p0
+yM)>=xG1?iF2:(p0
+e61&&(p0
+tG1<xH1?l03
+Unknown);TriTruthValue
+cR2=GetEvennessInfo(xW
+1));TriTruthValue
+eZ=Unknown;e23
+p0_positivity
+tN1
+eZ=iF2;lC
+l03{eZ=cR2;xY3
+yF3
+e23
+cR2
+tN1
+eZ=iF2;lC
+l03
+lC
+Unknown:{if(eI1!t42
+xW
+i8)&&xW
+i8>=xG1{eZ=iF2;}
+xY3}
+c73(eZ
+tN1
+l14
+min=xH1;if
+cN3
+p1
+yI){min=t33
+p0
+yM,p1
+yM);if(p0
+yM<xH1&&(!p1
+e61||p1
+nL3>=xG1&&min>=xG1
+min=xH1;}
+if
+cN3
+p0
+yM>=xH1&&p0
+e61&&p1
+e61)l14
+max=t33
+p0
+nL3,p1
+tG1;if(min>max)std::swap(min,max);nM
+min,max);}
+nM
+min,false);}
+case
+l03{nM
+false,fp_const_negativezero
+xF());}
+yF3{xY3
+e21
+cNeg:tW3
+set_neg();tK
+cSub:yJ
+cNeg);tmp2
+tX3
+tmp
+iH
+cAdd);tmp
+tY3
+tmp
+c91
+tmp2
+i0
+cInv:{c02
+lW-1))i0
+cDiv:yJ
+cInv);tmp2
+tX3
+tmp
+iH
+xC1
+AddParamMove(tmp2
+i0
+cRad:yV
+xC1
+yA
+fp_const_rad_to_deg
+xF())i0
+cDeg:yV
+xC1
+yA
+fp_const_deg_to_rad
+xF())i0
+cSqr:{c02
+lW
+2))i0
+cExp:yV
+cPow);tmp.yA
+fp_const_e
+xF()));tmp.nJ
+0)i0
+cExp2:yV
+cPow);tmp.yA
+nX3
+tmp.nJ
+0)i0
+cCbrt:tW3
+min.set(fp_cbrt);tO
+set(fp_cbrt);tK
+cSqrt:lD
+if(m
+yI)m
+yM=(m
+yM)<xH1?0:fp_sqrt(m
+yM);if(xI2
+tO
+val=(tO
+val)<xH1?0:fp_sqrt(tO
+val);tK
+cRSqrt:{c02
+lW-0.5))i0
+cHypot:{yZ2
+xsqr,ysqr,add,sqrt;xsqr
+tY3
+xsqr.yA
+nX3
+ysqr
+tX3
+ysqr.yA
+nX3
+xsqr
+iH
+cPow);ysqr
+iH
+cPow);add
+c91
+xsqr);add
+c91
+ysqr);add
+iH
+cAdd);sqrt
+c91
+add);sqrt
+iH
+cSqrt)i1
+CalculateResultBoundaries(sqrt);}
+case
+cQ3:yJ
+cLog2);tmp2
+tY3
+tmp
+iH
+cMul);tmp
+c91
+tmp2);tmp.nJ
+1)i0
+cCot:yJ
+cTan)x6
+lH
+cSec:yJ
+cCos)x6
+lH
+cCsc:yJ
+cSin)x6
+CalculateResultBoundaries(tmp);}
+lC
+cRDiv:case
+cRSub:case
+cDup:case
+cFetch:case
+cPopNMov:case
+cSinCos:case
+cSinhCosh:case
+cNop:case
+cJump:case
+iU2:lC
+cArg:case
+cConj:case
+cImag:case
+cReal:case
+cPolar:lC
+cPCall:lC
+cFCall:xY3
+nM);}
+tK1
+TriTruthValue
+GetIntegerInfo
+iS1
+eR{e23
+t72){case
+cImmed:return
+t42
+tree
+x41)?iF2:xX3
+t83
+cFloor:case
+cCeil:case
+cTrunc:case
+cInt:return
+iF2
+t83
+cAnd:case
+cOr:case
+cNot:case
+cNotNot:case
+cEqual:case
+i51:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:return
+iF2
+t83
+cIf:{TriTruthValue
+a=GetIntegerInfo(xW
+1));TriTruthValue
+b=GetIntegerInfo(xW
+2));if(a==b)return
+a
+xO2
+case
+cAdd:case
+cMul:{for
+l41
+if(GetIntegerInfo(xW
+a))!=iF2)return
+Unknown
+i1
+iF2;}
+yF3
+xY3
+return
+Unknown;}
+yP1
+IsLogicalValue
+iS1
+eR{e23
+t72){case
+cImmed:return
+lJ3
+tree
+x41,xG1||lJ3
+tree
+x41,e62
+1))t83
+cAnd:case
+cOr:case
+cNot:case
+cNotNot:case
+cAbsAnd:case
+cAbsOr:case
+cC3:case
+cAbsNotNot:case
+cEqual:case
+i51:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:nZ
+cMul:{for
+l41
+if(!c83
+a))cQ
+lD2}
+case
+cIf:case
+cAbsIf:yP
+c83
+1))&&c83
+2));}
+yF3
+xY3
+return
+t23}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;
+#if defined(__x86_64) || !defined(FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS)
+# define CBRT_IS_SLOW
+#endif
+#if defined(DEBUG_POWI) || defined(DEBUG_SUBSTITUTIONS)
+#include <cstdio>
+#endif
+l33
+xK1{extern
+const
+x83
+char
+powi_table[256];}
+l33{using
+t5
+yO1
+bool
+IsOptimizableUsingPowi(long
+immed,long
+penalty=0){xK1::eP3
+synth;synth.PushVar(iU2);size_t
+bytecodesize_backup=synth.GetByteCodeSize();xK1::x01
+immed,xK1::tU1
+xF::MulSequence,c92
+size_t
+bytecode_grow_amount=synth.GetByteCodeSize()-bytecodesize_backup
+i1
+bytecode_grow_amount<size_t(MAX_POWI_BYTECODE_LENGTH-penalty);}
+xL1
+ChangeIntoRootChain(nP1
+bool
+l13,long
+tY2,long
+tZ2){while(tZ2>0
+t82
+cCbrt);t92);tmp.e33
+xD2--tZ2;}
+while(tY2>0
+t82
+cSqrt);if(l13){tmp
+iH
+cRSqrt);l13
+eW3}
+t92);tmp.e33
+xD2--tY2;}
+if(l13
+t82
+cInv);t92
+xD2}
+}
+tK1
+e72
+RootPowerTable{static
+const
+Value_t
+RootPowers[(1+4)*(1+3)];}
+yO1
+const
+Value_t
+t9(1+4)*(1+3)]={e62
+1)lS
+2)lS
+2*2)lS
+2*2*2)lS
+2*2*2*2)lS
+3)lS
+3*2)lS
+3*2*2)lS
+3*2*2*2)lS
+3*2*2*2*2)lS
+3*3)lS
+3*3*2
+yG3
+yG3*2
+yG3*2*2)lS
+3*3*3
+eY2
+eY2*2
+eY2*2*2
+eY2*2*2*2)}
+;e72
+PowiResolver{static
+const
+x83
+MaxSep=4;static
+x03
+i13=5;typedef
+int
+cO3;typedef
+long
+x43;typedef
+long
+tP;e72
+yS2{yS2():n_int_sqrt(0),n_int_cbrt(0),sep_list(),n01(0){}
+int
+n_int_sqrt;int
+n_int_cbrt;int
+tT1
+MaxSep];tP
+n01;}
+yO1
+static
+yS2
+CreatePowiResult
+cX3
+exponent){yS2
+nS3;cO3
+tA=FindIntegerFactor(tU2
+if(tA==0){
+#ifdef DEBUG_POWI
+i02"no factor found for %Lg\n"
+,(cP3);
+#endif
+return
+nS3;}
+nS3.n01=y31
+exponent,tA);x43
+eT2=EvaluateFactorCost(tA,0,0,0)+cC
+nS3.n01);int
+s_count=0;int
+i23=0;int
+nZ3=0;
+#ifdef DEBUG_POWI
+i02"orig = %Lg\n"
+,(cP3);i02"plain factor = "
+iL3"%ld\n"
+,(int)tA,(long)eT2);
+#endif
+for
+lT1
+n_s=0;n_s<MaxSep;++n_s){int
+xD=0;x43
+yK1=eT2;cO3
+yX1=tA;for(int
+s=1;s<i13*4;++s){
+#ifdef CBRT_IS_SLOW
+if(s>=i13)break;
+#endif
+int
+n_sqrt=s%i13;int
+n_cbrt=s/i13;if(n_sqrt+n_cbrt>4)yA1
+Value_t
+lN1=exponent;lN1-=t9
+s];iE1=FindIntegerFactor(lN1);if(xT2!=0){tP
+xN=y31
+lN1,xT2);x43
+cost=EvaluateFactorCost(xT2,s_count+n_sqrt,i23+n_cbrt,nZ3+1)+cC
+xN);
+#ifdef DEBUG_POWI
+i02"Candidate sep %u (%d*sqrt %d*cbrt)factor = "
+iL3"%ld (for %Lg to %ld)\n"
+,s,n_sqrt,n_cbrt,xT2,(long)cost
+cX2
+lN1,(long)xN);
+#endif
+if(cost<yK1){xD=s;yX1=xT2;yK1=cost;}
+}
+}
+if(!xD)break;
+#ifdef DEBUG_POWI
+i02"CHOSEN sep %u (%d*sqrt %d*cbrt)factor = "
+iL3"%ld, exponent %Lg->%Lg\n"
+,xD,xD%i13,xD/i13,yX1,yK1
+cX2(exponent)cX2(exponent-t9
+xD]));
+#endif
+nS3.tT1
+n_s]=xD
+eX3-=t9
+xD];s_count+=xD%i13;i23+=xD/i13;eT2=yK1;tA=yX1;nZ3+=1;}
+nS3.n01=y31
+exponent,tA);
+#ifdef DEBUG_POWI
+i02"resulting exponent is %ld (from exponent=%Lg, best_factor=%Lg)\n"
+,nS3.n01,(cP3
+cX2
+tA);
+#endif
+while(tA%2==0){++nS3
+e52;tA/=2;}
+while(tA%3==0){++nS3.n_int_cbrt;tA/=3;eE3
+nS3;}
+private:static
+x43
+cC
+tP
+xN){static
+std::map
+cS2
+iM;if(xN<0){x43
+cost=22
+i1
+cost+cC-xN);}
+std::map
+cS2::y83
+i=iM.xU2
+xN);if(i!=iM.cX1
+xN)return
+i
+eC2;std::pair
+cS2
+nS3(xN,0.0);x43&cost=nS3.i63
+while(xN>1){int
+xT2=0;if(xN<256){xT2=xK1::powi_table[xN];if(xT2&128)xT2&=127;else
+xT2=0;if(xT2&64)xT2=-(xT2&63)-1;}
+if(xT2){cost+=cC
+xT2);xN/=xT2;yA1}
+if(!(xN&1)){xN/=2;cost+=6;}
+else{cost+=7;xN-=1;}
+}
+iM.y43,nS3)i1
+cost;}
+cB1
+tP
+y31
+yL1,iE1)yP
+makeLongInteger(value*e62
+xT2));}
+cB1
+bool
+yM1
+yL1,iE1)l14
+v=value*e62
+xT2)i1
+isLongInteger(v);}
+cB1
+cO3
+FindIntegerFactor(yL1){iE1=(2*2*2*2);
+#ifdef CBRT_IS_SLOW
+#else
+xT2*=(3*3*3);
+#endif
+cO3
+nS3=0;if(yM1
+value,xT2)){nS3=xT2;while((xT2%2)==0&&yM1
+value,xT2/2))nS3=xT2/=2;while((xT2%3)==0&&yM1
+value,xT2/3))nS3=xT2/=3;}
+#ifdef CBRT_IS_SLOW
+if(nS3==0){if(yM1
+value,3
+y03
+3;}
+#endif
+return
+nS3;}
+static
+int
+EvaluateFactorCost(int
+xT2,int
+s,int
+c,int
+nmuls){x03
+x13=6;
+#ifdef CBRT_IS_SLOW
+x03
+eU2=25;
+#else
+x03
+eU2=8;
+#endif
+int
+nS3=s*x13+c*eU2;while(xT2%2==0){xT2/=2;nS3+=x13;}
+while(xT2%3==0){xT2/=3;nS3+=eU2;}
+nS3+=nmuls
+i1
+nS3;}
+}
+;}
+t5{yP1
+yZ2::RecreateInversionsAndNegations(bool
+prefer_base2){bool
+changed=false
+e73
+0;a<l91++a)if(lX1.RecreateInversionsAndNegations(prefer_base2))yS1
+if(changed){exit_changed:Mark_Incompletely_Hashed(yQ2
+e23
+l92{case
+cMul:{eK
+nE2
+tX
+nF2,cR1;if(true){bool
+nK1=false
+iK2
+xE2=0
+e73
+tI1
+i12
+tI
+0)i22
+tI
+1)tD1){nK1=true;xE2=tI
+i8;xY3}
+if(nK1)l14
+immeds=1.0
+e73
+tI1
+tD1){immeds*=powgroup
+x41;yN1}
+for
+iZ1
+a=l91
+a-->0;nQ&powgroup=lX1;if(powgroup
+i12
+tI
+0)i22
+tI
+1)tD1
+nQ&log2=tI
+0);log2.lD1
+log2
+iH
+cQ3);log2.yA
+t33
+immeds,e62
+1)/xE2)));log2
+iW1;xY3}
+}
+}
+for
+iZ1
+a=tI1
+i12
+tI
+1)tD1){iT1&exp_param=tI
+1)iK2
+eD2
+exp_param
+x41;if(cZ1,nU2)){lD1
+nE2
+c52
+lX1
+c43
+yN1
+iP1
+exponent<xH1&&t42
+exponent)nQ
+iV;iV
+iH
+cPow);iV
+cS
+tI
+0));iV.yA-exponent));iV
+iW1;nE2
+c52
+iV);lD1
+yN1}
+iP1
+powgroup
+i22!nF2.nX2){nF2=tI
+0);lD1
+yN1
+iP1
+powgroup
+nC==cQ3&&!cR1.nX2){cR1=powgroup;lD1
+yN1}
+if(!nE2
+eU3){changed=true
+tX
+cF1;cF1
+iH
+cMul);cF1
+iF1
+nE2);cF1
+iW1
+tX
+iG
+cMul);cA1
+SetParamsMove
+eM
+if(cA1
+IsImmed()&&fp_equal
+eH2
+x41
+nH2
+eL3
+cInv)tN
+cF1);}
+cJ3
+cA1
+GetDepth()>=cF1
+nP2
+tC2
+cDiv
+iG1
+tN
+cF1);}
+else{eL3
+cRDiv)tN
+cF1
+iG1;}
+}
+}
+if(nF2.nX2
+nQ
+iG
+l92;cA1
+SetParamsMove
+eM
+while(cA1
+RecreateInversionsAndNegations(prefer_base2))cA1
+tE3;eL3
+cQ3)tN
+nF2
+iG1;yS1}
+if(cR1.nX2
+nQ
+iG
+cMul);mulgroup
+c91
+cR1
+l8
+1));cA1
+AddParamsMove
+eM
+while(cA1
+RecreateInversionsAndNegations(prefer_base2))cA1
+tE3;DelParams();eL3
+cQ3)tN
+cR1
+l8
+0)iG1;yS1
+e21
+cAdd:{eK
+i32
+e73
+l91
+a-->0;)if(eY3
+cMul){nG2
+y41:tX&mulgroup=cT2
+for
+iZ1
+b=cA1
+l91
+b-->0;){if
+eH2
+l8
+b).lV1
+xT2=mulgroup
+l8
+b)x41;lG3
+xT2
+xU
+y41;}
+cA1
+lD1
+cA1
+i91
+b
+tA2
+iP1
+lJ3
+xT2,e62-2)))eN
+y41;}
+cA1
+lD1
+cA1
+i91
+b);cA1
+yA
+e62
+2))tA2}
+}
+if(t0){cA1
+tB
+mulgroup);yN1}
+iP1
+eY3
+cDiv&&!IsIntType
+xF::nS3){nG2
+y51:tX&cF1=cT2
+if(cF1
+l8
+0)tD1){lG3
+cF1
+l8
+0)x41
+xU
+y51;}
+cF1.lD1
+cF1.i91
+0);cF1
+iH
+cInv
+tA2}
+if(t0)eN
+y51;}
+cF1.tB
+cF1);yN1}
+iP1
+eY3
+cRDiv&&!IsIntType
+xF::nS3){nG2
+xD1:tX&cF1=cT2
+if(cF1
+l8
+1)tD1){lG3
+cF1
+l8
+i8
+xU
+xD1;}
+cF1.lD1
+cF1.i91
+1);cF1
+iH
+cInv
+tA2}
+if(t0)eN
+xD1;}
+cF1.tB
+cF1);yN1}
+if(!i32
+eU3){
+#ifdef DEBUG_SUBSTITUTIONS
+i02"Will make a Sub conversion in:\n"
+);fflush(stdout);l21
+#endif
+yZ2
+yT2;yT2
+iH
+cAdd);yT2
+iF1
+i32);yT2
+iW1
+tX
+cS1;cS1
+iH
+cAdd);cS1
+iF1
+lJ2));cS1
+iW1;if(cS1
+tD1&&lJ3
+cS1
+x41,xG1
+tC2
+cNeg);eC);}
+cJ3
+cS1
+nP2==1
+tC2
+cRSub);eC)eV3}
+iP1
+yT2
+nC==cAdd
+tC2
+cSub)eV3
+eC
+l8
+0)iY1
+1;a<yT2.l91++a
+nQ
+eV2;eV2
+iH
+cSub);eV2
+iF1
+lJ2));eV2.yC2)tN
+eV2);eC
+n93}
+}
+else{eL3
+cSub)eV3
+eC);}
+}
+#ifdef DEBUG_SUBSTITUTIONS
+i02"After Sub conversion:\n"
+);fflush(stdout);l21
+#endif
+e21
+cPow:{iT1&p0
+i42
+0);iT1&p1
+i42
+1);if(p1
+tD1){if(p1
+x41!=xH1&&!t42
+p1
+x41)){eG
+yS2
+r=eG
+CreatePowiResult(fp_abs
+cR3);if(r.n01!=0){bool
+lH2
+eW3
+if(p1
+x41<xH1&&r.tT1
+0]==0&&r
+e52>0){lH2=true;}
+#ifdef DEBUG_POWI
+i02"Will resolve powi %Lg as powi(chain(%d,%d),%ld)"
+cX2
+fp_abs
+cR3,r
+e52,r.n_int_cbrt,r.n01);for
+lT1
+n=0;n<eG
+MaxSep;++n){if(r
+i52==0)break;int
+n_sqrt=r
+i52%eG
+i13;int
+n_cbrt=r
+i52/eG
+i13;i02"*chain(%d,%d)"
+,n_sqrt,n_cbrt);}
+i02"\n"
+);
+#endif
+yZ2
+cU2
+i42
+0)tX
+yU2=cU2;yU2.lD1
+ChangeIntoRootChain(yU2,lH2,r
+e52,r.n_int_cbrt);yU2
+iW1
+tX
+pow;if(r.n01!=1){pow
+iH
+cPow);pow
+c91
+yU2);pow.yA
+e62
+r.n01)));}
+else
+pow.swap(yU2)tX
+mul;mul
+iH
+cMul);mul
+c91
+pow);for
+lT1
+n=0;n<eG
+MaxSep;++n){if(r
+i52==0)break;int
+n_sqrt=r
+i52%eG
+i13;int
+n_cbrt=r
+i52/eG
+i13
+tX
+eW2=cU2;eW2.lD1
+ChangeIntoRootChain(eW2,false,n_sqrt,n_cbrt);eW2
+iW1;mul
+c91
+eW2);}
+if(p1
+x41<xH1&&!lH2){mul
+iW1;eL3
+cInv);nB1
+0,mul);i91
+1);}
+else{eL3
+cMul);SetParamsMove(mul.lJ2));}
+#ifdef DEBUG_POWI
+l21
+#endif
+yS1
+xY3}
+}
+if(GetOpcode()==cPow&&(!p1
+tD1||!isLongInteger
+cR3||!IsOptimizableUsingPowi
+xF(makeLongInteger
+cR3))){if(p0
+tD1&&p0
+x41>e62
+0.0)){if(prefer_base2)l14
+yV2=fp_log2(p0
+x41);lG3
+yV2
+nH2
+i91
+0);}
+else{n0
+eA1
+yV2))eX3
+cS
+p1
+t81
+nB1
+t1}
+eL3
+cExp2);yS1}
+else
+l14
+yV2=fp_log(p0
+x41);lG3
+yV2
+nH2
+i91
+0);}
+else{n0
+eA1
+yV2))eX3
+cS
+p1
+t81
+nB1
+t1}
+eL3
+cExp);yS1}
+}
+iP1
+GetPositivityInfo(p0)==iF2){if(prefer_base2
+nQ
+log;log
+iH
+cLog2);log
+cS
+p0);log
+iW1;n0
+p1)eX3
+c91
+log
+t81
+eL3
+cExp2);nB1
+t1
+yS1}
+else{yZ2
+log;log
+iH
+cLog);log
+cS
+p0);log
+iW1;n0
+p1)eX3
+c91
+log
+t81
+eL3
+cExp);nB1
+t1
+yS1}
+}
+e21
+cDiv:{if(GetParam(0)tD1&&lJ3
+GetParam(0)x41
+nH2
+eL3
+cInv);i91
+0);}
+xY3
+yF3
+xY3
+if(changed)goto
+exit_changed
+i1
+changed;}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+l33
+FUNCTIONPARSERTYPES;l33{using
+t5;class
+eF3{size_t
+nL1;size_t
+eH;size_t
+eI;size_t
+lO1;size_t
+t3;size_t
+t4;size_t
+n71;e43
+eF3():nL1(0),eH(0),eI(0),lO1(0),t3(0),t4(0),n71(0){}
+void
+i43
+OPCODE
+op){nL1+=1
+i33
+cCos)++eH
+i33
+cSin)++eI
+i33
+cSec)++eH
+i33
+cCsc)++eI
+i33
+cTan)++lO1
+i33
+cCot)++lO1
+i33
+cSinh)++t4
+i33
+cCosh)++t3
+i33
+cTanh)++n71;}
+size_t
+GetCSEscore()const{size_t
+nS3=nL1
+i1
+nS3;}
+int
+NeedsSinCos()const{bool
+y61=(nL1==(eH+eI+lO1));if((lO1&&(eI||eH))||(eI&&eH)){if(y61)return
+1
+i1
+2;eE3
+0;}
+int
+NeedsSinhCosh()const{bool
+y61=(nL1==(t3+t4+n71));if((n71&&(t4||t3))||(t4&&t3)){if(y61)return
+1
+i1
+2;eE3
+0;}
+size_t
+MinimumDepth()const{size_t
+n_sincos=std::min(eH,eI);size_t
+n_sinhcosh=std::min(t3,t4);if(n_sincos==0&&n_sinhcosh==0)return
+2
+i1
+1;}
+}
+yO1
+class
+TreeCountType:public
+std::multimap<fphash_t,std::pair<eF3,yZ2> >{}
+;xL1
+FindTreeCounts(tJ1&nI2,const
+nP1
+OPCODE
+xF2,bool
+skip_root=false){cX
+i=nI2.xU2
+nJ2);if(!skip_root){bool
+found
+eW3
+for(;i!=nI2.cX1
+nJ2;++i){if(tree
+xI
+i
+eC2.second)){i
+eC2.first.i43
+xF2);found=true;xY3}
+if(!found){eF3
+count;count.i43
+xF2);nI2.y43,std::make_pair(nJ2,std::make_pair
+cW3
+cU3)));}
+}
+x51
+FindTreeCounts(nI2,xW
+a),t72);}
+e72
+yW{bool
+BalanceGood;bool
+FoundChild;}
+yO1
+yW
+lP1
+iT1&root,iT1&cS3{if(root
+xI
+cS3){yW
+nS3={true,true}
+i1
+nS3;}
+yW
+nS3={true,false}
+;if(root
+nC==cIf||root
+nC==t03{yW
+cond=lP1
+root
+l8
+0),cS3;yW
+xV=lP1
+root
+l8
+1),cS3;yW
+y4=lP1
+root
+l8
+2),cS3;if
+l23||xV
+yX||y4
+yX){nS3
+yX=true;}
+nS3
+eD=((xV
+yX==y4
+yX)||l23
+i62)&&(cond
+eD||(xV
+yX&&y4
+yX))&&(xV
+eD||l23
+i62)&&(y4
+eD||l23
+i62);}
+else{bool
+iH1
+eW3
+bool
+nM1=false
+eK3
+b=root.GetParamCount(),a=0;a<b;++a){yW
+tmp=lP1
+root
+l8
+a),cS3;if(tmp
+yX)nS3
+yX=true;if(tmp
+eD==false)iH1=true;iP1
+tmp
+yX)nM1=true;}
+if(iH1&&!nM1)nS3
+eD
+eW3
+eE3
+nS3;}
+yP1
+cW2
+iR1
+i53
+const
+nP1
+const
+xK1::eP3&synth,const
+tJ1&nI2){for
+iZ1
+b=tree.GetParamCount(),a=0;a<b;++a){iT1&leaf=xW
+a);cX
+synth_it;for(x93
+tJ1::const_iterator
+i=nI2.y73
+i!=nI2.end();++i){if(i->first!=leaf.GetHash())yA1
+const
+eF3&occ
+nY2
+first;size_t
+score=occ.GetCSEscore();iT1&candidate
+nY2
+i63
+if(lF2
+candidate))yA1
+if(leaf
+nP2<occ.MinimumDepth())yA1
+if(score<2)yA1
+if(lP1
+i53
+leaf)eD==false)continue
+l43
+if(cW2(i53
+leaf,synth,nI2))lD2
+eE3
+t23
+yP1
+iI1
+iT1&y53,iT1&expr){yY1
+y53
+lF3
+expr))lD2
+yY1
+iI1
+y53
+l8
+a),expr
+y03
+true
+i1
+t23
+yP1
+GoodMomentForCSE
+iR1
+y53,iT1&expr){if(y53
+nC==cIf)lD2
+yY1
+y53
+lF3
+expr))lD2
+size_t
+i72=0;yY1
+iI1
+y53
+l8
+a),expr))++i72
+i1
+i72!=1;}
+}
+t5{tK1
+size_t
+yZ2::SynthCommonSubExpressions(xK1::xI1
+const{if(e91
+0)return
+0;size_t
+stacktop_before=synth.GetStackTop();tJ1
+nI2;FindTreeCounts(nI2,*this,GetOpcode(),true);for(;;){size_t
+yW2=0;
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+cV2<<"Finding a CSE candidate, root is:"
+<<std::y11*this);
+#endif
+cX
+cs_it(nI2.end());for(cX
+j=nI2.y73
+j!=nI2.end();){cX
+i(j++);const
+eF3&occ
+nY2
+first;size_t
+score=occ.GetCSEscore();iT1&tree
+nY2
+i63
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+cV2<<"Score "
+<<score<<":\n"
+<<std::flush;DumpTreeWithIndent(tree);
+#endif
+if(lF2
+tree))xZ
+if(tree
+nP2<occ.MinimumDepth())xZ
+if(score<2)xZ
+if(lP1*this
+cU3)eD==false)xZ
+if(cW2(*this
+cU3,synth,nI2)){yA1}
+if(!GoodMomentForCSE(*this
+cU3))xZ
+score*=tree
+nP2;if(score>yW2){yW2=score;cs_it=i;}
+}
+if(yW2<=0){
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+cV2<<"No more CSE candidates.\n"
+<<std::flush;
+#endif
+xY3
+iT1&tree=cs_it
+eC2.i63
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+cV2<<iX3"Common Subexpression:"
+;DumpTree
+xF(tree
+lE2
+std::endl;
+#endif
+#if 0
+int
+n11=occ.NeedsSinCos();int
+i9=occ.NeedsSinhCosh()tX
+i82,i92,yX2,yY2;if(n11){i82
+eX2
+i82
+iH
+cSin);i82
+iW1;i92
+eX2
+i92
+iH
+cCos);i92
+iW1;if(lF2
+i82)||lF2
+i92))i73==2){nI2.xG2
+yA1}
+n11=0;}
+}
+if(i9){yX2
+eX2
+yX2
+iH
+cSinh);yX2
+iW1;yY2
+eX2
+yY2
+iH
+cCosh);yY2
+iW1;if(lF2
+yX2)||lF2
+yY2)){if(i9==2){nI2.xG2
+yA1}
+i9=0;}
+}
+#endif
+tree.SynthesizeByteCode(synth,false);nI2.xG2
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+synth.x73
+Dump<0>(lE2"Done with Common Subexpression:"
+;DumpTree
+xF(tree
+lE2
+std::endl;
+#endif
+#if 0
+if(n11)i73==2||i9){synth.eL1}
+yB1
+cSinCos,1,2)yC1
+i82,1)yC1
+i92,0);}
+if(i9)i73)synth.eL1
+if(i9==2){synth.eL1}
+yB1
+cSinhCosh,1,2)yC1
+yX2,1)yC1
+yY2,0);}
+#endif
+eE3
+xV3
+stacktop_before;}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+tK1
+lU1
+xF::iA2{using
+t5;CopyOnWrite()tX
+tree;tree.GenerateFrom(*mData);FPoptimizer_Optimize::ApplyGrammars(tree);eO3
+x83>cT3;std
+xM3
+xF
+immed;size_t
+stacktop_max=0;tree.SynthesizeByteCode(cT3,immed,stacktop_max);if(mData->mStackSize!=stacktop_max){mData->mStackSize=x83(stacktop_max);
+#if !defined(FP_USE_THREAD_SAFE_EVAL) && \
+ !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA)
+mData->mStack
+xF3
+stacktop_max);
+#endif
+}
+mData->mByteCode.swap(cT3);mData->mImmed.swap(immed);}
+#define FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(type) tP1>lU1<type>::iA2{}
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+i93(MpfrFloat)
+#endif
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+i93(GmpInt)
+#endif
+#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+i93(std::complex<double>)
+#endif
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+i93(std::complex<float>)
+#endif
+#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+i93(std::complex<long
+double>)
+#endif
+#define FUNCTIONPARSER_INSTANTIATE_OPTIMIZE(type) x73 lU1<type>::iA2;
+#ifndef FP_DISABLE_DOUBLE_TYPE
+iA3(double)
+#endif
+#ifdef FP_SUPPORT_FLOAT_TYPE
+iA3(float)
+#endif
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+iA3(long
+double)
+#endif
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+iA3(long)
+#endif
+#endif // FP_SUPPORT_OPTIMIZER
+
+#endif
diff --git a/fparser/mpfr/GmpInt.cc b/fparser/mpfr/GmpInt.cc
new file mode 100644
index 0000000..490add4
--- /dev/null
+++ b/fparser/mpfr/GmpInt.cc
@@ -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
index 0000000..1c1c171
--- /dev/null
+++ b/fparser/mpfr/GmpInt.hh
@@ -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
index 0000000..112c684
--- /dev/null
+++ b/fparser/mpfr/MpfrFloat.cc
@@ -0,0 +1,976 @@
+#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_0(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)
+{
+ sin.copyIfShared();
+ cos.copyIfShared();
+ 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
index 0000000..d455d24
--- /dev/null
+++ b/fparser/mpfr/MpfrFloat.hh
@@ -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