diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
commit | ef962f6008f25ab7cbd4ca21bcc72b97a1e2d76f (patch) | |
tree | 8149bee93d1a3f91d4503bfb3853adac4af0a85e /fparser |
Imported Upstream version 0.0.34
Diffstat (limited to 'fparser')
-rw-r--r-- | fparser/CMakeLists.txt | 29 | ||||
-rw-r--r-- | fparser/docs/fparser.html | 1863 | ||||
-rw-r--r-- | fparser/docs/gpl.txt | 674 | ||||
-rw-r--r-- | fparser/docs/lgpl.txt | 165 | ||||
-rw-r--r-- | fparser/docs/style.css | 80 | ||||
-rw-r--r-- | fparser/examples/example.cc | 55 | ||||
-rw-r--r-- | fparser/examples/example2.cc | 85 | ||||
-rw-r--r-- | fparser/extrasrc/fp_identifier_parser.inc | 379 | ||||
-rw-r--r-- | fparser/extrasrc/fp_opcode_add.inc | 7696 | ||||
-rw-r--r-- | fparser/extrasrc/fpaux.hh | 1238 | ||||
-rw-r--r-- | fparser/extrasrc/fptypes.hh | 288 | ||||
-rw-r--r-- | fparser/fparser.cc | 3800 | ||||
-rw-r--r-- | fparser/fparser.hh | 223 | ||||
-rw-r--r-- | fparser/fparser.pro | 35 | ||||
-rw-r--r-- | fparser/fparser_gmpint.hh | 15 | ||||
-rw-r--r-- | fparser/fparser_mpfr.hh | 15 | ||||
-rw-r--r-- | fparser/fpconfig.hh | 88 | ||||
-rw-r--r-- | fparser/fpoptimizer.cc | 11745 | ||||
-rw-r--r-- | fparser/mpfr/GmpInt.cc | 710 | ||||
-rw-r--r-- | fparser/mpfr/GmpInt.hh | 148 | ||||
-rw-r--r-- | fparser/mpfr/MpfrFloat.cc | 976 | ||||
-rw-r--r-- | fparser/mpfr/MpfrFloat.hh | 206 |
22 files changed, 30513 insertions, 0 deletions
diff --git a/fparser/CMakeLists.txt b/fparser/CMakeLists.txt new file mode 100644 index 0000000..434218a --- /dev/null +++ b/fparser/CMakeLists.txt @@ -0,0 +1,29 @@ + +# define build type +SET( CMAKE_BUILD_TYPE Release ) + +PROJECT(fparser CXX) + +cmake_minimum_required(VERSION 2.8) + +# default +set(LIB_VERSION_MAJOR 4) +set(LIB_VERSION_MINOR 5) +set(LIB_VERSION_PATCH 1) +set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}) + +set(VERSION "v${LIB_VERSION_STRING}") + +#set(HEADERS fparser.hh fpconfig.hh fptypes.hh) +set(SOURCES fparser.cc fpoptimizer.cc) + +remove(CMAKE_CXX_FLAGS -Dfparser_EXPORTS) + +ADD_LIBRARY(fparser SHARED ${SOURCES}) + +set_target_properties(fparser PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_MAJOR}) + +INSTALL(TARGETS fparser DESTINATION lib${LIB_SUFFIX}) + +INSTALL(FILES fparser.hh DESTINATION include) + diff --git a/fparser/docs/fparser.html b/fparser/docs/fparser.html new file mode 100644 index 0000000..ffc73f4 --- /dev/null +++ b/fparser/docs/fparser.html @@ -0,0 +1,1863 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> + <link href="style.css" rel="stylesheet" type="text/css" title="normal" media=screen> + <title>Function Parser for C++ v4.5.1 : Documentation</title> +</head> + +<body> +<h1>Function Parser for C++ v4.5.1 </h1> + +<p>Authors: Juha Nieminen +(<a href="http://iki.fi/warp/">http://iki.fi/warp/</a>), +Joel Yliluoma +(<a href="http://iki.fi/bisqwit/">http://iki.fi/bisqwit/</a>). + +<p>The usage license of this library is located at the end of this file. + +<h2>Table of contents:</h2> + +<ul> + <li><a href="#whatsnew">What's new</a> + <li><a href="#preface">Preface</a> + <li><a href="#usage">Usage</a> + <ul> + <li><a href="#parsertypes">Parser types</a> + <li><a href="#configuring">Configuring the compilation</a> + <li><a href="#copyassignment">Copying and assignment</a> + <li><a href="#shortdesc">Short descriptions of FunctionParser methods</a> + <li><a href="#longdesc">Long descriptions of FunctionParser methods</a> + <ul> + <li><a href="#longdesc_Parse"><code>Parse()</code></a> + <li><a href="#longdesc_setDelimiterChar"><code>setDelimiterChar()</code></a> + <li><a href="#longdesc_ErrorMsg"><code>ErrorMsg()</code></a> + <li><a href="#longdesc_GetParseErrorType"><code>GetParseErrorType()</code></a> + <li><a href="#longdesc_Eval"><code>Eval()</code></a> + <li><a href="#longdesc_EvalError"><code>EvalError()</code></a> + <li><a href="#longdesc_Optimize"><code>Optimize()</code></a> + <li><a href="#longdesc_AddConstant"><code>AddConstant()</code></a> + <li><a href="#longdesc_AddUnit"><code>AddUnit()</code></a> + <li><a href="#longdesc_AddFunction1"><code>AddFunction()</code></a> (C++ function) + <li><a href="#longdesc_AddFunction2"><code>AddFunction()</code></a> (FunctionParser) + <li><a href="#longdesc_AddFunction3"><code>AddFunctionWrapper()</code></a> + <li><a href="#longdesc_RemoveIdentifier"><code>RemoveIdentifier()</code></a> + <li><a href="#longdesc_ParseAndDeduceVariables"><code>ParseAndDeduceVariables()</code></a> + </ul> + <li><a href="#functionobjects">Specialized function objects</a> + <li><a href="#base">FunctionParserBase</a> + </ul> + <li>Syntax + <ul> + <li><a href="#literals">Numeric literals</a> + <li><a href="#identifiers">Identifier names</a> + <li><a href="#functionsyntax">The function string syntax</a> + <li><a href="#inlinevars">Inline variables</a> + <li><a href="#whitespace">Whitespace</a> + </ul> + <li>Miscellaneous + <ul> + <li><a href="#fpaccuracy">About floating point accuracy</a> + <li><a href="#evaluationchecks">About evaluation-time checks</a> + <li><a href="#threadsafety">About thread safety</a> + <li><a href="#tipsandtricks">Tips and tricks</a> + <li><a href="#contact">Contacting the author</a> + </ul> +<!-- <li><a href="#algorithm">The algorithm used in the library</a> --> + <li><a href="#license">Usage license</a> +</ul> + +<a name="whatsnew"></a> +<h2>What's new</h2> + +<p>What's new in v4.5.1 + <ul> + <li>Reverted the automatic C++11 detection to a precompiler macro setting + (<code>FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS</code>) because not all + compilers yet fully support the C++11 math functions. + <li>Fixed a potential duplicate symbol problem that happens with explicit + template instantiations. + </ul> + +<p>What's new in v4.5 + <ul> + <li>Removed support for the <code>"eval()"</code> function from the + supported syntax. (This function was too dangerous, too difficult to + maintain internally, not very useful, and more or less a gimmick in + the first place.) + <li>Removed several of the conditional compiling macro definitions, namely + <code>FP_SUPPORT_TR1_MATH</code>, <code>FP_ENABLE_EVAL</code>, + <code>FP_EVAL_MAX_REC_LEVEL</code>, <code>FP_NO_EVALUATION_CHECKS</code> + and <code>FP_EPSILON</code>. + <li>The epsilon value used in comparisons is now set with a member function + of FunctionParser (which allows setting different values for different + versions of the parser). + <li>The math functions previously turned on with + <code>FP_SUPPORT_TR1_MATH</code> are now automatically used if + <code>__cplusplus</code> indicates that C++11 is in use. + <li>Fixed some compilation problems with clang++. + </ul> + + + +<!-- -------------------------------------------------------------------- --> +<a name="preface"></a> +<h2>Preface</h2> + +<p>This C++ library offers a class which can be used to parse and evaluate a +mathematical function from a string (which might be eg. requested from the +user). The syntax of the function string is similar to mathematical expressions +written in C/C++ (the exact syntax is specified later in this document). +The function can then be evaluated with different values of variables. + +<p>For example, a function like "<code>sin(sqrt(x*x+y*y))</code>" can be +parsed from a string (either <code>std::string</code> or a C-style string) +and then evaluated with different values of <code>x</code> and <code>y</code>. +This library can be useful for evaluating user-inputted functions, or in +some cases interpreting mathematical expressions in a scripting language. + +<p>This library aims for maximum speed in both parsing and evaluation, while +keeping maximum portability. The library should compile and work with any +standard-conforming C++ compiler. + +<p>Different numerical types are supported: <code>double</code>, + <code>float</code>, <code>long double</code>, <code>long int</code>, + <code>std::complex</code> (of types <code>double</code>, + <code>float</code> and <code>long double</code>), + multiple-precision floating point numbers using the MPFR library, and + arbitrary precision integers using the GMP library. (Note that it's + not necessary for these two libraries to exist in the system in order + to use the Function Parser library with the other numerical types. Support + for these libraries is optionally compiled in using preprocessor settings.) + + +<!-- -------------------------------------------------------------------- --> +<a name="usage"></a> +<h2>Usage</h2> + +<p>To use the <code>FunctionParser</code> class, you have to include +<code>"fparser.hh"</code> in your source code files which use the +<code>FunctionParser</code> class. + +<p>If you are going to use the MPFR version of the library, you need to +include <code>"fparser_mpfr.hh"</code>. If you are going to use the GMP +version of the library, you need to include <code>"fparser_gmpint.hh"</code>. +(Note that support for these special parser versions needs to be specified +with preprocessor macros. See the <a href="#parsertypes">documentation +below</a> for details.) + +<p>When compiling, you have to compile <code>fparser.cc</code> and +<code>fpoptimizer.cc</code> and link them to the main program. In many +developement environments it's enough to add those two files to your +current project (usually header files don't have to be added to the +project for the compilation to work). + +<p>If you are going to use the MPFR or the GMP versions of the library, +you also need to add <code>mpfr/MpfrFloat.cc</code> or +<code>mpfr/GmpInt.cc</code> files to your project, respectively. Otherwise +they should not be added to the project. + +<p>Note that part of the library source code is inside several +<code>.inc</code> files inside the <code>extrasrc</code> subdirectory +(these files contain auto-generated C++ code), provided in the library +package. These files are used by <code>fparser.cc</code> and don't need +to be added explicitly to the project in most IDEs (such as Visual Studio). +Basically, you don't need to do anything with these files, other than keep +them in the <code>extrasrc</code> subdirectory. + +<p>Simple usage example of the library: + +<pre> + FunctionParser fp; + fp.Parse("sqrt(x*x + y*y)", "x,y"); + double variables[2] = { 1.5, 2.9 }; + double result = fp.Eval(variables); +</pre> + +<!-- -------------------------------------------------------------------- --> +<a name="parsertypes"></a> +<h3>Parser types</h3> + +<p>Different versions of the function parser class are supported, using + different floating point or integral types for function evaluation. + +<p>All the classes other than the default one, <code>FunctionParser</code>, + need to be enabled at compile time by defining a preprocessor macro + (specified below) either in the <code>fpconfig.hh</code> file or your + compiler settings. (The reason for this is that every parser that is + included in the compilation process will make the compilation slower + and increase the size of the executable, so they are compiled only on + demand. Also, the GMP and MPFR versions of the parser require for those + libraries to be available, which is often not the case.) + +<p>Note that if you try to use the other class types without enabling them + with the correspondent preprocessor macro, you will get a linker error + (rather than a compiler error) because those classes will not have been + instantiated when the library was compiled. + +<p>Currently the <code>Optimize()</code> method works only for the + <code>FunctionParser</code>, <code>FunctionParser_f</code> and + <code>FunctionParser_ld</code> classes. For the other types it can be + called but it does nothing. + +<p> +<dl> + <dt><p><code>FunctionParser</code></dt> + <dd> + <p>This is the default class, which uses <code>double</code> as its + numerical type. This is the only class enabled by default. + <p>If you use some other type than this one, and you don't want this + version of the class compiled into the library, you can define the + preprocessor macro <code>FP_DISABLE_DOUBLE_TYPE</code>. + </dd> + + <dt><p><code>FunctionParser_f</code></dt> + <dd> + <p>This parser uses <code>float</code> as its numerical type. + <p>The <code>FP_SUPPORT_FLOAT_TYPE</code> preprocessor macro needs to be + defined for this class to be enabled. + </dd> + + <dt><p><code>FunctionParser_ld</code></dt> + <dd> + <p>This parser uses <code>long 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 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<double></code>, + <code>std::complex<float></code> and + <code>std::complex<long double></code> as their numerical type, + respectively. + <p>The preprocessor macros to enable them are + <code>FP_SUPPORT_COMPLEX_DOUBLE_TYPE</code>, + <code>FP_SUPPORT_COMPLEX_FLOAT_TYPE</code> and + <code>FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE</code>. + <p>If <code>FunctionParser_cld</code> is used, the + <code>FP_USE_STRTOLD</code> macro should also be defined if the compiler + supports the <code>strtold()</code> function. + </dd> + + <dt><p><code>FunctionParser_mpfr</code></dt> + <dd> + <p>This parser uses <code>MpfrFloat</code> as its numerical type. + <p>The <code>FP_SUPPORT_MPFR_FLOAT_TYPE</code> preprocessor macro needs + to be defined for this class to be enabled. + <p>Note that to use this version of the parser, + <code>"fparser_mpfr.hh"</code> needs to be included. + <p><code>MpfrFloat</code> is an auxiliary class which uses the MPFR + library for multiple-precision floating point numbers. The class + behaves largely like a floating point type, and is declared in the + <code>mpfr/MpfrFloat.hh</code> file (see that file for info about + the public interface of the class). + <p>If this class is enabled, <code>mpfr/MpfrFloat.cc</code> + needs to be compiled into the project, as well as the GMP and MPFR + libraries. (With the gcc compiler this means using the linker options + "<code>-lgmp -lmpfr</code>".) + </dd> + + <dt><p><code>FunctionParser_gmpint</code></dt> + <dd> + <p>This parser uses <code>GmpInt</code> as its numerical type. + <p>The <code>FP_SUPPORT_GMP_INT_TYPE</code> preprocessor macro needs + to be defined for this class to be enabled. + <p>Note that to use this version of the parser, + <code>"fparser_gmpint.hh"</code> needs to be included. + <p><code>GmpInt</code> is an auxiliary class which uses the GMP + library for arbitrary-precision integer numbers. The class + behaves largely like an integer type, and is declared in the + <code>mpfr/GmpInt.hh</code> file (see that file for info about + the public interface of the class). + <p>If this class is enabled, <code>mpfr/GmpInt.cc</code> + needs to be compiled into the project, as well as the GMP library. + <p>This version of the class also uses a reduced version of the syntax, + like the <code>long int</code> version. + <p><b>Note:</b> Since there's no upper limit to the size of GMP + integers, this version of the class should be used with care in + situations where malicious users might be able to exploit it to + make the program run out of memory. An example of this would be + a server-side application usable through the WWW. + </dd> +</dl> + +<p>Note that these different classes are completely independent and + instances of different classes cannot be given to each other using the + <code>AddFunction()</code> method. Only objects of the same type can + be given to that method. + +<p>The rest of the documentation assumes that <code>FunctionParser</code> + (which uses the <code>double</code> type) is used. The usage of the other + classes is identical except that <code>double</code> is replaced with the + correspondent type used by that class. (In other words, whenever the + rest of this documentation uses the type keyword '<code>double</code>', + the correspondent type should be used instead, when using another version + of the class.) + +<!-- -------------------------------------------------------------------- --> +<a name="configuring"></a> +<h3>Configuring the compilation</h3> + +<p>There is a set of precompiler options in the <code>fpconfig.hh</code> file +which can be used for setting certain features on or off. All of these options +can also be specified from the outside, using precompiler settings (eg. the +<code>-D</code> option in gcc), and thus it's not necessary to modify this +file. + +<dl> + <dt><p><code>FP_USE_STRTOLD</code> : (Default off)</dt> + <dd><p>If <code>FunctionParser_ld</code> or <code>FunctionParser_cld</code> + are used, this preprocessor macro should be defined if the compiler + supports the (C99) function <code>strtold()</code>. If not, then numeric + literals will be parsed with double precision only, which in most + systems is less accurate than long double precision, which will cause + small rounding errors. (This setting has no effect on the other parser + types.) Note that <code>strtold()</code> will also be automatically used + if <code>__cplusplus</code> indicates that C++11 is in use. + </dd> + + <dt><p><code>FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS</code> : (Default off)</dt> + <dd><p>Use C++11 math functions where applicable. (These are ostensibly + faster than the equivalent formulas using C++98 math functions.) Note + that not all compilers support these functions (even if they otherwise + support C++11.) + + <dt><p><code>FP_SUPPORT_OPTIMIZER</code> : (Default on)</dt> + <dd><p>If you are not going to use the <code>Optimize()</code> method, you + can comment this line out to speed-up the compilation a bit, as + well as making the binary a bit smaller. (<code>Optimize()</code> can + still be called, but it will not do anything.) + + <p>You can also disable the optimizer by specifying the + <code>FP_NO_SUPPORT_OPTIMIZER</code> precompiler constant in your + compiler settings. + </dd> + + <dt><p><code>FP_USE_THREAD_SAFE_EVAL</code> : (Default off)</dt> + <dd><p>Define this precompiler constant to make <code>Eval()</code> + thread-safe. Refer to the <a href="#threadsafety">thread safety + section</a> later in this document for more information. + Note that defining this may make <code>Eval()</code> slightly slower. + <p>Also note that the MPFR and GMP versions of the library cannot be + made thread-safe, and thus this setting has no effect on them. + </dd> + + <dt><p><code>FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA</code> : (Default off)</dt> + <dd><p>This is like the previous, but makes <code>Eval()</code> use the + <code>alloca()</code> function (instead of <code>std::vector</code>). + This will make it faster, but the <code>alloca()</code> + function is not standard and thus not supported by all compilers. + </dd> +</dl> + + +<!-- -------------------------------------------------------------------- --> +<a name="copyassignment"></a> +<h3>Copying and assignment</h3> + +<p>The class implements a safe copy constructor and assignment operator. + +<p>It uses the copy-on-write technique for efficiency. This means that + when copying or assigning a FunctionParser instance, the internal data + (which in some cases can be quite lengthy) is not immediately copied + but only when the contents of the copy (or the original) are changed. + +<p>This means that copying/assigning is a very fast operation, and if + the copies are never modified then actual data copying never happens + either. + +<p>The <code>Eval()</code> and <code>EvalError()</code> methods of the +copy can be called without the internal data being copied. + +<p>Calling <code>Parse()</code>, <code>Optimize()</code> or the user-defined +constant/function adding methods will cause a deep-copy. + + +<!-- -------------------------------------------------------------------- --> +<a name="shortdesc"></a> +<h3>Short descriptions of FunctionParser methods</h3> + +<pre> +int Parse(const std::string& Function, const std::string& Vars, + bool useDegrees = false); + +int Parse(const char* Function, const std::string& 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>>0</code>. + +<hr> +<pre> +void Optimize(); +</pre> + +<p>Tries to optimize the bytecode for faster evaluation. + +<hr> +<pre> +bool AddConstant(const std::string& 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& 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& 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& name, FunctionParser&); +</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& 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& 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); +</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& Function, const std::string& Vars, + bool useDegrees = false); + +int Parse(const char* Function, const std::string& 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>'"'</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& 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& 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& 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> 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> 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& name, FunctionParser&); +</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<typename DerivedWrapper> +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& 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 = FunctionParser();</code>") + +<hr> +<a name="longdesc_ParseAndDeduceVariables"></a> +<pre> +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); +</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><</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><</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<MyFunctionWrapper*> + (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<typename Value_t> +void someFunction(FunctionParserBase<Value_t>& 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<typename Value_t> +class SpecializedParser: public FunctionParserBase<Value_t> +{ + ... +}; +</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) * x</code>" + is not the same thing as "<code>2+5i * x</code>". The latter + would be equivalent to "<code>2 + (5i * 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<B A<=B<br>A!=B A>B A>=B</code></td> + <td>comparison between A and B (result is either 0 or 1)</td> + </tr><tr> + <td><code>A&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>></code>" or +"<code><</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>B, the result is A, else B.</td> +</tr><tr> + <td><code>min(A,B)</code></td> + <td>If A<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>"<variable name> := <expression>; <function>"</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><function></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 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 double</code> type. + +<p>This is especially important if you are using the <code>MpfrFloat</code> +type (in which case its string-parsing constructor or its +<code>ParseValue()</code> or <code>parseString()</code> member functions +should be used instead of using numerical literals). + +<a name="evaluationchecks"></a> +<h3>About evaluation-time checks</h3> + +<p><code>FunctionParser::Eval()</code> will perform certain sanity +checks before performing certain operations. For example, before calling the +<code>sqrt</code> function, it will check if the parameter is negative, and +if so, it will set the proper error code instead of calling the function. +These checks include: + +<ul> + <li>Division by (the exact value of) zero. + <li>Square root of a negative value. + <li>Logarithm of a non-positive value. + <li>Arcsine or arccosine of a value not in the range [-1, 1]. (This includes + hyperbolic versions of the functions.) +</ul> + +<p>However, the library <em>can not</em> guarantee that it will catch all +possible floating point errors before performing them, because this is +impossible to do with standard C++. For example, dividing a very large +value by a value which is very close to zero, or calculating the logarithm +of a very small value may overflow the result, as well as multiplying two +very large values. Raising a negative number to a non-integral power may +cause a <em>NaN</em> result, etc. + +<p>As a rule of thumb, the library will (by default) detect invalid operations +if they are invalid for a range of values. For example, square root is undefined +for all negative values, and arc sine is undefined only values outside the range +[-1, 1]. In general, operations which are invalid for only one single value +(rather than a contiguous range of values) will not be detected (division by +the exact value of zero is an exception to this rule) nor will +overflow/underflow situations. + +<p>The library cannot guarantee that floating point +errors will never happen during evaluation. This can make the library to +return the floating point values <em>inf</em> and <em>NaN</em>. Moreover, +if floating point errors cause an interrupt in the target computer +architecture and/or when using certain compiler settings, this library +cannot guarantee that it will never happen. + +<p>Note that the optimizer never performs any sanity checks. + + +<!-- -------------------------------------------------------------------- --> +<a name="threadsafety"></a> +<h3>About thread safety</h3> + +<p>None of the member functions of the FunctionParser class are thread-safe. +Most prominently, the <code>Eval()</code> function is not thread-safe. +(In other words, the <code>Eval()</code> function of a single FunctionParser +instance cannot be safely called simultaneously by two threads.) + +<p>There are ways to use this library in a thread-safe way, though. If each +thread uses its own FunctionParser instance, no problems will obviously +happen. Note, however, that if these instances need to be a copy of a given +FunctionParser instance (eg. one where the user has entered a function), +a deep copy of this instance has to be performed for each thread. By +default FunctionParser uses shallow-copying (copy-on-write), which means +that a simple assignment of copy construction will not copy the data itself. +To force a deep copy you can all the <code>ForceDeepCopy()</code> function on +each of the instances of each thread after the assignment or copying has been +done. + +<p>Another possibility is to compile the FunctionParser library so that +its <code>Eval()</code> function will be thread-safe. (This can be done by +defining the <code>FP_USE_THREAD_SAFE_EVAL</code> or the +<code>FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA</code> +precompiler constant.) As long as only one thread calls the other functions +of FunctionParser, the other threads can safely call the <code>Eval()</code> +of this one instance. + +<p>Note, however, that compiling the library like this can make +<code>Eval()</code> slightly slower. (The <code>alloca</code> version, if +supported by the compiler, will not be as slow.) + +<p>Also note that the MPFR and GMP versions of the library cannot be + made thread-safe, and thus this setting has no effect on them. + + +<!-- -------------------------------------------------------------------- --> +<a name="tipsandtricks"></a> +<h3>Tips and tricks</h3> + +<h4>Add constants automatically to all parser objects</h4> + +<p>Often the same constants (such as <em>pi</em> and <em>e</em>) and other +user-defined identifiers (such as units) are always used in all the +<code>FunctionParser</code> objects throughout the program. It would be +troublesome to always have to manually add these constants every time a +new parser object is created. + +<p>There is, however, a simple way to always add these user-defined identifiers +to all instances. Write a class like this: + +<pre> + class ParserWithConsts: public FunctionParser + { + public: + ParserWithConsts() + { + AddConstant("pi", 3.14159265358979323846); + AddConstant("e", 2.71828182845904523536); + } + }; +</pre> + +<p>Now instead of using <code>FunctionParser</code>, always use +<code>ParserWithConsts</code>. It will behave identically except that the +constants (and possibly other user-defined identifiers) will always be +automatically defined. (Objects of this type even survive +<a href="http://en.wikipedia.org/wiki/Object_slicing">slicing</a>, so +they are completely safe to use anywhere.) + + +<!-- -------------------------------------------------------------------- --> +<a name="contact"></a> +<h3>Contacting the author</h3> + +<p>Any comments, bug reports, etc. should be sent to warp@iki.fi + + +<!-- -------------------------------------------------------------------- --> +<!-- +<a name="algorithm"></a> +<h2>The algorithm used in the library</h2> + +<p>The whole idea behind the algorithm is to convert the regular infix +format (the regular syntax for mathematical operations in most languages, +like C and the input of the library) to postfix format. The postfix format +is also called stack arithmetic since an expression in postfix format +can be evaluated using a stack and operating with the top of the stack. + +<p>For example: + +<p><table border=2> +<tr><th>infix</th> <th>postfix</th></tr> +<tr><td><code>2+3</code></td><td><code>2 3 +</code></td></tr> +<tr><td><code>1+2+3</code></td><td><code>1 2 + 3 +</code></td></tr> +<tr><td><code>5*2+8/2</code></td><td><code>5 2 * 8 2 / +</code></td></tr> +<tr><td><code>(5+9)*3</code></td><td><code>5 9 + 3 *</code></td></tr> +</table> + +<p>The postfix notation should be read in this way: + +<p>Let's take for example the expression: <code>5 2 * 8 2 / +</code> +<ul> + <li>Put 5 on the stack + <li>Put 2 on the stack + <li>Multiply the two values on the top of the stack and put the result on + the stack (removing the two old values) + <li>Put 8 on the stack + <li>Put 2 on the stack + <li>Divide the two values on the top of the stack + <li>Add the two values on the top of the stack (which are in this case + the result of 5*2 and 8/2, that is, 10 and 4). +</ul> + +<p>At the end there's only one value in the stack, and that value is the +result of the expression. + +<p>Why stack arithmetic? + +<p>The last example above can give you a hint. + In infix format operators have precedence and we have to use parentheses to +group operations with lower precedence to be calculated before operations +with higher precedence. + This causes a problem when evaluating an infix expression, specially +when converting it to byte code. For example in this kind of expression: + <code>(x+1)/(y+2)</code> +we have to calculate first the two additions before we can calculate the +division. We have to also keep counting parentheses, since there can be +a countless amount of nested parentheses. This usually means that you +have to do some type of recursion. + +<p>The simplest and mostefficient way of calculating this is to convert it +to postfix notation. + The postfix notation has the advantage that you can make all operations +in a straightforward way. You just evaluate the expression from left to +right, applying each operation directly and that's it. There are no +parentheses to worry about. You don't need recursion anywhere. + You have to keep a stack, of course, but that's extremely easily done. +Also you just operate with the top of the stack, which makes it very easy. +You never have to go deeper than 2 items in the stack. + And even better: Evaluating an expression in postfix format is never +slower than in infix format. All the contrary, in many cases it's a lot +faster (eg. because all parentheses are optimized away). + The above example could be expressed in postfix format: + <code>x 1 + y 2 + /</code> + +<p>The good thing about the postfix notation is also the fact that it can +be extremely easily expressed in bytecode form. + You only need a byte value for each operation, for each variable and +to push a constant to the stack. + Then you can interpret this bytecode straightforwardly. You just interpret +it byte by byte, from the beginning to the end. You never have to go back, +make loops or anything. + +<p>This is what makes byte-coded stack arithmetic so fast. +--> + + +<!-- -------------------------------------------------------------------- --> +<a name="license"></a> +<h2>Usage license</h2> + +<p>Copyright © 2003-2011 Juha Nieminen, Joel Yliluoma + +<p>This Library is distributed under the + <a href="http://www.gnu.org/copyleft/lesser.html">Lesser General Public + License</a> (LGPL) version 3. + +</body> +</html> diff --git a/fparser/docs/gpl.txt b/fparser/docs/gpl.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/fparser/docs/gpl.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/fparser/docs/lgpl.txt b/fparser/docs/lgpl.txt new file mode 100644 index 0000000..cca7fc2 --- /dev/null +++ b/fparser/docs/lgpl.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/fparser/docs/style.css b/fparser/docs/style.css new file mode 100644 index 0000000..d5141d3 --- /dev/null +++ b/fparser/docs/style.css @@ -0,0 +1,80 @@ +html +{ + background-color: #E0E0E0; +} + +body +{ + background-color: white; + margin-left: 7%; + margin-top: 16px; + margin-right: 7%; + padding-top: 2em; + padding-left: 7%; + padding-right: 7%; + padding-bottom: 2%; + border-color: black; + border: solid; + border-width: 1px; +} + +h1 +{ + text-align: center; + background-color: #FFEEBB; + padding-bottom: 0.2em; + padding-top: 0.1em; +} + +h2 +{ + background-color: #FFFFCC; + padding-left: 0.5em; +} + +h3 +{ + background-color: #FFFFEE; +} + +blockquote +{ + padding-left: 2em; + padding-right: 2em; + font-style: italic; + background-color: #FFFAF0; +} + +li +{ + padding-top: 0.3em; +} + +pre +{ + background-color: #E8E8E8; + padding-left: 1em; + padding-top: 0.5em; + padding-bottom: 0.5em; +} + +code +{ + font-family: monospace; + color: #900040; +} + +.small +{ + font-size: 80%; +} + +.codecomment +{ + color: green; +} + +.highlight +{ + background: #C0D0FF; +} diff --git a/fparser/examples/example.cc b/fparser/examples/example.cc new file mode 100644 index 0000000..b4ab5f4 --- /dev/null +++ b/fparser/examples/example.cc @@ -0,0 +1,55 @@ +// Simple example file for the function parser
+// ===========================================
+
+/* When running the program, try for example with these values:
+
+f(x) = x^2
+min x: -5
+max x: 5
+step: 1
+
+*/
+
+#include "../fparser.hh"
+
+#include <iostream>
+#include <string>
+
+int main()
+{
+ std::string function;
+ double minx, maxx, step;
+ FunctionParser fparser;
+
+ fparser.AddConstant("pi", 3.1415926535897932);
+
+ while(true)
+ {
+ std::cout << "f(x) = ";
+ std::getline(std::cin, function);
+ if(std::cin.fail()) return 0;
+
+ int res = fparser.Parse(function, "x");
+ if(res < 0) break;
+
+ std::cout << std::string(res+7, ' ') << "^\n"
+ << fparser.ErrorMsg() << "\n\n";
+ }
+
+ std::cout << "min x: ";
+ std::cin >> minx;
+ std::cout << "max x: ";
+ std::cin >> maxx;
+ std::cout << "step: ";
+ std::cin >> step;
+ if(std::cin.fail()) return 0;
+
+ double vals[] = { 0 };
+ for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)
+ {
+ std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)
+ << std::endl;
+ }
+
+ return 0;
+}
diff --git a/fparser/examples/example2.cc b/fparser/examples/example2.cc new file mode 100644 index 0000000..958b9a1 --- /dev/null +++ b/fparser/examples/example2.cc @@ -0,0 +1,85 @@ +// Simple example file for the function parser +// =========================================== +/* Note that the library has to be compiled with + FP_SUPPORT_FLOAT_TYPE, FP_SUPPORT_LONG_DOUBLE_TYPE and + FP_SUPPORT_LONG_INT_TYPE + preprocessor macros defined for this example to work. + + Try with these input values with the different floating point parser + types to see the difference in accuracy: + +f(x) = x + 1.234567890123456789 +min x: 0 +max x: 2 +step: 1 +*/ + +#include "../fparser.hh" + +#include <iostream> +#include <iomanip> +#include <string> + +template<typename Parser> +void runExample(const char* valueTypeName) +{ + typedef typename Parser::value_type Value_t; + + std::cout << "Using " << valueTypeName << " parser." << std::endl; + + Parser fparser; + std::string function; + Value_t minx, maxx, step; + + fparser.AddConstant("pi", Value_t(3.1415926535897932)); + + std::cin.ignore(); + while(true) + { + std::cout << "f(x) = "; + std::getline(std::cin, function); + if(std::cin.fail()) return; + + int res = fparser.Parse(function, "x"); + if(res < 0) break; + + std::cout << std::string(res+7, ' ') << "^\n" + << fparser.ErrorMsg() << "\n\n"; + } + + std::cout << "min x: "; + std::cin >> minx; + std::cout << "max x: "; + std::cin >> maxx; + std::cout << "step: "; + std::cin >> step; + if(std::cin.fail()) return; + + Value_t vals[] = { 0 }; + for(vals[0] = minx; vals[0] <= maxx; vals[0] += step) + { + std::cout << std::setprecision(20); + std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals) + << std::endl; + } +} + +int main() +{ + int choice = 0; + do + { + std::cout << "1 = double, 2 = float, 3 = long double, 4 = long int: "; + std::cin >> choice; + } while(choice < 1 || choice > 4); + + switch(choice) + { + case 1: runExample<FunctionParser>("double"); break; + case 2: runExample<FunctionParser_f>("float"); break; + case 3: runExample<FunctionParser_ld>("long double"); break; + case 4: runExample<FunctionParser_li>("long int"); break; + } + + return 0; +} diff --git a/fparser/extrasrc/fp_identifier_parser.inc b/fparser/extrasrc/fp_identifier_parser.inc new file mode 100644 index 0000000..7489fd0 --- /dev/null +++ b/fparser/extrasrc/fp_identifier_parser.inc @@ -0,0 +1,379 @@ +/* NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + Part of this file is generated code (by using the make_function_name_parser +utility, found in the development version of this library). It's not intended +to be modified by hand. +*/ + + unsigned nameLength = 0; + const unsigned maximumNameLength = 0x80000000U-8; + /* + Due to the manner the identifier lengths are returned from + the readOpcode() function, the maximum supported length for + identifiers is 0x7FFFFFFF bytes. We minus 8 here to add some + buffer, because of the multibyteness of UTF-8. + Function names are limited to 0xFFFF bytes instead, but because + function names that long just are not defined, the point is moot. + */ + const unsigned char* const uptr = (const unsigned char*) input; + typedef signed char schar; + while(likely(nameLength < maximumNameLength)) + { + unsigned char byte = uptr[nameLength+0]; + /* Handle the common case of A-Za-z first */ + if(byte >= 0x40) + { + if(byte < 0x80) // 0x40..0x7F - most common case + { + // Valid characters in 40..7F: A-Za-z_ + // Valid bitmask for 40..5F: 01111111111111111111111111100001 + // Valid bitmask for 60..7F: 01111111111111111111111111100000 + if(sizeof(unsigned long) == 8) + { + const unsigned n = sizeof(unsigned long)*8-32; + // ^ avoids compiler warning when not 64-bit + unsigned long masklow6bits = 1UL << (byte & 0x3F); + if(masklow6bits & ~((1UL << 0) | (0x0FUL << (0x1B )) + | (1UL << n) | (0x1FUL << (0x1B+n)))) + { ++nameLength; continue; } + } + else + { + unsigned masklow5bits = 1 << (byte & 0x1F); + if((masklow5bits & ~(1 | (0x1F << 0x1B))) || byte == '_') + { ++nameLength; continue; } + } + break; + } + if(byte < 0xF0) + { + if(byte < 0xE0) + { + if(byte < 0xC2) break; // 0x80..0xC1 + if(byte == 0xC2 && uptr[nameLength+1]==0xA0) break; // skip nbsp + // C2-DF - next common case when >= 0x40 + // Valid sequence: C2-DF 80-BF + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + nameLength += 2; + continue; + } + if(byte == 0xE0) // E0 + { + // Valid sequence: E0 A0-BF 80-BF + if((unsigned char)(uptr[nameLength+1] - 0xA0) > (0xBF-0xA0)) break; + } + else + { + if(byte == 0xED) break; // ED is invalid + // Valid sequence: E1-EC 80-BF 80-BF + // And: EE-EF 80-BF 80-BF + if(byte == 0xE2) + { + // break on various space characters + if(uptr[nameLength+1] == 0x80 + && (schar(uptr[nameLength+2]) <= schar(0x8B) + || (uptr[nameLength+2] == 0xAF))) break; + if(uptr[nameLength+1] == 0x81 + && uptr[nameLength+2] == 0x9F) break; + } else + if(byte == 0xE3 && uptr[nameLength+1] == 0x80 + && uptr[nameLength+2] == 0x80) break; // this too + + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + } + if(schar(uptr[nameLength+2]) > schar(0xBF)) break; + nameLength += 3; + continue; + } + if(byte == 0xF0) // F0 + { + // Valid sequence: F0 90-BF 80-BF 80-BF + if((unsigned char)(uptr[nameLength+1] - 0x90) > (0xBF-0x90)) break; + } + else + { + if(byte > 0xF4) break; // F5-FF are invalid + if(byte == 0xF4) // F4 + { + // Valid sequence: F4 80-8F + if(schar(uptr[nameLength+1]) > schar(0x8F)) break; + } + else + { + // F1-F3 + // Valid sequence: F1-F3 80-BF 80-BF 80-BF + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + } + } + if(schar(uptr[nameLength+2]) > schar(0xBF)) break; + if(schar(uptr[nameLength+3]) > schar(0xBF)) break; + nameLength += 4; + continue; + } + if(nameLength > 0) + { + if(sizeof(unsigned long) == 8) + { + // Valid bitmask for 00..1F: 00000000000000000000000000000000 + // Valid bitmask for 20..3F: 00000000000000001111111111000000 + const unsigned n = sizeof(unsigned long)*8-32; + // ^ avoids compiler warning when not 64-bit + unsigned long masklow6bits = 1UL << byte; + if(masklow6bits & (((1UL << 10)-1UL) << (16+n))) + { ++nameLength; continue; } + } + else + { + if(byte >= '0' && byte <= '9') + { ++nameLength; continue; } + } + } + break; + } + + /* This function generated with make_function_name_parser.cc */ +#define lO l3 lH +#define lN switch( +#define lM l4 lH +#define lL if('i' l5 +#define lK 'n' l5 +#define lJ 0x80000003U; +#define lI l1 3]={ +#define lH case +#define lG 0x80000005U; +#define lF )==0)l0( +#define lE l8 3;}lH +#define lD std::memcmp(uptr+ +#define lC l2 3 lF +#define lB lA 1]){lH +#define lA :lN uptr[ +#define l9 'a' lB +#define l8 default:l0 +#define l7 lG l0 5;}lH +#define l6 <<16)| +#define l5 ==uptr[ +#define l4 lJ l0 3; +#define l3 0x80000004U;l0 4; +#define l2 lD 1,tmp, +#define l1 static const char tmp[ +#define l0 return +lN +nameLength){lH +2:lL +0]&&'f' l5 +1])l0(cIf +l6 +0x80000002U;l0 +2;lH +3 +lA +0]){lH +l9'b':if('s' l5 +2])l0(cAbs +l6 +lM'r':if('g' l5 +2])l0(cArg +l6 +l4 +lE'c' lB'o' lA +2]){lH's':l0(cCos +l6 +lJ +lH't':l0(cCot +l6 +lJ +lE's':if('c' l5 +2])l0(cCsc +l6 +l4 +lE'e':if('x' l5 +1]&&'p' l5 +2])l0(cExp +l6 +lM'i':if(lK +1]&&'t' l5 +2])l0(cInt +l6 +lM'l':if('o' l5 +1]&&'g' l5 +2])l0(cLog +l6 +lM'm' lB'a':if('x' l5 +2])l0(cMax +l6 +lM'i':if(lK +2])l0(cMin +l6 +l4 +lE'p':if('o' l5 +1]&&'w' l5 +2])l0(cPow +l6 +lM's' lB'e':if('c' l5 +2])l0(cSec +l6 +lM'i':if(lK +2])l0(cSin +l6 +l4 +lE't':if('a' l5 +1]&&lK +2])l0(cTan +l6 +l4 +lE +4 +lA +0]){lH +l9'c':if('o' l5 +2]&&'s' l5 +3])l0(cAcos +l6 +lO's':lL +2]&&lK +3])l0(cAsin +l6 +lO't':if('a' l5 +2]&&lK +3])l0(cAtan +l6 +l3 +l8 +4;} +lH'c' lB'b':if('r' l5 +2]&&'t' l5 +3])l0(cCbrt +l6 +lO'e':lL +2]&&'l' l5 +3])l0(cCeil +l6 +lO'o' lA +2]){lH'n':if('j' l5 +3])l0(cConj +l6 +lO's':if('h' l5 +3])l0(cCosh +l6 +l3 +l8 +4;} +l8 +4;} +lH'e':{lI'x','p','2'} +;if(lC +cExp2 +l6 +l3} +lH'i':{lI'm','a','g'} +;if(lC +cImag +l6 +l3} +lH'l':{lI'o','g','2'} +;if(lC +cLog2 +l6 +l3} +lH'r':{lI'e','a','l'} +;if(lC +cReal +l6 +l3} +lH's' lB'i':if(lK +2]&&'h' l5 +3])l0(cSinh +l6 +lO'q':if('r' l5 +2]&&'t' l5 +3])l0(cSqrt +l6 +l3 +l8 +4;} +lH't':{lI'a','n','h'} +;if(lC +cTanh +l6 +l3} +l8 +4;} +lH +5 +lA +0]){lH +l9'c':{lI'o','s','h'} +;if(lD +2,tmp,3 +lF +cAcosh +l6 +l7's':{lI'i','n','h'} +;if(lD +2,tmp,3 +lF +cAsinh +l6 +l7't':if('a' l5 +2]){if(lK +3]){lN +uptr[4]){lH'2':l0(cAtan2 +l6 +lG +lH'h':l0(cAtanh +l6 +lG +l8 +5;} +} +l0 +5;} +l0 +5;l8 +5;} +lH'f':{l1 +4]={'l','o','o','r'} +;if(l2 +4 +lF +cFloor +l6 +l7'h':{l1 +4]={'y','p','o','t'} +;if(l2 +4 +lF +cHypot +l6 +l7'l':{l1 +4]={'o','g','1','0'} +;if(l2 +4 +lF +cLog10 +l6 +l7'p':{l1 +4]={'o','l','a','r'} +;if(l2 +4 +lF +cPolar +l6 +l7't':{l1 +4]={'r','u','n','c'} +;if(l2 +4 +lF +cTrunc +l6 +lG +l0 +5;} +l8 +5;} +default:break;} +l0 +nameLength; diff --git a/fparser/extrasrc/fp_opcode_add.inc b/fparser/extrasrc/fp_opcode_add.inc new file mode 100644 index 0000000..ed05b22 --- /dev/null +++ b/fparser/extrasrc/fp_opcode_add.inc @@ -0,0 +1,7696 @@ +/* Function Parser for C++ v4.5.1 + + NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + This file contains generated code and is thus not intended to be to +be modified by hand. It was generated by util/bytecoderules_parser, which +is available in the development package. +*/ +#define HasInvalidRangesOpcode HasInvalidRangesOpcode<IsComplexType<Value_t>::result> +#define FP_TRACE_BYTECODE_OPTIMIZATION(srcline,from,to,with) \ + /*std::cout << "Changing \"" from "\"\t(line " #srcline ")\n" \ + " into \"" to "\"\n" with << std::flush*/ +#define FP_TRACE_OPCODENAME(op) \ + (op < VarBegin \ + ? FP_GetOpcodeName(OPCODE(op)) \ + : findName(mData->mNamePtrs,op,NameData<Value_t>::VARIABLE)) +#define FP_TRACE_BYTECODE_ADD(opcode) \ + /*std::cout << "Adding opcode: " << FP_TRACE_OPCODENAME(opcode) \ + << ", bytecode length " << data->ByteCode.size() \ + << ", pointer is " << (void*)ByteCodePtr \ + << ", code is " << (data->ByteCode.empty() \ + ? (void*)0 \ + : (void*)&data->ByteCode[0]) \ + << std::endl*/ +#define qH1 " B" mF +#define qG1 gT y*x; +#define qF1 hV 2;qI +#define qE1 <<"," aD +#define qD1 <<"," aB +#define qC1 "cNeg" +#define qB1 wA"," aD +#define qA1 "x[x!=Value_t(0)] " +#define q91 <<"," a8 +#define q81 wA"," a1 +#define q71 );qW q6 +#define q61 "cPow " +#define q51 "cSqrt" +#define q41 "cSqr " +#define q31 " cExp2" +#define q21 "cExp " +#define q11 ){hD wB +#define q01 "cCeil" +#define mZ "cImag" +#define mY "cConj" +#define mX "cDup " +#define mW hO wB +#define mV "cAbs" +#define mU wQ wH" " +#define mT qS w2 wB +#define mS "cFloor" +#define mR "cTan" +#define mQ " cDup" +#define mP "cSin" +#define mO (y hX; +#define mN "[ y+x]" +#define mM hV 2 gC +#define mL " cExp" +#define mK "A " wX +#define mJ "cLess" +#define mI "[-x]" wH +#define mH "cDiv" a7 +#define mG "cLog" +#define mF " cDiv" +#define mE " " a6 +#define mD " " aF +#define mC "cMin" +#define mB "cMax" +#define mA aY"x " +#define m9 gN wB +#define m8 "x cPow" +#define m7 g1 oG wB +#define m6 (x);gJ +#define m5 "B cSqr" +#define m4 oH dE wB +#define m3 "[y*x]" wH +#define m2 "cGreater" +#define m1 mV" " wL +#define m0 "cNeg " +#define aZ " cAdd" +#define aY "y " +#define aX "B[IsVarOpcode(B)] " +#define aW " cSub" +#define aV gY if(dO wB +#define aU "cInv" +#define aT mX aU +#define aS "cAbsNot" +#define aR "cLessOrEq" +#define aQ "cAdd " q51 +#define aP "[y*x] cPow" +#define aO "cCos" +#define aN "cLog2" +#define aM "cCosh" +#define aL "cLog10" +#define aK "B[B==A]" +#define aJ "cNotNot" +#define aI " " a2 +#define aH "cDup" aZ +#define aG "cGreaterOrEq" +#define aF "x" aZ +#define aE "cEqual" +#define aD " " aC +#define aC "A" wY +#define aB " " wU +#define aA " cNeg" +#define a9 " cRDiv" +#define a8 " B" wY +#define a7 " x" wH +#define a6 "cRSub" +#define a5 "A[IsVarOpcode(A)]" +#define a4 "x[x!=Value_t()] " +#define a3 " " a5" " +#define a2 " with" aD +#define a1 " " wG +#define a0 " cNot" +#define wZ "x[x==Value_t()]" wH +#define wY " " wC +#define wX "[x]" wH +#define wW "cNEqual" +#define wV a5 mF +#define wU "x = "<<x +#define wT "x[isInteger(x)] cPow" +#define wS a5 wH +#define wR "x[x!=Value_t(0)]" mF +#define wQ "x[x>Value_t(0)]" +#define wP "B[IsNeverNegativeValueOpcode(B)] " +#define wO "x[x==Value_t(1)] " +#define wN wA"\n" +#define wM <<"\n" +#define wL "x[x==Value_t(0)] " +#define wK "B[IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " wD +#define wJ "A[IsNeverNegativeValueOpcode(A)] " +#define wI "A[IsVarOpcode(A)&&mData->mByteCode.size()>2] " +#define wH " cMul" +#define wG aY"= "<<y wM +#define wF " x A[IsComparisonOpcode(A)]" +#define wE FP_TRACE_BYTECODE_ADD +#define wD "A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " wZ +#define wC "= "<<FP_TRACE_OPCODENAME +#define wB FP_TRACE_BYTECODE_OPTIMIZATION +#define wA " with" aB<< +#define w9 qT q6: +#define w8 cEqual +#define w7 Lbd gY +#define w6 Lcb gY +#define w5 opcode +#define w4 B==A){ +#define w3 q5 q4 +#define w2 cExp: +#define w1 qO A qP +#define w0 qO h2 +#define oZ qF g1 +#define oY if dC +#define oX fp_pow( +#define oW fp_log( +#define oV 3 gC A +#define oU x==g1 oG +#define oT gX Lml; +#define oS q4 Lbo +#define oR 3 gH +#define oQ cSinh: +#define oP g1 0) +#define oO 0.5)){ +#define oN Ldn;qT +#define oM ]==h3){ +#define oL qY g8 0 +#define oK .size() +#define oJ );qE +#define oI A oJ dU +#define oH g7 A= +#define oG 1)){ +#define oF qU hI +#define oE Lbo oF +#define oD qT hM hB +#define oC qL 3] +#define oB :hC qQ oC +#define oA cSub oB d3 hJ +#define o9 q7=-x +#define o8 gX Loi; +#define o7 );qF +#define o6 qE A o7 +#define o5 h3 d4 qL +#define o4 fp_log2( +#define o3 ==cSqr){ +#define o2 qT cSqr: +#define o1 cGreater +#define o0 Default6 +#define dZ Default5 +#define dY Default2 +#define dX Default1 +#define dW ImmedPtr +#define dV gA qZ qC +#define dU h3); +#define dT gC dU +#define dS cNotNot +#define dR fp_log10( +#define dQ cAbs); +#define dP fp_abs(x) +#define dO x>oP){ +#define dN mImmed +#define dM qE h3 gX +#define dL qK dJ w3 +#define dK cGreaterOrEq +#define dJ =q6; +#define dI qK dJ g6 +#define dH Value_t +#define dG q8 2 gH q4 +#define dF q0[0] +#define dE qK qR qX +#define dD qK qR IsLogicalOpcode(h2 +#define dC (qK== +#define dB hB oY +#define dA qY g8 oG +#define d9 pop_back() +#define d8 q6;q1 h3 gI +#define d7 q8 2 gC +#define d6 hR Lba; +#define d5 Default4 qU +#define d4 :if( +#define d3 qV hS d4 qL +#define d2 h3 gM if +#define d1 IsVarOpcode( +#define d0 mData-> +#define hZ ]qR w4 +#define hY gX Llq +#define hX ,x gX Lap +#define hW gT y+x;q8 +#define hV for qA +#define hU gQ cAbs: +#define hT unsigned +#define hS cAdd +#define hR ,y gX +#define hQ qL 3 hZ +#define hP y=q3-1]qR +#define hO y gO +#define hN qY if(dP +#define hM q6:qC +#define hL :if gF +#define hK qQ h9 hS hL +#define hJ 4 qZ mW(292,aY"cAdd B[IsVarOpcode(B)]" aW mD,mN aZ" B" aW,wA"," a8(B)<<"," a1);q4 +#define hI cNeg: +#define hH :qS cDup: +#define hG hS hH hK h1 wB(310,aH" " aH,"[Value_t(4)]" wH,);q4 +#define hF (x!=g1 +#define hE qL 2] +#define hD B g4 w4 +#define hC B=hE qO B)){ +#define hB if hF 0)){ +#define hA gX Lng; +#define h9 qK qV +#define h8 }break; +#define h7 <dH>()){ +#define h6 hR Lap; +#define h5 isEvenInteger( +#define h4 DegreesToRadians(x +#define h3 cMul +#define h2 A)){ +#define h1 ]==cDup){ +#define h0 hI wB(201,m0 mV,mV,);q4 Lab qU qB +#define gZ 3 h1 wB(311,aH wH" " aH,"cMul [Value_t(4)]" wH,);q4 +#define gY qU hM +#define gX );q4 +#define gW y,x gX Lba; +#define gV IsUnaryOpcode( +#define gU g6 w5= +#define gT q3-1]= +#define gS gR qR IsAlwaysIntegerOpcode(h2 +#define gR ;oH dF +#define gQ )){qQ h9 +#define gP break gR qO A gQ +#define gO =q3-1]; +#define gN qJ hO +#define gM :qJ qC +#define gL d2(dO +#define gK ]=q6 q9 2 gH +#define gJ return; +#define gI );w5= +#define gH ;qI q5 +#define gG qL 2 gK q0-=2; +#define gF (qL 2 +#define gE y;hT B;hT +#define gD d0 mByteCode +#define gC ;qI q1 +#define gB q9 2 gC h3 gI +#define gA ){if gF +#define g9 oY h3 dV +#define g8 if(x==g1 +#define g7 default: +#define g6 q5 q0-=1; +#define g5 if(!q0){q2 +#define g4 =hE qR +#define g3 B g4 IsNeverNegativeValueOpcode(B)){ +#define g2 &&!HasInvalidRangesOpcode( +#define g1 dH( +#define g0 FP_ReDefinePointers(); +#define qZ ]==q6){ +#define qY if(q0[0 qZ qC +#define qX IsNeverNegativeValueOpcode(h2 +#define qW gD qD +#define qV ){case +#define qU ;case +#define qT }break qU +#define qS qQ dF qV +#define qR ;if( +#define qQ switch( +#define qP )&&gD oK> +#define qO qR d1 +#define qN dF w1 2){ +#define qM d0 dN.d9; +#define qL q0[- +#define qK qL 1] +#define qJ oY q6){ +#define qI tmp-->0;) +#define qH q4 Default0; +#define qG }}qH +#define qF d0 dN qD +#define qE AddFunctionOpcode( +#define qD .push_back( +#define qC x=q7; +#define qB hM wB(132,"x " mV,"[fp_abs(x)]",wN);q4 Lac; +#define qA (hT tmp= +#define q9 ;hV +#define q8 d0 dN.d9 q9 +#define q7 q3 0] +#define q6 cImmed +#define q5 gD.d9; +#define q4 goto +#define q3 dW[ +#define q2 q4 Laa;}case +#define q1 q5 qE +#define q0 ByteCodePtr +hT*q0;dH*dW; +#define FP_ReDefinePointers() q0=!gD.empty()?&gD[0]+gD oK-1:0;dW=!d0 dN.empty()?&d0 dN[0]+d0 dN oK-1:0; +g0 +wE(opcode); +#if(!(FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION)) +dH +x;hT +A;dH +gE +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0 +oH +dF +qR +qX +wB(393,wJ +mV,"A" +,aI(A)wM);gJ +qG +TailCall_cAdd:g5 +hG +Lad;qT +h3 +hL]==hS){if(qL +gZ +Lae;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Laf;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lag +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Lah;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lai;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Laj +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lak;qT +oA +Lal;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lam +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lan;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Lao;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lap;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Laq;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lba;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +Lbb +gY +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbc;h8} +qH +TailCall_cDiv:g5 +cDiv +hH +wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +w7 +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Lbe +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Lbf;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lap;h8} +qH +TailCall_cEqual:g5 +w8:dA +A=dD +wB(421,"A[IsLogicalOpcode(A)] " +wO +aE,"A" +,qB1(A)wM);q4 +Lap;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Lbg;} +g8 +0 +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Lbh +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Lbh;} +wB(411,wL +aE,"cNot" +,wN);q4 +Lbi;qG +TailCall_cGreater:g5 +o1:oL +hU +wB(413,m1 +m2,aJ,wN);q4 +Lbj;m4(417,wJ +wL +m2,"A " +aJ,qB1(A)wM);q4 +Lbk;} +} +} +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Lbl;qG +TailCall_cGreaterOrEq:g5 +dK:qY +g8 +1 +hU +wB(414,mV" " +wO +aG,aJ,wN);q4 +Lbj;m4(418,wJ +wO +aG,"A " +aJ,qB1(A)wM);q4 +Lbk;} +} +} +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Lbm;qG +TailCall_cInv:g5 +cInv:qY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Lbn;qG +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);oS;} +} +g8 +1 +hU +wB(415,mV" " +wO +mJ,"cNot" +,wN);q4 +Lbp;m4(419,wJ +wO +mJ,"A" +a0,qB1(A)wM);q4 +Lbi;} +} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lbq;qG +TailCall_cLessOrEq:g5 +cLessOrEq:oL +hU +wB(416,m1 +aR,"cNot" +,wN);q4 +Lbp;m4(420,wJ +wL +aR,"A" +a0,qB1(A)wM);q4 +Lbi;} +} +} +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lca;qG +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);q4 +w6 +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lcc;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);q4 +Lcb;qT +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);q4 +Lcb;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);q4 +w6 +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lcd;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);q4 +Lcb;qT +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);q4 +Lcb;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lce;} +qG +TailCall_cMul:g5 +h3 +hH +wB(202,"cDup" +wH,"cSqr" +,);q4 +Lcf +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lcg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lci;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lcj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lck;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lcl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcn;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lcj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lco;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lcp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lcq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup:wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lda +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldb;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Ldc;qT +h3:qQ +hE +d3 +3 +h1 +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Ldd;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lde;} +wB(128,"y" +wH +a7,m3,q81);q4 +Ldf;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Ldg +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldh;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Ldi;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lap;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Ldj;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Ldk;h8 +g7 +dY:;A=dF +qO +A +gQ +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +q4 +Default4;g7 +Default4:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Ldl;} +} +q4 +dZ +oF +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lcg;} +q4 +dZ;g7 +dZ:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lcf;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Ldm;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:dA +A=dD +wB(422,"A[IsLogicalOpcode(A)] " +wO +wW,"A" +a0,qB1(A)wM);q4 +Lbi;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Ldn;} +g8 +0 +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Ldo +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Ldo;} +wB(412,wL +wW,aJ,wN);q4 +Lbk;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Ldp;qT +hI +wB(61,qC1 +aA,,);q4 +w6 +wB(100,"x" +aA,"[-x]" +,wN);q4 +Ldq;} +qH +TailCall_cNot:g5 +cNot:qS +cAbs:wB(227,mV +a0,"cNot" +,);q4 +Lea +qU +cAbsNot:A=dD +wB(389,"A[IsLogicalOpcode(A)] " +aS +a0,"A" +,aI(A)wM);q4 +Lcb;} +if(A!=q6){wB(390,"A[A!=cImmed] " +aS +a0,"A cAbsNotNot" +,aI(A)wM);q4 +Leb;} +q4 +o0 +qU +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Lec +qU +hS +gM +wB(424,aF +a0,"[-x] " +aE,wN);q4 +Led;} +q4 +o0 +qU +w8:wB(220,aE +a0,wW,);q4 +Lee +qU +o1:wB(218,m2 +a0,aR,);q4 +Lef +qU +dK:wB(219,aG +a0,mJ,);q4 +Leg +qU +cLess:wB(216,mJ +a0,aG,);q4 +Leh +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Lei +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Lej +oF +wB(226,qC1 +a0,"cNot" +,);q4 +Lea +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbb +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Lea +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Lek;g7 +o0:;A=dF +qR +qX +wB(391,wJ"cNot" +,"A " +aS,aI(A)wM);q4 +Lel;qG +TailCall_cNotNot:g5 +dS:qS +hS +gM +wB(423,aF" " +aJ,"[-x] " +wW,wN);q4 +Lem;qT +cNot:wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +Lbb +gY +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Len;h8} +qH +TailCall_cRDiv:g5 +cRDiv:dA +wB(268,wO"cRDiv" +,aU,wN);q4 +Leo;qG +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Lep;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Leq +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Leq;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Lep +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Lfa +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lap;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Lfb;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lfc +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Lfd;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lfe;} +qG +g7 +Default0:;A=w5 +qR +IsComparisonOpcode(h2 +qY +hK +qZ +mW(364,aY"cAdd" +wF,"[x-y] A" +,aI(A)qD1<<"," +a1);q4 +Lff;qT +hI +wB(365,qC1 +wF,"[-x] {OppositeComparisonOpcode(A)}" +,aI(A)qD1 +wM);q4 +Lfg;} +} +} +if(d1 +A +qP +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lfh;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lfi;} +} +} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:oZ +4));gG +Lfj:w5=h3;Lfk:g0 +Lfl:wE(cMul);q4 +TailCall_cMul;Lae:hV +4 +dT +oZ +4)q71 +gX +Lfj;Laf:q7=x+g1 +1);gG +Lbo:w5=h3;q4 +Lfl;Lag:gU +cSub;Lfm:wE(cSub);q4 +TailCall_cSub;Lah:hW +2 +gH +Lfn:g0 +Lfo:wE(cAdd);q4 +TailCall_cAdd;Lai:hW +oR +Lfp:qE +hS);Lfq:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Laj:o9;qL +2 +gK +q4 +Lfp;Lak:hW +2 +gH +q4 +Lfq;Lal:hW +4 +gH +Lga:qE +hS);Lgb:qE +B);Lgc:w5=cSub;g0 +q4 +Lfm;Lam:o9;oC=q6 +q9 +oR +q4 +Lga;Lan:hW +oR +q4 +Lgb;Lao:gT +y+x;Lap:qM +Lcb:q5 +gJ +Laq:q8 +oV +o7 +x +q71 +gX +Lfp;Lba:mM +A +gX +Lfp;Lbb:gU +dS;Lgd:wE(cNotNot);q4 +TailCall_cNotNot;Lbc:gT +fp_and(x +h6 +Lbd:oZ));dF +dJ +qE +dU +oZ +1));Lge:qW +q6);Lgf:w5=hS;q4 +Lfn;Lbe:o9;dI +wE(cDiv);q4 +TailCall_cDiv;Lbf:gT +y/x;q4 +Lap;Lbg:gT +fp_equal +mO +Lbh:dI +Lgg:wE(cEqual);q4 +TailCall_cEqual;Lbi:qM +q5 +Lgh:w5=cNot;g0 +Lgi:wE(cNot);q4 +TailCall_cNot;Lbj:q8 +2 +gH +Lgj:w5=dS;g0 +q4 +Lgd;Lbk:qM +w3 +Lgj;Lbl:gT +fp_less(x +h6 +Lbm:gT +fp_lessOrEq(x +h6 +Lbn:q7=g1 +1)/x;gJ +Lbp:dG +Lgh;Lbq:gT +fp_less +mO +Lca:gT +fp_lessOrEq +mO +Lcc:gT +fp_max(x +h6 +Lcd:gT +fp_min(x +h6 +Lce:gT +fp_mod +mO +Lcf:gU +cSqr;Lgk:wE(cSqr);q4 +TailCall_cSqr;Lcg:mM +cSqr);Lgl:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lch:hV +3 +gC +cSqr);dM +Lgl;Lci:q7=x+g1 +1);hE=q6 +q9 +2 +gC +cPow);gJ +Lcj:gG +q4 +Lfl;Lck:gT +x;Lgm:dG +Lfk;Lcl:qF1 +qM +Lgn:hV +4 +gH +Lgo:o6 +x);Lgp:qW +q6 +gX +Lfk;Lcm:qM +q4 +Lgn;Lcn:q8 +4 +gC +B +gX +Lgo;Lco:q8 +oR +q4 +Lgo;Lcp:qK +dJ +q4 +Lcb;Lcq:dI +q4 +Lfl;Lda:q7=x+x;q4 +Lcj;Ldb:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lgf;Ldc:gT +x;d7 +dU +qF +y*x +gX +Lge;Ldd:q8 +4 +dT +qF +x+x +gX +Lgp;Lde:qF1 +q8 +oR +gJ +Ldf:qG1 +q4 +Lgm;Ldg:o9;q4 +Lcq;Ldh:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lgc;Ldi:qG1 +q4 +Lap;Ldj:qM +w3 +Lgl;Ldk:dF=cDup;dW-=1;qM +Lgq:w5=hS;q4 +Lfo;Ldl:hV +2 +gH +Lha:qE +cSqr +gX +Lfk;Ldm:hV +oR +q4 +Lha;Ldn:gT +fp_nequal +mO +Ldo:dI +Lhb:wE(cNEqual);q4 +TailCall_cNEqual;Ldp:o9;g6 +oS;Ldq:o9;gJ +Lea:g6 +q4 +Lgi;Leb:q1 +cAbsNotNot);gJ +Lec:q5 +Lel:qE +cAbsNot);gJ +Led:o9;Lej:gU +w8;q4 +Lgg;Lee:gU +cNEqual;q4 +Lhb;Lef:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Leg:gU +cLess;wE(cLess);q4 +TailCall_cLess;Leh:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Lei:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Lek:q7=fp_not +m6 +Lem:o9;q4 +Lee;Len:gT +fp_or(x +h6 +Leo:qM +q5 +w5=cInv;g0 +wE(cInv);q4 +TailCall_cInv;Lep:oZ));dF +dJ +q4 +Lfj;Leq:g6 +q4 +Lgk;Lfa:g6 +q4 +Lgq;Lfb:gT +y-x;q4 +Lap;Lfc:o9;q4 +Lgq;Lfd:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lfq;Lfe:mM +A +oJ +cSub +gX +Lfq;Lff:gT +x-y;d7 +A);gJ +Lfg:o9;qK +dJ +q1 +OppositeComparisonOpcode(A));gJ +Lfh:qW +cDup);gJ +Lfi:dF=cDup;gJ +gJ +q4 +TailCall_cAnd;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cNeg;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cSub; +#endif +#if((FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION)) +dH +x;dH +gE +A;hT +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0} +qH +TailCall_cAdd:g5 +hG +Lad;qT +h3 +hL]==hS){if(qL +gZ +Lae;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Laf;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lag +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Lah;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lai;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Laj +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lak;qT +oA +Lal;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lam +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lan;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Lao;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lap;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Laq;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lba;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +Lbb +gY +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbc;h8} +qH +TailCall_cConj:g5 +cConj:qS +cConj:wB(63,mY" " +mY,,);q4 +w7 +wB(193,"x " +mY,"[fp_conj(x)]" +,wN);q4 +Lbe;} +qH +TailCall_cDiv:g5 +cDiv +hH +wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lbf +gY +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Lbg +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Lbh;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lap;h8} +qH +TailCall_cEqual:g5 +w8:dA +A=dD +wB(421,"A[IsLogicalOpcode(A)] " +wO +aE,"A" +,qB1(A)wM);q4 +Lap;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Lbi;} +g8 +0 +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Lbj +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Lbj;} +wB(411,wL +aE,"cNot" +,wN);q4 +Lbk;qG +TailCall_cGreater:g5 +o1:qY +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Lbl;qG +TailCall_cGreaterOrEq:g5 +dK:qY +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Lbm;qG +TailCall_cImag:g5 +cImag:qS +cAbs:wB(81,mV" " +mZ,"[Value_t()]" +wH,);q4 +Lbn +qU +cReal:wB(80,"cReal " +mZ,"[Value_t()]" +wH,);q4 +Lbn +gY +wB(192,"x " +mZ,"[fp_imag(x)]" +,wN);oS;} +qH +TailCall_cInv:g5 +cInv:qY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Lbp;qG +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);q4 +Lbq;} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lca;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lcb;qG +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);q4 +w7 +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lcc;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);q4 +Lbd;qT +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);q4 +Lbd;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);q4 +w7 +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lcd;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);q4 +Lbd;qT +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);q4 +Lbd;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lce;} +qG +TailCall_cMul:g5 +h3 +hH +wB(202,"cDup" +wH,"cSqr" +,);q4 +Lcf +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lcg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lci;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lcj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lck;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lcl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcn;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lcj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lco;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lcp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lcq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup:wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lda +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldb;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Ldc;qT +h3:qQ +hE +d3 +3 +h1 +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Ldd;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lde;} +wB(128,"y" +wH +a7,m3,q81);q4 +Ldf;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Ldg +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldh;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Ldi;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lap;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Ldj;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Ldk;h8 +g7 +dY:;A=dF +qO +A +gQ +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +q4 +Default4;g7 +Default4:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Ldl;} +} +q4 +dZ +oF +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lcg;} +q4 +dZ;g7 +dZ:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lcf;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Ldm;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:dA +A=dD +wB(422,"A[IsLogicalOpcode(A)] " +wO +wW,"A" +a0,qB1(A)wM);q4 +Lbk;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Ldn;} +g8 +0 +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Ldo +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Ldo;} +wB(412,wL +wW,aJ,wN);q4 +Ldp;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Ldq;qT +hI +wB(61,qC1 +aA,,);q4 +w7 +wB(100,"x" +aA,"[-x]" +,wN);q4 +Lea;} +qH +TailCall_cNot:g5 +cNot:qS +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Leb +qU +hS +gM +wB(424,aF +a0,"[-x] " +aE,wN);q4 +Lec;qT +w8:wB(220,aE +a0,wW,);q4 +Led +qU +o1:wB(218,m2 +a0,aR,);q4 +Lee +qU +dK:wB(219,aG +a0,mJ,);q4 +Lef +qU +cLess:wB(216,mJ +a0,aG,);q4 +Leg +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Leh +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Lei +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbb +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Lej +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Lek;} +qH +TailCall_cNotNot:g5 +dS:qS +hS +gM +wB(423,aF" " +aJ,"[-x] " +wW,wN);q4 +Lel;qT +cNot:wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +Lbb +gY +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Lem;h8} +qH +TailCall_cRDiv:g5 +cRDiv:dA +wB(268,wO"cRDiv" +,aU,wN);q4 +Len;qG +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Lbn;} +qH +TailCall_cReal:g5 +cReal:qY +wB(191,"x cReal" +,"[fp_real(x)]" +,wN);q4 +Leo;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Lep +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Lep;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Lbn +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Leq +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lap;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Lfa;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lfb +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Lfc;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lfd;} +qG +g7 +Default0:;A=w5 +w1 +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lfe;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lff;} +} +} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:oZ +4));gG +Lfg:w5=h3;Lfh:g0 +Lfi:wE(cMul);q4 +TailCall_cMul;Lae:hV +4 +dT +oZ +4)q71 +gX +Lfg;Laf:q7=x+g1 +1);gG +Lbq:w5=h3;q4 +Lfi;Lag:gU +cSub;Lfj:wE(cSub);q4 +TailCall_cSub;Lah:hW +2 +gH +Lfk:g0 +Lfl:wE(cAdd);q4 +TailCall_cAdd;Lai:hW +oR +Lfm:qE +hS);Lfn:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Laj:o9;qL +2 +gK +q4 +Lfm;Lak:hW +2 +gH +q4 +Lfn;Lal:hW +4 +gH +Lfo:qE +hS);Lfp:qE +B);Lfq:w5=cSub;g0 +q4 +Lfj;Lam:o9;oC=q6 +q9 +oR +q4 +Lfo;Lan:hW +oR +q4 +Lfp;Lao:gT +y+x;Lap:qM +Lbd:q5 +gJ +Laq:q8 +oV +o7 +x +q71 +gX +Lfm;Lba:mM +A +gX +Lfm;Lbb:gU +dS;Lga:wE(cNotNot);q4 +TailCall_cNotNot;Lbc:gT +fp_and(x +h6 +Lbe:q7=fp_conj +m6 +Lbf:oZ));dF +dJ +qE +dU +oZ +1));Lgb:qW +q6);Lgc:w5=hS;q4 +Lfk;Lbg:o9;dI +wE(cDiv);q4 +TailCall_cDiv;Lbh:gT +y/x;q4 +Lap;Lbi:gT +fp_equal +mO +Lbj:dI +Lgd:wE(cEqual);q4 +TailCall_cEqual;Lbk:qM +q5 +w5=cNot;g0 +Lge:wE(cNot);q4 +TailCall_cNot;Lbl:gT +fp_less(x +h6 +Lbm:gT +fp_lessOrEq(x +h6 +Lbn:oZ));dF +dJ +q4 +Lfg;Lbo:q7=fp_imag +m6 +Lbp:q7=g1 +1)/x;gJ +Lca:gT +fp_less +mO +Lcb:gT +fp_lessOrEq +mO +Lcc:gT +fp_max(x +h6 +Lcd:gT +fp_min(x +h6 +Lce:gT +fp_mod +mO +Lcf:gU +cSqr;Lgf:wE(cSqr);q4 +TailCall_cSqr;Lcg:mM +cSqr);Lgg:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lch:hV +3 +gC +cSqr);dM +Lgg;Lci:q7=x+g1 +1);hE=q6 +q9 +2 +gC +cPow);gJ +Lcj:gG +q4 +Lfi;Lck:gT +x;Lgh:dG +Lfh;Lcl:qF1 +qM +Lgi:hV +4 +gH +Lgj:o6 +x);Lgk:qW +q6 +gX +Lfh;Lcm:qM +q4 +Lgi;Lcn:q8 +4 +gC +B +gX +Lgj;Lco:q8 +oR +q4 +Lgj;Lcp:qK +dJ +q4 +Lbd;Lcq:dI +q4 +Lfi;Lda:q7=x+x;q4 +Lcj;Ldb:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lgc;Ldc:gT +x;d7 +dU +qF +y*x +gX +Lgb;Ldd:q8 +4 +dT +qF +x+x +gX +Lgk;Lde:qF1 +q8 +oR +gJ +Ldf:qG1 +q4 +Lgh;Ldg:o9;q4 +Lcq;Ldh:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lfq;Ldi:qG1 +q4 +Lap;Ldj:qM +w3 +Lgg;Ldk:dF=cDup;dW-=1;qM +Lgl:w5=hS;q4 +Lfl;Ldl:hV +2 +gH +Lgm:qE +cSqr +gX +Lfh;Ldm:hV +oR +q4 +Lgm;Ldn:gT +fp_nequal +mO +Ldo:dI +Lgn:wE(cNEqual);q4 +TailCall_cNEqual;Ldp:qM +q5 +w5=dS;g0 +q4 +Lga;Ldq:o9;g6 +q4 +Lbq;Lea:o9;gJ +Leb:q1 +cAbsNot);gJ +Lec:o9;Lei:gU +w8;q4 +Lgd;Led:gU +cNEqual;q4 +Lgn;Lee:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Lef:gU +cLess;wE(cLess);q4 +TailCall_cLess;Leg:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Leh:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Lej:g6 +q4 +Lge;Lek:q7=fp_not +m6 +Lel:o9;q4 +Led;Lem:gT +fp_or(x +h6 +Len:qM +q5 +w5=cInv;g0 +wE(cInv);q4 +TailCall_cInv;Leo:q7=fp_real +m6 +Lep:g6 +q4 +Lgf;Leq:g6 +q4 +Lgl;Lfa:gT +y-x;q4 +Lap;Lfb:o9;q4 +Lgl;Lfc:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lfn;Lfd:mM +A +oJ +cSub +gX +Lfn;Lfe:qW +cDup);gJ +Lff:dF=cDup;gJ +gJ +q4 +TailCall_cAnd;q4 +TailCall_cConj;q4 +TailCall_cImag;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cNeg;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cReal;q4 +TailCall_cSub; +#endif +#if((FP_FLOAT_VERSION) && !(FP_COMPLEX_VERSION)) +dH +x;hT +A;dH +gE +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0 +oH +dF +qR +qX +wB(393,wJ +mV,"A" +,aI(A)wM);gJ +qG +TailCall_cAcos:g5 +cAcos:hN<=m7(148,"x[fp_abs(x)<=Value_t(1)] cAcos" +,"[fp_acos(x)]" +,wN);q4 +Lad;qG +TailCall_cAcosh:g5 +cAcosh:qY +if(x>=m7(145,"x[x>=Value_t(1)] cAcosh" +,"[fp_acosh(x)]" +,wN);q4 +Lae;qG +TailCall_cAdd:g5 +hG +Laf;qT +h3 +hL]==hS){if(qL +gZ +Lag;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Lah;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lai +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Laj;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lak;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Lal +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lam;qT +oA +Lan;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lao +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lap;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Laq;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lba;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lbb;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lbc;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +w7 +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbe;h8} +qH +TailCall_cAsin:g5 +cAsin:hN<=m7(149,"x[fp_abs(x)<=Value_t(1)] cAsin" +,"[fp_asin(x)]" +,wN);q4 +Lbf;qG +TailCall_cAsinh:g5 +cAsinh:qY +wB(146,"x cAsinh" +,"[fp_asinh(x)]" +,wN);q4 +Lbg;} +qH +TailCall_cAtan:g5 +cAtan:qY +wB(150,"x cAtan" +,"[fp_atan(x)]" +,wN);q4 +Lbh;} +qH +TailCall_cAtan2:g5 +cAtan2:qY +m9(139,mA"cAtan2" +,"[fp_atan2(y,x)]" +,q81);q4 +Lbi;qG +TailCall_cAtanh:g5 +cAtanh:hN<m7(147,"x[fp_abs(x)<Value_t(1)] cAtanh" +,"[fp_atanh(x)]" +,wN);q4 +Lbj;qG +TailCall_cCbrt:g5 +cCbrt:qY +wB(151,"x cCbrt" +,"[fp_cbrt(x)]" +,wN);q4 +Lbk;} +qH +TailCall_cCeil:g5 +cCeil:qS +hI +wB(402,m0 +q01,mS +aA,);q4 +Lbl +gY +wB(135,"x " +q01,"[fp_ceil(x)]" +,wN);q4 +Lbm +gS +wB(396,"A[IsAlwaysIntegerOpcode(A)] " +q01,"A" +,aI(A)wM);gJ +qG +TailCall_cCos:g5 +cCos:qS +cAbs:wB(235,mV" " +aO,aO,);q4 +Lbn +oF +wB(238,m0 +aO,aO,);q4 +Lbn +gY +wB(152,"x " +aO,"[fp_cos(x)]" +,wN);oS;oH +qN +qQ +h9 +cSec:hD +wB(500,aK" cSec " +wI +aO,"B cSec " +aT,aI(A)q91(B)wM);q4 +Lbp;qT +cSin:hD +wB(494,aK" " +mP" " +wI +aO,"B cSinCos" +,aI(A)q91(B)wM);q4 +Lbq;h8} +qG +TailCall_cCosh:g5 +cCosh:qS +cAbs:wB(236,mV" " +aM,aM,);q4 +Lca +qU +cAsinh:wB(450,"cAsinh " +aM,"[DO_STACKPLUS1] " +q41"[Value_t(1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lcb +oF +wB(239,m0 +aM,aM,);q4 +Lca +gY +wB(153,"x " +aM,"[fp_cosh(x)]" +,wN);q4 +Lcc;oH +qN +oY +cSinh +q11(507,aK" cSinh " +wI +aM,"B cSinhCosh" +,aI(A)q91(B)wM);q4 +Lcd;} +} +qG +TailCall_cCot:g5 +cCot:A=qN +oY +cTan +q11(498,aK" " +mR" " +wI"cCot" +,"B " +mR" " +aT,aI(A)q91(B)wM);q4 +Lbp;} +qG +TailCall_cCsc:g5 +cCsc:A=qN +oY +cSin +q11(496,aK" " +mP" " +wI"cCsc" +,"B " +mP" " +aT,aI(A)q91(B)wM);q4 +Lbp;} +qG +TailCall_cDeg:g5 +cDeg:qY +wB(133,"x cDeg" +,"[RadiansToDegrees(x)]" +,wN);q4 +Lce;} +qH +TailCall_cDiv:g5 +cDiv:qS +cCos:wB(250,aO +mF,"cSec" +wH,);q4 +Lcf +qU +cCot:wB(254,"cCot" +mF,mR +wH,);q4 +Lcg +qU +cCsc:wB(252,"cCsc" +mF,mP +wH,);q4 +Lch +qU +cDup:wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lci +qU +w2 +wB(408,"cExp" +mF,m0"cExp" +wH,);q4 +Lcj +qU +cExp2:wB(409,"cExp2" +mF,m0"cExp2" +wH,);q4 +Lck +qU +cInv:wB(213,aU +mF,"cMul" +,);q4 +Lcl +qU +cPow:wB(407,"cPow" +mF,m0"cPow" +wH,);q4 +Lcm +qU +cSec:wB(253,"cSec" +mF,aO +wH,);q4 +Lcn +qU +cSin:wB(249,mP +mF,"cCsc" +wH,);q4 +Lco +qU +cSinCos:wB(502,"cSinCos" +mF,mR,);q4 +Lcp +qU +cSinhCosh:wB(509,"cSinhCosh" +mF,"cTanh" +,);q4 +Lcq +qU +cTan:wB(251,mR +mF,"cCot" +wH,);q4 +Lda +gY +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Ldb +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Ldc;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lba;} +dB +h3 +gA +qZ +hP(y/x)==fp_const_rad_to_deg +h7 +wB(321,"y[(y/x)==fp_const_rad_to_deg<Value_t>()]" +wH" " +wR,"cDeg" +,q81);q4 +Ldd;} +if((y/x)==fp_const_deg_to_rad +h7 +wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]" +wH" " +wR,"cRad" +,q81);q4 +Lde;} +wB(323,"y" +wH" " +wR,"[y/x]" +wH,q81);q4 +Ldf;} +} +wB(325,wR,"[Value_t(1)/x]" +wH,wN);q4 +Ldg;} +gP +cDiv:hC +wB(271,aX"cDiv " +wV,"[DO_STACKPLUS1] B A" +wH +mF,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Ldh;qT +cRDiv:qQ +hE +qV +hM +wB(266,"x" +a9" " +wV,"A" +wH" [x]" +a9,aI(A)qD1 +wM);q4 +Ldi;g7 +hC +wB(265,"B[IsVarOpcode(B)]" +a9" " +wV,"A" +wH" B" +a9,aI(A)q91(B)wM);q4 +Ldj;} +h8} +qG +TailCall_cEqual:g5 +w8:oL +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Ldk +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Ldk;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Ldl;qG +TailCall_cExp:g5 +w2 +qS +hS +gM +wB(404,aF +mL,q21"[fp_exp(x)]" +wH,wN);q4 +Ldm;qT +cLog:A=dE +wB(340,wJ +mG +mL,"A" +,aI(A)wM);q4 +oN +hM +wB(154,"x" +mL,"[fp_exp(x)]" +,wN);q4 +Ldo;} +qH +TailCall_cExp2:g5 +cExp2:qS +hS +gM +wB(405,aF +q31,"cExp2 [fp_exp2(x)]" +wH,wN);q4 +Ldp;qT +cLog2:A=dE +wB(341,wJ +aN +q31,"A" +,aI(A)wM);q4 +oN +hM +wB(155,"x" +q31,"[fp_exp2(x)]" +,wN);q4 +Ldq;} +wB(479,"cExp2" +,"[DO_STACKPLUS1] [fp_log(Value_t(2))]" +wH +mL,);incStackPtr();--mStackPtr;q4 +Lea;TailCall_cFloor:g5 +cFloor:qS +hI +wB(401,m0 +mS,q01 +aA,);q4 +Leb +gY +wB(136,"x " +mS,"[fp_floor(x)]" +,wN);q4 +Lec +gS +wB(395,"A[IsAlwaysIntegerOpcode(A)] " +mS,"A" +,aI(A)wM);gJ +qG +TailCall_cGreater:g5 +o1:qY +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Led;} +g8-oO +wB(431,"x[x==Value_t(-0.5)] " +m2,m0 +aS,wN);q4 +Lee;qG +TailCall_cGreaterOrEq:g5 +dK:qY +dB +cAbs){wB(427,mV" x[x!=Value_t(0)] " +aG,"[Value_t(0.5)/x]" +wH" " +aJ,wN);q4 +Lef;} +} +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Leg;} +g8 +oO +wB(430,"x[x==Value_t(0.5)] " +aG,"cAbsNotNot" +,wN);q4 +Leh;qG +TailCall_cHypot:g5 +cHypot +d4 +dF==cSinCos){wB(84,"cSinCos cHypot" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lci;} +qH +TailCall_cInt:g5 +cInt:qS +hM +wB(137,"x cInt" +,"[fp_int(x)]" +,wN);q4 +Lei +gS +wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt" +,"A" +,aI(A)wM);gJ +qG +TailCall_cInv:g5 +cInv:qS +cCos:wB(256,aO" " +aU,"cSec" +,);q4 +Lej +qU +cCot:wB(260,"cCot " +aU,mR,);q4 +Lcp +qU +cCsc:wB(258,"cCsc " +aU,mP,);q4 +Lek +qU +cInv:wB(62,aU" " +aU,,);q4 +Ldn +qU +cPow:wB(355,q61 +aU,m0"cPow" +,);q4 +Lel +qU +cSec:wB(259,"cSec " +aU,aO,);q4 +Lem +qU +cSin:wB(255,mP" " +aU,"cCsc" +,);q4 +Len +qU +cSqrt:wB(206,q51" " +aU,"cRSqrt" +,);q4 +Leo +qU +cTan:wB(257,mR" " +aU,"cCot" +,);q4 +Lep +gY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Leq;h8} +qH +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);q4 +Lfa;} +} +dB +cAbs){wB(426,mV" x[x!=Value_t(0)] " +mJ,"[Value_t(0.5)/x]" +wH +a0,wN);q4 +Lfb;} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lfc;} +g8 +oO +wB(429,"x[x==Value_t(0.5)] " +mJ,aS,wN);q4 +Lfd;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lfe;} +g8-oO +wB(432,"x[x==Value_t(-0.5)] " +aR,m0"cAbsNotNot" +,wN);q4 +Lff;qG +TailCall_cLog:g5 +cLog:mT(343,q21 +mG,,);q4 +Ldn +qU +gL +wB(491,mU +mG,mG" [fp_log(x)]" +aZ,wN);q4 +Lfg;} +o2 +wB(303,q41 +mG,mV" " +mG" " +aH,);q4 +Lfh +aV(156,wQ" " +mG,"[fp_log(x)]" +,wN);q4 +Lfi;h8} +qH +TailCall_cLog10:g5 +cLog10:mT(481,q21 +aL,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfj +qU +gL +wB(492,mU +aL,aL" [fp_log10(x)]" +aZ,wN);q4 +Lfk;} +o2 +wB(305,q41 +aL,mV" " +aL" " +aH,);q4 +Lfl +aV(157,wQ" " +aL,"[fp_log10(x)]" +,wN);q4 +Lfm;h8} +qH +TailCall_cLog2:g5 +cLog2:mT(480,q21 +aN,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfn +qU +cExp2:wB(344,"cExp2 " +aN,,);q4 +Ldn +qU +gL +wB(490,mU +aN,aN" [fp_log2(x)]" +aZ,wN);q4 +Lfo;} +o2 +wB(304,q41 +aN,mV" " +aN" " +aH,);q4 +Lfp +aV(158,wQ" " +aN,"[fp_log2(x)]" +,wN);q4 +Lfq;h8} +qH +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);q4 +Ldn +gY +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lga;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);q4 +oN +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);q4 +Ldn;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);q4 +Ldn +gY +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lgb;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);q4 +oN +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);q4 +Ldn;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lgc;} +qG +TailCall_cMul:g5 +h3:qS +cCsc:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(508,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc" +wH,"B cCot" +,aI(A)q91(B)wM);q4 +Lgd;} +} +} +q4 +dY +qU +cDup:wB(202,"cDup" +wH,"cSqr" +,);q4 +Lge +qU +cInv:wB(214,aU +wH,"cDiv" +,);q4 +Lgf +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lgg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgh;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lgi;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lgj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lgk;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lgl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgn;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lgj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lgo;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lgp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lgq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup +d4 +x+oU +wB(316,"cDup[x+x==Value_t(1)]" +aZ +a7,,wN);q4 +Lha;} +wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lhb +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lhc;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Lhd;qT +cDeg:wB(209,"cDeg" +a7,"[RadiansToDegrees(x)]" +wH,wN);q4 +Lhe +qU +cDiv +oB +qV +o5 +4 +qZ +mW(278,"y" +wH" " +aX +mH,m3 +qH1,wA"," +a8(B)<<"," +a1);q4 +Lhf;qT +hI +wB(279,m0 +aX +mH,mI +qH1,wA"," +a8(B)wM);q4 +Lhg +qU +q6:mW(277,aY +aX +mH,"[y*x] B" +mF,wA"," +a8(B)<<"," +a1);q4 +Lhh;} +qT +h3:qQ +hE +d3 +3 +h1 +if(x+oU +wB(318,"cDup[x+x==Value_t(1)]" +aZ +wH +a7,"cMul" +,wN);q4 +Lhi;} +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Lhj;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lhk;} +if((y*x)==fp_const_rad_to_deg +h7 +wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]" +wH +a7,"cDeg" +,q81);q4 +Ldd;} +if((y*x)==fp_const_deg_to_rad +h7 +wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]" +wH +a7,"cRad" +,q81);q4 +Lde;} +wB(128,"y" +wH +a7,m3,q81);q4 +Lhl;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Lhm +qU +cRDiv:qQ +hE +qV +o5 +3 +qZ +mW(285,"y" +wH +a9 +a7,m3 +a9,q81);q4 +Lhn;qT +hI +wB(286,qC1 +a9 +a7,mI +a9,wN);q4 +Lho +qU +q6:mW(284,"y" +a9 +a7,"[y*x]" +a9,q81);q4 +Lhp;qT +cRad:wB(210,"cRad" +a7,"[DegreesToRadians(x)]" +wH,wN);q4 +Lhq +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lia;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Lib;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lba;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Lic;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Lid;} +if(x==fp_const_rad_to_deg +h7 +wB(207,"x[x==fp_const_rad_to_deg<Value_t>()]" +wH,"cDeg" +,wN);q4 +Lie;} +if(x==fp_const_deg_to_rad +h7 +wB(208,"x[x==fp_const_deg_to_rad<Value_t>()]" +wH,"cRad" +,wN);q4 +Lif;h8 +g7 +dY:;A=dF +qO +A +gQ +cDiv:hC +wB(274,aX"cDiv " +wS,"[DO_STACKPLUS1] A" +wH +qH1,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Lig;} +q4 +d5 +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgh;} +q4 +dZ;g7 +dZ:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Lih;} +} +q4 +d5 +hI +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lgg;} +q4 +d5 +cRDiv +hL +qZ +qC +wB(267,"x" +a9" " +wS,"[DO_STACKPLUS1] " +mK +a9,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lii;} +wB(281,"cRDiv " +wS,"[DO_STACKPLUS1] A" +wH +a9,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lij;g7 +Default4:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lge;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lik;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:oL +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Lil +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Lil;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Lim;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Lin;qT +hI +wB(61,qC1 +aA,,);q4 +Ldn +qU +cSin:g9 +wB(244,"x" +wH" " +mP +aA,mI" " +mP,wN);q4 +Lio;} +qT +oQ +g9 +wB(245,"x" +wH" cSinh" +aA,mI" cSinh" +,wN);q4 +Lip;} +qT +cTan:g9 +wB(246,"x" +wH" " +mR +aA,mI" " +mR,wN);q4 +Liq;} +qT +cTanh:g9 +wB(247,"x" +wH" cTanh" +aA,mI" cTanh" +,wN);q4 +Lja;} +qT +hM +wB(100,"x" +aA,"[-x]" +,wN);q4 +Ljb;} +qH +TailCall_cNot:g5 +cNot:qS +cAbs:wB(227,mV +a0,"cNot" +,);q4 +Ljc +qU +cAbsNot:A=dD +wB(389,"A[IsLogicalOpcode(A)] " +aS +a0,"A" +,aI(A)wM);q4 +Ldn;} +if(A!=q6){wB(390,"A[A!=cImmed] " +aS +a0,"A cAbsNotNot" +,aI(A)wM);q4 +Ljd;} +q4 +o0 +qU +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Lje +qU +w8:wB(220,aE +a0,wW,);q4 +Ljf +qU +o1:wB(218,m2 +a0,aR,);q4 +Ljg +qU +dK:wB(219,aG +a0,mJ,);q4 +Ljh +qU +cLess:wB(216,mJ +a0,aG,);q4 +Lji +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Ljj +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Ljk +oF +wB(226,qC1 +a0,"cNot" +,);q4 +Ljc +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbd +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Ljc +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Ljl;g7 +o0:;A=dF +qR +qX +wB(391,wJ"cNot" +,"A " +aS,aI(A)wM);q4 +Ljm;qG +TailCall_cNotNot:g5 +dS +d4 +dF==cNot){wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +w7 +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Ljn;h8} +qH +TailCall_cPow:g5 +cPow:qY +if(!h5 +x+x)){oY +cSqr){wB(22,q41"x[!isEvenInteger(x+x)] cPow" +,mV" [x+x] cPow" +,wN);q4 +Ljo;} +} +if(isInteger(x +gQ +w2 +wB(43,q21 +wT,wX +mL,wN);q4 +Ljp +qU +cExp2:wB(44,"cExp2 " +wT,wX +q31,wN);q4 +Ljq +qU +cPow +hL +qZ +hP!isInteger(y)){wB(42,"y[!isInteger(y)] " +q61 +wT,aP,q81);q4 +Lka;} +} +wB(45,q61 +wT,wX" cPow" +,wN);q4 +Lkb;} +} +if(h5 +x +hU +wB(434,mV" x[isEvenInteger(x)] cPow" +,"[x] cPow" +,wN);q4 +Lkc +qU +h3 +hL]==cAbs){wB(435,mV +wH" x[isEvenInteger(x)] cPow" +,"cMul [x] cPow" +,wN);q4 +Lkd;h8} +} +g8)){wB(83,"x[x==Value_t()] cPow" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,wN);q4 +Lke;} +g8 +oO +wB(332,"x[x==Value_t(0.5)] cPow" +,q51,wN);q4 +Lkf;} +g8 +1)/g1 +3)){wB(333,"x[x==Value_t(1)/Value_t(3)] cPow" +,"cCbrt" +,wN);q4 +Lkg;} +g8 +1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)] cPow" +,"cCbrt " +aU,wN);q4 +Lkh;} +g8-oO +wB(335,"x[x==Value_t(-0.5)] cPow" +,"cRSqrt" +,wN);q4 +Lki;} +g8-oG +wB(336,"x[x==Value_t(-1)] cPow" +,aU,wN);q4 +Lkj;} +qQ +h9 +cPow +hL +qZ +hP +h5 +y)&&!h5 +x*y)){wB(21,"y[isEvenInteger(y)&&!isEvenInteger(x*y)] " +q61 +m8,mV" " +aP,q81);q4 +Lkk;} +wB(330,aY +q61 +m8,aP,q81);q4 +Lka;o2 +wB(46,q41 +m8,"[x+x] cPow" +,wN);q4 +Lkl +qU +q6:hP +y!=oP||x>=oP){wB(165,"y[y!=Value_t(0)||x>=Value_t(0)] " +m8,"[fp_pow(y,x)]" +,q81);q4 +Lkm;h8} +wB(455,m8,"[DO_POWI]" +,wN)qR +TryCompilePowi(x))gJ} +qH +TailCall_cRDiv:g5 +cRDiv:qS +cSinCos:wB(503,"cSinCos" +a9,"cCot" +,);q4 +Lep +qU +cSinhCosh:wB(510,"cSinhCosh" +a9,"cTanh " +aU,);q4 +Lkn +gY +g8 +oG +wB(268,wO"cRDiv" +,aU,wN);q4 +Lkj;h8} +qH +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Lko;} +qH +TailCall_cRad:g5 +cRad:qS +h3 +gM +wB(211,"x" +wH" cRad" +,"[DegreesToRadians(x)]" +wH,wN);q4 +Lkp;qT +hM +wB(134,"x cRad" +,"[DegreesToRadians(x)]" +,wN);q4 +Lkq;} +qH +TailCall_cSec:g5 +cSec:A=qN +qQ +h9 +cCos:hD +wB(497,aK" " +aO" " +wI"cSec" +,"B " +aO" " +aT,aI(A)q91(B)wM);q4 +Lbp;qT +cSin:hD +wB(495,aK" " +mP" " +wI"cSec" +,"B cSinCos " +aU,aI(A)q91(B)wM);q4 +Lla;h8 +qG +TailCall_cSin:g5 +cSin:qS +hI +wB(240,m0 +mP,mP +aA,);q4 +Llb +gY +wB(159,"x " +mP,"[fp_sin(x)]" +,wN);q4 +Llc;oH +qN +oY +cCsc +q11(499,aK" cCsc " +wI +mP,"B cCsc " +aT,aI(A)q91(B)wM);q4 +Lbp;} +} +qG +TailCall_cSinh:g5 +oQ +qS +cAcosh:wB(437,"cAcosh cSinh" +,"[DO_STACKPLUS1] " +q41"[Value_t(-1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lld +qU +cAsinh:wB(349,"cAsinh cSinh" +,,);q4 +Ldn +oF +wB(241,m0"cSinh" +,"cSinh" +aA,);q4 +Lle +gY +wB(160,"x cSinh" +,"[fp_sinh(x)]" +,wN);q4 +Llf;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Llg +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Llg +qU +cSqrt:A=dE +wB(338,wJ +q51" cSqr" +,"A" +,aI(A)wM);q4 +Ldn;h8} +qH +TailCall_cSqrt:g5 +cSqrt:qS +hS +d4 +qK +o3 +A=hE +w0 +if(oC +o3 +wB(512,"cSqr" +a3 +q41 +aQ,"A cHypot" +,aI(A)wM);q4 +Llh;} +} +B +g4 +gV +B)){A=oC +w0 +if(qL +4]o3 +wB(513,"cSqr" +a3"B[IsUnaryOpcode(B)] " +q41 +aQ,"A B cHypot" +," with" +a8(B)qE1(A)wM);q4 +Lli;} +} +} +o2 +wB(23,q41 +q51,mV,);q4 +Llj +gY +if(x>=oP){wB(161,"x[x>=Value_t(0)] " +q51,"[fp_sqrt(x)]" +,wN);q4 +Llk;h8} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Lko +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Lll +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lba;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Llm;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lln +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Llo;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Llp;} +qG +TailCall_cTan:g5 +cTan:qS +cAtan2:wB(354,"cAtan2 " +mR,"cDiv" +,);q4 +Lgf +oF +wB(242,m0 +mR,mR +aA,);q4 +Llq +gY +wB(163,"x " +mR,"[fp_tan(x)]" +,wN);q4 +Lma;oH +qN +oY +cCot +q11(501,aK" cCot " +wI +mR,"B cCot " +aT,aI(A)q91(B)wM);q4 +Lbp;} +} +qG +TailCall_cTanh:g5 +cTanh:qS +hI +wB(243,m0"cTanh" +,"cTanh" +aA,);q4 +Lmb +gY +wB(164,"x cTanh" +,"[fp_tanh(x)]" +,wN);q4 +Lmc;} +qH +TailCall_cTrunc:g5 +cTrunc:qS +hM +wB(138,"x cTrunc" +,"[fp_trunc(x)]" +,wN);q4 +Lmd +gS +wB(394,"A[IsAlwaysIntegerOpcode(A)] cTrunc" +,"A" +,aI(A)wM);gJ +qG +g7 +Default0:;A=w5 +qR +IsComparisonOpcode(h2 +qY +hK +qZ +mW(364,aY"cAdd" +wF,"[x-y] A" +,aI(A)qD1<<"," +a1);q4 +Lme;qT +cAtan +d4 +dP<fp_const_pi<dH>()*g1 +oO +wB(380,"cAtan[fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)]" +wF,"[fp_tan(x)] A" +,aI(A)qD1 +wM);q4 +Lmf;qT +cExp +d4 +dO +wB(370,"cExp[x>Value_t(0)]" +wF,"[fp_log(x)] A" +,aI(A)qD1 +wM);q4 +Lmg;qT +cExp2 +d4 +dO +wB(371,"cExp2[x>Value_t(0)]" +wF,"[fp_log2(x)] A" +,aI(A)qD1 +wM);q4 +Lmh;qT +cLog:g3 +wB(373,wP +mG +wF,"B [fp_exp(x)] A" +,aI(A)qD1 +q91(B)wM);q4 +Lmi;qT +cLog10:g3 +wB(375,wP +aL +wF,"B [fp_pow(Value_t(10),x)] A" +,aI(A)qD1 +q91(B)wM);q4 +Lmj;qT +cLog2:g3 +wB(374,wP +aN +wF,"B [fp_exp2(x)] A" +,aI(A)qD1 +q91(B)wM);q4 +Lmk;qT +h3 +hL +qZ +hP +y>oP){wB(366,"y[y>Value_t(0)]" +wH +wF,"[x/y] A" +,aI(A)qD1<<"," +a1);q4 +Lml;} +if(y<oP){wB(367,"y[y<Value_t(0)]" +wH +wF,"[x/y] {OppositeComparisonOpcode(A)}" +,aI(A)qD1<<"," +a1);q4 +Lmm;} +qT +hI +wB(365,qC1 +wF,"[-x] {OppositeComparisonOpcode(A)}" +,aI(A)qD1 +wM);q4 +Lmn +qU +cPow +d4 +x>oP +gA +qZ +hP +y>oP){wB(368,"y[y>Value_t(0)] cPow[x>Value_t(0)]" +wF,"[fp_pow(x,Value_t(1)/y)] A" +,aI(A)qD1<<"," +a1);q4 +Lmo;} +} +qT +oQ +wB(381,"cSinh" +wF,"[fp_asinh(x)] A" +,aI(A)qD1 +wM);q4 +Lmp +qU +cSqr +d4 +dO +wB(369,"cSqr[x>Value_t(0)]" +wF,mV" [fp_sqrt(x)] A" +,aI(A)qD1 +wM);q4 +Lmq;qT +cTanh +d4 +dP<m7(382,"cTanh[fp_abs(x)<Value_t(1)]" +wF,"[fp_atanh(x)] A" +,aI(A)qD1 +wM);q4 +Lna;h8} +} +} +if(d1 +A +qP +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lnb;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lnc;} +} +} +} +C=w5 +qR +IsCommutativeOrParamSwappableBinaryOpcode(C)){qS +cSin:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(505,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] " +mP" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinCos {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Lnd;} +} +qT +oQ +A=qK +w1 +3 +gA]==cCosh){B=hQ +wB(506,aK" " +aM" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Lne;} +} +h8} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +Lnf:wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:q7=fp_acos +m6 +Lae:q7=fp_acosh +m6 +Laf:oZ +4));gG +Lng:w5=h3;Lnh:g0 +Lni:wE(cMul);q4 +TailCall_cMul;Lag:hV +4 +dT +oZ +4));Lnj:qW +q6 +hA +Lah:q7=x+g1 +1);gG +Lfa:w5=h3;q4 +Lni;Lai:gU +cSub;Lnk:wE(cSub);q4 +TailCall_cSub;Laj:hW +2 +gH +Lnl:g0 +Lnm:wE(cAdd);q4 +TailCall_cAdd;Lak:hW +oR +Lnn:qE +hS);Lno:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Lal:o9;qL +2 +gK +q4 +Lnn;Lam:hW +2 +gH +q4 +Lno;Lan:hW +4 +gH +Lnp:qE +hS);Lnq:qE +B);Loa:w5=cSub;g0 +q4 +Lnk;Lao:o9;oC=q6 +q9 +oR +q4 +Lnp;Lap:hW +oR +q4 +Lnq;Laq:gT +y+x;Lba:qM +Ldn:q5 +gJ +Lbb:q8 +oV +o7 +x +q71 +gX +Lnn;Lbc:mM +A +gX +Lnn;Lbd:gU +dS;Lob:wE(cNotNot);q4 +TailCall_cNotNot;Lbe:gT +fp_and(x +d6 +Lbf:q7=fp_asin +m6 +Lbg:q7=fp_asinh +m6 +Lbh:q7=fp_atan +m6 +Lbi:gT +fp_atan2(gW +Lbj:q7=fp_atanh +m6 +Lbk:q7=fp_cbrt +m6 +Lbl:q1 +cFloor);Loc:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lbm:q7=fp_ceil +m6 +Lbn:g6 +Lod:wE(cCos);q4 +TailCall_cCos;Lbo:q7=fp_cos +m6 +Lbp:dF=cDup;w5=cInv;Loe:wE(cInv);q4 +TailCall_cInv;Lbq:mM +cSinCos);gJ +Lca:g6 +wE(cCosh);q4 +TailCall_cCosh;Lcb:q1 +cSqr +o7 +g1 +1));Lof:qW +q6 +oJ +hS);Log:w5=cSqrt;g0 +wE(cSqrt);q4 +TailCall_cSqrt;Lcc:q7=fp_cosh +m6 +Lcd:mM +cSinhCosh);gJ +Lce:q7=RadiansToDegrees +m6 +Lcf:q1 +cSec +hA +Lcg:q1 +cTan +hA +Lch:q1 +cSin +hA +Lci:oZ));dF +dJ +Loh:qE +dU +oZ +1));Loi:qW +q6);Loj:w5=hS;q4 +Lnl;Lcj:q1 +cNeg +oJ +cExp +hA +Lck:q1 +cNeg +oJ +cExp2 +hA +Lcl:g6 +q4 +Lfa;Lcm:q1 +cNeg +oJ +cPow +hA +Lcn:q1 +cCos +hA +Lco:q1 +cCsc +hA +Lcp:gU +cTan;Lok:wE(cTan);q4 +TailCall_cTan;Lcq:gU +cTanh;Lol:wE(cTanh);q4 +TailCall_cTanh;Lda:q1 +cCot +hA +Ldb:o9;dI +Lom:wE(cDiv);q4 +TailCall_cDiv;Ldc:gT +y/x;q4 +Lba;Ldd:qF1 +q8 +oR +Lon:w5=cDeg;g0 +wE(cDeg);q4 +TailCall_cDeg;Lde:qF1 +q8 +oR +Loo:w5=cRad;g0 +wE(cRad);q4 +TailCall_cRad;Ldf:gT +y/x;dG +Lng;Ldg:q7=g1 +1)/x;q4 +Lfa;Ldh:mM +oI +Lop:g0 +q4 +Lom;Ldi:q8 +3 +gC +oI +qF +x +q71);Loq:w5=cRDiv;g0 +wE(cRDiv);q4 +TailCall_cRDiv;Ldj:hV +3 +gC +oI +qE +B +gX +Loq;Ldk:dI +Lpa:wE(cEqual);q4 +TailCall_cEqual;Ldl:gT +fp_equal(gW +Ldm:d7 +cExp +o7 +fp_exp(x)gX +Lnj;Ldo:q7=fp_exp +m6 +Ldp:d7 +cExp2 +o7 +fp_exp2(x)gX +Lnj;Ldq:q7=fp_exp2 +m6 +Lea:qF +oW +g1 +2))q71);Lpb:qE +h3 +gI +cExp;g0 +wE(cExp);q4 +TailCall_cExp;Leb:q1 +cCeil +gX +Loc;Lec:q7=fp_floor +m6 +Led:gT +fp_less(x +d6 +Lee:qM +q1 +cNeg);Ljm:qE +cAbsNot);gJ +Lef:q7=g1 +0.5)/x;qK=d8 +dS;g0 +q4 +Lob;Leg:gT +fp_lessOrEq(x +d6 +Leh:qM +Ljd:q5 +Lpc:qE +cAbsNotNot);gJ +Lei:q7=fp_int +m6 +Lej:gU +cSec;wE(cSec);q4 +TailCall_cSec;Lek:gU +cSin;Lpd:wE(cSin);q4 +TailCall_cSin;Lel:q1 +cNeg +gI +cPow;Lpe:g0 +Lpf:wE(cPow);q4 +TailCall_cPow;Lem:gU +cCos;q4 +Lod;Len:gU +cCsc;wE(cCsc);q4 +TailCall_cCsc;Leo:q1 +cRSqrt);gJ +Lep:g6 +Lpg:w5=cCot;wE(cCot);q4 +TailCall_cCot;Leq:q7=g1 +1)/x;gJ +Lfb:q7=g1 +0.5)/x;qK=d8 +cNot;g0 +Lph:wE(cNot);q4 +TailCall_cNot;Lfc:gT +fp_less(gW +Lfd:qM +Lje:w3 +Ljm;Lfe:gT +fp_lessOrEq(gW +Lff:qM +q1 +cNeg +gX +Lpc;Lfg:d7 +cLog +o7 +oW +x)o8 +Lfh:q1 +dQ +qE +cLog);Lpi:qW +cDup +gX +Loj;Lfi:q7=oW +x);gJ +Lfj:qF +dR +fp_const_e<dH>()));Lpj:dF +dJ +q4 +Lng;Lfk:d7 +cLog10 +o7 +dR +x)o8 +Lfl:q1 +dQ +qE +cLog10 +gX +Lpi;Lfm:q7=dR +x);gJ +Lfn:qF +o4 +fp_const_e<dH>())gX +Lpj;Lfo:d7 +cLog2 +o7 +o4 +x)o8 +Lfp:q1 +dQ +qE +cLog2 +gX +Lpi;Lfq:q7=o4 +x);gJ +Lga:gT +fp_max(x +d6 +Lgb:gT +fp_min(x +d6 +Lgc:gT +fp_mod(gW +Lgd:hV +oR +q0-=3;q4 +Lpg;Lge:gU +cSqr;Lpk:wE(cSqr);q4 +TailCall_cSqr;Lgf:gU +cDiv;q4 +Lom;Lgg:mM +cSqr +gX +Loc;Lgh:hV +3 +gC +cSqr);dM +Loc;Lgi:q7=x+g1 +1);gG +w5=cPow;q4 +Lpf;Lgj:gG +q4 +Lni;Lgk:gT +x;Lpl:dG +Lnh;Lgl:qF1 +qM +Lpm:hV +4 +gH +Lpn:o6 +x);Lpo:qW +q6 +gX +Lnh;Lgm:qM +q4 +Lpm;Lgn:q8 +4 +gC +B +gX +Lpn;Lgo:q8 +oR +q4 +Lpn;Lgp:qK +dJ +q4 +Ldn;Lgq:dI +q4 +Lni;Lha:qM +Lpp:hV +oR +gJ +Lhb:q7=x+x;q4 +Lgj;Lhc:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Loj;Lhd:gT +x;d7 +dU +qF +y*x +o8 +Lhe:q7=RadiansToDegrees(x +gX +Lgq;Lhf:qG1 +q8 +4 +gH +Lpq:qE +dU +Lqa:qE +B +gI +cDiv;q4 +Lop;Lhg:o9;oC=q6 +q9 +oR +q4 +Lpq;Lhh:qG1 +q8 +oR +q4 +Lqa;Lhi:q8 +4 +gH +q4 +Lnh;Lhj:q8 +4 +dT +qF +x+x +gX +Lpo;Lhk:qF1 +qM +q4 +Lpp;Lhl:qG1 +q4 +Lpl;Lhm:o9;q4 +Lgq;Lhn:qG1 +q8 +oR +Lqb:dM +Loq;Lho:o9;qL +2 +gK +q4 +Lqb;Lhp:qG1 +dG +Loq;Lhq:q7=h4 +gX +Lgq;Lia:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Loa;Lib:qG1 +q4 +Lba;Lic:qM +w3 +Loc;Lid:dF=cDup;dW-=1;qM +Lqc:w5=hS;q4 +Lnm;Lie:qM +w3 +Lon;Lif:qM +w3 +Loo;Lig:hV +oV +gX +Lpq;Lih:hV +2 +gH +Lqd:qE +cSqr +gX +Lnh;Lii:q8 +oV +o7 +x +q71 +gX +Lqb;Lij:mM +A +gX +Lqb;Lik:hV +oR +q4 +Lqd;Lil:dI +Lqe:wE(cNEqual);q4 +TailCall_cNEqual;Lim:gT +fp_nequal(gW +Lin:o9;q4 +Lcl;Lio:o9 +gB +cSin;g0 +q4 +Lpd;Lip:o9 +gB +cSinh;g0 +wE(cSinh);q4 +TailCall_cSinh;Liq:o9 +gB +cTan;g0 +q4 +Lok;Lja:o9 +gB +cTanh;g0 +q4 +Lol;Ljb:o9;gJ +Ljc:g6 +q4 +Lph;Ljf:gU +cNEqual;q4 +Lqe;Ljg:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Ljh:gU +cLess;wE(cLess);q4 +TailCall_cLess;Lji:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Ljj:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Ljk:gU +w8;q4 +Lpa;Ljl:q7=fp_not +m6 +Ljn:gT +fp_or(x +d6 +Ljo:d7 +dQ +qF +x+x);Lqf:qW +q6 +gX +Lpe;Ljp:dL +Lpb;Ljq:qK=d8 +cExp2;g0 +wE(cExp2);q4 +TailCall_cExp2;Lka:qG1 +dG +Lpe;Lkb:qK +dJ +q1 +h3 +gX +Lpe;Lkc:dI +q4 +Lpf;Lkd:q8 +3 +dT +qF +x +gX +Lqf;Lke:q7=g1 +gX +Loh;Lkf:qM +w3 +Log;Lkg:qM +q5 +w5=cCbrt;g0 +wE(cCbrt);q4 +TailCall_cCbrt;Lkh:qM +q1 +cCbrt);Lqg:w5=cInv;g0 +q4 +Loe;Lki:qM +q4 +Leo;Lkj:qM +w3 +Lqg;Lkk:qF1 +q8 +3 +gC +dQ +qF +y*x +gX +Lqf;Lkl:q7=x+x;q4 +Lkc;Lkm:gT +oX +gW +Lkn:q1 +cTanh +gX +Lqg;Lko:oZ)gX +Lpj;Lkp:q7=h4 +gX +Lcl;Lkq:q7=h4);gJ +Lla:mM +cSinCos +gX +Lqg;Llb:q1 +cSin +gX +Loc;Llc:q7=fp_sin +m6 +Lld:q1 +cSqr +o7 +g1-1)gX +Lof;Lle:q1 +cSinh +gX +Loc;Llf:q7=fp_sinh +m6 +Llg:g6 +q4 +Lpk;Llh:hV +4 +gC +A);Lqh:w5=cHypot;g0 +wE(cHypot);q4 +TailCall_cHypot;Lli:hV +5 +gC +A +oJ +B +gX +Lqh;Llj:gU +cAbs;q4 +Lnf;Llk:q7=fp_sqrt +m6 +Lll:g6 +q4 +Lqc;Llm:gT +y-x;q4 +Lba;Lln:o9;q4 +Lqc;Llo:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lno;Llp:mM +A +oJ +cSub +gX +Lno;Llq:q1 +cTan +gX +Loc;Lma:q7=fp_tan +m6 +Lmb:q1 +cTanh +gX +Loc;Lmc:q7=fp_tanh +m6 +Lmd:q7=fp_trunc +m6 +Lme:gT +x-y;Lqi:q8 +2 +gH +Lqj:qE +A);gJ +Lmf:q7=fp_tan(x);Lqk:dL +Lqj;Lmg:q7=oW +x +gX +Lqk;Lmh:q7=o4 +x +gX +Lqk;Lmi:q7=fp_exp(x +gX +Lqk;Lmj:q7=oX +g1 +10),x +gX +Lqk;Lmk:q7=fp_exp2(x +gX +Lqk;Lml:gT +x/y;q4 +Lqi;Lmm:gT +x/y;q8 +2 +gH +Lql:qE +OppositeComparisonOpcode(A));gJ +Lmn:o9;dL +Lql;Lmo:gT +oX +x,g1 +1)/y +gX +Lqi;Lmp:q7=fp_asinh(x +gX +Lqk;Lmq:d7 +dQ +qF +fp_sqrt(x)q71 +gX +Lqj;Lna:q7=fp_atanh(x +gX +Lqk;Lnb:qW +cDup);gJ +Lnc:dF=cDup;gJ +Lnd:hV +3 +gC +cSinCos);Lqm:qE +GetParamSwappedBinaryOpcode(C));gJ +Lne:hV +3 +gC +cSinhCosh +gX +Lqm;gJ +q4 +TailCall_cAcos;q4 +TailCall_cAcosh;q4 +TailCall_cAnd;q4 +TailCall_cAsin;q4 +TailCall_cAsinh;q4 +TailCall_cAtan;q4 +TailCall_cAtan2;q4 +TailCall_cAtanh;q4 +TailCall_cCeil;q4 +TailCall_cFloor;q4 +TailCall_cInt;q4 +TailCall_cLog;q4 +TailCall_cLog10;q4 +TailCall_cLog2;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cRad;q4 +TailCall_cSec;q4 +TailCall_cSin;q4 +TailCall_cSinh;q4 +TailCall_cSqrt;q4 +TailCall_cSub;q4 +TailCall_cTan;q4 +TailCall_cTanh;q4 +TailCall_cTrunc; +#endif +#if((FP_COMPLEX_VERSION) && (FP_FLOAT_VERSION)) +dH +x;dH +gE +A;hT +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0} +qH +TailCall_cAcos:g5 +cAcos:qY +wB(172,"x cAcos" +,"[fp_acos(x)]" +,wN);q4 +Lad;} +qH +TailCall_cAcosh:g5 +cAcosh:qY +wB(169,"x cAcosh" +,"[fp_acosh(x)]" +,wN);q4 +Lae;} +qH +TailCall_cAdd:g5 +hG +Laf;qT +h3 +hL]==hS){if(qL +gZ +Lag;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Lah;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lai +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Laj;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lak;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Lal +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lam;qT +oA +Lan;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lao +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lap;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Laq;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lba;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lbb;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lbc;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +w7 +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbe;h8} +qH +TailCall_cArg:g5 +cArg:qY +wB(190,"x cArg" +,"[fp_arg(x)]" +,wN);q4 +Lbf;} +qH +TailCall_cAsin:g5 +cAsin:qY +wB(173,"x cAsin" +,"[fp_asin(x)]" +,wN);q4 +Lbg;} +qH +TailCall_cAsinh:g5 +cAsinh:qY +wB(170,"x cAsinh" +,"[fp_asinh(x)]" +,wN);q4 +Lbh;} +qH +TailCall_cAtan:g5 +cAtan:qY +if(g1 +x.real(),fp_abs(x.imag()))!=g1 +0,oG +wB(174,"x[Value_t(x.real(),fp_abs(x.imag()))!=Value_t(0,1)] cAtan" +,"[fp_atan(x)]" +,wN);q4 +Lbi;qG +TailCall_cAtan2:g5 +cAtan2:qY +m9(139,mA"cAtan2" +,"[fp_atan2(y,x)]" +,q81);q4 +Lbj;qG +TailCall_cAtanh:g5 +cAtanh:qY +if(g1 +fp_abs(x.real()),x.imag())!=g1 +1,0)){wB(171,"x[Value_t(fp_abs(x.real()),x.imag())!=Value_t(1,0)] cAtanh" +,"[fp_atanh(x)]" +,wN);q4 +Lbk;qG +TailCall_cCbrt:g5 +cCbrt:qY +wB(175,"x cCbrt" +,"[fp_cbrt(x)]" +,wN);q4 +Lbl;} +qH +TailCall_cCeil:g5 +cCeil:qS +hI +wB(402,m0 +q01,mS +aA,);q4 +Lbm +gY +wB(135,"x " +q01,"[fp_ceil(x)]" +,wN);q4 +Lbn +gS +wB(396,"A[IsAlwaysIntegerOpcode(A)] " +q01,"A" +,aI(A)wM);gJ +qG +TailCall_cConj:g5 +cConj:qS +cConj:wB(63,mY" " +mY,,);oS +gY +wB(193,"x " +mY,"[fp_conj(x)]" +,wN);q4 +Lbp;} +qH +TailCall_cCos:g5 +cCos:qS +cAcos:wB(346,"cAcos " +aO,,);q4 +oE +wB(238,m0 +aO,aO,);q4 +Lbq +gY +wB(176,"x " +aO,"[fp_cos(x)]" +,wN);q4 +Lca;oH +qN +qQ +h9 +cSec:hD +wB(500,aK" cSec " +wI +aO,"B cSec " +aT,aI(A)q91(B)wM);q4 +Lcb;qT +cSin:hD +wB(494,aK" " +mP" " +wI +aO,"B cSinCos" +,aI(A)q91(B)wM);q4 +Lcc;h8} +qG +TailCall_cCosh:g5 +cCosh:qS +cAsinh:wB(450,"cAsinh " +aM,"[DO_STACKPLUS1] " +q41"[Value_t(1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lcd +oF +wB(239,m0 +aM,aM,);q4 +Lce +gY +wB(177,"x " +aM,"[fp_cosh(x)]" +,wN);q4 +Lcf;oH +qN +oY +cSinh +q11(507,aK" cSinh " +wI +aM,"B cSinhCosh" +,aI(A)q91(B)wM);q4 +Lcg;} +} +qG +TailCall_cCot:g5 +cCot:A=qN +oY +cTan +q11(498,aK" " +mR" " +wI"cCot" +,"B " +mR" " +aT,aI(A)q91(B)wM);q4 +Lcb;} +qG +TailCall_cCsc:g5 +cCsc:A=qN +oY +cSin +q11(496,aK" " +mP" " +wI"cCsc" +,"B " +mP" " +aT,aI(A)q91(B)wM);q4 +Lcb;} +qG +TailCall_cDeg:g5 +cDeg:qY +wB(133,"x cDeg" +,"[RadiansToDegrees(x)]" +,wN);q4 +Lch;} +qH +TailCall_cDiv:g5 +cDiv:qS +cCos:wB(250,aO +mF,"cSec" +wH,);q4 +Lci +qU +cCot:wB(254,"cCot" +mF,mR +wH,);q4 +Lcj +qU +cCsc:wB(252,"cCsc" +mF,mP +wH,);q4 +Lck +qU +cDup:wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lcl +qU +w2 +wB(408,"cExp" +mF,m0"cExp" +wH,);q4 +Lcm +qU +cExp2:wB(409,"cExp2" +mF,m0"cExp2" +wH,);q4 +Lcn +qU +cInv:wB(213,aU +mF,"cMul" +,);q4 +Lco +qU +cPow:wB(407,"cPow" +mF,m0"cPow" +wH,);q4 +Lcp +qU +cSec:wB(253,"cSec" +mF,aO +wH,);q4 +Lcq +qU +cSin:wB(249,mP +mF,"cCsc" +wH,);q4 +Lda +qU +cSinCos:wB(502,"cSinCos" +mF,mR,);q4 +Ldb +qU +cSinhCosh:wB(509,"cSinhCosh" +mF,"cTanh" +,);q4 +Ldc +qU +cTan:wB(251,mR +mF,"cCot" +wH,);q4 +Ldd +gY +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Lde +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Ldf;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lba;} +dB +h3 +gA +qZ +hP(y/x)==fp_const_rad_to_deg +h7 +wB(321,"y[(y/x)==fp_const_rad_to_deg<Value_t>()]" +wH" " +wR,"cDeg" +,q81);q4 +Ldg;} +if((y/x)==fp_const_deg_to_rad +h7 +wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]" +wH" " +wR,"cRad" +,q81);q4 +Ldh;} +wB(323,"y" +wH" " +wR,"[y/x]" +wH,q81);q4 +Ldi;} +} +wB(325,wR,"[Value_t(1)/x]" +wH,wN);q4 +Ldj;} +gP +cDiv:hC +wB(271,aX"cDiv " +wV,"[DO_STACKPLUS1] B A" +wH +mF,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Ldk;qT +cRDiv:qQ +hE +qV +hM +wB(266,"x" +a9" " +wV,"A" +wH" [x]" +a9,aI(A)qD1 +wM);q4 +Ldl;g7 +hC +wB(265,"B[IsVarOpcode(B)]" +a9" " +wV,"A" +wH" B" +a9,aI(A)q91(B)wM);q4 +Ldm;} +h8} +qG +TailCall_cEqual:g5 +w8:oL +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Ldn +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Ldn;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Ldo;qG +TailCall_cExp:g5 +w2 +qS +hS +gM +wB(404,aF +mL,q21"[fp_exp(x)]" +wH,wN);q4 +Ldp;qT +cLog:A=dE +wB(340,wJ +mG +mL,"A" +,aI(A)wM);oS;qT +hM +wB(178,"x" +mL,"[fp_exp(x)]" +,wN);q4 +Ldq;} +qH +TailCall_cExp2:g5 +cExp2:qS +hS +gM +wB(405,aF +q31,"cExp2 [fp_exp2(x)]" +wH,wN);q4 +Lea;qT +cLog2:A=dE +wB(341,wJ +aN +q31,"A" +,aI(A)wM);oS;qT +hM +wB(179,"x" +q31,"[fp_exp2(x)]" +,wN);q4 +Leb;} +wB(479,"cExp2" +,"[DO_STACKPLUS1] [fp_log(Value_t(2))]" +wH +mL,);incStackPtr();--mStackPtr;q4 +Lec;TailCall_cFloor:g5 +cFloor:qS +hI +wB(401,m0 +mS,q01 +aA,);q4 +Led +gY +wB(136,"x " +mS,"[fp_floor(x)]" +,wN);q4 +Lee +gS +wB(395,"A[IsAlwaysIntegerOpcode(A)] " +mS,"A" +,aI(A)wM);gJ +qG +TailCall_cGreater:g5 +o1:qY +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Lef;qG +TailCall_cGreaterOrEq:g5 +dK:qY +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Leg;qG +TailCall_cHypot:g5 +cHypot +d4 +dF==cSinCos){wB(84,"cSinCos cHypot" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lcl;} +qH +TailCall_cImag:g5 +cImag:qS +cAbs:wB(81,mV" " +mZ,"[Value_t()]" +wH,);q4 +Leh +qU +cReal:wB(80,"cReal " +mZ,"[Value_t()]" +wH,);q4 +Leh +gY +wB(192,"x " +mZ,"[fp_imag(x)]" +,wN);q4 +Lei;} +qH +TailCall_cInt:g5 +cInt:qS +hM +wB(137,"x cInt" +,"[fp_int(x)]" +,wN);q4 +Lej +gS +wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt" +,"A" +,aI(A)wM);gJ +qG +TailCall_cInv:g5 +cInv:qS +cCos:wB(256,aO" " +aU,"cSec" +,);q4 +Lek +qU +cCot:wB(260,"cCot " +aU,mR,);q4 +Ldb +qU +cCsc:wB(258,"cCsc " +aU,mP,);q4 +Lel +qU +cInv:wB(62,aU" " +aU,,);oS +qU +cPow:wB(355,q61 +aU,m0"cPow" +,);q4 +Lem +qU +cSec:wB(259,"cSec " +aU,aO,);q4 +Len +qU +cSin:wB(255,mP" " +aU,"cCsc" +,);q4 +Leo +qU +cSqrt:wB(206,q51" " +aU,"cRSqrt" +,);q4 +Lep +qU +cTan:wB(257,mR" " +aU,"cCot" +,);q4 +Leq +gY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Lfa;h8} +qH +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);q4 +Lfb;} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lfc;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lfd;qG +TailCall_cLog:g5 +cLog:mT(343,q21 +mG,,);oS +qU +gL +wB(491,mU +mG,mG" [fp_log(x)]" +aZ,wN);q4 +Lfe;} +oD +wB(180,qA1 +mG,"[fp_log(x)]" +,wN);q4 +Lff;h8} +qH +TailCall_cLog10:g5 +cLog10:mT(481,q21 +aL,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfg +qU +gL +wB(492,mU +aL,aL" [fp_log10(x)]" +aZ,wN);q4 +Lfh;} +oD +wB(181,qA1 +aL,"[fp_log10(x)]" +,wN);q4 +Lfi;h8} +qH +TailCall_cLog2:g5 +cLog2:mT(480,q21 +aN,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfj +qU +cExp2:wB(344,"cExp2 " +aN,,);oS +qU +gL +wB(490,mU +aN,aN" [fp_log2(x)]" +aZ,wN);q4 +Lfk;} +oD +wB(182,qA1 +aN,"[fp_log2(x)]" +,wN);q4 +Lfl;h8} +qH +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);oS +gY +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lfm;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);oS;qT +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);oS;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);oS +gY +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lfn;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);oS;qT +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);oS;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lfo;} +qG +TailCall_cMul:g5 +h3:qS +cCsc:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(508,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc" +wH,"B cCot" +,aI(A)q91(B)wM);q4 +Lfp;} +} +} +q4 +dY +qU +cDup:wB(202,"cDup" +wH,"cSqr" +,);q4 +Lfq +qU +cInv:wB(214,aU +wH,"cDiv" +,);q4 +Lga +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lgb;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgc;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lgd;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lge;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lgf;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lgg;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgh;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgi;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lge;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lgj;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lgk;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lgl;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup +d4 +x+oU +wB(316,"cDup[x+x==Value_t(1)]" +aZ +a7,,wN);q4 +Lgm;} +wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lgn +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lgo;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Lgp;qT +cDeg:wB(209,"cDeg" +a7,"[RadiansToDegrees(x)]" +wH,wN);q4 +Lgq +qU +cDiv +oB +qV +o5 +4 +qZ +mW(278,"y" +wH" " +aX +mH,m3 +qH1,wA"," +a8(B)<<"," +a1);q4 +Lha;qT +hI +wB(279,m0 +aX +mH,mI +qH1,wA"," +a8(B)wM);q4 +Lhb +qU +q6:mW(277,aY +aX +mH,"[y*x] B" +mF,wA"," +a8(B)<<"," +a1);q4 +Lhc;} +qT +h3:qQ +hE +d3 +3 +h1 +if(x+oU +wB(318,"cDup[x+x==Value_t(1)]" +aZ +wH +a7,"cMul" +,wN);q4 +Lhd;} +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Lhe;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lhf;} +if((y*x)==fp_const_rad_to_deg +h7 +wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]" +wH +a7,"cDeg" +,q81);q4 +Ldg;} +if((y*x)==fp_const_deg_to_rad +h7 +wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]" +wH +a7,"cRad" +,q81);q4 +Ldh;} +wB(128,"y" +wH +a7,m3,q81);q4 +Lhg;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Lhh +qU +cRDiv:qQ +hE +qV +o5 +3 +qZ +mW(285,"y" +wH +a9 +a7,m3 +a9,q81);q4 +Lhi;qT +hI +wB(286,qC1 +a9 +a7,mI +a9,wN);q4 +Lhj +qU +q6:mW(284,"y" +a9 +a7,"[y*x]" +a9,q81);q4 +Lhk;qT +cRad:wB(210,"cRad" +a7,"[DegreesToRadians(x)]" +wH,wN);q4 +Lhl +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lhm;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Lhn;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lba;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Lho;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Lhp;} +if(x==fp_const_rad_to_deg +h7 +wB(207,"x[x==fp_const_rad_to_deg<Value_t>()]" +wH,"cDeg" +,wN);q4 +Lhq;} +if(x==fp_const_deg_to_rad +h7 +wB(208,"x[x==fp_const_deg_to_rad<Value_t>()]" +wH,"cRad" +,wN);q4 +Lia;h8 +g7 +dY:;A=dF +qO +A +gQ +cDiv:hC +wB(274,aX"cDiv " +wS,"[DO_STACKPLUS1] A" +wH +qH1,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Lib;} +q4 +d5 +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgc;} +q4 +dZ;g7 +dZ:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Lic;} +} +q4 +d5 +hI +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lgb;} +q4 +d5 +cRDiv +hL +qZ +qC +wB(267,"x" +a9" " +wS,"[DO_STACKPLUS1] " +mK +a9,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lid;} +wB(281,"cRDiv " +wS,"[DO_STACKPLUS1] A" +wH +a9,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lie;g7 +Default4:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lfq;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lif;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:oL +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Lig +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Lig;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Lih;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Lii;qT +hI +wB(61,qC1 +aA,,);oS +qU +cSin:g9 +wB(244,"x" +wH" " +mP +aA,mI" " +mP,wN);q4 +Lij;} +qT +oQ +g9 +wB(245,"x" +wH" cSinh" +aA,mI" cSinh" +,wN);q4 +Lik;} +qT +cTan:g9 +wB(246,"x" +wH" " +mR +aA,mI" " +mR,wN);q4 +Lil;} +qT +cTanh:g9 +wB(247,"x" +wH" cTanh" +aA,mI" cTanh" +,wN);q4 +Lim;} +qT +hM +wB(100,"x" +aA,"[-x]" +,wN);q4 +Lin;} +qH +TailCall_cNot:g5 +cNot:qS +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Lio +qU +w8:wB(220,aE +a0,wW,);q4 +Lip +qU +o1:wB(218,m2 +a0,aR,);q4 +Liq +qU +dK:wB(219,aG +a0,mJ,);q4 +Lja +qU +cLess:wB(216,mJ +a0,aG,);q4 +Ljb +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Ljc +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Ljd +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbd +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Lje +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Ljf;} +qH +TailCall_cNotNot:g5 +dS +d4 +dF==cNot){wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +w7 +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Ljg;h8} +qH +TailCall_cPolar:g5 +cPolar +d4 +q0[0 +qZ +y=q7;qJ +x +gO +wB(194,"x " +aY"cPolar" +,"[fp_polar(x,y)]" +," with " +aY"= " +<<y +qD1 +wM);q4 +Ljh;qG +TailCall_cPow:g5 +cPow:qY +if(isInteger(x +gQ +w2 +wB(43,q21 +wT,wX +mL,wN);q4 +Lji +qU +cExp2:wB(44,"cExp2 " +wT,wX +q31,wN);q4 +Ljj +qU +cPow +hL +qZ +hP!isInteger(y)){wB(42,"y[!isInteger(y)] " +q61 +wT,aP,q81);q4 +Ljk;} +} +wB(45,q61 +wT,wX" cPow" +,wN);q4 +Ljl;} +} +g8)){wB(83,"x[x==Value_t()] cPow" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,wN);q4 +Ljm;} +g8 +oO +wB(332,"x[x==Value_t(0.5)] cPow" +,q51,wN);q4 +Ljn;} +g8 +1)/g1 +3)){wB(333,"x[x==Value_t(1)/Value_t(3)] cPow" +,"cCbrt" +,wN);q4 +Ljo;} +g8 +1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)] cPow" +,"cCbrt " +aU,wN);q4 +Ljp;} +g8-oO +wB(335,"x[x==Value_t(-0.5)] cPow" +,"cRSqrt" +,wN);q4 +Ljq;} +g8-oG +wB(336,"x[x==Value_t(-1)] cPow" +,aU,wN);q4 +Lka;} +qQ +h9 +cPow +hL +qZ +mW(330,aY +q61 +m8,aP,q81);q4 +Ljk;o2 +wB(46,q41 +m8,"[x+x] cPow" +,wN);q4 +Lkb +qU +q6:mW(189,aY +m8,"[fp_pow(y,x)]" +,q81);q4 +Lkc;} +wB(455,m8,"[DO_POWI]" +,wN)qR +TryCompilePowi(x))gJ} +qH +TailCall_cRDiv:g5 +cRDiv:qS +cSinCos:wB(503,"cSinCos" +a9,"cCot" +,);q4 +Leq +qU +cSinhCosh:wB(510,"cSinhCosh" +a9,"cTanh " +aU,);q4 +Lkd +gY +g8 +oG +wB(268,wO"cRDiv" +,aU,wN);q4 +Lka;h8} +qH +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Leh;} +qH +TailCall_cRad:g5 +cRad:qS +h3 +gM +wB(211,"x" +wH" cRad" +,"[DegreesToRadians(x)]" +wH,wN);q4 +Lke;qT +hM +wB(134,"x cRad" +,"[DegreesToRadians(x)]" +,wN);q4 +Lkf;} +qH +TailCall_cReal:g5 +cReal:qY +wB(191,"x cReal" +,"[fp_real(x)]" +,wN);q4 +Lkg;} +qH +TailCall_cSec:g5 +cSec:A=qN +qQ +h9 +cCos:hD +wB(497,aK" " +aO" " +wI"cSec" +,"B " +aO" " +aT,aI(A)q91(B)wM);q4 +Lcb;qT +cSin:hD +wB(495,aK" " +mP" " +wI"cSec" +,"B cSinCos " +aU,aI(A)q91(B)wM);q4 +Lkh;h8 +qG +TailCall_cSin:g5 +cSin:qS +cAsin:wB(345,"cAsin " +mP,,);q4 +oE +wB(240,m0 +mP,mP +aA,);q4 +Lki +gY +wB(183,"x " +mP,"[fp_sin(x)]" +,wN);q4 +Lkj;oH +qN +oY +cCsc +q11(499,aK" cCsc " +wI +mP,"B cCsc " +aT,aI(A)q91(B)wM);q4 +Lcb;} +} +qG +TailCall_cSinh:g5 +oQ +qS +cAcosh:wB(437,"cAcosh cSinh" +,"[DO_STACKPLUS1] " +q41"[Value_t(-1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lkk +qU +cAsinh:wB(349,"cAsinh cSinh" +,,);q4 +oE +wB(241,m0"cSinh" +,"cSinh" +aA,);q4 +Lkl +gY +wB(184,"x cSinh" +,"[fp_sinh(x)]" +,wN);q4 +Lkm;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Lkn +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Lkn +qU +cSqrt:A=dE +wB(338,wJ +q51" cSqr" +,"A" +,aI(A)wM);oS;h8} +qH +TailCall_cSqrt:g5 +cSqrt:qS +hS +d4 +qK +o3 +A=hE +w0 +if(oC +o3 +wB(512,"cSqr" +a3 +q41 +aQ,"A cHypot" +,aI(A)wM);q4 +Lko;} +} +B +g4 +gV +B)){A=oC +w0 +if(qL +4]o3 +wB(513,"cSqr" +a3"B[IsUnaryOpcode(B)] " +q41 +aQ,"A B cHypot" +," with" +a8(B)qE1(A)wM);q4 +Lkp;} +} +} +o2 +wB(23,q41 +q51,mV,);q4 +Lkq +gY +wB(185,"x " +q51,"[fp_sqrt(x)]" +,wN);q4 +Lla;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Leh +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Llb +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lba;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Llc;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lld +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Lle;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Llf;} +qG +TailCall_cTan:g5 +cTan:qS +cAtan2:wB(354,"cAtan2 " +mR,"cDiv" +,);q4 +Lga +oF +wB(242,m0 +mR,mR +aA,);q4 +Llg +gY +wB(187,"x " +mR,"[fp_tan(x)]" +,wN);q4 +Llh;oH +qN +oY +cCot +q11(501,aK" cCot " +wI +mR,"B cCot " +aT,aI(A)q91(B)wM);q4 +Lcb;} +} +qG +TailCall_cTanh:g5 +cTanh:qS +cAtanh:wB(352,"cAtanh cTanh" +,,);q4 +oE +wB(243,m0"cTanh" +,"cTanh" +aA,);q4 +Lli +gY +wB(188,"x cTanh" +,"[fp_tanh(x)]" +,wN);q4 +Llj;} +qH +TailCall_cTrunc:g5 +cTrunc:qS +hM +wB(138,"x cTrunc" +,"[fp_trunc(x)]" +,wN);q4 +Llk +gS +wB(394,"A[IsAlwaysIntegerOpcode(A)] cTrunc" +,"A" +,aI(A)wM);gJ +qG +g7 +Default0:;A=w5 +w1 +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lll;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Llm;} +} +} +} +C=w5 +qR +IsCommutativeOrParamSwappableBinaryOpcode(C)){qS +cSin:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(505,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] " +mP" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinCos {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Lln;} +} +qT +oQ +A=qK +w1 +3 +gA]==cCosh){B=hQ +wB(506,aK" " +aM" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Llo;} +} +h8} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +Llp:wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:q7=fp_acos +m6 +Lae:q7=fp_acosh +m6 +Laf:oZ +4));gG +Llq:w5=h3;Lma:g0 +Lmb:wE(cMul);q4 +TailCall_cMul;Lag:hV +4 +dT +oZ +4));Lmc:qW +q6 +hY;Lah:q7=x+g1 +1);gG +Lfb:w5=h3;q4 +Lmb;Lai:gU +cSub;Lmd:wE(cSub);q4 +TailCall_cSub;Laj:hW +2 +gH +Lme:g0 +Lmf:wE(cAdd);q4 +TailCall_cAdd;Lak:hW +oR +Lmg:qE +hS);Lmh:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Lal:o9;qL +2 +gK +q4 +Lmg;Lam:hW +2 +gH +q4 +Lmh;Lan:hW +4 +gH +Lmi:qE +hS);Lmj:qE +B);Lmk:w5=cSub;g0 +q4 +Lmd;Lao:o9;oC=q6 +q9 +oR +q4 +Lmi;Lap:hW +oR +q4 +Lmj;Laq:gT +y+x;Lba:qM +Lbo:q5 +gJ +Lbb:q8 +oV +o7 +x +q71 +gX +Lmg;Lbc:mM +A +gX +Lmg;Lbd:gU +dS;wE(cNotNot);q4 +TailCall_cNotNot;Lbe:gT +fp_and(x +d6 +Lbf:q7=fp_arg +m6 +Lbg:q7=fp_asin +m6 +Lbh:q7=fp_asinh +m6 +Lbi:q7=fp_atan +m6 +Lbj:gT +fp_atan2(gW +Lbk:q7=fp_atanh +m6 +Lbl:q7=fp_cbrt +m6 +Lbm:q1 +cFloor);Lml:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lbn:q7=fp_ceil +m6 +Lbp:q7=fp_conj +m6 +Lbq:g6 +Lmm:wE(cCos);q4 +TailCall_cCos;Lca:q7=fp_cos +m6 +Lcb:dF=cDup;w5=cInv;Lmn:wE(cInv);q4 +TailCall_cInv;Lcc:mM +cSinCos);gJ +Lcd:q1 +cSqr +o7 +g1 +1));Lmo:qW +q6 +oJ +hS);Lmp:w5=cSqrt;g0 +wE(cSqrt);q4 +TailCall_cSqrt;Lce:g6 +wE(cCosh);q4 +TailCall_cCosh;Lcf:q7=fp_cosh +m6 +Lcg:mM +cSinhCosh);gJ +Lch:q7=RadiansToDegrees +m6 +Lci:q1 +cSec +hY;Lcj:q1 +cTan +hY;Lck:q1 +cSin +hY;Lcl:oZ));dF +dJ +Lmq:qE +dU +oZ +1));Lna:qW +q6);Lnb:w5=hS;q4 +Lme;Lcm:q1 +cNeg +oJ +cExp +hY;Lcn:q1 +cNeg +oJ +cExp2 +hY;Lco:g6 +q4 +Lfb;Lcp:q1 +cNeg +oJ +cPow +hY;Lcq:q1 +cCos +hY;Lda:q1 +cCsc +hY;Ldb:gU +cTan;Lnc:wE(cTan);q4 +TailCall_cTan;Ldc:gU +cTanh;Lnd:wE(cTanh);q4 +TailCall_cTanh;Ldd:q1 +cCot +hY;Lde:o9;dI +Lne:wE(cDiv);q4 +TailCall_cDiv;Ldf:gT +y/x;q4 +Lba;Ldg:qF1 +q8 +oR +Lnf:w5=cDeg;g0 +wE(cDeg);q4 +TailCall_cDeg;Ldh:qF1 +q8 +oR +Lng:w5=cRad;g0 +wE(cRad);q4 +TailCall_cRad;Ldi:gT +y/x;dG +Llq;Ldj:q7=g1 +1)/x;q4 +Lfb;Ldk:mM +oI +Lnh:g0 +q4 +Lne;Ldl:q8 +3 +gC +oI +qF +x +q71);Lni:w5=cRDiv;g0 +wE(cRDiv);q4 +TailCall_cRDiv;Ldm:hV +3 +gC +oI +qE +B +gX +Lni;Ldn:dI +Lnj:wE(cEqual);q4 +TailCall_cEqual;Ldo:gT +fp_equal(gW +Ldp:d7 +cExp +o7 +fp_exp(x)gX +Lmc;Ldq:q7=fp_exp +m6 +Lea:d7 +cExp2 +o7 +fp_exp2(x)gX +Lmc;Leb:q7=fp_exp2 +m6 +Lec:qF +oW +g1 +2))q71);Lnk:qE +h3 +gI +cExp;g0 +wE(cExp);q4 +TailCall_cExp;Led:q1 +cCeil +oT +Lee:q7=fp_floor +m6 +Lef:gT +fp_less(x +d6 +Leg:gT +fp_lessOrEq(x +d6 +Leh:oZ));Lnl:dF +dJ +q4 +Llq;Lei:q7=fp_imag +m6 +Lej:q7=fp_int +m6 +Lek:gU +cSec;wE(cSec);q4 +TailCall_cSec;Lel:gU +cSin;Lnm:wE(cSin);q4 +TailCall_cSin;Lem:q1 +cNeg +gI +cPow;Lnn:g0 +Lno:wE(cPow);q4 +TailCall_cPow;Len:gU +cCos;q4 +Lmm;Leo:gU +cCsc;wE(cCsc);q4 +TailCall_cCsc;Lep:q1 +cRSqrt);gJ +Leq:g6 +Lnp:w5=cCot;wE(cCot);q4 +TailCall_cCot;Lfa:q7=g1 +1)/x;gJ +Lfc:gT +fp_less(gW +Lfd:gT +fp_lessOrEq(gW +Lfe:d7 +cLog +o7 +oW +x)gX +Lna;Lff:q7=oW +x);gJ +Lfg:qF +dR +fp_const_e<dH>())gX +Lnl;Lfh:d7 +cLog10 +o7 +dR +x)gX +Lna;Lfi:q7=dR +x);gJ +Lfj:qF +o4 +fp_const_e<dH>())gX +Lnl;Lfk:d7 +cLog2 +o7 +o4 +x)gX +Lna;Lfl:q7=o4 +x);gJ +Lfm:gT +fp_max(x +d6 +Lfn:gT +fp_min(x +d6 +Lfo:gT +fp_mod(gW +Lfp:hV +oR +q0-=3;q4 +Lnp;Lfq:gU +cSqr;Lnq:wE(cSqr);q4 +TailCall_cSqr;Lga:gU +cDiv;q4 +Lne;Lgb:mM +cSqr +oT +Lgc:hV +3 +gC +cSqr);dM +Lml;Lgd:q7=x+g1 +1);gG +w5=cPow;q4 +Lno;Lge:gG +q4 +Lmb;Lgf:gT +x;Loa:dG +Lma;Lgg:qF1 +qM +Lob:hV +4 +gH +Loc:o6 +x);Lod:qW +q6 +gX +Lma;Lgh:qM +q4 +Lob;Lgi:q8 +4 +gC +B +gX +Loc;Lgj:q8 +oR +q4 +Loc;Lgk:qK +dJ +oS;Lgl:dI +q4 +Lmb;Lgm:qM +Loe:hV +oR +gJ +Lgn:q7=x+x;q4 +Lge;Lgo:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lnb;Lgp:gT +x;d7 +dU +qF +y*x +gX +Lna;Lgq:q7=RadiansToDegrees(x +gX +Lgl;Lha:qG1 +q8 +4 +gH +Lof:qE +dU +Log:qE +B +gI +cDiv;q4 +Lnh;Lhb:o9;oC=q6 +q9 +oR +q4 +Lof;Lhc:qG1 +q8 +oR +q4 +Log;Lhd:q8 +4 +gH +q4 +Lma;Lhe:q8 +4 +dT +qF +x+x +gX +Lod;Lhf:qF1 +qM +q4 +Loe;Lhg:qG1 +q4 +Loa;Lhh:o9;q4 +Lgl;Lhi:qG1 +q8 +oR +Loh:dM +Lni;Lhj:o9;qL +2 +gK +q4 +Loh;Lhk:qG1 +dG +Lni;Lhl:q7=h4 +gX +Lgl;Lhm:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lmk;Lhn:qG1 +q4 +Lba;Lho:qM +w3 +Lml;Lhp:dF=cDup;dW-=1;qM +Loi:w5=hS;q4 +Lmf;Lhq:qM +w3 +Lnf;Lia:qM +w3 +Lng;Lib:hV +oV +gX +Lof;Lic:hV +2 +gH +Loj:qE +cSqr +gX +Lma;Lid:q8 +oV +o7 +x +q71 +gX +Loh;Lie:mM +A +gX +Loh;Lif:hV +oR +q4 +Loj;Lig:dI +Lok:wE(cNEqual);q4 +TailCall_cNEqual;Lih:gT +fp_nequal(gW +Lii:o9;q4 +Lco;Lij:o9 +gB +cSin;g0 +q4 +Lnm;Lik:o9 +gB +cSinh;g0 +wE(cSinh);q4 +TailCall_cSinh;Lil:o9 +gB +cTan;g0 +q4 +Lnc;Lim:o9 +gB +cTanh;g0 +q4 +Lnd;Lin:o9;gJ +Lio:q1 +cAbsNot);gJ +Lip:gU +cNEqual;q4 +Lok;Liq:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Lja:gU +cLess;wE(cLess);q4 +TailCall_cLess;Ljb:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Ljc:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Ljd:gU +w8;q4 +Lnj;Lje:g6 +wE(cNot);q4 +TailCall_cNot;Ljf:q7=fp_not +m6 +Ljg:gT +fp_or(x +d6 +Ljh:gT +fp_polar(x +d6 +Lji:dL +Lnk;Ljj:qK=d8 +cExp2;g0 +wE(cExp2);q4 +TailCall_cExp2;Ljk:qG1 +dG +Lnn;Ljl:qK +dJ +q1 +h3 +gX +Lnn;Ljm:q7=g1 +gX +Lmq;Ljn:qM +w3 +Lmp;Ljo:qM +q5 +w5=cCbrt;g0 +wE(cCbrt);q4 +TailCall_cCbrt;Ljp:qM +q1 +cCbrt);Lol:w5=cInv;g0 +q4 +Lmn;Ljq:qM +q4 +Lep;Lka:qM +w3 +Lol;Lkb:q7=x+x;dI +q4 +Lno;Lkc:gT +oX +gW +Lkd:q1 +cTanh +gX +Lol;Lke:q7=h4 +gX +Lco;Lkf:q7=h4);gJ +Lkg:q7=fp_real +m6 +Lkh:mM +cSinCos +gX +Lol;Lki:q1 +cSin +oT +Lkj:q7=fp_sin +m6 +Lkk:q1 +cSqr +o7 +g1-1)gX +Lmo;Lkl:q1 +cSinh +oT +Lkm:q7=fp_sinh +m6 +Lkn:g6 +q4 +Lnq;Lko:hV +4 +gC +A);Lom:w5=cHypot;g0 +wE(cHypot);q4 +TailCall_cHypot;Lkp:hV +5 +gC +A +oJ +B +gX +Lom;Lkq:gU +cAbs;q4 +Llp;Lla:q7=fp_sqrt +m6 +Llb:g6 +q4 +Loi;Llc:gT +y-x;q4 +Lba;Lld:o9;q4 +Loi;Lle:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lmh;Llf:mM +A +oJ +cSub +gX +Lmh;Llg:q1 +cTan +oT +Llh:q7=fp_tan +m6 +Lli:q1 +cTanh +oT +Llj:q7=fp_tanh +m6 +Llk:q7=fp_trunc +m6 +Lll:qW +cDup);gJ +Llm:dF=cDup;gJ +Lln:hV +3 +gC +cSinCos);Lon:qE +GetParamSwappedBinaryOpcode(C));gJ +Llo:hV +3 +gC +cSinhCosh +gX +Lon;gJ +q4 +TailCall_cAcos;q4 +TailCall_cAcosh;q4 +TailCall_cAnd;q4 +TailCall_cArg;q4 +TailCall_cAsin;q4 +TailCall_cAsinh;q4 +TailCall_cAtan;q4 +TailCall_cAtan2;q4 +TailCall_cAtanh;q4 +TailCall_cCeil;q4 +TailCall_cConj;q4 +TailCall_cFloor;q4 +TailCall_cImag;q4 +TailCall_cInt;q4 +TailCall_cLog;q4 +TailCall_cLog10;q4 +TailCall_cLog2;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cOr;q4 +TailCall_cPolar;q4 +TailCall_cRDiv;q4 +TailCall_cRad;q4 +TailCall_cReal;q4 +TailCall_cSec;q4 +TailCall_cSin;q4 +TailCall_cSinh;q4 +TailCall_cSqrt;q4 +TailCall_cSub;q4 +TailCall_cTan;q4 +TailCall_cTanh;q4 +TailCall_cTrunc; +#endif +#undef FP_ReDefinePointers +#undef FP_TRACE_BYTECODE_OPTIMIZATION +#undef FP_TRACE_OPCODENAME diff --git a/fparser/extrasrc/fpaux.hh b/fparser/extrasrc/fpaux.hh new file mode 100644 index 0000000..fe2011c --- /dev/null +++ b/fparser/extrasrc/fpaux.hh @@ -0,0 +1,1238 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_AUX_H_ +#define ONCE_FPARSER_AUX_H_ + +#include "fptypes.hh" + +#include <cmath> + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +#include "mpfr/MpfrFloat.hh" +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +#include "mpfr/GmpInt.hh" +#endif + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS +#include <complex> +#endif + +#ifdef ONCE_FPARSER_H_ +namespace FUNCTIONPARSERTYPES +{ + template<typename> + struct IsIntType + { + enum { result = false }; + }; + template<> + struct IsIntType<long> + { + enum { result = true }; + }; +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + struct IsIntType<GmpInt> + { + enum { result = true }; + }; +#endif + + template<typename> + struct IsComplexType + { + enum { result = false }; + }; +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename T> + struct IsComplexType<std::complex<T> > + { + enum { result = true }; + }; +#endif + + +//========================================================================== +// Constants +//========================================================================== + template<typename Value_t> + inline Value_t fp_const_pi() // CONSTANT_PI + { + return Value_t(3.1415926535897932384626433832795028841971693993751L); + } + + template<typename Value_t> + inline Value_t fp_const_e() // CONSTANT_E + { + return Value_t(2.7182818284590452353602874713526624977572L); + } + template<typename Value_t> + inline Value_t fp_const_einv() // CONSTANT_EI + { + return Value_t(0.367879441171442321595523770161460867445811131L); + } + template<typename Value_t> + inline Value_t fp_const_log2() // CONSTANT_L2, CONSTANT_L2EI + { + return Value_t(0.69314718055994530941723212145817656807550013436025525412L); + } + template<typename Value_t> + inline Value_t fp_const_log10() // CONSTANT_L10, CONSTANT_L10EI + { + return Value_t(2.302585092994045684017991454684364207601101488628772976L); + } + template<typename Value_t> + inline Value_t fp_const_log2inv() // CONSTANT_L2I, CONSTANT_L2E + { + return Value_t(1.442695040888963407359924681001892137426645954L); + } + template<typename Value_t> + inline Value_t fp_const_log10inv() // CONSTANT_L10I, CONSTANT_L10E + { + return Value_t(0.434294481903251827651128918916605082294397L); + } + + template<typename Value_t> + inline const Value_t& fp_const_deg_to_rad() // CONSTANT_DR + { + static const Value_t factor = fp_const_pi<Value_t>() / Value_t(180); // to rad from deg + return factor; + } + + template<typename Value_t> + inline const Value_t& fp_const_rad_to_deg() // CONSTANT_RD + { + static const Value_t factor = Value_t(180) / fp_const_pi<Value_t>(); // to deg from rad + return factor; + } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline MpfrFloat fp_const_pi<MpfrFloat>() { return MpfrFloat::const_pi(); } + + template<> + inline MpfrFloat fp_const_e<MpfrFloat>() { return MpfrFloat::const_e(); } + + template<> + inline MpfrFloat fp_const_einv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_e(); } + + template<> + inline MpfrFloat fp_const_log2<MpfrFloat>() { return MpfrFloat::const_log2(); } + + /* + template<> + inline MpfrFloat fp_const_log10<MpfrFloat>() { return fp_log(MpfrFloat(10)); } + + template<> + inline MpfrFloat fp_const_log2inv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_log2(); } + + template<> + inline MpfrFloat fp_const_log10inv<MpfrFloat>() { return fp_log10(MpfrFloat::const_e()); } + */ +#endif + + +//========================================================================== +// Generic math functions +//========================================================================== + template<typename Value_t> + inline Value_t fp_abs(const Value_t& x) { return std::fabs(x); } + + template<typename Value_t> + inline Value_t fp_acos(const Value_t& x) { return std::acos(x); } + + template<typename Value_t> + inline Value_t fp_asin(const Value_t& x) { return std::asin(x); } + + template<typename Value_t> + inline Value_t fp_atan(const Value_t& x) { return std::atan(x); } + + template<typename Value_t> + inline Value_t fp_atan2(const Value_t& x, const Value_t& y) + { return std::atan2(x, y); } + + template<typename Value_t> + inline Value_t fp_ceil(const Value_t& x) { return std::ceil(x); } + + template<typename Value_t> + inline Value_t fp_cos(const Value_t& x) { return std::cos(x); } + + template<typename Value_t> + inline Value_t fp_cosh(const Value_t& x) { return std::cosh(x); } + + template<typename Value_t> + inline Value_t fp_exp(const Value_t& x) { return std::exp(x); } + + template<typename Value_t> + inline Value_t fp_floor(const Value_t& x) { return std::floor(x); } + + template<typename Value_t> + inline Value_t fp_log(const Value_t& x) { return std::log(x); } + + template<typename Value_t> + inline Value_t fp_mod(const Value_t& x, const Value_t& y) + { return std::fmod(x, y); } + + template<typename Value_t> + inline Value_t fp_sin(const Value_t& x) { return std::sin(x); } + + template<typename Value_t> + inline Value_t fp_sinh(const Value_t& x) { return std::sinh(x); } + + template<typename Value_t> + inline Value_t fp_sqrt(const Value_t& x) { return std::sqrt(x); } + + template<typename Value_t> + inline Value_t fp_tan(const Value_t& x) { return std::tan(x); } + + template<typename Value_t> + inline Value_t fp_tanh(const Value_t& x) { return std::tanh(x); } + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_asinh(const Value_t& x) { return std::asinh(x); } + + template<typename Value_t> + inline Value_t fp_acosh(const Value_t& x) { return std::acosh(x); } + + template<typename Value_t> + inline Value_t fp_atanh(const Value_t& x) { return std::atanh(x); } +#else + template<typename Value_t> + inline Value_t fp_asinh(const Value_t& x) + { return fp_log(x + fp_sqrt(x*x + Value_t(1))); } + + template<typename Value_t> + inline Value_t fp_acosh(const Value_t& x) + { return fp_log(x + fp_sqrt(x*x - Value_t(1))); } + + template<typename Value_t> + inline Value_t fp_atanh(const Value_t& x) + { + return fp_log( (Value_t(1)+x) / (Value_t(1)-x)) * Value_t(0.5); + // Note: x = +1 causes division by zero + // x = -1 causes log(0) + // Thus, x must not be +-1 + } +#endif // FP_SUPPORT_ASINH + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_hypot(const Value_t& x, const Value_t& y) + { return std::hypot(x,y); } +#else + template<typename Value_t> + inline Value_t fp_hypot(const Value_t& x, const Value_t& y) + { return fp_sqrt(x*x + y*y); } +#endif + + template<typename Value_t> + inline Value_t fp_pow_base(const Value_t& x, const Value_t& y) + { return std::pow(x, y); } + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_log2(const Value_t& x) { return std::log2(x); } +#else + template<typename Value_t> + inline Value_t fp_log2(const Value_t& x) + { + return fp_log(x) * fp_const_log2inv<Value_t>(); + } +#endif // FP_SUPPORT_LOG2 + + template<typename Value_t> + inline Value_t fp_log10(const Value_t& x) + { + return fp_log(x) * fp_const_log10inv<Value_t>(); + } + + template<typename Value_t> + inline Value_t fp_trunc(const Value_t& x) + { + return x < Value_t() ? fp_ceil(x) : fp_floor(x); + } + + template<typename Value_t> + inline Value_t fp_int(const Value_t& x) + { + return x < Value_t() ? + fp_ceil(x - Value_t(0.5)) : fp_floor(x + Value_t(0.5)); + } + + template<typename Value_t> + inline void fp_sinCos(Value_t& sinvalue, Value_t& cosvalue, + const Value_t& param) + { + // Assuming that "cosvalue" and "param" do not + // overlap, but "sinvalue" and "param" may. + cosvalue = fp_cos(param); + sinvalue = fp_sin(param); + } + + template<typename Value_t> + inline void fp_sinhCosh(Value_t& sinhvalue, Value_t& coshvalue, + const Value_t& param) + { + const Value_t ex(fp_exp(param)), emx(fp_exp(-param)); + sinhvalue = Value_t(0.5)*(ex-emx); + coshvalue = Value_t(0.5)*(ex+emx); + } + + template<typename Value_t> + struct Epsilon + { + static Value_t value; + static Value_t defaultValue() { return 0; } + }; + + template<> inline double Epsilon<double>::defaultValue() { return 1E-12; } + template<> inline float Epsilon<float>::defaultValue() { return 1E-5F; } + template<> inline long double Epsilon<long double>::defaultValue() { return 1E-14L; } + + template<> inline std::complex<double> + Epsilon<std::complex<double> >::defaultValue() { return 1E-12; } + + template<> inline std::complex<float> + Epsilon<std::complex<float> >::defaultValue() { return 1E-5F; } + + template<> inline std::complex<long double> + Epsilon<std::complex<long double> >::defaultValue() { return 1E-14L; } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> inline MpfrFloat + Epsilon<MpfrFloat>::defaultValue() { return MpfrFloat::someEpsilon(); } +#endif + + template<typename Value_t> Value_t Epsilon<Value_t>::value = + Epsilon<Value_t>::defaultValue(); + + +#ifdef _GNU_SOURCE + inline void fp_sinCos(double& sin, double& cos, const double& a) + { + sincos(a, &sin, &cos); + } + inline void fp_sinCos(float& sin, float& cos, const float& a) + { + sincosf(a, &sin, &cos); + } + inline void fp_sinCos(long double& sin, long double& cos, + const long double& a) + { + sincosl(a, &sin, &cos); + } +#endif + + +// ------------------------------------------------------------------------- +// Long int +// ------------------------------------------------------------------------- + inline long fp_abs(const long& x) { return x < 0 ? -x : x; } + inline long fp_acos(const long&) { return 0; } + inline long fp_asin(const long&) { return 0; } + inline long fp_atan(const long&) { return 0; } + inline long fp_atan2(const long&, const long&) { return 0; } + inline long fp_cbrt(const long&) { return 0; } + inline long fp_ceil(const long& x) { return x; } + inline long fp_cos(const long&) { return 0; } + inline long fp_cosh(const long&) { return 0; } + inline long fp_exp(const long&) { return 0; } + inline long fp_exp2(const long&) { return 0; } + inline long fp_floor(const long& x) { return x; } + inline long fp_log(const long&) { return 0; } + inline long fp_log2(const long&) { return 0; } + inline long fp_log10(const long&) { return 0; } + inline long fp_mod(const long& x, const long& y) { return x % y; } + inline long fp_pow(const long&, const long&) { return 0; } + inline long fp_sin(const long&) { return 0; } + inline long fp_sinh(const long&) { return 0; } + inline long fp_sqrt(const long&) { return 1; } + inline long fp_tan(const long&) { return 0; } + inline long fp_tanh(const long&) { return 0; } + inline long fp_asinh(const long&) { return 0; } + inline long fp_acosh(const long&) { return 0; } + inline long fp_atanh(const long&) { return 0; } + inline long fp_pow_base(const long&, const long&) { return 0; } + inline void fp_sinCos(long&, long&, const long&) {} + inline void fp_sinhCosh(long&, long&, const long&) {} + + //template<> inline long fp_epsilon<long>() { return 0; } + + +// ------------------------------------------------------------------------- +// MpfrFloat +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + inline MpfrFloat fp_abs(const MpfrFloat& x) { return MpfrFloat::abs(x); } + inline MpfrFloat fp_acos(const MpfrFloat& x) { return MpfrFloat::acos(x); } + inline MpfrFloat fp_acosh(const MpfrFloat& x) { return MpfrFloat::acosh(x); } + inline MpfrFloat fp_asin(const MpfrFloat& x) { return MpfrFloat::asin(x); } + inline MpfrFloat fp_asinh(const MpfrFloat& x) { return MpfrFloat::asinh(x); } + inline MpfrFloat fp_atan(const MpfrFloat& x) { return MpfrFloat::atan(x); } + inline MpfrFloat fp_atan2(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::atan2(x, y); } + inline MpfrFloat fp_atanh(const MpfrFloat& x) { return MpfrFloat::atanh(x); } + inline MpfrFloat fp_cbrt(const MpfrFloat& x) { return MpfrFloat::cbrt(x); } + inline MpfrFloat fp_ceil(const MpfrFloat& x) { return MpfrFloat::ceil(x); } + inline MpfrFloat fp_cos(const MpfrFloat& x) { return MpfrFloat::cos(x); } + inline MpfrFloat fp_cosh(const MpfrFloat& x) { return MpfrFloat::cosh(x); } + inline MpfrFloat fp_exp(const MpfrFloat& x) { return MpfrFloat::exp(x); } + inline MpfrFloat fp_exp2(const MpfrFloat& x) { return MpfrFloat::exp2(x); } + inline MpfrFloat fp_floor(const MpfrFloat& x) { return MpfrFloat::floor(x); } + inline MpfrFloat fp_hypot(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::hypot(x, y); } + inline MpfrFloat fp_int(const MpfrFloat& x) { return MpfrFloat::round(x); } + inline MpfrFloat fp_log(const MpfrFloat& x) { return MpfrFloat::log(x); } + inline MpfrFloat fp_log2(const MpfrFloat& x) { return MpfrFloat::log2(x); } + inline MpfrFloat fp_log10(const MpfrFloat& x) { return MpfrFloat::log10(x); } + inline MpfrFloat fp_mod(const MpfrFloat& x, const MpfrFloat& y) { return x % y; } + inline MpfrFloat fp_sin(const MpfrFloat& x) { return MpfrFloat::sin(x); } + inline MpfrFloat fp_sinh(const MpfrFloat& x) { return MpfrFloat::sinh(x); } + inline MpfrFloat fp_sqrt(const MpfrFloat& x) { return MpfrFloat::sqrt(x); } + inline MpfrFloat fp_tan(const MpfrFloat& x) { return MpfrFloat::tan(x); } + inline MpfrFloat fp_tanh(const MpfrFloat& x) { return MpfrFloat::tanh(x); } + inline MpfrFloat fp_trunc(const MpfrFloat& x) { return MpfrFloat::trunc(x); } + + inline MpfrFloat fp_pow(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + inline MpfrFloat fp_pow_base(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + + + inline void fp_sinCos(MpfrFloat& sin, MpfrFloat& cos, const MpfrFloat& a) + { + MpfrFloat::sincos(a, sin, cos); + } + + inline void fp_sinhCosh(MpfrFloat& sinhvalue, MpfrFloat& coshvalue, + const MpfrFloat& param) + { + const MpfrFloat paramCopy = param; + sinhvalue = fp_sinh(paramCopy); + coshvalue = fp_cosh(paramCopy); + } +#endif // FP_SUPPORT_MPFR_FLOAT_TYPE + + +// ------------------------------------------------------------------------- +// GMP int +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_GMP_INT_TYPE + inline GmpInt fp_abs(const GmpInt& x) { return GmpInt::abs(x); } + inline GmpInt fp_acos(const GmpInt&) { return 0; } + inline GmpInt fp_acosh(const GmpInt&) { return 0; } + inline GmpInt fp_asin(const GmpInt&) { return 0; } + inline GmpInt fp_asinh(const GmpInt&) { return 0; } + inline GmpInt fp_atan(const GmpInt&) { return 0; } + inline GmpInt fp_atan2(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_atanh(const GmpInt&) { return 0; } + inline GmpInt fp_cbrt(const GmpInt&) { return 0; } + inline GmpInt fp_ceil(const GmpInt& x) { return x; } + inline GmpInt fp_cos(const GmpInt&) { return 0; } + inline GmpInt fp_cosh(const GmpInt&) { return 0; } + inline GmpInt fp_exp(const GmpInt&) { return 0; } + inline GmpInt fp_exp2(const GmpInt&) { return 0; } + inline GmpInt fp_floor(const GmpInt& x) { return x; } + inline GmpInt fp_hypot(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_int(const GmpInt& x) { return x; } + inline GmpInt fp_log(const GmpInt&) { return 0; } + inline GmpInt fp_log2(const GmpInt&) { return 0; } + inline GmpInt fp_log10(const GmpInt&) { return 0; } + inline GmpInt fp_mod(const GmpInt& x, const GmpInt& y) { return x % y; } + inline GmpInt fp_pow(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_sin(const GmpInt&) { return 0; } + inline GmpInt fp_sinh(const GmpInt&) { return 0; } + inline GmpInt fp_sqrt(const GmpInt&) { return 0; } + inline GmpInt fp_tan(const GmpInt&) { return 0; } + inline GmpInt fp_tanh(const GmpInt&) { return 0; } + inline GmpInt fp_trunc(const GmpInt& x) { return x; } + inline GmpInt fp_pow_base(const GmpInt&, const GmpInt&) { return 0; } + inline void fp_sinCos(GmpInt&, GmpInt&, const GmpInt&) {} + inline void fp_sinhCosh(GmpInt&, GmpInt&, const GmpInt&) {} +#endif // FP_SUPPORT_GMP_INT_TYPE + + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_cbrt(const Value_t& x) { return std::cbrt(x); } +#else + template<typename Value_t> + inline Value_t fp_cbrt(const Value_t& x) + { + return (x > Value_t() ? fp_exp(fp_log( x) / Value_t(3)) : + x < Value_t() ? -fp_exp(fp_log(-x) / Value_t(3)) : + Value_t()); + } +#endif + +// ------------------------------------------------------------------------- +// Synthetic functions and fallbacks for when an optimized +// implementation or a library function is not available +// ------------------------------------------------------------------------- + template<typename Value_t> inline Value_t fp_arg(const Value_t& x); + template<typename Value_t> inline Value_t fp_exp2(const Value_t& x); + template<typename Value_t> inline Value_t fp_int(const Value_t& x); + template<typename Value_t> inline Value_t fp_trunc(const Value_t& x); + template<typename Value_t> + inline void fp_sinCos(Value_t& , Value_t& , const Value_t& ); + template<typename Value_t> + inline void fp_sinhCosh(Value_t& , Value_t& , const Value_t& ); + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + /* NOTE: Complex multiplication of a and b can be done with: + tmp = b.real * (a.real + a.imag) + result.real = tmp - a.imag * (b.real + b.imag) + result.imag = tmp + a.real * (b.imag - b.real) + This has fewer multiplications than the standard + algorithm. Take note, if you support mpfr complex one day. + */ + + template<typename T> + struct FP_ProbablyHasFastLibcComplex + { enum { result = false }; }; + /* The generic sqrt() etc. implementations in libstdc++ + * are very plain and non-optimized; however, it contains + * callbacks to libc complex math functions where possible, + * and I suspect that those may actually be well optimized. + * So we use std:: functions when we suspect they may be fast, + * and otherwise we use our own optimized implementations. + */ +#ifdef __GNUC__ + template<> struct FP_ProbablyHasFastLibcComplex<float> + { enum { result = true }; }; + template<> struct FP_ProbablyHasFastLibcComplex<double> + { enum { result = true }; }; + template<> struct FP_ProbablyHasFastLibcComplex<long double> + { enum { result = true }; }; +#endif + + template<typename T> + inline const std::complex<T> fp_make_imag(const std::complex<T>& v) + { + return std::complex<T> ( T(), v.real() ); + } + + template<typename T> + inline std::complex<T> fp_real(const std::complex<T>& x) + { + return x.real(); + } + template<typename T> + inline std::complex<T> fp_imag(const std::complex<T>& x) + { + return x.imag(); + } + template<typename T> + inline std::complex<T> fp_arg(const std::complex<T>& x) + { + return std::arg(x); + } + template<typename T> + inline std::complex<T> fp_conj(const std::complex<T>& x) + { + return std::conj(x); + } + template<typename T, bool> + inline std::complex<T> fp_polar(const T& x, const T& y) + { + T si, co; fp_sinCos(si, co, y); + return std::complex<T> (x*co, x*si); + } + template<typename T> + inline std::complex<T> fp_polar(const std::complex<T>& x, const std::complex<T>& y) + { + // x * cos(y) + i * x * sin(y) -- arguments are supposed to be REAL numbers + return fp_polar<T,true> (x.real(), y.real()); + //return std::polar(x.real(), y.real()); + //return x * (fp_cos(y) + (std::complex<T>(0,1) * fp_sin(y)); + } + + // These provide fallbacks in case there's no library function + template<typename T> + inline std::complex<T> fp_floor(const std::complex<T>& x) + { + return std::complex<T> (fp_floor(x.real()), fp_floor(x.imag())); + } + template<typename T> + inline std::complex<T> fp_trunc(const std::complex<T>& x) + { + return std::complex<T> (fp_trunc(x.real()), fp_trunc(x.imag())); + } + template<typename T> + inline std::complex<T> fp_int(const std::complex<T>& x) + { + return std::complex<T> (fp_int(x.real()), fp_int(x.imag())); + } + template<typename T> + inline std::complex<T> fp_ceil(const std::complex<T>& x) + { + return std::complex<T> (fp_ceil(x.real()), fp_ceil(x.imag())); + } + template<typename T> + inline std::complex<T> fp_abs(const std::complex<T>& x) + { + return std::abs(x); + //T extent = fp_max(fp_abs(x.real()), fp_abs(x.imag())); + //if(extent == T()) return x; + //return extent * fp_hypot(x.real() / extent, x.imag() / extent); + } + template<typename T> + inline std::complex<T> fp_exp(const std::complex<T>& x) + { + if(FP_ProbablyHasFastLibcComplex<T>::result) + return std::exp(x); + return fp_polar<T,true>(fp_exp(x.real()), x.imag()); + } + template<typename T> + inline std::complex<T> fp_log(const std::complex<T>& x) + { + if(FP_ProbablyHasFastLibcComplex<T>::result) + return std::log(x); + // log(abs(x)) + i*arg(x) + // log(Xr^2+Xi^2)*0.5 + i*arg(x) + if(x.imag()==T()) + return std::complex<T>( fp_log(fp_abs(x.real())), + fp_arg(x.real()) ); // Note: Uses real-value fp_arg() here! + return std::complex<T>( + fp_log(std::norm(x)) * T(0.5), + fp_arg(x).real() ); + } + template<typename T> + inline std::complex<T> fp_sqrt(const std::complex<T>& x) + { + if(FP_ProbablyHasFastLibcComplex<T>::result) + return std::sqrt(x); + return fp_polar<T,true> (fp_sqrt(fp_abs(x).real()), + T(0.5)*fp_arg(x).real()); + } + template<typename T> + inline std::complex<T> fp_acos(const std::complex<T>& x) + { + // -i * log(x + i * sqrt(1 - x^2)) + const std::complex<T> i (T(), T(1)); + return -i * fp_log(x + i * fp_sqrt(T(1) - x*x)); + // Note: Real version of acos() cannot handle |x| > 1, + // because it would cause sqrt(negative value). + } + template<typename T> + inline std::complex<T> fp_asin(const std::complex<T>& x) + { + // -i * log(i*x + sqrt(1 - x^2)) + const std::complex<T> i (T(), T(1)); + return -i * fp_log(i*x + fp_sqrt(T(1) - x*x)); + // Note: Real version of asin() cannot handle |x| > 1, + // because it would cause sqrt(negative value). + } + template<typename T> + inline std::complex<T> fp_atan(const std::complex<T>& x) + { + // 0.5i * (log(1-i*x) - log(1+i*x)) + // -0.5i * log( (1+i*x) / (1-i*x) ) + const std::complex<T> i (T(), T(1)); + return (T(-0.5)*i) * fp_log( (T(1)+i*x) / (T(1)-i*x) ); + // Note: x = -1i causes division by zero + // x = +1i causes log(0) + // Thus, x must not be +-1i + } + template<typename T> + inline std::complex<T> fp_cos(const std::complex<T>& x) + { + return std::cos(x); + // // (exp(i*x) + exp(-i*x)) / (2) + // //const std::complex<T> i (T(), T(1)); + // //return (fp_exp(i*x) + fp_exp(-i*x)) * T(0.5); + // // Also: cos(Xr)*cosh(Xi) - i*sin(Xr)*sinh(Xi) + // return std::complex<T> ( + // fp_cos(x.real())*fp_cosh(x.imag()), + // -fp_sin(x.real())*fp_sinh(x.imag())); + } + template<typename T> + inline std::complex<T> fp_sin(const std::complex<T>& x) + { + return std::sin(x); + // // (exp(i*x) - exp(-i*x)) / (2i) + // //const std::complex<T> i (T(), T(1)); + // //return (fp_exp(i*x) - fp_exp(-i*x)) * (T(-0.5)*i); + // // Also: sin(Xr)*cosh(Xi) + cos(Xr)*sinh(Xi) + // return std::complex<T> ( + // fp_sin(x.real())*fp_cosh(x.imag()), + // fp_cos(x.real())*fp_sinh(x.imag())); + } + template<typename T> + inline void fp_sinCos( + std::complex<T>& sinvalue, + std::complex<T>& cosvalue, + const std::complex<T>& x) + { + //const std::complex<T> i (T(), T(1)), expix(fp_exp(i*x)), expmix(fp_exp((-i)*x)); + //cosvalue = (expix + expmix) * T(0.5); + //sinvalue = (expix - expmix) * (i*T(-0.5)); + // The above expands to the following: + T srx, crx; fp_sinCos(srx, crx, x.real()); + T six, cix; fp_sinhCosh(six, cix, x.imag()); + sinvalue = std::complex<T>(srx*cix, crx*six); + cosvalue = std::complex<T>(crx*cix, -srx*six); + } + template<typename T> + inline void fp_sinhCosh( + std::complex<T>& sinhvalue, + std::complex<T>& coshvalue, + const std::complex<T>& x) + { + T srx, crx; fp_sinhCosh(srx, crx, x.real()); + T six, cix; fp_sinCos(six, cix, x.imag()); + sinhvalue = std::complex<T>(srx*cix, crx*six); + coshvalue = std::complex<T>(crx*cix, srx*six); + } + template<typename T> + inline std::complex<T> fp_tan(const std::complex<T>& x) + { + return std::tan(x); + //std::complex<T> si, co; + //fp_sinCos(si, co, x); + //return si/co; + // // (i-i*exp(2i*x)) / (exp(2i*x)+1) + // const std::complex<T> i (T(), T(1)), exp2ix=fp_exp((2*i)*x); + // return (i-i*exp2ix) / (exp2ix+T(1)); + // // Also: sin(x)/cos(y) + // // return fp_sin(x)/fp_cos(x); + } + template<typename T> + inline std::complex<T> fp_cosh(const std::complex<T>& x) + { + return std::cosh(x); + // // (exp(x) + exp(-x)) * 0.5 + // // Also: cosh(Xr)*cos(Xi) + i*sinh(Xr)*sin(Xi) + // return std::complex<T> ( + // fp_cosh(x.real())*fp_cos(x.imag()), + // fp_sinh(x.real())*fp_sin(x.imag())); + } + template<typename T> + inline std::complex<T> fp_sinh(const std::complex<T>& x) + { + return std::sinh(x); + // // (exp(x) - exp(-x)) * 0.5 + // // Also: sinh(Xr)*cos(Xi) + i*cosh(Xr)*sin(Xi) + // return std::complex<T> ( + // fp_sinh(x.real())*fp_cos(x.imag()), + // fp_cosh(x.real())*fp_sin(x.imag())); + } + template<typename T> + inline std::complex<T> fp_tanh(const std::complex<T>& x) + { + return std::tanh(x); + //std::complex<T> si, co; + //fp_sinhCosh(si, co, x); + //return si/co; + // // (exp(2*x)-1) / (exp(2*x)+1) + // // Also: sinh(x)/tanh(x) + // const std::complex<T> exp2x=fp_exp(x+x); + // return (exp2x-T(1)) / (exp2x+T(1)); + } + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename T> + inline std::complex<T> fp_acosh(const std::complex<T>& x) + { return fp_log(x + fp_sqrt(x*x - std::complex<T>(1))); } + template<typename T> + inline std::complex<T> fp_asinh(const std::complex<T>& x) + { return fp_log(x + fp_sqrt(x*x + std::complex<T>(1))); } + template<typename T> + inline std::complex<T> fp_atanh(const std::complex<T>& x) + { return fp_log( (std::complex<T>(1)+x) / (std::complex<T>(1)-x)) + * std::complex<T>(0.5); } +#endif + template<typename T> + inline std::complex<T> fp_pow(const std::complex<T>& x, const std::complex<T>& y) + { + // return std::pow(x,y); + + // With complex numbers, pow(x,y) can be solved with + // the general formula: exp(y*log(x)). It handles + // all special cases gracefully. + // It expands to the following: + // A) + // t1 = log(x) + // t2 = y * t1 + // res = exp(t2) + // B) + // t1.r = log(x.r * x.r + x.i * x.i) * 0.5 \ fp_log() + // t1.i = atan2(x.i, x.r) / + // t2.r = y.r*t1.r - y.i*t1.i \ multiplication + // t2.i = y.r*t1.i + y.i*t1.r / + // rho = exp(t2.r) \ fp_exp() + // theta = t2.i / + // res.r = rho * cos(theta) \ fp_polar(), called from + // res.i = rho * sin(theta) / fp_exp(). Uses sincos(). + // Aside from the common "norm" calculation in atan2() + // and in the log parameter, both of which are part of fp_log(), + // there does not seem to be any incentive to break this + // function down further; it would not help optimizing it. + // However, we do handle the following special cases: + // + // When x is real (positive or negative): + // t1.r = log(abs(x.r)) + // t1.i = x.r<0 ? -pi : 0 + // When y is real: + // t2.r = y.r * t1.r + // t2.i = y.r * t1.i + const std::complex<T> t = + (x.imag() != T()) + ? fp_log(x) + : std::complex<T> (fp_log(fp_abs(x.real())), + fp_arg(x.real())); // Note: Uses real-value fp_arg() here! + return y.imag() != T() + ? fp_exp(y * t) + : fp_polar<T,true> (fp_exp(y.real()*t.real()), y.real()*t.imag()); + } + template<typename T> + inline std::complex<T> fp_cbrt(const std::complex<T>& x) + { + // For real numbers, prefer giving a real solution + // rather than a complex solution. + // For example, cbrt(-3) has the following three solutions: + // A) 0.7211247966535 + 1.2490247864016i + // B) 0.7211247966535 - 1.2490247864016i + // C) -1.442249593307 + // exp(log(x)/3) gives A, but we prefer to give C. + if(x.imag() == T()) return fp_cbrt(x.real()); + const std::complex<T> t(fp_log(x)); + return fp_polar<T,true> (fp_exp(t.real() / T(3)), t.imag() / T(3)); + } + + template<typename T> + inline std::complex<T> fp_exp2(const std::complex<T>& x) + { + // pow(2, x) + // polar(2^Xr, Xi*log(2)) + return fp_polar<T,true> (fp_exp2(x.real()), x.imag()*fp_const_log2<T>()); + } + template<typename T> + inline std::complex<T> fp_mod(const std::complex<T>& x, const std::complex<T>& y) + { + // Modulo function is probably not defined for complex numbers. + // But we do our best to calculate it the same way as it is done + // with real numbers, so that at least it is in some way "consistent". + if(y.imag() == 0) return fp_mod(x.real(), y.real()); // optimization + std::complex<T> n = fp_trunc(x / y); + return x - n * y; + } + + /* libstdc++ already defines a streaming operator for complex values, + * but we redefine our own that it is compatible with the input + * accepted by fparser. I.e. instead of (5,3) we now get (5+3i), + * and instead of (-4,0) we now get -4. + */ + template<typename T> + inline std::ostream& operator<<(std::ostream& os, const std::complex<T>& value) + { + if(value.imag() == T()) return os << value.real(); + if(value.real() == T()) return os << value.imag() << 'i'; + if(value.imag() < T()) + return os << '(' << value.real() << "-" << -value.imag() << "i)"; + else + return os << '(' << value.real() << "+" << value.imag() << "i)"; + } + + /* Less-than or greater-than operators are not technically defined + * for Complex types. However, in fparser and its tool set, these + * operators are widely required to be present. + * Our implementation here is based on converting the complex number + * into a scalar and the doing a scalar comparison on the value. + * The means by which the number is changed into a scalar is based + * on the following principles: + * - Does not introduce unjustified amounts of extra inaccuracy + * - Is transparent to purely real values + * (this disqualifies something like x.real() + x.imag()) + * - Does not ignore the imaginary value completely + * (this may be relevant especially in testbed) + * - Is not so complicated that it would slow down a great deal + * + * Basically our formula here is the same as std::abs(), + * except that it keeps the sign of the original real number, + * and it does not do a sqrt() calculation that is not really + * needed because we are only interested in the relative magnitudes. + * + * Equality and nonequality operators must not need to be overloaded. + * They are already implemented in standard, and we must + * not introduce flawed equality assumptions. + */ + template<typename T> + inline T fp_complexScalarize(const std::complex<T>& x) + { + T res(std::norm(x)); + if(x.real() < T()) res = -res; + return res; + } + template<typename T> + inline T fp_realComplexScalarize(const T& x) + { + T res(x*x); + if(x < T()) res = -res; + return res; + } + // { return x.real() * (T(1.0) + fp_abs(x.imag())); } + #define d(op) \ + template<typename T> \ + inline bool operator op (const std::complex<T>& x, T y) \ + { return fp_complexScalarize(x) op fp_realComplexScalarize(y); } \ + template<typename T> \ + inline bool operator op (const std::complex<T>& x, const std::complex<T>& y) \ + { return fp_complexScalarize(x) op \ + fp_complexScalarize(y); } \ + template<typename T> \ + inline bool operator op (T x, const std::complex<T>& y) \ + { return fp_realComplexScalarize(x) op fp_complexScalarize(y); } + d( < ) d( <= ) d( > ) d( >= ) + #undef d +#endif + + template<typename Value_t> + inline Value_t fp_real(const Value_t& x) { return x; } + template<typename Value_t> + inline Value_t fp_imag(const Value_t& ) { return Value_t(); } + template<typename Value_t> + inline Value_t fp_arg(const Value_t& x) + { return x < Value_t() ? -fp_const_pi<Value_t>() : Value_t(); } + template<typename Value_t> + inline Value_t fp_conj(const Value_t& x) { return x; } + template<typename Value_t> + inline Value_t fp_polar(const Value_t& x, const Value_t& y) + { return x * fp_cos(y); } // This is of course a meaningless function. + + template<typename Value_t> + inline std::complex<Value_t> fp_atan2(const std::complex<Value_t>& y, + const std::complex<Value_t>& x) + { + if(y == Value_t()) return fp_arg(x); + if(x == Value_t()) return fp_const_pi<Value_t>() * Value_t(-0.5); + // 2*atan(y / (sqrt(x^2+y^2) + x) ) + // 2*atan( (sqrt(x^2+y^2) - x) / y) + std::complex<Value_t> res( fp_atan(y / (fp_hypot(x,y) + x)) ); + return res+res; + } + +// ------------------------------------------------------------------------- +// Comparison +// ------------------------------------------------------------------------- + template<typename Value_t> + inline bool fp_equal(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x == y) + : (fp_abs(x - y) <= Epsilon<Value_t>::value); } + + template<typename Value_t> + inline bool fp_nequal(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x != y) + : (fp_abs(x - y) > Epsilon<Value_t>::value); } + + template<typename Value_t> + inline bool fp_less(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x < y) + : (x < y - Epsilon<Value_t>::value); } + + template<typename Value_t> + inline bool fp_lessOrEq(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x <= y) + : (x <= y + Epsilon<Value_t>::value); } + + + template<typename Value_t> + inline bool fp_greater(const Value_t& x, const Value_t& y) + { return fp_less(y, x); } + + template<typename Value_t> + inline bool fp_greaterOrEq(const Value_t& x, const Value_t& y) + { return fp_lessOrEq(y, x); } + + template<typename Value_t> + inline bool fp_truth(const Value_t& d) + { + return IsIntType<Value_t>::result + ? d != Value_t() + : fp_abs(d) >= Value_t(0.5); + } + + template<typename Value_t> + inline bool fp_absTruth(const Value_t& abs_d) + { + return IsIntType<Value_t>::result + ? abs_d > Value_t() + : abs_d >= Value_t(0.5); + } + + template<typename Value_t> + inline const Value_t& fp_min(const Value_t& d1, const Value_t& d2) + { return d1<d2 ? d1 : d2; } + + template<typename Value_t> + inline const Value_t& fp_max(const Value_t& d1, const Value_t& d2) + { return d1>d2 ? d1 : d2; } + + template<typename Value_t> + inline const Value_t fp_not(const Value_t& b) + { return Value_t(!fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_notNot(const Value_t& b) + { return Value_t(fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_absNot(const Value_t& b) + { return Value_t(!fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_absNotNot(const Value_t& b) + { return Value_t(fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_and(const Value_t& a, const Value_t& b) + { return Value_t(fp_truth(a) && fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_or(const Value_t& a, const Value_t& b) + { return Value_t(fp_truth(a) || fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_absAnd(const Value_t& a, const Value_t& b) + { return Value_t(fp_absTruth(a) && fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_absOr(const Value_t& a, const Value_t& b) + { return Value_t(fp_absTruth(a) || fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_make_imag(const Value_t& ) // Imaginary 1. In real mode, always zero. + { + return Value_t(); + } + + ///////////// + /* Opcode analysis functions are used by fp_opcode_add.inc */ + /* Moved here from fparser.cc because fp_opcode_add.inc + * is also now included by fpoptimizer.cc + */ + bool IsLogicalOpcode(unsigned op); + bool IsComparisonOpcode(unsigned op); + unsigned OppositeComparisonOpcode(unsigned op); + bool IsNeverNegativeValueOpcode(unsigned op); + bool IsAlwaysIntegerOpcode(unsigned op); + bool IsUnaryOpcode(unsigned op); + bool IsBinaryOpcode(unsigned op); + bool IsVarOpcode(unsigned op); + bool IsCommutativeOrParamSwappableBinaryOpcode(unsigned op); + unsigned GetParamSwappedBinaryOpcode(unsigned op); + + template<bool ComplexType> + bool HasInvalidRangesOpcode(unsigned op); + + template<typename Value_t> + inline Value_t DegreesToRadians(const Value_t& degrees) + { + return degrees * fp_const_deg_to_rad<Value_t>(); + } + + template<typename Value_t> + inline Value_t RadiansToDegrees(const Value_t& radians) + { + return radians * fp_const_rad_to_deg<Value_t>(); + } + + template<typename Value_t> + inline long makeLongInteger(const Value_t& value) + { + return (long) fp_int(value); + } + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename T> + inline long makeLongInteger(const std::complex<T>& value) + { + return (long) fp_int( std::abs(value) ); + } +#endif + + // Is value an integer that fits in "long" datatype? + template<typename Value_t> + inline bool isLongInteger(const Value_t& value) + { + return value == Value_t( makeLongInteger(value) ); + } + + template<typename Value_t> + inline bool isOddInteger(const Value_t& value) + { + const Value_t halfValue = (value + Value_t(1)) * Value_t(0.5); + return fp_equal(halfValue, fp_floor(halfValue)); + } + + template<typename Value_t> + inline bool isEvenInteger(const Value_t& value) + { + const Value_t halfValue = value * Value_t(0.5); + return fp_equal(halfValue, fp_floor(halfValue)); + } + + template<typename Value_t> + inline bool isInteger(const Value_t& value) + { + return fp_equal(value, fp_floor(value)); + } + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline bool isEvenInteger(const long& value) + { + return value%2 == 0; + } + + template<> + inline bool isInteger(const long&) { return true; } + + template<> + inline bool isLongInteger(const long&) { return true; } + + template<> + inline long makeLongInteger(const long& value) + { + return value; + } +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline bool isInteger(const MpfrFloat& value) { return value.isInteger(); } + + template<> + inline bool isEvenInteger(const MpfrFloat& value) + { + return isInteger(value) && value%2 == 0; + } + + template<> + inline long makeLongInteger(const MpfrFloat& value) + { + return (long) value.toInt(); + } +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool isEvenInteger(const GmpInt& value) + { + return value%2 == 0; + } + + template<> + inline bool isInteger(const GmpInt&) { return true; } + + template<> + inline long makeLongInteger(const GmpInt& value) + { + return (long) value.toInt(); + } +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline bool isOddInteger(const long& value) + { + return value%2 != 0; + } +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline bool isOddInteger(const MpfrFloat& value) + { + return value.isInteger() && value%2 != 0; + } +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool isOddInteger(const GmpInt& value) + { + return value%2 != 0; + } +#endif + + +// ------------------------------------------------------------------------- +// fp_pow +// ------------------------------------------------------------------------- + // Commented versions in fparser.cc + template<typename Value_t> + inline Value_t fp_pow_with_exp_log(const Value_t& x, const Value_t& y) + { + return fp_exp(fp_log(x) * y); + } + + template<typename Value_t> + inline Value_t fp_powi(Value_t x, unsigned long y) + { + Value_t result(1); + while(y != 0) + { + if(y & 1) { result *= x; y -= 1; } + else { x *= x; y /= 2; } + } + return result; + } + + template<typename Value_t> + Value_t fp_pow(const Value_t& x, const Value_t& y) + { + if(x == Value_t(1)) return Value_t(1); + if(isLongInteger(y)) + { + if(y >= Value_t(0)) + return fp_powi(x, makeLongInteger(y)); + else + return Value_t(1) / fp_powi(x, -makeLongInteger(y)); + } + if(y >= Value_t(0)) + { + if(x > Value_t(0)) return fp_pow_with_exp_log(x, y); + if(x == Value_t(0)) return Value_t(0); + if(!isInteger(y*Value_t(16))) + return -fp_pow_with_exp_log(-x, y); + } + else + { + if(x > Value_t(0)) return fp_pow_with_exp_log(Value_t(1) / x, -y); + if(x < Value_t(0)) + { + if(!isInteger(y*Value_t(-16))) + return -fp_pow_with_exp_log(Value_t(-1) / x, -y); + } + } + return fp_pow_base(x, y); + } + + template<typename Value_t> + inline Value_t fp_exp2(const Value_t& x) + { + return fp_pow(Value_t(2), x); + } +} // namespace FUNCTIONPARSERTYPES + +#endif // ONCE_FPARSER_H_ +#endif // ONCE_FPARSER_AUX_H_ diff --git a/fparser/extrasrc/fptypes.hh b/fparser/extrasrc/fptypes.hh new file mode 100644 index 0000000..159903b --- /dev/null +++ b/fparser/extrasrc/fptypes.hh @@ -0,0 +1,288 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_TYPES_H_ +#define ONCE_FPARSER_TYPES_H_ + +#include "../fpconfig.hh" +#include <cstring> + +#ifdef ONCE_FPARSER_H_ +#include <map> +#endif + +namespace FUNCTIONPARSERTYPES +{ + enum OPCODE + { +// The order of opcodes in the function list must +// match that which is in the Functions[] array. + cAbs, + cAcos, cAcosh, + cArg, /* get the phase angle of a complex value */ + cAsin, cAsinh, + cAtan, cAtan2, cAtanh, + cCbrt, cCeil, + cConj, /* get the complex conjugate of a complex value */ + cCos, cCosh, cCot, cCsc, + cExp, cExp2, cFloor, cHypot, + cIf, + cImag, /* get imaginary part of a complex value */ + cInt, cLog, cLog10, cLog2, cMax, cMin, + cPolar, /* create a complex number from polar coordinates */ + cPow, + cReal, /* get real part of a complex value */ + cSec, cSin, cSinh, cSqrt, cTan, cTanh, + cTrunc, + +// These do not need any ordering: +// Except that if you change the order of {eq,neq,lt,le,gt,ge}, you +// must also change the order in ConstantFolding_ComparisonOperations(). + cImmed, cJump, + cNeg, cAdd, cSub, cMul, cDiv, cMod, + cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq, + cNot, cAnd, cOr, + cNotNot, /* Protects the double-not sequence from optimizations */ + + cDeg, cRad, /* Multiplication and division by 180 / pi */ + + cFCall, cPCall, + +#ifdef FP_SUPPORT_OPTIMIZER + cPopNMov, /* cPopNMov(x,y) moves [y] to [x] and deletes anything + * above [x]. Used for disposing of temporaries. + */ + cLog2by, /* log2by(x,y) = log2(x) * y */ + cNop, /* Used by fpoptimizer internally; should not occur in bytecode */ +#endif + cSinCos, /* sin(x) followed by cos(x) (two values are pushed to stack) */ + cSinhCosh, /* hyperbolic equivalent of sincos */ + cAbsAnd, /* As cAnd, but assume both operands are absolute values */ + cAbsOr, /* As cOr, but assume both operands are absolute values */ + cAbsNot, /* As cAbsNot, but assume the operand is an absolute value */ + cAbsNotNot, /* As cAbsNotNot, but assume the operand is an absolute value */ + cAbsIf, /* As cAbsIf, but assume the 1st operand is an absolute value */ + + cDup, /* Duplicates the last value in the stack: Push [Stacktop] */ + cFetch, /* Same as Dup, except with absolute index + * (next value is index) */ + cInv, /* Inverts the last value in the stack (x = 1/x) */ + cSqr, /* squares the last operand in the stack, no push/pop */ + cRDiv, /* reverse division (not x/y, but y/x) */ + cRSub, /* reverse subtraction (not x-y, but y-x) */ + cRSqrt, /* inverse square-root (1/sqrt(x)) */ + + VarBegin + }; + +#ifdef ONCE_FPARSER_H_ + struct FuncDefinition + { + enum FunctionFlags + { + Enabled = 0x01, + AngleIn = 0x02, + AngleOut = 0x04, + OkForInt = 0x08, + ComplexOnly = 0x10 + }; + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + const char name[8]; +#else + struct name { } name; +#endif + unsigned params : 8; + unsigned flags : 8; + + inline bool okForInt() const { return (flags & OkForInt) != 0; } + inline bool complexOnly() const { return (flags & ComplexOnly) != 0; } + }; + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +# define FP_FNAME(n) n +#else +# define FP_FNAME(n) {} +#endif +// This list must be in the same order as that in OPCODE enum, +// because the opcode value is used to index this array, and +// the pointer to array element is used for generating the opcode. + const FuncDefinition Functions[]= + { + /*cAbs */ { FP_FNAME("abs"), 1, FuncDefinition::OkForInt }, + /*cAcos */ { FP_FNAME("acos"), 1, FuncDefinition::AngleOut }, + /*cAcosh*/ { FP_FNAME("acosh"), 1, FuncDefinition::AngleOut }, + /*cArg */ { FP_FNAME("arg"), 1, FuncDefinition::AngleOut | FuncDefinition::ComplexOnly }, + /*cAsin */ { FP_FNAME("asin"), 1, FuncDefinition::AngleOut }, + /*cAsinh*/ { FP_FNAME("asinh"), 1, FuncDefinition::AngleOut }, + /*cAtan */ { FP_FNAME("atan"), 1, FuncDefinition::AngleOut }, + /*cAtan2*/ { FP_FNAME("atan2"), 2, FuncDefinition::AngleOut }, + /*cAtanh*/ { FP_FNAME("atanh"), 1, 0 }, + /*cCbrt */ { FP_FNAME("cbrt"), 1, 0 }, + /*cCeil */ { FP_FNAME("ceil"), 1, 0 }, + /*cConj */ { FP_FNAME("conj"), 1, FuncDefinition::ComplexOnly }, + /*cCos */ { FP_FNAME("cos"), 1, FuncDefinition::AngleIn }, + /*cCosh */ { FP_FNAME("cosh"), 1, FuncDefinition::AngleIn }, + /*cCot */ { FP_FNAME("cot"), 1, FuncDefinition::AngleIn }, + /*cCsc */ { FP_FNAME("csc"), 1, FuncDefinition::AngleIn }, + /*cExp */ { FP_FNAME("exp"), 1, 0 }, + /*cExp2 */ { FP_FNAME("exp2"), 1, 0 }, + /*cFloor*/ { FP_FNAME("floor"), 1, 0 }, + /*cHypot*/ { FP_FNAME("hypot"), 2, 0 }, + /*cIf */ { FP_FNAME("if"), 0, FuncDefinition::OkForInt }, + /*cImag */ { FP_FNAME("imag"), 1, FuncDefinition::ComplexOnly }, + /*cInt */ { FP_FNAME("int"), 1, 0 }, + /*cLog */ { FP_FNAME("log"), 1, 0 }, + /*cLog10*/ { FP_FNAME("log10"), 1, 0 }, + /*cLog2 */ { FP_FNAME("log2"), 1, 0 }, + /*cMax */ { FP_FNAME("max"), 2, FuncDefinition::OkForInt }, + /*cMin */ { FP_FNAME("min"), 2, FuncDefinition::OkForInt }, + /*cPolar */{ FP_FNAME("polar"), 2, FuncDefinition::ComplexOnly | FuncDefinition::AngleIn }, + /*cPow */ { FP_FNAME("pow"), 2, 0 }, + /*cReal */ { FP_FNAME("real"), 1, FuncDefinition::ComplexOnly }, + /*cSec */ { FP_FNAME("sec"), 1, FuncDefinition::AngleIn }, + /*cSin */ { FP_FNAME("sin"), 1, FuncDefinition::AngleIn }, + /*cSinh */ { FP_FNAME("sinh"), 1, FuncDefinition::AngleIn }, + /*cSqrt */ { FP_FNAME("sqrt"), 1, 0 }, + /*cTan */ { FP_FNAME("tan"), 1, FuncDefinition::AngleIn }, + /*cTanh */ { FP_FNAME("tanh"), 1, FuncDefinition::AngleIn }, + /*cTrunc*/ { FP_FNAME("trunc"), 1, 0 } + }; +#undef FP_FNAME + + struct NamePtr + { + const char* name; + unsigned nameLength; + + NamePtr(const char* n, unsigned l): name(n), nameLength(l) {} + + inline bool operator==(const NamePtr& rhs) const + { + return nameLength == rhs.nameLength + && std::memcmp(name, rhs.name, nameLength) == 0; + } + inline bool operator<(const NamePtr& rhs) const + { + for(unsigned i = 0; i < nameLength; ++i) + { + if(i == rhs.nameLength) return false; + const char c1 = name[i], c2 = rhs.name[i]; + if(c1 < c2) return true; + if(c2 < c1) return false; + } + return nameLength < rhs.nameLength; + } + }; + + template<typename Value_t> + struct NameData + { + enum DataType { CONSTANT, UNIT, FUNC_PTR, PARSER_PTR, VARIABLE }; + DataType type; + unsigned index; + Value_t value; + + NameData(DataType t, unsigned v) : type(t), index(v), value() { } + NameData(DataType t, Value_t v) : type(t), index(), value(v) { } + NameData() { } + }; + + template<typename Value_t> + class NamePtrsMap: public + std::map<FUNCTIONPARSERTYPES::NamePtr, + FUNCTIONPARSERTYPES::NameData<Value_t> > + { + }; + + const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]); +#endif // ONCE_FPARSER_H_ +} + +#ifdef ONCE_FPARSER_H_ +#include <vector> + +template<typename Value_t> +struct FunctionParserBase<Value_t>::Data +{ + unsigned mReferenceCounter; + + char mDelimiterChar; + ParseErrorType mParseErrorType; + int mEvalErrorType; + bool mUseDegreeConversion; + bool mHasByteCodeFlags; + const char* mErrorLocation; + + unsigned mVariablesAmount; + std::string mVariablesString; + FUNCTIONPARSERTYPES::NamePtrsMap<Value_t> mNamePtrs; + + struct InlineVariable + { + FUNCTIONPARSERTYPES::NamePtr mName; + unsigned mFetchIndex; + }; + + typedef std::vector<InlineVariable> InlineVarNamesContainer; + InlineVarNamesContainer mInlineVarNames; + + struct FuncWrapperPtrData + { + /* Only one of the pointers will point to a function, the other + will be null. (The raw function pointer could be implemented + as a FunctionWrapper specialization, but it's done like this + for efficiency.) */ + FunctionPtr mRawFuncPtr; + FunctionWrapper* mFuncWrapperPtr; + unsigned mParams; + + FuncWrapperPtrData(); + ~FuncWrapperPtrData(); + FuncWrapperPtrData(const FuncWrapperPtrData&); + FuncWrapperPtrData& operator=(const FuncWrapperPtrData&); + }; + + struct FuncParserPtrData + { + FunctionParserBase<Value_t>* mParserPtr; + unsigned mParams; + }; + + std::vector<FuncWrapperPtrData> mFuncPtrs; + std::vector<FuncParserPtrData> mFuncParsers; + + std::vector<unsigned> mByteCode; + std::vector<Value_t> mImmed; + +#if !defined(FP_USE_THREAD_SAFE_EVAL) && \ + !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) + std::vector<Value_t> mStack; + // Note: When mStack exists, + // mStack.size() and mStackSize are mutually redundant. +#endif + + unsigned mStackSize; + + Data(); + Data(const Data&); + Data& operator=(const Data&); // not implemented on purpose + ~Data(); +}; +#endif + +//#include "fpaux.hh" + +#endif diff --git a/fparser/fparser.cc b/fparser/fparser.cc new file mode 100644 index 0000000..11fa09e --- /dev/null +++ b/fparser/fparser.cc @@ -0,0 +1,3800 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#include "fpconfig.hh" +#include "fparser.hh" + +#include <set> +#include <cstdlib> +#include <cstring> +#include <cctype> +#include <cmath> +#include <cassert> +#include <limits> + +#include "extrasrc/fptypes.hh" +#include "extrasrc/fpaux.hh" +using namespace FUNCTIONPARSERTYPES; + +#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA +#ifndef FP_USE_THREAD_SAFE_EVAL +#define FP_USE_THREAD_SAFE_EVAL +#endif +#endif + +#ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif + +//========================================================================= +// Opcode analysis functions +//========================================================================= +// These functions are used by the Parse() bytecode optimizer (mostly from +// code in fp_opcode_add.inc). + +bool FUNCTIONPARSERTYPES::IsLogicalOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsComparisonOpcode(unsigned op) +{ + switch(op) + { + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; + } + return false; +} + +unsigned FUNCTIONPARSERTYPES::OppositeComparisonOpcode(unsigned op) +{ + switch(op) + { + case cLess: return cGreater; + case cGreater: return cLess; + case cLessOrEq: return cGreaterOrEq; + case cGreaterOrEq: return cLessOrEq; + } + return op; +} + +bool FUNCTIONPARSERTYPES::IsNeverNegativeValueOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + case cSqrt: case cRSqrt: case cSqr: + case cHypot: + case cAbs: + case cAcos: case cCosh: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsAlwaysIntegerOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + case cInt: case cFloor: case cCeil: case cTrunc: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsUnaryOpcode(unsigned op) +{ + switch(op) + { + case cInv: case cNeg: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cSqr: case cRSqrt: + case cDeg: case cRad: + return true; + } + return (op < FUNC_AMOUNT && Functions[op].params == 1); +} + +bool FUNCTIONPARSERTYPES::IsBinaryOpcode(unsigned op) +{ + switch(op) + { + case cAdd: case cSub: case cRSub: + case cMul: case cDiv: case cRDiv: + case cMod: + case cEqual: case cNEqual: case cLess: + case cLessOrEq: case cGreater: case cGreaterOrEq: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + return true; + } + return (op < FUNC_AMOUNT && Functions[op].params == 2); +} + +bool FUNCTIONPARSERTYPES::IsVarOpcode(unsigned op) +{ + // See comment in declaration of FP_ParamGuardMask + return int(op) >= VarBegin; +} + +bool FUNCTIONPARSERTYPES::IsCommutativeOrParamSwappableBinaryOpcode(unsigned op) +{ + switch(op) + { + case cAdd: + case cMul: + case cEqual: case cNEqual: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cMin: case cMax: case cHypot: + return true; + case cDiv: case cSub: case cRDiv: case cRSub: + return true; + case cLess: case cGreater: + case cLessOrEq: case cGreaterOrEq: return true; + } + return false; +} + +unsigned FUNCTIONPARSERTYPES::GetParamSwappedBinaryOpcode(unsigned op) +{ + switch(op) + { + case cAdd: + case cMul: + case cEqual: case cNEqual: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cMin: case cMax: case cHypot: + return op; + case cDiv: return cRDiv; + case cSub: return cRSub; + case cRDiv: return cDiv; + case cRSub: return cSub; + case cLess: return cGreater; + case cGreater: return cLess; + case cLessOrEq: return cGreaterOrEq; + case cGreaterOrEq: return cLessOrEq; + } + return op; // Error +} + +template<bool ComplexType> +bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op) +{ + // Returns true, if the given opcode has a range of + // input values that gives an error. + if(ComplexType) + { + // COMPLEX: + switch(op) + { + case cAtan: // allowed range: x != +-1i + case cAtanh: // allowed range: x != +-1 + //case cCot: // allowed range: tan(x) != 0 + //case cCsc: // allowed range: sin(x) != 0 + case cLog: // allowed range: x != 0 + case cLog2: // allowed range: x != 0 + case cLog10: // allowed range: x != 0 + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by:// allowed range: x != 0 + #endif + //case cPow: // allowed when: x != 0 or y != 0 + //case cSec: // allowed range: cos(x) != 0 + //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2) + //case cTanh: // allowed range: log(x) != -1 --> x != +-(pi/2)i + case cRSqrt: // allowed range: x != 0 + //case cDiv: // allowed range: y != 0 + //case cRDiv: // allowed range: x != 0 + //case cInv: // allowed range: x != 0 + return true; + } + } + else + { + // REAL: + switch(op) + { + case cAcos: // allowed range: |x| <= 1 + case cAsin: // allowed range: |x| <= 1 + case cAcosh: // allowed range: x >= 1 + case cAtanh: // allowed range: |x| < 1 + //case cCot: // allowed range: tan(x) != 0 + //case cCsc: // allowed range: sin(x) != 0 + case cLog: // allowed range: x > 0 + case cLog2: // allowed range: x > 0 + case cLog10: // allowed range: x > 0 + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by:// allowed range: x > 0 + #endif + //case cPow: // allowed when: x > 0 or (x = 0 and y != 0) or (x<0) + // Technically, when (x<0 and y is not integer), + // it is not allowed, but we allow it anyway + // in order to make nontrivial roots work. + //case cSec: // allowed range: cos(x) != 0 + case cSqrt: // allowed range: x >= 0 + case cRSqrt: // allowed range: x > 0 + //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2) + //case cDiv: // allowed range: y != 0 + //case cRDiv: // allowed range: x != 0 + //case cInv: // allowed range: x != 0 + return true; + } + } + return false; +} + +template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode<false>(unsigned op); +template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode<true>(unsigned op); + + +#if(0) // Implementation moved to fpaux.hh due to linker problems +//========================================================================= +// Mathematical template functions +//========================================================================= +/* fp_pow() is a wrapper for std::pow() + * that produces an identical value for + * exp(1) ^ 2.0 (0x4000000000000000) + * as exp(2.0) (0x4000000000000000) + * - std::pow() on x86_64 + * produces 2.0 (0x3FFFFFFFFFFFFFFF) instead! + * See comments below for other special traits. + */ +namespace +{ + template<typename ValueT> + inline ValueT fp_pow_with_exp_log(const ValueT& x, const ValueT& y) + { + // Exponentiation using exp(log(x)*y). + // See http://en.wikipedia.org/wiki/Exponentiation#Real_powers + // Requirements: x > 0. + return fp_exp(fp_log(x) * y); + } + + template<typename ValueT> + inline ValueT fp_powi(ValueT x, unsigned long y) + { + // Fast binary exponentiation algorithm + // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring + // Requirements: y is non-negative integer. + ValueT result(1); + while(y != 0) + { + if(y & 1) { result *= x; y -= 1; } + else { x *= x; y /= 2; } + } + return result; + } +} + +template<typename ValueT> +ValueT FUNCTIONPARSERTYPES::fp_pow(const ValueT& x, const ValueT& y) +{ + if(x == ValueT(1)) return ValueT(1); + // y is now zero or positive + if(isLongInteger(y)) + { + // Use fast binary exponentiation algorithm + if(y >= ValueT(0)) + return fp_powi(x, makeLongInteger(y)); + else + return ValueT(1) / fp_powi(x, -makeLongInteger(y)); + } + if(y >= ValueT(0)) + { + // y is now positive. Calculate using exp(log(x)*y). + if(x > ValueT(0)) return fp_pow_with_exp_log(x, y); + if(x == ValueT(0)) return ValueT(0); + // At this point, y > 0.0 and x is known to be < 0.0, + // because positive and zero cases are already handled. + if(!isInteger(y*ValueT(16))) + return -fp_pow_with_exp_log(-x, y); + // ^This is not technically correct, but it allows + // functions such as cbrt(x^5), that is, x^(5/3), + // to be evaluated when x is negative. + // It is too complicated (and slow) to test whether y + // is a formed from a ratio of an integer to an odd integer. + // (And due to floating point inaccuracy, pointless too.) + // For example, x^1.30769230769... is + // actually x^(17/13), i.e. (x^17) ^ (1/13). + // (-5)^(17/13) gives us now -8.204227562330453. + // To see whether the result is right, we can test the given + // root: (-8.204227562330453)^13 gives us the value of (-5)^17, + // which proves that the expression was correct. + // + // The y*16 check prevents e.g. (-4)^(3/2) from being calculated, + // as it would confuse functioninfo when pow() returns no error + // but sqrt() does when the formula is converted into sqrt(x)*x. + // + // The errors in this approach are: + // (-2)^sqrt(2) should produce NaN + // or actually sqrt(2)I + 2^sqrt(2), + // produces -(2^sqrt(2)) instead. + // (Impact: Neglible) + // Thus, at worst, we're changing a NaN (or complex) + // result into a negative real number result. + } + else + { + // y is negative. Utilize the x^y = 1/(x^-y) identity. + if(x > ValueT(0)) return fp_pow_with_exp_log(ValueT(1) / x, -y); + if(x < ValueT(0)) + { + if(!isInteger(y*ValueT(-16))) + return -fp_pow_with_exp_log(ValueT(-1) / x, -y); + // ^ See comment above. + } + // Remaining case: 0.0 ^ negative number + } + // This is reached when: + // x=0, and y<0 + // x<0, and y*16 is either positive or negative integer + // It is used for producing error values and as a safe fallback. + return fp_pow_base(x, y); +} +#endif + + +//========================================================================= +// Elementary (atom) parsing functions +//========================================================================= +namespace +{ + const unsigned FP_ParamGuardMask = 1U << (sizeof(unsigned) * 8u - 1u); + // ^ This mask is used to prevent cFetch/other opcode's parameters + // from being confused into opcodes or variable indices within the + // bytecode optimizer. Because the way it is tested in bytecoderules.dat + // for speed reasons, it must also be the sign-bit of the "int" datatype. + // Perhaps an "assert(IsVarOpcode(X | FP_ParamGuardMask) == false)" + // might be justified to put somewhere in the code, just in case? + + + /* Reads an UTF8-encoded sequence which forms a valid identifier name from + the given input string and returns its length. If bit 31 is set, the + return value also contains the internal function opcode (defined in + fptypes.hh) that matches the name. + */ + unsigned readIdentifierCommon(const char* input) + { + /* Assuming unsigned = 32 bits: + 76543210 76543210 76543210 76543210 + Return value if built-in function: + 1PPPPPPP PPPPPPPP LLLLLLLL LLLLLLLL + P = function opcode (15 bits) + L = function name length (16 bits) + Return value if not built-in function: + 0LLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL + L = identifier length (31 bits) + If unsigned has more than 32 bits, the other + higher order bits are to be assumed zero. + */ +#include "extrasrc/fp_identifier_parser.inc" + return 0; + } + + template<typename Value_t> + inline unsigned readIdentifier(const char* input) + { + const unsigned value = readIdentifierCommon(input); + if( (value & 0x80000000U) != 0) // Function? + { + // Verify that the function actually exists for this datatype + if(IsIntType<Value_t>::result + && !Functions[(value >> 16) & 0x7FFF].okForInt()) + { + // If it does not exist, return it as an identifier instead + return value & 0xFFFFu; + } + if(!IsComplexType<Value_t>::result + && Functions[(value >> 16) & 0x7FFF].complexOnly()) + { + // If it does not exist, return it as an identifier instead + return value & 0xFFFFu; + } + } + return value; + } + + // Returns true if the entire string is a valid identifier + template<typename Value_t> + bool containsOnlyValidIdentifierChars(const std::string& name) + { + if(name.empty()) return false; + return readIdentifier<Value_t>(name.c_str()) == (unsigned) name.size(); + } + + + // ----------------------------------------------------------------------- + // Wrappers for strto... functions + // ----------------------------------------------------------------------- + template<typename Value_t> + inline Value_t fp_parseLiteral(const char* str, char** endptr) + { + return std::strtod(str, endptr); + } + +#if defined(FP_USE_STRTOLD) || defined(FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS) + template<> + inline long double fp_parseLiteral<long double>(const char* str, + char** endptr) + { + using namespace std; // Just in case strtold() is not inside std:: + return strtold(str, endptr); + } +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline long fp_parseLiteral<long>(const char* str, char** endptr) + { + return std::strtol(str, endptr, 10); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename T> + inline std::complex<T> fp_parseComplexLiteral(const char* str, + char** endptr) + { + T result = fp_parseLiteral<T> (str,endptr); + const char* end = *endptr; + if( (*end == 'i' || *end == 'I') + && !std::isalnum(end[1]) ) + { + ++*endptr; + return std::complex<T> (T(), result); + } + return std::complex<T> (result, T()); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + template<> + inline std::complex<double> fp_parseLiteral<std::complex<double> > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral<double> (str,endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + inline std::complex<float> fp_parseLiteral<std::complex<float> > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral<float> (str,endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + inline std::complex<long double> fp_parseLiteral<std::complex<long double> > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral<long double> (str,endptr); + } +#endif + + // ----------------------------------------------------------------------- + // Hexadecimal floating point literal parsing + // ----------------------------------------------------------------------- + inline int testXdigit(unsigned c) + { + if((c-'0') < 10u) return c&15; // 0..9 + if(((c|0x20)-'a') < 6u) return 9+(c&15); // A..F or a..f + return -1; // Not a hex digit + } + + template<typename elem_t, unsigned n_limbs, unsigned limb_bits> + inline void addXdigit(elem_t* buffer, unsigned nibble) + { + for(unsigned p=0; p<n_limbs; ++p) + { + unsigned carry = unsigned( buffer[p] >> (elem_t)(limb_bits-4) ); + buffer[p] = (buffer[p] << 4) | nibble; + nibble = carry; + } + } + + template<typename Value_t> + Value_t parseHexLiteral(const char* str, char** endptr) + { + const unsigned bits_per_char = 8; + + const int MantissaBits = + std::numeric_limits<Value_t>::radix == 2 + ? std::numeric_limits<Value_t>::digits + : (((sizeof(Value_t) * bits_per_char) &~ 3) - 4); + + typedef unsigned long elem_t; + const int ExtraMantissaBits = 4 + ((MantissaBits+3)&~3); // Store one digit more for correct rounding + const unsigned limb_bits = sizeof(elem_t) * bits_per_char; + const unsigned n_limbs = (ExtraMantissaBits + limb_bits-1) / limb_bits; + elem_t mantissa_buffer[n_limbs] = { 0 }; + + int n_mantissa_bits = 0; // Track the number of bits + int exponent = 0; // The exponent that will be used to multiply the mantissa + // Read integer portion + while(true) + { + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit<elem_t,n_limbs,limb_bits> (mantissa_buffer, xdigit); + ++str; + + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) + { + // Exhausted the precision. Parse the rest (until exponent) + // normally but ignore the actual digits. + for(; testXdigit(*str) >= 0; ++str) + exponent += 4; + // Read but ignore decimals + if(*str == '.') + for(++str; testXdigit(*str) >= 0; ++str) + {} + goto read_exponent; + } + } + // Read decimals + if(*str == '.') + for(++str; ; ) + { + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit<elem_t,n_limbs,limb_bits> (mantissa_buffer, xdigit); + ++str; + + exponent -= 4; + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) + { + // Exhausted the precision. Skip the rest + // of the decimals, until the exponent. + while(testXdigit(*str) >= 0) + ++str; + break; + } + } + + // Read exponent + read_exponent: + if(*str == 'p' || *str == 'P') + { + const char* str2 = str+1; + long p_exponent = strtol(str2, const_cast<char**> (&str2), 10); + if(str2 != str+1 && p_exponent == (long)(int)p_exponent) + { + exponent += (int)p_exponent; + str = str2; + } + } + + if(endptr) *endptr = const_cast<char*> (str); + + Value_t result = std::ldexp(Value_t(mantissa_buffer[0]), exponent); + for(unsigned p=1; p<n_limbs; ++p) + { + exponent += limb_bits; + result += ldexp(Value_t(mantissa_buffer[p]), exponent); + } + return result; + } + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + long parseHexLiteral<long>(const char* str, char** endptr) + { + return std::strtol(str, endptr, 16); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + template<> + std::complex<double> + parseHexLiteral<std::complex<double> >(const char* str, char** endptr) + { + return parseHexLiteral<double> (str, endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + std::complex<float> + parseHexLiteral<std::complex<float> >(const char* str, char** endptr) + { + return parseHexLiteral<float> (str, endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + std::complex<long double> + parseHexLiteral<std::complex<long double> >(const char* str, char** endptr) + { + return parseHexLiteral<long double> (str, endptr); + } +#endif +} + +//========================================================================= +// Utility functions +//========================================================================= +namespace +{ + // ----------------------------------------------------------------------- + // Add a new identifier to the specified identifier map + // ----------------------------------------------------------------------- + // Return value will be false if the name already existed + template<typename Value_t> + bool addNewNameData(NamePtrsMap<Value_t>& namePtrs, + std::pair<NamePtr, NameData<Value_t> >& newName, + bool isVar) + { + typename NamePtrsMap<Value_t>::iterator nameIter = + namePtrs.lower_bound(newName.first); + + if(nameIter != namePtrs.end() && newName.first == nameIter->first) + { + // redefining a var is not allowed. + if(isVar) return false; + + // redefining other tokens is allowed, if the type stays the same. + if(nameIter->second.type != newName.second.type) + return false; + + // update the data + nameIter->second = newName.second; + return true; + } + + if(!isVar) + { + // Allocate a copy of the name (pointer stored in the map key) + // However, for VARIABLEs, the pointer points to VariableString, + // which is managed separately. Thusly, only done when !IsVar. + char* namebuf = new char[newName.first.nameLength]; + memcpy(namebuf, newName.first.name, newName.first.nameLength); + newName.first.name = namebuf; + } + + namePtrs.insert(nameIter, newName); + return true; + } +} + + +//========================================================================= +// Data struct implementation +//========================================================================= +template<typename Value_t> +FunctionParserBase<Value_t>::Data::Data(): + mReferenceCounter(1), + mDelimiterChar(0), + mParseErrorType(NO_FUNCTION_PARSED_YET), + mEvalErrorType(0), + mUseDegreeConversion(false), + mErrorLocation(0), + mVariablesAmount(0), + mStackSize(0) +{} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::Data(const Data& rhs): + mReferenceCounter(0), + mDelimiterChar(rhs.mDelimiterChar), + mParseErrorType(rhs.mParseErrorType), + mEvalErrorType(rhs.mEvalErrorType), + mUseDegreeConversion(rhs.mUseDegreeConversion), + mErrorLocation(rhs.mErrorLocation), + mVariablesAmount(rhs.mVariablesAmount), + mVariablesString(rhs.mVariablesString), + mNamePtrs(), + mFuncPtrs(rhs.mFuncPtrs), + mFuncParsers(rhs.mFuncParsers), + mByteCode(rhs.mByteCode), + mImmed(rhs.mImmed), +#ifndef FP_USE_THREAD_SAFE_EVAL + mStack(rhs.mStackSize), +#endif + mStackSize(rhs.mStackSize) +{ + for(typename NamePtrsMap<Value_t>::const_iterator i = rhs.mNamePtrs.begin(); + i != rhs.mNamePtrs.end(); + ++i) + { + if(i->second.type == NameData<Value_t>::VARIABLE) + { + const std::size_t variableStringOffset = + i->first.name - rhs.mVariablesString.c_str(); + std::pair<NamePtr, NameData<Value_t> > tmp + (NamePtr(&mVariablesString[variableStringOffset], + i->first.nameLength), + i->second); + mNamePtrs.insert(mNamePtrs.end(), tmp); + } + else + { + std::pair<NamePtr, NameData<Value_t> > tmp + (NamePtr(new char[i->first.nameLength], i->first.nameLength), + i->second ); + memcpy(const_cast<char*>(tmp.first.name), i->first.name, + tmp.first.nameLength); + mNamePtrs.insert(mNamePtrs.end(), tmp); + } + } +} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::~Data() +{ + for(typename NamePtrsMap<Value_t>::iterator i = mNamePtrs.begin(); + i != mNamePtrs.end(); + ++i) + { + if(i->second.type != NameData<Value_t>::VARIABLE) + delete[] i->first.name; + } +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::incFuncWrapperRefCount +(FunctionWrapper* wrapper) +{ + ++wrapper->mReferenceCount; +} + +template<typename Value_t> +unsigned FunctionParserBase<Value_t>::decFuncWrapperRefCount +(FunctionWrapper* wrapper) +{ + return --wrapper->mReferenceCount; +} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::FuncWrapperPtrData(): + mRawFuncPtr(0), mFuncWrapperPtr(0), mParams(0) +{} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::~FuncWrapperPtrData() +{ + if(mFuncWrapperPtr && + FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0) + delete mFuncWrapperPtr; +} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::FuncWrapperPtrData +(const FuncWrapperPtrData& rhs): + mRawFuncPtr(rhs.mRawFuncPtr), + mFuncWrapperPtr(rhs.mFuncWrapperPtr), + mParams(rhs.mParams) +{ + if(mFuncWrapperPtr) + FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr); +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::Data::FuncWrapperPtrData& +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::operator= +(const FuncWrapperPtrData& rhs) +{ + if(&rhs != this) + { + if(mFuncWrapperPtr && + FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0) + delete mFuncWrapperPtr; + mRawFuncPtr = rhs.mRawFuncPtr; + mFuncWrapperPtr = rhs.mFuncWrapperPtr; + mParams = rhs.mParams; + if(mFuncWrapperPtr) + FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr); + } + return *this; +} + + +//========================================================================= +// FunctionParser constructors, destructor and assignment +//========================================================================= +template<typename Value_t> +FunctionParserBase<Value_t>::FunctionParserBase(): + mData(new Data), + mStackPtr(0) +{ +} + +template<typename Value_t> +FunctionParserBase<Value_t>::~FunctionParserBase() +{ + if(--(mData->mReferenceCounter) == 0) + delete mData; +} + +template<typename Value_t> +FunctionParserBase<Value_t>::FunctionParserBase(const FunctionParserBase& cpy): + mData(cpy.mData), + mStackPtr(0) +{ + ++(mData->mReferenceCounter); +} + +template<typename Value_t> +FunctionParserBase<Value_t>& +FunctionParserBase<Value_t>::operator=(const FunctionParserBase& cpy) +{ + if(mData != cpy.mData) + { + if(--(mData->mReferenceCounter) == 0) delete mData; + + mData = cpy.mData; + ++(mData->mReferenceCounter); + } + return *this; +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::Data* +FunctionParserBase<Value_t>::getParserData() +{ + return mData; +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::setDelimiterChar(char c) +{ + mData->mDelimiterChar = c; +} + + +//--------------------------------------------------------------------------- +// Copy-on-write method +//--------------------------------------------------------------------------- +template<typename Value_t> +void FunctionParserBase<Value_t>::CopyOnWrite() +{ + if(mData->mReferenceCounter > 1) + { + Data* oldData = mData; + mData = new Data(*oldData); + --(oldData->mReferenceCounter); + mData->mReferenceCounter = 1; + } +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::ForceDeepCopy() +{ + CopyOnWrite(); +} + + +//========================================================================= +// Epsilon +//========================================================================= +template<typename Value_t> +Value_t FunctionParserBase<Value_t>::epsilon() +{ + return Epsilon<Value_t>::value; +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::setEpsilon(Value_t value) +{ + Epsilon<Value_t>::value = value; +} + + +//========================================================================= +// User-defined identifier addition functions +//========================================================================= +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddConstant(const std::string& name, + Value_t value) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::CONSTANT, value)); + + return addNewNameData(mData->mNamePtrs, newName, false); +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddUnit(const std::string& name, + Value_t value) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::UNIT, value)); + return addNewNameData(mData->mNamePtrs, newName, false); +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddFunction +(const std::string& name, FunctionPtr ptr, unsigned paramsAmount) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::FUNC_PTR, + unsigned(mData->mFuncPtrs.size()))); + + const bool success = addNewNameData(mData->mNamePtrs, newName, false); + if(success) + { + mData->mFuncPtrs.push_back(typename Data::FuncWrapperPtrData()); + mData->mFuncPtrs.back().mRawFuncPtr = ptr; + mData->mFuncPtrs.back().mParams = paramsAmount; + } + return success; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::addFunctionWrapperPtr +(const std::string& name, FunctionWrapper* wrapper, unsigned paramsAmount) +{ + if(!AddFunction(name, FunctionPtr(0), paramsAmount)) return false; + mData->mFuncPtrs.back().mFuncWrapperPtr = wrapper; + return true; +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::FunctionWrapper* +FunctionParserBase<Value_t>::GetFunctionWrapper(const std::string& name) +{ + CopyOnWrite(); + NamePtr namePtr(name.data(), unsigned(name.size())); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(namePtr); + + if(nameIter != mData->mNamePtrs.end() && + nameIter->second.type == NameData<Value_t>::FUNC_PTR) + { + return mData->mFuncPtrs[nameIter->second.index].mFuncWrapperPtr; + } + return 0; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::CheckRecursiveLinking +(const FunctionParserBase* fp) const +{ + if(fp == this) return true; + for(unsigned i = 0; i < fp->mData->mFuncParsers.size(); ++i) + if(CheckRecursiveLinking(fp->mData->mFuncParsers[i].mParserPtr)) + return true; + return false; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddFunction(const std::string& name, + FunctionParserBase& fp) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name) || + CheckRecursiveLinking(&fp)) + return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::PARSER_PTR, + unsigned(mData->mFuncParsers.size()))); + + const bool success = addNewNameData(mData->mNamePtrs, newName, false); + if(success) + { + mData->mFuncParsers.push_back(typename Data::FuncParserPtrData()); + mData->mFuncParsers.back().mParserPtr = &fp; + mData->mFuncParsers.back().mParams = fp.mData->mVariablesAmount; + } + return success; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::RemoveIdentifier(const std::string& name) +{ + CopyOnWrite(); + + NamePtr namePtr(name.data(), unsigned(name.size())); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(namePtr); + + if(nameIter != mData->mNamePtrs.end()) + { + if(nameIter->second.type == NameData<Value_t>::VARIABLE) + { + // Illegal attempt to delete variables + return false; + } + delete[] nameIter->first.name; + mData->mNamePtrs.erase(nameIter); + return true; + } + return false; +} + + +//========================================================================= +// Function parsing +//========================================================================= +namespace +{ + // Error messages returned by ErrorMsg(): + const char* const ParseErrorMessage[]= + { + "Syntax error", // 0 + "Mismatched parenthesis", // 1 + "Missing ')'", // 2 + "Empty parentheses", // 3 + "Syntax error: Operator expected", // 4 + "Not enough memory", // 5 + "An unexpected error occurred. Please make a full bug report " + "to the author", // 6 + "Syntax error in parameter 'Vars' given to " + "FunctionParser::Parse()", // 7 + "Illegal number of parameters to function", // 8 + "Syntax error: Premature end of string", // 9 + "Syntax error: Expecting ( after function", // 10 + "Syntax error: Unknown identifier", // 11 + "(No function has been parsed yet)", + "" + }; + + template<typename Value_t> + inline typename FunctionParserBase<Value_t>::ParseErrorType + noCommaError(char c) + { + return c == ')' ? + FunctionParserBase<Value_t>::ILL_PARAMS_AMOUNT : + FunctionParserBase<Value_t>::SYNTAX_ERROR; + } + + template<typename Value_t> + inline typename FunctionParserBase<Value_t>::ParseErrorType + noParenthError(char c) + { + return c == ',' ? + FunctionParserBase<Value_t>::ILL_PARAMS_AMOUNT : + FunctionParserBase<Value_t>::MISSING_PARENTH; + } + + template<unsigned offset> + struct IntLiteralMask + { + enum { mask = + // ( 1UL << ('-'-offset)) | + (0x3FFUL << ('0'-offset)) }; /* 0x3FF = 10 bits worth "1" */ + // Note: If you change fparser to support negative numbers parsing + // (as opposed to parsing them as cNeg followed by literal), + // enable the '-' line above, and change the offset value + // in BeginsLiteral() to '-' instead of '.'. + }; + + template<typename Value_t, unsigned offset> + struct LiteralMask + { + enum { mask = + ( 1UL << ('.'-offset)) | + IntLiteralMask<offset>::mask }; + }; +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<unsigned offset> + struct LiteralMask<long, offset>: public IntLiteralMask<offset> + { + }; +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<unsigned offset> + struct LiteralMask<GmpInt, offset>: public IntLiteralMask<offset> + { + }; +#endif + + template<unsigned offset> + struct SimpleSpaceMask + { + enum { mask = + (1UL << ('\r'-offset)) | + (1UL << ('\n'-offset)) | + (1UL << ('\v'-offset)) | + (1UL << ('\t'-offset)) | + (1UL << (' ' -offset)) }; + }; + + template<typename Value_t> + inline bool BeginsLiteral(unsigned byte) + { + enum { n = sizeof(unsigned long)>=8 ? 0 : '.' }; + byte -= n; + if(byte > (unsigned char)('9'-n)) return false; + unsigned long shifted = 1UL << byte; + const unsigned long mask = LiteralMask<Value_t, n>::mask; + return (mask & shifted) != 0; + } + + template<typename CharPtr> + inline void SkipSpace(CharPtr& function) + { +/* + Space characters in unicode: +U+0020 SPACE Depends on font, often adjusted (see below) +U+00A0 NO-BREAK SPACE As a space, but often not adjusted +U+2000 EN QUAD 1 en (= 1/2 em) +U+2001 EM QUAD 1 em (nominally, the height of the font) +U+2002 EN SPACE 1 en (= 1/2 em) +U+2003 EM SPACE 1 em +U+2004 THREE-PER-EM SPACE 1/3 em +U+2005 FOUR-PER-EM SPACE 1/4 em +U+2006 SIX-PER-EM SPACE 1/6 em +U+2007 FIGURE SPACE Tabular width, the width of digits +U+2008 PUNCTUATION SPACE The width of a period . +U+2009 THIN SPACE 1/5 em (or sometimes 1/6 em) +U+200A HAIR SPACE Narrower than THIN SPACE +U+200B ZERO WIDTH SPACE Nominally no width, but may expand +U+202F NARROW NO-BREAK SPACE Narrower than NO-BREAK SPACE (or SPACE) +U+205F MEDIUM MATHEMATICAL SPACE 4/18 em +U+3000 IDEOGRAPHIC SPACE The width of ideographic (CJK) characters. + Also: +U+000A \n +U+000D \r +U+0009 \t +U+000B \v + As UTF-8 sequences: + 09 + 0A + 0B + 0D + 20 + C2 A0 + E2 80 80-8B + E2 80 AF + E2 81 9F + E3 80 80 +*/ + while(true) + { + enum { n = sizeof(unsigned long)>=8 ? 0 : '\t' }; + typedef signed char schar; + unsigned byte = (unsigned char)*function; + byte -= n; + // ^Note: values smaller than n intentionally become + // big values here due to integer wrap. The + // comparison below thus excludes them, making + // the effective range 0x09..0x20 (32-bit) + // or 0x00..0x20 (64-bit) within the if-clause. + if(byte <= (unsigned char)(' '-n)) + { + unsigned long shifted = 1UL << byte; + const unsigned long mask = SimpleSpaceMask<n>::mask; + if(mask & shifted) + { ++function; continue; } // \r, \n, \t, \v and space + break; + } + if(likely(byte < 0xC2-n)) break; + + if(byte == 0xC2-n && function[1] == char(0xA0)) + { function += 2; continue; } // U+00A0 + if(byte == 0xE3-n && + function[1] == char(0x80) && function[2] == char(0x80)) + { function += 3; continue; } // U+3000 + if(byte == 0xE2-n) + { + if(function[1] == char(0x81)) + { + if(function[2] != char(0x9F)) break; + function += 3; // U+205F + continue; + } + if(function[1] == char(0x80)) + if(function[2] == char(0xAF) || // U+202F + schar(function[2]) <= schar(0x8B) // U+2000..U+200B + ) + { + function += 3; + continue; + } + } + break; + } // while(true) + } // SkipSpace(CharPtr& function) +} + +// --------------------------------------------------------------------------- +// Return parse error message +// --------------------------------------------------------------------------- +template<typename Value_t> +const char* FunctionParserBase<Value_t>::ErrorMsg() const +{ + return ParseErrorMessage[mData->mParseErrorType]; +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::ParseErrorType +FunctionParserBase<Value_t>::GetParseErrorType() const +{ + return mData->mParseErrorType; +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::EvalError() const +{ + return mData->mEvalErrorType; +} + + +// --------------------------------------------------------------------------- +// Parse variables +// --------------------------------------------------------------------------- +template<typename Value_t> +bool FunctionParserBase<Value_t>::ParseVariables +(const std::string& inputVarString) +{ + if(mData->mVariablesString == inputVarString) return true; + + /* Delete existing variables from mNamePtrs */ + for(typename NamePtrsMap<Value_t>::iterator i = + mData->mNamePtrs.begin(); + i != mData->mNamePtrs.end(); ) + { + if(i->second.type == NameData<Value_t>::VARIABLE) + { + typename NamePtrsMap<Value_t>::iterator j (i); + ++i; + mData->mNamePtrs.erase(j); + } + else ++i; + } + mData->mVariablesString = inputVarString; + + const std::string& vars = mData->mVariablesString; + const unsigned len = unsigned(vars.size()); + + unsigned varNumber = VarBegin; + + const char* beginPtr = vars.c_str(); + const char* finalPtr = beginPtr + len; + while(beginPtr < finalPtr) + { + SkipSpace(beginPtr); + unsigned nameLength = readIdentifier<Value_t>(beginPtr); + if(nameLength == 0 || (nameLength & 0x80000000U)) return false; + const char* endPtr = beginPtr + nameLength; + SkipSpace(endPtr); + if(endPtr != finalPtr && *endPtr != ',') return false; + + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(beginPtr, nameLength), + NameData<Value_t>(NameData<Value_t>::VARIABLE, varNumber++)); + + if(!addNewNameData(mData->mNamePtrs, newName, true)) + { + return false; + } + + beginPtr = endPtr + 1; + } + + mData->mVariablesAmount = varNumber - VarBegin; + return true; +} + +// --------------------------------------------------------------------------- +// Parse() public interface functions +// --------------------------------------------------------------------------- +template<typename Value_t> +int FunctionParserBase<Value_t>::Parse(const char* Function, + const std::string& Vars, + bool useDegrees) +{ + CopyOnWrite(); + + if(!ParseVariables(Vars)) + { + mData->mParseErrorType = INVALID_VARS; + return int(strlen(Function)); + } + + return ParseFunction(Function, useDegrees); +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::Parse(const std::string& Function, + const std::string& Vars, + bool useDegrees) +{ + CopyOnWrite(); + + if(!ParseVariables(Vars)) + { + mData->mParseErrorType = INVALID_VARS; + return int(Function.size()); + } + + return ParseFunction(Function.c_str(), useDegrees); +} + + +// --------------------------------------------------------------------------- +// Main parsing function +// --------------------------------------------------------------------------- +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseFunction(const char* function, + bool useDegrees) +{ + mData->mUseDegreeConversion = useDegrees; + mData->mParseErrorType = FP_NO_ERROR; + + mData->mInlineVarNames.clear(); + mData->mByteCode.clear(); mData->mByteCode.reserve(128); + mData->mImmed.clear(); mData->mImmed.reserve(128); + mData->mStackSize = mStackPtr = 0; + + mData->mHasByteCodeFlags = false; + + const char* ptr = Compile(function); + mData->mInlineVarNames.clear(); + + if(mData->mHasByteCodeFlags) + { + for(unsigned i = unsigned(mData->mByteCode.size()); i-- > 0; ) + mData->mByteCode[i] &= ~FP_ParamGuardMask; + } + + if(mData->mParseErrorType != FP_NO_ERROR) + return int(mData->mErrorLocation - function); + + assert(ptr); // Should never be null at this point. It's a bug otherwise. + if(*ptr) + { + if(mData->mDelimiterChar == 0 || *ptr != mData->mDelimiterChar) + mData->mParseErrorType = EXPECT_OPERATOR; + return int(ptr - function); + } + +#ifndef FP_USE_THREAD_SAFE_EVAL + mData->mStack.resize(mData->mStackSize); +#endif + + return -1; +} + + +//========================================================================= +// Parsing and bytecode compiling functions +//========================================================================= +template<typename Value_t> +inline const char* FunctionParserBase<Value_t>::SetErrorType(ParseErrorType t, + const char* pos) +{ + mData->mParseErrorType = t; + mData->mErrorLocation = pos; + return 0; +} + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::incStackPtr() +{ + if(++mStackPtr > mData->mStackSize) ++(mData->mStackSize); +} + +namespace +{ + const unsigned char powi_factor_table[128] = + { + 0,1,0,0,0,0,0,0, 0, 0,0,0,0,0,0,3,/* 0 - 15 */ + 0,0,0,0,0,0,0,0, 0, 5,0,3,0,0,3,0,/* 16 - 31 */ + 0,0,0,0,0,0,0,3, 0, 0,0,0,0,5,0,0,/* 32 - 47 */ + 0,0,5,3,0,0,3,5, 0, 3,0,0,3,0,0,3,/* 48 - 63 */ + 0,0,0,0,0,0,0,0, 0, 0,0,3,0,0,3,0,/* 64 - 79 */ + 0,9,0,0,0,5,0,3, 0, 0,5,7,0,0,0,5,/* 80 - 95 */ + 0,0,0,3,5,0,3,0, 0, 3,0,0,3,0,5,3,/* 96 - 111 */ + 0,0,3,5,0,9,0,7, 3,11,0,3,0,5,3,0,/* 112 - 127 */ + }; + + inline int get_powi_factor(long abs_int_exponent) + { + if(abs_int_exponent >= int(sizeof(powi_factor_table))) return 0; + return powi_factor_table[abs_int_exponent]; + } + +#if 0 + int EstimatePowiComplexity(int abs_int_exponent) + { + int cost = 0; + while(abs_int_exponent > 1) + { + int factor = get_powi_factor(abs_int_exponent); + if(factor) + { + cost += EstimatePowiComplexity(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + cost += 3; // sqr + } + else + { + cost += 4; // dup+mul + abs_int_exponent -= 1; + } + } + return cost; + } +#endif + + bool IsEligibleIntPowiExponent(long int_exponent) + { + if(int_exponent == 0) return false; + long abs_int_exponent = int_exponent; + #if 0 + int cost = 0; + + if(abs_int_exponent < 0) + { + cost += 11; + abs_int_exponent = -abs_int_exponent; + } + + cost += EstimatePowiComplexity(abs_int_exponent); + + return cost < (10*3 + 4*4); + #else + if(abs_int_exponent < 0) abs_int_exponent = -abs_int_exponent; + + return (abs_int_exponent >= 1) + && (abs_int_exponent <= 46 || + (abs_int_exponent <= 1024 && + (abs_int_exponent & (abs_int_exponent - 1)) == 0)); + #endif + } + + /* Needed by fp_opcode_add.inc if tracing is enabled */ + template<typename Value_t> + std::string findName(const NamePtrsMap<Value_t>& nameMap, + unsigned index, + typename NameData<Value_t>::DataType type) + { + for(typename NamePtrsMap<Value_t>::const_iterator + iter = nameMap.begin(); + iter != nameMap.end(); + ++iter) + { + if(iter->second.type == type && iter->second.index == index) + return std::string(iter->first.name, + iter->first.name + iter->first.nameLength); + } + return "?"; + } +} + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::AddImmedOpcode(Value_t value) +{ + mData->mImmed.push_back(value); + mData->mByteCode.push_back(cImmed); +} + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::CompilePowi(long abs_int_exponent) +{ + int num_muls=0; + while(abs_int_exponent > 1) + { + long factor = get_powi_factor(abs_int_exponent); + if(factor) + { + CompilePowi(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + mData->mByteCode.push_back(cSqr); + // ^ Don't put AddFunctionOpcode here, + // it would slow down a great deal. + } + else + { + mData->mByteCode.push_back(cDup); + incStackPtr(); + abs_int_exponent -= 1; + ++num_muls; + } + } + if(num_muls > 0) + { + mData->mByteCode.resize(mData->mByteCode.size()+num_muls, cMul); + mStackPtr -= num_muls; + } +} + +template<typename Value_t> +inline bool FunctionParserBase<Value_t>::TryCompilePowi(Value_t original_immed) +{ + Value_t changed_immed = original_immed; + for(int sqrt_count=0; /**/; ++sqrt_count) + { + long int_exponent = makeLongInteger(changed_immed); + if(isLongInteger(changed_immed) && + IsEligibleIntPowiExponent(int_exponent)) + { + long abs_int_exponent = int_exponent; + if(abs_int_exponent < 0) + abs_int_exponent = -abs_int_exponent; + + mData->mImmed.pop_back(); mData->mByteCode.pop_back(); + --mStackPtr; + // ^Though the above is accounted for by the procedure + // that generates cPow, we need it for correct cFetch + // indexes in CompilePowi(). + + while(sqrt_count > 0) + { + int opcode = cSqrt; + if(sqrt_count == 1 && int_exponent < 0) + { + opcode = cRSqrt; + int_exponent = -int_exponent; + } + mData->mByteCode.push_back(opcode); + --sqrt_count; + } + if((abs_int_exponent & 1) == 0) + { + // This special rule fixes the optimization + // shortcoming of (-x)^2 with minimal overhead. + AddFunctionOpcode(cSqr); + abs_int_exponent >>= 1; + } + CompilePowi(abs_int_exponent); + if(int_exponent < 0) mData->mByteCode.push_back(cInv); + ++mStackPtr; // Needed because cPow adding will assume this. + return true; + } + if(sqrt_count >= 4) break; + changed_immed += changed_immed; + } + + // When we don't know whether x >= 0, we still know that + // x^y can be safely converted into exp(y * log(x)) + // when y is _not_ integer, because we know that x >= 0. + // Otherwise either expression will give a NaN. + if(/*!isInteger(original_immed) ||*/ + IsNeverNegativeValueOpcode(mData->mByteCode[mData->mByteCode.size()-2])) + { + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + //--mStackPtr; - accounted for by the procedure that generates cPow + AddFunctionOpcode(cLog); + AddImmedOpcode(original_immed); + //incStackPtr(); - this and the next are redundant because... + AddFunctionOpcode(cMul); + //--mStackPtr; - ...because the cImmed was popped earlier. + AddFunctionOpcode(cExp); + return true; + } + return false; +} + +//#include "fpoptimizer/opcodename.hh" +// ^ needed only if FP_TRACE_BYTECODE_OPTIMIZATION() is used + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::AddFunctionOpcode(unsigned opcode) +{ +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 0 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} + +#ifdef FP_SUPPORT_LONG_INT_TYPE +template<> +inline void FunctionParserBase<long>::AddFunctionOpcode(unsigned opcode) +{ + typedef long Value_t; +#define FP_FLOAT_VERSION 0 +#define FP_COMPLEX_VERSION 0 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> +inline void FunctionParserBase<GmpInt>::AddFunctionOpcode(unsigned opcode) +{ + typedef GmpInt Value_t; +#define FP_FLOAT_VERSION 0 +#define FP_COMPLEX_VERSION 0 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +template<> +inline void FunctionParserBase<std::complex<double> >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex<double> Value_t; +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 1 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +template<> +inline void FunctionParserBase<std::complex<float> >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex<float> Value_t; +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 1 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +template<> +inline void FunctionParserBase<std::complex<long double> >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex<long double> Value_t; +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 1 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +template<typename Value_t> +unsigned +FunctionParserBase<Value_t>::ParseIdentifier(const char* function) +{ + return readIdentifier<Value_t>(function); +} + +template<typename Value_t> +std::pair<const char*, Value_t> +FunctionParserBase<Value_t>::ParseLiteral(const char* function) +{ + char* endptr; +#if 0 /* Profile the hex literal parser */ + if(function[0]=='0' && function[1]=='x') + { + // Parse hexadecimal literal if fp_parseLiteral didn't already + Value_t val = parseHexLiteral<Value_t>(function+2, &endptr); + if(endptr == function+2) + return std::pair<const char*,Value_t> (function, Value_t()); + return std::pair<const char*, Value_t> (endptr, val); + } +#endif + Value_t val = fp_parseLiteral<Value_t>(function, &endptr); + + if(endptr == function+1 && function[0] == '0' && function[1] == 'x') + { + // Parse hexadecimal literal if fp_parseLiteral didn't already + val = parseHexLiteral<Value_t>(function+2, &endptr); + if(endptr == function+2) + return std::pair<const char*,Value_t> (function, Value_t()); + } + else if(endptr == function) + return std::pair<const char*,Value_t> (function, Value_t()); + + return std::pair<const char*,Value_t> (endptr, val); +} + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +template<> +std::pair<const char*, MpfrFloat> +FunctionParserBase<MpfrFloat>::ParseLiteral(const char* function) +{ + char* endPtr; + const MpfrFloat val = MpfrFloat::parseString(function, &endPtr); + if(endPtr == function) + return std::pair<const char*,MpfrFloat> (function, MpfrFloat()); + return std::pair<const char*,MpfrFloat> (endPtr, val); +} +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> +std::pair<const char*, GmpInt> +FunctionParserBase<GmpInt>::ParseLiteral(const char* function) +{ + char* endPtr; + const GmpInt val = GmpInt::parseString(function, &endPtr); + if(endPtr == function) + return std::pair<const char*,GmpInt> (function, GmpInt()); + return std::pair<const char*,GmpInt> (endPtr, val); +} +#endif + + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileLiteral(const char* function) +{ + std::pair<const char*, Value_t> result = ParseLiteral(function); + + if(result.first == function) + return SetErrorType(SYNTAX_ERROR, result.first); + + AddImmedOpcode(result.second); + incStackPtr(); + SkipSpace(result.first); + return result.first; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileIf(const char* function) +{ + if(*function != '(') return SetErrorType(EXPECT_PARENTH_FUNC, function); + + function = CompileExpression(function+1); + if(!function) return 0; + if(*function != ',') + return SetErrorType(noCommaError<Value_t>(*function), function); + + OPCODE opcode = cIf; + if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back(); + if(IsNeverNegativeValueOpcode(mData->mByteCode.back())) + { + // If we know that the condition to be tested is always + // a positive value (such as when produced by "x<y"), + // we can use the faster opcode to evaluate it. + // cIf tests whether fabs(cond) >= 0.5, + // cAbsIf simply tests whether cond >= 0.5. + opcode = cAbsIf; + } + + mData->mByteCode.push_back(opcode); + const unsigned curByteCodeSize = unsigned(mData->mByteCode.size()); + PushOpcodeParam<false>(0); // Jump index; to be set later + PushOpcodeParam<true> (0); // Immed jump index; to be set later + + --mStackPtr; + + function = CompileExpression(function + 1); + if(!function) return 0; + if(*function != ',') + return SetErrorType(noCommaError<Value_t>(*function), function); + + mData->mByteCode.push_back(cJump); + const unsigned curByteCodeSize2 = unsigned(mData->mByteCode.size()); + const unsigned curImmedSize2 = unsigned(mData->mImmed.size()); + PushOpcodeParam<false>(0); // Jump index; to be set later + PushOpcodeParam<true> (0); // Immed jump index; to be set later + + --mStackPtr; + + function = CompileExpression(function + 1); + if(!function) return 0; + if(*function != ')') + return SetErrorType(noParenthError<Value_t>(*function), function); + + PutOpcodeParamAt<true> ( mData->mByteCode.back(), unsigned(mData->mByteCode.size()-1) ); + // ^Necessary for guarding against if(x,1,2)+1 being changed + // into if(x,1,3) by fp_opcode_add.inc + + // Set jump indices + PutOpcodeParamAt<false>( curByteCodeSize2+1, curByteCodeSize ); + PutOpcodeParamAt<false>( curImmedSize2, curByteCodeSize+1 ); + PutOpcodeParamAt<false>( unsigned(mData->mByteCode.size())-1, curByteCodeSize2); + PutOpcodeParamAt<false>( unsigned(mData->mImmed.size()), curByteCodeSize2+1); + + ++function; + SkipSpace(function); + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileFunctionParams +(const char* function, unsigned requiredParams) +{ + if(*function != '(') return SetErrorType(EXPECT_PARENTH_FUNC, function); + + if(requiredParams > 0) + { + const char* function_end = CompileExpression(function+1); + if(!function_end) + { + // If an error occurred, verify whether it was caused by () + ++function; + SkipSpace(function); + if(*function == ')') + return SetErrorType(ILL_PARAMS_AMOUNT, function); + // Not caused by (), use the error message given by CompileExpression() + return 0; + } + function = function_end; + + for(unsigned i = 1; i < requiredParams; ++i) + { + if(*function != ',') + return SetErrorType(noCommaError<Value_t>(*function), function); + + function = CompileExpression(function+1); + if(!function) return 0; + } + // No need for incStackPtr() because each parse parameter calls it + mStackPtr -= requiredParams-1; + } + else + { + incStackPtr(); // return value of function is pushed onto the stack + ++function; + SkipSpace(function); + } + + if(*function != ')') + return SetErrorType(noParenthError<Value_t>(*function), function); + ++function; + SkipSpace(function); + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileElement(const char* function) +{ + if(BeginsLiteral<Value_t>( (unsigned char) *function)) + return CompileLiteral(function); + + unsigned nameLength = readIdentifier<Value_t>(function); + if(nameLength == 0) + { + // No identifier found + if(*function == '(') return CompileParenthesis(function); + if(*function == ')') return SetErrorType(MISM_PARENTH, function); + return SetErrorType(SYNTAX_ERROR, function); + } + + // Function, variable or constant + if(nameLength & 0x80000000U) // Function + { + OPCODE func_opcode = OPCODE( (nameLength >> 16) & 0x7FFF ); + return CompileFunction(function + (nameLength & 0xFFFF), func_opcode); + } + + NamePtr name(function, nameLength); + const char* endPtr = function + nameLength; + SkipSpace(endPtr); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(name); + if(nameIter == mData->mNamePtrs.end()) + { + // Check if it's an inline variable: + for(typename Data::InlineVarNamesContainer::reverse_iterator iter = + mData->mInlineVarNames.rbegin(); + iter != mData->mInlineVarNames.rend(); + ++iter) + { + if(name == iter->mName) + { + if( iter->mFetchIndex+1 == mStackPtr) + { + mData->mByteCode.push_back(cDup); + } + else + { + mData->mByteCode.push_back(cFetch); + PushOpcodeParam<true>(iter->mFetchIndex); + } + incStackPtr(); + return endPtr; + } + } + + return SetErrorType(UNKNOWN_IDENTIFIER, function); + } + + const NameData<Value_t>* nameData = &nameIter->second; + switch(nameData->type) + { + case NameData<Value_t>::VARIABLE: // is variable + if(unlikely(!mData->mByteCode.empty() && + mData->mByteCode.back() == nameData->index)) + mData->mByteCode.push_back(cDup); + else + mData->mByteCode.push_back(nameData->index); + incStackPtr(); + return endPtr; + + case NameData<Value_t>::CONSTANT: // is constant + AddImmedOpcode(nameData->value); + incStackPtr(); + return endPtr; + + case NameData<Value_t>::UNIT: // is unit (error if appears here) + break; + + case NameData<Value_t>::FUNC_PTR: // is C++ function + function = CompileFunctionParams + (endPtr, mData->mFuncPtrs[nameData->index].mParams); + //if(!function) return 0; + mData->mByteCode.push_back(cFCall); + PushOpcodeParam<true>(nameData->index); + return function; + + case NameData<Value_t>::PARSER_PTR: // is FunctionParser + function = CompileFunctionParams + (endPtr, mData->mFuncParsers[nameData->index].mParams); + //if(!function) return 0; + mData->mByteCode.push_back(cPCall); + PushOpcodeParam<true>(nameData->index); + return function; + } + + // When it's an unit (or unrecognized type): + return SetErrorType(SYNTAX_ERROR, function); +} + +template<typename Value_t> +inline const char* FunctionParserBase<Value_t>::CompileFunction +(const char* function, unsigned func_opcode) +{ + SkipSpace(function); + const FuncDefinition& funcDef = Functions[func_opcode]; + + if(func_opcode == cIf) // "if" is a special case + return CompileIf(function); + + unsigned requiredParams = funcDef.params; + + function = CompileFunctionParams(function, requiredParams); + if(!function) return 0; + + if(mData->mUseDegreeConversion) + { + if(funcDef.flags & FuncDefinition::AngleIn) + AddFunctionOpcode(cRad); + + AddFunctionOpcode(func_opcode); + + if(funcDef.flags & FuncDefinition::AngleOut) + AddFunctionOpcode(cDeg); + } + else + { + AddFunctionOpcode(func_opcode); + } + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileParenthesis(const char* function) +{ + ++function; // Skip '(' + + SkipSpace(function); + if(*function == ')') return SetErrorType(EMPTY_PARENTH, function); + function = CompileExpression(function); + if(!function) return 0; + + if(*function != ')') return SetErrorType(MISSING_PARENTH, function); + ++function; // Skip ')' + + SkipSpace(function); + return function; +} + +template<typename Value_t> +const char* +FunctionParserBase<Value_t>::CompilePossibleUnit(const char* function) +{ + unsigned nameLength = readIdentifier<Value_t>(function); + if(nameLength & 0x80000000U) return function; // built-in function name + if(nameLength != 0) + { + NamePtr name(function, nameLength); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(name); + if(nameIter != mData->mNamePtrs.end()) + { + const NameData<Value_t>* nameData = &nameIter->second; + if(nameData->type == NameData<Value_t>::UNIT) + { + AddImmedOpcode(nameData->value); + incStackPtr(); + AddFunctionOpcode(cMul); + --mStackPtr; + + const char* endPtr = function + nameLength; + SkipSpace(endPtr); + return endPtr; + } + } + } + + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompilePow(const char* function) +{ + function = CompileElement(function); + if(!function) return 0; + function = CompilePossibleUnit(function); + + if(*function == '^') + { + ++function; + SkipSpace(function); + + unsigned op = cPow; + if(mData->mByteCode.back() == cImmed) + { + if(mData->mImmed.back() == fp_const_e<Value_t>()) + { op = cExp; mData->mByteCode.pop_back(); + mData->mImmed.pop_back(); --mStackPtr; } + else if(mData->mImmed.back() == Value_t(2)) + { op = cExp2; mData->mByteCode.pop_back(); + mData->mImmed.pop_back(); --mStackPtr; } + } + + function = CompileUnaryMinus(function); + if(!function) return 0; + + // add opcode + AddFunctionOpcode(op); + + if(op == cPow) --mStackPtr; + } + return function; +} + +/* Currently the power operator is skipped for integral types because its + usefulness with them is questionable, and in the case of GmpInt, for safety + reasons: + - With long int almost any power, except for very small ones, would + overflow the result, so the usefulness of this is rather questionable. + - With GmpInt the power operator could be easily abused to make the program + run out of memory (think of a function like "10^10^10^10^1000000"). +*/ +#ifdef FP_SUPPORT_LONG_INT_TYPE +template<> +inline const char* +FunctionParserBase<long>::CompilePow(const char* function) +{ + function = CompileElement(function); + if(!function) return 0; + return CompilePossibleUnit(function); +} +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> +inline const char* +FunctionParserBase<GmpInt>::CompilePow(const char* function) +{ + function = CompileElement(function); + if(!function) return 0; + return CompilePossibleUnit(function); +} +#endif + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileUnaryMinus(const char* function) +{ + char op = *function; + switch(op) + { + case '-': + case '!': + ++function; + SkipSpace(function); + + function = CompileUnaryMinus(function); + if(!function) return 0; + + AddFunctionOpcode(op=='-' ? cNeg : cNot); + + return function; + default: break; + } + return CompilePow(function); +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileMult(const char* function) +{ + function = CompileUnaryMinus(function); + if(!function) return 0; + + Value_t pending_immed(1); + #define FP_FlushImmed(do_reset) \ + if(pending_immed != Value_t(1)) \ + { \ + unsigned op = cMul; \ + if(!IsIntType<Value_t>::result && mData->mByteCode.back() == cInv) \ + { \ + /* (...) cInv 5 cMul -> (...) 5 cRDiv */ \ + /* ^ ^ | */ \ + mData->mByteCode.pop_back(); \ + op = cRDiv; \ + } \ + AddImmedOpcode(pending_immed); \ + incStackPtr(); \ + AddFunctionOpcode(op); \ + --mStackPtr; \ + if(do_reset) pending_immed = Value_t(1); \ + } + while(true) + { + char c = *function; + if(c == '%') + { + FP_FlushImmed(true); + ++function; + SkipSpace(function); + function = CompileUnaryMinus(function); + if(!function) return 0; + AddFunctionOpcode(cMod); + --mStackPtr; + continue; + } + if(c != '*' && c != '/') break; + + bool safe_cumulation = (c == '*' || !IsIntType<Value_t>::result); + if(!safe_cumulation) + { + FP_FlushImmed(true); + } + + ++function; + SkipSpace(function); + if(mData->mByteCode.back() == cImmed + && (safe_cumulation + || mData->mImmed.back() == Value_t(1))) + { + // 5 (...) cMul --> (...) ||| 5 cMul + // 5 (...) cDiv --> (...) cInv ||| 5 cMul + // ^ | ^ + pending_immed *= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + --mStackPtr; + function = CompileUnaryMinus(function); + if(!function) return 0; + if(c == '/') + AddFunctionOpcode(cInv); + continue; + } + if(safe_cumulation + && mData->mByteCode.back() == cMul + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) 5 cMul (...) cMul -> (:::) (...) cMul ||| 5 cMul + // (:::) 5 cMul (...) cDiv -> (:::) (...) cDiv ||| 5 cMul + // ^ ^ + pending_immed *= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + // cDiv is not tested here because the bytecode + // optimizer will convert this kind of cDivs into cMuls. + bool lhs_inverted = false; + if(!IsIntType<Value_t>::result && c == '*' + && mData->mByteCode.back() == cInv) + { + // (:::) cInv (...) cMul -> (:::) (...) cRDiv + // (:::) cInv (...) cDiv -> (:::) (...) cMul cInv + // ^ ^ | + mData->mByteCode.pop_back(); + lhs_inverted = true; + } + function = CompileUnaryMinus(function); + if(!function) return 0; + if(safe_cumulation + && mData->mByteCode.back() == cMul + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cMul cMul -> (:::) (...) cMul ||| 5 Mul + // (:::) (...) 5 cMul cDiv -> (:::) (...) cDiv ||| /5 Mul + // ^ ^ + if(c == '*') + pending_immed *= mData->mImmed.back(); + else + pending_immed /= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + else + if(safe_cumulation + && mData->mByteCode.back() == cRDiv + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cRDiv cMul -> (:::) (...) cDiv ||| 5 cMul + // (:::) (...) 5 cRDiv cDiv -> (:::) (...) cMul ||| /5 cMul + // ^ ^ + if(c == '*') + { c = '/'; pending_immed *= mData->mImmed.back(); } + else + { c = '*'; pending_immed /= mData->mImmed.back(); } + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + if(!lhs_inverted) // if (/x/y) was changed to /(x*y), add missing cInv + { + AddFunctionOpcode(c == '*' ? cMul : cDiv); + --mStackPtr; + } + else if(c == '*') // (/x)*y -> rdiv(x,y) + { + AddFunctionOpcode(cRDiv); + --mStackPtr; + } + else // (/x)/y -> /(x*y) + { + AddFunctionOpcode(cMul); + --mStackPtr; + AddFunctionOpcode(cInv); + } + } + FP_FlushImmed(false); + #undef FP_FlushImmed + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileAddition(const char* function) +{ + function = CompileMult(function); + if(!function) return 0; + + Value_t pending_immed(0); + #define FP_FlushImmed(do_reset) \ + if(pending_immed != Value_t(0)) \ + { \ + unsigned op = cAdd; \ + if(mData->mByteCode.back() == cNeg) \ + { \ + /* (...) cNeg 5 cAdd -> (...) 5 cRSub */ \ + /* ^ ^ | */ \ + mData->mByteCode.pop_back(); \ + op = cRSub; \ + } \ + AddImmedOpcode(pending_immed); \ + incStackPtr(); \ + AddFunctionOpcode(op); \ + --mStackPtr; \ + if(do_reset) pending_immed = Value_t(0); \ + } + while(true) + { + char c = *function; + if(c != '+' && c != '-') break; + ++function; + SkipSpace(function); + if(mData->mByteCode.back() == cImmed) + { + // 5 (...) cAdd --> (...) ||| 5 cAdd + // 5 (...) cSub --> (...) cNeg ||| 5 cAdd + // ^ | ^ + pending_immed += mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + --mStackPtr; + function = CompileMult(function); + if(!function) return 0; + if(c == '-') + AddFunctionOpcode(cNeg); + continue; + } + if(mData->mByteCode.back() == cAdd + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) 5 cAdd (...) cAdd -> (:::) (...) cAdd ||| 5 cAdd + // (:::) 5 cAdd (...) cSub -> (:::) (...) cSub ||| 5 cAdd + // ^ ^ + pending_immed += mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + // cSub is not tested here because the bytecode + // optimizer will convert this kind of cSubs into cAdds. + bool lhs_negated = false; + if(mData->mByteCode.back() == cNeg) + { + // (:::) cNeg (...) cAdd -> (:::) (...) cRSub + // (:::) cNeg (...) cSub -> (:::) (...) cAdd cNeg + // ^ ^ | + mData->mByteCode.pop_back(); + lhs_negated = true; + } + function = CompileMult(function); + if(!function) return 0; + if(mData->mByteCode.back() == cAdd + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cAdd cAdd -> (:::) (...) cAdd ||| 5 Add + // (:::) (...) 5 cAdd cSub -> (:::) (...) cSub ||| -5 Add + // ^ ^ + if(c == '+') + pending_immed += mData->mImmed.back(); + else + pending_immed -= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + else + if(mData->mByteCode.back() == cRSub + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cRSub cAdd -> (:::) (...) cSub ||| 5 cAdd + // (:::) (...) 5 cRSub cSub -> (:::) (...) cAdd ||| -5 cAdd + // ^ ^ + if(c == '+') + { c = '-'; pending_immed += mData->mImmed.back(); } + else + { c = '+'; pending_immed -= mData->mImmed.back(); } + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + if(!lhs_negated) // if (-x-y) was changed to -(x+y), add missing cNeg + { + AddFunctionOpcode(c == '+' ? cAdd : cSub); + --mStackPtr; + } + else if(c == '+') // (-x)+y -> rsub(x,y) + { + AddFunctionOpcode(cRSub); + --mStackPtr; + } + else // (-x)-y -> -(x+y) + { + AddFunctionOpcode(cAdd); + --mStackPtr; + AddFunctionOpcode(cNeg); + } + } + FP_FlushImmed(false); + #undef FP_FlushImmed + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileComparison(const char* function) +{ + unsigned op=0; + while(true) + { + function = CompileAddition(function); + if(!function) return 0; + + if(op) + { + AddFunctionOpcode(op); + --mStackPtr; + } + switch(*function) + { + case '=': + ++function; op = cEqual; break; + case '!': + if(function[1] == '=') + { function += 2; op = cNEqual; break; } + // If '=' does not follow '!', a syntax error will + // be generated at the outermost parsing level + return function; + case '<': + if(function[1] == '=') + { function += 2; op = cLessOrEq; break; } + ++function; op = cLess; break; + case '>': + if(function[1] == '=') + { function += 2; op = cGreaterOrEq; break; } + ++function; op = cGreater; break; + default: return function; + } + SkipSpace(function); + } + return function; +} + +template<typename Value_t> +inline const char* FunctionParserBase<Value_t>::CompileAnd(const char* function) +{ + std::size_t param0end=0; + while(true) + { + function = CompileComparison(function); + if(!function) return 0; + + if(param0end) + { + if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back(); + + AddFunctionOpcode(cAnd); + --mStackPtr; + } + if(*function != '&') break; + ++function; + SkipSpace(function); + param0end = mData->mByteCode.size(); + } + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileExpression(const char* function) +{ + std::size_t param0end=0; + while(true) + { + SkipSpace(function); + function = CompileAnd(function); + if(!function) return 0; + + if(param0end) + { + if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back(); + + AddFunctionOpcode(cOr); + --mStackPtr; + } + if(*function != '|') break; + ++function; + param0end = mData->mByteCode.size(); + } + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::Compile(const char* function) +{ + while(true) + { + // Check if an identifier appears as first token: + SkipSpace(function); + unsigned nameLength = readIdentifier<Value_t>(function); + if(nameLength > 0 && !(nameLength & 0x80000000U)) + { + typename Data::InlineVariable inlineVar = + { NamePtr(function, nameLength), 0 }; + + // Check if it's an unknown identifier: + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(inlineVar.mName); + if(nameIter == mData->mNamePtrs.end()) + { + const char* function2 = function + nameLength; + SkipSpace(function2); + + // Check if ":=" follows the unknown identifier: + if(function2[0] == ':' && function2[1] == '=') + { + // Parse the expression that follows and create the + // inline variable: + function2 = CompileExpression(function2 + 2); + if(!function2) return 0; + if(*function2 != ';') return function2; + + inlineVar.mFetchIndex = mStackPtr - 1; + mData->mInlineVarNames.push_back(inlineVar); + + // Continue with the expression after the ';': + function = function2 + 1; + continue; + } + } + } + break; + } + + return CompileExpression(function); +} + +template<typename Value_t> template<bool PutFlag> +inline void FunctionParserBase<Value_t>::PushOpcodeParam + (unsigned value) +{ + mData->mByteCode.push_back(value | (PutFlag ? FP_ParamGuardMask : 0u)); + if(PutFlag) mData->mHasByteCodeFlags = true; +} + +template<typename Value_t> template<bool PutFlag> +inline void FunctionParserBase<Value_t>::PutOpcodeParamAt + (unsigned value, unsigned offset) +{ + mData->mByteCode[offset] = value | (PutFlag ? FP_ParamGuardMask : 0u); + if(PutFlag) mData->mHasByteCodeFlags = true; +} + +//=========================================================================== +// Function evaluation +//=========================================================================== +template<typename Value_t> +Value_t FunctionParserBase<Value_t>::Eval(const Value_t* Vars) +{ + if(mData->mParseErrorType != FP_NO_ERROR) return Value_t(0); + + const unsigned* const byteCode = &(mData->mByteCode[0]); + const Value_t* const immed = mData->mImmed.empty() ? 0 : &(mData->mImmed[0]); + const unsigned byteCodeSize = unsigned(mData->mByteCode.size()); + unsigned IP, DP=0; + int SP=-1; + +#ifdef FP_USE_THREAD_SAFE_EVAL + /* If Eval() may be called by multiple threads simultaneously, + * then Eval() must allocate its own stack. + */ +#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA + /* alloca() allocates room from the hardware stack. + * It is automatically freed when the function returns. + */ + Value_t* const Stack = (Value_t*)alloca(mData->mStackSize*sizeof(Value_t)); +#else + /* Allocate from the heap. Ensure that it is freed + * automatically no matter which exit path is taken. + */ + struct AutoDealloc + { + Value_t* ptr; + ~AutoDealloc() { delete[] ptr; } + } AutoDeallocStack = { new Value_t[mData->mStackSize] }; + Value_t*& Stack = AutoDeallocStack.ptr; +#endif +#else + /* No thread safety, so use a global stack. */ + std::vector<Value_t>& Stack = mData->mStack; +#endif + + for(IP=0; IP<byteCodeSize; ++IP) + { + switch(byteCode[IP]) + { +// Functions: + case cAbs: Stack[SP] = fp_abs(Stack[SP]); break; + + case cAcos: + if(IsComplexType<Value_t>::result == false + && (Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1))) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_acos(Stack[SP]); break; + + case cAcosh: + if(IsComplexType<Value_t>::result == false + && Stack[SP] < Value_t(1)) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_acosh(Stack[SP]); break; + + case cAsin: + if(IsComplexType<Value_t>::result == false + && (Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1))) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_asin(Stack[SP]); break; + + case cAsinh: Stack[SP] = fp_asinh(Stack[SP]); break; + + case cAtan: Stack[SP] = fp_atan(Stack[SP]); break; + + case cAtan2: Stack[SP-1] = fp_atan2(Stack[SP-1], Stack[SP]); + --SP; break; + + case cAtanh: + if(IsComplexType<Value_t>::result + ? (Stack[SP] == Value_t(-1) || Stack[SP] == Value_t(1)) + : (Stack[SP] <= Value_t(-1) || Stack[SP] >= Value_t(1))) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_atanh(Stack[SP]); break; + + case cCbrt: Stack[SP] = fp_cbrt(Stack[SP]); break; + + case cCeil: Stack[SP] = fp_ceil(Stack[SP]); break; + + case cCos: Stack[SP] = fp_cos(Stack[SP]); break; + + case cCosh: Stack[SP] = fp_cosh(Stack[SP]); break; + + case cCot: + { + const Value_t t = fp_tan(Stack[SP]); + if(t == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/t; break; + } + + case cCsc: + { + const Value_t s = fp_sin(Stack[SP]); + if(s == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/s; break; + } + + + case cExp: Stack[SP] = fp_exp(Stack[SP]); break; + + case cExp2: Stack[SP] = fp_exp2(Stack[SP]); break; + + case cFloor: Stack[SP] = fp_floor(Stack[SP]); break; + + case cHypot: + Stack[SP-1] = fp_hypot(Stack[SP-1], Stack[SP]); + --SP; break; + + case cIf: + if(fp_truth(Stack[SP--])) + IP += 2; + else + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + } + break; + + case cInt: Stack[SP] = fp_int(Stack[SP]); break; + + case cLog: + if(IsComplexType<Value_t>::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log(Stack[SP]); break; + + case cLog10: + if(IsComplexType<Value_t>::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log10(Stack[SP]); + break; + + case cLog2: + if(IsComplexType<Value_t>::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log2(Stack[SP]); + break; + + case cMax: Stack[SP-1] = fp_max(Stack[SP-1], Stack[SP]); + --SP; break; + + case cMin: Stack[SP-1] = fp_min(Stack[SP-1], Stack[SP]); + --SP; break; + + case cPow: + // x:Negative ^ y:NonInteger is failure, + // except when the reciprocal of y forms an integer + /*if(IsComplexType<Value_t>::result == false + && Stack[SP-1] < Value_t(0) && + !isInteger(Stack[SP]) && + !isInteger(1.0 / Stack[SP])) + { mEvalErrorType=3; return Value_t(0); }*/ + // x:0 ^ y:negative is failure + if(Stack[SP-1] == Value_t(0) && + Stack[SP] < Value_t(0)) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP-1] = fp_pow(Stack[SP-1], Stack[SP]); + --SP; break; + + case cTrunc: Stack[SP] = fp_trunc(Stack[SP]); break; + + case cSec: + { + const Value_t c = fp_cos(Stack[SP]); + if(c == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/c; break; + } + + case cSin: Stack[SP] = fp_sin(Stack[SP]); break; + + case cSinh: Stack[SP] = fp_sinh(Stack[SP]); break; + + case cSqrt: + if(IsComplexType<Value_t>::result == false && + Stack[SP] < Value_t(0)) + { mData->mEvalErrorType=2; return Value_t(0); } + Stack[SP] = fp_sqrt(Stack[SP]); break; + + case cTan: Stack[SP] = fp_tan(Stack[SP]); break; + + case cTanh: Stack[SP] = fp_tanh(Stack[SP]); break; + + +// Misc: + case cImmed: Stack[++SP] = immed[DP++]; break; + + case cJump: + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + break; + } + +// Operators: + case cNeg: Stack[SP] = -Stack[SP]; break; + case cAdd: Stack[SP-1] += Stack[SP]; --SP; break; + case cSub: Stack[SP-1] -= Stack[SP]; --SP; break; + case cMul: Stack[SP-1] *= Stack[SP]; --SP; break; + + case cDiv: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] /= Stack[SP]; --SP; break; + + case cMod: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] = fp_mod(Stack[SP-1], Stack[SP]); + --SP; break; + + case cEqual: + Stack[SP-1] = fp_equal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cNEqual: + Stack[SP-1] = fp_nequal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLess: + Stack[SP-1] = fp_less(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLessOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP-1], Stack[SP]); + --SP; break; + + case cGreater: + Stack[SP-1] = fp_less(Stack[SP], Stack[SP-1]); + --SP; break; + + case cGreaterOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP], Stack[SP-1]); + --SP; break; + + case cNot: Stack[SP] = fp_not(Stack[SP]); break; + + case cNotNot: Stack[SP] = fp_notNot(Stack[SP]); break; + + case cAnd: + Stack[SP-1] = fp_and(Stack[SP-1], Stack[SP]); + --SP; break; + + case cOr: + Stack[SP-1] = fp_or(Stack[SP-1], Stack[SP]); + --SP; break; + +// Degrees-radians conversion: + case cDeg: Stack[SP] = RadiansToDegrees(Stack[SP]); break; + case cRad: Stack[SP] = DegreesToRadians(Stack[SP]); break; + +// User-defined function calls: + case cFCall: + { + const unsigned index = byteCode[++IP]; + const unsigned params = mData->mFuncPtrs[index].mParams; + const Value_t retVal = + mData->mFuncPtrs[index].mRawFuncPtr ? + mData->mFuncPtrs[index].mRawFuncPtr(&Stack[SP-params+1]) : + mData->mFuncPtrs[index].mFuncWrapperPtr->callFunction + (&Stack[SP-params+1]); + SP -= int(params)-1; + Stack[SP] = retVal; + break; + } + + case cPCall: + { + unsigned index = byteCode[++IP]; + unsigned params = mData->mFuncParsers[index].mParams; + Value_t retVal = + mData->mFuncParsers[index].mParserPtr->Eval + (&Stack[SP-params+1]); + SP -= int(params)-1; + Stack[SP] = retVal; + const int error = + mData->mFuncParsers[index].mParserPtr->EvalError(); + if(error) + { + mData->mEvalErrorType = error; + return 0; + } + break; + } + + + case cFetch: + { + unsigned stackOffs = byteCode[++IP]; + Stack[SP+1] = Stack[stackOffs]; ++SP; + break; + } + +#ifdef FP_SUPPORT_OPTIMIZER + case cPopNMov: + { + unsigned stackOffs_target = byteCode[++IP]; + unsigned stackOffs_source = byteCode[++IP]; + Stack[stackOffs_target] = Stack[stackOffs_source]; + SP = stackOffs_target; + break; + } + + case cLog2by: + if(IsComplexType<Value_t>::result + ? Stack[SP-1] == Value_t(0) + : !(Stack[SP-1] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP-1] = fp_log2(Stack[SP-1]) * Stack[SP]; + --SP; + break; + + case cNop: break; +#endif // FP_SUPPORT_OPTIMIZER + + case cSinCos: + fp_sinCos(Stack[SP], Stack[SP+1], Stack[SP]); + ++SP; + break; + case cSinhCosh: + fp_sinhCosh(Stack[SP], Stack[SP+1], Stack[SP]); + ++SP; + break; + + case cAbsNot: + Stack[SP] = fp_absNot(Stack[SP]); break; + case cAbsNotNot: + Stack[SP] = fp_absNotNot(Stack[SP]); break; + case cAbsAnd: + Stack[SP-1] = fp_absAnd(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsOr: + Stack[SP-1] = fp_absOr(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsIf: + if(fp_absTruth(Stack[SP--])) + IP += 2; + else + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + } + break; + + case cDup: Stack[SP+1] = Stack[SP]; ++SP; break; + + case cInv: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/Stack[SP]; + break; + + case cSqr: + Stack[SP] = Stack[SP]*Stack[SP]; + break; + + case cRDiv: + if(Stack[SP-1] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] = Stack[SP] / Stack[SP-1]; --SP; break; + + case cRSub: Stack[SP-1] = Stack[SP] - Stack[SP-1]; --SP; break; + + case cRSqrt: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1) / fp_sqrt(Stack[SP]); break; + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + case cReal: Stack[SP] = fp_real(Stack[SP]); break; + case cImag: Stack[SP] = fp_imag(Stack[SP]); break; + case cArg: Stack[SP] = fp_arg(Stack[SP]); break; + case cConj: Stack[SP] = fp_conj(Stack[SP]); break; + case cPolar: + Stack[SP-1] = fp_polar(Stack[SP-1], Stack[SP]); + --SP; break; +#endif + + +// Variables: + default: + Stack[++SP] = Vars[byteCode[IP]-VarBegin]; + } + } + + mData->mEvalErrorType=0; + return Stack[SP]; +} + + +//=========================================================================== +// Variable deduction +//=========================================================================== +namespace +{ + template<typename Value_t> + int deduceVariables(FunctionParserBase<Value_t>& fParser, + const char* funcStr, + std::string& destVarString, + int* amountOfVariablesFound, + std::vector<std::string>* destVarNames, + bool useDegrees) + { + typedef std::set<std::string> StrSet; + StrSet varNames; + + int oldIndex = -1; + + while(true) + { + destVarString.clear(); + for(StrSet::iterator iter = varNames.begin(); + iter != varNames.end(); + ++iter) + { + if(iter != varNames.begin()) destVarString += ","; + destVarString += *iter; + } + + const int index = + fParser.Parse(funcStr, destVarString, useDegrees); + if(index < 0) break; + if(index == oldIndex) return index; + + unsigned nameLength = readIdentifier<Value_t>(funcStr + index); + if(nameLength & 0x80000000U) return index; + if(nameLength == 0) return index; + + varNames.insert(std::string(funcStr + index, nameLength)); + oldIndex = index; + } + + if(amountOfVariablesFound) + *amountOfVariablesFound = int(varNames.size()); + + if(destVarNames) + destVarNames->assign(varNames.begin(), varNames.end()); + + return -1; + } +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseAndDeduceVariables +(const std::string& function, + int* amountOfVariablesFound, + bool useDegrees) +{ + std::string varString; + return deduceVariables(*this, function.c_str(), varString, + amountOfVariablesFound, 0, useDegrees); +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseAndDeduceVariables +(const std::string& function, + std::string& resultVarString, + int* amountOfVariablesFound, + bool useDegrees) +{ + std::string varString; + const int index = + deduceVariables(*this, function.c_str(), varString, + amountOfVariablesFound, 0, useDegrees); + if(index < 0) resultVarString = varString; + return index; +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseAndDeduceVariables +(const std::string& function, + std::vector<std::string>& resultVars, + bool useDegrees) +{ + std::string varString; + std::vector<std::string> vars; + const int index = + deduceVariables(*this, function.c_str(), varString, + 0, &vars, useDegrees); + if(index < 0) resultVars.swap(vars); + return index; +} + + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +//=========================================================================== +// Bytecode injection +//=========================================================================== +template<typename Value_t> +void FunctionParserBase<Value_t>::InjectRawByteCode +(const unsigned* bytecode, unsigned bytecodeAmount, + const Value_t* immed, unsigned immedAmount, unsigned stackSize) +{ + CopyOnWrite(); + + mData->mByteCode.assign(bytecode, bytecode + bytecodeAmount); + mData->mImmed.assign(immed, immed + immedAmount); + mData->mStackSize = stackSize; + +#ifndef FP_USE_THREAD_SAFE_EVAL + mData->mStack.resize(stackSize); +#endif +} + +//=========================================================================== +// Debug output +//=========================================================================== +#include <iomanip> +#include <sstream> +namespace +{ + inline void printHex(std::ostream& dest, unsigned n) + { + std::ios::fmtflags flags = dest.flags(); + dest.width(4); dest.fill('0'); std::hex(dest); //uppercase(dest); + dest << n; + dest.flags(flags); + } + + void padLine(std::ostringstream& dest, unsigned destLength) + { + for(std::size_t currentLength = dest.str().length(); + currentLength < destLength; + ++currentLength) + { + dest << ' '; + } + } + + const struct PowiMuliType + { + unsigned opcode_square; + unsigned opcode_cumulate; + unsigned opcode_invert; + unsigned opcode_half; + unsigned opcode_invhalf; + } iseq_powi = {cSqr,cMul,cInv,cSqrt,cRSqrt}, + iseq_muli = {~unsigned(0), cAdd,cNeg, ~unsigned(0),~unsigned(0) }; + + template<typename Value_t> + Value_t ParsePowiMuli( + const PowiMuliType& opcodes, + const std::vector<unsigned>& ByteCode, unsigned& IP, + unsigned limit, + std::size_t factor_stack_base, + std::vector<Value_t>& stack, + bool IgnoreExcess) + { + Value_t result = Value_t(1); + while(IP < limit) + { + if(ByteCode[IP] == opcodes.opcode_square) + { + if(!isInteger(result)) break; + result *= Value_t(2); + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_invert) + { + if(result < Value_t(0)) break; + result = -result; + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_half) + { + if(result > Value_t(0) && isEvenInteger(result)) + break; + if(isInteger(result * Value_t(0.5))) break; + result *= Value_t(0.5); + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_invhalf) + { + if(result > Value_t(0) && isEvenInteger(result)) + break; + if(isInteger(result * Value_t(-0.5))) break; + result *= Value_t(-0.5); + ++IP; + continue; + } + + unsigned dup_fetch_pos = IP; + Value_t lhs = Value_t(1); + + if(ByteCode[IP] == cFetch) + { + unsigned index = ByteCode[++IP]; + if(index < factor_stack_base + || std::size_t(index-factor_stack_base) >= stack.size()) + { + // It wasn't a powi-fetch after all + IP = dup_fetch_pos; + break; + } + lhs = stack[index - factor_stack_base]; + // Note: ^This assumes that cFetch of recentmost + // is always converted into cDup. + goto dup_or_fetch; + } + + if(ByteCode[IP] == cDup) + { + lhs = result; + goto dup_or_fetch; + + dup_or_fetch: + stack.push_back(result); + ++IP; + Value_t subexponent = ParsePowiMuli + (opcodes, + ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); + if(IP >= limit && IgnoreExcess) + return lhs*subexponent; + if(IP >= limit || ByteCode[IP] != opcodes.opcode_cumulate) + { + // It wasn't a powi-dup after all + IP = dup_fetch_pos; + break; + } + ++IP; // skip opcode_cumulate + stack.pop_back(); + result += lhs*subexponent; + continue; + } + break; + } + return result; + } + + template<typename Value_t> + Value_t ParsePowiSequence(const std::vector<unsigned>& ByteCode, + unsigned& IP, unsigned limit, + std::size_t factor_stack_base, + bool IgnoreExcess = false) + { + std::vector<Value_t> stack; + stack.push_back(Value_t(1)); + return ParsePowiMuli(iseq_powi, ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); + } + + template<typename Value_t> + Value_t ParseMuliSequence(const std::vector<unsigned>& ByteCode, + unsigned& IP, unsigned limit, + std::size_t factor_stack_base, + bool IgnoreExcess = false) + { + std::vector<Value_t> stack; + stack.push_back(Value_t(1)); + return ParsePowiMuli(iseq_muli, ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); + } + + struct IfInfo + { + std::pair<int,std::string> condition; + std::pair<int,std::string> thenbranch; + unsigned endif_location; + + IfInfo() : condition(), thenbranch(), endif_location() { } + }; +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::PrintByteCode(std::ostream& dest, + bool showExpression) const +{ + dest << "Size of stack: " << mData->mStackSize << "\n"; + + std::ostringstream outputBuffer; + std::ostream& output = (showExpression ? outputBuffer : dest); + + const std::vector<unsigned>& ByteCode = mData->mByteCode; + const std::vector<Value_t>& Immed = mData->mImmed; + + std::vector<std::pair<int,std::string> > stack; + std::vector<IfInfo> if_stack; + + for(unsigned IP = 0, DP = 0; IP <= ByteCode.size(); ++IP) + { + after_powi_or_muli:; + std::string n; + bool out_params = false; + unsigned params = 2, produces = 1, opcode = 0; + + if(showExpression && !if_stack.empty() && + ( // Normal If termination rule: + if_stack.back().endif_location == IP + // This rule matches when cJumps are threaded: + || (IP < ByteCode.size() && ByteCode[IP] == cJump + && !if_stack.back().thenbranch.second.empty()) + )) + { + printHex(output, IP); + if(if_stack.back().endif_location == IP) + output << ": ----- (phi)"; + else + output << ": ----- (phi+)"; + + stack.resize(stack.size()+2); + std::swap(stack[stack.size()-3], stack[stack.size()-1]); + std::swap(if_stack.back().condition, stack[stack.size()-3]); + std::swap(if_stack.back().thenbranch, stack[stack.size()-2]); + opcode = cIf; + params = 3; + --IP; + if_stack.pop_back(); + } + else + { + if(IP >= ByteCode.size()) break; + opcode = ByteCode[IP]; + + if(showExpression && ( + opcode == cSqr || opcode == cDup + || opcode == cInv + || opcode == cSqrt || opcode == cRSqrt + || opcode == cFetch + )) + { + unsigned changed_ip = IP; + Value_t exponent = + ParsePowiSequence<Value_t> + (ByteCode, changed_ip, + if_stack.empty() + ? (unsigned)ByteCode.size() + : if_stack.back().endif_location, + stack.size()-1); + std::string operation_prefix; + std::ostringstream operation_value; + int prio = 0; + if(exponent == Value_t(1.0)) + { + if(opcode != cDup) goto not_powi_or_muli; + Value_t factor = + ParseMuliSequence<Value_t> + (ByteCode, changed_ip, + if_stack.empty() + ? (unsigned)ByteCode.size() + : if_stack.back().endif_location, + stack.size()-1); + if(factor == Value_t(1) || factor == Value_t(-1)) + goto not_powi_or_muli; + operation_prefix = "*"; + operation_value << factor; + prio = 3; + } + else + { + prio = 2; + operation_prefix = "^"; + operation_value << exponent; + } + + //unsigned explanation_before = changed_ip-2; + unsigned explanation_before = changed_ip-1; + + const char* explanation_prefix = "_"; + for(const unsigned first_ip = IP; IP < changed_ip; ++IP) + { + printHex(output, IP); + output << ": "; + + const char* sep = "|"; + if(first_ip+1 == changed_ip) + { sep = "="; explanation_prefix = " "; } + else if(IP == first_ip) sep = "\\"; + else if(IP+1 == changed_ip) sep = "/"; + else explanation_prefix = "="; + + switch(ByteCode[IP]) + { + case cInv: output << "inv"; break; + case cNeg: output << "neg"; break; + case cDup: output << "dup"; break; + case cSqr: output << "sqr"; break; + case cMul: output << "mul"; break; + case cAdd: output << "add"; break; + case cCbrt: output << "cbrt"; break; + case cSqrt: output << "sqrt"; break; + case cRSqrt: output << "rsqrt"; break; + case cFetch: + { + unsigned index = ByteCode[++IP]; + output << "cFetch(" << index << ")"; + break; + } + default: break; + } + padLine(outputBuffer, 20); + output << sep; + if(IP >= explanation_before) + { + explanation_before = (unsigned)ByteCode.size(); + output << explanation_prefix + << '[' << (stack.size()-1) << ']'; + std::string last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + output << last; + output << operation_prefix; + output << operation_value.str(); + } + else + { + unsigned p = first_ip; + Value_t exp = operation_prefix=="^" ? + ParsePowiSequence<Value_t> + (ByteCode, p, IP+1, stack.size()-1, true) : + ParseMuliSequence<Value_t> + (ByteCode, p, IP+1, stack.size()-1, true); + std::string last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + output << " ..." << last; + output << operation_prefix; + output << exp; + } + dest << outputBuffer.str() << std::endl; + outputBuffer.str(""); + } + + std::string& last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + last += operation_prefix; + last += operation_value.str(); + stack.back().first = prio; + + goto after_powi_or_muli; + } + not_powi_or_muli:; + printHex(output, IP); + output << ": "; + + switch(opcode) + { + case cIf: + { + unsigned label = ByteCode[IP+1]+1; + output << "jz "; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); + break; + } + case cAbsIf: + { + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; + output << "jz_abs " << dp << ","; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); + break; + } + + case cJump: + { + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; + + if(!if_stack.empty() && !stack.empty()) + { + std::swap(if_stack.back().thenbranch, stack.back()); + if_stack.back().endif_location = label; + stack.pop_back(); + } + + output << "jump " << dp << ","; + printHex(output, label); + params = 0; + produces = 0; + IP += 2; + break; + } + case cImmed: + { + if(showExpression) + { + std::ostringstream buf; + buf.precision(8); + buf << Immed[DP]; + stack.push_back( std::make_pair(0, buf.str()) ); + } + output.precision(8); + output << "push " << Immed[DP]; + ++DP; + produces = 0; + break; + } + + case cFCall: + { + const unsigned index = ByteCode[++IP]; + params = mData->mFuncPtrs[index].mParams; + static std::string name; + name = "f:" + findName(mData->mNamePtrs, index, + NameData<Value_t>::FUNC_PTR); + n = name.c_str(); + out_params = true; + break; + } + + case cPCall: + { + const unsigned index = ByteCode[++IP]; + params = mData->mFuncParsers[index].mParams; + static std::string name; + name = "p:" + findName(mData->mNamePtrs, index, + NameData<Value_t>::PARSER_PTR); + n = name.c_str(); + out_params = true; + break; + } + + default: + if(IsVarOpcode(opcode)) + { + if(showExpression) + { + stack.push_back(std::make_pair(0, + (findName(mData->mNamePtrs, opcode, + NameData<Value_t>::VARIABLE)))); + } + output << "push Var" << opcode-VarBegin; + produces = 0; + } + else + { + switch(OPCODE(opcode)) + { + case cNeg: n = "neg"; params = 1; break; + case cAdd: n = "add"; break; + case cSub: n = "sub"; break; + case cMul: n = "mul"; break; + case cDiv: n = "div"; break; + case cMod: n = "mod"; break; + case cPow: n = "pow"; break; + case cEqual: n = "eq"; break; + case cNEqual: n = "neq"; break; + case cLess: n = "lt"; break; + case cLessOrEq: n = "le"; break; + case cGreater: n = "gt"; break; + case cGreaterOrEq: n = "ge"; break; + case cAnd: n = "and"; break; + case cOr: n = "or"; break; + case cNot: n = "not"; params = 1; break; + case cNotNot: n = "notnot"; params = 1; break; + case cDeg: n = "deg"; params = 1; break; + case cRad: n = "rad"; params = 1; break; + + case cFetch: + { + unsigned index = ByteCode[++IP]; + if(showExpression && index < stack.size()) + stack.push_back(stack[index]); + output << "cFetch(" << index << ")"; + produces = 0; + break; + } + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by: n = "log2by"; params = 2; out_params = 1; break; + case cPopNMov: + { + std::size_t a = ByteCode[++IP]; + std::size_t b = ByteCode[++IP]; + if(showExpression && b < stack.size()) + { + std::pair<int, std::string> stacktop(0, "?"); + if(b < stack.size()) stacktop = stack[b]; + stack.resize(a); + stack.push_back(stacktop); + } + output << "cPopNMov(" << a << ", " << b << ")"; + produces = 0; + break; + } + case cNop: + output << "nop"; params = 0; produces = 0; + break; + #endif + case cSinCos: + { + if(showExpression) + { + std::pair<int, std::string> sin = stack.back(); + std::pair<int, std::string> cos( + 0, "cos(" + sin.second + ")"); + sin.first = 0; + sin.second = "sin(" + sin.second + ")"; + stack.back() = sin; + stack.push_back(cos); + } + output << "sincos"; + produces = 0; + break; + } + case cSinhCosh: + { + if(showExpression) + { + std::pair<int, std::string> sinh = stack.back(); + std::pair<int, std::string> cosh( + 0, "cosh(" + sinh.second + ")"); + sinh.first = 0; + sinh.second = "sinh(" + sinh.second + ")"; + stack.back() = sinh; + stack.push_back(cosh); + } + output << "sinhcosh"; + produces = 0; + break; + } + case cAbsAnd: n = "abs_and"; break; + case cAbsOr: n = "abs_or"; break; + case cAbsNot: n = "abs_not"; params = 1; break; + case cAbsNotNot: n = "abs_notnot"; params = 1; break; + case cDup: + { + if(showExpression) + stack.push_back(stack.back()); + output << "dup"; + produces = 0; + break; + } + case cInv: n = "inv"; params = 1; break; + case cSqr: n = "sqr"; params = 1; break; + case cRDiv: n = "rdiv"; break; + case cRSub: n = "rsub"; break; + case cRSqrt: n = "rsqrt"; params = 1; break; + + default: + n = Functions[opcode-cAbs].name; + params = Functions[opcode-cAbs].params; + out_params = params != 1; + } + } + } + } + if(produces) output << n; + if(out_params) output << " (" << params << ")"; + if(showExpression) + { + padLine(outputBuffer, 20); + + if(produces > 0) + { + std::ostringstream buf; + const char *paramsep = ",", *suff = ""; + int prio = 0; bool commutative = false; + switch(opcode) + { + case cIf: buf << "if("; suff = ")"; + break; + case cAbsIf: buf << "if("; suff = ")"; + break; + case cOr: prio = 6; paramsep = "|"; commutative = true; + break; + case cAnd: prio = 5; paramsep = "&"; commutative = true; + break; + case cAdd: prio = 4; paramsep = "+"; commutative = true; + break; + case cSub: prio = 4; paramsep = "-"; + break; + case cMul: prio = 3; paramsep = "*"; commutative = true; + break; + case cDiv: prio = 3; paramsep = "/"; + break; + case cPow: prio = 2; paramsep = "^"; + break; + case cAbsOr: prio = 6; paramsep = "|"; commutative = true; + break; + case cAbsAnd: prio = 5; paramsep = "&"; commutative = true; + break; + case cSqr: prio = 2; suff = "^2"; + break; + case cNeg: buf << "(-("; suff = "))"; + break; + case cNot: buf << "(!("; suff = "))"; + break; + default: buf << n << '('; suff = ")"; + } + + const char* sep = ""; + for(unsigned a=0; a<params; ++a) + { + buf << sep; + if(stack.size() + a < params) + buf << "?"; + else + { + const std::pair<int,std::string>& prev = + stack[stack.size() - params + a]; + if(prio > 0 && (prev.first > prio || + (prev.first==prio && !commutative))) + buf << '(' << prev.second << ')'; + else + buf << prev.second; + } + sep = paramsep; + } + if(stack.size() >= params) + stack.resize(stack.size() - params); + else + stack.clear(); + buf << suff; + stack.push_back(std::make_pair(prio, buf.str())); + //if(n.size() <= 4 && !out_params) padLine(outputBuffer, 20); + } + //padLine(outputBuffer, 20); + output << "= "; + if(((opcode == cIf || opcode == cAbsIf) && params != 3) + || opcode == cJump + #ifdef FP_SUPPORT_OPTIMIZER + || opcode == cNop + #endif + ) + output << "(void)"; + else if(stack.empty()) + output << "[?] ?"; + else + output << '[' << (stack.size()-1) << ']' + << stack.back().second; + } + + if(showExpression) + { + dest << outputBuffer.str() << std::endl; + outputBuffer.str(""); + } + else + output << std::endl; + } + dest << std::flush; +} +#endif + + +#ifndef FP_SUPPORT_OPTIMIZER +template<typename Value_t> +void FunctionParserBase<Value_t>::Optimize() +{ + // Do nothing if no optimizations are supported. +} +#endif + + +#define FUNCTIONPARSER_INSTANTIATE_CLASS(type) \ + template class FunctionParserBase< type >; + +#ifndef FP_DISABLE_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(double) +#endif + +#ifdef FP_SUPPORT_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(float) +#endif + +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(long double) +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(long) +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(MpfrFloat) +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(GmpInt) +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<double>) +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<float>) +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<long double>) +#endif diff --git a/fparser/fparser.hh b/fparser/fparser.hh new file mode 100644 index 0000000..282e9b5 --- /dev/null +++ b/fparser/fparser.hh @@ -0,0 +1,223 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_H_ +#define ONCE_FPARSER_H_ + +#include <string> +#include <vector> + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +#include <iostream> +#endif + +#ifdef _MSC_VER +// Visual Studio's warning about missing definitions for the explicit +// FunctionParserBase instantiations is irrelevant here. +#pragma warning(disable : 4661) +#endif + +namespace FPoptimizer_CodeTree { template<typename Value_t> class CodeTree; } + +template<typename Value_t> +class FunctionParserBase +{ + public: + enum ParseErrorType + { + SYNTAX_ERROR=0, MISM_PARENTH, MISSING_PARENTH, EMPTY_PARENTH, + EXPECT_OPERATOR, OUT_OF_MEMORY, UNEXPECTED_ERROR, INVALID_VARS, + ILL_PARAMS_AMOUNT, PREMATURE_EOS, EXPECT_PARENTH_FUNC, + UNKNOWN_IDENTIFIER, + NO_FUNCTION_PARSED_YET, + FP_NO_ERROR + }; + + typedef Value_t value_type; + + + int Parse(const char* Function, const std::string& Vars, + bool useDegrees = false); + int Parse(const std::string& Function, const std::string& Vars, + bool useDegrees = false); + + void setDelimiterChar(char); + + static Value_t epsilon(); + static void setEpsilon(Value_t); + + const char* ErrorMsg() const; + ParseErrorType GetParseErrorType() const; + + Value_t Eval(const Value_t* Vars); + int EvalError() const; + + bool AddConstant(const std::string& name, Value_t value); + bool AddUnit(const std::string& name, Value_t value); + + typedef Value_t (*FunctionPtr)(const Value_t*); + + bool AddFunction(const std::string& name, + FunctionPtr, unsigned paramsAmount); + bool AddFunction(const std::string& name, FunctionParserBase&); + + class FunctionWrapper; + + template<typename DerivedWrapper> + bool AddFunctionWrapper(const std::string& name, const DerivedWrapper&, + unsigned paramsAmount); + + FunctionWrapper* GetFunctionWrapper(const std::string& name); + + bool RemoveIdentifier(const std::string& name); + + void Optimize(); + + + int ParseAndDeduceVariables(const std::string& function, + int* amountOfVariablesFound = 0, + bool useDegrees = false); + int ParseAndDeduceVariables(const std::string& function, + std::string& resultVarString, + int* amountOfVariablesFound = 0, + bool useDegrees = false); + int ParseAndDeduceVariables(const std::string& function, + std::vector<std::string>& resultVars, + bool useDegrees = false); + + + FunctionParserBase(); + ~FunctionParserBase(); + + // Copy constructor and assignment operator (implemented using the + // copy-on-write technique for efficiency): + FunctionParserBase(const FunctionParserBase&); + FunctionParserBase& operator=(const FunctionParserBase&); + + + void ForceDeepCopy(); + + + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + // For debugging purposes only. + // Performs no sanity checks or anything. If the values are wrong, the + // library will crash. Do not use unless you know what you are doing. + void InjectRawByteCode(const unsigned* bytecode, unsigned bytecodeAmount, + const Value_t* immed, unsigned immedAmount, + unsigned stackSize); + + void PrintByteCode(std::ostream& dest, bool showExpression = true) const; +#endif + + + +//======================================================================== + protected: +//======================================================================== + // A derived class can implement its own evaluation logic by using + // the parser data (found in fptypes.hh). + struct Data; + Data* getParserData(); + + +//======================================================================== + private: +//======================================================================== + + friend class FPoptimizer_CodeTree::CodeTree<Value_t>; + +// Private data: +// ------------ + Data* mData; + unsigned mStackPtr; + + +// Private methods: +// --------------- + void CopyOnWrite(); + bool CheckRecursiveLinking(const FunctionParserBase*) const; + bool NameExists(const char*, unsigned); + bool ParseVariables(const std::string&); + int ParseFunction(const char*, bool); + const char* SetErrorType(ParseErrorType, const char*); + + void AddFunctionOpcode(unsigned); + void AddImmedOpcode(Value_t v); + void incStackPtr(); + void CompilePowi(long); + bool TryCompilePowi(Value_t); + + const char* CompileIf(const char*); + const char* CompileFunctionParams(const char*, unsigned); + const char* CompileElement(const char*); + const char* CompilePossibleUnit(const char*); + const char* CompilePow(const char*); + const char* CompileUnaryMinus(const char*); + const char* CompileMult(const char*); + const char* CompileAddition(const char*); + const char* CompileComparison(const char*); + const char* CompileAnd(const char*); + const char* CompileExpression(const char*); + inline const char* CompileFunction(const char*, unsigned); + inline const char* CompileParenthesis(const char*); + inline const char* CompileLiteral(const char*); + template<bool SetFlag> + inline void PushOpcodeParam(unsigned); + template<bool SetFlag> + inline void PutOpcodeParamAt(unsigned, unsigned offset); + const char* Compile(const char*); + + bool addFunctionWrapperPtr(const std::string&, FunctionWrapper*, unsigned); + static void incFuncWrapperRefCount(FunctionWrapper*); + static unsigned decFuncWrapperRefCount(FunctionWrapper*); + +protected: + // Parsing utility functions + static std::pair<const char*, Value_t> ParseLiteral(const char*); + static unsigned ParseIdentifier(const char*); +}; + +class FunctionParser: public FunctionParserBase<double> {}; +class FunctionParser_f: public FunctionParserBase<float> {}; +class FunctionParser_ld: public FunctionParserBase<long double> {}; +class FunctionParser_li: public FunctionParserBase<long> {}; + +#include <complex> +class FunctionParser_cd: public FunctionParserBase<std::complex<double> > {}; +class FunctionParser_cf: public FunctionParserBase<std::complex<float> > {}; +class FunctionParser_cld: public FunctionParserBase<std::complex<long double> > {}; + + + +template<typename Value_t> +class FunctionParserBase<Value_t>::FunctionWrapper +{ + unsigned mReferenceCount; + friend class FunctionParserBase<Value_t>; + + public: + FunctionWrapper(): mReferenceCount(1) {} + FunctionWrapper(const FunctionWrapper&): mReferenceCount(1) {} + virtual ~FunctionWrapper() {} + FunctionWrapper& operator=(const FunctionWrapper&) { return *this; } + + virtual Value_t callFunction(const Value_t*) = 0; +}; + +template<typename Value_t> +template<typename DerivedWrapper> +bool FunctionParserBase<Value_t>::AddFunctionWrapper +(const std::string& name, const DerivedWrapper& wrapper, unsigned paramsAmount) +{ + return addFunctionWrapperPtr + (name, new DerivedWrapper(wrapper), paramsAmount); +} +#endif diff --git a/fparser/fparser.pro b/fparser/fparser.pro new file mode 100644 index 0000000..3b2e7b7 --- /dev/null +++ b/fparser/fparser.pro @@ -0,0 +1,35 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Tue Mar 10 07:42:54 2009 +###################################################################### + +CONFIG -= qt +TEMPLATE = lib +TARGET = +DEPENDPATH += . +INCLUDEPATH += . +VERSION = 4.5.1 + +# Input +HEADERS += fparser.hh fpconfig.hh fptypes.hh +SOURCES += fparser.cc fpoptimizer.cc + +# +# INSTALL +# +isEmpty(PREFIX) { + PREFIX = /usr/local +} +install.target = install +install.commands = mkdir -p \"$$PREFIX/lib$$LIB_SUFFIX\" +install.commands += && mkdir -p \"$$PREFIX/include\" +unix:!macx { + install.commands += && cp -at \"$$PREFIX/include/\" fparser.hh + install.commands += && cp -at \"$$PREFIX/lib$$LIB_SUFFIX/\" libfparser.so* +} +win32:install.commands += && cp -at \"$$PREFIX/lib$$LIB_SUFFIX/\" release/fparser4.dll +macx { + install.commands += && cp fparser.hh \"$$PREFIX/include/\" + install.commands += && cp libfparser*.dylib \"$$PREFIX/lib$$LIB_SUFFIX/\" +} + +QMAKE_EXTRA_TARGETS += install diff --git a/fparser/fparser_gmpint.hh b/fparser/fparser_gmpint.hh new file mode 100644 index 0000000..6254a4e --- /dev/null +++ b/fparser/fparser_gmpint.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_GMPINT_H_ +#define ONCE_FPARSER_GMPINT_H_ + +#include "fparser.hh" +#include "mpfr/GmpInt.hh" + +class FunctionParser_gmpint: public FunctionParserBase<GmpInt> {}; + +#endif diff --git a/fparser/fparser_mpfr.hh b/fparser/fparser_mpfr.hh new file mode 100644 index 0000000..1eb772f --- /dev/null +++ b/fparser/fparser_mpfr.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_MPFR_H_ +#define ONCE_FPARSER_MPFR_H_ + +#include "fparser.hh" +#include "mpfr/MpfrFloat.hh" + +class FunctionParser_mpfr: public FunctionParserBase<MpfrFloat> {}; + +#endif diff --git a/fparser/fpconfig.hh b/fparser/fpconfig.hh new file mode 100644 index 0000000..1a8a55f --- /dev/null +++ b/fparser/fpconfig.hh @@ -0,0 +1,88 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// Configuration file +// ------------------ + +/* NOTE: + This file is for the internal use of the function parser only. + You don't need to include this file in your source files, just + include "fparser.hh". +*/ + + +/* Uncomment any of these lines or define them in your compiler settings + to enable the correspondent version of the parser. (These are disabled + by default because they rely on C99 functions, and non-standard libraries + in the case pf MPFR and GMP, and they make compiling needlessly slower + and the resulting binary needlessly larger if they are not used in the + program.) +*/ +//#define FP_SUPPORT_FLOAT_TYPE +//#define FP_SUPPORT_LONG_DOUBLE_TYPE +//#define FP_SUPPORT_LONG_INT_TYPE +//#define FP_SUPPORT_MPFR_FLOAT_TYPE +//#define FP_SUPPORT_GMP_INT_TYPE +//#define FP_SUPPORT_COMPLEX_DOUBLE_TYPE +//#define FP_SUPPORT_COMPLEX_FLOAT_TYPE +//#define FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + +/* If you are using FunctionParser_ld or FunctionParser_cld and your compiler + supports the strtold() function, you should uncomment the following line. + */ +//#define FP_USE_STRTOLD + + +/* Uncomment this line or define it in your compiler settings if you want + to disable compiling the basic double version of the library, in case + one of the above types is used but not the double type. (If the double + type is not used, then disabling it makes compiling faster and the + resulting binary smaller.) + */ +//#define FP_DISABLE_DOUBLE_TYPE + +/* Uncomment this line or define it in your compiler settings to make the + parser use C++11 math functions. (Note that these may not be supported + by all compilers.) +*/ +//#define FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + +/* + Whether to use shortcut evaluation for the & and | operators: +*/ +#ifndef FP_DISABLE_SHORTCUT_LOGICAL_EVALUATION +#define FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION +#endif + +/* + Comment out the following lines out if you are not going to use the + optimizer and want a slightly smaller library. The Optimize() method + can still be called, but it will not do anything. + If you are unsure, just leave it. It won't slow down the other parts of + the library. +*/ +#ifndef FP_NO_SUPPORT_OPTIMIZER +#define FP_SUPPORT_OPTIMIZER +#endif + +#if defined(FP_SUPPORT_COMPLEX_DOUBLE_TYPE) || defined(FP_SUPPORT_COMPLEX_FLOAT_TYPE) || defined(FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE) +#define FP_SUPPORT_COMPLEX_NUMBERS +#endif + + +/* + No member function of FunctionParser is thread-safe. Most prominently, + Eval() is not thread-safe. By uncommenting one of these lines the Eval() + function can be made thread-safe at the cost of a possible small overhead. + The second version requires that the compiler supports the alloca() function, + which is not standard, but is faster. + */ +//#define FP_USE_THREAD_SAFE_EVAL +//#define FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA diff --git a/fparser/fpoptimizer.cc b/fparser/fpoptimizer.cc new file mode 100644 index 0000000..4eab746 --- /dev/null +++ b/fparser/fpoptimizer.cc @@ -0,0 +1,11745 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.1 *| +|*-------------------------------------------------------------------------*| +|* Function optimizer *| +|*-------------------------------------------------------------------------*| +|* Copyright: Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +/* NOTE: + This file contains generated code (from the optimizer sources) and is + not intended to be modified by hand. If you want to modify the optimizer, + download the development version of the library. +*/ + +#include "fpconfig.hh" +#ifdef FP_SUPPORT_OPTIMIZER +#include "fparser.hh" +#include "extrasrc/fptypes.hh" +#include "extrasrc/fpaux.hh" +#define l14 {Value_t +#define l04 ),info, +#define iZ3 {data-> +#define iY3 ==cNot|| +#define iX3 "Found " +#define iW3 info.lQ[b +#define iV3 ;o<<"\n"; +#define iU3 )yR 2,cPow +#define iT3 ;}static yU1 +#define iS3 (tree)!= +#define iR3 ),Value( +#define iQ3 stackpos +#define iP3 minValue0 +#define iO3 "dup(%u) " +#define iN3 =true;iO1 +#define iM3 eR{assert +#define iL3 "%d, cost " +#define iK3 "PUSH " iL2 +#define iJ3 "immed "<< +#define iI3 mFuncParsers +#define iH3 param.data +#define iG3 stderr +#define iF3 sep2=" " +#define iE3 FPHASH_CONST +#define iD3 cache_needed[ +#define iC3 fprintf +#define iB3 "Applying " +#define iA3 FUNCTIONPARSER_INSTANTIATE_OPTIMIZE +#define i93 FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE +#define i83 HANDLE_UNARY_CONST_FUNC +#define i73 {if(n11 +#define i63 second; +#define i53 within, +#define i43 AddFrom( +#define i33 tH3== +#define i23 c_count +#define i13 MaxOp +#define i03 else nM +#define tZ3 =tZ cL3 +#define tY3 .nJ 0)); +#define tX3 .nJ 1)); +#define tW3 lD m. +#define tV3 ;a<tree.xB +#define tU3 iZ);}if +#define tT3 cS ifp2 +#define tS3 sim.xB1 +#define tR3 );tO tL1 +#define tQ3 ].swap( +#define tP3 codes[b +#define tO3 whydump +#define tN3 for lS1 +#define tM3 for(;a< +#define tL3 nparams +#define tK3 281856, +#define tJ3 cTan i7 +#define tI3 l2 2,2, +#define tH3 ;if(op +#define tG3 l4 0,1, +#define tF3 0x12 nH +#define tE3 FixIncompleteHashes() +#define tD3 cSinh, +#define tC3 ,cTan nS +#define tB3 ,iX 1, +#define tA3 nS 0, +#define t93 cAbs nS +#define t83 ;case +#define t73 i1 t83 +#define t63 Params[ +#define t53 Params( +#define t43 &&p nL3 +#define t33 fp_pow( +#define t23 false;} +#define t13 lD1 y4. +#define t03 cAbsIf) +#define eZ3 l91++b) +#define eY3 lX1 nC== +#define eX3 ;exponent +#define eW3 =false; +#define eV3 tN cS1); +#define eU3 .empty() +#define eT3 nS3))n92 +#define eS3 (opcode== +#define eR3 <data eJ3;++ +#define eQ3 l14 nS3( +#define eP3 ByteCodeSynth xF +#define eO3 std xM3< +#define eN3 middle2 +#define eM3 std::string +#define eL3 SetOpcode( +#define eK3 ;for iZ1 +#define eJ3 .size() +#define eI3 ].second +#define eH3 ].first +#define eG3 return p +#define eF3 TreeCountItem +#define eE3 }return +#define eD3 Ne_Mask +#define eC3 Gt_Mask +#define eB3 Lt_Mask +#define eA3 const eK +#define e93 .n7 synth. +#define e83 range nE3 +#define e73 eK3 a= +#define e63 ,eQ,c92 +#define e53 eO|lT1) +#define e43 public: +#define e33 Rehash( +#define e23 switch( +#define e13 pclone +#define e03 cOr,l6 +#define cZ3 newpow +#define cY3 change +#define cX3 (Value_t +#define cW3 (count +#define cV3 133,2, +#define cU3 ,tree +#define cT3 byteCode +#define cS3 child) +#define cR3 (p1 x41) +#define cQ3 cLog2by +#define cP3 long iD1 +#define cO3 factor_t +#define cN3 (p0 yI&& +#define cM3 value1 +#define cL3 a));if(! +#define cK3 fp_mod( +#define cJ3 else{if( +#define cI3 )min.set( +#define cH3 xF());nD +#define cG3 max.known +#define cF3 known&& +#define cE3 tX p2;p2 +#define cD3 {tree.x4 +#define cC3 cAbsNot +#define cB3 ,x53 l8 +#define cA3 e23 lY1 +#define c93 xW 0)nC +#define c83 IsLogicalValue(xW +#define c73 }switch +#define c63 stackptr +#define c53 cLog);xG +#define c43 l8 0)); +#define c33 opcodes +#define c23 did_muli +#define c13 &Value){ +#define c03 yD const +#define yZ3 (param. +#define yY3 ){e23 +#define yX3 :if(&*lE1){ +#define yW3 :{n31 r= +#define yV3 xY3 e23 +#define yU3 param=*( +#define yT3 cAbsIf, +#define yS3 cNotNot, +#define yR3 l4 16,1, +#define yQ3 yO3 info +#define yP3 lE1=r.specs;if(r.found){ +#define yO3 *x8)[a]. +#define yN3 cLess,cH +#define yM3 default_function_handling +#define yL3 l4 20,1, +#define yK3 l4 4,1, +#define yJ3 450998, +#define yI3 cExp2 nS +#define yH3 lJ 2},0, +#define yG3 )lS 3*3*2*2 +#define yF3 default: +#define yE3 range<nV +#define yD3 range xF +#define yC3 Ge0Lt1 +#define yB3 Gt0Le1 +#define yA3 cAdd lV2 +#define y93 if(op1== +#define y83 iterator +#define y73 begin(); +#define y63 TreeSet +#define y53 parent +#define y43 insert(i +#define y33 newrel +#define y23 y03 xX3 xO2 +#define y13 y03 iF2;if( +#define y03 ))return +#define xZ3 ;if(half +#define xY3 break;} +#define xX3 IsNever +#define xW3 e62 eO1 +#define xV3 synth.xH +#define xU3 b_needed +#define xT3 cachepos +#define xS3 ,lE1,info +#define xR3 half= +#define xQ3 131,4,1, +#define xP3 131,8,1, +#define xO3 ,iM,1,lC1+1); +#define xN3 4,1,2,1, +#define xM3 ::vector +#define xL3 1 y5 n41 +#define xK3 FindPos( +#define xJ3 src_pos +#define xI3 xM1 xQ+ +#define xH3 reserve( +#define xG3 treeptr +#define xF3 .resize( +#define xE3 tO1 void +#define xD3 ImmedTag +#define xC3 a,const +#define xB3 RefCount +#define xA3 Birth(); +#define x93 typename +#define x83 unsigned +#define x73 template +#define x63 7168, +#define x53 leaf1 +#define x43 cost_t +#define x33 fpdata +#define x23 middle +#define x13 sqrt_cost +#define x03 const int +#define nZ3 mul_count +#define nY3 );nZ l5:: +#define nX3 e62 2))); +#define nW3 maxValue1 +#define nV3 minValue1 +#define nU3 maxValue0 +#define nT3 ValueType +#define nS3 result +#define nR3 nS3;}case +#define nQ3 nS3.tL +#define nP3 ::res,b8< +#define nO3 eG3 yM +#define nN3 .what nS1 +#define nM3 e62 1),e62 1)); +#define nL3 .max.val +#define nK3 nS3 yM2 +#define nJ3 nS3 e61 +#define nI3 nS3 yI +#define nH3 nS3 nL3 +#define nG3 nS3 tG1 +#define nF3 nS3 yM +#define nE3 xF nS3 +#define nD3 tO n3 0), +#define nC3 i8);nD lC +#define nB3 abs_mul +#define nA3 xM3<x83>&e71 +#define n93 l8 a)); +#define n83 pos_set +#define n73 goto e1 +#define n63 p1.lT2 p1 +#define n53 [funcno]. +#define n43 eN1[++IP] +#define n33 sim.x2 1, +#define n23 {sim.Eat( +#define n13 eN1[IP]== +#define n03 subtree +#define lZ3 invtree +#define lY3 MakeHash( +#define lX3 parampair +#define lW3 rulenumit +#define lV3 cAnd l3 +#define lU3 ,cMul l3 +#define lT3 cAnd,l6 +#define lS3 x9 lT 2, +#define lR3 },{{1, +#define lQ3 cEqual, +#define lP3 lQ3 lA +#define lO3 t01},{{3, +#define lN3 MakeEqual +#define lM3 nC1,l5:: +#define lL3 nC1,{l5:: +#define lK3 newbase +#define lJ3 fp_equal( +#define lI3 branch1op +#define lH3 branch2op +#define lG3 if(lJ3 +#define lF3 l8 a)xI +#define lE3 overlap +#define lD3 truth_b +#define lC3 truth_a +#define lB3 found_dup +#define lA3 nQ r;r iH +#define l93 void set( +#define l83 {tP1 lE +#define l73 rangeutil +#define l63 Plan_Has( +#define l53 StackMax) +#define l43 i1 true;} +#define l33 namespace +#define l23 (cond yX +#define l13 inverted +#define l03 xX3: +#define iZ2 iftree +#define iY2 depcodes +#define iX2 explicit +#define iW2 cCosh nS +#define iV2 t01 nH +#define iU2 VarBegin +#define iT2 t63 a] +#define iS2 iR2 size() +#define iR2 Params. +#define iQ2 ].data); +#define iP2 i8)));nZ +#define iO2 yQ1.SubTrees +#define iN2 yQ1.Others +#define iM2 );synth +#define iL2 ;DumpTree( +#define iK2 ;Value_t +#define iJ2 begin(), +#define iI2 cond_add +#define iH2 cond_mul +#define iG2 cond_and +#define iF2 IsAlways +#define iE2 func lQ1 +#define iD2 bool eM1 +#define iC2 Forget() +#define iB2 .second); +#define iA2 Optimize() +#define i92 costree +#define i82 sintree +#define i72 leaf_count +#define i62 &&cond eD) +#define i52 .tT1 n] +#define i42 =GetParam( +#define i32 sub_params +#define i22 nC==cLog2&& +#define i12 nC==cPow&& +#define i02 printf( +#define tZ2 cbrt_count +#define tY2 sqrt_count +#define tX2 cPow i7 +#define tW2 ,cPow, +#define tV2 ,cGreater +#define tU2 exponent); +#define tT2 Finite +#define tS2 min.n3 0), +#define tR2 p1 cS ifp1 +#define tQ2 yR 2,cAdd) +#define tP2 pcall_tree +#define tO2 after_powi +#define tN2 GetHash(). +#define tM2 yP t23 +#define tL2 params) +#define tK2 grammar +#define tJ2 cEqual t11 +#define tI2 cLog nS +#define tH2 cNeg,lT 1, +#define tG2 ),0},{ +#define tF2 std::move( +#define tE2 iH cond nC +#define tD2 tree iH +#define tC2 ){eL3 +#define tB2 tree))cJ +#define tA2 );t0=!t0;} +#define t92 tmp c91 tree +#define t82 nQ tmp;tmp iH +#define t72 tree nC +#define t62 MakeNEqual +#define t52 )?0:1))l7 +#define t42 isInteger( +#define t32 Comparison +#define t22 needs_flip +#define t12 (half&63)-1; +#define t02 value] +#define eZ2 lT1 opcode +#define eY2 )lS 3*3*3*2 +#define eX2 cS tree); +#define eW2 mul_item +#define eV2 innersub +#define eU2 cbrt_cost +#define eT2 best_cost +#define eS2 condition +#define eR2 nominator +#define eQ2 per_item +#define eP2 item_type +#define eO2 first2 +#define eN2 l4 18,1, +#define eM2 cIf,iX 3, +#define eL2 lJ 1},0, +#define eK2 tJ 1},0, +#define eJ2 Decision +#define eI2 not_tree +#define eH2 (mulgroup +#define eG2 (lR));nD lC +#define eF2 Become(xW +#define eE2 group_by +#define eD2 exponent= +#define eC2 ->second +#define eB2 targetpos +#define eA2 ParamSpec +#define e92 rhs.hash2;} +#define e82 rhs.hash1 +#define e72 struct +#define e62 Value_t( +#define e52 .n_int_sqrt +#define e42 const std::eP +#define e32 const char* +#define e22 nT 409641, +#define e12 ,xF1);lC +#define e02 );xY3 +#define cZ2 if(t72== +#define cY2 eO3 bool> +#define cX2 ,(long double) +#define cW2 ContainsOtherCandidates +#define cV2 std::cout +#define cU2 source_tree +#define cT2 GetParam eS +#define cS2 <tP,x43> +#define cR2 p1_evenness +#define cQ2 isNegative( +#define cP2 neg_set +#define cO2 }else{x8=new +#define cN2 );}void +#define cM2 cNop,cNop}} +#define cL2 cTanh,cNop, +#define cK2 NewHash +#define cJ2 >e72 cB< +#define cI2 matches +#define cH2 {cV2<< +#define cG2 iS1 void*)& +#define cF2 cGreater,cH +#define cE2 cSin i7 +#define cD2 cCos nS +#define cC2 ,t21 0x1 nH +#define cB2 +=1 i1 n91; +#define cA2 negated +#define c92 synth); +#define c82 Specializer +#define c72 ifdata.ofs +#define c62 (IfData&ifdata +#define c52 .push_back( +#define c42 ;}data;data. +#define c32 );sim.x2 2, +#define c22 nP)l14 tmp= +#define c12 (*x8)[0].info +#define c02 CodeTree +#define yZ2 c02 xF +#define yY2 coshtree +#define yX2 sinhtree +#define yW2 best_score +#define yV2 mulvalue +#define yU2 pow_item +#define yT2 subgroup +#define yS2 PowiResult +#define yR2 .match_tree +#define yQ2 )l43 +#define yP2 0));yD3 +#define yO2 maxValue +#define yN2 minValue +#define yM2 yI eW3 if( +#define yL2 fp_min(yL, +#define yK2 div_tree +#define yJ2 pow_tree +#define yI2 preserve +#define yH2 ,cCos i7 +#define yG2 (rule cU3,info +#define yF2 e62 0.5) +#define yE2 PullResult() +#define yD2 dup_or_fetch +#define yC2 e33 false +#define yB2 test_order +#define yA2 lX3, +#define y92 .param_count +#define y82 shift(index) +#define y72 rulenumber +#define y62 cTanh nS +#define y52 cSinh nS +#define y42 cInv,lT 1, +#define y32 constraints= +#define y22 factor_immed +#define y12 changes +#define y02 n81 cS y4 l8 +#define xZ2 cS leaf2 l8 +#define xY2 cS x53 l8 +#define xX2 cS cond l8 +#define xW2 exp_diff +#define xV2 ExponentInfo +#define xU2 lower_bound( +#define xT2 factor +#define xS2 is_logical +#define xR2 newrel_and +#define xQ2 tH[c eE +#define xP2 ;iM.Remember( +#define xO2 i1 Unknown;} +#define xN2 res_stackpos +#define xM2 half_pos +#define xL2 >>1)):( +#define xK2 CodeTreeData +#define xJ2 multiply( +#define xI2 tO known) +#define xH2 var_trees +#define xG2 erase(cs_it); +#define xF2 parent_opcode +#define xE2 log2_exponent +#define xD2 yB swap(tmp); +#define xC2 Value(Value:: +#define xB2 dup_fetch_pos +#define xA2 a;if(eK1){x8= +#define x92 {cZ start_at; +#define x82 xX3 cQ lC +#define x72 cSin nS +#define x62 Value_EvenInt +#define x52 )){data xC +#define x42 MakeFalse,{l5 +#define x32 if(list.first +#define x22 AddCollection +#define x12 ConditionType +#define x02 DUP_ONE(apos) +#define nZ2 SpecialOpcode +#define nY2 =i eC2. +#define nX2 IsDefined() +#define nW2 fp_max(yL); +#define nV2 (tree,cV2 +#define nU2 e62-1) +#define nT2 assimilated +#define nS2 denominator +#define nR2 fraction +#define nQ2 l2 18,2, +#define nP2 .GetDepth() +#define nO2 iH t72) +#define nN2 xI leaf2 l8 +#define nM2 DUP_BOTH(); +#define nL2 x73 lL +#define nK2 -1-offset]. +#define nJ2 tree.GetHash() +#define nI2 TreeCounts +#define nH2 ,e62 1))){ +#define nG2 bool t0 eW3 +#define nF2 found_log2 +#define nE2 div_params +#define nD2 immed_sum +#define nC2 :sim.Eat(1, +#define nB2 OPCODE(opcode) +#define nA2 ;sim.Push( +#define n92 break;nS3*= +#define n82 FactorStack xF +#define n72 iF2 cQ lC +#define n62 cLessOrEq, +#define n52 282870 nT +#define n42 cNotNot nS +#define n32 cNot nS +#define n22 replacing_slot +#define n12 RefParams +#define n02 if_always[ +#define lZ2 WhatDoWhenCase +#define lY2 exponent_immed +#define lX2 new_base_immed +#define lW2 base_immed +#define lV2 ||op1== +#define lU2 remaining +#define lT2 Rehash t8 +#define lS2 data[a eI3 +#define lR2 lT2 r);} +#define lQ2 if(newrel_or== +#define lP2 .UseGetNeeded( +#define lO2 e7 2,131, +#define lN2 Immed eJ3); +#define lM2 OptimizedUsing +#define lL2 Var_or_Funcno +#define lK2 lL2; +#define lJ2 GetParams( +#define lI2 crc32_t +#define lH2 signed_chain +#define lG2 MinusInf +#define lF2 synth.Find( +#define lE2 );cV2<< +#define lD2 return true; +#define lC2 n_immeds +#define lB2 stack eJ3 +#define lA2 FindClone(xM +#define l92 GetOpcode()) +#define l82 needs_rehash +#define l72 AnyWhere_Rec +#define l62 minimum_need +#define l52 ~x83(0) +#define l42 41,42,43,44, +#define l32 p1_logical_b +#define l22 p0_logical_b +#define l12 p1_logical_a +#define l02 p0_logical_a +#define iZ1 (size_t +#define iY1 )e73 +#define iX1 TopLevel) +#define iW1 .e33) +#define iV1 {pow.CopyOnWrite +#define iU1 nB OPCODE +#define iT1 const yZ2 +#define iS1 (const +#define iR1 iS1 yZ2& +#define iQ1 ,PowiCache&iM, +#define iP1 else if( +#define iO1 iP1!nS3 +#define iN1 synth.DoDup( +#define iM1 cache_needed +#define iL1 e7 2,1,e7 2, +#define iK1 [c72+ +#define iJ1 treelist +#define iI1 IsDescendantOf( +#define iH1 has_bad_balance +#define iG1 )tN mulgroup) +#define iF1 .SetParamsMove( +#define iE1 cO3 xT2 +#define iD1 double)exponent +#define iC1 {if(GetOpcode() +#define iB1 cV2<<std::y11 +#define iA1 cV2<<"POP " +#define i91 DelParam( +#define i81 set(fp_ceil);tK +#define i71 fp_abs(max.val)) +#define i61 fp_abs(min.val) +#define i51 cNEqual +#define i41 },0,0x0},{{ +#define i31 tJ 2 i41 +#define i21 Oneness_NotOne| +#define i11 Value_IsInteger +#define i01 Constness_Const +#define tZ1 DumpHashesFrom( +#define tY1 reltype +#define tX1 const Value_t&i) +#define tW1 const c02& +#define tV1 const Value_t&v +#define tU1 SequenceOpcodes +#define tT1 sep_list[ +#define tS1 ;else_tree +#define tR1 goto fail;} +#define tQ1 l1 0x4 nH +#define tP1 x73< +#define tO1 n12); +#define tN1 ){case iF2: +#define tM1 grammar_rules[*r] +#define tL1 x73 set_if< +#define tK1 x73 lX +#define tJ1 TreeCountType xF +#define tI1 GetParamCount(nX +#define tH1 >(e62 1), +#define tG1 nL3) +#define tF1 )lX3.second +#define tE1 e62 0.0)){nU +#define tD1 .IsImmed() +#define tC1 a)tD1) +#define tB1 nB2); +#define tA1 stack[lB2- +#define t91 stack c52 +#define t81 )eX3 iW1; +#define t71 synth.PushImmed( +#define t61 MaxChildDepth +#define t51 repl_param_list, +#define t41 const Rule&rule, +#define t31 std::pair<It,It> +#define t21 cPow,lA +#define t11 ,l0 2, +#define t01 ,l1 0x12 +#define eZ1 Sign_Negative +#define eY1 Value_Logical +#define eX1 yZ2&b +#define eW1 new_factor_immed +#define eV1 occurance_pos +#define eU1 exponent_hash +#define eT1 exponent_list +#define eS1 CollectionSet xF +#define eR1 CollectMulGroup( +#define eQ1 source_set +#define eP1 exponent,y63 +#define eO1 *const func)( +#define eN1 ByteCode +#define eM1 operator +#define eL1 FindAndDup(tree); +#define eK1 &*start_at +#define eJ1 <<nJ2. +#define eI1 xW 1)tD1&& +#define eH1 retry_anyparams_3 +#define eG1 retry_anyparams_2 +#define eF1 e6(),eO3 +#define eE1 needlist_cached_t +#define eD1 yH3 0x4 lR3 +#define eC1 eL2 0x4 lR3 +#define eB1 ),lM2( +#define eA1 CodeTreeImmed xF( +#define e91 GetParamCount()== +#define e81 .back().thenbranch +#define e71 eN1,size_t&IP,size_t limit,size_t y2 +#define e61 .cG3 +#define e51 (lR,xW i8));nD +#define e41 ;flipped=!flipped;} +#define e31 ,l1 0x0},{{3, +#define e21 }xY3 case +#define e11 for iZ1 b=0;b< +#define e01 by_float_exponent +#define cZ1 lJ3 exponent +#define cY1 new_exp +#define cX1 end()&&i->first== +#define cW1 return BecomeZero; +#define cV1 =comp.AddItem(atree +#define cU1 return BecomeOne; +#define cT1 if(lQ eJ3<=n1) +#define cS1 addgroup +#define cR1 found_log2by +#define cQ1 nC==cC3) +#define cP1 ParsePowiMuli( +#define cO1 lL2) +#define cN1 eL 529654 nT +#define cM1 branch1_backup +#define cL1 branch2_backup +#define cK1 exponent_map +#define cJ1 plain_set +#define cI1 rangehalf +#define cH1 LightWeight( +#define cG1 xV3 1 +#define cF1 divgroup +#define cE1 ,iM e63 +#define cD1 if(value +#define cC1 tK1 c0 +#define cB1 tK1 static +#define cA1 mulgroup. +#define c91 .AddParamMove( +#define c81 yB AddParamMove( +#define c71 ;n81 cY op1 yB DelParams +#define c61 should_regenerate=true; +#define c51 should_regenerate, +#define c41 Collection +#define c31 RelationshipResult +#define c21 Subdivide_Combine( +#define c11 long value +#define c01 )const yP +#define yZ1 rhs c01 hash1 +#define yY1 for iZ1 a xY +#define yX1 best_sep_factor +#define yW1 SynthesizeParam +#define yV1 needlist_cached +#define yU1 inline x83 +#define yT1 opcode,bool pad +#define yS1 changed=true; +#define yR1 );xM iF1 +#define yQ1 NeedList +#define yP1 tK1 bool +#define yO1 ;tK1 +#define yN1 i91 a);} +#define yM1 MakesInteger( +#define yL1 const Value_t&value +#define yK1 best_sep_cost +#define yJ1 MultiplicationRange +#define yI1 .min.set(fp_floor); +#define yH1 pihalf_limits +#define yG1 yR 2,cMul);lC +#define yF1 n_stacked +#define yE1 cK2.hash1 +#define yD1 AnyParams_Rec +#define yC1 ;synth.StackTopIs( +#define yB1 synth.AddOperation( +#define yA1 continue; +#define y91 Become(value l8 0)) +#define y81 }inline +#define y71 PositionalParams,0} +#define y61 always_sincostan +#define y51 Recheck_RefCount_Div +#define y41 Recheck_RefCount_Mul +#define y31 MultiplyAndMakeLong( +#define y21 covers_plus1 +#define y11 endl;DumpHashes( +#define y01 if(synth.FindAndDup( +#define xZ1 grammar_func +#define xY1 tree tD1 cQ +#define xX1 cOr l3 16,1, +#define xW1 252421 nT 24830, +#define xV1 l2 0,2,165888 nT +#define xU1 Modulo_Radians}, +#define xT1 yB SetParam( +#define xS1 PositionType +#define xR1 CollectionResult +#define xQ1 const_offset +#define xP1 inline TriTruthValue +#define xO1 stacktop_desired +#define xN1 iU3);lC +#define xM1 SetStackTop( +#define xL1 tK1 void +#define xK1 FPoptimizer_ByteCode +#define xJ1 1)?(poly^( +#define xI1 eP3&synth) +#define xH1 e62 0) +#define xG1 xH1) +#define xF1 cond_type +#define xE1 fphash_value_t +#define xD1 Recheck_RefCount_RDiv +#define xC1 cMul);tmp tY3 tmp. +#define xB1 SwapLastTwoInStack(); +#define xA1 SetParams(lJ2) +#define x91 fPExponentIsTooLarge( +#define x81 CollectMulGroup_Item( +#define x71 pair<Value_t,y63> +#define x61 (x53 l8 1)nN2 +#define x51 for iZ1 a=0;a<yC++a) +#define x41 .GetImmed() +#define x31 {int mStackPtr=0; +#define x21 nL xM1 xQ-1); +#define x11 covers_full_cycle +#define x01 AssembleSequence( +#define nZ1 inverse_nominator +#define nY1 252180 nT 281854, +#define nX1 <<std::dec<<")";} +#define nW1 {DataP slot_holder(y1[ +#define nV1 },{l5::MakeNotP1,l5:: +#define nU1 },{l5::MakeNotP0,l5:: +#define nT1 },{l5::MakeNotNotP1,l5:: +#define nS1 !=xJ)if(TestCase( +#define nR1 AddFunctionOpcode +#define nQ1 public e6,public eO3 +#define nP1 yZ2&tree, +#define nO1 std::pair<T1,T2>& +#define nN1 tP1 x93 +#define nM1 has_good_balance_found +#define nL1 n_occurrences +#define nK1 found_log2_on_exponent +#define nJ1 covers_minus1 +#define nI1 needs_resynth +#define nH1 immed_product +#define nG1 l33 FPoptimizer_Optimize +#define nF1 (ParamSpec_Extract xF( +#define nE1 yV3 bitmask& +#define nD1 Sign_Positive +#define nC1 ::MakeTrue +#define nB1 SetParamMove( +#define nA1 CodeTreeImmed(e62 +#define n91 Suboptimal +#define n81 changed_if +#define n71 n_as_tanh_param +#define n61 opposite= +#define n51 xE1( +#define n41 eN1 eJ3 +#define n31 MatchResultType +#define n21 yP yZ2( +#define n11 needs_sincos +#define n01 resulting_exponent +#define lZ1 Unknown:yF3;} +#define lY1 GetLogicalValue(xW +#define lX1 GetParam(a) +#define lW1 cMul l3 0,1, +#define lV1 IsImmed())l14 +#define lU1 void FunctionParserBase +#define lT1 (x83 +#define lS1 lT1 a=0;a<xT;++a) +#define lR1 o<<"("<<std::hex<<data. +#define lQ1 (val);else*this=model;} +#define lP1 IfBalanceGood( +#define lO1 n_as_tan_param +#define lN1 changed_exponent +#define lM1 inverse_denominator +#define lL1 ;cK2.hash2+= +#define lK1 retry_positionalparams_2 +#define lJ1 x83 index +#define lI1 situation_flags& +#define lH1 518 nT 400412, +#define lG1 data.subfunc_opcode +#define lF1 },{l5::MakeNotNotP0,l5:: +#define lE1 (yO3 start_at +#define lD1 CopyOnWrite(); +#define lC1 recursioncount +#define lB1 PlanNtimesCache( +#define lA1 FPoptimizer_Grammar +#define l91 GetParamCount(); +#define l81 GetPositivityInfo iS3 +#define l71 ParamSpec_SubFunctionData +#define l61 t43<e62 +#define l51 (tree.GetParamCount() +#define l41 iZ1 a=yC a-->0;) +#define l31 PositionalParams_Rec +#define l21 DumpTreeWithIndent(*this); +#define l11 e23 type){case cond_or: +#define l01 tP1 x83 Compare> +#define iZ tree.i91 a +#define iY .l91 a-->0;)if( +#define iX lA 0x4},{{ +#define iW lJ 2 i41 1, +#define iV edited_powgroup +#define iU has_unknown_max +#define iT has_unknown_min +#define iS static const yD3 +#define iR if(keep_powi +#define iQ synthed_tree +#define iP 7168 nT 401798, +#define iO SelectedParams,0 i41 +#define iN collections +#define iM cache +#define iL ,cIf,l0 3, +#define iK ,eN1,IP,limit,y2,stack); +#define iJ by_exponent +#define iI );p2.lT2 p2 yB eL3 iZ2 nC);cJ} +#define iH .eL3 +#define iG mulgroup;mulgroup iH +#define iF (p0 e61&&p0 nL3 i2 +#define iE cN3 p0 yM>=e62 0.0)) +#define iD goto ReplaceTreeWithOne t83 +#define iC !=xJ)return n02 +#define iB e01.data +#define iA iX2 xK2( +#define i9 needs_sinhcosh +#define i8 1)x41 +#define i7 ,l4 2,1, +#define i6 cAdd l3 0, +#define i5 tG2 e62 +#define i4 tK1 n9 +#define i3 MakeFalse,l5:: +#define i2 <=fp_const_negativezero xF()) +#define i1 ;return +#define i0 )i1 lH +#define tZ CalculateResultBoundaries(xW +#define tY p0=CalculateResultBoundaries( +#define tX ;yZ2 +#define tW ,2,1 iM2.xR if(found[data. +#define tV 408964 nT 24963, +#define tU 528503 nT 24713, +#define tT matched_params +#define tS [n1 eH3=true;lQ[n1 eI3 +#define tR lA1::Grammar* +#define tQ AddOperation(cInv,1,1 iM2.xR} +#define tP int_exponent_t +#define tO m.max. +#define tN ;AddParamMove( +#define tM nM nU2,e62 1)); +#define tL cG3 eW3 +#define tK return m;}case +#define tJ x9 AnyParams, +#define tI powgroup l8 +#define tH relationships +#define tG ]!=~size_t(0)){synth.yT +#define tF }},{ProduceNewTree,2,1, +#define tE nA1( +#define tD has_mulgroups_remaining +#define tC MatchInfo xF& +#define tB e33);i32 c52 +#define tA best_factor +#define t9 RootPowerTable xF::RootPowers[ +#define t8 (c81 +#define t7 :goto ReplaceTreeWithZero t83 +#define t6 MatchPositionSpec_AnyParams xF +#define t5 l33 FPoptimizer_CodeTree +#define t4 n_as_sinh_param +#define t3 n_as_cosh_param +#define t2 ();pow iH cLog yB eL3 cMul +#define t1 0,tU2 i91 1); +#define t0 is_signed +#define eZ result_positivity +#define eY biggest_minimum +#define eX const l71 +#define eW 122999 nT 139399, +#define eV 142455 nT 141449, +#define eU cond_tree +#define eT then_tree +#define eS (a);bool needs_cow=GetRefCount()>1; +#define eR yZ2&tree) +#define eQ sequencing +#define eP string FP_GetOpcodeName( +#define eO );eN1 c52 0x80000000u +#define eN {if(needs_cow){lD1 goto +#define eM (lJ2));cA1 e33); +#define eL ,nQ2 +#define eK eO3 yZ2> +#define eJ if_stack +#define eI n_as_sin_param +#define eH n_as_cos_param +#define eG PowiResolver:: +#define eF cIf,tG3 +#define eE ].relationship +#define eD .BalanceGood +#define eC AddParamMove(yT2 +#define eB valueType +#define eA back().endif_location +#define e9 xE1 key +#define e8 AddParamMove(mul); +#define e7 130,1, +#define e6 MatchPositionSpecBase +#define e5 iX2 c02( +#define e4 smallest_maximum +#define e3 ]!=~size_t(0)&&found[data. +#define e2 }PACKED_GRAMMAR_ATTRIBUTE; +#define e1 ReplaceTreeWithParam0; +#define e0 factor_needs_rehashing +#define cZ MatchPositionSpecBaseP +#define cY .e33 yB eL3 +#define cX x93 tJ1::y83 +#define cW ParamSpec_Extract xF(nN.param_list, +#define cV }x32 x41==e62 +#define cU 243,244,245,246,249,250,251,253,255,256,257,258,259}};} +#define cT ];};extern"C"{ +#define cS .AddParam( +#define cR iL2 tree lE2"\n"; +#define cQ )return false; +#define cP 79,122,123,160,161,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240, +#define cO 27,28,29,30,31,32,33,35,36, +#define cN const ParamSpec_SubFunction +#define cM const ParamSpec_ParamHolder +#define cL otherhalf +#define cK :{AdoptChildrenWithSameOpcode(tree); +#define cJ goto redo; +#define cI StackState +#define cH l2 16,2, +#define cG const SequenceOpCode xF +#define cF MatchPositionSpec_PositionalParams xF +#define cE const nP1 std::ostream&o +#define cD e62 1.5)*fp_const_pi xF() +#define cC CalculatePowiFactorCost( +#define cB ImmedHashGenerator +#define cA paramholder_matches +#define c9 ::map<fphash_t,std::set<eM3> > +#define c8 ComparisonSetBase:: +#define c7 AddParamMove(comp.cJ1[a].value); +#define c6 T1,x93 T2>inline iD2()( +#define c5 has_nonlogical_values +#define c4 from_logical_context) +#define c3 AnyParams,0}},{ProduceNewTree, +#define c2 for iZ1 a=xV.l91 a-->0;) +#define c1 POWI_CACHE_SIZE +#define c0 static inline yZ2 +#define yZ ++IP;yA1}if(n13 c33. +#define yY },{l5::xJ,l5::Never},{l5::xJ,l5::Never}} +#define yX .FoundChild +#define yW BalanceResultType +#define yV {yZ2 tmp;tmp iH +#define yU yB1 GetOpcode(), +#define yT DoDup(found[data. +#define yS xB3(0),Opcode( +#define yR ;sim.Eat( +#define yQ );void nR1 eZ2,c82< +#define yP {return +#define yO const yP data-> +#define yN +=fp_const_twopi xF(); +#define yM .min.val +#define yL fp_sin(min),fp_sin(max)) +#define yK fp_const_twopi xF());if( +#define yJ {yZ2 tmp,tmp2;tmp2 iH +#define yI .min.known +#define yH for iZ1 a=0;a<l91++a){if( +#define yG MatchPositionSpec_AnyWhere +#define yF if yZ3 data.match_type== +#define yE void OutFloatHex(std::ostream&o, +#define yD {static void lY3 nB fphash_t&cK2, +#define yC tree.l91 +#define yB );tree. +#define yA AddParam(CodeTreeImmed( +#define y9 cGreaterOrEq, +#define y8 ,x93 yZ2:: +#define y7 xF model=cI1 xF()){if(known +#define y6 AssembleSequence_Subdivide( +#define y5 ]=0x80000000u|x83( +#define y4 branch2 +#define y3 x83 c;x83 short l[ +#define y2 factor_stack_base +#define y1 data->Params +#define y0 (lW3 r=range.first;r!=range.i63++r){ +#define xZ {nI2.erase(i);yA1} +#define xY =0;a<y53.l91++a)if( +#define xX ,t21 0x4 nH +#define xW tree l8 +#define xV branch1 +#define xU ,nU2))eN +#define xT nN y92 +#define xS =fp_cosh(m yM);tO val=fp_cosh(tO val); +#define xR StackTopIs(*this)i1;} +#define xQ StackTop +#define xP FPOPT_autoptr +#define xO +=nS3 i1 nS3;}tK1 inline Value_t +#define xN int_exponent +#define xM newnode +#define xL lJ 1 i41 +#define xK has_highlevel_opcodes +#define xJ Unchanged +#define xI .IsIdenticalTo( +#define xH GetStackTop()- +#define xG sim.AddConst( +#define xF <Value_t> +#define xE cE=cV2 +#define xD best_selected_sep +#define xC ->Recalculate_Hash_NoRecursion();} +#define xB l91++a)if(ApplyGrammar(tK2,xW a), +#define xA lU3 2,1, +#define x9 ,cAdd, +#define x8 position +#define x7 x51{yD3 +#define x6 ;tmp2 tY3 tmp iH cInv);tmp c91 tmp2)i1 +#define x5 eO3 c02> +#define x4 SetParam(0,iZ2 l8 0))tX p1;p1 iH +#define x3 TestImmedConstraints yZ3 constraints cU3)cQ +#define x2 SwapLastTwoInStack()yR +#define x1 n23 1,cInv e02 xG-1 xN1 +#define x0 paramholder_index +#define nZ lD2 case +#define nY occurance_counts +#define nX );a-->0;){iT1&powgroup=lX1;if(powgroup +#define nW )){tree.tE3;} +#define nV Value_t>p=tZ a));if(p. +#define nU tree.ReplaceWithImmed( +#define nT ,{2, +#define nS ,l0 1, +#define nR ,cAdd l3 2,1, +#define nQ ){yZ2 +#define nP if(xW 0)tD1 +#define nO const FPoptimizer_CodeTree::yZ2&tree +#define nN model_tree +#define nM return yD3( +#define nL ){using l33 FUNCTIONPARSERTYPES; +#define nK eK&n12 +#define nJ AddParam(xW +#define nI ConstantFolding_LogicCommon(tree,c8 +#define nH },{{2, +#define nG nN1 Ref>inline void xP<Ref>:: +#define nF AnyParams,1 i41 +#define nE ):data(new xK2 xF( +#define nD goto do_return;} +#define nC .GetOpcode() +#define nB FUNCTIONPARSERTYPES:: +#define nA b;}};tP1>e72 Comp<nB +#define n9 xK2 xF::xK2( +#define n8 lL2(),t53),Hash(),Depth(1 eB1 0){} +#define n7 SynthesizeByteCode(c92 +#define n6 while(ApplyGrammar(cG2 +#define n5 GetIntegerInfo(xW 0))==iF2)n73 +#define n4 ;tree c91 n81 yQ2 +#define n3 tL1 cGreater>(e62 +#define n2 DumpParams xF yZ3 data.param_list,iH3 y92,o); +#define n1 restholder_index +#define n0 yZ2 exponent eX3 iH cMul)eX3 cS +#define lZ lR);if(fp_nequal(tmp,xG1){nU e62 1)/tmp);nD}lC +#define lY :if(ParamComparer xF()(t63 1],t63 0])){std::swap(t63 0],t63 1]);Opcode= +#define lX <x93 Value_t> +#define lW xF tmp;tmp iH cPow);tmp tY3 tmp.yA e62 +#define lV i01,0x0}, +#define lU AddParamMove(pow l8 1));pow.i91 1);pow.e33 yB nB1 0,pow);goto NowWeAreMulGroup;} +#define lT GroupFunction,0},lV{{ +#define lS ,e62 1)/e62 +#define lR xW 0)x41 +#define lQ restholder_matches +#define lP yE1|=key;xE1 crc=(key>>10)|(key<<(64-10))lL1((~n51 crc))*3)^1234567;}}; +#define lO n81;n81 nO2;n81 c91 xW 0));n81 cS xV l8 +#define lN tK1 yZ2::c02( +#define lM tree.SetParam(0,xW 0)l8 0)xT1 1,CodeTreeImmed( +#define lL lX void eP3::nR1 eZ2,c82< +#define lK cMul,lT 2, +#define lJ cMul,AnyParams, +#define lI (xW 0)tD1&&xW 1)tD1){nU +#define lH CalculateResultBoundaries(tmp);}case +#define lG :cY3=comp.AddRelationship(atree l8 0),atree l8 1),c8 +#define lF cPow,l0 2 +#define lE x93 Value_t>inline iD2()iS1 Value_t&xC3 Value_t&b)yP a +#define lD {yD3 m=tZ 0)); +#define lC break t83 +#define lB xL1 yZ2:: +#define lA y71,0, +#define l9 l1 0x0 nH +#define l8 .GetParam( +#define l7 tX n81;n81 nO2;n81 iF1 tree.lJ2));n81 cY +#define l6 SelectedParams,0},0,0x0 nH +#define l5 RangeComparisonData +#define l4 y71},{ProduceNewTree, +#define l3 ,AnyParams,0}},{ReplaceParams, +#define l2 y71},{ReplaceParams, +#define l1 cMul,SelectedParams,0},0, +#define l0 lA 0x0},{{ +#ifdef _MSC_VER +typedef +x83 +int +lI2; +#else +#include <stdint.h> +typedef +uint_least32_t +lI2; +#endif +l33 +crc32{enum{startvalue=0xFFFFFFFFUL,poly=0xEDB88320UL} +;tP1 +lI2 +crc>e72 +b8{enum{b1=(crc&xJ1 +crc +xL2 +crc>>1),b2=(b1&xJ1 +b1 +xL2 +b1>>1),b3=(b2&xJ1 +b2 +xL2 +b2>>1),b4=(b3&xJ1 +b3 +xL2 +b3>>1),b5=(b4&xJ1 +b4 +xL2 +b4>>1),b6=(b5&xJ1 +b5 +xL2 +b5>>1),b7=(b6&xJ1 +b6 +xL2 +b6>>1),res=(b7&xJ1 +b7 +xL2 +b7>>1)} +;} +;inline +lI2 +update(lI2 +crc,x83 +b){ +#define B4(n) b8<n>nP3 n+1>nP3 n+2>nP3 n+3>::res +#define R(n) B4(n),B4(n+4),B4(n+8),B4(n+12) +static +const +lI2 +table[256]={R(0x00),R(0x10),R(0x20),R(0x30),R(0x40),R(0x50),R(0x60),R(0x70),R(0x80),R(0x90),R(0xA0),R(0xB0),R(0xC0),R(0xD0),R(0xE0),R(0xF0)} +; +#undef R +#undef B4 +return((crc>>8))^table[(crc^b)&0xFF];y81 +lI2 +calc_upd(lI2 +c,const +x83 +char*buf,size_t +size){lI2 +value=c +eK3 +p=0;p<size;++p)value=update(value,buf[p])i1 +value;y81 +lI2 +calc +iS1 +x83 +char*buf,size_t +size)yP +calc_upd(startvalue,buf,size);} +} +#ifndef FPOptimizerAutoPtrHH +#define FPOptimizerAutoPtrHH +nN1 +Ref>class +xP{e43 +xP():p(0){} +xP(Ref*b):p(b){xA3} +xP +iS1 +xP&b):p(b.p){xA3 +y81 +Ref&eM1*(c01*p;y81 +Ref*eM1->(c01 +p;} +xP&eM1=(Ref*b){Set(b)i1*this;} +xP&eM1=iS1 +xP&b){Set(b.p)i1*this;} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +xP(xP&&b):p(b.p){b.p=0;} +xP&eM1=(xP&&b){if(p!=b.p){iC2;p=b.p;b.p=0;eE3*this;} +#endif +~xP(){Forget(cN2 +UnsafeSetP(Ref*newp){p=newp;} +void +swap(xP<Ref>&b){Ref*tmp=p;p=b.p;b.p=tmp;} +private:inline +static +void +Have(Ref*p2);inline +void +iC2;inline +void +xA3 +inline +void +Set(Ref*p2);private:Ref*p;} +;nG +iC2{if(!p)return;p->xB3-=1;if(!p->xB3)delete +p;} +nG +Have(Ref*p2){if(p2)++(p2->xB3);} +nG +Birth(){Have(p);} +nG +Set(Ref*p2){Have(p2);iC2;p=p2;} +#endif +#include <utility> +e72 +Compare2ndRev{nN1 +T>inline +iD2()iS1 +T&xC3 +T&b +c01 +a.second>b.i63} +} +;e72 +Compare1st{nN1 +c6 +const +nO1 +xC3 +nO1 +b +c01 +a.first<b.first;} +nN1 +c6 +const +nO1 +a,T1 +b +c01 +a.first<b;} +nN1 +c6 +T1 +xC3 +nO1 +b +c01 +a<b.first;} +} +; +#ifndef FPoptimizerHashHH +#define FPoptimizerHashHH +#ifdef _MSC_VER +typedef +x83 +long +long +xE1; +#define FPHASH_CONST(x) x##ULL +#else +#include <stdint.h> +typedef +uint_fast64_t +xE1; +#define FPHASH_CONST(x) x##ULL +#endif +l33 +FUNCTIONPARSERTYPES{e72 +fphash_t{xE1 +hash1,hash2;fphash_t():hash1(0),hash2(0){} +fphash_t +iS1 +xE1&xC3 +xE1&b):hash1(a),hash2(b){} +iD2==iS1 +fphash_t&yZ1==e82&&hash2==e92 +iD2!=iS1 +fphash_t&yZ1!=e82||hash2!=e92 +iD2<iS1 +fphash_t&yZ1!=e82?hash1<e82:hash2<e92} +;} +#endif +#ifndef FPOptimizer_CodeTreeHH +#define FPOptimizer_CodeTreeHH +#ifdef FP_SUPPORT_OPTIMIZER +#include <vector> +#include <utility> +l33 +lA1{e72 +Grammar;} +l33 +xK1{tK1 +class +ByteCodeSynth;} +t5{tK1 +class +c02 +yO1 +e72 +xK2 +yO1 +class +c02{typedef +xP<xK2 +xF>DataP;DataP +data;e43 +c02();~c02();e72 +OpcodeTag{} +;e5 +iU1 +o,OpcodeTag);e72 +FuncOpcodeTag{} +;e5 +iU1 +o,x83 +f,FuncOpcodeTag);e72 +xD3{} +;e5 +tV1,xD3); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +e5 +Value_t&&v,xD3); +#endif +e72 +VarTag{} +;e5 +x83 +varno,VarTag);e72 +CloneTag{} +;e5 +tW1 +b,CloneTag);void +GenerateFrom +iS1 +x93 +FunctionParserBase +xF::Data&data,bool +keep_powi=false);void +GenerateFrom +iS1 +x93 +FunctionParserBase +xF::Data&data,const +x5&xH2,bool +keep_powi=false);void +SynthesizeByteCode(eO3 +x83>&cT3,std +xM3 +xF&immed,size_t&stacktop_max);void +SynthesizeByteCode(xK1::eP3&synth,bool +MustPopTemps=true)const;size_t +SynthCommonSubExpressions(xK1::xI1 +const;void +SetParams +iS1 +x5&xE3 +SetParamsMove(x5&tO1 +c02 +GetUniqueRef(); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +void +SetParams(x5&&tO1 +#endif +void +SetParam +iZ1 +which,tW1 +b);void +nB1 +size_t +which,c02&b);void +AddParam(tW1 +param);void +AddParamMove(c02¶m);void +AddParams +iS1 +x5&xE3 +AddParamsMove(x5&xE3 +AddParamsMove(x5&n12,size_t +n22);void +i91 +size_t +index);void +DelParams();void +Become(tW1 +b);inline +size_t +GetParamCount(c01 +lJ2)eJ3;y81 +c02&GetParam +iZ1 +n)yP +lJ2)[n];y81 +tW1 +GetParam +iZ1 +n +c01 +lJ2)[n];y81 +void +eL3 +iU1 +o)iZ3 +Opcode=o;y81 +iU1 +GetOpcode()yO +Opcode;y81 +nB +fphash_t +GetHash()yO +Hash;y81 +const +x5&lJ2 +c01 +y1;y81 +x5&lJ2)yP +y1;y81 +size_t +GetDepth()yO +Depth;y81 +const +Value_t&GetImmed()yO +Value;y81 +x83 +GetVar()yO +lK2 +y81 +x83 +GetFuncNo()yO +lK2 +y81 +bool +IsDefined(c01 +GetOpcode()!=nB +cNop;y81 +bool +IsImmed(c01 +GetOpcode()==nB +cImmed;y81 +bool +IsVar(c01 +GetOpcode()==nB +iU2;y81 +x83 +GetRefCount()yO +xB3;} +void +ReplaceWithImmed(tX1;void +e33 +bool +constantfolding=true);void +Sort();inline +void +Mark_Incompletely_Hashed()iZ3 +Depth=0;y81 +bool +Is_Incompletely_Hashed()yO +Depth==0;y81 +const +tR +GetOptimizedUsing()yO +lM2;y81 +void +SetOptimizedUsing +iS1 +tR +g)iZ3 +lM2=g;} +bool +RecreateInversionsAndNegations(bool +prefer_base2=false);void +tE3;void +swap(c02&b){data.swap(b.data);} +bool +IsIdenticalTo(tW1 +b)const;void +lD1} +yO1 +e72 +xK2{int +xB3;iU1 +Opcode +iK2 +Value;x83 +lK2 +eK +Params;nB +fphash_t +Hash;size_t +Depth;const +tR +lM2;xK2();xK2 +iS1 +xK2&b);iA +iU1 +o);iA +iU1 +o,x83 +f);iA +tX1; +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +iA +Value_t&&i);xK2(xK2&&b); +#endif +bool +IsIdenticalTo +iS1 +xK2&b)const;void +Sort();void +Recalculate_Hash_NoRecursion();private:void +eM1=iS1 +xK2&b);} +yO1 +c0 +CodeTreeImmed(tX1 +n21 +i +y8 +xD3());} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +cC1 +CodeTreeImmed +cX3&&i)n21 +tF2 +i)y8 +xD3());} +#endif +cC1 +CodeTreeOp(iU1 +opcode)n21 +opcode +y8 +OpcodeTag());} +cC1 +CodeTreeFuncOp(iU1 +opcode,x83 +f)n21 +opcode,f +y8 +FuncOpcodeTag());} +cC1 +CodeTreeVar +lT1 +varno)n21 +varno +y8 +VarTag());} +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +xL1 +DumpHashes(xE);xL1 +DumpTree(xE);xL1 +DumpTreeWithIndent(xE,const +eM3&indent="\\" +); +#endif +} +#endif +#endif +#ifndef FPOptimizer_GrammarHH +#define FPOptimizer_GrammarHH +#include <iostream> +t5{tK1 +class +c02;} +l33 +lA1{enum +ImmedConstraint_Value{ValueMask=0x07,Value_AnyNum=0x0,x62=0x1,Value_OddInt=0x2,i11=0x3,Value_NonInteger=0x4,eY1=0x5} +;enum +ImmedConstraint_Sign{SignMask=0x18,Sign_AnySign=0x00,nD1=0x08,eZ1=0x10,Sign_NoIdea=0x18} +;enum +ImmedConstraint_Oneness{OnenessMask=0x60,Oneness_Any=0x00,Oneness_One=0x20,Oneness_NotOne=0x40} +;enum +ImmedConstraint_Constness{ConstnessMask=0x180,Constness_Any=0x00,i01=0x80,Constness_NotConst=0x100} +;enum +Modulo_Mode{Modulo_None=0,Modulo_Radians=1} +;enum +Situation_Flags{LogicalContextOnly=0x01,NotForIntegers=0x02,OnlyForIntegers=0x04,OnlyForComplex=0x08,NotForComplex=0x10} +;enum +nZ2{NumConstant,ParamHolder,SubFunction} +;enum +ParamMatchingType{PositionalParams,SelectedParams,AnyParams,GroupFunction} +;enum +RuleType{ProduceNewTree,ReplaceParams} +; +#ifdef __GNUC__ +# define PACKED_GRAMMAR_ATTRIBUTE __attribute__((packed)) +#else +# define PACKED_GRAMMAR_ATTRIBUTE +#endif +typedef +std::pair<nZ2,const +void*>eA2 +yO1 +eA2 +ParamSpec_Extract +lT1 +paramlist,lJ1)yO1 +bool +ParamSpec_Compare +iS1 +void*xC3 +void*b,nZ2 +type);x83 +ParamSpec_GetDepCode +iS1 +eA2&b);e72 +ParamSpec_ParamHolder{lJ1:8;x83 +constraints:9;x83 +depcode:15;e2 +tK1 +e72 +ParamSpec_NumConstant +l14 +constvalue;x83 +modulo;} +;e72 +l71{x83 +param_count:2;x83 +param_list:30;iU1 +subfunc_opcode:8;ParamMatchingType +match_type:3;x83 +n1:5;e2 +e72 +ParamSpec_SubFunction{l71 +data;x83 +constraints:9;x83 +depcode:7;e2 +e72 +Rule{RuleType +ruletype:2;x83 +situation_flags:5;x83 +repl_param_count:2+9;x83 +repl_param_list:30;l71 +match_tree;e2 +e72 +Grammar{x83 +rule_count;x83 +short +rule_list[999 +cT +extern +const +Rule +grammar_rules[];} +xL1 +DumpParam +iS1 +eA2&p,std::ostream&o=cV2);xL1 +DumpParams +lT1 +paramlist,x83 +count,std::ostream&o=cV2);} +#endif +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif +#define CONSTANT_POS_INF HUGE_VAL +#define CONSTANT_NEG_INF (-HUGE_VAL) +l33 +FUNCTIONPARSERTYPES{tK1 +inline +Value_t +fp_const_pihalf()yP +fp_const_pi +xF()*yF2;} +tK1 +inline +Value_t +fp_const_twopi()eQ3 +fp_const_pi +xF());nS3 +xO +fp_const_twoe()eQ3 +fp_const_e +xF());nS3 +xO +fp_const_twoeinv()eQ3 +fp_const_einv +xF());nS3 +xO +fp_const_negativezero()yP-Epsilon +xF::value;} +} +#ifdef FP_SUPPORT_OPTIMIZER +#include <vector> +#include <utility> +#include <iostream> +nG1{using +l33 +lA1;using +t5;using +l33 +FUNCTIONPARSERTYPES +yO1 +class +MatchInfo{e43 +eO3 +std::pair<bool,eK> >lQ;eK +cA;eO3 +x83>tT;e43 +MatchInfo():lQ(),cA(),tT(){} +e43 +bool +SaveOrTestRestHolder +lT1 +n1,eA3&iJ1){cT1{lQ +xF3 +n1+1);lQ +tS=iJ1 +l43 +if(lQ[n1 +eH3==false){lQ +tS=iJ1 +l43 +eA3&found=lQ[n1 +eI3;if(iJ1 +eJ3!=found +eJ3 +cQ +for +iZ1 +a=0;a<iJ1 +eJ3;++a)if(!iJ1[a]xI +found[a])cQ +lD2} +void +SaveRestHolder +lT1 +n1,eK&iJ1){cT1 +lQ +xF3 +n1+1);lQ +tS.swap(iJ1);} +bool +SaveOrTestParamHolder +lT1 +x0,iT1&xG3){if(cA +eJ3<=x0){cA.xH3 +x0+1);cA +xF3 +x0);cA +c52 +xG3 +yQ2 +if(!cA[x0].nX2){cA[x0]=xG3 +l43 +return +xG3 +xI +cA[x0]cN2 +SaveMatchedParamIndex(lJ1){tT +c52 +index);} +iT1&GetParamHolderValueIfFound +lT1 +x0)const{static +iT1 +dummytree;if(cA +eJ3<=x0)return +dummytree +i1 +cA[x0];} +iT1&GetParamHolderValue +lT1 +x0 +c01 +cA[x0];} +bool +HasRestHolder +lT1 +n1 +c01 +lQ +eJ3>n1&&lQ[n1 +eH3==true;} +eA3&GetRestHolderValues +lT1 +n1)const{static +eA3 +empty_result;cT1 +return +empty_result +i1 +lQ[n1 +eI3;} +const +eO3 +x83>&GetMatchedParamIndexes(c01 +tT;} +void +swap(tC +b){lQ.swap(b.lQ);cA.swap(b.cA);tT.swap(b.tT);} +tC +eM1=iS1 +tC +b){lQ=b.lQ;cA=b.cA;tT=b.tT +i1*this;} +} +;class +e6;typedef +xP<e6>cZ;class +e6{e43 +int +xB3;e43 +e6():xB3(0){} +virtual~e6(){} +} +;e72 +n31{bool +found;cZ +specs;n31(bool +f):found(f),specs(){} +n31(bool +f,const +cZ&s):found(f),specs(s){} +} +;xL1 +SynthesizeRule(t41 +nP1 +tC +info)yO1 +n31 +TestParam +iS1 +eA2&yA2 +const +nP1 +const +cZ&start_at,tC +info)yO1 +n31 +TestParams(eX&nN,const +nP1 +const +cZ&start_at,tC +info,bool +iX1 +yO1 +bool +ApplyGrammar +iS1 +Grammar&tK2,FPoptimizer_CodeTree::nP1 +bool +from_logical_context=false);xL1 +ApplyGrammars(FPoptimizer_CodeTree::eR +yO1 +bool +IsLogisticallyPlausibleParamsMatch(eX¶ms,const +eR;} +l33 +lA1{xL1 +DumpMatch(t41 +nO,const +FPoptimizer_Optimize::tC +info,bool +DidMatch,std::ostream&o=cV2);xL1 +DumpMatch(t41 +nO,const +FPoptimizer_Optimize::tC +info,e32 +tO3,std::ostream&o=cV2);} +#endif +#include <string> +e42 +lA1::nZ2 +yT1=false);e42 +iU1 +yT1=false); +#include <string> +#include <sstream> +#include <assert.h> +#include <iostream> +using +l33 +lA1;using +l33 +FUNCTIONPARSERTYPES;e42 +lA1::nZ2 +yT1){ +#if 1 +e32 +p=0;e23 +opcode){case +NumConstant:p="NumConstant" +;lC +ParamHolder:p="ParamHolder" +;lC +SubFunction:p="SubFunction" +;xY3 +std::ostringstream +tmp;assert(p);tmp<<p;if(pad)while(tmp.str()eJ3<12)tmp<<' ' +i1 +tmp.str(); +#else +std::ostringstream +tmp;tmp<<opcode;if(pad)while(tmp.str()eJ3<5)tmp<<' ' +i1 +tmp.str(); +#endif +} +e42 +iU1 +yT1){ +#if 1 +e32 +p=0;e23 +opcode){case +cAbs:p="cAbs" +;lC +cAcos:p="cAcos" +;lC +cAcosh:p="cAcosh" +;lC +cArg:p="cArg" +;lC +cAsin:p="cAsin" +;lC +cAsinh:p="cAsinh" +;lC +cAtan:p="cAtan" +;lC +cAtan2:p="cAtan2" +;lC +cAtanh:p="cAtanh" +;lC +cCbrt:p="cCbrt" +;lC +cCeil:p="cCeil" +;lC +cConj:p="cConj" +;lC +cCos:p="cCos" +;lC +cCosh:p="cCosh" +;lC +cCot:p="cCot" +;lC +cCsc:p="cCsc" +;lC +cExp:p="cExp" +;lC +cExp2:p="cExp2" +;lC +cFloor:p="cFloor" +;lC +cHypot:p="cHypot" +;lC +cIf:p="cIf" +;lC +cImag:p="cImag" +;lC +cInt:p="cInt" +;lC +cLog:p="cLog" +;lC +cLog2:p="cLog2" +;lC +cLog10:p="cLog10" +;lC +cMax:p="cMax" +;lC +cMin:p="cMin" +;lC +cPolar:p="cPolar" +;lC +cPow:p="cPow" +;lC +cReal:p="cReal" +;lC +cSec:p="cSec" +;lC +cSin:p="cSin" +;lC +cSinh:p="cSinh" +;lC +cSqrt:p="cSqrt" +;lC +cTan:p="cTan" +;lC +cTanh:p="cTanh" +;lC +cTrunc:p="cTrunc" +;lC +cImmed:p="cImmed" +;lC +cJump:p="cJump" +;lC +cNeg:p="cNeg" +;lC +cAdd:p="cAdd" +;lC +cSub:p="cSub" +;lC +cMul:p="cMul" +;lC +cDiv:p="cDiv" +;lC +cMod:p="cMod" +;lC +cEqual:p="cEqual" +;lC +i51:p="cNEqual" +;lC +cLess:p="cLess" +;lC +cLessOrEq:p="cLessOrEq" +;lC +cGreater:p="cGreater" +;lC +cGreaterOrEq:p="cGreaterOrEq" +;lC +cNot:p="cNot" +;lC +cAnd:p="cAnd" +;lC +cOr:p="cOr" +;lC +cDeg:p="cDeg" +;lC +cRad:p="cRad" +;lC +cFCall:p="cFCall" +;lC +cPCall:p="cPCall" +;break; +#ifdef FP_SUPPORT_OPTIMIZER +case +cFetch:p="cFetch" +;lC +cPopNMov:p="cPopNMov" +;lC +cQ3:p="cLog2by" +;lC +cNop:p="cNop" +;break; +#endif +case +cSinCos:p="cSinCos" +;lC +cSinhCosh:p="cSinhCosh" +;lC +cC3:p="cAbsNot" +;lC +cAbsNotNot:p="cAbsNotNot" +;lC +cAbsAnd:p="cAbsAnd" +;lC +cAbsOr:p="cAbsOr" +;lC +cAbsIf:p="cAbsIf" +;lC +cDup:p="cDup" +;lC +cInv:p="cInv" +;lC +cSqr:p="cSqr" +;lC +cRDiv:p="cRDiv" +;lC +cRSub:p="cRSub" +;lC +cNotNot:p="cNotNot" +;lC +cRSqrt:p="cRSqrt" +;lC +iU2:p="VarBegin" +;xY3 +std::ostringstream +tmp;assert(p);tmp<<p;if(pad)while(tmp.str()eJ3<12)tmp<<' ' +i1 +tmp.str(); +#else +std::ostringstream +tmp;tmp<<opcode;if(pad)while(tmp.str()eJ3<5)tmp<<' ' +i1 +tmp.str(); +#endif +} +#ifdef FP_SUPPORT_OPTIMIZER +#include <vector> +#include <utility> +#ifndef FP_GENERATING_POWI_TABLE +enum{MAX_POWI_BYTECODE_LENGTH=20} +; +#else +enum{MAX_POWI_BYTECODE_LENGTH=999} +; +#endif +enum{MAX_MULI_BYTECODE_LENGTH=3} +;l33 +xK1{tK1 +class +ByteCodeSynth{e43 +ByteCodeSynth():eN1(),Immed(),cI(),xQ(0),StackMax(0){eN1.xH3 +64);Immed.xH3 +8);cI.xH3 +16 +cN2 +Pull(eO3 +x83>&bc,std +xM3 +xF&imm,size_t&StackTop_max){for +lT1 +a=0;a<n41;++a){eN1[a]&=~0x80000000u;} +eN1.swap(bc);Immed.swap(imm);StackTop_max=StackMax;} +size_t +GetByteCodeSize(c01 +n41;} +size_t +GetStackTop(c01 +xQ;} +void +PushVar +lT1 +varno){eN1 +c52 +varno);xI3 +1 +cN2 +PushImmed +cX3 +immed +nL +eN1 +c52 +cImmed);Immed +c52 +immed);xI3 +1 +cN2 +StackTopIs(nO,int +offset=0){if((int)xQ>offset){cI[xQ +nK2 +first=true;cI[xQ +nK2 +second=tree;} +} +bool +IsStackTop(nO,int +offset=0 +c01(int)xQ>offset&&cI[xQ +nK2 +first&&cI[xQ +nK2 +second +xI +tree);y81 +void +EatNParams +lT1 +eat_count){xQ-=eat_count;} +void +ProducedNParams +lT1 +produce_count){xI3 +produce_count +cN2 +DoPopNMov +iZ1 +eB2,size_t +srcpos +nL +eN1 +c52 +cPopNMov +e53 +eB2 +e53 +srcpos);xM1 +srcpos+1);cI[eB2]=cI[srcpos];xM1 +eB2+1 +cN2 +DoDup +iZ1 +xJ3 +nL +if(xJ3==xQ-1){eN1 +c52 +cDup);} +else{eN1 +c52 +cFetch +e53 +xJ3);} +xI3 +1);cI[xQ-1]=cI[xJ3];} +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +tP1 +int>void +Dump(){std::ostream&o=cV2;o<<"Stack state now(" +<<xQ<<"):\n" +e73 +0;a<xQ;++a){o<<a<<": " +;if(cI[a +eH3){nO=cI[a +eI3;o<<'['<<std::hex<<(void*)(&tree.lJ2))<<std::dec<<','<<tree.GetRefCount()<<']' +iL2 +tree,o);} +else +o<<"?" +iV3} +o<<std::flush;} +#endif +size_t +xK3 +nO)const{for +iZ1 +a=xQ;a-->0;)if(cI[a +eH3&&cI[a +eI3 +xI +tree +y03 +a +i1~size_t(0);} +bool +Find(nO +c01 +xK3 +tree)!=~size_t(0);} +bool +FindAndDup(nO){size_t +pos=xK3 +tree);if(pos!=~size_t(0)){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iX3"duplicate at [" +<<pos<<"]: " +iL2 +tree +lE2" -- issuing cDup or cFetch\n" +; +#endif +DoDup(pos +yQ2 +return +t23 +e72 +IfData{size_t +ofs;} +;void +SynthIfStep1 +c62,iU1 +op +x21 +c72=n41;eN1 +c52 +op +eO +eO +cN2 +SynthIfStep2 +c62 +x21 +eN1 +iK1 +xL3+2);eN1 +iK1 +2 +y5 +lN2 +c72=n41;eN1 +c52 +cJump +eO +eO +cN2 +SynthIfStep3 +c62 +x21 +eN1.back()|=0x80000000u;eN1 +iK1 +xL3-1);eN1 +iK1 +2 +y5 +lN2 +xI3 +1 +iY1 +0;a<c72;++a){if(eN1[a]==cJump&&eN1[a+1]==(0x80000000u|(c72-1))){eN1[a+xL3-1);eN1[a+2 +y5 +lN2 +c73(eN1[a]){case +cAbsIf:case +cIf:case +cJump:case +cPopNMov:a+=2;lC +cFCall:case +cPCall:case +cFetch:a+=1;break;yF3 +xY3} +} +protected:void +xM1 +size_t +value){xQ=value;if(xQ>l53{StackMax=xQ;cI +xF3 +l53;} +} +protected:eO3 +x83>eN1;std +xM3 +xF +Immed;eO3 +std::pair<bool,FPoptimizer_CodeTree::yZ2> >cI;size_t +xQ;size_t +StackMax;private:void +incStackPtr(){if(xQ+2>l53 +cI +xF3 +StackMax=xQ+2);} +tP1 +bool +IsIntType,bool +IsComplexType>e72 +c82{} +;e43 +void +AddOperation +eZ2,x83 +eat_count,x83 +produce_count=1){EatNParams(eat_count);nR1(opcode);ProducedNParams(produce_count +cN2 +nR1 +eZ2,c82<false,false>yQ +false,true>yQ +true,false>yQ +true,true>);inline +void +nR1 +eZ2){nR1(opcode,c82<bool(nB +IsIntType +xF::nS3),bool(nB +IsComplexType +xF::nS3)>());} +} +yO1 +e72 +SequenceOpCode +yO1 +e72 +tU1{static +cG +AddSequence;static +cG +MulSequence;} +;xL1 +x01 +long +count,cG&eQ,xI1;} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES;l33 +xK1{tK1 +e72 +SequenceOpCode +l14 +basevalue;x83 +op_flip;x83 +op_normal,op_normal_flip;x83 +op_inverse,op_inverse_flip;} +yO1 +cG +tU1 +xF::AddSequence={xH1,cNeg +x9 +cAdd,cSub,cRSub} +yO1 +cG +tU1 +xF::MulSequence={e62 +1),cInv,cMul,cMul,cDiv,cRDiv} +; +#define findName(a,b,c) "var" +#define TryCompilePowi(o) false +#define mData this +#define mByteCode eN1 +#define mImmed Immed +nL2 +false,false>)x31 +# define FP_FLOAT_VERSION 1 +# define FP_COMPLEX_VERSION 0 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +nL2 +true,false>)x31 +# define FP_FLOAT_VERSION 0 +# define FP_COMPLEX_VERSION 0 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +#ifdef FP_SUPPORT_COMPLEX_NUMBERS +nL2 +false,true>)x31 +# define FP_FLOAT_VERSION 1 +# define FP_COMPLEX_VERSION 1 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +nL2 +true,true>)x31 +# define FP_FLOAT_VERSION 0 +# define FP_COMPLEX_VERSION 1 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +#endif +#undef findName +#undef mImmed +#undef mByteCode +#undef mData +#undef TryCompilePowi +} +using +l33 +xK1; +#define POWI_TABLE_SIZE 256 +#define POWI_WINDOW_SIZE 3 +l33 +xK1{ +#ifndef FP_GENERATING_POWI_TABLE +extern +const +x83 +char +powi_table[POWI_TABLE_SIZE];const +#endif +x83 +char +powi_table[POWI_TABLE_SIZE]={0,1,1,1,2,1,2,1,xN3 +4,1,2,xP3 +2,1,xN3 +8,cV3 +xQ3 +15,1,16,1,2,1,4,1,2,xP3 +2,1,4,cV3 +1,16,1,25,xQ3 +27,5,8,3,2,1,30,1,31,3,32,1,2,1,xN3 +8,1,2,xQ3 +39,1,16,137,2,1,4,cV3 +xP3 +45,135,4,31,2,5,32,1,2,131,50,1,51,1,8,3,2,1,54,1,55,3,16,1,57,133,4,137,2,135,60,1,61,3,62,133,63,1,iL1 +131,iL1 +139,lO2 +e7 +30,1,130,137,2,31,lO2 +e7 +e7 +130,cV3 +1,e7 +e7 +2,1,130,133,iL1 +61,130,133,62,139,130,137,e7 +lO2 +e7 +e7 +iL1 +131,e7 +e7 +130,131,2,133,lO2 +130,141,e7 +130,cV3 +1,e7 +5,135,e7 +lO2 +e7 +lO2 +130,133,130,141,130,131,e7 +e7 +2,131} +;} +static +x03 +c1=256; +#define FPO(x) +l33{class +PowiCache{private:int +iM[c1];int +iM1[c1];e43 +PowiCache():iM(),iM1(){iM[1]=1;} +bool +Plan_Add(c11,int +count){cD1>=c1 +cQ +iM1[t02+=count +i1 +iM[t02!=0;} +void +l63 +c11){cD1<c1)iM[t02=1;} +void +Start +iZ1 +value1_pos){for(int +n=2;n<c1;++n)iM[n]=-1;Remember(1,value1_pos);DumpContents();} +int +Find(c11)const{cD1<c1){if(iM[t02>=0){FPO(iC3(iG3,"* I found %ld from cache (%u,%d)\n",value,(unsigned)cache[value],iD3 value]))i1 +iM[t02;} +eE3-1;} +void +Remember(c11,size_t +iQ3){cD1>=c1)return;FPO(iC3(iG3,"* Remembering that %ld can be found at %u (%d uses remain)\n",value,(unsigned)iQ3,iD3 value]));iM[t02=(int)iQ3;} +void +DumpContents()const{FPO(for(int a=1;a<POWI_CACHE_SIZE;++a)if(cache[a]>=0||iD3 a]>0){iC3(iG3,"== cache: sp=%d, val=%d, needs=%d\n",cache[a],a,iD3 a]);})} +int +UseGetNeeded(c11){cD1>=0&&value<c1)return--iM1[t02 +i1 +0;} +} +yO1 +size_t +y6 +long +count +iQ1 +cG&eQ,xI1;xL1 +c21 +size_t +apos,long +aval,size_t +bpos,long +bval +iQ1 +x83 +cumulation_opcode,x83 +cimulation_opcode_flip,xI1;void +lB1 +c11 +iQ1 +int +need_count,int +lC1=0){cD1<1)return; +#ifdef FP_GENERATING_POWI_TABLE +if(lC1>32)throw +false; +#endif +if(iM.Plan_Add(value,need_count +y03;long +xR3 +1;cD1<POWI_TABLE_SIZE){xR3 +powi_table[t02 +xZ3&128){half&=127 +xZ3&64)xR3-t12 +FPO(iC3(iG3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,value/half));lB1 +half +xO3 +iM.l63 +half)i1;} +iP1 +half&64){xR3-t12} +} +else +cD1&1)xR3 +value&((1<<POWI_WINDOW_SIZE)-1);else +xR3 +value/2;long +cL=value-half +xZ3>cL||half<0)std::swap(half,cL);FPO(iC3(iG3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,otherhalf))xZ3==cL){lB1 +half,iM,2,lC1+1);} +else{lB1 +half +xO3 +lB1 +cL>0?cL:-cL +xO3} +iM.l63 +value);} +tK1 +size_t +y6 +c11 +iQ1 +cG&eQ,xI1{int +xT3=iM.Find(value);if(xT3>=0)yP +xT3;} +long +xR3 +1;cD1<POWI_TABLE_SIZE){xR3 +powi_table[t02 +xZ3&128){half&=127 +xZ3&64)xR3-t12 +FPO(iC3(iG3,"* I want %ld, my plan is %ld * %ld\n",value,half,value/half));size_t +xM2=y6 +half +cE1 +if(iM +lP2 +half)>0||xM2!=cG1){iN1 +xM2)xP2 +half,cG1);} +x01 +value/half +e63 +size_t +iQ3=cG1 +xP2 +value,iQ3);iM.DumpContents()i1 +iQ3;} +iP1 +half&64){xR3-t12} +} +else +cD1&1)xR3 +value&((1<<POWI_WINDOW_SIZE)-1);else +xR3 +value/2;long +cL=value-half +xZ3>cL||half<0)std::swap(half,cL);FPO(iC3(iG3,"* I want %ld, my plan is %ld + %ld\n",value,half,value-half))xZ3==cL){size_t +xM2=y6 +half +cE1 +c21 +xM2,half,xM2,half,iM,eQ.op_normal,eQ.op_normal_flip,c92} +else{long +part1=half;long +part2=cL>0?cL:-cL;size_t +part1_pos=y6 +part1 +cE1 +size_t +part2_pos=y6 +part2 +cE1 +FPO(iC3(iG3,"Subdivide(%ld: %ld, %ld)\n",value,half,otherhalf));c21 +part1_pos,part1,part2_pos,part2,iM,cL>0?eQ.op_normal:eQ.op_inverse,cL>0?eQ.op_normal_flip:eQ.op_inverse_flip,c92} +size_t +iQ3=cG1 +xP2 +value,iQ3);iM.DumpContents()i1 +iQ3;} +xL1 +c21 +size_t +apos,long +aval,size_t +bpos,long +bval +iQ1 +x83 +cumulation_opcode,x83 +cumulation_opcode_flip,xI1{int +a_needed=iM +lP2 +aval);int +xU3=iM +lP2 +bval);bool +flipped +eW3 +#define DUP_BOTH() do{if(apos<bpos){size_t tmp=apos;apos=bpos;bpos=tmp e41 FPO(iC3(iG3,"-> " iO3 iO3"op\n",(unsigned)apos,(unsigned)bpos));iN1 apos);iN1 apos==bpos?cG1:bpos);}while(0) +#define DUP_ONE(p) do{FPO(iC3(iG3,"-> " iO3"op\n",(unsigned)p));iN1 p);}while(0) +if(a_needed>0){if(xU3>0){nM2} +cJ3 +bpos!=cG1)nM2 +else{x02 +e41} +} +iP1 +xU3>0){if(apos!=cG1)nM2 +else +DUP_ONE(bpos);} +cJ3 +apos==bpos&&apos==cG1)x02;iP1 +apos==cG1&&bpos==xV3 +2){FPO(iC3(iG3,"-> op\n"))e41 +iP1 +apos==xV3 +2&&bpos==cG1)FPO(iC3(iG3,"-> op\n"));iP1 +apos==cG1)DUP_ONE(bpos);iP1 +bpos==cG1){x02 +e41 +else +nM2} +yB1 +flipped?cumulation_opcode_flip:cumulation_opcode,2);} +xL1 +cH1 +long +count,cG&eQ,xI1{while +cW3<256){int +xR3 +xK1::powi_table[count]xZ3&128){half&=127;cH1 +half +e63 +count/=half;} +else +xY3 +if +cW3==1)return;if(!cW3&1)){yB1 +cSqr,1);cH1 +count/2 +e63} +else{iN1 +cG1);cH1 +count-1 +e63 +yB1 +cMul,2);} +} +} +l33 +xK1{xL1 +x01 +long +count,cG&eQ,xI1{if +cW3==0)t71 +eQ.basevalue);else{bool +t22 +eW3 +if +cW3<0){t22=true;count=-count;} +if(false)cH1 +count +e63 +iP1 +count>1){PowiCache +iM;lB1 +count,iM,1);size_t +xO1=synth.GetStackTop();iM.Start(cG1);FPO(iC3(iG3,"Calculating result for %ld...\n",count));size_t +xN2=y6 +count +cE1 +size_t +n_excess=xV3 +xO1;if(n_excess>0||xN2!=xO1-1){synth.DoPopNMov(xO1-1,xN2);} +} +if(t22)yB1 +eQ.op_flip,1);} +} +} +#endif +#ifndef FPOptimizer_ValueRangeHH +#define FPOptimizer_ValueRangeHH +t5{l33 +l73{l01 +e72 +Comp{} +;tP1>e72 +Comp<nB +cLess>l83<nA +cLessOrEq>l83<=nA +cGreater>l83>nA +cGreaterOrEq>l83>=nA +cEqual>l83==nA +i51>l83!=b;} +} +;} +tK1 +e72 +cI1 +l14 +val;bool +known;cI1():val(),known(false){} +cI1(tV1):val(v),known(true){y81 +l93 +tV1){known=true;val=v;} +l93 +xW3 +Value_t),cI1 +y7)val=iE2 +l93 +xW3 +const +Value_t&),cI1 +y7)val=iE2 +l01 +void +set_if +cX3 +v,xW3 +Value_t),cI1 +y7&&l73::Comp<Compare>()(val,v))val=iE2 +l01 +void +set_if(tV1,xW3 +const +Value_t&),cI1 +y7&&l73::Comp<Compare>()(val,v))val=iE2} +yO1 +e72 +range{cI1 +xF +min,max;range():min(),max(){} +range +cX3 +mi,Value_t +ma):min(mi),max(ma){} +range(bool,Value_t +ma):min(),max(ma){} +range +cX3 +mi,bool):min(mi),max(){} +void +set_abs();void +set_neg();} +yO1 +bool +IsLogicalTrueValue +iS1 +yD3&p,bool +abs)yO1 +bool +IsLogicalFalseValue +iS1 +yD3&p,bool +abs);} +#endif +#ifndef FPOptimizer_RangeEstimationHH +#define FPOptimizer_RangeEstimationHH +t5{enum +TriTruthValue{iF2,xX3,Unknown} +yO1 +yD3 +CalculateResultBoundaries +iS1 +eR +yO1 +bool +IsLogicalValue +iS1 +eR +yO1 +TriTruthValue +GetIntegerInfo +iS1 +eR +yO1 +xP1 +GetEvennessInfo +iS1 +eR{if(!tree +tD1)return +Unknown;yL1=tree +x41;if(nB +isEvenInteger(value +y13 +nB +isOddInteger(value +y23 +tK1 +xP1 +GetPositivityInfo +iS1 +eR{yD3 +p=CalculateResultBoundaries(tree);if(p +yI&&p +yM>=e62 +y13 +p +e61 +l61 +y23 +tK1 +xP1 +GetLogicalValue +iS1 +nP1 +bool +abs){yD3 +p=CalculateResultBoundaries(tree);if(IsLogicalTrueValue(p,abs +y13 +IsLogicalFalseValue(p,abs +y23} +#endif +#ifndef FPOptimizer_ConstantFoldingHH +#define FPOptimizer_ConstantFoldingHH +t5{xL1 +ConstantFolding(eR;} +#endif +l33{using +l33 +FUNCTIONPARSERTYPES;using +t5;e72 +ComparisonSetBase{enum{eB3=0x1,Eq_Mask=0x2,Le_Mask=0x3,eC3=0x4,eD3=0x5,Ge_Mask=0x6} +;static +int +Swap_Mask(int +m)yP(m&Eq_Mask)|((m&eB3)?eC3:0)|((m&eC3)?eB3:0);} +enum +c31{Ok,BecomeZero,BecomeOne,n91} +;enum +x12{cond_or,iG2,iH2,iI2} +;} +yO1 +e72 +ComparisonSet:public +ComparisonSetBase{e72 +t32{yZ2 +a +tX +b;int +relationship;t32():a(),b(),relationship(){} +} +;eO3 +t32>tH;e72 +Item{yZ2 +value;bool +cA2;Item():value(),cA2(false){} +} +;eO3 +Item>cJ1;int +xQ1;ComparisonSet():tH(),cJ1(),xQ1(0){} +c31 +AddItem +iR1 +a,bool +cA2,x12 +type){for +iZ1 +c=0;c<cJ1 +eJ3;++c)if(cJ1[c].value +xI +a)){if(cA2!=cJ1[c].cA2){l11 +cU1 +case +iI2:cJ1.erase(cJ1.begin()+c);xQ1 +cB2 +case +iG2:case +iH2:cW1} +eE3 +n91;} +Item +pole;pole.value=a;pole.cA2=cA2;cJ1 +c52 +pole)i1 +Ok;} +c31 +AddRelationship(yZ2 +a,yZ2 +b,int +tY1,x12 +type){l11 +if(tY1==7)cU1 +lC +iI2:if(tY1==7){xQ1 +cB2} +lC +iG2:case +iH2:if(tY1==0)cW1 +xY3 +if(!(a.GetHash()<b.GetHash())){a.swap(b);tY1=Swap_Mask(tY1);} +for +iZ1 +c=0;c<tH +eJ3;++c){if(tH[c].a +xI +a)&&tH[c].b +xI +b)){l11{int +y33=xQ2|tY1;if(y33==7)cU1 +xQ2=y33;xY3 +case +iG2:case +iH2:{int +y33=xQ2&tY1;if(y33==0)cW1 +xQ2=y33;xY3 +case +iI2:{int +newrel_or=xQ2|tY1;int +xR2=xQ2&tY1;lQ2 +5&&xR2==0){xQ2=eD3 +i1 +n91;} +lQ2 +7&&xR2==0){xQ1+=1;tH.erase(tH.begin()+c)i1 +n91;} +lQ2 +7&&xR2==Eq_Mask){xQ2=Eq_Mask;xQ1 +cB2} +yA1} +eE3 +n91;} +} +t32 +comp;comp.a=a;comp.b=b;comp.relationship=tY1;tH +c52 +comp)i1 +Ok;} +} +;nN1 +Value_t,x93 +CondType>bool +ConstantFolding_LogicCommon(nP1 +CondType +xF1,bool +xS2){bool +should_regenerate +eW3 +ComparisonSet +xF +comp;x51{x93 +c8 +c31 +cY3=c8 +Ok;iT1&atree=xW +a);e23 +atree +nC){case +cEqual +lG +Eq_Mask +e12 +i51 +lG +eD3 +e12 +cLess +lG +eB3 +e12 +cLessOrEq +lG +Le_Mask +e12 +cGreater +lG +eC3 +e12 +cGreaterOrEq +lG +Ge_Mask +e12 +cNot:cY3 +cV1 +l8 +0),true +e12 +cNotNot:cY3 +cV1 +l8 +0),false,xF1);break;yF3 +if(xS2||IsLogicalValue(atree))cY3 +cV1,false,xF1);c73(cY3){ReplaceTreeWithZero:nU +0)i1 +true;ReplaceTreeWithOne:nU +1);nZ +c8 +Ok:lC +c8 +BecomeZero +t7 +c8 +BecomeOne:iD +c8 +n91:c61 +xY3} +if(should_regenerate){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Before ConstantFolding_LogicCommon: " +cR +#endif +if(xS2){tree.DelParams();} +else{for +l41{iT1&atree=xW +a);if(IsLogicalValue(atree))iZ);} +} +for +iZ1 +a=0;a<comp.cJ1 +eJ3;++a){if(comp.cJ1[a].cA2 +lA3 +cNot);r.c7 +r.lR2 +iP1!xS2 +lA3 +cNotNot);r.c7 +r.lR2 +else +tree.c7} +for +iZ1 +a=0;a<comp.tH +eJ3;++a +lA3 +cNop);e23 +comp.tH[a +eE){case +c8 +eB3:r +iH +cLess);lC +c8 +Eq_Mask:r +iH +cEqual);lC +c8 +eC3:r +iH +cGreater);lC +c8 +Le_Mask:r +iH +cLessOrEq);lC +c8 +eD3:r +iH +i51);lC +c8 +Ge_Mask:r +iH +cGreaterOrEq +e02 +r +c91 +comp.tH[a].a);r +c91 +comp.tH[a].b);r.lR2 +if(comp.xQ1!=0)tree.yA +e62 +comp.xQ1))); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"After ConstantFolding_LogicCommon: " +cR +#endif +lD2 +eE3 +t23 +yP1 +ConstantFolding_AndLogic(iM3(tree.GetOpcode()==cAnd||tree.GetOpcode()==cAbsAnd)i1 +nI +iG2,true);} +yP1 +ConstantFolding_OrLogic(iM3(tree.GetOpcode()==cOr||tree.GetOpcode()==cAbsOr)i1 +nI +cond_or,true);} +yP1 +ConstantFolding_AddLogicItems(iM3(tree.GetOpcode()==cAdd)i1 +nI +iI2,false);} +yP1 +ConstantFolding_MulLogicItems(iM3(tree.GetOpcode()==cMul)i1 +nI +iH2,false);} +} +#include <vector> +#include <map> +#include <algorithm> +l33{using +l33 +FUNCTIONPARSERTYPES;using +t5;e72 +CollectionSetBase{enum +xR1{Ok,n91} +;} +yO1 +e72 +CollectionSet:public +CollectionSetBase{e72 +c41{yZ2 +value +tX +xT2;bool +e0;c41():value(),xT2(),e0(false){} +c41 +iR1 +v,iT1&f):value(v),xT2(f),e0(false){} +} +;std::multimap<fphash_t,c41>iN;typedef +x93 +std::multimap<fphash_t,c41>::y83 +xS1;CollectionSet():iN(){} +xS1 +FindIdenticalValueTo +iR1 +value){fphash_t +hash=value.GetHash();for(xS1 +i=iN.xU2 +hash);i!=iN.cX1 +hash;++i){cD1 +xI +i +eC2.value +y03 +i;eE3 +iN.end();} +bool +Found +iS1 +xS1&b)yP +b!=iN.end();} +xR1 +AddCollectionTo +iR1 +xT2,const +xS1&into_which){c41&c=into_which +eC2;if(c.e0)c.xT2 +cS +xT2);else{yZ2 +add;add +iH +cAdd);add +c91 +c.xT2);add +cS +xT2);c.xT2.swap(add);c.e0=true;eE3 +n91;} +xR1 +x22 +iR1 +value,iT1&xT2){const +fphash_t +hash=value.GetHash();xS1 +i=iN.xU2 +hash);for(;i!=iN.cX1 +hash;++i){if(i +eC2.value +xI +value +y03 +AddCollectionTo(xT2,i);} +iN.y43,std::make_pair(hash,c41(value,xT2)))i1 +Ok;} +xR1 +x22 +iR1 +a)yP +x22(a,nA1 +1)));} +} +yO1 +e72 +ConstantExponentCollection{typedef +eK +y63;typedef +std::x71 +xV2;eO3 +xV2>data;ConstantExponentCollection():data(){} +void +MoveToSet_Unique +iS1 +Value_t&eP1&eQ1){data +c52 +std::x71(eP1()));data.back().second.swap(eQ1 +cN2 +MoveToSet_NonUnique +iS1 +Value_t&eP1&eQ1){x93 +eO3 +xV2>::y83 +i=std::xU2 +data.iJ2 +data.end(),exponent,Compare1st());if(i!=data.cX1 +exponent){i +eC2.y43 +eC2.end(),eQ1.iJ2 +eQ1.end());} +else{data.y43,std::x71(exponent,eQ1));} +} +bool +iA2{bool +changed +eW3 +std::sort(data.iJ2 +data.end(),Compare1st());redo:for +iZ1 +a=0;a +eR3 +a)l14 +exp_a=data[a +eH3;lG3 +exp_a,e62 +1)))yA1 +for +iZ1 +b=a+1;b +eR3 +b)l14 +exp_b=data[b +eH3 +iK2 +xW2=exp_b-exp_a;if(xW2>=fp_abs(exp_a))break +iK2 +exp_diff_still_probable_integer=xW2*e62 +16);if(t42 +exp_diff_still_probable_integer)&&!(t42 +exp_b)&&!t42 +xW2))){y63&a_set=lS2;y63&b_set=data[b +eI3; +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Before ConstantExponentCollection iteration:\n" +;Dump(cV2); +#endif +if(isEvenInteger(exp_b)&&!isEvenInteger(xW2+exp_a)nQ +tmp2;tmp2 +iH +cMul);tmp2 +iF1 +b_set);tmp2 +iW1 +tX +tmp;tmp +iH +cAbs);tmp +c91 +tmp2);tmp +iW1;b_set +xF3 +1);b_set[0 +tQ3 +tmp);} +a_set.insert(a_set.end(),b_set.iJ2 +b_set.end());y63 +b_copy=b_set;data.erase(data.begin()+b);MoveToSet_NonUnique(xW2,b_copy);yS1 +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"After ConstantExponentCollection iteration:\n" +;Dump(cV2); +#endif +cJ} +} +eE3 +changed;} +#ifdef DEBUG_SUBSTITUTIONS +void +Dump(std::ostream&out){for +iZ1 +a=0;a +eR3 +a){out.precision(12);out<<data[a +eH3<<": " +;e11 +lS2 +eJ3;++b){if(b>0)out<<'*' +iL2 +lS2[b],out);} +out<<std::endl;} +} +#endif +} +yO1 +static +yZ2 +x81 +yZ2&value,bool&xK +yY3 +value +nC){case +cPow:{yZ2 +eD2 +value +l8 +1);value.y91 +i1 +exponent;} +case +cRSqrt:value.y91;xK=true +i1 +nA1-0.5))t83 +cInv:value.y91;xK=true +i1 +nA1-1));yF3 +xY3 +return +nA1 +1));} +cB1 +void +eR1 +eS1&mul,const +nP1 +iT1&xT2,bool&c51 +bool&xK){for +iZ1 +a=0;a<yC++a +nQ +value(xW +a))tX +exponent(x81 +value,xK));if(!xT2 +tD1||xT2 +x41!=e62 +1.0)nQ +cY1;cY1 +iH +cMul);cY1 +cS +tU2 +cY1 +cS +xT2);cY1 +iW1 +eX3.swap(cY1);} +#if 0 /* FIXME: This does not work */ +cD1 +nC==cMul){if(1){bool +exponent_is_even=exponent +tD1&&isEvenInteger(exponent +x41);e11 +value.eZ3{bool +tmp=false +tX +val(value +l8 +b))tX +exp(x81 +val,tmp));if(exponent_is_even||(exp +tD1&&isEvenInteger(exp +x41))nQ +cY1;cY1 +iH +cMul);cY1 +cS +tU2 +cY1 +c91 +exp);cY1.ConstantFolding();if(!cY1 +tD1||!isEvenInteger(cY1 +x41)){goto +cannot_adopt_mul;} +} +} +} +eR1 +mul,value,exponent,c51 +xK);} +else +cannot_adopt_mul: +#endif +{if(mul.x22(value,exponent)==CollectionSetBase::n91)c61} +} +} +yP1 +ConstantFolding_MulGrouping(eR{bool +xK +eW3 +bool +should_regenerate +eW3 +eS1 +mul;eR1 +mul +cU3,nA1 +1)),c51 +xK);typedef +std::pair<yZ2,eK>eT1;typedef +std::multimap<fphash_t,eT1>cK1;cK1 +iJ;for(x93 +eS1::xS1 +j=mul.iN.y73 +j!=mul.iN.end();++j +nQ&value=j +eC2.value +tX&eD2 +j +eC2.xT2;if(j +eC2.e0)exponent +iW1;const +fphash_t +eU1=exponent.GetHash();x93 +cK1::y83 +i=iJ.xU2 +eU1);for(;i!=iJ.cX1 +eU1;++i)if(i +eC2.first +xI +exponent)){if(!exponent +tD1||!cZ1 +x41,e62 +1)))c61 +i +eC2.second +c52 +value);goto +skip_b;} +iJ.y43,std::make_pair(eU1,std::make_pair(exponent,eK +iZ1(1),value))));skip_b:;} +#ifdef FP_MUL_COMBINE_EXPONENTS +ConstantExponentCollection +xF +e01;for(x93 +cK1::y83 +j,i=iJ.y73 +i!=iJ.end();i=j){j=i;++j;eT1&list=i +eC2;x32.lV1 +eD2 +list.first +x41;if(!(exponent==xG1)e01.MoveToSet_Unique(exponent,list +iB2 +iJ.erase(i);} +} +if(e01.iA2)c61 +#endif +if(should_regenerate +nQ +before=tree;before.lD1 +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Before ConstantFolding_MulGrouping: " +iL2 +before +lE2"\n" +; +#endif +tree.DelParams();for(x93 +cK1::y83 +i=iJ.y73 +i!=iJ.end();++i){eT1&list=i +eC2; +#ifndef FP_MUL_COMBINE_EXPONENTS +x32.lV1 +eD2 +list.first +x41;if(exponent==xG1 +yA1 +if(cZ1 +nH2 +tree.AddParamsMove(list +iB2 +yA1} +} +#endif +yZ2 +mul;mul +iH +cMul);mul +iF1 +list +iB2 +mul +iW1;if(xK&&list.first +tD1){x32 +x41==e62 +1)/e62 +3)nQ +cbrt;cbrt +iH +cCbrt);cbrt.e8 +cbrt.lT2 +cbrt);yA1 +cV +0.5)nQ +sqrt;sqrt +iH +cSqrt);sqrt.e8 +sqrt.lT2 +sqrt);yA1 +cV-0.5)nQ +rsqrt;rsqrt +iH +cRSqrt);rsqrt.e8 +rsqrt.lT2 +rsqrt);yA1 +cV-1)nQ +inv;inv +iH +cInv);inv.e8 +inv.lT2 +inv);yA1} +} +yZ2 +pow;pow +iH +cPow);pow.e8 +pow +c91 +list.first);pow.lT2 +pow);} +#ifdef FP_MUL_COMBINE_EXPONENTS +iJ.clear(iY1 +0;a<iB +eJ3;++a)l14 +eD2 +iB[a +eH3;if(cZ1 +nH2 +tree.AddParamsMove(iB[a]iB2 +yA1} +yZ2 +mul;mul +iH +cMul);mul +iF1 +iB[a]iB2 +mul +iW1 +tX +pow;pow +iH +cPow);pow.e8 +pow.yA +exponent));pow.lT2 +pow);} +#endif +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"After ConstantFolding_MulGrouping: " +cR +#endif +return!tree +xI +before);eE3 +t23 +yP1 +ConstantFolding_AddGrouping(eR{bool +should_regenerate +eW3 +eS1 +add;x51{if(xW +a)nC==cMul)yA1 +if(add.x22(xW +a))==CollectionSetBase::n91)c61} +cY2 +lU2 +l51);size_t +tD=0;x51{iT1&mulgroup=xW +a);if +eH2 +nC==cMul){e11 +cA1 +eZ3{if +eH2 +l8 +b)tD1)yA1 +x93 +eS1::xS1 +c=add.FindIdenticalValueTo +eH2 +l8 +b));if(add.Found(c)nQ +tmp +eH2 +y8 +CloneTag());tmp.i91 +b);tmp +iW1;add.AddCollectionTo(tmp,c);c61 +goto +done_a;} +} +lU2[a]=true;tD+=1;done_a:;} +} +if(tD>0){if(tD>1){eO3 +std::pair<yZ2,size_t> >nY;std::multimap<fphash_t,size_t>eV1;bool +lB3 +eW3 +x51 +if(lU2[a]){e11 +xW +a).eZ3{iT1&p=xW +a)l8 +b);const +fphash_t +p_hash=p.GetHash();for(std::multimap<fphash_t,size_t>::const_iterator +i=eV1.xU2 +p_hash);i!=eV1.cX1 +p_hash;++i){if(nY[i +eC2 +eH3 +xI +p)){nY[i +eC2 +eI3+=1;lB3=true;goto +found_mulgroup_item_dup;} +} +nY +c52 +std::make_pair(p,size_t(1)));eV1.insert(std::make_pair(p_hash,nY +eJ3-1));found_mulgroup_item_dup:;} +} +if(lB3 +nQ +eE2;{size_t +max=0 +eK3 +p=0;p<nY +eJ3;++p)if(nY[p +eI3<=1)nY[p +eI3=0;else{nY[p +eI3*=nY[p +eH3 +nP2;if(nY[p +eI3>max){eE2=nY[p +eH3;max=nY[p +eI3;} +} +} +yZ2 +group_add;group_add +iH +cAdd); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Duplicate across some trees: " +iL2 +eE2 +lE2" in " +cR +#endif +x51 +if(lU2[a])e11 +xW +a).eZ3 +if(eE2 +xI +xW +a)l8 +b))nQ +tmp(xW +a)y8 +CloneTag());tmp.i91 +b);tmp +iW1;group_add +c91 +tmp);lU2[a]eW3 +xY3 +group_add +iW1 +tX +group;group +iH +cMul);group +c91 +eE2);group +c91 +group_add);group +iW1;add.x22(group);c61} +} +x51 +if(lU2[a]){if(add.x22(xW +a))==CollectionSetBase::n91)c61} +} +if(should_regenerate){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Before ConstantFolding_AddGrouping: " +cR +#endif +tree.DelParams();for(x93 +eS1::xS1 +j=add.iN.y73 +j!=add.iN.end();++j +nQ&value=j +eC2.value +tX&coeff=j +eC2.xT2;if(j +eC2.e0)coeff +iW1;if(coeff +tD1){lG3 +coeff +x41,xG1)yA1 +lG3 +coeff +x41 +nH2 +tree +c91 +value);yA1} +} +yZ2 +mul;mul +iH +cMul);mul +c91 +value);mul +c91 +coeff);mul.e33 +yB +e8} +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"After ConstantFolding_AddGrouping: " +cR +#endif +lD2 +eE3 +t23} +l33{using +l33 +FUNCTIONPARSERTYPES;using +t5 +yO1 +bool +ConstantFolding_IfOperations(iM3(tree.GetOpcode()==cIf||tree.GetOpcode()==cAbsIf);for(;;){if(c93==cNot){tD2 +cIf);xW +0).eF2 +0)c43 +xW +1).swap(xW +2));} +iP1 +xW +0)cQ1{tD2 +t03;xW +0).eF2 +0)c43 +xW +1).swap(xW +2));} +else +yV3 +lY1 +0),t72==t03 +tN1 +tree.eF2 +1));nZ +l03 +tree.eF2 +2));nZ +lZ1 +if(c93==cIf||c93==cAbsIf +nQ +cond=xW +0)tX +lC3;lC3 +tE2==cIf?cNotNot:cAbsNotNot);lC3 +xX2 +1));ConstantFolding(lC3)tX +lD3;lD3 +tE2==cIf?cNotNot:cAbsNotNot);lD3 +xX2 +2));ConstantFolding(lD3);if(lC3 +tD1||lD3 +tD1 +nQ +eT;eT +tE2);eT +xX2 +1));eT +tX3 +eT.nJ +2));eT +iW1 +tX +else_tree +tS1 +tE2)tS1 +xX2 +2))tS1.nJ +1))tS1.nJ +2))tS1 +cY +cond +nC +xT1 +0,cond +l8 +0)yB +nB1 +1,eT +yB +nB1 +2,else_tree +yQ2} +if(xW +1)nC==xW +2)nC&&(xW +1)nC==cIf||xW +1)nC==t03 +nQ&x53=xW +1)tX&leaf2=xW +2);if(x53 +l8 +0)nN2 +0))&&x61 +1))||x53 +l8 +2)nN2 +2)))nQ +eT;eT +nO2;eT +tY3 +eT +xY2 +1));eT +xZ2 +1));eT +iW1 +tX +else_tree +tS1 +nO2 +tS1.nJ +0))tS1 +xY2 +2))tS1 +xZ2 +2))tS1 +cY +x53 +nC +xT1 +0 +cB3 +0)yB +nB1 +1,eT +yB +nB1 +2,else_tree +yQ2 +if +x61 +1))&&x53 +l8 +2)nN2 +2))nQ +eU;eU +nO2;eU +c91 +xW +0));eU +xY2 +0));eU +xZ2 +0));eU +cY +x53 +nC +yB +nB1 +0,eU +xT1 +2 +cB3 +2)xT1 +1 +cB3 +1)yQ2 +if +x61 +2))&&x53 +l8 +2)nN2 +1))nQ +eI2;eI2 +iH +leaf2 +nC==cIf?cNot:cC3);eI2 +xZ2 +0));eI2 +iW1 +tX +eU;eU +nO2;eU +c91 +xW +0));eU +xY2 +0));eU +c91 +eI2);eU +cY +x53 +nC +yB +nB1 +0,eU +xT1 +2 +cB3 +2)xT1 +1 +cB3 +1)yQ2} +yZ2&xV=xW +1)tX&y4=xW +2);if(xV +xI +y4)){tree.eF2 +1)yQ2 +const +OPCODE +op1=xV +nC;const +OPCODE +op2=y4 +nC;y93 +op2){if(xV.e91 +1 +nQ +lO +0));y02 +0))c71()n4 +if(xV.e91 +2&&y4.e91 +2){if(xV +l8 +0)xI +y4 +l8 +0))nQ +param0=xV +l8 +0)tX +lO +1));y02 +1))c71 +t8 +param0)n4 +if(xV +l8 +1)xI +y4 +l8 +1))nQ +param1=xV +l8 +1)tX +lO +0));y02 +0))c71 +t8 +n81 +c81 +param1 +yQ2} +y93 +yA3 +cMul +lV2 +cAnd +lV2 +cOr +lV2 +cAbsAnd +lV2 +cAbsOr +lV2 +cMin +lV2 +cMax){eK +lE3;c2{for +iZ1 +b=y4.l91 +b-->0;){if(xV +lF3 +y4 +l8 +b))){if(lE3 +eU3){xV.t13 +lD1} +lE3 +c52 +xV +n93 +y4.i91 +b);xV.i91 +a +e02} +} +if(!lE3 +eU3){xV +iW1;y4 +iW1 +l7 +op1 +yB +SetParamsMove(lE3)n4} +} +y93 +yA3 +cMul||(op1==cAnd&&IsLogicalValue(y4))||(op1==cOr&&IsLogicalValue(y4))){c2 +if(xV +lF3 +y4)){xV.lD1 +xV.i91 +a);xV +iW1 +tX +cL1=y4;y4=tE +op1==yA3 +cOr +t52 +op1 +c81 +cL1)n4} +if((op1==cAnd +lV2 +cOr)&&op2==cNotNot +nQ&lH3=y4 +l8 +0);c2 +if(xV +lF3 +lH3)){xV.lD1 +xV.i91 +a);xV +iW1 +tX +cL1=lH3;y4=tE +op1==cOr +t52 +op1 +c81 +cL1)n4} +if(op2==cAdd||op2==cMul||(op2==cAnd&&IsLogicalValue(xV))||(op2==cOr&&IsLogicalValue(xV))){for +iZ1 +a=y4 +iY +y4 +lF3 +xV)){y4.t13 +i91 +a);y4 +iW1 +tX +cM1=xV;xV=tE +op2==cAdd||op2==cOr +t52 +op2 +c81 +cM1)n4} +if((op2==cAnd||op2==cOr)&&op1==cNotNot +nQ&lI3=xV +l8 +0 +iY1 +y4 +iY +y4 +lF3 +lI3)){y4.t13 +i91 +a);y4 +iW1 +tX +cM1=lI3;xV=tE +op2==cOr +t52 +op2 +c81 +cM1)n4 +eE3 +t23} +#include <limits> +l33{using +l33 +FUNCTIONPARSERTYPES;using +t5 +yO1 +int +maxFPExponent()yP +std::numeric_limits +xF::max_exponent;} +yP1 +x91 +Value_t +base,Value_t +exponent){if(base<xG1 +lD2 +lG3 +base,xG1||lJ3 +base,e62 +1))cQ +return +exponent>=e62 +maxFPExponent +xF())/fp_log2(base);} +yP1 +ConstantFolding_PowOperations(iM3(tree.GetOpcode()==cPow);nP&&xW +1).lV1 +const_value=t33 +lR,xW +i8);nU +const_value)i1 +t23 +if(eI1 +lJ3 +xW +i8 +nH2 +tree.eF2 +0)yQ2 +nP&&lJ3 +lR +nH2 +nU +1)i1 +t23 +nP&&xW +1)nC==cMul){bool +y12=false +iK2 +lW2=lR +tX +mulgroup=xW +1 +iY1 +mulgroup +iY +mulgroup +l8 +a).lV1 +imm=mulgroup +l8 +a)x41;{if(x91 +lW2,imm))break +iK2 +lX2=t33 +lW2,imm);lG3 +lX2,xG1)break;if(!y12){y12=true;cA1 +lD1} +lW2=lX2;cA1 +i91 +a +e02} +if(y12){cA1 +e33); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Before pow-mul change: " +cR +#endif +xW +0).Become(eA1 +lW2));xW +1).Become +eH2); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"After pow-mul change: " +cR +#endif +} +} +if(eI1 +c93==cMul)l14 +lY2=xW +i8 +iK2 +y22=1.0;bool +y12=false +tX&mulgroup=xW +0 +iY1 +mulgroup +iY +mulgroup +l8 +a).lV1 +imm=mulgroup +l8 +a)x41;{if(x91 +imm,lY2))break +iK2 +eW1=t33 +imm,lY2);lG3 +eW1,xG1)break;if(!y12){y12=true;cA1 +lD1} +y22*=eW1;cA1 +i91 +a +e02} +if(y12){cA1 +e33)tX +cZ3;cZ3 +iH +cPow);cZ3 +iF1 +tree.lJ2));cZ3.yC2 +yB +eL3 +cMul +c81 +cZ3 +yB +AddParam(eA1 +y22)yQ2} +if(xW +0)i12 +eI1 +xW +0)l8 +1).lV1 +a=xW +0)l8 +i8 +iK2 +b=xW +i8 +iK2 +c=a*b;if(isEvenInteger(a)&&!isEvenInteger(c)nQ +lK3;lK3 +iH +cAbs);lK3.nJ +0)c43 +lK3.e33 +yB +nB1 +0,lK3);} +else +tree.SetParam(0,xW +0)l8 +0)xT1 +1,eA1 +c));eE3 +t23} +l33{using +l33 +FUNCTIONPARSERTYPES;using +t5;e72 +l5{enum +eJ2{MakeFalse=0,MakeTrue=1,t62=2,lN3=3,MakeNotNotP0=4,MakeNotNotP1=5,MakeNotP0=6,MakeNotP1=7,xJ=8} +;enum +lZ2{Never=0,Eq0=1,Eq1=2,yB3=3,yC3=4} +;eJ2 +if_identical;eJ2 +n02 +4];e72{eJ2 +what:4;lZ2 +when:4;} +l02,l12,l22,l32 +yO1 +eJ2 +Analyze +iR1 +xC3 +eX1)const{if(a +xI +b +y03 +if_identical;yD3 +tY +a);yD3 +p1=CalculateResultBoundaries(b);if(p0 +e61&&p1 +yI){if(p0 +nL3<p1 +yM&&n02 +0]iC +0];if(p0 +nL3<=p1 +yM&&n02 +1]iC +1];} +if +cN3 +p1 +e61){if(p0 +yM>p1 +nL3&&n02 +2]iC +2];if(p0 +yM>=p1 +nL3&&n02 +3]iC +3];} +if(IsLogicalValue(a)){if(l02 +nN3 +l02.when,p1 +y03 +l02.what;if(l22 +nN3 +l22.when,p1 +y03 +l22.what;} +if(IsLogicalValue(b)){if(l12 +nN3 +l12.when,p0 +y03 +l12.what;if(l32 +nN3 +l32.when,p0 +y03 +l32.what;eE3 +xJ;} +cB1 +bool +TestCase(lZ2 +when,const +yD3&p){if(!p +yI||!p +e61 +cQ +e23 +when){case +Eq0:nO3==e62 +0.0)t43==p +yM +t83 +Eq1:nO3==e62 +1.0)t43==p +nL3 +t83 +yB3:nO3>xH1 +t43<=e62 +1)t83 +yC3:nO3>=xH1 +l61 +1);yF3;eE3 +t23} +;l33 +RangeComparisonsData{static +const +l5 +Data[6]={{l5 +lL3 +i3 +xJ,l5::i3 +xJ +lF1 +Eq1 +nT1 +Eq1 +nU1 +Eq0 +nV1 +Eq0} +} +,{l5::x42 +lM3 +xJ,l5 +lM3 +xJ +lF1 +Eq0 +nT1 +Eq0 +nU1 +Eq1 +nV1 +Eq1} +} +,{l5::x42 +lM3 +t62,l5::i3 +MakeFalse +nU1 +yB3 +nT1 +yC3 +yY,{l5 +lL3 +xJ,l5 +lM3 +i3 +lN3 +nU1 +yC3 +nT1 +yB3 +yY,{l5::x42::i3 +i3 +MakeTrue,l5::t62 +lF1 +yC3 +nV1 +yB3 +yY,{l5 +lL3 +i3 +lN3,l5::xJ,l5 +nC1 +lF1 +yB3 +nV1 +yC3 +yY} +;} +yP1 +ConstantFolding_Comparison(eR{using +l33 +RangeComparisonsData;assert(tree.GetOpcode()>=cEqual&&tree.GetOpcode()<=cGreaterOrEq);e23 +Data[t72-cEqual].Analyze(xW +0),xW +1))){case +l5::MakeFalse:nU +0);nZ +l5 +nC1:nU +1 +nY3 +lN3:tD2 +cEqual +nY3 +t62:tD2 +i51 +nY3 +MakeNotNotP0:tD2 +cNotNot +yB +i91 +1 +nY3 +MakeNotNotP1:tD2 +cNotNot +yB +i91 +0 +nY3 +MakeNotP0:tD2 +cNot +yB +i91 +1 +nY3 +MakeNotP1:tD2 +cNot +yB +i91 +0 +nY3 +xJ:;} +if(xW +1)tD1)e23 +c93){case +cAsin:lM +fp_sin(xW +iP2 +cAcos:lM +fp_cos(xW +i8))yB +eL3 +t72==cLess?cGreater:t72==cLessOrEq?cGreaterOrEq:t72==cGreater?cLess:t72==cGreaterOrEq?cLessOrEq:t72);nZ +cAtan:lM +fp_tan(xW +iP2 +cLog:lM +fp_exp(xW +iP2 +cSinh:lM +fp_asinh(xW +iP2 +cTanh:if(fp_less(fp_abs(xW +i8)nH2 +lM +fp_atanh(xW +i8))yQ2 +break;yF3 +xY3 +return +t23} +#include <list> +#include <algorithm> +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES;l33{ +#ifdef DEBUG_SUBSTITUTIONS +yE +double +d){union{double +d;uint_least64_t +h +c42 +d=d;lR1 +h +nX1 +#ifdef FP_SUPPORT_FLOAT_TYPE +yE +float +f){union{float +f;uint_least32_t +h +c42 +f=f;lR1 +h +nX1 +#endif +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +yE +long +double +ld){union{long +double +ld;e72{uint_least64_t +a;x83 +short +b;} +s +c42 +ld=ld;lR1 +s.b<<data.s.a +nX1 +#endif +#ifdef FP_SUPPORT_LONG_INT_TYPE +yE +long +ld){o<<"(" +<<std::hex<<ld +nX1 +#endif +#endif +} +t5{lN +nE)){} +lN +const +Value_t&i +y8 +xD3 +nE +i +x52 +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +lN +Value_t&&i +y8 +xD3 +nE +tF2 +i)x52 +#endif +lN +x83 +v +y8 +VarTag +nE +iU2,v +x52 +lN +iU1 +o +y8 +OpcodeTag +nE +o +x52 +lN +iU1 +o,x83 +f +y8 +FuncOpcodeTag +nE +o,f +x52 +lN +const +eX1 +y8 +CloneTag +nE*b.data)){} +tK1 +yZ2::~c02(){} +lB +ReplaceWithImmed(tX1{ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Replacing " +iL2*this);if(IsImmed())OutFloatHex(cV2,GetImmed()lE2" with const value " +<<i;OutFloatHex(cV2,i +lE2"\n" +; +#endif +data=new +xK2 +xF(i);} +tK1 +e72 +ParamComparer{iD2()iR1 +xC3 +eX1)const{if(a +nP2!=b +nP2)return +a +nP2<b +nP2 +i1 +a.GetHash()<b.GetHash();} +} +;xL1 +xK2 +xF::Sort(yY3 +Opcode){case +cAdd:case +cMul:case +cMin:case +cMax:case +cAnd:case +cAbsAnd:case +cOr:case +cAbsOr:case +cHypot:case +cEqual:case +i51:std::sort(iR2 +iJ2 +iR2 +end(),ParamComparer +xF());lC +cLess +lY +cGreater;} +lC +cLessOrEq +lY +cGreaterOrEq;} +lC +cGreater +lY +cLess;} +lC +cGreaterOrEq +lY +cLessOrEq;} +break;yF3 +xY3} +lB +AddParam +iR1 +param){y1 +c52 +param);} +lB +AddParamMove(yZ2¶m){y1 +c52 +yZ2());y1.back().swap(param);} +lB +SetParam +iZ1 +which,const +eX1)nW1 +which +iQ2 +y1[which]=b;} +lB +nB1 +size_t +which,eX1)nW1 +which +iQ2 +y1[which +tQ3 +b);} +lB +AddParams +iS1 +nK){y1.insert(y1.end(),n12.iJ2 +n12.end());} +lB +AddParamsMove(nK){size_t +endpos=y1 +eJ3,added=n12 +eJ3;y1 +xF3 +endpos+added,yZ2())eK3 +p=0;p<added;++p)y1[endpos+p +tQ3 +n12[p]);} +lB +AddParamsMove(nK,size_t +n22)nW1 +n22 +iQ2 +i91 +n22);AddParamsMove(tO1} +lB +SetParams +iS1 +nK){eK +tmp(tO1 +y1.swap(tmp);} +lB +SetParamsMove(nK){y1.swap(tO1 +n12.clear();} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +lB +SetParams(eK&&n12){SetParamsMove(tO1} +#endif +lB +i91 +size_t +index){eK&Params=y1; +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +iR2 +erase(iR2 +begin()+index); +#else +t63 +index].data=0 +eK3 +p=index;p+1<iS2;++p)t63 +p].data.UnsafeSetP(&*t63 +p+1 +iQ2 +t63 +iS2-1].data.UnsafeSetP(0);iR2 +resize(iS2-1); +#endif +} +lB +DelParams(){y1.clear();} +yP1 +yZ2::IsIdenticalTo +iS1 +eX1)const{if(&*data==&*b.data)return +true +i1 +data->IsIdenticalTo(*b.data);} +yP1 +xK2 +xF::IsIdenticalTo +iS1 +xK2 +xF&b)const{if(Hash!=b.Hash +cQ +if(Opcode!=b.Opcode +cQ +e23 +Opcode){case +cImmed:return +lJ3 +Value,b.Value)t83 +iU2:return +lL2==b.lK2 +case +cFCall:case +cPCall:if(lL2!=b.lL2 +cQ +break;yF3 +xY3 +if(iS2!=b.iS2 +cQ +for +iZ1 +a=0;a<iS2;++a){if(!iT2 +xI +b.iT2)cQ} +lD2} +lB +Become +iS1 +eX1){if(&b!=this&&&*data!=&*b.data){DataP +tmp=b.data;lD1 +data.swap(tmp);} +} +lB +CopyOnWrite(){if(GetRefCount()>1)data=new +xK2 +xF(*data);} +tK1 +yZ2 +yZ2::GetUniqueRef(){if(GetRefCount()>1)return +yZ2(*this,CloneTag())i1*this;} +i4):yS +cNop +iR3),n8 +i4 +const +xK2&b):yS +b.Opcode +iR3 +b.Value),lL2(b.cO1,t53 +b.Params),Hash(b.Hash),Depth(b.Depth +eB1 +b.lM2){} +i4 +tX1:yS +cImmed +iR3 +i),n8 +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +i4 +xK2 +xF&&b):yS +b.Opcode +iR3 +tF2 +b.Value)),lL2(b.cO1,t53 +tF2 +b.Params)),Hash(b.Hash),Depth(b.Depth +eB1 +b.lM2){} +i4 +Value_t&&i):yS +cImmed +iR3 +tF2 +i)),n8 +#endif +i4 +iU1 +o):yS +o +iR3),n8 +i4 +iU1 +o,x83 +f):yS +o +iR3),lL2(f),t53),Hash(),Depth(1 +eB1 +0){} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +#include <sstream> +#include <string> +#include <map> +#include <set> +#include <iostream> +using +l33 +FUNCTIONPARSERTYPES; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +l33{xL1 +tZ1 +nO,std +c9&done,std::ostream&o){x51 +tZ1 +xW +a),done,o);std::ostringstream +buf +iL2 +tree,buf);done[nJ2].insert(buf.str());} +} +#endif +t5{ +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +xL1 +DumpHashes(cE){std +c9 +done;tZ1 +tree,done,o);for(std +c9::const_iterator +i=done.y73 +i!=done.end();++i){const +std::set<eM3>&flist=i +eC2;if(flist +eJ3!=1)o<<"ERROR - HASH COLLISION?\n" +;for(std::set<eM3>::const_iterator +j=flist.y73 +j!=flist.end();++j){o<<'['<<std::hex<<i->first.hash1<<','<<i->first.hash2<<']'<<std::dec;o<<": " +<<*j<<"\n" +;} +} +} +xL1 +DumpTree(cE){e32 +iF3;e23 +t72){case +cImmed:o<<tree +x41 +t73 +iU2:o<<"Var" +<<(tree.GetVar()-iU2)t73 +cAdd:iF3"+" +;lC +cMul:iF3"*" +;lC +cAnd:iF3"&" +;lC +cOr:iF3"|" +;lC +cPow:iF3"^" +;break;yF3 +iF3;o<<FP_GetOpcodeName(t72);cZ2 +cFCall||t72==cPCall)o<<':'<<tree.GetFuncNo();} +o<<'(';if +l51<=1&&sep2[1])o<<(sep2+1)<<' ';x51{if(a>0)o<<' ' +iL2 +xW +a),o);if(a+1<tree.GetParamCount())o<<sep2;} +o<<')';} +xL1 +DumpTreeWithIndent(cE,const +eM3&indent){o<<'['<<std::hex<<(void*)(&tree.lJ2))<<std::dec<<','<<tree.GetRefCount()<<']';o<<indent<<'_';e23 +t72){case +cImmed:o<<"cImmed " +<<tree +x41;o<<'\n' +t73 +iU2:o<<"VarBegin " +<<(tree.GetVar()-iU2);o<<'\n' +i1;yF3 +o<<FP_GetOpcodeName(t72);cZ2 +cFCall||t72==cPCall)o<<':'<<tree.GetFuncNo();o<<'\n';} +x51{eM3 +ind=indent +eK3 +p=0;p<ind +eJ3;p+=2)if(ind[p]=='\\')ind[p]=' ';ind+=(a+1<tree.GetParamCount())?" |" +:" \\" +;DumpTreeWithIndent(xW +a),o,ind);} +o<<std::flush;} +#endif +} +#endif +using +l33 +lA1;using +l33 +FUNCTIONPARSERTYPES; +#include <cctype> +l33 +lA1{x83 +ParamSpec_GetDepCode +iS1 +eA2&b +yY3 +b.first){case +ParamHolder:{cM*s=(cM*)b.second +i1 +s->depcode;} +case +SubFunction:{cN*s=(cN*)b.second +i1 +s->depcode;} +yF3 +xY3 +return +0;} +xL1 +DumpParam +iS1 +eA2&yA2 +std::ostream&o){static +const +char +ParamHolderNames[][2]={"%" +,"&" +,"x" +,"y" +,"z" +,"a" +,"b" +,"c" +} +;x83 +y32 +0;e23 +lX3.first){case +NumConstant:{const +ParamSpec_NumConstant +xF¶m=*iS1 +ParamSpec_NumConstant +xF*tF1;using +l33 +FUNCTIONPARSERTYPES;o.precision(12);o<<param.constvalue;xY3 +case +ParamHolder:{cM&yU3 +cM*tF1;o<<ParamHolderNames[param.index];y32 +param.constraints;xY3 +case +SubFunction:{cN&yU3 +cN*tF1;y32 +param.constraints;yF +GroupFunction){if +yZ3 +lG1==cNeg){o<<"-" +;n2} +iP1 +param.lG1==cInv){o<<"/" +;n2} +else{eM3 +opcode=FP_GetOpcodeName((iU1)param.lG1).substr(1 +iY1 +0;a<opcode +eJ3;++a)opcode[a]=(char)std::toupper(opcode[a]);o<<opcode<<"( " +;n2 +o<<" )" +;} +} +else{o<<'('<<FP_GetOpcodeName((iU1)param.lG1)<<' ';yF +PositionalParams)o<<'[';yF +SelectedParams)o<<'{';n2 +if +yZ3 +data.n1!=0)o<<" <" +<<iH3.n1<<'>';yF +PositionalParams)o<<"]" +;yF +SelectedParams)o<<"}" +;o<<')';} +xY3 +c73(ImmedConstraint_Value(constraints&ValueMask)){case +ValueMask:lC +Value_AnyNum:lC +x62:o<<"@E" +;lC +Value_OddInt:o<<"@O" +;lC +i11:o<<"@I" +;lC +Value_NonInteger:o<<"@F" +;lC +eY1:o<<"@L" +;yV3 +ImmedConstraint_Sign(constraints&SignMask)){case +SignMask:lC +Sign_AnySign:lC +nD1:o<<"@P" +;lC +eZ1:o<<"@N" +;yV3 +ImmedConstraint_Oneness(constraints&OnenessMask)){case +OnenessMask:lC +Oneness_Any:lC +Oneness_One:o<<"@1" +;lC +Oneness_NotOne:o<<"@M" +;yV3 +ImmedConstraint_Constness(constraints&ConstnessMask)){case +ConstnessMask:lC +i01:if(lX3.first==ParamHolder){cM&yU3 +cM*tF1;if +yZ3 +index<2)xY3 +o<<"@C" +;lC +Constness_NotConst:o<<"@V" +;lC +Oneness_Any:xY3} +xL1 +DumpParams +lT1 +paramlist,x83 +count,std::ostream&o){for +lT1 +a=0;a<count;++a){if(a>0)o<<' ';const +eA2¶m=ParamSpec_Extract +xF(paramlist,a);DumpParam +xF(param,o);x83 +depcode=ParamSpec_GetDepCode(param);if(depcode!=0)o<<"@D" +<<depcode;} +} +} +#include <algorithm> +using +l33 +lA1;using +l33 +FUNCTIONPARSERTYPES;l33{cM +plist_p[37]={{2,0,0x0} +nT +0,0x4} +nT +nD1,0x0} +nT +eZ1|Constness_NotConst,0x0} +nT +Sign_NoIdea,0x0} +nT +eY1,0x0} +,{3,Sign_NoIdea,0x0} +,{3,0,0x0} +,{3,eY1,0x0} +,{3,0,0x8} +,{3,Value_OddInt,0x0} +,{3,Value_NonInteger,0x0} +,{3,x62,0x0} +,{3,nD1,0x0} +,{0,eZ1|lV{0,lV{0,nD1|lV{0,x62|lV{0,i01,0x1} +,{0,i11|nD1|lV{0,i21 +i01,0x1} +,{0,i21 +lV{0,Oneness_One|lV{0,eY1|lV{1,lV{1,x62|lV{1,i21 +lV{1,i11|lV{1,nD1|lV{1,eZ1|lV{6,0,0x0} +,{4,0,0x0} +,{4,i11,0x0} +,{4,lV{4,0,0x16} +,{5,0,0x0} +,{5,lV} +yO1 +e72 +plist_n_container{static +const +ParamSpec_NumConstant +xF +plist_n[20];} +yO1 +const +ParamSpec_NumConstant +xF +plist_n_container +xF::plist_n[20]={{e62-2 +i5-1 +i5-0.5 +i5-0.25 +i5 +0 +tG2 +fp_const_deg_to_rad +xF(tG2 +fp_const_einv +xF(tG2 +fp_const_log10inv +xF(i5 +0.5 +tG2 +fp_const_log2 +xF(i5 +1 +tG2 +fp_const_log2inv +xF(i5 +2 +tG2 +fp_const_log10 +xF(tG2 +fp_const_e +xF(tG2 +fp_const_rad_to_deg +xF(tG2-fp_const_pihalf +xF(),xU1{xH1,xU1{fp_const_pihalf +xF(),xU1{fp_const_pi +xF(),xU1} +;cN +plist_s[517]={{{1,15,tH2 +398,tH2 +477,tH2 +15,cNeg,GroupFunction,0} +,i01,0x1 +lR3 +15,y42 +24,y42 +465,y42 +466,y42 +498,cInv,lT +2,327995 +x9 +l0 +2,48276 +x9 +l6 +260151 +x9 +l6 +470171 +x9 +l6 +169126 +x9 +l6 +48418 +x9 +l6 +1328 +x9 +l6 +283962 +x9 +l6 +169275 +x9 +l6 +39202 +x9 +l6 +283964 +x9 +l6 +283973 +x9 +l6 +476619 +x9 +l6 +296998 +x9 +l6 +47 +x9 +SelectedParams,0} +,0,0x4 +nH +161839 +x9 +l6 +25036 +x9 +l6 +35847 +x9 +l6 +60440 +x9 +l6 +30751 +x9 +l6 +270599 +x9 +l6 +60431 +x9 +l6 +259119 +x9 +l6 +183474 +x9 +l6 +332066 +x9 +l6 +7168 +x9 +l6 +197632 +x9 +l6 +291840 +x9 +l6 +283648 +x9 +l6 +238866 +x9 +l6 +239902 +x9 +l6 +31751 +x9 +l6 +244743 +x9 +l6 +384022 +x9 +SelectedParams,0} +,0,0x4 +nH +385262 +x9 +l6 +386086 +x9 +l6 +393254 +x9 +SelectedParams,0} +,0,0x5 +nH +393254 +x9 +l6 +386095 +x9 +l6 +387312 +x9 +l6 +18662 +x9 +l6 +61670 +x9 +l6 +387397 +x9 +l6 +247855 +x9 +SelectedParams,0} +,0,0x1 +nH +342063 +x9 +l6 +297007 +x9 +l6 +15820 +x9 +l6 +393263 +x9 +l6 +393263 +x9 +SelectedParams,0} +,0,0x5 +nH +161847 +x9 +l6 +258103 +x9 +l6 +249073 +x9 +l6 +249076 +x9 +iO +0,0 +x9 +nF +0,0 +i31 +1,45 +x9 +nF +1,53 +x9 +nF +1,54 +x9 +nF +1,55 +x9 +nF +1,56 +x9 +nF +1,26 +x9 +nF +1,259 +eK2 +0x16 +lR3 +253 +x9 +nF +1,272 +i31 +1,323 +eK2 +0x16 +lR3 +0 +x9 +nF +1,21 +x9 +nF +1,447 +eK2 +0x4 +lR3 +449 +eK2 +0x4 +lR3 +0 +eK2 +0x4 +lR3 +0 +tJ +2} +,0,0x4 +lR3 +15 +x9 +nF +1,24 +tJ +2} +,0,0x0 +nH +58392 +i31 +0,0 +tJ +1} +,nD1,0x0 +nH +24591 +lS3 +33807 +lS3 +48143 +lS3 +285720 +lS3 +290840 +lS3 +305152,l9 +312400,l9 +39202,l9 +121894,l9 +421926,l9 +429094,l9 +443430,l9 +317834,l9 +329098,l9 +7633,l9 +7706,l9 +7730,l9 +38,l9 +50587,l9 +406528,l9 +24583,l9 +31751,l9 +405511,l9 +321551 +iV2 +327713,l9 +322596,l9 +88361,l9 +335174,l9 +327050,l9 +493606,l9 +496678,l9 +503846,l9 +516134,l9 +7217,l9 +333875,l9 +336896,l9 +524326,l9 +509952,l9 +286727,l9 +90127,l9 +131087,l9 +296976,tQ1 +324623,l1 +0x14 +nH +332815,l1 +0x10} +,{{3,7340056,tQ1 +289092,l9 +92176 +iV2 +337935 +e31 +7340060 +lO3 +7340176,l9 +338959 +e31 +7340061 +iV2 +7206,l9 +x63 +l9 +357414,l9 +368678,l9 +370745,l1 +0x7} +,{{3,7340177,l9 +39277,tQ1 +426398 +lO3 +40272286 +iV2 +490910 +lO3 +40336798 +iV2 +50600,l9 +426462 +iV2 +490974 +iV2 +370726,l1 +0x6 +nH +371750,l1 +0x6 +nH +428070 +e31 +40336862 +iV2 +38378,l9 +50671 +e31 +47662080,l9 +477184,l9 +568320,l9 +371727,l1 +0x7} +,{{3,15779306,l9 +370703,l1 +0x7 +nH +39277,l9 +39279,l1 +0x4} +,{{3,15779238,l9 +39338,tQ1 +436262,l9 +508966,l9 +39409,tQ1 +296998,tQ1 +35847,l9 +15,tQ1 +377894,l9 +386063,l1 +0x1 +nH +15,l9 +7192,l9 +122904,l9 +121880,l9 +30751,l9 +57,l9 +7456,l9 +15674 +e31 +67579935,l9 +39237,l9 +58768,l9 +62924,l9 +121856,l9 +15760 +e31 +64009216,l1 +0x0} +,{{0,0,xL +0,0,iW +2,eC1 +2,eD1 +3,eC1 +3,eD1 +38,xL +1,38,iW +14,xL +1,57,xL +1,16,eL2 +0x0 +nH +471103,eL2 +0x1 +lR3 +303,xL +1,323,yH3 +0x0 +nH +471363,eL2 +0x16 +lR3 +293,eC1 +294,eD1 +295,xL +1,296,iW +400,xL +1,0,xL +1,460,xL +1,465,xL +1,16,eL2 +0x1 +lR3 +57,yH3 +0x1 +lR3 +0,iW +21,xL +1,15,eL2 +0x0 +nH +24591,xL +1,24,iW +517,yH3 +0x0 +nH +46095,lK +46104,lK +15397,lK +287789,lK +66584,lK +404763,lK +62504,lK +15409,lK +39951,lK +24591,lK +33807,lK +50200,lK +62509,lK +50176,lF,178176,t21 +tF3 +283648,lF,19456,lF,27648,lF,89088,lF,86016,lF,488448,lF,14342,lF,58375,lF,46147 +xX +46151,lF,284679,lF,7183,lF,46159 +xX +38993 +xX +50265,lF,50249,lF,283808,lF,284835,lF,24822,lF,10240,lF,11264,lF,7170,lF,x63 +lF,17408,lF,164864,lF,237568,lF,242688,t21 +0x14 +nH +476160,lF,25607,lF,121871,lF,50252,lF,39374,lF,50183,lF,7192,lF,121887,lF,252979,lF,46155,lF,38919,lF,50267,lF,50268,lF,50253,lF,46190,lF,50295,lF,7563,t21 +0x10 +nH +416811,lF,416819,lF,40046,lF,46191 +xX +415795,lF,40047 +xX +415787,lF,39015,t21 +0x5 +nH +39326 +xX +39326,lF,39332,t21 +0x5 +nH +39333 +cC2 +50590 +xX +50590,lF,39338 +xX +39338,lF,39335,t21 +0x5 +nH +15786 +xX +146858,lF,39372,lF,39379,lF,39380,lF,39390 +xX +50654 +xX +50654,lF,24,t21 +0x6 +nH +62,lF,24,lF,62,t21 +0x6 +nH +43,lF,43 +xX +51,lF,51 +xX +50269,lF,50176 +xX +50270,lF,39159,lF,39183 +xX +7168 +xX +31744,lF,99328,lF,31746,lF,100376,lF,39409 +xX +39411 +xX +39411,lF,39420,lF,39420 +xX +15,lF,39025,t21 +0x5 +nH +39422,lF,16384,lF,62853,lF,15360,lF,15 +cC2 +16,lF,7183 +cC2 +7172 +tW2 +y71,nD1,0x0 +nH +24591 +tW2 +lT +2,50200 +tW2 +lT +2,63521 +tW2 +lT +2,62500 +tW2 +lT +2,50453 +tW2 +lT +2,62488 +tW2 +lT +1,0,t93 +7,t93 +194,t93 +0,cAcos +tA3 +cAcosh +tA3 +cAsin +tA3 +cAsinh +nS +119,cAsinh +tA3 +cAtan +t11 +306176,cAtan2 +t11 +x63 +cAtan2 +tA3 +cAtanh +nS +246,cCeil +tA3 +cCeil +tB3 +0,cD2 +0,cCos +tB3 +7,cD2 +91,cD2 +92,cD2 +119,cD2 +236,cD2 +255,cD2 +214,iW2 +236,iW2 +464,iW2 +0,cCosh +tB3 +0,iW2 +0,cExp +nS +7,cExp +nS +91,cExp +tA3 +yI3 +7,yI3 +91,yI3 +246,cFloor +tA3 +cFloor,lA +0x4 +nH +309540,cHypot +t11 +316708,cHypot +t11 +316724,cHypot,l0 +3,32513024,eM2 +34627584 +iL +31493120,eM2 +89213952 +iL +149042176 +iL +246647808 +iL +301234176 +iL +494360576 +iL +498558976 +iL +62933520 +iL +62933520,eM2 +62933526 +iL +62933526,eM2 +24670208 +iL +579378176 +iL +573578240 +iL +32513024 +iL +566254592 +iL +7900160 +iL +588822528,cIf +nS +119,cInt +nS +246,tI2 +0,tI2 +7,tI2 +31,tI2 +194,tI2 +363,tI2 +15,cLog,lT +1,24,cLog,lT +1,0,cLog10 +tA3 +cLog2 +t11 +x63 +cMax +t11 +35847,cMax +t11 +30751,cMax +tA3 +cMax,AnyParams,1} +,0,0x4 +nH +x63 +cMin +t11 +35847,cMin +t11 +30751,cMin +tA3 +cMin,AnyParams,1} +,0,0x4 +nH +24591,cMin,lT +1,0,x72 +7,x72 +91,x72 +92,x72 +119,x72 +149,x72 +231,cSin,lA +0x5 +lR3 +246,x72 +255,x72 +254,x72 +0,cSin +tB3 +273,cSin,lA +0x1 +lR3 +214,y52 +231,tD3 +lA +0x5 +lR3 +246,y52 +254,y52 +255,y52 +464,y52 +0,cSinh +tB3 +0,y52 +15,cSqrt,lT +1,0,cTan +tA3 +cTan +tB3 +115,cTan +tB3 +116 +tC3 +231 +tC3 +246 +tC3 +273 +tC3 +254 +tC3 +255,cTan +tA3 +y62 +0,cTanh +tB3 +213,y62 +231,y62 +246,y62 +254,y62 +255,y62 +0,cTrunc +t11 +15384,cSub,lT +2,15384,cDiv,lT +2,476626,cDiv,lT +2,121913,tJ2 +x63 +lP3 +tF3 +x63 +tJ2 +31744,lP3 +0x20 +nH +31751,lP3 +0x24 +nH +31751,tJ2 +121913,i51 +t11 +x63 +cLess,lA +tF3 +41984,cLess,lA +0x4 +nH +41984,cLess +t11 +7,cLess +t11 +x63 +cLessOrEq +t11 +296182,cLessOrEq +t11 +7168 +tV2,lA +tF3 +41984 +tV2,lA +0x4 +nH +41984 +tV2 +t11 +7 +tV2 +t11 +x63 +y9 +l0 +2,296182,cGreaterOrEq +tA3 +n32 +245,n32 +7,n32 +550,n32 +553,n32 +554,n32 +556,n32 +31,n32 +559,n32 +15,n32 +560,cNot +t11 +7706,lT3 +x63 +lT3 +35847,lT3 +30751,lT3 +463903,lT3 +466975,cAnd,iO +0,0,cAnd,nF +2,x63 +e03 +7706,e03 +35847,e03 +463903,e03 +466975,e03 +30751,cOr,iO +1,0,n42 +91,n42 +131,n42 +245,n42 +215,n42 +246,cDeg +nS +246,cRad +t11 +x63 +cAbsAnd,l6 +x63 +cAbsOr,iO +1,0,cC3 +tA3 +cAbsNotNot,l0 +3,32513024,yT3 +lA +0x0} +,} +;} +l33 +lA1{const +Rule +grammar_rules[262]={{ProduceNewTree,17,1,0,{1,0,cAbs,eN2 +409,{1,146,cAtan,eN2 +403 +nT +1324,cAtan2,eN2 +405 +nT +307201,cAtan2 +eL +253174 +nT +255224,cAtan2 +eL +259324 +nT +257274,cAtan2,eN2 +152,{1,252,cCeil +i7 +486,{1,68 +yH2 +482,{1,122 +yH2 +483,{1,124 +yH2 +151,{1,125 +yH2 +419,{1,123 +yH2 +0,{1,403,cCos,l2 +2,1,246,{1,252,cCos,l2 +18,1,0,{1,400 +yH2 +301,{1,406,cCosh,l2 +2,1,246,{1,252,cCosh,l2 +18,1,0,{1,400,cCosh +i7 +458,{1,121,cFloor,eN2 +150,{1,252,cFloor,tG3 +156,{3,7382016,eF +549,{3,8430592,eF +556,{3,8436736,eF +157,{3,42998784,eF +550,{3,42999808,eF +562,{3,43039744,eF +557,{3,49291264,eF +538,{3,49325056,eF +469,{3,1058318,eF +473,{3,1058324,eF +473,{3,9438734,eF +469,{3,9438740,cIf,l2 +0,3,32542225,{3,36732434,cIf,l2 +0,3,32542231,{3,36732440,cIf,yR3 +573,{3,32513026,cIf,yR3 +515,{3,455505423,cIf,yR3 +515,{3,433506837,cIf +i7 +78,{1,256,cLog +i7 +69,{1,258,cLog +i7 +404,{1,72,cLog +i7 +159,{1,147,cLog,l2 +0,1,0 +nT +487425,cMax +l3 +16,1,445 +nT +yJ3 +cMax +l3 +0,1,0 +nT +483329,cMin +l3 +16,1,446 +nT +yJ3 +cMin,c3 +0,1,153 +nT +24832 +tW2 +tG3 +153 +nT +25854 +tW2 +tG3 +154 +nT +129039 +tW2 +xV1 +32055 +tW2 +xV1 +32056 +tW2 +xV1 +32057 +tW2 +l2 +0,2,166288 +nT +32137 +tW2 +xV1 +33082 +tW2 +l2 +0,2,7168 +nT +12688 +tW2 +l2 +0,2,7434 +nT +12553,tX2 +435 +nT +46146,tX2 +436 +nT +46154,tX2 +437 +nT +46150,tX2 +169 +nT +83983,tX2 +168 +nT +130082,tX2 +175 +nT +133154 +tW2 +tI3 +476160 +nT +471055 +tW2 +tI3 +274432 +nT +273423 +tW2 +tI3 +251904 +nT +266274 +tW2 +tI3 +251904 +nT +263186,tX2 +171,{1,252,cE2 +421,{1,68,cE2 +151,{1,122,cE2 +419,{1,124,cE2 +170,{1,125,cE2 +482,{1,123,cE2 +0,{1,405,cE2 +172,{1,252,cSinh +i7 +328,{1,404,cSinh +i7 +173,{1,252,tJ3 +0,{1,408,tJ3 +176,{1,410,tJ3 +177,{1,252,cTanh,l2 +0,1,442 +nT +449551,i6 +1,441 +nT +yJ3 +i6 +1,167 +nT +268549,i6 +1,181 +nT +276749,i6 +1,180 +nT +276500,i6 +2,190770 +nT +189622,i6 +2,194748 +nT +193723,i6 +2,202943 +nT +196795,i6 +2,59699 +nT +298148,i6 +2,59714 +nT +325815,i6 +2,59724 +nT +343224 +x9 +c3 +2,1,337,{1,333 +tJ +1 +tF +336,{1,338 +tJ +1} +} +,{ReplaceParams,2,1,340 +nT +1363 +nR +342 +nT +1365 +nR +463 +nT +472524 +nR +47 +nT +356711 +nR +349 +nT +200751 +nR +360 +nT +199727 +nR +480 +nT +207053 +nR +481 +nT +208077 +nR +417 +nT +211144 +nR +209 +nT +211145 +nR +418 +nT +215240 +nR +212 +nT +212329 +nR +204 +nT +373097 +nR +211 +nT +372944 +nR +217 +nT +201944 +nR +221 +nT +223448 +nR +367 +nT +508329 +nR +219 +nT +508126 +nR +224 +nT +225705 +nR +223 +nT +225776 +nR +365 +nT +230825 +nR +426 +nT +377057 +nR +497 +nT +377054 +nR +497 +nT +204201 +nR +426 +nT +375280 +nR +224 +nT +375006,cAdd +l3 +2,2,407781 +nT +233698,cAdd +l3 +2,2,59763 +nT +233842,i6 +1,372 +nT +1397,lW1 +95 +nT +24705,lW1 +96 +nT +24708,lW1 +444 +nT +449551,lW1 +443 +nT +yJ3 +lW1 +100 +nT +101750,lW1 +108 +nT +106821,lW1 +105 +nT +103749 +lU3 +0,2,110607 +nT +108869 +lU3 +0,2,107535 +nT +109893,lJ +0 +tF +112 +nT +111634,cMul,SelectedParams,0 +tF +567,{1,52,lJ +1 +tF +568,{1,42,lJ +1} +} +,{ReplaceParams,2,1,467 +nT +45516 +xA +356 +nT +51555 +xA +468 +nT +49612 +xA +357 +nT +47459 +xA +429 +nT +438699 +xA +432 +nT +441774 +xA +486 +nT +498726 +xA +494 +nT +504870 +xA +382 +nT +435579 +xA +497 +nT +435709 +xA +426 +nT +508287 +xA +414 +nT +500092 +xA +499 +nT +352744 +xA +345 +nT +367092 +xA +381 +nT +425318 +xA +478 +nT +425460 +xA +47 +nT +512501 +xA +505 +nT +355817 +xA +47 +nT +516598 +xA +507 +nT +518182 +xA +508 +nT +358896 +xA +351 +nT +388605 +xA +511 +nT +360939 +xA +503 +nT +354788 +xA +514 +nT +525350 +xA +510 +nT +394342 +xA +386 +nT +351346 +lU3 +2,2,363004 +nT +361968 +lU3 +16,1,117 +nT +1157 +lU3 +16,1,118 +nT +1158 +lU3 +16,1,402 +nT +411024 +lU3 +16,2,58768 +nT +1472 +lU3 +16,2,15760 +nT +1474 +lU3 +17,1,0,{1,400 +lU3 +17,1,57,{1,14,lJ +0} +} +,{ProduceNewTree,4,1,538 +nT +41,lQ3 +yK3 +0 +nT +5167,lQ3 +cH +41984 +e22 +lQ3 +cH +tU +lQ3 +cH +eV +lQ3 +cH +eW +cEqual +cN1 +24849,cEqual +eL +tV +cEqual +eL +n52 +281873,cEqual +eL +iP +cEqual +eL +lH1 +lQ3 +yK3 +562 +nT +41,i51,yK3 +538 +nT +5167,i51,cH +41984 +e22 +i51,cH +tU +i51,cH +eV +i51,cH +eW +i51 +cN1 +24849,i51 +eL +tV +i51 +eL +n52 +281873,i51 +eL +iP +i51 +eL +lH1 +i51,cH +tU +yN3 +eV +yN3 +eW +cLess,eN2 +571 +nT +46080,cLess +cN1 +24832,cLess +eL +xW1 +cLess +eL +tV +cLess +eL +n52 +tK3 +cLess +eL +nY1 +cLess +eL +iP +cLess +eL +lH1 +cLess,yL3 +562 +e22 +yN3 +tU +n62 +cH +eV +n62 +cH +eW +n62 +eN2 +565 +nT +409615,cLessOrEq +cN1 +24832,cLessOrEq +eL +xW1 +cLessOrEq +eL +tV +cLessOrEq +eL +n52 +tK3 +cLessOrEq +eL +nY1 +cLessOrEq +eL +iP +cLessOrEq +eL +lH1 +n62 +yL3 +562 +nT +409647,n62 +cH +tU +cF2 +eV +cF2 +eW +cGreater,eN2 +539 +nT +409615 +tV2 +cN1 +24832 +tV2 +eL +xW1 +cGreater +eL +tV +cGreater +eL +n52 +281856 +tV2 +eL +nY1 +cGreater +eL +iP +cGreater +eL +lH1 +cGreater,yL3 +538 +nT +409647,cF2 +tU +y9 +cH +eV +y9 +cH +eW +y9 +eN2 +572 +nT +46080,y9 +nQ2 +529654 +nT +24832,y9 +nQ2 +xW1 +y9 +nQ2 +tV +y9 +nQ2 +n52 +tK3 +y9 +nQ2 +nY1 +y9 +nQ2 +iP +y9 +nQ2 +lH1 +y9 +yL3 +538 +e22 +y9 +yK3 +519,{1,137,cNot,yR3 +571,{1,2,cNot,l2 +0,1,452 +nT +yJ3 +lV3 +0,2,537097,{3,547892744,cAnd,c3 +16,1,566,{1,5,cAnd,AnyParams,1} +} +,{ReplaceParams,16,1,569 +nT +13314,lV3 +16,1,544 +nT +553498,lV3 +16,1,546 +nT +462369,lV3 +16,1,548 +nT +466465,lV3 +0,1,457 +nT +yJ3 +xX1 +570 +nT +13314,xX1 +563 +nT +8197,xX1 +541 +nT +553498,xX1 +542 +nT +462369,xX1 +543 +nT +466465,xX1 +564 +nT +143365,cOr,c3 +4,1,525,{1,137,yS3 +yR3 +572,{1,2,yS3 +l4 +17,1,0,{1,0,yS3 +eN2 +537,{1,256,cAbsNotNot,c3 +18,1,531,{1,254,cAbsNotNot,c3 +0,1,572,{3,43039744,yT3 +tG3 +571,{3,49325056,yT3 +yR3 +454,{3,32513586,yT3 +l2 +16,3,32542225,{3,36732434,yT3 +y71} +,} +;e72 +grammar_optimize_abslogical_type{y3 +9 +cT +grammar_optimize_abslogical_type +grammar_optimize_abslogical={9,{34,192,228,238,242,247,254,260,261} +} +;} +e72 +grammar_optimize_ignore_if_sideeffects_type{y3 +59 +cT +grammar_optimize_ignore_if_sideeffects_type +grammar_optimize_ignore_if_sideeffects={59,{0,20,21,22,23,24,25,26,cO +l42 +78,cP +cU +e72 +grammar_optimize_nonshortcut_logical_evaluation_type{y3 +56 +cT +grammar_optimize_nonshortcut_logical_evaluation_type +grammar_optimize_nonshortcut_logical_evaluation={56,{0,25,cO +l42 +78,cP +241,243,244,245,246,248,249,250,251,252,253,255,256,257,258,259} +} +;} +e72 +grammar_optimize_recreate_type{y3 +22 +cT +grammar_optimize_recreate_type +grammar_optimize_recreate={22,{18,55,56,57,80,81,82,83,84,85,117,118,120,121,130,131,132,133,134,135,136,137} +} +;} +e72 +grammar_optimize_round1_type{y3 +125 +cT +grammar_optimize_round1_type +grammar_optimize_round1={125,{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,19,25,cO +37,38,l42 +45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,63,64,65,66,67,68,69,70,71,78,79,80,81,82,83,84,85,86,87,88,93,94,95,96,97,98,99,100,101,117,118,119,120,121,122,123,124,125,126,127,128,129,138,160,161,162,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240,cU +e72 +grammar_optimize_round2_type{y3 +103 +cT +grammar_optimize_round2_type +grammar_optimize_round2={103,{0,15,16,17,25,cO +39,40,l42 +45,46,47,48,49,50,51,52,53,54,59,60,72,73,78,79,86,87,88,89,90,91,92,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,119,122,123,124,125,126,127,128,139,159,160,161,162,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240,cU +e72 +grammar_optimize_round3_type{y3 +79 +cT +grammar_optimize_round3_type +grammar_optimize_round3={79,{74,75,76,77,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,170,171,172,173,174,175,176,177,181,182,183,184,185,186,187,188,189,190,191,193,194,195,196,197,198,199,201,202,203,205,206,207,208,209,210,211,213,214,215,217,218,219,220,221,222,223,225,226,227,229,230,231,232,233,234,235} +} +;} +e72 +grammar_optimize_round4_type{y3 +12 +cT +grammar_optimize_round4_type +grammar_optimize_round4={12,{18,55,56,57,130,131,132,133,134,135,136,137} +} +;} +e72 +grammar_optimize_shortcut_logical_evaluation_type{y3 +53 +cT +grammar_optimize_shortcut_logical_evaluation_type +grammar_optimize_shortcut_logical_evaluation={53,{0,25,cO +l42 +78,cP +cU} +l33 +lA1{tK1 +eA2 +ParamSpec_Extract +lT1 +paramlist,lJ1){index=(paramlist>>(index*10))&1023;if(index>=57)return +eA2(SubFunction,cG2 +plist_s[index-57]);if(index>=37)return +eA2(NumConstant,cG2 +plist_n_container +xF::plist_n[index-37])i1 +eA2(ParamHolder,cG2 +plist_p[index]);} +} +#ifdef FP_SUPPORT_OPTIMIZER +#include <stdio.h> +#include <algorithm> +#include <map> +#include <sstream> +using +l33 +FUNCTIONPARSERTYPES;using +l33 +lA1;using +t5;using +nG1;l33{nN1 +It,x93 +T,x93 +Comp>t31 +MyEqualRange(It +first,It +last,const +T&val,Comp +comp){size_t +len=last-first;while(len>0){size_t +xR3 +len/2;It +x23(first);x23+=half;if(comp(*x23,val)){first=x23;++first;len=len-half-1;} +iP1 +comp(val,*x23)){len=half;} +else{It +left(first);{It&eO2=left;It +last2(x23);size_t +len2=last2-eO2;while(len2>0){size_t +half2=len2/2;It +eN3(eO2);eN3+=half2;if(comp(*eN3,val)){eO2=eN3;++eO2;len2=len2-half2-1;} +else +len2=half2;} +} +first+=len;It +right(++x23);{It&eO2=right;It&last2=first;size_t +len2=last2-eO2;while(len2>0){size_t +half2=len2/2;It +eN3(eO2);eN3+=half2;if(comp(val,*eN3))len2=half2;else{eO2=eN3;++eO2;len2=len2-half2-1;} +} +eE3 +t31(left,right);} +eE3 +t31(first,first);} +tK1 +e72 +OpcodeRuleCompare{iD2()iS1 +nP1 +x83 +y72)const{const +Rule&rule=grammar_rules[y72]i1 +t72<rule +yR2.subfunc_opcode;} +iD2()lT1 +y72,const +eR +const{const +Rule&rule=grammar_rules[y72]i1 +rule +yR2.subfunc_opcode<t72;} +} +yO1 +bool +TestRuleAndApplyIfMatch(t41 +nP1 +bool +c4{MatchInfo +xF +info;n31 +found(false,cZ());if((rule.lI1 +LogicalContextOnly)&&!c4{tR1 +if(nB +IsIntType +xF::nS3){if(rule.lI1 +NotForIntegers)tR1 +cJ3 +rule.lI1 +OnlyForIntegers)tR1 +if(nB +IsComplexType +xF::nS3){if(rule.lI1 +NotForComplex)tR1 +cJ3 +rule.lI1 +OnlyForComplex)tR1 +for(;;){ +#ifdef DEBUG_SUBSTITUTIONS +#endif +found=TestParams(rule +yR2 +cU3,found.specs,info,true);if(found.found)break;if(!&*found.specs){fail:; +#ifdef DEBUG_SUBSTITUTIONS +DumpMatch +yG2,false); +#endif +return +t23} +#ifdef DEBUG_SUBSTITUTIONS +DumpMatch +yG2,true); +#endif +SynthesizeRule +yG2 +yQ2} +nG1{yP1 +ApplyGrammar +iS1 +Grammar&tK2,nP1 +bool +c4{if(tree.GetOptimizedUsing()==&tK2){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Already optimized: " +iL2 +tree +lE2"\n" +<<std::flush; +#endif +return +t23 +if(true){bool +changed +eW3 +e23 +t72){case +cNot:case +cNotNot:case +cAnd:case +cOr:for +iZ1 +a=0 +tV3 +true))yS1 +lC +cIf:case +cAbsIf:if(ApplyGrammar(tK2,xW +0),t72==cIf))yS1 +for +iZ1 +a=1 +tV3 +c4)yS1 +break;yF3 +for +iZ1 +a=0 +tV3 +false))yS1} +if(changed){tree.Mark_Incompletely_Hashed(yQ2} +typedef +const +x83 +short*lW3;std::pair<lW3,lW3>range=MyEqualRange(tK2.rule_list,tK2.rule_list+tK2.rule_count +cU3,OpcodeRuleCompare +xF());eO3 +x83 +short>rules;rules.xH3 +range.second-range.first);for +y0 +if(IsLogisticallyPlausibleParamsMatch(tM1 +yR2 +cU3))rules +c52*r);} +range.first=!rules +eU3?&rules[0]:0;range.second=!rules +eU3?&rules[rules +eJ3-1]+1:0;if(range.first!=range.second){ +#ifdef DEBUG_SUBSTITUTIONS +if(range.first!=range.second)cH2"Input (" +<<FP_GetOpcodeName(t72)<<")[" +<<tree.GetParamCount()<<"]" +;if(c4 +cV2<<"(Logical)" +;x83 +first=l52,prev=l52;e32 +sep=", rules " +;for +y0 +if(first==l52)first=prev=*r;iP1*r==prev+1)prev=*r;else +cH2 +sep<<first;sep="," +;if(prev!=first)cV2<<'-'<<prev;first=prev=*r;} +} +if(first!=l52)cH2 +sep<<first;if(prev!=first)cV2<<'-'<<prev;} +cV2<<": " +iL2 +tree +lE2"\n" +<<std::flush;} +#endif +bool +changed +eW3 +for +y0 +#ifndef DEBUG_SUBSTITUTIONS +if(!IsLogisticallyPlausibleParamsMatch(tM1 +yR2 +cU3))yA1 +#endif +if(TestRuleAndApplyIfMatch(tM1 +cU3,c4){yS1 +xY3} +if(changed){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Changed." +<<std::endl;cV2<<"Output: " +iL2 +tree +lE2"\n" +<<std::flush; +#endif +tree.Mark_Incompletely_Hashed(yQ2} +tree.SetOptimizedUsing(&tK2)i1 +t23 +yP1 +ApplyGrammar +iS1 +void*p,FPoptimizer_CodeTree::eR +yP +ApplyGrammar(*iS1 +Grammar*)p +cU3);} +xL1 +ApplyGrammars(FPoptimizer_CodeTree::eR{ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_round1\n" +; +#endif +n6 +grammar_optimize_round1 +cU3 +nW +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_round2\n" +; +#endif +n6 +grammar_optimize_round2 +cU3 +nW +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_round3\n" +; +#endif +n6 +grammar_optimize_round3 +cU3 +nW +#ifndef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_nonshortcut_logical_evaluation\n" +; +#endif +n6 +grammar_optimize_nonshortcut_logical_evaluation +cU3 +nW +#endif +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_round4\n" +; +#endif +n6 +grammar_optimize_round4 +cU3 +nW +#ifdef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_shortcut_logical_evaluation\n" +; +#endif +n6 +grammar_optimize_shortcut_logical_evaluation +cU3 +nW +#endif +#ifdef FP_ENABLE_IGNORE_IF_SIDEEFFECTS +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_ignore_if_sideeffects\n" +; +#endif +n6 +grammar_optimize_ignore_if_sideeffects +cU3 +nW +#endif +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iB3"grammar_optimize_abslogical\n" +; +#endif +n6 +grammar_optimize_abslogical +cU3 +nW +#undef C +} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +#include <algorithm> +#include <assert.h> +#include <cstring> +#include <cmath> +#include <memory> /* for auto_ptr */ +using +l33 +FUNCTIONPARSERTYPES;using +l33 +lA1;using +t5;using +nG1;l33{yP1 +TestImmedConstraints +lT1 +bitmask,const +eR{e23 +bitmask&ValueMask){case +Value_AnyNum:case +ValueMask:lC +x62:if(GetEvennessInfo +iS3 +n72 +Value_OddInt:if(GetEvennessInfo +iS3 +x82 +i11:if(GetIntegerInfo +iS3 +n72 +Value_NonInteger:if(GetIntegerInfo +iS3 +x82 +eY1:if(!IsLogicalValue(tree)cQ +nE1 +SignMask){case +Sign_AnySign:lC +nD1:if(l81 +n72 +eZ1:if(l81 +x82 +Sign_NoIdea:if(l81 +Unknown +cQ +nE1 +OnenessMask){case +Oneness_Any:case +OnenessMask:lC +Oneness_One:if(!xY1 +if(!lJ3 +fp_abs(tree +x41),e62 +1))cQ +lC +Oneness_NotOne:if(!xY1 +lG3 +fp_abs(tree +x41),e62 +1))cQ +nE1 +ConstnessMask){case +Constness_Any:lC +i01:if(!xY1 +lC +Constness_NotConst:if(xY1 +xY3 +lD2} +tP1 +x83 +extent,x83 +nbits,x93 +eP2=x83 +int>e72 +nbitmap{private:static +const +x83 +bits_in_char=8;static +const +x83 +eQ2=(sizeof(eP2)*bits_in_char)/nbits;eP2 +data[(extent+eQ2-1)/eQ2];e43 +void +inc(lJ1,int +by=1){data[pos(index)]+=by*eP2(1<<y82);y81 +void +dec(lJ1){inc(index,-1);} +int +get(lJ1 +c01(data[pos(index)]>>y82)&mask()iT3 +pos(lJ1)yP +index/eQ2 +iT3 +shift(lJ1)yP +nbits*(index%eQ2)iT3 +mask()yP(1<<nbits)-1 +iT3 +mask(lJ1)yP +mask()<<y82;} +} +;e72 +Needs{int +SubTrees:8;int +Others:8;int +l62:8;int +Immeds:8;nbitmap<iU2,2>SubTreesDetail;Needs(){std::memset(this,0,sizeof(*this));} +Needs +iS1 +Needs&b){std::memcpy(this,&b,sizeof(b));} +Needs&eM1=iS1 +Needs&b){std::memcpy(this,&b,sizeof(b))i1*this;} +} +yO1 +Needs +CreateNeedList_uncached(eX&tL2{Needs +yQ1;for +lT1 +a=0;a<params +y92;++a){const +eA2&lX3=ParamSpec_Extract +xF(params.param_list,a);e23 +lX3.first){case +SubFunction:{cN&yU3 +cN*tF1;yF +GroupFunction)++yQ1.Immeds;else{++iO2;assert(iH3.subfunc_opcode<VarBegin);yQ1.SubTreesDetail.inc +yZ3 +lG1);} +++yQ1.l62;xY3 +case +NumConstant:case +ParamHolder:++iN2;++yQ1.l62;xY3 +eE3 +yQ1;} +tK1 +Needs&CreateNeedList(eX&tL2{typedef +std::map<eX*,Needs>eE1;static +eE1 +yV1;eE1::y83 +i=yV1.xU2&tL2;if(i!=yV1.cX1&tL2 +return +i +eC2 +i1 +yV1.y43,std::make_pair(¶ms,CreateNeedList_uncached +xF(tL2))eC2;} +tK1 +yZ2 +CalculateGroupFunction +iS1 +eA2&yA2 +const +tC +info +yY3 +lX3.first){case +NumConstant:{const +ParamSpec_NumConstant +xF¶m=*iS1 +ParamSpec_NumConstant +xF*tF1 +i1 +CodeTreeImmed +yZ3 +constvalue);} +case +ParamHolder:{cM&yU3 +cM*tF1 +i1 +info.GetParamHolderValueIfFound +yZ3 +index);} +case +SubFunction:{cN&yU3 +cN*tF1 +tX +nS3;nS3 +iH +param.lG1);nS3.lJ2).xH3 +iH3 +y92);for +lT1 +a=0;a<iH3 +y92;++a +nQ +tmp(CalculateGroupFunction +nF1 +iH3.param_list,a),info));nS3 +c91 +tmp);} +nS3 +iW1 +i1 +nS3;} +eE3 +yZ2();} +} +nG1{yP1 +IsLogisticallyPlausibleParamsMatch(eX¶ms,const +eR{Needs +yQ1(CreateNeedList +xF(tL2);size_t +tL3=yC +if(tL3<size_t(yQ1.l62))tM2 +for +iZ1 +a=0;a<tL3;++a){x83 +opcode=xW +a)nC;e23 +opcode){case +cImmed:if(yQ1.Immeds>0)--yQ1.Immeds;else--iN2;lC +iU2:case +cFCall:case +cPCall:--iN2;break;yF3 +assert(opcode<VarBegin);if(iO2>0&&yQ1.SubTreesDetail.get(opcode)>0){--iO2;yQ1.SubTreesDetail.dec(opcode);} +else--iN2;} +} +if(yQ1.Immeds>0||iO2>0||iN2>0)tM2 +if(params.match_type!=AnyParams){if(0||iO2<0||iN2<0)tM2} +lD2} +tK1 +n31 +TestParam +iS1 +eA2&yA2 +const +nP1 +const +cZ&start_at,tC +info +yY3 +lX3.first){case +NumConstant:{const +ParamSpec_NumConstant +xF¶m=*iS1 +ParamSpec_NumConstant +xF*tF1;if(!xY1 +Value_t +imm=tree +x41;switch +yZ3 +modulo){case +Modulo_None:lC +Modulo_Radians:imm=cK3 +imm,yK +imm<xG1 +imm +yN +if(imm>fp_const_pi +xF())imm-=fp_const_twopi +xF(e02 +return +lJ3 +imm,param.constvalue);} +case +ParamHolder:{cM&yU3 +cM*tF1;if(!x3 +return +info.SaveOrTestParamHolder +yZ3 +index +cU3);} +case +SubFunction:{cN&yU3 +cN*tF1;yF +GroupFunction){if(!x3 +yZ2 +xZ1=CalculateGroupFunction(yA2 +info); +#ifdef DEBUG_SUBSTITUTIONS +DumpHashes(xZ1 +lE2*iS1 +void**)&xZ1 +x41;cV2<<"\n" +;cV2<<*iS1 +void**)&tree +x41;cV2<<"\n" +;DumpHashes(tree +lE2"Comparing " +iL2 +xZ1 +lE2" and " +iL2 +tree +lE2": " +;cV2<<(xZ1 +xI +tree)?"true" +:"false" +lE2"\n" +; +#endif +return +xZ1 +xI +tree);} +cJ3!eK1){if(!x3 +if(t72!=param.lG1 +cQ +eE3 +TestParams +yZ3 +data +cU3,start_at,info,false);} +} +eE3 +t23 +tK1 +e72 +l31 +x92 +MatchInfo +xF +info;l31():start_at(),info(){} +} +yO1 +class +MatchPositionSpec_PositionalParams:nQ1 +l31 +xF>{e43 +iX2 +MatchPositionSpec_PositionalParams +iZ1 +n):eF1 +l31 +xF>(n){} +} +;e72 +l72 +x92 +l72():start_at(){} +} +;class +yG:nQ1 +l72>{e43 +x83 +trypos;iX2 +yG +iZ1 +n):eF1 +l72>(n),trypos(0){} +} +yO1 +n31 +TestParam_AnyWhere +iS1 +eA2&yA2 +const +nP1 +const +cZ&start_at,tC +info,cY2&used,bool +iX1{xP<yG>x8;x83 +xA2(yG*)eK1;a=x8->trypos;goto +retry_anywhere_2;cO2 +yG +l51);a=0;} +tM3 +yC++a){if(used[a])yA1 +retry_anywhere +yW3 +TestParam(yA2 +xW +a)xS3);yP3 +used[a]=true;if(iX1 +info.SaveMatchedParamIndex(a);x8->trypos=a +i1 +n31(true,&*x8);} +} +retry_anywhere_2 +yX3 +goto +retry_anywhere;} +eE3 +t23 +tK1 +e72 +yD1 +x92 +MatchInfo +xF +info;cY2 +used;iX2 +yD1 +iZ1 +tL3):start_at(),info(),used(tL3){} +} +yO1 +class +MatchPositionSpec_AnyParams:nQ1 +yD1 +xF>{e43 +iX2 +MatchPositionSpec_AnyParams +iZ1 +n,size_t +m):eF1 +yD1 +xF>(n,yD1 +xF(m)){} +} +yO1 +n31 +TestParams(eX&nN,const +nP1 +const +cZ&start_at,tC +info,bool +iX1{if(nN.match_type!=AnyParams){if(xT!=tree.GetParamCount()cQ} +if(!IsLogisticallyPlausibleParamsMatch(nN +cU3))tM2 +e23 +nN.match_type){case +PositionalParams:{xP<cF>x8;x83 +xA2(cF*)eK1;a=xT-1;goto +lK1;cO2 +cF(xT);a=0;} +tM3 +xT;++a){(yQ3=info;retry_positionalparams +yW3 +TestParam(cW +a),xW +a)xS3);yP3 +yA1} +} +lK1 +yX3 +info=(yQ3;goto +retry_positionalparams;} +if(a>0){--a;goto +lK1;} +info=c12 +i1 +t23 +if(iX1 +tN3 +info.SaveMatchedParamIndex(a)i1 +n31(true,&*x8);} +case +SelectedParams:case +AnyParams:{xP<t6>x8;cY2 +used +l51);eO3 +x83>iY2(xT);eO3 +x83>yB2(xT);tN3{const +eA2 +lX3=cW +a);iY2[a]=ParamSpec_GetDepCode(lX3);} +{x83 +b=0;tN3 +if(iY2[a]!=0)yB2[b++]=a;tN3 +if(iY2[a]==0)yB2[b++]=a;} +x83 +xA2(t6*)eK1;if(xT==0){a=0;goto +retry_anyparams_4;} +a=xT-1;goto +eG1;cO2 +t6(xT +cU3.GetParamCount());a=0;if(xT!=0){c12=info;(*x8)[0].used=used;} +} +tM3 +xT;++a){if(a>0){(yQ3=info;(yO3 +used=used;} +retry_anyparams +yW3 +TestParam_AnyWhere +xF(cW +yB2[a])cU3 +xS3,used,iX1;yP3 +yA1} +} +eG1 +yX3 +info=(yQ3;used=(yO3 +used;goto +retry_anyparams;} +eH1:if(a>0){--a;goto +eG1;} +info=c12 +i1 +t23 +retry_anyparams_4:if(nN.n1!=0){if(!TopLevel||!info.HasRestHolder(nN.n1)){eK +cI2;cI2.reserve +l51);for +lT1 +b=0;b<yC++b){if(used[b])yA1 +cI2 +c52 +xW +b));used[b]=true;if(iX1 +info.SaveMatchedParamIndex(b);} +if(!info.SaveOrTestRestHolder(nN.n1,cI2)){goto +eH1;} +} +else{eA3&cI2=info.GetRestHolderValues(nN.n1 +iY1 +0;a<cI2 +eJ3;++a){bool +found +eW3 +for +lT1 +b=0;b<yC++b){if(used[b])yA1 +if(cI2[a]xI +xW +b))){used[b]=true;if(iX1 +info.SaveMatchedParamIndex(b);found=true;xY3} +if(!found){goto +eH1;} +} +} +eE3 +n31(true,xT?&*x8:0);} +case +GroupFunction:xY3 +return +t23} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +#include <algorithm> +#include <assert.h> +using +t5;using +nG1;l33{tK1 +yZ2 +yW1 +iS1 +eA2&yA2 +tC +info,bool +inner=true +yY3 +lX3.first){case +NumConstant:{const +ParamSpec_NumConstant +xF¶m=*iS1 +ParamSpec_NumConstant +xF*tF1 +i1 +CodeTreeImmed +yZ3 +constvalue);} +case +ParamHolder:{cM&yU3 +cM*tF1 +i1 +info.GetParamHolderValue +yZ3 +index);} +case +SubFunction:{cN&yU3 +cN*tF1 +tX +tree;tD2 +param.lG1);for +lT1 +a=0;a<iH3 +y92;++a +nQ +nparam=yW1 +nF1 +iH3.param_list,a +l04 +true +c81 +nparam);} +if +yZ3 +data.n1!=0){eK +trees(info.GetRestHolderValues +yZ3 +data.n1)yB +AddParamsMove(trees);if +l51==1){assert(tree.GetOpcode()==cAdd||tree.GetOpcode()==cMul||tree.GetOpcode()==cMin||tree.GetOpcode()==cMax||tree.GetOpcode()==cAnd||tree.GetOpcode()==cOr||tree.GetOpcode()==cAbsAnd||tree.GetOpcode()==cAbsOr);tree.eF2 +0));} +else +if +l51==0 +yY3 +t72){case +cAdd:case +cOr:tree=nA1 +0));lC +cMul:case +cAnd:tree=nA1 +1));yF3 +xY3} +} +if(inner)tree +iW1 +i1 +tree;} +eE3 +yZ2();} +} +nG1{xL1 +SynthesizeRule(t41 +nP1 +tC +info +yY3 +rule.ruletype){case +ProduceNewTree:{tree.Become(yW1 +nF1 +rule.t51 +0 +l04 +false)e02 +case +ReplaceParams:yF3{eO3 +x83>list=info.GetMatchedParamIndexes();std::sort(list.iJ2 +list.end()iY1 +list +eJ3;a-->0;)tree.i91 +list[a]);for +lT1 +a=0;a<rule.repl_param_count;++a +nQ +nparam=yW1 +nF1 +rule.t51 +a +l04 +true +c81 +nparam);} +xY3} +} +} +#endif +#ifdef DEBUG_SUBSTITUTIONS +#include <sstream> +#include <cstring> +using +l33 +FUNCTIONPARSERTYPES;using +l33 +lA1;using +t5;using +nG1;l33 +lA1{xL1 +DumpMatch(t41 +const +nP1 +const +tC +info,bool +DidMatch,std::ostream&o){DumpMatch +yG2,DidMatch?iX3"match" +:iX3"mismatch" +,o);} +xL1 +DumpMatch(t41 +const +nP1 +const +tC +info,e32 +tO3,std::ostream&o){static +const +char +ParamHolderNames[][2]={"%" +,"&" +,"x" +,"y" +,"z" +,"a" +,"b" +,"c" +} +;o<<tO3<<" (rule " +<<(&rule-grammar_rules)<<")" +<<":\n Pattern : " +;{eA2 +tmp;tmp.first=SubFunction;ParamSpec_SubFunction +tmp2;tmp2.data=rule +yR2;tmp.second=cG2 +tmp2;DumpParam +xF(tmp,o);} +o<<"\n Replacement: " +;DumpParams +xF(rule.t51 +rule.repl_param_count,o)iV3 +o<<" Tree : " +iL2 +tree,o)iV3 +if(!std::strcmp(tO3,iX3"match" +))DumpHashes(tree,o +iY1 +0;a<info.cA +eJ3;++a){if(!info.cA[a].nX2)yA1 +o<<" " +<<ParamHolderNames[a]<<" = " +iL2 +info.cA[a],o)iV3} +e11 +info.lQ +eJ3;++b){if(!iW3 +eH3)yA1 +for +iZ1 +a=0;a<iW3 +eI3 +eJ3;++a){o<<" <" +<<b<<"> = " +iL2 +iW3 +eI3[a],o);o<<std::endl;} +} +o<<std::flush;} +} +#endif +#include <list> +#include <algorithm> +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES;l33{yP1 +MarkIncompletes(FPoptimizer_CodeTree::eR{if(tree.Is_Incompletely_Hashed())lD2 +bool +l82 +eW3 +x51 +l82|=MarkIncompletes(xW +a));if(l82)tree.Mark_Incompletely_Hashed()i1 +l82;} +xL1 +FixIncompletes(FPoptimizer_CodeTree::eR{if(tree.Is_Incompletely_Hashed()){x51 +FixIncompletes(xW +a)yB +e33);} +} +} +t5{lB +Sort()iZ3 +Sort();} +lB +e33 +bool +constantfolding){if(constantfolding)ConstantFolding(*this);else +Sort();data +xC +tK1 +e72 +cB +c03 +Value_t +c13 +yE1=0; +#if 0 +long +double +value=Value;e9=crc32::calc(iS1 +x83 +char*)&value,sizeof(value));key^=(key<<24); +#elif 0 +union{e72{x83 +char +filler1[16]iK2 +v;x83 +char +filler2[16];} +buf2;e72{x83 +char +filler3[sizeof +cX3)+16-sizeof(xE1)];e9;} +buf1;} +data;memset(&data,0,sizeof(data));data.buf2.v=Value;e9=data.buf1.key; +#else +int +exponent +iK2 +nR2=std::frexp(Value,&tU2 +e9=lT1(exponent+0x8000)&0xFFFF);if(nR2<0){nR2=-nR2;key=key^0xFFFF;} +else +key+=0x10000;nR2-=yF2;key<<=39;key|=n51(nR2+nR2)*e62 +1u<<31))<<8; +#endif +lP +#ifdef FP_SUPPORT_COMPLEX_NUMBERS +nN1 +T +cJ2 +std::complex<T> >c03 +std::complex<T>c13 +cB<T>::lY3 +cK2,Value.real());nB +fphash_t +temp;cB<T>::lY3 +temp,Value.imag());yE1^=temp.hash2;cK2.hash2^=temp.hash1;} +} +; +#endif +#ifdef FP_SUPPORT_LONG_INT_TYPE +tP1 +cJ2 +long>yD +long +Value){e9=Value;lP +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE +tP1 +cJ2 +GmpInt>c03 +GmpInt +c13 +e9=Value.toInt();lP +#endif +xL1 +xK2 +xF::Recalculate_Hash_NoRecursion(){fphash_t +cK2(n51 +Opcode)<<56,Opcode*iE3(0x1131462E270012B));Depth=1;e23 +Opcode){case +cImmed:{cB +xF::lY3 +cK2,Value +e02 +case +iU2:{yE1|=n51 +cO1<<48 +lL1((n51 +cO1)*11)^iE3(0x3A83A83A83A83A0);xY3 +case +cFCall:case +cPCall:{yE1|=n51 +cO1<<48 +lL1((~n51 +cO1)*7)^3456789;} +yF3{size_t +t61=0 +e73 +0;a<iS2;++a){if(iT2 +nP2>t61)t61=iT2 +nP2;yE1+=((iT2.tN2 +hash1*(a+1))>>12)lL1 +iT2.tN2 +hash1 +lL1(3)*iE3(0x9ABCD801357);cK2.hash2*=iE3(0xECADB912345)lL1(~iT2.tN2 +hash2)^4567890;} +Depth+=t61;} +} +if(Hash!=cK2){Hash=cK2;lM2=0;} +} +lB +tE3{MarkIncompletes(*this);FixIncompletes(*this);} +} +#endif +#include <cmath> +#include <list> +#include <cassert> +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES;l33{using +t5 +yO1 +bool +x01 +const +nP1 +long +count,const +xK1::SequenceOpCode +xF&eQ,xK1::eP3&synth,size_t +max_bytecode_grow_length);static +const +e72 +SinCosTanDataType{OPCODE +whichopcode;OPCODE +inverse_opcode;enum{eR2,nS2,nZ1,lM1} +;OPCODE +codes[4];} +SinCosTanData[12]={{cTan,cCot,{cSin,cCos,cCsc,cSec} +} +,{cCot,cCot,{cCos,cSin,cSec,cCsc} +} +,{cCos,cSec,{cSin,cTan,cCsc,cCot} +} +,{cSec,cCos,{cTan,cSin,cCot,cCsc} +} +,{cSin,cCsc,{cCos,cCot,cSec,cTan} +} +,{cCsc,cSin,{cCot,cCos,cTan,cSec} +} +,{cL2{tD3 +cCosh,cM2,{tD3 +cNop,{cL2 +cNop,cCosh} +} +,{cCosh,cNop,{tD3 +cL2 +cNop} +} +,{cNop,cTanh,{cCosh,tD3 +cM2,{cNop,tD3{cNop,cTanh,cCosh,cNop} +} +,{cNop,cCosh,{cTanh,tD3 +cM2} +;} +t5{lB +SynthesizeByteCode(eO3 +x83>&eN1,std +xM3 +xF&Immed,size_t&stacktop_max){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Making bytecode for:\n" +;l21 +#endif +while(RecreateInversionsAndNegations()){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"One change issued, produced:\n" +;l21 +#endif +tE3;using +nG1;using +l33 +lA1;const +void*g=cG2 +grammar_optimize_recreate;while(ApplyGrammar(*iS1 +Grammar*)g,*this)){tE3;} +} +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Actually synthesizing, after recreating inv/neg:\n" +;l21 +#endif +xK1::eP3 +synth;SynthesizeByteCode(synth,false +iM2.Pull(eN1,Immed,stacktop_max);} +lB +SynthesizeByteCode(xK1::eP3&synth,bool +MustPopTemps)const{y01*this))yP;} +for +iZ1 +a=0;a<12;++a){const +SinCosTanDataType&data=SinCosTanData[a];if(data.whichopcode!=cNop)iC1!=data.whichopcode)yA1 +c02 +lZ3;lZ3.xA1);lZ3 +iH +data.inverse_opcode);lZ3.yC2);y01 +lZ3)){synth.tQ +else +iC1!=cInv)yA1 +if(GetParam(0)nC!=data.inverse_opcode)yA1 +y01 +GetParam(0))){synth.tQ +size_t +found[4];e11 +4;++b){c02 +tree;if(data.tP3]==cNop){tD2 +cInv);c02 +n03;n03.xA1);n03 +iH +data.tP3^2]);n03.yC2 +c81 +n03);} +else{tree.xA1 +yB +eL3 +data.tP3]);} +tree.yC2);found[b]=synth.xK3 +tree);} +if(found[data.eR2 +e3 +nS2 +tG +eR2]iM2.yT +nS2]);yB1 +cDiv +tW +eR2 +e3 +lM1 +tG +eR2]iM2.yT +lM1]);yB1 +cMul +tW +nZ1 +e3 +lM1 +tG +nZ1]iM2.yT +lM1]);yB1 +cRDiv +tW +nZ1 +e3 +nS2 +tG +nZ1]iM2.yT +nS2]);yB1 +cMul,2,1 +iM2.tQ +size_t +n_subexpressions_synthesized=SynthCommonSubExpressions(c92 +e23 +l92{case +iU2:synth.PushVar(GetVar());lC +cImmed:t71 +GetImmed());lC +cAdd:case +cMul:case +cMin:case +cMax:case +cAnd:case +cOr:case +cAbsAnd:case +cAbsOr:iC1==cMul){bool +c23 +eW3 +yH +lX1 +tD1&&isLongInteger(lX1 +x41)){c11=makeLongInteger(lX1 +x41);c02 +tmp(*this,x93 +c02::CloneTag());tmp.i91 +a);tmp +iW1;if(x01 +tmp,value,xK1::tU1 +xF::AddSequence,synth,MAX_MULI_BYTECODE_LENGTH)){c23=true;xY3} +} +if(c23)xY3 +int +yF1=0;cY2 +done(GetParamCount(),false);c02 +iQ;iQ +iH +l92;for(;;){bool +found +eW3 +yH +done[a])yA1 +if(synth.IsStackTop(lX1)){found=true;done[a]=true;lX1.n7 +iQ +cS +lX1);if(++yF1>1){yU +2);iQ.yC2)yC1 +iQ);yF1=yF1-2+1;} +} +} +if(!found)xY3 +yH +done[a])yA1 +lX1.n7 +iQ +cS +lX1);if(++yF1>1){yU +2);iQ.yC2)yC1 +iQ);yF1=yF1-2+1;} +} +if(yF1==0 +yY3 +l92{case +cAdd:case +cOr:case +cAbsOr:t71 +0);lC +cMul:case +cAnd:case +cAbsAnd:t71 +1);lC +cMin:case +cMax:t71 +0);break;yF3 +xY3++yF1;} +assert(n_stacked==1);xY3 +case +cPow:{tW1 +p0 +i42 +0);tW1 +p1 +i42 +1);if(!p1 +tD1||!isLongInteger +cR3||!x01 +p0,makeLongInteger +cR3,xK1::tU1 +xF::MulSequence,synth,MAX_POWI_BYTECODE_LENGTH)){p0.n7 +p1.n7 +yU +2);e21 +cIf:case +cAbsIf:{x93 +xK1::eP3::IfData +ifdata;GetParam(0)e93 +SynthIfStep1(ifdata,l92;GetParam(1)e93 +SynthIfStep2(ifdata);GetParam(2)e93 +SynthIfStep3(ifdata +e02 +case +cFCall:case +cPCall:{for +iZ1 +a=0;a<l91++a)lX1.n7 +yU +lT1)GetParamCount());yB1 +0x80000000u|GetFuncNo(),0,0 +e02 +yF3{for +iZ1 +a=0;a<l91++a)lX1.n7 +yU +lT1)GetParamCount()e02} +synth.StackTopIs(*this);if(MustPopTemps&&n_subexpressions_synthesized>0){size_t +top=synth.GetStackTop(iM2.DoPopNMov(top-1-n_subexpressions_synthesized,top-1);} +} +} +l33{yP1 +x01 +const +nP1 +long +count,const +xK1::SequenceOpCode +xF&eQ,xK1::eP3&synth,size_t +max_bytecode_grow_length){if +cW3!=0){xK1::eP3 +backup=synth;tree.n7 +size_t +bytecodesize_backup=synth.GetByteCodeSize();xK1::x01 +count +e63 +size_t +bytecode_grow_amount=synth.GetByteCodeSize()-bytecodesize_backup;if(bytecode_grow_amount>max_bytecode_grow_length){synth=backup +i1 +t23 +lD2} +else{xK1::x01 +count,eQ,synth +yQ2} +} +#endif +#include <cmath> +#include <cassert> +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES;l33{using +t5; +#define FactorStack std xM3 +const +e72 +PowiMuliType{x83 +opcode_square;x83 +opcode_cumulate;x83 +opcode_invert;x83 +opcode_half;x83 +opcode_invhalf;} +iseq_powi={cSqr,cMul,cInv,cSqrt,cRSqrt} +,iseq_muli={l52 +x9 +cNeg,l52,l52} +yO1 +Value_t +cP1 +const +PowiMuliType&c33,const +std +nA3,n82&stack)eQ3 +1);while(IP<limit){if(n13 +c33.opcode_square){if(!t42 +eT3 +2;yZ +opcode_invert){nS3=-nS3;yZ +opcode_half){if(nS3>xH1&&isEvenInteger(eT3 +yF2;yZ +opcode_invhalf){if(nS3>xH1&&isEvenInteger(eT3 +e62-0.5);++IP;yA1} +size_t +xB2=IP +iK2 +lhs(1);if(n13 +cFetch){lJ1=n43;if(index<y2||size_t(index-y2)>=lB2){IP=xB2;xY3 +lhs=stack[index-y2];goto +yD2;} +if(n13 +cDup){lhs=nS3;goto +yD2;yD2:t91 +nS3);++IP +iK2 +subexponent=cP1 +c33 +iK +if(IP>=limit||eN1[IP]!=c33.opcode_cumulate){IP=xB2;xY3++IP;stack.pop_back();nS3+=lhs*subexponent;yA1} +xY3 +return +nS3;} +tK1 +Value_t +ParsePowiSequence +iS1 +std +nA3){n82 +stack;t91 +e62 +1))i1 +cP1 +iseq_powi +iK} +tK1 +Value_t +ParseMuliSequence +iS1 +std +nA3){n82 +stack;t91 +e62 +1))i1 +cP1 +iseq_muli +iK} +tK1 +class +CodeTreeParserData{e43 +iX2 +CodeTreeParserData(bool +k_powi):stack(),clones(),keep_powi(k_powi){} +void +Eat +iZ1 +tL3,OPCODE +opcode +nQ +xM;xM +iH +opcode);eK +params=Pop(tL3 +yR1 +tL2;if(!keep_powi)e23 +opcode){case +cTanh:{yZ2 +sinh,cosh;sinh +iH +cSinh);sinh +cS +xM +c43 +sinh +iW1;cosh +iH +cCosh);cosh +c91 +xM +c43 +cosh +iW1 +tX +pow;pow +iH +cPow);pow +c91 +cosh);pow.yA +nU2));pow +iW1;xM +iH +cMul);xM.nB1 +0,sinh);xM +c91 +pow +e02 +case +cTan:{yZ2 +sin,cos;sin +iH +cSin);sin +cS +xM +c43 +sin +iW1;cos +iH +cCos);cos +c91 +xM +c43 +cos +iW1 +tX +pow;pow +iH +cPow);pow +c91 +cos);pow.yA +nU2));pow +iW1;xM +iH +cMul);xM.nB1 +0,sin);xM +c91 +pow +e02 +case +cPow:{iT1&p0=xM +l8 +0);iT1&p1=xM +l8 +1);if(p1 +nC==cAdd){eK +mulgroup(p1.GetParamCount()iY1 +0;a<p1.l91++a +nQ +pow;pow +iH +cPow);pow +cS +p0);pow +cS +p1 +n93 +pow +iW1;mulgroup[a +tQ3 +pow);} +xM +iH +cMul +yR1 +mulgroup);} +xY3 +yF3 +xY3 +xM.e33!keep_powi);lA2,false); +#ifdef DEBUG_SUBSTITUTIONS +iA1<<tL3<<", " +<<FP_GetOpcodeName(opcode)<<"->" +<<FP_GetOpcodeName(xM +nC)<<": " +iK3 +xM);iB1 +xM); +#endif +t91 +xM +cN2 +EatFunc +iZ1 +tL3,OPCODE +opcode,x83 +funcno +nQ +xM=CodeTreeFuncOp +xF(opcode,funcno);eK +params=Pop(tL3 +yR1 +tL2;xM.yC2); +#ifdef DEBUG_SUBSTITUTIONS +iA1<<tL3<<", " +iK3 +xM);iB1 +xM); +#endif +lA2);t91 +xM +cN2 +AddConst(yL1 +nQ +xM=CodeTreeImmed(value);lA2);Push(xM +cN2 +AddVar +lT1 +varno +nQ +xM=CodeTreeVar +xF(varno);lA2);Push(xM +cN2 +SwapLastTwoInStack(){tA1 +1 +tQ3 +tA1 +2]cN2 +Dup(){Fetch(lB2-1 +cN2 +Fetch +iZ1 +which){Push(stack[which]);} +nN1 +T>void +Push(T +tree){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<iK3 +tree);iB1 +tree); +#endif +t91 +tree +cN2 +PopNMov +iZ1 +target,size_t +source){stack[target]=stack[source];stack +xF3 +target+1);} +yZ2 +yE2{clones.clear()tX +nS3(stack.back());stack +xF3 +lB2-1)i1 +nS3;} +eK +Pop +iZ1 +n_pop){eK +nS3(n_pop);for +lT1 +n=0;n<n_pop;++n)nS3[n +tQ3 +tA1 +n_pop+n]); +#ifdef DEBUG_SUBSTITUTIONS +for +iZ1 +n=n_pop;n-->0;){iA1 +iL2 +nS3[n]);iB1 +nS3[n]);} +#endif +stack +xF3 +lB2-n_pop)i1 +nS3;} +size_t +GetStackTop(c01 +lB2;} +private:void +FindClone(yZ2&,bool=true)yP;} +private:eK +stack;std::multimap<fphash_t,yZ2>clones;bool +keep_powi;private:CodeTreeParserData +iS1 +CodeTreeParserData&);CodeTreeParserData&eM1=iS1 +CodeTreeParserData&);} +yO1 +e72 +IfInfo{yZ2 +eS2 +tX +thenbranch;size_t +endif_location;IfInfo():eS2(),thenbranch(),endif_location(){} +} +;} +t5{lB +GenerateFrom +iS1 +x93 +FunctionParserBase +xF::Data&x33,bool +keep_powi){eK +xH2;xH2.xH3 +x33.mVariablesAmount);for +lT1 +n=0;n<x33.mVariablesAmount;++n){xH2 +c52 +CodeTreeVar +xF(n+iU2));} +GenerateFrom(x33,xH2,keep_powi);} +lB +GenerateFrom +iS1 +x93 +FunctionParserBase +xF::Data&x33,const +x5&xH2,bool +keep_powi){const +eO3 +x83>&eN1=x33.mByteCode;const +std +xM3 +xF&Immed=x33.mImmed; +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"ENTERS GenerateFrom()\n" +; +#endif +CodeTreeParserData +xF +sim(keep_powi);eO3 +IfInfo +xF>eJ +eK3 +IP=0,DP=0;;++IP){tO2:while(!eJ +eU3&&(eJ.eA==IP||(IP<n41&&n13 +cJump&&eJ +e81.nX2))){c02 +elsebranch=sim.yE2 +nA2 +eJ.back().eS2)nA2 +eJ +e81)nA2 +elsebranch)yR +3,cIf);eJ.pop_back();} +if(IP>=n41)break;x83 +opcode=eN1[IP];if(eS3 +cSqr||opcode==cDup||eS3 +cInv&&!IsIntType +xF::nS3)||opcode==cNeg||opcode==cSqrt||opcode==cRSqrt||opcode==cFetch)){size_t +was_ip=IP +iK2 +eD2 +ParsePowiSequence +xF(eN1,IP,eJ +eU3?n41:eJ.eA,sim.xH +1);if(exponent!=e62 +1.0)){xG +exponent +iU3);goto +tO2;} +if +eS3 +cDup||opcode==cFetch||opcode==cNeg)l14 +xT2=ParseMuliSequence +xF(eN1,IP,eJ +eU3?n41:eJ.eA,sim.xH +1);if(xT2!=e62 +1.0)){xG +xT2)yR +2,cMul);goto +tO2;} +} +IP=was_ip;} +if(nB2>=iU2){lJ1=opcode-iU2 +nA2 +xH2[index]);} +else{e23 +nB2){case +cIf:case +cAbsIf:{eJ +xF3 +eJ +eJ3+1);c02 +res(sim.yE2);eJ.back().eS2.swap(res);eJ.eA=n41;IP+=2;yA1} +case +cJump:{c02 +res(sim.yE2);eJ +e81.swap(res);eJ.eA=eN1[IP+1]+1;IP+=2;yA1} +case +cImmed:xG +Immed[DP++]);lC +cDup:sim.Dup();lC +cNop:lC +cFCall:{x83 +funcno=n43;assert(funcno<fpdata.mFuncPtrs.size());x83 +params=x33.mFuncPtrs +n53 +mParams;sim.EatFunc(params,nB2,funcno +e02 +case +cPCall:{x83 +funcno=n43;assert(funcno<fpdata.iI3.size());const +FunctionParserBase +xF&p=*x33.iI3 +n53 +mParserPtr;x83 +params=x33.iI3 +n53 +mParams;x5 +paramlist=sim.Pop(tL2;c02 +tP2;tP2.GenerateFrom(*p.mData,paramlist)nA2 +tP2 +e02 +case +cInv:xG +1 +c32 +cDiv);lC +cNeg +nC2 +cNeg);break;xG +0 +c32 +cSub);lC +cSqr:xG +2 +xN1 +cSqrt:xG +yF2 +xN1 +cRSqrt:xG +e62-0.5)xN1 +cCbrt:xG +e62 +1)/e62 +3)xN1 +cDeg:xG +fp_const_rad_to_deg +xF())yG1 +cRad:xG +fp_const_deg_to_rad +xF())yG1 +cExp:iR)goto +yM3;xG +fp_const_e +xF()c32 +cPow);lC +cExp2:iR)goto +yM3;xG +2.0 +c32 +cPow);lC +cCot +nC2 +cTan);iR)x1 +cCsc +nC2 +cSin);iR)x1 +cSec +nC2 +cCos);iR)x1 +cInt: +#ifndef __x86_64 +iR)n23 +1,cInt +e02 +#endif +xG +yF2)tQ2 +yR +1,cFloor);lC +cLog10 +nC2 +c53 +fp_const_log10inv +xF())yG1 +cLog2 +nC2 +c53 +fp_const_log2inv +xF())yG1 +cQ3:n33 +c53 +fp_const_log2inv +xF())yR +3,cMul);lC +cHypot:xG +2 +iU3);tS3 +xG +2 +iU3)tQ2;xG +yF2 +xN1 +cSinCos:sim.Dup()yR +1,cSin);n33 +cCos);lC +cSinhCosh:sim.Dup()yR +1,cSinh);n33 +cCosh);lC +cRSub:tS3 +case +cSub:iR)n23 +2,cSub +e02 +xG-1)yR +2,cMul)tQ2;lC +cRDiv:tS3 +case +cDiv:iR||IsIntType +xF::nS3)n23 +2,cDiv +e02 +xG-1 +iU3)yG1 +cAdd:case +cMul:case +cMod:case +cPow:case +cEqual:case +cLess:case +cGreater:case +i51:case +cLessOrEq:case +cGreaterOrEq:case +cAnd:case +cOr:case +cAbsAnd:case +cAbsOr:sim.Eat(2,tB1 +lC +cNot:case +cNotNot:case +cC3:case +cAbsNotNot +nC2 +tB1 +lC +cFetch:sim.Fetch(n43);lC +cPopNMov:{x83 +stackOffs_target=n43;x83 +stackOffs_source=n43;sim.PopNMov(stackOffs_target,stackOffs_source +e02 +yF3 +yM3:;x83 +funcno=opcode-cAbs;assert(funcno<FUNC_AMOUNT);const +FuncDefinition&func=Functions[funcno]yR +func.params,tB1 +xY3} +} +Become(sim.yE2); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Produced tree:\n" +;l21 +#endif +} +} +#endif +#include <algorithm> +#ifdef FP_SUPPORT_OPTIMIZER +#include <assert.h> +#define FP_MUL_COMBINE_EXPONENTS +l33{using +l33 +FUNCTIONPARSERTYPES;using +t5 +yO1 +static +void +AdoptChildrenWithSameOpcode(eR{ +#ifdef DEBUG_SUBSTITUTIONS +bool +nT2 +eW3 +#endif +for +l41 +if(xW +a)nC==t72){ +#ifdef DEBUG_SUBSTITUTIONS +if(!nT2)cH2"Before assimilation: " +cR +nT2=true;} +#endif +tree.AddParamsMove(xW +a).GetUniqueRef().lJ2),a);} +#ifdef DEBUG_SUBSTITUTIONS +if(nT2)cH2"After assimilation: " +cR} +#endif +} +} +t5{xL1 +ConstantFolding(eR{tree.Sort(); +#ifdef DEBUG_SUBSTITUTIONS +void*c63=0;cV2<<"[" +<<(&c63)<<"]Runs ConstantFolding for: " +cR +DumpHashes(tree +lE2 +std::flush; +#endif +if(false){redo:;tree.Sort(); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"[" +<<(&c63)<<"]Re-runs ConstantFolding: " +cR +DumpHashes(tree); +#endif +} +if(t72!=cImmed){yD3 +p=CalculateResultBoundaries(tree);if(p +yI&&p +e61&&p +yM==p +tG1{nU +p +yM);nD} +if(false){ReplaceTreeWithOne:nU +e62 +1));goto +do_return;ReplaceTreeWithZero:nU +xG1;goto +do_return;ReplaceTreeWithParam0: +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Before replace: " +;cV2<<std::hex<<'[' +eJ1 +hash1<<',' +eJ1 +hash2<<']'<<std::dec +cR +#endif +tree.eF2 +0)); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"After replace: " +;cV2<<std::hex<<'[' +eJ1 +hash1<<',' +eJ1 +hash2<<']'<<std::dec +cR +#endif +cJ +c73(t72){case +cImmed:lC +iU2:lC +cAnd:case +cAbsAnd +cK +bool +c5 +eW3 +for +l41{if(!c83 +a)))c5=true;cA3 +a),t72==cAbsAnd)){case +xX3 +t7 +iF2:iZ);lC +lZ1 +c73 +l51){case +0:iD +1:tD2 +t72==cAnd?cNotNot:cAbsNotNot);cJ +yF3 +cZ2 +cAnd||!c5)if(ConstantFolding_AndLogic(tB2 +e21 +cOr:case +cAbsOr +cK +bool +c5 +eW3 +for +l41{if(!c83 +a)))c5=true;cA3 +a),t72==cAbsOr)tN1 +iD +l03 +iZ);lC +lZ1 +c73 +l51){case +0 +t7 +1:tD2 +t72==cOr?cNotNot:cAbsNotNot);cJ +yF3 +cZ2 +cOr||!c5)if(ConstantFolding_OrLogic(tB2 +e21 +cNot:case +cC3:{x83 +n61 +0;e23 +c93){case +cEqual:n61 +i51;lC +i51:n61 +cEqual;lC +cLess:n61 +cGreaterOrEq;lC +cGreater:n61 +cLessOrEq;lC +cLessOrEq:n61 +cGreater;lC +cGreaterOrEq:n61 +cLess;lC +cNotNot:n61 +cNot;lC +cNot:n61 +cNotNot;lC +cC3:n61 +cAbsNotNot;lC +cAbsNotNot:n61 +cC3;break;yF3 +xY3 +if(opposite){tD2 +OPCODE(opposite)yB +SetParamsMove(xW +0).GetUniqueRef().lJ2));cJ +c73(lY1 +0)cU3 +cQ1){case +iF2 +t7 +l03 +iD +lZ1 +cZ2 +cNot&&GetPositivityInfo(xW +0))==iF2)tD2 +cC3);if(c93==cIf||c93==cAbsIf +nQ +iZ2=xW +0);iT1&ifp1=iZ2 +l8 +1);iT1&ifp2=iZ2 +l8 +2);if(ifp1 +nC +iY3 +ifp1 +cQ1 +cD3 +ifp1 +nC==cNot?cNotNot:cAbsNotNot);tR2 +c43 +n63)cE3 +nO2;p2 +tT3 +iI +if(ifp2 +nC +iY3 +ifp2 +cQ1 +cD3 +t72);tR2);n63)cE3 +iH +ifp2 +nC==cNot?cNotNot:cAbsNotNot);p2 +tT3 +l8 +0)iI +e21 +cNotNot:case +cAbsNotNot:{if(c83 +0)))n73 +cA3 +0),t72==cAbsNotNot)){case +xX3 +t7 +iF2:iD +lZ1 +cZ2 +cNotNot&&GetPositivityInfo(xW +0))==iF2)tD2 +cAbsNotNot);if(c93==cIf||c93==cAbsIf +nQ +iZ2=xW +0);iT1&ifp1=iZ2 +l8 +1);iT1&ifp2=iZ2 +l8 +2);if(ifp1 +nC +iY3 +ifp1 +cQ1{tree.SetParam(0,iZ2 +l8 +0)yB +AddParam(ifp1)cE3 +nO2;p2 +tT3 +iI +if(ifp2 +nC +iY3 +ifp2 +cQ1 +cD3 +t72);tR2);n63 +yB +AddParam(ifp2 +yB +eL3 +iZ2 +nC);cJ} +e21 +cIf:case +cAbsIf:{if(ConstantFolding_IfOperations(tB2 +xY3 +case +cMul:{NowWeAreMulGroup:;AdoptChildrenWithSameOpcode(tree)iK2 +nH1=e62 +1);size_t +lC2=0;bool +nI1 +eW3 +x51{if(!xW +tC1 +yA1 +Value_t +immed=xW +a)x41;if(immed==xG1 +goto +ReplaceTreeWithZero;nH1*=immed;++lC2;} +if(lC2>1||(lC2==1&&lJ3 +nH1,e62 +1))))nI1=true;if(nI1){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"cMul: Will add new " +iJ3 +nH1<<"\n" +; +#endif +for +l41 +if(xW +tC1{ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<" - For that, deleting " +iJ3 +xW +a)x41;cV2<<"\n" +; +#endif +tU3(!lJ3 +nH1,e62 +1)))tree +cS +eA1 +nH1));c73 +l51){case +0:iD +1:n73 +yF3 +if(ConstantFolding_MulGrouping(tB2 +if(ConstantFolding_MulLogicItems(tB2 +e21 +cAdd +cK +Value_t +nD2=0.0;size_t +lC2=0;bool +nI1 +eW3 +x51{if(!xW +tC1 +yA1 +Value_t +immed=xW +a)x41;nD2+=immed;++lC2;} +if(lC2>1||(lC2==1&&nD2==xG1)nI1=true;if(nI1){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"cAdd: Will add new " +iJ3 +nD2<<"\n" +;cV2<<"In: " +cR +#endif +for +l41 +if(xW +tC1{ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<" - For that, deleting " +iJ3 +xW +a)x41;cV2<<"\n" +; +#endif +tU3(!(nD2==e62 +0.0)))tree +cS +eA1 +nD2));c73 +l51){case +0 +t7 +1:n73 +yF3 +if(ConstantFolding_AddGrouping(tB2 +if(ConstantFolding_AddLogicItems(tB2 +e21 +cMin +cK +size_t +yI2=0;yD3 +e4;x51{while(a+1<tree.GetParamCount()&&xW +a)xI +xW +a+1)))iZ+1);yE3 +max.cF3(!e4 +e61||(p +tG1<e4 +tG1){e4 +nL3=p +nL3;e4 +e61=true;yI2=a;} +} +if(e4 +e61)for +l41{yE3 +min.cF3 +a!=yI2&&p +yM>=e4 +tG1 +tU3 +l51==1){n73 +e21 +cMax +cK +size_t +yI2=0;yD3 +eY;x51{while(a+1<tree.GetParamCount()&&xW +a)xI +xW +a+1)))iZ+1);yE3 +min.cF3(!eY +yI||p +yM>eY +yM)){eY +yM=p +yM;eY +yI=true;yI2=a;} +} +if(eY +yI){for +l41{yE3 +max.cF3 +a!=yI2&&(p +tG1<eY +yM){iZ);} +} +} +if +l51==1){n73 +e21 +cEqual:case +i51:case +cLess:case +cGreater:case +cLessOrEq:case +cGreaterOrEq:if(ConstantFolding_Comparison(tB2 +lC +cAbs:{yD3 +tY +xW +0));if +iE +n73 +if +iF{tD2 +cMul +yB +yA +e62 +1)));goto +NowWeAreMulGroup;} +if(c93==cMul){iT1&p=xW +0);eK +n83;eK +cP2 +e73 +0;a<p.l91++a){tY +p +n93 +if +iE{n83 +c52 +p +n93} +if +iF{cP2 +c52 +p +n93} +} +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"Abs: mul group has " +<<n83 +eJ3<<" pos, " +<<cP2 +eJ3<<"neg\n" +; +#endif +if(!n83 +eU3||!cP2 +eU3){ +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"AbsReplace-Before: " +iL2 +tree +lE2"\n" +<<std::flush;DumpHashes +nV2); +#endif +yZ2 +e13;e13 +iH +cMul +iY1 +0;a<p.l91++a){tY +p +n93 +if(iE||iF){} +else +e13 +cS +p +n93} +e13 +iW1 +tX +nB3;nB3 +iH +cAbs);nB3 +c91 +e13);nB3 +iW1 +tX +iG +cMul);mulgroup +c91 +nB3);cA1 +AddParamsMove(n83);if(!cP2 +eU3){if(cP2 +eJ3%2)cA1 +yA +nU2));cA1 +AddParamsMove(cP2);} +tree.Become +eH2); +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"AbsReplace-After: " +;DumpTree +nV2 +lE2"\n" +<<std::flush;DumpHashes +nV2); +#endif +goto +NowWeAreMulGroup;} +} +xY3 +#define HANDLE_UNARY_CONST_FUNC(funcname) nP){nU funcname(lR));nD +case +cLog:i83(fp_log);if(c93==cPow +nQ +pow=xW +0);if(GetPositivityInfo(pow +l8 +0))==iF2)iV1 +t2 +yB +lU +if(GetEvennessInfo(pow +l8 +1))==iF2)iV1()tX +abs;abs +iH +cAbs);abs +c91 +pow +c43 +abs.Rehash +t2);pow.nB1 +0,abs +yB +lU} +iP1 +c93==cAbs +nQ +pow=xW +0)l8 +0);if(pow +nC==cPow)iV1()tX +abs;abs +iH +cAbs);abs +c91 +pow +c43 +abs.Rehash +t2);pow.nB1 +0,abs +yB +lU} +lC +cAcosh:i83(fp_acosh);lC +cAsinh:i83(fp_asinh);lC +cAtanh:i83(fp_atanh);lC +cAcos:i83(fp_acos);lC +cAsin:i83(fp_asin);lC +cAtan:i83(fp_atan);lC +cCosh:i83(fp_cosh);lC +cSinh:i83(fp_sinh);lC +cTanh:i83(fp_tanh);lC +cSin:i83(fp_sin);lC +cCos:i83(fp_cos);lC +cTan:i83(fp_tan);lC +cCeil:if(n5 +i83(fp_ceil);lC +cTrunc:if(n5 +i83(fp_trunc);lC +cFloor:if(n5 +i83(fp_floor);lC +cInt:if(n5 +i83(fp_int);lC +cCbrt:i83(fp_cbrt);lC +cSqrt:i83(fp_sqrt);lC +cExp:i83(fp_exp);lC +cLog2:i83(fp_log2);lC +cLog10:i83(fp_log10);lC +cQ3:if +lI +fp_log2(lR)*xW +nC3 +cArg:i83(fp_arg);lC +cConj:i83(fp_conj);lC +cImag:i83(fp_imag);lC +cReal:i83(fp_real);lC +cPolar:if +lI +fp_polar +e51 +lC +cMod:if +lI +fp_mod +e51 +lC +cAtan2:{yD3 +tY +xW +yP2 +p1=tZ +1));nP&&lJ3 +lR,xG1){if(p1 +e61&&(p1 +tG1<xG1{nU +fp_const_pi +cH3 +if(p1 +yI&&p1 +yM>=tE1 +xG1;nD} +if(eI1 +lJ3 +xW +i8,xG1){if(p0 +e61&&(p0 +tG1<xG1{nU-fp_const_pihalf +cH3 +if +cN3 +p0 +yM>xG1{nU +fp_const_pihalf +cH3} +if +lI +fp_atan2 +e51 +if((p1 +yI&&p1 +yM>xG1||(p1 +e61&&(p1 +tG1<fp_const_negativezero +xF())nQ +yJ2;yJ2 +iH +cPow);yJ2 +c91 +xW +1));yJ2.yA +nU2));yJ2 +iW1 +tX +yK2;yK2 +iH +cMul);yK2 +c91 +xW +0));yK2 +c91 +yJ2);yK2 +cY +cAtan +yB +nB1 +0,yK2 +yB +i91 +1);e21 +cPow:{if(ConstantFolding_PowOperations(tB2 +xY3 +case +cDiv:nP&&eI1 +xW +i8!=tE1 +lR/xW +nC3 +cInv:nP&&lR!=tE1 +e62 +1)/lR);nD +lC +cSub:if +lI +lR-xW +nC3 +cNeg:nP){nU-lR);nD +lC +cRad:nP){nU +RadiansToDegrees +eG2 +cDeg:nP){nU +DegreesToRadians +eG2 +cSqr:nP){nU +lR*lR);nD +lC +cExp2:i83(fp_exp2);lC +cRSqrt:nP){nU +e62 +1)/fp_sqrt +eG2 +cCot:c22 +fp_tan(lZ +cSec:c22 +fp_cos(lZ +cCsc:c22 +fp_sin(lZ +cHypot:if +lI +fp_hypot +e51 +lC +cRDiv:case +cRSub:case +cDup:case +cFetch:case +cPopNMov:case +cSinCos:case +cSinhCosh:case +cNop:case +cJump:lC +cPCall:case +cFCall:xY3 +do_return:; +#ifdef DEBUG_SUBSTITUTIONS +cV2<<"[" +<<(&c63)<<"]Done ConstantFolding, result: " +cR +DumpHashes(tree); +#endif +} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +t5{xL1 +yD3::set_abs(nL +bool +has_negative=!min.known||min.val<e62);bool +has_positive=!cG3||max.val>e62);bool +crosses_axis=has_negative&&has_positive;cI1 +xF +newmax;if(min.cF3 +cG3)newmax.set(fp_max(i61,i71);if(crosses_axis +cI3 +e62));cJ3 +min.cF3 +cG3 +cI3 +fp_min(i61,i71);iP1 +min.known +cI3 +i61);else +min.set(i71;} +max=newmax;} +xL1 +yD3::set_neg(){std::swap(min,max);min.val=-min.val;max.val=-max.val;} +yP1 +IsLogicalTrueValue +iS1 +yD3&p,bool +abs){if(nB +IsIntType +xF::nS3){if(p +yI&&p +yM>=e62 +1))lD2 +if(!abs&&p +e61 +t43<=nU2)lD2} +cJ3 +p +yI&&p +yM>=yF2)lD2 +if(!abs&&p +e61 +t43<=e62-0.5))lD2 +eE3 +t23 +yP1 +IsLogicalFalseValue +iS1 +yD3&p,bool +abs){if(nB +IsIntType +xF::nS3){if(abs)eG3 +e61 +l61 +1);else +eG3 +yI&&p +e61&&p +yM>nU2 +l61 +1);} +cJ3 +abs)eG3 +e61 +l61 +0.5);else +eG3 +yI&&p +e61&&p +yM>e62-0.5)l61 +0.5);} +} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES;using +t5;t5{tK1 +yD3 +CalculateResultBoundaries +iS1 +eR +#ifdef DEBUG_SUBSTITUTIONS_extra_verbose +{using +l33 +FUNCTIONPARSERTYPES;yD3 +tmp=CalculateResultBoundaries_do(tree +lE2"Estimated boundaries: " +;if(tmp +yI)cV2<<tmp +yM;else +cV2<<"-inf" +;cV2<<" .. " +;if(tmp +e61)cV2<<tmp +nL3;else +cV2<<"+inf" +;cV2<<": " +iL2 +tree +lE2 +std::endl +i1 +tmp;} +tK1 +yD3 +yZ2::CalculateResultBoundaries_do +iS1 +eR +#endif +{iS +yH1(-fp_const_pihalf +xF(),fp_const_pihalf +xF());iS +pi_limits(-fp_const_pi +xF(),fp_const_pi +xF());iS +abs_pi_limits(xH1,fp_const_pi +xF());iS +plusminus1_limits(nU2,e62 +1));using +l33 +std;e23 +t72){case +cImmed:nM +tree +x41 +cU3 +x41)t83 +cAnd:case +cAbsAnd:case +cOr:case +cAbsOr:case +cNot:case +cC3:case +cNotNot:case +cAbsNotNot:case +cEqual:case +i51:case +cLess:case +cLessOrEq:case +cGreater:case +cGreaterOrEq:{nM +xH1,e62 +1));} +case +cAbs:tW3 +set_abs();tK +cLog:tW3 +tS2 +fp_log);nD3 +fp_log);tK +cLog2:tW3 +tS2 +fp_log2);nD3 +fp_log2);tK +cLog10:tW3 +tS2 +fp_log10);nD3 +fp_log10);tK +cAcosh:tW3 +min.tL1 +cGreaterOrEq +tH1 +fp_acosh +tR3 +cGreaterOrEq +tH1 +fp_acosh);tK +cAsinh:tW3 +min.set(fp_asinh);tO +set(fp_asinh);tK +cAtanh:tW3 +min.n3-1),fp_atanh +tR3 +cLess +tH1 +fp_atanh);tK +cAcos:lD +nM(tO +cF3(tO +val)<e62 +1))?fp_acos(tO +val):xH1,(m +yI&&(m +yM)>=nU2)?fp_acos(m +yM):fp_const_pi +xF());} +case +cAsin:tW3 +min.n3-1),fp_asin,yH1 +yM +tR3 +cLess +tH1 +fp_asin,yH1 +tG1;tK +cAtan:tW3 +min.set(fp_atan,yH1 +yM);tO +set(fp_atan,yH1 +tG1;tK +cAtan2:{nP&&lJ3 +lR,xG1)yP +abs_pi_limits;} +if(eI1 +lJ3 +xW +i8,xG1)yP +yH1;eE3 +pi_limits;} +case +cSin:lD +bool +x11=!m +yI||!tO +known||(tO +val-m +yM)>=(yK +x11)tM +Value_t +min=cK3 +m +yM,yK +min<xG1 +min +yN +Value_t +max=cK3 +tO +val,yK +max<xG1 +max +yN +if(max<min)max +yN +bool +y21=(min<=fp_const_pihalf +xF()&&max>=fp_const_pihalf +xF());bool +nJ1=(min<=cD&&max>=cD);if(y21&&nJ1)tM +if(nJ1)nM +nU2,nW2 +if(y21)nM +yL2 +e62 +1));nM +yL2 +nW2} +case +cCos:lD +if(m +yI)m +yM+=fp_const_pihalf +xF();if(xI2 +tO +val+=fp_const_pihalf +xF();bool +x11=!m +yI||!tO +known||(tO +val-m +yM)>=(yK +x11)tM +Value_t +min=cK3 +m +yM,yK +min<xG1 +min +yN +Value_t +max=cK3 +tO +val,yK +max<xG1 +max +yN +if(max<min)max +yN +bool +y21=(min<=fp_const_pihalf +xF()&&max>=fp_const_pihalf +xF());bool +nJ1=(min<=cD&&max>=cD);if(y21&&nJ1)tM +if(nJ1)nM +nU2,nW2 +if(y21)nM +yL2 +e62 +1));nM +yL2 +nW2} +case +cTan:{nM);} +case +cCeil:lD +tO +i81 +cFloor:lD +m +yI1 +tK +cTrunc:lD +m +yI1 +tO +i81 +cInt:lD +m +yI1 +tO +i81 +cSinh:tW3 +min.set(fp_sinh);tO +set(fp_sinh);tK +cTanh:tW3 +min.set(fp_tanh,plusminus1_limits.min);tO +set(fp_tanh,plusminus1_limits.max);tK +cCosh:lD +if(m +yI){if(xI2{if(m +yM>=xH1&&tO +val>=xG1{m +yM +xS} +iP1(m +yM)<xH1&&tO +val>=xG1 +l14 +tmp +xS +if(tmp>tO +val)tO +val=tmp;m +yM=e62 +1);} +else{m +yM +xS +std::swap(m +yM,tO +val);} +} +cJ3 +m +yM>=xG1{m.tL +m +yM=fp_cosh(m +yM);} +else{m.tL +m +yM=e62 +1);} +} +} +else{m +yI=true;m +yM=e62 +1);if(xI2{m +yM=fp_cosh(tO +val);m.tL} +else +m.tL} +tK +cIf:case +cAbsIf:{yD3 +res1=tZ +1));yD3 +res2=tZ +2));if(!res2 +yI)res1 +yI +eW3 +iP1 +res1 +yI&&(res2 +yM)<res1 +yM)res1 +yM=res2 +yM;if(!res2 +e61)res1.tL +iP1 +res1 +e61&&(res2 +tG1>res1 +tG1 +res1 +nL3=res2 +nL3 +i1 +res1;} +case +cMin:{bool +iT +eW3 +bool +iU +eW3 +e83;x7 +m +tZ3 +m +yI)iT +iN3 +yI||(m +yM)<nF3)nF3=m +yM;if(!xI2 +iU +iN3 +e61||(tO +val)<nG3 +nH3=tO +val;} +if(iT)nK3 +iU)nQ3 +return +nR3 +cMax:{bool +iT +eW3 +bool +iU +eW3 +e83;x7 +m +tZ3 +m +yI)iT +iN3 +yI||m +yM>nF3)nF3=m +yM;if(!xI2 +iU +iN3 +e61||tO +val>nG3 +nH3=tO +val;} +if(iT)nK3 +iU)nQ3 +return +nR3 +cAdd:{e83(xH1,xG1;x7 +item=tZ +a));if(item +yI)nF3+=item +yM;else +nK3 +item +e61)nH3+=item +nL3;else +nQ3 +if(!nI3&&!nJ3)xY3 +if(nI3&&nJ3&&nF3>nG3 +std::swap(nF3,nG3 +i1 +nR3 +cMul:{e72 +Value{enum +nT3{tT2,lG2,PlusInf} +;nT3 +eB +iK2 +value;Value(nT3 +t):eB(t),value(0){} +Value +cX3 +v):eB(tT2),value(v){} +bool +cQ2 +c01 +eB==lG2||(eB==tT2&&value<xG1;} +void +eM1*=iS1 +Value&rhs){if(eB==tT2&&rhs.eB==tT2)value*=rhs.value;else +eB=(cQ2)!=rhs.cQ2)?lG2:PlusInf);} +iD2<iS1 +Value&rhs +c01(eB==lG2&&rhs.eB!=lG2)||(eB==tT2&&(rhs.eB==PlusInf||(rhs.eB==tT2&&value<rhs.value)));} +} +;e72 +yJ1{Value +yN2,yO2;yJ1():yN2(Value::PlusInf),yO2(Value::lG2){} +void +xJ2 +Value +cM3,const +Value&value2){cM3*=value2;if(cM3<yN2)yN2=cM3;if(yO2<cM3)yO2=cM3;} +} +;e83(nM3 +x7 +item +tZ3 +item +yI&&!item +e61)nM);Value +iP3=nI3?Value(nF3):xC2 +lG2);Value +nU3=nJ3?Value(nG3:xC2 +PlusInf);Value +nV3=item +yI?Value(item +yM):xC2 +lG2);Value +nW3=item +e61?Value(item +tG1:xC2 +PlusInf);yJ1 +range;range.xJ2 +iP3,nV3);range.xJ2 +iP3,nW3);range.xJ2 +nU3,nV3);range.xJ2 +nU3,nW3);if(range.yN2.eB==Value::tT2)nF3=range.yN2.value;else +nK3 +range.yO2.eB==Value::tT2)nH3=range.yO2.value;else +nQ3 +if(!nI3&&!nJ3)xY3 +if(nI3&&nJ3&&nF3>nG3 +std::swap(nF3,nG3 +i1 +nR3 +cMod:{yD3 +x=tZ +yP2 +y=tZ +1));if(y +e61){if(y +nL3>=xG1{if(!x +yI||(x +yM)<xG1 +nM-y +nL3,y +tG1;i03 +xH1,y +tG1;} +cJ3!x +e61||(x +tG1>=xG1 +nM +y +nL3,-y +tG1;i03 +y +nL3,fp_const_negativezero +xF());} +} +i03);} +case +cPow:{if(eI1 +xW +i8==xG1{nM +nM3} +nP&&lR==xG1{nM +xH1,xG1;} +nP&&lJ3 +lR +nH2 +nM +nM3} +if(eI1 +xW +i8>xH1&&GetEvennessInfo(xW +1))==iF2)l14 +eD2 +xW +i8;yD3 +tmp=tZ +yP2 +nS3;nI3=true;nF3=0;if(tmp +yI&&tmp +yM>=xG1 +nF3=t33 +tmp +yM,tU2 +iP1 +tmp +e61&&tmp +nL3<=xG1 +nF3=t33 +tmp +nL3,tU2 +nQ3 +if(tmp +yI&&tmp +e61){nJ3=true;nH3=fp_max(fp_abs(tmp +yM),fp_abs(tmp +tG1);nH3=t33 +nH3,tU2 +eE3 +nS3;} +yD3 +tY +xW +yP2 +p1=tZ +1));TriTruthValue +p0_positivity=cN3(p0 +yM)>=xG1?iF2:(p0 +e61&&(p0 +tG1<xH1?l03 +Unknown);TriTruthValue +cR2=GetEvennessInfo(xW +1));TriTruthValue +eZ=Unknown;e23 +p0_positivity +tN1 +eZ=iF2;lC +l03{eZ=cR2;xY3 +yF3 +e23 +cR2 +tN1 +eZ=iF2;lC +l03 +lC +Unknown:{if(eI1!t42 +xW +i8)&&xW +i8>=xG1{eZ=iF2;} +xY3} +c73(eZ +tN1 +l14 +min=xH1;if +cN3 +p1 +yI){min=t33 +p0 +yM,p1 +yM);if(p0 +yM<xH1&&(!p1 +e61||p1 +nL3>=xG1&&min>=xG1 +min=xH1;} +if +cN3 +p0 +yM>=xH1&&p0 +e61&&p1 +e61)l14 +max=t33 +p0 +nL3,p1 +tG1;if(min>max)std::swap(min,max);nM +min,max);} +nM +min,false);} +case +l03{nM +false,fp_const_negativezero +xF());} +yF3{xY3 +e21 +cNeg:tW3 +set_neg();tK +cSub:yJ +cNeg);tmp2 +tX3 +tmp +iH +cAdd);tmp +tY3 +tmp +c91 +tmp2 +i0 +cInv:{c02 +lW-1))i0 +cDiv:yJ +cInv);tmp2 +tX3 +tmp +iH +xC1 +AddParamMove(tmp2 +i0 +cRad:yV +xC1 +yA +fp_const_rad_to_deg +xF())i0 +cDeg:yV +xC1 +yA +fp_const_deg_to_rad +xF())i0 +cSqr:{c02 +lW +2))i0 +cExp:yV +cPow);tmp.yA +fp_const_e +xF()));tmp.nJ +0)i0 +cExp2:yV +cPow);tmp.yA +nX3 +tmp.nJ +0)i0 +cCbrt:tW3 +min.set(fp_cbrt);tO +set(fp_cbrt);tK +cSqrt:lD +if(m +yI)m +yM=(m +yM)<xH1?0:fp_sqrt(m +yM);if(xI2 +tO +val=(tO +val)<xH1?0:fp_sqrt(tO +val);tK +cRSqrt:{c02 +lW-0.5))i0 +cHypot:{yZ2 +xsqr,ysqr,add,sqrt;xsqr +tY3 +xsqr.yA +nX3 +ysqr +tX3 +ysqr.yA +nX3 +xsqr +iH +cPow);ysqr +iH +cPow);add +c91 +xsqr);add +c91 +ysqr);add +iH +cAdd);sqrt +c91 +add);sqrt +iH +cSqrt)i1 +CalculateResultBoundaries(sqrt);} +case +cQ3:yJ +cLog2);tmp2 +tY3 +tmp +iH +cMul);tmp +c91 +tmp2);tmp.nJ +1)i0 +cCot:yJ +cTan)x6 +lH +cSec:yJ +cCos)x6 +lH +cCsc:yJ +cSin)x6 +CalculateResultBoundaries(tmp);} +lC +cRDiv:case +cRSub:case +cDup:case +cFetch:case +cPopNMov:case +cSinCos:case +cSinhCosh:case +cNop:case +cJump:case +iU2:lC +cArg:case +cConj:case +cImag:case +cReal:case +cPolar:lC +cPCall:lC +cFCall:xY3 +nM);} +tK1 +TriTruthValue +GetIntegerInfo +iS1 +eR{e23 +t72){case +cImmed:return +t42 +tree +x41)?iF2:xX3 +t83 +cFloor:case +cCeil:case +cTrunc:case +cInt:return +iF2 +t83 +cAnd:case +cOr:case +cNot:case +cNotNot:case +cEqual:case +i51:case +cLess:case +cLessOrEq:case +cGreater:case +cGreaterOrEq:return +iF2 +t83 +cIf:{TriTruthValue +a=GetIntegerInfo(xW +1));TriTruthValue +b=GetIntegerInfo(xW +2));if(a==b)return +a +xO2 +case +cAdd:case +cMul:{for +l41 +if(GetIntegerInfo(xW +a))!=iF2)return +Unknown +i1 +iF2;} +yF3 +xY3 +return +Unknown;} +yP1 +IsLogicalValue +iS1 +eR{e23 +t72){case +cImmed:return +lJ3 +tree +x41,xG1||lJ3 +tree +x41,e62 +1))t83 +cAnd:case +cOr:case +cNot:case +cNotNot:case +cAbsAnd:case +cAbsOr:case +cC3:case +cAbsNotNot:case +cEqual:case +i51:case +cLess:case +cLessOrEq:case +cGreater:case +cGreaterOrEq:nZ +cMul:{for +l41 +if(!c83 +a))cQ +lD2} +case +cIf:case +cAbsIf:yP +c83 +1))&&c83 +2));} +yF3 +xY3 +return +t23} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES; +#if defined(__x86_64) || !defined(FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS) +# define CBRT_IS_SLOW +#endif +#if defined(DEBUG_POWI) || defined(DEBUG_SUBSTITUTIONS) +#include <cstdio> +#endif +l33 +xK1{extern +const +x83 +char +powi_table[256];} +l33{using +t5 +yO1 +bool +IsOptimizableUsingPowi(long +immed,long +penalty=0){xK1::eP3 +synth;synth.PushVar(iU2);size_t +bytecodesize_backup=synth.GetByteCodeSize();xK1::x01 +immed,xK1::tU1 +xF::MulSequence,c92 +size_t +bytecode_grow_amount=synth.GetByteCodeSize()-bytecodesize_backup +i1 +bytecode_grow_amount<size_t(MAX_POWI_BYTECODE_LENGTH-penalty);} +xL1 +ChangeIntoRootChain(nP1 +bool +l13,long +tY2,long +tZ2){while(tZ2>0 +t82 +cCbrt);t92);tmp.e33 +xD2--tZ2;} +while(tY2>0 +t82 +cSqrt);if(l13){tmp +iH +cRSqrt);l13 +eW3} +t92);tmp.e33 +xD2--tY2;} +if(l13 +t82 +cInv);t92 +xD2} +} +tK1 +e72 +RootPowerTable{static +const +Value_t +RootPowers[(1+4)*(1+3)];} +yO1 +const +Value_t +t9(1+4)*(1+3)]={e62 +1)lS +2)lS +2*2)lS +2*2*2)lS +2*2*2*2)lS +3)lS +3*2)lS +3*2*2)lS +3*2*2*2)lS +3*2*2*2*2)lS +3*3)lS +3*3*2 +yG3 +yG3*2 +yG3*2*2)lS +3*3*3 +eY2 +eY2*2 +eY2*2*2 +eY2*2*2*2)} +;e72 +PowiResolver{static +const +x83 +MaxSep=4;static +x03 +i13=5;typedef +int +cO3;typedef +long +x43;typedef +long +tP;e72 +yS2{yS2():n_int_sqrt(0),n_int_cbrt(0),sep_list(),n01(0){} +int +n_int_sqrt;int +n_int_cbrt;int +tT1 +MaxSep];tP +n01;} +yO1 +static +yS2 +CreatePowiResult +cX3 +exponent){yS2 +nS3;cO3 +tA=FindIntegerFactor(tU2 +if(tA==0){ +#ifdef DEBUG_POWI +i02"no factor found for %Lg\n" +,(cP3); +#endif +return +nS3;} +nS3.n01=y31 +exponent,tA);x43 +eT2=EvaluateFactorCost(tA,0,0,0)+cC +nS3.n01);int +s_count=0;int +i23=0;int +nZ3=0; +#ifdef DEBUG_POWI +i02"orig = %Lg\n" +,(cP3);i02"plain factor = " +iL3"%ld\n" +,(int)tA,(long)eT2); +#endif +for +lT1 +n_s=0;n_s<MaxSep;++n_s){int +xD=0;x43 +yK1=eT2;cO3 +yX1=tA;for(int +s=1;s<i13*4;++s){ +#ifdef CBRT_IS_SLOW +if(s>=i13)break; +#endif +int +n_sqrt=s%i13;int +n_cbrt=s/i13;if(n_sqrt+n_cbrt>4)yA1 +Value_t +lN1=exponent;lN1-=t9 +s];iE1=FindIntegerFactor(lN1);if(xT2!=0){tP +xN=y31 +lN1,xT2);x43 +cost=EvaluateFactorCost(xT2,s_count+n_sqrt,i23+n_cbrt,nZ3+1)+cC +xN); +#ifdef DEBUG_POWI +i02"Candidate sep %u (%d*sqrt %d*cbrt)factor = " +iL3"%ld (for %Lg to %ld)\n" +,s,n_sqrt,n_cbrt,xT2,(long)cost +cX2 +lN1,(long)xN); +#endif +if(cost<yK1){xD=s;yX1=xT2;yK1=cost;} +} +} +if(!xD)break; +#ifdef DEBUG_POWI +i02"CHOSEN sep %u (%d*sqrt %d*cbrt)factor = " +iL3"%ld, exponent %Lg->%Lg\n" +,xD,xD%i13,xD/i13,yX1,yK1 +cX2(exponent)cX2(exponent-t9 +xD])); +#endif +nS3.tT1 +n_s]=xD +eX3-=t9 +xD];s_count+=xD%i13;i23+=xD/i13;eT2=yK1;tA=yX1;nZ3+=1;} +nS3.n01=y31 +exponent,tA); +#ifdef DEBUG_POWI +i02"resulting exponent is %ld (from exponent=%Lg, best_factor=%Lg)\n" +,nS3.n01,(cP3 +cX2 +tA); +#endif +while(tA%2==0){++nS3 +e52;tA/=2;} +while(tA%3==0){++nS3.n_int_cbrt;tA/=3;eE3 +nS3;} +private:static +x43 +cC +tP +xN){static +std::map +cS2 +iM;if(xN<0){x43 +cost=22 +i1 +cost+cC-xN);} +std::map +cS2::y83 +i=iM.xU2 +xN);if(i!=iM.cX1 +xN)return +i +eC2;std::pair +cS2 +nS3(xN,0.0);x43&cost=nS3.i63 +while(xN>1){int +xT2=0;if(xN<256){xT2=xK1::powi_table[xN];if(xT2&128)xT2&=127;else +xT2=0;if(xT2&64)xT2=-(xT2&63)-1;} +if(xT2){cost+=cC +xT2);xN/=xT2;yA1} +if(!(xN&1)){xN/=2;cost+=6;} +else{cost+=7;xN-=1;} +} +iM.y43,nS3)i1 +cost;} +cB1 +tP +y31 +yL1,iE1)yP +makeLongInteger(value*e62 +xT2));} +cB1 +bool +yM1 +yL1,iE1)l14 +v=value*e62 +xT2)i1 +isLongInteger(v);} +cB1 +cO3 +FindIntegerFactor(yL1){iE1=(2*2*2*2); +#ifdef CBRT_IS_SLOW +#else +xT2*=(3*3*3); +#endif +cO3 +nS3=0;if(yM1 +value,xT2)){nS3=xT2;while((xT2%2)==0&&yM1 +value,xT2/2))nS3=xT2/=2;while((xT2%3)==0&&yM1 +value,xT2/3))nS3=xT2/=3;} +#ifdef CBRT_IS_SLOW +if(nS3==0){if(yM1 +value,3 +y03 +3;} +#endif +return +nS3;} +static +int +EvaluateFactorCost(int +xT2,int +s,int +c,int +nmuls){x03 +x13=6; +#ifdef CBRT_IS_SLOW +x03 +eU2=25; +#else +x03 +eU2=8; +#endif +int +nS3=s*x13+c*eU2;while(xT2%2==0){xT2/=2;nS3+=x13;} +while(xT2%3==0){xT2/=3;nS3+=eU2;} +nS3+=nmuls +i1 +nS3;} +} +;} +t5{yP1 +yZ2::RecreateInversionsAndNegations(bool +prefer_base2){bool +changed=false +e73 +0;a<l91++a)if(lX1.RecreateInversionsAndNegations(prefer_base2))yS1 +if(changed){exit_changed:Mark_Incompletely_Hashed(yQ2 +e23 +l92{case +cMul:{eK +nE2 +tX +nF2,cR1;if(true){bool +nK1=false +iK2 +xE2=0 +e73 +tI1 +i12 +tI +0)i22 +tI +1)tD1){nK1=true;xE2=tI +i8;xY3} +if(nK1)l14 +immeds=1.0 +e73 +tI1 +tD1){immeds*=powgroup +x41;yN1} +for +iZ1 +a=l91 +a-->0;nQ&powgroup=lX1;if(powgroup +i12 +tI +0)i22 +tI +1)tD1 +nQ&log2=tI +0);log2.lD1 +log2 +iH +cQ3);log2.yA +t33 +immeds,e62 +1)/xE2)));log2 +iW1;xY3} +} +} +for +iZ1 +a=tI1 +i12 +tI +1)tD1){iT1&exp_param=tI +1)iK2 +eD2 +exp_param +x41;if(cZ1,nU2)){lD1 +nE2 +c52 +lX1 +c43 +yN1 +iP1 +exponent<xH1&&t42 +exponent)nQ +iV;iV +iH +cPow);iV +cS +tI +0));iV.yA-exponent));iV +iW1;nE2 +c52 +iV);lD1 +yN1} +iP1 +powgroup +i22!nF2.nX2){nF2=tI +0);lD1 +yN1 +iP1 +powgroup +nC==cQ3&&!cR1.nX2){cR1=powgroup;lD1 +yN1} +if(!nE2 +eU3){changed=true +tX +cF1;cF1 +iH +cMul);cF1 +iF1 +nE2);cF1 +iW1 +tX +iG +cMul);cA1 +SetParamsMove +eM +if(cA1 +IsImmed()&&fp_equal +eH2 +x41 +nH2 +eL3 +cInv)tN +cF1);} +cJ3 +cA1 +GetDepth()>=cF1 +nP2 +tC2 +cDiv +iG1 +tN +cF1);} +else{eL3 +cRDiv)tN +cF1 +iG1;} +} +} +if(nF2.nX2 +nQ +iG +l92;cA1 +SetParamsMove +eM +while(cA1 +RecreateInversionsAndNegations(prefer_base2))cA1 +tE3;eL3 +cQ3)tN +nF2 +iG1;yS1} +if(cR1.nX2 +nQ +iG +cMul);mulgroup +c91 +cR1 +l8 +1));cA1 +AddParamsMove +eM +while(cA1 +RecreateInversionsAndNegations(prefer_base2))cA1 +tE3;DelParams();eL3 +cQ3)tN +cR1 +l8 +0)iG1;yS1 +e21 +cAdd:{eK +i32 +e73 +l91 +a-->0;)if(eY3 +cMul){nG2 +y41:tX&mulgroup=cT2 +for +iZ1 +b=cA1 +l91 +b-->0;){if +eH2 +l8 +b).lV1 +xT2=mulgroup +l8 +b)x41;lG3 +xT2 +xU +y41;} +cA1 +lD1 +cA1 +i91 +b +tA2 +iP1 +lJ3 +xT2,e62-2)))eN +y41;} +cA1 +lD1 +cA1 +i91 +b);cA1 +yA +e62 +2))tA2} +} +if(t0){cA1 +tB +mulgroup);yN1} +iP1 +eY3 +cDiv&&!IsIntType +xF::nS3){nG2 +y51:tX&cF1=cT2 +if(cF1 +l8 +0)tD1){lG3 +cF1 +l8 +0)x41 +xU +y51;} +cF1.lD1 +cF1.i91 +0);cF1 +iH +cInv +tA2} +if(t0)eN +y51;} +cF1.tB +cF1);yN1} +iP1 +eY3 +cRDiv&&!IsIntType +xF::nS3){nG2 +xD1:tX&cF1=cT2 +if(cF1 +l8 +1)tD1){lG3 +cF1 +l8 +i8 +xU +xD1;} +cF1.lD1 +cF1.i91 +1);cF1 +iH +cInv +tA2} +if(t0)eN +xD1;} +cF1.tB +cF1);yN1} +if(!i32 +eU3){ +#ifdef DEBUG_SUBSTITUTIONS +i02"Will make a Sub conversion in:\n" +);fflush(stdout);l21 +#endif +yZ2 +yT2;yT2 +iH +cAdd);yT2 +iF1 +i32);yT2 +iW1 +tX +cS1;cS1 +iH +cAdd);cS1 +iF1 +lJ2));cS1 +iW1;if(cS1 +tD1&&lJ3 +cS1 +x41,xG1 +tC2 +cNeg);eC);} +cJ3 +cS1 +nP2==1 +tC2 +cRSub);eC)eV3} +iP1 +yT2 +nC==cAdd +tC2 +cSub)eV3 +eC +l8 +0)iY1 +1;a<yT2.l91++a +nQ +eV2;eV2 +iH +cSub);eV2 +iF1 +lJ2));eV2.yC2)tN +eV2);eC +n93} +} +else{eL3 +cSub)eV3 +eC);} +} +#ifdef DEBUG_SUBSTITUTIONS +i02"After Sub conversion:\n" +);fflush(stdout);l21 +#endif +e21 +cPow:{iT1&p0 +i42 +0);iT1&p1 +i42 +1);if(p1 +tD1){if(p1 +x41!=xH1&&!t42 +p1 +x41)){eG +yS2 +r=eG +CreatePowiResult(fp_abs +cR3);if(r.n01!=0){bool +lH2 +eW3 +if(p1 +x41<xH1&&r.tT1 +0]==0&&r +e52>0){lH2=true;} +#ifdef DEBUG_POWI +i02"Will resolve powi %Lg as powi(chain(%d,%d),%ld)" +cX2 +fp_abs +cR3,r +e52,r.n_int_cbrt,r.n01);for +lT1 +n=0;n<eG +MaxSep;++n){if(r +i52==0)break;int +n_sqrt=r +i52%eG +i13;int +n_cbrt=r +i52/eG +i13;i02"*chain(%d,%d)" +,n_sqrt,n_cbrt);} +i02"\n" +); +#endif +yZ2 +cU2 +i42 +0)tX +yU2=cU2;yU2.lD1 +ChangeIntoRootChain(yU2,lH2,r +e52,r.n_int_cbrt);yU2 +iW1 +tX +pow;if(r.n01!=1){pow +iH +cPow);pow +c91 +yU2);pow.yA +e62 +r.n01)));} +else +pow.swap(yU2)tX +mul;mul +iH +cMul);mul +c91 +pow);for +lT1 +n=0;n<eG +MaxSep;++n){if(r +i52==0)break;int +n_sqrt=r +i52%eG +i13;int +n_cbrt=r +i52/eG +i13 +tX +eW2=cU2;eW2.lD1 +ChangeIntoRootChain(eW2,false,n_sqrt,n_cbrt);eW2 +iW1;mul +c91 +eW2);} +if(p1 +x41<xH1&&!lH2){mul +iW1;eL3 +cInv);nB1 +0,mul);i91 +1);} +else{eL3 +cMul);SetParamsMove(mul.lJ2));} +#ifdef DEBUG_POWI +l21 +#endif +yS1 +xY3} +} +if(GetOpcode()==cPow&&(!p1 +tD1||!isLongInteger +cR3||!IsOptimizableUsingPowi +xF(makeLongInteger +cR3))){if(p0 +tD1&&p0 +x41>e62 +0.0)){if(prefer_base2)l14 +yV2=fp_log2(p0 +x41);lG3 +yV2 +nH2 +i91 +0);} +else{n0 +eA1 +yV2))eX3 +cS +p1 +t81 +nB1 +t1} +eL3 +cExp2);yS1} +else +l14 +yV2=fp_log(p0 +x41);lG3 +yV2 +nH2 +i91 +0);} +else{n0 +eA1 +yV2))eX3 +cS +p1 +t81 +nB1 +t1} +eL3 +cExp);yS1} +} +iP1 +GetPositivityInfo(p0)==iF2){if(prefer_base2 +nQ +log;log +iH +cLog2);log +cS +p0);log +iW1;n0 +p1)eX3 +c91 +log +t81 +eL3 +cExp2);nB1 +t1 +yS1} +else{yZ2 +log;log +iH +cLog);log +cS +p0);log +iW1;n0 +p1)eX3 +c91 +log +t81 +eL3 +cExp);nB1 +t1 +yS1} +} +e21 +cDiv:{if(GetParam(0)tD1&&lJ3 +GetParam(0)x41 +nH2 +eL3 +cInv);i91 +0);} +xY3 +yF3 +xY3 +if(changed)goto +exit_changed +i1 +changed;} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +using +l33 +FUNCTIONPARSERTYPES;l33{using +t5;class +eF3{size_t +nL1;size_t +eH;size_t +eI;size_t +lO1;size_t +t3;size_t +t4;size_t +n71;e43 +eF3():nL1(0),eH(0),eI(0),lO1(0),t3(0),t4(0),n71(0){} +void +i43 +OPCODE +op){nL1+=1 +i33 +cCos)++eH +i33 +cSin)++eI +i33 +cSec)++eH +i33 +cCsc)++eI +i33 +cTan)++lO1 +i33 +cCot)++lO1 +i33 +cSinh)++t4 +i33 +cCosh)++t3 +i33 +cTanh)++n71;} +size_t +GetCSEscore()const{size_t +nS3=nL1 +i1 +nS3;} +int +NeedsSinCos()const{bool +y61=(nL1==(eH+eI+lO1));if((lO1&&(eI||eH))||(eI&&eH)){if(y61)return +1 +i1 +2;eE3 +0;} +int +NeedsSinhCosh()const{bool +y61=(nL1==(t3+t4+n71));if((n71&&(t4||t3))||(t4&&t3)){if(y61)return +1 +i1 +2;eE3 +0;} +size_t +MinimumDepth()const{size_t +n_sincos=std::min(eH,eI);size_t +n_sinhcosh=std::min(t3,t4);if(n_sincos==0&&n_sinhcosh==0)return +2 +i1 +1;} +} +yO1 +class +TreeCountType:public +std::multimap<fphash_t,std::pair<eF3,yZ2> >{} +;xL1 +FindTreeCounts(tJ1&nI2,const +nP1 +OPCODE +xF2,bool +skip_root=false){cX +i=nI2.xU2 +nJ2);if(!skip_root){bool +found +eW3 +for(;i!=nI2.cX1 +nJ2;++i){if(tree +xI +i +eC2.second)){i +eC2.first.i43 +xF2);found=true;xY3} +if(!found){eF3 +count;count.i43 +xF2);nI2.y43,std::make_pair(nJ2,std::make_pair +cW3 +cU3)));} +} +x51 +FindTreeCounts(nI2,xW +a),t72);} +e72 +yW{bool +BalanceGood;bool +FoundChild;} +yO1 +yW +lP1 +iT1&root,iT1&cS3{if(root +xI +cS3){yW +nS3={true,true} +i1 +nS3;} +yW +nS3={true,false} +;if(root +nC==cIf||root +nC==t03{yW +cond=lP1 +root +l8 +0),cS3;yW +xV=lP1 +root +l8 +1),cS3;yW +y4=lP1 +root +l8 +2),cS3;if +l23||xV +yX||y4 +yX){nS3 +yX=true;} +nS3 +eD=((xV +yX==y4 +yX)||l23 +i62)&&(cond +eD||(xV +yX&&y4 +yX))&&(xV +eD||l23 +i62)&&(y4 +eD||l23 +i62);} +else{bool +iH1 +eW3 +bool +nM1=false +eK3 +b=root.GetParamCount(),a=0;a<b;++a){yW +tmp=lP1 +root +l8 +a),cS3;if(tmp +yX)nS3 +yX=true;if(tmp +eD==false)iH1=true;iP1 +tmp +yX)nM1=true;} +if(iH1&&!nM1)nS3 +eD +eW3 +eE3 +nS3;} +yP1 +cW2 +iR1 +i53 +const +nP1 +const +xK1::eP3&synth,const +tJ1&nI2){for +iZ1 +b=tree.GetParamCount(),a=0;a<b;++a){iT1&leaf=xW +a);cX +synth_it;for(x93 +tJ1::const_iterator +i=nI2.y73 +i!=nI2.end();++i){if(i->first!=leaf.GetHash())yA1 +const +eF3&occ +nY2 +first;size_t +score=occ.GetCSEscore();iT1&candidate +nY2 +i63 +if(lF2 +candidate))yA1 +if(leaf +nP2<occ.MinimumDepth())yA1 +if(score<2)yA1 +if(lP1 +i53 +leaf)eD==false)continue +l43 +if(cW2(i53 +leaf,synth,nI2))lD2 +eE3 +t23 +yP1 +iI1 +iT1&y53,iT1&expr){yY1 +y53 +lF3 +expr))lD2 +yY1 +iI1 +y53 +l8 +a),expr +y03 +true +i1 +t23 +yP1 +GoodMomentForCSE +iR1 +y53,iT1&expr){if(y53 +nC==cIf)lD2 +yY1 +y53 +lF3 +expr))lD2 +size_t +i72=0;yY1 +iI1 +y53 +l8 +a),expr))++i72 +i1 +i72!=1;} +} +t5{tK1 +size_t +yZ2::SynthCommonSubExpressions(xK1::xI1 +const{if(e91 +0)return +0;size_t +stacktop_before=synth.GetStackTop();tJ1 +nI2;FindTreeCounts(nI2,*this,GetOpcode(),true);for(;;){size_t +yW2=0; +#ifdef DEBUG_SUBSTITUTIONS_CSE +cV2<<"Finding a CSE candidate, root is:" +<<std::y11*this); +#endif +cX +cs_it(nI2.end());for(cX +j=nI2.y73 +j!=nI2.end();){cX +i(j++);const +eF3&occ +nY2 +first;size_t +score=occ.GetCSEscore();iT1&tree +nY2 +i63 +#ifdef DEBUG_SUBSTITUTIONS_CSE +cV2<<"Score " +<<score<<":\n" +<<std::flush;DumpTreeWithIndent(tree); +#endif +if(lF2 +tree))xZ +if(tree +nP2<occ.MinimumDepth())xZ +if(score<2)xZ +if(lP1*this +cU3)eD==false)xZ +if(cW2(*this +cU3,synth,nI2)){yA1} +if(!GoodMomentForCSE(*this +cU3))xZ +score*=tree +nP2;if(score>yW2){yW2=score;cs_it=i;} +} +if(yW2<=0){ +#ifdef DEBUG_SUBSTITUTIONS_CSE +cV2<<"No more CSE candidates.\n" +<<std::flush; +#endif +xY3 +iT1&tree=cs_it +eC2.i63 +#ifdef DEBUG_SUBSTITUTIONS_CSE +cV2<<iX3"Common Subexpression:" +;DumpTree +xF(tree +lE2 +std::endl; +#endif +#if 0 +int +n11=occ.NeedsSinCos();int +i9=occ.NeedsSinhCosh()tX +i82,i92,yX2,yY2;if(n11){i82 +eX2 +i82 +iH +cSin);i82 +iW1;i92 +eX2 +i92 +iH +cCos);i92 +iW1;if(lF2 +i82)||lF2 +i92))i73==2){nI2.xG2 +yA1} +n11=0;} +} +if(i9){yX2 +eX2 +yX2 +iH +cSinh);yX2 +iW1;yY2 +eX2 +yY2 +iH +cCosh);yY2 +iW1;if(lF2 +yX2)||lF2 +yY2)){if(i9==2){nI2.xG2 +yA1} +i9=0;} +} +#endif +tree.SynthesizeByteCode(synth,false);nI2.xG2 +#ifdef DEBUG_SUBSTITUTIONS_CSE +synth.x73 +Dump<0>(lE2"Done with Common Subexpression:" +;DumpTree +xF(tree +lE2 +std::endl; +#endif +#if 0 +if(n11)i73==2||i9){synth.eL1} +yB1 +cSinCos,1,2)yC1 +i82,1)yC1 +i92,0);} +if(i9)i73)synth.eL1 +if(i9==2){synth.eL1} +yB1 +cSinhCosh,1,2)yC1 +yX2,1)yC1 +yY2,0);} +#endif +eE3 +xV3 +stacktop_before;} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +tK1 +lU1 +xF::iA2{using +t5;CopyOnWrite()tX +tree;tree.GenerateFrom(*mData);FPoptimizer_Optimize::ApplyGrammars(tree);eO3 +x83>cT3;std +xM3 +xF +immed;size_t +stacktop_max=0;tree.SynthesizeByteCode(cT3,immed,stacktop_max);if(mData->mStackSize!=stacktop_max){mData->mStackSize=x83(stacktop_max); +#if !defined(FP_USE_THREAD_SAFE_EVAL) && \ + !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) +mData->mStack +xF3 +stacktop_max); +#endif +} +mData->mByteCode.swap(cT3);mData->mImmed.swap(immed);} +#define FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(type) tP1>lU1<type>::iA2{} +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +i93(MpfrFloat) +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE +i93(GmpInt) +#endif +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +i93(std::complex<double>) +#endif +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +i93(std::complex<float>) +#endif +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +i93(std::complex<long +double>) +#endif +#define FUNCTIONPARSER_INSTANTIATE_OPTIMIZE(type) x73 lU1<type>::iA2; +#ifndef FP_DISABLE_DOUBLE_TYPE +iA3(double) +#endif +#ifdef FP_SUPPORT_FLOAT_TYPE +iA3(float) +#endif +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +iA3(long +double) +#endif +#ifdef FP_SUPPORT_LONG_INT_TYPE +iA3(long) +#endif +#endif // FP_SUPPORT_OPTIMIZER + +#endif diff --git a/fparser/mpfr/GmpInt.cc b/fparser/mpfr/GmpInt.cc new file mode 100644 index 0000000..490add4 --- /dev/null +++ b/fparser/mpfr/GmpInt.cc @@ -0,0 +1,710 @@ +#include "GmpInt.hh" +#include <gmp.h> +#include <deque> +#include <vector> +#include <cstring> +#include <cctype> + +//=========================================================================== +// Shared data +//=========================================================================== +namespace +{ + unsigned long gIntDefaultNumberOfBits = 256; + + std::vector<char>& intString() + { + static std::vector<char> str; + return str; + } +} + +//=========================================================================== +// Auxiliary structs +//=========================================================================== +struct GmpInt::GmpIntData +{ + unsigned mRefCount; + GmpIntData* nextFreeNode; + mpz_t mInteger; + + GmpIntData(): mRefCount(1), nextFreeNode(0) {} +}; + +class GmpInt::GmpIntDataContainer +{ + std::deque<GmpInt::GmpIntData> mData; + GmpInt::GmpIntData* mFirstFreeNode; + GmpInt::GmpIntData* mConst_0; + + public: + GmpIntDataContainer(): mFirstFreeNode(0), mConst_0(0) {} + + ~GmpIntDataContainer() + { + for(size_t i = 0; i < mData.size(); ++i) + mpz_clear(mData[i].mInteger); + } + + GmpInt::GmpIntData* allocateGmpIntData(unsigned long numberOfBits, + bool initToZero) + { + if(mFirstFreeNode) + { + GmpInt::GmpIntData* node = mFirstFreeNode; + mFirstFreeNode = node->nextFreeNode; + if(initToZero) mpz_set_si(node->mInteger, 0); + ++(node->mRefCount); + return node; + } + + mData.push_back(GmpInt::GmpIntData()); + if(numberOfBits > 0) + mpz_init2(mData.back().mInteger, numberOfBits); + else + mpz_init(mData.back().mInteger); + return &mData.back(); + } + + void releaseGmpIntData(GmpIntData* data) + { + if(--(data->mRefCount) == 0) + { + data->nextFreeNode = mFirstFreeNode; + mFirstFreeNode = data; + } + } + + GmpInt::GmpIntData* const_0() + { + if(!mConst_0) + mConst_0 = allocateGmpIntData(gIntDefaultNumberOfBits, true); + return mConst_0; + } +}; + + +GmpInt::GmpIntDataContainer& GmpInt::gmpIntDataContainer() +{ + static GmpIntDataContainer container; + return container; +} + +//=========================================================================== +// Auxiliary functions +//=========================================================================== +void GmpInt::setDefaultNumberOfBits(unsigned long value) +{ + gIntDefaultNumberOfBits = value; +} + +unsigned long GmpInt::getDefaultNumberOfBits() +{ + return gIntDefaultNumberOfBits; +} + +inline void GmpInt::copyIfShared() +{ + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + GmpIntData* oldData = mData; + mData = gmpIntDataContainer().allocateGmpIntData(0, false); + mpz_set(mData->mInteger, oldData->mInteger); + } +} + + +//=========================================================================== +// Constructors, destructor, assignment +//=========================================================================== +GmpInt::GmpInt(DummyType): + mData(gmpIntDataContainer().allocateGmpIntData(0, false)) +{} + +GmpInt::GmpInt() +{ + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); +} + +GmpInt::GmpInt(long value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_si(mData->mInteger, value); + } +} + +GmpInt::GmpInt(unsigned long value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_ui(mData->mInteger, value); + } +} + +GmpInt::GmpInt(int value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_si(mData->mInteger, value); + } +} + +GmpInt::GmpInt(double value) +{ + const double absValue = value >= 0.0 ? value : -value; + if(absValue < 1.0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_d(mData->mInteger, value); + } +} + +GmpInt::GmpInt(long double value) +{ + const long double absValue = value >= 0.0L ? value : -value; + if(absValue < 1.0L) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_d(mData->mInteger, double(value)); + } +} + +GmpInt::GmpInt(const GmpInt& rhs): + mData(rhs.mData) +{ + ++(mData->mRefCount); +} + +GmpInt& GmpInt::operator=(const GmpInt& rhs) +{ + if(mData != rhs.mData) + { + gmpIntDataContainer().releaseGmpIntData(mData); + mData = rhs.mData; + ++(mData->mRefCount); + } + return *this; +} + +GmpInt& GmpInt::operator=(signed long value) +{ + if(value == 0) + { + gmpIntDataContainer().releaseGmpIntData(mData); + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + } + mpz_set_si(mData->mInteger, value); + } + return *this; +} + +GmpInt::~GmpInt() +{ + gmpIntDataContainer().releaseGmpIntData(mData); +} + + +//=========================================================================== +// Data getters +//=========================================================================== +template<> +void GmpInt::get_raw_mpfr_data<mpz_t>(mpz_t& dest_mpz_t) +{ + std::memcpy(&dest_mpz_t, mData->mInteger, sizeof(mpz_t)); +} + +const char* GmpInt::getAsString(int base) const +{ + intString().resize(mpz_sizeinbase(mData->mInteger, base) + 2); + return mpz_get_str(&intString()[0], base, mData->mInteger); +} + +long GmpInt::toInt() const +{ + return mpz_get_si(mData->mInteger); +} + + +//=========================================================================== +// Modifying operators +//=========================================================================== +GmpInt& GmpInt::operator+=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_add(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator+=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_add_ui(mData->mInteger, mData->mInteger, value); + else + mpz_sub_ui(mData->mInteger, mData->mInteger, -value); + return *this; +} + +GmpInt& GmpInt::operator-=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_sub(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator-=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_sub_ui(mData->mInteger, mData->mInteger, value); + else + mpz_add_ui(mData->mInteger, mData->mInteger, -value); + return *this; +} + +GmpInt& GmpInt::operator*=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_mul(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator*=(long value) +{ + copyIfShared(); + mpz_mul_si(mData->mInteger, mData->mInteger, value); + return *this; +} + +GmpInt& GmpInt::operator/=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_tdiv_q(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator/=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, value); + else + { + mpz_neg(mData->mInteger, mData->mInteger); + mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, -value); + } + return *this; +} + +GmpInt& GmpInt::operator%=(const GmpInt& rhs) +{ + copyIfShared(); + if(operator<(0)) + { + negate(); + mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + negate(); + } + else + { + mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + } + return *this; +} + +GmpInt& GmpInt::operator%=(long value) +{ + copyIfShared(); + if(value < 0) value = -value; + if(operator<(0)) + { + negate(); + mpz_mod_ui(mData->mInteger, mData->mInteger, value); + negate(); + } + else + { + mpz_mod_ui(mData->mInteger, mData->mInteger, value); + } + return *this; +} + +GmpInt& GmpInt::operator<<=(unsigned long bits) +{ + copyIfShared(); + mpz_mul_2exp(mData->mInteger, mData->mInteger, bits); + return *this; +} + +GmpInt& GmpInt::operator>>=(unsigned long bits) +{ + copyIfShared(); + mpz_tdiv_q_2exp(mData->mInteger, mData->mInteger, bits); + return *this; +} + + +//=========================================================================== +// Modifying functions +//=========================================================================== +void GmpInt::addProduct(const GmpInt& value1, const GmpInt& value2) +{ + copyIfShared(); + mpz_addmul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger); +} + +void GmpInt::addProduct(const GmpInt& value1, unsigned long value2) +{ + copyIfShared(); + mpz_addmul_ui(mData->mInteger, value1.mData->mInteger, value2); +} + +void GmpInt::subProduct(const GmpInt& value1, const GmpInt& value2) +{ + copyIfShared(); + mpz_submul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger); +} + +void GmpInt::subProduct(const GmpInt& value1, unsigned long value2) +{ + copyIfShared(); + mpz_submul_ui(mData->mInteger, value1.mData->mInteger, value2); +} + +void GmpInt::negate() +{ + copyIfShared(); + mpz_neg(mData->mInteger, mData->mInteger); +} + +void GmpInt::abs() +{ + copyIfShared(); + mpz_abs(mData->mInteger, mData->mInteger); +} + +GmpInt GmpInt::abs(const GmpInt& value) +{ + GmpInt retval(kNoInitialization); + mpz_abs(retval.mData->mInteger, value.mData->mInteger); + return retval; +} + + +//=========================================================================== +// Non-modifying operators +//=========================================================================== +GmpInt GmpInt::operator+(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_add(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator+(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_add_ui(retval.mData->mInteger, mData->mInteger, value); + else + mpz_sub_ui(retval.mData->mInteger, mData->mInteger, -value); + return retval; +} + +GmpInt GmpInt::operator-(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_sub(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator-(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_sub_ui(retval.mData->mInteger, mData->mInteger, value); + else + mpz_add_ui(retval.mData->mInteger, mData->mInteger, -value); + return retval; +} + +GmpInt GmpInt::operator*(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_mul(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator*(long value) const +{ + GmpInt retval(kNoInitialization); + mpz_mul_si(retval.mData->mInteger, mData->mInteger, value); + return retval; +} + +GmpInt GmpInt::operator/(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_tdiv_q(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator/(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_tdiv_q_ui(retval.mData->mInteger, mData->mInteger, value); + else + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_tdiv_q_ui(retval.mData->mInteger, retval.mData->mInteger, -value); + } + return retval; +} + +GmpInt GmpInt::operator%(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + if(operator<(0)) + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_mod(retval.mData->mInteger, + retval.mData->mInteger, rhs.mData->mInteger); + retval.negate(); + } + else + { + mpz_mod(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + } + return retval; +} + +GmpInt GmpInt::operator%(long value) const +{ + GmpInt retval(kNoInitialization); + if(value < 0) value = -value; + if(operator<(0)) + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_mod_ui(retval.mData->mInteger, retval.mData->mInteger, value); + retval.negate(); + } + else + { + mpz_mod_ui(retval.mData->mInteger, mData->mInteger, value); + } + return retval; +} + +GmpInt GmpInt::operator-() const +{ + GmpInt retval(kNoInitialization); + mpz_neg(retval.mData->mInteger, mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator<<(unsigned long bits) const +{ + GmpInt retval(kNoInitialization); + mpz_mul_2exp(retval.mData->mInteger, mData->mInteger, bits); + return retval; +} + +GmpInt GmpInt::operator>>(unsigned long bits) const +{ + GmpInt retval(kNoInitialization); + mpz_tdiv_q_2exp(retval.mData->mInteger, mData->mInteger, bits); + return retval; +} + + +//=========================================================================== +// Comparison operators +//=========================================================================== +bool GmpInt::operator<(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) < 0; +} + +bool GmpInt::operator<(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) < 0; +} + +bool GmpInt::operator<=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) <= 0; +} + +bool GmpInt::operator<=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) <= 0; +} + +bool GmpInt::operator>(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) > 0; +} + +bool GmpInt::operator>(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) > 0; +} + +bool GmpInt::operator>=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) >= 0; +} + +bool GmpInt::operator>=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) >= 0; +} + +bool GmpInt::operator==(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) == 0; +} + +bool GmpInt::operator==(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) == 0; +} + +bool GmpInt::operator!=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) != 0; +} + +bool GmpInt::operator!=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) != 0; +} + +void GmpInt::parseValue(const char* value) +{ + mpz_set_str(mData->mInteger, value, 10); +} + +void GmpInt::parseValue(const char* value, char** endptr) +{ + static std::vector<char> str; + + unsigned startIndex = 0; + while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex; + if(!value[startIndex]) { *endptr = const_cast<char*>(value); return; } + + unsigned endIndex = startIndex; + if(value[endIndex] == '-') ++endIndex; + if(!std::isdigit(value[endIndex])) + { *endptr = const_cast<char*>(value); return; } + if(value[endIndex] == '0' && value[endIndex+1] == 'x') + { + endIndex += 1; + while(std::isxdigit(value[++endIndex])) {} + } + else + { + while(std::isdigit(value[++endIndex])) {} + } + + str.reserve(endIndex - startIndex + 1); + str.assign(value + startIndex, value + endIndex); + str.push_back(0); + + mpz_set_str(mData->mInteger, &str[0], 0); + *endptr = const_cast<char*>(value + endIndex); +} + +GmpInt GmpInt::parseString(const char* str, char** endptr) +{ + GmpInt retval(kNoInitialization); + retval.parseValue(str, endptr); + return retval; +} + +//=========================================================================== +// Operator functions +//=========================================================================== +GmpInt operator+(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs); + else + mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + return retval; +} + +GmpInt operator-(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger); + else + { + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + mpz_neg(retval.mData->mInteger, retval.mData->mInteger); + } + return retval; +} + +GmpInt operator*(long lhs, const GmpInt& rhs) +{ + return rhs * lhs; +} + +GmpInt operator/(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) / rhs; +} + +GmpInt operator%(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) % rhs; +} diff --git a/fparser/mpfr/GmpInt.hh b/fparser/mpfr/GmpInt.hh new file mode 100644 index 0000000..1c1c171 --- /dev/null +++ b/fparser/mpfr/GmpInt.hh @@ -0,0 +1,148 @@ +#ifndef ONCE_FP_GMP_INT_HH_ +#define ONCE_FP_GMP_INT_HH_ + +#include <iostream> + +class GmpInt +{ + public: + /* A default of 256 bits will be used for all newly-instantiated GmpInt + objects. This default can be changed with the function below. + */ + static void setDefaultNumberOfBits(unsigned long); + static unsigned long getDefaultNumberOfBits(); + + GmpInt(); + GmpInt(long value); + GmpInt(unsigned long value); + GmpInt(int value); + GmpInt(double value); + GmpInt(long double value); + + GmpInt(const GmpInt&); + GmpInt& operator=(const GmpInt&); + GmpInt& operator=(signed long value); + + ~GmpInt(); + + + /* This function can be used to retrieve the raw mpz_t data structure + used by this object. (The template trick is used to avoid a dependency + of this header file with <gmp.h>.) + In other words, it can be called like: + + mpz_t raw_mpz_data; + intValue.get_raw_mpz_data(raw_mpz_data); + + Note that the returned mpz_t should be considered as read-only and + not be modified from the outside because it may be shared among + several objects. If the calling code needs to modify the data, it + should copy it for itself first with the appropriate GMP library + functions. + */ + template<typename Mpz_t> + void get_raw_mpfr_data(Mpz_t& dest_mpz_t); + + + // Note that the returned char* points to an internal (shared) buffer + // which will be valid until the next time this function is called + // (by any object). + const char* getAsString(int base = 10) const; + long toInt() const; + + GmpInt& operator+=(const GmpInt&); + GmpInt& operator+=(long); + GmpInt& operator-=(const GmpInt&); + GmpInt& operator-=(long); + GmpInt& operator*=(const GmpInt&); + GmpInt& operator*=(long); + GmpInt& operator/=(const GmpInt&); + GmpInt& operator/=(long); + GmpInt& operator%=(const GmpInt&); + GmpInt& operator%=(long); + + GmpInt& operator<<=(unsigned long); + GmpInt& operator>>=(unsigned long); + + // Equivalent to "+= value1 * value2;" + void addProduct(const GmpInt& value1, const GmpInt& value2); + void addProduct(const GmpInt& value1, unsigned long value2); + + // Equivalent to "-= value1 * value2;" + void subProduct(const GmpInt& value1, const GmpInt& value2); + void subProduct(const GmpInt& value1, unsigned long value2); + + void negate(); + void abs(); + static GmpInt abs(const GmpInt&); + + GmpInt operator+(const GmpInt&) const; + GmpInt operator+(long) const; + GmpInt operator-(const GmpInt&) const; + GmpInt operator-(long) const; + GmpInt operator*(const GmpInt&) const; + GmpInt operator*(long) const; + GmpInt operator/(const GmpInt&) const; + GmpInt operator/(long) const; + GmpInt operator%(const GmpInt&) const; + GmpInt operator%(long) const; + + GmpInt operator-() const; + + GmpInt operator<<(unsigned long) const; + GmpInt operator>>(unsigned long) const; + + bool operator<(const GmpInt&) const; + bool operator<(long) const; + bool operator<=(const GmpInt&) const; + bool operator<=(long) const; + bool operator>(const GmpInt&) const; + bool operator>(long) const; + bool operator>=(const GmpInt&) const; + bool operator>=(long) const; + bool operator==(const GmpInt&) const; + bool operator==(long) const; + bool operator!=(const GmpInt&) const; + bool operator!=(long) const; + + void parseValue(const char* value); + void parseValue(const char* value, char** endptr); + static GmpInt parseString(const char* str, char** endptr); + + + private: + struct GmpIntData; + class GmpIntDataContainer; + + GmpIntData* mData; + + enum DummyType { kNoInitialization }; + GmpInt(DummyType); + + void copyIfShared(); + static GmpIntDataContainer& gmpIntDataContainer(); + + friend GmpInt operator+(long lhs, const GmpInt& rhs); + friend GmpInt operator-(long lhs, const GmpInt& rhs); +}; + +GmpInt operator+(long lhs, const GmpInt& rhs); +GmpInt operator-(long lhs, const GmpInt& rhs); +GmpInt operator*(long lhs, const GmpInt& rhs); +GmpInt operator/(long lhs, const GmpInt& rhs); +GmpInt operator%(long lhs, const GmpInt& rhs); + +inline bool operator<(long lhs, const GmpInt& rhs) { return rhs > lhs; } +inline bool operator<=(long lhs, const GmpInt& rhs) { return rhs >= lhs; } +inline bool operator>(long lhs, const GmpInt& rhs) { return rhs < lhs; } +inline bool operator>=(long lhs, const GmpInt& rhs) { return rhs <= lhs; } +inline bool operator==(long lhs, const GmpInt& rhs) { return rhs == lhs; } +inline bool operator!=(long lhs, const GmpInt& rhs) { return rhs != lhs; } + +inline std::ostream& operator<<(std::ostream& os, const GmpInt& value) +{ + os << value.getAsString(); + return os; +} + +#endif diff --git a/fparser/mpfr/MpfrFloat.cc b/fparser/mpfr/MpfrFloat.cc new file mode 100644 index 0000000..112c684 --- /dev/null +++ b/fparser/mpfr/MpfrFloat.cc @@ -0,0 +1,976 @@ +#include "MpfrFloat.hh" +#include <stdio.h> +#include <mpfr.h> +#include <deque> +#include <vector> +#include <cstring> +#include <cassert> + +//=========================================================================== +// Auxiliary structs +//=========================================================================== +struct MpfrFloat::MpfrFloatData +{ + unsigned mRefCount; + MpfrFloatData* nextFreeNode; + mpfr_t mFloat; + + MpfrFloatData(): mRefCount(1), nextFreeNode(0) {} +}; + +class MpfrFloat::MpfrFloatDataContainer +{ + unsigned long mDefaultPrecision; + std::deque<MpfrFloatData> mData; + MpfrFloatData* mFirstFreeNode; + + MpfrFloatData + *mConst_0, *mConst_pi, *mConst_e, *mConst_log2, *mConst_epsilon; + + void recalculateEpsilon() + { + mpfr_set_si(mConst_epsilon->mFloat, 1, GMP_RNDN); + mpfr_div_2ui(mConst_epsilon->mFloat, mConst_epsilon->mFloat, + mDefaultPrecision*7/8 - 1, GMP_RNDN); + } + + public: + MpfrFloatDataContainer(): + mDefaultPrecision(256), mFirstFreeNode(0), mConst_0(0), + mConst_pi(0), mConst_e(0), mConst_log2(0), mConst_epsilon(0) + {} + + ~MpfrFloatDataContainer() + { + for(size_t i = 0; i < mData.size(); ++i) + mpfr_clear(mData[i].mFloat); + } + + MpfrFloatData* allocateMpfrFloatData(bool initToZero) + { + if(mFirstFreeNode) + { + MpfrFloatData* node = mFirstFreeNode; + mFirstFreeNode = node->nextFreeNode; + if(initToZero) mpfr_set_si(node->mFloat, 0, GMP_RNDN); + ++(node->mRefCount); + return node; + } + + mData.push_back(MpfrFloatData()); + mpfr_init2(mData.back().mFloat, mDefaultPrecision); + if(initToZero) mpfr_set_si(mData.back().mFloat, 0, GMP_RNDN); + return &mData.back(); + } + + void releaseMpfrFloatData(MpfrFloatData* data) + { + if(--(data->mRefCount) == 0) + { + data->nextFreeNode = mFirstFreeNode; + mFirstFreeNode = data; + } + } + + void setDefaultPrecision(unsigned long bits) + { + if(bits != mDefaultPrecision) + { + mDefaultPrecision = bits; + for(size_t i = 0; i < mData.size(); ++i) + mpfr_prec_round(mData[i].mFloat, bits, GMP_RNDN); + + if(mConst_pi) mpfr_const_pi(mConst_pi->mFloat, GMP_RNDN); + if(mConst_e) + { + mpfr_set_si(mConst_e->mFloat, 1, GMP_RNDN); + mpfr_exp(mConst_e->mFloat, mConst_e->mFloat, GMP_RNDN); + } + if(mConst_log2) mpfr_const_log2(mConst_log2->mFloat, GMP_RNDN); + if(mConst_epsilon) recalculateEpsilon(); + } + } + + unsigned long getDefaultPrecision() const + { + return mDefaultPrecision; + } + + MpfrFloatData* const_0() + { + if(!mConst_0) mConst_0 = allocateMpfrFloatData(true); + return mConst_0; + } + + MpfrFloat const_pi() + { + if(!mConst_pi) + { + mConst_pi = allocateMpfrFloatData(false); + mpfr_const_pi(mConst_pi->mFloat, GMP_RNDN); + } + return MpfrFloat(mConst_pi); + } + + MpfrFloat const_e() + { + if(!mConst_e) + { + mConst_e = allocateMpfrFloatData(false); + mpfr_set_si(mConst_e->mFloat, 1, GMP_RNDN); + mpfr_exp(mConst_e->mFloat, mConst_e->mFloat, GMP_RNDN); + } + return MpfrFloat(mConst_e); + } + + MpfrFloat const_log2() + { + if(!mConst_log2) + { + mConst_log2 = allocateMpfrFloatData(false); + mpfr_const_log2(mConst_log2->mFloat, GMP_RNDN); + } + return MpfrFloat(mConst_log2); + } + + MpfrFloat const_epsilon() + { + if(!mConst_epsilon) + { + mConst_epsilon = allocateMpfrFloatData(false); + recalculateEpsilon(); + } + return MpfrFloat(mConst_epsilon); + } +}; + + +//=========================================================================== +// Shared data +//=========================================================================== +// This should ensure that the container is not accessed by any MpfrFloat +// instance before it has been constructed or after it has been destroyed +// (which might otherwise happen if MpfrFloat is instantiated globally.) +MpfrFloat::MpfrFloatDataContainer& MpfrFloat::mpfrFloatDataContainer() +{ + static MpfrFloat::MpfrFloatDataContainer container; + return container; +} + + +//=========================================================================== +// Auxiliary functions +//=========================================================================== +void MpfrFloat::setDefaultMantissaBits(unsigned long bits) +{ + mpfrFloatDataContainer().setDefaultPrecision(bits); +} + +unsigned long MpfrFloat::getCurrentDefaultMantissaBits() +{ + return mpfrFloatDataContainer().getDefaultPrecision(); +} + +inline void MpfrFloat::copyIfShared() +{ + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + MpfrFloatData* oldData = mData; + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set(mData->mFloat, oldData->mFloat, GMP_RNDN); + } +} + + +//=========================================================================== +// Constructors, destructor, assignment +//=========================================================================== +MpfrFloat::MpfrFloat(DummyType): + mData(mpfrFloatDataContainer().allocateMpfrFloatData(false)) +{} + +MpfrFloat::MpfrFloat(MpfrFloatData* data): + mData(data) +{ + assert(data != 0); + ++(mData->mRefCount); +} + +MpfrFloat::MpfrFloat(): + mData(mpfrFloatDataContainer().const_0()) +{ + ++(mData->mRefCount); +} + +MpfrFloat::MpfrFloat(double value) +{ + if(value == 0.0) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_d(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(long double value) +{ + if(value == 0.0L) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_ld(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(long value) +{ + if(value == 0) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(int value) +{ + if(value == 0) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(const char* value, char** endptr): + mData(mpfrFloatDataContainer().allocateMpfrFloatData(false)) +{ + mpfr_strtofr(mData->mFloat, value, endptr, 0, GMP_RNDN); +} + +MpfrFloat::~MpfrFloat() +{ + mpfrFloatDataContainer().releaseMpfrFloatData(mData); +} + +MpfrFloat::MpfrFloat(const MpfrFloat& rhs): + mData(rhs.mData) +{ + ++(mData->mRefCount); +} + +MpfrFloat& MpfrFloat::operator=(const MpfrFloat& rhs) +{ + if(mData != rhs.mData) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = rhs.mData; + ++(mData->mRefCount); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(double value) +{ + if(value == 0.0) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_d(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(long double value) +{ + if(value == 0.0L) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_ld(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(long value) +{ + if(value == 0) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(int value) +{ + if(value == 0) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +/* +MpfrFloat& MpfrFloat::operator=(const char* value) +{ + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + + mpfr_set_str(mData->mFloat, value, 10, GMP_RNDN); + return *this; +} +*/ + +void MpfrFloat::parseValue(const char* value) +{ + copyIfShared(); + mpfr_set_str(mData->mFloat, value, 10, GMP_RNDN); +} + +void MpfrFloat::parseValue(const char* value, char** endptr) +{ + copyIfShared(); + mpfr_strtofr(mData->mFloat, value, endptr, 0, GMP_RNDN); +} + + +//=========================================================================== +// Data getters +//=========================================================================== +template<> +void MpfrFloat::get_raw_mpfr_data<mpfr_t>(mpfr_t& dest_mpfr_t) +{ + std::memcpy(&dest_mpfr_t, mData->mFloat, sizeof(mpfr_t)); +} + +const char* MpfrFloat::getAsString(unsigned precision) const +{ +#if(MPFR_VERSION_MAJOR < 2 || (MPFR_VERSION_MAJOR == 2 && MPFR_VERSION_MINOR < 4)) + static const char* retval = + "[mpfr_snprintf() is not supported in mpfr versions prior to 2.4]"; + return retval; +#else + static std::vector<char> str; + str.resize(precision+30); + mpfr_snprintf(&(str[0]), precision+30, "%.*RNg", precision, mData->mFloat); + return &(str[0]); +#endif +} + +bool MpfrFloat::isInteger() const +{ + return mpfr_integer_p(mData->mFloat) != 0; +} + +long MpfrFloat::toInt() const +{ + return mpfr_get_si(mData->mFloat, GMP_RNDN); +} + +double MpfrFloat::toDouble() const +{ + return mpfr_get_d(mData->mFloat, GMP_RNDN); +} + + +//=========================================================================== +// Modifying operators +//=========================================================================== +MpfrFloat& MpfrFloat::operator+=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_add(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator+=(double value) +{ + copyIfShared(); + mpfr_add_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator-=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_sub(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator-=(double value) +{ + copyIfShared(); + mpfr_sub_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator*=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_mul(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator*=(double value) +{ + copyIfShared(); + mpfr_mul_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator/=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_div(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator/=(double value) +{ + copyIfShared(); + mpfr_div_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator%=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_fmod(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + + +//=========================================================================== +// Modifying functions +//=========================================================================== +void MpfrFloat::negate() +{ + copyIfShared(); + mpfr_neg(mData->mFloat, mData->mFloat, GMP_RNDN); +} + +void MpfrFloat::abs() +{ + copyIfShared(); + mpfr_abs(mData->mFloat, mData->mFloat, GMP_RNDN); +} + + +//=========================================================================== +// Non-modifying operators +//=========================================================================== +MpfrFloat MpfrFloat::operator+(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_add(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator+(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_add_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_sub(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_sub_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator*(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_mul(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator*(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_mul_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator/(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_div(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator/(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_div_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator%(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_fmod(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-() const +{ + MpfrFloat retval(kNoInitialization); + mpfr_neg(retval.mData->mFloat, mData->mFloat, GMP_RNDN); + return retval; +} + + + +//=========================================================================== +// Comparison operators +//=========================================================================== +bool MpfrFloat::operator<(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) < 0; +} + +bool MpfrFloat::operator<(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) < 0; +} + +bool MpfrFloat::operator<=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) <= 0; +} + +bool MpfrFloat::operator<=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) <= 0; +} + +bool MpfrFloat::operator>(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) > 0; +} + +bool MpfrFloat::operator>(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) > 0; +} + +bool MpfrFloat::operator>=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) >= 0; +} + +bool MpfrFloat::operator>=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) >= 0; +} + +bool MpfrFloat::operator==(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) == 0; +} + +bool MpfrFloat::operator==(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) == 0; +} + +bool MpfrFloat::operator!=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) != 0; +} + +bool MpfrFloat::operator!=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) != 0; +} + + +//=========================================================================== +// Operator functions +//=========================================================================== +MpfrFloat operator+(double lhs, const MpfrFloat& rhs) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_add_d(retval.mData->mFloat, rhs.mData->mFloat, lhs, GMP_RNDN); + return retval; +} + +MpfrFloat operator-(double lhs, const MpfrFloat& rhs) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_d_sub(retval.mData->mFloat, lhs, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat operator*(double lhs, const MpfrFloat& rhs) +{ + return rhs * lhs; +} + +MpfrFloat operator/(double lhs, const MpfrFloat& rhs) +{ + return MpfrFloat(lhs) / rhs; +} + +MpfrFloat operator%(double lhs, const MpfrFloat& rhs) +{ + return MpfrFloat(lhs) % rhs; +} + +std::ostream& operator<<(std::ostream& os, const MpfrFloat& value) +{ + os << value.getAsString(unsigned(os.precision())); + return os; +} + +//=========================================================================== +// Static functions +//=========================================================================== +MpfrFloat MpfrFloat::log(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::log2(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::log10(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp2(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp10(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cos(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sin(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::tan(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_tan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sec(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sec(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::csc(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_csc(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cot(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cot(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +void MpfrFloat::sincos(const MpfrFloat& value, + MpfrFloat& sin, + MpfrFloat& cos) +{ + sin.copyIfShared(); + cos.copyIfShared(); + mpfr_sin_cos + (sin.mData->mFloat, cos.mData->mFloat, value.mData->mFloat, GMP_RNDN); +} + +MpfrFloat MpfrFloat::acos(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asin(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan2(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan2(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::hypot(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_hypot(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::tanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_tanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::acosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sqrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sqrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cbrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cbrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::root(const MpfrFloat& value, unsigned long root) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_root(retval.mData->mFloat, value.mData->mFloat, root, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value, long exponent) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow_si(retval.mData->mFloat, value.mData->mFloat, exponent, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::abs(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_abs(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::dim(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_dim(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::round(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_round(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::ceil(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_ceil(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::floor(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_floor(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::trunc(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_trunc(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::parseString(const char* str, char** endptr) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_strtofr(retval.mData->mFloat, str, endptr, 0, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::const_pi() +{ + return mpfrFloatDataContainer().const_pi(); +} + +MpfrFloat MpfrFloat::const_e() +{ + return mpfrFloatDataContainer().const_e(); +} + +MpfrFloat MpfrFloat::const_log2() +{ + return mpfrFloatDataContainer().const_log2(); +} + +MpfrFloat MpfrFloat::someEpsilon() +{ + return mpfrFloatDataContainer().const_epsilon(); +} diff --git a/fparser/mpfr/MpfrFloat.hh b/fparser/mpfr/MpfrFloat.hh new file mode 100644 index 0000000..d455d24 --- /dev/null +++ b/fparser/mpfr/MpfrFloat.hh @@ -0,0 +1,206 @@ +#ifndef ONCE_FP_MPFR_FLOAT_ +#define ONCE_FP_MPFR_FLOAT_ + +#include <iostream> + +class MpfrFloat +{ + public: + /* A default of 256 bits will be used unless changed with this function. + Note that all existing and cached GMP objects will be resized to the + specified precision (which can be a somewhat heavy operation). + */ + static void setDefaultMantissaBits(unsigned long bits); + + static unsigned long getCurrentDefaultMantissaBits(); + + /* The default constructor initializes the object to the value 0. + It's efficient to instantiate such zero-initialized objects because + all of them will share the same mpfr data. (Also any object initialized + with or assigned the explicit value of zero will also share that one + mpfr data.) Thus multiple zero-initialized MpfrFloat instances won't + consume significant amounts of memory (until they are modified to + contain some other value, of course). + + Important caveat: + ---------------- + Note that initializing an MpfrFloat object with, for example, 0.1 will + suffer from accuracy problems (at least if the MpfrFloat object has + more mantissa bits than a double). The C++ double value 0.1 has only + 53 mantissa bits, while the MpfrFloat object usually has more. If the + MpfrFloat object is initialized with a double, only that many bits of + accuracy will end up in the value of the MpfrFloat object. This can + create significant rounding/accuracy problems in some cases. + If you need to initialize the MpfrObject with some value (which cannot + be represented accurately by base-2 floating point numbers, eg. 0.1) + at full mantissa precision, you have to use parseValue("0.1") instead, + rather than relying on the constructor taking a double type value. + */ + MpfrFloat(); + MpfrFloat(double value); + MpfrFloat(long double value); + MpfrFloat(long value); + MpfrFloat(int value); + MpfrFloat(const char* value, char** endptr); + + ~MpfrFloat(); + + MpfrFloat(const MpfrFloat&); + + MpfrFloat& operator=(const MpfrFloat&); + MpfrFloat& operator=(double value); + MpfrFloat& operator=(long double value); + MpfrFloat& operator=(long value); + MpfrFloat& operator=(int value); + //MpfrFloat& operator=(const char* value); + + void parseValue(const char* value); + void parseValue(const char* value, char** endptr); + + + /* This function can be used to retrieve the raw mpfr_t data structure + used by this object. (The template trick is used to avoid a dependency + of this header file with <mpfr.h>.) + In other words, it can be called like: + + mpfr_t raw_mpfr_data; + floatValue.get_raw_mpfr_data(raw_mpfr_data); + + Note that the returned mpfr_t should be considered as read-only and + not be modified from the outside because it may be shared among + several objects. If the calling code needs to modify the data, it + should copy it for itself first with the appropriate MPFR library + functions. + */ + template<typename Mpfr_t> + void get_raw_mpfr_data(Mpfr_t& dest_mpfr_t); + + + /* Note that the returned char* points to an internal (shared) buffer + which will be valid until the next time this function is called + (by any object). + */ + const char* getAsString(unsigned precision) const; + + bool isInteger() const; + long toInt() const; + double toDouble() const; + + MpfrFloat& operator+=(const MpfrFloat&); + MpfrFloat& operator+=(double); + MpfrFloat& operator-=(const MpfrFloat&); + MpfrFloat& operator-=(double); + MpfrFloat& operator*=(const MpfrFloat&); + MpfrFloat& operator*=(double); + MpfrFloat& operator/=(const MpfrFloat&); + MpfrFloat& operator/=(double); + MpfrFloat& operator%=(const MpfrFloat&); + + void negate(); + void abs(); + + MpfrFloat operator+(const MpfrFloat&) const; + MpfrFloat operator+(double) const; + MpfrFloat operator-(const MpfrFloat&) const; + MpfrFloat operator-(double) const; + MpfrFloat operator*(const MpfrFloat&) const; + MpfrFloat operator*(double) const; + MpfrFloat operator/(const MpfrFloat&) const; + MpfrFloat operator/(double) const; + MpfrFloat operator%(const MpfrFloat&) const; + + MpfrFloat operator-() const; + + bool operator<(const MpfrFloat&) const; + bool operator<(double) const; + bool operator<=(const MpfrFloat&) const; + bool operator<=(double) const; + bool operator>(const MpfrFloat&) const; + bool operator>(double) const; + bool operator>=(const MpfrFloat&) const; + bool operator>=(double) const; + bool operator==(const MpfrFloat&) const; + bool operator==(double) const; + bool operator!=(const MpfrFloat&) const; + bool operator!=(double) const; + + static MpfrFloat log(const MpfrFloat&); + static MpfrFloat log2(const MpfrFloat&); + static MpfrFloat log10(const MpfrFloat&); + static MpfrFloat exp(const MpfrFloat&); + static MpfrFloat exp2(const MpfrFloat&); + static MpfrFloat exp10(const MpfrFloat&); + static MpfrFloat cos(const MpfrFloat&); + static MpfrFloat sin(const MpfrFloat&); + static MpfrFloat tan(const MpfrFloat&); + static MpfrFloat sec(const MpfrFloat&); + static MpfrFloat csc(const MpfrFloat&); + static MpfrFloat cot(const MpfrFloat&); + static void sincos(const MpfrFloat&, MpfrFloat& sin, MpfrFloat& cos); + static MpfrFloat acos(const MpfrFloat&); + static MpfrFloat asin(const MpfrFloat&); + static MpfrFloat atan(const MpfrFloat&); + static MpfrFloat atan2(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat hypot(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat cosh(const MpfrFloat&); + static MpfrFloat sinh(const MpfrFloat&); + static MpfrFloat tanh(const MpfrFloat&); + static MpfrFloat acosh(const MpfrFloat&); + static MpfrFloat asinh(const MpfrFloat&); + static MpfrFloat atanh(const MpfrFloat&); + static MpfrFloat sqrt(const MpfrFloat&); + static MpfrFloat cbrt(const MpfrFloat&); + static MpfrFloat root(const MpfrFloat&, unsigned long root); + static MpfrFloat pow(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat pow(const MpfrFloat&, long exponent); + static MpfrFloat abs(const MpfrFloat&); + static MpfrFloat dim(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat round(const MpfrFloat&); + static MpfrFloat ceil(const MpfrFloat&); + static MpfrFloat floor(const MpfrFloat&); + static MpfrFloat trunc(const MpfrFloat&); + + static MpfrFloat parseString(const char* str, char** endptr); + + // These values are cached (and recalculated every time the mantissa bits + // change), so it's efficient to call these repeatedly: + static MpfrFloat const_pi(); + static MpfrFloat const_e(); + static MpfrFloat const_log2(); + static MpfrFloat someEpsilon(); + + + private: + struct MpfrFloatData; + class MpfrFloatDataContainer; + + MpfrFloatData* mData; + + enum DummyType { kNoInitialization }; + MpfrFloat(DummyType); + MpfrFloat(MpfrFloatData*); + + void copyIfShared(); + static MpfrFloatDataContainer& mpfrFloatDataContainer(); + + friend MpfrFloat operator+(double lhs, const MpfrFloat& rhs); + friend MpfrFloat operator-(double lhs, const MpfrFloat& rhs); +}; + +MpfrFloat operator+(double lhs, const MpfrFloat& rhs); +MpfrFloat operator-(double lhs, const MpfrFloat& rhs); +MpfrFloat operator*(double lhs, const MpfrFloat& rhs); +MpfrFloat operator/(double lhs, const MpfrFloat& rhs); +MpfrFloat operator%(double lhs, const MpfrFloat& rhs); + +inline bool operator<(double lhs, const MpfrFloat& rhs) { return rhs > lhs; } +inline bool operator<=(double lhs, const MpfrFloat& rhs) { return rhs >= lhs; } +inline bool operator>(double lhs, const MpfrFloat& rhs) { return rhs < lhs; } +inline bool operator>=(double lhs, const MpfrFloat& rhs) { return rhs <= lhs; } +inline bool operator==(double lhs, const MpfrFloat& rhs) { return rhs == lhs; } +inline bool operator!=(double lhs, const MpfrFloat& rhs) { return rhs != lhs; } + +// This function takes into account the value of os.precision() +std::ostream& operator<<(std::ostream& os, const MpfrFloat& value); + +#endif |