]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Bump fparser to version 4.5
authormaier <maier@0785d39b-7218-0410-832d-ea1e28bc413d>
Sun, 30 Sep 2012 11:02:44 +0000 (11:02 +0000)
committermaier <maier@0785d39b-7218-0410-832d-ea1e28bc413d>
Sun, 30 Sep 2012 11:02:44 +0000 (11:02 +0000)
git-svn-id: https://svn.dealii.org/branches/branch_cmake@26888 0785d39b-7218-0410-832d-ea1e28bc413d

32 files changed:
deal.II/TODO.CMAKE
deal.II/cmake/setup_deal_ii.cmake
deal.II/contrib/README.contrib
deal.II/contrib/functionparser/CMakeLists.txt
deal.II/contrib/functionparser/Makefile [deleted file]
deal.II/contrib/functionparser/README [new file with mode: 0644]
deal.II/contrib/functionparser/docs/fparser.html [new file with mode: 0644]
deal.II/contrib/functionparser/docs/gpl.txt [new file with mode: 0644]
deal.II/contrib/functionparser/docs/lgpl.txt [new file with mode: 0644]
deal.II/contrib/functionparser/docs/style.css [new file with mode: 0644]
deal.II/contrib/functionparser/examples/example.cc [moved from deal.II/contrib/functionparser/example.cc with 83% similarity]
deal.II/contrib/functionparser/examples/example2.cc [new file with mode: 0644]
deal.II/contrib/functionparser/extrasrc/fp_identifier_parser.inc [new file with mode: 0644]
deal.II/contrib/functionparser/extrasrc/fp_opcode_add.inc [new file with mode: 0644]
deal.II/contrib/functionparser/extrasrc/fpaux.hh [new file with mode: 0644]
deal.II/contrib/functionparser/extrasrc/fptypes.hh [new file with mode: 0644]
deal.II/contrib/functionparser/fparser.cc
deal.II/contrib/functionparser/fparser.h [deleted file]
deal.II/contrib/functionparser/fparser.hh [new file with mode: 0644]
deal.II/contrib/functionparser/fparser.txt [deleted file]
deal.II/contrib/functionparser/fparser_gmpint.hh [new file with mode: 0644]
deal.II/contrib/functionparser/fparser_mpfr.hh [new file with mode: 0644]
deal.II/contrib/functionparser/fpconfig.h [deleted file]
deal.II/contrib/functionparser/fpconfig.hh [new file with mode: 0644]
deal.II/contrib/functionparser/fpoptimizer.cc
deal.II/contrib/functionparser/fptypes.h [deleted file]
deal.II/contrib/functionparser/lgpl-3.0.txt [new file with mode: 0644]
deal.II/contrib/functionparser/mpfr/GmpInt.cc [new file with mode: 0644]
deal.II/contrib/functionparser/mpfr/GmpInt.hh [new file with mode: 0644]
deal.II/contrib/functionparser/mpfr/MpfrFloat.cc [new file with mode: 0644]
deal.II/contrib/functionparser/mpfr/MpfrFloat.hh [new file with mode: 0644]
deal.II/source/base/function_parser.cc

index 07280ccdbfbb59baa5a846aa5c635d9823454208..0a19e9f453e430d83a97acbf0297ec32b1fbae6d 100644 (file)
@@ -5,16 +5,16 @@ Major:
 
 * Add the rest of the Bug tests
 
-* Bump functionparser to version 4.5
+* Test the fparser 4.5 functionality.
 
 * The following features have to be written:
     * MUMPS
     * SLEPC
     * HDF5
-    * HSL
     * TECPLOT
 
 * Write a wrapper around cmake. Something like
+    * download and 'install' cmake if necessary
     $ make config
     $ make
     ...
@@ -43,13 +43,7 @@ Minor:
 * What to do with ./lib/meshes ? I have moved it to ./contrib/meshes for
   the time being...
 
-* The original decision to have a dedicated p4est/FAST and p4est/DEBUG
-  structure is a bit unfortunate and therefor replaced by a FindP4EST
-  module that searches libp4est.so and treats this as FAST and
-  libp4est_debug.so or libp4est.g.so and treats this as debug library.
-  TODO: Update the p4est-setup.sh script...
-
-* Reenable support for metis versions 4.x ?!
+* TODO: Update the p4est-setup.sh script...
 
 * The contrib libraries are included too early. User CXX_FLAGS won't be
   included in the contrib object targets...
index cf3ee143166a0d2c3ae3ff7343506fd8a1828a95..233acea212e92115a2818335fd52c3b7dbc5a779 100644 (file)
@@ -34,6 +34,8 @@
 #
 #     DEAL_II_INCLUDE_DIRS
 #     DEAL_II_LIBRARIES
+#     DEAL_II_LIBRARIES_DEBUG
+#     DEAL_II_LIBRARIES_RELEASE
 #
 #     DEAL_II_BUILD_TYPES
 #
index f962480b72731351eb35d62e5f347ae8a6afb541..77c8ee36a97d3bea7ac4012f69e3a3cd7646dd8c 100644 (file)
@@ -18,11 +18,11 @@ boost-1.49.0/LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt
 A full version of the library can be downloaded at http://www.boost.org/.
 
 
-functionparser (TODO: for fparser4.5)
+functionparser
 ==============
 
-Contains the functionparser project which copyrighted by Juha Nieminen and
-licensed under the GNU Lesser General Public License (LGPL) Version 3.
+Contains the functionparser project which is copyrighted by Juha Nieminen
+and licensed under the GNU Lesser General Public License (LGPL) Version 3.
 See functionparser/README, functionparser/lgpl-3.0.txt or
 http://warp.povusers.org/FunctionParser/
 
index f6997c24d44bb32863c06e7e0f18d9cdc5787e13..c32d8011dafa46447456c208bcea14150a67ceeb 100644 (file)
@@ -1 +1 @@
-DEAL_II_ADD_LIBRARY(obj_functionparser OBJECT "fparser.cc")
+DEAL_II_ADD_LIBRARY(obj_functionparser OBJECT fparser.cc)
diff --git a/deal.II/contrib/functionparser/Makefile b/deal.II/contrib/functionparser/Makefile
deleted file mode 100644 (file)
index 08ab75c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# $Id$
-# Copyright (C) 2005, 2008 by Wolfgang Bangerth
-
-
-D = ../..
-
-include $D/common/Make.global_options
-
-# rules
-$(LIBDIR)/contrib/functionparser/fparser.$(OBJEXT): fparser.cc fparser.h
-       @echo =====function parser==optimized==$(MT)== $(<F)
-       @mkdir -p $(LIBDIR)/contrib/functionparser/
-       @$(CXX) $(CXXFLAGS.o) -c fparser.cc -o $@
-
-
-
-clean:
-       -rm -f *~ 
-
-
-.PHONY: clean
diff --git a/deal.II/contrib/functionparser/README b/deal.II/contrib/functionparser/README
new file mode 100644 (file)
index 0000000..00bdbc5
--- /dev/null
@@ -0,0 +1,7 @@
+This directory contains the functionparser project which is copyrighted
+by Juha Nieminen and licensed under the GNU Lesser General Public License
+(LGPL) Version 3.  See functionparser/README, functionparser/lgpl-3.0.txt
+or http://warp.povusers.org/FunctionParser/
+
+A full version of the functionparser project can be downloaded at
+http://warp.povusers.org/FunctionParser/.
diff --git a/deal.II/contrib/functionparser/docs/fparser.html b/deal.II/contrib/functionparser/docs/fparser.html
new file mode 100644 (file)
index 0000000..da99f67
--- /dev/null
@@ -0,0 +1,1848 @@
+<!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    : Documentation</title>
+</head>
+
+<body>
+<h1>Function Parser for C++ v4.5    </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
+  <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_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/deal.II/contrib/functionparser/docs/gpl.txt b/deal.II/contrib/functionparser/docs/gpl.txt
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/deal.II/contrib/functionparser/docs/lgpl.txt b/deal.II/contrib/functionparser/docs/lgpl.txt
new file mode 100644 (file)
index 0000000..cca7fc2
--- /dev/null
@@ -0,0 +1,165 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/deal.II/contrib/functionparser/docs/style.css b/deal.II/contrib/functionparser/docs/style.css
new file mode 100644 (file)
index 0000000..d5141d3
--- /dev/null
@@ -0,0 +1,80 @@
+html
+{
+  background-color: #E0E0E0;
+}
+
+body
+{
+  background-color: white;
+  margin-left: 7%;
+  margin-top: 16px;
+  margin-right: 7%;
+  padding-top: 2em;
+  padding-left: 7%;
+  padding-right: 7%;
+  padding-bottom: 2%;
+  border-color: black;
+  border: solid;
+  border-width: 1px;
+}
+
+h1
+{
+  text-align: center;
+  background-color: #FFEEBB;
+  padding-bottom: 0.2em;
+  padding-top: 0.1em;
+}
+
+h2
+{
+  background-color: #FFFFCC;
+  padding-left: 0.5em;
+}
+
+h3
+{
+  background-color: #FFFFEE;
+}
+
+blockquote
+{
+  padding-left: 2em;
+  padding-right: 2em;
+  font-style: italic;
+  background-color: #FFFAF0;
+}
+
+li
+{
+  padding-top: 0.3em;
+}
+
+pre
+{
+  background-color: #E8E8E8;
+  padding-left: 1em;
+  padding-top: 0.5em;
+  padding-bottom: 0.5em;
+}
+
+code
+{
+  font-family: monospace;
+  color: #900040;
+}
+
+.small
+{
+  font-size: 80%;
+}
+
+.codecomment
+{
+  color: green;
+}
+
+.highlight
+{
+  background: #C0D0FF;
+}
similarity index 83%
rename from deal.II/contrib/functionparser/example.cc
rename to deal.II/contrib/functionparser/examples/example.cc
index 608492e475f7a9d8fc7f8cfefdd50e139fb4a478..b4ab5f45c80fe4c187615884aeeec2a5100e6b87 100644 (file)
@@ -1,50 +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);
-        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;
-
-    double vals[1];
-    for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)
-        std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)
-                  << std::endl;
-
-    return 0;
-}
+// Simple example file for the function parser\r
+// ===========================================\r
+\r
+/* When running the program, try for example with these values:\r
+\r
+f(x) = x^2\r
+min x: -5\r
+max x: 5\r
+step: 1\r
+\r
+*/\r
+\r
+#include "../fparser.hh"\r
+\r
+#include <iostream>\r
+#include <string>\r
+\r
+int main()\r
+{\r
+    std::string function;\r
+    double minx, maxx, step;\r
+    FunctionParser fparser;\r
+\r
+    fparser.AddConstant("pi", 3.1415926535897932);\r
+\r
+    while(true)\r
+    {\r
+        std::cout << "f(x) = ";\r
+        std::getline(std::cin, function);\r
+        if(std::cin.fail()) return 0;\r
+\r
+        int res = fparser.Parse(function, "x");\r
+        if(res < 0) break;\r
+\r
+        std::cout << std::string(res+7, ' ') << "^\n"\r
+                  << fparser.ErrorMsg() << "\n\n";\r
+    }\r
+\r
+    std::cout << "min x: ";\r
+    std::cin >> minx;\r
+    std::cout << "max x: ";\r
+    std::cin >> maxx;\r
+    std::cout << "step: ";\r
+    std::cin >> step;\r
+    if(std::cin.fail()) return 0;\r
+\r
+    double vals[] = { 0 };\r
+    for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)\r
+    {\r
+        std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)\r
+                  << std::endl;\r
+    }\r
+\r
+    return 0;\r
+}\r
diff --git a/deal.II/contrib/functionparser/examples/example2.cc b/deal.II/contrib/functionparser/examples/example2.cc
new file mode 100644 (file)
index 0000000..958b9a1
--- /dev/null
@@ -0,0 +1,85 @@
+// Simple example file for the function parser
+// ===========================================
+/* Note that the library has to be compiled with
+   FP_SUPPORT_FLOAT_TYPE, FP_SUPPORT_LONG_DOUBLE_TYPE and
+   FP_SUPPORT_LONG_INT_TYPE
+   preprocessor macros defined for this example to work.
+
+   Try with these input values with the different floating point parser
+   types to see the difference in accuracy:
+
+f(x) = x + 1.234567890123456789
+min x: 0
+max x: 2
+step: 1
+*/
+
+#include "../fparser.hh"
+
+#include <iostream>
+#include <iomanip>
+#include <string>
+
+template<typename Parser>
+void runExample(const char* valueTypeName)
+{
+    typedef typename Parser::value_type Value_t;
+
+    std::cout << "Using " << valueTypeName << " parser." << std::endl;
+
+    Parser fparser;
+    std::string function;
+    Value_t minx, maxx, step;
+
+    fparser.AddConstant("pi", Value_t(3.1415926535897932));
+
+    std::cin.ignore();
+    while(true)
+    {
+        std::cout << "f(x) = ";
+        std::getline(std::cin, function);
+        if(std::cin.fail()) return;
+
+        int res = fparser.Parse(function, "x");
+        if(res < 0) break;
+
+        std::cout << std::string(res+7, ' ') << "^\n"
+                  << fparser.ErrorMsg() << "\n\n";
+    }
+
+    std::cout << "min x: ";
+    std::cin >> minx;
+    std::cout << "max x: ";
+    std::cin >> maxx;
+    std::cout << "step: ";
+    std::cin >> step;
+    if(std::cin.fail()) return;
+
+    Value_t vals[] = { 0 };
+    for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)
+    {
+        std::cout << std::setprecision(20);
+        std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)
+                  << std::endl;
+    }
+}
+
+int main()
+{
+    int choice = 0;
+    do
+    {
+        std::cout << "1 = double, 2 = float, 3 = long double, 4 = long int: ";
+        std::cin >> choice;
+    } while(choice < 1 || choice > 4);
+
+    switch(choice)
+    {
+      case 1: runExample<FunctionParser>("double"); break;
+      case 2: runExample<FunctionParser_f>("float"); break;
+      case 3: runExample<FunctionParser_ld>("long double"); break;
+      case 4: runExample<FunctionParser_li>("long int"); break;
+    }
+
+    return 0;
+}
diff --git a/deal.II/contrib/functionparser/extrasrc/fp_identifier_parser.inc b/deal.II/contrib/functionparser/extrasrc/fp_identifier_parser.inc
new file mode 100644 (file)
index 0000000..00d5081
--- /dev/null
@@ -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;
\ No newline at end of file
diff --git a/deal.II/contrib/functionparser/extrasrc/fp_opcode_add.inc b/deal.II/contrib/functionparser/extrasrc/fp_opcode_add.inc
new file mode 100644 (file)
index 0000000..cb7280c
--- /dev/null
@@ -0,0 +1,7748 @@
+/* Function Parser for C++ v4.5     
+
+  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 q81 "cNeg"
+#define q71 <<","aP
+#define q61 wA","aP
+#define q51 <<","aQ
+#define q41 ", "wU<<","
+#define q31 wA","aE
+#define q21 "B[IsVarOpcode(B)]"m7
+#define q11 );qW q6
+#define q01 "cSqrt"
+#define mZ "cSqr "
+#define mY ){hD wB
+#define mX "cSec"
+#define mW "cCeil"
+#define mV "A "a3
+#define mU "cImag"
+#define mT "cConj"
+#define mS a4" "a6
+#define mR hO wB
+#define mQ "cAbs"
+#define mP qS w2 wB
+#define mO "cFloor"
+#define mN "cTan"
+#define mM "cSin"
+#define mL (y hX;
+#define mK " "aS
+#define mJ "[ y+x]"
+#define mI hV 2 gC
+#define mH "cExp"
+#define mG "cNeg "
+#define mF " cSub"
+#define mE " cDup"
+#define mD " cNeg"
+#define mC "cDup "
+#define mB "cLess"
+#define mA "cLog"
+#define m9 "cMin"
+#define m8 "cMax"
+#define m7 " cDiv"
+#define m6 wH" "
+#define m5 (x);gJ
+#define m4 " "wU wM
+#define m3 aU"x "
+#define m2 gN wB
+#define m1 g1 oG wB
+#define m0 "B cSqr"
+#define aZ "[y*x]"
+#define aY oH dE wB
+#define aX mQ" "
+#define aW "cGreater"
+#define aV " cAdd"
+#define aU "y "
+#define aT gY if(dO wB
+#define aS "cInv"
+#define aR mC aS
+#define aQ " B"a0
+#define aP " "aO
+#define aO "A"a0
+#define aN "cAbsNot"
+#define aM "cLessOrEq"
+#define aL "cAdd "q01
+#define aK "cCos"
+#define aJ "cLog2"
+#define aI "cCosh"
+#define aH "cLog10"
+#define aG "B[B==A]"
+#define aF "cNotNot"
+#define aE " "wG
+#define aD "A[IsVarOpcode(A)]"
+#define aC " "aD" "
+#define aB " cNot"
+#define aA "   "a2
+#define a9 "cDup"aV
+#define a8 "cGreaterOrEq"
+#define a7 " cRDiv"
+#define a6 "x"aV
+#define a5 "cEqual"
+#define a4 "cRSub"
+#define a3 "[x]"wH
+#define a2 " with"aP
+#define a1 " cPow"
+#define a0 " "wC
+#define wZ "x[x!=Value_t()] "
+#define wY " x"wH
+#define wX "x[x==Value_t()]"wH
+#define wW "cNEqual"
+#define wV aD m7
+#define wU "x = "<<x
+#define wT aD wH
+#define wS "x[isInteger(x)]"a1
+#define wR "x[x!=Value_t(0)]"m7
+#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 aU"= "<<y wM
+#define wF " x A[IsComparisonOpcode(A)]"
+#define wE FP_TRACE_BYTECODE_ADD
+#define wD "A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "wX
+#define wC "= "<<FP_TRACE_OPCODENAME
+#define wB FP_TRACE_BYTECODE_OPTIMIZATION
+#define wA "    with "wU<<
+#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 mR(292,aU"cAdd B[IsVarOpcode(B)]"mF" "a6,mJ aV" B"mF,wA","aQ(B)<<","aE);q4
+#define hI cNeg:
+#define hH :qS cDup:
+#define hG hS hH hK h1 wB(310,a9" "a9,"[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,mG mQ,mQ,);q4 Lab qU qB
+#define gZ 3 h1 wB(311,a9 m6 a9,"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 "mQ,"[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
+mQ,"A"
+,aA(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"
+wY
+aV,"[x+Value_t(1)]"
+wH,wN);q4
+Laf;}
+}
+q4
+dX
+oF
+wB(199,q81
+aV,"cSub"
+,);q4
+Lag
+gY
+hK
+qZ
+mR(127,aU"cAdd "
+a6,"[y+x]"
+aV,q31);q4
+Lah;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mR(298,aU"cAdd "
+mS,mJ
+aV" "
+a4,q31);q4
+Lai;qT
+hI
+wB(299,mG
+mS,"[-x]"
+aV" "
+a4,wN);q4
+Laj
+qU
+q6:mR(297,aU
+mS,mJ" "
+a4,q31);q4
+Lak;qT
+oA
+Lal;qT
+hI
+wB(293,mG"B[IsVarOpcode(B)]"
+mF" "
+a6,"[-x]"
+aV" B"
+mF,wA","
+aQ(B)wM);q4
+Lam
+qU
+q6:mR(291,aU"B[IsVarOpcode(B)]"
+mF" "
+a6,mJ" B"
+mF,wA","
+aQ(B)<<","
+aE);q4
+Lan;}
+w9
+mR(105,aU
+a6,"[y+x]"
+,q31);q4
+Lao;}
+g8)){wB(57,"x[x==Value_t()]"
+aV,,wN);q4
+Lap;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x "
+a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aV" "
+a4,aA(A)<<","
+m4);incStackPtr();--mStackPtr;q4
+Laq;}
+wB(295,a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A"
+aV" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lba;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mC"cAnd"
+,aF,);q4
+Lbb
+gY
+m2(117,m3"cAnd"
+,"[fp_and(x,y)]"
+,q31);q4
+Lbc;h8}
+qH
+TailCall_cDiv:g5
+cDiv
+hH
+wB(78,"cDup"
+m7,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,);q4
+w7
+if
+hF
+gQ
+hI
+wB(125,mG
+wZ"cDiv"
+,"[-x]"
+m7,wN);q4
+Lbe
+qU
+q6:mR(103,aU
+wZ"cDiv"
+,"[y/x]"
+,q31);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
+a5,"A"
+,q61(A)wM);q4
+Lap;}
+}
+m2(115,m3
+a5,"[fp_equal(y,x)]"
+,q31);q4
+Lbg;}
+g8
+0
+hU
+wB(359,aX
+wL
+a5,"[x] "
+a5,wN);q4
+Lbh
+qU
+cSqr:wB(361,mZ
+wL
+a5,"[x] "
+a5,wN);q4
+Lbh;}
+wB(411,wL
+a5,"cNot"
+,wN);q4
+Lbi;qG
+TailCall_cGreater:g5
+o1:oL
+hU
+wB(413,aX
+wL
+aW,aF,wN);q4
+Lbj;aY(417,wJ
+wL
+aW,"A "
+aF,q61(A)wM);q4
+Lbk;}
+}
+}
+m2(113,m3
+aW,"[fp_less(x,y)]"
+,q31);q4
+Lbl;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+g8
+1
+hU
+wB(414,aX
+wO
+a8,aF,wN);q4
+Lbj;aY(418,wJ
+wO
+a8,"A "
+aF,q61(A)wM);q4
+Lbk;}
+}
+}
+m2(114,m3
+a8,"[fp_lessOrEq(x,y)]"
+,q31);q4
+Lbm;qG
+TailCall_cInv:g5
+cInv:qY
+if
+hF)){wB(101,wZ
+aS,"[Value_t(1)/x]"
+,wN);q4
+Lbn;qG
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mB,mV,q61(A)wM);oS;}
+}
+g8
+1
+hU
+wB(415,aX
+wO
+mB,"cNot"
+,wN);q4
+Lbp;aY(419,wJ
+wO
+mB,"A"
+aB,q61(A)wM);q4
+Lbi;}
+}
+}
+m2(111,m3
+mB,"[fp_less(y,x)]"
+,q31);q4
+Lbq;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:oL
+hU
+wB(416,aX
+wL
+aM,"cNot"
+,wN);q4
+Lbp;aY(420,wJ
+wL
+aM,"A"
+aB,q61(A)wM);q4
+Lbi;}
+}
+}
+m2(112,m3
+aM,"[fp_lessOrEq(y,x)]"
+,q31);q4
+Lca;qG
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mC
+m8,,);q4
+w6
+m2(141,m3
+m8,"[fp_max(x,y)]"
+,q31);q4
+Lcc;}
+gP
+cDup:hD
+wB(66,aG
+mE
+aC
+m8,"B"
+mE,aA(A)q51(B)wM);q4
+Lcb;qT
+cMax:hD
+wB(68,aG" "
+m8
+aC
+m8,"B "
+m8,aA(A)q51(B)wM);q4
+Lcb;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mC
+m9,,);q4
+w6
+m2(140,m3
+m9,"[fp_min(x,y)]"
+,q31);q4
+Lcd;}
+gP
+cDup:hD
+wB(65,aG
+mE
+aC
+m9,"B"
+mE,aA(A)q51(B)wM);q4
+Lcb;qT
+cMin:hD
+wB(67,aG" "
+m9
+aC
+m9,"B "
+m9,aA(A)q51(B)wM);q4
+Lcb;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m2(104,aU
+wZ"cMod"
+,"[fp_mod(y,x)]"
+,q31);q4
+Lce;}
+qG
+TailCall_cMul:g5
+h3
+hH
+wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lcf
+oF
+qQ
+h9
+cDup:wB(467,mC
+q81
+wH,"cSqr"
+mD,);q4
+Lcg;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aG
+wH
+aC
+q81
+wH,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lch;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mC"x"
+a1
+wH,"[x+Value_t(1)]"
+a1,wN);q4
+Lci;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wT" "
+wX,a3,q61(A)wM);q4
+Lcj;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mR(92,aU
+wD,a3,q61(A)<<","
+aE);q4
+Lck;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mR(96,aU
+wK,mV,q61(A)q51(B)<<","
+aE);q4
+Lcl;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lcm;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lcn;}
+}
+}
+if(d1
+B)){wB(90,"B[IsVarOpcode(B)] "
+wD,a3,q61(A)q51(B)wM);q4
+Lcj;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mV,q61(A)q51(B)wM);q4
+Lco;}
+}
+}
+if(d1
+h2
+wB(88,aD" "
+wX,"[x]"
+,q61(A)wM);q4
+Lcp;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wX,a3,q61(A)wM);q4
+Lcq;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup:wB(317,a9
+wY,"[x+x]"
+wH,wN);q4
+Lda
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,aD" y"
+wH
+aV
+wY,a3" A "
+aZ
+wH
+aV,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Ldb;}
+w9
+mR(385,aU"cAdd"
+wY,a3" "
+aZ
+aV,q31);q4
+Ldc;qT
+h3:qQ
+hE
+d3
+3
+h1
+wB(319,a9
+wH
+wY,"cMul [x+x]"
+wH,wN);q4
+Ldd;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+wY,,q31);q4
+Lde;}
+wB(128,"y"
+wH
+wY,aZ
+wH,q31);q4
+Ldf;qT
+hI
+wB(122,q81
+wY,"[-x]"
+wH,wN);q4
+Ldg
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,aD" y"
+m6"cSub"
+wY,a3" A "
+aZ
+m6"cSub"
+,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Ldh;}
+}
+w9
+mR(102,"y"
+wY,aZ,q31);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,q81,wN);q4
+Ldj;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,a9,wN);q4
+Ldk;h8
+g7
+dY:;A=dF
+qO
+A
+gQ
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aG
+mD
+m6
+wT,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lch;}
+q4
+Default4;g7
+Default4:;hD
+wB(461,aG
+m6
+wT,m0
+wH,aA(A)q51(B)wM);q4
+Ldl;}
+}
+q4
+dZ
+oF
+hD
+wB(464,aG
+mD" "
+wT,m0
+mD,aA(A)q51(B)wM);q4
+Lcg;}
+q4
+dZ;g7
+dZ:;B=qK
+qR
+w4
+wB(458,aG" "
+wT,m0,aA(A)q51(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]"
+m6"B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(D)wM);q4
+Ldm;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:dA
+A=dD
+wB(422,"A[IsLogicalOpcode(A)] "
+wO
+wW,"A"
+aB,q61(A)wM);q4
+Lbi;}
+}
+m2(116,m3
+wW,"[fp_nequal(y,x)]"
+,q31);q4
+Ldn;}
+g8
+0
+hU
+wB(360,aX
+wL
+wW,"[x] "
+wW,wN);q4
+Ldo
+qU
+cSqr:wB(362,mZ
+wL
+wW,"[x] "
+wW,wN);q4
+Ldo;}
+wB(412,wL
+wW,aF,wN);q4
+Lbk;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+m6
+q81,"[-x]"
+wH,wN);q4
+Ldp;qT
+hI
+wB(61,q81
+mD,,);q4
+w6
+wB(100,"x"
+mD,"[-x]"
+,wN);q4
+Ldq;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbs:wB(227,mQ
+aB,"cNot"
+,);q4
+Lea
+qU
+cAbsNot:A=dD
+wB(389,"A[IsLogicalOpcode(A)] "
+aN
+aB,"A"
+,aA(A)wM);q4
+Lcb;}
+if(A!=q6){wB(390,"A[A!=cImmed] "
+aN
+aB,"A cAbsNotNot"
+,aA(A)wM);q4
+Leb;}
+q4
+o0
+qU
+cAbsNotNot:wB(231,"cAbsNotNot"
+aB,aN,);q4
+Lec
+qU
+hS
+gM
+wB(424,a6
+aB,"[-x] "
+a5,wN);q4
+Led;}
+q4
+o0
+qU
+w8:wB(220,a5
+aB,wW,);q4
+Lee
+qU
+o1:wB(218,aW
+aB,aM,);q4
+Lef
+qU
+dK:wB(219,a8
+aB,mB,);q4
+Leg
+qU
+cLess:wB(216,mB
+aB,a8,);q4
+Leh
+qU
+cLessOrEq:wB(217,aM
+aB,aW,);q4
+Lei
+qU
+cNEqual:wB(221,wW
+aB,a5,);q4
+Lej
+oF
+wB(226,q81
+aB,"cNot"
+,);q4
+Lea
+qU
+cNot:wB(229,"cNot"
+aB,aF,);q4
+Lbb
+qU
+dS:wB(230,aF
+aB,"cNot"
+,);q4
+Lea
+gY
+wB(107,"x"
+aB,"[fp_not(x)]"
+,wN);q4
+Lek;g7
+o0:;A=dF
+qR
+qX
+wB(391,wJ"cNot"
+,"A "
+aN,aA(A)wM);q4
+Lel;qG
+TailCall_cNotNot:g5
+dS:qS
+hS
+gM
+wB(423,a6" "
+aF,"[-x] "
+wW,wN);q4
+Lem;qT
+cNot:wB(232,"cNot "
+aF,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mC"cOr"
+,aF,);q4
+Lbb
+gY
+m2(118,m3"cOr"
+,"[fp_or(x,y)]"
+,q31);q4
+Len;h8}
+qH
+TailCall_cRDiv:g5
+cRDiv:dA
+wB(268,wO"cRDiv"
+,aS,wN);q4
+Leo;qG
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,mC
+a4,"[Value_t()]"
+wH,);q4
+Lep;}
+qH
+TailCall_cSqr:g5
+cSqr:qS
+cAbs:wB(204,aX"cSqr"
+,"cSqr"
+,);q4
+Leq
+oF
+wB(203,mG"cSqr"
+,"cSqr"
+,);q4
+Leq;}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,mC"cSub"
+,"[Value_t()]"
+wH,);q4
+Lep
+oF
+wB(200,q81
+mF,"cAdd"
+,);q4
+Lfa
+gY
+g8)){wB(58,"x[x==Value_t()]"
+mF,,wN);q4
+Lap;}
+m2(106,m3"cSub"
+,"[y-x]"
+,q31);q4
+Lfb;}
+wB(51,"x"
+mF,"[-x]"
+aV,wN);q4
+Lfc
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x "
+a4
+aC"cSub"
+,"A"
+aV" [x] "
+a4,aA(A)<<","
+m4);q4
+Lfd;}
+wB(296,a4
+aC"cSub"
+,"[DO_STACKPLUS1] A"
+mF" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lfe;}
+qG
+g7
+Default0:;A=w5
+qR
+IsComparisonOpcode(h2
+qY
+hK
+qZ
+mR(364,aU"cAdd"
+wF,"[x-y] A"
+,aA(A)<<q41
+aE);q4
+Lff;qT
+hI
+wB(365,q81
+wF,"[-x] {OppositeComparisonOpcode(A)}"
+,aA(A)<<","
+m4);q4
+Lfg;}
+}
+}
+if(d1
+A
+qP
+0){B=q0[0
+hZ
+wB(475,aG" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mE,aA(A)q51(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"
+mE,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(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)q11
+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
+q11
+gX
+Lfp;Lba:mI
+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
+mL
+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
+mL
+Lca:gT
+fp_lessOrEq
+mL
+Lcc:gT
+fp_max(x
+h6
+Lcd:gT
+fp_min(x
+h6
+Lce:gT
+fp_mod
+mL
+Lcf:gU
+cSqr;Lgk:wE(cSqr);q4
+TailCall_cSqr;Lcg:mI
+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:hV
+2;qI
+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
+q11);dM
+Lgf;Ldc:gT
+x;d7
+dU
+qF
+y*x
+gX
+Lge;Ldd:q8
+4
+dT
+qF
+x+x
+gX
+Lgp;Lde:hV
+2;qI
+q8
+oR
+gJ
+Ldf:gT
+y*x;q4
+Lgm;Ldg:o9;q4
+Lcq;Ldh:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q11);dM
+Lgc;Ldi:gT
+y*x;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
+mL
+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
+m5
+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
+q11
+gX
+Lfq;Lfe:mI
+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"
+wY
+aV,"[x+Value_t(1)]"
+wH,wN);q4
+Laf;}
+}
+q4
+dX
+oF
+wB(199,q81
+aV,"cSub"
+,);q4
+Lag
+gY
+hK
+qZ
+mR(127,aU"cAdd "
+a6,"[y+x]"
+aV,q31);q4
+Lah;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mR(298,aU"cAdd "
+mS,mJ
+aV" "
+a4,q31);q4
+Lai;qT
+hI
+wB(299,mG
+mS,"[-x]"
+aV" "
+a4,wN);q4
+Laj
+qU
+q6:mR(297,aU
+mS,mJ" "
+a4,q31);q4
+Lak;qT
+oA
+Lal;qT
+hI
+wB(293,mG"B[IsVarOpcode(B)]"
+mF" "
+a6,"[-x]"
+aV" B"
+mF,wA","
+aQ(B)wM);q4
+Lam
+qU
+q6:mR(291,aU"B[IsVarOpcode(B)]"
+mF" "
+a6,mJ" B"
+mF,wA","
+aQ(B)<<","
+aE);q4
+Lan;}
+w9
+mR(105,aU
+a6,"[y+x]"
+,q31);q4
+Lao;}
+g8)){wB(57,"x[x==Value_t()]"
+aV,,wN);q4
+Lap;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x "
+a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aV" "
+a4,aA(A)<<","
+m4);incStackPtr();--mStackPtr;q4
+Laq;}
+wB(295,a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A"
+aV" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lba;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mC"cAnd"
+,aF,);q4
+Lbb
+gY
+m2(117,m3"cAnd"
+,"[fp_and(x,y)]"
+,q31);q4
+Lbc;h8}
+qH
+TailCall_cConj:g5
+cConj:qS
+cConj:wB(63,mT" "
+mT,,);q4
+w7
+wB(193,"x "
+mT,"[fp_conj(x)]"
+,wN);q4
+Lbe;}
+qH
+TailCall_cDiv:g5
+cDiv
+hH
+wB(78,"cDup"
+m7,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,);q4
+Lbf
+gY
+if
+hF
+gQ
+hI
+wB(125,mG
+wZ"cDiv"
+,"[-x]"
+m7,wN);q4
+Lbg
+qU
+q6:mR(103,aU
+wZ"cDiv"
+,"[y/x]"
+,q31);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
+a5,"A"
+,q61(A)wM);q4
+Lap;}
+}
+m2(115,m3
+a5,"[fp_equal(y,x)]"
+,q31);q4
+Lbi;}
+g8
+0
+hU
+wB(359,aX
+wL
+a5,"[x] "
+a5,wN);q4
+Lbj
+qU
+cSqr:wB(361,mZ
+wL
+a5,"[x] "
+a5,wN);q4
+Lbj;}
+wB(411,wL
+a5,"cNot"
+,wN);q4
+Lbk;qG
+TailCall_cGreater:g5
+o1:qY
+m2(113,m3
+aW,"[fp_less(x,y)]"
+,q31);q4
+Lbl;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+m2(114,m3
+a8,"[fp_lessOrEq(x,y)]"
+,q31);q4
+Lbm;qG
+TailCall_cImag:g5
+cImag:qS
+cAbs:wB(81,aX
+mU,"[Value_t()]"
+wH,);q4
+Lbn
+qU
+cReal:wB(80,"cReal "
+mU,"[Value_t()]"
+wH,);q4
+Lbn
+gY
+wB(192,"x "
+mU,"[fp_imag(x)]"
+,wN);oS;}
+qH
+TailCall_cInv:g5
+cInv:qY
+if
+hF)){wB(101,wZ
+aS,"[Value_t(1)/x]"
+,wN);q4
+Lbp;qG
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mB,mV,q61(A)wM);q4
+Lbq;}
+}
+m2(111,m3
+mB,"[fp_less(y,x)]"
+,q31);q4
+Lca;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:qY
+m2(112,m3
+aM,"[fp_lessOrEq(y,x)]"
+,q31);q4
+Lcb;qG
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mC
+m8,,);q4
+w7
+m2(141,m3
+m8,"[fp_max(x,y)]"
+,q31);q4
+Lcc;}
+gP
+cDup:hD
+wB(66,aG
+mE
+aC
+m8,"B"
+mE,aA(A)q51(B)wM);q4
+Lbd;qT
+cMax:hD
+wB(68,aG" "
+m8
+aC
+m8,"B "
+m8,aA(A)q51(B)wM);q4
+Lbd;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mC
+m9,,);q4
+w7
+m2(140,m3
+m9,"[fp_min(x,y)]"
+,q31);q4
+Lcd;}
+gP
+cDup:hD
+wB(65,aG
+mE
+aC
+m9,"B"
+mE,aA(A)q51(B)wM);q4
+Lbd;qT
+cMin:hD
+wB(67,aG" "
+m9
+aC
+m9,"B "
+m9,aA(A)q51(B)wM);q4
+Lbd;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m2(104,aU
+wZ"cMod"
+,"[fp_mod(y,x)]"
+,q31);q4
+Lce;}
+qG
+TailCall_cMul:g5
+h3
+hH
+wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lcf
+oF
+qQ
+h9
+cDup:wB(467,mC
+q81
+wH,"cSqr"
+mD,);q4
+Lcg;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aG
+wH
+aC
+q81
+wH,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lch;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mC"x"
+a1
+wH,"[x+Value_t(1)]"
+a1,wN);q4
+Lci;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wT" "
+wX,a3,q61(A)wM);q4
+Lcj;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mR(92,aU
+wD,a3,q61(A)<<","
+aE);q4
+Lck;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mR(96,aU
+wK,mV,q61(A)q51(B)<<","
+aE);q4
+Lcl;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lcm;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lcn;}
+}
+}
+if(d1
+B)){wB(90,"B[IsVarOpcode(B)] "
+wD,a3,q61(A)q51(B)wM);q4
+Lcj;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mV,q61(A)q51(B)wM);q4
+Lco;}
+}
+}
+if(d1
+h2
+wB(88,aD" "
+wX,"[x]"
+,q61(A)wM);q4
+Lcp;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wX,a3,q61(A)wM);q4
+Lcq;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup:wB(317,a9
+wY,"[x+x]"
+wH,wN);q4
+Lda
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,aD" y"
+wH
+aV
+wY,a3" A "
+aZ
+wH
+aV,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Ldb;}
+w9
+mR(385,aU"cAdd"
+wY,a3" "
+aZ
+aV,q31);q4
+Ldc;qT
+h3:qQ
+hE
+d3
+3
+h1
+wB(319,a9
+wH
+wY,"cMul [x+x]"
+wH,wN);q4
+Ldd;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+wY,,q31);q4
+Lde;}
+wB(128,"y"
+wH
+wY,aZ
+wH,q31);q4
+Ldf;qT
+hI
+wB(122,q81
+wY,"[-x]"
+wH,wN);q4
+Ldg
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,aD" y"
+m6"cSub"
+wY,a3" A "
+aZ
+m6"cSub"
+,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Ldh;}
+}
+w9
+mR(102,"y"
+wY,aZ,q31);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,q81,wN);q4
+Ldj;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,a9,wN);q4
+Ldk;h8
+g7
+dY:;A=dF
+qO
+A
+gQ
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aG
+mD
+m6
+wT,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lch;}
+q4
+Default4;g7
+Default4:;hD
+wB(461,aG
+m6
+wT,m0
+wH,aA(A)q51(B)wM);q4
+Ldl;}
+}
+q4
+dZ
+oF
+hD
+wB(464,aG
+mD" "
+wT,m0
+mD,aA(A)q51(B)wM);q4
+Lcg;}
+q4
+dZ;g7
+dZ:;B=qK
+qR
+w4
+wB(458,aG" "
+wT,m0,aA(A)q51(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]"
+m6"B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(D)wM);q4
+Ldm;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:dA
+A=dD
+wB(422,"A[IsLogicalOpcode(A)] "
+wO
+wW,"A"
+aB,q61(A)wM);q4
+Lbk;}
+}
+m2(116,m3
+wW,"[fp_nequal(y,x)]"
+,q31);q4
+Ldn;}
+g8
+0
+hU
+wB(360,aX
+wL
+wW,"[x] "
+wW,wN);q4
+Ldo
+qU
+cSqr:wB(362,mZ
+wL
+wW,"[x] "
+wW,wN);q4
+Ldo;}
+wB(412,wL
+wW,aF,wN);q4
+Ldp;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+m6
+q81,"[-x]"
+wH,wN);q4
+Ldq;qT
+hI
+wB(61,q81
+mD,,);q4
+w7
+wB(100,"x"
+mD,"[-x]"
+,wN);q4
+Lea;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbsNotNot:wB(231,"cAbsNotNot"
+aB,aN,);q4
+Leb
+qU
+hS
+gM
+wB(424,a6
+aB,"[-x] "
+a5,wN);q4
+Lec;qT
+w8:wB(220,a5
+aB,wW,);q4
+Led
+qU
+o1:wB(218,aW
+aB,aM,);q4
+Lee
+qU
+dK:wB(219,a8
+aB,mB,);q4
+Lef
+qU
+cLess:wB(216,mB
+aB,a8,);q4
+Leg
+qU
+cLessOrEq:wB(217,aM
+aB,aW,);q4
+Leh
+qU
+cNEqual:wB(221,wW
+aB,a5,);q4
+Lei
+qU
+cNot:wB(229,"cNot"
+aB,aF,);q4
+Lbb
+qU
+dS:wB(230,aF
+aB,"cNot"
+,);q4
+Lej
+gY
+wB(107,"x"
+aB,"[fp_not(x)]"
+,wN);q4
+Lek;}
+qH
+TailCall_cNotNot:g5
+dS:qS
+hS
+gM
+wB(423,a6" "
+aF,"[-x] "
+wW,wN);q4
+Lel;qT
+cNot:wB(232,"cNot "
+aF,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mC"cOr"
+,aF,);q4
+Lbb
+gY
+m2(118,m3"cOr"
+,"[fp_or(x,y)]"
+,q31);q4
+Lem;h8}
+qH
+TailCall_cRDiv:g5
+cRDiv:dA
+wB(268,wO"cRDiv"
+,aS,wN);q4
+Len;qG
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,mC
+a4,"[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,aX"cSqr"
+,"cSqr"
+,);q4
+Lep
+oF
+wB(203,mG"cSqr"
+,"cSqr"
+,);q4
+Lep;}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,mC"cSub"
+,"[Value_t()]"
+wH,);q4
+Lbn
+oF
+wB(200,q81
+mF,"cAdd"
+,);q4
+Leq
+gY
+g8)){wB(58,"x[x==Value_t()]"
+mF,,wN);q4
+Lap;}
+m2(106,m3"cSub"
+,"[y-x]"
+,q31);q4
+Lfa;}
+wB(51,"x"
+mF,"[-x]"
+aV,wN);q4
+Lfb
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x "
+a4
+aC"cSub"
+,"A"
+aV" [x] "
+a4,aA(A)<<","
+m4);q4
+Lfc;}
+wB(296,a4
+aC"cSub"
+,"[DO_STACKPLUS1] A"
+mF" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lfd;}
+qG
+g7
+Default0:;A=w5
+w1
+0){B=q0[0
+hZ
+wB(475,aG" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mE,aA(A)q51(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"
+mE,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(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)q11
+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
+q11
+gX
+Lfm;Lba:mI
+A
+gX
+Lfm;Lbb:gU
+dS;Lga:wE(cNotNot);q4
+TailCall_cNotNot;Lbc:gT
+fp_and(x
+h6
+Lbe:q7=fp_conj
+m5
+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
+mL
+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
+m5
+Lbp:q7=g1
+1)/x;gJ
+Lca:gT
+fp_less
+mL
+Lcb:gT
+fp_lessOrEq
+mL
+Lcc:gT
+fp_max(x
+h6
+Lcd:gT
+fp_min(x
+h6
+Lce:gT
+fp_mod
+mL
+Lcf:gU
+cSqr;Lgf:wE(cSqr);q4
+TailCall_cSqr;Lcg:mI
+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:hV
+2;qI
+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
+q11);dM
+Lgc;Ldc:gT
+x;d7
+dU
+qF
+y*x
+gX
+Lgb;Ldd:q8
+4
+dT
+qF
+x+x
+gX
+Lgk;Lde:hV
+2;qI
+q8
+oR
+gJ
+Ldf:gT
+y*x;q4
+Lgh;Ldg:o9;q4
+Lcq;Ldh:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q11);dM
+Lfq;Ldi:gT
+y*x;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
+mL
+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
+m5
+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
+m5
+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
+q11
+gX
+Lfn;Lfd:mI
+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
+mQ,"A"
+,aA(A)wM);gJ
+qG
+TailCall_cAcos:g5
+cAcos:hN<=m1(148,"x[fp_abs(x)<=Value_t(1)] cAcos"
+,"[fp_acos(x)]"
+,wN);q4
+Lad;qG
+TailCall_cAcosh:g5
+cAcosh:qY
+if(x>=m1(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"
+wY
+aV,"[x+Value_t(1)]"
+wH,wN);q4
+Lah;}
+}
+q4
+dX
+oF
+wB(199,q81
+aV,"cSub"
+,);q4
+Lai
+gY
+hK
+qZ
+mR(127,aU"cAdd "
+a6,"[y+x]"
+aV,q31);q4
+Laj;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mR(298,aU"cAdd "
+mS,mJ
+aV" "
+a4,q31);q4
+Lak;qT
+hI
+wB(299,mG
+mS,"[-x]"
+aV" "
+a4,wN);q4
+Lal
+qU
+q6:mR(297,aU
+mS,mJ" "
+a4,q31);q4
+Lam;qT
+oA
+Lan;qT
+hI
+wB(293,mG"B[IsVarOpcode(B)]"
+mF" "
+a6,"[-x]"
+aV" B"
+mF,wA","
+aQ(B)wM);q4
+Lao
+qU
+q6:mR(291,aU"B[IsVarOpcode(B)]"
+mF" "
+a6,mJ" B"
+mF,wA","
+aQ(B)<<","
+aE);q4
+Lap;}
+w9
+mR(105,aU
+a6,"[y+x]"
+,q31);q4
+Laq;}
+g8)){wB(57,"x[x==Value_t()]"
+aV,,wN);q4
+Lba;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x "
+a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aV" "
+a4,aA(A)<<","
+m4);incStackPtr();--mStackPtr;q4
+Lbb;}
+wB(295,a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A"
+aV" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lbc;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mC"cAnd"
+,aF,);q4
+w7
+m2(117,m3"cAnd"
+,"[fp_and(x,y)]"
+,q31);q4
+Lbe;h8}
+qH
+TailCall_cAsin:g5
+cAsin:hN<=m1(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
+m2(139,m3"cAtan2"
+,"[fp_atan2(y,x)]"
+,q31);q4
+Lbi;qG
+TailCall_cAtanh:g5
+cAtanh:hN<m1(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,mG
+mW,mO
+mD,);q4
+Lbl
+gY
+wB(135,"x "
+mW,"[fp_ceil(x)]"
+,wN);q4
+Lbm
+gS
+wB(396,"A[IsAlwaysIntegerOpcode(A)] "
+mW,"A"
+,aA(A)wM);gJ
+qG
+TailCall_cCos:g5
+cCos:qS
+cAbs:wB(235,aX
+aK,aK,);q4
+Lbn
+oF
+wB(238,mG
+aK,aK,);q4
+Lbn
+gY
+wB(152,"x "
+aK,"[fp_cos(x)]"
+,wN);oS;oH
+qN
+qQ
+h9
+cSec:hD
+wB(500,aG" "
+mX" "
+wI
+aK,"B "
+mX" "
+aR,aA(A)q51(B)wM);q4
+Lbp;qT
+cSin:hD
+wB(494,aG" "
+mM" "
+wI
+aK,"B cSinCos"
+,aA(A)q51(B)wM);q4
+Lbq;h8}
+qG
+TailCall_cCosh:g5
+cCosh:qS
+cAbs:wB(236,aX
+aI,aI,);q4
+Lca
+qU
+cAsinh:wB(450,"cAsinh "
+aI,"[DO_STACKPLUS1] "
+mZ"[Value_t(1)] "
+aL,);incStackPtr();--mStackPtr;q4
+Lcb
+oF
+wB(239,mG
+aI,aI,);q4
+Lca
+gY
+wB(153,"x "
+aI,"[fp_cosh(x)]"
+,wN);q4
+Lcc;oH
+qN
+oY
+cSinh
+mY(507,aG" cSinh "
+wI
+aI,"B cSinhCosh"
+,aA(A)q51(B)wM);q4
+Lcd;}
+}
+qG
+TailCall_cCot:g5
+cCot:A=qN
+oY
+cTan
+mY(498,aG" "
+mN" "
+wI"cCot"
+,"B "
+mN" "
+aR,aA(A)q51(B)wM);q4
+Lbp;}
+qG
+TailCall_cCsc:g5
+cCsc:A=qN
+oY
+cSin
+mY(496,aG" "
+mM" "
+wI"cCsc"
+,"B "
+mM" "
+aR,aA(A)q51(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,aK
+m7,mX
+wH,);q4
+Lcf
+qU
+cCot:wB(254,"cCot"
+m7,mN
+wH,);q4
+Lcg
+qU
+cCsc:wB(252,"cCsc"
+m7,mM
+wH,);q4
+Lch
+qU
+cDup:wB(78,"cDup"
+m7,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,);q4
+Lci
+qU
+w2
+wB(408,mH
+m7,mG
+mH
+wH,);q4
+Lcj
+qU
+cExp2:wB(409,"cExp2"
+m7,mG"cExp2"
+wH,);q4
+Lck
+qU
+cInv:wB(213,aS
+m7,"cMul"
+,);q4
+Lcl
+qU
+cPow:wB(407,"cPow"
+m7,q81
+a1
+wH,);q4
+Lcm
+qU
+cSec:wB(253,mX
+m7,aK
+wH,);q4
+Lcn
+qU
+cSin:wB(249,mM
+m7,"cCsc"
+wH,);q4
+Lco
+qU
+cSinCos:wB(502,"cSinCos"
+m7,mN,);q4
+Lcp
+qU
+cSinhCosh:wB(509,"cSinhCosh"
+m7,"cTanh"
+,);q4
+Lcq
+qU
+cTan:wB(251,mN
+m7,"cCot"
+wH,);q4
+Lda
+gY
+if
+hF
+gQ
+hI
+wB(125,mG
+wZ"cDiv"
+,"[-x]"
+m7,wN);q4
+Ldb
+qU
+q6:mR(103,aU
+wZ"cDiv"
+,"[y/x]"
+,q31);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>()]"
+m6
+wR,"cDeg"
+,q31);q4
+Ldd;}
+if((y/x)==fp_const_deg_to_rad
+h7
+wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]"
+m6
+wR,"cRad"
+,q31);q4
+Lde;}
+wB(323,"y"
+m6
+wR,"[y/x]"
+wH,q31);q4
+Ldf;}
+}
+wB(325,wR,"[Value_t(1)/x]"
+wH,wN);q4
+Ldg;}
+gP
+cDiv:hC
+wB(271,q21" "
+wV,"[DO_STACKPLUS1] B A"
+m6"cDiv"
+,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4
+Ldh;qT
+cRDiv:qQ
+hE
+qV
+hM
+wB(266,"x"
+a7" "
+wV,"A"
+m6"[x]"
+a7,aA(A)<<","
+m4);q4
+Ldi;g7
+hC
+wB(265,"B[IsVarOpcode(B)]"
+a7" "
+wV,"A"
+m6"B"
+a7,aA(A)q51(B)wM);q4
+Ldj;}
+h8}
+qG
+TailCall_cEqual:g5
+w8:oL
+hU
+wB(359,aX
+wL
+a5,"[x] "
+a5,wN);q4
+Ldk
+qU
+cSqr:wB(361,mZ
+wL
+a5,"[x] "
+a5,wN);q4
+Ldk;}
+}
+m2(115,m3
+a5,"[fp_equal(y,x)]"
+,q31);q4
+Ldl;qG
+TailCall_cExp:g5
+w2
+qS
+hS
+gM
+wB(404,a6" "
+mH,mH" [fp_exp(x)]"
+wH,wN);q4
+Ldm;qT
+cLog:A=dE
+wB(340,wJ
+mA" "
+mH,"A"
+,aA(A)wM);q4
+oN
+hM
+wB(154,"x "
+mH,"[fp_exp(x)]"
+,wN);q4
+Ldo;}
+qH
+TailCall_cExp2:g5
+cExp2:qS
+hS
+gM
+wB(405,a6" cExp2"
+,"cExp2 [fp_exp2(x)]"
+wH,wN);q4
+Ldp;qT
+cLog2:A=dE
+wB(341,wJ
+aJ" cExp2"
+,"A"
+,aA(A)wM);q4
+oN
+hM
+wB(155,"x cExp2"
+,"[fp_exp2(x)]"
+,wN);q4
+Ldq;}
+wB(479,"cExp2"
+,"[DO_STACKPLUS1] [fp_log(Value_t(2))]"
+m6
+mH,);incStackPtr();--mStackPtr;q4
+Lea;TailCall_cFloor:g5
+cFloor:qS
+hI
+wB(401,mG
+mO,mW
+mD,);q4
+Leb
+gY
+wB(136,"x "
+mO,"[fp_floor(x)]"
+,wN);q4
+Lec
+gS
+wB(395,"A[IsAlwaysIntegerOpcode(A)] "
+mO,"A"
+,aA(A)wM);gJ
+qG
+TailCall_cGreater:g5
+o1:qY
+m2(113,m3
+aW,"[fp_less(x,y)]"
+,q31);q4
+Led;}
+g8-oO
+wB(431,"x[x==Value_t(-0.5)] "
+aW,mG
+aN,wN);q4
+Lee;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+dB
+cAbs){wB(427,aX"x[x!=Value_t(0)] "
+a8,"[Value_t(0.5)/x]"
+m6
+aF,wN);q4
+Lef;}
+}
+m2(114,m3
+a8,"[fp_lessOrEq(x,y)]"
+,q31);q4
+Leg;}
+g8
+oO
+wB(430,"x[x==Value_t(0.5)] "
+a8,"cAbsNotNot"
+,wN);q4
+Leh;qG
+TailCall_cHypot:g5
+cHypot
+d4
+dF==cSinCos){wB(84,"cSinCos cHypot"
+,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,);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"
+,aA(A)wM);gJ
+qG
+TailCall_cInv:g5
+cInv:qS
+cCos:wB(256,aK
+mK,mX,);q4
+Lej
+qU
+cCot:wB(260,"cCot"
+mK,mN,);q4
+Lcp
+qU
+cCsc:wB(258,"cCsc"
+mK,mM,);q4
+Lek
+qU
+cInv:wB(62,aS
+mK,,);q4
+Ldn
+qU
+cPow:wB(355,"cPow"
+mK,q81
+a1,);q4
+Lel
+qU
+cSec:wB(259,mX
+mK,aK,);q4
+Lem
+qU
+cSin:wB(255,mM
+mK,"cCsc"
+,);q4
+Len
+qU
+cSqrt:wB(206,q01
+mK,"cRSqrt"
+,);q4
+Leo
+qU
+cTan:wB(257,mN
+mK,"cCot"
+,);q4
+Lep
+gY
+if
+hF)){wB(101,wZ
+aS,"[Value_t(1)/x]"
+,wN);q4
+Leq;h8}
+qH
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mB,mV,q61(A)wM);q4
+Lfa;}
+}
+dB
+cAbs){wB(426,aX"x[x!=Value_t(0)] "
+mB,"[Value_t(0.5)/x]"
+wH
+aB,wN);q4
+Lfb;}
+}
+m2(111,m3
+mB,"[fp_less(y,x)]"
+,q31);q4
+Lfc;}
+g8
+oO
+wB(429,"x[x==Value_t(0.5)] "
+mB,aN,wN);q4
+Lfd;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:qY
+m2(112,m3
+aM,"[fp_lessOrEq(y,x)]"
+,q31);q4
+Lfe;}
+g8-oO
+wB(432,"x[x==Value_t(-0.5)] "
+aM,mG"cAbsNotNot"
+,wN);q4
+Lff;qG
+TailCall_cLog:g5
+cLog:mP(343,mH" "
+mA,,);q4
+Ldn
+qU
+gL
+wB(491,wQ
+m6
+mA,mA" [fp_log(x)]"
+aV,wN);q4
+Lfg;}
+o2
+wB(303,mZ
+mA,aX
+mA" "
+a9,);q4
+Lfh
+aT(156,wQ" "
+mA,"[fp_log(x)]"
+,wN);q4
+Lfi;h8}
+qH
+TailCall_cLog10:g5
+cLog10:mP(481,mH" "
+aH,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfj
+qU
+gL
+wB(492,wQ
+m6
+aH,aH" [fp_log10(x)]"
+aV,wN);q4
+Lfk;}
+o2
+wB(305,mZ
+aH,aX
+aH" "
+a9,);q4
+Lfl
+aT(157,wQ" "
+aH,"[fp_log10(x)]"
+,wN);q4
+Lfm;h8}
+qH
+TailCall_cLog2:g5
+cLog2:mP(480,mH" "
+aJ,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfn
+qU
+cExp2:wB(344,"cExp2 "
+aJ,,);q4
+Ldn
+qU
+gL
+wB(490,wQ
+m6
+aJ,aJ" [fp_log2(x)]"
+aV,wN);q4
+Lfo;}
+o2
+wB(304,mZ
+aJ,aX
+aJ" "
+a9,);q4
+Lfp
+aT(158,wQ" "
+aJ,"[fp_log2(x)]"
+,wN);q4
+Lfq;h8}
+qH
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mC
+m8,,);q4
+Ldn
+gY
+m2(141,m3
+m8,"[fp_max(x,y)]"
+,q31);q4
+Lga;}
+gP
+cDup:hD
+wB(66,aG
+mE
+aC
+m8,"B"
+mE,aA(A)q51(B)wM);q4
+oN
+cMax:hD
+wB(68,aG" "
+m8
+aC
+m8,"B "
+m8,aA(A)q51(B)wM);q4
+Ldn;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mC
+m9,,);q4
+Ldn
+gY
+m2(140,m3
+m9,"[fp_min(x,y)]"
+,q31);q4
+Lgb;}
+gP
+cDup:hD
+wB(65,aG
+mE
+aC
+m9,"B"
+mE,aA(A)q51(B)wM);q4
+oN
+cMin:hD
+wB(67,aG" "
+m9
+aC
+m9,"B "
+m9,aA(A)q51(B)wM);q4
+Ldn;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m2(104,aU
+wZ"cMod"
+,"[fp_mod(y,x)]"
+,q31);q4
+Lgc;}
+qG
+TailCall_cMul:g5
+h3:qS
+cCsc:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(508,aG" "
+aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc"
+wH,"B cCot"
+,aA(A)q51(B)wM);q4
+Lgd;}
+}
+}
+q4
+dY
+qU
+cDup:wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lge
+qU
+cInv:wB(214,aS
+wH,"cDiv"
+,);q4
+Lgf
+oF
+qQ
+h9
+cDup:wB(467,mC
+q81
+wH,"cSqr"
+mD,);q4
+Lgg;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aG
+wH
+aC
+q81
+wH,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lgh;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mC"x"
+a1
+wH,"[x+Value_t(1)]"
+a1,wN);q4
+Lgi;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wT" "
+wX,a3,q61(A)wM);q4
+Lgj;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mR(92,aU
+wD,a3,q61(A)<<","
+aE);q4
+Lgk;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mR(96,aU
+wK,mV,q61(A)q51(B)<<","
+aE);q4
+Lgl;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lgm;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lgn;}
+}
+}
+if(d1
+B)){wB(90,"B[IsVarOpcode(B)] "
+wD,a3,q61(A)q51(B)wM);q4
+Lgj;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mV,q61(A)q51(B)wM);q4
+Lgo;}
+}
+}
+if(d1
+h2
+wB(88,aD" "
+wX,"[x]"
+,q61(A)wM);q4
+Lgp;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wX,a3,q61(A)wM);q4
+Lgq;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup
+d4
+x+oU
+wB(316,"cDup[x+x==Value_t(1)]"
+aV
+wY,,wN);q4
+Lha;}
+wB(317,a9
+wY,"[x+x]"
+wH,wN);q4
+Lhb
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,aD" y"
+wH
+aV
+wY,a3" A "
+aZ
+wH
+aV,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Lhc;}
+w9
+mR(385,aU"cAdd"
+wY,a3" "
+aZ
+aV,q31);q4
+Lhd;qT
+cDeg:wB(209,"cDeg"
+wY,"[RadiansToDegrees(x)]"
+wH,wN);q4
+Lhe
+qU
+cDiv
+oB
+qV
+o5
+4
+qZ
+mR(278,"y"
+m6
+q21
+wY,aZ
+m6"B"
+m7,wA","
+aQ(B)<<","
+aE);q4
+Lhf;qT
+hI
+wB(279,mG
+q21
+wY,"[-x]"
+m6"B"
+m7,wA","
+aQ(B)wM);q4
+Lhg
+qU
+q6:mR(277,aU
+q21
+wY,aZ" B"
+m7,wA","
+aQ(B)<<","
+aE);q4
+Lhh;}
+qT
+h3:qQ
+hE
+d3
+3
+h1
+if(x+oU
+wB(318,"cDup[x+x==Value_t(1)]"
+aV
+wH
+wY,"cMul"
+,wN);q4
+Lhi;}
+wB(319,a9
+wH
+wY,"cMul [x+x]"
+wH,wN);q4
+Lhj;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+wY,,q31);q4
+Lhk;}
+if((y*x)==fp_const_rad_to_deg
+h7
+wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]"
+wH
+wY,"cDeg"
+,q31);q4
+Ldd;}
+if((y*x)==fp_const_deg_to_rad
+h7
+wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]"
+wH
+wY,"cRad"
+,q31);q4
+Lde;}
+wB(128,"y"
+wH
+wY,aZ
+wH,q31);q4
+Lhl;qT
+hI
+wB(122,q81
+wY,"[-x]"
+wH,wN);q4
+Lhm
+qU
+cRDiv:qQ
+hE
+qV
+o5
+3
+qZ
+mR(285,"y"
+wH
+a7
+wY,aZ
+wH
+a7,q31);q4
+Lhn;qT
+hI
+wB(286,q81
+a7
+wY,"[-x]"
+wH
+a7,wN);q4
+Lho
+qU
+q6:mR(284,"y"
+a7
+wY,aZ
+a7,q31);q4
+Lhp;qT
+cRad:wB(210,"cRad"
+wY,"[DegreesToRadians(x)]"
+wH,wN);q4
+Lhq
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,aD" y"
+m6"cSub"
+wY,a3" A "
+aZ
+m6"cSub"
+,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Lia;}
+}
+w9
+mR(102,"y"
+wY,aZ,q31);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,q81,wN);q4
+Lic;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,a9,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,q21" "
+wT,"[DO_STACKPLUS1] A"
+m6"B"
+m7,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4
+Lig;}
+q4
+d5
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aG
+mD
+m6
+wT,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lgh;}
+q4
+dZ;g7
+dZ:;hD
+wB(461,aG
+m6
+wT,m0
+wH,aA(A)q51(B)wM);q4
+Lih;}
+}
+q4
+d5
+hI
+hD
+wB(464,aG
+mD" "
+wT,m0
+mD,aA(A)q51(B)wM);q4
+Lgg;}
+q4
+d5
+cRDiv
+hL
+qZ
+qC
+wB(267,"x"
+a7" "
+wT,"[DO_STACKPLUS1] "
+mV
+a7,aA(A)<<","
+m4);incStackPtr();--mStackPtr;q4
+Lii;}
+wB(281,"cRDiv "
+wT,"[DO_STACKPLUS1] A"
+wH
+a7,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lij;g7
+Default4:;B=qK
+qR
+w4
+wB(458,aG" "
+wT,m0,aA(A)q51(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]"
+m6"B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(D)wM);q4
+Lik;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:oL
+hU
+wB(360,aX
+wL
+wW,"[x] "
+wW,wN);q4
+Lil
+qU
+cSqr:wB(362,mZ
+wL
+wW,"[x] "
+wW,wN);q4
+Lil;}
+}
+m2(116,m3
+wW,"[fp_nequal(y,x)]"
+,q31);q4
+Lim;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+m6
+q81,"[-x]"
+wH,wN);q4
+Lin;qT
+hI
+wB(61,q81
+mD,,);q4
+Ldn
+qU
+cSin:g9
+wB(244,"x"
+m6
+mM
+mD,"[-x]"
+m6
+mM,wN);q4
+Lio;}
+qT
+oQ
+g9
+wB(245,"x"
+m6"cSinh"
+mD,"[-x]"
+m6"cSinh"
+,wN);q4
+Lip;}
+qT
+cTan:g9
+wB(246,"x"
+m6
+mN
+mD,"[-x]"
+m6
+mN,wN);q4
+Liq;}
+qT
+cTanh:g9
+wB(247,"x"
+m6"cTanh"
+mD,"[-x]"
+m6"cTanh"
+,wN);q4
+Lja;}
+qT
+hM
+wB(100,"x"
+mD,"[-x]"
+,wN);q4
+Ljb;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbs:wB(227,mQ
+aB,"cNot"
+,);q4
+Ljc
+qU
+cAbsNot:A=dD
+wB(389,"A[IsLogicalOpcode(A)] "
+aN
+aB,"A"
+,aA(A)wM);q4
+Ldn;}
+if(A!=q6){wB(390,"A[A!=cImmed] "
+aN
+aB,"A cAbsNotNot"
+,aA(A)wM);q4
+Ljd;}
+q4
+o0
+qU
+cAbsNotNot:wB(231,"cAbsNotNot"
+aB,aN,);q4
+Lje
+qU
+w8:wB(220,a5
+aB,wW,);q4
+Ljf
+qU
+o1:wB(218,aW
+aB,aM,);q4
+Ljg
+qU
+dK:wB(219,a8
+aB,mB,);q4
+Ljh
+qU
+cLess:wB(216,mB
+aB,a8,);q4
+Lji
+qU
+cLessOrEq:wB(217,aM
+aB,aW,);q4
+Ljj
+qU
+cNEqual:wB(221,wW
+aB,a5,);q4
+Ljk
+oF
+wB(226,q81
+aB,"cNot"
+,);q4
+Ljc
+qU
+cNot:wB(229,"cNot"
+aB,aF,);q4
+Lbd
+qU
+dS:wB(230,aF
+aB,"cNot"
+,);q4
+Ljc
+gY
+wB(107,"x"
+aB,"[fp_not(x)]"
+,wN);q4
+Ljl;g7
+o0:;A=dF
+qR
+qX
+wB(391,wJ"cNot"
+,"A "
+aN,aA(A)wM);q4
+Ljm;qG
+TailCall_cNotNot:g5
+dS
+d4
+dF==cNot){wB(232,"cNot "
+aF,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mC"cOr"
+,aF,);q4
+w7
+m2(118,m3"cOr"
+,"[fp_or(x,y)]"
+,q31);q4
+Ljn;h8}
+qH
+TailCall_cPow:g5
+cPow:qY
+if(!h5
+x+x)){oY
+cSqr){wB(22,mZ"x[!isEvenInteger(x+x)]"
+a1,aX"[x+x]"
+a1,wN);q4
+Ljo;}
+}
+if(isInteger(x
+gQ
+w2
+wB(43,mH" "
+wS,a3" "
+mH,wN);q4
+Ljp
+qU
+cExp2:wB(44,"cExp2 "
+wS,a3" cExp2"
+,wN);q4
+Ljq
+qU
+cPow
+hL
+qZ
+hP!isInteger(y)){wB(42,"y[!isInteger(y)]"
+a1" "
+wS,aZ
+a1,q31);q4
+Lka;}
+}
+wB(45,"cPow "
+wS,a3
+a1,wN);q4
+Lkb;}
+}
+if(h5
+x
+hU
+wB(434,aX"x[isEvenInteger(x)]"
+a1,"[x]"
+a1,wN);q4
+Lkc
+qU
+h3
+hL]==cAbs){wB(435,mQ
+m6"x[isEvenInteger(x)]"
+a1,"cMul [x]"
+a1,wN);q4
+Lkd;h8}
+}
+g8)){wB(83,"x[x==Value_t()]"
+a1,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,wN);q4
+Lke;}
+g8
+oO
+wB(332,"x[x==Value_t(0.5)]"
+a1,q01,wN);q4
+Lkf;}
+g8
+1)/g1
+3)){wB(333,"x[x==Value_t(1)/Value_t(3)]"
+a1,"cCbrt"
+,wN);q4
+Lkg;}
+g8
+1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)]"
+a1,"cCbrt"
+mK,wN);q4
+Lkh;}
+g8-oO
+wB(335,"x[x==Value_t(-0.5)]"
+a1,"cRSqrt"
+,wN);q4
+Lki;}
+g8-oG
+wB(336,"x[x==Value_t(-1)]"
+a1,aS,wN);q4
+Lkj;}
+qQ
+h9
+cPow
+hL
+qZ
+hP
+h5
+y)&&!h5
+x*y)){wB(21,"y[isEvenInteger(y)&&!isEvenInteger(x*y)]"
+a1" x"
+a1,aX
+aZ
+a1,q31);q4
+Lkk;}
+wB(330,"y"
+a1" x"
+a1,aZ
+a1,q31);q4
+Lka;o2
+wB(46,mZ"x"
+a1,"[x+x]"
+a1,wN);q4
+Lkl
+qU
+q6:hP
+y!=oP||x>=oP){wB(165,"y[y!=Value_t(0)||x>=Value_t(0)] x"
+a1,"[fp_pow(y,x)]"
+,q31);q4
+Lkm;h8}
+wB(455,"x"
+a1,"[DO_POWI]"
+,wN)qR
+TryCompilePowi(x))gJ}
+qH
+TailCall_cRDiv:g5
+cRDiv:qS
+cSinCos:wB(503,"cSinCos"
+a7,"cCot"
+,);q4
+Lep
+qU
+cSinhCosh:wB(510,"cSinhCosh"
+a7,"cTanh"
+mK,);q4
+Lkn
+gY
+g8
+oG
+wB(268,wO"cRDiv"
+,aS,wN);q4
+Lkj;h8}
+qH
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,mC
+a4,"[Value_t()]"
+wH,);q4
+Lko;}
+qH
+TailCall_cRad:g5
+cRad:qS
+h3
+gM
+wB(211,"x"
+m6"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,aG" "
+aK" "
+wI
+mX,"B "
+aK" "
+aR,aA(A)q51(B)wM);q4
+Lbp;qT
+cSin:hD
+wB(495,aG" "
+mM" "
+wI
+mX,"B cSinCos"
+mK,aA(A)q51(B)wM);q4
+Lla;h8
+qG
+TailCall_cSin:g5
+cSin:qS
+hI
+wB(240,mG
+mM,mM
+mD,);q4
+Llb
+gY
+wB(159,"x "
+mM,"[fp_sin(x)]"
+,wN);q4
+Llc;oH
+qN
+oY
+cCsc
+mY(499,aG" cCsc "
+wI
+mM,"B cCsc "
+aR,aA(A)q51(B)wM);q4
+Lbp;}
+}
+qG
+TailCall_cSinh:g5
+oQ
+qS
+cAcosh:wB(437,"cAcosh cSinh"
+,"[DO_STACKPLUS1] "
+mZ"[Value_t(-1)] "
+aL,);incStackPtr();--mStackPtr;q4
+Lld
+qU
+cAsinh:wB(349,"cAsinh cSinh"
+,,);q4
+Ldn
+oF
+wB(241,mG"cSinh"
+,"cSinh"
+mD,);q4
+Lle
+gY
+wB(160,"x cSinh"
+,"[fp_sinh(x)]"
+,wN);q4
+Llf;}
+qH
+TailCall_cSqr:g5
+cSqr:qS
+cAbs:wB(204,aX"cSqr"
+,"cSqr"
+,);q4
+Llg
+oF
+wB(203,mG"cSqr"
+,"cSqr"
+,);q4
+Llg
+qU
+cSqrt:A=dE
+wB(338,wJ
+q01" cSqr"
+,"A"
+,aA(A)wM);q4
+Ldn;h8}
+qH
+TailCall_cSqrt:g5
+cSqrt:qS
+hS
+d4
+qK
+o3
+A=hE
+w0
+if(oC
+o3
+wB(512,"cSqr"
+aC
+mZ
+aL,"A cHypot"
+,aA(A)wM);q4
+Llh;}
+}
+B
+g4
+gV
+B)){A=oC
+w0
+if(qL
+4]o3
+wB(513,"cSqr"
+aC"B[IsUnaryOpcode(B)] "
+mZ
+aL,"A B cHypot"
+,"    with"
+aQ(B)q71(A)wM);q4
+Lli;}
+}
+}
+o2
+wB(23,mZ
+q01,mQ,);q4
+Llj
+gY
+if(x>=oP){wB(161,"x[x>=Value_t(0)] "
+q01,"[fp_sqrt(x)]"
+,wN);q4
+Llk;h8}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,mC"cSub"
+,"[Value_t()]"
+wH,);q4
+Lko
+oF
+wB(200,q81
+mF,"cAdd"
+,);q4
+Lll
+gY
+g8)){wB(58,"x[x==Value_t()]"
+mF,,wN);q4
+Lba;}
+m2(106,m3"cSub"
+,"[y-x]"
+,q31);q4
+Llm;}
+wB(51,"x"
+mF,"[-x]"
+aV,wN);q4
+Lln
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x "
+a4
+aC"cSub"
+,"A"
+aV" [x] "
+a4,aA(A)<<","
+m4);q4
+Llo;}
+wB(296,a4
+aC"cSub"
+,"[DO_STACKPLUS1] A"
+mF" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Llp;}
+qG
+TailCall_cTan:g5
+cTan:qS
+cAtan2:wB(354,"cAtan2 "
+mN,"cDiv"
+,);q4
+Lgf
+oF
+wB(242,mG
+mN,mN
+mD,);q4
+Llq
+gY
+wB(163,"x "
+mN,"[fp_tan(x)]"
+,wN);q4
+Lma;oH
+qN
+oY
+cCot
+mY(501,aG" cCot "
+wI
+mN,"B cCot "
+aR,aA(A)q51(B)wM);q4
+Lbp;}
+}
+qG
+TailCall_cTanh:g5
+cTanh:qS
+hI
+wB(243,mG"cTanh"
+,"cTanh"
+mD,);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"
+,aA(A)wM);gJ
+qG
+g7
+Default0:;A=w5
+qR
+IsComparisonOpcode(h2
+qY
+hK
+qZ
+mR(364,aU"cAdd"
+wF,"[x-y] A"
+,aA(A)<<q41
+aE);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"
+,aA(A)<<","
+m4);q4
+Lmf;qT
+cExp
+d4
+dO
+wB(370,"cExp[x>Value_t(0)]"
+wF,"[fp_log(x)] A"
+,aA(A)<<","
+m4);q4
+Lmg;qT
+cExp2
+d4
+dO
+wB(371,"cExp2[x>Value_t(0)]"
+wF,"[fp_log2(x)] A"
+,aA(A)<<","
+m4);q4
+Lmh;qT
+cLog:g3
+wB(373,wP
+mA
+wF,"B [fp_exp(x)] A"
+,aA(A)<<q41
+aQ(B)wM);q4
+Lmi;qT
+cLog10:g3
+wB(375,wP
+aH
+wF,"B [fp_pow(Value_t(10),x)] A"
+,aA(A)<<q41
+aQ(B)wM);q4
+Lmj;qT
+cLog2:g3
+wB(374,wP
+aJ
+wF,"B [fp_exp2(x)] A"
+,aA(A)<<q41
+aQ(B)wM);q4
+Lmk;qT
+h3
+hL
+qZ
+hP
+y>oP){wB(366,"y[y>Value_t(0)]"
+wH
+wF,"[x/y] A"
+,aA(A)<<q41
+aE);q4
+Lml;}
+if(y<oP){wB(367,"y[y<Value_t(0)]"
+wH
+wF,"[x/y] {OppositeComparisonOpcode(A)}"
+,aA(A)<<q41
+aE);q4
+Lmm;}
+qT
+hI
+wB(365,q81
+wF,"[-x] {OppositeComparisonOpcode(A)}"
+,aA(A)<<","
+m4);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"
+,aA(A)<<q41
+aE);q4
+Lmo;}
+}
+qT
+oQ
+wB(381,"cSinh"
+wF,"[fp_asinh(x)] A"
+,aA(A)<<","
+m4);q4
+Lmp
+qU
+cSqr
+d4
+dO
+wB(369,"cSqr[x>Value_t(0)]"
+wF,aX"[fp_sqrt(x)] A"
+,aA(A)<<","
+m4);q4
+Lmq;qT
+cTanh
+d4
+dP<m1(382,"cTanh[fp_abs(x)<Value_t(1)]"
+wF,"[fp_atanh(x)] A"
+,aA(A)<<","
+m4);q4
+Lna;h8}
+}
+}
+if(d1
+A
+qP
+0){B=q0[0
+hZ
+wB(475,aG" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mE,aA(A)q51(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"
+mE,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(D)wM);q4
+Lnc;}
+}
+}
+}
+C=w5
+qR
+IsCommutativeOrParamSwappableBinaryOpcode(C)){qS
+cSin:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(505,aG" "
+aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] "
+mM" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinCos {GetParamSwappedBinaryOpcode(C)}"
+,"    with C"
+a0(C)q71(A)q51(B)wM);q4
+Lnd;}
+}
+qT
+oQ
+A=qK
+w1
+3
+gA]==cCosh){B=hQ
+wB(506,aG" "
+aI" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}"
+,"    with C"
+a0(C)q71(A)q51(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
+m5
+Lae:q7=fp_acosh
+m5
+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
+q11
+gX
+Lnn;Lbc:mI
+A
+gX
+Lnn;Lbd:gU
+dS;Lob:wE(cNotNot);q4
+TailCall_cNotNot;Lbe:gT
+fp_and(x
+d6
+Lbf:q7=fp_asin
+m5
+Lbg:q7=fp_asinh
+m5
+Lbh:q7=fp_atan
+m5
+Lbi:gT
+fp_atan2(gW
+Lbj:q7=fp_atanh
+m5
+Lbk:q7=fp_cbrt
+m5
+Lbl:q1
+cFloor);Loc:w5=cNeg;g0
+wE(cNeg);q4
+TailCall_cNeg;Lbm:q7=fp_ceil
+m5
+Lbn:g6
+Lod:wE(cCos);q4
+TailCall_cCos;Lbo:q7=fp_cos
+m5
+Lbp:dF=cDup;w5=cInv;Loe:wE(cInv);q4
+TailCall_cInv;Lbq:mI
+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
+m5
+Lcd:mI
+cSinhCosh);gJ
+Lce:q7=RadiansToDegrees
+m5
+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:hV
+2;qI
+q8
+oR
+Lon:w5=cDeg;g0
+wE(cDeg);q4
+TailCall_cDeg;Lde:hV
+2;qI
+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:mI
+oI
+Lop:g0
+q4
+Lom;Ldi:q8
+3
+gC
+oI
+qF
+x
+q11);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
+m5
+Ldp:d7
+cExp2
+o7
+fp_exp2(x)gX
+Lnj;Ldq:q7=fp_exp2
+m5
+Lea:qF
+oW
+g1
+2))q11);Lpb:qE
+h3
+gI
+cExp;g0
+wE(cExp);q4
+TailCall_cExp;Leb:q1
+cCeil
+gX
+Loc;Lec:q7=fp_floor
+m5
+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
+m5
+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:mI
+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:hV
+2;qI
+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
+q11);dM
+Loj;Lhd:gT
+x;d7
+dU
+qF
+y*x
+o8
+Lhe:q7=RadiansToDegrees(x
+gX
+Lgq;Lhf:gT
+y*x;q8
+4
+gH
+Lpq:qE
+dU
+Lqa:qE
+B
+gI
+cDiv;q4
+Lop;Lhg:o9;oC=q6
+q9
+oR
+q4
+Lpq;Lhh:gT
+y*x;q8
+oR
+q4
+Lqa;Lhi:q8
+4
+gH
+q4
+Lnh;Lhj:q8
+4
+dT
+qF
+x+x
+gX
+Lpo;Lhk:hV
+2;qI
+qM
+q4
+Lpp;Lhl:gT
+y*x;q4
+Lpl;Lhm:o9;q4
+Lgq;Lhn:gT
+y*x;q8
+oR
+Lqb:dM
+Loq;Lho:o9;qL
+2
+gK
+q4
+Lqb;Lhp:gT
+y*x;dG
+Loq;Lhq:q7=h4
+gX
+Lgq;Lia:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q11);dM
+Loa;Lib:gT
+y*x;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
+q11
+gX
+Lqb;Lij:mI
+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
+m5
+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:gT
+y*x;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:hV
+2;qI
+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:mI
+cSinCos
+gX
+Lqg;Llb:q1
+cSin
+gX
+Loc;Llc:q7=fp_sin
+m5
+Lld:q1
+cSqr
+o7
+g1-1)gX
+Lof;Lle:q1
+cSinh
+gX
+Loc;Llf:q7=fp_sinh
+m5
+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
+m5
+Lll:g6
+q4
+Lqc;Llm:gT
+y-x;q4
+Lba;Lln:o9;q4
+Lqc;Llo:q8
+oV
+oJ
+hS
+o7
+x
+q11
+gX
+Lno;Llp:mI
+A
+oJ
+cSub
+gX
+Lno;Llq:q1
+cTan
+gX
+Loc;Lma:q7=fp_tan
+m5
+Lmb:q1
+cTanh
+gX
+Loc;Lmc:q7=fp_tanh
+m5
+Lmd:q7=fp_trunc
+m5
+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)q11
+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"
+wY
+aV,"[x+Value_t(1)]"
+wH,wN);q4
+Lah;}
+}
+q4
+dX
+oF
+wB(199,q81
+aV,"cSub"
+,);q4
+Lai
+gY
+hK
+qZ
+mR(127,aU"cAdd "
+a6,"[y+x]"
+aV,q31);q4
+Laj;qT
+cRSub:qQ
+hE
+d3
+3
+qZ
+mR(298,aU"cAdd "
+mS,mJ
+aV" "
+a4,q31);q4
+Lak;qT
+hI
+wB(299,mG
+mS,"[-x]"
+aV" "
+a4,wN);q4
+Lal
+qU
+q6:mR(297,aU
+mS,mJ" "
+a4,q31);q4
+Lam;qT
+oA
+Lan;qT
+hI
+wB(293,mG"B[IsVarOpcode(B)]"
+mF" "
+a6,"[-x]"
+aV" B"
+mF,wA","
+aQ(B)wM);q4
+Lao
+qU
+q6:mR(291,aU"B[IsVarOpcode(B)]"
+mF" "
+a6,mJ" B"
+mF,wA","
+aQ(B)<<","
+aE);q4
+Lap;}
+w9
+mR(105,aU
+a6,"[y+x]"
+,q31);q4
+Laq;}
+g8)){wB(57,"x[x==Value_t()]"
+aV,,wN);q4
+Lba;h8
+g7
+dX:;A=dF
+w0
+oY
+cRSub
+dV
+wB(290,"x "
+a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A [x]"
+aV" "
+a4,aA(A)<<","
+m4);incStackPtr();--mStackPtr;q4
+Lbb;}
+wB(295,a4
+aC"cAdd"
+,"[DO_STACKPLUS1] A"
+aV" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lbc;}
+qG
+TailCall_cAnd:g5
+cAnd
+hH
+wB(224,mC"cAnd"
+,aF,);q4
+w7
+m2(117,m3"cAnd"
+,"[fp_and(x,y)]"
+,q31);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
+m2(139,m3"cAtan2"
+,"[fp_atan2(y,x)]"
+,q31);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,mG
+mW,mO
+mD,);q4
+Lbm
+gY
+wB(135,"x "
+mW,"[fp_ceil(x)]"
+,wN);q4
+Lbn
+gS
+wB(396,"A[IsAlwaysIntegerOpcode(A)] "
+mW,"A"
+,aA(A)wM);gJ
+qG
+TailCall_cConj:g5
+cConj:qS
+cConj:wB(63,mT" "
+mT,,);oS
+gY
+wB(193,"x "
+mT,"[fp_conj(x)]"
+,wN);q4
+Lbp;}
+qH
+TailCall_cCos:g5
+cCos:qS
+cAcos:wB(346,"cAcos "
+aK,,);q4
+oE
+wB(238,mG
+aK,aK,);q4
+Lbq
+gY
+wB(176,"x "
+aK,"[fp_cos(x)]"
+,wN);q4
+Lca;oH
+qN
+qQ
+h9
+cSec:hD
+wB(500,aG" "
+mX" "
+wI
+aK,"B "
+mX" "
+aR,aA(A)q51(B)wM);q4
+Lcb;qT
+cSin:hD
+wB(494,aG" "
+mM" "
+wI
+aK,"B cSinCos"
+,aA(A)q51(B)wM);q4
+Lcc;h8}
+qG
+TailCall_cCosh:g5
+cCosh:qS
+cAsinh:wB(450,"cAsinh "
+aI,"[DO_STACKPLUS1] "
+mZ"[Value_t(1)] "
+aL,);incStackPtr();--mStackPtr;q4
+Lcd
+oF
+wB(239,mG
+aI,aI,);q4
+Lce
+gY
+wB(177,"x "
+aI,"[fp_cosh(x)]"
+,wN);q4
+Lcf;oH
+qN
+oY
+cSinh
+mY(507,aG" cSinh "
+wI
+aI,"B cSinhCosh"
+,aA(A)q51(B)wM);q4
+Lcg;}
+}
+qG
+TailCall_cCot:g5
+cCot:A=qN
+oY
+cTan
+mY(498,aG" "
+mN" "
+wI"cCot"
+,"B "
+mN" "
+aR,aA(A)q51(B)wM);q4
+Lcb;}
+qG
+TailCall_cCsc:g5
+cCsc:A=qN
+oY
+cSin
+mY(496,aG" "
+mM" "
+wI"cCsc"
+,"B "
+mM" "
+aR,aA(A)q51(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,aK
+m7,mX
+wH,);q4
+Lci
+qU
+cCot:wB(254,"cCot"
+m7,mN
+wH,);q4
+Lcj
+qU
+cCsc:wB(252,"cCsc"
+m7,mM
+wH,);q4
+Lck
+qU
+cDup:wB(78,"cDup"
+m7,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,);q4
+Lcl
+qU
+w2
+wB(408,mH
+m7,mG
+mH
+wH,);q4
+Lcm
+qU
+cExp2:wB(409,"cExp2"
+m7,mG"cExp2"
+wH,);q4
+Lcn
+qU
+cInv:wB(213,aS
+m7,"cMul"
+,);q4
+Lco
+qU
+cPow:wB(407,"cPow"
+m7,q81
+a1
+wH,);q4
+Lcp
+qU
+cSec:wB(253,mX
+m7,aK
+wH,);q4
+Lcq
+qU
+cSin:wB(249,mM
+m7,"cCsc"
+wH,);q4
+Lda
+qU
+cSinCos:wB(502,"cSinCos"
+m7,mN,);q4
+Ldb
+qU
+cSinhCosh:wB(509,"cSinhCosh"
+m7,"cTanh"
+,);q4
+Ldc
+qU
+cTan:wB(251,mN
+m7,"cCot"
+wH,);q4
+Ldd
+gY
+if
+hF
+gQ
+hI
+wB(125,mG
+wZ"cDiv"
+,"[-x]"
+m7,wN);q4
+Lde
+qU
+q6:mR(103,aU
+wZ"cDiv"
+,"[y/x]"
+,q31);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>()]"
+m6
+wR,"cDeg"
+,q31);q4
+Ldg;}
+if((y/x)==fp_const_deg_to_rad
+h7
+wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]"
+m6
+wR,"cRad"
+,q31);q4
+Ldh;}
+wB(323,"y"
+m6
+wR,"[y/x]"
+wH,q31);q4
+Ldi;}
+}
+wB(325,wR,"[Value_t(1)/x]"
+wH,wN);q4
+Ldj;}
+gP
+cDiv:hC
+wB(271,q21" "
+wV,"[DO_STACKPLUS1] B A"
+m6"cDiv"
+,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4
+Ldk;qT
+cRDiv:qQ
+hE
+qV
+hM
+wB(266,"x"
+a7" "
+wV,"A"
+m6"[x]"
+a7,aA(A)<<","
+m4);q4
+Ldl;g7
+hC
+wB(265,"B[IsVarOpcode(B)]"
+a7" "
+wV,"A"
+m6"B"
+a7,aA(A)q51(B)wM);q4
+Ldm;}
+h8}
+qG
+TailCall_cEqual:g5
+w8:oL
+hU
+wB(359,aX
+wL
+a5,"[x] "
+a5,wN);q4
+Ldn
+qU
+cSqr:wB(361,mZ
+wL
+a5,"[x] "
+a5,wN);q4
+Ldn;}
+}
+m2(115,m3
+a5,"[fp_equal(y,x)]"
+,q31);q4
+Ldo;qG
+TailCall_cExp:g5
+w2
+qS
+hS
+gM
+wB(404,a6" "
+mH,mH" [fp_exp(x)]"
+wH,wN);q4
+Ldp;qT
+cLog:A=dE
+wB(340,wJ
+mA" "
+mH,"A"
+,aA(A)wM);oS;qT
+hM
+wB(178,"x "
+mH,"[fp_exp(x)]"
+,wN);q4
+Ldq;}
+qH
+TailCall_cExp2:g5
+cExp2:qS
+hS
+gM
+wB(405,a6" cExp2"
+,"cExp2 [fp_exp2(x)]"
+wH,wN);q4
+Lea;qT
+cLog2:A=dE
+wB(341,wJ
+aJ" cExp2"
+,"A"
+,aA(A)wM);oS;qT
+hM
+wB(179,"x cExp2"
+,"[fp_exp2(x)]"
+,wN);q4
+Leb;}
+wB(479,"cExp2"
+,"[DO_STACKPLUS1] [fp_log(Value_t(2))]"
+m6
+mH,);incStackPtr();--mStackPtr;q4
+Lec;TailCall_cFloor:g5
+cFloor:qS
+hI
+wB(401,mG
+mO,mW
+mD,);q4
+Led
+gY
+wB(136,"x "
+mO,"[fp_floor(x)]"
+,wN);q4
+Lee
+gS
+wB(395,"A[IsAlwaysIntegerOpcode(A)] "
+mO,"A"
+,aA(A)wM);gJ
+qG
+TailCall_cGreater:g5
+o1:qY
+m2(113,m3
+aW,"[fp_less(x,y)]"
+,q31);q4
+Lef;qG
+TailCall_cGreaterOrEq:g5
+dK:qY
+m2(114,m3
+a8,"[fp_lessOrEq(x,y)]"
+,q31);q4
+Leg;qG
+TailCall_cHypot:g5
+cHypot
+d4
+dF==cSinCos){wB(84,"cSinCos cHypot"
+,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,);q4
+Lcl;}
+qH
+TailCall_cImag:g5
+cImag:qS
+cAbs:wB(81,aX
+mU,"[Value_t()]"
+wH,);q4
+Leh
+qU
+cReal:wB(80,"cReal "
+mU,"[Value_t()]"
+wH,);q4
+Leh
+gY
+wB(192,"x "
+mU,"[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"
+,aA(A)wM);gJ
+qG
+TailCall_cInv:g5
+cInv:qS
+cCos:wB(256,aK
+mK,mX,);q4
+Lek
+qU
+cCot:wB(260,"cCot"
+mK,mN,);q4
+Ldb
+qU
+cCsc:wB(258,"cCsc"
+mK,mM,);q4
+Lel
+qU
+cInv:wB(62,aS
+mK,,);oS
+qU
+cPow:wB(355,"cPow"
+mK,q81
+a1,);q4
+Lem
+qU
+cSec:wB(259,mX
+mK,aK,);q4
+Len
+qU
+cSin:wB(255,mM
+mK,"cCsc"
+,);q4
+Leo
+qU
+cSqrt:wB(206,q01
+mK,"cRSqrt"
+,);q4
+Lep
+qU
+cTan:wB(257,mN
+mK,"cCot"
+,);q4
+Leq
+gY
+if
+hF)){wB(101,wZ
+aS,"[Value_t(1)/x]"
+,wN);q4
+Lfa;h8}
+qH
+TailCall_cLess:g5
+cLess:oL)){A=dE
+wB(301,wJ
+wL
+mB,mV,q61(A)wM);q4
+Lfb;}
+}
+m2(111,m3
+mB,"[fp_less(y,x)]"
+,q31);q4
+Lfc;qG
+TailCall_cLessOrEq:g5
+cLessOrEq:qY
+m2(112,m3
+aM,"[fp_lessOrEq(y,x)]"
+,q31);q4
+Lfd;qG
+TailCall_cLog:g5
+cLog:mP(343,mH" "
+mA,,);oS
+qU
+gL
+wB(491,wQ
+m6
+mA,mA" [fp_log(x)]"
+aV,wN);q4
+Lfe;}
+oD
+wB(180,"x[x!=Value_t(0)] "
+mA,"[fp_log(x)]"
+,wN);q4
+Lff;h8}
+qH
+TailCall_cLog10:g5
+cLog10:mP(481,mH" "
+aH,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfg
+qU
+gL
+wB(492,wQ
+m6
+aH,aH" [fp_log10(x)]"
+aV,wN);q4
+Lfh;}
+oD
+wB(181,"x[x!=Value_t(0)] "
+aH,"[fp_log10(x)]"
+,wN);q4
+Lfi;h8}
+qH
+TailCall_cLog2:g5
+cLog2:mP(480,mH" "
+aJ,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]"
+wH,);incStackPtr();--mStackPtr;q4
+Lfj
+qU
+cExp2:wB(344,"cExp2 "
+aJ,,);oS
+qU
+gL
+wB(490,wQ
+m6
+aJ,aJ" [fp_log2(x)]"
+aV,wN);q4
+Lfk;}
+oD
+wB(182,"x[x!=Value_t(0)] "
+aJ,"[fp_log2(x)]"
+,wN);q4
+Lfl;h8}
+qH
+TailCall_cMax:g5
+cMax
+hH
+wB(60,mC
+m8,,);oS
+gY
+m2(141,m3
+m8,"[fp_max(x,y)]"
+,q31);q4
+Lfm;}
+gP
+cDup:hD
+wB(66,aG
+mE
+aC
+m8,"B"
+mE,aA(A)q51(B)wM);oS;qT
+cMax:hD
+wB(68,aG" "
+m8
+aC
+m8,"B "
+m8,aA(A)q51(B)wM);oS;h8}
+qG
+TailCall_cMin:g5
+cMin
+hH
+wB(59,mC
+m9,,);oS
+gY
+m2(140,m3
+m9,"[fp_min(x,y)]"
+,q31);q4
+Lfn;}
+gP
+cDup:hD
+wB(65,aG
+mE
+aC
+m9,"B"
+mE,aA(A)q51(B)wM);oS;qT
+cMin:hD
+wB(67,aG" "
+m9
+aC
+m9,"B "
+m9,aA(A)q51(B)wM);oS;h8}
+qG
+TailCall_cMod:g5
+cMod:qY
+if
+hF)){m2(104,aU
+wZ"cMod"
+,"[fp_mod(y,x)]"
+,q31);q4
+Lfo;}
+qG
+TailCall_cMul:g5
+h3:qS
+cCsc:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(508,aG" "
+aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc"
+wH,"B cCot"
+,aA(A)q51(B)wM);q4
+Lfp;}
+}
+}
+q4
+dY
+qU
+cDup:wB(202,"cDup"
+wH,"cSqr"
+,);q4
+Lfq
+qU
+cInv:wB(214,aS
+wH,"cDiv"
+,);q4
+Lga
+oF
+qQ
+h9
+cDup:wB(467,mC
+q81
+wH,"cSqr"
+mD,);q4
+Lgb;oH
+qK
+qO
+A)gA
+oM
+B=hQ
+wB(473,aG
+wH
+aC
+q81
+wH,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lgc;}
+}
+}
+}
+q4
+dY
+qU
+cPow
+gM
+if
+gF
+h1
+wB(314,mC"x"
+a1
+wH,"[x+Value_t(1)]"
+a1,wN);q4
+Lgd;}
+}
+q4
+dY
+gY
+g8
+gQ
+h3:A=hE
+w0
+wB(93,wT" "
+wX,a3,q61(A)wM);q4
+Lge;}
+q4
+Default3;g7
+Default3:;A=qK
+qR
+IsBinaryOpcode(A)g2
+h2
+qQ
+hE
+qV
+q6:mR(92,aU
+wD,a3,q61(A)<<","
+aE);q4
+Lgf;g7
+B
+g4
+IsBinaryOpcode(B)g2
+B)){qQ
+oC
+qV
+q6:mR(96,aU
+wK,mV,q61(A)q51(B)<<","
+aE);q4
+Lgg;g7
+C=oC
+qO
+C)){wB(94,"C[IsVarOpcode(C)] "
+wK,mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lgh;}
+if(gV
+C)g2
+C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] "
+wK,"B "
+mV,q61(A)q51(B)<<", C"
+a0(C)wM);q4
+Lgi;}
+}
+}
+if(d1
+B)){wB(90,"B[IsVarOpcode(B)] "
+wD,a3,q61(A)q51(B)wM);q4
+Lge;}
+if(gV
+B)g2
+B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "
+wD,mV,q61(A)q51(B)wM);q4
+Lgj;}
+}
+}
+if(d1
+h2
+wB(88,aD" "
+wX,"[x]"
+,q61(A)wM);q4
+Lgk;}
+if(gV
+A)g2
+h2
+wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "
+wX,a3,q61(A)wM);q4
+Lgl;}
+}
+}
+qQ
+h9
+hS:qQ
+hE
+qV
+cDup
+d4
+x+oU
+wB(316,"cDup[x+x==Value_t(1)]"
+aV
+wY,,wN);q4
+Lgm;}
+wB(317,a9
+wY,"[x+x]"
+wH,wN);q4
+Lgn
+qU
+o5
+3
+qZ
+hO
+A=qL
+4]w0
+wB(386,aD" y"
+wH
+aV
+wY,a3" A "
+aZ
+wH
+aV,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Lgo;}
+w9
+mR(385,aU"cAdd"
+wY,a3" "
+aZ
+aV,q31);q4
+Lgp;qT
+cDeg:wB(209,"cDeg"
+wY,"[RadiansToDegrees(x)]"
+wH,wN);q4
+Lgq
+qU
+cDiv
+oB
+qV
+o5
+4
+qZ
+mR(278,"y"
+m6
+q21
+wY,aZ
+m6"B"
+m7,wA","
+aQ(B)<<","
+aE);q4
+Lha;qT
+hI
+wB(279,mG
+q21
+wY,"[-x]"
+m6"B"
+m7,wA","
+aQ(B)wM);q4
+Lhb
+qU
+q6:mR(277,aU
+q21
+wY,aZ" B"
+m7,wA","
+aQ(B)<<","
+aE);q4
+Lhc;}
+qT
+h3:qQ
+hE
+d3
+3
+h1
+if(x+oU
+wB(318,"cDup[x+x==Value_t(1)]"
+aV
+wH
+wY,"cMul"
+,wN);q4
+Lhd;}
+wB(319,a9
+wH
+wY,"cMul [x+x]"
+wH,wN);q4
+Lhe;w9
+hP
+y*oU
+wB(70,"y[y*x==Value_t(1)]"
+wH
+wY,,q31);q4
+Lhf;}
+if((y*x)==fp_const_rad_to_deg
+h7
+wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]"
+wH
+wY,"cDeg"
+,q31);q4
+Ldg;}
+if((y*x)==fp_const_deg_to_rad
+h7
+wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]"
+wH
+wY,"cRad"
+,q31);q4
+Ldh;}
+wB(128,"y"
+wH
+wY,aZ
+wH,q31);q4
+Lhg;qT
+hI
+wB(122,q81
+wY,"[-x]"
+wH,wN);q4
+Lhh
+qU
+cRDiv:qQ
+hE
+qV
+o5
+3
+qZ
+mR(285,"y"
+wH
+a7
+wY,aZ
+wH
+a7,q31);q4
+Lhi;qT
+hI
+wB(286,q81
+a7
+wY,"[-x]"
+wH
+a7,wN);q4
+Lhj
+qU
+q6:mR(284,"y"
+a7
+wY,aZ
+a7,q31);q4
+Lhk;qT
+cRad:wB(210,"cRad"
+wY,"[DegreesToRadians(x)]"
+wH,wN);q4
+Lhl
+qU
+cSub
+hL
+oM
+if(qL
+3
+qZ
+hO
+A=qL
+4]w0
+wB(387,aD" y"
+m6"cSub"
+wY,a3" A "
+aZ
+m6"cSub"
+,wA", "
+aU"= "
+<<y
+q71(A)wM);q4
+Lhm;}
+}
+w9
+mR(102,"y"
+wY,aZ,q31);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,q81,wN);q4
+Lho;}
+g8
+2)){wB(198,"x[x==Value_t(2)]"
+wH,a9,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,q21" "
+wT,"[DO_STACKPLUS1] A"
+m6"B"
+m7,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4
+Lib;}
+q4
+d5
+h3:qQ
+hE
+qV
+hI
+B=hQ
+wB(470,aG
+mD
+m6
+wT,m0
+m6
+q81,aA(A)q51(B)wM);q4
+Lgc;}
+q4
+dZ;g7
+dZ:;hD
+wB(461,aG
+m6
+wT,m0
+wH,aA(A)q51(B)wM);q4
+Lic;}
+}
+q4
+d5
+hI
+hD
+wB(464,aG
+mD" "
+wT,m0
+mD,aA(A)q51(B)wM);q4
+Lgb;}
+q4
+d5
+cRDiv
+hL
+qZ
+qC
+wB(267,"x"
+a7" "
+wT,"[DO_STACKPLUS1] "
+mV
+a7,aA(A)<<","
+m4);incStackPtr();--mStackPtr;q4
+Lid;}
+wB(281,"cRDiv "
+wT,"[DO_STACKPLUS1] A"
+wH
+a7,aA(A)wM);incStackPtr();--mStackPtr;q4
+Lie;g7
+Default4:;B=qK
+qR
+w4
+wB(458,aG" "
+wT,m0,aA(A)q51(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]"
+m6"B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]"
+wH,"D C cSqr"
+wH,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(D)wM);q4
+Lif;}
+}
+}
+}
+qG
+TailCall_cNEqual:g5
+cNEqual:oL
+hU
+wB(360,aX
+wL
+wW,"[x] "
+wW,wN);q4
+Lig
+qU
+cSqr:wB(362,mZ
+wL
+wW,"[x] "
+wW,wN);q4
+Lig;}
+}
+m2(116,m3
+wW,"[fp_nequal(y,x)]"
+,q31);q4
+Lih;qG
+TailCall_cNeg:g5
+hI
+qS
+h3
+gM
+wB(123,"x"
+m6
+q81,"[-x]"
+wH,wN);q4
+Lii;qT
+hI
+wB(61,q81
+mD,,);oS
+qU
+cSin:g9
+wB(244,"x"
+m6
+mM
+mD,"[-x]"
+m6
+mM,wN);q4
+Lij;}
+qT
+oQ
+g9
+wB(245,"x"
+m6"cSinh"
+mD,"[-x]"
+m6"cSinh"
+,wN);q4
+Lik;}
+qT
+cTan:g9
+wB(246,"x"
+m6
+mN
+mD,"[-x]"
+m6
+mN,wN);q4
+Lil;}
+qT
+cTanh:g9
+wB(247,"x"
+m6"cTanh"
+mD,"[-x]"
+m6"cTanh"
+,wN);q4
+Lim;}
+qT
+hM
+wB(100,"x"
+mD,"[-x]"
+,wN);q4
+Lin;}
+qH
+TailCall_cNot:g5
+cNot:qS
+cAbsNotNot:wB(231,"cAbsNotNot"
+aB,aN,);q4
+Lio
+qU
+w8:wB(220,a5
+aB,wW,);q4
+Lip
+qU
+o1:wB(218,aW
+aB,aM,);q4
+Liq
+qU
+dK:wB(219,a8
+aB,mB,);q4
+Lja
+qU
+cLess:wB(216,mB
+aB,a8,);q4
+Ljb
+qU
+cLessOrEq:wB(217,aM
+aB,aW,);q4
+Ljc
+qU
+cNEqual:wB(221,wW
+aB,a5,);q4
+Ljd
+qU
+cNot:wB(229,"cNot"
+aB,aF,);q4
+Lbd
+qU
+dS:wB(230,aF
+aB,"cNot"
+,);q4
+Lje
+gY
+wB(107,"x"
+aB,"[fp_not(x)]"
+,wN);q4
+Ljf;}
+qH
+TailCall_cNotNot:g5
+dS
+d4
+dF==cNot){wB(232,"cNot "
+aF,"cNot"
+,);gJ}
+qH
+TailCall_cOr:g5
+cOr
+hH
+wB(223,mC"cOr"
+,aF,);q4
+w7
+m2(118,m3"cOr"
+,"[fp_or(x,y)]"
+,q31);q4
+Ljg;h8}
+qH
+TailCall_cPolar:g5
+cPolar
+d4
+q0[0
+qZ
+y=q7;qJ
+x
+gO
+wB(194,"x "
+aU"cPolar"
+,"[fp_polar(x,y)]"
+,"    with "
+aU"= "
+<<y<<","
+m4);q4
+Ljh;qG
+TailCall_cPow:g5
+cPow:qY
+if(isInteger(x
+gQ
+w2
+wB(43,mH" "
+wS,a3" "
+mH,wN);q4
+Lji
+qU
+cExp2:wB(44,"cExp2 "
+wS,a3" cExp2"
+,wN);q4
+Ljj
+qU
+cPow
+hL
+qZ
+hP!isInteger(y)){wB(42,"y[!isInteger(y)]"
+a1" "
+wS,aZ
+a1,q31);q4
+Ljk;}
+}
+wB(45,"cPow "
+wS,a3
+a1,wN);q4
+Ljl;}
+}
+g8)){wB(83,"x[x==Value_t()]"
+a1,"[Value_t()]"
+m6"[Value_t(1)]"
+aV,wN);q4
+Ljm;}
+g8
+oO
+wB(332,"x[x==Value_t(0.5)]"
+a1,q01,wN);q4
+Ljn;}
+g8
+1)/g1
+3)){wB(333,"x[x==Value_t(1)/Value_t(3)]"
+a1,"cCbrt"
+,wN);q4
+Ljo;}
+g8
+1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)]"
+a1,"cCbrt"
+mK,wN);q4
+Ljp;}
+g8-oO
+wB(335,"x[x==Value_t(-0.5)]"
+a1,"cRSqrt"
+,wN);q4
+Ljq;}
+g8-oG
+wB(336,"x[x==Value_t(-1)]"
+a1,aS,wN);q4
+Lka;}
+qQ
+h9
+cPow
+hL
+qZ
+mR(330,"y"
+a1" x"
+a1,aZ
+a1,q31);q4
+Ljk;o2
+wB(46,mZ"x"
+a1,"[x+x]"
+a1,wN);q4
+Lkb
+qU
+q6:mR(189,aU"x"
+a1,"[fp_pow(y,x)]"
+,q31);q4
+Lkc;}
+wB(455,"x"
+a1,"[DO_POWI]"
+,wN)qR
+TryCompilePowi(x))gJ}
+qH
+TailCall_cRDiv:g5
+cRDiv:qS
+cSinCos:wB(503,"cSinCos"
+a7,"cCot"
+,);q4
+Leq
+qU
+cSinhCosh:wB(510,"cSinhCosh"
+a7,"cTanh"
+mK,);q4
+Lkd
+gY
+g8
+oG
+wB(268,wO"cRDiv"
+,aS,wN);q4
+Lka;h8}
+qH
+TailCall_cRSub:g5
+cRSub
+d4
+q0[0
+h1
+wB(77,mC
+a4,"[Value_t()]"
+wH,);q4
+Leh;}
+qH
+TailCall_cRad:g5
+cRad:qS
+h3
+gM
+wB(211,"x"
+m6"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,aG" "
+aK" "
+wI
+mX,"B "
+aK" "
+aR,aA(A)q51(B)wM);q4
+Lcb;qT
+cSin:hD
+wB(495,aG" "
+mM" "
+wI
+mX,"B cSinCos"
+mK,aA(A)q51(B)wM);q4
+Lkh;h8
+qG
+TailCall_cSin:g5
+cSin:qS
+cAsin:wB(345,"cAsin "
+mM,,);q4
+oE
+wB(240,mG
+mM,mM
+mD,);q4
+Lki
+gY
+wB(183,"x "
+mM,"[fp_sin(x)]"
+,wN);q4
+Lkj;oH
+qN
+oY
+cCsc
+mY(499,aG" cCsc "
+wI
+mM,"B cCsc "
+aR,aA(A)q51(B)wM);q4
+Lcb;}
+}
+qG
+TailCall_cSinh:g5
+oQ
+qS
+cAcosh:wB(437,"cAcosh cSinh"
+,"[DO_STACKPLUS1] "
+mZ"[Value_t(-1)] "
+aL,);incStackPtr();--mStackPtr;q4
+Lkk
+qU
+cAsinh:wB(349,"cAsinh cSinh"
+,,);q4
+oE
+wB(241,mG"cSinh"
+,"cSinh"
+mD,);q4
+Lkl
+gY
+wB(184,"x cSinh"
+,"[fp_sinh(x)]"
+,wN);q4
+Lkm;}
+qH
+TailCall_cSqr:g5
+cSqr:qS
+cAbs:wB(204,aX"cSqr"
+,"cSqr"
+,);q4
+Lkn
+oF
+wB(203,mG"cSqr"
+,"cSqr"
+,);q4
+Lkn
+qU
+cSqrt:A=dE
+wB(338,wJ
+q01" cSqr"
+,"A"
+,aA(A)wM);oS;h8}
+qH
+TailCall_cSqrt:g5
+cSqrt:qS
+hS
+d4
+qK
+o3
+A=hE
+w0
+if(oC
+o3
+wB(512,"cSqr"
+aC
+mZ
+aL,"A cHypot"
+,aA(A)wM);q4
+Lko;}
+}
+B
+g4
+gV
+B)){A=oC
+w0
+if(qL
+4]o3
+wB(513,"cSqr"
+aC"B[IsUnaryOpcode(B)] "
+mZ
+aL,"A B cHypot"
+,"    with"
+aQ(B)q71(A)wM);q4
+Lkp;}
+}
+}
+o2
+wB(23,mZ
+q01,mQ,);q4
+Lkq
+gY
+wB(185,"x "
+q01,"[fp_sqrt(x)]"
+,wN);q4
+Lla;}
+qH
+TailCall_cSub:g5
+cSub
+hH
+wB(76,mC"cSub"
+,"[Value_t()]"
+wH,);q4
+Leh
+oF
+wB(200,q81
+mF,"cAdd"
+,);q4
+Llb
+gY
+g8)){wB(58,"x[x==Value_t()]"
+mF,,wN);q4
+Lba;}
+m2(106,m3"cSub"
+,"[y-x]"
+,q31);q4
+Llc;}
+wB(51,"x"
+mF,"[-x]"
+aV,wN);q4
+Lld
+gR
+w0
+oY
+cRSub
+dV
+wB(289,"x "
+a4
+aC"cSub"
+,"A"
+aV" [x] "
+a4,aA(A)<<","
+m4);q4
+Lle;}
+wB(296,a4
+aC"cSub"
+,"[DO_STACKPLUS1] A"
+mF" "
+a4,aA(A)wM);incStackPtr();--mStackPtr;q4
+Llf;}
+qG
+TailCall_cTan:g5
+cTan:qS
+cAtan2:wB(354,"cAtan2 "
+mN,"cDiv"
+,);q4
+Lga
+oF
+wB(242,mG
+mN,mN
+mD,);q4
+Llg
+gY
+wB(187,"x "
+mN,"[fp_tan(x)]"
+,wN);q4
+Llh;oH
+qN
+oY
+cCot
+mY(501,aG" cCot "
+wI
+mN,"B cCot "
+aR,aA(A)q51(B)wM);q4
+Lcb;}
+}
+qG
+TailCall_cTanh:g5
+cTanh:qS
+cAtanh:wB(352,"cAtanh cTanh"
+,,);q4
+oE
+wB(243,mG"cTanh"
+,"cTanh"
+mD,);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"
+,aA(A)wM);gJ
+qG
+g7
+Default0:;A=w5
+w1
+0){B=q0[0
+hZ
+wB(475,aG" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]"
+,"B"
+mE,aA(A)q51(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"
+mE,aA(A)q51(B)<<", C"
+a0(C)<<", D"
+a0(D)wM);q4
+Llm;}
+}
+}
+}
+C=w5
+qR
+IsCommutativeOrParamSwappableBinaryOpcode(C)){qS
+cSin:A=qK
+w1
+3
+gA]==cCos){B=hQ
+wB(505,aG" "
+aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] "
+mM" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinCos {GetParamSwappedBinaryOpcode(C)}"
+,"    with C"
+a0(C)q71(A)q51(B)wM);q4
+Lln;}
+}
+qT
+oQ
+A=qK
+w1
+3
+gA]==cCosh){B=hQ
+wB(506,aG" "
+aI" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]"
+,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}"
+,"    with C"
+a0(C)q71(A)q51(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
+m5
+Lae:q7=fp_acosh
+m5
+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
+q11
+gX
+Lmg;Lbc:mI
+A
+gX
+Lmg;Lbd:gU
+dS;wE(cNotNot);q4
+TailCall_cNotNot;Lbe:gT
+fp_and(x
+d6
+Lbf:q7=fp_arg
+m5
+Lbg:q7=fp_asin
+m5
+Lbh:q7=fp_asinh
+m5
+Lbi:q7=fp_atan
+m5
+Lbj:gT
+fp_atan2(gW
+Lbk:q7=fp_atanh
+m5
+Lbl:q7=fp_cbrt
+m5
+Lbm:q1
+cFloor);Lml:w5=cNeg;g0
+wE(cNeg);q4
+TailCall_cNeg;Lbn:q7=fp_ceil
+m5
+Lbp:q7=fp_conj
+m5
+Lbq:g6
+Lmm:wE(cCos);q4
+TailCall_cCos;Lca:q7=fp_cos
+m5
+Lcb:dF=cDup;w5=cInv;Lmn:wE(cInv);q4
+TailCall_cInv;Lcc:mI
+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
+m5
+Lcg:mI
+cSinhCosh);gJ
+Lch:q7=RadiansToDegrees
+m5
+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:hV
+2;qI
+q8
+oR
+Lnf:w5=cDeg;g0
+wE(cDeg);q4
+TailCall_cDeg;Ldh:hV
+2;qI
+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:mI
+oI
+Lnh:g0
+q4
+Lne;Ldl:q8
+3
+gC
+oI
+qF
+x
+q11);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
+m5
+Lea:d7
+cExp2
+o7
+fp_exp2(x)gX
+Lmc;Leb:q7=fp_exp2
+m5
+Lec:qF
+oW
+g1
+2))q11);Lnk:qE
+h3
+gI
+cExp;g0
+wE(cExp);q4
+TailCall_cExp;Led:q1
+cCeil
+oT
+Lee:q7=fp_floor
+m5
+Lef:gT
+fp_less(x
+d6
+Leg:gT
+fp_lessOrEq(x
+d6
+Leh:oZ));Lnl:dF
+dJ
+q4
+Llq;Lei:q7=fp_imag
+m5
+Lej:q7=fp_int
+m5
+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:mI
+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:hV
+2;qI
+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
+q11);dM
+Lnb;Lgp:gT
+x;d7
+dU
+qF
+y*x
+gX
+Lna;Lgq:q7=RadiansToDegrees(x
+gX
+Lgl;Lha:gT
+y*x;q8
+4
+gH
+Lof:qE
+dU
+Log:qE
+B
+gI
+cDiv;q4
+Lnh;Lhb:o9;oC=q6
+q9
+oR
+q4
+Lof;Lhc:gT
+y*x;q8
+oR
+q4
+Log;Lhd:q8
+4
+gH
+q4
+Lma;Lhe:q8
+4
+dT
+qF
+x+x
+gX
+Lod;Lhf:hV
+2;qI
+qM
+q4
+Loe;Lhg:gT
+y*x;q4
+Loa;Lhh:o9;q4
+Lgl;Lhi:gT
+y*x;q8
+oR
+Loh:dM
+Lni;Lhj:o9;qL
+2
+gK
+q4
+Loh;Lhk:gT
+y*x;dG
+Lni;Lhl:q7=h4
+gX
+Lgl;Lhm:gT
+x;qL
+4]dJ
+q8
+4
+dT
+o6
+y*x
+q11);dM
+Lmk;Lhn:gT
+y*x;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
+q11
+gX
+Loh;Lie:mI
+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
+m5
+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:gT
+y*x;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
+m5
+Lkh:mI
+cSinCos
+gX
+Lol;Lki:q1
+cSin
+oT
+Lkj:q7=fp_sin
+m5
+Lkk:q1
+cSqr
+o7
+g1-1)gX
+Lmo;Lkl:q1
+cSinh
+oT
+Lkm:q7=fp_sinh
+m5
+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
+m5
+Llb:g6
+q4
+Loi;Llc:gT
+y-x;q4
+Lba;Lld:o9;q4
+Loi;Lle:q8
+oV
+oJ
+hS
+o7
+x
+q11
+gX
+Lmh;Llf:mI
+A
+oJ
+cSub
+gX
+Lmh;Llg:q1
+cTan
+oT
+Llh:q7=fp_tan
+m5
+Lli:q1
+cTanh
+oT
+Llj:q7=fp_tanh
+m5
+Llk:q7=fp_trunc
+m5
+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/deal.II/contrib/functionparser/extrasrc/fpaux.hh b/deal.II/contrib/functionparser/extrasrc/fpaux.hh
new file mode 100644 (file)
index 0000000..2ce6da2
--- /dev/null
@@ -0,0 +1,1295 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* 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); }
+
+#if __cplusplus > 201100
+    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
+
+#if __cplusplus > 201100
+    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); }
+
+#if __cplusplus > 201100
+    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>
+    inline Value_t fp_epsilon()
+    {
+        return FunctionParserBase<Value_t>::epsilon();
+    }
+
+
+#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);
+    }
+
+    template<>
+    inline MpfrFloat fp_epsilon<MpfrFloat>() { return MpfrFloat::someEpsilon(); }
+#endif // FP_SUPPORT_MPFR_FLOAT_TYPE
+
+
+// -------------------------------------------------------------------------
+// GMP int
+// -------------------------------------------------------------------------
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+    inline GmpInt fp_abs(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&) {}
+
+    template<>
+    inline GmpInt fp_epsilon<GmpInt>() { return 0; }
+#endif // FP_SUPPORT_GMP_INT_TYPE
+
+
+#if __cplusplus > 201100
+    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));
+    }
+
+#if __cplusplus > 201100
+    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) <= fp_epsilon<Value_t>()); }
+
+    template<typename Value_t>
+    inline bool fp_nequal(const Value_t& x, const Value_t& y)
+    { return IsIntType<Value_t>::result
+        ? (x != y)
+        : (fp_abs(x - y) > fp_epsilon<Value_t>()); }
+
+    template<typename Value_t>
+    inline bool fp_less(const Value_t& x, const Value_t& y)
+    { return IsIntType<Value_t>::result
+        ? (x < y)
+        : (x < y - fp_epsilon<Value_t>()); }
+
+    template<typename Value_t>
+    inline bool fp_lessOrEq(const Value_t& x, const Value_t& y)
+    { return IsIntType<Value_t>::result
+        ? (x <= y)
+        : (x <= y + fp_epsilon<Value_t>()); }
+
+
+    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_
+
+
+#ifndef FP_DISABLE_DOUBLE_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_D(g) g(double)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_D(g)
+#endif
+
+#ifdef FP_SUPPORT_FLOAT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_F(g) g(float)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_F(g)
+#endif
+
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_LD(g) g(long double)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_LD(g)
+#endif
+
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_LI(g) g(long)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_LI(g)
+#endif
+
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_MF(g) g(MpfrFloat)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_MF(g)
+#endif
+
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_GI(g) g(GmpInt)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_GI(g)
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_CD(cd) cd(std::complex<double>)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_CD(cd)
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_CF(cd) cd(std::complex<float>)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_CF(cd)
+#endif
+
+#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+# define FUNCTIONPARSER_INSTANTIATE_CLD(cd) cd(std::complex<long double>)
+#else
+# define FUNCTIONPARSER_INSTANTIATE_CLD(cd)
+#endif
+
+/* Add 'FUNCTIONPARSER_INSTANTIATE_TYPES' at the end of all .cc files
+   containing FunctionParserBase implementations.
+ */
+#define FUNCTIONPARSER_INSTANTIATE_BASE(type) \
+    template class FunctionParserBase<type>;
+
+#define FUNCTIONPARSER_INSTANTIATE_TYPES \
+    FUNCTIONPARSER_INSTANTIATE_D(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_F(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_LD(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_LI(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_MF(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_GI(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_CD(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_CF(FUNCTIONPARSER_INSTANTIATE_BASE) \
+    FUNCTIONPARSER_INSTANTIATE_CLD(FUNCTIONPARSER_INSTANTIATE_BASE)
+
+#endif // ONCE_FPARSER_AUX_H_
diff --git a/deal.II/contrib/functionparser/extrasrc/fptypes.hh b/deal.II/contrib/functionparser/extrasrc/fptypes.hh
new file mode 100644 (file)
index 0000000..4023c8b
--- /dev/null
@@ -0,0 +1,288 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* 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
index d71f7e5f3a3e306c73df635f377827ba27cb8bd1..77ffc69079e03217a6705376174da79a47a626d8 100644 (file)
@@ -1,19 +1,27 @@
-//===============================
-// Function parser v2.83 by Warp
-//===============================
-
-#include "fpconfig.h"
-#include "fparser.h"
-#include "fptypes.h"
-using namespace FUNCTIONPARSERTYPES;
-using namespace fparser;
-
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* Copyright: Juha Nieminen, Joel Yliluoma                                 *|
+|*                                                                         *|
+|* This library is distributed under the terms of the                      *|
+|* GNU Lesser General Public License version 3.                            *|
+|* (See lgpl.txt and gpl.txt for the license text.)                        *|
+\***************************************************************************/
+
+#include "fpconfig.hh"
+#include "fparser.hh"
+
+#include <set>
 #include <cstdlib>
 #include <cstring>
 #include <cctype>
 #include <cmath>
+#include <cassert>
+#include <limits>
 
-using namespace std;
+#include "extrasrc/fptypes.hh"
+#include "extrasrc/fpaux.hh"
+using namespace FUNCTIONPARSERTYPES;
 
 #ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA
 #ifndef FP_USE_THREAD_SAFE_EVAL
@@ -21,1279 +29,2838 @@ using namespace std;
 #endif
 #endif
 
-#ifndef M_PI
-#define M_PI 3.1415926535897932384626433832795
+#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
 
-namespace
-{
-    const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]);
-
+//=========================================================================
+// Opcode analysis functions
+//=========================================================================
+// These functions are used by the Parse() bytecode optimizer (mostly from
+// code in fp_opcode_add.inc).
 
-    // BCB4 does not implement the standard lower_bound function.
-    // This is used instead:
-    const FuncDefinition* fp_lower_bound(const FuncDefinition* first,
-                                         const FuncDefinition* last,
-                                         const FuncDefinition& value)
-    {
-        while(first < last)
-        {
-            const FuncDefinition* middle = first+(last-first)/2;
-            if(*middle < value) first = middle+1;
-            else last = middle;
-        }
-        return last;
-    }
-
-
-    // Returns a pointer to the FuncDefinition instance which 'name' is
-    // the same as the one given by 'F'. If no such function name exists,
-    // returns 0.
-    inline const FuncDefinition* FindFunction(const char* F)
+bool FUNCTIONPARSERTYPES::IsLogicalOpcode(unsigned op)
+{
+    switch(op)
     {
-        FuncDefinition func = { F, 0, 0, 0 };
-        while(isalnum(F[func.nameLength])) ++func.nameLength;
-        if(func.nameLength)
-        {
-            const FuncDefinition* found =
-                fp_lower_bound(Functions, Functions+FUNC_AMOUNT, func);
-            if(found == Functions+FUNC_AMOUNT || func < *found)
-                return 0;
-            return found;
-        }
-        return 0;
+      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;
 }
 
-
-//---------------------------------------------------------------------------
-// Copy-on-write method
-//---------------------------------------------------------------------------
-void FunctionParser::CopyOnWrite()
+bool FUNCTIONPARSERTYPES::IsComparisonOpcode(unsigned op)
 {
-    if(data->referenceCounter > 1)
+    switch(op)
     {
-        Data* oldData = data;
-        data = new Data(*oldData);
-        --(oldData->referenceCounter);
-        data->referenceCounter = 1;
+      case cEqual: case cNEqual:
+      case cLess: case cLessOrEq:
+      case cGreater: case cGreaterOrEq:
+          return true;
+      default: break;
     }
+    return false;
 }
 
-
-//---------------------------------------------------------------------------
-// Constructors and destructors
-//---------------------------------------------------------------------------
-//===========================================================================
-FunctionParser::FunctionParser():
-    parseErrorType(FP_NO_ERROR), evalErrorType(0),
-    data(new Data),
-    evalRecursionLevel(0)
-{
-    data->referenceCounter = 1;
-}
-
-FunctionParser::~FunctionParser()
+unsigned FUNCTIONPARSERTYPES::OppositeComparisonOpcode(unsigned op)
 {
-    if(--(data->referenceCounter) == 0)
+    switch(op)
     {
-        delete data;
+      case cLess: return cGreater;
+      case cGreater: return cLess;
+      case cLessOrEq: return cGreaterOrEq;
+      case cGreaterOrEq: return cLessOrEq;
     }
+    return op;
 }
 
-FunctionParser::FunctionParser(const FunctionParser& cpy):
-    parseErrorType(cpy.parseErrorType),
-    evalErrorType(cpy.evalErrorType),
-    data(cpy.data),
-    evalRecursionLevel(0)
-{
-    ++(data->referenceCounter);
-}
-
-FunctionParser& FunctionParser::operator=(const FunctionParser& cpy)
+bool FUNCTIONPARSERTYPES::IsNeverNegativeValueOpcode(unsigned op)
 {
-    if(data != cpy.data)
+    switch(op)
     {
-        if(--(data->referenceCounter) == 0) delete data;
-
-        parseErrorType = cpy.parseErrorType;
-        evalErrorType = cpy.evalErrorType;
-        data = cpy.data;
-        evalRecursionLevel = cpy.evalRecursionLevel;
-
-        ++(data->referenceCounter);
+      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 *this;
-}
-
-void FunctionParser::ForceDeepCopy()
-{
-    CopyOnWrite();
-}
-
-FunctionParser::Data::Data():
-    useDegreeConversion(false),
-    isOptimized(false),
-    ByteCode(0), ByteCodeSize(0),
-    Immed(0), ImmedSize(0),
-    Stack(0), StackSize(0)
-{}
-
-FunctionParser::Data::~Data()
-{
-    if(ByteCode) { delete[] ByteCode; ByteCode=0; }
-    if(Immed) { delete[] Immed; Immed=0; }
-    if(Stack) { delete[] Stack; Stack=0; }
-}
-
-// Makes a deep-copy of Data:
-FunctionParser::Data::Data(const Data& cpy):
-    varAmount(cpy.varAmount), useDegreeConversion(cpy.useDegreeConversion),
-    Variables(cpy.Variables), Constants(cpy.Constants), Units(cpy.Units),
-    FuncPtrNames(cpy.FuncPtrNames), FuncPtrs(cpy.FuncPtrs),
-    FuncParserNames(cpy.FuncParserNames), FuncParsers(cpy.FuncParsers),
-    ByteCode(0), ByteCodeSize(cpy.ByteCodeSize),
-    Immed(0), ImmedSize(cpy.ImmedSize),
-    Stack(0), StackSize(cpy.StackSize)
-{
-    if(ByteCodeSize) ByteCode = new unsigned[ByteCodeSize];
-    if(ImmedSize) Immed = new double[ImmedSize];
-    if(StackSize) Stack = new double[StackSize];
-
-    for(unsigned i=0; i<ByteCodeSize; ++i) ByteCode[i] = cpy.ByteCode[i];
-    for(unsigned i=0; i<ImmedSize; ++i) Immed[i] = cpy.Immed[i];
-
-    // No need to copy the stack contents because it's obsolete outside Eval()
+    return false;
 }
 
-
-//---------------------------------------------------------------------------
-// Function parsing
-//---------------------------------------------------------------------------
-//===========================================================================
-namespace
+bool FUNCTIONPARSERTYPES::IsAlwaysIntegerOpcode(unsigned op)
 {
-    // Error messages returned by ErrorMsg():
-    const char* ParseErrorMessage[]=
+    switch(op)
     {
-        "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
-        ""
-    };
-
-
-    enum VarNameType
-    { NOT_VALID_NAME, VALID_NEW_NAME, RESERVED_FUNCTION,
-      USER_DEF_CONST, USER_DEF_UNIT,
-      USER_DEF_FUNC_PTR, USER_DEF_FUNC_PARSER
-    };
+      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;
 }
 
-
-// Parse variables
-bool FunctionParser::ParseVars(const string& Vars, map<string, unsigned>& dest)
+bool FUNCTIONPARSERTYPES::IsUnaryOpcode(unsigned op)
 {
-    unsigned varNumber = VarBegin;
-    unsigned ind1 = 0, ind2;
-
-    while(ind1 < Vars.size())
+    switch(op)
     {
-        if(!isalpha(Vars[ind1]) && Vars[ind1]!='_') return false;
-        for(ind2=ind1+1; ind2<Vars.size() && Vars[ind2]!=','; ++ind2)
-            if(!isalnum(Vars[ind2]) && Vars[ind2]!='_') return false;
-        const string varName = Vars.substr(ind1, ind2-ind1);
-        if(VarNameType(varName) != VALID_NEW_NAME) return false;
-
-        if(dest.insert(make_pair(varName, varNumber++)).second == false)
-            return false;
-
-        ind1 = ind2+1;
+      case cInv: case cNeg:
+      case cNot: case cAbsNot:
+      case cNotNot: case cAbsNotNot:
+      case cSqr: case cRSqrt:
+      case cDeg: case cRad:
+          return true;
     }
-    return true;
+    return (op < FUNC_AMOUNT && Functions[op].params == 1);
 }
 
-namespace
+bool FUNCTIONPARSERTYPES::IsBinaryOpcode(unsigned op)
 {
-    bool varNameHasOnlyValidChars(const std::string& name)
+    switch(op)
     {
-        if(name.empty() || (!isalpha(name[0]) && name[0] != '_'))
-            return false;
-        for(unsigned i=0; i<name.size(); ++i)
-            if(!isalnum(name[i]) && name[i] != '_')
-                return false;
-        return true;
+      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);
 }
 
-int FunctionParser::VarNameType(const std::string& name) const
+bool FUNCTIONPARSERTYPES::IsVarOpcode(unsigned op)
 {
-    if(!varNameHasOnlyValidChars(name)) return NOT_VALID_NAME;
-
-    const char* n = name.c_str();
-    if(FindFunction(n)) return RESERVED_FUNCTION;
-    if(FindConstant(n, data->Constants) != data->Constants.end())
-        return USER_DEF_CONST;
-
-    // Units are independent from the rest and thus the following check
-    // is actually not needed:
-    //if(FindConstant(n, data->Units) != data->Units.end())
-    //    return USER_DEF_UNIT;
-
-    if(FindVariable(n, data->FuncParserNames) != data->FuncParserNames.end())
-        return USER_DEF_FUNC_PARSER;
-    if(FindVariable(n, data->FuncPtrNames) != data->FuncPtrNames.end())
-        return USER_DEF_FUNC_PTR;
-
-    return VALID_NEW_NAME;
+    // See comment in declaration of FP_ParamGuardMask
+    return int(op) >= VarBegin;
 }
 
-
-// Constants:
-bool FunctionParser::AddConstant(const string& name, double value)
+bool FUNCTIONPARSERTYPES::IsCommutativeOrParamSwappableBinaryOpcode(unsigned op)
 {
-    int nameType = VarNameType(name);
-    if(nameType == VALID_NEW_NAME || nameType == USER_DEF_CONST)
+    switch(op)
     {
-        CopyOnWrite();
-        data->Constants[name] = value;
-        return true;
+      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;
 }
 
-// Units:
-bool FunctionParser::AddUnit(const std::string& name, double value)
-{
-    if(!varNameHasOnlyValidChars(name)) return false;
-    CopyOnWrite();
-    data->Units[name] = value;
-    return true;
-}
-
-// Function pointers
-bool FunctionParser::AddFunction(const std::string& name,
-                                 FunctionPtr func, unsigned paramsAmount)
+unsigned FUNCTIONPARSERTYPES::GetParamSwappedBinaryOpcode(unsigned op)
 {
-    int nameType = VarNameType(name);
-    if(nameType == VALID_NEW_NAME)
+    switch(op)
     {
-        CopyOnWrite();
-        data->FuncPtrNames[name] = data->FuncPtrs.size();
-        data->FuncPtrs.push_back(Data::FuncPtrData(func, paramsAmount));
-        return true;
+      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 false;
+    return op; // Error
 }
 
-bool FunctionParser::CheckRecursiveLinking(const FunctionParser* fp) const
+template<bool ComplexType>
+bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op)
 {
-    if(fp == this) return true;
-    for(unsigned i=0; i<fp->data->FuncParsers.size(); ++i)
-        if(CheckRecursiveLinking(fp->data->FuncParsers[i])) return true;
+    // 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;
 }
 
-bool FunctionParser::AddFunction(const std::string& name,
-                                 FunctionParser& parser)
+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
 {
-    int nameType = VarNameType(name);
-    if(nameType == VALID_NEW_NAME)
+    template<typename ValueT>
+    inline ValueT fp_pow_with_exp_log(const ValueT& x, const ValueT& y)
     {
-        if(CheckRecursiveLinking(&parser)) return false;
-
-        CopyOnWrite();
+        // 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);
+    }
 
-        data->FuncParserNames[name] = data->FuncParsers.size();
-        data->FuncParsers.push_back(&parser);
-        return true;
+    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;
     }
-    return false;
 }
 
-
-
-// Main parsing function
-// ---------------------
-int FunctionParser::Parse(const std::string& Function,
-                          const std::string& Vars,
-                          bool useDegrees)
+template<typename ValueT>
+ValueT FUNCTIONPARSERTYPES::fp_pow(const ValueT& x, const ValueT& y)
 {
-    CopyOnWrite();
-
-    data->Variables.clear();
-
-    if(!ParseVars(Vars, data->Variables))
+    if(x == ValueT(1)) return ValueT(1);
+    // y is now zero or positive
+    if(isLongInteger(y))
     {
-        parseErrorType = INVALID_VARS;
-        return Function.size();
+        // Use fast binary exponentiation algorithm
+        if(y >= ValueT(0))
+            return fp_powi(x,              makeLongInteger(y));
+        else
+            return ValueT(1) / fp_powi(x, -makeLongInteger(y));
     }
-    data->varAmount = data->Variables.size(); // this is for Eval()
-
-    const char* Func = Function.c_str();
-
-    parseErrorType = FP_NO_ERROR;
-
-    int Result = CheckSyntax(Func);
-    if(Result >= 0) return Result;
-
-    data->useDegreeConversion = useDegrees;
-    Result = Compile(Func);
-    if(Result >= 0) return Result;
-
-    data->Variables.clear();
-
-    parseErrorType = FP_NO_ERROR;
-    return -1;
+    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 char* const fpOperators[] =
+    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)
     {
-        "+", "-", "*", "/", "%", "^",
-        "=", "!=", "<=", "<", ">=", ">", "&", "|",
-        0
-    };
+        /* 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;
+    }
 
-    // Is given char an operator?
-    // (Returns 0 if not, else the size of the operator)
-    inline int IsOperator(const char* F)
+    template<typename Value_t>
+    inline unsigned readIdentifier(const char* input)
     {
-        for(unsigned opInd = 0; fpOperators[opInd]; ++opInd)
+        const unsigned value = readIdentifierCommon(input);
+        if( (value & 0x80000000U) != 0) // Function?
         {
-            const char* op = fpOperators[opInd];
-            for(unsigned n = 0; F[n] == *op; ++n)
+            // 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())
             {
-                ++op;
-                if(*op == 0) return op-fpOperators[opInd];
+                // If it does not exist, return it as an identifier instead
+                return value & 0xFFFFu;
             }
         }
-        return 0;
+        return value;
     }
 
-    // skip whitespace
-    inline void sws(const char* F, int& Ind)
+    // Returns true if the entire string is a valid identifier
+    template<typename Value_t>
+    bool containsOnlyValidIdentifierChars(const std::string& name)
     {
-        while(F[Ind] && isspace(F[Ind])) ++Ind;
+        if(name.empty()) return false;
+        return readIdentifier<Value_t>(name.c_str()) == (unsigned) name.size();
     }
-}
 
-// Returns an iterator to the variable with the same name as 'F', or to
-// Variables.end() if no such variable exists:
-inline FunctionParser::Data::VarMap_t::const_iterator
-FunctionParser::FindVariable(const char* F, const Data::VarMap_t& vars) const
-{
-    if(vars.size())
+
+    // -----------------------------------------------------------------------
+    // Wrappers for strto... functions
+    // -----------------------------------------------------------------------
+    template<typename Value_t>
+    inline Value_t fp_parseLiteral(const char* str, char** endptr)
     {
-        unsigned ind = 0;
-        while(isalnum(F[ind]) || F[ind] == '_') ++ind;
-        if(ind)
-        {
-            string name(F, ind);
-            return vars.find(name);
-        }
+        return std::strtod(str, endptr);
     }
-    return vars.end();
-}
 
-inline FunctionParser::Data::ConstMap_t::const_iterator
-FunctionParser::FindConstant(const char* F,
-                             const Data::ConstMap_t& consts) const
-{
-    if(consts.size())
+#if defined(FP_USE_STRTOLD) || __cplusplus > 201100
+    template<>
+    inline long double fp_parseLiteral<long double>(const char* str,
+                                                    char** endptr)
     {
-        unsigned ind = 0;
-        while(isalnum(F[ind]) || F[ind] == '_') ++ind;
-        if(ind)
-        {
-            string name(F, ind);
-            return consts.find(name);
-        }
+        using namespace std; // Just in case strtold() is not inside std::
+        return strtold(str, endptr);
     }
-    return consts.end();
-}
+#endif
 
-int FunctionParser::CheckForUnit(const char* Function, int Ind) const
-{
-    int c = Function[Ind];
-    if(isalpha(c) || c == '_')
+#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)
     {
-        Data::ConstMap_t::const_iterator uIter =
-            FindConstant(&Function[Ind], data->Units);
-        if(uIter != data->Units.end())
+        T result = fp_parseLiteral<T> (str,endptr);
+        const char* end = *endptr;
+        if( (*end == 'i'  || *end == 'I')
+        &&  !std::isalnum(end[1]) )
         {
-            Ind += uIter->first.size();
-            sws(Function, Ind);
+            ++*endptr;
+            return std::complex<T> (T(), result);
         }
+        return std::complex<T> (result, T());
     }
-    return Ind;
-}
-
-//---------------------------------------------------------------------------
-// Check function string syntax
-// ----------------------------
-int FunctionParser::CheckSyntax(const char* Function)
-{
-    const Data::VarMap_t& Variables = data->Variables;
-    const Data::ConstMap_t& Constants = data->Constants;
-    const Data::VarMap_t& FuncPtrNames = data->FuncPtrNames;
-    const Data::VarMap_t& FuncParserNames = data->FuncParserNames;
-
-    vector<int> functionParenthDepth;
+#endif
 
-    int Ind=0, ParenthCnt=0, c;
-    char* Ptr;
+#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
 
-    while(true)
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+    template<>
+    inline std::complex<float> fp_parseLiteral<std::complex<float> >
+    (const char* str, char** endptr)
     {
-        sws(Function, Ind);
-        c=Function[Ind];
+        return fp_parseComplexLiteral<float> (str,endptr);
+    }
+#endif
 
-// Check for valid operand (must appear)
+#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
 
-        // Check for leading - or !
-        if(c=='-' || c=='!') { sws(Function, ++Ind); c=Function[Ind]; }
-        if(c==0) { parseErrorType=PREMATURE_EOS; return Ind; }
+    // -----------------------------------------------------------------------
+    // 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
+    }
 
-        // Check for math function
-        bool foundFunc = false;
-        const FuncDefinition* fptr = FindFunction(&Function[Ind]);
-        if(fptr)
+    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)
         {
-            Ind += fptr->nameLength;
-            foundFunc = true;
+            unsigned carry = unsigned( buffer[p] >> (elem_t)(limb_bits-4) );
+            buffer[p] = (buffer[p] << 4) | nibble;
+            nibble = carry;
         }
-        else
+    }
+
+    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)
         {
-            // Check for user-defined function
-            Data::VarMap_t::const_iterator fIter =
-                FindVariable(&Function[Ind], FuncPtrNames);
-            if(fIter != FuncPtrNames.end())
+            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)
             {
-                Ind += fIter->first.size();
-                foundFunc = true;
+                // 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;
             }
-            else
+        }
+        // Read decimals
+        if(*str == '.')
+            for(++str; ; )
             {
-                Data::VarMap_t::const_iterator pIter =
-                    FindVariable(&Function[Ind], FuncParserNames);
-                if(pIter != FuncParserNames.end())
+                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)
                 {
-                    Ind += pIter->first.size();
-                    foundFunc = true;
+                    // Exhausted the precision. Skip the rest
+                    // of the decimals, until the exponent.
+                    while(testXdigit(*str) >= 0)
+                        ++str;
+                    break;
                 }
             }
-        }
-
-        if(foundFunc)
-        {
-            sws(Function, Ind);
-            c = Function[Ind];
-            if(c!='(') { parseErrorType=EXPECT_PARENTH_FUNC; return Ind; }
-
-            int Ind2 = Ind+1;
-            sws(Function, Ind2);
-            if(Function[Ind2] == ')')
-            {
-                Ind = Ind2+1;
-                sws(Function, Ind);
-                c = Function[Ind];
-                // Ugly, but other methods would just be uglier...
-                goto CheckOperator;
-            }
-
-            functionParenthDepth.push_back(ParenthCnt+1);
-        }
-
-        // Check for opening parenthesis
-        if(c=='(')
-        {
-            ++ParenthCnt;
-            sws(Function, ++Ind);
-            if(Function[Ind]==')') { parseErrorType=EMPTY_PARENTH; return Ind;}
-            continue;
-        }
 
-        // Check for number
-        if(isdigit(c) || (c=='.' && isdigit(Function[Ind+1])))
+        // Read exponent
+    read_exponent:
+        if(*str == 'p' || *str == 'P')
         {
-            strtod(&Function[Ind], &Ptr);
-            Ind += int(Ptr-&Function[Ind]);
-            sws(Function, Ind);
-            c = Function[Ind];
-        }
-        else
-        { // Check for variable
-            Data::VarMap_t::const_iterator vIter =
-                FindVariable(&Function[Ind], Variables);
-            if(vIter != Variables.end())
-                Ind += vIter->first.size();
-            else
+            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)
             {
-                // Check for constant
-                Data::ConstMap_t::const_iterator cIter =
-                    FindConstant(&Function[Ind], Constants);
-                if(cIter != Constants.end())
-                    Ind += cIter->first.size();
-                else
-                { parseErrorType=SYNTAX_ERROR; return Ind; }
+                exponent += (int)p_exponent;
+                str = str2;
             }
-            sws(Function, Ind);
-            c = Function[Ind];
         }
 
-        // Check for unit
-        Ind = CheckForUnit(Function, Ind);
-        c = Function[Ind];
+        if(endptr) *endptr = const_cast<char*> (str);
 
-        // Check for closing parenthesis
-        while(c==')')
+        Value_t result = std::ldexp(Value_t(mantissa_buffer[0]), exponent);
+        for(unsigned p=1; p<n_limbs; ++p)
         {
-            if(functionParenthDepth.size() &&
-               functionParenthDepth.back() == ParenthCnt)
-                functionParenthDepth.pop_back();
-            if((--ParenthCnt)<0) { parseErrorType=MISM_PARENTH; return Ind; }
-            sws(Function, ++Ind);
-            c=Function[Ind];
+            exponent += limb_bits;
+            result += ldexp(Value_t(mantissa_buffer[p]), exponent);
         }
+        return result;
+    }
 
-    CheckOperator:
-// If we get here, we have a legal operand and now a legal unit, operator or
-// end of string must follow
-
-        // Check for unit
-        Ind = CheckForUnit(Function, Ind);
-        c = Function[Ind];
-
-        // Check for EOS
-        if(c==0) break; // The only way to end the checking loop without error
-
-        // Check for operator
-        int opSize = 0;
-        if(c == ',' && !functionParenthDepth.empty() &&
-           functionParenthDepth.back() == ParenthCnt)
-            opSize = 1;
-        else
-            opSize = IsOperator(Function+Ind);
-        if(opSize == 0)
-        { parseErrorType=EXPECT_OPERATOR; return Ind; }
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+    template<>
+    long parseHexLiteral<long>(const char* str, char** endptr)
+    {
+        return std::strtol(str, endptr, 16);
+    }
+#endif
 
-// If we get here, we have an operand and an operator; the next loop will
-// check for another operand (must appear)
-        Ind += opSize;
-    } // while
+#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
 
-    // Check that all opened parentheses are also closed
-    if(ParenthCnt>0) { parseErrorType=MISSING_PARENTH; return Ind; }
+#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
 
-// The string is ok
-    parseErrorType=FP_NO_ERROR;
-    return -1;
+#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
 }
 
-
-// Compile function string to bytecode
-// -----------------------------------
-int FunctionParser::Compile(const char* Function)
+//=========================================================================
+// Utility functions
+//=========================================================================
+namespace
 {
-    if(data->ByteCode) { delete[] data->ByteCode; data->ByteCode=0; }
-    if(data->Immed) { delete[] data->Immed; data->Immed=0; }
-    if(data->Stack) { delete[] data->Stack; data->Stack=0; }
-    data->isOptimized = false;
-
-    vector<unsigned> byteCode; byteCode.reserve(1024);
-    tempByteCode = &byteCode;
+    // -----------------------------------------------------------------------
+    // 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);
 
-    vector<double> immed; immed.reserve(1024);
-    tempImmed = &immed;
+        if(nameIter != namePtrs.end() && newName.first == nameIter->first)
+        {
+            // redefining a var is not allowed.
+            if(isVar) return false;
 
-    data->StackSize = StackPtr = 0;
+            // redefining other tokens is allowed, if the type stays the same.
+            if(nameIter->second.type != newName.second.type)
+                return false;
 
-    int ind = CompileExpression(Function, 0);
-    if(parseErrorType != FP_NO_ERROR) return ind;
+            // update the data
+            nameIter->second = newName.second;
+            return true;
+        }
 
-    data->ByteCodeSize = byteCode.size();
-    data->ImmedSize = immed.size();
+        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;
+        }
 
-    if(data->ByteCodeSize)
-    {
-        data->ByteCode = new unsigned[data->ByteCodeSize];
-        memcpy(data->ByteCode, &byteCode[0],
-               sizeof(unsigned)*data->ByteCodeSize);
-    }
-    if(data->ImmedSize)
-    {
-        data->Immed = new double[data->ImmedSize];
-        memcpy(data->Immed, &immed[0],
-               sizeof(double)*data->ImmedSize);
+        namePtrs.insert(nameIter, newName);
+        return true;
     }
-#ifndef FP_USE_THREAD_SAFE_EVAL
-    if(data->StackSize)
-        data->Stack = new double[data->StackSize];
-#endif
-
-    return -1;
 }
 
 
-inline void FunctionParser::AddCompiledByte(unsigned c)
-{
-    tempByteCode->push_back(c);
-}
-
-inline void FunctionParser::AddImmediate(double i)
-{
-    tempImmed->push_back(i);
-}
+//=========================================================================
+// 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)
+{}
 
-inline void FunctionParser::AddFunctionOpcode(unsigned opcode)
+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)
 {
-    if(data->useDegreeConversion)
-        switch(opcode)
+    for(typename NamePtrsMap<Value_t>::const_iterator i = rhs.mNamePtrs.begin();
+        i != rhs.mNamePtrs.end();
+        ++i)
+    {
+        if(i->second.type == NameData<Value_t>::VARIABLE)
         {
-          case cCos:
-          case cCosh:
-          case cCot:
-          case cCsc:
-          case cSec:
-          case cSin:
-          case cSinh:
-          case cTan:
-          case cTanh:
-              AddCompiledByte(cRad);
+            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);
         }
-
-    AddCompiledByte(opcode);
-
-    if(data->useDegreeConversion)
-        switch(opcode)
+        else
         {
-          case cAcos:
-#ifndef NO_ASINH
-          case cAcosh:
-          case cAsinh:
-          case cAtanh:
-#endif
-          case cAsin:
-          case cAtan:
-          case cAtan2:
-              AddCompiledByte(cDeg);
+            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);
         }
+    }
 }
 
-inline void FunctionParser::incStackPtr()
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::~Data()
 {
-    if(++StackPtr > data->StackSize) ++(data->StackSize);
+    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;
+}
 
-// Compile if()
-int FunctionParser::CompileIf(const char* F, int ind)
+template<typename Value_t>
+unsigned FunctionParserBase<Value_t>::decFuncWrapperRefCount
+(FunctionWrapper* wrapper)
 {
-    int ind2 = CompileExpression(F, ind, true); // condition
-    sws(F, ind2);
-    if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
-    AddCompiledByte(cIf);
-    unsigned curByteCodeSize = tempByteCode->size();
-    AddCompiledByte(0); // Jump index; to be set later
-    AddCompiledByte(0); // Immed jump index; to be set later
+    return --wrapper->mReferenceCount;
+}
 
-    --StackPtr;
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::FuncWrapperPtrData():
+    mRawFuncPtr(0), mFuncWrapperPtr(0), mParams(0)
+{}
 
-    ind2 = CompileExpression(F, ind2+1, true); // then
-    sws(F, ind2);
-    if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
-    AddCompiledByte(cJump);
-    unsigned curByteCodeSize2 = tempByteCode->size();
-    unsigned curImmedSize2 = tempImmed->size();
-    AddCompiledByte(0); // Jump index; to be set later
-    AddCompiledByte(0); // Immed jump index; to be set later
+template<typename Value_t>
+FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::~FuncWrapperPtrData()
+{
+    if(mFuncWrapperPtr &&
+       FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0)
+        delete mFuncWrapperPtr;
+}
 
-    --StackPtr;
+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);
+}
 
-    ind2 = CompileExpression(F, ind2+1, true); // else
-    sws(F, ind2);
-    if(F[ind2] != ')') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; }
+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;
+}
 
-    // Set jump indices
-    (*tempByteCode)[curByteCodeSize] = curByteCodeSize2+1;
-    (*tempByteCode)[curByteCodeSize+1] = curImmedSize2;
-    (*tempByteCode)[curByteCodeSize2] = tempByteCode->size()-1;
-    (*tempByteCode)[curByteCodeSize2+1] = tempImmed->size();
 
-    return ind2+1;
+//=========================================================================
+// FunctionParser constructors, destructor and assignment
+//=========================================================================
+template<typename Value_t>
+FunctionParserBase<Value_t>::FunctionParserBase():
+    mData(new Data),
+    mStackPtr(0)
+{
 }
 
-int FunctionParser::CompileFunctionParams(const char* F, int ind,
-                                          unsigned requiredParams)
+template<typename Value_t>
+FunctionParserBase<Value_t>::~FunctionParserBase()
 {
-    int ind2 = ind;
-    if(requiredParams > 0)
-    {
-        unsigned curStackPtr = StackPtr;
-        ind2 = CompileExpression(F, ind);
+    if(--(mData->mReferenceCounter) == 0)
+        delete mData;
+}
 
-        if(StackPtr != curStackPtr+requiredParams)
-        { parseErrorType=ILL_PARAMS_AMOUNT; return ind; }
+template<typename Value_t>
+FunctionParserBase<Value_t>::FunctionParserBase(const FunctionParserBase& cpy):
+    mData(cpy.mData),
+    mStackPtr(0)
+{
+    ++(mData->mReferenceCounter);
+}
 
-        StackPtr -= requiredParams - 1;
-    }
-    else
+template<typename Value_t>
+FunctionParserBase<Value_t>&
+FunctionParserBase<Value_t>::operator=(const FunctionParserBase& cpy)
+{
+    if(mData != cpy.mData)
     {
-        incStackPtr();
+        if(--(mData->mReferenceCounter) == 0) delete mData;
+
+        mData = cpy.mData;
+        ++(mData->mReferenceCounter);
     }
+    return *this;
+}
 
-    sws(F, ind2);
-    return ind2+1; // F[ind2] is ')'
+template<typename Value_t>
+typename FunctionParserBase<Value_t>::Data*
+FunctionParserBase<Value_t>::getParserData()
+{
+    return mData;
 }
 
-// Compiles element
-int FunctionParser::CompileElement(const char* F, int ind)
+template<typename Value_t>
+void FunctionParserBase<Value_t>::setDelimiterChar(char c)
 {
-    sws(F, ind);
-    char c = F[ind];
+    mData->mDelimiterChar = c;
+}
 
-    if(c == '(')
-    {
-        ind = CompileExpression(F, ind+1);
-        sws(F, ind);
-        return ind+1; // F[ind] is ')'
-    }
 
-    if(isdigit(c) || c=='.' /*|| c=='-'*/) // Number
+//---------------------------------------------------------------------------
+// Copy-on-write method
+//---------------------------------------------------------------------------
+template<typename Value_t>
+void FunctionParserBase<Value_t>::CopyOnWrite()
+{
+    if(mData->mReferenceCounter > 1)
     {
-        const char* startPtr = &F[ind];
-        char* endPtr;
-        double val = strtod(startPtr, &endPtr);
-        AddImmediate(val);
-        AddCompiledByte(cImmed);
-        incStackPtr();
-        return ind+(endPtr-startPtr);
+        Data* oldData = mData;
+        mData = new Data(*oldData);
+        --(oldData->mReferenceCounter);
+        mData->mReferenceCounter = 1;
     }
+}
 
-    if(isalpha(c) || c == '_') // Function, variable or constant
-    {
-        const FuncDefinition* func = FindFunction(F+ind);
-        if(func) // is function
-        {
-            int ind2 = ind + func->nameLength;
-            sws(F, ind2); // F[ind2] is '('
-            if(strcmp(func->name, "if") == 0) // "if" is a special case
-            {
-                return CompileIf(F, ind2+1);
-            }
+template<typename Value_t>
+void FunctionParserBase<Value_t>::ForceDeepCopy()
+{
+    CopyOnWrite();
+}
 
-#ifndef DISABLE_EVAL
-            unsigned requiredParams =
-                strcmp(func->name, "eval") == 0 ?
-                data->Variables.size() : func->params;
-#else
-            unsigned requiredParams = func->params;
-#endif
-            ind2 = CompileFunctionParams(F, ind2+1, requiredParams);
-            AddFunctionOpcode(func->opcode);
-            return ind2; // F[ind2-1] is ')'
-        }
 
-        Data::VarMap_t::const_iterator vIter =
-            FindVariable(F+ind, data->Variables);
-        if(vIter != data->Variables.end()) // is variable
-        {
-            AddCompiledByte(vIter->second);
-            incStackPtr();
-            return ind + vIter->first.size();
-        }
+//=========================================================================
+// Epsilon
+//=========================================================================
+template<> double FunctionParserBase<double>::sEpsilon = 1E-12;
+template<> float FunctionParserBase<float>::sEpsilon = 1E-5F;
+template<> long double FunctionParserBase<long double>::sEpsilon = 1E-14L;
+template<> long FunctionParserBase<long>::sEpsilon = 0;
 
-        Data::ConstMap_t::const_iterator cIter =
-            FindConstant(F+ind, data->Constants);
-        if(cIter != data->Constants.end()) // is constant
-        {
-            AddImmediate(cIter->second);
-            AddCompiledByte(cImmed);
-            incStackPtr();
-            return ind + cIter->first.size();
-        }
+template<> std::complex<double>
+FunctionParserBase<std::complex<double> >::sEpsilon = 1E-12;
 
-        Data::VarMap_t::const_iterator fIter =
-            FindVariable(F+ind, data->FuncPtrNames);
-        if(fIter != data->FuncPtrNames.end()) // is user-defined func pointer
-        {
-            unsigned index = fIter->second;
+template<> std::complex<float>
+FunctionParserBase<std::complex<float> >::sEpsilon = 1E-5F;
 
-            int ind2 = ind + fIter->first.length();
-            sws(F, ind2); // F[ind2] is '('
+template<> std::complex<long double>
+FunctionParserBase<std::complex<long double> >::sEpsilon = 1E-14L;
 
-            ind2 = CompileFunctionParams(F, ind2+1,
-                                         data->FuncPtrs[index].params);
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+template<> MpfrFloat
+FunctionParserBase<MpfrFloat>::sEpsilon(MpfrFloat::someEpsilon());
+#endif
 
-            AddCompiledByte(cFCall);
-            AddCompiledByte(index);
-            return ind2;
-        }
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+template<> GmpInt FunctionParserBase<GmpInt>::sEpsilon = 0;
+#endif
 
-        Data::VarMap_t::const_iterator pIter =
-            FindVariable(F+ind, data->FuncParserNames);
-        if(pIter != data->FuncParserNames.end()) // is user-defined func parser
-        {
-            unsigned index = pIter->second;
+template<typename Value_t>
+Value_t FunctionParserBase<Value_t>::epsilon()
+{
+    return sEpsilon;
+}
+
+template<typename Value_t>
+void FunctionParserBase<Value_t>::setEpsilon(Value_t value)
+{
+    sEpsilon = value;
+}
 
-            int ind2 = ind + pIter->first.length();
-            sws(F, ind2); // F[ind2] is '('
 
-            ind2 = CompileFunctionParams
-                (F, ind2+1, data->FuncParsers[index]->data->varAmount);
+//=========================================================================
+// 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;
 
-            AddCompiledByte(cPCall);
-            AddCompiledByte(index);
-            return ind2;
-        }
-    }
+    CopyOnWrite();
+    std::pair<NamePtr, NameData<Value_t> > newName
+        (NamePtr(name.data(), unsigned(name.size())),
+         NameData<Value_t>(NameData<Value_t>::CONSTANT, value));
 
-    parseErrorType = UNEXPECTED_ERROR;
-    return ind;
+    return addNewNameData(mData->mNamePtrs, newName, false);
 }
 
-// Compiles a unit factor possibly appearing after an element
-int FunctionParser::CompilePossibleUnit(const char* F, int ind)
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::AddUnit(const std::string& name,
+                                          Value_t value)
 {
-    if(isalpha(F[ind]) || F[ind] == '_')
-    {
-        // If the syntax checker is bug-free, this should always work:
-        Data::ConstMap_t::const_iterator uIter =
-            FindConstant(F+ind, data->Units);
+    if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false;
 
-        AddImmediate(uIter->second);
-        AddCompiledByte(cImmed);
-        incStackPtr();
-        AddCompiledByte(cMul);
-        --StackPtr;
-        ind += uIter->first.size();
-        sws(F, ind);
-    }
-    return ind;
+    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);
 }
 
-// Compiles '^'
-int FunctionParser::CompilePow(const char* F, int ind)
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::AddFunction
+(const std::string& name, FunctionPtr ptr, unsigned paramsAmount)
 {
-    int ind2 = CompileElement(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
-    ind2 = CompilePossibleUnit(F, ind2);
+    if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false;
 
-    while(F[ind2] == '^')
+    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)
     {
-        ind2 = CompileUnaryMinus(F, ind2+1);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
-        AddCompiledByte(cPow);
-        --StackPtr;
+        mData->mFuncPtrs.push_back(typename Data::FuncWrapperPtrData());
+        mData->mFuncPtrs.back().mRawFuncPtr = ptr;
+        mData->mFuncPtrs.back().mParams = paramsAmount;
     }
+    return success;
+}
 
-    return ind2;
+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;
 }
 
-// Compiles unary '-'
-int FunctionParser::CompileUnaryMinus(const char* F, int ind)
+template<typename Value_t>
+typename FunctionParserBase<Value_t>::FunctionWrapper*
+FunctionParserBase<Value_t>::GetFunctionWrapper(const std::string& name)
 {
-    sws(F, ind);
-    if(F[ind] == '-' || F[ind] == '!')
+    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)
     {
-        int ind2 = ind+1;
-        sws(F, ind2);
-        ind2 = CompilePow(F, ind2);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
+        return mData->mFuncPtrs[nameIter->second.index].mFuncWrapperPtr;
+    }
+    return 0;
+}
 
-        // if we are negating a constant, negate the constant itself:
-        if(F[ind] == '-' && tempByteCode->back() == cImmed)
-            tempImmed->back() = -tempImmed->back();
+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;
+}
 
-        // if we are negating a negation, we can remove both:
-        else if((F[ind] == '-' && tempByteCode->back() == cNeg))
-            tempByteCode->pop_back();
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::AddFunction(const std::string& name,
+                                              FunctionParserBase& fp)
+{
+    if(!containsOnlyValidIdentifierChars<Value_t>(name) ||
+       CheckRecursiveLinking(&fp))
+        return false;
 
-        else
-            AddCompiledByte(F[ind] == '-' ? cNeg : cNot);
+    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())));
 
-        return ind2;
+    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;
     }
-
-    int ind2 = CompilePow(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
-    return ind2;
+    return success;
 }
 
-// Compiles '*', '/' and '%'
-int FunctionParser::CompileMult(const char* F, int ind)
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::RemoveIdentifier(const std::string& name)
 {
-    int ind2 = CompileUnaryMinus(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
-    char op;
+    CopyOnWrite();
+
+    NamePtr namePtr(name.data(), unsigned(name.size()));
 
-    while((op = F[ind2]) == '*' || op == '/' || op == '%')
+    typename NamePtrsMap<Value_t>::iterator nameIter =
+        mData->mNamePtrs.find(namePtr);
+
+    if(nameIter != mData->mNamePtrs.end())
     {
-        ind2 = CompileUnaryMinus(F, ind2+1);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
-        switch(op)
+        if(nameIter->second.type == NameData<Value_t>::VARIABLE)
         {
-          case '*': AddCompiledByte(cMul); break;
-          case '/': AddCompiledByte(cDiv); break;
-          case '%': AddCompiledByte(cMod); break;
+            // Illegal attempt to delete variables
+            return false;
         }
-        --StackPtr;
+        delete[] nameIter->first.name;
+        mData->mNamePtrs.erase(nameIter);
+        return true;
     }
-
-    return ind2;
+    return false;
 }
 
-// Compiles '+' and '-'
-int FunctionParser::CompileAddition(const char* F, int ind)
+
+//=========================================================================
+// Function parsing
+//=========================================================================
+namespace
 {
-    int ind2 = CompileMult(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
-    char op;
+    // 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)) };
+    };
 
-    while((op = F[ind2]) == '+' || op == '-')
+    template<typename Value_t>
+    inline bool BeginsLiteral(unsigned byte)
     {
-        ind2 = CompileMult(F, ind2+1);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
-        AddCompiledByte(op=='+' ? cAdd : cSub);
-        --StackPtr;
+        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;
     }
 
-    return ind2;
+    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;
 }
 
-// Compiles '=', '<' and '>'
-int FunctionParser::CompileComparison(const char* F, int ind)
+
+// ---------------------------------------------------------------------------
+// Parse variables
+// ---------------------------------------------------------------------------
+template<typename Value_t>
+bool FunctionParserBase<Value_t>::ParseVariables
+(const std::string& inputVarString)
 {
-    int ind2 = CompileAddition(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
-    char op;
+    if(mData->mVariablesString == inputVarString) return true;
 
-    while((op = F[ind2]) == '=' || op == '<' || op == '>' || op == '!')
+    /* Delete existing variables from mNamePtrs */
+    for(typename NamePtrsMap<Value_t>::iterator i =
+            mData->mNamePtrs.begin();
+        i != mData->mNamePtrs.end(); )
     {
-        int opSize = (F[ind2+1] == '=' ? 2 : 1);
-        ind2 = CompileAddition(F, ind2+opSize);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
-        switch(op)
+        if(i->second.type == NameData<Value_t>::VARIABLE)
         {
-          case '=':
-              AddCompiledByte(cEqual); break;
-          case '<':
-              AddCompiledByte(opSize == 1 ? cLess : cLessOrEq); break;
-          case '>':
-              AddCompiledByte(opSize == 1 ? cGreater : cGreaterOrEq); break;
-          case '!':
-              AddCompiledByte(cNEqual); break;
+            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;
         }
-        --StackPtr;
+
+        beginPtr = endPtr + 1;
     }
 
-    return ind2;
+    mData->mVariablesAmount = varNumber - VarBegin;
+    return true;
 }
 
-// Compiles '&'
-int FunctionParser::CompileAnd(const char* F, int ind)
+// ---------------------------------------------------------------------------
+// Parse() public interface functions
+// ---------------------------------------------------------------------------
+template<typename Value_t>
+int FunctionParserBase<Value_t>::Parse(const char* Function,
+                                       const std::string& Vars,
+                                       bool useDegrees)
 {
-    int ind2 = CompileComparison(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
+    CopyOnWrite();
 
-    while(F[ind2] == '&')
+    if(!ParseVariables(Vars))
     {
-        ind2 = CompileComparison(F, ind2+1);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
-        AddCompiledByte(cAnd);
-        --StackPtr;
+        mData->mParseErrorType = INVALID_VARS;
+        return int(strlen(Function));
     }
 
-    return ind2;
+    return ParseFunction(Function, useDegrees);
 }
 
-// Compiles '|'
-int FunctionParser::CompileOr(const char* F, int ind)
+template<typename Value_t>
+int FunctionParserBase<Value_t>::Parse(const std::string& Function,
+                                       const std::string& Vars,
+                                       bool useDegrees)
 {
-    int ind2 = CompileAnd(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
+    CopyOnWrite();
 
-    while(F[ind2] == '|')
+    if(!ParseVariables(Vars))
     {
-        ind2 = CompileAnd(F, ind2+1);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
-        AddCompiledByte(cOr);
-        --StackPtr;
+        mData->mParseErrorType = INVALID_VARS;
+        return int(Function.size());
     }
 
-    return ind2;
+    return ParseFunction(Function.c_str(), useDegrees);
 }
 
-// Compiles ','
-int FunctionParser::CompileExpression(const char* F, int ind, bool stopAtComma)
+
+// ---------------------------------------------------------------------------
+// Main parsing function
+// ---------------------------------------------------------------------------
+template<typename Value_t>
+int FunctionParserBase<Value_t>::ParseFunction(const char* function,
+                                               bool useDegrees)
 {
-    int ind2 = CompileOr(F, ind);
-    if(parseErrorType != FP_NO_ERROR) return ind2;
-    sws(F, ind2);
+    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(stopAtComma) return ind2;
+    if(mData->mParseErrorType != FP_NO_ERROR)
+        return int(mData->mErrorLocation - function);
 
-    while(F[ind2] == ',')
+    assert(ptr); // Should never be null at this point. It's a bug otherwise.
+    if(*ptr)
     {
-        ind2 = CompileOr(F, ind2+1);
-        if(parseErrorType != FP_NO_ERROR) return ind2;
-        sws(F, ind2);
+        if(mData->mDelimiterChar == 0 || *ptr != mData->mDelimiterChar)
+            mData->mParseErrorType = EXPECT_OPERATOR;
+        return int(ptr - function);
     }
 
-    return ind2;
+#ifndef FP_USE_THREAD_SAFE_EVAL
+    mData->mStack.resize(mData->mStackSize);
+#endif
+
+    return -1;
 }
 
 
-// Return parse error message
-// --------------------------
-const char* FunctionParser::ErrorMsg() const
+//=========================================================================
+// Parsing and bytecode compiling functions
+//=========================================================================
+template<typename Value_t>
+inline const char* FunctionParserBase<Value_t>::SetErrorType(ParseErrorType t,
+                                                             const char* pos)
 {
-    if(parseErrorType != FP_NO_ERROR) return ParseErrorMessage[parseErrorType];
+    mData->mParseErrorType = t;
+    mData->mErrorLocation = pos;
     return 0;
 }
 
-//---------------------------------------------------------------------------
-// Function evaluation
-//---------------------------------------------------------------------------
-//===========================================================================
+template<typename Value_t>
+inline void FunctionParserBase<Value_t>::incStackPtr()
+{
+    if(++mStackPtr > mData->mStackSize) ++(mData->mStackSize);
+}
+
 namespace
 {
-    inline int doubleToInt(double d)
+    const unsigned char powi_factor_table[128] =
     {
-        return d<0 ? -int((-d)+.5) : int(d+.5);
-    }
+        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 double Min(double d1, double d2)
+    inline int get_powi_factor(long abs_int_exponent)
     {
-        return d1<d2 ? d1 : d2;
+        if(abs_int_exponent >= int(sizeof(powi_factor_table))) return 0;
+        return powi_factor_table[abs_int_exponent];
     }
-    inline double Max(double d1, double d2)
+
+#if 0
+    int EstimatePowiComplexity(int abs_int_exponent)
     {
-        return d1>d2 ? d1 : d2;
+        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
 
-
-    inline double DegreesToRadians(double degrees)
+    bool IsEligibleIntPowiExponent(long int_exponent)
     {
-        return degrees*(M_PI/180.0);
+        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
     }
-    inline double RadiansToDegrees(double radians)
+
+    /* 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)
     {
-        return radians*(180.0/M_PI);
+        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 "?";
     }
 }
 
-double FunctionParser::Eval(const double* Vars)
+template<typename Value_t>
+inline void FunctionParserBase<Value_t>::AddImmedOpcode(Value_t value)
 {
-    const unsigned* const ByteCode = data->ByteCode;
-    const double* const Immed = data->Immed;
-    const unsigned ByteCodeSize = data->ByteCodeSize;
-    unsigned IP, DP=0;
-    int SP=-1;
-
-#ifdef FP_USE_THREAD_SAFE_EVAL
-#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA
-    double* const Stack = (double*)alloca(data->StackSize*sizeof(double));
-#else
-    std::vector<double> Stack(data->StackSize);
-#endif
-#else
-    double* const Stack = data->Stack;
-#endif
+    mData->mImmed.push_back(value);
+    mData->mByteCode.push_back(cImmed);
+}
 
-    for(IP=0; IP<ByteCodeSize; ++IP)
+template<typename Value_t>
+inline void FunctionParserBase<Value_t>::CompilePowi(long abs_int_exponent)
+{
+    int num_muls=0;
+    while(abs_int_exponent > 1)
     {
-        switch(ByteCode[IP])
+        long factor = get_powi_factor(abs_int_exponent);
+        if(factor)
         {
-// Functions:
-          case   cAbs: Stack[SP] = fabs(Stack[SP]); break;
-          case  cAcos: if(Stack[SP] < -1 || Stack[SP] > 1)
-                       { evalErrorType=4; return 0; }
-                       Stack[SP] = acos(Stack[SP]); break;
-#ifndef NO_ASINH
-          case cAcosh: Stack[SP] = acosh(Stack[SP]); break;
-#endif
-          case  cAsin: if(Stack[SP] < -1 || Stack[SP] > 1)
-                       { evalErrorType=4; return 0; }
-                       Stack[SP] = asin(Stack[SP]); break;
-#ifndef NO_ASINH
-          case cAsinh: Stack[SP] = asinh(Stack[SP]); break;
-#endif
-          case  cAtan: Stack[SP] = atan(Stack[SP]); break;
-          case cAtan2: Stack[SP-1] = atan2(Stack[SP-1], Stack[SP]);
-                       --SP; break;
-#ifndef NO_ASINH
-          case cAtanh: Stack[SP] = atanh(Stack[SP]); break;
-#endif
-          case  cCeil: Stack[SP] = ceil(Stack[SP]); break;
-          case   cCos: Stack[SP] = cos(Stack[SP]); break;
-          case  cCosh: Stack[SP] = cosh(Stack[SP]); break;
+            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:
               {
-                  double t = tan(Stack[SP]);
-                  if(t == 0) { evalErrorType=1; return 0; }
-                  Stack[SP] = 1/t; break;
+                  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:
               {
-                  double s = sin(Stack[SP]);
-                  if(s == 0) { evalErrorType=1; return 0; }
-                  Stack[SP] = 1/s; break;
+                  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;
               }
 
 
-#ifndef DISABLE_EVAL
-          case  cEval:
-              {
-                  double retVal = 0;
-                  if(evalRecursionLevel == EVAL_MAX_REC_LEVEL)
-                  {
-                      evalErrorType = 5;
-                  }
+          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
                   {
-#ifndef FP_USE_THREAD_SAFE_EVAL
-                      data->Stack = new double[data->StackSize];
-#endif
-                      ++evalRecursionLevel;
-                      retVal = Eval(&Stack[SP-data->varAmount+1]);
-                      --evalRecursionLevel;
-#ifndef FP_USE_THREAD_SAFE_EVAL
-                      delete[] data->Stack;
-                      data->Stack = Stack;
-#endif
+                      const unsigned* buf = &byteCode[IP+1];
+                      IP = buf[0];
+                      DP = buf[1];
                   }
-                  SP -= data->varAmount-1;
-                  Stack[SP] = retVal;
                   break;
-              }
-#endif
 
-          case   cExp: Stack[SP] = exp(Stack[SP]); break;
-          case cFloor: Stack[SP] = floor(Stack[SP]); 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    cIf:
-              {
-                  unsigned jumpAddr = ByteCode[++IP];
-                  unsigned immedAddr = ByteCode[++IP];
-                  if(doubleToInt(Stack[SP]) == 0)
-                  {
-                      IP = jumpAddr;
-                      DP = immedAddr;
-                  }
-                  --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   cInt: Stack[SP] = floor(Stack[SP]+.5); break;
-          case   cLog: if(Stack[SP] <= 0) { evalErrorType=3; return 0; }
-                       Stack[SP] = log(Stack[SP]); break;
-          case cLog10: if(Stack[SP] <= 0) { evalErrorType=3; return 0; }
-                       Stack[SP] = log10(Stack[SP]); break;
-          case   cMax: Stack[SP-1] = Max(Stack[SP-1], Stack[SP]);
+          case   cMax: Stack[SP-1] = fp_max(Stack[SP-1], Stack[SP]);
                        --SP; break;
-          case   cMin: Stack[SP-1] = Min(Stack[SP-1], Stack[SP]);
+
+          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:
               {
-                  double c = cos(Stack[SP]);
-                  if(c == 0) { evalErrorType=1; return 0; }
-                  Stack[SP] = 1/c; break;
+                  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] = sin(Stack[SP]); break;
-          case  cSinh: Stack[SP] = sinh(Stack[SP]); break;
-          case  cSqrt: if(Stack[SP] < 0) { evalErrorType=2; return 0; }
-                       Stack[SP] = sqrt(Stack[SP]); break;
-          case   cTan: Stack[SP] = tan(Stack[SP]); break;
-          case  cTanh: Stack[SP] = tanh(Stack[SP]); 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: DP = ByteCode[IP+2];
-                       IP = ByteCode[IP+1];
-                       break;
+          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] == 0) { evalErrorType=1; return 0; }
-                       Stack[SP-1] /= Stack[SP]; --SP; break;
-          case   cMod: if(Stack[SP] == 0) { evalErrorType=1; return 0; }
-                       Stack[SP-1] = fmod(Stack[SP-1], Stack[SP]);
-                       --SP; break;
-          case   cPow: Stack[SP-1] = pow(Stack[SP-1], Stack[SP]);
-                       --SP; break;
 
-#ifdef FP_EPSILON
-          case cEqual: Stack[SP-1] =
-                           (fabs(Stack[SP-1]-Stack[SP]) <= FP_EPSILON);
-                       --SP; break;
-          case cNEqual: Stack[SP-1] =
-                            (fabs(Stack[SP-1] - Stack[SP]) >= FP_EPSILON);
-                       --SP; break;
-          case  cLess: Stack[SP-1] = (Stack[SP-1] < Stack[SP]-FP_EPSILON);
-                       --SP; break;
-          case  cLessOrEq: Stack[SP-1] = (Stack[SP-1] <= Stack[SP]+FP_EPSILON);
-                       --SP; break;
-          case cGreater: Stack[SP-1] = (Stack[SP-1]-FP_EPSILON > Stack[SP]);
-                         --SP; break;
-          case cGreaterOrEq: Stack[SP-1] =
-                                 (Stack[SP-1]+FP_EPSILON >= Stack[SP]);
-                         --SP; break;
-#else
-          case cEqual: Stack[SP-1] = (Stack[SP-1] == Stack[SP]);
-                       --SP; break;
-          case cNEqual: Stack[SP-1] = (Stack[SP-1] != Stack[SP]);
-                       --SP; break;
-          case  cLess: Stack[SP-1] = (Stack[SP-1] < Stack[SP]);
-                       --SP; break;
-          case  cLessOrEq: Stack[SP-1] = (Stack[SP-1] <= Stack[SP]);
-                       --SP; break;
-          case cGreater: Stack[SP-1] = (Stack[SP-1] > Stack[SP]);
-                         --SP; break;
-          case cGreaterOrEq: Stack[SP-1] = (Stack[SP-1] >= Stack[SP]);
-                         --SP; break;
-#endif
+          case   cDiv:
+              if(Stack[SP] == Value_t(0))
+              { mData->mEvalErrorType=1; return Value_t(0); }
+              Stack[SP-1] /= Stack[SP]; --SP; break;
 
-          case   cAnd: Stack[SP-1] =
-                           (doubleToInt(Stack[SP-1]) &&
-                            doubleToInt(Stack[SP]));
-                       --SP; break;
-          case    cOr: Stack[SP-1] =
-                           (doubleToInt(Stack[SP-1]) ||
-                            doubleToInt(Stack[SP]));
-                       --SP; break;
-          case   cNot: Stack[SP] = !doubleToInt(Stack[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;
@@ -1302,10 +2869,13 @@ double FunctionParser::Eval(const double* Vars)
 // User-defined function calls:
           case cFCall:
               {
-                  unsigned index = ByteCode[++IP];
-                  unsigned params = data->FuncPtrs[index].params;
-                  double retVal =
-                      data->FuncPtrs[index].ptr(&Stack[SP-params+1]);
+                  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;
@@ -1313,164 +2883,903 @@ double FunctionParser::Eval(const double* Vars)
 
           case cPCall:
               {
-                  unsigned index = ByteCode[++IP];
-                  unsigned params = data->FuncParsers[index]->data->varAmount;
-                  double retVal =
-                      data->FuncParsers[index]->Eval(&Stack[SP-params+1]);
+                  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;
 
-#ifdef SUPPORT_OPTIMIZER
-          case   cVar: break; // Paranoia. These should never exist
           case   cDup: Stack[SP+1] = Stack[SP]; ++SP; break;
+
           case   cInv:
-              if(Stack[SP] == 0.0) { evalErrorType=1; return 0; }
-              Stack[SP] = 1.0/Stack[SP];
+              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];
+              Stack[++SP] = Vars[byteCode[IP]-VarBegin];
         }
     }
 
-    evalErrorType=0;
+    mData->mEvalErrorType=0;
     return Stack[SP];
 }
 
 
-#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT
+//===========================================================================
+// 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)
     {
-        dest.width(8); dest.fill('0'); std::hex(dest); //uppercase(dest);
+        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() { }
+    };
 }
 
-void FunctionParser::PrintByteCode(std::ostream& dest) const
+template<typename Value_t>
+void FunctionParserBase<Value_t>::PrintByteCode(std::ostream& dest,
+                                                bool showExpression) const
 {
-    dest << "Size of stack: " << data->StackSize << "\n";
+    dest << "Size of stack: " << mData->mStackSize << "\n";
 
-    const unsigned* const ByteCode = data->ByteCode;
-    const double* const Immed = data->Immed;
+    std::ostringstream outputBuffer;
+    std::ostream& output = (showExpression ? outputBuffer : dest);
 
-    for(unsigned IP=0, DP=0; IP<data->ByteCodeSize; ++IP)
-    {
-        printHex(dest, IP);
-        dest << ": ";
+    const std::vector<unsigned>& ByteCode = mData->mByteCode;
+    const std::vector<Value_t>& Immed = mData->mImmed;
 
-        unsigned opcode = ByteCode[IP];
+    std::vector<std::pair<int,std::string> > stack;
+    std::vector<IfInfo> if_stack;
 
-        switch(opcode)
+    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())
+          ))
         {
-          case cIf:
-              dest << "jz\t";
-              printHex(dest, ByteCode[IP+1]+1);
-              dest << endl;
-              IP += 2;
-              break;
+            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;
+                }
 
-          case cJump:
-              dest << "jump\t";
-              printHex(dest, ByteCode[IP+1]+1);
-              dest << endl;
-              IP += 2;
-              break;
-          case cImmed:
-              dest.precision(10);
-              dest << "push\t" << Immed[DP++] << endl;
-              break;
+                //unsigned explanation_before = changed_ip-2;
+                unsigned explanation_before = changed_ip-1;
 
-          case cFCall:
+                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 index = ByteCode[++IP];
-                  Data::VarMap_t::const_iterator iter =
-                      data->FuncPtrNames.begin();
-                  while(iter->second != index) ++iter;
-                  dest << "fcall\t" << iter->first
-                       << " (" << data->FuncPtrs[index].params << ")" << endl;
+                  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 cPCall:
+              case cAbsIf:
               {
-                  unsigned index = ByteCode[++IP];
-                  Data::VarMap_t::const_iterator iter =
-                      data->FuncParserNames.begin();
-                  while(iter->second != index) ++iter;
-                  dest << "pcall\t" << iter->first
-                       << " (" << data->FuncParsers[index]->data->varAmount
-                       << ")" << endl;
+                  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;
               }
 
-          default:
-              if(opcode < VarBegin)
+              case cJump:
               {
-                  string n;
-                  unsigned params = 1;
-                  switch(opcode)
-                  {
-                    case cNeg: n = "neg"; 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"; break;
-                    case cDeg: n = "deg"; break;
-                    case cRad: n = "rad"; break;
-
-#ifndef DISABLE_EVAL
-                    case cEval: n = "call\t0"; break;
-#endif
-
-#ifdef SUPPORT_OPTIMIZER
-                    case cVar: n = "(var)"; break;
-                    case cDup: n = "dup"; break;
-                    case cInv: n = "inv"; break;
-#endif
+                  unsigned dp    = ByteCode[IP+2];
+                  unsigned label = ByteCode[IP+1]+1;
 
-                    default:
-                        n = Functions[opcode-cAbs].name;
-                        params = Functions[opcode-cAbs].params;
+                  if(!if_stack.empty() && !stack.empty())
+                  {
+                      std::swap(if_stack.back().thenbranch, stack.back());
+                      if_stack.back().endif_location = label;
+                      stack.pop_back();
                   }
-                  dest << n;
-                  if(params != 1) dest << " (" << params << ")";
-                  dest << endl;
+
+                  output << "jump " << dp << ",";
+                  printHex(output, label);
+                  params = 0;
+                  produces = 0;
+                  IP += 2;
+                  break;
               }
-              else
+              case cImmed:
               {
-                  dest << "push\tVar" << opcode-VarBegin << endl;
+                  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 SUPPORT_OPTIMIZER
-void FunctionParser::MakeTree(void *) const {}
-void FunctionParser::Optimize()
+#ifndef FP_SUPPORT_OPTIMIZER
+template<typename Value_t>
+void FunctionParserBase<Value_t>::Optimize()
 {
     // Do nothing if no optimizations are supported.
 }
 #endif
+
+FUNCTIONPARSER_INSTANTIATE_TYPES
diff --git a/deal.II/contrib/functionparser/fparser.h b/deal.II/contrib/functionparser/fparser.h
deleted file mode 100644 (file)
index 9ef0d3d..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/***************************************************************************\
-|* Function parser v2.83 by Warp                                           *|
-|* -----------------------------                                           *|
-|* Parses and evaluates the given function with the given variable values. *|
-|* See fparser.txt for details.                                            *|
-|*                                                                         *|
-\***************************************************************************/
-
-#ifndef ONCE_FPARSER_H_
-#define ONCE_FPARSER_H_
-
-#include <string>
-#include <map>
-#include <vector>
-
-#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT
-#include <iostream>
-#endif
-namespace fparser {
-
-class FunctionParser
-{
-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,
-        FP_NO_ERROR
-    };
-
-
-    int Parse(const std::string& Function, const std::string& Vars,
-              bool useDegrees = false);
-    const char* ErrorMsg() const;
-    inline ParseErrorType GetParseErrorType() const { return parseErrorType; }
-
-    double Eval(const double* Vars);
-    inline int EvalError() const { return evalErrorType; }
-
-    bool AddConstant(const std::string& name, double value);
-    bool AddUnit(const std::string& name, double value);
-
-    typedef double (*FunctionPtr)(const double*);
-
-    bool AddFunction(const std::string& name,
-                     FunctionPtr, unsigned paramsAmount);
-    bool AddFunction(const std::string& name, FunctionParser&);
-
-    void Optimize();
-
-
-    FunctionParser();
-    ~FunctionParser();
-
-    // Copy constructor and assignment operator (implemented using the
-    // copy-on-write technique for efficiency):
-    FunctionParser(const FunctionParser&);
-    FunctionParser& operator=(const FunctionParser&);
-
-
-    void ForceDeepCopy();
-
-
-#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT
-    // For debugging purposes only:
-    void PrintByteCode(std::ostream& dest) const;
-#endif
-     
-    // Added by Luca Heltai. For consistency checking.
-    unsigned int NVars() {
-      return data->varAmount;
-    }
-    
-
-
-
-
-//========================================================================
-private:
-//========================================================================
-
-// Private data:
-// ------------
-    ParseErrorType parseErrorType;
-    int evalErrorType;
-
-    struct Data
-    {
-        unsigned referenceCounter;
-
-        int varAmount;
-        bool useDegreeConversion, isOptimized;
-
-        typedef std::map<std::string, unsigned> VarMap_t;
-        VarMap_t Variables;
-
-        typedef std::map<std::string, double> ConstMap_t;
-        ConstMap_t Constants;
-        ConstMap_t Units;
-
-        VarMap_t FuncPtrNames;
-        struct FuncPtrData
-        {
-            FunctionPtr ptr; unsigned params;
-            FuncPtrData(FunctionPtr p, unsigned par): ptr(p), params(par) {}
-        };
-        std::vector<FuncPtrData> FuncPtrs;
-
-        VarMap_t FuncParserNames;
-        std::vector<FunctionParser*> FuncParsers;
-
-        unsigned* ByteCode;
-        unsigned ByteCodeSize;
-        double* Immed;
-        unsigned ImmedSize;
-        double* Stack;
-        unsigned StackSize;
-
-        Data();
-        ~Data();
-        Data(const Data&);
-
-        Data& operator=(const Data&); // not implemented on purpose
-    };
-
-    Data* data;
-    unsigned evalRecursionLevel;
-
-    // Temp data needed in Compile():
-    unsigned StackPtr;
-    std::vector<unsigned>* tempByteCode;
-    std::vector<double>* tempImmed;
-
-
-// Private methods:
-// ---------------
-    void CopyOnWrite();
-
-
-    bool CheckRecursiveLinking(const FunctionParser*) const;
-
-    bool ParseVars(const std::string& Vars,
-                   std::map<std::string, unsigned>& dest);
-    int VarNameType(const std::string&) const;
-    Data::VarMap_t::const_iterator
-    FindVariable(const char*, const Data::VarMap_t&) const;
-    Data::ConstMap_t::const_iterator
-    FindConstant(const char*, const Data::ConstMap_t&) const;
-    int CheckForUnit(const char*, int) const;
-    int CheckSyntax(const char*);
-    int Compile(const char*);
-    bool IsVariable(int);
-    void AddCompiledByte(unsigned);
-    void AddImmediate(double);
-    void AddFunctionOpcode(unsigned);
-    inline void incStackPtr();
-    int CompileIf(const char*, int);
-    int CompileFunctionParams(const char*, int, unsigned);
-    int CompileElement(const char*, int);
-    int CompilePossibleUnit(const char*, int);
-    int CompilePow(const char*, int);
-    int CompileUnaryMinus(const char*, int);
-    int CompileMult(const char*, int);
-    int CompileAddition(const char*, int);
-    int CompileComparison(const char*, int);
-    int CompileAnd(const char*, int);
-    int CompileOr(const char*, int);
-    int CompileExpression(const char*, int, bool=false);
-
-
-    void MakeTree(void*) const;
-};
-
-}
-#endif
diff --git a/deal.II/contrib/functionparser/fparser.hh b/deal.II/contrib/functionparser/fparser.hh
new file mode 100644 (file)
index 0000000..b2959a8
--- /dev/null
@@ -0,0 +1,224 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* 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;
+    static Value_t sEpsilon;
+
+
+// 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/deal.II/contrib/functionparser/fparser.txt b/deal.II/contrib/functionparser/fparser.txt
deleted file mode 100644 (file)
index 27803fa..0000000
+++ /dev/null
@@ -1,897 +0,0 @@
-  Function parser for C++  v2.83 by Warp.
-  ======================================
-
-  Optimization code contributed by Bisqwit (http://iki.fi/bisqwit/)
-
-
-  The usage license of this library is located at the end of this text file.
-
-
-  What's new in v2.83
-  -------------------
-  - Fixed bug in the optimizer which caused functions like "x-y*1" to crash.
-
-  What's new in v2.82
-  -------------------
-  - Fixed bug in the optimizer which caused a crash with some functions.
-
-  What's new in v2.81
-  -------------------
-  - Added support for units (see help on the AddUnit() method).
-  - Added support for optionally making the Eval() function thread-safe
-    with a precompiler constant.
-
-
-  Table of contents:
-  -----------------
-  - Preface
-  - Usage
-    * Configuring the compilation
-    * Copying and assignment
-    * Short descriptions of FunctionParser methods
-    * Long descriptions of FunctionParser methods
-  - About thread safety
-  - The function string
-  - Contacting the author
-  - The algorithm used in the library
-  - Usage license
-
-
-
-=============================================================================
-  - Preface
-=============================================================================
-
-  Often people need to ask some mathematical expression from the user and
-then evaluate values for that expression. The simplest example is a program
-which draws the graphic of a user-defined function on screen.
-
-  This library adds C-style function string parsing to the program. This
-means that you can evaluate the string "sqrt(1-x^2+y^2)" with given values
-of 'x' and 'y'.
-
-  The library is intended to be very fast. It byte-compiles the function
-string at parse time and interpretes this byte-code at evaluation time.
-The evaluation is straightforward and no recursions are done (uses stack
-arithmetic).
-  Empirical tests show that it indeed is very fast (specially compared to
-libraries which evaluate functions by just interpreting the raw function
-string).
-
-  The library is made in ISO C++ and requires a standard-conforming C++
-compiler.
-
-
-=============================================================================
-  - Usage
-=============================================================================
-
-  To use the FunctionParser class, you have to include "fparser.hh" in
-your source code files which use the FunctionParser class.
-
-  When compiling, you have to compile fparser.cc and fpoptimizer.cc and
-link them to the main program. In some developement environments it's
-enough to add those two files to your current project.
-
-  If you are not going to use the optimizer (ie. you have commented out
-SUPPORT_OPTIMIZER in fpconfig.hh), you can leave the latter file out.
-
-
-  * Configuring the compilation:
-    ---------------------------
-
-    There is a set of precompiler options in the fpconfig.hh file
-  which can be used for setting certain features on or off:
-
-  NO_ASINH : (Default on)
-       By default the library does not support the asinh(), acosh()
-       and atanh() functions because they are not part of the ISO C++
-       standard. If your compiler supports them and you want the
-       parser to support them as well, comment out this line.
-
-  DISABLE_EVAL : (Default off)
-       Even though the maximum recursion level of the eval() function
-       is limited, it is still possible to write functions which never
-       reach this maximum recursion level but take enormous amounts of
-       time to evaluate (this can be undesirable eg. in web server-side
-       applications).
-       Uncommenting this line will disable the eval() function completely,
-       thus removing the danger of exploitation.
-
-       Note that you can also disable eval() by specifying the
-       DISABLE_EVAL precompiler constant in your compiler (eg.
-       with -DDISABLE_EVAL in gcc).
-
-  EVAL_MAX_REC_LEVEL : (Default 1000)
-       Sets the maximum recursion level allowed for eval().
-
-  SUPPORT_OPTIMIZER : (Default on)
-       If you are not going to use the Optimize() method, you can comment
-       this line out to speed-up the compilation of fparser.cc a bit, as
-       well as making the binary a bit smaller. (Optimize() can still be
-       called, but it will not do anything.)
-
-       You can also disable the optimizer by specifying the
-       NO_SUPPORT_OPTIMIZER precompiler constant in your compiler
-       (eg. with -DNO_SUPPORT_OPTIMIZER in gcc).
-
-  FP_EPSILON : (Default 1e-14)
-       Epsilon value used in comparison operators.
-       If this line is commented out, then no epsilon will be used.
-
-  FP_USE_THREAD_SAFE_EVAL : (Default off)
-       Define this precompiler constant to make Eval() thread-safe.
-       Refer to the thread safety section later in this document for
-       more information.
-       Note that defining this may make Eval() slightly slower.
-
-  FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA : (Default off)
-       This like the previous, but makes Eval() use the alloca() function
-       (instead of std::vector). This will make it faster, but the alloca()
-       function is not standard and thus not supported by all compilers.
-
-
-  * Copying and assignment:
-    ----------------------
-
-    The class implements a safe copy constructor and assignment operator.
-
-    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.
-    This means that copying/assigning is a very fast operation, and if
-  the copies are never modified then actual data copying never happens
-  either.
-
-    The Eval() and EvalError() methods of the copy can be called without
-  the internal data being copied.
-    Calling Parse(), Optimize() or the user-defined constant/function adding
-  methods will cause a deep-copy.
-
-    (C++ basics: The copy constructor is called when a new FunctionParser
-     instance is initialized with another, ie. like:
-
-       FunctionParser fp2 = fp1; // or: FunctionParser fp2(fp1);
-
-     or when a function takes a FunctionParser instance as parameter, eg:
-
-       void foo(FunctionParser p) // takes an instance of FunctionParser
-       { ... }
-
-     The assignment operator is called when a FunctionParser instance is
-     assigned to another, like "fp2 = fp1;".)
-
-
-  * Short descriptions of FunctionParser methods:
-    --------------------------------------------
-
-int Parse(const std::string& Function, const std::string& Vars,
-          bool useDegrees = false);
-
-    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.
-
-
-const char* ErrorMsg(void) const;
-
-    Returns an error message corresponding to the error in Parse(), or 0 if
-    no such error occurred.
-
-
-ParseErrorType GetParseErrorType() const;
-
-    Returns the type of parsing error which occurred. Possible return types
-    are described in the long description.
-
-
-double Eval(const double* Vars);
-
-    Evaluates the function given to Parse().
-
-
-int EvalError(void) const;
-
-    Returns 0 if no error happened in the previous call to Eval(), else an
-    error code >0.
-
-
-void Optimize();
-
-    Tries to optimize the bytecode for faster evaluation.
-
-
-bool AddConstant(const std::string& name, double value);
-
-    Add a constant to the parser. Returns false if the name of the constant
-    is invalid, else true.
-
-
-bool AddUnit(const std::string& name, double value);
-
-    Add a new unit to the parser. Returns false if the name of the unit
-    is invalid, else true.
-
-
-bool AddFunction(const std::string& name,
-                 double (*functionPtr)(const double*),
-                 unsigned paramsAmount);
-
-    Add a user-defined function to the parser (as a function pointer).
-    Returns false if the name of the function is invalid, else true.
-
-
-bool AddFunction(const std::string& name, FunctionParser&);
-
-    Add a user-defined function to the parser (as a FunctionParser instance).
-    Returns false if the name of the function is invalid, else true.
-
-
-
-  * Long descriptions of FunctionParser methods:
-    -------------------------------------------
-
----------------------------------------------------------------------------
-int Parse(const std::string& Function, const std::string& Vars,
-          bool useDegrees = false);
----------------------------------------------------------------------------
-
-      Parses the given function (and compiles it to internal format).
-    Destroys previous function. Following calls to Eval() will evaluate
-    the given function.
-      The strings given as parameters are not needed anymore after parsing.
-
-    Parameters:
-      Function  : String containing the function to parse.
-      Vars      : String containing the variable names, separated by commas.
-                  Eg. "x,y", "VarX,VarY,VarZ,n" or "x1,x2,x3,x4,__VAR__".
-      useDegrees: (Optional.) Whether to use degrees or radians in
-                  trigonometric functions. (Default: radians)
-
-    Variables can have any size and they are case sensitive (ie. "var",
-    "VAR" and "Var" are *different* variable names). Letters, digits and
-    underscores 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 'Vars' string. Function names are not legal variable names.
-
-    Using longer variable names causes no overhead whatsoever to the Eval()
-    method, so it's completely safe to use variable names of any size.
-
-    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.
-
-    Return values:
-    -On success the function returns -1.
-    -On error the function returns an index to where the error was found
-     (0 is the first character, 1 the second, etc). If the error was not
-     a parsing error returns an index to the end of the string + 1.
-
-    Example: parser.Parse("3*x+y", "x,y");
-
-
----------------------------------------------------------------------------
-const char* ErrorMsg(void) const;
----------------------------------------------------------------------------
-
-    Returns a pointer to an error message string corresponding to the error
-    caused by Parse() (you can use this to print the proper error message to
-    the user). If no such error has occurred, returns 0.
-
-
----------------------------------------------------------------------------
-ParseErrorType GetParseErrorType() const;
----------------------------------------------------------------------------
-
-    Returns the type of parse error which occurred.
-
-    This method can be used to get the error type if ErrorMsg() 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.
-
-    FunctionParser::ParseErrorType is an enumerated type inside the class
-    (ie. its values are accessed like "FunctionParser::SYNTAX_ERROR").
-
-    The possible values for FunctionParser::ParseErrorType are listed below,
-    along with their equivalent error message returned by the ErrorMsg()
-    method:
-
-FP_NO_ERROR        : If no error occurred in the previous call to Parse().
-SYNTAX_ERROR       : "Syntax error"
-MISM_PARENTH       : "Mismatched parenthesis"
-MISSING_PARENTH    : "Missing ')'"
-EMPTY_PARENTH      : "Empty parentheses"
-EXPECT_OPERATOR    : "Syntax error: Operator expected"
-OUT_OF_MEMORY      : "Not enough memory"
-UNEXPECTED_ERROR   : "An unexpected error occurred. Please make a full bug "
-                     "report to the author"
-INVALID_VARS       : "Syntax error in parameter 'Vars' given to "
-                     "FunctionParser::Parse()"
-ILL_PARAMS_AMOUNT  : "Illegal number of parameters to function"
-PREMATURE_EOS      : "Syntax error: Premature end of string"
-EXPECT_PARENTH_FUNC: "Syntax error: Expecting ( after function"
-
-
----------------------------------------------------------------------------
-double Eval(const double* Vars);
----------------------------------------------------------------------------
-
-    Evaluates the function given to Parse().
-    The array given as parameter must contain the same amount of values as
-    the amount of variables given to Parse(). Each value corresponds to each
-    variable, in the same order.
-
-    Return values:
-    -On success returns the evaluated value of the function given to
-     Parse().
-    -On error (such as division by 0) the return value is unspecified,
-     probably 0.
-
-    Example:
-
-      double Vars[] = {1, -2.5};
-      double result = parser.Eval(Vars);
-
-
----------------------------------------------------------------------------
-int EvalError(void) const;
----------------------------------------------------------------------------
-
-    Used to test if the call to Eval() succeeded.
-
-    Return values:
-      If there was no error in the previous call to Eval(), returns 0,
-      else returns a positive value as follows:
-        1: division by zero
-        2: sqrt error (sqrt of a negative value)
-        3: log error (logarithm of a negative value)
-        4: trigonometric error (asin or acos of illegal value)
-        5: maximum recursion level in eval() reached
-
-
----------------------------------------------------------------------------
-void Optimize();
----------------------------------------------------------------------------
-
-    This method can be called after calling the Parse() 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).
-
-      For example, the bytecode for the function "5+x*y-25*4/8" will be
-    reduced to a bytecode equivalent to the function "x*y-7.5" (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.
-
-      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 Optimize() 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 Optimize() will only
-    slow down the program.
-      Also, if the original function is expected to be optimal, then calling
-    Optimize() would be useless.
-
-      Note: Currently this method does not make any checks (like Eval() does)
-    and thus things like "1/0" will cause undefined behaviour. (On the other
-    hand, if such expression is given to the parser, Eval() 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 Eval() once before calling
-    Optimize() and checking EvalError().
-
-      If the destination application is not going to use this method,
-    the compiler constant SUPPORT_OPTIMIZER can be undefined in fpconfig.hh
-    to make the library smaller (Optimize() can still be called, but it will
-    not do anything).
-
-    (If you are interested in seeing how this method optimizes the opcode,
-    you can call the PrintByteCode() method before and after the call to
-    Optimize() to see the difference.)
-
-
----------------------------------------------------------------------------
-bool AddConstant(const std::string& name, double value);
----------------------------------------------------------------------------
-
-    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.
-
-      Constants used by a function must be added before calling Parse()
-    for that function. Constants are preserved between Parse() 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.)
-
-      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 Parse() is called. (That is, changing the value of a constant
-    after calling Parse() and before calling Eval() will have no effect.)
-
-      The return value will be false if the 'name' of the constant was
-    illegal, else true. If the name was illegal, the method does nothing.
-
-    Example: parser.AddConstant("pi", 3.1415926535897932);
-
-    Now for example parser.Parse("x*pi", "x"); will be identical to the
-    call parser.Parse("x*3.1415926535897932", "x");
-
-
----------------------------------------------------------------------------
-bool AddUnit(const std::string& name, double value);
----------------------------------------------------------------------------
-
-    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.
-
-      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. "5in" is the same as saying
-    "5*300" or "1500" (assuming "in" has been added as a unit with the
-    value 300).
-
-      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 "5/2in" is parsed as "5/(2*300)".
-    (If 5/2 inches is what one wants, it has to be written "(5/2)in".)
-
-      You can use the AddUnit() 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. "x in").
-    To change the value of a unit, call AddUnit() again with the same unit
-    name and the new value.
-
-      Note that units are independent from variables, constants and functions.
-    This means that a unit can have the same name as those (there isn't any
-    syntactical problem in that), thus for example "x x" is a valid function
-    if "x" is a variable or constant and "x" is a unit, although for the sake
-    of clarity that is usually not recommended.
-
-    Example: parser.AddUnit("in", 300);
-
-      Now for example the function "5in" will be identical to "(5*300)".
-    Other usage examples include "x in", "3in+2", "pow(x,2)in", "(x+2)in".
-
-
----------------------------------------------------------------------------
-bool AddFunction(const std::string& name,
-                 double (*functionPtr)(const double*),
-                 unsigned paramsAmount);
----------------------------------------------------------------------------
-
-    This method can be used to add new functions to the parser. For example,
-    if you would like to add a function "sqr(A)" which squares the value
-    of A, you can do it with this method (so that you don't need to touch
-    the source code of the parser).
-
-      The method takes three parameters:
-
-    - The name of the function. The name follows the same naming conventions
-      as variable names.
-
-    - 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:
-          double functionName(const double* params);
-
-    - 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 double* it gets as a parameter).
-
-    The return value will be false if the given name was invalid (either it
-    did not follow the variable naming conventions, or the name was already
-    reserved), else true. If the return value is false, nothing is added.
-
-    Example:
-    Suppose we have a C++ function like this:
-
-    double Square(const double* p)
-    {
-        return p[0]*p[0];
-    }
-
-    Now we can add this function to the parser like this:
-
-    parser.AddFunction("sqr", Square, 1);
-
-    parser.Parse("2*sqr(x)", "x");
-
-
-    An example of a useful function taking no parameters is a function
-    returning a random value. For example:
-
-    double Rand(const double*)
-    {
-        return drand48();
-    }
-
-    parser.AddFunction("rand", Rand, 0);
-
-
-    IMPORTANT NOTE: If you use the Optimize() 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 Rand() function given as example above is one such problematic case.)
-
-
----------------------------------------------------------------------------
-bool AddFunction(const std::string& name, FunctionParser&);
----------------------------------------------------------------------------
-
-    This method is almost identical to the previous AddFunction(), but
-    instead of taking a C++ function, it takes another FunctionParser
-    instance.
-
-    There are some important restrictions on making a FunctionParser instance
-    call another:
-
-    - The FunctionParser instance given as parameter must be initialized
-      with a Parse() call before giving it as parameter. That is, if you
-      want to use the parser A in the parser B, you must call A.Parse()
-      before you can call B.AddFunction("name", A).
-
-    - The amount of variables in the FunctionParser instance given as
-      parameter must not change after it has been given to the AddFunction()
-      of another instance. Changing the number of variables will result in
-      malfunction.
-
-    - AddFunction() will fail (ie. return false) if a recursive loop is
-      formed. The method specifically checks that no such loop is built.
-
-    Example:
-
-    FunctionParser f1, f2;
-    f1.Parse("x*x", "x");
-    f2.AddFunction("sqr", f1);
-
-    This version of the AddFunction() 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).
-
-
-
-
-=============================================================================
-  - About thread safety
-=============================================================================
-
-  None of the member functions of the FunctionParser class are thread-safe.
-Most prominently, the Eval() function is not thread-safe. (In other words,
-the Eval() function of a single FunctionParser instance cannot be safely
-called simultaneously by two threads.)
-
-  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 ForceDeepCopy() function on each of
-the instances of each thread after the assignment or copying has been done.
-
-  Another possibility is to compile the FunctionParser library so that
-its Eval() function will be thread-safe. (This can be done by defining
-the FP_USE_THREAD_SAFE_EVAL or the FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA
-precompiler constant.) As long as only one thread calls the other functions
-of FunctionParser, the other threads can safely call the Eval() of this
-one instance.
-  Note, however, that compiling the library like this can make Eval()
-slightly slower. (The alloca version, if supported by the compiler,
-will not be as slow.)
-
-
-=============================================================================
-  - The function string
-=============================================================================
-
-  The function string understood by the class is very similar to the C-syntax.
-  Arithmetic float expressions can be created from float literals, variables
-or functions using the following operators in this order of precedence:
-
-   ()             expressions in parentheses first
-   A unit         a unit multiplier (if one has been added)
-   A^B            exponentiation (A raised to the power B)
-   -A             unary minus
-   !A             unary logical not (result is 1 if int(A) is 0, else 0)
-   A*B  A/B  A%B  multiplication, division and modulo
-   A+B  A-B       addition and subtraction
-   A=B  A!=B  A<B  A<=B  A>B  A>=B
-                  comparison between A and B (result is either 0 or 1)
-   A&B            result is 1 if int(A) and int(B) differ from 0, else 0
-   A|B            result is 1 if int(A) or int(B) differ from 0, else 0
-
-    Since the unary minus has higher precedence than any other operator, for
-  example the following expression is valid: x*-y
-
-    The comparison operators use an epsilon value, so expressions which may
-  differ in very least-significant digits should work correctly. For example,
-  "0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 1" should always return 1, and
-  the same comparison done with ">" or "<" should always return 0.
-  (The epsilon value can be configured in the fpconfig.hh file.)
-  Without epsilon this comparison probably returns the wrong value.
-
-  The class supports these functions:
-
-  abs(A)    : Absolute value of A. If A is negative, returns -A otherwise
-              returns A.
-  acos(A)   : Arc-cosine of A. Returns the angle, measured in radians,
-              whose cosine is A.
-  acosh(A)  : Same as acos() but for hyperbolic cosine.
-  asin(A)   : Arc-sine of A. Returns the angle, measured in radians, whose
-              sine is A.
-  asinh(A)  : Same as asin() but for hyperbolic sine.
-  atan(A)   : Arc-tangent of (A). Returns the angle, measured in radians,
-              whose tangent is (A).
-  atan2(A,B): Arc-tangent of A/B. The two main differences to atan() is
-              that it will return the right angle depending on the signs of
-              A and B (atan() can only return values betwen -pi/2 and pi/2),
-              and that the return value of pi/2 and -pi/2 are possible.
-  atanh(A)  : Same as atan() but for hyperbolic tangent.
-  ceil(A)   : Ceiling of A. Returns the smallest integer greater than A.
-              Rounds up to the next higher integer.
-  cos(A)    : Cosine of A. Returns the cosine of the angle A, where A is
-              measured in radians.
-  cosh(A)   : Same as cos() but for hyperbolic cosine.
-  cot(A)    : Cotangent of A (equivalent to 1/tan(A)).
-  csc(A)    : Cosecant of A (equivalent to 1/sin(A)).
-  eval(...) : 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 if() to avoid
-              infinite recursion.
-  exp(A)    : 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.
-  floor(A)  : Floor of A. Returns the largest integer less than A. Rounds
-              down to the next lower integer.
-  if(A,B,C) : 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 eval() in them.
-  int(A)    : Rounds A to the closest integer. 0.5 is rounded to 1.
-  log(A)    : Natural (base e) logarithm of A.
-  log10(A)  : Base 10 logarithm of A.
-  max(A,B)  : If A>B, the result is A, else B.
-  min(A,B)  : If A<B, the result is A, else B.
-  sec(A)    : Secant of A (equivalent to 1/cos(A)).
-  sin(A)    : Sine of A. Returns the sine of the angle A, where A is
-              measured in radians.
-  sinh(A)   : Same as sin() but for hyperbolic sine.
-  sqrt(A)   : Square root of A. Returns the value whose square is A.
-  tan(A)    : Tangent of A. Returns the tangent of the angle A, where A
-              is measured in radians.
-  tanh(A)   : Same as tan() but for hyperbolic tangent.
-
-
-  Examples of function string understood by the class:
-
-  "1+2"
-  "x-1"
-  "-sin(sqrt(x^2+y^2))"
-  "sqrt(XCoord*XCoord + YCoord*YCoord)"
-
-  An example of a recursive function is the factorial function:
-
-  "if(n>1, n*eval(n-1), 1)"
-
-  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).
-
-  Also note that even though the maximum recursion level of eval() 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,
-  but you can disable the eval() function completely in the fpconfig.hh file.
-
-
-=============================================================================
-  - Contacting the author
-=============================================================================
-
-  Any comments, bug reports, etc. should be sent to warp@iki.fi
-
-
-=============================================================================
-  - The algorithm used in the library
-=============================================================================
-
-  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.
-
-  For example:
-
-  infix    postfix
-  2+3      2 3 +
-  1+2+3    1 2 + 3 +
-  5*2+8/2  5 2 * 8 2 / +
-  (5+9)*3  5 9 + 3 *
-
-  The postfix notation should be read in this way:
-
-  Let's take for example the expression: 5 2 * 8 2 / +
-  - Put 5 on the stack
-  - Put 2 on the stack
-  - Multiply the two values on the top of the stack and put the result on
-    the stack (removing the two old values)
-  - Put 8 on the stack
-  - Put 2 on the stack
-  - Divide the two values on the top of the stack
-  - 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).
-
-  At the end there's only one value in the stack, and that value is the
-result of the expression.
-
-  Why stack arithmetic?
-
-  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:
-    (x+1)/(y+2)
-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.
-
-  The most simple and efficient 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:
-    x 1 + y 2 + /
-
-  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.
-
-  This is what makes byte-coded stack arithmetic so fast.
-
-
-
-=============================================================================
-  Usage license:
-=============================================================================
-
-Copyright Â© 2003-2005 Juha Nieminen, Joel Yliluoma
-
-  This library is distributed under two distinct usage licenses depending
-on the software ("Software" below) which uses the Function Parser library
-("Library" below).
-  The reason for having two distinct usage licenses is to make the library
-compatible with the GPL license while still being usable in other non-GPL
-(even commercial) software.
-
-A) If the Software using the Library is distributed under the GPL license,
-   then the Library can be used under the GPL license as well.
-
-   The Library will be under the GPL license only when used with the
-   Software. If the Library is separated from the Software and used in
-   another different software under a different license, then the Library
-   will have the B) license below.
-
-   Exception to the above: If the Library is modified for the GPL Software,
-   then the Library cannot be used with the B) license without the express
-   permission of the author of the modifications. A modified library will
-   be under the GPL license by default. That is, only the original,
-   unmodified version of the Library can be taken to another software
-   with the B) license below.
-
-   The author of the Software should provide an URL to the original
-   version of the Library if the one used in the Software has been
-   modified. (http://iki.fi/warp/FunctionParser/)
-
-   This text file must be distributed in its original intact form along
-   with the sources of the Library. (Documentation about possible
-   modifications to the library should be put in a different text file.)
-
-B) If the Software using the Library is not distributed under the GPL
-   license but under any other license, then the following usage license
-   applies to the Library:
-
-  1. This library is free for non-commercial usage. You can do whatever you
-     like with it as long as you don't claim you made it yourself.
-
-  2. It is possible to use this library in a commercial program, but in this
-     case you MUST contact me first (warp@iki.fi) and ask express permission
-     for this. (Read explanation at the end of the file.)
-       If you are making a free program or a shareware program with just a
-     nominal price (5 US dollars or less), you don't have to ask for
-     permission.
-       In any case, I DON'T WANT MONEY for the usage of this library. It is
-     free, period.
-
-  3. You can make any modifications you want to it so that it conforms your
-     needs. If you make modifications to it, you have, of course, credits for
-     the modified parts.
-
-  4. If you use this library in your own program, you don't have to provide
-     the source code if you don't want to (ie. the source code of your program
-     or this library).
-       If you DO include the source code for this library, this text file
-     must be included in its original intact form.
-
-  5. If you distribute a program which uses this library, and specially if you
-     provide the source code, proper credits MUST be included. Trying to
-     obfuscate the fact that this library is not made by you or that it is
-     free is expressly prohibited. When crediting the usage of this library,
-     it's enough to include my name and email address, that is:
-     "Juha Nieminen (warp@iki.fi)". Also a URL to the library download page
-     would be nice, although not required. The official URL is:
-       http://iki.fi/warp/FunctionParser/
-
-  6. And the necessary "lawyer stuff":
-
-     The above copyright notice and this permission notice shall be
-     included in all copies or substantial portions of the Software.
-
-     The software is provided "as is", without warranty of any kind,
-     express or implied, including but not limited to the warranties of
-     merchantability, fitness for a particular purpose and noninfringement.
-     In no event shall the authors or copyright holders be liable for any
-     claim, damages or other liability, whether in an action of contract,
-     tort or otherwise, arising from, out of or in connection with the
-     software or the use or other dealings in the software.
-
-
----  Explanation of the section 2 of the B) license above:
-
-  The section 2 tries to define "fair use" of the library in commercial
-programs.
-  "Fair use" of the library means that the program is not heavily dependent
-on the library, but the library only provides a minor secondary feature
-to the program.
-  "Heavily dependent" means that the program depends so much on the library
-that without it the functionality of the program would be seriously
-degraded or the program would even become completely non-functional.
-
-  In other words: If the program does not depend heavily on the library,
-that is, the library only provides a minor secondary feature which could
-be removed without the program being degraded in any considerable way,
-then it's OK to use the library in the commercial program.
-  If, however, the program depends so heavily on the library that
-removing it would make the program non-functional or degrade its
-functionality considerably, then it's NOT OK to use the library.
-
-  The ideology behind this is that it's not fair to use a free library
-as a base for a commercial program, but it's fair if the library is
-just a minor, unimportant extra.
-
-  If you are going to ask me for permission to use the library in a
-commercial program, please describe the feature which the library will
-be providing and how important it is to the program.
diff --git a/deal.II/contrib/functionparser/fparser_gmpint.hh b/deal.II/contrib/functionparser/fparser_gmpint.hh
new file mode 100644 (file)
index 0000000..fdb4450
--- /dev/null
@@ -0,0 +1,15 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* 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/deal.II/contrib/functionparser/fparser_mpfr.hh b/deal.II/contrib/functionparser/fparser_mpfr.hh
new file mode 100644 (file)
index 0000000..443ec96
--- /dev/null
@@ -0,0 +1,15 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* 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/deal.II/contrib/functionparser/fpconfig.h b/deal.II/contrib/functionparser/fpconfig.h
deleted file mode 100644 (file)
index 1eda03e..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-//===============================
-// Function parser v2.83 by Warp
-//===============================
-
-// 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".
-
-/*
- Comment out the following line if your compiler supports the (non-standard)
- asinh, acosh and atanh functions and you want them to be supported. If
- you are not sure, just leave it (those function will then not be supported).
-*/
-#define NO_ASINH
-
-
-/*
- Uncomment the following line to disable the eval() function if it could
- be too dangerous in the target application.
- Note that even though the maximum recursion level of eval() is limited,
- it is still possible to write functions using it which take enormous
- amounts of time to evaluate even though the maximum recursion is never
- reached. This may be undesirable in some applications.
-*/
-//#define DISABLE_EVAL
-
-
-/*
- Maximum recursion level for eval() calls:
-*/
-#define EVAL_MAX_REC_LEVEL 1000
-
-
-/*
- 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 NO_SUPPORT_OPTIMIZER
-#define SUPPORT_OPTIMIZER
-#endif
-
-
-/*
- Epsilon value used with the comparison operators (must be non-negative):
- (Comment it out if you don't want to use epsilon in comparisons. Might
- lead to marginally faster evaluation of the comparison operators, but
- can introduce inaccuracies in comparisons.)
-*/
-#define FP_EPSILON 1e-14
-
-
-/*
- No member function of FunctionParser is thread-safe. Most prominently,
- Eval() is not thread-safe. By uncommenting one of these lines the Eval()
- function can be made thread-safe at the cost of a possible small overhead.
- The second version requires that the compiler supports the alloca() function,
- which is not standard, but is faster.
- */
-//#define FP_USE_THREAD_SAFE_EVAL
-//#define FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA
diff --git a/deal.II/contrib/functionparser/fpconfig.hh b/deal.II/contrib/functionparser/fpconfig.hh
new file mode 100644 (file)
index 0000000..e729a12
--- /dev/null
@@ -0,0 +1,82 @@
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* 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
+
+/*
+ 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
index 66207296c4032748e77e7eb7103624bbcc75c1fd..7c41f511ca9f28f0155d94e9b580f13d8cf0351d 100644 (file)
-//============================================
-// Function parser v2.82 optimizer by Bisqwit
-//============================================
-
-/*
- NOTE!
- ----
- Everything that goes into the #ifndef SUPPORT_OPTIMIZER part
- (ie. when SUPPORT_OPTIMIZER is not defined) should be put in
- the end of fparser.cc file, not in this file.
-
- Everything in this file should be inside the #ifdef SUPPORT_OPTIMIZER
- block (except the #include "fpconfig.h" line).
+/***************************************************************************\
+|* Function Parser for C++ v4.5                                            *|
+|*-------------------------------------------------------------------------*|
+|* 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.h"
-
-#ifdef SUPPORT_OPTIMIZER
-
-#include "fparser.h"
-#include "fptypes.h"
-using namespace FUNCTIONPARSERTYPES;
-
-#include <cmath>
-#include <list>
+#include "fpconfig.hh"
+#ifdef FP_SUPPORT_OPTIMIZER
+#include "fparser.hh"
+#include "extrasrc/fptypes.hh"
+#include "extrasrc/fpaux.hh"
+#define l64 y91 a),
+#define l54 if(n5 iK3
+#define l44 ,{ReplaceParams,
+#define l34 cTan iO
+#define l24 "Found "
+#define l14 ,cPow,
+#define l04 stackpos
+#define iZ3 sim.nY 1,
+#define iY3 ,tree,info
+#define iX3 "dup(%u) "
+#define iW3 "%d, cost "
+#define iV3 "PUSH "i13(
+#define iU3 "immed "<<
+#define iT3 mFuncParsers
+#define iS3 e62{assert
+#define iR3 stderr
+#define iQ3 sep2=" "
+#define iP3 FPHASH_CONST
+#define iO3 .SetParamsMove(
+#define iN3 cache_needed[
+#define iM3 fprintf
+#define iL3 ::cout<<"Applying "
+#define iK3 HANDLE_UNARY_CONST_FUNC
+#define iJ3 1)i61){
+#define iI3 c_count
+#define iH3 s_count
+#define iG3 2)lS 2*
+#define iF3 tmp.yH1
+#define iE3 tmp2.nJ
+#define iD3 ,tZ 2,
+#define iC3 (p0 n51&&
+#define iB3 else nM
+#define iA3 max.val
+#define i93 eK2 if(
+#define i83 tree c9
+#define i73 sim.x61
+#define i63 ].swap(
+#define i53 codes[b
+#define i43 whydump
+#define i33 );}case
+#define i23 :if(eQ3
+#define i13 ;DumpTree
+#define i03 :{lX1 r
+#define tZ3 nparams
+#define tY3 cLog iO
+#define tX3 l4 16,1,
+#define tW3 l4 0,1,
+#define tV3 0x12 nH
+#define tU3 ,0,0x16},{
+#define tT3 nQ 0,
+#define tS3 cAbs nQ
+#define tR3 false;}
+#define tQ3 nE1 cF1
+#define tP3 xF1++b)
+#define tO3 =false;
+#define tN3 {data->
+#define tM3 info.
+#define tL3 b.Value)
+#define tK3 b.Opcode
+#define tJ3 ,tB info
+#define tI3 tree xD
+#define tH3 xD cMul);
+#define tG3 ParamHolder
+#define tF3 size()
+#define tE3 .second
+#define tD3 ]tE3
+#define tC3 ].first
+#define tB3 Ne_Mask
+#define tA3 Gt_Mask
+#define t93 Lt_Mask
+#define t83 opcode,
+#define t73 resize(
+#define t63 t33 nC1;
+#define t53 xD cond nC
+#define t43 );}else
+#define t33 lE2 a)
+#define t23 AddFrom(
+#define t13 max.known
+#define t03 =fp_pow(
+#define eZ3 (tree)!=
+#define eY3 );if(
+#define eX3 public:
+#define eW3 pclone
+#define eV3 Others
+#define eU3 --cN1.
+#define eT3 cOr,l6
+#define eS3 newpow
+#define eR3 if(p0 yN
+#define eQ3 &*(*x5 n71){
+#define eP3 ,lT 1,0,
+#define eO3 lE2 1)
+#define eN3 (op1==
+#define eM3 change
+#define eL3 (count
+#define eK3 133,2,
+#define eJ3 Needs
+#define eI3 byteCode
+#define eH3 (p1 nC1
+#define eG3 lS1 nC==
+#define eF3 cLog2by
+#define eE3 factor_t
+#define eD3 (*x5)[0].info
+#define eC3 tree nC1
+#define eB3 value1
+#define eA3 Finite
+#define e93 fp_mod(
+#define e83 )const
+#define e73 (e83{
+#define e63 else{if(
+#define e53 xK());nD
+#define e43 TreeCountItem
+#define e33 if(op==
+#define e23 yN val)<
+#define e13 p yN val
+#define e03 c9 ifp2
+#define cZ3 cAbsNot
+#define cY3 stackptr
+#define cX3 cLog);xL
+#define cW3 switch(tM
+#define cV3 p1 cK p1);
+#define cU3 );p1 c9 ifp1
+#define cT3 .empty()
+#define cS3 opcodes
+#define cR3 did_muli
+#define cQ3 xD data.
+#define cP3 &Value){
+#define cO3 yH const
+#define cN3 used[b]
+#define cM3 sizeof(
+#define cL3 cAbsIf,
+#define cK3 cNotNot,
+#define cJ3 18,2 eN1
+#define cI3 c22 iE,
+#define cH3 450998,
+#define cG3 cAtan2,
+#define cF3 cExp2 nQ
+#define cE3 lJ 2},0,
+#define cD3 middle2
+#define cC3 ::string
+#define cB3 fp_equal(
+#define cA3 ;if(cB3
+#define c93 (iE2 l8 1)xC1
+#define c83 FP_GetOpcodeName(
+#define c73 default:
+#define c63 n31;case
+#define c53 tG));nV
+#define c43 range nJ3
+#define c33 range<yN2
+#define c23 range xK
+#define c13 Ge0Lt1
+#define c03 Gt0Le1
+#define yZ3 cAdd lS2
+#define yY3 ==cOr tE2
+#define yX3 IsLogicalValue y91
+#define yW3 cAbsIf)
+#define yV3 iterator
+#define yU3 begin();
+#define yT3 TreeSet
+#define yS3 parent
+#define yR3 insert(i
+#define yQ3 newrel
+#define yP3 for iJ nS
+#define yO3 ;tree tK2
+#define yN3 ;nV l5::
+#define yM3 ;for iA1 a=
+#define yL3 param.
+#define yK3 &param=*
+#define yJ3 break;l73
+#define yI3 xE lT 2,
+#define yH3 ;}static yU1
+#define yG3 ::ByteCodeSynth xK
+#define yF3 break;}
+#define yE3 synth lO2
+#define yD3 synth.xM
+#define yC3 b_needed
+#define yB3 cachepos
+#define yA3 half=
+#define y93 ,iB,1,l51+1);
+#define y83 131,4,1,
+#define y73 131,8,1,
+#define y63 4,1,2,1,
+#define y53 )n31 lH
+#define y43 ,1,562 nP
+#define y33 ){case
+#define y23 (yL3
+#define y13 ){switch(
+#define y03 (cond yV
+#define xZ3 {i31 lE
+#define xY3 template lL
+#define xX3 iY2 tF3
+#define xW3 template lX
+#define xV3 ::vector
+#define xU3 FindPos(
+#define xT3 src_pos
+#define xS3 reserve(
+#define xR3 nJ1 void
+#define xQ3 treeptr
+#define xP3 tA1 void
+#define xO3 ImmedTag
+#define xN3 a,const
+#define xM3 RefCount
+#define xL3 Birth();
+#define xK3 typename
+#define xJ3 7168,
+#define xI3 cost_t
+#define xH3 fpdata
+#define xG3 middle
+#define xF3 };enum
+#define xE3 tG1 1))){
+#define xD3 sqrt_cost
+#define xC3 const int
+#define xB3 maxValue1
+#define xA3 minValue1
+#define x93 maxValue0
+#define x83 minValue0
+#define x73 ValueType
+#define x63 yN n3 0),
+#define x53 =true;lI2
+#define x43 yK known
+#define x33 yK n3 0),
+#define x23 abs_mul
+#define x13 l8 a));
+#define x03 pos_set
+#define nZ3 ContainsOtherCandidates
+#define nY3 goto cY
+#define nX3 l14 xV1
+#define nW3 t2=!t2;}
+#define nV3 bool t2 tO3
+#define nU3 (yK val)
+#define nT3 result
+#define nS3 .tL1 n]
+#define nR3 1)tG1 1));
+#define nQ3 nT3 yN known
+#define nP3 nT3 n51
+#define nO3 ),child);
+#define nN3 mulgroup)
+#define nM3 nP3 tO3 if(
+#define nL3 nT3 yN val
+#define nK3 nT3 tF2
+#define nJ3 xK nT3
+#define nI3 const std::eT
+#define nH3 const char*
+#define nG3 nE3 IsNever nV2
+#define nF3 nE3 IsAlways;if(
+#define nE3 ))return
+#define nD3 y3 cAdd);
+#define nC3 subtree
+#define nB3 invtree
+#define nA3 MakeHash(
+#define n93 yR false;
+#define n83 rulenumit
+#define n73 cAnd l3
+#define n63 282870 nP
+#define n53 ,tree nX
+#define n43 ,1,538 nP
+#define n33 cAnd,l6
+#define n23 MakeEqual
+#define n13 MakeTrue,
+#define n03 newbase
+#define lZ3 branch1op
+#define lY3 branch2op
+#define lX3 overlap
+#define lW3 nE1 c9 y6
+#define lV3 truth_b
+#define lU3 truth_a
+#define lT3 if y91 0)
+#define lS3 found_dup
+#define lR3 (mulgroup
+#define lQ3 cH1 eJ&
+#define lP3 rangeutil
+#define lO3 Plan_Has(
+#define lN3 StackMax)
+#define lM3 ;if(half
+#define lL3 ;}void
+#define lK3 cGreater,
+#define lJ3 ,cGreater
+#define lI3 )lL3
+#define lH3 nT3 xQ
+#define lG3 const xA2
+#define lF3 namespace
+#define lE3 ByteCode[
+#define lD3 inverted
+#define lC3 IsNever:
+#define lB3 .known&&
+#define lA3 ==cNot||
+#define l93 iftree
+#define l83 if(i01==
+#define l73 }switch(
+#define l63 depcodes
+#define l53 explicit
+#define l43 l2 16 eI
+#define l33 l91 2,1,
+#define l23 cCosh nQ
+#define l13 n91 1,
+#define l03 VarBegin
+#define iZ2 Params[a].
+#define iY2 Params.
+#define iX2 ].data);
+#define iW2 PlusInf
+#define iV2 Value_t
+#define iU2 ;iV2
+#define iT2 (nT3
+#define iS2 synth);
+#define iR2 lJ2 apos==
+#define iQ2 default_function_handling
+#define iP2 xD i01);
+#define iO2 tE3)
+#define iN2 begin(),
+#define iM2 cond_add
+#define iL2 cond_mul
+#define iK2 cond_and
+#define iJ2 ){eJ r;r xD
+#define iI2 func lL1
+#define iH2 const eH
+#define iG2 bool eA1
+#define iF2 unsigned
+#define iE2 leaf1
+#define iD2 costree
+#define iC2 sintree
+#define iB2 leaf_count
+#define iA2 sub_params
+#define i92 tG1-1)))xC
+#define i82 printf(
+#define i72 swap(tmp);
+#define i62 cbrt_count
+#define i52 sqrt_count
+#define i42 ,std::cout
+#define i32 pcall_tree
+#define i22 after_powi
+#define i12 GetHash().
+#define i02 *x5 n71,info
+#define tZ2 eQ1=0;a eX2
+#define tY2 eQ1;if t51
+#define tX2 grammar
+#define tW2 cCos iO
+#define tV2 l14 l2 0,2,
+#define tU2 cEqual eW1
+#define tT2 0x12},{{3,
+#define tS2 cNeg,lT 1,
+#define tR2 ,bool abs)
+#define tQ2 sim.Eat(
+#define tP2 .what nU1
+#define tO2 tJ2 nT3(
+#define tN2 ,n42 l2 c22
+#define tM2 if y91 1)i61&&
+#define tL2 ;range.xE2
+#define tK2 .DelParam(
+#define tJ2 ){iV2
+#define tI2 nR tJ2 tmp=
+#define tH2 );nD lC
+#define tG2 iC3 p0 tF2>=x22
+#define tF2 .min.val
+#define tE2 )?0:1))l7
+#define tD2 .n_int_sqrt
+#define tC2 ;}else{x5=new
+#define tB2 (half&63)-1;
+#define tA2 ),0},{
+#define t92 ),Value
+#define t82 data;data.
+#define t72 MakeNEqual
+#define t62 (exponent
+#define t52 Dump(std::
+#define t42 isInteger(
+#define t32 Comparison
+#define t22 needs_flip
+#define t12 value]
+#define t02 ~size_t(0)
+#define eZ2 xJ1 xS+1);
+#define eY2 TopLevel)
+#define eX2 <xV;++a)
+#define eW2 }}return
+#define eV2 vector<bool>
+#define eU2 *)&*start_at;
+#define eT2 Rule&rule,
+#define eS2 >::res,b8<
+#define eR2 continue;}
+#define eQ2 c9 tree);
+#define eP2 mul_item
+#define eO2 innersub
+#define eN2 cbrt_cost
+#define eM2 best_cost
+#define eL2 fp_min(yL
+#define eK2 tree t31);}
+#define eJ2 tree))cZ
+#define eI2 condition
+#define eH2 per_item
+#define eG2 item_type
+#define eF2 first2
+#define eE2 l4 18,1,
+#define eD2 lJ 1},0,
+#define eC2 Decision
+#define eB2 not_tree
+#define eA2 group_by
+#define e92 exponent=
+#define e82 ->second
+#define e72 :xL iV2(
+#define e62 eJ&tree)
+#define e52 targetpos
+#define e42 ParamSpec
+#define e32 rhs.hash2;}
+#define e22 rhs.hash1
+#define e12 struct
+#define e02 Forget()
+#define cZ2 &&cond e8))
+#define cY2 source_tree
+#define cX2 nC==cLog2&&
+#define cW2 ,eL1 0x1 nH
+#define cV2 )lS 3*3*
+#define cU2 (tK==eA3&&
+#define cT2 );yF3
+#define cS2 ;iB.Remember(
+#define cR2 <tW,xI3>
+#define cQ2 );sim.nY 2,
+#define cP2 )continue
+#define cO2 CodeTree lW
+#define cN2 p1_evenness
+#define cM2 isNegative(
+#define cL2 yN known&&(
+#define cK2 neg_set
+#define cJ2 cNop,cNop}}
+#define cI2 cTanh,cNop,
+#define cH2 NewHash
+#define cG2 >e12 cA<
+#define cF2 matches
+#define cE2 .match_tree
+#define cD2 cH1 void*)&
+#define cC2 cSin iO
+#define cB2 cTan nQ
+#define cA2 ,cLog nQ
+#define c92 cCos nQ
+#define c82 long value
+#define c72 (std::move(
+#define c62 (xX l8 a)xF
+#define c52 negated
+#define c42 Specializer
+#define c32 params
+#define c22 18,2,
+#define c12 coshtree
+#define c02 sinhtree
+#define yZ2 best_score
+#define yY2 mulvalue
+#define yX2 pow_item
+#define yW2 subgroup
+#define yV2 nC==cPow&&tO
+#define yU2 PowiResult
+#define yT2 ))y53
+#define yS2 0));c23
+#define yR2 maxValue
+#define yQ2 minValue
+#define yP2 div_tree
+#define yO2 pow_tree
+#define yN2 iV2 nT
+#define yM2 preserve
+#define yL2 PullResult()
+#define yK2 dup_or_fetch
+#define yJ2 nominator]
+#define yI2 test_order
+#define yH2 parampair
+#define yG2 yH2,
+#define yF2 .param_count
+#define yE2 minimum_need
+#define yD2 shift(index)
+#define yC2 {std::cout<<
+#define yB2 rulenumber
+#define yA2 l2 16,2,
+#define y92 cTanh nQ
+#define y82 l14 l2 2,2,
+#define y72 ,cPow iO
+#define y62 cSinh nQ
+#define y52 cIf,n91 3,
+#define y42 cInv,lT 1,
+#define y32 constraints=
+#define y22 GetDepth()
+#define y12 factor_immed
+#define y02 changes
+#define xZ2 c9 cond l8
+#define xY2 Become y91
+#define xX2 for(xK3
+#define xW2 exp_diff
+#define xV2 ExponentInfo
+#define xU2 lower_bound(
+#define xT2 factor
+#define xS2 is_logical
+#define xR2 newrel_and
+#define xQ2 )){data x7 lN
+#define xP2 Suboptimal
+#define xO2 eK[c eA
+#define xN2 res_stackpos
+#define xM2 half_pos
+#define xL2 ifdata.ofs
+#define xK2 i8 push_back(
+#define xJ2 n31 true;}
+#define xI2 >>1)):(
+#define xH2 CodeTreeData
+#define xG2 exponent)
+#define xF2 yN known)
+#define xE2 multiply(
+#define xD2 )y3 cPow)
+#define xC2 var_trees
+#define xB2 nB OPCODE
+#define xA2 CodeTree&
+#define x92 parent_opcode
+#define x82 GetParam(a eS
+#define x72 {cW start_at;
+#define x62 changed=true;
+#define x52 log2_exponent
+#define x42 iV2(2)));
+#define x32 lR,tH)tH2
+#define x22 iV2(0.0))
+#define x12 dup_fetch_pos
+#define x02 IsNever cL lC
+#define nZ2 cSin nQ
+#define nY2 Value_EvenInt
+#define nX2 AddCollection
+#define nW2 ConditionType
+#define nV2 n31 Unknown;}
+#define nU2 1 y7 i8 size(
+#define nT2 (iF2
+#define nS2 iA|nT2)
+#define nR2 SpecialOpcode
+#define nQ2 =i e82.
+#define nP2 yN known&&p
+#define nO2 assimilated
+#define nN2 denominator
+#define nM2 fraction
+#define nL2 DUP_BOTH();
+#define nK2 0x80000000u
+#define nJ2 IsDescendantOf
+#define nI2 TreeCounts
+#define nH2 SetOpcode(
+#define nG2 found_log2
+#define nF2 div_params
+#define nE2 immed_sum
+#define nD2 lE3++IP]
+#define nC2 sim n92
+#define nB2 ;sim.Push(
+#define nA2 ,cMul l3
+#define n92 .Eat(1,
+#define n82 OPCODE(opcode)
+#define n72 FactorStack xK
+#define n62 Rehash(false);
+#define n52 IsAlways cL lC
+#define n42 cEqual,
+#define n32 cNotNot nQ
+#define n22 cNot nQ
+#define n12 DumpHashesFrom
+#define n02 replacing_slot
+#define lZ2 RefParams
+#define lY2 if_always[
+#define lX2 WhatDoWhenCase
+#define lW2 exponent_immed
+#define lV2 new_base_immed
+#define lU2 base_immed
+#define lT2 );std::cout<<
+#define lS2 ||op1==
+#define lR2 l8 0));
+#define lQ2 data[a tD3
+#define lP2 if(newrel_or==
+#define lO2 .AddOperation(
+#define lN2 DUP_ONE(apos);
+#define lM2 flipped
+#define lL2 .UseGetNeeded(
+#define lK2 ,fp_max(yL);
+#define lJ2 else if(
+#define lI2 lJ2!nT3
+#define lH2 synth.PushImmed(
+#define lG2 (*x5)[a].info
+#define lF2 ,PowiCache&iB,
+#define lE2 tree l8
+#define lD2 <<tree.i12
+#define lC2 const eJ&
+#define lB2 ,l1 0x0},{{3,
+#define lA2 ,0,0x4},{{1,
+#define l92 {case IsAlways:
+#define l82 e3 2,131,
+#define l72 (IfData&ifdata
+#define l62 [xS-1-offset].
+#define l52 lE3 a
+#define l42 Immed.tF3);
+#define l32 OptimizedUsing
+#define l22 Var_or_Funcno
+#define l12 l22;
+#define l02 GetParams(
+#define iZ1 crc32_t
+#define iY1 signed_chain
+#define iX1 MinusInf
+#define iW1 n_immeds
+#define iV1 stack.tF3
+#define iU1 FindClone(xI
+#define iT1 lE3 IP]
+#define iS1 GetOpcode())
+#define iR1 needs_rehash
+#define iQ1 AnyWhere_Rec
+#define iP1 ~iF2(0)
+#define iO1 41,42,43,44,
+#define iN1 p1_logical_b
+#define iM1 p0_logical_b
+#define iL1 p1_logical_a
+#define iK1 p0_logical_a
+#define iJ1 *const func)
+#define iI1 synth.DoDup(
+#define iH1 cache_needed
+#define iG1 e3 2,1,e3 2,
+#define iF1 treelist
+#define iE1 has_bad_balance
+#define iD1 {if(GetOpcode()
+#define iC1 if(remaining[a])
+#define iB1 (*x5 n71=r.specs;if(r.found){
+#define iA1 (size_t
+#define i91 }yF3 case
+#define i81 for iA1 b=0;b<
+#define i71 for iA1 a y0
+#define i61 .IsImmed()
+#define i51 i61){if(
+#define i41 eE3 xT2
+#define i31 template<
+#define i21 divgroup
+#define i11 2*2*2)lS 3
+#define i01 tree nC
+#define tZ1 xW3 void
+#define tY1 yD3 1
+#define tX1 ,iB,eU,iS2
+#define tW1 fp_abs(iA3))
+#define tV1 fp_abs(min.val)
+#define tU1 tJ 2},0,0x0},{{
+#define tT1 Oneness_NotOne|
+#define tS1 Value_IsInteger
+#define tR1 Constness_Const
+#define tQ1 ;xI iO3
+#define tP1 l32(
+#define tO1 reltype
+#define tN1 SequenceOpcodes
+#define tM1 synth.Find(
+#define tL1 sep_list[
+#define tK1 TreeCountType xK
+#define tJ1 nI2.erase(cs_it);
+#define tI1 nE3 true
+#define tH1 yK set(fp_floor);
+#define tG1 ,iV2(
+#define tF1 );exponent
+#define tE1 back().thenbranch
+#define tD1 grammar_rules[*r]
+#define tC1 goto fail;}
+#define tB1 l1 0x4 nH
+#define tA1 lZ2);
+#define t91 IsDefined()){
+#define t81 eJ tmp;tmp xD
+#define t71 >(iV2(1),
+#define t61 x22{xO
+#define t51 (&*start_at){x5=(
+#define t41 DelParam(a);}
+#define t31 tK2 a
+#define t21 a)i61)
+#define t11 n82);
+#define t01 0.5)xD2;lC
+#define eZ1 std::cout<<"POP "
+#define eY1 stack[iV1-
+#define eX1 stack.push_back(
+#define eW1 ,l0 2,
+#define eV1 CollectionSet xK
+#define eU1 xK())y3 cMul);lC
+#define eT1 .Rehash();
+#define eS1 ParsePowiMuli
+#define eR1 MaxChildDepth
+#define eQ1 iF2 a
+#define eP1 std::pair<It,It>
+#define eO1 cLess,l2
+#define eN1 ,n63 281856,
+#define eM1 cNEqual,
+#define eL1 cPow,lA
+#define eK1 Sign_Negative
+#define eJ1 Value_Logical
+#define eI1 yD MakeFalse,{l5
+#define eH1 new_factor_immed
+#define eG1 occurance_pos
+#define eF1 exponent_hash
+#define eE1 exponent_list
+#define eD1 CollectMulGroup(
+#define eC1 source_set
+#define eB1 exponent,yT3
+#define eA1 operator
+#define e91 FindAndDup(tree);
+#define e81 ParamSpec_Extract
+#define e71 retry_anyparams_3
+#define e61 retry_anyparams_2
+#define e51 needlist_cached_t
+#define e41 lJ 2}lA2
+#define e31 lJ 1}lA2
+#define e21 CodeTreeImmed xK(
+#define e11 by_float_exponent
+#define e01 fp_equal t62
+#define cZ1 new_exp
+#define cY1 end()&&i->first==
+#define cX1 return BecomeZero;
+#define cW1 return BecomeOne;
+#define cV1 if(lQ.tF3<=n1)
+#define cU1 addgroup
+#define cT1 found_log2by
+#define cS1 nC==cZ3)
+#define cR1 if(keep_powi
+#define cQ1 l22)
+#define cP1 branch1_backup
+#define cO1 branch2_backup
+#define cN1 NeedList
+#define cM1 tree.SetParam(
+#define cL1 exponent_map
+#define cK1 plain_set
+#define cJ1 rangehalf
+#define cI1 ;synth.StackTopIs(
+#define cH1 (const
+#define cG1 cH1 iV2&
+#define cF1 eT1 tI3 op1);tree.DelParams()
+#define cE1 .GetParamCount()==
+#define cD1 LightWeight(
+#define cC1 if(value
+#define cB1 xW3 yX
+#define cA1 xW3 static
+#define c91 m yN set(fp_ceil);tV
+#define c81 m yN val
+#define c71 m yN known
+#define c61 )yH2 tE3;
+#define c51 ::MakeTrue
+#define c41 should_regenerate=true;
+#define c31 should_regenerate,
+#define c21 Collection
+#define c11 RelationshipResult
+#define c01 Subdivide_Combine(
+#define yZ1 e83 yR
+#define yY1 rhs yZ1 hash1
+#define yX1 PositionalParams,0
+#define yW1 best_sep_factor
+#define yV1 needlist_cached
+#define yU1 inline iF2
+#define yT1 252421 nP 24830
+#define yS1 t83 bool pad
+#define yR1 MakesInteger(
+#define yQ1 mulgroup.
+#define yP1 .AddParamMove(
+#define yO1 =comp.AddItem(atree
+#define yN1 tree i61 cL
+#define yM1 ByteCodeSynth xK&synth)
+#define yL1 lF3 FPoptimizer_Optimize
+#define yK1 (long double)
+#define yJ1 const iV2&value
+#define yI1 best_sep_cost
+#define yH1 AddParamMove(tree);
+#define yG1 MultiplicationRange
+#define yF1 pihalf_limits
+#define yE1 n_stacked
+#define yD1 cH2.hash1
+#define yC1 AnyParams_Rec
+#define yB1 ):e2(),std xV3<
+#define yA1 i13 cJ
+#define y91 (lE2
+#define y81 Become(value l8 0))
+#define y71 always_sincostan
+#define y61 Recheck_RefCount_Div
+#define y51 Recheck_RefCount_Mul
+#define y41 mulgroup;mulgroup xD
+#define y31 MultiplyAndMakeLong(
+#define y21 iV2(0)
+#define y11 covers_plus1
+#define y01 if(synth.FindAndDup(
+#define xZ1 SynthesizeParam(
+#define xY1 grammar_func
+#define xX1 cOr l3 16,1,
+#define xW1 252180 nP 281854
+#define xV1 l2 0,2,165888 nP
+#define xU1 l1 tV3
+#define xT1 Modulo_Radians},
+#define xS1 PositionType
+#define xR1 CollectionResult
+#define xQ1 ;m yN template set_if<
+#define xP1 ByteCode,size_t&IP,size_t limit,size_t y1
+#define xO1 iT2))break;nT3*=
+#define xN1 xW3 bool
+#define xM1 const_offset
+#define xL1 inline TriTruthValue
+#define xK1 stacktop_desired
+#define xJ1 SetStackTop(
+#define xI1 }inline
+#define xH1 FPoptimizer_ByteCode
+#define xG1 1)?(poly^(
+#define xF1 GetParamCount();
+#define xE1 public e2,public std xV3<
+#define xD1 y21)
+#define xC1 xF leaf2 l8
+#define xB1 c22 529654 nP
+#define xA1 cond_type
+#define x91 fphash_value_t
+#define x81 Recheck_RefCount_RDiv
+#define x71 cMul);tmp.nJ 0));tmp.
+#define x61 SwapLastTwoInStack();
+#define x51 fPExponentIsTooLarge(
+#define x41 CollectMulGroup_Item(
+#define x31 pair<iV2,yT3>
+#define x21 nL xJ1 xS-1);
+#define x11 covers_full_cycle
+#define x01 AssembleSequence(
+#define nZ1 <<std::dec<<")";}
+#define nY1 yD MakeNotP1,l5::
+#define nX1 yD MakeNotP0,l5::
+#define nW1 {DataP slot_holder(xY[
+#define nV1 :return p tF2
+#define nU1 !=xB)if(TestCase(
+#define nT1 &&IsLogicalValue(
+#define nS1 std::pair<T1,T2>&
+#define nR1 i31 xK3
+#define nQ1 has_good_balance_found
+#define nP1 n_occurrences
+#define nO1 found_log2_on_exponent
+#define nN1 covers_minus1
+#define nM1 needs_resynth
+#define nL1 immed_product
+#define nK1 ,2,1 xN if(found[data.
+#define nJ1 ;xW3
+#define nI1 yJ3 bitmask&
+#define nH1 Sign_Positive
+#define nG1 SetParamMove(
+#define nF1 CodeTreeImmed(iV2(
+#define nE1 changed_if
+#define nD1 0,xG2;DelParam(1);
+#define nC1 .GetImmed()
+#define nB1 for iA1 a=0;a<c8++a)
+#define nA1 iF2 index
+#define n91 lA 0x4},{{
+#define n81 iI1 found[data.
+#define n71 )[a].start_at
+#define n61 ,cIf,l0 3,
+#define n51 .min.known
+#define n41 .xF1 a-->0;)if(
+#define n31 ;return
+#define n21 n31 xP2;}
+#define n11 >::Optimize(){}
+#define n01 n_as_tanh_param
+#define lZ1 opposite=
+#define lY1 x91(
+#define lX1 MatchResultType
+#define lW1 needs_sincos
+#define lV1 resulting_exponent
+#define lU1 val):Value(Value::
+#define lT1 Unknown:c73;}
+#define lS1 GetParam(a)
+#define lR1 inverse_nominator]
+#define lQ1 cMul l3 0,1,
+#define lP1 tree yP1
+#define lO1 AddFunctionOpcode(
+#define lN1 SetParams(l02));
+#define lM1 o<<"("<<std::hex<<data.
+#define lL1 (val);else*this=model;}
+#define lK1 IfBalanceGood(
+#define lJ1 n_as_tan_param
+#define lI1 changed_exponent
+#define lH1 &&e13<iV2(
+#define lG1 inverse_denominator
+#define lF1 ;cH2.hash2+=
+#define lE1 xK(rule.repl_param_list,
+#define lD1 retry_positionalparams_2
+#define lC1 situation_flags&
+#define lB1 518 nP 400412,
+#define lA1 7168 nP 401798
+#define l91 }},{ProduceNewTree,
+#define l81 data.subfunc_opcode
+#define l71 i61 tJ2
+#define l61 CopyOnWrite();
+#define l51 recursioncount
+#define l41 PlanNtimesCache(
+#define l31 >){int mStackPtr=0;
+#define l21 FPoptimizer_Grammar
+#define l11 AddOperation(cInv,1,1 xN}
+#define l01 GetPositivityInfo eZ3
+#define iZ ParamSpec_SubFunctionData
+#define iY iA1 a=c8 a-->0;)
+#define iX PositionalParams_Rec
+#define iW yD MakeNotNotP1,l5::
+#define iV ,cMul x4
+#define iU eT1 tI3 iE2 nC);tree.
+#define iT yD MakeNotNotP0,l5::
+#define iS lE3 xL2+
+#define iR DumpTreeWithIndent(*this);
+#define iQ switch(type y33 cond_or:
+#define iP ;if(eY2 tM3 SaveMatchedParamIndex(
+#define iO ,l4 2,1,
+#define iN CalculateResultBoundaries(
+#define iM i31 iF2 Compare>
+#define iL cE3 0x0},{{1,
+#define iK edited_powgroup
+#define iJ iA1 a=xF1 a
+#define iI has_unknown_max
+#define iH has_unknown_min
+#define iG static const c23
+#define iF synthed_tree
+#define iE 408964 nP 24963
+#define iD SelectedParams,0},0,0x0},{{
+#define iC collections
+#define iB cache
+#define iA ;xK2 nK2
+#define i9 )iA);
+#define i8 ByteCode.
+#define i7 ;pow xD cLog);tree tH3
+#define i6 goto ReplaceTreeWithOne;case
+#define i5 ]);yE3
+#define i4 !=xB)return lY2
+#define i3 e11.data
+#define i2 l53 xH2(
+#define i1 needs_sinhcosh
+#define i0 cAdd x4
+#define tZ cAdd l3 0,
+#define tY tA2 iV2(
+#define tX xW3 nA
+#define tW int_exponent_t
+#define tV return m;}case
+#define tU MakeFalse,l5::
+#define tT lT2 std::endl;DumpHashes(
+#define tS ,ByteCode,IP,limit,y1,stack);
+#define tR matched_params
+#define tQ [n1 tC3=true;lQ[n1 tD3
+#define tP l21::Grammar*
+#define tO powgroup l8
+#define tN );p2 cK p2);tI3 l93 nC);cZ}
+#define tM GetLogicalValue y91
+#define tL t02&&found[data.
+#define tK valueType
+#define tJ xE AnyParams,
+#define tI =iN lE2
+#define tH eO3 nC1
+#define tG (tH)
+#define tF nF1(
+#define tE has_mulgroups_remaining
+#define tD by_exponent
+#define tC const iZ
+#define tB MatchInfo xK&
+#define tA Rehash();iA2.push_back(
+#define t9 best_factor
+#define t8 RootPowerTable xK::RootPowers[
+#define t7 MatchPositionSpec_AnyParams xK
+#define t6 cLessOrEq,l2
+#define t5 lF3 FPoptimizer_CodeTree
+#define t4 n_as_sinh_param
+#define t3 n_as_cosh_param
+#define t2 is_signed
+#define t1 result_positivity
+#define t0 yN known tO3
+#define eZ biggest_minimum
+#define eY 142455 nP 141449,
+#define eX cond_tree
+#define eW else_tree
+#define eV then_tree
+#define eU sequencing
+#define eT string c83
+#define eS );bool needs_cow=GetRefCount()>1;
+#define eR nM iV2(-nR3
+#define eQ {AdoptChildrenWithSameOpcode(tree);
+#define eP lJ3,l2 c22
+#define eO ;AddParamMove(
+#define eN yN known&&p0 yN val<=fp_const_negativezero xK())
+#define eM tree.GetParamCount()
+#define eL :goto ReplaceTreeWithZero;case
+#define eK relationships
+#define eJ CodeTree xK
+#define eI ,2,122999 nP 139399,
+#define eH std xV3<eJ>
+#define eG if_stack
+#define eF (l02));yQ1 Rehash();
+#define eE n_as_sin_param
+#define eD n_as_cos_param
+#define eC PowiResolver::
+#define eB cIf,tW3
+#define eA ].relationship
+#define e9 PACKED_GRAMMAR_ATTRIBUTE;
+#define e8 .BalanceGood
+#define e7 AddParamMove(yW2
+#define e6 back().endif_location
+#define e5 x91 key
+#define e4 AddParamMove(mul);
+#define e3 130,1,
+#define e2 MatchPositionSpecBase
+#define e1 l53 CodeTree(
+#define e0 smallest_maximum
+#define cZ goto redo;
+#define cY ReplaceTreeWithParam0;
+#define cX factor_needs_rehashing
+#define cW MatchPositionSpecBaseP
+#define cV xK3 tK1::yV3
+#define cU e81 xK(nN.param_list,
+#define cT 243,244,245,246,249,250,251,253,255,256,257,258,259}};}
+#define cS ];};extern"C"{
+#define cR 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 cQ 27,28,29,30,31,32,33,35,36,
+#define cP const ParamSpec_SubFunction
+#define cO const ParamSpec_ParamHolder
+#define cN otherhalf
+#define cM StackState
+#define cL )return false;
+#define cK eT1 lP1
+#define cJ (tree lT2"\n";
+#define cI const SequenceOpCode xK
+#define cH paramholder_matches[nZ]
+#define cG MatchPositionSpec_PositionalParams xK
+#define cF lC2 tree,std::ostream&o
+#define cE paramholder_matches.
+#define cD iV2(1.5)*fp_const_pi xK()
+#define cC xB,l5::Never yD xB,l5::Never}
+#define cB CalculatePowiFactorCost(
+#define cA ImmedHashGenerator
+#define c9 .AddParam(
+#define c8 eM;
+#define c7 ::map<fphash_t,std::set<std cC3> >
+#define c6 ComparisonSetBase::
+#define c5 AddParamMove(comp.cK1[a].value);
+#define c4 ,yA2 528503 nP 24713,
+#define c3 T1,xK3 T2>inline iG2()(
+#define c2 has_nonlogical_values
+#define c1 from_logical_context)
+#define c0 AnyParams,0 l91
+#define yZ for iA1 a=xX.xF1 a-->0;)
+#define yY POWI_CACHE_SIZE
+#define yX static inline eJ
+#define yW ++IP;eR2 if(iT1==cS3.
+#define yV .FoundChild
+#define yU BalanceResultType
+#define yT xM3(0),Opcode(
+#define yS );void lO1 iF2 t83 c42<
+#define yR {return
+#define yQ const yR data->
+#define yP +=fp_const_twopi xK();
+#define yO fp_const_twopi xK()eY3
+#define yN .max.
+#define yM eJ tmp,tmp2;tmp2 xD
+#define yL fp_sin(min),fp_sin(max))
+#define yK m.min.
+#define yJ lO2 GetOpcode(),
+#define yI for iA1 a=0;a<xF1++a){if(
+#define yH static void nA3 nB fphash_t&cH2,
+#define yG MatchPositionSpec_AnyWhere
+#define yF if y23 data.match_type==
+#define yE void OutFloatHex(std::ostream&o,
+#define yD },{l5::
+#define yC AddParam(CodeTreeImmed(
+#define yB cGreaterOrEq,
+#define yA ,xK3 eJ::
+#define y9 xK model=cJ1 xK()){if(known
+#define y8 AssembleSequence_Subdivide(
+#define y7 ]=nK2|iF2(
+#define y6 branch2
+#define y5 (n83 r=range.first;r!=range tE3;++r){
+#define y4 !=t02){n81
+#define y3 ;tQ2 2,
+#define y2 iF2 c;iF2 short l[
+#define y1 factor_stack_base
+#define y0 =0;a<yS3.xF1++a)if(
+#define xZ ,eL1 0x4 nH
+#define xY data->Params
+#define xX branch1
+#define xW );eR2 if(list.first nC1==iV2(
+#define xV nN yF2
+#define xU =fp_cosh nU3;c81=fp_cosh(c81);
+#define xT {nI2.erase(i);eR2
+#define xS StackTop
+#define xR FPOPT_autoptr
+#define xQ +=nT3 n31 nT3;}xW3 inline iV2
+#define xP int_exponent
+#define xO tree.ReplaceWithImmed(
+#define xN )cI1*this)n31;}
+#define xM GetStackTop()-
+#define xL sim.AddConst(
+#define xK <iV2>
+#define xJ .SetParam(0,l93 lR2 eJ p1;p1 xD
+#define xI newnode
+#define xH has_highlevel_opcodes
+#define xG eD2 0x0},{{
+#define xF .IsIdenticalTo(
+#define xE ,cAdd,
+#define xD .nH2
+#define xC {if(needs_cow){l61 goto
+#define xB Unchanged
+#define xA cF=std::cout
+#define x9 best_selected_sep
+#define x8 i31>void FunctionParserBase<
+#define x7 ->Recalculate_Hash_NoRecursion();}
+#define x6 xF1++a)if(ApplyGrammar(tX2,t33,
+#define x5 position
+#define x4 l3 2,1,
+#define x3 ;iE3 0));tmp xD cInv);tmp yP1 tmp2)n31
+#define x2 nB1{c23
+#define x1 std xV3<CodeTree>
+#define x0 TestImmedConstraints y23 constraints,tree)cL
+#define nZ paramholder_index
+#define nY x61 tQ2
+#define nX )){tree.FixIncompleteHashes();}
+#define nW );cR1){nC2 cInv cT2 xL-1 xD2;lC
+#define nV return true;case
+#define nU occurance_counts
+#define nT >p tI a)eY3 p.
+#define nS -->0;){lC2 powgroup=lS1;if(powgroup
+#define nR lT3 i61
+#define nQ ,l0 1,
+#define nP ,{2,
+#define nO const FPoptimizer_CodeTree::eJ&tree
+#define nN model_tree
+#define nM return c23(
+#define nL ){using lF3 FUNCTIONPARSERTYPES;
+#define nK eH&lZ2
+#define nJ AddParam y91
+#define nI ConstantFolding_LogicCommon(tree,c6
+#define nH },{{2,
+#define nG nR1 Ref>inline void xR<Ref>::
+#define nF AnyParams,1},0,0x0},{{
+#define nE ):data(new xH2 xK(
+#define nD goto do_return;}
+#define nC .GetOpcode()
+#define nB FUNCTIONPARSERTYPES::
+#define nA xH2 xK::xH2(
+#define n9 b;}};i31>e12 Comp<nB
+#define n8 l22(),Params(),Hash(),Depth(1),tP1 0){}
+#define n7 SynthesizeByteCode(iS2
+#define n6 while(ApplyGrammar(cD2
+#define n5 GetIntegerInfo y91 0))==IsAlways)nY3
+#define n4 ;lP1 nE1)xJ2
+#define n3 template set_if<cGreater>(iV2(
+#define n2 DumpParams xK y23 data.param_list,yL3 data yF2,o);
+#define n1 restholder_index
+#define n0 eJ exponent;exponent xD cMul tF1 c9
+#define lZ lR eY3 fp_nequal(tmp,xD1){xO iV2(1)/tmp);nD}lC
+#define lY :if(ParamComparer xK()(Params[1],Params[0])){std::swap(Params[0],Params[1]);Opcode=
+#define lX <xK3 iV2>
+#define lW xK tmp;tmp xD cPow);tmp.nJ 0));tmp.yC iV2(
+#define lV tR1,0x0},
+#define lU AddParamMove(pow l8 1));pow tK2 1);pow eT1 tree.nG1 0,pow);goto NowWeAreMulGroup;}
+#define lT GroupFunction,0},lV{{
+#define lS tG1 1)/iV2(
+#define lR lE2 0)nC1
+#define lQ restholder_matches
+#define lP yD1|=key;x91 crc=(key>>10)|(key<<(64-10))lF1((~lY1 crc))*3)^1234567;}};
+#define lO nE1;nE1 iP2 nE1.AddParamMove y91 0));nE1 c9 xX l8
+#define lN xW3 eJ::CodeTree(
+#define lM cM1 0,lE2 0)lR2 cM1 1,CodeTreeImmed(
+#define lL lX void ByteCodeSynth xK::lO1 iF2 t83 c42<
+#define lK cMul,lT 2,
+#define lJ cMul,AnyParams,
+#define lI y91 0)i61&&eO3 i61){xO
+#define lH iN tmp i33
+#define lG :eM3=comp.AddRelationship(atree l8 0),atree l8 1),c6
+#define lF cPow,l0 2
+#define lE xK3 iV2>inline iG2()cG1 xN3 iV2&b)yR a
+#define lD {c23 m tI 0));
+#define lC break;case
+#define lB tZ1 eJ::
+#define lA yX1},0,
+#define l9 l1 0x0 nH
+#define l8 .GetParam(
+#define l7 ;eJ nE1;nE1 iP2 nE1 iO3 tree.l02));nE1 eT1 tI3
+#define l6 SelectedParams,0},0,0x0 nH
+#define l5 RangeComparisonData
+#define l4 yX1 l91
+#define l3 ,AnyParams,0}}l44
+#define l2 yX1}}l44
+#define l1 cMul,SelectedParams,0},0,
+#define l0 lA 0x0},{{
+#ifdef _MSC_VER
+typedef
+iF2
+int
+iZ1;
+#else
+#include <stdint.h>
+typedef
+uint_least32_t
+iZ1;
+#endif
+lF3
+crc32{enum{startvalue=0xFFFFFFFFUL,poly=0xEDB88320UL}
+;i31
+iZ1
+crc>e12
+b8{enum{b1=(crc&xG1
+crc
+xI2
+crc>>1),b2=(b1&xG1
+b1
+xI2
+b1>>1),b3=(b2&xG1
+b2
+xI2
+b2>>1),b4=(b3&xG1
+b3
+xI2
+b3>>1),b5=(b4&xG1
+b4
+xI2
+b4>>1),b6=(b5&xG1
+b5
+xI2
+b5>>1),b7=(b6&xG1
+b6
+xI2
+b6>>1),res=(b7&xG1
+b7
+xI2
+b7>>1)}
+;}
+;inline
+iZ1
+update(iZ1
+crc,iF2
+b){
+#define B4(n) b8<n eS2 n+1 eS2 n+2 eS2 n+3>::res
+#define R(n) B4(n),B4(n+4),B4(n+8),B4(n+12)
+static
+const
+iZ1
+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];xI1
+iZ1
+calc_upd(iZ1
+c,const
+iF2
+char*buf,size_t
+size){iZ1
+value=c;for
+iA1
+p=0;p<size;++p)value=update(value,buf[p])n31
+value;xI1
+iZ1
+calc
+cH1
+iF2
+char*buf,size_t
+size)yR
+calc_upd(startvalue,buf,size);}
+}
+#ifndef FPOptimizerAutoPtrHH
+#define FPOptimizerAutoPtrHH
+nR1
+Ref>class
+xR{eX3
+xR():p(0){}
+xR(Ref*b):p(b){xL3}
+xR
+cH1
+xR&b):p(b.p){xL3
+xI1
+Ref&eA1*(yZ1*p;xI1
+Ref*eA1->(yZ1
+p;}
+xR&eA1=(Ref*b){Set(b)n31*this;}
+xR&eA1=cH1
+xR&b){Set(b.p)n31*this;}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+xR(xR&&b):p(b.p){b.p=0;}
+xR&eA1=(xR&&b){if(p!=b.p){e02;p=b.p;b.p=0;}
+return*this;}
+#endif
+~xR(){e02
+lL3
+UnsafeSetP(Ref*newp){p=newp
+lL3
+swap(xR<Ref>&b){Ref*tmp=p;p=b.p;b.p=tmp;}
+private:inline
+static
+void
+Have(Ref*p2);inline
+void
+e02;inline
+void
+xL3
+inline
+void
+Set(Ref*p2);private:Ref*p;}
+;nG
+e02{if(!p)return;p->xM3-=1;if(!p->xM3)delete
+p;}
+nG
+Have(Ref*p2){if(p2)++(p2->xM3);}
+nG
+Birth(){Have(p);}
+nG
+Set(Ref*p2){Have(p2);e02;p=p2;}
+#endif
 #include <utility>
-#include <cassert>
-using namespace std;
-
+e12
+Compare2ndRev{nR1
+T>inline
+iG2()cH1
+T&xN3
+T&b
+yZ1
+a
+tE3>b
+tE3;}
+}
+;e12
+Compare1st{nR1
+c3
+const
+nS1
+xN3
+nS1
+b
+yZ1
+a.first<b.first;}
+nR1
+c3
+const
+nS1
+a,T1
+b
+yZ1
+a.first<b;}
+nR1
+c3
+T1
+xN3
+nS1
+b
+yZ1
+a<b.first;}
+}
+;
+#ifndef FPoptimizerHashHH
+#define FPoptimizerHashHH
+#ifdef _MSC_VER
+typedef
+iF2
+long
+long
+x91;
+#define FPHASH_CONST(x) x##ULL
+#else
+#include <stdint.h>
+typedef
+uint_fast64_t
+x91;
+#define FPHASH_CONST(x) x##ULL
+#endif
+lF3
+FUNCTIONPARSERTYPES{e12
+fphash_t{x91
+hash1,hash2;fphash_t():hash1(0),hash2(0){}
+fphash_t
+cH1
+x91&xN3
+x91&b):hash1(a),hash2(b){}
+iG2==cH1
+fphash_t&yY1==e22&&hash2==e32
+iG2!=cH1
+fphash_t&yY1!=e22||hash2!=e32
+iG2<cH1
+fphash_t&yY1!=e22?hash1<e22:hash2<e32}
+;}
+#endif
+#ifndef FPOptimizer_CodeTreeHH
+#define FPOptimizer_CodeTreeHH
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <vector>
+#include <utility>
+lF3
+l21{e12
+Grammar;}
+lF3
+xH1{xW3
+class
+ByteCodeSynth;}
+t5{xW3
+class
+CodeTree
+nJ1
+e12
+xH2
+nJ1
+class
+CodeTree{typedef
+xR<xH2
+xK>DataP;DataP
+data;eX3
+CodeTree();~CodeTree();e12
+OpcodeTag{}
+;e1
+xB2
+o,OpcodeTag);e12
+FuncOpcodeTag{}
+;e1
+xB2
+o,iF2
+f,FuncOpcodeTag);e12
+xO3{}
+;e1
+const
+iV2&v,xO3);
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+e1
+iV2&&v,xO3);
+#endif
+e12
+VarTag{}
+;e1
+iF2
+varno,VarTag);e12
+CloneTag{}
+;e1
+lG3
+b,CloneTag);void
+GenerateFrom
+cH1
+xK3
+FunctionParserBase
+xK::Data&data,bool
+keep_powi=false);void
+GenerateFrom
+cH1
+xK3
+FunctionParserBase
+xK::Data&data,const
+x1&xC2,bool
+keep_powi=false);void
+SynthesizeByteCode(std
+xV3<iF2>&eI3,std
+xV3
+xK&immed,size_t&stacktop_max);void
+SynthesizeByteCode(xH1
+yG3&synth,bool
+MustPopTemps=true
+e83;size_t
+SynthCommonSubExpressions(xH1::yM1
+const;void
+SetParams
+cH1
+x1&xP3
+SetParamsMove(x1&tA1
+CodeTree
+GetUniqueRef();
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+void
+SetParams(x1&&tA1
+#endif
+void
+SetParam
+iA1
+which,lG3
+b);void
+nG1
+size_t
+which,xA2
+b);void
+AddParam
+cH1
+xA2
+param);void
+AddParamMove(xA2
+param);void
+AddParams
+cH1
+x1&xP3
+AddParamsMove(x1&xP3
+AddParamsMove(x1&lZ2,size_t
+n02);void
+DelParam
+iA1
+index);void
+DelParams();void
+Become
+cH1
+xA2
+b);inline
+size_t
+GetParamCount(yZ1
+l02).tF3;xI1
+xA2
+GetParam
+iA1
+n)yR
+l02)[n];xI1
+lG3
+GetParam
+iA1
+n
+yZ1
+l02)[n];xI1
+void
+nH2
+xB2
+o)tN3
+Opcode=o;xI1
+xB2
+GetOpcode()yQ
+Opcode;xI1
+nB
+fphash_t
+GetHash()yQ
+Hash;xI1
+const
+x1&l02
+yZ1
+xY;xI1
+x1&l02)yR
+xY;xI1
+size_t
+y22
+yQ
+Depth;xI1
+const
+iV2&GetImmed()yQ
+Value;xI1
+iF2
+GetVar()yQ
+l12
+xI1
+iF2
+GetFuncNo()yQ
+l12
+xI1
+bool
+IsDefined(yZ1
+GetOpcode()!=nB
+cNop;xI1
+bool
+IsImmed(yZ1
+GetOpcode()==nB
+cImmed;xI1
+bool
+IsVar(yZ1
+GetOpcode()==nB
+l03;xI1
+iF2
+GetRefCount()yQ
+xM3
+lL3
+ReplaceWithImmed
+cG1
+i);void
+Rehash(bool
+constantfolding=true);void
+Sort();inline
+void
+Mark_Incompletely_Hashed()tN3
+Depth=0;xI1
+bool
+Is_Incompletely_Hashed()yQ
+Depth==0;xI1
+const
+tP
+GetOptimizedUsing()yQ
+l32;xI1
+void
+SetOptimizedUsing
+cH1
+tP
+g)tN3
+l32=g;}
+bool
+RecreateInversionsAndNegations(bool
+prefer_base2=false);void
+FixIncompleteHashes();void
+swap(xA2
+b){data.swap(b.data);}
+bool
+IsIdenticalTo
+cH1
+xA2
+b
+e83;void
+l61}
+nJ1
+e12
+xH2{int
+xM3;xB2
+Opcode
+iU2
+Value;iF2
+l12
+eH
+Params;nB
+fphash_t
+Hash;size_t
+Depth;const
+tP
+l32;xH2();xH2
+cH1
+xH2&b);i2
+xB2
+o);i2
+xB2
+o,iF2
+f);i2
+const
+iV2&i);
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+i2
+iV2&&i);xH2(xH2&&b);
+#endif
+bool
+IsIdenticalTo
+cH1
+xH2&b
+e83;void
+Sort();void
+Recalculate_Hash_NoRecursion();private:void
+eA1=cH1
+xH2&b);}
+nJ1
+yX
+CodeTreeImmed
+cG1
+i)yR
+eJ(i
+yA
+xO3());}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+cB1
+CodeTreeImmed(iV2&&i)yR
+eJ
+c72
+i)yA
+xO3());}
+#endif
+cB1
+CodeTreeOp(xB2
+opcode)yR
+eJ(opcode
+yA
+OpcodeTag());}
+cB1
+CodeTreeFuncOp(xB2
+t83
+iF2
+f)yR
+eJ(t83
+f
+yA
+FuncOpcodeTag());}
+cB1
+CodeTreeVar
+nT2
+varno)yR
+eJ(varno
+yA
+VarTag());}
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+tZ1
+DumpHashes(xA)xR3
+DumpTree(xA)xR3
+DumpTreeWithIndent(xA,const
+std
+cC3&indent="\\"
+);
+#endif
+}
+#endif
+#endif
+#ifndef FPOptimizer_GrammarHH
+#define FPOptimizer_GrammarHH
+#include <iostream>
+t5{xW3
+class
+CodeTree;}
+lF3
+l21{enum
+ImmedConstraint_Value{ValueMask=0x07,Value_AnyNum=0x0,nY2=0x1,Value_OddInt=0x2,tS1=0x3,Value_NonInteger=0x4,eJ1=0x5
+xF3
+ImmedConstraint_Sign{SignMask=0x18,Sign_AnySign=0x00,nH1=0x08,eK1=0x10,Sign_NoIdea=0x18
+xF3
+ImmedConstraint_Oneness{OnenessMask=0x60,Oneness_Any=0x00,Oneness_One=0x20,Oneness_NotOne=0x40
+xF3
+ImmedConstraint_Constness{ConstnessMask=0x180,Constness_Any=0x00,tR1=0x80,Constness_NotConst=0x100
+xF3
+Modulo_Mode{Modulo_None=0,Modulo_Radians=1
+xF3
+Situation_Flags{LogicalContextOnly=0x01,NotForIntegers=0x02,OnlyForIntegers=0x04,OnlyForComplex=0x08,NotForComplex=0x10
+xF3
+nR2{NumConstant,tG3,SubFunction
+xF3
+ParamMatchingType{PositionalParams,SelectedParams,AnyParams,GroupFunction
+xF3
+RuleType{ProduceNewTree,ReplaceParams}
+;
+#ifdef __GNUC__
+# define PACKED_GRAMMAR_ATTRIBUTE __attribute__((packed))
+#else
+# define PACKED_GRAMMAR_ATTRIBUTE
+#endif
+typedef
+std::pair<nR2,const
+void*>e42
+nJ1
+e42
+e81
+nT2
+paramlist,nA1)nJ1
+bool
+ParamSpec_Compare
+cH1
+void*xN3
+void*b,nR2
+type);iF2
+ParamSpec_GetDepCode
+cH1
+e42&b);e12
+ParamSpec_ParamHolder{nA1:8;iF2
+constraints:9;iF2
+depcode:15;}
+e9
+xW3
+e12
+ParamSpec_NumConstant{iV2
+constvalue;iF2
+modulo;}
+;e12
+iZ{iF2
+param_count:2;iF2
+param_list:30;xB2
+subfunc_opcode:8;ParamMatchingType
+match_type:3;iF2
+n1:5;}
+e9
+e12
+ParamSpec_SubFunction{iZ
+data;iF2
+constraints:9;iF2
+depcode:7;}
+e9
+e12
+Rule{RuleType
+ruletype:2;iF2
+situation_flags:5;iF2
+repl_param_count:2+9;iF2
+repl_param_list:30;iZ
+match_tree;}
+e9
+e12
+Grammar{iF2
+rule_count;iF2
+short
+rule_list[999
+cS
+extern
+const
+Rule
+grammar_rules[];}
+tZ1
+DumpParam
+cH1
+e42&p,std::ostream&o=std::cout)xR3
+DumpParams
+nT2
+paramlist,iF2
+count,std::ostream&o=std::cout);}
+#endif
 #ifndef M_PI
 #define M_PI 3.1415926535897932384626433832795
 #endif
-
-#define CONSTANT_E     2.71828182845904509080  // exp(1)
-#define CONSTANT_PI    M_PI                    // atan2(0,-1)
-#define CONSTANT_L10   2.30258509299404590109  // log(10)
-#define CONSTANT_L10I  0.43429448190325176116  // 1/log(10)
-#define CONSTANT_L10E  CONSTANT_L10I           // log10(e)
-#define CONSTANT_L10EI CONSTANT_L10            // 1/log10(e)
-#define CONSTANT_DR    (180.0 / M_PI)          // 180/pi
-#define CONSTANT_RD    (M_PI / 180.0)          // pi/180
-
-// Debugging in optimizer? Not recommended for production use.
-//#define TREE_DEBUG
-#ifdef TREE_DEBUG
-// Debug verbosely?
-#include <ostream>
+#define CONSTANT_POS_INF HUGE_VAL
+#define CONSTANT_NEG_INF (-HUGE_VAL)
+lF3
+FUNCTIONPARSERTYPES{xW3
+inline
+iV2
+fp_const_pihalf()yR
+fp_const_pi
+xK()*iV2(0.5);}
+xW3
+inline
+iV2
+fp_const_twopi(tO2
+fp_const_pi
+xK());lH3
+fp_const_twoe(tO2
+fp_const_e
+xK());lH3
+fp_const_twoeinv(tO2
+fp_const_einv
+xK());lH3
+fp_const_negativezero()yR-fp_epsilon
+xK();}
+}
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <vector>
+#include <utility>
+#include <iostream>
+yL1{using
+lF3
+l21;using
+t5;using
+lF3
+FUNCTIONPARSERTYPES
+nJ1
+class
+MatchInfo{eX3
+std
+xV3<std::pair<bool,eH> >lQ;eH
+paramholder_matches;std
+xV3<iF2>tR;eX3
+MatchInfo():lQ(),paramholder_matches(),tR(){}
+eX3
+bool
+SaveOrTestRestHolder
+nT2
+n1,iH2&iF1){cV1{lQ.t73
+n1+1);lQ
+tQ=iF1
+xJ2
+if(lQ[n1
+tC3==false){lQ
+tQ=iF1
+xJ2
+iH2&found=lQ[n1
+tD3;if(iF1.tF3!=found.tF3
+cL
+for
+iA1
+a=0;a<iF1.tF3;++a)if(!iF1[a]xF
+found[a])cL
+return
+true
+lL3
+SaveRestHolder
+nT2
+n1,eH&iF1){cV1
+lQ.t73
+n1+1);lQ
+tQ.swap(iF1);}
+bool
+SaveOrTestParamHolder
+nT2
+nZ,lC2
+xQ3){if(cE
+tF3<=nZ){cE
+xS3
+nZ+1);cE
+t73
+nZ);cE
+push_back(xQ3)xJ2
+if(!cH.t91
+cH=xQ3
+xJ2
+return
+xQ3
+xF
+cH
+lI3
+SaveMatchedParamIndex(nA1){tR.push_back(index);}
+lC2
+GetParamHolderValueIfFound
+nT2
+nZ
+e83{static
+const
+eJ
+dummytree;if(cE
+tF3<=nZ)return
+dummytree
+n31
+cH;}
+lC2
+GetParamHolderValue
+nT2
+nZ
+yZ1
+cH;}
+bool
+HasRestHolder
+nT2
+n1
+yZ1
+lQ.tF3>n1&&lQ[n1
+tC3==true;}
+iH2&GetRestHolderValues
+nT2
+n1
+e83{static
+iH2
+empty_result;cV1
+return
+empty_result
+n31
+lQ[n1
+tD3;}
+const
+std
+xV3<iF2>&GetMatchedParamIndexes(yZ1
+tR
+lL3
+swap(tB
+b){lQ.swap(b.lQ);cE
+swap(b.paramholder_matches);tR.swap(b.tR);}
+tB
+eA1=cH1
+tB
+b){lQ=b.lQ;paramholder_matches=b.paramholder_matches;tR=b.tR
+n31*this;}
+}
+;class
+e2;typedef
+xR<e2>cW;class
+e2{eX3
+int
+xM3;eX3
+e2():xM3(0){}
+virtual~e2(){}
+}
+;e12
+lX1{bool
+found;cW
+specs;lX1(bool
+f):found(f),specs(){}
+lX1(bool
+f,const
+cW&s):found(f),specs(s){}
+}
+xR3
+SynthesizeRule
+cH1
+eT2
+eJ&tree
+tJ3)nJ1
+lX1
+TestParam
+cH1
+e42&yG2
+lC2
+tree,const
+cW&start_at
+tJ3)nJ1
+lX1
+TestParams(tC&nN,lC2
+tree,const
+cW&start_at
+tJ3,bool
+eY2
+nJ1
+bool
+ApplyGrammar
+cH1
+Grammar&tX2,FPoptimizer_CodeTree::eJ&tree,bool
+from_logical_context=false)xR3
+ApplyGrammars(FPoptimizer_CodeTree::e62
+nJ1
+bool
+IsLogisticallyPlausibleParamsMatch(tC&c32,lC2
+tree);}
+lF3
+l21{tZ1
+DumpMatch
+cH1
+eT2
+nO,const
+FPoptimizer_Optimize::tB
+info,bool
+DidMatch,std::ostream&o=std::cout)xR3
+DumpMatch
+cH1
+eT2
+nO,const
+FPoptimizer_Optimize::tB
+info,nH3
+i43,std::ostream&o=std::cout);}
+#endif
+#include <string>
+nI3
+l21::nR2
+yS1=false);nI3
+xB2
+yS1=false);
+#include <string>
+#include <sstream>
+#include <assert.h>
+#include <iostream>
+using
+lF3
+l21;using
+lF3
+FUNCTIONPARSERTYPES;nI3
+l21::nR2
+yS1){
+#if 1
+nH3
+p=0;switch(opcode
+y33
+NumConstant:p="NumConstant"
+;lC
+tG3:p="ParamHolder"
+;lC
+SubFunction:p="SubFunction"
+;yF3
+std::ostringstream
+tmp;assert(p);tmp<<p;if(pad)while(tmp.str().tF3<12)tmp<<' 'n31
+tmp.str();
+#else
+std::ostringstream
+tmp;tmp<<opcode;if(pad)while(tmp.str().tF3<5)tmp<<' 'n31
+tmp.str();
 #endif
-
-namespace {
-inline double Min(double d1, double d2)
-{
-    return d1<d2 ? d1 : d2;
 }
-inline double Max(double d1, double d2)
-{
-    return d1>d2 ? d1 : d2;
+nI3
+xB2
+yS1){
+#if 1
+nH3
+p=0;switch(opcode
+y33
+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
+cNEqual: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
+eF3:p="cLog2by"
+;lC
+cNop:p="cNop"
+;break;
+#endif
+case
+cSinCos:p="cSinCos"
+;lC
+cSinhCosh:p="cSinhCosh"
+;lC
+cZ3: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
+l03:p="VarBegin"
+;yF3
+std::ostringstream
+tmp;assert(p);tmp<<p;if(pad)while(tmp.str().tF3<12)tmp<<' 'n31
+tmp.str();
+#else
+std::ostringstream
+tmp;tmp<<opcode;if(pad)while(tmp.str().tF3<5)tmp<<' 'n31
+tmp.str();
+#endif
 }
-
-class compres
-{
-    // states: 0=false, 1=true, 2=unknown
-public:
-    compres(bool b) : state(b) {}
-    compres(char v) : state(v) {}
-    // is it?
-    operator bool() const { return state != 0; }
-    // is it not?
-    bool operator! () const { return state != 1; }
-    bool operator==(bool b) const { return state != !b; }
-    bool operator!=(bool b) const { return state != b; }
-private:
-    char state;
-};
-
-const compres maybe = (char)2;
-
-struct CodeTree;
-
-class SubTree
-{
-    CodeTree *tree;
-    bool sign;  // Only possible when parent is cAdd or cMul
-
-    inline void flipsign() { sign = !sign; }
-public:
-    SubTree();
-    SubTree(double value);
-    SubTree(const SubTree &b);
-    SubTree(const CodeTree &b);
-
-    ~SubTree();
-    const SubTree &operator= (const SubTree &b);
-    const SubTree &operator= (const CodeTree &b);
-
-    bool getsign() const { return sign; }
-
-    const CodeTree* operator-> () const { return tree; }
-    const CodeTree& operator* () const { return *tree; }
-    struct CodeTree* operator-> () { return tree; }
-    struct CodeTree& operator* () { return *tree; }
-
-    bool operator< (const SubTree& b) const;
-    bool operator== (const SubTree& b) const;
-    void Negate(); // Note: Parent must be cAdd
-    void Invert(); // Note: Parent must be cMul
-
-    void CheckConstNeg();
-    void CheckConstInv();
-};
-
-bool IsNegate(const SubTree &p1, const SubTree &p2);
-bool IsInverse(const SubTree &p1, const SubTree &p2);
-
-typedef list<SubTree> paramlist;
-
-#ifdef TREE_DEBUG
-struct CodeTreeData;
-std::ostream& operator << (std::ostream& str, const CodeTreeData& tree);
-std::ostream& operator << (std::ostream& str, const CodeTree& tree);
+#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
-
-struct CodeTreeData
-{
-    paramlist args;
-
-private:
-    unsigned op;       // Operation
-    double value;      // In case of cImmed
-    unsigned var;      // In case of cVar
-    unsigned funcno;   // In case of cFCall, cPCall
-
-public:
-    CodeTreeData() : op(cAdd) {}
-    ~CodeTreeData() {}
-
-    void SetOp(unsigned newop)     { op=newop; }
-    void SetFuncNo(unsigned newno) { funcno=newno; }
-
-    inline unsigned GetOp() const { return op; }
-    inline double GetImmed() const { return value; }
-    inline unsigned GetVar() const { return var; }
-    inline unsigned GetFuncNo() const { return funcno; }
-
-    bool IsFunc() const  { return op == cFCall || op == cPCall; }
-    bool IsImmed() const { return op == cImmed; }
-    bool IsVar() const   { return op == cVar; }
-
-    void AddParam(const SubTree &p)
-    {
-        args.push_back(p);
-    }
-    void SetVar(unsigned v)
-    {
-        args.clear();
-        op  = cVar;
-        var = v;
-    }
-    void SetImmed(double v)
-    {
-        args.clear();
-        op       = cImmed;
-        value    = orig = v;
-        inverted = negated = false;
-    }
-    void NegateImmed()
-    {
-        negated = !negated;
-        UpdateValue();
-    }
-    void InvertImmed()
-    {
-        inverted = !inverted;
-        UpdateValue();
-    }
-
-    bool IsOriginal() const { return !(IsInverted() || IsNegated()); }
-    bool IsInverted() const { return inverted; }
-    bool IsNegated() const { return negated; }
-    bool IsInvertedOriginal() const { return IsInverted() && !IsNegated(); }
-    bool IsNegatedOriginal() const { return !IsInverted() && IsNegated(); }
-
-private:
-    void UpdateValue()
-    {
-        value = orig;
-        if(IsInverted()) { value = 1.0 / value;
-                           // FIXME: potential divide by zero.
-                         }
-        if(IsNegated()) value = -value;
-    }
-
-    double orig;
-    bool inverted;
-    bool negated;
-protected:
-    // Ensure we don't accidentally copy this
-    void operator=(const CodeTreeData &b);
-};
-
-
-class CodeTreeDataPtr
-{
-    typedef pair<CodeTreeData, unsigned> p_t;
-    typedef p_t* pp;
-    mutable pp p;
-
-    void Alloc()   const { ++p->second; }
-    void Dealloc() const { if(!--p->second) delete p; p = 0; }
-
-    void PrepareForWrite()
-    {
-        // We're ready if we're the only owner.
-        if(p->second == 1) return;
-
-        // Then make a clone.
-        p_t *newtree = new p_t(p->first, 1);
-        // Forget the old
-        Dealloc();
-        // Keep the new
-        p = newtree;
-    }
-
-public:
-    CodeTreeDataPtr() : p(new p_t) { p->second = 1; }
-    CodeTreeDataPtr(const CodeTreeDataPtr &b): p(b.p) { Alloc(); }
-    ~CodeTreeDataPtr() { Dealloc(); }
-    const CodeTreeDataPtr &operator= (const CodeTreeDataPtr &b)
-    {
-        b.Alloc();
-        Dealloc();
-        p = b.p;
-        return *this;
-    }
-    const CodeTreeData *operator-> () const { return &p->first; }
-    const CodeTreeData &operator*  () const { return p->first; }
-    CodeTreeData *operator-> () { PrepareForWrite(); return &p->first; }
-    CodeTreeData &operator*  () { PrepareForWrite(); return p->first; }
-
-    void Shock();
-};
-
-
-#define CHECKCONSTNEG(item, op) \
-    ((op)==cMul) \
-       ? (item).CheckConstInv() \
-       : (item).CheckConstNeg()
-
-struct CodeTree
-{
-    CodeTreeDataPtr data;
-
-private:
-    typedef paramlist::iterator pit;
-    typedef paramlist::const_iterator pcit;
-
-    /*
-    template<unsigned v> inline void chk() const
-    {
-    }
-    */
-
-public:
-    const pcit GetBegin() const { return data->args.begin(); }
-    const pcit GetEnd()   const { return data->args.end(); }
-    const pit GetBegin() { return data->args.begin(); }
-    const pit GetEnd()   { return data->args.end(); }
-    const SubTree& getp0() const { /*chk<1>();*/pcit tmp=GetBegin();               return *tmp; }
-    const SubTree& getp1() const { /*chk<2>();*/pcit tmp=GetBegin(); ++tmp;        return *tmp; }
-    const SubTree& getp2() const { /*chk<3>();*/pcit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
-    unsigned GetArgCount() const { return data->args.size(); }
-    void Erase(const pit p)      { data->args.erase(p); }
-
-    SubTree& getp0() { /*chk<1>();*/pit tmp=GetBegin();               return *tmp; }
-    SubTree& getp1() { /*chk<2>();*/pit tmp=GetBegin(); ++tmp;        return *tmp; }
-    SubTree& getp2() { /*chk<3>();*/pit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; }
-
-    // set
-    void SetImmed(double v) { data->SetImmed(v); }
-    void SetOp(unsigned op) { data->SetOp(op); }
-    void SetVar(unsigned v) { data->SetVar(v); }
-    // get
-    double GetImmed() const { return data->GetImmed(); }
-    unsigned GetVar() const { return data->GetVar(); }
-    unsigned GetOp() const  { return data->GetOp(); }
-    // test
-    bool IsImmed() const { return data->IsImmed(); }
-    bool IsVar()   const { return data->IsVar(); }
-    // act
-    void AddParam(const SubTree &p) { data->AddParam(p); }
-    void NegateImmed() { data->NegateImmed(); } // don't use when op!=cImmed
-    void InvertImmed() { data->InvertImmed(); } // don't use when op!=cImmed
-
-    compres NonZero() const { if(!IsImmed()) return maybe;
-                              return GetImmed() != 0.0; }
-    compres IsPositive() const { if(!IsImmed()) return maybe;
-                                 return GetImmed() > 0.0; }
-
-private:
-    struct ConstList
-    {
-        double voidvalue;
-        list<pit> cp;
-        double value;
-        unsigned size() const { return cp.size(); }
-    };
-    struct ConstList BuildConstList();
-    void KillConst(const ConstList &cl)
-    {
-        for(list<pit>::const_iterator i=cl.cp.begin(); i!=cl.cp.end(); ++i)
-            Erase(*i);
-    }
-    void FinishConst(const ConstList &cl, bool has_voidvalue)
-    {
-        if(has_voidvalue)
-        {
-            if(cl.value != cl.voidvalue)
-            {
-                if(cl.size() == 1) return; // nothing to do
-                AddParam(cl.value); // add the resulting constant
-            }
-        }
-        else
-        {
-            if(cl.size() <= 0) return; // nothing to do
-            AddParam(cl.value); // add the resulting constant
-        }
-        KillConst(cl); // remove all listed constants
-    }
-
-public:
-    CodeTree() {}
-    CodeTree(double v) { SetImmed(v); }
-
-    CodeTree(unsigned op, const SubTree &p)
-    {
-        SetOp(op);
-        AddParam(p);
-    }
-    CodeTree(unsigned op, const SubTree &p1, const SubTree &p2)
-    {
-        SetOp(op);
-        AddParam(p1);
-        AddParam(p2);
-    }
-
-    bool operator== (const CodeTree& b) const;
-    bool operator< (const CodeTree& b) const;
-
-private:
-    bool IsSortable() const
-    {
-        switch(GetOp())
-        {
-            case cAdd:  case cMul:
-            case cEqual:
-            case cAnd: case cOr:
-            case cMax: case cMin:
-                return true;
-            default:
-                return false;
-        }
-    }
-    void SortIfPossible()
-    {
-        if(IsSortable())
-        {
-            data->args.sort();
-        }
-    }
-
-    void ReplaceWithConst(double value)
-    {
-        SetImmed(value);
-
-        /* REMEMBER TO CALL CheckConstInv / CheckConstNeg
-         * FOR PARENT SubTree, OR MAYHEM HAPPENS
-         */
-    }
-
-    void ReplaceWith(const CodeTree &b)
-    {
-        // If b is child of *this, mayhem
-        // happens. So we first make a clone
-        // and then proceed with copy.
-        CodeTreeDataPtr tmp = b.data;
-        tmp.Shock();
-        data = tmp;
-    }
-
-    void ReplaceWith(unsigned op, const SubTree &p)
-    {
-        ReplaceWith(CodeTree(op, p));
-    }
-
-    void ReplaceWith(unsigned op, const SubTree &p1, const SubTree &p2)
-    {
-        ReplaceWith(CodeTree(op, p1, p2));
-    }
-
-    void OptimizeConflict()
-    {
-        // This optimization does this: x-x = 0, x/x = 1, a+b-a = b.
-
-        if(GetOp() == cAdd || GetOp() == cMul)
-        {
-        Redo:
-            pit a, b;
-            for(a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                for(b=a; ++b != GetEnd(); )
-                {
-                    const SubTree &p1 = *a;
-                    const SubTree &p2 = *b;
-
-                    if(GetOp() == cMul ? IsInverse(p1,p2)
-                                       : IsNegate(p1,p2))
-                    {
-                        // These parameters complement each others out
-                        Erase(b);
-                        Erase(a);
-                        goto Redo;
-                    }
-                }
-            }
-        }
-        OptimizeRedundant();
-    }
-
-    void OptimizeRedundant()
-    {
-        // This optimization does this: min()=0, max()=0, add()=0, mul()=1
-
-        if(!GetArgCount())
-        {
-            if(GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
-                ReplaceWithConst(0);
-            else if(GetOp() == cMul)
-                ReplaceWithConst(1);
-            return;
-        }
-
-        // And this: mul(x) = x, min(x) = x, max(x) = x, add(x) = x
-
-        if(GetArgCount() == 1)
-        {
-            if(GetOp() == cMul || GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
-                if(!getp0().getsign())
-                    ReplaceWith(*getp0());
-        }
-
-        OptimizeDoubleNegations();
-    }
-
-    void OptimizeDoubleNegations()
-    {
-        if(GetOp() == cAdd)
-        {
-            // Eschew double negations
-
-            // If any of the elements is !cAdd of cMul
-            // and has a numeric constant, negate
-            // the constant and negate sign.
-            
-            for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                SubTree &pa = *a;
-                if(pa.getsign()
-                && pa->GetOp() == cMul)
-                {
-                    // Before doing the check, ensure that
-                    // we are not changing a x*1 into x*-1.
-                    pa->OptimizeConstantMath1();
-                    
-                    // OptimizeConstantMath1() may have changed
-                    // the type of the expression (but not its sign),
-                    // so verify that we're still talking about a cMul group.
-                    if(pa->GetOp() == cMul)
-                    {
-                        CodeTree &p = *pa;
-                        for(pit b=p.GetBegin();
-                                b!=p.GetEnd(); ++b)
-                        {
-                            SubTree &pb = *b;
-                            if(pb->IsImmed())
-                            {
-                                pb.Negate();
-                                pa.Negate();
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        if(GetOp() == cMul)
-        {
-            // If any of the elements is !cMul of cPow
-            // and has a numeric exponent, negate
-            // the exponent and negate sign.
-
-            for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                SubTree &pa = *a;
-                if(pa.getsign() && pa->GetOp() == cPow)
-                {
-                    CodeTree &p = *pa;
-                    if(p.getp1()->IsImmed())
-                    {
-                        // negate ok for pow when op=cImmed
-                        p.getp1().Negate();
-                        pa.Negate();
-                    }
-                }
-            }
-        }
-    }
-
-    void OptimizeConstantMath1()
-    {
-        // This optimization does three things:
-        //      - For adding groups:
-        //          Constants are added together.
-        //      - For multiplying groups:
-        //          Constants are multiplied together.
-        //      - For function calls:
-        //          If all parameters are constants,
-        //          the call is replaced with constant value.
-
-        // First, do this:
-        OptimizeAddMulFlat();
-
-#ifdef TREE_DEBUG
-        cout << "BEFORE MATH1    :" << *this << endl;
-#endif
-        switch(GetOp())
-        {
-            case cAdd:
-            {
-                ConstList cl = BuildConstList();
-                FinishConst(cl, true);
-                break;
-            }
-            case cMul:
-            {
-                ConstList cl = BuildConstList();
-
-                if(cl.value == 0.0) ReplaceWithConst(0.0);
-                else FinishConst(cl, true);
-
-                break;
-            }
-            case cMin:
-            case cMax:
-            {
-                ConstList cl = BuildConstList();
-                FinishConst(cl, false); // No "default" value
-                break;
-            }
-            
-            #define ConstantUnaryFun(token, fun) \
-                case token: { const SubTree &p0 = getp0(); \
-                    if(p0->IsImmed()) ReplaceWithConst(fun(p0->GetImmed())); \
-                    break; }
-            #define ConstantBinaryFun(token, fun) \
-                case token: { const SubTree &p0 = getp0(); \
-                              const SubTree &p1 = getp1(); \
-                    if(p0->IsImmed() && \
-                       p1->IsImmed()) ReplaceWithConst(fun(p0->GetImmed(), p1->GetImmed())); \
-                    break; }
-
-            // FIXME: potential invalid parameters for functions
-            //        can cause exceptions here
-
-            ConstantUnaryFun(cAbs,   fabs);
-            ConstantUnaryFun(cAcos,  acos);
-            ConstantUnaryFun(cAsin,  asin);
-            ConstantUnaryFun(cAtan,  atan);
-            ConstantUnaryFun(cCeil,  ceil);
-            ConstantUnaryFun(cCos,   cos);
-            ConstantUnaryFun(cCosh,  cosh);
-            ConstantUnaryFun(cFloor, floor);
-            ConstantUnaryFun(cLog,   log);
-            ConstantUnaryFun(cSin,   sin);
-            ConstantUnaryFun(cSinh,  sinh);
-            ConstantUnaryFun(cTan,   tan);
-            ConstantUnaryFun(cTanh,  tanh);
-            ConstantBinaryFun(cAtan2, atan2);
-            ConstantBinaryFun(cMod,   fmod); // not a func, but belongs here too
-            ConstantBinaryFun(cPow,   pow);
-
-            case cNeg:
-            case cSub:
-            case cDiv:
-                /* Unreached (nonexistent operator)
-                 * TODO: internal error here?
-                 */
-                break;
-
-            case cCot:
-            case cCsc:
-            case cSec:
-            case cDeg:
-            case cRad:
-            case cLog10:
-            case cSqrt:
-            case cExp:
-                /* Unreached (nonexistent function)
-                 * TODO: internal error here?
-                 */
-                 break;
-        }
-#ifdef TREE_DEBUG
-        cout << "AFTER MATH1 A   :" << *this << endl;
+enum{MAX_MULI_BYTECODE_LENGTH=3}
+;lF3
+xH1{xW3
+class
+ByteCodeSynth{eX3
+ByteCodeSynth():ByteCode(),Immed(),cM(),xS(0),StackMax(0){i8
+xS3
+64);Immed.xS3
+8);cM.xS3
+16
+lI3
+Pull(std
+xV3<iF2>&bc,std
+xV3
+xK&imm,size_t&StackTop_max){for(eQ1=0;a<i8
+tF3;++a){l52]&=~nK2;}
+i8
+swap(bc);Immed.swap(imm);StackTop_max=StackMax;}
+size_t
+GetByteCodeSize(yZ1
+i8
+tF3;}
+size_t
+GetStackTop(yZ1
+xS
+lL3
+PushVar
+nT2
+varno){xK2
+varno);eZ2}
+void
+PushImmed(iV2
+immed
+nL
+xK2
+cImmed);Immed.push_back(immed);eZ2}
+void
+StackTopIs(nO,int
+offset=0){if((int)xS>offset){cM
+l62
+first=true;cM
+l62
+second=tree;}
+}
+bool
+IsStackTop(nO,int
+offset=0
+yZ1(int)xS>offset&&cM
+l62
+first&&cM
+l62
+second
+xF
+tree);xI1
+void
+EatNParams
+nT2
+eat_count){xS-=eat_count
+lL3
+ProducedNParams
+nT2
+produce_count){xJ1
+xS+produce_count
+lI3
+DoPopNMov
+iA1
+e52,size_t
+srcpos
+nL
+xK2
+cPopNMov)nS2
+e52)nS2
+srcpos);xJ1
+srcpos+1);cM[e52]=cM[srcpos];xJ1
+e52+1
+lI3
+DoDup
+iA1
+xT3
+nL
+if(xT3==xS-1){xK2
+cDup
+t43{xK2
+cFetch)nS2
+xT3);}
+eZ2
+cM[xS-1]=cM[xT3];}
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+i31
+int>void
+Dump(){std::ostream&o=std::cout;o<<"Stack state now("
+<<xS<<"):\n"
+yM3
+0;a<xS;++a){o<<a<<": "
+;if(cM[a
+tC3){nO=cM[a
+tD3;o<<'['<<std::hex<<(void*)(&tree.l02))<<std::dec<<','<<tree.GetRefCount()<<']'i13(tree,o
+t43
+o<<"?"
+;o<<"\n"
+;}
+o<<std::flush;}
+#endif
+size_t
+xU3
+nO
+e83{for
+iA1
+a=xS;a-->0;)if(cM[a
+tC3&&cM[a
+tD3
+xF
+tree
+nE3
+a
+n31
+t02;}
+bool
+Find(nO
+yZ1
+xU3
+tree)!=t02;}
+bool
+FindAndDup(nO){size_t
+pos=xU3
+tree
+eY3
+pos!=t02){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<l24"duplicate at ["
+<<pos<<"]: "
+i13(tree
+lT2" -- issuing cDup or cFetch\n"
+;
+#endif
+DoDup(pos)xJ2
+return
+tR3
+e12
+IfData{size_t
+ofs;}
+;void
+SynthIfStep1
+l72,xB2
+op
+x21
+xL2=i8
+tF3;xK2
+op
+i9
+xK2
+nK2
+lI3
+SynthIfStep2
+l72
+x21
+iS
+nU2)+2);iS
+2
+y7
+l42
+xL2=i8
+tF3;xK2
+cJump
+i9
+xK2
+nK2
+lI3
+SynthIfStep3
+l72
+x21
+i8
+back()|=nK2;iS
+nU2)-1);iS
+2
+y7
+l42
+eZ2
+for
+iA1
+a=0;a<xL2;++a){if(l52]==cJump&&l52+1]==(nK2|(xL2-1))){l52+nU2)-1);l52+2
+y7
+l42
+l73
+l52]y33
+cAbsIf:case
+cIf:case
+cJump:case
+cPopNMov:a+=2;lC
+cFCall:case
+cPCall:case
+cFetch:a+=1;break;c73
+yF3}
+}
+protected:void
+xJ1
+size_t
+value){xS=value;if(xS>lN3{StackMax=xS;cM.t73
+lN3;}
+}
+protected:std
+xV3<iF2>ByteCode;std
+xV3
+xK
+Immed;std
+xV3<std::pair<bool,FPoptimizer_CodeTree::eJ> >cM;size_t
+xS;size_t
+StackMax;private:void
+incStackPtr(){if(xS+2>lN3
+cM.t73
+StackMax=xS+2);}
+i31
+bool
+IsIntType,bool
+IsComplexType>e12
+c42{}
+;eX3
+void
+AddOperation
+nT2
+t83
+iF2
+eat_count,iF2
+produce_count=1){EatNParams(eat_count);lO1
+opcode);ProducedNParams(produce_count
+lI3
+lO1
+iF2
+t83
+c42<false,false>yS
+false,true>yS
+true,false>yS
+true,true>);inline
+void
+lO1
+iF2
+opcode){lO1
+t83
+c42<bool(nB
+IsIntType
+xK::nT3),bool(nB
+IsComplexType
+xK::nT3)>());}
+}
+nJ1
+e12
+SequenceOpCode
+nJ1
+e12
+tN1{static
+cI
+AddSequence;static
+cI
+MulSequence;}
+xR3
+x01
+long
+count,cI&eU,yM1;}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;lF3
+xH1{xW3
+e12
+SequenceOpCode{iV2
+basevalue;iF2
+op_flip;iF2
+op_normal,op_normal_flip;iF2
+op_inverse,op_inverse_flip;}
+nJ1
+cI
+tN1
+xK::AddSequence={y21,cNeg
+xE
+cAdd,cSub,cRSub}
+nJ1
+cI
+tN1
+xK::MulSequence={iV2(1),cInv,cMul,cMul,cDiv,cRDiv}
+;
+#define findName(a,b,c) "var"
+#define TryCompilePowi(o) false
+#define mData this
+#define mByteCode ByteCode
+#define mImmed Immed
+xY3
+false,false
+l31
+# define FP_FLOAT_VERSION 1
+# define FP_COMPLEX_VERSION 0
+# include "extrasrc/fp_opcode_add.inc"
+# undef FP_COMPLEX_VERSION
+# undef FP_FLOAT_VERSION
+}
+xY3
+true,false
+l31
+# 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
+xY3
+false,true
+l31
+# define FP_FLOAT_VERSION 1
+# define FP_COMPLEX_VERSION 1
+# include "extrasrc/fp_opcode_add.inc"
+# undef FP_COMPLEX_VERSION
+# undef FP_FLOAT_VERSION
+}
+xY3
+true,true
+l31
+# 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
+lF3
+xH1;
+#define POWI_TABLE_SIZE 256
+#define POWI_WINDOW_SIZE 3
+lF3
+xH1{
+#ifndef FP_GENERATING_POWI_TABLE
+extern
+const
+iF2
+char
+powi_table[POWI_TABLE_SIZE];const
+#endif
+iF2
+char
+powi_table[POWI_TABLE_SIZE]={0,1,1,1,2,1,2,1,y63
+4,1,2,y73
+2,1,y63
+8,eK3
+y83
+15,1,16,1,2,1,4,1,2,y73
+2,1,4,eK3
+1,16,1,25,y83
+27,5,8,3,2,1,30,1,31,3,32,1,2,1,y63
+8,1,2,y83
+39,1,16,137,2,1,4,eK3
+y73
+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,iG1
+131,iG1
+139,l82
+e3
+30,1,130,137,2,31,l82
+e3
+e3
+130,eK3
+1,e3
+e3
+2,1,130,133,iG1
+61,130,133,62,139,130,137,e3
+l82
+e3
+e3
+iG1
+131,e3
+e3
+130,131,2,133,l82
+130,141,e3
+130,eK3
+1,e3
+5,135,e3
+l82
+e3
+l82
+130,133,130,141,130,131,e3
+e3
+2,131}
+;}
+static
+xC3
+yY=256;
+#define FPO(x)
+lF3{class
+PowiCache{private:int
+iB[yY];int
+iH1[yY];eX3
+PowiCache():iB(),iH1(){iB[1]=1;}
+bool
+Plan_Add(c82,int
+count){cC1>=yY
+cL
+iH1[t12+=count
+n31
+iB[t12!=0
+lL3
+lO3
+c82){cC1<yY)iB[t12=1
+lL3
+Start
+iA1
+value1_pos){for(int
+n=2;n<yY;++n)iB[n]=-1;Remember(1,value1_pos);DumpContents();}
+int
+Find(c82
+e83{cC1<yY){if(iB[t12>=0){FPO(iM3(iR3,"* I found %ld from cache (%u,%d)\n",value,(unsigned)cache[value],iN3 value]))n31
+iB[t12;eW2-1
+lL3
+Remember(c82,size_t
+l04){cC1>=yY)return;FPO(iM3(iR3,"* Remembering that %ld can be found at %u (%d uses remain)\n",value,(unsigned)l04,iN3 value]));iB[t12=(int)l04
+lL3
+DumpContents
+e73
+FPO(for(int a=1;a<POWI_CACHE_SIZE;++a)if(cache[a]>=0||iN3 a]>0){iM3(iR3,"== cache: sp=%d, val=%d, needs=%d\n",cache[a],a,iN3 a]);})}
+int
+UseGetNeeded(c82){cC1>=0&&value<yY)return--iH1[t12
+n31
+0;}
+}
+nJ1
+size_t
+y8
+long
+count
+lF2
+cI&eU,yM1
+xR3
+c01
+size_t
+apos,long
+aval,size_t
+bpos,long
+bval
+lF2
+iF2
+cumulation_opcode,iF2
+cimulation_opcode_flip,yM1;void
+l41
+c82
+lF2
+int
+need_count,int
+l51=0){cC1<1)return;
+#ifdef FP_GENERATING_POWI_TABLE
+if(l51>32)throw
+false;
+#endif
+if(iB.Plan_Add(value,need_count
+nE3;long
+yA3
+1;cC1<POWI_TABLE_SIZE){yA3
+powi_table[t12
+lM3&128){half&=127
+lM3&64)yA3-tB2
+FPO(iM3(iR3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,value/half));l41
+half
+y93
+iB.lO3
+half)n31;}
+lJ2
+half&64){yA3-tB2}
+}
+else
+cC1&1)yA3
+value&((1<<POWI_WINDOW_SIZE)-1);else
+yA3
+value/2;long
+cN=value-half
+lM3>cN||half<0)std::swap(half,cN);FPO(iM3(iR3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,otherhalf))lM3==cN){l41
+half,iB,2,l51+1
+t43{l41
+half
+y93
+l41
+cN>0?cN:-cN
+y93}
+iB.lO3
+value);}
+xW3
+size_t
+y8
+c82
+lF2
+cI&eU,yM1{int
+yB3=iB.Find(value
+eY3
+yB3>=0)yR
+yB3;}
+long
+yA3
+1;cC1<POWI_TABLE_SIZE){yA3
+powi_table[t12
+lM3&128){half&=127
+lM3&64)yA3-tB2
+FPO(iM3(iR3,"* I want %ld, my plan is %ld * %ld\n",value,half,value/half));size_t
+xM2=y8
+half
+tX1
+if(iB
+lL2
+half)>0||xM2!=tY1){iI1
+xM2)cS2
+half,tY1);}
+x01
+value/half,eU,iS2
+size_t
+l04=tY1
+cS2
+value,l04);iB.DumpContents()n31
+l04;}
+lJ2
+half&64){yA3-tB2}
+}
+else
+cC1&1)yA3
+value&((1<<POWI_WINDOW_SIZE)-1);else
+yA3
+value/2;long
+cN=value-half
+lM3>cN||half<0)std::swap(half,cN);FPO(iM3(iR3,"* I want %ld, my plan is %ld + %ld\n",value,half,value-half))lM3==cN){size_t
+xM2=y8
+half
+tX1
+c01
+xM2,half,xM2,half,iB,eU.op_normal,eU.op_normal_flip,iS2}
+else{long
+part1=half;long
+part2=cN>0?cN:-cN;size_t
+part1_pos=y8
+part1
+tX1
+size_t
+part2_pos=y8
+part2
+tX1
+FPO(iM3(iR3,"Subdivide(%ld: %ld, %ld)\n",value,half,otherhalf));c01
+part1_pos,part1,part2_pos,part2,iB,cN>0?eU.op_normal:eU.op_inverse,cN>0?eU.op_normal_flip:eU.op_inverse_flip,iS2}
+size_t
+l04=tY1
+cS2
+value,l04);iB.DumpContents()n31
+l04;}
+tZ1
+c01
+size_t
+apos,long
+aval,size_t
+bpos,long
+bval
+lF2
+iF2
+cumulation_opcode,iF2
+cumulation_opcode_flip,yM1{int
+a_needed=iB
+lL2
+aval);int
+yC3=iB
+lL2
+bval);bool
+lM2
+tO3
+#define DUP_BOTH() do{if(apos<bpos){size_t tmp=apos;apos=bpos;bpos=tmp;lM2=!lM2;}FPO(iM3(iR3,"-> "iX3 iX3"op\n",(unsigned)apos,(unsigned)bpos));iI1 apos);iI1 apos==bpos?tY1:bpos);}while(0)
+#define DUP_ONE(p) do{FPO(iM3(iR3,"-> "iX3"op\n",(unsigned)p));iI1 p);}while(0)
+if(a_needed>0){if(yC3>0){nL2}
+e63
+bpos!=tY1)nL2
+else{lN2
+lM2=!lM2;}
+}
+}
+lJ2
+yC3>0){if(apos!=tY1)nL2
+else
+DUP_ONE(bpos);}
+e63
+apos==bpos&&apos==tY1)lN2
+iR2
+tY1&&bpos==yD3
+2){FPO(iM3(iR3,"-> op\n"));lM2=!lM2;}
+iR2
+yD3
+2&&bpos==tY1)FPO(iM3(iR3,"-> op\n"));iR2
+tY1)DUP_ONE(bpos);lJ2
+bpos==tY1){lN2
+lM2=!lM2;}
+else
+nL2}
+yE3
+lM2?cumulation_opcode_flip:cumulation_opcode,2);}
+tZ1
+cD1
+long
+count,cI&eU,yM1{while
+eL3<256){int
+yA3
+xH1::powi_table[count]lM3&128){half&=127;cD1
+half,eU,iS2
+count/=half;}
+else
+yF3
+if
+eL3==1)return;if(!eL3&1)){yE3
+cSqr,1);cD1
+count/2,eU,iS2}
+else{iI1
+tY1);cD1
+count-1,eU,iS2
+yE3
+cMul,2);}
+}
+}
+lF3
+xH1{tZ1
+x01
+long
+count,cI&eU,yM1{if
+eL3==0)lH2
+eU.basevalue);else{bool
+t22
+tO3
+if
+eL3<0){t22=true;count=-count;}
+if(false)cD1
+count,eU,iS2
+lJ2
+count>1){PowiCache
+iB;l41
+count,iB,1);size_t
+xK1=synth.GetStackTop();iB.Start(tY1);FPO(iM3(iR3,"Calculating result for %ld...\n",count));size_t
+xN2=y8
+count
+tX1
+size_t
+n_excess=yD3
+xK1;if(n_excess>0||xN2!=xK1-1){synth.DoPopNMov(xK1-1,xN2);}
+}
+if(t22)yE3
+eU.op_flip,1);}
+}
+}
+#endif
+#ifndef FPOptimizer_ValueRangeHH
+#define FPOptimizer_ValueRangeHH
+t5{lF3
+lP3{iM
+e12
+Comp{}
+;i31>e12
+Comp<nB
+cLess>xZ3<n9
+cLessOrEq>xZ3<=n9
+cGreater>xZ3>n9
+cGreaterOrEq>xZ3>=n9
+cEqual>xZ3==n9
+cNEqual>xZ3!=b;}
+}
+;}
+xW3
+e12
+cJ1{iV2
+val;bool
+known;cJ1():val(),known(false){}
+cJ1
+cG1
+v):val(v),known(true){xI1
+void
+set
+cG1
+v){known=true;val=v
+lL3
+set(iV2(iJ1(iV2),cJ1
+y9)val=iI2
+void
+set(iV2(iJ1
+cG1),cJ1
+y9)val=iI2
+iM
+void
+set_if(iV2
+v
+tG1
+iJ1(iV2),cJ1
+y9&&lP3::Comp<Compare>()(val,v))val=iI2
+iM
+void
+set_if
+cG1
+v
+tG1
+iJ1
+cG1),cJ1
+y9&&lP3::Comp<Compare>()(val,v))val=iI2}
+nJ1
+e12
+range{cJ1
+xK
+min,max;range():min(),max(){}
+range(iV2
+mi,iV2
+ma):min(mi),max(ma){}
+range(bool,iV2
+ma):min(),max(ma){}
+range(iV2
+mi,bool):min(mi),max(){}
+void
+set_abs();void
+set_neg();}
+nJ1
+bool
+IsLogicalTrueValue
+cH1
+c23&p
+tR2
+nJ1
+bool
+IsLogicalFalseValue
+cH1
+c23&p
+tR2;}
+#endif
+#ifndef FPOptimizer_RangeEstimationHH
+#define FPOptimizer_RangeEstimationHH
+t5{enum
+TriTruthValue{IsAlways,IsNever,Unknown}
+nJ1
+c23
+iN
+lC2
+tree)nJ1
+bool
+IsLogicalValue
+cH1
+e62
+nJ1
+TriTruthValue
+GetIntegerInfo
+cH1
+e62
+nJ1
+xL1
+GetEvennessInfo
+cH1
+e62{if(!tree
+i61)return
+Unknown;yJ1=eC3;if(isEvenInteger(value
+nF3
+isOddInteger(value
+nG3
+xW3
+xL1
+GetPositivityInfo
+cH1
+e62{c23
+p=iN
+tree
+eY3
+p
+n51&&p
+tF2>=iV2(nF3
+p
+yN
+known
+lH1
+nG3
+xW3
+xL1
+GetLogicalValue
+lQ3
+tree
+tR2{c23
+p=iN
+tree
+eY3
+IsLogicalTrueValue(p,abs
+nF3
+IsLogicalFalseValue(p,abs
+nG3}
+#endif
+#ifndef FPOptimizer_ConstantFoldingHH
+#define FPOptimizer_ConstantFoldingHH
+t5{tZ1
+ConstantFolding(e62;}
+#endif
+lF3{using
+lF3
+FUNCTIONPARSERTYPES;using
+t5;e12
+ComparisonSetBase{enum{t93=0x1,Eq_Mask=0x2,Le_Mask=0x3,tA3=0x4,tB3=0x5,Ge_Mask=0x6}
+;static
+int
+Swap_Mask(int
+m)yR(m&Eq_Mask)|((m&t93)?tA3:0)|((m&tA3)?t93:0);}
+enum
+c11{Ok,BecomeZero,BecomeOne,xP2
+xF3
+nW2{cond_or,iK2,iL2,iM2}
+;}
+nJ1
+e12
+ComparisonSet:public
+ComparisonSetBase{e12
+t32{eJ
+a;eJ
+b;int
+relationship;t32():a(),b(),relationship(){}
+}
+;std
+xV3<t32>eK;e12
+Item{eJ
+value;bool
+c52;Item():value(),c52(false){}
+}
+;std
+xV3<Item>cK1;int
+xM1;ComparisonSet():eK(),cK1(),xM1(0){}
+c11
+AddItem
+lQ3
+a,bool
+c52,nW2
+type){for
+iA1
+c=0;c<cK1.tF3;++c)if(cK1[c].value
+xF
+a)){if(c52!=cK1[c].c52){iQ
+cW1
+case
+iM2:cK1.erase(cK1.begin()+c);xM1+=1
+n31
+xP2;case
+iK2:case
+iL2:cX1
+eW2
+xP2;}
+Item
+pole;pole.value=a;pole.c52=c52;cK1.push_back(pole)n31
+Ok;}
+c11
+AddRelationship(eJ
+a,eJ
+b,int
+tO1,nW2
+type){iQ
+if(tO1==7)cW1
+lC
+iM2:if(tO1==7){xM1+=1
+n21
+lC
+iK2:case
+iL2:if(tO1==0)cX1
+yF3
+if(!(a.GetHash()<b.GetHash())){a.swap(b);tO1=Swap_Mask(tO1);}
+for
+iA1
+c=0;c<eK.tF3;++c){if(eK[c].a
+xF
+a)&&eK[c].b
+xF
+b)){iQ{int
+yQ3=xO2|tO1;if(yQ3==7)cW1
+xO2=yQ3;yF3
+case
+iK2:case
+iL2:{int
+yQ3=xO2&tO1;if(yQ3==0)cX1
+xO2=yQ3;yF3
+case
+iM2:{int
+newrel_or=xO2|tO1;int
+xR2=xO2&tO1;lP2
+5&&xR2==0){xO2=tB3
+n21
+lP2
+7&&xR2==0){xM1+=1;eK.erase(eK.begin()+c)n21
+lP2
+7&&xR2==Eq_Mask){xO2=Eq_Mask;xM1+=1
+n21
+eR2}
+return
+xP2;}
+}
+t32
+comp;comp.a=a;comp.b=b;comp.relationship=tO1;eK.push_back(comp)n31
+Ok;}
+}
+;nR1
+iV2,xK3
+CondType>bool
+ConstantFolding_LogicCommon(eJ&tree,CondType
+xA1,bool
+xS2){bool
+should_regenerate
+tO3
+ComparisonSet
+xK
+comp;nB1{xK3
+c6
+c11
+eM3=c6
+Ok;lC2
+atree=t33;switch(atree
+nC
+y33
+cEqual
+lG
+Eq_Mask,xA1);lC
+cNEqual
+lG
+tB3,xA1);lC
+cLess
+lG
+t93,xA1);lC
+cLessOrEq
+lG
+Le_Mask,xA1);lC
+cGreater
+lG
+tA3,xA1);lC
+cGreaterOrEq
+lG
+Ge_Mask,xA1);lC
+cNot:eM3
+yO1
+l8
+0),true,xA1);lC
+cNotNot:eM3
+yO1
+l8
+0),false,xA1);break;c73
+if(xS2||IsLogicalValue(atree))eM3
+yO1,false,xA1);l73
+eM3){ReplaceTreeWithZero:xO
+0)n31
+true;ReplaceTreeWithOne:xO
+1);nV
+c6
+Ok:lC
+c6
+BecomeZero
+eL
+c6
+BecomeOne:i6
+c6
+xP2:c41
+yF3}
+if(should_regenerate){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantFolding_LogicCommon: "
+yA1
+#endif
+if(xS2){tree.DelParams(t43{for
+iY{lC2
+atree=lE2
+a
+eY3
+IsLogicalValue(atree))eK2}
+for
+iA1
+a=0;a<comp.cK1.tF3;++a){if(comp.cK1[a].c52
+iJ2
+cNot);r.c5
+r
+cK
+r);}
+lJ2!xS2
+iJ2
+cNotNot);r.c5
+r
+cK
+r
+t43
+tree.c5}
+for
+iA1
+a=0;a<comp.eK.tF3;++a
+iJ2
+cNop);switch(comp.eK[a
+eA
+y33
+c6
+t93:r
+xD
+cLess);lC
+c6
+Eq_Mask:r
+xD
+cEqual);lC
+c6
+tA3:r
+xD
+cGreater);lC
+c6
+Le_Mask:r
+xD
+cLessOrEq);lC
+c6
+tB3:r
+xD
+cNEqual);lC
+c6
+Ge_Mask:r
+xD
+cGreaterOrEq
+cT2
+r
+yP1
+comp.eK[a].a);r
+yP1
+comp.eK[a].b);r
+cK
+r);}
+if(comp.xM1!=0)tree.yC
+iV2(comp.xM1)));
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantFolding_LogicCommon: "
+yA1
+#endif
+return
+true;}
+return
+tR3
+xN1
+ConstantFolding_AndLogic(iS3(tree.GetOpcode()==cAnd||tree.GetOpcode()==cAbsAnd)n31
+nI
+iK2,true);}
+xN1
+ConstantFolding_OrLogic(iS3(tree.GetOpcode()==cOr||tree.GetOpcode()==cAbsOr)n31
+nI
+cond_or,true);}
+xN1
+ConstantFolding_AddLogicItems(iS3(tree.GetOpcode()==cAdd)n31
+nI
+iM2,false);}
+xN1
+ConstantFolding_MulLogicItems(iS3(tree.GetOpcode()==cMul)n31
+nI
+iL2,false);}
+}
+#include <vector>
+#include <map>
+#include <algorithm>
+lF3{using
+lF3
+FUNCTIONPARSERTYPES;using
+t5;e12
+CollectionSetBase{enum
+xR1{Ok,xP2}
+;}
+nJ1
+e12
+CollectionSet:public
+CollectionSetBase{e12
+c21{eJ
+value;eJ
+xT2;bool
+cX;c21():value(),xT2(),cX(false){}
+c21
+lQ3
+v,lC2
+f):value(v),xT2(f),cX(false){}
+}
+;std::multimap<fphash_t,c21>iC;typedef
+xK3
+std::multimap<fphash_t,c21>::yV3
+xS1;CollectionSet():iC(){}
+xS1
+FindIdenticalValueTo
+lQ3
+value){fphash_t
+hash=value.GetHash();for(xS1
+i=iC.xU2
+hash);i!=iC.cY1
+hash;++i){cC1
+xF
+i
+e82.value
+nE3
+i;}
+return
+iC.end();}
+bool
+Found
+cH1
+xS1&b)yR
+b!=iC.end();}
+xR1
+AddCollectionTo
+lQ3
+xT2,const
+xS1&into_which){c21&c=into_which
+e82;if(c.cX)c.xT2
+c9
+xT2);else{eJ
+add;add
+xD
+cAdd);add
+yP1
+c.xT2);add
+c9
+xT2);c.xT2.swap(add);c.cX=true;}
+return
+xP2;}
+xR1
+nX2
+lQ3
+value,lC2
+xT2){const
+fphash_t
+hash=value.GetHash();xS1
+i=iC.xU2
+hash);for(;i!=iC.cY1
+hash;++i){if(i
+e82.value
+xF
+value
+nE3
+AddCollectionTo(xT2,i);}
+iC.yR3,std::make_pair(hash,c21(value,xT2)))n31
+Ok;}
+xR1
+nX2
+lQ3
+a)yR
+nX2(a,nF1
+1)));}
+}
+nJ1
+e12
+ConstantExponentCollection{typedef
+eH
+yT3;typedef
+std::x31
+xV2;std
+xV3<xV2>data;ConstantExponentCollection():data(){}
+void
+MoveToSet_Unique
+cG1
+eB1&eC1){data.push_back(std::x31(eB1()));data.back()tE3.swap(eC1
+lI3
+MoveToSet_NonUnique
+cG1
+eB1&eC1){xK3
+std
+xV3<xV2>::yV3
+i=std::xU2
+data.iN2
+data.end(),exponent,Compare1st()eY3
+i!=data.cY1
+xG2{i
+e82.yR3
+e82.end(),eC1.iN2
+eC1.end()t43{data.yR3,std::x31
+t62,eC1));}
+}
+bool
+Optimize(){bool
+changed
+tO3
+std::sort(data.iN2
+data.end(),Compare1st());redo:for
+iA1
+a=0;a<data.tF3;++a
+tJ2
+exp_a=data[a
+tC3
+cA3
+exp_a
+tG1
+1))cP2;for
+iA1
+b=a+1;b<data.tF3;++b
+tJ2
+exp_b=data[b
+tC3
+iU2
+xW2=exp_b-exp_a;if(xW2>=fp_abs(exp_a))break
+iU2
+exp_diff_still_probable_integer=xW2*iV2(16
+eY3
+t42
+exp_diff_still_probable_integer)&&!(t42
+exp_b)&&!t42
+xW2))){yT3&a_set=lQ2;yT3&b_set=data[b
+tD3;
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantExponentCollection iteration:\n"
+;t52
+cout);
+#endif
+if(isEvenInteger(exp_b)&&!isEvenInteger(xW2+exp_a)){eJ
+tmp2;tmp2
+tH3
+tmp2
+iO3
+b_set);tmp2
+eT1
+t81
+cAbs);tmp
+yP1
+tmp2);tmp
+eT1
+b_set.t73
+1);b_set[0].i72}
+a_set.insert(a_set.end(),b_set.iN2
+b_set.end());yT3
+b_copy=b_set;data.erase(data.begin()+b);MoveToSet_NonUnique(xW2,b_copy);x62
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantExponentCollection iteration:\n"
+;t52
+cout);
+#endif
+cZ}
+eW2
+changed;}
+#ifdef DEBUG_SUBSTITUTIONS
+void
+t52
+ostream&out){for
+iA1
+a=0;a<data.tF3;++a){out.precision(12);out<<data[a
+tC3<<": "
+;i81
+lQ2.tF3;++b){if(b>0)out<<'*'i13(lQ2[b],out);}
+out<<std::endl;}
+}
+#endif
+}
+nJ1
+static
+eJ
+x41
+eJ&value,bool&xH
+y13
+value
+nC
+y33
+cPow:{eJ
+e92
+value
+l8
+1);value.y81
+n31
+exponent;}
+case
+cRSqrt:value.y81;xH=true
+n31
+nF1-0.5));case
+cInv:value.y81;xH=true
+n31
+nF1-1));c73
+yF3
+return
+nF1
+1));}
+cA1
+void
+eD1
+eV1&mul,lC2
+tree,lC2
+xT2,bool&c31
+bool&xH){nB1{eJ
+value
+y91
+a));eJ
+exponent(x41
+value,xH)eY3!xT2
+i61||xT2
+nC1!=iV2(1.0)){eJ
+cZ1;cZ1
+tH3
+cZ1
+c9
+xG2;cZ1
+c9
+xT2);cZ1
+eT1
+exponent.swap(cZ1);}
+#if 0 /* FIXME: This does not work */
+cC1
+nC==cMul){if(1){bool
+exponent_is_even=exponent
+i61&&isEvenInteger
+t62
+nC1);i81
+value.tP3{bool
+tmp
+tO3
+eJ
+val(value
+l8
+b));eJ
+exp(x41
+val,tmp)eY3
+exponent_is_even||(exp
+i61&&isEvenInteger(exp
+nC1))){eJ
+cZ1;cZ1
+tH3
+cZ1
+c9
+xG2;cZ1
+yP1
+exp);cZ1.ConstantFolding(eY3!cZ1
+i61||!isEvenInteger(cZ1
+nC1)){goto
+cannot_adopt_mul;}
+}
+}
+}
+eD1
+mul,value,exponent,c31
+xH
+t43
+cannot_adopt_mul:
+#endif
+{if(mul.nX2(value,xG2==CollectionSetBase::xP2)c41}
+}
+}
+xN1
+ConstantFolding_MulGrouping(e62{bool
+xH
+tO3
+bool
+should_regenerate
+tO3
+eV1
+mul;eD1
+mul,tree,nF1
+1)),c31
+xH);typedef
+std::pair<eJ,eH>eE1;typedef
+std::multimap<fphash_t,eE1>cL1;cL1
+tD;xX2
+eV1::xS1
+j=mul.iC.yU3
+j!=mul.iC.end();++j){eJ&value=j
+e82.value;eJ&e92
+j
+e82.xT2;if(j
+e82.cX)exponent
+eT1
+const
+fphash_t
+eF1=exponent.GetHash();xK3
+cL1::yV3
+i=tD.xU2
+eF1);for(;i!=tD.cY1
+eF1;++i)if(i
+e82.first
+xF
+xG2){if(!exponent
+i61||!e01
+nC1
+tG1
+1)))c41
+i
+e82
+tE3.push_back(value);goto
+skip_b;}
+tD.yR3,std::make_pair(eF1,std::make_pair
+t62,eH
+iA1(1),value))));skip_b:;}
+#ifdef FP_MUL_COMBINE_EXPONENTS
+ConstantExponentCollection
+xK
+e11;xX2
+cL1::yV3
+j,i=tD.yU3
+i!=tD.end();i=j){j=i;++j;eE1&list=i
+e82;if(list.first
+l71
+e92
+list.first
+nC1;if(!t62==xD1)e11.MoveToSet_Unique
+t62,list
+iO2;tD.erase(i);}
+}
+if(e11.Optimize())c41
+#endif
+if(should_regenerate){eJ
+before=tree;before.l61
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantFolding_MulGrouping: "
+i13(before
+lT2"\n"
+;
+#endif
+tree.DelParams();xX2
+cL1::yV3
+i=tD.yU3
+i!=tD.end();++i){eE1&list=i
+e82;
+#ifndef FP_MUL_COMBINE_EXPONENTS
+if(list.first
+l71
+e92
+list.first
+nC1;if
+t62==xD1
+continue;if(e01
+xE3
+tree.AddParamsMove(list
+iO2;eR2}
+#endif
+eJ
+mul;mul
+tH3
+mul
+iO3
+list
+iO2;mul
+eT1
+if(xH&&list.first
+i51
+list.first
+nC1==iV2(1)/iV2(3)){eJ
+cbrt;cbrt
+xD
+cCbrt);cbrt.e4
+cbrt
+cK
+cbrt
+xW
+0.5)){eJ
+sqrt;sqrt
+xD
+cSqrt);sqrt.e4
+sqrt
+cK
+sqrt
+xW-0.5)){eJ
+rsqrt;rsqrt
+xD
+cRSqrt);rsqrt.e4
+rsqrt
+cK
+rsqrt
+xW-1)){eJ
+inv;inv
+xD
+cInv);inv.e4
+inv
+cK
+inv);eR2}
+eJ
+pow;pow
+xD
+cPow);pow.e4
+pow
+yP1
+list.first);pow
+cK
+pow);}
+#ifdef FP_MUL_COMBINE_EXPONENTS
+tD.clear()yM3
+0;a<i3.tF3;++a
+tJ2
+e92
+i3[a
+tC3;if(e01
+xE3
+tree.AddParamsMove(i3[a]iO2;eR2
+eJ
+mul;mul
+tH3
+mul
+iO3
+i3[a]iO2;mul
+eT1
+eJ
+pow;pow
+xD
+cPow);pow.e4
+pow.yC
+xG2);pow
+cK
+pow);}
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantFolding_MulGrouping: "
+yA1
+#endif
+return!tree
+xF
+before);}
+return
+tR3
+xN1
+ConstantFolding_AddGrouping(e62{bool
+should_regenerate
+tO3
+eV1
+add;nB1{if
+y91
+a)nC==cMul
+cP2;if(add.nX2
+y91
+a))==CollectionSetBase::xP2)c41}
+std::eV2
+remaining(eM);size_t
+tE=0;nB1{lC2
+mulgroup=t33;if
+lR3
+nC==cMul){i81
+yQ1
+tP3{if
+lR3
+l8
+b)i61
+cP2;xK3
+eV1::xS1
+c=add.FindIdenticalValueTo
+lR3
+l8
+b)eY3
+add.Found(c)){eJ
+tmp
+lR3
+yA
+CloneTag());tmp
+tK2
+b);tmp
+eT1
+add.AddCollectionTo(tmp,c);c41
+goto
+done_a;}
+}
+remaining[a]=true;tE+=1;done_a:;}
+}
+if(tE>0){if(tE>1){std
+xV3<std::pair<eJ,size_t> >nU;std::multimap<fphash_t,size_t>eG1;bool
+lS3
+tO3
+nB1
+iC1{i81
+t33.tP3{lC2
+p=t33
+l8
+b);const
+fphash_t
+p_hash=p.GetHash();for(std::multimap<fphash_t,size_t>::const_iterator
+i=eG1.xU2
+p_hash);i!=eG1.cY1
+p_hash;++i){if(nU[i
+e82
+tC3
+xF
+p)){nU[i
+e82
+tD3+=1;lS3=true;goto
+found_mulgroup_item_dup;}
+}
+nU.push_back(std::make_pair(p,size_t(1)));eG1.insert(std::make_pair(p_hash,nU.tF3-1));found_mulgroup_item_dup:;}
+}
+if(lS3){eJ
+eA2;{size_t
+max=0;for
+iA1
+p=0;p<nU.tF3;++p)if(nU[p
+tD3<=1)nU[p
+tD3=0;else{nU[p
+tD3*=nU[p
+tC3.y22;if(nU[p
+tD3>max){eA2=nU[p
+tC3;max=nU[p
+tD3;}
+}
+}
+eJ
+group_add;group_add
+xD
+cAdd);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Duplicate across some trees: "
+i13(eA2
+lT2" in "
+yA1
+#endif
+nB1
+iC1
+i81
+t33.tP3
+if(eA2
+xF
+t33
+l8
+b))){eJ
+tmp
+y91
+a)yA
+CloneTag());tmp
+tK2
+b);tmp
+eT1
+group_add
+yP1
+tmp);remaining[a]tO3
+yF3
+group_add
+eT1
+eJ
+group;group
+tH3
+group
+yP1
+eA2);group
+yP1
+group_add);group
+eT1
+add.nX2(group);c41}
+}
+nB1
+iC1{if(add.nX2
+y91
+a))==CollectionSetBase::xP2)c41}
+}
+if(should_regenerate){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before ConstantFolding_AddGrouping: "
+yA1
+#endif
+tree.DelParams();xX2
+eV1::xS1
+j=add.iC.yU3
+j!=add.iC.end();++j){eJ&value=j
+e82.value;eJ&coeff=j
+e82.xT2;if(j
+e82.cX)coeff
+eT1
+if(coeff
+i51
+cB3
+coeff
+nC1,xD1
+cP2
+cA3
+coeff
+nC1
+xE3
+lP1
+value);eR2}
+eJ
+mul;mul
+tH3
+mul
+yP1
+value);mul
+yP1
+coeff);mul
+cK
+mul);}
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After ConstantFolding_AddGrouping: "
+yA1
+#endif
+return
+true;}
+return
+tR3}
+lF3{using
+lF3
+FUNCTIONPARSERTYPES;using
+t5
+nJ1
+bool
+ConstantFolding_IfOperations(iS3(tree.GetOpcode()==cIf||tree.GetOpcode()==cAbsIf);for(;;){lT3
+nC==cNot){tI3
+cIf);lE2
+0).xY2
+0)lR2
+eO3.swap
+y91
+2)t43
+lT3
+cS1{tI3
+yW3;lE2
+0).xY2
+0)lR2
+eO3.swap
+y91
+2)t43
+yJ3
+tM
+0),i01==yW3)l92
+tree.xY2
+1));nV
+lC3
+tree.xY2
+2));nV
+lT1
+lT3
+nC==cIf||lE2
+0)nC==yW3{eJ
+cond=lE2
+0);eJ
+lU3;lU3
+t53==cIf?cNotNot:cAbsNotNot);lU3
+xZ2
+1));ConstantFolding(lU3);eJ
+lV3;lV3
+t53==cIf?cNotNot:cAbsNotNot);lV3
+xZ2
+2));ConstantFolding(lV3
+eY3
+lU3
+i61||lV3
+i61){eJ
+eV;eV
+t53);eV
+xZ2
+1));eV.nJ
+1));eV.nJ
+2));eV
+eT1
+eJ
+eW;eW
+t53);eW
+xZ2
+2));eW.nJ
+1));eW.nJ
+2));eW
+eT1
+tree
+t53);cM1
+0,cond
+lR2
+tree.nG1
+1,eV);tree.nG1
+2,eW)xJ2}
+if
+y91
+1)nC==lE2
+2)nC&&y91
+1)nC==cIf||eO3
+nC==yW3){eJ&iE2=eO3;eJ&leaf2=lE2
+2
+eY3
+iE2
+l8
+0)xC1
+0))&&c93
+1))||iE2
+l8
+2)xC1
+2)))){eJ
+eV;eV
+iP2
+eV.nJ
+0));eV
+c9
+iE2
+l8
+1));eV
+c9
+leaf2
+l8
+1));eV
+eT1
+eJ
+eW;eW
+iP2
+eW.nJ
+0));eW
+c9
+iE2
+l8
+2));eW
+c9
+leaf2
+l8
+2));eW
+iU
+SetParam(0,iE2
+lR2
+tree.nG1
+1,eV);tree.nG1
+2,eW)xJ2
+if
+c93
+1))&&iE2
+l8
+2)xC1
+2))){eJ
+eX;eX
+iP2
+eX.AddParamMove
+y91
+0));eX
+c9
+iE2
+lR2
+eX
+c9
+leaf2
+lR2
+eX
+iU
+nG1
+0,eX);cM1
+2,iE2
+l8
+2));cM1
+1,iE2
+l8
+1))xJ2
+if
+c93
+2))&&iE2
+l8
+2)xC1
+1))){eJ
+eB2;eB2
+xD
+leaf2
+nC==cIf?cNot:cZ3);eB2
+c9
+leaf2
+lR2
+eB2
+eT1
+eJ
+eX;eX
+iP2
+eX.AddParamMove
+y91
+0));eX
+c9
+iE2
+lR2
+eX
+yP1
+eB2);eX
+iU
+nG1
+0,eX);cM1
+2,iE2
+l8
+2));cM1
+1,iE2
+l8
+1))xJ2}
+eJ&xX=eO3;eJ&y6=lE2
+2
+eY3
+xX
+xF
+y6)){tree.xY2
+1))xJ2
+const
+OPCODE
+op1=xX
+nC;const
+OPCODE
+op2=y6
+nC;if
+eN3
+op2){if(xX
+cE1
+1){eJ
+lO
+0));lW3
+lR2
+tQ3
+n4
+if(xX
+cE1
+2&&y6
+cE1
+2){if(xX
+l8
+0)xF
+y6
+l8
+0))){eJ
+param0=xX
+l8
+0);eJ
+lO
+1));lW3
+l8
+1));tQ3;lP1
+param0)n4
+if(xX
+l8
+1)xF
+y6
+l8
+1))){eJ
+param1=xX
+l8
+1);eJ
+lO
+0));lW3
+lR2
+tQ3;lP1
+nE1);lP1
+param1)xJ2}
+if
+eN3
+yZ3
+cMul
+lS2
+cAnd
+lS2
+cOr
+lS2
+cAbsAnd
+lS2
+cAbsOr
+lS2
+cMin
+lS2
+cMax){eH
+lX3;yZ{for
+iA1
+b=y6.xF1
+b-->0;){if
+c62
+y6
+l8
+b))){if(lX3
+cT3){xX.l61
+y6.l61}
+lX3.push_back(xX
+x13
+y6
+tK2
+b);xX
+t31
+cT2}
+}
+if(!lX3
+cT3){xX
+eT1
+y6.Rehash()l7
+op1);tree
+iO3
+lX3)n4}
+}
+if
+eN3
+yZ3
+cMul||eN3
+cAnd
+nT1
+y6))||eN3
+cOr
+nT1
+y6))){yZ
+if
+c62
+y6)){xX.l61
+xX
+t31);xX
+eT1
+eJ
+cO1=y6;y6=tF
+op1==yZ3
+cOr
+tE2
+op1);lP1
+cO1)n4}
+if(eN3
+cAnd
+lS2
+cOr)&&op2==cNotNot){eJ&lY3=y6
+l8
+0);yZ
+if
+c62
+lY3)){xX.l61
+xX
+t31);xX
+eT1
+eJ
+cO1=lY3;y6=tF
+op1
+yY3
+op1);lP1
+cO1)n4}
+if(op2==cAdd||op2==cMul||(op2==cAnd
+nT1
+xX))||(op2==cOr
+nT1
+xX))){for
+iA1
+a=y6
+n41
+y6
+l8
+a)xF
+xX)){y6.l61
+y6
+t31);y6
+eT1
+eJ
+cP1=xX;xX=tF
+op2==cAdd||op2
+yY3
+op2);lP1
+cP1)n4}
+if((op2==cAnd||op2==cOr)&&op1==cNotNot){eJ&lZ3=xX
+l8
+0)yM3
+y6
+n41
+y6
+l8
+a)xF
+lZ3)){y6.l61
+y6
+t31);y6
+eT1
+eJ
+cP1=lZ3;xX=tF
+op2
+yY3
+op2);lP1
+cP1)n4}
+return
+tR3}
+#include <limits>
+lF3{using
+lF3
+FUNCTIONPARSERTYPES;using
+t5
+nJ1
+int
+maxFPExponent()yR
+std::numeric_limits
+xK::max_exponent;}
+xN1
+x51
+iV2
+base,iV2
+xG2{if(base<xD1
+return
+true
+cA3
+base,xD1||cB3
+base
+tG1
+1))cL
+return
+exponent>=iV2(maxFPExponent
+xK())/fp_log2(base);}
+xN1
+ConstantFolding_PowOperations(iS3(tree.GetOpcode()==cPow);nR&&eO3
+l71
+const_value
+t03
+lR,tH);xO
+const_value)n31
+tR3
+tM2
+cB3
+tH
+xE3
+tree.xY2
+0))xJ2
+nR&&cB3
+lR
+xE3
+xO
+1)n31
+tR3
+nR&&eO3
+nC==cMul){bool
+y02=false
+iU2
+lU2=lR;eJ
+mulgroup=eO3
+yM3
+mulgroup
+n41
+mulgroup
+l8
+a)l71
+imm=mulgroup
+l8
+a)nC1;{if(x51
+lU2,imm))break
+iU2
+lV2
+t03
+lU2,imm)cA3
+lV2,xD1)break;if(!y02){y02=true;yQ1
+l61}
+lU2=lV2;yQ1
+DelParam(a
+cT2}
+if(y02){yQ1
+Rehash();
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before pow-mul change: "
+yA1
+#endif
+lE2
+0).Become(e21
+lU2));eO3.Become
+lR3);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After pow-mul change: "
+yA1
+#endif
+}
+}
+tM2
+lE2
+0)nC==cMul
+tJ2
+lW2=tH
+iU2
+y12=1.0;bool
+y02
+tO3
+eJ&mulgroup=lE2
+0)yM3
+mulgroup
+n41
+mulgroup
+l8
+a)l71
+imm=mulgroup
+l8
+a)nC1;{if(x51
+imm,lW2))break
+iU2
+eH1
+t03
+imm,lW2)cA3
+eH1,xD1)break;if(!y02){y02=true;yQ1
+l61}
+y12*=eH1;yQ1
+DelParam(a
+cT2}
+if(y02){yQ1
+Rehash();eJ
+eS3;eS3
+xD
+cPow);eS3
+iO3
+tree.l02));eS3.n62
+tree
+tH3
+lP1
+eS3);i83
+e21
+y12))xJ2}
+lT3
+nC==cPow&&eO3
+i61&&lE2
+0)l8
+1)l71
+a=lE2
+0)l8
+1)nC1
+iU2
+b=tH
+iU2
+c=a*b;if(isEvenInteger(a)&&!isEvenInteger(c)){eJ
+n03;n03
+xD
+cAbs);n03.nJ
+0)lR2
+n03
+eT1
+tree.nG1
+0,n03
+t43
+cM1
+0,lE2
+0)lR2
+cM1
+1,e21
+c));}
+return
+tR3}
+lF3{using
+lF3
+FUNCTIONPARSERTYPES;using
+t5;e12
+l5{enum
+eC2{MakeFalse=0,MakeTrue=1,t72=2,n23=3,MakeNotNotP0=4,MakeNotNotP1=5,MakeNotP0=6,MakeNotP1=7,xB=8
+xF3
+lX2{Never=0,Eq0=1,Eq1=2,c03=3,c13=4}
+;eC2
+if_identical;eC2
+lY2
+4];e12{eC2
+what:4;lX2
+when:4;}
+iK1,iL1,iM1,iN1
+nJ1
+eC2
+Analyze
+lQ3
+a,lC2
+b
+e83{if(a
+xF
+b
+nE3
+if_identical;c23
+p0=iN
+a);c23
+p1=iN
+b);eR3
+known&&p1
+n51){eR3
+val<p1
+tF2&&lY2
+0]i4
+0];eR3
+val<=p1
+tF2&&lY2
+1]i4
+1];}
+if
+iC3
+p1
+xF2{if(p0
+tF2>p1
+yN
+val&&lY2
+2]i4
+2];if(p0
+tF2>=p1
+yN
+val&&lY2
+3]i4
+3];}
+if(IsLogicalValue(a)){if(iK1
+tP2
+iK1.when,p1
+nE3
+iK1.what;if(iM1
+tP2
+iM1.when,p1
+nE3
+iM1.what;}
+if(IsLogicalValue(b)){if(iL1
+tP2
+iL1.when,p0
+nE3
+iL1.what;if(iN1
+tP2
+iN1.when,p0
+nE3
+iN1.what;}
+return
+xB;}
+cA1
+bool
+TestCase(lX2
+when,const
+c23&p){if(!p
+n51||!p
+yN
+known
+cL
+switch(when
+y33
+Eq0
+nV1==iV2(0.0)&&e13==p
+tF2;case
+Eq1
+nV1==iV2(1.0)&&e13==e13;case
+c03
+nV1>y21&&e13<=iV2(1);case
+c13
+nV1>=y21
+lH1
+1);c73;}
+return
+tR3}
+;lF3
+RangeComparisonsData{static
+const
+l5
+Data[6]={{l5
+c51,{l5::tU
+xB,l5::tU
+xB
+iT
+Eq1
+iW
+Eq1
+nX1
+Eq0
+nY1
+Eq0}
+eI1
+c51,l5::xB,l5
+c51,l5::xB
+iT
+Eq0
+iW
+Eq0
+nX1
+Eq1
+nY1
+Eq1}
+eI1
+c51,l5::t72,l5::tU
+MakeFalse
+nX1
+c03
+iW
+c13
+yD
+cC
+yD
+n13{l5::xB,l5
+c51,l5::tU
+n23
+nX1
+c13
+iW
+c03
+yD
+cC
+eI1::tU
+tU
+n13
+l5::t72
+iT
+c13
+nY1
+c03
+yD
+cC
+yD
+n13{l5::tU
+n23,l5::xB,l5
+c51
+iT
+c03
+nY1
+c13
+yD
+cC}
+}
+;}
+xN1
+ConstantFolding_Comparison(e62{using
+lF3
+RangeComparisonsData;assert(tree.GetOpcode()>=cEqual&&tree.GetOpcode()<=cGreaterOrEq);switch(Data[i01-cEqual].Analyze
+y91
+0),eO3)y33
+l5::MakeFalse:xO
+0);nV
+l5
+c51:xO
+1)yN3
+n23:tI3
+cEqual)yN3
+t72:tI3
+cNEqual)yN3
+MakeNotNotP0:tI3
+cNotNot)yO3
+1)yN3
+MakeNotNotP1:tI3
+cNotNot)yO3
+0)yN3
+MakeNotP0:tI3
+cNot)yO3
+1)yN3
+MakeNotP1:tI3
+cNot)yO3
+0)yN3
+xB:;}
+if
+y91
+1)i61)switch
+y91
+0)nC
+y33
+cAsin:lM
+fp_sin
+c53
+cAcos:lM
+fp_cos
+tG));tI3
+i01==cLess?cGreater:i01==cLessOrEq?cGreaterOrEq:i01==cGreater?cLess:i01==cGreaterOrEq?cLessOrEq:i01);nV
+cAtan:lM
+fp_tan
+c53
+cLog:lM
+fp_exp
+c53
+cSinh:lM
+fp_asinh
+c53
+cTanh:if(fp_less(fp_abs
+tG
+xE3
+lM
+fp_atanh
+tG))xJ2
+break;c73
+yF3
+return
+tR3}
+#include <list>
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;lF3{
+#ifdef DEBUG_SUBSTITUTIONS
+yE
+double
+d){union{double
+d;uint_least64_t
+h;}
+t82
+d=d;lM1
+h
+nZ1
+#ifdef FP_SUPPORT_FLOAT_TYPE
+yE
+float
+f){union{float
+f;uint_least32_t
+h;}
+t82
+f=f;lM1
+h
+nZ1
+#endif
+#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE
+yE
+long
+double
+ld){union{long
+double
+ld;e12{uint_least64_t
+a;iF2
+short
+b;}
+s;}
+t82
+ld=ld;lM1
+s.b<<data.s.a
+nZ1
+#endif
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+yE
+long
+ld){o<<"("
+<<std::hex<<ld
+nZ1
+#endif
+#endif
+}
+t5{lN
+nE)){}
+lN
+const
+iV2&i
+yA
+xO3
+nE
+i)){data
+x7
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+lN
+iV2&&i
+yA
+xO3
+nE
+std::move(i))){data
+x7
+#endif
+lN
+iF2
+v
+yA
+VarTag
+nE
+l03,v
+xQ2
+xB2
+o
+yA
+OpcodeTag
+nE
+o
+xQ2
+xB2
+o,iF2
+f
+yA
+FuncOpcodeTag
+nE
+o,f
+xQ2
+lC2
+b
+yA
+CloneTag
+nE*b.data)){}
+xW3
+eJ::~CodeTree(){}
+lB
+ReplaceWithImmed
+cG1
+i){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Replacing "
+i13(*this
+eY3
+IsImmed())OutFloatHex(std::cout,GetImmed()lT2" with const value "
+<<i;OutFloatHex(std::cout,i
+lT2"\n"
+;
+#endif
+data=new
+xH2
+xK(i);}
+xW3
+e12
+ParamComparer{iG2()lQ3
+a,lC2
+b
+e83{if(a.y22!=b.y22)return
+a.y22<b.y22
+n31
+a.GetHash()<b.GetHash();}
+}
+xR3
+xH2
+xK::Sort(y13
+Opcode
+y33
+cAdd:case
+cMul:case
+cMin:case
+cMax:case
+cAnd:case
+cAbsAnd:case
+cOr:case
+cAbsOr:case
+cHypot:case
+cEqual:case
+cNEqual:std::sort(iY2
+iN2
+iY2
+end(),ParamComparer
+xK());lC
+cLess
+lY
+cGreater;}
+lC
+cLessOrEq
+lY
+cGreaterOrEq;}
+lC
+cGreater
+lY
+cLess;}
+lC
+cGreaterOrEq
+lY
+cLessOrEq;}
+break;c73
+yF3}
+lB
+AddParam
+lQ3
+param){xY.push_back(param);}
+lB
+AddParamMove(eJ&param){xY.push_back(eJ());xY.back().swap(param);}
+lB
+SetParam
+iA1
+which,lC2
+b)nW1
+which
+iX2
+xY[which]=b;}
+lB
+nG1
+size_t
+which,eJ&b)nW1
+which
+iX2
+xY[which
+i63
+b);}
+lB
+AddParams
+cH1
+nK){xY.insert(xY.end(),lZ2.iN2
+lZ2.end());}
+lB
+AddParamsMove(nK){size_t
+endpos=xY.tF3,added=lZ2.tF3;xY.t73
+endpos+added,eJ());for
+iA1
+p=0;p<added;++p)xY[endpos+p
+i63
+lZ2[p]);}
+lB
+AddParamsMove(nK,size_t
+n02)nW1
+n02
+iX2
+DelParam(n02);AddParamsMove(tA1}
+lB
+SetParams
+cH1
+nK){eH
+tmp(tA1
+xY.i72}
+lB
+SetParamsMove(nK){xY.swap(tA1
+lZ2.clear();}
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+lB
+SetParams(eH&&lZ2){SetParamsMove(tA1}
+#endif
+lB
+DelParam
+iA1
+index){eH&Params=xY;
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+iY2
+erase(iY2
+begin()+index);
+#else
+Params[index].data=0;for
+iA1
+p=index;p+1<xX3;++p)Params[p].data.UnsafeSetP(&*Params[p+1
+iX2
+Params[xX3-1].data.UnsafeSetP(0);iY2
+t73
+xX3-1);
+#endif
+}
+lB
+DelParams(){xY.clear();}
+xN1
+eJ::IsIdenticalTo
+lQ3
+b
+e83{if(&*data==&*b.data)return
+true
+n31
+data->IsIdenticalTo(*b.data);}
+xN1
+xH2
+xK::IsIdenticalTo
+cH1
+xH2
+xK&b
+e83{if(Hash!=b.Hash
+cL
+if(Opcode!=tK3
+cL
+switch(Opcode
+y33
+cImmed:return
+cB3
+Value,tL3;case
+l03:return
+l22==b.l12
+case
+cFCall:case
+cPCall:if(l22!=b.l22
+cL
+break;c73
+yF3
+if(xX3!=b.xX3
+cL
+for
+iA1
+a=0;a<xX3;++a){if(!Params[a]xF
+b.Params[a])cL}
+return
+true;}
+lB
+Become
+lQ3
+b){if(&b!=this&&&*data!=&*b.data){DataP
+tmp=b.data;l61
+data.i72}
+}
+lB
+CopyOnWrite(){if(GetRefCount()>1)data=new
+xH2
+xK(*data);}
+xW3
+eJ
+eJ::GetUniqueRef(){if(GetRefCount()>1)return
+eJ(*this,CloneTag())n31*this;}
+tX):yT
+cNop
+t92(),n8
+tX
+const
+xH2&b):yT
+tK3
+t92(tL3,l22(b.cQ1,Params(b.Params),Hash(b.Hash),Depth(b.Depth),tP1
+b.l32){}
+tX
+const
+iV2&i):yT
+cImmed
+t92(i),n8
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+tX
+xH2
+xK&&b):yT
+tK3
+t92
+c72
+tL3),l22(b.cQ1,Params
+c72
+b.Params)),Hash(b.Hash),Depth(b.Depth),tP1
+b.l32){}
+tX
+iV2&&i):yT
+cImmed
+t92
+c72
+i)),n8
+#endif
+tX
+xB2
+o):yT
+o
+t92(),n8
+tX
+xB2
+o,iF2
+f):yT
+o
+t92(),l22(f),Params(),Hash(),Depth(1),tP1
+0){}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <sstream>
+#include <string>
+#include <map>
+#include <set>
+#include <iostream>
+using
+lF3
+FUNCTIONPARSERTYPES;
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+lF3{tZ1
+n12(nO,std
+c7&done,std::ostream&o){nB1
+n12
+l64
+done,o);std::ostringstream
+buf
+i13(tree,buf);done[tree.GetHash()].insert(buf.str());}
+}
+#endif
+t5{
+#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING
+tZ1
+DumpHashes(cF){std
+c7
+done;n12(tree,done,o);for(std
+c7::const_iterator
+i=done.yU3
+i!=done.end();++i){const
+std::set<std
+cC3>&flist=i
+e82;if(flist.tF3!=1)o<<"ERROR - HASH COLLISION?\n"
+;for(std::set<std
+cC3>::const_iterator
+j=flist.yU3
+j!=flist.end();++j){o<<'['<<std::hex<<i->first.hash1<<','<<i->first.hash2<<']'<<std::dec;o<<": "
+<<*j<<"\n"
+;}
+}
+}
+tZ1
+DumpTree(cF){nH3
+iQ3;switch(i01
+y33
+cImmed:o<<eC3
+c63
+l03:o<<"Var"
+<<(tree.GetVar()-l03)c63
+cAdd:iQ3"+"
+;lC
+cMul:iQ3"*"
+;lC
+cAnd:iQ3"&"
+;lC
+cOr:iQ3"|"
+;lC
+cPow:iQ3"^"
+;break;c73
+iQ3;o<<c83
+i01);l83
+cFCall||i01==cPCall)o<<':'<<tree.GetFuncNo();}
+o<<'(';if(eM<=1&&sep2[1])o<<(sep2+1)<<' ';nB1{if(a>0)o<<' 'i13
+l64
+o
+eY3
+a+1<eM)o<<sep2;}
+o<<')';}
+tZ1
+DumpTreeWithIndent(cF,const
+std
+cC3&indent){o<<'['<<std::hex<<(void*)(&tree.l02))<<std::dec<<','<<tree.GetRefCount()<<']';o<<indent<<'_';switch(i01
+y33
+cImmed:o<<"cImmed "
+<<eC3;o<<'\n'c63
+l03:o<<"VarBegin "
+<<(tree.GetVar()-l03);o<<'\n'n31;c73
+o<<c83
+i01);l83
+cFCall||i01==cPCall)o<<':'<<tree.GetFuncNo();o<<'\n';}
+nB1{std
+cC3
+ind=indent;for
+iA1
+p=0;p<ind.tF3;p+=2)if(ind[p]=='\\')ind[p]=' ';ind+=(a+1<eM)?" |"
+:" \\"
+;DumpTreeWithIndent
+l64
+o,ind);}
+o<<std::flush;}
+#endif
+}
+#endif
+using
+lF3
+l21;using
+lF3
+FUNCTIONPARSERTYPES;
+#include <cctype>
+lF3
+l21{iF2
+ParamSpec_GetDepCode
+cH1
+e42&b
+y13
+b.first
+y33
+tG3:{cO*s=(cO*)b
+tE3
+n31
+s->depcode;}
+case
+SubFunction:{cP*s=(cP*)b
+tE3
+n31
+s->depcode;}
+c73
+yF3
+return
+0;}
+tZ1
+DumpParam
+cH1
+e42&yG2
+std::ostream&o){static
+const
+char
+ParamHolderNames[][2]={"%"
+,"&"
+,"x"
+,"y"
+,"z"
+,"a"
+,"b"
+,"c"
+}
+;iF2
+y32
+0;switch(yH2.first
+y33
+NumConstant:{const
+ParamSpec_NumConstant
+xK
+yK3
+cH1
+ParamSpec_NumConstant
+xK*c61
+using
+lF3
+FUNCTIONPARSERTYPES;o.precision(12);o<<yL3
+constvalue;yF3
+case
+tG3:{cO
+yK3(cO*c61
+o<<ParamHolderNames[yL3
+index];y32
+yL3
+constraints;yF3
+case
+SubFunction:{cP
+yK3(cP*c61
+y32
+yL3
+constraints;yF
+GroupFunction){if
+y23
+l81==cNeg){o<<"-"
+;n2}
+lJ2
+yL3
+l81==cInv){o<<"/"
+;n2}
+else{std
+cC3
+opcode=c83(xB2)yL3
+l81).substr(1)yM3
+0;a<opcode.tF3;++a)opcode[a]=(char)std::toupper(opcode[a]);o<<opcode<<"( "
+;n2
+o<<" )"
+;}
+}
+else{o<<'('<<c83(xB2)yL3
+l81)<<' ';yF
+PositionalParams)o<<'[';yF
+SelectedParams)o<<'{';n2
+if
+y23
+data.n1!=0)o<<" <"
+<<yL3
+data.n1<<'>';yF
+PositionalParams)o<<"]"
+;yF
+SelectedParams)o<<"}"
+;o<<')';}
+yF3
+l73
+ImmedConstraint_Value(constraints&ValueMask)y33
+ValueMask:lC
+Value_AnyNum:lC
+nY2:o<<"@E"
+;lC
+Value_OddInt:o<<"@O"
+;lC
+tS1:o<<"@I"
+;lC
+Value_NonInteger:o<<"@F"
+;lC
+eJ1:o<<"@L"
+;yJ3
+ImmedConstraint_Sign(constraints&SignMask)y33
+SignMask:lC
+Sign_AnySign:lC
+nH1:o<<"@P"
+;lC
+eK1:o<<"@N"
+;yJ3
+ImmedConstraint_Oneness(constraints&OnenessMask)y33
+OnenessMask:lC
+Oneness_Any:lC
+Oneness_One:o<<"@1"
+;lC
+Oneness_NotOne:o<<"@M"
+;yJ3
+ImmedConstraint_Constness(constraints&ConstnessMask)y33
+ConstnessMask:lC
+tR1:if(yH2.first==tG3){cO
+yK3(cO*c61
+if
+y23
+index<2)yF3
+o<<"@C"
+;lC
+Constness_NotConst:o<<"@V"
+;lC
+Oneness_Any:yF3}
+tZ1
+DumpParams
+nT2
+paramlist,iF2
+count,std::ostream&o){for(eQ1=0;a<count;++a){if(a>0)o<<' ';const
+e42&param=e81
+xK(paramlist,a);DumpParam
+xK(param,o);iF2
+depcode=ParamSpec_GetDepCode(param
+eY3
+depcode!=0)o<<"@D"
+<<depcode;}
+}
+}
+#include <algorithm>
+using
+lF3
+l21;using
+lF3
+FUNCTIONPARSERTYPES;lF3{cO
+plist_p[37]={{2,0,0x0}
+nP
+0,0x4}
+nP
+nH1,0x0}
+nP
+eK1|Constness_NotConst,0x0}
+nP
+Sign_NoIdea,0x0}
+nP
+eJ1,0x0}
+,{3,Sign_NoIdea,0x0}
+,{3,0,0x0}
+,{3,eJ1,0x0}
+,{3,0,0x8}
+,{3,Value_OddInt,0x0}
+,{3,Value_NonInteger,0x0}
+,{3,nY2,0x0}
+,{3,nH1,0x0}
+,{0,eK1|lV{0,lV{0,nH1|lV{0,nY2|lV{0,tR1,0x1}
+,{0,tS1|nH1|lV{0,tT1
+tR1,0x1}
+,{0,tT1
+lV{0,Oneness_One|lV{0,eJ1|lV{1,lV{1,nY2|lV{1,tT1
+lV{1,tS1|lV{1,nH1|lV{1,eK1|lV{6,0,0x0}
+,{4,0,0x0}
+,{4,tS1,0x0}
+,{4,lV{4
+tU3
+5,0,0x0}
+,{5,lV}
+nJ1
+e12
+plist_n_container{static
+const
+ParamSpec_NumConstant
+xK
+plist_n[20];}
+nJ1
+const
+ParamSpec_NumConstant
+xK
+plist_n_container
+xK::plist_n[20]={{iV2(-2
+tY-1
+tY-0.5
+tY-0.25
+tY
+0
+tA2
+fp_const_deg_to_rad
+xK(tA2
+fp_const_einv
+xK(tA2
+fp_const_log10inv
+xK(tY
+0.5
+tA2
+fp_const_log2
+xK(tY
+1
+tA2
+fp_const_log2inv
+xK(tY
+2
+tA2
+fp_const_log10
+xK(tA2
+fp_const_e
+xK(tA2
+fp_const_rad_to_deg
+xK(tA2-fp_const_pihalf
+xK(),xT1{y21,xT1{fp_const_pihalf
+xK(),xT1{fp_const_pi
+xK(),xT1}
+;cP
+plist_s[517]={{{1,15,tS2
+398,tS2
+477,tS2
+15,cNeg,GroupFunction,0}
+,tR1,0x1}
+,{{1,15,y42
+24,y42
+465,y42
+466,y42
+498,cInv,lT
+2,327995
+xE
+l0
+2,48276
+xE
+l6
+260151
+xE
+l6
+470171
+xE
+l6
+169126
+xE
+l6
+48418
+xE
+l6
+1328
+xE
+l6
+283962
+xE
+l6
+169275
+xE
+l6
+39202
+xE
+l6
+283964
+xE
+l6
+283973
+xE
+l6
+476619
+xE
+l6
+296998
+xE
+l6
+47
+xE
+SelectedParams,0}
+,0,0x4
+nH
+161839
+xE
+l6
+25036
+xE
+l6
+35847
+xE
+l6
+60440
+xE
+l6
+30751
+xE
+l6
+270599
+xE
+l6
+60431
+xE
+l6
+259119
+xE
+l6
+183474
+xE
+l6
+332066
+xE
+l6
+7168
+xE
+l6
+197632
+xE
+l6
+291840
+xE
+l6
+283648
+xE
+l6
+238866
+xE
+l6
+239902
+xE
+l6
+31751
+xE
+l6
+244743
+xE
+l6
+384022
+xE
+SelectedParams,0}
+,0,0x4
+nH
+385262
+xE
+l6
+386086
+xE
+l6
+393254
+xE
+SelectedParams,0}
+,0,0x5
+nH
+393254
+xE
+l6
+386095
+xE
+l6
+387312
+xE
+l6
+18662
+xE
+l6
+61670
+xE
+l6
+387397
+xE
+l6
+247855
+xE
+SelectedParams,0}
+,0,0x1
+nH
+342063
+xE
+l6
+297007
+xE
+l6
+15820
+xE
+l6
+393263
+xE
+l6
+393263
+xE
+SelectedParams,0}
+,0,0x5
+nH
+161847
+xE
+l6
+258103
+xE
+l6
+249073
+xE
+l6
+249076
+xE
+iD
+0,0
+xE
+nF
+0,0
+tU1
+1,45
+xE
+nF
+1,53
+xE
+nF
+1,54
+xE
+nF
+1,55
+xE
+nF
+1,56
+xE
+nF
+1,26
+xE
+nF
+1,259
+tJ
+1}
+tU3{1,253
+xE
+nF
+1,272
+tU1
+1,323
+tJ
+1}
+tU3{1,0
+xE
+nF
+1,21
+xE
+nF
+1,447
+tJ
+1}
+lA2
+449
+tJ
+1}
+lA2
+0
+tJ
+1}
+lA2
+0
+tJ
+2}
+lA2
+15
+xE
+nF
+1,24
+tJ
+2}
+,0,0x0
+nH
+58392
+tU1
+0,0
+tJ
+1}
+,nH1,0x0
+nH
+24591
+yI3
+33807
+yI3
+48143
+yI3
+285720
+yI3
+290840
+yI3
+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,xU1
+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,tB1
+324623,l1
+0x14
+nH
+332815,l1
+0x10}
+,{{3,7340056,tB1
+289092,l9
+92176,xU1
+337935
+lB2
+7340060,l1
+tT2
+7340176,l9
+338959
+lB2
+7340061,xU1
+7206,l9
+xJ3
+l9
+357414,l9
+368678,l9
+370745,l1
+0x7}
+,{{3,7340177,l9
+39277,tB1
+426398,l1
+tT2
+40272286,xU1
+490910,l1
+tT2
+40336798,xU1
+50600,l9
+426462,xU1
+490974,xU1
+370726,l1
+0x6
+nH
+371750,l1
+0x6
+nH
+428070
+lB2
+40336862,xU1
+38378,l9
+50671
+lB2
+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,tB1
+436262,l9
+508966,l9
+39409,tB1
+296998,tB1
+35847,l9
+15,tB1
+377894,l9
+386063,l1
+0x1
+nH
+15,l9
+7192,l9
+122904,l9
+121880,l9
+30751,l9
+57,l9
+7456,l9
+15674
+lB2
+67579935,l9
+39237,l9
+58768,l9
+62924,l9
+121856,l9
+15760
+lB2
+64009216,l1
+0x0}
+,{{0,0,xG
+0,0,iL
+2,e31
+2,e41
+3,e31
+3,e41
+38,xG
+1,38,iL
+14,xG
+1,57,xG
+1,16,eD2
+0x0
+nH
+471103,eD2
+0x1}
+,{{1,303,xG
+1,323,cE3
+0x0
+nH
+471363,eD2
+0x16}
+,{{1,293,e31
+294,e41
+295,xG
+1,296,iL
+400,xG
+1,0,xG
+1,460,xG
+1,465,xG
+1,16,eD2
+0x1}
+,{{1,57,cE3
+0x1}
+,{{1,0,iL
+21,xG
+1,15,eD2
+0x0
+nH
+24591,xG
+1,24,iL
+517,cE3
+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,eL1
+tV3
+283648,lF,19456,lF,27648,lF,89088,lF,86016,lF,488448,lF,14342,lF,58375,lF,46147
+xZ
+46151,lF,284679,lF,7183,lF,46159
+xZ
+38993
+xZ
+50265,lF,50249,lF,283808,lF,284835,lF,24822,lF,10240,lF,11264,lF,7170,lF,xJ3
+lF,17408,lF,164864,lF,237568,lF,242688,eL1
+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,eL1
+0x10
+nH
+416811,lF,416819,lF,40046,lF,46191
+xZ
+415795,lF,40047
+xZ
+415787,lF,39015,eL1
+0x5
+nH
+39326
+xZ
+39326,lF,39332,eL1
+0x5
+nH
+39333
+cW2
+50590
+xZ
+50590,lF,39338
+xZ
+39338,lF,39335,eL1
+0x5
+nH
+15786
+xZ
+146858,lF,39372,lF,39379,lF,39380,lF,39390
+xZ
+50654
+xZ
+50654,lF,24,eL1
+0x6
+nH
+62,lF,24,lF,62,eL1
+0x6
+nH
+43,lF,43
+xZ
+51,lF,51
+xZ
+50269,lF,50176
+xZ
+50270,lF,39159,lF,39183
+xZ
+7168
+xZ
+31744,lF,99328,lF,31746,lF,100376,lF,39409
+xZ
+39411
+xZ
+39411,lF,39420,lF,39420
+xZ
+15,lF,39025,eL1
+0x5
+nH
+39422,lF,16384,lF,62853,lF,15360,lF,15
+cW2
+16,lF,7183
+cW2
+7172
+l14
+yX1}
+,nH1,0x0
+nH
+24591
+l14
+lT
+2,50200
+l14
+lT
+2,63521
+l14
+lT
+2,62500
+l14
+lT
+2,50453
+l14
+lT
+2,62488,cPow
+eP3
+tS3
+7,tS3
+194,tS3
+0,cAcos
+tT3
+cAcosh
+tT3
+cAsin
+tT3
+cAsinh
+nQ
+119,cAsinh
+tT3
+cAtan
+eW1
+306176,cAtan2
+eW1
+xJ3
+cAtan2
+tT3
+cAtanh
+nQ
+246,cCeil
+tT3
+cCeil,l13
+0,c92
+0,cCos,l13
+7,c92
+91,c92
+92,c92
+119,c92
+236,c92
+255,c92
+214,l23
+236,l23
+464,l23
+0,cCosh,l13
+0,l23
+0,cExp
+nQ
+7,cExp
+nQ
+91,cExp
+tT3
+cF3
+7,cF3
+91,cF3
+246,cFloor
+tT3
+cFloor,lA
+0x4
+nH
+309540,cHypot
+eW1
+316708,cHypot
+eW1
+316724,cHypot,l0
+3,32513024,y52
+34627584
+n61
+31493120,y52
+89213952
+n61
+149042176
+n61
+246647808
+n61
+301234176
+n61
+494360576
+n61
+498558976
+n61
+62933520
+n61
+62933520,y52
+62933526
+n61
+62933526,y52
+24670208
+n61
+579378176
+n61
+573578240
+n61
+32513024
+n61
+566254592
+n61
+7900160
+n61
+588822528,cIf
+nQ
+119,cInt
+nQ
+246
+cA2
+0
+cA2
+7
+cA2
+31
+cA2
+194
+cA2
+363
+cA2
+15,cLog,lT
+1,24,cLog
+eP3
+cLog10
+tT3
+cLog2
+eW1
+xJ3
+cMax
+eW1
+35847,cMax
+eW1
+30751,cMax
+tT3
+cMax,AnyParams,1}
+,0,0x4
+nH
+xJ3
+cMin
+eW1
+35847,cMin
+eW1
+30751,cMin
+tT3
+cMin,AnyParams,1}
+,0,0x4
+nH
+24591,cMin
+eP3
+nZ2
+7,nZ2
+91,nZ2
+92,nZ2
+119,nZ2
+149,nZ2
+231,cSin,lA
+0x5}
+,{{1,246,nZ2
+255,nZ2
+254,nZ2
+0,cSin,l13
+273,cSin,lA
+0x1}
+,{{1,214,y62
+231,cSinh,lA
+0x5}
+,{{1,246,y62
+254,y62
+255,y62
+464,y62
+0,cSinh,l13
+0,y62
+15,cSqrt
+eP3
+cB2
+0,cTan,l13
+115,cTan,l13
+116,cB2
+231,cB2
+246,cB2
+273,cB2
+254,cB2
+255,cB2
+0,y92
+0,cTanh,l13
+213,y92
+231,y92
+246,y92
+254,y92
+255,y92
+0,cTrunc
+eW1
+15384,cSub,lT
+2,15384,cDiv,lT
+2,476626,cDiv,lT
+2,121913,tU2
+xJ3
+n42
+lA
+tV3
+xJ3
+tU2
+31744,n42
+lA
+0x20
+nH
+31751,n42
+lA
+0x24
+nH
+31751,tU2
+121913,eM1
+l0
+2,xJ3
+cLess,lA
+tV3
+41984,cLess,lA
+0x4
+nH
+41984,cLess
+eW1
+7,cLess
+eW1
+xJ3
+cLessOrEq
+eW1
+296182,cLessOrEq
+eW1
+7168
+lJ3,lA
+tV3
+41984
+lJ3,lA
+0x4
+nH
+41984
+lJ3
+eW1
+7
+lJ3
+eW1
+xJ3
+yB
+l0
+2,296182,cGreaterOrEq
+tT3
+n22
+245,n22
+7,n22
+550,n22
+553,n22
+554,n22
+556,n22
+31,n22
+559,n22
+15,n22
+560,cNot
+eW1
+7706,n33
+xJ3
+n33
+35847,n33
+30751,n33
+463903,n33
+466975,cAnd,iD
+0,0,cAnd,nF
+2,xJ3
+eT3
+7706,eT3
+35847,eT3
+463903,eT3
+466975,eT3
+30751,cOr,iD
+1,0,n32
+91,n32
+131,n32
+245,n32
+215,n32
+246,cDeg
+nQ
+246,cRad
+eW1
+xJ3
+cAbsAnd,l6
+xJ3
+cAbsOr,iD
+1,0,cZ3
+tT3
+cAbsNotNot,l0
+3,32513024,cL3
+lA
+0x0}
+,}
+;}
+lF3
+l21{const
+Rule
+grammar_rules[262]={{ProduceNewTree,17,1,0,{1,0,cAbs,eE2
+409,{1,146,cAtan,eE2
+403
+nP
+1324,cG3
+eE2
+405
+nP
+307201,cG3
+l2
+c22
+253174
+nP
+255224,cG3
+l2
+c22
+259324
+nP
+257274,cG3
+eE2
+152,{1,252,cCeil
+iO
+486,{1,68,tW2
+482,{1,122,tW2
+483,{1,124,tW2
+151,{1,125,tW2
+419,{1,123,tW2
+0,{1,403,cCos,l2
+2,1,246,{1,252,cCos,l2
+18,1,0,{1,400,tW2
+301,{1,406,cCosh,l2
+2,1,246,{1,252,cCosh,l2
+18,1,0,{1,400,cCosh
+iO
+458,{1,121,cFloor,eE2
+150,{1,252,cFloor,tW3
+156,{3,7382016,eB
+549,{3,8430592,eB
+556,{3,8436736,eB
+157,{3,42998784,eB
+550,{3,42999808,eB
+562,{3,43039744,eB
+557,{3,49291264,eB
+538,{3,49325056,eB
+469,{3,1058318,eB
+473,{3,1058324,eB
+473,{3,9438734,eB
+469,{3,9438740,cIf,l2
+0,3,32542225,{3,36732434,cIf,l2
+0,3,32542231,{3,36732440,cIf,tX3
+573,{3,32513026,cIf,tX3
+515,{3,455505423,cIf,tX3
+515,{3,433506837,cIf
+iO
+78,{1,256,tY3
+69,{1,258,tY3
+404,{1,72,tY3
+159,{1,147,cLog,l2
+0,1,0
+nP
+487425,cMax
+l3
+16,1,445
+nP
+cH3
+cMax
+l3
+0,1,0
+nP
+483329,cMin
+l3
+16,1,446
+nP
+cH3
+cMin,c0
+0,1,153
+nP
+24832
+l14
+tW3
+153
+nP
+25854
+l14
+tW3
+154
+nP
+129039
+nX3
+32055
+nX3
+32056
+nX3
+32057
+tV2
+166288
+nP
+32137
+nX3
+33082
+tV2
+7168
+nP
+12688
+tV2
+7434
+nP
+12553
+y72
+435
+nP
+46146
+y72
+436
+nP
+46154
+y72
+437
+nP
+46150
+y72
+169
+nP
+83983
+y72
+168
+nP
+130082
+y72
+175
+nP
+133154
+y82
+476160
+nP
+471055
+y82
+274432
+nP
+273423
+y82
+251904
+nP
+266274
+y82
+251904
+nP
+263186
+y72
+171,{1,252,cC2
+421,{1,68,cC2
+151,{1,122,cC2
+419,{1,124,cC2
+170,{1,125,cC2
+482,{1,123,cC2
+0,{1,405,cC2
+172,{1,252,cSinh
+iO
+328,{1,404,cSinh
+iO
+173,{1,252,l34
+0,{1,408,l34
+176,{1,410,l34
+177,{1,252,cTanh,l2
+0,1,442
+nP
+449551,tZ
+1,441
+nP
+cH3
+tZ
+1,167
+nP
+268549,tZ
+1,181
+nP
+276749,tZ
+1,180
+nP
+276500
+iD3
+190770
+nP
+189622
+iD3
+194748
+nP
+193723
+iD3
+202943
+nP
+196795
+iD3
+59699
+nP
+298148
+iD3
+59714
+nP
+325815
+iD3
+59724
+nP
+343224
+xE
+c0
+2,1,337,{1,333
+tJ
+1
+l33
+336,{1,338
+tJ
+1}
+}
+l44
+2,1,340
+nP
+1363,i0
+342
+nP
+1365,i0
+463
+nP
+472524,i0
+47
+nP
+356711,i0
+349
+nP
+200751,i0
+360
+nP
+199727,i0
+480
+nP
+207053,i0
+481
+nP
+208077,i0
+417
+nP
+211144,i0
+209
+nP
+211145,i0
+418
+nP
+215240,i0
+212
+nP
+212329,i0
+204
+nP
+373097,i0
+211
+nP
+372944,i0
+217
+nP
+201944,i0
+221
+nP
+223448,i0
+367
+nP
+508329,i0
+219
+nP
+508126,i0
+224
+nP
+225705,i0
+223
+nP
+225776,i0
+365
+nP
+230825,i0
+426
+nP
+377057,i0
+497
+nP
+377054,i0
+497
+nP
+204201,i0
+426
+nP
+375280,i0
+224
+nP
+375006,cAdd
+l3
+2,2,407781
+nP
+233698,cAdd
+l3
+2,2,59763
+nP
+233842,tZ
+1,372
+nP
+1397,lQ1
+95
+nP
+24705,lQ1
+96
+nP
+24708,lQ1
+444
+nP
+449551,lQ1
+443
+nP
+cH3
+lQ1
+100
+nP
+101750,lQ1
+108
+nP
+106821,lQ1
+105
+nP
+103749
+nA2
+0,2,110607
+nP
+108869
+nA2
+0,2,107535
+nP
+109893,lJ
+0
+l33
+112
+nP
+111634,cMul,SelectedParams,0
+l33
+567,{1,52,lJ
+1
+l33
+568,{1,42,lJ
+1}
+}
+l44
+2,1,467
+nP
+45516
+iV
+356
+nP
+51555
+iV
+468
+nP
+49612
+iV
+357
+nP
+47459
+iV
+429
+nP
+438699
+iV
+432
+nP
+441774
+iV
+486
+nP
+498726
+iV
+494
+nP
+504870
+iV
+382
+nP
+435579
+iV
+497
+nP
+435709
+iV
+426
+nP
+508287
+iV
+414
+nP
+500092
+iV
+499
+nP
+352744
+iV
+345
+nP
+367092
+iV
+381
+nP
+425318
+iV
+478
+nP
+425460
+iV
+47
+nP
+512501
+iV
+505
+nP
+355817
+iV
+47
+nP
+516598
+iV
+507
+nP
+518182
+iV
+508
+nP
+358896
+iV
+351
+nP
+388605
+iV
+511
+nP
+360939
+iV
+503
+nP
+354788
+iV
+514
+nP
+525350
+iV
+510
+nP
+394342
+iV
+386
+nP
+351346
+nA2
+2,2,363004
+nP
+361968
+nA2
+16,1,117
+nP
+1157
+nA2
+16,1,118
+nP
+1158
+nA2
+16,1,402
+nP
+411024
+nA2
+16,2,58768
+nP
+1472
+nA2
+16,2,15760
+nP
+1474
+nA2
+17,1,0,{1,400
+nA2
+17,1,57,{1,14,lJ
+0
+l91
+4
+n43
+41,n42
+l4
+4,1,0
+nP
+5167,n42
+yA2
+41984
+nP
+409641,cEqual
+c4
+n42
+yA2
+eY
+n42
+l43
+n42
+l2
+xB1
+24849
+tN2
+iE
+tN2
+n63
+281873
+tN2
+lA1
+tN2
+lB1
+n42
+l4
+4
+y43
+41,eM1
+l4
+4
+n43
+5167,eM1
+yA2
+41984
+nP
+409641,cNEqual
+c4
+eM1
+yA2
+eY
+eM1
+l43
+eM1
+l2
+xB1
+24849,eM1
+l2
+cI3
+eM1
+l2
+c22
+n63
+281873,eM1
+l2
+c22
+lA1,eM1
+l2
+c22
+lB1
+cNEqual
+c4
+eO1
+16,2,eY
+eO1
+16
+eI
+cLess,eE2
+571
+nP
+46080,eO1
+xB1
+24832,eO1
+c22
+yT1,eO1
+cI3
+eO1
+cJ3
+eO1
+c22
+xW1,eO1
+c22
+lA1,eO1
+c22
+lB1
+cLess,l4
+20
+y43
+409641,cLess
+c4
+t6
+16,2,eY
+t6
+16
+eI
+cLessOrEq,eE2
+565
+nP
+409615,t6
+xB1
+24832,t6
+c22
+yT1,t6
+cI3
+t6
+cJ3
+t6
+c22
+xW1,t6
+c22
+lA1,t6
+c22
+lB1
+cLessOrEq,l4
+20
+y43
+409647,cLessOrEq
+c4
+lK3
+yA2
+eY
+lK3
+l43
+lK3
+eE2
+539
+nP
+409615
+eP
+529654
+nP
+24832
+eP
+yT1
+eP
+iE
+eP
+n63
+281856
+eP
+xW1
+eP
+lA1
+eP
+lB1
+lK3
+l4
+20
+n43
+409647
+lJ3
+c4
+yB
+yA2
+eY
+yB
+l43
+yB
+eE2
+572
+nP
+46080,yB
+l2
+xB1
+24832,yB
+l2
+c22
+yT1,yB
+l2
+cI3
+yB
+l2
+cJ3
+yB
+l2
+c22
+xW1,yB
+l2
+c22
+lA1,yB
+l2
+c22
+lB1
+yB
+l4
+20
+n43
+409641,yB
+l4
+4,1,519,{1,137,cNot,tX3
+571,{1,2,cNot,l2
+0,1,452
+nP
+cH3
+n73
+0,2,537097,{3,547892744,cAnd,c0
+16,1,566,{1,5,cAnd,AnyParams,1}
+}
+l44
+16,1,569
+nP
+13314,n73
+16,1,544
+nP
+553498,n73
+16,1,546
+nP
+462369,n73
+16,1,548
+nP
+466465,n73
+0,1,457
+nP
+cH3
+xX1
+570
+nP
+13314,xX1
+563
+nP
+8197,xX1
+541
+nP
+553498,xX1
+542
+nP
+462369,xX1
+543
+nP
+466465,xX1
+564
+nP
+143365,cOr,c0
+4,1,525,{1,137,cK3
+tX3
+572,{1,2,cK3
+l4
+17,1,0,{1,0,cK3
+eE2
+537,{1,256,cAbsNotNot,c0
+18,1,531,{1,254,cAbsNotNot,c0
+0,1,572,{3,43039744,cL3
+tW3
+571,{3,49325056,cL3
+tX3
+454,{3,32513586,cL3
+l2
+16,3,32542225,{3,36732434,cL3
+yX1}
+}
+,}
+;e12
+grammar_optimize_abslogical_type{y2
+9
+cS
+grammar_optimize_abslogical_type
+grammar_optimize_abslogical={9,{34,192,228,238,242,247,254,260,261}
+}
+;}
+e12
+grammar_optimize_ignore_if_sideeffects_type{y2
+59
+cS
+grammar_optimize_ignore_if_sideeffects_type
+grammar_optimize_ignore_if_sideeffects={59,{0,20,21,22,23,24,25,26,cQ
+iO1
+78,cR
+cT
+e12
+grammar_optimize_nonshortcut_logical_evaluation_type{y2
+56
+cS
+grammar_optimize_nonshortcut_logical_evaluation_type
+grammar_optimize_nonshortcut_logical_evaluation={56,{0,25,cQ
+iO1
+78,cR
+241,243,244,245,246,248,249,250,251,252,253,255,256,257,258,259}
+}
+;}
+e12
+grammar_optimize_recreate_type{y2
+22
+cS
+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}
+}
+;}
+e12
+grammar_optimize_round1_type{y2
+125
+cS
+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,cQ
+37,38,iO1
+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,cT
+e12
+grammar_optimize_round2_type{y2
+103
+cS
+grammar_optimize_round2_type
+grammar_optimize_round2={103,{0,15,16,17,25,cQ
+39,40,iO1
+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,cT
+e12
+grammar_optimize_round3_type{y2
+79
+cS
+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}
+}
+;}
+e12
+grammar_optimize_round4_type{y2
+12
+cS
+grammar_optimize_round4_type
+grammar_optimize_round4={12,{18,55,56,57,130,131,132,133,134,135,136,137}
+}
+;}
+e12
+grammar_optimize_shortcut_logical_evaluation_type{y2
+53
+cS
+grammar_optimize_shortcut_logical_evaluation_type
+grammar_optimize_shortcut_logical_evaluation={53,{0,25,cQ
+iO1
+78,cR
+cT}
+lF3
+l21{xW3
+e42
+e81
+nT2
+paramlist,nA1){index=(paramlist>>(index*10))&1023;if(index>=57)return
+e42(SubFunction,cD2
+plist_s[index-57]eY3
+index>=37)return
+e42(NumConstant,cD2
+plist_n_container
+xK::plist_n[index-37])n31
+e42(tG3,cD2
+plist_p[index]);}
+}
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <stdio.h>
+#include <algorithm>
+#include <map>
+#include <sstream>
+using
+lF3
+FUNCTIONPARSERTYPES;using
+lF3
+l21;using
+t5;using
+yL1;lF3{nR1
+It,xK3
+T,xK3
+Comp>eP1
+MyEqualRange(It
+first,It
+last,const
+T&val,Comp
+comp){size_t
+len=last-first;while(len>0){size_t
+yA3
+len/2;It
+xG3(first);xG3+=half;if(comp(*xG3,val)){first=xG3;++first;len=len-half-1;}
+lJ2
+comp(val,*xG3)){len=half;}
+else{It
+left(first);{It&eF2=left;It
+last2(xG3);size_t
+len2=last2-eF2;while(len2>0){size_t
+half2=len2/2;It
+cD3(eF2);cD3+=half2;if(comp(*cD3,val)){eF2=cD3;++eF2;len2=len2-half2-1;}
+else
+len2=half2;}
+}
+first+=len;It
+right(++xG3);{It&eF2=right;It&last2=first;size_t
+len2=last2-eF2;while(len2>0){size_t
+half2=len2/2;It
+cD3(eF2);cD3+=half2;if(comp(val,*cD3))len2=half2;else{eF2=cD3;++eF2;len2=len2-half2-1;}
+eW2
+eP1(left,right);eW2
+eP1(first,first);}
+xW3
+e12
+OpcodeRuleCompare{iG2()lQ3
+tree,iF2
+yB2
+e83{const
+Rule&rule=grammar_rules[yB2]n31
+i01<rule
+cE2.subfunc_opcode;}
+iG2()nT2
+yB2,lC2
+tree
+e83{const
+Rule&rule=grammar_rules[yB2]n31
+rule
+cE2.subfunc_opcode<i01;}
+}
+nJ1
+bool
+TestRuleAndApplyIfMatch
+cH1
+eT2
+eJ&tree,bool
+c1{MatchInfo
+xK
+info;lX1
+found(false,cW()eY3(rule.lC1
+LogicalContextOnly)&&!c1{tC1
+if(nB
+IsIntType
+xK::nT3){if(rule.lC1
+NotForIntegers)tC1
+e63
+rule.lC1
+OnlyForIntegers)tC1
+if(nB
+IsComplexType
+xK::nT3){if(rule.lC1
+NotForComplex)tC1
+e63
+rule.lC1
+OnlyForComplex)tC1
+for(;;){
+#ifdef DEBUG_SUBSTITUTIONS
+#endif
+found=TestParams(rule
+cE2,tree,found.specs,info,true
+eY3
+found.found)break;if(!&*found.specs){fail:;
+#ifdef DEBUG_SUBSTITUTIONS
+DumpMatch(rule
+iY3,false);
+#endif
+return
+tR3}
+#ifdef DEBUG_SUBSTITUTIONS
+DumpMatch(rule
+iY3,true);
+#endif
+SynthesizeRule(rule
+iY3)xJ2}
+yL1{xN1
+ApplyGrammar
+cH1
+Grammar&tX2,eJ&tree,bool
+c1{if(tree.GetOptimizedUsing()==&tX2){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Already optimized:  "
+i13(tree
+lT2"\n"
+<<std::flush;
+#endif
+return
+tR3
+if(true){bool
+changed
+tO3
+switch(i01
+y33
+cNot:case
+cNotNot:case
+cAnd:case
+cOr:for
+iA1
+a=0;a<tree.x6
+true))x62
+lC
+cIf:case
+cAbsIf:if(ApplyGrammar(tX2,lE2
+0),i01==cIf))x62
+for
+iA1
+a=1;a<tree.x6
+c1)x62
+break;c73
+for
+iA1
+a=0;a<tree.x6
+false))x62}
+if(changed){tree.Mark_Incompletely_Hashed()xJ2}
+typedef
+const
+iF2
+short*n83;std::pair<n83,n83>range=MyEqualRange(tX2.rule_list,tX2.rule_list+tX2.rule_count,tree,OpcodeRuleCompare
+xK());std
+xV3<iF2
+short>rules;rules.xS3
+range
+tE3-range.first);for
+y5
+if(IsLogisticallyPlausibleParamsMatch(tD1
+cE2,tree))rules.push_back(*r);}
+range.first=!rules
+cT3?&rules[0]:0;range
+tE3=!rules
+cT3?&rules[rules.tF3-1]+1:0;if(range.first!=range
+iO2{
+#ifdef DEBUG_SUBSTITUTIONS
+if(range.first!=range
+iO2
+yC2"Input ("
+<<c83
+i01)<<")["
+<<eM<<"]"
+;if(c1
+std::cout<<"(Logical)"
+;iF2
+first=iP1,prev=iP1;nH3
+sep=", rules "
+;for
+y5
+if(first==iP1)first=prev=*r;lJ2*r==prev+1)prev=*r;else
+yC2
+sep<<first;sep=","
+;if(prev!=first)std::cout<<'-'<<prev;first=prev=*r;}
+}
+if(first!=iP1)yC2
+sep<<first;if(prev!=first)std::cout<<'-'<<prev;}
+std::cout<<": "
+i13(tree
+lT2"\n"
+<<std::flush;}
+#endif
+bool
+changed
+tO3
+for
+y5
+#ifndef DEBUG_SUBSTITUTIONS
+if(!IsLogisticallyPlausibleParamsMatch(tD1
+cE2,tree)cP2;
+#endif
+if(TestRuleAndApplyIfMatch(tD1,tree,c1){x62
+yF3}
+if(changed){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Changed."
+<<std::endl;std::cout<<"Output: "
+i13(tree
+lT2"\n"
+<<std::flush;
+#endif
+tree.Mark_Incompletely_Hashed()xJ2}
+tree.SetOptimizedUsing(&tX2)n31
+tR3
+xN1
+ApplyGrammar
+cH1
+void*p,FPoptimizer_CodeTree::e62
+yR
+ApplyGrammar(*cH1
+Grammar*)p,tree);}
+tZ1
+ApplyGrammars(FPoptimizer_CodeTree::e62{
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_round1\n"
+;
+#endif
+n6
+grammar_optimize_round1
+n53
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_round2\n"
+;
+#endif
+n6
+grammar_optimize_round2
+n53
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_round3\n"
+;
+#endif
+n6
+grammar_optimize_round3
+n53
+#ifndef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_nonshortcut_logical_evaluation\n"
+;
+#endif
+n6
+grammar_optimize_nonshortcut_logical_evaluation
+n53
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_round4\n"
+;
+#endif
+n6
+grammar_optimize_round4
+n53
+#ifdef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_shortcut_logical_evaluation\n"
+;
+#endif
+n6
+grammar_optimize_shortcut_logical_evaluation
+n53
+#endif
+#ifdef FP_ENABLE_IGNORE_IF_SIDEEFFECTS
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_ignore_if_sideeffects\n"
+;
+#endif
+n6
+grammar_optimize_ignore_if_sideeffects
+n53
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+std
+iL3"grammar_optimize_abslogical\n"
+;
+#endif
+n6
+grammar_optimize_abslogical
+n53
+#undef C
+}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <algorithm>
+#include <assert.h>
+#include <cstring>
+#include <cmath>
+#include <memory> /* for auto_ptr */
+using
+lF3
+FUNCTIONPARSERTYPES;using
+lF3
+l21;using
+t5;using
+yL1;lF3{xN1
+TestImmedConstraints
+nT2
+bitmask,lC2
+tree
+y13
+bitmask&ValueMask
+y33
+Value_AnyNum:case
+ValueMask:lC
+nY2:if(GetEvennessInfo
+eZ3
+n52
+Value_OddInt:if(GetEvennessInfo
+eZ3
+x02
+tS1:if(GetIntegerInfo
+eZ3
+n52
+Value_NonInteger:if(GetIntegerInfo
+eZ3
+x02
+eJ1:if(!IsLogicalValue(tree)cL
+nI1
+SignMask
+y33
+Sign_AnySign:lC
+nH1:if(l01
+n52
+eK1:if(l01
+x02
+Sign_NoIdea:if(l01
+Unknown
+cL
+nI1
+OnenessMask
+y33
+Oneness_Any:case
+OnenessMask:lC
+Oneness_One:if(!yN1
+if(!cB3
+fp_abs(eC3)tG1
+1))cL
+lC
+Oneness_NotOne:if(!yN1
+if(cB3
+fp_abs(eC3)tG1
+1))cL
+nI1
+ConstnessMask
+y33
+Constness_Any:lC
+tR1:if(!yN1
+lC
+Constness_NotConst:if(yN1
+yF3
+return
+true;}
+i31
+iF2
+extent,iF2
+nbits,xK3
+eG2=iF2
+int>e12
+nbitmap{private:static
+const
+iF2
+bits_in_char=8;static
+const
+iF2
+eH2=(cM3
+eG2)*bits_in_char)/nbits;eG2
+data[(extent+eH2-1)/eH2];eX3
+void
+inc(nA1,int
+by=1){data[pos(index)]+=by*eG2(1<<yD2);xI1
+void
+dec(nA1){inc(index,-1);}
+int
+get(nA1
+yZ1(data[pos(index)]>>yD2)&mask()yH3
+pos(nA1)yR
+index/eH2
+yH3
+shift(nA1)yR
+nbits*(index%eH2)yH3
+mask()yR(1<<nbits)-1
+yH3
+mask(nA1)yR
+mask()<<yD2;}
+}
+;e12
+eJ3{int
+SubTrees:8;int
+eV3:8;int
+yE2:8;int
+Immeds:8;nbitmap<l03,2>SubTreesDetail;eJ3(){std::memset(this,0,cM3*this));}
+eJ3
+cH1
+eJ3&b){std::memcpy(this,&b,cM3
+b));}
+eJ3&eA1=cH1
+eJ3&b){std::memcpy(this,&b,cM3
+b))n31*this;}
+}
+nJ1
+eJ3
+CreateNeedList_uncached(tC&c32){eJ3
+cN1;for(eQ1=0;a<c32
+yF2;++a){const
+e42&yH2=e81
+xK(c32.param_list,a);switch(yH2.first
+y33
+SubFunction:{cP
+yK3(cP*c61
+yF
+GroupFunction)++cN1.Immeds;else{++cN1.SubTrees;assert(param.data.subfunc_opcode<VarBegin);cN1.SubTreesDetail.inc
+y23
+l81);}
+++cN1.yE2;yF3
+case
+NumConstant:case
+tG3:++cN1.eV3;++cN1.yE2;break;eW2
+cN1;}
+xW3
+eJ3&CreateNeedList(tC&c32){typedef
+std::map<tC*,eJ3>e51;static
+e51
+yV1;e51::yV3
+i=yV1.xU2&c32
+eY3
+i!=yV1.cY1&c32)return
+i
+e82
+n31
+yV1.yR3,std::make_pair(&c32,CreateNeedList_uncached
+xK(c32)))e82;}
+xW3
+eJ
+CalculateGroupFunction
+cH1
+e42&yG2
+const
+tB
+info
+y13
+yH2.first
+y33
+NumConstant:{const
+ParamSpec_NumConstant
+xK
+yK3
+cH1
+ParamSpec_NumConstant
+xK*)yH2
+tE3
+n31
+CodeTreeImmed
+y23
+constvalue
+i33
+tG3:{cO
+yK3(cO*)yH2
+tE3
+n31
+tM3
+GetParamHolderValueIfFound
+y23
+index
+i33
+SubFunction:{cP
+yK3(cP*c61
+eJ
+nT3;nT3
+xD
+yL3
+l81);nT3.l02).xS3
+yL3
+data
+yF2);for(eQ1=0;a<yL3
+data
+yF2;++a){eJ
+tmp(CalculateGroupFunction(e81
+xK
+y23
+data.param_list,a),info));nT3
+yP1
+tmp);}
+nT3.Rehash()n31
+nT3;eW2
+eJ();}
+}
+yL1{xN1
+IsLogisticallyPlausibleParamsMatch(tC&c32,lC2
+tree){eJ3
+cN1(CreateNeedList
+xK(c32));size_t
+tZ3=c8
+if(tZ3<size_t(cN1.yE2))n93}
+for
+iA1
+a=0;a<tZ3;++a){iF2
+opcode=t33
+nC;switch(opcode
+y33
+cImmed:if(cN1.Immeds>0)eU3
+Immeds;else
+eU3
+eV3;lC
+l03:case
+cFCall:case
+cPCall:eU3
+eV3;break;c73
+assert(opcode<VarBegin);if(cN1.SubTrees>0&&cN1.SubTreesDetail.get(opcode)>0){eU3
+SubTrees;cN1.SubTreesDetail.dec(opcode
+t43
+eU3
+eV3;}
+}
+if(cN1.Immeds>0||cN1.SubTrees>0||cN1.eV3>0)n93}
+if(c32.match_type!=AnyParams){if(0||cN1.SubTrees<0||cN1.eV3<0)n93
+eW2
+true;}
+xW3
+lX1
+TestParam
+cH1
+e42&yG2
+lC2
+tree,const
+cW&start_at
+tJ3
+y13
+yH2.first
+y33
+NumConstant:{const
+ParamSpec_NumConstant
+xK
+yK3
+cH1
+ParamSpec_NumConstant
+xK*c61
+if(!yN1
+iV2
+imm=eC3;switch
+y23
+modulo
+y33
+Modulo_None:lC
+Modulo_Radians:imm=e93
+imm,yO
+imm<xD1
+imm
+yP
+if(imm>fp_const_pi
+xK())imm-=fp_const_twopi
+xK(cT2
+return
+cB3
+imm,yL3
+constvalue
+i33
+tG3:{cO
+yK3(cO*c61
+if(!x0
+return
+tM3
+SaveOrTestParamHolder
+y23
+index,tree
+i33
+SubFunction:{cP
+yK3(cP*c61
+yF
+GroupFunction){if(!x0
+eJ
+xY1=CalculateGroupFunction(yG2
+info);
+#ifdef DEBUG_SUBSTITUTIONS
+DumpHashes(xY1
+lT2*cH1
+void**)&xY1
+nC1;std::cout<<"\n"
+;std::cout<<*cH1
+void**)&eC3;std::cout<<"\n"
+;DumpHashes(tree
+lT2"Comparing "
+i13(xY1
+lT2" and "
+i13(tree
+lT2": "
+;std::cout<<(xY1
+xF
+tree)?"true"
+:"false"
+lT2"\n"
+;
+#endif
+return
+xY1
+xF
+tree);}
+e63!&*start_at){if(!x0
+if(i01!=yL3
+l81
+cL}
+return
+TestParams
+y23
+data,tree,start_at,info,false);}
+eW2
+tR3
+xW3
+e12
+iX
+x72
+MatchInfo
+xK
+info;iX():start_at(),info(){}
+}
+nJ1
+class
+MatchPositionSpec_PositionalParams:xE1
+iX
+xK>{eX3
+l53
+MatchPositionSpec_PositionalParams
+iA1
+n
+yB1
+iX
+xK>(n){}
+}
+;e12
+iQ1
+x72
+iQ1():start_at(){}
+}
+;class
+yG:xE1
+iQ1>{eX3
+iF2
+trypos;l53
+yG
+iA1
+n
+yB1
+iQ1>(n),trypos(0){}
+}
+nJ1
+lX1
+TestParam_AnyWhere
+cH1
+e42&yG2
+lC2
+tree,const
+cW&start_at
+tJ3,std::eV2&used,bool
+eY2{xR<yG>x5;tY2
+yG
+eU2
+a=x5->trypos;goto
+retry_anywhere_2
+tC2
+yG(eM);a=0;}
+for(;a<c8++a){if(used[a]cP2;retry_anywhere
+i03=TestParam(yG2
+t33,(i02);iB1
+used[a]=true
+iP
+a);x5->trypos=a
+n31
+lX1(true,&*x5);}
+}
+retry_anywhere_2
+i23
+goto
+retry_anywhere;eW2
+tR3
+xW3
+e12
+yC1
+x72
+MatchInfo
+xK
+info;std::eV2
+used;l53
+yC1
+iA1
+tZ3):start_at(),info(),used(tZ3){}
+}
+nJ1
+class
+MatchPositionSpec_AnyParams:xE1
+yC1
+xK>{eX3
+l53
+MatchPositionSpec_AnyParams
+iA1
+n,size_t
+m
+yB1
+yC1
+xK>(n,yC1
+xK(m)){}
+}
+nJ1
+lX1
+TestParams(tC&nN,lC2
+tree,const
+cW&start_at
+tJ3,bool
+eY2{if(nN.match_type!=AnyParams){if(xV!=eM
+cL}
+if(!IsLogisticallyPlausibleParamsMatch(nN,tree))n93
+l73
+nN.match_type
+y33
+PositionalParams:{xR<cG>x5;tY2
+cG
+eU2
+a=xV-1;goto
+lD1
+tC2
+cG(xV);a=0;}
+for(;a
+eX2{lG2=info;retry_positionalparams
+i03=TestParam(cU
+a),t33,(i02);iB1
+eR2}
+lD1
+i23
+info=lG2;goto
+retry_positionalparams;}
+if(a>0){--a;goto
+lD1;}
+info=eD3
+n31
+tR3
+if(eY2
+for(tZ2
+tM3
+SaveMatchedParamIndex(a)n31
+lX1(true,&*x5
+i33
+SelectedParams:case
+AnyParams:{xR<t7>x5;std::eV2
+used(eM);std
+xV3<iF2>l63(xV);std
+xV3<iF2>yI2(xV);for(tZ2{const
+e42
+yH2=cU
+a);l63[a]=ParamSpec_GetDepCode(yH2);}
+{iF2
+b=0;for(tZ2
+if(l63[a]!=0)yI2[b++]=a;for(tZ2
+if(l63[a]==0)yI2[b++]=a;}
+tY2
+t7
+eU2
+if(xV==0){a=0;goto
+retry_anyparams_4;}
+a=xV-1;goto
+e61
+tC2
+t7(xV,eM);a=0;if(xV!=0){eD3=info;(*x5)[0].used=used;}
+}
+for(;a
+eX2{if(a>0){lG2=info;(*x5)[a].used=used;}
+retry_anyparams
+i03=TestParam_AnyWhere
+xK(cU
+yI2[a]),tree,(i02,used,eY2;iB1
+eR2}
+e61
+i23
+info=lG2;used=(*x5)[a].used;goto
+retry_anyparams;}
+e71:if(a>0){--a;goto
+e61;}
+info=eD3
+n31
+tR3
+retry_anyparams_4:if(nN.n1!=0){if(!TopLevel||!tM3
+HasRestHolder(nN.n1)){eH
+cF2;cF2.xS3
+eM);for
+nT2
+b=0;b<c8++b){if(cN3
+cP2;cF2.push_back
+y91
+b));cN3=true
+iP
+b);}
+if(!tM3
+SaveOrTestRestHolder(nN.n1,cF2)){goto
+e71;}
+}
+else{iH2&cF2=tM3
+GetRestHolderValues(nN.n1)yM3
+0;a<cF2.tF3;++a){bool
+found
+tO3
+for
+nT2
+b=0;b<c8++b){if(cN3
+cP2;if(cF2[a]xF
+lE2
+b))){cN3=true
+iP
+b);found=true;yF3}
+if(!found){goto
+e71;}
+}
+eW2
+lX1(true,xV?&*x5:0
+i33
+GroupFunction:yF3
+return
+tR3}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <algorithm>
+#include <assert.h>
+using
+t5;using
+yL1;lF3{xW3
+eJ
+xZ1
+const
+e42&yG2
+tB
+info,bool
+inner=true
+y13
+yH2.first
+y33
+NumConstant:{const
+ParamSpec_NumConstant
+xK
+yK3
+cH1
+ParamSpec_NumConstant
+xK*)yH2
+tE3
+n31
+CodeTreeImmed
+y23
+constvalue
+i33
+tG3:{cO
+yK3(cO*)yH2
+tE3
+n31
+tM3
+GetParamHolderValue
+y23
+index
+i33
+SubFunction:{cP
+yK3(cP*c61
+eJ
+tree;tI3
+yL3
+l81);for(eQ1=0;a<yL3
+data
+yF2;++a){eJ
+nparam=xZ1
+e81
+xK
+y23
+data.param_list,a),info,true);lP1
+nparam);}
+if
+y23
+data.n1!=0){eH
+trees(tM3
+GetRestHolderValues
+y23
+data.n1));tree.AddParamsMove(trees
+eY3
+eM==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.xY2
+0));}
+lJ2
+eM==0
+y13
+i01
+y33
+cAdd:case
+cOr:tree=nF1
+0));lC
+cMul:case
+cAnd:tree=nF1
+1));c73
+yF3}
+}
+if(inner)tree.Rehash()n31
+tree;eW2
+eJ();}
+}
+yL1{tZ1
+SynthesizeRule
+cH1
+eT2
+eJ&tree
+tJ3
+y13
+rule.ruletype
+y33
+ProduceNewTree:{tree.Become(xZ1
+e81
+lE1
+0),info,false)cT2
+case
+ReplaceParams:c73{std
+xV3<iF2>list=tM3
+GetMatchedParamIndexes();std::sort(list.iN2
+list.end())yM3
+list.tF3;a-->0;)tree
+tK2
+list[a]);for(eQ1=0;a<rule.repl_param_count;++a){eJ
+nparam=xZ1
+e81
+lE1
+a),info,true);lP1
+nparam);}
+yF3}
+}
+}
+#endif
+#ifdef DEBUG_SUBSTITUTIONS
+#include <sstream>
+#include <cstring>
+using
+lF3
+FUNCTIONPARSERTYPES;using
+lF3
+l21;using
+t5;using
+yL1;lF3
+l21{tZ1
+DumpMatch
+cH1
+eT2
+lC2
+tree,const
+tB
+info,bool
+DidMatch,std::ostream&o){DumpMatch(rule
+iY3,DidMatch?l24"match"
+:l24"mismatch"
+,o);}
+tZ1
+DumpMatch
+cH1
+eT2
+lC2
+tree,const
+tB
+info,nH3
+i43,std::ostream&o){static
+const
+char
+ParamHolderNames[][2]={"%"
+,"&"
+,"x"
+,"y"
+,"z"
+,"a"
+,"b"
+,"c"
+}
+;o<<i43<<" (rule "
+<<(&rule-grammar_rules)<<")"
+<<":\n  Pattern    : "
+;{e42
+tmp;tmp.first=SubFunction;ParamSpec_SubFunction
+tmp2;tmp2.data=rule
+cE2;tmp
+tE3=cD2
+tmp2;DumpParam
+xK(tmp,o);}
+o<<"\n  Replacement: "
+;DumpParams
+lE1
+rule.repl_param_count,o);o<<"\n"
+;o<<"  Tree       : "
+i13(tree,o);o<<"\n"
+;if(!std::strcmp(i43,l24"match"
+))DumpHashes(tree,o)yM3
+0;a<tM3
+cE
+tF3;++a){if(!tM3
+paramholder_matches[a].IsDefined()cP2;o<<"           "
+<<ParamHolderNames[a]<<" = "
+i13(tM3
+paramholder_matches[a],o);o<<"\n"
+;}
+i81
+tM3
+lQ.tF3;++b){if(!tM3
+lQ[b
+tC3
+cP2
+yM3
+0;a<tM3
+lQ[b
+tD3.tF3;++a){o<<"         <"
+<<b<<"> = "
+i13(tM3
+lQ[b
+tD3[a],o);o<<std::endl;}
+}
+o<<std::flush;}
+}
+#endif
+#include <list>
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;lF3{xN1
+MarkIncompletes(FPoptimizer_CodeTree::e62{if(tree.Is_Incompletely_Hashed(tI1;bool
+iR1
+tO3
+nB1
+iR1|=MarkIncompletes
+y91
+a)eY3
+iR1)tree.Mark_Incompletely_Hashed()n31
+iR1;}
+tZ1
+FixIncompletes(FPoptimizer_CodeTree::e62{if(tree.Is_Incompletely_Hashed()){nB1
+FixIncompletes
+y91
+a));tree
+eT1}
+}
+}
+t5{lB
+Sort()tN3
+Sort();}
+lB
+Rehash(bool
+constantfolding){if(constantfolding)ConstantFolding(*this);else
+Sort();data
+x7
+xW3
+e12
+cA{cO3
+iV2
+cP3
+yD1=0;
+#if 0
+long
+double
+value=Value;e5=crc32::calc(cH1
+iF2
+char*)&value,cM3
+value));key^=(key<<24);
+#elif 0
+union{e12{iF2
+char
+filler1[16]iU2
+v;iF2
+char
+filler2[16];}
+buf2;e12{iF2
+char
+filler3[cM3
+iV2)+16-c
+M3
+x91)];e5;}
+buf1;}
+data;memset(&data,0,cM3
+data));data.buf2.v=Value;e5=data.buf1.key;
+#else
+int
+exponent
+iU2
+nM2=std::frexp(Value,&xG2;e5=nT2
+t62+0x8000)&0xFFFF
+eY3
+nM2<0){nM2=-nM2;key=key^0xFFFF;}
+else
+key+=0x10000;nM2-=iV2(0.5);key<<=39;key|=lY1(nM2+nM2)*iV2(1u<<31))<<8;
+#endif
+lP
+#ifdef FP_SUPPORT_COMPLEX_NUMBERS
+nR1
+T
+cG2
+std::complex<T> >{cO3
+std::complex<T>cP3
+cA<T>::nA3
+cH2,Value.real());nB
+fphash_t
+temp;cA<T>::nA3
+temp,Value.imag());yD1^=temp.hash2;cH2.hash2^=temp.hash1;}
+}
+;
+#endif
+#ifdef FP_SUPPORT_LONG_INT_TYPE
+i31
+cG2
+long>{yH
+long
+Value){e5=Value;lP
+#endif
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+i31
+cG2
+GmpInt>{cO3
+GmpInt
+cP3
+e5=Value.toInt();lP
+#endif
+tZ1
+xH2
+xK::Recalculate_Hash_NoRecursion(){fphash_t
+cH2(lY1
+Opcode)<<56,Opcode*iP3(0x1131462E270012B));Depth=1;switch(Opcode
+y33
+cImmed:{cA
+xK::nA3
+cH2,Value
+cT2
+case
+l03:{yD1|=lY1
+cQ1<<48
+lF1((lY1
+cQ1)*11)^iP3(0x3A83A83A83A83A0);yF3
+case
+cFCall:case
+cPCall:{yD1|=lY1
+cQ1<<48
+lF1((~lY1
+cQ1)*7)^3456789;}
+c73{size_t
+eR1=0
+yM3
+0;a<xX3;++a){if(iZ2
+y22>eR1)eR1=iZ2
+y22;yD1+=((iZ2
+i12
+hash1*(a+1))>>12)lF1
+iZ2
+i12
+hash1
+lF1(3)*iP3(0x9ABCD801357);cH2.hash2*=iP3(0xECADB912345)lF1(~iZ2
+i12
+hash2)^4567890;}
+Depth+=eR1;}
+}
+if(Hash!=cH2){Hash=cH2;l32=0;}
+}
+lB
+FixIncompleteHashes(){MarkIncompletes(*this);FixIncompletes(*this);}
+}
+#endif
+#include <cmath>
+#include <list>
+#include <cassert>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;lF3{using
+t5
+nJ1
+bool
+x01
+lC2
+tree,long
+count,const
+xH1::SequenceOpCode
+xK&eU,xH1
+yG3&synth,size_t
+max_bytecode_grow_length);static
+const
+e12
+SinCosTanDataType{OPCODE
+whichopcode;OPCODE
+inverse_opcode;enum{nominator,nN2,inverse_nominator,lG1}
+;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}
+}
+,{cI2{cSinh,cCosh,cJ2,{cSinh,cNop,{cI2
+cNop,cCosh}
+}
+,{cCosh,cNop,{cSinh,cI2
+cNop}
+}
+,{cNop,cTanh,{cCosh,cSinh,cJ2,{cNop,cSinh,{cNop,cTanh,cCosh,cNop}
+}
+,{cNop,cCosh,{cTanh,cSinh,cJ2}
+;}
+t5{lB
+SynthesizeByteCode(std
+xV3<iF2>&ByteCode,std
+xV3
+xK&Immed,size_t&stacktop_max){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Making bytecode for:\n"
+;iR
+#endif
+while(RecreateInversionsAndNegations()){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"One change issued, produced:\n"
+;iR
+#endif
+FixIncompleteHashes();using
+yL1;using
+lF3
+l21;const
+void*g=cD2
+grammar_optimize_recreate;while(ApplyGrammar(*cH1
+Grammar*)g,*this)){FixIncompleteHashes();}
+}
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Actually synthesizing, after recreating inv/neg:\n"
+;iR
+#endif
+xH1
+yG3
+synth;SynthesizeByteCode(synth,false);synth.Pull(ByteCode,Immed,stacktop_max);}
+lB
+SynthesizeByteCode(xH1
+yG3&synth,bool
+MustPopTemps
+e83{y01*this))yR;}
+for
+iA1
+a=0;a<12;++a){const
+SinCosTanDataType&data=SinCosTanData[a];if(data.whichopcode!=cNop)iD1!=data.whichopcode
+cP2;CodeTree
+nB3;nB3.lN1
+nB3
+cQ3
+inverse_opcode);nB3.n62
+y01
+nB3)){synth.l11
+else
+iD1!=cInv
+cP2;if(GetParam(0)nC!=data.inverse_opcode
+cP2;y01
+GetParam(0))){synth.l11
+size_t
+found[4];i81
+4;++b){CodeTree
+tree;if(data.i53]==cNop){tI3
+cInv);CodeTree
+nC3;nC3.lN1
+nC3
+cQ3
+i53^2]);nC3.n62
+lP1
+nC3
+t43{tree.lN1
+tree
+cQ3
+i53]);}
+tree.n62
+found[b]=synth.xU3
+tree);}
+if(found[data.yJ2!=tL
+nN2]y4
+yJ2);n81
+nN2
+i5
+cDiv
+nK1
+yJ2!=tL
+lG1]y4
+yJ2);n81
+lG1
+i5
+cMul
+nK1
+lR1!=tL
+lG1]y4
+lR1);n81
+lG1
+i5
+cRDiv
+nK1
+lR1!=tL
+nN2]y4
+lR1);n81
+nN2
+i5
+cMul,2,1);synth.l11
+size_t
+n_subexpressions_synthesized=SynthCommonSubExpressions(iS2
+switch(iS1{case
+l03:synth.PushVar(GetVar());lC
+cImmed:lH2
+GetImmed());lC
+cAdd:case
+cMul:case
+cMin:case
+cMax:case
+cAnd:case
+cOr:case
+cAbsAnd:case
+cAbsOr:iD1==cMul){bool
+cR3
+tO3
+yI
+lS1
+i61&&isLongInteger(lS1
+nC1)){c82=makeLongInteger(lS1
+nC1);CodeTree
+tmp(*this,xK3
+CodeTree::CloneTag());tmp
+t31);tmp
+eT1
+if(x01
+tmp,value,xH1::tN1
+xK::AddSequence,synth,MAX_MULI_BYTECODE_LENGTH)){cR3=true;yF3}
+}
+if(cR3)yF3
+int
+yE1=0;std::eV2
+done(GetParamCount(),false);CodeTree
+iF;iF
+xD
+iS1;for(;;){bool
+found
+tO3
+yI
+done[a]cP2;if(synth.IsStackTop(lS1)){found=true;done[a]=true;lS1.n7
+iF
+c9
+lS1
+eY3++yE1>1){synth
+yJ
+2);iF.Rehash(false)cI1
+iF);yE1=yE1-2+1;}
+}
+}
+if(!found)yF3
+yI
+done[a]cP2;lS1.n7
+iF
+c9
+lS1
+eY3++yE1>1){synth
+yJ
+2);iF.Rehash(false)cI1
+iF);yE1=yE1-2+1;}
+}
+if(yE1==0
+y13
+iS1{case
+cAdd:case
+cOr:case
+cAbsOr:lH2
+0);lC
+cMul:case
+cAnd:case
+cAbsAnd:lH2
+1);lC
+cMin:case
+cMax:lH2
+0);break;c73
+yF3++yE1;}
+assert(n_stacked==1);yF3
+case
+cPow:{lG3
+p0=GetParam(0);lG3
+p1=GetParam(1
+eY3!p1
+i61||!isLongInteger
+eH3)||!x01
+p0,makeLongInteger
+eH3),xH1::tN1
+xK::MulSequence,synth,MAX_POWI_BYTECODE_LENGTH)){p0.n7
+p1.n7
+synth
+yJ
+2);i91
+cIf:case
+cAbsIf:{xK3
+xH1
+yG3::IfData
+ifdata;GetParam(0).n7
+synth.SynthIfStep1(ifdata,iS1;GetParam(1).n7
+synth.SynthIfStep2(ifdata);GetParam(2).n7
+synth.SynthIfStep3(ifdata
+cT2
+case
+cFCall:case
+cPCall:{for
+iA1
+a=0;a<xF1++a)lS1.n7
+synth
+yJ
+nT2)GetParamCount());yE3
+nK2|GetFuncNo(),0,0
+cT2
+c73{for
+iA1
+a=0;a<xF1++a)lS1.n7
+synth
+yJ
+nT2)GetParamCount()cT2}
+synth.StackTopIs(*this
+eY3
+MustPopTemps&&n_subexpressions_synthesized>0){size_t
+top=synth.GetStackTop();synth.DoPopNMov(top-1-n_subexpressions_synthesized,top-1);}
+}
+}
+lF3{xN1
+x01
+lC2
+tree,long
+count,const
+xH1::SequenceOpCode
+xK&eU,xH1
+yG3&synth,size_t
+max_bytecode_grow_length){if
+eL3!=0){xH1
+yG3
+backup=synth;tree.n7
+size_t
+bytecodesize_backup=synth.GetByteCodeSize();xH1::x01
+count,eU,iS2
+size_t
+bytecode_grow_amount=synth.GetByteCodeSize()-bytecodesize_backup;if(bytecode_grow_amount>max_bytecode_grow_length){synth=backup
+n31
+tR3
+return
+true;}
+else{xH1::x01
+count,eU,synth)xJ2}
+}
+#endif
+#include <cmath>
+#include <cassert>
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;lF3{using
+t5;
+#define FactorStack std xV3
+const
+e12
+PowiMuliType{iF2
+opcode_square;iF2
+opcode_cumulate;iF2
+opcode_invert;iF2
+opcode_half;iF2
+opcode_invhalf;}
+iseq_powi={cSqr,cMul,cInv,cSqrt,cRSqrt}
+,iseq_muli={iP1
+xE
+cNeg,iP1,iP1}
+nJ1
+iV2
+eS1
+cH1
+PowiMuliType&cS3,const
+std
+xV3<iF2>&xP1,n72&stack
+tO2
+1);while(IP<limit){if(iT1==cS3.opcode_square){if(!isInteger
+xO1
+2;yW
+opcode_invert){nT3=-nT3;yW
+opcode_half){if
+iT2>y21&&isEvenInteger
+xO1
+iV2(0.5);yW
+opcode_invhalf){if
+iT2>y21&&isEvenInteger
+xO1
+iV2(-0.5);++IP;eR2
+size_t
+x12=IP
+iU2
+lhs(1
+eY3
+iT1==cFetch){nA1=nD2;if(index<y1||size_t(index-y1)>=iV1){IP=x12;yF3
+lhs=stack[index-y1];goto
+yK2;}
+if(iT1==cDup){lhs=nT3;goto
+yK2;yK2:eX1
+nT3);++IP
+iU2
+subexponent=eS1(cS3
+tS
+if(IP>=limit||iT1!=cS3.opcode_cumulate){IP=x12;yF3++IP;stack.pop_back();nT3+=lhs*subexponent;eR2
+yF3
+return
+nT3;}
+xW3
+iV2
+ParsePowiSequence
+cH1
+std
+xV3<iF2>&xP1){n72
+stack;eX1
+iV2(1))n31
+eS1(iseq_powi
+tS}
+xW3
+iV2
+ParseMuliSequence
+cH1
+std
+xV3<iF2>&xP1){n72
+stack;eX1
+iV2(1))n31
+eS1(iseq_muli
+tS}
+xW3
+class
+CodeTreeParserData{eX3
+l53
+CodeTreeParserData(bool
+k_powi):stack(),clones(),keep_powi(k_powi){}
+void
+Eat
+iA1
+tZ3,OPCODE
+opcode){eJ
+xI;xI
+xD
+opcode);eH
+c32=Pop(tZ3)tQ1
+c32
+eY3!keep_powi)switch(opcode
+y33
+cTanh:{eJ
+sinh,cosh;sinh
+xD
+cSinh);sinh
+c9
+xI
+lR2
+sinh
+eT1
+cosh
+xD
+cCosh);cosh
+yP1
+xI
+lR2
+cosh
+eT1
+eJ
+pow;pow
+xD
+cPow);pow
+yP1
+cosh);pow.yC
+iV2(-1)));pow
+eT1
+xI
+tH3
+xI.nG1
+0,sinh);xI
+yP1
+pow
+cT2
+case
+cTan:{eJ
+sin,cos;sin
+xD
+cSin);sin
+c9
+xI
+lR2
+sin
+eT1
+cos
+xD
+cCos);cos
+yP1
+xI
+lR2
+cos
+eT1
+eJ
+pow;pow
+xD
+cPow);pow
+yP1
+cos);pow.yC
+iV2(-1)));pow
+eT1
+xI
+tH3
+xI.nG1
+0,sin);xI
+yP1
+pow
+cT2
+case
+cPow:{lC2
+p0=xI
+l8
+0);lC2
+p1=xI
+l8
+1
+eY3
+p1
+nC==cAdd){eH
+mulgroup(p1.GetParamCount())yM3
+0;a<p1.xF1++a){eJ
+pow;pow
+xD
+cPow);pow
+c9
+p0);pow
+c9
+p1
+x13
+pow
+eT1
+mulgroup[a
+i63
+pow);}
+xI
+xD
+cMul)tQ1
+nN3;}
+yF3
+c73
+yF3
+xI.Rehash(!keep_powi);iU1,false);
+#ifdef DEBUG_SUBSTITUTIONS
+eZ1<<tZ3<<", "
+<<c83
+opcode)<<"->"
+<<c83
+xI
+nC)<<": "
+iV3
+xI
+tT
+xI);
+#endif
+eX1
+xI
+lI3
+EatFunc
+iA1
+tZ3,OPCODE
+t83
+iF2
+funcno){eJ
+xI=CodeTreeFuncOp
+xK(t83
+funcno);eH
+c32=Pop(tZ3)tQ1
+c32);xI.n62
+#ifdef DEBUG_SUBSTITUTIONS
+eZ1<<tZ3<<", "
+iV3
+xI
+tT
+xI);
+#endif
+iU1);eX1
+xI
+lI3
+AddConst(yJ1){eJ
+xI=CodeTreeImmed(value);iU1);Push(xI
+lI3
+AddVar
+nT2
+varno){eJ
+xI=CodeTreeVar
+xK(varno);iU1);Push(xI
+lI3
+SwapLastTwoInStack(){eY1
+1
+i63
+eY1
+2]lI3
+Dup(){Fetch(iV1-1
+lI3
+Fetch
+iA1
+which){Push(stack[which]);}
+nR1
+T>void
+Push(T
+tree){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<iV3
+tree
+tT
+tree);
+#endif
+eX1
+tree
+lI3
+PopNMov
+iA1
+target,size_t
+source){stack[target]=stack[source];stack.t73
+target+1);}
+eJ
+yL2{clones.clear();eJ
+nT3(stack.back());stack.t73
+iV1-1)n31
+nT3;}
+eH
+Pop
+iA1
+n_pop){eH
+nT3(n_pop);for
+nT2
+n=0;n<n_pop;++n)nT3[n
+i63
+eY1
+n_pop+n]);
+#ifdef DEBUG_SUBSTITUTIONS
+for
+iA1
+n=n_pop;n-->0;){eZ1
+i13
+iT2[n]tT
+nT3[n]);}
+#endif
+stack.t73
+iV1-n_pop)n31
+nT3;}
+size_t
+GetStackTop(yZ1
+iV1;}
+private:void
+FindClone(eJ&,bool=true)yR;}
+private:eH
+stack;std::multimap<fphash_t,eJ>clones;bool
+keep_powi;private:CodeTreeParserData
+cH1
+CodeTreeParserData&);CodeTreeParserData&eA1=cH1
+CodeTreeParserData&);}
+nJ1
+e12
+IfInfo{eJ
+eI2;eJ
+thenbranch;size_t
+endif_location;IfInfo():eI2(),thenbranch(),endif_location(){}
+}
+;}
+t5{lB
+GenerateFrom
+cH1
+xK3
+FunctionParserBase
+xK::Data&xH3,bool
+keep_powi){eH
+xC2;xC2.xS3
+xH3.mVariablesAmount);for
+nT2
+n=0;n<xH3.mVariablesAmount;++n){xC2.push_back(CodeTreeVar
+xK(n+l03));}
+GenerateFrom(xH3,xC2,keep_powi);}
+lB
+GenerateFrom
+cH1
+xK3
+FunctionParserBase
+xK::Data&xH3,const
+x1&xC2,bool
+keep_powi){const
+std
+xV3<iF2>&ByteCode=xH3.mByteCode;const
+std
+xV3
+xK&Immed=xH3.mImmed;
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"ENTERS GenerateFrom()\n"
+;
+#endif
+CodeTreeParserData
+xK
+sim(keep_powi);std
+xV3<IfInfo
+xK>eG;for
+iA1
+IP=0,DP=0;;++IP){i22:while(!eG
+cT3&&(eG.e6==IP||(IP<i8
+tF3&&iT1==cJump&&eG.tE1.IsDefined()))){CodeTree
+elsebranch=sim.yL2
+nB2
+eG.back().eI2)nB2
+eG.tE1)nB2
+elsebranch);tQ2
+3,cIf);eG.pop_back();}
+if(IP>=i8
+tF3)break;iF2
+opcode=iT1;if((opcode==cSqr||opcode==cDup||(opcode==cInv&&!IsIntType
+xK::nT3)||opcode==cNeg||opcode==cSqrt||opcode==cRSqrt||opcode==cFetch)){size_t
+was_ip=IP
+iU2
+e92
+ParsePowiSequence
+xK(ByteCode,IP,eG
+cT3?i8
+tF3:eG.e6,sim.xM
+1);if
+t62!=iV2(1.0)){xL
+exponent
+xD2;goto
+i22;}
+if(opcode==cDup||opcode==cFetch||opcode==cNeg
+tJ2
+xT2=ParseMuliSequence
+xK(ByteCode,IP,eG
+cT3?i8
+tF3:eG.e6,sim.xM
+1
+eY3
+xT2!=iV2(1.0)){xL
+xT2)y3
+cMul);goto
+i22;}
+}
+IP=was_ip;}
+if(n82>=l03){nA1=opcode-l03
+nB2
+xC2[index]t43{switch(n82
+y33
+cIf:case
+cAbsIf:{eG.t73
+eG.tF3+1);CodeTree
+res(sim.yL2);eG.back().eI2.swap(res);eG.e6=i8
+tF3;IP+=2;eR2
+case
+cJump:{CodeTree
+res(sim.yL2);eG.tE1.swap(res);eG.e6=lE3
+IP+1]+1;IP+=2;eR2
+case
+cImmed:xL
+Immed[DP++]);lC
+cDup:sim.Dup();lC
+cNop:lC
+cFCall:{iF2
+funcno=nD2;assert(funcno<fpdata.mFuncPtrs.size());iF2
+c32=xH3.mFuncPtrs[funcno].mParams;sim.EatFunc(c32,n82,funcno
+cT2
+case
+cPCall:{iF2
+funcno=nD2;assert(funcno<fpdata.iT3.size());const
+FunctionParserBase
+xK&p=*xH3.iT3[funcno].mParserPtr;iF2
+c32=xH3.iT3[funcno].mParams;x1
+paramlist=sim.Pop(c32);CodeTree
+i32;i32.GenerateFrom(*p.mData,paramlist)nB2
+i32
+cT2
+case
+cInv:xL
+1
+cQ2
+cDiv);lC
+cNeg:nC2
+cNeg);break;xL
+0
+cQ2
+cSub);lC
+cSqr:xL
+2
+xD2;lC
+cSqrt
+e72
+t01
+cRSqrt
+e72-t01
+cCbrt
+e72
+1)/iV2(3)xD2;lC
+cDeg:xL
+fp_const_rad_to_deg
+eU1
+cRad:xL
+fp_const_deg_to_rad
+eU1
+cExp:cR1)goto
+iQ2;xL
+fp_const_e
+xK()cQ2
+cPow);lC
+cExp2:cR1)goto
+iQ2;xL
+2.0
+cQ2
+cPow);lC
+cCot:nC2
+cTan
+nW
+cCsc:nC2
+cSin
+nW
+cSec:nC2
+cCos
+nW
+cInt:
+#ifndef __x86_64
+cR1){nC2
+cInt
+cT2
+#endif
+xL
+iV2(0.5))nD3
+nC2
+cFloor);lC
+cLog10:nC2
+cX3
+fp_const_log10inv
+eU1
+cLog2:nC2
+cX3
+fp_const_log2inv
+eU1
+eF3:iZ3
+cX3
+fp_const_log2inv
+xK());tQ2
+3,cMul);lC
+cHypot:xL
+2
+xD2;i73
+xL
+2
+xD2
+nD3
+xL
+iV2(t01
+cSinCos:sim.Dup();nC2
+cSin);iZ3
+cCos);lC
+cSinhCosh:sim.Dup();nC2
+cSinh);iZ3
+cCosh);lC
+cRSub:i73
+case
+cSub:cR1){tQ2
+2,cSub
+cT2
+xL-1)y3
+cMul)nD3
+lC
+cRDiv:i73
+case
+cDiv:cR1||IsIntType
+xK::nT3){tQ2
+2,cDiv
+cT2
+xL-1
+xD2
+y3
+cMul);lC
+cAdd:case
+cMul:case
+cMod:case
+cPow:case
+cEqual:case
+cLess:case
+cGreater:case
+cNEqual:case
+cLessOrEq:case
+cGreaterOrEq:case
+cAnd:case
+cOr:case
+cAbsAnd:case
+cAbsOr:tQ2
+2,t11
+lC
+cNot:case
+cNotNot:case
+cZ3:case
+cAbsNotNot:nC2
+t11
+lC
+cFetch:sim.Fetch(nD2);lC
+cPopNMov:{iF2
+stackOffs_target=nD2;iF2
+stackOffs_source=nD2;sim.PopNMov(stackOffs_target,stackOffs_source
+cT2
+c73
+iQ2:;iF2
+funcno=opcode-cAbs;assert(funcno<FUNC_AMOUNT);const
+FuncDefinition&func=Functions[funcno];tQ2
+func.c32,t11
+yF3}
+}
+Become(sim.yL2);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Produced tree:\n"
+;iR
+#endif
+}
+}
+#endif
+#include <algorithm>
+#ifdef FP_SUPPORT_OPTIMIZER
+#include <assert.h>
+#define FP_MUL_COMBINE_EXPONENTS
+lF3{using
+lF3
+FUNCTIONPARSERTYPES;using
+t5
+nJ1
+static
+void
+AdoptChildrenWithSameOpcode(e62{
+#ifdef DEBUG_SUBSTITUTIONS
+bool
+nO2
+tO3
+#endif
+for
+iY
+if
+y91
+a)nC==i01){
+#ifdef DEBUG_SUBSTITUTIONS
+if(!nO2)yC2"Before assimilation: "
+yA1
+nO2=true;}
+#endif
+tree.AddParamsMove
+y91
+a).GetUniqueRef().l02),a);}
+#ifdef DEBUG_SUBSTITUTIONS
+if(nO2)yC2"After assimilation:   "
+yA1}
+#endif
+}
+}
+t5{tZ1
+ConstantFolding(e62{tree.Sort();
+#ifdef DEBUG_SUBSTITUTIONS
+void*cY3=0;std::cout<<"["
+<<(&cY3)<<"]Runs ConstantFolding for: "
+yA1
+DumpHashes(tree
+lT2
+std::flush;
 #endif
-
-        OptimizeConflict();
-
-#ifdef TREE_DEBUG
-        cout << "AFTER MATH1 B   :" << *this << endl;
+if(false){redo:;tree.Sort();
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"["
+<<(&cY3)<<"]Re-runs ConstantFolding: "
+yA1
+DumpHashes(tree);
 #endif
-    }
-
-    void OptimizeAddMulFlat()
-    {
-        // This optimization flattens the topography of the tree.
-        //   Examples:
-        //       x + (y+z) = x+y+z
-        //       x * (y/z) = x*y/z
-        //       x / (y/z) = x/y*z
-        //       min(x, min(y,z)) = min(x,y,z)
-        //       max(x, max(y,z)) = max(x,y,z)
-
-        if(GetOp() == cAdd
-        || GetOp() == cMul
-        || GetOp() == cMin
-        || GetOp() == cMax)
-        {
-            // If children are same type as parent add them here
-            for(pit b, a=GetBegin(); a!=GetEnd(); a=b)
-            {
-                const SubTree &pa = *a;  b=a; ++b;
-                if(pa->GetOp() != GetOp()) continue;
-
-                // Child is same type
-                for(pcit c=pa->GetBegin();
-                         c!=pa->GetEnd();
-                         ++c)
-                {
-                    const SubTree &pb = *c;
-                    if(pa.getsign())
-                    {
-                        // +a -(+b +c)
-                        // means b and c will be negated
-
-                        SubTree tmp = pb;
-                        if(GetOp() == cMul)
-                            tmp.Invert();
-                        else
-                            tmp.Negate();
-                        AddParam(tmp);
-                    }
-                    else
-                        AddParam(pb);
-                }
-                Erase(a);
-
-                // Note: OptimizeConstantMath1() would be a good thing to call next.
-            }
-        }
-    }
-
-    void OptimizeLinearCombine()
-    {
-        // This optimization does the following:
-        //
-        //   x*x*x*x -> x^4
-        //   x+x+x+x -> x*4
-        //   x*x     -> x^2
-        //   x/z/z   ->
-        //   
-        //   min(x,x,y) -> min(x,y)
-        //   max(x,x,y) -> max(x,y)
-        //   max(x,x)   -> max(x)
-
-        // Remove conflicts first, so we don't have to worry about signs.
-        OptimizeConflict();
-
-        bool didchanges = false;
-        bool FactorIsImportant = true;
-        unsigned ReplacementOpcode = GetOp();
-        
-        switch(GetOp())
-        {
-        case cAdd:
-            FactorIsImportant = true;
-            ReplacementOpcode = cMul;
-            goto Redo;
-        case cMul:
-            FactorIsImportant = true;
-            ReplacementOpcode = cPow;
-            goto Redo;
-        case cMin:
-            FactorIsImportant = false;
-            goto Redo;
-        case cMax:
-            FactorIsImportant = false;
-            goto Redo;
-        default: break;
-        Redo:
-            for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                const SubTree &pa = *a;
-
-                list<pit> poslist;
-
-                for(pit b=a; ++b!=GetEnd(); )
-                {
-                    const SubTree &pb = *b;
-                    if(*pa == *pb)
-                        poslist.push_back(b);
-                }
-
-                unsigned min = 2;
-                if(poslist.size() >= min)
-                {
-                    SubTree arvo = pa;
-                    bool negate = arvo.getsign();
-
-                    double factor = poslist.size() + 1;
-
-                    if(negate)
-                    {
-                        arvo.Negate();
-                        factor = -factor;
-                    }
-                    
-                    if(FactorIsImportant)
-                    {
-                        CodeTree tmp;
-                        tmp.SetOp(ReplacementOpcode);
-                        tmp.AddParam(arvo);
-                        tmp.AddParam(factor);
-
-                        list<pit>::const_iterator j;
-                        for(j=poslist.begin(); j!=poslist.end(); ++j)
-                            Erase(*j);
-                        poslist.clear();
-                        *a = tmp;
-                    }
-                    else
-                    {
-                        list<pit>::const_iterator j;
-                        bool first=true;
-                        for(j=poslist.begin(); j!=poslist.end(); ++j, first=false)
-                            if(!first)
-                                Erase(*j);
-                    }
-                    didchanges = true;
-                    goto Redo;
-                }
-            }
-        }
-        
-        if(didchanges)
-        {
-            // As a result, there might be need for this:
-            OptimizeAddMulFlat();
-            // And this:
-            OptimizeRedundant();
-        }
-    }
-
-    void OptimizeLogarithm()
-    {
-        /*
-            This is basic logarithm math:
-              pow(X,Y)/log(Y) = X
-              log(X)/log(Y) = logY(X)
-              log(X^Y)      = log(X)*Y
-              log(X*Y)      = log(X)+log(Y)
-              exp(log(X)*Y) = X^Y
-
-            This function does these optimizations:
-               pow(const_E, log(x))   = x
-               pow(const_E, log(x)*y) = x^y
-               pow(10,      log(x)*const_L10I*y) = x^y
-               pow(z,       log(x)/log(z)*y)     = x^y
-
-            And this:
-               log(x^z)             = z * log(x)
-            Which automatically causes these too:
-               log(pow(const_E, x))         = x
-               log(pow(y,       x))         = x * log(y)
-               log(pow(pow(const_E, y), x)) = x*y
-
-            And it does this too:
-               log(x) + log(y) + log(z) = log(x * y * z)
-               log(x * exp(y)) = log(x) + y
-
-        */
-
-        // Must be already in exponential form.
-
-        // Optimize exponents before doing something.
-        OptimizeExponents();
-
-        if(GetOp() == cLog)
-        {
-            // We should have one parameter for log() function.
-            // If we don't, we're screwed.
-
-            const SubTree &p = getp0();
-
-            if(p->GetOp() == cPow)
-            {
-                // Found log(x^y)
-                SubTree p0 = p->getp0(); // x
-                SubTree p1 = p->getp1(); // y
-
-                // Build the new logarithm.
-                CodeTree tmp(GetOp(), p0);  // log(x)
-
-                // Become log(x) * y
-                ReplaceWith(cMul, tmp, p1);
-            }
-            else if(p->GetOp() == cMul)
-            {
-                // Redefine &p nonconst
-                SubTree &p = getp0();
-
-                p->OptimizeAddMulFlat();
-                p->OptimizeExponents();
-                
-                p.CheckConstInv();
-
-                list<SubTree> adds;
-
-                for(pit b, a = p->GetBegin();
-                           a != p->GetEnd(); a=b)
-                {
-                    SubTree &pa = *a;  b=a; ++b;
-                    if(pa->GetOp() == cPow
-                    && pa->getp0()->IsImmed()
-                    && pa->getp0()->GetImmed() == CONSTANT_E)
-                    {
-                        adds.push_back(pa->getp1());
-                        p->Erase(a);
-                        continue;
-                    }
-                }
-                if(adds.size())
-                {
-                    CodeTree tmp(cAdd, *this);
-
-                    list<SubTree>::const_iterator i;
-                    for(i=adds.begin(); i!=adds.end(); ++i)
-                        tmp.AddParam(*i);
-
-                    ReplaceWith(tmp);
-                }
-            }
-        }
-        if(GetOp() == cAdd)
-        {
-            // Check which ones are logs.
-            list<pit> poslist;
-
-            for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                const SubTree &pa = *a;
-                if(pa->GetOp() == cLog)
-                    poslist.push_back(a);
-            }
-
-            if(poslist.size() >= 2)
-            {
-                CodeTree tmp(cMul, 1.0); // eek
-
-                list<pit>::const_iterator j;
-                for(j=poslist.begin(); j!=poslist.end(); ++j)
-                {
-                    const SubTree &pb = **j;
-                    // Take all of its children
-                    for(pcit b=pb->GetBegin();
-                             b!=pb->GetEnd();
-                             ++b)
-                    {
-                        SubTree tmp2 = *b;
-                        if(pb.getsign()) tmp2.Negate();
-                        tmp.AddParam(tmp2);
-                    }
-                    Erase(*j);
-                }
-                poslist.clear();
-
-                AddParam(CodeTree(cLog, tmp));
-            }
-            // Done, hopefully
-        }
-        if(GetOp() == cPow)
-        {
-            const SubTree &p0 = getp0();
-            SubTree &p1 = getp1();
-
-            if(p0->IsImmed() && p0->GetImmed() == CONSTANT_E
-            && p1->GetOp() == cLog)
-            {
-                // pow(const_E, log(x)) = x
-                ReplaceWith(*(p1->getp0()));
-            }
-            else if(p1->GetOp() == cMul)
-            {
-                //bool didsomething = true;
-                
-                pit poslogpos; bool foundposlog = false;
-                pit neglogpos; bool foundneglog = false;
-
-                ConstList cl = p1->BuildConstList();
-
-                for(pit a=p1->GetBegin(); a!=p1->GetEnd(); ++a)
-                {
-                    const SubTree &pa = *a;
-                    if(pa->GetOp() == cLog)
-                    {
-                        if(!pa.getsign())
-                        {
-                            foundposlog = true;
-                            poslogpos   = a;
-                        }
-                        else if(*p0 == *(pa->getp0()))
-                        {
-                            foundneglog = true;
-                            neglogpos   = a;
-                        }
-                    }
-                }
-
-                if(p0->IsImmed()
-                && p0->GetImmed() == 10.0
-                && cl.value == CONSTANT_L10I
-                && foundposlog)
-                {
-                    SubTree base = (*poslogpos)->getp0();
-                    p1->KillConst(cl);
-                    p1->Erase(poslogpos);
-                    p1->OptimizeRedundant();
-                    SubTree mul = p1;
-
-                    ReplaceWith(cPow, base, mul);
-
-                    // FIXME: what optimizations should be done now?
-                    return;
-                }
-
-                // Put back the constant
-                FinishConst(cl, true);
-
-                if(p0->IsImmed()
-                && p0->GetImmed() == CONSTANT_E
-                && foundposlog)
-                {
-                    SubTree base = (*poslogpos)->getp0();
-                    p1->Erase(poslogpos);
-
-                    p1->OptimizeRedundant();
-                    SubTree mul = p1;
-
-                    ReplaceWith(cPow, base, mul);
-
-                    // FIXME: what optimizations should be done now?
-                    return;
-                }
-
-                if(foundposlog
-                && foundneglog
-                && *((*neglogpos)->getp0()) == *p0)
-                {
-                    SubTree base = (*poslogpos)->getp0();
-                    p1->Erase(poslogpos);
-                    p1->Erase(neglogpos);
-
-                    p1->OptimizeRedundant();
-                    SubTree mul = p1;
-
-                    ReplaceWith(cPow, base, mul);
-
-                    // FIXME: what optimizations should be done now?
-                    return;
-                }
-            }
-        }
-    }
-
-    void OptimizeFunctionCalls()
-    {
-        /* Goals: sin(asin(x)) = x
-         *        cos(acos(x)) = x
-         *        tan(atan(x)) = x
-         * NOTE:
-         *   Do NOT do these:
-         *     asin(sin(x))
-         *     acos(cos(x))
-         *     atan(tan(x))
-         *   Because someone might want to wrap the angle.
-         */
-        // FIXME: TODO
-    }
-
-    void OptimizePowMulAdd()
-    {
-        // x^3 * x -> x^4
-        // x*3 + x -> x*4
-        // FIXME: Do those
-
-        // x^1 -> x
-        if(GetOp() == cPow)
-        {
-            const SubTree &base     = getp0();
-            const SubTree &exponent = getp1();
-
-            if(exponent->IsImmed())
-            {
-                if(exponent->GetImmed() == 1.0)
-                    ReplaceWith(*base);
-                else if(exponent->GetImmed() == 0.0
-                     && base->NonZero())
-                    ReplaceWithConst(1.0);
-            }
-        }
-    }
-
-    void OptimizeExponents()
-    {
-        /* Goals:
-         *     (x^y)^z   -> x^(y*z)
-         *     x^y * x^z -> x^(y+z)
-         */
-        // First move to exponential form.
-        OptimizeLinearCombine();
-
-        bool didchanges = false;
-
-    Redo:
-        if(GetOp() == cPow)
-        {
-            // (x^y)^z   -> x^(y*z)
-
-            const SubTree &p0 = getp0();
-            const SubTree &p1 = getp1();
-            if(p0->GetOp() == cPow)
-            {
-                CodeTree tmp(cMul, p0->getp1(), p1);
-                tmp.Optimize();
-
-                ReplaceWith(cPow, p0->getp0(), tmp);
-
-                didchanges = true;
-                goto Redo;
-            }
-        }
-        if(GetOp() == cMul)
-        {
-            // x^y * x^z -> x^(y+z)
-
-            for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                const SubTree &pa = *a;
-
-                if(pa->GetOp() != cPow) continue;
-
-                list<pit> poslist;
-
-                for(pit b=a; ++b != GetEnd(); )
-                {
-                    const SubTree &pb = *b;
-                    if(pb->GetOp() == cPow
-                    && *(pa->getp0())
-                    == *(pb->getp0()))
-                    {
-                        poslist.push_back(b);
-                    }
-                }
-
-                if(poslist.size() >= 1)
-                {
-                    poslist.push_back(a);
-
-                    CodeTree base = *(pa->getp0());
-
-                    CodeTree exponent(cAdd, 0.0); //eek
-
-                    // Collect all exponents to cAdd
-                    list<pit>::const_iterator i;
-                    for(i=poslist.begin(); i!=poslist.end(); ++i)
-                    {
-                        const SubTree &pb = **i;
-
-                        SubTree tmp2 = pb->getp1();
-                        if(pb.getsign()) tmp2.Invert();
-
-                        exponent.AddParam(tmp2);
-                    }
-
-                    exponent.Optimize();
-
-                    CodeTree result(cPow, base, exponent);
-
-                    for(i=poslist.begin(); i!=poslist.end(); ++i)
-                        Erase(*i);
-                    poslist.clear();
-
-                    AddParam(result); // We're cMul, remember
-
-                    didchanges = true;
-                    goto Redo;
-                }
-            }
-        }
-
-        OptimizePowMulAdd();
-
-        if(didchanges)
-        {
-            // As a result, there might be need for this:
-            OptimizeConflict();
-        }
-    }
-
-    void OptimizeLinearExplode()
-    {
-        // x^2 -> x*x
-        // But only if x is just a simple thing
-
-        // Won't work on anything else.
-        if(GetOp() != cPow) return;
-
-        // TODO TODO TODO
-    }
-
-    void OptimizePascal()
-    {
-#if 0    // Too big, too specific, etc
-
-        // Won't work on anything else.
-        if(GetOp() != cAdd) return;
-
-        // Must be done after OptimizeLinearCombine();
-
-        // Don't need pascal triangle
-        // Coefficient for x^a * y^b * z^c = 3! / (a! * b! * c!)
-
-        // We are greedy and want other than just binomials
-        // FIXME
-
-        // note: partial ones are also nice
-        //     x*x + x*y + y*y
-        //   = (x+y)^2 - x*y
-        //
-        //     x x * x y * + y y * +
-        // ->  x y + dup * x y * -
-#endif
-    }
-
-public:
-
-    void Optimize();
-
-    void Assemble(vector<unsigned> &byteCode,
-                  vector<double>   &immed,
-                  size_t& stacktop_cur,
-                  size_t& stacktop_max) const;
-
-    void FinalOptimize()
-    {
-        // First optimize each parameter.
-        for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            (*a)->FinalOptimize();
-
-        /* These things are to be done:
-         *
-         * x * CONSTANT_DR        -> cDeg(x)
-         * x * CONSTANT_RD        -> cRad(x)
-         * pow(x, 0.5)            -> sqrt(x)
-         * log(x) * CONSTANT_L10I -> log10(x)
-         * pow(CONSTANT_E, x)     -> exp(x)
-         * inv(sin(x))            -> csc(x)
-         * inv(cos(x))            -> sec(x)
-         * inv(tan(x))            -> cot(x)
-         */
-
-
-        if(GetOp() == cPow)
-        {
-            const SubTree &p0 = getp0();
-            const SubTree &p1 = getp1();
-            if(p0->GetOp()    == cImmed
-            && p0->GetImmed() == CONSTANT_E)
-            {
-                ReplaceWith(cExp, p1);
-            }
-            else if(p1->GetOp()    == cImmed
-                 && p1->GetImmed() == 0.5)
-            {
-                ReplaceWith(cSqrt, p0);
-            }
-        }
-        if(GetOp() == cMul)
-        {
-            if(GetArgCount() == 1 && getp0().getsign())
-            {
-                /***/if(getp0()->GetOp() == cSin)ReplaceWith(cCsc, getp0()->getp0());
-                else if(getp0()->GetOp() == cCos)ReplaceWith(cSec, getp0()->getp0());
-                else if(getp0()->GetOp() == cTan)ReplaceWith(cCot, getp0()->getp0());
-            }
-        }
-        // Separate "if", because op may have just changed
-        if(GetOp() == cMul)
-        {
-            /* NOTE: Not gcov'd yet */
-            
-            CodeTree *found_log = 0;
-
-            ConstList cl = BuildConstList();
-
-            for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                SubTree &pa = *a;
-                if(pa->GetOp() == cLog && !pa.getsign())
-                    found_log = &*pa;
-            }
-            if(cl.value == CONSTANT_L10I && found_log)
-            {
-                // Change the log() to log10()
-                found_log->SetOp(cLog10);
-                // And forget the constant
-                KillConst(cl);
-            }
-            else if(cl.value == CONSTANT_DR)
-            {
-                KillConst(cl);
-                OptimizeRedundant();
-#ifdef TREE_DEBUG
-    cout << "PRE_REP         :" << (*this) << endl;
-#endif
-                ReplaceWith(cDeg, *this);
-#ifdef TREE_DEBUG
-    cout << "POST_REP        :" << (*this) << endl;
-#endif
-            }
-            else if(cl.value == CONSTANT_RD)
-            {
-                KillConst(cl);
-                OptimizeRedundant();
-                ReplaceWith(cRad, *this);
-            }
-            else FinishConst(cl, true);
-        }
-
-        SortIfPossible();
-    }
-};
-
-#ifdef TREE_DEBUG
-std::ostream& operator << (std::ostream& str, const CodeTree& tree)
-{
-    const CodeTreeData& data = *tree.data;
-    switch( (FUNCTIONPARSERTYPES::OPCODE) data.GetOp())
-    {
-        case cImmed: str << data.GetImmed(); return str;
-        case cVar:   str << "Var" << data.GetVar(); return str;
-        case cFCall: str << "FCall(Func" << data.GetFuncNo() << ")"; break;
-        case cPCall: str << "PCall(Func" << data.GetFuncNo() << ")"; break;
-        
-        case cAbs: str << "cAbs"; break;
-        case cAcos: str << "cAcos"; break;
-#ifndef NO_ASINH
-        case cAcosh: str << "cAcosh"; break;
-#endif
-        case cAsin: str << "cAsin"; break;
-#ifndef NO_ASINH
-        case cAsinh: str << "cAsinh"; break;
-#endif
-        case cAtan: str << "cAtan"; break;
-        case cAtan2: str << "cAtan2"; break;
-#ifndef NO_ASINH
-        case cAtanh: str << "cAtanh"; break;
-#endif
-        case cCeil: str << "cCeil"; break;
-        case cCos: str << "cCos"; break;
-        case cCosh: str << "cCosh"; break;
-        case cCot: str << "cCot"; break;
-        case cCsc: str << "cCsc"; break;
-#ifndef DISABLE_EVAL
-        case cEval: str << "cEval"; break;
-#endif
-        case cExp: str << "cExp"; break;
-        case cFloor: str << "cFloor"; break;
-        case cIf: str << "cIf"; break;
-        case cInt: str << "cInt"; break;
-        case cLog: str << "cLog"; break;
-        case cLog10: str << "cLog10"; break;
-        case cMax: str << "cMax"; break;
-        case cMin: str << "cMin"; break;
-        case cSec: str << "cSec"; break;
-        case cSin: str << "cSin"; break;
-        case cSinh: str << "cSinh"; break;
-        case cSqrt: str << "cSqrt"; break;
-        case cTan: str << "cTan"; break;
-        case cTanh: str << "cTanh"; break;
-
-        // These do not need any ordering:
-        case cJump: str << "cJump"; break;
-        case cNeg: str << "cNeg"; break;
-        case cAdd: str << "cAdd"; break;
-        case cSub: str << "cSub"; break;
-        case cMul: str << "cMul"; break;
-        case cDiv: str << "cDiv"; break;
-        case cMod: str << "cMod"; break;
-        case cPow: str << "cPow"; break;
-        case cEqual: str << "cEqual"; break;
-        case cNEqual: str << "cNEqual"; break;
-        case cLess: str << "cLess"; break;
-        case cLessOrEq: str << "cLessOrEq"; break;
-        case cGreater: str << "cGreater"; break;
-        case cGreaterOrEq: str << "cGreaterOrEq"; break;
-        case cNot: str << "cNot"; break;
-        case cAnd: str << "cAnd"; break;
-        case cOr: str << "cOr"; break;
-        case cDeg: str << "cDeg"; break;
-        case cRad: str << "cRad"; break;
-        case cDup: str << "cDup"; break;
-        case cInv: str << "cInv"; break;
-        case VarBegin: str << "VarBegin"; break;
-    }
-    str << '(';
-    
-    bool first = true;
-    for(paramlist::const_iterator
-        i = data.args.begin(); i != data.args.end(); ++i)
-    {
-        if(first) first=false; else str << ", ";
-        const SubTree& sub = *i;
-        if(sub.getsign()) str << '!';
-        str << *sub;
-    }
-    str << ')';
-    
-    return str;
 }
+if(i01!=cImmed){c23
+p=iN
+tree
+eY3
+p
+n51&&p
+nP2
+tF2==e13){xO
+p
+tF2);nD}
+if(false){ReplaceTreeWithOne:xO
+iV2(1));goto
+do_return;ReplaceTreeWithZero:xO
+xD1;goto
+do_return;ReplaceTreeWithParam0:
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Before replace: "
+;std::cout<<std::hex<<'['lD2
+hash1<<','lD2
+hash2<<']'<<std::dec
+yA1
 #endif
-
-void CodeTreeDataPtr::Shock()
-{
- /*
-    PrepareForWrite();
-    paramlist &p2 = (*this)->args;
-    for(paramlist::iterator i=p2.begin(); i!=p2.end(); ++i)
-    {
-        (*i)->data.Shock();
-    }
- */
+tree.xY2
+0));
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"After replace: "
+;std::cout<<std::hex<<'['lD2
+hash1<<','lD2
+hash2<<']'<<std::dec
+yA1
+#endif
+cZ
+l73
+i01
+y33
+cImmed:lC
+l03:lC
+cAnd:case
+cAbsAnd:eQ
+bool
+c2
+tO3
+for
+iY{if(!yX3
+a)))c2=true;cW3
+a),i01==cAbsAnd)y33
+IsNever
+eL
+IsAlways:tree
+t31);lC
+lT1
+l73
+eM
+y33
+0:i6
+1:tI3
+i01==cAnd?cNotNot:cAbsNotNot);cZ
+c73
+l83
+cAnd||!c2)if(ConstantFolding_AndLogic(eJ2
+i91
+cOr:case
+cAbsOr:eQ
+bool
+c2
+tO3
+for
+iY{if(!yX3
+a)))c2=true;cW3
+a),i01==cAbsOr))l92
+i6
+lC3
+tree
+t31);lC
+lT1
+l73
+eM
+y33
+0
+eL
+1:tI3
+i01==cOr?cNotNot:cAbsNotNot);cZ
+c73
+l83
+cOr||!c2)if(ConstantFolding_OrLogic(eJ2
+i91
+cNot:case
+cZ3:{iF2
+lZ1
+0;switch
+y91
+0)nC
+y33
+cEqual:lZ1
+cNEqual;lC
+cNEqual:lZ1
+cEqual;lC
+cLess:lZ1
+cGreaterOrEq;lC
+cGreater:lZ1
+cLessOrEq;lC
+cLessOrEq:lZ1
+cGreater;lC
+cGreaterOrEq:lZ1
+cLess;lC
+cNotNot:lZ1
+cNot;lC
+cNot:lZ1
+cNotNot;lC
+cZ3:lZ1
+cAbsNotNot;lC
+cAbsNotNot:lZ1
+cZ3;break;c73
+yF3
+if(opposite){tI3
+OPCODE(opposite));tree.SetParamsMove
+y91
+0).GetUniqueRef().l02));cZ
+l73
+tM
+0),tree
+cS1
+y33
+IsAlways
+eL
+lC3
+i6
+lT1
+l83
+cNot&&GetPositivityInfo
+y91
+0))==IsAlways)tI3
+cZ3);lT3
+nC==cIf||lE2
+0)nC==yW3{eJ
+l93=lE2
+0);lC2
+ifp1=l93
+l8
+1);lC2
+ifp2=l93
+l8
+2
+eY3
+ifp1
+nC
+lA3
+ifp1
+cS1{tree
+xJ
+ifp1
+nC==cNot?cNotNot:cAbsNotNot
+cU3
+lR2
+cV3
+eJ
+p2;p2
+iP2
+p2
+e03
+tN
+if(ifp2
+nC
+lA3
+ifp2
+cS1{tree
+xJ
+i01
+cU3);cV3
+eJ
+p2;p2
+xD
+ifp2
+nC==cNot?cNotNot:cAbsNotNot);p2
+e03
+l8
+0)tN
+i91
+cNotNot:case
+cAbsNotNot:{if(yX3
+0)))nY3
+cW3
+0),i01==cAbsNotNot)y33
+IsNever
+eL
+IsAlways:i6
+lT1
+l83
+cNotNot&&GetPositivityInfo
+y91
+0))==IsAlways)tI3
+cAbsNotNot);lT3
+nC==cIf||lE2
+0)nC==yW3{eJ
+l93=lE2
+0);lC2
+ifp1=l93
+l8
+1);lC2
+ifp2=l93
+l8
+2
+eY3
+ifp1
+nC
+lA3
+ifp1
+cS1{cM1
+0,l93
+lR2
+i83
+ifp1);eJ
+p2;p2
+iP2
+p2
+e03
+tN
+if(ifp2
+nC
+lA3
+ifp2
+cS1{tree
+xJ
+i01
+cU3);cV3
+tree
+e03);tI3
+l93
+nC);cZ}
+i91
+cIf:case
+cAbsIf:{if(ConstantFolding_IfOperations(eJ2
+yF3
+case
+cMul:{NowWeAreMulGroup:;AdoptChildrenWithSameOpcode(tree)iU2
+nL1=iV2(1);size_t
+iW1=0;bool
+nM1
+tO3
+nB1{if(!lE2
+t21
+continue
+iU2
+immed=t63
+if(immed==xD1
+goto
+ReplaceTreeWithZero;nL1*=immed;++iW1;}
+if(iW1>1||(iW1==1&&cB3
+nL1
+tG1
+1))))nM1=true;if(nM1){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"cMul: Will add new "
+iU3
+nL1<<"\n"
+;
+#endif
+for
+iY
+if
+y91
+t21{
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<" - For that, deleting "
+iU3
+t63
+std::cout<<"\n"
+;
+#endif
+i93!cB3
+nL1
+tG1
+1)))i83
+e21
+nL1));l73
+eM
+y33
+0:i6
+1:nY3
+c73
+if(ConstantFolding_MulGrouping(eJ2
+if(ConstantFolding_MulLogicItems(eJ2
+i91
+cAdd:eQ
+iV2
+nE2=0.0;size_t
+iW1=0;bool
+nM1
+tO3
+nB1{if(!lE2
+t21
+continue
+iU2
+immed=t63
+nE2+=immed;++iW1;}
+if(iW1>1||(iW1==1&&nE2==xD1)nM1=true;if(nM1){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"cAdd: Will add new "
+iU3
+nE2<<"\n"
+;std::cout<<"In: "
+yA1
+#endif
+for
+iY
+if
+y91
+t21{
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<" - For that, deleting "
+iU3
+t63
+std::cout<<"\n"
+;
+#endif
+i93!(nE2==x22)i83
+e21
+nE2));l73
+eM
+y33
+0
+eL
+1:nY3
+c73
+if(ConstantFolding_AddGrouping(eJ2
+if(ConstantFolding_AddLogicItems(eJ2
+i91
+cMin:eQ
+size_t
+yM2=0;c23
+e0;nB1{while(a+1<eM&&t33
+xF
+lE2
+a+1)))tree
+t31+1);c33
+max
+lB3(!e0
+yN
+known||(e13)<e0
+yN
+val)){e0
+yN
+val=e13;e0
+yN
+known=true;yM2=a;}
 }
-
-CodeTree::ConstList CodeTree::BuildConstList()
-{
-    ConstList result;
-    result.value     =
-    result.voidvalue = GetOp()==cMul ? 1.0 : 0.0;
-
-    bool first = true;
-    
-    list<pit> &cp = result.cp;
-    for(pit b, a=GetBegin(); a!=GetEnd(); a=b)
-    {
-        SubTree &pa = *a;  b=a; ++b;
-        if(!pa->IsImmed()) continue;
-
-        double thisvalue = pa->GetImmed();
-        if(thisvalue == result.voidvalue)
-        {
-            // This value is no good, forget it
-            Erase(a);
-            continue;
-        }
-        switch(GetOp())
-        {
-            case cMul:
-                result.value *= thisvalue;
-                break;
-            case cAdd:
-                result.value += thisvalue;
-                break;
-            case cMin:
-                if(first || thisvalue < result.value) result.value = thisvalue;
-                break;
-            case cMax:
-                if(first || thisvalue > result.value) result.value = thisvalue;
-                break;
-            default: break; /* Unreached */
-        }
-        cp.push_back(a);
-        first = false;
-    }
-    if(GetOp() == cMul)
-    {
-        /*
-          If one of the values is -1 and it's not the only value,
-          then some other value will be negated.
-        */
-        for(bool done=false; cp.size() > 1 && !done; )
-        {
-            done = true;
-            for(list<pit>::iterator b,a=cp.begin(); a!=cp.end(); a=b)
-            {
-                b=a; ++b;
-                if((**a)->GetImmed() == -1.0)
-                {
-                    Erase(*a);
-                    cp.erase(a);
-
-                    // take randomly something
-                    (**cp.begin())->data->NegateImmed();
-                    if(cp.size() < 2)break;
-                    done = false;
-                }
-            }
-        }
-    }
-    return result;
+if(e0
+xF2
+for
+iY{c33
+min
+lB3
+a!=yM2&&p
+tF2>=e0
+yN
+val)i93
+eM==1){nY3
+i91
+cMax:eQ
+size_t
+yM2=0;c23
+eZ;nB1{while(a+1<eM&&t33
+xF
+lE2
+a+1)))tree
+t31+1);c33
+min
+lB3(!eZ
+n51||p
+tF2>eZ
+tF2)){eZ
+tF2=p
+tF2;eZ
+n51=true;yM2=a;}
 }
-
-void CodeTree::Assemble
-   (vector<unsigned> &byteCode,
-    vector<double>   &immed,
-    size_t& stacktop_cur,
-    size_t& stacktop_max) const
-{
-    #define AddCmd(op) byteCode.push_back((op))
-    #define AddConst(v) do { \
-        byteCode.push_back(cImmed); \
-        immed.push_back((v)); \
-    } while(0)
-    #define SimuPush(n) stacktop_cur += (n)
-    #define SimuPop(n) do { \
-        if(stacktop_cur > stacktop_max) stacktop_max = stacktop_cur; \
-        stacktop_cur -= (n); \
-    } while(0)
-
-    if(IsVar())
-    {
-        SimuPush(1);
-        AddCmd(GetVar());
-        return;
-    }
-    if(IsImmed())
-    {
-        SimuPush(1);
-        AddConst(GetImmed());
-        return;
-    }
-
-    switch(GetOp())
-    {
-        case cAdd:
-        case cMul:
-        case cMin:
-        case cMax:
-        {
-            unsigned opcount = 0;
-            for(pcit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                const SubTree &pa = *a;
-
-                if(opcount < 2) ++opcount;
-
-                bool pnega = pa.getsign();
-
-                bool done = false;
-                if(pa->IsImmed())
-                {
-                    if(GetOp() == cMul
-                    && pa->data->IsInverted()
-                    && (pnega || opcount==2)
-                      )
-                    {
-                        CodeTree tmp = *pa;
-                        tmp.data->InvertImmed();
-                        tmp.Assemble(byteCode, immed,
-                                     stacktop_cur, stacktop_max);
-                        pnega = !pnega;
-                        done = true;
-                    }
-                    else if(GetOp() == cAdd
-                    && (pa->data->IsNegatedOriginal()
-                //     || pa->GetImmed() < 0
-                       )
-                    && (pnega || opcount==2)
-                           )
-                    {
-                        CodeTree tmp = *pa;
-                        tmp.data->NegateImmed();
-                        tmp.Assemble(byteCode, immed,
-                                     stacktop_cur, stacktop_max);
-                        pnega = !pnega;
-                        done = true;
-                    }
-                }
-                if(!done)
-                    pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max);
-
-                if(opcount == 2)
-                {
-                    unsigned tmpop = GetOp();
-                    if(pnega) // negation in non-first operand
-                    {
-                        tmpop = (tmpop == cMul) ? cDiv : cSub;
-                    }
-                    SimuPop(1);
-                    AddCmd(tmpop);
-                }
-                else if(pnega) // negation in the first operand
-                {
-                    if(GetOp() == cMul) AddCmd(cInv);
-                    else AddCmd(cNeg);
-                }
-            }
-            break;
-        }
-        case cIf:
-        {
-            // If the parameter amount is != 3, we're screwed.
-            getp0()->Assemble(byteCode, immed, stacktop_cur, stacktop_max); // expression
-            SimuPop(1);
-
-            unsigned ofs = byteCode.size();
-            AddCmd(cIf);
-            AddCmd(0); // code index
-            AddCmd(0); // immed index
-
-            getp1()->Assemble(byteCode, immed, stacktop_cur, stacktop_max); // true branch
-            SimuPop(1);
-
-            byteCode[ofs+1] = byteCode.size()+2;
-            byteCode[ofs+2] = immed.size();
-
-            ofs = byteCode.size();
-            AddCmd(cJump);
-            AddCmd(0); // code index
-            AddCmd(0); // immed index
-
-            getp2()->Assemble(byteCode, immed, stacktop_cur, stacktop_max); // false branch
-            SimuPop(1);
-
-            byteCode[ofs+1] = byteCode.size()-1;
-            byteCode[ofs+2] = immed.size();
-            
-            SimuPush(1);
-
-            break;
-        }
-        case cFCall:
-        {
-            // If the parameter count is invalid, we're screwed.
-            size_t was_stacktop = stacktop_cur;
-            for(pcit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                const SubTree &pa = *a;
-                pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max);
-            }
-            AddCmd(GetOp());
-            AddCmd(data->GetFuncNo());
-            SimuPop(stacktop_cur - was_stacktop - 1);
-            break;
-        }
-        case cPCall:
-        {
-            // If the parameter count is invalid, we're screwed.
-            size_t was_stacktop = stacktop_cur;
-            for(pcit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                const SubTree &pa = *a;
-                pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max);
-            }
-            AddCmd(GetOp());
-            AddCmd(data->GetFuncNo());
-            SimuPop(stacktop_cur - was_stacktop - 1);
-            break;
-        }
-        default:
-        {
-            // If the parameter count is invalid, we're screwed.
-            size_t was_stacktop = stacktop_cur;
-            for(pcit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                const SubTree &pa = *a;
-                pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max);
-            }
-            AddCmd(GetOp());
-            SimuPop(stacktop_cur - was_stacktop - 1);
-            break;
-        }
-    }
+if(eZ
+n51){for
+iY{c33
+max
+lB3
+a!=yM2&&(e13)<eZ
+tF2){eK2}
 }
-
-void CodeTree::Optimize()
-{
-    // Phase:
-    //   Phase 0: Do local optimizations.
-    //   Phase 1: Optimize each.
-    //   Phase 2: Do local optimizations again.
-
-    for(unsigned phase=0; phase<=2; ++phase)
-    {
-        if(phase == 1)
-        {
-            // Optimize each parameter.
-            for(pit a=GetBegin(); a!=GetEnd(); ++a)
-            {
-                (*a)->Optimize();
-                CHECKCONSTNEG(*a, GetOp());
-            }
-            continue;
-        }
-        if(phase == 0 || phase == 2)
-        {
-            // Do local optimizations.
-
-            OptimizeConstantMath1();
-            OptimizeLogarithm();
-            OptimizeFunctionCalls();
-            OptimizeExponents();
-            OptimizeLinearExplode();
-            OptimizePascal();
-
-            /* Optimization paths:
-
-               doublenegations=
-               redundant= * doublenegations
-               conflict= * redundant
-               addmulflat=
-               constantmath1= addmulflat * conflict
-               linearcombine= conflict * addmulflat¹ redundant¹
-               powmuladd=
-               exponents= linearcombine * powmuladd conflict¹
-               logarithm= exponents *
-               functioncalls= IDLE
-               linearexplode= IDLE
-               pascal= IDLE
-
-               * = actions here
-               Â¹ = only if made changes
-            */
-        }
-    }
+if(eM==1){nY3
+i91
+cEqual:case
+cNEqual:case
+cLess:case
+cGreater:case
+cLessOrEq:case
+cGreaterOrEq:if(ConstantFolding_Comparison(eJ2
+lC
+cAbs:{c23
+p0
+tI
+0));if
+tG2
+nY3
+if(p0
+eN{tree
+tH3
+tree.yC
+iV2(1)));goto
+NowWeAreMulGroup;}
+lT3
+nC==cMul){lC2
+p=lE2
+0);eH
+x03;eH
+cK2
+yM3
+0;a<p.xF1++a){p0=iN
+p
+x13
+if
+tG2{x03.push_back(p
+x13}
+if(p0
+eN{cK2.push_back(p
+x13}
 }
-
-
-bool CodeTree::operator== (const CodeTree& b) const
-{
-    if(GetOp() != b.GetOp()) return false;
-    if(IsImmed()) if(GetImmed()  != b.GetImmed())  return false;
-    if(IsVar())   if(GetVar()    != b.GetVar())    return false;
-    if(data->IsFunc())
-        if(data->GetFuncNo() != b.data->GetFuncNo()) return false;
-    return data->args == b.data->args;
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"Abs: mul group has "
+<<x03.tF3<<" pos, "
+<<cK2.tF3<<"neg\n"
+;
+#endif
+if(!x03
+cT3||!cK2
+cT3){
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"AbsReplace-Before: "
+i13(tree
+lT2"\n"
+<<std::flush;DumpHashes(tree
+i42);
+#endif
+eJ
+eW3;eW3
+xD
+cMul)yM3
+0;a<p.xF1++a){p0=iN
+p
+x13
+if(tG2||(p0
+eN){}
+else
+eW3
+c9
+p
+x13}
+eW3
+eT1
+eJ
+x23;x23
+xD
+cAbs);x23
+yP1
+eW3);x23
+eT1
+eJ
+y41
+cMul);mulgroup
+yP1
+x23);yQ1
+AddParamsMove(x03
+eY3!cK2
+cT3){if(cK2.tF3%2)yQ1
+yC
+iV2(-1)));yQ1
+AddParamsMove(cK2);}
+tree.Become
+lR3);
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"AbsReplace-After: "
+i13(tree
+i42
+lT2"\n"
+<<std::flush;DumpHashes(tree
+i42);
+#endif
+goto
+NowWeAreMulGroup;}
 }
-
-bool CodeTree::operator< (const CodeTree& b) const
-{
-    if(GetArgCount() != b.GetArgCount())
-        return GetArgCount() > b.GetArgCount();
-
-    if(GetOp() != b.GetOp())
-    {
-        // sort immeds last
-        if(IsImmed() != b.IsImmed()) return IsImmed() < b.IsImmed();
-
-        return GetOp() < b.GetOp();
-    }
-
-    if(IsImmed())
-    {
-        if(GetImmed() != b.GetImmed()) return GetImmed() < b.GetImmed();
-    }
-    if(IsVar() && GetVar() != b.GetVar())
-    {
-        return GetVar() < b.GetVar();
-    }
-    if(data->IsFunc() && data->GetFuncNo() != b.data->GetFuncNo())
-    {
-        return data->GetFuncNo() < b.data->GetFuncNo();
-    }
-
-    pcit i = GetBegin(), j = b.GetBegin();
-    for(; i != GetEnd(); ++i, ++j)
-    {
-        const SubTree &pa = *i, &pb = *j;
-
-        if(!(pa == pb))
-            return pa < pb;
-    }
-    return false;
+yF3
+#define HANDLE_UNARY_CONST_FUNC(funcname) nR){xO funcname(lR));nD
+case
+cLog:iK3(fp_log);lT3
+nC==cPow){eJ
+pow=lE2
+0
+eY3
+GetPositivityInfo(pow
+l8
+0))==IsAlways){pow.CopyOnWrite()i7
+tree.lU
+if(GetEvennessInfo(pow
+l8
+1))==IsAlways){pow.l61
+eJ
+abs;abs
+xD
+cAbs);abs
+yP1
+pow
+lR2
+abs.Rehash()i7
+pow.nG1
+0,abs);tree.lU}
+else
+lT3
+nC==cAbs){eJ
+pow=lE2
+0)l8
+0
+eY3
+pow
+nC==cPow){pow.l61
+eJ
+abs;abs
+xD
+cAbs);abs
+yP1
+pow
+lR2
+abs.Rehash()i7
+pow.nG1
+0,abs);tree.lU}
+lC
+cAcosh:iK3(fp_acosh);lC
+cAsinh:iK3(fp_asinh);lC
+cAtanh:iK3(fp_atanh);lC
+cAcos:iK3(fp_acos);lC
+cAsin:iK3(fp_asin);lC
+cAtan:iK3(fp_atan);lC
+cCosh:iK3(fp_cosh);lC
+cSinh:iK3(fp_sinh);lC
+cTanh:iK3(fp_tanh);lC
+cSin:iK3(fp_sin);lC
+cCos:iK3(fp_cos);lC
+cTan:iK3(fp_tan);lC
+cCeil:l54(fp_ceil);lC
+cTrunc:l54(fp_trunc);lC
+cFloor:l54(fp_floor);lC
+cInt:l54(fp_int);lC
+cCbrt:iK3(fp_cbrt);lC
+cSqrt:iK3(fp_sqrt);lC
+cExp:iK3(fp_exp);lC
+cLog2:iK3(fp_log2);lC
+cLog10:iK3(fp_log10);lC
+eF3:if
+lI
+fp_log2(lR)*tH
+tH2
+cArg:iK3(fp_arg);lC
+cConj:iK3(fp_conj);lC
+cImag:iK3(fp_imag);lC
+cReal:iK3(fp_real);lC
+cPolar:if
+lI
+fp_polar(x32
+cMod:if
+lI
+e93
+x32
+cAtan2:{c23
+p0
+tI
+yS2
+p1
+tI
+1));nR&&cB3
+lR,xD1){if(p1
+cL2
+p1
+e23
+xD1{xO
+fp_const_pi
+e53
+if(p1
+n51&&p1
+tF2>=t61
+xD1;nD}
+tM2
+cB3
+tH,xD1){if(p0
+cL2
+p0
+e23
+xD1{xO-fp_const_pihalf
+e53
+if
+iC3
+p0
+tF2>xD1{xO
+fp_const_pihalf
+e53}
+if
+lI
+fp_atan2(lR,tH));nD
+if((p1
+n51&&p1
+tF2>xD1||(p1
+cL2
+p1
+e23
+fp_const_negativezero
+xK())){eJ
+yO2;yO2
+xD
+cPow);yO2.AddParamMove
+y91
+1));yO2.yC
+iV2(-1)));yO2
+eT1
+eJ
+yP2;yP2
+tH3
+yP2.AddParamMove
+y91
+0));yP2
+yP1
+yO2);yP2
+eT1
+tI3
+cAtan);tree.nG1
+0,yP2)yO3
+1);i91
+cPow:{if(ConstantFolding_PowOperations(eJ2
+yF3
+case
+cDiv:nR&&eO3
+i61&&tH!=t61
+lR/tH
+tH2
+cInv:nR&&lR!=t61
+iV2(1)/lR
+tH2
+cSub:if
+lI
+lR-tH
+tH2
+cNeg:nR){xO-lR
+tH2
+cRad:nR){xO
+RadiansToDegrees(lR)tH2
+cDeg:nR){xO
+DegreesToRadians(lR)tH2
+cSqr:nR){xO
+lR*lR
+tH2
+cExp2:iK3(fp_exp2);lC
+cRSqrt:nR){xO
+iV2(1)/fp_sqrt(lR)tH2
+cCot:tI2
+fp_tan(lZ
+cSec:tI2
+fp_cos(lZ
+cCsc:tI2
+fp_sin(lZ
+cHypot:if
+lI
+fp_hypot(x32
+cRDiv:case
+cRSub:case
+cDup:case
+cFetch:case
+cPopNMov:case
+cSinCos:case
+cSinhCosh:case
+cNop:case
+cJump:lC
+cPCall:case
+cFCall:yF3
+do_return:;
+#ifdef DEBUG_SUBSTITUTIONS
+std::cout<<"["
+<<(&cY3)<<"]Done ConstantFolding, result: "
+yA1
+DumpHashes(tree);
+#endif
 }
-
-
-bool IsNegate(const SubTree &p1, const SubTree &p2) /*const */
-{
-    if(p1->IsImmed() && p2->IsImmed())
-    {
-        return p1->GetImmed() == -p2->GetImmed();
-    }
-    if(p1.getsign() == p2.getsign()) return false;
-    return *p1 == *p2;
-}
-bool IsInverse(const SubTree &p1, const SubTree &p2) /*const*/
-{
-    if(p1->IsImmed() && p2->IsImmed())
-    {
-        // FIXME: potential divide by zero.
-        return p1->GetImmed() == 1.0 / p2->GetImmed();
-    }
-    if(p1.getsign() == p2.getsign()) return false;
-    return *p1 == *p2;
 }
-
-SubTree::SubTree() : tree(new CodeTree), sign(false)
-{
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+t5{tZ1
+c23::set_abs(nL
+bool
+has_negative=!min.known||min.val<iV2();bool
+has_positive=!t13||iA3>iV2();bool
+crosses_axis=has_negative&&has_positive;cJ1
+xK
+newmax;if(min
+lB3
+t13)newmax.set(fp_max(tV1,tW1
+eY3
+crosses_axis)min.set(iV2());e63
+min
+lB3
+t13)min.set(fp_min(tV1,tW1);lJ2
+min.known)min.set(tV1);else
+min.set(tW1;}
+max=newmax;}
+tZ1
+c23::set_neg(){std::swap(min,max);min.val=-min.val;iA3=-iA3;}
+xN1
+IsLogicalTrueValue
+cH1
+c23&p
+tR2{if(nB
+IsIntType
+xK::nT3){if(p
+n51&&p
+tF2>=iV2(1
+tI1;if(!abs&&p
+nP2
+yN
+val<=iV2(-1
+tI1;}
+e63
+p
+n51&&p
+tF2>=iV2(0.5
+tI1;if(!abs&&p
+nP2
+yN
+val<=iV2(-0.5
+tI1;}
+return
+tR3
+xN1
+IsLogicalFalseValue
+cH1
+c23&p
+tR2{if(nB
+IsIntType
+xK::nT3){if(abs)return
+p
+yN
+known
+lH1
+1);else
+return
+p
+n51&&p
+nP2
+tF2>iV2(-1)lH1
+1);}
+e63
+abs)return
+p
+yN
+known
+lH1
+0.5);else
+return
+p
+n51&&p
+nP2
+tF2>iV2(-0.5)lH1
+0.5);}
 }
-
-SubTree::SubTree(const SubTree &b) : tree(new CodeTree(*b.tree)), sign(b.sign)
-{
 }
-
-#define SubTreeDecl(p1, p2) \
-    SubTree::SubTree p1 : tree(new CodeTree p2), sign(false) { }
-
-SubTreeDecl( (const CodeTree &b), (b) )
-SubTreeDecl( (double value),             (value) )
-
-#undef SubTreeDecl
-
-SubTree::~SubTree()
-{
-    delete tree; tree=0;
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;using
+t5;t5{xW3
+c23
+iN
+lC2
+tree)
+#ifdef DEBUG_SUBSTITUTIONS_extra_verbose
+{using
+lF3
+FUNCTIONPARSERTYPES;c23
+tmp=CalculateResultBoundaries_do(tree
+lT2"Estimated boundaries: "
+;if(tmp
+n51)std::cout<<tmp
+tF2;else
+std::cout<<"-inf"
+;std::cout<<" .. "
+;if(tmp
+xF2
+std::cout<<tmp
+yN
+val;else
+std::cout<<"+inf"
+;std::cout<<": "
+i13(tree
+lT2
+std::endl
+n31
+tmp;}
+xW3
+c23
+eJ::CalculateResultBoundaries_do
+cH1
+e62
+#endif
+{iG
+yF1(-fp_const_pihalf
+xK(),fp_const_pihalf
+xK());iG
+pi_limits(-fp_const_pi
+xK(),fp_const_pi
+xK());iG
+abs_pi_limits(y21,fp_const_pi
+xK());iG
+plusminus1_limits(iV2(-nR3
+using
+lF3
+std;switch(i01
+y33
+cImmed:nM
+eC3,eC3);case
+cAnd:case
+cAbsAnd:case
+cOr:case
+cAbsOr:case
+cNot:case
+cZ3:case
+cNotNot:case
+cAbsNotNot:case
+cEqual:case
+cNEqual:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:{nM
+y21
+tG1
+1)i33
+cAbs:lD
+m.set_abs();tV
+cLog:lD
+x33
+fp_log);m
+x63
+fp_log);tV
+cLog2:lD
+x33
+fp_log2);m
+x63
+fp_log2);tV
+cLog10:lD
+x33
+fp_log10);m
+x63
+fp_log10);tV
+cAcosh:lD
+yK
+template
+set_if<cGreaterOrEq
+t71
+fp_acosh)xQ1
+cGreaterOrEq
+t71
+fp_acosh);tV
+cAsinh:lD
+yK
+set(fp_asinh);m
+yN
+set(fp_asinh);tV
+cAtanh:lD
+yK
+n3-1),fp_atanh)xQ1
+cLess
+t71
+fp_atanh);tV
+cAcos:lD
+nM(c71&&(c81)<iV2(1))?fp_acos(c81):y21,(x43&&nU3>=iV2(-1))?fp_acos
+nU3:fp_const_pi
+xK()i33
+cAsin:lD
+yK
+n3-1),fp_asin,yF1
+tF2)xQ1
+cLess
+t71
+fp_asin,yF1
+yN
+val);tV
+cAtan:lD
+yK
+set(fp_atan,yF1
+tF2);m
+yN
+set(fp_atan,yF1
+yN
+val);tV
+cAtan2:{nR&&cB3
+lR,xD1)yR
+abs_pi_limits;}
+tM2
+cB3
+tH,xD1)yR
+yF1;}
+return
+pi_limits;}
+case
+cSin:lD
+bool
+x11=!x43||!c71||(c81-yK
+val)>=(yO
+x11)eR
+iV2
+min=e93
+yK
+val,yO
+min<xD1
+min
+yP
+iV2
+max=e93
+c81,yO
+max<xD1
+max
+yP
+if(max<min)max
+yP
+bool
+y11=(min<=fp_const_pihalf
+xK()&&max>=fp_const_pihalf
+xK());bool
+nN1=(min<=cD&&max>=cD
+eY3
+y11&&nN1)eR
+if(nN1)nM
+iV2(-1)lK2
+if(y11)nM
+eL2
+tG1
+1));nM
+eL2
+lK2}
+case
+cCos:lD
+if(x43)yK
+val+=fp_const_pihalf
+xK(eY3
+c71)c81+=fp_const_pihalf
+xK();bool
+x11=!x43||!c71||(c81-yK
+val)>=(yO
+x11)eR
+iV2
+min=e93
+yK
+val,yO
+min<xD1
+min
+yP
+iV2
+max=e93
+c81,yO
+max<xD1
+max
+yP
+if(max<min)max
+yP
+bool
+y11=(min<=fp_const_pihalf
+xK()&&max>=fp_const_pihalf
+xK());bool
+nN1=(min<=cD&&max>=cD
+eY3
+y11&&nN1)eR
+if(nN1)nM
+iV2(-1)lK2
+if(y11)nM
+eL2
+tG1
+1));nM
+eL2
+lK2}
+case
+cTan:{nM
+i33
+cCeil:lD
+c91
+cFloor:lD
+tH1
+tV
+cTrunc:lD
+tH1
+c91
+cInt:lD
+tH1
+c91
+cSinh:lD
+yK
+set(fp_sinh);m
+yN
+set(fp_sinh);tV
+cTanh:lD
+yK
+set(fp_tanh,plusminus1_limits.min);m
+yN
+set(fp_tanh,plusminus1_limits.max);tV
+cCosh:lD
+if(x43){if(c71){if(yK
+val>=y21&&c81>=xD1{yK
+val
+xU}
+lJ2
+nU3<y21&&c81>=xD1{iV2
+tmp
+xU
+if(tmp>c81)c81=tmp;yK
+val=iV2(1
+t43{yK
+val
+xU
+std::swap(yK
+val,c81);}
 }
-
-const SubTree &SubTree::operator= (const SubTree &b)
-{
-    sign = b.sign;
-    CodeTree *oldtree = tree;
-    tree = new CodeTree(*b.tree);
-    delete oldtree;
-    return *this;
-}
-const SubTree &SubTree::operator= (const CodeTree &b)
-{
-    sign = false;
-    CodeTree *oldtree = tree;
-    tree = new CodeTree(b);
-    delete oldtree;
-    return *this;
+e63
+yK
+val>=xD1{m
+t0
+yK
+val=fp_cosh
+nU3;}
+else{m
+t0
+yK
+val=iV2(1);}
 }
-
-bool SubTree::operator< (const SubTree& b) const
-{
-    if(getsign() != b.getsign()) return getsign() < b.getsign();
-    return *tree < *b.tree;
-}
-bool SubTree::operator== (const SubTree& b) const
-{
-    return sign == b.sign && *tree == *b.tree;
-}
-void SubTree::Negate() // Note: Parent must be cAdd
-{
-    flipsign();
-    CheckConstNeg();
-}
-void SubTree::CheckConstNeg()
-{
-    if(tree->IsImmed() && getsign())
-    {
-        tree->NegateImmed();
-        sign = false;
-    }
-}
-void SubTree::Invert() // Note: Parent must be cMul
-{
-    flipsign();
-    CheckConstInv();
-}
-void SubTree::CheckConstInv()
-{
-    if(tree->IsImmed() && getsign())
-    {
-        tree->InvertImmed();
-        sign = false;
-    }
 }
-
-}//namespace
-
-void FunctionParser::MakeTree(void *r) const
-{
-    // Dirty hack. Should be fixed.
-    CodeTree* result = static_cast<CodeTree*>(r);
-
-    vector<CodeTree> stack(1);
-
-    #define GROW(n) do { \
-        stacktop += n; \
-        if(stack.size() <= stacktop) stack.resize(stacktop+1); \
-    } while(0)
-
-    #define EAT(n, opcode) do { \
-        unsigned newstacktop = stacktop-(n); \
-        if((n) == 0) GROW(1); \
-        stack[stacktop].SetOp((opcode)); \
-        for(unsigned a=0, b=(n); a<b; ++a) \
-            stack[stacktop].AddParam(stack[newstacktop+a]); \
-        stack.erase(stack.begin() + newstacktop, \
-                    stack.begin() + stacktop); \
-        stacktop = newstacktop; GROW(1); \
-    } while(0)
-
-    #define ADDCONST(n) do { \
-        stack[stacktop].SetImmed((n)); \
-        GROW(1); \
-    } while(0)
-
-    unsigned stacktop=0;
-
-    list<unsigned> labels;
-
-    const unsigned* const ByteCode = data->ByteCode;
-    const unsigned ByteCodeSize = data->ByteCodeSize;
-    const double* const Immed = data->Immed;
-
-    for(unsigned IP=0, DP=0; ; ++IP)
-    {
-        while(labels.size() > 0
-        && *labels.begin() == IP)
-        {
-            // The "else" of an "if" ends here
-            EAT(3, cIf);
-            labels.erase(labels.begin());
-        }
-
-        if(IP >= ByteCodeSize)
-        {
-            break;
-        }
-
-        unsigned opcode = ByteCode[IP];
-
-        if(opcode == cIf)
-        {
-            IP += 2;
-        }
-        else if(opcode == cJump)
-        {
-            labels.push_front(ByteCode[IP+1]+1);
-            IP += 2;
-        }
-        else if(opcode == cImmed)
-        {
-            ADDCONST(Immed[DP++]);
-        }
-        else if(opcode < VarBegin)
-        {
-            switch(opcode)
-            {
-                // Unary operators
-                case cNeg:
-                {
-                    EAT(1, cAdd); // Unary minus is negative adding.
-                    stack[stacktop-1].getp0().Negate();
-                    break;
-                }
-                // Binary operators
-                case cSub:
-                {
-                    EAT(2, cAdd); // Minus is negative adding
-                    stack[stacktop-1].getp1().Negate();
-                    break;
-                }
-                case cDiv:
-                {
-                    EAT(2, cMul); // Divide is inverse multiply
-                    stack[stacktop-1].getp1().Invert();
-                    break;
-                }
-
-                // ADD ALL TWO PARAMETER NON-FUNCTIONS HERE
-                case cAdd: case cMul:
-                case cMod: case cPow:
-                case cEqual: case cLess: case cGreater:
-                case cNEqual: case cLessOrEq: case cGreaterOrEq:
-                case cAnd: case cOr:
-                    EAT(2, opcode);
-                    break;
-
-                // ADD ALL UNARY NON-FUNCTIONS HERE
-                case cNot:
-                    EAT(1, opcode);
-                    break;
-
-                case cFCall:
-                {
-                    unsigned index = ByteCode[++IP];
-                    unsigned params = data->FuncPtrs[index].params;
-                    EAT(params, opcode);
-                    stack[stacktop-1].data->SetFuncNo(index);
-                    break;
-                }
-                case cPCall:
-                {
-                    unsigned index = ByteCode[++IP];
-                    unsigned params =
-                        data->FuncParsers[index]->data->varAmount;
-                    EAT(params, opcode);
-                    stack[stacktop-1].data->SetFuncNo(index);
-                    break;
-                }
-
-                // Converted to cMul on fly
-                case cDeg:
-                    ADDCONST(CONSTANT_DR);
-                    EAT(2, cMul);
-                    break;
-
-                // Converted to cMul on fly
-                case cRad:
-                    ADDCONST(CONSTANT_RD);
-                    EAT(2, cMul);
-                    break;
-
-                // Functions
-                default:
-                {
-                    //assert(opcode >= cAbs);
-                    unsigned funcno = opcode-cAbs;
-                    assert(funcno < sizeof(Functions)/sizeof(Functions[0]));
-                    const FuncDefinition& func = Functions[funcno];
-
-                    //const FuncDefinition& func = Functions[opcode-cAbs];
-
-                    unsigned paramcount = func.params;
-#ifndef DISABLE_EVAL
-                    if(opcode == cEval) paramcount = data->varAmount;
-#endif
-                    if(opcode == cSqrt)
-                    {
-                        // Converted on fly: sqrt(x) = x^0.5
-                        opcode = cPow;
-                        paramcount = 2;
-                        ADDCONST(0.5);
-                    }
-                    if(opcode == cExp)
-                    {
-                        // Converted on fly: exp(x) = CONSTANT_E^x
-
-                        opcode = cPow;
-                        paramcount = 2;
-                        // reverse the parameters... kludgey
-                        stack[stacktop] = stack[stacktop-1];
-                        stack[stacktop-1].SetImmed(CONSTANT_E);
-                        GROW(1);
-                    }
-                    bool do_inv = false;
-                    if(opcode == cCot) { do_inv = true; opcode = cTan; }
-                    if(opcode == cCsc) { do_inv = true; opcode = cSin; }
-                    if(opcode == cSec) { do_inv = true; opcode = cCos; }
-
-                    bool do_log10 = false;
-                    if(opcode == cLog10)
-                    {
-                        // Converted on fly: log10(x) = log(x) * CONSTANT_L10I
-                        opcode = cLog;
-                        do_log10 = true;
-                    }
-                    EAT(paramcount, opcode);
-                    if(do_log10)
-                    {
-                        ADDCONST(CONSTANT_L10I);
-                        EAT(2, cMul);
-                    }
-                    if(do_inv)
-                    {
-                        // Unary cMul, inverted. No need for "1.0"
-                        EAT(1, cMul);
-                        stack[stacktop-1].getp0().Invert();
-                    }
-                    break;
-                }
-            }
-        }
-        else
-        {
-            stack[stacktop].SetVar(opcode);
-            GROW(1);
-        }
-    }
-
-    if(!stacktop)
-    {
-        // ERROR: Stack does not have any values!
-        return;
-    }
-
-    --stacktop; // Ignore the last element, it is always nop (cAdd).
-
-    if(stacktop > 0)
-    {
-        // ERROR: Stack has too many values!
-        return;
-    }
-
-    // Okay, the tree is now stack[0]
-    *result = stack[0];
+else{x43=true;yK
+val=iV2(1
+eY3
+c71){yK
+val=fp_cosh(c81);m
+t0}
+else
+m
+t0}
+tV
+cIf:case
+cAbsIf:{c23
+res1
+tI
+1));c23
+res2
+tI
+2)eY3!res2
+n51)res1
+n51
+tO3
+lJ2
+res1
+n51&&(res2
+tF2)<res1
+tF2)res1
+tF2=res2
+tF2;if(!res2
+xF2
+res1
+t0
+lJ2
+res1
+cL2
+res2
+yN
+val)>res1
+yN
+val)res1
+yN
+val=res2
+yN
+val
+n31
+res1;}
+case
+cMin:{bool
+iH
+tO3
+bool
+iI
+tO3
+c43;x2
+m
+tI
+a)eY3!x43)iH
+x53
+n51||nU3<nK3)nK3=yK
+val;if(!c71)iI
+x53
+yN
+known||(c81)<nL3)nL3=c81;}
+if(iH)nM3
+iI)nT3
+t0
+return
+nT3;}
+case
+cMax:{bool
+iH
+tO3
+bool
+iI
+tO3
+c43;x2
+m
+tI
+a)eY3!x43)iH
+x53
+n51||yK
+val>nK3)nK3=yK
+val;if(!c71)iI
+x53
+yN
+known||c81>nL3)nL3=c81;}
+if(iH)nM3
+iI)nT3
+t0
+return
+nT3;}
+case
+cAdd:{c43(y21,xD1;x2
+item
+tI
+a)eY3
+item
+n51)nK3+=item
+tF2;else
+nM3
+item
+xF2
+nL3+=item
+yN
+val;else
+nT3
+t0
+if(!nP3&&!nT3
+xF2
+yF3
+if
+iT2
+n51&&nQ3&&nK3>nL3)std::swap
+iT2
+tF2,nL3)n31
+nT3;}
+case
+cMul:{e12
+Value{enum
+x73{eA3,iX1,iW2}
+;x73
+tK
+iU2
+value;Value(x73
+t):tK(t),value(0){}
+Value(iV2
+v):tK(eA3),value(v){}
+bool
+cM2
+yZ1
+tK==iX1||cU2
+value<xD1
+lL3
+eA1*=cH1
+Value&rhs){if
+cU2
+rhs.tK==eA3)value*=rhs.value;else
+tK=(cM2)!=rhs.cM2)?iX1:iW2);}
+iG2<cH1
+Value&rhs
+yZ1(tK==iX1&&rhs.tK!=iX1)||cU2(rhs.tK==iW2||(rhs.tK==eA3&&value<rhs.value)));}
 }
-
-void FunctionParser::Optimize()
-{
-    if(data->isOptimized) return;
-    CopyOnWrite();
-
-    CodeTree tree;
-    MakeTree(&tree);
-
-#ifdef TREE_DEBUG
-    cout << "BEFORE OPT      :" << tree << endl;
+;e12
+yG1{Value
+yQ2,yR2;yG1():yQ2(Value::iW2),yR2(Value::iX1){}
+void
+xE2
+Value
+eB3,const
+Value&value2){eB3*=value2;if(eB3<yQ2)yQ2=eB3;if(yR2<eB3)yR2=eB3;}
+}
+;c43(iV2(nR3
+x2
+item
+tI
+a)eY3!item
+n51&&!item
+xF2
+nM);Value
+x83=nP3?Value
+iT2.min.lU1
+iX1);Value
+x93=nQ3?Value
+iT2
+yN
+lU1
+iW2);Value
+xA3=item
+n51?Value(item.min.lU1
+iX1);Value
+xB3=item
+yN
+known?Value(item
+yN
+lU1
+iW2);yG1
+range
+tL2
+x83,xA3)tL2
+x83,xB3)tL2
+x93,xA3)tL2
+x93,xB3
+eY3
+range.yQ2.tK==Value::eA3)nK3=range.yQ2.value;else
+nM3
+range.yR2.tK==Value::eA3)nL3=range.yR2.value;else
+nT3
+t0
+if(!nP3&&!nT3
+xF2
+yF3
+if
+iT2
+n51&&nQ3&&nK3>nL3)std::swap
+iT2
+tF2,nL3)n31
+nT3;}
+case
+cMod:{c23
+x
+tI
+yS2
+y
+tI
+1)eY3
+y
+xF2{if(y
+yN
+val>=xD1{if(!x
+n51||(x
+tF2)<xD1
+nM-y
+yN
+val,y
+yN
+val);iB3
+y21,y
+yN
+val);}
+e63!x
+yN
+known||(x
+yN
+val)>=xD1
+nM
+y
+yN
+val,-y
+yN
+val);iB3
+y
+yN
+val,fp_const_negativezero
+xK());}
+}
+iB3
+i33
+cPow:{tM2
+tH==xD1{nM
+iV2(nR3}
+nR&&lR==xD1{nM
+y21,xD1;}
+nR&&cB3
+lR
+xE3
+nM
+iV2(nR3}
+tM2
+tH>y21&&GetEvennessInfo
+y91
+1))==IsAlways
+tJ2
+e92
+tH;c23
+tmp
+tI
+yS2
+nT3;nP3=true;nK3=0;if(tmp
+n51&&tmp
+tF2>=xD1
+nK3
+t03
+tmp
+tF2,xG2;lJ2
+tmp
+yN
+known&&tmp
+yN
+val<=xD1
+nK3
+t03
+tmp
+yN
+val,xG2;nT3
+t0
+if(tmp
+n51&&tmp
+xF2{nQ3=true;nL3=fp_max(fp_abs(tmp
+tF2),fp_abs(tmp
+yN
+val));nL3=fp_pow
+iT2
+yN
+val,xG2;}
+return
+nT3;}
+c23
+p0
+tI
+yS2
+p1
+tI
+1));TriTruthValue
+p0_positivity=iC3(p0
+tF2)>=xD1?IsAlways:(p0
+cL2
+p0
+e23
+y21?lC3
+Unknown);TriTruthValue
+cN2=GetEvennessInfo
+y91
+1));TriTruthValue
+t1=Unknown;switch(p0_positivity)l92
+t1=IsAlways;lC
+lC3{t1=cN2;yF3
+c73
+switch(cN2)l92
+t1=IsAlways;lC
+lC3
+lC
+Unknown:{tM2!isInteger
+tG&&tH>=xD1{t1=IsAlways;}
+yF3}
+l73
+t1)l92{iV2
+min=y21;if
+iC3
+p1
+n51){min
+t03
+p0
+tF2,p1
+tF2
+eY3
+p0
+tF2<y21&&(!p1
+yN
+known||p1
+yN
+val>=xD1&&min>=xD1
+min=y21;}
+if
+iC3
+p0
+tF2>=y21&&p0
+yN
+known&&p1
+xF2{iV2
+max
+t03
+p0
+yN
+val,p1
+yN
+val
+eY3
+min>max)std::swap(min,max);nM
+min,max);}
+nM
+min,false
+i33
+lC3{nM
+false,fp_const_negativezero
+xK());}
+c73{yF3
+i91
+cNeg:lD
+m.set_neg();tV
+cSub:{yM
+cNeg);iE3
+1));tmp
+xD
+cAdd);tmp.nJ
+0));tmp
+yP1
+tmp2
+y53
+cInv:{cO2-1
+yT2
+cDiv:{yM
+cInv);iE3
+1));tmp
+xD
+x71
+AddParamMove(tmp2
+y53
+cRad:{t81
+x71
+yC
+fp_const_rad_to_deg
+xK(yT2
+cDeg:{t81
+x71
+yC
+fp_const_deg_to_rad
+xK(yT2
+cSqr:{cO2
+2
+yT2
+cExp:{t81
+cPow);tmp.yC
+fp_const_e
+xK()));tmp.nJ
+0)y53
+cExp2:{t81
+cPow);tmp.yC
+x42
+tmp.nJ
+0)y53
+cCbrt:lD
+yK
+set(fp_cbrt);m
+yN
+set(fp_cbrt);tV
+cSqrt:lD
+if(x43)yK
+val=nU3<y21?0:fp_sqrt
+nU3;if(c71)c81=(c81)<y21?0:fp_sqrt(c81);tV
+cRSqrt:{cO2-0.5
+yT2
+cHypot:{eJ
+xsqr,ysqr,add,sqrt;xsqr.nJ
+0));xsqr.yC
+x42
+ysqr.nJ
+1));ysqr.yC
+x42
+xsqr
+xD
+cPow);ysqr
+xD
+cPow);add
+yP1
+xsqr);add
+yP1
+ysqr);add
+xD
+cAdd);sqrt
+yP1
+add);sqrt
+xD
+cSqrt)n31
+iN
+sqrt
+i33
+eF3:{yM
+cLog2);iE3
+0));tmp
+tH3
+tmp
+yP1
+tmp2);tmp.nJ
+1)y53
+cCot:{yM
+cTan)x3
+lH
+cSec:{yM
+cCos)x3
+lH
+cCsc:{yM
+cSin)x3
+iN
+tmp);}
+lC
+cRDiv:case
+cRSub:case
+cDup:case
+cFetch:case
+cPopNMov:case
+cSinCos:case
+cSinhCosh:case
+cNop:case
+cJump:case
+l03:lC
+cArg:case
+cConj:case
+cImag:case
+cReal:case
+cPolar:lC
+cPCall:lC
+cFCall:yF3
+nM);}
+xW3
+TriTruthValue
+GetIntegerInfo
+cH1
+e62{switch(i01
+y33
+cImmed:return
+t42
+eC3)?IsAlways:IsNever;case
+cFloor:case
+cCeil:case
+cTrunc:case
+cInt:return
+IsAlways;case
+cAnd:case
+cOr:case
+cNot:case
+cNotNot:case
+cEqual:case
+cNEqual:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:return
+IsAlways;case
+cIf:{TriTruthValue
+a=GetIntegerInfo
+y91
+1));TriTruthValue
+b=GetIntegerInfo
+y91
+2)eY3
+a==b)return
+a
+nV2
+case
+cAdd:case
+cMul:{for
+iY
+if(GetIntegerInfo
+y91
+a))!=IsAlways)return
+Unknown
+n31
+IsAlways;}
+c73
+yF3
+return
+Unknown;}
+xN1
+IsLogicalValue
+cH1
+e62{switch(i01
+y33
+cImmed:return
+cB3
+eC3,xD1||cB3
+eC3
+tG1
+1));case
+cAnd:case
+cOr:case
+cNot:case
+cNotNot:case
+cAbsAnd:case
+cAbsOr:case
+cZ3:case
+cAbsNotNot:case
+cEqual:case
+cNEqual:case
+cLess:case
+cLessOrEq:case
+cGreater:case
+cGreaterOrEq:nV
+cMul:{for
+iY
+if(!yX3
+a))cL
+return
+true;}
+case
+cIf:case
+cAbsIf:yR
+yX3
+1))nT1
+lE2
+2));}
+c73
+yF3
+return
+tR3}
 #endif
-    // Do all sorts of optimizations
-    tree.Optimize();
-
-#ifdef TREE_DEBUG
-    cout << "BEFORE FINAL    :" << tree << endl;
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;
+#if defined(__x86_64) || __cplusplus < 201100
+# define CBRT_IS_SLOW
 #endif
-
-    // Last changes before assembly
-    tree.FinalOptimize();
-
-#ifdef TREE_DEBUG
-    cout << "AFTER           :" << tree << endl;
+#if defined(DEBUG_POWI) || defined(DEBUG_SUBSTITUTIONS)
+#include <cstdio>
 #endif
-    // Now rebuild from the tree.
-
-    vector<unsigned> byteCode;
-    vector<double> immed;
-
-#if 0
-    byteCode.resize(Comp.ByteCodeSize);
-    for(unsigned a=0; a<Comp.ByteCodeSize; ++a)byteCode[a] = Comp.ByteCode[a];
-
-    immed.resize(Comp.ImmedSize);
-    for(unsigned a=0; a<Comp.ImmedSize; ++a)immed[a] = Comp.Immed[a];
+lF3
+xH1{extern
+const
+iF2
+char
+powi_table[256];}
+lF3{using
+t5
+nJ1
+bool
+IsOptimizableUsingPowi(long
+immed,long
+penalty=0){xH1
+yG3
+synth;synth.PushVar(l03);size_t
+bytecodesize_backup=synth.GetByteCodeSize();xH1::x01
+immed,xH1::tN1
+xK::MulSequence,iS2
+size_t
+bytecode_grow_amount=synth.GetByteCodeSize()-bytecodesize_backup
+n31
+bytecode_grow_amount<size_t(MAX_POWI_BYTECODE_LENGTH-penalty);}
+tZ1
+ChangeIntoRootChain(eJ&tree,bool
+lD3,long
+i52,long
+i62){while(i62>0){t81
+cCbrt);iF3
+tmp
+eT1
+tree.i72--i62;}
+while(i52>0){t81
+cSqrt
+eY3
+lD3){tmp
+xD
+cRSqrt);lD3
+tO3}
+iF3
+tmp
+eT1
+tree.i72--i52;}
+if(lD3){t81
+cInv);iF3
+tree.i72}
+}
+xW3
+e12
+RootPowerTable{static
+const
+iV2
+RootPowers[(1+4)*(1+3)];}
+nJ1
+const
+iV2
+t8(1+4)*(1+3)]={iV2(1)lS
+iG3
+iG3
+2*iG3
+i11)lS
+3*2)lS
+3*2*2)lS
+3*i11*2*i11*3
+cV2
+2
+cV2
+2*2
+cV2
+i11*3*2*i11*3*3
+cV2
+3*2
+cV2
+3*2*2
+cV2
+3*i11*3*3*2*2*2*2)}
+;e12
+PowiResolver{static
+const
+iF2
+MaxSep=4;static
+xC3
+MaxOp=5;typedef
+int
+eE3;typedef
+long
+xI3;typedef
+long
+tW;e12
+yU2{yU2():n_int_sqrt(0),n_int_cbrt(0),sep_list(),lV1(0){}
+int
+n_int_sqrt;int
+n_int_cbrt;int
+tL1
+MaxSep];tW
+lV1;}
+nJ1
+static
+yU2
+CreatePowiResult(iV2
+xG2{yU2
+nT3;eE3
+t9=FindIntegerFactor(xG2;if(t9==0){
+#ifdef DEBUG_POWI
+i82"no factor found for %Lg\n"
+,yK1
+xG2;
+#endif
+return
+nT3;}
+nT3.lV1=y31
+exponent,t9);xI3
+eM2=EvaluateFactorCost(t9,0,0,0)+cB
+nT3.lV1);int
+iH3=0;int
+iI3=0;int
+mul_count=0;
+#ifdef DEBUG_POWI
+i82"orig = %Lg\n"
+,yK1
+xG2;i82"plain factor = "
+iW3"%ld\n"
+,(int)t9,(long)eM2);
+#endif
+for
+nT2
+n_s=0;n_s<MaxSep;++n_s){int
+x9=0;xI3
+yI1=eM2;eE3
+yW1=t9;for(int
+s=1;s<MaxOp*4;++s){
+#ifdef CBRT_IS_SLOW
+if(s>=MaxOp)break;
+#endif
+int
+n_sqrt=s%MaxOp;int
+n_cbrt=s/MaxOp;if(n_sqrt+n_cbrt>4
+cP2
+iU2
+lI1=exponent;lI1-=t8
+s];i41=FindIntegerFactor(lI1
+eY3
+xT2!=0){tW
+xP=y31
+lI1,xT2);xI3
+cost=EvaluateFactorCost(xT2,iH3+n_sqrt,iI3+n_cbrt,mul_count+1)+cB
+xP);
+#ifdef DEBUG_POWI
+i82"Candidate sep %u (%d*sqrt %d*cbrt)factor = "
+iW3"%ld (for %Lg to %ld)\n"
+,s,n_sqrt,n_cbrt,xT2,(long)cost,yK1
+lI1,(long)xP);
+#endif
+if(cost<yI1){x9=s;yW1=xT2;yI1=cost;}
+}
+}
+if(!x9)break;
+#ifdef DEBUG_POWI
+i82"CHOSEN sep %u (%d*sqrt %d*cbrt)factor = "
+iW3"%ld, exponent %Lg->%Lg\n"
+,x9,x9%MaxOp,x9/MaxOp,yW1,yI1,yK1(xG2,yK1
+t62-t8
+x9]));
+#endif
+nT3.tL1
+n_s]=x9;exponent-=t8
+x9];iH3+=x9%MaxOp;iI3+=x9/MaxOp;eM2=yI1;t9=yW1;mul_count+=1;}
+nT3.lV1=y31
+exponent,t9);
+#ifdef DEBUG_POWI
+i82"resulting exponent is %ld (from exponent=%Lg, best_factor=%Lg)\n"
+,nT3.lV1,yK1
+exponent,yK1
+t9);
+#endif
+while(t9%2==0){++nT3
+tD2;t9/=2;}
+while(t9%3==0){++nT3.n_int_cbrt;t9/=3;}
+return
+nT3;}
+private:static
+xI3
+cB
+tW
+xP){static
+std::map
+cR2
+iB;if(xP<0){xI3
+cost=22
+n31
+cost+cB-xP);}
+std::map
+cR2::yV3
+i=iB.xU2
+xP
+eY3
+i!=iB.cY1
+xP)return
+i
+e82;std::pair
+cR2
+nT3(xP,0.0);xI3&cost=nT3
+tE3;while(xP>1){int
+xT2=0;if(xP<256){xT2=xH1::powi_table[xP];if(xT2&128)xT2&=127;else
+xT2=0;if(xT2&64)xT2=-(xT2&63)-1;}
+if(xT2){cost+=cB
+xT2);xP/=xT2;eR2
+if(!(xP&1)){xP/=2;cost+=6;}
+else{cost+=7;xP-=1;}
+}
+iB.yR3,nT3)n31
+cost;}
+cA1
+tW
+y31
+yJ1,i41)yR
+makeLongInteger(value*iV2(xT2));}
+cA1
+bool
+yR1
+yJ1,i41
+tJ2
+v=value*iV2(xT2)n31
+isLongInteger(v);}
+cA1
+eE3
+FindIntegerFactor(yJ1){i41=(2*2*2*2);
+#ifdef CBRT_IS_SLOW
 #else
-    byteCode.clear(); immed.clear();
-    size_t stacktop_cur = 0;
-    size_t stacktop_max = 0;
-    tree.Assemble(byteCode, immed, stacktop_cur, stacktop_max);
-    
-    if(data->StackSize < stacktop_max)
-    {
-        delete[] data->Stack;
-        data->Stack = new double[stacktop_max];
-        data->StackSize = stacktop_max;
-    }
+xT2*=(3*3*3);
 #endif
-
-    delete[] data->ByteCode; data->ByteCode = 0;
-    if((data->ByteCodeSize = byteCode.size()) > 0)
-    {
-        data->ByteCode = new unsigned[data->ByteCodeSize];
-        for(unsigned a=0; a<byteCode.size(); ++a)
-            data->ByteCode[a] = byteCode[a];
-    }
-
-    delete[] data->Immed; data->Immed = 0;
-    if((data->ImmedSize = immed.size()) > 0)
-    {
-        data->Immed = new double[data->ImmedSize];
-        for(unsigned a=0; a<immed.size(); ++a)
-            data->Immed[a] = immed[a];
-    }
-
-    data->isOptimized = true;
+eE3
+nT3=0;if(yR1
+value,xT2)){nT3=xT2;while((xT2%2)==0&&yR1
+value,xT2/2))nT3=xT2/=2;while((xT2%3)==0&&yR1
+value,xT2/3))nT3=xT2/=3;}
+#ifdef CBRT_IS_SLOW
+if
+iT2==0){if(yR1
+value,3
+nE3
+3;}
+#endif
+return
+nT3;}
+static
+int
+EvaluateFactorCost(int
+xT2,int
+s,int
+c,int
+nmuls){xC3
+xD3=6;
+#ifdef CBRT_IS_SLOW
+xC3
+eN2=25;
+#else
+xC3
+eN2=8;
+#endif
+int
+nT3=s*xD3+c*eN2;while(xT2%2==0){xT2/=2;nT3+=xD3;}
+while(xT2%3==0){xT2/=3;nT3+=eN2;}
+nT3+=nmuls
+n31
+nT3;}
 }
+;}
+t5{xN1
+eJ::RecreateInversionsAndNegations(bool
+prefer_base2){bool
+changed=false
+yM3
+0;a<xF1++a)if(lS1.RecreateInversionsAndNegations(prefer_base2))x62
+if(changed){exit_changed:Mark_Incompletely_Hashed()xJ2
+switch(iS1{case
+cMul:{eH
+nF2;eJ
+nG2,cT1;if(true){bool
+nO1=false
+iU2
+x52=0;yP3
+yV2
+0)cX2
+tO
+iJ3
+nO1=true;x52=tO
+1)nC1;yF3}
+if(nO1
+tJ2
+immeds=1.0;yP3
+i61){immeds*=powgroup
+nC1;t41}
+for
+iJ-->0;){eJ&powgroup=lS1;if(powgroup
+yV2
+0)cX2
+tO
+iJ3
+eJ&log2=tO
+0);log2.l61
+log2
+xD
+eF3);log2.yC
+fp_pow(immeds
+tG1
+1)/x52)));log2
+eT1
+yF3}
+}
+}
+yP3
+yV2
+iJ3
+lC2
+exp_param=tO
+1)iU2
+e92
+exp_param
+nC1;if(e01
+tG1-1))){l61
+nF2.push_back(lS1
+lR2
+t41
+lJ2
+exponent<y21&&t42
+xG2){eJ
+iK;iK
+xD
+cPow);iK
+c9
+tO
+0));iK.yC-xG2);iK
+eT1
+nF2.push_back(iK);l61
+t41}
+lJ2
+powgroup
+cX2!nG2.t91
+nG2=tO
+0);l61
+t41
+lJ2
+powgroup
+nC==eF3&&!cT1.t91
+cT1=powgroup;l61
+t41}
+if(!nF2
+cT3){x62
+eJ
+i21;i21
+tH3
+i21
+iO3
+nF2);i21
+eT1
+eJ
+y41
+cMul);yQ1
+SetParamsMove
+eF
+if(yQ1
+IsImmed()&&fp_equal
+lR3
+nC1
+xE3
+nH2
+cInv)eO
+i21);}
+e63
+yQ1
+y22>=i21.y22){nH2
+cDiv)eO
+nN3
+eO
+i21
+t43{nH2
+cRDiv)eO
+i21)eO
+nN3;}
+}
+}
+if(nG2.t91
+eJ
+y41
+iS1;yQ1
+SetParamsMove
+eF
+while(yQ1
+RecreateInversionsAndNegations(prefer_base2))yQ1
+FixIncompleteHashes();nH2
+eF3)eO
+nG2)eO
+nN3;x62}
+if(cT1.t91
+eJ
+y41
+cMul);mulgroup
+yP1
+cT1
+l8
+1));yQ1
+AddParamsMove
+eF
+while(yQ1
+RecreateInversionsAndNegations(prefer_base2))yQ1
+FixIncompleteHashes();DelParams();nH2
+eF3)eO
+cT1
+l8
+0))eO
+nN3;x62
+i91
+cAdd:{eH
+iA2;for
+iJ-->0;)if(eG3
+cMul){nV3
+y51:;eJ&mulgroup=x82
+for
+iA1
+b=yQ1
+xF1
+b-->0;){if
+lR3
+l8
+b)l71
+xT2=mulgroup
+l8
+b)nC1
+cA3
+xT2
+i92
+y51;}
+yQ1
+l61
+yQ1
+DelParam(b);nW3
+lJ2
+cB3
+xT2
+tG1-2)))xC
+y51;}
+yQ1
+l61
+yQ1
+DelParam(b);yQ1
+yC
+x42
+nW3}
+}
+if(t2){yQ1
+tA
+nN3;t41}
+lJ2
+eG3
+cDiv&&!IsIntType
+xK::nT3){nV3
+y61:;eJ&i21=x82
+if(i21
+l8
+0)i51
+cB3
+i21
+l8
+0)nC1
+i92
+y61;}
+i21.l61
+i21
+tK2
+0);i21
+xD
+cInv);nW3}
+if(t2)xC
+y61;}
+i21.tA
+i21);t41}
+lJ2
+eG3
+cRDiv&&!IsIntType
+xK::nT3){nV3
+x81:;eJ&i21=x82
+if(i21
+l8
+1)i51
+cB3
+i21
+l8
+1)nC1
+i92
+x81;}
+i21.l61
+i21
+tK2
+1);i21
+xD
+cInv);nW3}
+if(t2)xC
+x81;}
+i21.tA
+i21);t41}
+if(!iA2
+cT3){
+#ifdef DEBUG_SUBSTITUTIONS
+i82"Will make a Sub conversion in:\n"
+);fflush(stdout);iR
+#endif
+eJ
+yW2;yW2
+xD
+cAdd);yW2
+iO3
+iA2);yW2
+eT1
+eJ
+cU1;cU1
+xD
+cAdd);cU1
+iO3
+l02));cU1
+eT1
+if(cU1
+i61&&cB3
+cU1
+nC1,xD1){nH2
+cNeg);e7);}
+e63
+cU1.y22==1){nH2
+cRSub);e7)eO
+cU1);}
+lJ2
+yW2
+nC==cAdd){nH2
+cSub)eO
+cU1);e7
+lR2
+for
+iA1
+a=1;a<yW2.xF1++a){eJ
+eO2;eO2
+xD
+cSub);eO2
+iO3
+l02));eO2.Rehash(false)eO
+eO2);e7
+x13}
+}
+else{nH2
+cSub)eO
+cU1);e7);}
+}
+#ifdef DEBUG_SUBSTITUTIONS
+i82"After Sub conversion:\n"
+);fflush(stdout);iR
+#endif
+i91
+cPow:{lC2
+p0=GetParam(0);lC2
+p1=GetParam(1
+eY3
+p1
+i51
+p1
+nC1!=y21&&!t42
+p1
+nC1)){eC
+yU2
+r=eC
+CreatePowiResult(fp_abs
+eH3)eY3
+r.lV1!=0){bool
+iY1
+tO3
+if
+eH3<y21&&r.tL1
+0]==0&&r
+tD2>0){iY1=true;}
+#ifdef DEBUG_POWI
+i82"Will resolve powi %Lg as powi(chain(%d,%d),%ld)"
+,yK1
+fp_abs
+eH3),r
+tD2,r.n_int_cbrt,r.lV1);for
+nT2
+n=0;n<eC
+MaxSep;++n){if(r
+nS3==0)break;int
+n_sqrt=r
+nS3%eC
+MaxOp;int
+n_cbrt=r
+nS3/eC
+MaxOp;i82"*chain(%d,%d)"
+,n_sqrt,n_cbrt);}
+i82"\n"
+);
+#endif
+eJ
+cY2=GetParam(0);eJ
+yX2=cY2;yX2.l61
+ChangeIntoRootChain(yX2,iY1,r
+tD2,r.n_int_cbrt);yX2
+eT1
+eJ
+pow;if(r.lV1!=1){pow
+xD
+cPow);pow
+yP1
+yX2);pow.yC
+iV2(r.lV1))t43
+pow.swap(yX2);eJ
+mul;mul
+tH3
+mul
+yP1
+pow);for
+nT2
+n=0;n<eC
+MaxSep;++n){if(r
+nS3==0)break;int
+n_sqrt=r
+nS3%eC
+MaxOp;int
+n_cbrt=r
+nS3/eC
+MaxOp;eJ
+eP2=cY2;eP2.l61
+ChangeIntoRootChain(eP2,false,n_sqrt,n_cbrt);eP2
+eT1
+mul
+yP1
+eP2);}
+if
+eH3<y21&&!iY1){mul
+eT1
+nH2
+cInv);nG1
+0,mul);DelParam(1
+t43{nH2
+cMul);SetParamsMove(mul.l02));}
+#ifdef DEBUG_POWI
+iR
+#endif
+x62
+yF3}
+}
+if(GetOpcode()==cPow&&(!p1
+i61||!isLongInteger
+eH3)||!IsOptimizableUsingPowi
+xK(makeLongInteger
+eH3)))){if(p0
+i61&&p0
+nC1>x22{if(prefer_base2
+tJ2
+yY2=fp_log2(p0
+nC1)cA3
+yY2
+xE3
+DelParam(0
+t43{n0
+e21
+yY2)tF1
+c9
+p1
+tF1
+eT1
+nG1
+nD1}
+nH2
+cExp2);x62}
+else{iV2
+yY2=fp_log(p0
+nC1)cA3
+yY2
+xE3
+DelParam(0
+t43{n0
+e21
+yY2)tF1
+c9
+p1
+tF1
+eT1
+nG1
+nD1}
+nH2
+cExp);x62}
+}
+lJ2
+GetPositivityInfo(p0)==IsAlways){if(prefer_base2){eJ
+log;log
+xD
+cLog2);log
+c9
+p0);log
+eT1
+n0
+p1
+tF1
+yP1
+log
+tF1
+eT1
+nH2
+cExp2);nG1
+nD1
+x62}
+else{eJ
+log;log
+xD
+cLog);log
+c9
+p0);log
+eT1
+n0
+p1
+tF1
+yP1
+log
+tF1
+eT1
+nH2
+cExp);nG1
+nD1
+x62}
+}
+i91
+cDiv:{if(GetParam(0)i61&&cB3
+GetParam(0)nC1
+xE3
+nH2
+cInv);DelParam(0);}
+yF3
+c73
+yF3
+if(changed)goto
+exit_changed
+n31
+changed;}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+using
+lF3
+FUNCTIONPARSERTYPES;lF3{using
+t5;class
+e43{size_t
+nP1;size_t
+eD;size_t
+eE;size_t
+lJ1;size_t
+t3;size_t
+t4;size_t
+n01;eX3
+e43():nP1(0),eD(0),eE(0),lJ1(0),t3(0),t4(0),n01(0){}
+void
+t23
+OPCODE
+op){nP1+=1;e33
+cCos)++eD;e33
+cSin)++eE;e33
+cSec)++eD;e33
+cCsc)++eE;e33
+cTan)++lJ1;e33
+cCot)++lJ1;e33
+cSinh)++t4;e33
+cCosh)++t3;e33
+cTanh)++n01;}
+size_t
+GetCSEscore
+e73
+size_t
+nT3=nP1
+n31
+nT3;}
+int
+NeedsSinCos
+e73
+bool
+y71=(nP1==(eD+eE+lJ1)eY3(lJ1&&(eE||eD))||(eE&&eD)){if(y71)return
+1
+n31
+2;}
+return
+0;}
+int
+NeedsSinhCosh
+e73
+bool
+y71=(nP1==(t3+t4+n01)eY3(n01&&(t4||t3))||(t4&&t3)){if(y71)return
+1
+n31
+2;}
+return
+0;}
+size_t
+MinimumDepth
+e73
+size_t
+n_sincos=std::min(eD,eE);size_t
+n_sinhcosh=std::min(t3,t4
+eY3
+n_sincos==0&&n_sinhcosh==0)return
+2
+n31
+1;}
+}
+nJ1
+class
+TreeCountType:public
+std::multimap<fphash_t,std::pair<e43,eJ> >{}
+xR3
+FindTreeCounts(tK1&nI2,lC2
+tree,OPCODE
+x92,bool
+skip_root=false){cV
+i=nI2.xU2
+tree.GetHash()eY3!skip_root){bool
+found
+tO3
+for(;i!=nI2.cY1
+tree.GetHash();++i){if(tree
+xF
+i
+e82
+iO2){i
+e82.first.t23
+x92);found=true;yF3}
+if(!found){e43
+count;count.t23
+x92);nI2.yR3,std::make_pair(tree.GetHash(),std::make_pair
+eL3,tree)));}
+}
+nB1
+FindTreeCounts(nI2,t33,i01);}
+e12
+yU{bool
+BalanceGood;bool
+FoundChild;}
+nJ1
+yU
+lK1
+lC2
+root,lC2
+child){if(root
+xF
+child)){yU
+nT3={true,true}
+n31
+nT3;}
+yU
+nT3={true,false}
+;if(root
+nC==cIf||root
+nC==yW3{yU
+cond=lK1
+root
+l8
+0
+nO3
+yU
+xX=lK1
+root
+l8
+1
+nO3
+yU
+y6=lK1
+root
+l8
+2
+nO3
+if
+y03||xX
+yV||y6
+yV){nT3
+yV=true;}
+nT3
+e8=((xX
+yV==y6
+yV)||y03
+cZ2&&(cond
+e8||(xX
+yV&&y6
+yV))&&(xX
+e8||y03
+cZ2&&(y6
+e8||y03
+cZ2;}
+else{bool
+iE1
+tO3
+bool
+nQ1
+tO3
+for
+iA1
+b=root.GetParamCount(),a=0;a<b;++a){yU
+tmp=lK1
+root
+l8
+a
+nO3
+if(tmp
+yV)nT3
+yV=true;if(tmp
+e8==false)iE1=true;lJ2
+tmp
+yV)nQ1=true;}
+if(iE1&&!nQ1)nT3
+e8
+tO3}
+return
+nT3;}
+xN1
+nZ3
+lQ3
+within,lC2
+tree,const
+xH1
+yG3&synth,const
+tK1&nI2){for
+iA1
+b=eM,a=0;a<b;++a){lC2
+leaf=t33;cV
+synth_it;xX2
+tK1::const_iterator
+i=nI2.yU3
+i!=nI2.end();++i){if(i->first!=leaf.GetHash()cP2;const
+e43&occ
+nQ2
+first;size_t
+score=occ.GetCSEscore();lC2
+candidate
+nQ2
+second;if(tM1
+candidate)cP2;if(leaf.y22<occ.MinimumDepth()cP2;if(score<2
+cP2;if(lK1
+within,leaf)e8==false
+cP2
+xJ2
+if(nZ3(within,leaf,synth,nI2
+tI1;}
+return
+tR3
+xN1
+nJ2
+lQ3
+yS3,lC2
+expr){i71
+yS3
+l8
+a)xF
+expr
+tI1;i71
+nJ2(yS3
+l8
+a),expr
+tI1
+n31
+tR3
+xN1
+GoodMomentForCSE
+lQ3
+yS3,lC2
+expr){if(yS3
+nC==cIf)return
+true;i71
+yS3
+l8
+a)xF
+expr
+tI1;size_t
+iB2=0;i71
+nJ2(yS3
+l8
+a),expr))++iB2
+n31
+iB2!=1;}
+}
+t5{xW3
+size_t
+eJ::SynthCommonSubExpressions(xH1::yM1
+const{if(GetParamCount()==0)return
+0;size_t
+stacktop_before=synth.GetStackTop();tK1
+nI2;FindTreeCounts(nI2,*this,GetOpcode(),true);for(;;){size_t
+yZ2=0;
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+std::cout<<"Finding a CSE candidate, root is:"
+<<std::endl;DumpHashes(*this);
+#endif
+cV
+cs_it(nI2.end());for(cV
+j=nI2.yU3
+j!=nI2.end();){cV
+i(j++);const
+e43&occ
+nQ2
+first;size_t
+score=occ.GetCSEscore();lC2
+tree
+nQ2
+second;
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+std::cout<<"Score "
+<<score<<":\n"
+<<std::flush;DumpTreeWithIndent(tree);
+#endif
+if(tM1
+tree))xT
+if(tree.y22<occ.MinimumDepth())xT
+if(score<2)xT
+if(lK1*this,tree)e8==false)xT
+if(nZ3(*this,tree,synth,nI2)){eR2
+if(!GoodMomentForCSE(*this,tree))xT
+score*=tree.y22;if(score>yZ2){yZ2=score;cs_it=i;}
+}
+if(yZ2<=0){
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+std::cout<<"No more CSE candidates.\n"
+<<std::flush;
+#endif
+yF3
+lC2
+tree=cs_it
+e82
+tE3;
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+std::cout<<l24"Common Subexpression:"
+i13
+xK(tree
+lT2
+std::endl;
+#endif
+#if 0
+int
+lW1=occ.NeedsSinCos();int
+i1=occ.NeedsSinhCosh();eJ
+iC2,iD2,c02,c12;if(lW1){iC2
+eQ2
+iC2
+xD
+cSin);iC2
+eT1
+iD2
+eQ2
+iD2
+xD
+cCos);iD2
+eT1
+if(tM1
+iC2)||tM1
+iD2)){if(lW1==2){tJ1
+eR2
+lW1=0;}
+}
+if(i1){c02
+eQ2
+c02
+xD
+cSinh);c02
+eT1
+c12
+eQ2
+c12
+xD
+cCosh);c12
+eT1
+if(tM1
+c02)||tM1
+c12)){if(i1==2){tJ1
+eR2
+i1=0;}
+}
+#endif
+tree.SynthesizeByteCode(synth,false);tJ1
+#ifdef DEBUG_SUBSTITUTIONS_CSE
+synth.template
+Dump<0>(lT2"Done with Common Subexpression:"
+i13
+xK(tree
+lT2
+std::endl;
+#endif
+#if 0
+if(lW1){if(lW1==2||i1){synth.e91}
+yE3
+cSinCos,1,2)cI1
+iC2,1)cI1
+iD2,0);}
+if(i1){if(lW1)synth.e91
+if(i1==2){synth.e91}
+yE3
+cSinhCosh,1,2)cI1
+c02,1)cI1
+c12,0);}
+#endif
+}
+return
+yD3
+stacktop_before;}
+}
+#endif
+#ifdef FP_SUPPORT_OPTIMIZER
+tZ1
+FunctionParserBase
+xK::Optimize(){using
+t5;l61
+eJ
+tree;tree.GenerateFrom(*mData);FPoptimizer_Optimize::ApplyGrammars(tree);std
+xV3<iF2>eI3;std
+xV3
+xK
+immed;size_t
+stacktop_max=0;tree.SynthesizeByteCode(eI3,immed,stacktop_max
+eY3
+mData->mStackSize!=stacktop_max){mData->mStackSize=iF2(stacktop_max);
+#if !defined(FP_USE_THREAD_SAFE_EVAL) && \
+    !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA)
+mData->mStack.t73
+stacktop_max);
+#endif
+}
+mData->mByteCode.swap(eI3);mData->mImmed.swap(immed);}
+#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE
+x8
+MpfrFloat
+n11
+#endif
+#ifdef FP_SUPPORT_GMP_INT_TYPE
+x8
+GmpInt
+n11
+#endif
+#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE
+x8
+std::complex<double>n11
+#endif
+#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE
+x8
+std::complex<float>n11
+#endif
+#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE
+x8
+std::complex<long
+double>n11
+#endif
+FUNCTIONPARSER_INSTANTIATE_TYPES
+#endif
 
-
-#endif // #ifdef SUPPORT_OPTIMIZER
+#endif
diff --git a/deal.II/contrib/functionparser/fptypes.h b/deal.II/contrib/functionparser/fptypes.h
deleted file mode 100644 (file)
index a353491..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-//===============================
-// Function parser v2.83 by Warp
-//===============================
-
-// 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.
-
-
-
-namespace FUNCTIONPARSERTYPES
-{
-// The functions must be in alphabetical order:
-    enum OPCODE
-    {
-        cAbs, cAcos,
-#ifndef NO_ASINH
-        cAcosh,
-#endif
-        cAsin,
-#ifndef NO_ASINH
-        cAsinh,
-#endif
-        cAtan,
-        cAtan2,
-#ifndef NO_ASINH
-        cAtanh,
-#endif
-        cCeil, cCos, cCosh, cCot, cCsc,
-#ifndef DISABLE_EVAL
-        cEval,
-#endif
-        cExp, cFloor, cIf, cInt, cLog, cLog10, cMax, cMin,
-        cSec, cSin, cSinh, cSqrt, cTan, cTanh,
-
-// These do not need any ordering:
-        cImmed, cJump,
-        cNeg, cAdd, cSub, cMul, cDiv, cMod, cPow,
-        cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq,
-        cNot, cAnd, cOr,
-
-        cDeg, cRad,
-
-        cFCall, cPCall,
-
-#ifdef SUPPORT_OPTIMIZER
-        cVar, cDup, cInv,
-#endif
-
-        VarBegin
-    };
-
-    struct FuncDefinition
-    {
-        const char* name;
-        unsigned nameLength;
-        unsigned opcode;
-        unsigned params;
-
-        // This is basically strcmp(), but taking 'nameLength' as string
-        // length (not ending '\0'):
-        bool operator<(const FuncDefinition& 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;
-        }
-    };
-
-
-// This list must be in alphabetical order:
-    const FuncDefinition Functions[]=
-    {
-        { "abs", 3, cAbs, 1 },
-        { "acos", 4, cAcos, 1 },
-#ifndef NO_ASINH
-        { "acosh", 5, cAcosh, 1 },
-#endif
-        { "asin", 4, cAsin, 1 },
-#ifndef NO_ASINH
-        { "asinh", 5, cAsinh, 1 },
-#endif
-        { "atan", 4, cAtan, 1 },
-        { "atan2", 5, cAtan2, 2 },
-#ifndef NO_ASINH
-        { "atanh", 5, cAtanh, 1 },
-#endif
-        { "ceil", 4, cCeil, 1 },
-        { "cos", 3, cCos, 1 },
-        { "cosh", 4, cCosh, 1 },
-        { "cot", 3, cCot, 1 },
-        { "csc", 3, cCsc, 1 },
-#ifndef DISABLE_EVAL
-        { "eval", 4, cEval, 0 },
-#endif
-        { "exp", 3, cExp, 1 },
-        { "floor", 5, cFloor, 1 },
-        { "if", 2, cIf, 0 },
-        { "int", 3, cInt, 1 },
-        { "log", 3, cLog, 1 },
-        { "log10", 5, cLog10, 1 },
-        { "max", 3, cMax, 2 },
-        { "min", 3, cMin, 2 },
-        { "sec", 3, cSec, 1 },
-        { "sin", 3, cSin, 1 },
-        { "sinh", 4, cSinh, 1 },
-        { "sqrt", 4, cSqrt, 1 },
-        { "tan", 3, cTan, 1 },
-        { "tanh", 4, cTanh, 1 }
-    };
-}
diff --git a/deal.II/contrib/functionparser/lgpl-3.0.txt b/deal.II/contrib/functionparser/lgpl-3.0.txt
new file mode 100644 (file)
index 0000000..65c5ca8
--- /dev/null
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/deal.II/contrib/functionparser/mpfr/GmpInt.cc b/deal.II/contrib/functionparser/mpfr/GmpInt.cc
new file mode 100644 (file)
index 0000000..490add4
--- /dev/null
@@ -0,0 +1,710 @@
+#include "GmpInt.hh"
+#include <gmp.h>
+#include <deque>
+#include <vector>
+#include <cstring>
+#include <cctype>
+
+//===========================================================================
+// Shared data
+//===========================================================================
+namespace
+{
+    unsigned long gIntDefaultNumberOfBits = 256;
+
+    std::vector<char>& intString()
+    {
+        static std::vector<char> str;
+        return str;
+    }
+}
+
+//===========================================================================
+// Auxiliary structs
+//===========================================================================
+struct GmpInt::GmpIntData
+{
+    unsigned mRefCount;
+    GmpIntData* nextFreeNode;
+    mpz_t mInteger;
+
+    GmpIntData(): mRefCount(1), nextFreeNode(0) {}
+};
+
+class GmpInt::GmpIntDataContainer
+{
+    std::deque<GmpInt::GmpIntData> mData;
+    GmpInt::GmpIntData* mFirstFreeNode;
+    GmpInt::GmpIntData* mConst_0;
+
+ public:
+    GmpIntDataContainer(): mFirstFreeNode(0), mConst_0(0) {}
+
+    ~GmpIntDataContainer()
+    {
+        for(size_t i = 0; i < mData.size(); ++i)
+            mpz_clear(mData[i].mInteger);
+    }
+
+    GmpInt::GmpIntData* allocateGmpIntData(unsigned long numberOfBits,
+                                           bool initToZero)
+    {
+        if(mFirstFreeNode)
+        {
+            GmpInt::GmpIntData* node = mFirstFreeNode;
+            mFirstFreeNode = node->nextFreeNode;
+            if(initToZero) mpz_set_si(node->mInteger, 0);
+            ++(node->mRefCount);
+            return node;
+        }
+
+        mData.push_back(GmpInt::GmpIntData());
+        if(numberOfBits > 0)
+            mpz_init2(mData.back().mInteger, numberOfBits);
+        else
+            mpz_init(mData.back().mInteger);
+        return &mData.back();
+    }
+
+    void releaseGmpIntData(GmpIntData* data)
+    {
+        if(--(data->mRefCount) == 0)
+        {
+            data->nextFreeNode = mFirstFreeNode;
+            mFirstFreeNode = data;
+        }
+    }
+
+    GmpInt::GmpIntData* const_0()
+    {
+        if(!mConst_0)
+            mConst_0 = allocateGmpIntData(gIntDefaultNumberOfBits, true);
+        return mConst_0;
+    }
+};
+
+
+GmpInt::GmpIntDataContainer& GmpInt::gmpIntDataContainer()
+{
+    static GmpIntDataContainer container;
+    return container;
+}
+
+//===========================================================================
+// Auxiliary functions
+//===========================================================================
+void GmpInt::setDefaultNumberOfBits(unsigned long value)
+{
+    gIntDefaultNumberOfBits = value;
+}
+
+unsigned long GmpInt::getDefaultNumberOfBits()
+{
+    return gIntDefaultNumberOfBits;
+}
+
+inline void GmpInt::copyIfShared()
+{
+    if(mData->mRefCount > 1)
+    {
+        --(mData->mRefCount);
+        GmpIntData* oldData = mData;
+        mData = gmpIntDataContainer().allocateGmpIntData(0, false);
+        mpz_set(mData->mInteger, oldData->mInteger);
+    }
+}
+
+
+//===========================================================================
+// Constructors, destructor, assignment
+//===========================================================================
+GmpInt::GmpInt(DummyType):
+    mData(gmpIntDataContainer().allocateGmpIntData(0, false))
+{}
+
+GmpInt::GmpInt()
+{
+    mData = gmpIntDataContainer().const_0();
+    ++(mData->mRefCount);
+}
+
+GmpInt::GmpInt(long value)
+{
+    if(value == 0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_si(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(unsigned long value)
+{
+    if(value == 0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_ui(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(int value)
+{
+    if(value == 0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_si(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(double value)
+{
+    const double absValue = value >= 0.0 ? value : -value;
+    if(absValue < 1.0)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_d(mData->mInteger, value);
+    }
+}
+
+GmpInt::GmpInt(long double value)
+{
+    const long double absValue = value >= 0.0L ? value : -value;
+    if(absValue < 1.0L)
+    {
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        mData = gmpIntDataContainer().allocateGmpIntData
+            (gIntDefaultNumberOfBits, false);
+        mpz_set_d(mData->mInteger, double(value));
+    }
+}
+
+GmpInt::GmpInt(const GmpInt& rhs):
+    mData(rhs.mData)
+{
+    ++(mData->mRefCount);
+}
+
+GmpInt& GmpInt::operator=(const GmpInt& rhs)
+{
+    if(mData != rhs.mData)
+    {
+        gmpIntDataContainer().releaseGmpIntData(mData);
+        mData = rhs.mData;
+        ++(mData->mRefCount);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator=(signed long value)
+{
+    if(value == 0)
+    {
+        gmpIntDataContainer().releaseGmpIntData(mData);
+        mData = gmpIntDataContainer().const_0();
+        ++(mData->mRefCount);
+    }
+    else
+    {
+        if(mData->mRefCount > 1)
+        {
+            --(mData->mRefCount);
+            mData = gmpIntDataContainer().allocateGmpIntData
+                (gIntDefaultNumberOfBits, false);
+        }
+        mpz_set_si(mData->mInteger, value);
+    }
+    return *this;
+}
+
+GmpInt::~GmpInt()
+{
+    gmpIntDataContainer().releaseGmpIntData(mData);
+}
+
+
+//===========================================================================
+// Data getters
+//===========================================================================
+template<>
+void GmpInt::get_raw_mpfr_data<mpz_t>(mpz_t& dest_mpz_t)
+{
+    std::memcpy(&dest_mpz_t, mData->mInteger, sizeof(mpz_t));
+}
+
+const char* GmpInt::getAsString(int base) const
+{
+    intString().resize(mpz_sizeinbase(mData->mInteger, base) + 2);
+    return mpz_get_str(&intString()[0], base, mData->mInteger);
+}
+
+long GmpInt::toInt() const
+{
+    return mpz_get_si(mData->mInteger);
+}
+
+
+//===========================================================================
+// Modifying operators
+//===========================================================================
+GmpInt& GmpInt::operator+=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_add(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator+=(long value)
+{
+    copyIfShared();
+    if(value >= 0)
+        mpz_add_ui(mData->mInteger, mData->mInteger, value);
+    else
+        mpz_sub_ui(mData->mInteger, mData->mInteger, -value);
+    return *this;
+}
+
+GmpInt& GmpInt::operator-=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_sub(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator-=(long value)
+{
+    copyIfShared();
+    if(value >= 0)
+        mpz_sub_ui(mData->mInteger, mData->mInteger, value);
+    else
+        mpz_add_ui(mData->mInteger, mData->mInteger, -value);
+    return *this;
+}
+
+GmpInt& GmpInt::operator*=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_mul(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator*=(long value)
+{
+    copyIfShared();
+    mpz_mul_si(mData->mInteger, mData->mInteger, value);
+    return *this;
+}
+
+GmpInt& GmpInt::operator/=(const GmpInt& rhs)
+{
+    copyIfShared();
+    mpz_tdiv_q(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return *this;
+}
+
+GmpInt& GmpInt::operator/=(long value)
+{
+    copyIfShared();
+    if(value >= 0)
+        mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, value);
+    else
+    {
+        mpz_neg(mData->mInteger, mData->mInteger);
+        mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, -value);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator%=(const GmpInt& rhs)
+{
+    copyIfShared();
+    if(operator<(0))
+    {
+        negate();
+        mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+        negate();
+    }
+    else
+    {
+        mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator%=(long value)
+{
+    copyIfShared();
+    if(value < 0) value = -value;
+    if(operator<(0))
+    {
+        negate();
+        mpz_mod_ui(mData->mInteger, mData->mInteger, value);
+        negate();
+    }
+    else
+    {
+        mpz_mod_ui(mData->mInteger, mData->mInteger, value);
+    }
+    return *this;
+}
+
+GmpInt& GmpInt::operator<<=(unsigned long bits)
+{
+    copyIfShared();
+    mpz_mul_2exp(mData->mInteger, mData->mInteger, bits);
+    return *this;
+}
+
+GmpInt& GmpInt::operator>>=(unsigned long bits)
+{
+    copyIfShared();
+    mpz_tdiv_q_2exp(mData->mInteger, mData->mInteger, bits);
+    return *this;
+}
+
+
+//===========================================================================
+// Modifying functions
+//===========================================================================
+void GmpInt::addProduct(const GmpInt& value1, const GmpInt& value2)
+{
+    copyIfShared();
+    mpz_addmul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
+}
+
+void GmpInt::addProduct(const GmpInt& value1, unsigned long value2)
+{
+    copyIfShared();
+    mpz_addmul_ui(mData->mInteger, value1.mData->mInteger, value2);
+}
+
+void GmpInt::subProduct(const GmpInt& value1, const GmpInt& value2)
+{
+    copyIfShared();
+    mpz_submul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
+}
+
+void GmpInt::subProduct(const GmpInt& value1, unsigned long value2)
+{
+    copyIfShared();
+    mpz_submul_ui(mData->mInteger, value1.mData->mInteger, value2);
+}
+
+void GmpInt::negate()
+{
+    copyIfShared();
+    mpz_neg(mData->mInteger, mData->mInteger);
+}
+
+void GmpInt::abs()
+{
+    copyIfShared();
+    mpz_abs(mData->mInteger, mData->mInteger);
+}
+
+GmpInt GmpInt::abs(const GmpInt& value)
+{
+    GmpInt retval(kNoInitialization);
+    mpz_abs(retval.mData->mInteger, value.mData->mInteger);
+    return retval;
+}
+
+
+//===========================================================================
+// Non-modifying operators
+//===========================================================================
+GmpInt GmpInt::operator+(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_add(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator+(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value >= 0)
+        mpz_add_ui(retval.mData->mInteger, mData->mInteger, value);
+    else
+        mpz_sub_ui(retval.mData->mInteger, mData->mInteger, -value);
+    return retval;
+}
+
+GmpInt GmpInt::operator-(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_sub(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator-(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value >= 0)
+        mpz_sub_ui(retval.mData->mInteger, mData->mInteger, value);
+    else
+        mpz_add_ui(retval.mData->mInteger, mData->mInteger, -value);
+    return retval;
+}
+
+GmpInt GmpInt::operator*(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_mul(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator*(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_mul_si(retval.mData->mInteger, mData->mInteger, value);
+    return retval;
+}
+
+GmpInt GmpInt::operator/(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_tdiv_q(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator/(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value >= 0)
+        mpz_tdiv_q_ui(retval.mData->mInteger, mData->mInteger, value);
+    else
+    {
+        mpz_neg(retval.mData->mInteger, mData->mInteger);
+        mpz_tdiv_q_ui(retval.mData->mInteger, retval.mData->mInteger, -value);
+    }
+    return retval;
+}
+
+GmpInt GmpInt::operator%(const GmpInt& rhs) const
+{
+    GmpInt retval(kNoInitialization);
+    if(operator<(0))
+    {
+        mpz_neg(retval.mData->mInteger, mData->mInteger);
+        mpz_mod(retval.mData->mInteger,
+                retval.mData->mInteger, rhs.mData->mInteger);
+        retval.negate();
+    }
+    else
+    {
+        mpz_mod(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
+    }
+    return retval;
+}
+
+GmpInt GmpInt::operator%(long value) const
+{
+    GmpInt retval(kNoInitialization);
+    if(value < 0) value = -value;
+    if(operator<(0))
+    {
+        mpz_neg(retval.mData->mInteger, mData->mInteger);
+        mpz_mod_ui(retval.mData->mInteger, retval.mData->mInteger, value);
+        retval.negate();
+    }
+    else
+    {
+        mpz_mod_ui(retval.mData->mInteger, mData->mInteger, value);
+    }
+    return retval;
+}
+
+GmpInt GmpInt::operator-() const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_neg(retval.mData->mInteger, mData->mInteger);
+    return retval;
+}
+
+GmpInt GmpInt::operator<<(unsigned long bits) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_mul_2exp(retval.mData->mInteger, mData->mInteger, bits);
+    return retval;
+}
+
+GmpInt GmpInt::operator>>(unsigned long bits) const
+{
+    GmpInt retval(kNoInitialization);
+    mpz_tdiv_q_2exp(retval.mData->mInteger, mData->mInteger, bits);
+    return retval;
+}
+
+
+//===========================================================================
+// Comparison operators
+//===========================================================================
+bool GmpInt::operator<(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) < 0;
+}
+
+bool GmpInt::operator<(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) < 0;
+}
+
+bool GmpInt::operator<=(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) <= 0;
+}
+
+bool GmpInt::operator<=(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) <= 0;
+}
+
+bool GmpInt::operator>(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) > 0;
+}
+
+bool GmpInt::operator>(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) > 0;
+}
+
+bool GmpInt::operator>=(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) >= 0;
+}
+
+bool GmpInt::operator>=(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) >= 0;
+}
+
+bool GmpInt::operator==(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) == 0;
+}
+
+bool GmpInt::operator==(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) == 0;
+}
+
+bool GmpInt::operator!=(const GmpInt& rhs) const
+{
+    return mpz_cmp(mData->mInteger, rhs.mData->mInteger) != 0;
+}
+
+bool GmpInt::operator!=(long value) const
+{
+    return mpz_cmp_si(mData->mInteger, value) != 0;
+}
+
+void GmpInt::parseValue(const char* value)
+{
+    mpz_set_str(mData->mInteger, value, 10);
+}
+
+void GmpInt::parseValue(const char* value, char** endptr)
+{
+    static std::vector<char> str;
+
+    unsigned startIndex = 0;
+    while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex;
+    if(!value[startIndex]) { *endptr = const_cast<char*>(value); return; }
+
+    unsigned endIndex = startIndex;
+    if(value[endIndex] == '-') ++endIndex;
+    if(!std::isdigit(value[endIndex]))
+    { *endptr = const_cast<char*>(value); return; }
+    if(value[endIndex] == '0' && value[endIndex+1] == 'x')
+    {
+        endIndex += 1;
+        while(std::isxdigit(value[++endIndex])) {}
+    }
+    else
+    {
+        while(std::isdigit(value[++endIndex])) {}
+    }
+
+    str.reserve(endIndex - startIndex + 1);
+    str.assign(value + startIndex, value + endIndex);
+    str.push_back(0);
+
+    mpz_set_str(mData->mInteger, &str[0], 0);
+    *endptr = const_cast<char*>(value + endIndex);
+}
+
+GmpInt GmpInt::parseString(const char* str, char** endptr)
+{
+    GmpInt retval(kNoInitialization);
+    retval.parseValue(str, endptr);
+    return retval;
+}
+
+//===========================================================================
+// Operator functions
+//===========================================================================
+GmpInt operator+(long lhs, const GmpInt& rhs)
+{
+    GmpInt retval(GmpInt::kNoInitialization);
+    if(lhs >= 0)
+        mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs);
+    else
+        mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
+    return retval;
+}
+
+GmpInt operator-(long lhs, const GmpInt& rhs)
+{
+    GmpInt retval(GmpInt::kNoInitialization);
+    if(lhs >= 0)
+        mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger);
+    else
+    {
+        mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
+        mpz_neg(retval.mData->mInteger, retval.mData->mInteger);
+    }
+    return retval;
+}
+
+GmpInt operator*(long lhs, const GmpInt& rhs)
+{
+    return rhs * lhs;
+}
+
+GmpInt operator/(long lhs, const GmpInt& rhs)
+{
+    return GmpInt(lhs) / rhs;
+}
+
+GmpInt operator%(long lhs, const GmpInt& rhs)
+{
+    return GmpInt(lhs) % rhs;
+}
diff --git a/deal.II/contrib/functionparser/mpfr/GmpInt.hh b/deal.II/contrib/functionparser/mpfr/GmpInt.hh
new file mode 100644 (file)
index 0000000..1c1c171
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef ONCE_FP_GMP_INT_HH_
+#define ONCE_FP_GMP_INT_HH_
+
+#include <iostream>
+
+class GmpInt
+{
+ public:
+    /* A default of 256 bits will be used for all newly-instantiated GmpInt
+       objects. This default can be changed with the function below.
+    */
+    static void setDefaultNumberOfBits(unsigned long);
+    static unsigned long getDefaultNumberOfBits();
+
+    GmpInt();
+    GmpInt(long value);
+    GmpInt(unsigned long value);
+    GmpInt(int value);
+    GmpInt(double value);
+    GmpInt(long double value);
+
+    GmpInt(const GmpInt&);
+    GmpInt& operator=(const GmpInt&);
+    GmpInt& operator=(signed long value);
+
+    ~GmpInt();
+
+
+    /* This function can be used to retrieve the raw mpz_t data structure
+       used by this object. (The template trick is used to avoid a dependency
+       of this header file with <gmp.h>.)
+       In other words, it can be called like:
+
+         mpz_t raw_mpz_data;
+         intValue.get_raw_mpz_data(raw_mpz_data);
+
+       Note that the returned mpz_t should be considered as read-only and
+       not be modified from the outside because it may be shared among
+       several objects. If the calling code needs to modify the data, it
+       should copy it for itself first with the appropriate GMP library
+       functions.
+     */
+    template<typename Mpz_t>
+    void get_raw_mpfr_data(Mpz_t& dest_mpz_t);
+
+
+    // Note that the returned char* points to an internal (shared) buffer
+    // which will be valid until the next time this function is called
+    // (by any object).
+    const char* getAsString(int base = 10) const;
+    long toInt() const;
+
+    GmpInt& operator+=(const GmpInt&);
+    GmpInt& operator+=(long);
+    GmpInt& operator-=(const GmpInt&);
+    GmpInt& operator-=(long);
+    GmpInt& operator*=(const GmpInt&);
+    GmpInt& operator*=(long);
+    GmpInt& operator/=(const GmpInt&);
+    GmpInt& operator/=(long);
+    GmpInt& operator%=(const GmpInt&);
+    GmpInt& operator%=(long);
+
+    GmpInt& operator<<=(unsigned long);
+    GmpInt& operator>>=(unsigned long);
+
+    // Equivalent to "+= value1 * value2;"
+    void addProduct(const GmpInt& value1, const GmpInt& value2);
+    void addProduct(const GmpInt& value1, unsigned long value2);
+
+    // Equivalent to "-= value1 * value2;"
+    void subProduct(const GmpInt& value1, const GmpInt& value2);
+    void subProduct(const GmpInt& value1, unsigned long value2);
+
+    void negate();
+    void abs();
+    static GmpInt abs(const GmpInt&);
+
+    GmpInt operator+(const GmpInt&) const;
+    GmpInt operator+(long) const;
+    GmpInt operator-(const GmpInt&) const;
+    GmpInt operator-(long) const;
+    GmpInt operator*(const GmpInt&) const;
+    GmpInt operator*(long) const;
+    GmpInt operator/(const GmpInt&) const;
+    GmpInt operator/(long) const;
+    GmpInt operator%(const GmpInt&) const;
+    GmpInt operator%(long) const;
+
+    GmpInt operator-() const;
+
+    GmpInt operator<<(unsigned long) const;
+    GmpInt operator>>(unsigned long) const;
+
+    bool operator<(const GmpInt&) const;
+    bool operator<(long) const;
+    bool operator<=(const GmpInt&) const;
+    bool operator<=(long) const;
+    bool operator>(const GmpInt&) const;
+    bool operator>(long) const;
+    bool operator>=(const GmpInt&) const;
+    bool operator>=(long) const;
+    bool operator==(const GmpInt&) const;
+    bool operator==(long) const;
+    bool operator!=(const GmpInt&) const;
+    bool operator!=(long) const;
+
+    void parseValue(const char* value);
+    void parseValue(const char* value, char** endptr);
+    static GmpInt parseString(const char* str, char** endptr);
+
+
+ private:
+    struct GmpIntData;
+    class GmpIntDataContainer;
+
+    GmpIntData* mData;
+
+    enum DummyType { kNoInitialization };
+    GmpInt(DummyType);
+
+    void copyIfShared();
+    static GmpIntDataContainer& gmpIntDataContainer();
+
+    friend GmpInt operator+(long lhs, const GmpInt& rhs);
+    friend GmpInt operator-(long lhs, const GmpInt& rhs);
+};
+
+GmpInt operator+(long lhs, const GmpInt& rhs);
+GmpInt operator-(long lhs, const GmpInt& rhs);
+GmpInt operator*(long lhs, const GmpInt& rhs);
+GmpInt operator/(long lhs, const GmpInt& rhs);
+GmpInt operator%(long lhs, const GmpInt& rhs);
+
+inline bool operator<(long lhs, const GmpInt& rhs) { return rhs > lhs; }
+inline bool operator<=(long lhs, const GmpInt& rhs) { return rhs >= lhs; }
+inline bool operator>(long lhs, const GmpInt& rhs) { return rhs < lhs; }
+inline bool operator>=(long lhs, const GmpInt& rhs) { return rhs <= lhs; }
+inline bool operator==(long lhs, const GmpInt& rhs) { return rhs == lhs; }
+inline bool operator!=(long lhs, const GmpInt& rhs) { return rhs != lhs; }
+
+inline std::ostream& operator<<(std::ostream& os, const GmpInt& value)
+{
+    os << value.getAsString();
+    return os;
+}
+
+#endif
diff --git a/deal.II/contrib/functionparser/mpfr/MpfrFloat.cc b/deal.II/contrib/functionparser/mpfr/MpfrFloat.cc
new file mode 100644 (file)
index 0000000..112c684
--- /dev/null
@@ -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/deal.II/contrib/functionparser/mpfr/MpfrFloat.hh b/deal.II/contrib/functionparser/mpfr/MpfrFloat.hh
new file mode 100644 (file)
index 0000000..d455d24
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef ONCE_FP_MPFR_FLOAT_
+#define ONCE_FP_MPFR_FLOAT_
+
+#include <iostream>
+
+class MpfrFloat
+{
+ public:
+    /* A default of 256 bits will be used unless changed with this function.
+       Note that all existing and cached GMP objects will be resized to the
+       specified precision (which can be a somewhat heavy operation).
+    */
+    static void setDefaultMantissaBits(unsigned long bits);
+
+    static unsigned long getCurrentDefaultMantissaBits();
+
+    /* The default constructor initializes the object to the value 0.
+       It's efficient to instantiate such zero-initialized objects because
+       all of them will share the same mpfr data. (Also any object initialized
+       with or assigned the explicit value of zero will also share that one
+       mpfr data.) Thus multiple zero-initialized MpfrFloat instances won't
+       consume significant amounts of memory (until they are modified to
+       contain some other value, of course).
+
+       Important caveat:
+       ----------------
+       Note that initializing an MpfrFloat object with, for example, 0.1 will
+       suffer from accuracy problems (at least if the MpfrFloat object has
+       more mantissa bits than a double). The C++ double value 0.1 has only
+       53 mantissa bits, while the MpfrFloat object usually has more. If the
+       MpfrFloat object is initialized with a double, only that many bits of
+       accuracy will end up in the value of the MpfrFloat object. This can
+       create significant rounding/accuracy problems in some cases.
+       If you need to initialize the MpfrObject with some value (which cannot
+       be represented accurately by base-2 floating point numbers, eg. 0.1)
+       at full mantissa precision, you have to use parseValue("0.1") instead,
+       rather than relying on the constructor taking a double type value.
+    */
+    MpfrFloat();
+    MpfrFloat(double value);
+    MpfrFloat(long double value);
+    MpfrFloat(long value);
+    MpfrFloat(int value);
+    MpfrFloat(const char* value, char** endptr);
+
+    ~MpfrFloat();
+
+    MpfrFloat(const MpfrFloat&);
+
+    MpfrFloat& operator=(const MpfrFloat&);
+    MpfrFloat& operator=(double value);
+    MpfrFloat& operator=(long double value);
+    MpfrFloat& operator=(long value);
+    MpfrFloat& operator=(int value);
+    //MpfrFloat& operator=(const char* value);
+
+    void parseValue(const char* value);
+    void parseValue(const char* value, char** endptr);
+
+
+    /* This function can be used to retrieve the raw mpfr_t data structure
+       used by this object. (The template trick is used to avoid a dependency
+       of this header file with <mpfr.h>.)
+       In other words, it can be called like:
+
+         mpfr_t raw_mpfr_data;
+         floatValue.get_raw_mpfr_data(raw_mpfr_data);
+
+       Note that the returned mpfr_t should be considered as read-only and
+       not be modified from the outside because it may be shared among
+       several objects. If the calling code needs to modify the data, it
+       should copy it for itself first with the appropriate MPFR library
+       functions.
+     */
+    template<typename Mpfr_t>
+    void get_raw_mpfr_data(Mpfr_t& dest_mpfr_t);
+
+
+    /* Note that the returned char* points to an internal (shared) buffer
+       which will be valid until the next time this function is called
+       (by any object).
+    */
+    const char* getAsString(unsigned precision) const;
+
+    bool isInteger() const;
+    long toInt() const;
+    double toDouble() const;
+
+    MpfrFloat& operator+=(const MpfrFloat&);
+    MpfrFloat& operator+=(double);
+    MpfrFloat& operator-=(const MpfrFloat&);
+    MpfrFloat& operator-=(double);
+    MpfrFloat& operator*=(const MpfrFloat&);
+    MpfrFloat& operator*=(double);
+    MpfrFloat& operator/=(const MpfrFloat&);
+    MpfrFloat& operator/=(double);
+    MpfrFloat& operator%=(const MpfrFloat&);
+
+    void negate();
+    void abs();
+
+    MpfrFloat operator+(const MpfrFloat&) const;
+    MpfrFloat operator+(double) const;
+    MpfrFloat operator-(const MpfrFloat&) const;
+    MpfrFloat operator-(double) const;
+    MpfrFloat operator*(const MpfrFloat&) const;
+    MpfrFloat operator*(double) const;
+    MpfrFloat operator/(const MpfrFloat&) const;
+    MpfrFloat operator/(double) const;
+    MpfrFloat operator%(const MpfrFloat&) const;
+
+    MpfrFloat operator-() const;
+
+    bool operator<(const MpfrFloat&) const;
+    bool operator<(double) const;
+    bool operator<=(const MpfrFloat&) const;
+    bool operator<=(double) const;
+    bool operator>(const MpfrFloat&) const;
+    bool operator>(double) const;
+    bool operator>=(const MpfrFloat&) const;
+    bool operator>=(double) const;
+    bool operator==(const MpfrFloat&) const;
+    bool operator==(double) const;
+    bool operator!=(const MpfrFloat&) const;
+    bool operator!=(double) const;
+
+    static MpfrFloat log(const MpfrFloat&);
+    static MpfrFloat log2(const MpfrFloat&);
+    static MpfrFloat log10(const MpfrFloat&);
+    static MpfrFloat exp(const MpfrFloat&);
+    static MpfrFloat exp2(const MpfrFloat&);
+    static MpfrFloat exp10(const MpfrFloat&);
+    static MpfrFloat cos(const MpfrFloat&);
+    static MpfrFloat sin(const MpfrFloat&);
+    static MpfrFloat tan(const MpfrFloat&);
+    static MpfrFloat sec(const MpfrFloat&);
+    static MpfrFloat csc(const MpfrFloat&);
+    static MpfrFloat cot(const MpfrFloat&);
+    static void sincos(const MpfrFloat&, MpfrFloat& sin, MpfrFloat& cos);
+    static MpfrFloat acos(const MpfrFloat&);
+    static MpfrFloat asin(const MpfrFloat&);
+    static MpfrFloat atan(const MpfrFloat&);
+    static MpfrFloat atan2(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat hypot(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat cosh(const MpfrFloat&);
+    static MpfrFloat sinh(const MpfrFloat&);
+    static MpfrFloat tanh(const MpfrFloat&);
+    static MpfrFloat acosh(const MpfrFloat&);
+    static MpfrFloat asinh(const MpfrFloat&);
+    static MpfrFloat atanh(const MpfrFloat&);
+    static MpfrFloat sqrt(const MpfrFloat&);
+    static MpfrFloat cbrt(const MpfrFloat&);
+    static MpfrFloat root(const MpfrFloat&, unsigned long root);
+    static MpfrFloat pow(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat pow(const MpfrFloat&, long exponent);
+    static MpfrFloat abs(const MpfrFloat&);
+    static MpfrFloat dim(const MpfrFloat&, const MpfrFloat&);
+    static MpfrFloat round(const MpfrFloat&);
+    static MpfrFloat ceil(const MpfrFloat&);
+    static MpfrFloat floor(const MpfrFloat&);
+    static MpfrFloat trunc(const MpfrFloat&);
+
+    static MpfrFloat parseString(const char* str, char** endptr);
+
+    // These values are cached (and recalculated every time the mantissa bits
+    // change), so it's efficient to call these repeatedly:
+    static MpfrFloat const_pi();
+    static MpfrFloat const_e();
+    static MpfrFloat const_log2();
+    static MpfrFloat someEpsilon();
+
+
+ private:
+    struct MpfrFloatData;
+    class MpfrFloatDataContainer;
+
+    MpfrFloatData* mData;
+
+    enum DummyType { kNoInitialization };
+    MpfrFloat(DummyType);
+    MpfrFloat(MpfrFloatData*);
+
+    void copyIfShared();
+    static MpfrFloatDataContainer& mpfrFloatDataContainer();
+
+    friend MpfrFloat operator+(double lhs, const MpfrFloat& rhs);
+    friend MpfrFloat operator-(double lhs, const MpfrFloat& rhs);
+};
+
+MpfrFloat operator+(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator-(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator*(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator/(double lhs, const MpfrFloat& rhs);
+MpfrFloat operator%(double lhs, const MpfrFloat& rhs);
+
+inline bool operator<(double lhs, const MpfrFloat& rhs) { return rhs > lhs; }
+inline bool operator<=(double lhs, const MpfrFloat& rhs) { return rhs >= lhs; }
+inline bool operator>(double lhs, const MpfrFloat& rhs) { return rhs < lhs; }
+inline bool operator>=(double lhs, const MpfrFloat& rhs) { return rhs <= lhs; }
+inline bool operator==(double lhs, const MpfrFloat& rhs) { return rhs == lhs; }
+inline bool operator!=(double lhs, const MpfrFloat& rhs) { return rhs != lhs; }
+
+// This function takes into account the value of os.precision()
+std::ostream& operator<<(std::ostream& os, const MpfrFloat& value);
+
+#endif
index b431ef753e66ddcbcaa88465d390468a1b30a98c..ea574f5bd2744c53c26ab65ede94ce6be6110d0d 100644 (file)
 #include <deal.II/lac/vector.h>
 
 #ifdef HAVE_FUNCTIONPARSER
-#  include <fparser.h>
+namespace fparser
+{
+#  include <fparser.hh>
+}
 #else
 
 namespace fparser
@@ -128,7 +131,8 @@ void FunctionParser<dim>::initialize (const std::string   &variables,
                                        // problems with the number of
                                        // variables...
     }
-
+/*
+TODO: Remove or port to fparser 4.5
                                    // Now we define how many variables
                                    // we expect to read in.  We
                                    // distinguish between two cases:
@@ -153,6 +157,7 @@ void FunctionParser<dim>::initialize (const std::string   &variables,
                ExcDimensionMismatch(n_vars,fp[0].NVars()));
 
                                    // Now set the initialization bit.
+*/
   initialized = true;
 }
 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.