From b4963e5e4be010e2beb9e90cd17d12eb4d114612 Mon Sep 17 00:00:00 2001 From: maier Date: Sun, 30 Sep 2012 11:02:44 +0000 Subject: [PATCH] Bump fparser to version 4.5 git-svn-id: https://svn.dealii.org/branches/branch_cmake@26888 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/TODO.CMAKE | 12 +- deal.II/cmake/setup_deal_ii.cmake | 2 + deal.II/contrib/README.contrib | 6 +- deal.II/contrib/functionparser/CMakeLists.txt | 2 +- deal.II/contrib/functionparser/Makefile | 21 - deal.II/contrib/functionparser/README | 7 + .../contrib/functionparser/docs/fparser.html | 1848 +++ deal.II/contrib/functionparser/docs/gpl.txt | 674 + deal.II/contrib/functionparser/docs/lgpl.txt | 165 + deal.II/contrib/functionparser/docs/style.css | 80 + .../functionparser/{ => examples}/example.cc | 105 +- .../functionparser/examples/example2.cc | 85 + .../extrasrc/fp_identifier_parser.inc | 379 + .../functionparser/extrasrc/fp_opcode_add.inc | 7748 +++++++++ .../contrib/functionparser/extrasrc/fpaux.hh | 1295 ++ .../functionparser/extrasrc/fptypes.hh | 288 + deal.II/contrib/functionparser/fparser.cc | 4487 +++-- deal.II/contrib/functionparser/fparser.h | 176 - deal.II/contrib/functionparser/fparser.hh | 224 + deal.II/contrib/functionparser/fparser.txt | 897 - .../contrib/functionparser/fparser_gmpint.hh | 15 + .../contrib/functionparser/fparser_mpfr.hh | 15 + deal.II/contrib/functionparser/fpconfig.h | 67 - deal.II/contrib/functionparser/fpconfig.hh | 82 + deal.II/contrib/functionparser/fpoptimizer.cc | 13789 +++++++++++++--- deal.II/contrib/functionparser/fptypes.h | 117 - deal.II/contrib/functionparser/lgpl-3.0.txt | 165 + deal.II/contrib/functionparser/mpfr/GmpInt.cc | 710 + deal.II/contrib/functionparser/mpfr/GmpInt.hh | 148 + .../contrib/functionparser/mpfr/MpfrFloat.cc | 976 ++ .../contrib/functionparser/mpfr/MpfrFloat.hh | 206 + deal.II/source/base/function_parser.cc | 9 +- 32 files changed, 30308 insertions(+), 4492 deletions(-) delete mode 100644 deal.II/contrib/functionparser/Makefile create mode 100644 deal.II/contrib/functionparser/README create mode 100644 deal.II/contrib/functionparser/docs/fparser.html create mode 100644 deal.II/contrib/functionparser/docs/gpl.txt create mode 100644 deal.II/contrib/functionparser/docs/lgpl.txt create mode 100644 deal.II/contrib/functionparser/docs/style.css rename deal.II/contrib/functionparser/{ => examples}/example.cc (83%) create mode 100644 deal.II/contrib/functionparser/examples/example2.cc create mode 100644 deal.II/contrib/functionparser/extrasrc/fp_identifier_parser.inc create mode 100644 deal.II/contrib/functionparser/extrasrc/fp_opcode_add.inc create mode 100644 deal.II/contrib/functionparser/extrasrc/fpaux.hh create mode 100644 deal.II/contrib/functionparser/extrasrc/fptypes.hh delete mode 100644 deal.II/contrib/functionparser/fparser.h create mode 100644 deal.II/contrib/functionparser/fparser.hh delete mode 100644 deal.II/contrib/functionparser/fparser.txt create mode 100644 deal.II/contrib/functionparser/fparser_gmpint.hh create mode 100644 deal.II/contrib/functionparser/fparser_mpfr.hh delete mode 100644 deal.II/contrib/functionparser/fpconfig.h create mode 100644 deal.II/contrib/functionparser/fpconfig.hh delete mode 100644 deal.II/contrib/functionparser/fptypes.h create mode 100644 deal.II/contrib/functionparser/lgpl-3.0.txt create mode 100644 deal.II/contrib/functionparser/mpfr/GmpInt.cc create mode 100644 deal.II/contrib/functionparser/mpfr/GmpInt.hh create mode 100644 deal.II/contrib/functionparser/mpfr/MpfrFloat.cc create mode 100644 deal.II/contrib/functionparser/mpfr/MpfrFloat.hh diff --git a/deal.II/TODO.CMAKE b/deal.II/TODO.CMAKE index 07280ccdbf..0a19e9f453 100644 --- a/deal.II/TODO.CMAKE +++ b/deal.II/TODO.CMAKE @@ -5,16 +5,16 @@ Major: * Add the rest of the Bug tests -* Bump functionparser to version 4.5 +* Test the fparser 4.5 functionality. * The following features have to be written: * MUMPS * SLEPC * HDF5 - * HSL * TECPLOT * Write a wrapper around cmake. Something like + * download and 'install' cmake if necessary $ make config $ make ... @@ -43,13 +43,7 @@ Minor: * What to do with ./lib/meshes ? I have moved it to ./contrib/meshes for the time being... -* The original decision to have a dedicated p4est/FAST and p4est/DEBUG - structure is a bit unfortunate and therefor replaced by a FindP4EST - module that searches libp4est.so and treats this as FAST and - libp4est_debug.so or libp4est.g.so and treats this as debug library. - TODO: Update the p4est-setup.sh script... - -* Reenable support for metis versions 4.x ?! +* TODO: Update the p4est-setup.sh script... * The contrib libraries are included too early. User CXX_FLAGS won't be included in the contrib object targets... diff --git a/deal.II/cmake/setup_deal_ii.cmake b/deal.II/cmake/setup_deal_ii.cmake index cf3ee14316..233acea212 100644 --- a/deal.II/cmake/setup_deal_ii.cmake +++ b/deal.II/cmake/setup_deal_ii.cmake @@ -34,6 +34,8 @@ # # DEAL_II_INCLUDE_DIRS # DEAL_II_LIBRARIES +# DEAL_II_LIBRARIES_DEBUG +# DEAL_II_LIBRARIES_RELEASE # # DEAL_II_BUILD_TYPES # diff --git a/deal.II/contrib/README.contrib b/deal.II/contrib/README.contrib index f962480b72..77c8ee36a9 100644 --- a/deal.II/contrib/README.contrib +++ b/deal.II/contrib/README.contrib @@ -18,11 +18,11 @@ boost-1.49.0/LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt A full version of the library can be downloaded at http://www.boost.org/. -functionparser (TODO: for fparser4.5) +functionparser ============== -Contains the functionparser project which copyrighted by Juha Nieminen and -licensed under the GNU Lesser General Public License (LGPL) Version 3. +Contains the functionparser project which is copyrighted by Juha Nieminen +and licensed under the GNU Lesser General Public License (LGPL) Version 3. See functionparser/README, functionparser/lgpl-3.0.txt or http://warp.povusers.org/FunctionParser/ diff --git a/deal.II/contrib/functionparser/CMakeLists.txt b/deal.II/contrib/functionparser/CMakeLists.txt index f6997c24d4..c32d8011da 100644 --- a/deal.II/contrib/functionparser/CMakeLists.txt +++ b/deal.II/contrib/functionparser/CMakeLists.txt @@ -1 +1 @@ -DEAL_II_ADD_LIBRARY(obj_functionparser OBJECT "fparser.cc") +DEAL_II_ADD_LIBRARY(obj_functionparser OBJECT fparser.cc) diff --git a/deal.II/contrib/functionparser/Makefile b/deal.II/contrib/functionparser/Makefile deleted file mode 100644 index 08ab75cca8..0000000000 --- a/deal.II/contrib/functionparser/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# $Id$ -# Copyright (C) 2005, 2008 by Wolfgang Bangerth - - -D = ../.. - -include $D/common/Make.global_options - -# rules -$(LIBDIR)/contrib/functionparser/fparser.$(OBJEXT): fparser.cc fparser.h - @echo =====function parser==optimized==$(MT)== $( + + + + + Function Parser for C++ v4.5 : Documentation + + + +

Function Parser for C++ v4.5

+ +

Authors: Juha Nieminen +(http://iki.fi/warp/), +Joel Yliluoma +(http://iki.fi/bisqwit/). + +

The usage license of this library is located at the end of this file. + +

Table of contents:

+ + + + +

What's new

+ +

What's new in v4.5 +

+ + + + + +

Preface

+ +

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. + +

For example, a function like "sin(sqrt(x*x+y*y))" can be +parsed from a string (either std::string or a C-style string) +and then evaluated with different values of x and y. +This library can be useful for evaluating user-inputted functions, or in +some cases interpreting mathematical expressions in a scripting language. + +

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. + +

Different numerical types are supported: double, + float, long double, long int, + std::complex (of types double, + float and long double), + 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.) + + + + +

Usage

+ +

To use the FunctionParser class, you have to include +"fparser.hh" in your source code files which use the +FunctionParser class. + +

If you are going to use the MPFR version of the library, you need to +include "fparser_mpfr.hh". If you are going to use the GMP +version of the library, you need to include "fparser_gmpint.hh". +(Note that support for these special parser versions needs to be specified +with preprocessor macros. See the documentation +below for details.) + +

When compiling, you have to compile fparser.cc and +fpoptimizer.cc 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). + +

If you are going to use the MPFR or the GMP versions of the library, +you also need to add mpfr/MpfrFloat.cc or +mpfr/GmpInt.cc files to your project, respectively. Otherwise +they should not be added to the project. + +

Note that part of the library source code is inside several +.inc files inside the extrasrc subdirectory +(these files contain auto-generated C++ code), provided in the library +package. These files are used by fparser.cc 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 extrasrc subdirectory. + +

Simple usage example of the library: + +

+    FunctionParser fp;
+    fp.Parse("sqrt(x*x + y*y)", "x,y");
+    double variables[2] = { 1.5, 2.9 };
+    double result = fp.Eval(variables);
+
+ + + +

Parser types

+ +

Different versions of the function parser class are supported, using + different floating point or integral types for function evaluation. + +

All the classes other than the default one, FunctionParser, + need to be enabled at compile time by defining a preprocessor macro + (specified below) either in the fpconfig.hh 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.) + +

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. + +

Currently the Optimize() method works only for the + FunctionParser, FunctionParser_f and + FunctionParser_ld classes. For the other types it can be + called but it does nothing. + +

+

+

FunctionParser

+
+

This is the default class, which uses double as its + numerical type. This is the only class enabled by default. +

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 FP_DISABLE_DOUBLE_TYPE. +

+ +

FunctionParser_f

+
+

This parser uses float as its numerical type. +

The FP_SUPPORT_FLOAT_TYPE preprocessor macro needs to be + defined for this class to be enabled. +

+ +

FunctionParser_ld

+
+

This parser uses long double as its numerical type. +

The FP_SUPPORT_LONG_DOUBLE_TYPE preprocessor macro needs + to be defined for this class to be enabled. +

Note that the FP_USE_STRTOLD preprocessor macro should + also be defined when using this version of the parser if the compiler + supports the (C99) function strtold(). (See + documentation below.) +

+ +

FunctionParser_li

+
+

This parser uses long int as its numerical type. +

The FP_SUPPORT_LONG_INT_TYPE preprocessor macro needs + to be defined for this class to be enabled. +

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 abs(), eval(), + if(), min() and max(), besides + basic arithmetic operators, except for the power operator). +

+ +

FunctionParser_cd, FunctionParser_cf, + FunctionParser_cld

+
+

These parsers use std::complex<double>, + std::complex<float> and + std::complex<long double> as their numerical type, + respectively. +

The preprocessor macros to enable them are + FP_SUPPORT_COMPLEX_DOUBLE_TYPE, + FP_SUPPORT_COMPLEX_FLOAT_TYPE and + FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE. +

If FunctionParser_cld is used, the + FP_USE_STRTOLD macro should also be defined if the compiler + supports the strtold() function. +

+ +

FunctionParser_mpfr

+
+

This parser uses MpfrFloat as its numerical type. +

The FP_SUPPORT_MPFR_FLOAT_TYPE preprocessor macro needs + to be defined for this class to be enabled. +

Note that to use this version of the parser, + "fparser_mpfr.hh" needs to be included. +

MpfrFloat 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 + mpfr/MpfrFloat.hh file (see that file for info about + the public interface of the class). +

If this class is enabled, mpfr/MpfrFloat.cc + 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 + "-lgmp -lmpfr".) +

+ +

FunctionParser_gmpint

+
+

This parser uses GmpInt as its numerical type. +

The FP_SUPPORT_GMP_INT_TYPE preprocessor macro needs + to be defined for this class to be enabled. +

Note that to use this version of the parser, + "fparser_gmpint.hh" needs to be included. +

GmpInt 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 + mpfr/GmpInt.hh file (see that file for info about + the public interface of the class). +

If this class is enabled, mpfr/GmpInt.cc + needs to be compiled into the project, as well as the GMP library. +

This version of the class also uses a reduced version of the syntax, + like the long int version. +

Note: 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. +

+
+ +

Note that these different classes are completely independent and + instances of different classes cannot be given to each other using the + AddFunction() method. Only objects of the same type can + be given to that method. + +

The rest of the documentation assumes that FunctionParser + (which uses the double type) is used. The usage of the other + classes is identical except that double is replaced with the + correspondent type used by that class. (In other words, whenever the + rest of this documentation uses the type keyword 'double', + the correspondent type should be used instead, when using another version + of the class.) + + + +

Configuring the compilation

+ +

There is a set of precompiler options in the fpconfig.hh file +which can be used for setting certain features on or off. All of these options +can also be specified from the outside, using precompiler settings (eg. the +-D option in gcc), and thus it's not necessary to modify this +file. + +

+

FP_USE_STRTOLD : (Default off)

+

If FunctionParser_ld or FunctionParser_cld + are used, this preprocessor macro should be defined if the compiler + supports the (C99) function strtold(). 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 strtold() will also be automatically used + if __cplusplus indicates that C++11 is in use. +

+ +

FP_SUPPORT_OPTIMIZER : (Default on)

+

If you are not going to use the Optimize() method, you + can comment this line out to speed-up the compilation a bit, as + well as making the binary a bit smaller. (Optimize() can + still be called, but it will not do anything.) + +

You can also disable the optimizer by specifying the + FP_NO_SUPPORT_OPTIMIZER precompiler constant in your + compiler settings. +

+ +

FP_USE_THREAD_SAFE_EVAL : (Default off)

+

Define this precompiler constant to make Eval() + thread-safe. Refer to the thread safety + section later in this document for more information. + Note that defining this may make Eval() slightly slower. +

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. +

+ +

FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA : (Default off)

+

This is like the previous, but makes Eval() use the + alloca() function (instead of std::vector). + This will make it faster, but the alloca() + function is not standard and thus not supported by all compilers. +

+
+ + + + +

Copying and assignment

+ +

The class implements a safe copy constructor and assignment operator. + +

It uses the copy-on-write technique for efficiency. This means that + when copying or assigning a FunctionParser instance, the internal data + (which in some cases can be quite lengthy) is not immediately copied + but only when the contents of the copy (or the original) are changed. + +

This means that copying/assigning is a very fast operation, and if + the copies are never modified then actual data copying never happens + either. + +

The Eval() and EvalError() methods of the +copy can be called without the internal data being copied. + +

Calling Parse(), Optimize() or the user-defined +constant/function adding methods will cause a deep-copy. + + + + +

Short descriptions of FunctionParser methods

+ +
+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);
+
+ +

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. + +


+
+void setDelimiterChar(char);
+
+ +

Sets an ending delimiter character for the function string. (See the + long description for more details.) + +


+
+static double epsilon();
+static void setEpsilon(double);
+
+ +

Setter and getter for the epsilon value used with comparison operators. + +


+
+const char* ErrorMsg(void) const;
+
+ +

Returns an error message corresponding to the error in +Parse(), or an empty string if no such error occurred. + +


+
+ParseErrorType GetParseErrorType() const;
+
+ +

Returns the type of parsing error which occurred. Possible return types + are described in the long description. + +


+
+double Eval(const double* Vars);
+
+ +

Evaluates the function given to Parse(). + +


+
+int EvalError(void) const;
+
+ +

Returns 0 if no error happened in the previous call to +Eval(), else an error code >0. + +


+
+void Optimize();
+
+ +

Tries to optimize the bytecode for faster evaluation. + +


+
+bool AddConstant(const std::string& name, double value);
+
+ +

Add a constant to the parser. Returns false if the name of +the constant is invalid, else true. + +


+
+bool AddUnit(const std::string& name, double value);
+
+ +

Add a new unit to the parser. Returns false if the name of +the unit is invalid, else true. + +


+
+bool AddFunction(const std::string& name,
+                 double (*functionPtr)(const double*),
+                 unsigned paramsAmount);
+
+ +

Add a user-defined function to the parser (as a function pointer). +Returns false if the name of the function is invalid, else +true. + +


+
+bool AddFunction(const std::string& name, FunctionParser&);
+
+ +

Add a user-defined function to the parser (as a FunctionParser +instance). Returns false if the name of the function is invalid, +else true. + +


+
+bool RemoveIdentifier(const std::string& name);
+
+ +

Removes the constant, unit or user-defined function with the specified +name from the parser. + +


+
+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);
+
+ +

Like Parse(), 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. + + + +

Long descriptions of FunctionParser methods

+ +
+ +
+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);
+
+ +

Parses the given function (and compiles it to internal format). +Destroys previous function. Following calls to Eval() will evaluate +the given function. + +

The strings given as parameters are not needed anymore after parsing. + +

Parameters: + + + + + + + + + + + +
FunctionString containing the function to parse.
VarsString containing the variable names, separated by commas.
+ Eg. "x,y", "VarX,VarY,VarZ,n" or + "x1,x2,x3,x4,__VAR__". +
useDegrees(Optional.) Whether to use degrees or radians in + trigonometric functions. (Default: radians)
+ +

If a char* is given as the Function parameter, +it must be a null-terminated string. + +

Variables can have any size and they are case sensitive (ie. +"var", "VAR" and "Var" are +different 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 'Vars' string. Function names are not legal +variable names. + +

Using longer variable names causes no overhead whatsoever to the +Eval() method, so it's completely safe to use variable names +of any size. + +

The third, optional parameter specifies whether angles should be + interpreted as radians or degrees in trigonometrical functions. + If not specified, the default value is radians. + +

Return values: + +

+ +

Example: parser.Parse("3*x+y", "x,y"); + + +


+ +
+void setDelimiterChar(char);
+
+ +

By default the parser expects the entire function string to be valid +(ie. the entire contents of the given std::string, or a C string +ending in the null character '\0'). + +

If a delimiter character is specified with this function, then if it's +encountered at the outermost parsing level by the Parse() +function, and the input function has been valid so far, Parse() +will return an index to this character inside the input string, but rather +than set an error code, FP_NO_ERROR will be set. + +

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. + +

For example, suppose you are writing an interpreter for a scripting + language, which can have commands like this: + +

let MyFunction(x,y) = { sin(x*x+y*y) } // A 2-dimensional function + +

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 '}' as +the delimiter character and then simply give a pointer to the character +which comes after the '{'. If all goes well, the +Parse() function will return an index to the '}' +character (from the given starting point) and GetParseErrorType() +will return FP_NO_ERROR. You can use the return +value (if it's not -1) to jump forward in the string to the +delimiter character. + +

Note that a null character ('\0') or the end of the +std::string (if one was given) will still be a valid end of +the function string even if a delimiter character was specified. (In this +case Parse() will return -1 if there was no error, +as usual.) + +

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 '}', +'"', ']', etc). + + +


+ +
+static double epsilon();
+static void setEpsilon(double);
+
+ +

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: + +

+ + +
+ +
+const char* ErrorMsg(void) const;
+
+ +

Returns a pointer to an error message string corresponding to the error +caused by Parse() (you can use this to print the proper error +message to the user). If no such error has occurred, returns an empty string. + + +


+ +
+ParseErrorType GetParseErrorType() const;
+
+ +

Returns the type of parse error which occurred. + +

This method can be used to get the error type if ErrorMsg() +is not enough for printing the error message. In other words, this can be +used for printing customized error messages (eg. in another language). +If the default error messages suffice, then this method doesn't need +to be called. + +FunctionParser::ParseErrorType is an enumerated type inside +the class (ie. its values are accessed like +"FunctionParser::SYNTAX_ERROR"). + +

The possible values for FunctionParser::ParseErrorType are listed below, +along with their equivalent error message returned by the +ErrorMsg() method: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FP_NO_ERRORIf no error occurred in the previous call to Parse().
SYNTAX_ERROR"Syntax error"
MISM_PARENTH"Mismatched parenthesis"
MISSING_PARENTH"Missing ')'"
EMPTY_PARENTH"Empty parentheses"
EXPECT_OPERATOR"Syntax error: Operator expected"
OUT_OF_MEMORY"Not enough memory"
UNEXPECTED_ERROR"An unexpected error occurred. Please make a full bug report to the + author"
INVALID_VARS"Syntax error in parameter 'Vars' given to FunctionParser::Parse()"
ILL_PARAMS_AMOUNT"Illegal number of parameters to function"
PREMATURE_EOS"Syntax error: Premature end of string"
EXPECT_PARENTH_FUNC"Syntax error: Expecting ( after function"
UNKNOWN_IDENTIFIER"Syntax error: Unknown identifier"
NO_FUNCTION_PARSED_YET"(No function has been parsed yet)"
+ + +


+ +
+double Eval(const double* Vars);
+
+ +

Evaluates the function given to Parse(). +The array given as parameter must contain the same amount of values as +the amount of variables given to Parse(). Each value corresponds +to each variable, in the same order. + +

Return values: +

+ +

Example: + +

double Vars[] = {1, -2.5};
+double result = parser.Eval(Vars); + + +


+ +
+int EvalError(void) const;
+
+ +

Used to test if the call to Eval() succeeded. + +

Return values: + +

If there was no error in the previous call to Eval(), +returns 0, else returns a positive value as follows: +

+ + +
+ +
+void Optimize();
+
+ +

This method can be called after calling the Parse() method. +It will try to simplify the internal bytecode so that it will evaluate faster +(it tries to reduce the amount of opcodes in the bytecode). + +

For example, the bytecode for the function "5+x*y-25*4/8" will +be reduced to a bytecode equivalent to the function "x*y-7.5" (the +original 11 opcodes will be reduced to 5). Besides calculating constant +expressions (like in the example), it also performs other types of +simplifications with variable and function expressions. + +

This method is quite slow and the decision of whether to use it or +not should depend on the type of application. If a function is parsed +once and evaluated millions of times, then calling Optimize() +may speed-up noticeably. However, if there are tons of functions to parse +and each one is evaluated once or just a few times, then calling +Optimize() will only slow down the program. + +

Also, if the original function is expected to be optimal, then calling +Optimize() would be useless. + +

Note: Currently this method does not make any checks (like +Eval() does) and thus things like "1/0" will cause +undefined behaviour. (On the other hand, if such expression is given to the +parser, Eval() will always give an error code, no matter what +the parameters.) If caching this type of errors is important, a work-around +is to call Eval() once before calling Optimize() +and checking EvalError(). + +

If the destination application is not going to use this method, +the compiler constant FP_SUPPORT_OPTIMIZER can be undefined in +fpconfig.hh to make the library smaller (Optimize() +can still be called, but it will not do anything). + +

(If you are interested in seeing how this method optimizes the opcode, +you can call the PrintByteCode() method before and after the +call to Optimize() to see the difference.) + + +


+ +
+bool AddConstant(const std::string& name, double value);
+
+ +

This method can be used to add constants to the parser. Syntactically + constants are identical to variables (ie. they follow the same naming + rules and they can be used in the function string in the same way as + variables), but internally constants are directly replaced with their + value at parse time. + +

Constants used by a function must be added before calling +Parse() for that function. Constants are preserved between +Parse() calls in the current FunctionParser instance, so +they don't need to be added but once. (If you use the same constant in +several instances of FunctionParser, you will need to add it to all the +instances separately.) + +

Constants can be added at any time and the value of old constants can +be changed, but new additions and changes will only have effect the next +time Parse() is called. (That is, changing the value of a constant +after calling Parse() and before calling Eval() +will have no effect.) + +

The return value will be false if the 'name' of +the constant was illegal, else true. If the name was illegal, +the method does nothing. + +

Example: parser.AddConstant("pi", 3.1415926535897932); + +

Now for example parser.Parse("x*pi", "x"); will be identical +to the call parser.Parse("x*3.1415926535897932", "x"); + + +


+ +
+bool AddUnit(const std::string& name, double value);
+
+ +

In some applications it is desirable to have units of measurement. +A typical example is an application which creates a page layout to be +printed. When printing, distances are usually measured in points +(defined by the resolution of the printer). However, it is often more +useful for the user to be able to specify measurements in other units +such as centimeters or inches. + +

A unit is simply a value by which the preceding element is multiplied. +For example, if the printing has been set up to 300 DPI, one inch is +then 300 points (dots). Thus saying eg. "5in" is the same as saying +"5*300" or "1500" (assuming "in" has +been added as a unit with the value 300). + +

Note that units are slightly different from a multiplication in +that they have a higher precedence than any other operator (except +parentheses). Thus for example "5/2in" is parsed as +"5/(2*300)". +(If 5/2 inches is what one wants, it has to be written "(5/2)in".) + +

You can use the AddUnit() method to add a new unit. The +unit can then be used after any element in the function (and will work as +a multiplier for that element). An element is a float literal, a constant, +a variable, a function or any expression in parentheses. When the element +is not a float literal nor an expression in parentheses, there has to naturally +be at least one whitespace between the element and the unit (eg. +"x in"). To change the value of a unit, call +AddUnit() again with the same unit name and the new value. + +

Unit names share the same namespace as constants, functions and + variables, and thus should be distinct from those. + +

Example: parser.AddUnit("in", 300); + +

Now for example the function "5in" will be identical to +"(5*300)". Other usage examples include "x in", +"3in+2", "pow(x,2)in", "(x+2)in". + + +


+ +
+bool AddFunction(const std::string& name,
+                 double (*functionPtr)(const double*),
+                 unsigned paramsAmount);
+
+ +This method can be used to add new functions to the parser. For example, +if you would like to add a function "sqr(A)" which squares the +value of A, you can do it with this method (so that you don't +need to touch the source code of the parser). + +

The method takes three parameters: + +

+ +

The return value will be false if the given name was invalid +(either it did not follow the variable naming conventions, or the name was +already reserved), else true. If the return value is +false, nothing is added. + +

Example: Suppose we have a C++ function like this: + +

double Square(const double* p)
+{
+    return p[0]*p[0];
+} + +

Now we can add this function to the parser like this: + +

parser.AddFunction("sqr", Square, 1);
+parser.Parse("2*sqr(x)", "x"); + +

An example of a useful function taking no parameters is a function + returning a random value. For example: + +

double Rand(const double*)
+{
+    return drand48();
} + +

parser.AddFunction("rand", Rand, 0); + +

Important note: If you use the Optimize() method, +it will assume that the user-given function has no side-effects, that is, +it always returns the same value for the same parameters. The optimizer will +optimize the function call away in some cases, making this assumption. +(The Rand() function given as example above is one such +problematic case.) + + +


+ +
+bool AddFunction(const std::string& name, FunctionParser&);
+
+ +

This method is almost identical to the previous AddFunction(), +but instead of taking a C++ function, it takes another FunctionParser +instance. + +

There are some important restrictions on making a FunctionParser instance + call another: + +

+ +

Example: + +

FunctionParser f1, f2;
+

f1.Parse("x*x", "x");
+

f2.AddFunction("sqr", f1); + +

This version of the AddFunction() method can be useful to +eg. chain user-given functions. For example, ask the user for a function F1, + and then ask the user another function F2, but now the user can + call F1 in this second function if he wants (and so on with a third + function F3, where he can call F1 and F2, etc). + +


+ +
+template<typename DerivedWrapper>
+bool AddFunctionWrapper(const std::string& name, const DerivedWrapper&,
+                        unsigned paramsAmount);
+
+ +

See section on specialized function objects. + +


+ +
+bool RemoveIdentifier(const std::string& name);
+
+ +

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 +true, else nothing will be done and the return value will be +false. + +

(Note: If you want to remove everything from an existing +FunctionParser instance, simply assign a fresh instance to it, ie. like +"parser = FunctionParser();") + +


+ +
+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);
+
+ +

These functions work in the same way as the Parse() function, +but the variables in the input function string are deduced automatically. The +parameters are: + +

+ +

As with Parse(), the return value will be -1 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. + + + +

Specialized function objects

+ +

The AddFunction() 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 boost::function or other similar specialized stateful +function objects instead of raw function pointers. This library provides a +mechanism to achieve this. + +

Creating and adding a specialized function object

+ +

In order to create a specialized function object, create a class derived +from the FunctionParser::FunctionWrapper class. This class +declares a virtual function named callFunction that the derived +class must implement. For example: + +

+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];
+    }
+};
+
+ +

You can then add an instance of this class to FunctionParser +using the AddFunctionWrapper() method, which works like +AddFunction(), but takes a wrapper object instead of a function +pointer as parameter. For example: + +

+MyFunctionWrapper wrapper;
+parser.AddFunctionWrapper("funcName", wrapper, 1);
+
+ +

Note that FunctionParser 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 +FunctionParser instance. Hence the above could also be written as: + +

+parser.AddFunctionWrapper("funcName", MyFunctionWrapper(), 1);
+
+ +

Note that this also means that the wrapper class must have a working +copy constructor. + +

Also note that if the FunctionParser instance is copied, all +the copies will share the same function wrapper objects given to the original. + +

Retrieving specialized function objects

+ +

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 +AddFunctionWrapper(). 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 GetFunctionWrapper() 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. + +

Note that the returned pointer will be of type +FunctionParser::FunctionWrapper. In order to get a pointer to +the actual derived type, the calling code should perform a +dynamic_cast, for example like this: + +

+MyFunctionWrapper* wrapper =
+    dynamic_cast<MyFunctionWrapper*>
+    (parser.GetFunctionWrapper("funcName"));
+
+if(!wrapper) { /* oops, the retrieval failed */ }
+else ...
+
+ +

(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.) + +

The calling code is free to modify the object in any way it wants, but it +must not delete it (because FunctionParser itself handles this). + + + + +

FunctionParserBase

+ +

All the different parser types are derived from a templated base class +named FunctionParserBase. 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 FunctionParserBase directly is the easiest way to achieve +this. + +

For example, if you want to make a function that handles more than one +type of parser, it can be done like this: + +

+template<typename Value_t>
+void someFunction(FunctionParserBase<Value_t>& parser)
+{
+    // do something with 'parser' here
+}
+
+ +

Now it's convenient to call that function with more than one type of +parser, for example: + +

+FunctionParser realParser;
+FunctionParser_cd complexParser;
+
+someFunction(realParser);
+someFunction(complexParser);
+
+ +

Another example is a class that inherits from FunctionParser +which also wants to support different numerical types. Such class can be +declared as: + +

+template<typename Value_t>
+class SpecializedParser: public FunctionParserBase<Value_t>
+{
+    ...
+};
+
+ + + +

Syntax

+ + +

Numeric literals

+ +

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). + +

An integer literal can consist solely of numerical digits (possibly with + a preceding unary minus). For example, "12345". + +

If the literal is preceded by the characters "0x", it + will be interpreted as a hexadecimal literal, where digits can also include + the letters from 'A' to 'F' (in either uppercase + or lowercase). For example, "0x89ABC" (which corresponds to the + value 563900). + +

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 "12.34", optionally followed by a + decimal exponent. + +

A decimal exponent consists of an 'E' or 'e', + followed by an optional plus or minus sign, followed by decimal digits, and + indicates multiplication by a power of 10. For example, "1.2e5" + (which is equivalent to the value 120000). + +

If a floating point literal is preceded by the characters "0x" + 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). + +

A binary exponent has the same format as a decimal exponent, except that + 'P' or 'p' is used. A binary exponent indicates + multiplication by a power of 2. For example, "0xA.Bp10" + (which is equivalent to the value 10944). + +

With the complex versions of the library, the imaginary part of a numeric + literal is written as a regular numeric literal with an 'i' + appended, for example "5i". Note that when also specifying + the real part of a complex literal, parentheses should be used to avoid + precedence problems. (For example, "(2+5i) * x" + is not the same thing as "2+5i * x". The latter + would be equivalent to "2 + (5i * x)".) + + +

Identifier names

+ +

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. + +

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. + +

All functions, variables, constants and units must use unique names. + It's not possible to add two different identifiers with the same name. + + + + +

The function string syntax

+ +

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: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
()expressions in parentheses first
A unita unit multiplier (if one has been added)
A^Bexponentiation (A raised to the power B)
-Aunary minus
!Aunary logical not (result is 1 if int(A) is 0, else 0)
A*B A/B A%Bmultiplication, division and modulo
A+B A-Baddition and subtraction
A=B A<B A<=B
A!=B A>B A>=B
comparison between A and B (result is either 0 or 1)
A&Bresult is 1 if int(A) and int(B) differ from + 0, else 0.
+ 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.
A|Bresult is 1 if int(A) or int(B) differ from 0, + else 0.
+ 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.
+ +

(Note that currently the exponentiation operator is not supported for + FunctionParser_li nor FunctionParser_gmpint. + 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".) + +

Since the unary minus has higher precedence than any other operator, for + example the following expression is valid: x*-y + +

The comparison operators use an epsilon value, so expressions which may +differ in very least-significant digits should work correctly. For example, +"0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 1" should always +return 1, and the same comparison done with ">" or +"<" should always return 0. (The epsilon value can be +configured in the fpconfig.hh file.) +Without epsilon this comparison probably returns the wrong value. + +

The class supports these functions: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
abs(A)Absolute value (magnitude) of A. + With real numbers, if A is negative, returns -A otherwise returns A. + With complex numbers, equivalent to hypot(real(x),imag(x)).
acos(A)Arc-cosine of A. Returns the angle, measured in radians, whose cosine is A.
acosh(A)Same as acos() but for hyperbolic cosine.
arg(A)Phase angle of complex number A. Equivalent to atan2(imag(x),real(x)).
asin(A)Arc-sine of A. Returns the angle, measured in radians, whose sine is A.
asinh(A)Same as asin() but for hyperbolic sine.
atan(A)Arc-tangent of (A). Returns the angle, measured in radians, + whose tangent is A.
atan2(A,B)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.
atanh(A)Same as atan() but for hyperbolic tangent.
cbrt(A)Cube root of A. Returns a solution to expression pow(x,3)=A.
conj(A)Complex conjugate of A. Equivalent to real(x) - 1i*imag(x) or polar(abs(x),-arg(x)).
ceil(A)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.
cos(A)Cosine of A. Returns the cosine of the angle A, where A is + measured in radians.
cosh(A)Same as cos() but for hyperbolic cosine.
cot(A)Cotangent of A. Equivalent to 1/tan(A).
csc(A)Cosecant of A. Equivalent to 1/sin(A).
eval(...)This a recursive call to the function to be evaluated. The + number of parameters must be the same as the number of parameters + taken by the function. Must be called inside if() to avoid + infinite recursion.
exp(A)Exponential of A. Returns the value of e raised to the power + A where e is the base of the natural logarithm, i.e. the + non-repeating value approximately equal to 2.71828182846.
exp2(A)Base 2 exponential of A. Equivalent to pow(2,A).
floor(A)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.
hypot(A,B)Euclidean distance function. Equivalent to sqrt(A^2+B^2).
if(A,B,C)If int(A) differs from 0, the return value of this function is B, + else C. Only the parameter which needs to be evaluated is + evaluated, the other parameter is skipped; this makes it safe to + use eval() in them.
imag(A)Return the imaginary part of complex number A. Equivalent to abs(A)*sin(arg(A)).
int(A)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.
log(A)Natural (base e) logarithm of A. Returns the solution to expression exp(x)=A.
log2(A)Base 2 logarithm of A. Equivalent to log(A)/log(2).
log10(A)Base 10 logarithm of A.
max(A,B)If A>B, the result is A, else B.
min(A,B)If A<B, the result is A, else B.
polar(A,B)Returns a complex number from magnitude A, phase angle B (in radians). + Equivalent to real(A)*(cos(real(B))+1i*sin(real(B))).
pow(A,B)Exponentiation (A raised to the power B).
real(A)Return the real part of complex number A. Equivalent to abs(A)*cos(arg(A)).
sec(A)Secant of A. Equivalent to 1/cos(A).
sin(A)Sine of A. Returns the sine of the angle A, where A is + measured in radians.
sinh(A)Same as sin() but for hyperbolic sine.
sqrt(A)Square root of A. Returns a solution to expression pow(x,2)=A.
tan(A)Tangent of A. Returns the tangent of the angle A, where A + is measured in radians.
tanh(A)Same as tan() but for hyperbolic tangent.
trunc(A)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.
+ +

(Note that for FunctionParser_li and + FunctionParser_gmpint only the functions + abs(), eval(), if(), + min() and max() are supported.) + +

Examples of function string understood by the class: + +

"1+2"
+"x-1"
+"-sin(sqrt(x^2+y^2))"
+"sqrt(XCoord*XCoord + YCoord*YCoord)"
+ +

An example of a recursive function is the factorial function: + +"if(n>1, n*eval(n-1), 1)" + +

Note that a recursive call has some overhead, which makes it a bit slower + than any other operation. It may be a good idea to avoid recursive functions + in very time-critical applications. Recursion also takes some memory, so + extremely deep recursions should be avoided (eg. millions of nested recursive + calls). + +

Also note that even though the maximum recursion level of +eval() is limited, it is possible to write functions which +never reach that level but still take enormous amounts of time to evaluate. +This can sometimes be undesirable because it is prone to exploitation, +which is why eval() is disabled by default. It can be enabled +in the fpconfig.hh file. + + + + +

Inline variables

+ +

The function syntax supports defining new variables inside the function +string itself. This can be done with the following syntax: + +

"<variable name> := <expression>; <function>" + +

For example: + +

"length := sqrt(x*x+y*y); 2*length*sin(length)" + +

(Spaces around the ':=' operator are optional.) + +

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. + +

The variable name must be an unused identifier (in other words, not an +existing function, variable or unit name). + +

The <function> part can have further inline variable +definitions, and thus it's possible to have any amount of them, for example: + +

"A := x^2; B := y^2; C := z^2; sqrt(A+B+C)" + +

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: + +

"A := x^2; A := 2*A; sqrt(A)" + + + + +

Whitespace

+ +

Arbitrary amounts of whitespace can optionally be included between + elements in the function string. + The following unicode characters are interpreted as whitespace: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Character numberCharacter nameUTF-8 byte sequence
U+0009HORIZONTAL TABULATION 09
U+000ALINE FEED 0A
U+000BVERTICAL TABULATION 0B
U+000DCARRIAGE RETURN 0D
U+0020SPACE 20
U+00A0NO-BREAK SPACE C2 A0
U+2000EN QUAD E2 80 80
U+2001EM QUAD E2 80 81
U+2002EN SPACE E2 80 82
U+2003EM SPACE E2 80 83
U+2004THREE-PER-EM SPACE E2 80 84
U+2005FOUR-PER-EM SPACE E2 80 85
U+2006SIX-PER-EM SPACE E2 80 86
U+2007FIGURE SPACE E2 80 87
U+2008PUNCTUATION SPACE E2 80 88
U+2009THIN SPACE E2 80 89
U+200AHAIR SPACE E2 80 8A
U+200BZERO WIDTH SPACE E2 80 8B
U+202FNARROW NO-BREAK SPACE E2 80 AF
U+205FMEDIUM MATHEMATICAL SPACEE2 81 9F
U+3000IDEOGRAPHIC SPACE E3 80 80
+ + +

Miscellaneous

+ + +

About floating point accuracy

+ +

Note that if you are using FunctionParser_ld or +FunctionParser_cld and you want calculations to be as accurate +as the long double type allows, you should pay special attention +to floating point literals in your own code. For example, this is a very +typical mistake: + +

FunctionParser_ld parser;
+parser.AddConstant("pi", 3.14159265358979323846);
+ +

The mistake might not be immediately apparent. The mistake is that a +literal of type double is passed to the AddConstant() +function even though it expects a value of type long double. +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: + +

FunctionParser_ld parser;
+parser.AddConstant("pi", 3.14159265358979323846L);
+ +

The same principle should be used everywhere in your own code, if you are +using the long double type. + +

This is especially important if you are using the MpfrFloat +type (in which case its string-parsing constructor or its +ParseValue() or parseString() member functions +should be used instead of using numerical literals). + + +

About evaluation-time checks

+ +

FunctionParser::Eval() will perform certain sanity +checks before performing certain operations. For example, before calling the +sqrt 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: + +

+ +

However, the library can not 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 NaN result, etc. + +

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. + +

The library cannot guarantee that floating point +errors will never happen during evaluation. This can make the library to +return the floating point values inf and NaN. 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. + +

Note that the optimizer never performs any sanity checks. + + + + +

About thread safety

+ +

None of the member functions of the FunctionParser class are thread-safe. +Most prominently, the Eval() function is not thread-safe. +(In other words, the Eval() function of a single FunctionParser +instance cannot be safely called simultaneously by two threads.) + +

There are ways to use this library in a thread-safe way, though. If each +thread uses its own FunctionParser instance, no problems will obviously +happen. Note, however, that if these instances need to be a copy of a given +FunctionParser instance (eg. one where the user has entered a function), +a deep copy of this instance has to be performed for each thread. By +default FunctionParser uses shallow-copying (copy-on-write), which means +that a simple assignment of copy construction will not copy the data itself. +To force a deep copy you can all the ForceDeepCopy() function on +each of the instances of each thread after the assignment or copying has been +done. + +

Another possibility is to compile the FunctionParser library so that +its Eval() function will be thread-safe. (This can be done by +defining the FP_USE_THREAD_SAFE_EVAL or the +FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA +precompiler constant.) As long as only one thread calls the other functions +of FunctionParser, the other threads can safely call the Eval() +of this one instance. + +

Note, however, that compiling the library like this can make +Eval() slightly slower. (The alloca version, if +supported by the compiler, will not be as slow.) + +

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. + + + + +

Tips and tricks

+ +

Add constants automatically to all parser objects

+ +

Often the same constants (such as pi and e) and other +user-defined identifiers (such as units) are always used in all the +FunctionParser objects throughout the program. It would be +troublesome to always have to manually add these constants every time a +new parser object is created. + +

There is, however, a simple way to always add these user-defined identifiers +to all instances. Write a class like this: + +

+    class ParserWithConsts: public FunctionParser
+    {
+     public:
+        ParserWithConsts()
+        {
+            AddConstant("pi", 3.14159265358979323846);
+            AddConstant("e", 2.71828182845904523536);
+        }
+    };
+
+ +

Now instead of using FunctionParser, always use +ParserWithConsts. 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 +slicing, so +they are completely safe to use anywhere.) + + + + +

Contacting the author

+ +

Any comments, bug reports, etc. should be sent to warp@iki.fi + + + + + + + + +

Usage license

+ +

Copyright © 2003-2011 Juha Nieminen, Joel Yliluoma + +

This Library is distributed under the + Lesser General Public + License (LGPL) version 3. + + + diff --git a/deal.II/contrib/functionparser/docs/gpl.txt b/deal.II/contrib/functionparser/docs/gpl.txt new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/deal.II/contrib/functionparser/docs/gpl.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + 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. + + + Copyright (C) + + 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 . + +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: + + Copyright (C) + 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 +. + + 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 +. diff --git a/deal.II/contrib/functionparser/docs/lgpl.txt b/deal.II/contrib/functionparser/docs/lgpl.txt new file mode 100644 index 0000000000..cca7fc278f --- /dev/null +++ b/deal.II/contrib/functionparser/docs/lgpl.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/deal.II/contrib/functionparser/docs/style.css b/deal.II/contrib/functionparser/docs/style.css new file mode 100644 index 0000000000..d5141d3ae6 --- /dev/null +++ b/deal.II/contrib/functionparser/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/deal.II/contrib/functionparser/example.cc b/deal.II/contrib/functionparser/examples/example.cc similarity index 83% rename from deal.II/contrib/functionparser/example.cc rename to deal.II/contrib/functionparser/examples/example.cc index 608492e475..b4ab5f45c8 100644 --- a/deal.II/contrib/functionparser/example.cc +++ b/deal.II/contrib/functionparser/examples/example.cc @@ -1,50 +1,55 @@ -// Simple example file for the function parser -// =========================================== - -/* When running the program, try for example with these values: - -f(x) = x^2 -min x: -5 -max x: 5 -step: 1 - -*/ - -#include "fparser.hh" - -#include -#include - -int main() -{ - std::string function; - double minx, maxx, step; - FunctionParser fparser; - - fparser.AddConstant("pi", 3.1415926535897932); - - while(true) - { - std::cout << "f(x) = "; - std::getline(std::cin, function); - int res = fparser.Parse(function, "x"); - if(res < 0) break; - - std::cout << std::string(res+7, ' ') << "^\n" - << fparser.ErrorMsg() << "\n\n"; - } - - std::cout << "min x: "; - std::cin >> minx; - std::cout << "max x: "; - std::cin >> maxx; - std::cout << "step: "; - std::cin >> step; - - double vals[1]; - for(vals[0] = minx; vals[0] <= maxx; vals[0] += step) - std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals) - << std::endl; - - return 0; -} +// Simple example file for the function parser +// =========================================== + +/* 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 +#include + +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/deal.II/contrib/functionparser/examples/example2.cc b/deal.II/contrib/functionparser/examples/example2.cc new file mode 100644 index 0000000000..958b9a1e6c --- /dev/null +++ b/deal.II/contrib/functionparser/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 +#include +#include + +template +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("double"); break; + case 2: runExample("float"); break; + case 3: runExample("long double"); break; + case 4: runExample("long int"); break; + } + + return 0; +} diff --git a/deal.II/contrib/functionparser/extrasrc/fp_identifier_parser.inc b/deal.II/contrib/functionparser/extrasrc/fp_identifier_parser.inc new file mode 100644 index 0000000000..00d5081a7f --- /dev/null +++ b/deal.II/contrib/functionparser/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; \ No newline at end of file diff --git a/deal.II/contrib/functionparser/extrasrc/fp_opcode_add.inc b/deal.II/contrib/functionparser/extrasrc/fp_opcode_add.inc new file mode 100644 index 0000000000..cb7280ca44 --- /dev/null +++ b/deal.II/contrib/functionparser/extrasrc/fp_opcode_add.inc @@ -0,0 +1,7748 @@ +/* Function Parser for C++ v4.5 + + NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + This file contains generated code and is thus not intended to be to +be modified by hand. It was generated by util/bytecoderules_parser, which +is available in the development package. +*/ +#define HasInvalidRangesOpcode HasInvalidRangesOpcode::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::VARIABLE)) +#define FP_TRACE_BYTECODE_ADD(opcode) \ + /*std::cout << "Adding opcode: " << FP_TRACE_OPCODENAME(opcode) \ + << ", bytecode length " << data->ByteCode.size() \ + << ", pointer is " << (void*)ByteCodePtr \ + << ", code is " << (data->ByteCode.empty() \ + ? (void*)0 \ + : (void*)&data->ByteCode[0]) \ + << std::endl*/ +#define q81 "cNeg" +#define q71 <<","aP +#define q61 wA","aP +#define q51 <<","aQ +#define q41 ", "wU<<"," +#define q31 wA","aE +#define q21 "B[IsVarOpcode(B)]"m7 +#define q11 );qW q6 +#define q01 "cSqrt" +#define mZ "cSqr " +#define mY ){hD wB +#define mX "cSec" +#define mW "cCeil" +#define mV "A "a3 +#define mU "cImag" +#define mT "cConj" +#define mS a4" "a6 +#define mR hO wB +#define mQ "cAbs" +#define mP qS w2 wB +#define mO "cFloor" +#define mN "cTan" +#define mM "cSin" +#define mL (y hX; +#define mK " "aS +#define mJ "[ y+x]" +#define mI hV 2 gC +#define mH "cExp" +#define mG "cNeg " +#define mF " cSub" +#define mE " cDup" +#define mD " cNeg" +#define mC "cDup " +#define mB "cLess" +#define mA "cLog" +#define m9 "cMin" +#define m8 "cMax" +#define m7 " cDiv" +#define m6 wH" " +#define m5 (x);gJ +#define m4 " "wU wM +#define m3 aU"x " +#define m2 gN wB +#define m1 g1 oG wB +#define m0 "B cSqr" +#define aZ "[y*x]" +#define aY oH dE wB +#define aX mQ" " +#define aW "cGreater" +#define aV " cAdd" +#define aU "y " +#define aT gY if(dO wB +#define aS "cInv" +#define aR mC aS +#define aQ " B"a0 +#define aP " "aO +#define aO "A"a0 +#define aN "cAbsNot" +#define aM "cLessOrEq" +#define aL "cAdd "q01 +#define aK "cCos" +#define aJ "cLog2" +#define aI "cCosh" +#define aH "cLog10" +#define aG "B[B==A]" +#define aF "cNotNot" +#define aE " "wG +#define aD "A[IsVarOpcode(A)]" +#define aC " "aD" " +#define aB " cNot" +#define aA " "a2 +#define a9 "cDup"aV +#define a8 "cGreaterOrEq" +#define a7 " cRDiv" +#define a6 "x"aV +#define a5 "cEqual" +#define a4 "cRSub" +#define a3 "[x]"wH +#define a2 " with"aP +#define a1 " cPow" +#define a0 " "wC +#define wZ "x[x!=Value_t()] " +#define wY " x"wH +#define wX "x[x==Value_t()]"wH +#define wW "cNEqual" +#define wV aD m7 +#define wU "x = "<Value_t(0)]" +#define wP "B[IsNeverNegativeValueOpcode(B)] " +#define wO "x[x==Value_t(1)] " +#define wN wA"\n" +#define wM <<"\n" +#define wL "x[x==Value_t(0)] " +#define wK "B[IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "wD +#define wJ "A[IsNeverNegativeValueOpcode(A)] " +#define wI "A[IsVarOpcode(A)&&mData->mByteCode.size()>2] " +#define wH " cMul" +#define wG aU"= "<oP){ +#define dN mImmed +#define dM qE h3 gX +#define dL qK dJ w3 +#define dK cGreaterOrEq +#define dJ =q6; +#define dI qK dJ g6 +#define dH Value_t +#define dG q8 2 gH q4 +#define dF q0[0] +#define dE qK qR qX +#define dD qK qR IsLogicalOpcode(h2 +#define dC (qK== +#define dB hB oY +#define dA qY g8 oG +#define d9 pop_back() +#define d8 q6;q1 h3 gI +#define d7 q8 2 gC +#define d6 hR Lba; +#define d5 Default4 qU +#define d4 :if( +#define d3 qV hS d4 qL +#define d2 h3 gM if +#define d1 IsVarOpcode( +#define d0 mData-> +#define hZ ]qR w4 +#define hY gX Llq +#define hX ,x gX Lap +#define hW gT y+x;q8 +#define hV for qA +#define hU gQ cAbs: +#define hT unsigned +#define hS cAdd +#define hR ,y gX +#define hQ qL 3 hZ +#define hP y=q3-1]qR +#define hO y gO +#define hN qY if(dP +#define hM q6:qC +#define hL :if gF +#define hK qQ h9 hS hL +#define hJ 4 qZ mR(292,aU"cAdd B[IsVarOpcode(B)]"mF" "a6,mJ aV" B"mF,wA","aQ(B)<<","aE);q4 +#define hI cNeg: +#define hH :qS cDup: +#define hG hS hH hK h1 wB(310,a9" "a9,"[Value_t(4)]"wH,);q4 +#define hF (x!=g1 +#define hE qL 2] +#define hD B g4 w4 +#define hC B=hE qO B)){ +#define hB if hF 0)){ +#define hA gX Lng; +#define h9 qK qV +#define h8 }break; +#define h7 ()){ +#define h6 hR Lap; +#define h5 isEvenInteger( +#define h4 DegreesToRadians(x +#define h3 cMul +#define h2 A)){ +#define h1 ]==cDup){ +#define h0 hI wB(201,mG mQ,mQ,);q4 Lab qU qB +#define gZ 3 h1 wB(311,a9 m6 a9,"cMul [Value_t(4)]"wH,);q4 +#define gY qU hM +#define gX );q4 +#define gW y,x gX Lba; +#define gV IsUnaryOpcode( +#define gU g6 w5= +#define gT q3-1]= +#define gS gR qR IsAlwaysIntegerOpcode(h2 +#define gR ;oH dF +#define gQ )){qQ h9 +#define gP break gR qO A gQ +#define gO =q3-1]; +#define gN qJ hO +#define gM :qJ qC +#define gL d2(dO +#define gK ]=q6 q9 2 gH +#define gJ return; +#define gI );w5= +#define gH ;qI q5 +#define gG qL 2 gK q0-=2; +#define gF (qL 2 +#define gE y;hT B;hT +#define gD d0 mByteCode +#define gC ;qI q1 +#define gB q9 2 gC h3 gI +#define gA ){if gF +#define g9 oY h3 dV +#define g8 if(x==g1 +#define g7 default: +#define g6 q5 q0-=1; +#define g5 if(!q0){q2 +#define g4 =hE qR +#define g3 B g4 IsNeverNegativeValueOpcode(B)){ +#define g2 &&!HasInvalidRangesOpcode( +#define g1 dH( +#define g0 FP_ReDefinePointers(); +#define qZ ]==q6){ +#define qY if(q0[0 qZ qC +#define qX IsNeverNegativeValueOpcode(h2 +#define qW gD qD +#define qV ){case +#define qU ;case +#define qT }break qU +#define qS qQ dF qV +#define qR ;if( +#define qQ switch( +#define qP )&&gD oK> +#define qO qR d1 +#define qN dF w1 2){ +#define qM d0 dN.d9; +#define qL q0[- +#define qK qL 1] +#define qJ oY q6){ +#define qI tmp-->0;) +#define qH q4 Default0; +#define qG }}qH +#define qF d0 dN qD +#define qE AddFunctionOpcode( +#define qD .push_back( +#define qC x=q7; +#define qB hM wB(132,"x "mQ,"[fp_abs(x)]",wN);q4 Lac; +#define qA (hT tmp= +#define q9 ;hV +#define q8 d0 dN.d9 q9 +#define q7 q3 0] +#define q6 cImmed +#define q5 gD.d9; +#define q4 goto +#define q3 dW[ +#define q2 q4 Laa;}case +#define q1 q5 qE +#define q0 ByteCodePtr +hT*q0;dH*dW; +#define FP_ReDefinePointers() q0=!gD.empty()?&gD[0]+gD oK-1:0;dW=!d0 dN.empty()?&d0 dN[0]+d0 dN oK-1:0; +g0 +wE(opcode); +#if(!(FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION)) +dH +x;hT +A;dH +gE +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0 +oH +dF +qR +qX +wB(393,wJ +mQ,"A" +,aA(A)wM);gJ +qG +TailCall_cAdd:g5 +hG +Lad;qT +h3 +hL]==hS){if(qL +gZ +Lae;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +wY +aV,"[x+Value_t(1)]" +wH,wN);q4 +Laf;} +} +q4 +dX +oF +wB(199,q81 +aV,"cSub" +,);q4 +Lag +gY +hK +qZ +mR(127,aU"cAdd " +a6,"[y+x]" +aV,q31);q4 +Lah;qT +cRSub:qQ +hE +d3 +3 +qZ +mR(298,aU"cAdd " +mS,mJ +aV" " +a4,q31);q4 +Lai;qT +hI +wB(299,mG +mS,"[-x]" +aV" " +a4,wN);q4 +Laj +qU +q6:mR(297,aU +mS,mJ" " +a4,q31);q4 +Lak;qT +oA +Lal;qT +hI +wB(293,mG"B[IsVarOpcode(B)]" +mF" " +a6,"[-x]" +aV" B" +mF,wA"," +aQ(B)wM);q4 +Lam +qU +q6:mR(291,aU"B[IsVarOpcode(B)]" +mF" " +a6,mJ" B" +mF,wA"," +aQ(B)<<"," +aE);q4 +Lan;} +w9 +mR(105,aU +a6,"[y+x]" +,q31);q4 +Lao;} +g8)){wB(57,"x[x==Value_t()]" +aV,,wN);q4 +Lap;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x " +a4 +aC"cAdd" +,"[DO_STACKPLUS1] A [x]" +aV" " +a4,aA(A)<<"," +m4);incStackPtr();--mStackPtr;q4 +Laq;} +wB(295,a4 +aC"cAdd" +,"[DO_STACKPLUS1] A" +aV" " +a4,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lba;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mC"cAnd" +,aF,);q4 +Lbb +gY +m2(117,m3"cAnd" +,"[fp_and(x,y)]" +,q31);q4 +Lbc;h8} +qH +TailCall_cDiv:g5 +cDiv +hH +wB(78,"cDup" +m7,"[Value_t()]" +m6"[Value_t(1)]" +aV,);q4 +w7 +if +hF +gQ +hI +wB(125,mG +wZ"cDiv" +,"[-x]" +m7,wN);q4 +Lbe +qU +q6:mR(103,aU +wZ"cDiv" +,"[y/x]" +,q31);q4 +Lbf;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lap;h8} +qH +TailCall_cEqual:g5 +w8:dA +A=dD +wB(421,"A[IsLogicalOpcode(A)] " +wO +a5,"A" +,q61(A)wM);q4 +Lap;} +} +m2(115,m3 +a5,"[fp_equal(y,x)]" +,q31);q4 +Lbg;} +g8 +0 +hU +wB(359,aX +wL +a5,"[x] " +a5,wN);q4 +Lbh +qU +cSqr:wB(361,mZ +wL +a5,"[x] " +a5,wN);q4 +Lbh;} +wB(411,wL +a5,"cNot" +,wN);q4 +Lbi;qG +TailCall_cGreater:g5 +o1:oL +hU +wB(413,aX +wL +aW,aF,wN);q4 +Lbj;aY(417,wJ +wL +aW,"A " +aF,q61(A)wM);q4 +Lbk;} +} +} +m2(113,m3 +aW,"[fp_less(x,y)]" +,q31);q4 +Lbl;qG +TailCall_cGreaterOrEq:g5 +dK:qY +g8 +1 +hU +wB(414,aX +wO +a8,aF,wN);q4 +Lbj;aY(418,wJ +wO +a8,"A " +aF,q61(A)wM);q4 +Lbk;} +} +} +m2(114,m3 +a8,"[fp_lessOrEq(x,y)]" +,q31);q4 +Lbm;qG +TailCall_cInv:g5 +cInv:qY +if +hF)){wB(101,wZ +aS,"[Value_t(1)/x]" +,wN);q4 +Lbn;qG +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mB,mV,q61(A)wM);oS;} +} +g8 +1 +hU +wB(415,aX +wO +mB,"cNot" +,wN);q4 +Lbp;aY(419,wJ +wO +mB,"A" +aB,q61(A)wM);q4 +Lbi;} +} +} +m2(111,m3 +mB,"[fp_less(y,x)]" +,q31);q4 +Lbq;qG +TailCall_cLessOrEq:g5 +cLessOrEq:oL +hU +wB(416,aX +wL +aM,"cNot" +,wN);q4 +Lbp;aY(420,wJ +wL +aM,"A" +aB,q61(A)wM);q4 +Lbi;} +} +} +m2(112,m3 +aM,"[fp_lessOrEq(y,x)]" +,q31);q4 +Lca;qG +TailCall_cMax:g5 +cMax +hH +wB(60,mC +m8,,);q4 +w6 +m2(141,m3 +m8,"[fp_max(x,y)]" +,q31);q4 +Lcc;} +gP +cDup:hD +wB(66,aG +mE +aC +m8,"B" +mE,aA(A)q51(B)wM);q4 +Lcb;qT +cMax:hD +wB(68,aG" " +m8 +aC +m8,"B " +m8,aA(A)q51(B)wM);q4 +Lcb;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mC +m9,,);q4 +w6 +m2(140,m3 +m9,"[fp_min(x,y)]" +,q31);q4 +Lcd;} +gP +cDup:hD +wB(65,aG +mE +aC +m9,"B" +mE,aA(A)q51(B)wM);q4 +Lcb;qT +cMin:hD +wB(67,aG" " +m9 +aC +m9,"B " +m9,aA(A)q51(B)wM);q4 +Lcb;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m2(104,aU +wZ"cMod" +,"[fp_mod(y,x)]" +,q31);q4 +Lce;} +qG +TailCall_cMul:g5 +h3 +hH +wB(202,"cDup" +wH,"cSqr" +,);q4 +Lcf +oF +qQ +h9 +cDup:wB(467,mC +q81 +wH,"cSqr" +mD,);q4 +Lcg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aG +wH +aC +q81 +wH,m0 +m6 +q81,aA(A)q51(B)wM);q4 +Lch;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mC"x" +a1 +wH,"[x+Value_t(1)]" +a1,wN);q4 +Lci;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wT" " +wX,a3,q61(A)wM);q4 +Lcj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mR(92,aU +wD,a3,q61(A)<<"," +aE);q4 +Lck;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mR(96,aU +wK,mV,q61(A)q51(B)<<"," +aE);q4 +Lcl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lcm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lcn;} +} +} +if(d1 +B)){wB(90,"B[IsVarOpcode(B)] " +wD,a3,q61(A)q51(B)wM);q4 +Lcj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mV,q61(A)q51(B)wM);q4 +Lco;} +} +} +if(d1 +h2 +wB(88,aD" " +wX,"[x]" +,q61(A)wM);q4 +Lcp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wX,a3,q61(A)wM);q4 +Lcq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup:wB(317,a9 +wY,"[x+x]" +wH,wN);q4 +Lda +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,aD" y" +wH +aV +wY,a3" A " +aZ +wH +aV,wA", " +aU"= " +<mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Ldm;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:dA +A=dD +wB(422,"A[IsLogicalOpcode(A)] " +wO +wW,"A" +aB,q61(A)wM);q4 +Lbi;} +} +m2(116,m3 +wW,"[fp_nequal(y,x)]" +,q31);q4 +Ldn;} +g8 +0 +hU +wB(360,aX +wL +wW,"[x] " +wW,wN);q4 +Ldo +qU +cSqr:wB(362,mZ +wL +wW,"[x] " +wW,wN);q4 +Ldo;} +wB(412,wL +wW,aF,wN);q4 +Lbk;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +m6 +q81,"[-x]" +wH,wN);q4 +Ldp;qT +hI +wB(61,q81 +mD,,);q4 +w6 +wB(100,"x" +mD,"[-x]" +,wN);q4 +Ldq;} +qH +TailCall_cNot:g5 +cNot:qS +cAbs:wB(227,mQ +aB,"cNot" +,);q4 +Lea +qU +cAbsNot:A=dD +wB(389,"A[IsLogicalOpcode(A)] " +aN +aB,"A" +,aA(A)wM);q4 +Lcb;} +if(A!=q6){wB(390,"A[A!=cImmed] " +aN +aB,"A cAbsNotNot" +,aA(A)wM);q4 +Leb;} +q4 +o0 +qU +cAbsNotNot:wB(231,"cAbsNotNot" +aB,aN,);q4 +Lec +qU +hS +gM +wB(424,a6 +aB,"[-x] " +a5,wN);q4 +Led;} +q4 +o0 +qU +w8:wB(220,a5 +aB,wW,);q4 +Lee +qU +o1:wB(218,aW +aB,aM,);q4 +Lef +qU +dK:wB(219,a8 +aB,mB,);q4 +Leg +qU +cLess:wB(216,mB +aB,a8,);q4 +Leh +qU +cLessOrEq:wB(217,aM +aB,aW,);q4 +Lei +qU +cNEqual:wB(221,wW +aB,a5,);q4 +Lej +oF +wB(226,q81 +aB,"cNot" +,);q4 +Lea +qU +cNot:wB(229,"cNot" +aB,aF,);q4 +Lbb +qU +dS:wB(230,aF +aB,"cNot" +,);q4 +Lea +gY +wB(107,"x" +aB,"[fp_not(x)]" +,wN);q4 +Lek;g7 +o0:;A=dF +qR +qX +wB(391,wJ"cNot" +,"A " +aN,aA(A)wM);q4 +Lel;qG +TailCall_cNotNot:g5 +dS:qS +hS +gM +wB(423,a6" " +aF,"[-x] " +wW,wN);q4 +Lem;qT +cNot:wB(232,"cNot " +aF,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mC"cOr" +,aF,);q4 +Lbb +gY +m2(118,m3"cOr" +,"[fp_or(x,y)]" +,q31);q4 +Len;h8} +qH +TailCall_cRDiv:g5 +cRDiv:dA +wB(268,wO"cRDiv" +,aS,wN);q4 +Leo;qG +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,mC +a4,"[Value_t()]" +wH,);q4 +Lep;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,aX"cSqr" +,"cSqr" +,);q4 +Leq +oF +wB(203,mG"cSqr" +,"cSqr" +,);q4 +Leq;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,mC"cSub" +,"[Value_t()]" +wH,);q4 +Lep +oF +wB(200,q81 +mF,"cAdd" +,);q4 +Lfa +gY +g8)){wB(58,"x[x==Value_t()]" +mF,,wN);q4 +Lap;} +m2(106,m3"cSub" +,"[y-x]" +,q31);q4 +Lfb;} +wB(51,"x" +mF,"[-x]" +aV,wN);q4 +Lfc +gR +w0 +oY +cRSub +dV +wB(289,"x " +a4 +aC"cSub" +,"A" +aV" [x] " +a4,aA(A)<<"," +m4);q4 +Lfd;} +wB(296,a4 +aC"cSub" +,"[DO_STACKPLUS1] A" +mF" " +a4,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lfe;} +qG +g7 +Default0:;A=w5 +qR +IsComparisonOpcode(h2 +qY +hK +qZ +mR(364,aU"cAdd" +wF,"[x-y] A" +,aA(A)<mByteCode.size()>0]" +,"B" +mE,aA(A)q51(B)wM);q4 +Lfh;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mE,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Lfi;} +} +} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:oZ +4));gG +Lfj:w5=h3;Lfk:g0 +Lfl:wE(cMul);q4 +TailCall_cMul;Lae:hV +4 +dT +oZ +4)q11 +gX +Lfj;Laf:q7=x+g1 +1);gG +Lbo:w5=h3;q4 +Lfl;Lag:gU +cSub;Lfm:wE(cSub);q4 +TailCall_cSub;Lah:hW +2 +gH +Lfn:g0 +Lfo:wE(cAdd);q4 +TailCall_cAdd;Lai:hW +oR +Lfp:qE +hS);Lfq:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Laj:o9;qL +2 +gK +q4 +Lfp;Lak:hW +2 +gH +q4 +Lfq;Lal:hW +4 +gH +Lga:qE +hS);Lgb:qE +B);Lgc:w5=cSub;g0 +q4 +Lfm;Lam:o9;oC=q6 +q9 +oR +q4 +Lga;Lan:hW +oR +q4 +Lgb;Lao:gT +y+x;Lap:qM +Lcb:q5 +gJ +Laq:q8 +oV +o7 +x +q11 +gX +Lfp;Lba:mI +A +gX +Lfp;Lbb:gU +dS;Lgd:wE(cNotNot);q4 +TailCall_cNotNot;Lbc:gT +fp_and(x +h6 +Lbd:oZ));dF +dJ +qE +dU +oZ +1));Lge:qW +q6);Lgf:w5=hS;q4 +Lfn;Lbe:o9;dI +wE(cDiv);q4 +TailCall_cDiv;Lbf:gT +y/x;q4 +Lap;Lbg:gT +fp_equal +mL +Lbh:dI +Lgg:wE(cEqual);q4 +TailCall_cEqual;Lbi:qM +q5 +Lgh:w5=cNot;g0 +Lgi:wE(cNot);q4 +TailCall_cNot;Lbj:q8 +2 +gH +Lgj:w5=dS;g0 +q4 +Lgd;Lbk:qM +w3 +Lgj;Lbl:gT +fp_less(x +h6 +Lbm:gT +fp_lessOrEq(x +h6 +Lbn:q7=g1 +1)/x;gJ +Lbp:dG +Lgh;Lbq:gT +fp_less +mL +Lca:gT +fp_lessOrEq +mL +Lcc:gT +fp_max(x +h6 +Lcd:gT +fp_min(x +h6 +Lce:gT +fp_mod +mL +Lcf:gU +cSqr;Lgk:wE(cSqr);q4 +TailCall_cSqr;Lcg:mI +cSqr);Lgl:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lch:hV +3 +gC +cSqr);dM +Lgl;Lci:q7=x+g1 +1);hE=q6 +q9 +2 +gC +cPow);gJ +Lcj:gG +q4 +Lfl;Lck:gT +x;Lgm:dG +Lfk;Lcl:hV +2;qI +qM +Lgn:hV +4 +gH +Lgo:o6 +x);Lgp:qW +q6 +gX +Lfk;Lcm:qM +q4 +Lgn;Lcn:q8 +4 +gC +B +gX +Lgo;Lco:q8 +oR +q4 +Lgo;Lcp:qK +dJ +q4 +Lcb;Lcq:dI +q4 +Lfl;Lda:q7=x+x;q4 +Lcj;Ldb:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Lgf;Ldc:gT +x;d7 +dU +qF +y*x +gX +Lge;Ldd:q8 +4 +dT +qF +x+x +gX +Lgp;Lde:hV +2;qI +q8 +oR +gJ +Ldf:gT +y*x;q4 +Lgm;Ldg:o9;q4 +Lcq;Ldh:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Lgc;Ldi:gT +y*x;q4 +Lap;Ldj:qM +w3 +Lgl;Ldk:dF=cDup;dW-=1;qM +Lgq:w5=hS;q4 +Lfo;Ldl:hV +2 +gH +Lha:qE +cSqr +gX +Lfk;Ldm:hV +oR +q4 +Lha;Ldn:gT +fp_nequal +mL +Ldo:dI +Lhb:wE(cNEqual);q4 +TailCall_cNEqual;Ldp:o9;g6 +oS;Ldq:o9;gJ +Lea:g6 +q4 +Lgi;Leb:q1 +cAbsNotNot);gJ +Lec:q5 +Lel:qE +cAbsNot);gJ +Led:o9;Lej:gU +w8;q4 +Lgg;Lee:gU +cNEqual;q4 +Lhb;Lef:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Leg:gU +cLess;wE(cLess);q4 +TailCall_cLess;Leh:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Lei:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Lek:q7=fp_not +m5 +Lem:o9;q4 +Lee;Len:gT +fp_or(x +h6 +Leo:qM +q5 +w5=cInv;g0 +wE(cInv);q4 +TailCall_cInv;Lep:oZ));dF +dJ +q4 +Lfj;Leq:g6 +q4 +Lgk;Lfa:g6 +q4 +Lgq;Lfb:gT +y-x;q4 +Lap;Lfc:o9;q4 +Lgq;Lfd:q8 +oV +oJ +hS +o7 +x +q11 +gX +Lfq;Lfe:mI +A +oJ +cSub +gX +Lfq;Lff:gT +x-y;d7 +A);gJ +Lfg:o9;qK +dJ +q1 +OppositeComparisonOpcode(A));gJ +Lfh:qW +cDup);gJ +Lfi:dF=cDup;gJ +gJ +q4 +TailCall_cAnd;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cNeg;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cSub; +#endif +#if((FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION)) +dH +x;dH +gE +A;hT +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0} +qH +TailCall_cAdd:g5 +hG +Lad;qT +h3 +hL]==hS){if(qL +gZ +Lae;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +wY +aV,"[x+Value_t(1)]" +wH,wN);q4 +Laf;} +} +q4 +dX +oF +wB(199,q81 +aV,"cSub" +,);q4 +Lag +gY +hK +qZ +mR(127,aU"cAdd " +a6,"[y+x]" +aV,q31);q4 +Lah;qT +cRSub:qQ +hE +d3 +3 +qZ +mR(298,aU"cAdd " +mS,mJ +aV" " +a4,q31);q4 +Lai;qT +hI +wB(299,mG +mS,"[-x]" +aV" " +a4,wN);q4 +Laj +qU +q6:mR(297,aU +mS,mJ" " +a4,q31);q4 +Lak;qT +oA +Lal;qT +hI +wB(293,mG"B[IsVarOpcode(B)]" +mF" " +a6,"[-x]" +aV" B" +mF,wA"," +aQ(B)wM);q4 +Lam +qU +q6:mR(291,aU"B[IsVarOpcode(B)]" +mF" " +a6,mJ" B" +mF,wA"," +aQ(B)<<"," +aE);q4 +Lan;} +w9 +mR(105,aU +a6,"[y+x]" +,q31);q4 +Lao;} +g8)){wB(57,"x[x==Value_t()]" +aV,,wN);q4 +Lap;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x " +a4 +aC"cAdd" +,"[DO_STACKPLUS1] A [x]" +aV" " +a4,aA(A)<<"," +m4);incStackPtr();--mStackPtr;q4 +Laq;} +wB(295,a4 +aC"cAdd" +,"[DO_STACKPLUS1] A" +aV" " +a4,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lba;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mC"cAnd" +,aF,);q4 +Lbb +gY +m2(117,m3"cAnd" +,"[fp_and(x,y)]" +,q31);q4 +Lbc;h8} +qH +TailCall_cConj:g5 +cConj:qS +cConj:wB(63,mT" " +mT,,);q4 +w7 +wB(193,"x " +mT,"[fp_conj(x)]" +,wN);q4 +Lbe;} +qH +TailCall_cDiv:g5 +cDiv +hH +wB(78,"cDup" +m7,"[Value_t()]" +m6"[Value_t(1)]" +aV,);q4 +Lbf +gY +if +hF +gQ +hI +wB(125,mG +wZ"cDiv" +,"[-x]" +m7,wN);q4 +Lbg +qU +q6:mR(103,aU +wZ"cDiv" +,"[y/x]" +,q31);q4 +Lbh;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lap;h8} +qH +TailCall_cEqual:g5 +w8:dA +A=dD +wB(421,"A[IsLogicalOpcode(A)] " +wO +a5,"A" +,q61(A)wM);q4 +Lap;} +} +m2(115,m3 +a5,"[fp_equal(y,x)]" +,q31);q4 +Lbi;} +g8 +0 +hU +wB(359,aX +wL +a5,"[x] " +a5,wN);q4 +Lbj +qU +cSqr:wB(361,mZ +wL +a5,"[x] " +a5,wN);q4 +Lbj;} +wB(411,wL +a5,"cNot" +,wN);q4 +Lbk;qG +TailCall_cGreater:g5 +o1:qY +m2(113,m3 +aW,"[fp_less(x,y)]" +,q31);q4 +Lbl;qG +TailCall_cGreaterOrEq:g5 +dK:qY +m2(114,m3 +a8,"[fp_lessOrEq(x,y)]" +,q31);q4 +Lbm;qG +TailCall_cImag:g5 +cImag:qS +cAbs:wB(81,aX +mU,"[Value_t()]" +wH,);q4 +Lbn +qU +cReal:wB(80,"cReal " +mU,"[Value_t()]" +wH,);q4 +Lbn +gY +wB(192,"x " +mU,"[fp_imag(x)]" +,wN);oS;} +qH +TailCall_cInv:g5 +cInv:qY +if +hF)){wB(101,wZ +aS,"[Value_t(1)/x]" +,wN);q4 +Lbp;qG +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mB,mV,q61(A)wM);q4 +Lbq;} +} +m2(111,m3 +mB,"[fp_less(y,x)]" +,q31);q4 +Lca;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m2(112,m3 +aM,"[fp_lessOrEq(y,x)]" +,q31);q4 +Lcb;qG +TailCall_cMax:g5 +cMax +hH +wB(60,mC +m8,,);q4 +w7 +m2(141,m3 +m8,"[fp_max(x,y)]" +,q31);q4 +Lcc;} +gP +cDup:hD +wB(66,aG +mE +aC +m8,"B" +mE,aA(A)q51(B)wM);q4 +Lbd;qT +cMax:hD +wB(68,aG" " +m8 +aC +m8,"B " +m8,aA(A)q51(B)wM);q4 +Lbd;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mC +m9,,);q4 +w7 +m2(140,m3 +m9,"[fp_min(x,y)]" +,q31);q4 +Lcd;} +gP +cDup:hD +wB(65,aG +mE +aC +m9,"B" +mE,aA(A)q51(B)wM);q4 +Lbd;qT +cMin:hD +wB(67,aG" " +m9 +aC +m9,"B " +m9,aA(A)q51(B)wM);q4 +Lbd;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m2(104,aU +wZ"cMod" +,"[fp_mod(y,x)]" +,q31);q4 +Lce;} +qG +TailCall_cMul:g5 +h3 +hH +wB(202,"cDup" +wH,"cSqr" +,);q4 +Lcf +oF +qQ +h9 +cDup:wB(467,mC +q81 +wH,"cSqr" +mD,);q4 +Lcg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aG +wH +aC +q81 +wH,m0 +m6 +q81,aA(A)q51(B)wM);q4 +Lch;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mC"x" +a1 +wH,"[x+Value_t(1)]" +a1,wN);q4 +Lci;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wT" " +wX,a3,q61(A)wM);q4 +Lcj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mR(92,aU +wD,a3,q61(A)<<"," +aE);q4 +Lck;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mR(96,aU +wK,mV,q61(A)q51(B)<<"," +aE);q4 +Lcl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lcm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lcn;} +} +} +if(d1 +B)){wB(90,"B[IsVarOpcode(B)] " +wD,a3,q61(A)q51(B)wM);q4 +Lcj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mV,q61(A)q51(B)wM);q4 +Lco;} +} +} +if(d1 +h2 +wB(88,aD" " +wX,"[x]" +,q61(A)wM);q4 +Lcp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wX,a3,q61(A)wM);q4 +Lcq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup:wB(317,a9 +wY,"[x+x]" +wH,wN);q4 +Lda +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,aD" y" +wH +aV +wY,a3" A " +aZ +wH +aV,wA", " +aU"= " +<mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Ldm;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:dA +A=dD +wB(422,"A[IsLogicalOpcode(A)] " +wO +wW,"A" +aB,q61(A)wM);q4 +Lbk;} +} +m2(116,m3 +wW,"[fp_nequal(y,x)]" +,q31);q4 +Ldn;} +g8 +0 +hU +wB(360,aX +wL +wW,"[x] " +wW,wN);q4 +Ldo +qU +cSqr:wB(362,mZ +wL +wW,"[x] " +wW,wN);q4 +Ldo;} +wB(412,wL +wW,aF,wN);q4 +Ldp;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +m6 +q81,"[-x]" +wH,wN);q4 +Ldq;qT +hI +wB(61,q81 +mD,,);q4 +w7 +wB(100,"x" +mD,"[-x]" +,wN);q4 +Lea;} +qH +TailCall_cNot:g5 +cNot:qS +cAbsNotNot:wB(231,"cAbsNotNot" +aB,aN,);q4 +Leb +qU +hS +gM +wB(424,a6 +aB,"[-x] " +a5,wN);q4 +Lec;qT +w8:wB(220,a5 +aB,wW,);q4 +Led +qU +o1:wB(218,aW +aB,aM,);q4 +Lee +qU +dK:wB(219,a8 +aB,mB,);q4 +Lef +qU +cLess:wB(216,mB +aB,a8,);q4 +Leg +qU +cLessOrEq:wB(217,aM +aB,aW,);q4 +Leh +qU +cNEqual:wB(221,wW +aB,a5,);q4 +Lei +qU +cNot:wB(229,"cNot" +aB,aF,);q4 +Lbb +qU +dS:wB(230,aF +aB,"cNot" +,);q4 +Lej +gY +wB(107,"x" +aB,"[fp_not(x)]" +,wN);q4 +Lek;} +qH +TailCall_cNotNot:g5 +dS:qS +hS +gM +wB(423,a6" " +aF,"[-x] " +wW,wN);q4 +Lel;qT +cNot:wB(232,"cNot " +aF,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mC"cOr" +,aF,);q4 +Lbb +gY +m2(118,m3"cOr" +,"[fp_or(x,y)]" +,q31);q4 +Lem;h8} +qH +TailCall_cRDiv:g5 +cRDiv:dA +wB(268,wO"cRDiv" +,aS,wN);q4 +Len;qG +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,mC +a4,"[Value_t()]" +wH,);q4 +Lbn;} +qH +TailCall_cReal:g5 +cReal:qY +wB(191,"x cReal" +,"[fp_real(x)]" +,wN);q4 +Leo;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,aX"cSqr" +,"cSqr" +,);q4 +Lep +oF +wB(203,mG"cSqr" +,"cSqr" +,);q4 +Lep;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,mC"cSub" +,"[Value_t()]" +wH,);q4 +Lbn +oF +wB(200,q81 +mF,"cAdd" +,);q4 +Leq +gY +g8)){wB(58,"x[x==Value_t()]" +mF,,wN);q4 +Lap;} +m2(106,m3"cSub" +,"[y-x]" +,q31);q4 +Lfa;} +wB(51,"x" +mF,"[-x]" +aV,wN);q4 +Lfb +gR +w0 +oY +cRSub +dV +wB(289,"x " +a4 +aC"cSub" +,"A" +aV" [x] " +a4,aA(A)<<"," +m4);q4 +Lfc;} +wB(296,a4 +aC"cSub" +,"[DO_STACKPLUS1] A" +mF" " +a4,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lfd;} +qG +g7 +Default0:;A=w5 +w1 +0){B=q0[0 +hZ +wB(475,aG" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mE,aA(A)q51(B)wM);q4 +Lfe;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mE,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Lff;} +} +} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:oZ +4));gG +Lfg:w5=h3;Lfh:g0 +Lfi:wE(cMul);q4 +TailCall_cMul;Lae:hV +4 +dT +oZ +4)q11 +gX +Lfg;Laf:q7=x+g1 +1);gG +Lbq:w5=h3;q4 +Lfi;Lag:gU +cSub;Lfj:wE(cSub);q4 +TailCall_cSub;Lah:hW +2 +gH +Lfk:g0 +Lfl:wE(cAdd);q4 +TailCall_cAdd;Lai:hW +oR +Lfm:qE +hS);Lfn:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Laj:o9;qL +2 +gK +q4 +Lfm;Lak:hW +2 +gH +q4 +Lfn;Lal:hW +4 +gH +Lfo:qE +hS);Lfp:qE +B);Lfq:w5=cSub;g0 +q4 +Lfj;Lam:o9;oC=q6 +q9 +oR +q4 +Lfo;Lan:hW +oR +q4 +Lfp;Lao:gT +y+x;Lap:qM +Lbd:q5 +gJ +Laq:q8 +oV +o7 +x +q11 +gX +Lfm;Lba:mI +A +gX +Lfm;Lbb:gU +dS;Lga:wE(cNotNot);q4 +TailCall_cNotNot;Lbc:gT +fp_and(x +h6 +Lbe:q7=fp_conj +m5 +Lbf:oZ));dF +dJ +qE +dU +oZ +1));Lgb:qW +q6);Lgc:w5=hS;q4 +Lfk;Lbg:o9;dI +wE(cDiv);q4 +TailCall_cDiv;Lbh:gT +y/x;q4 +Lap;Lbi:gT +fp_equal +mL +Lbj:dI +Lgd:wE(cEqual);q4 +TailCall_cEqual;Lbk:qM +q5 +w5=cNot;g0 +Lge:wE(cNot);q4 +TailCall_cNot;Lbl:gT +fp_less(x +h6 +Lbm:gT +fp_lessOrEq(x +h6 +Lbn:oZ));dF +dJ +q4 +Lfg;Lbo:q7=fp_imag +m5 +Lbp:q7=g1 +1)/x;gJ +Lca:gT +fp_less +mL +Lcb:gT +fp_lessOrEq +mL +Lcc:gT +fp_max(x +h6 +Lcd:gT +fp_min(x +h6 +Lce:gT +fp_mod +mL +Lcf:gU +cSqr;Lgf:wE(cSqr);q4 +TailCall_cSqr;Lcg:mI +cSqr);Lgg:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lch:hV +3 +gC +cSqr);dM +Lgg;Lci:q7=x+g1 +1);hE=q6 +q9 +2 +gC +cPow);gJ +Lcj:gG +q4 +Lfi;Lck:gT +x;Lgh:dG +Lfh;Lcl:hV +2;qI +qM +Lgi:hV +4 +gH +Lgj:o6 +x);Lgk:qW +q6 +gX +Lfh;Lcm:qM +q4 +Lgi;Lcn:q8 +4 +gC +B +gX +Lgj;Lco:q8 +oR +q4 +Lgj;Lcp:qK +dJ +q4 +Lbd;Lcq:dI +q4 +Lfi;Lda:q7=x+x;q4 +Lcj;Ldb:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Lgc;Ldc:gT +x;d7 +dU +qF +y*x +gX +Lgb;Ldd:q8 +4 +dT +qF +x+x +gX +Lgk;Lde:hV +2;qI +q8 +oR +gJ +Ldf:gT +y*x;q4 +Lgh;Ldg:o9;q4 +Lcq;Ldh:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Lfq;Ldi:gT +y*x;q4 +Lap;Ldj:qM +w3 +Lgg;Ldk:dF=cDup;dW-=1;qM +Lgl:w5=hS;q4 +Lfl;Ldl:hV +2 +gH +Lgm:qE +cSqr +gX +Lfh;Ldm:hV +oR +q4 +Lgm;Ldn:gT +fp_nequal +mL +Ldo:dI +Lgn:wE(cNEqual);q4 +TailCall_cNEqual;Ldp:qM +q5 +w5=dS;g0 +q4 +Lga;Ldq:o9;g6 +q4 +Lbq;Lea:o9;gJ +Leb:q1 +cAbsNot);gJ +Lec:o9;Lei:gU +w8;q4 +Lgd;Led:gU +cNEqual;q4 +Lgn;Lee:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Lef:gU +cLess;wE(cLess);q4 +TailCall_cLess;Leg:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Leh:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Lej:g6 +q4 +Lge;Lek:q7=fp_not +m5 +Lel:o9;q4 +Led;Lem:gT +fp_or(x +h6 +Len:qM +q5 +w5=cInv;g0 +wE(cInv);q4 +TailCall_cInv;Leo:q7=fp_real +m5 +Lep:g6 +q4 +Lgf;Leq:g6 +q4 +Lgl;Lfa:gT +y-x;q4 +Lap;Lfb:o9;q4 +Lgl;Lfc:q8 +oV +oJ +hS +o7 +x +q11 +gX +Lfn;Lfd:mI +A +oJ +cSub +gX +Lfn;Lfe:qW +cDup);gJ +Lff:dF=cDup;gJ +gJ +q4 +TailCall_cAnd;q4 +TailCall_cConj;q4 +TailCall_cImag;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cNeg;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cReal;q4 +TailCall_cSub; +#endif +#if((FP_FLOAT_VERSION) && !(FP_COMPLEX_VERSION)) +dH +x;hT +A;dH +gE +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0 +oH +dF +qR +qX +wB(393,wJ +mQ,"A" +,aA(A)wM);gJ +qG +TailCall_cAcos:g5 +cAcos:hN<=m1(148,"x[fp_abs(x)<=Value_t(1)] cAcos" +,"[fp_acos(x)]" +,wN);q4 +Lad;qG +TailCall_cAcosh:g5 +cAcosh:qY +if(x>=m1(145,"x[x>=Value_t(1)] cAcosh" +,"[fp_acosh(x)]" +,wN);q4 +Lae;qG +TailCall_cAdd:g5 +hG +Laf;qT +h3 +hL]==hS){if(qL +gZ +Lag;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +wY +aV,"[x+Value_t(1)]" +wH,wN);q4 +Lah;} +} +q4 +dX +oF +wB(199,q81 +aV,"cSub" +,);q4 +Lai +gY +hK +qZ +mR(127,aU"cAdd " +a6,"[y+x]" +aV,q31);q4 +Laj;qT +cRSub:qQ +hE +d3 +3 +qZ +mR(298,aU"cAdd " +mS,mJ +aV" " +a4,q31);q4 +Lak;qT +hI +wB(299,mG +mS,"[-x]" +aV" " +a4,wN);q4 +Lal +qU +q6:mR(297,aU +mS,mJ" " +a4,q31);q4 +Lam;qT +oA +Lan;qT +hI +wB(293,mG"B[IsVarOpcode(B)]" +mF" " +a6,"[-x]" +aV" B" +mF,wA"," +aQ(B)wM);q4 +Lao +qU +q6:mR(291,aU"B[IsVarOpcode(B)]" +mF" " +a6,mJ" B" +mF,wA"," +aQ(B)<<"," +aE);q4 +Lap;} +w9 +mR(105,aU +a6,"[y+x]" +,q31);q4 +Laq;} +g8)){wB(57,"x[x==Value_t()]" +aV,,wN);q4 +Lba;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x " +a4 +aC"cAdd" +,"[DO_STACKPLUS1] A [x]" +aV" " +a4,aA(A)<<"," +m4);incStackPtr();--mStackPtr;q4 +Lbb;} +wB(295,a4 +aC"cAdd" +,"[DO_STACKPLUS1] A" +aV" " +a4,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lbc;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mC"cAnd" +,aF,);q4 +w7 +m2(117,m3"cAnd" +,"[fp_and(x,y)]" +,q31);q4 +Lbe;h8} +qH +TailCall_cAsin:g5 +cAsin:hN<=m1(149,"x[fp_abs(x)<=Value_t(1)] cAsin" +,"[fp_asin(x)]" +,wN);q4 +Lbf;qG +TailCall_cAsinh:g5 +cAsinh:qY +wB(146,"x cAsinh" +,"[fp_asinh(x)]" +,wN);q4 +Lbg;} +qH +TailCall_cAtan:g5 +cAtan:qY +wB(150,"x cAtan" +,"[fp_atan(x)]" +,wN);q4 +Lbh;} +qH +TailCall_cAtan2:g5 +cAtan2:qY +m2(139,m3"cAtan2" +,"[fp_atan2(y,x)]" +,q31);q4 +Lbi;qG +TailCall_cAtanh:g5 +cAtanh:hN()]" +m6 +wR,"cDeg" +,q31);q4 +Ldd;} +if((y/x)==fp_const_deg_to_rad +h7 +wB(322,"y[(y/x)==fp_const_deg_to_rad()]" +m6 +wR,"cRad" +,q31);q4 +Lde;} +wB(323,"y" +m6 +wR,"[y/x]" +wH,q31);q4 +Ldf;} +} +wB(325,wR,"[Value_t(1)/x]" +wH,wN);q4 +Ldg;} +gP +cDiv:hC +wB(271,q21" " +wV,"[DO_STACKPLUS1] B A" +m6"cDiv" +,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4 +Ldh;qT +cRDiv:qQ +hE +qV +hM +wB(266,"x" +a7" " +wV,"A" +m6"[x]" +a7,aA(A)<<"," +m4);q4 +Ldi;g7 +hC +wB(265,"B[IsVarOpcode(B)]" +a7" " +wV,"A" +m6"B" +a7,aA(A)q51(B)wM);q4 +Ldj;} +h8} +qG +TailCall_cEqual:g5 +w8:oL +hU +wB(359,aX +wL +a5,"[x] " +a5,wN);q4 +Ldk +qU +cSqr:wB(361,mZ +wL +a5,"[x] " +a5,wN);q4 +Ldk;} +} +m2(115,m3 +a5,"[fp_equal(y,x)]" +,q31);q4 +Ldl;qG +TailCall_cExp:g5 +w2 +qS +hS +gM +wB(404,a6" " +mH,mH" [fp_exp(x)]" +wH,wN);q4 +Ldm;qT +cLog:A=dE +wB(340,wJ +mA" " +mH,"A" +,aA(A)wM);q4 +oN +hM +wB(154,"x " +mH,"[fp_exp(x)]" +,wN);q4 +Ldo;} +qH +TailCall_cExp2:g5 +cExp2:qS +hS +gM +wB(405,a6" cExp2" +,"cExp2 [fp_exp2(x)]" +wH,wN);q4 +Ldp;qT +cLog2:A=dE +wB(341,wJ +aJ" cExp2" +,"A" +,aA(A)wM);q4 +oN +hM +wB(155,"x cExp2" +,"[fp_exp2(x)]" +,wN);q4 +Ldq;} +wB(479,"cExp2" +,"[DO_STACKPLUS1] [fp_log(Value_t(2))]" +m6 +mH,);incStackPtr();--mStackPtr;q4 +Lea;TailCall_cFloor:g5 +cFloor:qS +hI +wB(401,mG +mO,mW +mD,);q4 +Leb +gY +wB(136,"x " +mO,"[fp_floor(x)]" +,wN);q4 +Lec +gS +wB(395,"A[IsAlwaysIntegerOpcode(A)] " +mO,"A" +,aA(A)wM);gJ +qG +TailCall_cGreater:g5 +o1:qY +m2(113,m3 +aW,"[fp_less(x,y)]" +,q31);q4 +Led;} +g8-oO +wB(431,"x[x==Value_t(-0.5)] " +aW,mG +aN,wN);q4 +Lee;qG +TailCall_cGreaterOrEq:g5 +dK:qY +dB +cAbs){wB(427,aX"x[x!=Value_t(0)] " +a8,"[Value_t(0.5)/x]" +m6 +aF,wN);q4 +Lef;} +} +m2(114,m3 +a8,"[fp_lessOrEq(x,y)]" +,q31);q4 +Leg;} +g8 +oO +wB(430,"x[x==Value_t(0.5)] " +a8,"cAbsNotNot" +,wN);q4 +Leh;qG +TailCall_cHypot:g5 +cHypot +d4 +dF==cSinCos){wB(84,"cSinCos cHypot" +,"[Value_t()]" +m6"[Value_t(1)]" +aV,);q4 +Lci;} +qH +TailCall_cInt:g5 +cInt:qS +hM +wB(137,"x cInt" +,"[fp_int(x)]" +,wN);q4 +Lei +gS +wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt" +,"A" +,aA(A)wM);gJ +qG +TailCall_cInv:g5 +cInv:qS +cCos:wB(256,aK +mK,mX,);q4 +Lej +qU +cCot:wB(260,"cCot" +mK,mN,);q4 +Lcp +qU +cCsc:wB(258,"cCsc" +mK,mM,);q4 +Lek +qU +cInv:wB(62,aS +mK,,);q4 +Ldn +qU +cPow:wB(355,"cPow" +mK,q81 +a1,);q4 +Lel +qU +cSec:wB(259,mX +mK,aK,);q4 +Lem +qU +cSin:wB(255,mM +mK,"cCsc" +,);q4 +Len +qU +cSqrt:wB(206,q01 +mK,"cRSqrt" +,);q4 +Leo +qU +cTan:wB(257,mN +mK,"cCot" +,);q4 +Lep +gY +if +hF)){wB(101,wZ +aS,"[Value_t(1)/x]" +,wN);q4 +Leq;h8} +qH +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mB,mV,q61(A)wM);q4 +Lfa;} +} +dB +cAbs){wB(426,aX"x[x!=Value_t(0)] " +mB,"[Value_t(0.5)/x]" +wH +aB,wN);q4 +Lfb;} +} +m2(111,m3 +mB,"[fp_less(y,x)]" +,q31);q4 +Lfc;} +g8 +oO +wB(429,"x[x==Value_t(0.5)] " +mB,aN,wN);q4 +Lfd;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m2(112,m3 +aM,"[fp_lessOrEq(y,x)]" +,q31);q4 +Lfe;} +g8-oO +wB(432,"x[x==Value_t(-0.5)] " +aM,mG"cAbsNotNot" +,wN);q4 +Lff;qG +TailCall_cLog:g5 +cLog:mP(343,mH" " +mA,,);q4 +Ldn +qU +gL +wB(491,wQ +m6 +mA,mA" [fp_log(x)]" +aV,wN);q4 +Lfg;} +o2 +wB(303,mZ +mA,aX +mA" " +a9,);q4 +Lfh +aT(156,wQ" " +mA,"[fp_log(x)]" +,wN);q4 +Lfi;h8} +qH +TailCall_cLog10:g5 +cLog10:mP(481,mH" " +aH,"[DO_STACKPLUS1] [fp_log10(fp_const_e())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfj +qU +gL +wB(492,wQ +m6 +aH,aH" [fp_log10(x)]" +aV,wN);q4 +Lfk;} +o2 +wB(305,mZ +aH,aX +aH" " +a9,);q4 +Lfl +aT(157,wQ" " +aH,"[fp_log10(x)]" +,wN);q4 +Lfm;h8} +qH +TailCall_cLog2:g5 +cLog2:mP(480,mH" " +aJ,"[DO_STACKPLUS1] [fp_log2(fp_const_e())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfn +qU +cExp2:wB(344,"cExp2 " +aJ,,);q4 +Ldn +qU +gL +wB(490,wQ +m6 +aJ,aJ" [fp_log2(x)]" +aV,wN);q4 +Lfo;} +o2 +wB(304,mZ +aJ,aX +aJ" " +a9,);q4 +Lfp +aT(158,wQ" " +aJ,"[fp_log2(x)]" +,wN);q4 +Lfq;h8} +qH +TailCall_cMax:g5 +cMax +hH +wB(60,mC +m8,,);q4 +Ldn +gY +m2(141,m3 +m8,"[fp_max(x,y)]" +,q31);q4 +Lga;} +gP +cDup:hD +wB(66,aG +mE +aC +m8,"B" +mE,aA(A)q51(B)wM);q4 +oN +cMax:hD +wB(68,aG" " +m8 +aC +m8,"B " +m8,aA(A)q51(B)wM);q4 +Ldn;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mC +m9,,);q4 +Ldn +gY +m2(140,m3 +m9,"[fp_min(x,y)]" +,q31);q4 +Lgb;} +gP +cDup:hD +wB(65,aG +mE +aC +m9,"B" +mE,aA(A)q51(B)wM);q4 +oN +cMin:hD +wB(67,aG" " +m9 +aC +m9,"B " +m9,aA(A)q51(B)wM);q4 +Ldn;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m2(104,aU +wZ"cMod" +,"[fp_mod(y,x)]" +,q31);q4 +Lgc;} +qG +TailCall_cMul:g5 +h3:qS +cCsc:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(508,aG" " +aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc" +wH,"B cCot" +,aA(A)q51(B)wM);q4 +Lgd;} +} +} +q4 +dY +qU +cDup:wB(202,"cDup" +wH,"cSqr" +,);q4 +Lge +qU +cInv:wB(214,aS +wH,"cDiv" +,);q4 +Lgf +oF +qQ +h9 +cDup:wB(467,mC +q81 +wH,"cSqr" +mD,);q4 +Lgg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aG +wH +aC +q81 +wH,m0 +m6 +q81,aA(A)q51(B)wM);q4 +Lgh;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mC"x" +a1 +wH,"[x+Value_t(1)]" +a1,wN);q4 +Lgi;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wT" " +wX,a3,q61(A)wM);q4 +Lgj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mR(92,aU +wD,a3,q61(A)<<"," +aE);q4 +Lgk;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mR(96,aU +wK,mV,q61(A)q51(B)<<"," +aE);q4 +Lgl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lgm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lgn;} +} +} +if(d1 +B)){wB(90,"B[IsVarOpcode(B)] " +wD,a3,q61(A)q51(B)wM);q4 +Lgj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mV,q61(A)q51(B)wM);q4 +Lgo;} +} +} +if(d1 +h2 +wB(88,aD" " +wX,"[x]" +,q61(A)wM);q4 +Lgp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wX,a3,q61(A)wM);q4 +Lgq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup +d4 +x+oU +wB(316,"cDup[x+x==Value_t(1)]" +aV +wY,,wN);q4 +Lha;} +wB(317,a9 +wY,"[x+x]" +wH,wN);q4 +Lhb +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,aD" y" +wH +aV +wY,a3" A " +aZ +wH +aV,wA", " +aU"= " +<()]" +wH +wY,"cDeg" +,q31);q4 +Ldd;} +if((y*x)==fp_const_deg_to_rad +h7 +wB(308,"y[(y*x)==fp_const_deg_to_rad()]" +wH +wY,"cRad" +,q31);q4 +Lde;} +wB(128,"y" +wH +wY,aZ +wH,q31);q4 +Lhl;qT +hI +wB(122,q81 +wY,"[-x]" +wH,wN);q4 +Lhm +qU +cRDiv:qQ +hE +qV +o5 +3 +qZ +mR(285,"y" +wH +a7 +wY,aZ +wH +a7,q31);q4 +Lhn;qT +hI +wB(286,q81 +a7 +wY,"[-x]" +wH +a7,wN);q4 +Lho +qU +q6:mR(284,"y" +a7 +wY,aZ +a7,q31);q4 +Lhp;qT +cRad:wB(210,"cRad" +wY,"[DegreesToRadians(x)]" +wH,wN);q4 +Lhq +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,aD" y" +m6"cSub" +wY,a3" A " +aZ +m6"cSub" +,wA", " +aU"= " +<()]" +wH,"cDeg" +,wN);q4 +Lie;} +if(x==fp_const_deg_to_rad +h7 +wB(208,"x[x==fp_const_deg_to_rad()]" +wH,"cRad" +,wN);q4 +Lif;h8 +g7 +dY:;A=dF +qO +A +gQ +cDiv:hC +wB(274,q21" " +wT,"[DO_STACKPLUS1] A" +m6"B" +m7,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4 +Lig;} +q4 +d5 +h3:qQ +hE +qV +hI +B=hQ +wB(470,aG +mD +m6 +wT,m0 +m6 +q81,aA(A)q51(B)wM);q4 +Lgh;} +q4 +dZ;g7 +dZ:;hD +wB(461,aG +m6 +wT,m0 +wH,aA(A)q51(B)wM);q4 +Lih;} +} +q4 +d5 +hI +hD +wB(464,aG +mD" " +wT,m0 +mD,aA(A)q51(B)wM);q4 +Lgg;} +q4 +d5 +cRDiv +hL +qZ +qC +wB(267,"x" +a7" " +wT,"[DO_STACKPLUS1] " +mV +a7,aA(A)<<"," +m4);incStackPtr();--mStackPtr;q4 +Lii;} +wB(281,"cRDiv " +wT,"[DO_STACKPLUS1] A" +wH +a7,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lij;g7 +Default4:;B=qK +qR +w4 +wB(458,aG" " +wT,m0,aA(A)q51(B)wM);q4 +Lge;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +m6"B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Lik;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:oL +hU +wB(360,aX +wL +wW,"[x] " +wW,wN);q4 +Lil +qU +cSqr:wB(362,mZ +wL +wW,"[x] " +wW,wN);q4 +Lil;} +} +m2(116,m3 +wW,"[fp_nequal(y,x)]" +,q31);q4 +Lim;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +m6 +q81,"[-x]" +wH,wN);q4 +Lin;qT +hI +wB(61,q81 +mD,,);q4 +Ldn +qU +cSin:g9 +wB(244,"x" +m6 +mM +mD,"[-x]" +m6 +mM,wN);q4 +Lio;} +qT +oQ +g9 +wB(245,"x" +m6"cSinh" +mD,"[-x]" +m6"cSinh" +,wN);q4 +Lip;} +qT +cTan:g9 +wB(246,"x" +m6 +mN +mD,"[-x]" +m6 +mN,wN);q4 +Liq;} +qT +cTanh:g9 +wB(247,"x" +m6"cTanh" +mD,"[-x]" +m6"cTanh" +,wN);q4 +Lja;} +qT +hM +wB(100,"x" +mD,"[-x]" +,wN);q4 +Ljb;} +qH +TailCall_cNot:g5 +cNot:qS +cAbs:wB(227,mQ +aB,"cNot" +,);q4 +Ljc +qU +cAbsNot:A=dD +wB(389,"A[IsLogicalOpcode(A)] " +aN +aB,"A" +,aA(A)wM);q4 +Ldn;} +if(A!=q6){wB(390,"A[A!=cImmed] " +aN +aB,"A cAbsNotNot" +,aA(A)wM);q4 +Ljd;} +q4 +o0 +qU +cAbsNotNot:wB(231,"cAbsNotNot" +aB,aN,);q4 +Lje +qU +w8:wB(220,a5 +aB,wW,);q4 +Ljf +qU +o1:wB(218,aW +aB,aM,);q4 +Ljg +qU +dK:wB(219,a8 +aB,mB,);q4 +Ljh +qU +cLess:wB(216,mB +aB,a8,);q4 +Lji +qU +cLessOrEq:wB(217,aM +aB,aW,);q4 +Ljj +qU +cNEqual:wB(221,wW +aB,a5,);q4 +Ljk +oF +wB(226,q81 +aB,"cNot" +,);q4 +Ljc +qU +cNot:wB(229,"cNot" +aB,aF,);q4 +Lbd +qU +dS:wB(230,aF +aB,"cNot" +,);q4 +Ljc +gY +wB(107,"x" +aB,"[fp_not(x)]" +,wN);q4 +Ljl;g7 +o0:;A=dF +qR +qX +wB(391,wJ"cNot" +,"A " +aN,aA(A)wM);q4 +Ljm;qG +TailCall_cNotNot:g5 +dS +d4 +dF==cNot){wB(232,"cNot " +aF,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mC"cOr" +,aF,);q4 +w7 +m2(118,m3"cOr" +,"[fp_or(x,y)]" +,q31);q4 +Ljn;h8} +qH +TailCall_cPow:g5 +cPow:qY +if(!h5 +x+x)){oY +cSqr){wB(22,mZ"x[!isEvenInteger(x+x)]" +a1,aX"[x+x]" +a1,wN);q4 +Ljo;} +} +if(isInteger(x +gQ +w2 +wB(43,mH" " +wS,a3" " +mH,wN);q4 +Ljp +qU +cExp2:wB(44,"cExp2 " +wS,a3" cExp2" +,wN);q4 +Ljq +qU +cPow +hL +qZ +hP!isInteger(y)){wB(42,"y[!isInteger(y)]" +a1" " +wS,aZ +a1,q31);q4 +Lka;} +} +wB(45,"cPow " +wS,a3 +a1,wN);q4 +Lkb;} +} +if(h5 +x +hU +wB(434,aX"x[isEvenInteger(x)]" +a1,"[x]" +a1,wN);q4 +Lkc +qU +h3 +hL]==cAbs){wB(435,mQ +m6"x[isEvenInteger(x)]" +a1,"cMul [x]" +a1,wN);q4 +Lkd;h8} +} +g8)){wB(83,"x[x==Value_t()]" +a1,"[Value_t()]" +m6"[Value_t(1)]" +aV,wN);q4 +Lke;} +g8 +oO +wB(332,"x[x==Value_t(0.5)]" +a1,q01,wN);q4 +Lkf;} +g8 +1)/g1 +3)){wB(333,"x[x==Value_t(1)/Value_t(3)]" +a1,"cCbrt" +,wN);q4 +Lkg;} +g8 +1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)]" +a1,"cCbrt" +mK,wN);q4 +Lkh;} +g8-oO +wB(335,"x[x==Value_t(-0.5)]" +a1,"cRSqrt" +,wN);q4 +Lki;} +g8-oG +wB(336,"x[x==Value_t(-1)]" +a1,aS,wN);q4 +Lkj;} +qQ +h9 +cPow +hL +qZ +hP +h5 +y)&&!h5 +x*y)){wB(21,"y[isEvenInteger(y)&&!isEvenInteger(x*y)]" +a1" x" +a1,aX +aZ +a1,q31);q4 +Lkk;} +wB(330,"y" +a1" x" +a1,aZ +a1,q31);q4 +Lka;o2 +wB(46,mZ"x" +a1,"[x+x]" +a1,wN);q4 +Lkl +qU +q6:hP +y!=oP||x>=oP){wB(165,"y[y!=Value_t(0)||x>=Value_t(0)] x" +a1,"[fp_pow(y,x)]" +,q31);q4 +Lkm;h8} +wB(455,"x" +a1,"[DO_POWI]" +,wN)qR +TryCompilePowi(x))gJ} +qH +TailCall_cRDiv:g5 +cRDiv:qS +cSinCos:wB(503,"cSinCos" +a7,"cCot" +,);q4 +Lep +qU +cSinhCosh:wB(510,"cSinhCosh" +a7,"cTanh" +mK,);q4 +Lkn +gY +g8 +oG +wB(268,wO"cRDiv" +,aS,wN);q4 +Lkj;h8} +qH +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,mC +a4,"[Value_t()]" +wH,);q4 +Lko;} +qH +TailCall_cRad:g5 +cRad:qS +h3 +gM +wB(211,"x" +m6"cRad" +,"[DegreesToRadians(x)]" +wH,wN);q4 +Lkp;qT +hM +wB(134,"x cRad" +,"[DegreesToRadians(x)]" +,wN);q4 +Lkq;} +qH +TailCall_cSec:g5 +cSec:A=qN +qQ +h9 +cCos:hD +wB(497,aG" " +aK" " +wI +mX,"B " +aK" " +aR,aA(A)q51(B)wM);q4 +Lbp;qT +cSin:hD +wB(495,aG" " +mM" " +wI +mX,"B cSinCos" +mK,aA(A)q51(B)wM);q4 +Lla;h8 +qG +TailCall_cSin:g5 +cSin:qS +hI +wB(240,mG +mM,mM +mD,);q4 +Llb +gY +wB(159,"x " +mM,"[fp_sin(x)]" +,wN);q4 +Llc;oH +qN +oY +cCsc +mY(499,aG" cCsc " +wI +mM,"B cCsc " +aR,aA(A)q51(B)wM);q4 +Lbp;} +} +qG +TailCall_cSinh:g5 +oQ +qS +cAcosh:wB(437,"cAcosh cSinh" +,"[DO_STACKPLUS1] " +mZ"[Value_t(-1)] " +aL,);incStackPtr();--mStackPtr;q4 +Lld +qU +cAsinh:wB(349,"cAsinh cSinh" +,,);q4 +Ldn +oF +wB(241,mG"cSinh" +,"cSinh" +mD,);q4 +Lle +gY +wB(160,"x cSinh" +,"[fp_sinh(x)]" +,wN);q4 +Llf;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,aX"cSqr" +,"cSqr" +,);q4 +Llg +oF +wB(203,mG"cSqr" +,"cSqr" +,);q4 +Llg +qU +cSqrt:A=dE +wB(338,wJ +q01" cSqr" +,"A" +,aA(A)wM);q4 +Ldn;h8} +qH +TailCall_cSqrt:g5 +cSqrt:qS +hS +d4 +qK +o3 +A=hE +w0 +if(oC +o3 +wB(512,"cSqr" +aC +mZ +aL,"A cHypot" +,aA(A)wM);q4 +Llh;} +} +B +g4 +gV +B)){A=oC +w0 +if(qL +4]o3 +wB(513,"cSqr" +aC"B[IsUnaryOpcode(B)] " +mZ +aL,"A B cHypot" +," with" +aQ(B)q71(A)wM);q4 +Lli;} +} +} +o2 +wB(23,mZ +q01,mQ,);q4 +Llj +gY +if(x>=oP){wB(161,"x[x>=Value_t(0)] " +q01,"[fp_sqrt(x)]" +,wN);q4 +Llk;h8} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,mC"cSub" +,"[Value_t()]" +wH,);q4 +Lko +oF +wB(200,q81 +mF,"cAdd" +,);q4 +Lll +gY +g8)){wB(58,"x[x==Value_t()]" +mF,,wN);q4 +Lba;} +m2(106,m3"cSub" +,"[y-x]" +,q31);q4 +Llm;} +wB(51,"x" +mF,"[-x]" +aV,wN);q4 +Lln +gR +w0 +oY +cRSub +dV +wB(289,"x " +a4 +aC"cSub" +,"A" +aV" [x] " +a4,aA(A)<<"," +m4);q4 +Llo;} +wB(296,a4 +aC"cSub" +,"[DO_STACKPLUS1] A" +mF" " +a4,aA(A)wM);incStackPtr();--mStackPtr;q4 +Llp;} +qG +TailCall_cTan:g5 +cTan:qS +cAtan2:wB(354,"cAtan2 " +mN,"cDiv" +,);q4 +Lgf +oF +wB(242,mG +mN,mN +mD,);q4 +Llq +gY +wB(163,"x " +mN,"[fp_tan(x)]" +,wN);q4 +Lma;oH +qN +oY +cCot +mY(501,aG" cCot " +wI +mN,"B cCot " +aR,aA(A)q51(B)wM);q4 +Lbp;} +} +qG +TailCall_cTanh:g5 +cTanh:qS +hI +wB(243,mG"cTanh" +,"cTanh" +mD,);q4 +Lmb +gY +wB(164,"x cTanh" +,"[fp_tanh(x)]" +,wN);q4 +Lmc;} +qH +TailCall_cTrunc:g5 +cTrunc:qS +hM +wB(138,"x cTrunc" +,"[fp_trunc(x)]" +,wN);q4 +Lmd +gS +wB(394,"A[IsAlwaysIntegerOpcode(A)] cTrunc" +,"A" +,aA(A)wM);gJ +qG +g7 +Default0:;A=w5 +qR +IsComparisonOpcode(h2 +qY +hK +qZ +mR(364,aU"cAdd" +wF,"[x-y] A" +,aA(A)<()*g1 +oO +wB(380,"cAtan[fp_abs(x)()*Value_t(0.5)]" +wF,"[fp_tan(x)] A" +,aA(A)<<"," +m4);q4 +Lmf;qT +cExp +d4 +dO +wB(370,"cExp[x>Value_t(0)]" +wF,"[fp_log(x)] A" +,aA(A)<<"," +m4);q4 +Lmg;qT +cExp2 +d4 +dO +wB(371,"cExp2[x>Value_t(0)]" +wF,"[fp_log2(x)] A" +,aA(A)<<"," +m4);q4 +Lmh;qT +cLog:g3 +wB(373,wP +mA +wF,"B [fp_exp(x)] A" +,aA(A)<oP){wB(366,"y[y>Value_t(0)]" +wH +wF,"[x/y] A" +,aA(A)<oP +gA +qZ +hP +y>oP){wB(368,"y[y>Value_t(0)] cPow[x>Value_t(0)]" +wF,"[fp_pow(x,Value_t(1)/y)] A" +,aA(A)<Value_t(0)]" +wF,aX"[fp_sqrt(x)] A" +,aA(A)<<"," +m4);q4 +Lmq;qT +cTanh +d4 +dPmByteCode.size()>0]" +,"B" +mE,aA(A)q51(B)wM);q4 +Lnb;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mE,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Lnc;} +} +} +} +C=w5 +qR +IsCommutativeOrParamSwappableBinaryOpcode(C)){qS +cSin:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(505,aG" " +aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] " +mM" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinCos {GetParamSwappedBinaryOpcode(C)}" +," with C" +a0(C)q71(A)q51(B)wM);q4 +Lnd;} +} +qT +oQ +A=qK +w1 +3 +gA]==cCosh){B=hQ +wB(506,aG" " +aI" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}" +," with C" +a0(C)q71(A)q51(B)wM);q4 +Lne;} +} +h8} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +Lnf:wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:q7=fp_acos +m5 +Lae:q7=fp_acosh +m5 +Laf:oZ +4));gG +Lng:w5=h3;Lnh:g0 +Lni:wE(cMul);q4 +TailCall_cMul;Lag:hV +4 +dT +oZ +4));Lnj:qW +q6 +hA +Lah:q7=x+g1 +1);gG +Lfa:w5=h3;q4 +Lni;Lai:gU +cSub;Lnk:wE(cSub);q4 +TailCall_cSub;Laj:hW +2 +gH +Lnl:g0 +Lnm:wE(cAdd);q4 +TailCall_cAdd;Lak:hW +oR +Lnn:qE +hS);Lno:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Lal:o9;qL +2 +gK +q4 +Lnn;Lam:hW +2 +gH +q4 +Lno;Lan:hW +4 +gH +Lnp:qE +hS);Lnq:qE +B);Loa:w5=cSub;g0 +q4 +Lnk;Lao:o9;oC=q6 +q9 +oR +q4 +Lnp;Lap:hW +oR +q4 +Lnq;Laq:gT +y+x;Lba:qM +Ldn:q5 +gJ +Lbb:q8 +oV +o7 +x +q11 +gX +Lnn;Lbc:mI +A +gX +Lnn;Lbd:gU +dS;Lob:wE(cNotNot);q4 +TailCall_cNotNot;Lbe:gT +fp_and(x +d6 +Lbf:q7=fp_asin +m5 +Lbg:q7=fp_asinh +m5 +Lbh:q7=fp_atan +m5 +Lbi:gT +fp_atan2(gW +Lbj:q7=fp_atanh +m5 +Lbk:q7=fp_cbrt +m5 +Lbl:q1 +cFloor);Loc:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lbm:q7=fp_ceil +m5 +Lbn:g6 +Lod:wE(cCos);q4 +TailCall_cCos;Lbo:q7=fp_cos +m5 +Lbp:dF=cDup;w5=cInv;Loe:wE(cInv);q4 +TailCall_cInv;Lbq:mI +cSinCos);gJ +Lca:g6 +wE(cCosh);q4 +TailCall_cCosh;Lcb:q1 +cSqr +o7 +g1 +1));Lof:qW +q6 +oJ +hS);Log:w5=cSqrt;g0 +wE(cSqrt);q4 +TailCall_cSqrt;Lcc:q7=fp_cosh +m5 +Lcd:mI +cSinhCosh);gJ +Lce:q7=RadiansToDegrees +m5 +Lcf:q1 +cSec +hA +Lcg:q1 +cTan +hA +Lch:q1 +cSin +hA +Lci:oZ));dF +dJ +Loh:qE +dU +oZ +1));Loi:qW +q6);Loj:w5=hS;q4 +Lnl;Lcj:q1 +cNeg +oJ +cExp +hA +Lck:q1 +cNeg +oJ +cExp2 +hA +Lcl:g6 +q4 +Lfa;Lcm:q1 +cNeg +oJ +cPow +hA +Lcn:q1 +cCos +hA +Lco:q1 +cCsc +hA +Lcp:gU +cTan;Lok:wE(cTan);q4 +TailCall_cTan;Lcq:gU +cTanh;Lol:wE(cTanh);q4 +TailCall_cTanh;Lda:q1 +cCot +hA +Ldb:o9;dI +Lom:wE(cDiv);q4 +TailCall_cDiv;Ldc:gT +y/x;q4 +Lba;Ldd:hV +2;qI +q8 +oR +Lon:w5=cDeg;g0 +wE(cDeg);q4 +TailCall_cDeg;Lde:hV +2;qI +q8 +oR +Loo:w5=cRad;g0 +wE(cRad);q4 +TailCall_cRad;Ldf:gT +y/x;dG +Lng;Ldg:q7=g1 +1)/x;q4 +Lfa;Ldh:mI +oI +Lop:g0 +q4 +Lom;Ldi:q8 +3 +gC +oI +qF +x +q11);Loq:w5=cRDiv;g0 +wE(cRDiv);q4 +TailCall_cRDiv;Ldj:hV +3 +gC +oI +qE +B +gX +Loq;Ldk:dI +Lpa:wE(cEqual);q4 +TailCall_cEqual;Ldl:gT +fp_equal(gW +Ldm:d7 +cExp +o7 +fp_exp(x)gX +Lnj;Ldo:q7=fp_exp +m5 +Ldp:d7 +cExp2 +o7 +fp_exp2(x)gX +Lnj;Ldq:q7=fp_exp2 +m5 +Lea:qF +oW +g1 +2))q11);Lpb:qE +h3 +gI +cExp;g0 +wE(cExp);q4 +TailCall_cExp;Leb:q1 +cCeil +gX +Loc;Lec:q7=fp_floor +m5 +Led:gT +fp_less(x +d6 +Lee:qM +q1 +cNeg);Ljm:qE +cAbsNot);gJ +Lef:q7=g1 +0.5)/x;qK=d8 +dS;g0 +q4 +Lob;Leg:gT +fp_lessOrEq(x +d6 +Leh:qM +Ljd:q5 +Lpc:qE +cAbsNotNot);gJ +Lei:q7=fp_int +m5 +Lej:gU +cSec;wE(cSec);q4 +TailCall_cSec;Lek:gU +cSin;Lpd:wE(cSin);q4 +TailCall_cSin;Lel:q1 +cNeg +gI +cPow;Lpe:g0 +Lpf:wE(cPow);q4 +TailCall_cPow;Lem:gU +cCos;q4 +Lod;Len:gU +cCsc;wE(cCsc);q4 +TailCall_cCsc;Leo:q1 +cRSqrt);gJ +Lep:g6 +Lpg:w5=cCot;wE(cCot);q4 +TailCall_cCot;Leq:q7=g1 +1)/x;gJ +Lfb:q7=g1 +0.5)/x;qK=d8 +cNot;g0 +Lph:wE(cNot);q4 +TailCall_cNot;Lfc:gT +fp_less(gW +Lfd:qM +Lje:w3 +Ljm;Lfe:gT +fp_lessOrEq(gW +Lff:qM +q1 +cNeg +gX +Lpc;Lfg:d7 +cLog +o7 +oW +x)o8 +Lfh:q1 +dQ +qE +cLog);Lpi:qW +cDup +gX +Loj;Lfi:q7=oW +x);gJ +Lfj:qF +dR +fp_const_e()));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())gX +Lpj;Lfo:d7 +cLog2 +o7 +o4 +x)o8 +Lfp:q1 +dQ +qE +cLog2 +gX +Lpi;Lfq:q7=o4 +x);gJ +Lga:gT +fp_max(x +d6 +Lgb:gT +fp_min(x +d6 +Lgc:gT +fp_mod(gW +Lgd:hV +oR +q0-=3;q4 +Lpg;Lge:gU +cSqr;Lpk:wE(cSqr);q4 +TailCall_cSqr;Lgf:gU +cDiv;q4 +Lom;Lgg:mI +cSqr +gX +Loc;Lgh:hV +3 +gC +cSqr);dM +Loc;Lgi:q7=x+g1 +1);gG +w5=cPow;q4 +Lpf;Lgj:gG +q4 +Lni;Lgk:gT +x;Lpl:dG +Lnh;Lgl:hV +2;qI +qM +Lpm:hV +4 +gH +Lpn:o6 +x);Lpo:qW +q6 +gX +Lnh;Lgm:qM +q4 +Lpm;Lgn:q8 +4 +gC +B +gX +Lpn;Lgo:q8 +oR +q4 +Lpn;Lgp:qK +dJ +q4 +Ldn;Lgq:dI +q4 +Lni;Lha:qM +Lpp:hV +oR +gJ +Lhb:q7=x+x;q4 +Lgj;Lhc:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Loj;Lhd:gT +x;d7 +dU +qF +y*x +o8 +Lhe:q7=RadiansToDegrees(x +gX +Lgq;Lhf:gT +y*x;q8 +4 +gH +Lpq:qE +dU +Lqa:qE +B +gI +cDiv;q4 +Lop;Lhg:o9;oC=q6 +q9 +oR +q4 +Lpq;Lhh:gT +y*x;q8 +oR +q4 +Lqa;Lhi:q8 +4 +gH +q4 +Lnh;Lhj:q8 +4 +dT +qF +x+x +gX +Lpo;Lhk:hV +2;qI +qM +q4 +Lpp;Lhl:gT +y*x;q4 +Lpl;Lhm:o9;q4 +Lgq;Lhn:gT +y*x;q8 +oR +Lqb:dM +Loq;Lho:o9;qL +2 +gK +q4 +Lqb;Lhp:gT +y*x;dG +Loq;Lhq:q7=h4 +gX +Lgq;Lia:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Loa;Lib:gT +y*x;q4 +Lba;Lic:qM +w3 +Loc;Lid:dF=cDup;dW-=1;qM +Lqc:w5=hS;q4 +Lnm;Lie:qM +w3 +Lon;Lif:qM +w3 +Loo;Lig:hV +oV +gX +Lpq;Lih:hV +2 +gH +Lqd:qE +cSqr +gX +Lnh;Lii:q8 +oV +o7 +x +q11 +gX +Lqb;Lij:mI +A +gX +Lqb;Lik:hV +oR +q4 +Lqd;Lil:dI +Lqe:wE(cNEqual);q4 +TailCall_cNEqual;Lim:gT +fp_nequal(gW +Lin:o9;q4 +Lcl;Lio:o9 +gB +cSin;g0 +q4 +Lpd;Lip:o9 +gB +cSinh;g0 +wE(cSinh);q4 +TailCall_cSinh;Liq:o9 +gB +cTan;g0 +q4 +Lok;Lja:o9 +gB +cTanh;g0 +q4 +Lol;Ljb:o9;gJ +Ljc:g6 +q4 +Lph;Ljf:gU +cNEqual;q4 +Lqe;Ljg:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Ljh:gU +cLess;wE(cLess);q4 +TailCall_cLess;Lji:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Ljj:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Ljk:gU +w8;q4 +Lpa;Ljl:q7=fp_not +m5 +Ljn:gT +fp_or(x +d6 +Ljo:d7 +dQ +qF +x+x);Lqf:qW +q6 +gX +Lpe;Ljp:dL +Lpb;Ljq:qK=d8 +cExp2;g0 +wE(cExp2);q4 +TailCall_cExp2;Lka:gT +y*x;dG +Lpe;Lkb:qK +dJ +q1 +h3 +gX +Lpe;Lkc:dI +q4 +Lpf;Lkd:q8 +3 +dT +qF +x +gX +Lqf;Lke:q7=g1 +gX +Loh;Lkf:qM +w3 +Log;Lkg:qM +q5 +w5=cCbrt;g0 +wE(cCbrt);q4 +TailCall_cCbrt;Lkh:qM +q1 +cCbrt);Lqg:w5=cInv;g0 +q4 +Loe;Lki:qM +q4 +Leo;Lkj:qM +w3 +Lqg;Lkk:hV +2;qI +q8 +3 +gC +dQ +qF +y*x +gX +Lqf;Lkl:q7=x+x;q4 +Lkc;Lkm:gT +oX +gW +Lkn:q1 +cTanh +gX +Lqg;Lko:oZ)gX +Lpj;Lkp:q7=h4 +gX +Lcl;Lkq:q7=h4);gJ +Lla:mI +cSinCos +gX +Lqg;Llb:q1 +cSin +gX +Loc;Llc:q7=fp_sin +m5 +Lld:q1 +cSqr +o7 +g1-1)gX +Lof;Lle:q1 +cSinh +gX +Loc;Llf:q7=fp_sinh +m5 +Llg:g6 +q4 +Lpk;Llh:hV +4 +gC +A);Lqh:w5=cHypot;g0 +wE(cHypot);q4 +TailCall_cHypot;Lli:hV +5 +gC +A +oJ +B +gX +Lqh;Llj:gU +cAbs;q4 +Lnf;Llk:q7=fp_sqrt +m5 +Lll:g6 +q4 +Lqc;Llm:gT +y-x;q4 +Lba;Lln:o9;q4 +Lqc;Llo:q8 +oV +oJ +hS +o7 +x +q11 +gX +Lno;Llp:mI +A +oJ +cSub +gX +Lno;Llq:q1 +cTan +gX +Loc;Lma:q7=fp_tan +m5 +Lmb:q1 +cTanh +gX +Loc;Lmc:q7=fp_tanh +m5 +Lmd:q7=fp_trunc +m5 +Lme:gT +x-y;Lqi:q8 +2 +gH +Lqj:qE +A);gJ +Lmf:q7=fp_tan(x);Lqk:dL +Lqj;Lmg:q7=oW +x +gX +Lqk;Lmh:q7=o4 +x +gX +Lqk;Lmi:q7=fp_exp(x +gX +Lqk;Lmj:q7=oX +g1 +10),x +gX +Lqk;Lmk:q7=fp_exp2(x +gX +Lqk;Lml:gT +x/y;q4 +Lqi;Lmm:gT +x/y;q8 +2 +gH +Lql:qE +OppositeComparisonOpcode(A));gJ +Lmn:o9;dL +Lql;Lmo:gT +oX +x,g1 +1)/y +gX +Lqi;Lmp:q7=fp_asinh(x +gX +Lqk;Lmq:d7 +dQ +qF +fp_sqrt(x)q11 +gX +Lqj;Lna:q7=fp_atanh(x +gX +Lqk;Lnb:qW +cDup);gJ +Lnc:dF=cDup;gJ +Lnd:hV +3 +gC +cSinCos);Lqm:qE +GetParamSwappedBinaryOpcode(C));gJ +Lne:hV +3 +gC +cSinhCosh +gX +Lqm;gJ +q4 +TailCall_cAcos;q4 +TailCall_cAcosh;q4 +TailCall_cAnd;q4 +TailCall_cAsin;q4 +TailCall_cAsinh;q4 +TailCall_cAtan;q4 +TailCall_cAtan2;q4 +TailCall_cAtanh;q4 +TailCall_cCeil;q4 +TailCall_cFloor;q4 +TailCall_cInt;q4 +TailCall_cLog;q4 +TailCall_cLog10;q4 +TailCall_cLog2;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cRad;q4 +TailCall_cSec;q4 +TailCall_cSin;q4 +TailCall_cSinh;q4 +TailCall_cSqrt;q4 +TailCall_cSub;q4 +TailCall_cTan;q4 +TailCall_cTanh;q4 +TailCall_cTrunc; +#endif +#if((FP_COMPLEX_VERSION) && (FP_FLOAT_VERSION)) +dH +x;dH +gE +A;hT +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0} +qH +TailCall_cAcos:g5 +cAcos:qY +wB(172,"x cAcos" +,"[fp_acos(x)]" +,wN);q4 +Lad;} +qH +TailCall_cAcosh:g5 +cAcosh:qY +wB(169,"x cAcosh" +,"[fp_acosh(x)]" +,wN);q4 +Lae;} +qH +TailCall_cAdd:g5 +hG +Laf;qT +h3 +hL]==hS){if(qL +gZ +Lag;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +wY +aV,"[x+Value_t(1)]" +wH,wN);q4 +Lah;} +} +q4 +dX +oF +wB(199,q81 +aV,"cSub" +,);q4 +Lai +gY +hK +qZ +mR(127,aU"cAdd " +a6,"[y+x]" +aV,q31);q4 +Laj;qT +cRSub:qQ +hE +d3 +3 +qZ +mR(298,aU"cAdd " +mS,mJ +aV" " +a4,q31);q4 +Lak;qT +hI +wB(299,mG +mS,"[-x]" +aV" " +a4,wN);q4 +Lal +qU +q6:mR(297,aU +mS,mJ" " +a4,q31);q4 +Lam;qT +oA +Lan;qT +hI +wB(293,mG"B[IsVarOpcode(B)]" +mF" " +a6,"[-x]" +aV" B" +mF,wA"," +aQ(B)wM);q4 +Lao +qU +q6:mR(291,aU"B[IsVarOpcode(B)]" +mF" " +a6,mJ" B" +mF,wA"," +aQ(B)<<"," +aE);q4 +Lap;} +w9 +mR(105,aU +a6,"[y+x]" +,q31);q4 +Laq;} +g8)){wB(57,"x[x==Value_t()]" +aV,,wN);q4 +Lba;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x " +a4 +aC"cAdd" +,"[DO_STACKPLUS1] A [x]" +aV" " +a4,aA(A)<<"," +m4);incStackPtr();--mStackPtr;q4 +Lbb;} +wB(295,a4 +aC"cAdd" +,"[DO_STACKPLUS1] A" +aV" " +a4,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lbc;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mC"cAnd" +,aF,);q4 +w7 +m2(117,m3"cAnd" +,"[fp_and(x,y)]" +,q31);q4 +Lbe;h8} +qH +TailCall_cArg:g5 +cArg:qY +wB(190,"x cArg" +,"[fp_arg(x)]" +,wN);q4 +Lbf;} +qH +TailCall_cAsin:g5 +cAsin:qY +wB(173,"x cAsin" +,"[fp_asin(x)]" +,wN);q4 +Lbg;} +qH +TailCall_cAsinh:g5 +cAsinh:qY +wB(170,"x cAsinh" +,"[fp_asinh(x)]" +,wN);q4 +Lbh;} +qH +TailCall_cAtan:g5 +cAtan:qY +if(g1 +x.real(),fp_abs(x.imag()))!=g1 +0,oG +wB(174,"x[Value_t(x.real(),fp_abs(x.imag()))!=Value_t(0,1)] cAtan" +,"[fp_atan(x)]" +,wN);q4 +Lbi;qG +TailCall_cAtan2:g5 +cAtan2:qY +m2(139,m3"cAtan2" +,"[fp_atan2(y,x)]" +,q31);q4 +Lbj;qG +TailCall_cAtanh:g5 +cAtanh:qY +if(g1 +fp_abs(x.real()),x.imag())!=g1 +1,0)){wB(171,"x[Value_t(fp_abs(x.real()),x.imag())!=Value_t(1,0)] cAtanh" +,"[fp_atanh(x)]" +,wN);q4 +Lbk;qG +TailCall_cCbrt:g5 +cCbrt:qY +wB(175,"x cCbrt" +,"[fp_cbrt(x)]" +,wN);q4 +Lbl;} +qH +TailCall_cCeil:g5 +cCeil:qS +hI +wB(402,mG +mW,mO +mD,);q4 +Lbm +gY +wB(135,"x " +mW,"[fp_ceil(x)]" +,wN);q4 +Lbn +gS +wB(396,"A[IsAlwaysIntegerOpcode(A)] " +mW,"A" +,aA(A)wM);gJ +qG +TailCall_cConj:g5 +cConj:qS +cConj:wB(63,mT" " +mT,,);oS +gY +wB(193,"x " +mT,"[fp_conj(x)]" +,wN);q4 +Lbp;} +qH +TailCall_cCos:g5 +cCos:qS +cAcos:wB(346,"cAcos " +aK,,);q4 +oE +wB(238,mG +aK,aK,);q4 +Lbq +gY +wB(176,"x " +aK,"[fp_cos(x)]" +,wN);q4 +Lca;oH +qN +qQ +h9 +cSec:hD +wB(500,aG" " +mX" " +wI +aK,"B " +mX" " +aR,aA(A)q51(B)wM);q4 +Lcb;qT +cSin:hD +wB(494,aG" " +mM" " +wI +aK,"B cSinCos" +,aA(A)q51(B)wM);q4 +Lcc;h8} +qG +TailCall_cCosh:g5 +cCosh:qS +cAsinh:wB(450,"cAsinh " +aI,"[DO_STACKPLUS1] " +mZ"[Value_t(1)] " +aL,);incStackPtr();--mStackPtr;q4 +Lcd +oF +wB(239,mG +aI,aI,);q4 +Lce +gY +wB(177,"x " +aI,"[fp_cosh(x)]" +,wN);q4 +Lcf;oH +qN +oY +cSinh +mY(507,aG" cSinh " +wI +aI,"B cSinhCosh" +,aA(A)q51(B)wM);q4 +Lcg;} +} +qG +TailCall_cCot:g5 +cCot:A=qN +oY +cTan +mY(498,aG" " +mN" " +wI"cCot" +,"B " +mN" " +aR,aA(A)q51(B)wM);q4 +Lcb;} +qG +TailCall_cCsc:g5 +cCsc:A=qN +oY +cSin +mY(496,aG" " +mM" " +wI"cCsc" +,"B " +mM" " +aR,aA(A)q51(B)wM);q4 +Lcb;} +qG +TailCall_cDeg:g5 +cDeg:qY +wB(133,"x cDeg" +,"[RadiansToDegrees(x)]" +,wN);q4 +Lch;} +qH +TailCall_cDiv:g5 +cDiv:qS +cCos:wB(250,aK +m7,mX +wH,);q4 +Lci +qU +cCot:wB(254,"cCot" +m7,mN +wH,);q4 +Lcj +qU +cCsc:wB(252,"cCsc" +m7,mM +wH,);q4 +Lck +qU +cDup:wB(78,"cDup" +m7,"[Value_t()]" +m6"[Value_t(1)]" +aV,);q4 +Lcl +qU +w2 +wB(408,mH +m7,mG +mH +wH,);q4 +Lcm +qU +cExp2:wB(409,"cExp2" +m7,mG"cExp2" +wH,);q4 +Lcn +qU +cInv:wB(213,aS +m7,"cMul" +,);q4 +Lco +qU +cPow:wB(407,"cPow" +m7,q81 +a1 +wH,);q4 +Lcp +qU +cSec:wB(253,mX +m7,aK +wH,);q4 +Lcq +qU +cSin:wB(249,mM +m7,"cCsc" +wH,);q4 +Lda +qU +cSinCos:wB(502,"cSinCos" +m7,mN,);q4 +Ldb +qU +cSinhCosh:wB(509,"cSinhCosh" +m7,"cTanh" +,);q4 +Ldc +qU +cTan:wB(251,mN +m7,"cCot" +wH,);q4 +Ldd +gY +if +hF +gQ +hI +wB(125,mG +wZ"cDiv" +,"[-x]" +m7,wN);q4 +Lde +qU +q6:mR(103,aU +wZ"cDiv" +,"[y/x]" +,q31);q4 +Ldf;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lba;} +dB +h3 +gA +qZ +hP(y/x)==fp_const_rad_to_deg +h7 +wB(321,"y[(y/x)==fp_const_rad_to_deg()]" +m6 +wR,"cDeg" +,q31);q4 +Ldg;} +if((y/x)==fp_const_deg_to_rad +h7 +wB(322,"y[(y/x)==fp_const_deg_to_rad()]" +m6 +wR,"cRad" +,q31);q4 +Ldh;} +wB(323,"y" +m6 +wR,"[y/x]" +wH,q31);q4 +Ldi;} +} +wB(325,wR,"[Value_t(1)/x]" +wH,wN);q4 +Ldj;} +gP +cDiv:hC +wB(271,q21" " +wV,"[DO_STACKPLUS1] B A" +m6"cDiv" +,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4 +Ldk;qT +cRDiv:qQ +hE +qV +hM +wB(266,"x" +a7" " +wV,"A" +m6"[x]" +a7,aA(A)<<"," +m4);q4 +Ldl;g7 +hC +wB(265,"B[IsVarOpcode(B)]" +a7" " +wV,"A" +m6"B" +a7,aA(A)q51(B)wM);q4 +Ldm;} +h8} +qG +TailCall_cEqual:g5 +w8:oL +hU +wB(359,aX +wL +a5,"[x] " +a5,wN);q4 +Ldn +qU +cSqr:wB(361,mZ +wL +a5,"[x] " +a5,wN);q4 +Ldn;} +} +m2(115,m3 +a5,"[fp_equal(y,x)]" +,q31);q4 +Ldo;qG +TailCall_cExp:g5 +w2 +qS +hS +gM +wB(404,a6" " +mH,mH" [fp_exp(x)]" +wH,wN);q4 +Ldp;qT +cLog:A=dE +wB(340,wJ +mA" " +mH,"A" +,aA(A)wM);oS;qT +hM +wB(178,"x " +mH,"[fp_exp(x)]" +,wN);q4 +Ldq;} +qH +TailCall_cExp2:g5 +cExp2:qS +hS +gM +wB(405,a6" cExp2" +,"cExp2 [fp_exp2(x)]" +wH,wN);q4 +Lea;qT +cLog2:A=dE +wB(341,wJ +aJ" cExp2" +,"A" +,aA(A)wM);oS;qT +hM +wB(179,"x cExp2" +,"[fp_exp2(x)]" +,wN);q4 +Leb;} +wB(479,"cExp2" +,"[DO_STACKPLUS1] [fp_log(Value_t(2))]" +m6 +mH,);incStackPtr();--mStackPtr;q4 +Lec;TailCall_cFloor:g5 +cFloor:qS +hI +wB(401,mG +mO,mW +mD,);q4 +Led +gY +wB(136,"x " +mO,"[fp_floor(x)]" +,wN);q4 +Lee +gS +wB(395,"A[IsAlwaysIntegerOpcode(A)] " +mO,"A" +,aA(A)wM);gJ +qG +TailCall_cGreater:g5 +o1:qY +m2(113,m3 +aW,"[fp_less(x,y)]" +,q31);q4 +Lef;qG +TailCall_cGreaterOrEq:g5 +dK:qY +m2(114,m3 +a8,"[fp_lessOrEq(x,y)]" +,q31);q4 +Leg;qG +TailCall_cHypot:g5 +cHypot +d4 +dF==cSinCos){wB(84,"cSinCos cHypot" +,"[Value_t()]" +m6"[Value_t(1)]" +aV,);q4 +Lcl;} +qH +TailCall_cImag:g5 +cImag:qS +cAbs:wB(81,aX +mU,"[Value_t()]" +wH,);q4 +Leh +qU +cReal:wB(80,"cReal " +mU,"[Value_t()]" +wH,);q4 +Leh +gY +wB(192,"x " +mU,"[fp_imag(x)]" +,wN);q4 +Lei;} +qH +TailCall_cInt:g5 +cInt:qS +hM +wB(137,"x cInt" +,"[fp_int(x)]" +,wN);q4 +Lej +gS +wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt" +,"A" +,aA(A)wM);gJ +qG +TailCall_cInv:g5 +cInv:qS +cCos:wB(256,aK +mK,mX,);q4 +Lek +qU +cCot:wB(260,"cCot" +mK,mN,);q4 +Ldb +qU +cCsc:wB(258,"cCsc" +mK,mM,);q4 +Lel +qU +cInv:wB(62,aS +mK,,);oS +qU +cPow:wB(355,"cPow" +mK,q81 +a1,);q4 +Lem +qU +cSec:wB(259,mX +mK,aK,);q4 +Len +qU +cSin:wB(255,mM +mK,"cCsc" +,);q4 +Leo +qU +cSqrt:wB(206,q01 +mK,"cRSqrt" +,);q4 +Lep +qU +cTan:wB(257,mN +mK,"cCot" +,);q4 +Leq +gY +if +hF)){wB(101,wZ +aS,"[Value_t(1)/x]" +,wN);q4 +Lfa;h8} +qH +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mB,mV,q61(A)wM);q4 +Lfb;} +} +m2(111,m3 +mB,"[fp_less(y,x)]" +,q31);q4 +Lfc;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m2(112,m3 +aM,"[fp_lessOrEq(y,x)]" +,q31);q4 +Lfd;qG +TailCall_cLog:g5 +cLog:mP(343,mH" " +mA,,);oS +qU +gL +wB(491,wQ +m6 +mA,mA" [fp_log(x)]" +aV,wN);q4 +Lfe;} +oD +wB(180,"x[x!=Value_t(0)] " +mA,"[fp_log(x)]" +,wN);q4 +Lff;h8} +qH +TailCall_cLog10:g5 +cLog10:mP(481,mH" " +aH,"[DO_STACKPLUS1] [fp_log10(fp_const_e())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfg +qU +gL +wB(492,wQ +m6 +aH,aH" [fp_log10(x)]" +aV,wN);q4 +Lfh;} +oD +wB(181,"x[x!=Value_t(0)] " +aH,"[fp_log10(x)]" +,wN);q4 +Lfi;h8} +qH +TailCall_cLog2:g5 +cLog2:mP(480,mH" " +aJ,"[DO_STACKPLUS1] [fp_log2(fp_const_e())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfj +qU +cExp2:wB(344,"cExp2 " +aJ,,);oS +qU +gL +wB(490,wQ +m6 +aJ,aJ" [fp_log2(x)]" +aV,wN);q4 +Lfk;} +oD +wB(182,"x[x!=Value_t(0)] " +aJ,"[fp_log2(x)]" +,wN);q4 +Lfl;h8} +qH +TailCall_cMax:g5 +cMax +hH +wB(60,mC +m8,,);oS +gY +m2(141,m3 +m8,"[fp_max(x,y)]" +,q31);q4 +Lfm;} +gP +cDup:hD +wB(66,aG +mE +aC +m8,"B" +mE,aA(A)q51(B)wM);oS;qT +cMax:hD +wB(68,aG" " +m8 +aC +m8,"B " +m8,aA(A)q51(B)wM);oS;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mC +m9,,);oS +gY +m2(140,m3 +m9,"[fp_min(x,y)]" +,q31);q4 +Lfn;} +gP +cDup:hD +wB(65,aG +mE +aC +m9,"B" +mE,aA(A)q51(B)wM);oS;qT +cMin:hD +wB(67,aG" " +m9 +aC +m9,"B " +m9,aA(A)q51(B)wM);oS;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m2(104,aU +wZ"cMod" +,"[fp_mod(y,x)]" +,q31);q4 +Lfo;} +qG +TailCall_cMul:g5 +h3:qS +cCsc:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(508,aG" " +aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc" +wH,"B cCot" +,aA(A)q51(B)wM);q4 +Lfp;} +} +} +q4 +dY +qU +cDup:wB(202,"cDup" +wH,"cSqr" +,);q4 +Lfq +qU +cInv:wB(214,aS +wH,"cDiv" +,);q4 +Lga +oF +qQ +h9 +cDup:wB(467,mC +q81 +wH,"cSqr" +mD,);q4 +Lgb;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aG +wH +aC +q81 +wH,m0 +m6 +q81,aA(A)q51(B)wM);q4 +Lgc;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mC"x" +a1 +wH,"[x+Value_t(1)]" +a1,wN);q4 +Lgd;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wT" " +wX,a3,q61(A)wM);q4 +Lge;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mR(92,aU +wD,a3,q61(A)<<"," +aE);q4 +Lgf;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mR(96,aU +wK,mV,q61(A)q51(B)<<"," +aE);q4 +Lgg;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lgh;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mV,q61(A)q51(B)<<", C" +a0(C)wM);q4 +Lgi;} +} +} +if(d1 +B)){wB(90,"B[IsVarOpcode(B)] " +wD,a3,q61(A)q51(B)wM);q4 +Lge;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mV,q61(A)q51(B)wM);q4 +Lgj;} +} +} +if(d1 +h2 +wB(88,aD" " +wX,"[x]" +,q61(A)wM);q4 +Lgk;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wX,a3,q61(A)wM);q4 +Lgl;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup +d4 +x+oU +wB(316,"cDup[x+x==Value_t(1)]" +aV +wY,,wN);q4 +Lgm;} +wB(317,a9 +wY,"[x+x]" +wH,wN);q4 +Lgn +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,aD" y" +wH +aV +wY,a3" A " +aZ +wH +aV,wA", " +aU"= " +<()]" +wH +wY,"cDeg" +,q31);q4 +Ldg;} +if((y*x)==fp_const_deg_to_rad +h7 +wB(308,"y[(y*x)==fp_const_deg_to_rad()]" +wH +wY,"cRad" +,q31);q4 +Ldh;} +wB(128,"y" +wH +wY,aZ +wH,q31);q4 +Lhg;qT +hI +wB(122,q81 +wY,"[-x]" +wH,wN);q4 +Lhh +qU +cRDiv:qQ +hE +qV +o5 +3 +qZ +mR(285,"y" +wH +a7 +wY,aZ +wH +a7,q31);q4 +Lhi;qT +hI +wB(286,q81 +a7 +wY,"[-x]" +wH +a7,wN);q4 +Lhj +qU +q6:mR(284,"y" +a7 +wY,aZ +a7,q31);q4 +Lhk;qT +cRad:wB(210,"cRad" +wY,"[DegreesToRadians(x)]" +wH,wN);q4 +Lhl +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,aD" y" +m6"cSub" +wY,a3" A " +aZ +m6"cSub" +,wA", " +aU"= " +<()]" +wH,"cDeg" +,wN);q4 +Lhq;} +if(x==fp_const_deg_to_rad +h7 +wB(208,"x[x==fp_const_deg_to_rad()]" +wH,"cRad" +,wN);q4 +Lia;h8 +g7 +dY:;A=dF +qO +A +gQ +cDiv:hC +wB(274,q21" " +wT,"[DO_STACKPLUS1] A" +m6"B" +m7,aA(A)q51(B)wM);incStackPtr();--mStackPtr;q4 +Lib;} +q4 +d5 +h3:qQ +hE +qV +hI +B=hQ +wB(470,aG +mD +m6 +wT,m0 +m6 +q81,aA(A)q51(B)wM);q4 +Lgc;} +q4 +dZ;g7 +dZ:;hD +wB(461,aG +m6 +wT,m0 +wH,aA(A)q51(B)wM);q4 +Lic;} +} +q4 +d5 +hI +hD +wB(464,aG +mD" " +wT,m0 +mD,aA(A)q51(B)wM);q4 +Lgb;} +q4 +d5 +cRDiv +hL +qZ +qC +wB(267,"x" +a7" " +wT,"[DO_STACKPLUS1] " +mV +a7,aA(A)<<"," +m4);incStackPtr();--mStackPtr;q4 +Lid;} +wB(281,"cRDiv " +wT,"[DO_STACKPLUS1] A" +wH +a7,aA(A)wM);incStackPtr();--mStackPtr;q4 +Lie;g7 +Default4:;B=qK +qR +w4 +wB(458,aG" " +wT,m0,aA(A)q51(B)wM);q4 +Lfq;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +m6"B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Lif;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:oL +hU +wB(360,aX +wL +wW,"[x] " +wW,wN);q4 +Lig +qU +cSqr:wB(362,mZ +wL +wW,"[x] " +wW,wN);q4 +Lig;} +} +m2(116,m3 +wW,"[fp_nequal(y,x)]" +,q31);q4 +Lih;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +m6 +q81,"[-x]" +wH,wN);q4 +Lii;qT +hI +wB(61,q81 +mD,,);oS +qU +cSin:g9 +wB(244,"x" +m6 +mM +mD,"[-x]" +m6 +mM,wN);q4 +Lij;} +qT +oQ +g9 +wB(245,"x" +m6"cSinh" +mD,"[-x]" +m6"cSinh" +,wN);q4 +Lik;} +qT +cTan:g9 +wB(246,"x" +m6 +mN +mD,"[-x]" +m6 +mN,wN);q4 +Lil;} +qT +cTanh:g9 +wB(247,"x" +m6"cTanh" +mD,"[-x]" +m6"cTanh" +,wN);q4 +Lim;} +qT +hM +wB(100,"x" +mD,"[-x]" +,wN);q4 +Lin;} +qH +TailCall_cNot:g5 +cNot:qS +cAbsNotNot:wB(231,"cAbsNotNot" +aB,aN,);q4 +Lio +qU +w8:wB(220,a5 +aB,wW,);q4 +Lip +qU +o1:wB(218,aW +aB,aM,);q4 +Liq +qU +dK:wB(219,a8 +aB,mB,);q4 +Lja +qU +cLess:wB(216,mB +aB,a8,);q4 +Ljb +qU +cLessOrEq:wB(217,aM +aB,aW,);q4 +Ljc +qU +cNEqual:wB(221,wW +aB,a5,);q4 +Ljd +qU +cNot:wB(229,"cNot" +aB,aF,);q4 +Lbd +qU +dS:wB(230,aF +aB,"cNot" +,);q4 +Lje +gY +wB(107,"x" +aB,"[fp_not(x)]" +,wN);q4 +Ljf;} +qH +TailCall_cNotNot:g5 +dS +d4 +dF==cNot){wB(232,"cNot " +aF,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mC"cOr" +,aF,);q4 +w7 +m2(118,m3"cOr" +,"[fp_or(x,y)]" +,q31);q4 +Ljg;h8} +qH +TailCall_cPolar:g5 +cPolar +d4 +q0[0 +qZ +y=q7;qJ +x +gO +wB(194,"x " +aU"cPolar" +,"[fp_polar(x,y)]" +," with " +aU"= " +<mByteCode.size()>0]" +,"B" +mE,aA(A)q51(B)wM);q4 +Lll;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mE,aA(A)q51(B)<<", C" +a0(C)<<", D" +a0(D)wM);q4 +Llm;} +} +} +} +C=w5 +qR +IsCommutativeOrParamSwappableBinaryOpcode(C)){qS +cSin:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(505,aG" " +aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] " +mM" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinCos {GetParamSwappedBinaryOpcode(C)}" +," with C" +a0(C)q71(A)q51(B)wM);q4 +Lln;} +} +qT +oQ +A=qK +w1 +3 +gA]==cCosh){B=hQ +wB(506,aG" " +aI" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}" +," with C" +a0(C)q71(A)q51(B)wM);q4 +Llo;} +} +h8} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +Llp:wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:q7=fp_acos +m5 +Lae:q7=fp_acosh +m5 +Laf:oZ +4));gG +Llq:w5=h3;Lma:g0 +Lmb:wE(cMul);q4 +TailCall_cMul;Lag:hV +4 +dT +oZ +4));Lmc:qW +q6 +hY;Lah:q7=x+g1 +1);gG +Lfb:w5=h3;q4 +Lmb;Lai:gU +cSub;Lmd:wE(cSub);q4 +TailCall_cSub;Laj:hW +2 +gH +Lme:g0 +Lmf:wE(cAdd);q4 +TailCall_cAdd;Lak:hW +oR +Lmg:qE +hS);Lmh:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Lal:o9;qL +2 +gK +q4 +Lmg;Lam:hW +2 +gH +q4 +Lmh;Lan:hW +4 +gH +Lmi:qE +hS);Lmj:qE +B);Lmk:w5=cSub;g0 +q4 +Lmd;Lao:o9;oC=q6 +q9 +oR +q4 +Lmi;Lap:hW +oR +q4 +Lmj;Laq:gT +y+x;Lba:qM +Lbo:q5 +gJ +Lbb:q8 +oV +o7 +x +q11 +gX +Lmg;Lbc:mI +A +gX +Lmg;Lbd:gU +dS;wE(cNotNot);q4 +TailCall_cNotNot;Lbe:gT +fp_and(x +d6 +Lbf:q7=fp_arg +m5 +Lbg:q7=fp_asin +m5 +Lbh:q7=fp_asinh +m5 +Lbi:q7=fp_atan +m5 +Lbj:gT +fp_atan2(gW +Lbk:q7=fp_atanh +m5 +Lbl:q7=fp_cbrt +m5 +Lbm:q1 +cFloor);Lml:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lbn:q7=fp_ceil +m5 +Lbp:q7=fp_conj +m5 +Lbq:g6 +Lmm:wE(cCos);q4 +TailCall_cCos;Lca:q7=fp_cos +m5 +Lcb:dF=cDup;w5=cInv;Lmn:wE(cInv);q4 +TailCall_cInv;Lcc:mI +cSinCos);gJ +Lcd:q1 +cSqr +o7 +g1 +1));Lmo:qW +q6 +oJ +hS);Lmp:w5=cSqrt;g0 +wE(cSqrt);q4 +TailCall_cSqrt;Lce:g6 +wE(cCosh);q4 +TailCall_cCosh;Lcf:q7=fp_cosh +m5 +Lcg:mI +cSinhCosh);gJ +Lch:q7=RadiansToDegrees +m5 +Lci:q1 +cSec +hY;Lcj:q1 +cTan +hY;Lck:q1 +cSin +hY;Lcl:oZ));dF +dJ +Lmq:qE +dU +oZ +1));Lna:qW +q6);Lnb:w5=hS;q4 +Lme;Lcm:q1 +cNeg +oJ +cExp +hY;Lcn:q1 +cNeg +oJ +cExp2 +hY;Lco:g6 +q4 +Lfb;Lcp:q1 +cNeg +oJ +cPow +hY;Lcq:q1 +cCos +hY;Lda:q1 +cCsc +hY;Ldb:gU +cTan;Lnc:wE(cTan);q4 +TailCall_cTan;Ldc:gU +cTanh;Lnd:wE(cTanh);q4 +TailCall_cTanh;Ldd:q1 +cCot +hY;Lde:o9;dI +Lne:wE(cDiv);q4 +TailCall_cDiv;Ldf:gT +y/x;q4 +Lba;Ldg:hV +2;qI +q8 +oR +Lnf:w5=cDeg;g0 +wE(cDeg);q4 +TailCall_cDeg;Ldh:hV +2;qI +q8 +oR +Lng:w5=cRad;g0 +wE(cRad);q4 +TailCall_cRad;Ldi:gT +y/x;dG +Llq;Ldj:q7=g1 +1)/x;q4 +Lfb;Ldk:mI +oI +Lnh:g0 +q4 +Lne;Ldl:q8 +3 +gC +oI +qF +x +q11);Lni:w5=cRDiv;g0 +wE(cRDiv);q4 +TailCall_cRDiv;Ldm:hV +3 +gC +oI +qE +B +gX +Lni;Ldn:dI +Lnj:wE(cEqual);q4 +TailCall_cEqual;Ldo:gT +fp_equal(gW +Ldp:d7 +cExp +o7 +fp_exp(x)gX +Lmc;Ldq:q7=fp_exp +m5 +Lea:d7 +cExp2 +o7 +fp_exp2(x)gX +Lmc;Leb:q7=fp_exp2 +m5 +Lec:qF +oW +g1 +2))q11);Lnk:qE +h3 +gI +cExp;g0 +wE(cExp);q4 +TailCall_cExp;Led:q1 +cCeil +oT +Lee:q7=fp_floor +m5 +Lef:gT +fp_less(x +d6 +Leg:gT +fp_lessOrEq(x +d6 +Leh:oZ));Lnl:dF +dJ +q4 +Llq;Lei:q7=fp_imag +m5 +Lej:q7=fp_int +m5 +Lek:gU +cSec;wE(cSec);q4 +TailCall_cSec;Lel:gU +cSin;Lnm:wE(cSin);q4 +TailCall_cSin;Lem:q1 +cNeg +gI +cPow;Lnn:g0 +Lno:wE(cPow);q4 +TailCall_cPow;Len:gU +cCos;q4 +Lmm;Leo:gU +cCsc;wE(cCsc);q4 +TailCall_cCsc;Lep:q1 +cRSqrt);gJ +Leq:g6 +Lnp:w5=cCot;wE(cCot);q4 +TailCall_cCot;Lfa:q7=g1 +1)/x;gJ +Lfc:gT +fp_less(gW +Lfd:gT +fp_lessOrEq(gW +Lfe:d7 +cLog +o7 +oW +x)gX +Lna;Lff:q7=oW +x);gJ +Lfg:qF +dR +fp_const_e())gX +Lnl;Lfh:d7 +cLog10 +o7 +dR +x)gX +Lna;Lfi:q7=dR +x);gJ +Lfj:qF +o4 +fp_const_e())gX +Lnl;Lfk:d7 +cLog2 +o7 +o4 +x)gX +Lna;Lfl:q7=o4 +x);gJ +Lfm:gT +fp_max(x +d6 +Lfn:gT +fp_min(x +d6 +Lfo:gT +fp_mod(gW +Lfp:hV +oR +q0-=3;q4 +Lnp;Lfq:gU +cSqr;Lnq:wE(cSqr);q4 +TailCall_cSqr;Lga:gU +cDiv;q4 +Lne;Lgb:mI +cSqr +oT +Lgc:hV +3 +gC +cSqr);dM +Lml;Lgd:q7=x+g1 +1);gG +w5=cPow;q4 +Lno;Lge:gG +q4 +Lmb;Lgf:gT +x;Loa:dG +Lma;Lgg:hV +2;qI +qM +Lob:hV +4 +gH +Loc:o6 +x);Lod:qW +q6 +gX +Lma;Lgh:qM +q4 +Lob;Lgi:q8 +4 +gC +B +gX +Loc;Lgj:q8 +oR +q4 +Loc;Lgk:qK +dJ +oS;Lgl:dI +q4 +Lmb;Lgm:qM +Loe:hV +oR +gJ +Lgn:q7=x+x;q4 +Lge;Lgo:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Lnb;Lgp:gT +x;d7 +dU +qF +y*x +gX +Lna;Lgq:q7=RadiansToDegrees(x +gX +Lgl;Lha:gT +y*x;q8 +4 +gH +Lof:qE +dU +Log:qE +B +gI +cDiv;q4 +Lnh;Lhb:o9;oC=q6 +q9 +oR +q4 +Lof;Lhc:gT +y*x;q8 +oR +q4 +Log;Lhd:q8 +4 +gH +q4 +Lma;Lhe:q8 +4 +dT +qF +x+x +gX +Lod;Lhf:hV +2;qI +qM +q4 +Loe;Lhg:gT +y*x;q4 +Loa;Lhh:o9;q4 +Lgl;Lhi:gT +y*x;q8 +oR +Loh:dM +Lni;Lhj:o9;qL +2 +gK +q4 +Loh;Lhk:gT +y*x;dG +Lni;Lhl:q7=h4 +gX +Lgl;Lhm:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q11);dM +Lmk;Lhn:gT +y*x;q4 +Lba;Lho:qM +w3 +Lml;Lhp:dF=cDup;dW-=1;qM +Loi:w5=hS;q4 +Lmf;Lhq:qM +w3 +Lnf;Lia:qM +w3 +Lng;Lib:hV +oV +gX +Lof;Lic:hV +2 +gH +Loj:qE +cSqr +gX +Lma;Lid:q8 +oV +o7 +x +q11 +gX +Loh;Lie:mI +A +gX +Loh;Lif:hV +oR +q4 +Loj;Lig:dI +Lok:wE(cNEqual);q4 +TailCall_cNEqual;Lih:gT +fp_nequal(gW +Lii:o9;q4 +Lco;Lij:o9 +gB +cSin;g0 +q4 +Lnm;Lik:o9 +gB +cSinh;g0 +wE(cSinh);q4 +TailCall_cSinh;Lil:o9 +gB +cTan;g0 +q4 +Lnc;Lim:o9 +gB +cTanh;g0 +q4 +Lnd;Lin:o9;gJ +Lio:q1 +cAbsNot);gJ +Lip:gU +cNEqual;q4 +Lok;Liq:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Lja:gU +cLess;wE(cLess);q4 +TailCall_cLess;Ljb:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Ljc:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Ljd:gU +w8;q4 +Lnj;Lje:g6 +wE(cNot);q4 +TailCall_cNot;Ljf:q7=fp_not +m5 +Ljg:gT +fp_or(x +d6 +Ljh:gT +fp_polar(x +d6 +Lji:dL +Lnk;Ljj:qK=d8 +cExp2;g0 +wE(cExp2);q4 +TailCall_cExp2;Ljk:gT +y*x;dG +Lnn;Ljl:qK +dJ +q1 +h3 +gX +Lnn;Ljm:q7=g1 +gX +Lmq;Ljn:qM +w3 +Lmp;Ljo:qM +q5 +w5=cCbrt;g0 +wE(cCbrt);q4 +TailCall_cCbrt;Ljp:qM +q1 +cCbrt);Lol:w5=cInv;g0 +q4 +Lmn;Ljq:qM +q4 +Lep;Lka:qM +w3 +Lol;Lkb:q7=x+x;dI +q4 +Lno;Lkc:gT +oX +gW +Lkd:q1 +cTanh +gX +Lol;Lke:q7=h4 +gX +Lco;Lkf:q7=h4);gJ +Lkg:q7=fp_real +m5 +Lkh:mI +cSinCos +gX +Lol;Lki:q1 +cSin +oT +Lkj:q7=fp_sin +m5 +Lkk:q1 +cSqr +o7 +g1-1)gX +Lmo;Lkl:q1 +cSinh +oT +Lkm:q7=fp_sinh +m5 +Lkn:g6 +q4 +Lnq;Lko:hV +4 +gC +A);Lom:w5=cHypot;g0 +wE(cHypot);q4 +TailCall_cHypot;Lkp:hV +5 +gC +A +oJ +B +gX +Lom;Lkq:gU +cAbs;q4 +Llp;Lla:q7=fp_sqrt +m5 +Llb:g6 +q4 +Loi;Llc:gT +y-x;q4 +Lba;Lld:o9;q4 +Loi;Lle:q8 +oV +oJ +hS +o7 +x +q11 +gX +Lmh;Llf:mI +A +oJ +cSub +gX +Lmh;Llg:q1 +cTan +oT +Llh:q7=fp_tan +m5 +Lli:q1 +cTanh +oT +Llj:q7=fp_tanh +m5 +Llk:q7=fp_trunc +m5 +Lll:qW +cDup);gJ +Llm:dF=cDup;gJ +Lln:hV +3 +gC +cSinCos);Lon:qE +GetParamSwappedBinaryOpcode(C));gJ +Llo:hV +3 +gC +cSinhCosh +gX +Lon;gJ +q4 +TailCall_cAcos;q4 +TailCall_cAcosh;q4 +TailCall_cAnd;q4 +TailCall_cArg;q4 +TailCall_cAsin;q4 +TailCall_cAsinh;q4 +TailCall_cAtan;q4 +TailCall_cAtan2;q4 +TailCall_cAtanh;q4 +TailCall_cCeil;q4 +TailCall_cConj;q4 +TailCall_cFloor;q4 +TailCall_cImag;q4 +TailCall_cInt;q4 +TailCall_cLog;q4 +TailCall_cLog10;q4 +TailCall_cLog2;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cOr;q4 +TailCall_cPolar;q4 +TailCall_cRDiv;q4 +TailCall_cRad;q4 +TailCall_cReal;q4 +TailCall_cSec;q4 +TailCall_cSin;q4 +TailCall_cSinh;q4 +TailCall_cSqrt;q4 +TailCall_cSub;q4 +TailCall_cTan;q4 +TailCall_cTanh;q4 +TailCall_cTrunc; +#endif +#undef FP_ReDefinePointers +#undef FP_TRACE_BYTECODE_OPTIMIZATION +#undef FP_TRACE_OPCODENAME diff --git a/deal.II/contrib/functionparser/extrasrc/fpaux.hh b/deal.II/contrib/functionparser/extrasrc/fpaux.hh new file mode 100644 index 0000000000..2ce6da2944 --- /dev/null +++ b/deal.II/contrib/functionparser/extrasrc/fpaux.hh @@ -0,0 +1,1295 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_AUX_H_ +#define ONCE_FPARSER_AUX_H_ + +#include "fptypes.hh" + +#include + +#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 +#endif + +#ifdef ONCE_FPARSER_H_ +namespace FUNCTIONPARSERTYPES +{ + template + struct IsIntType + { + enum { result = false }; + }; + template<> + struct IsIntType + { + enum { result = true }; + }; +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + struct IsIntType + { + enum { result = true }; + }; +#endif + + template + struct IsComplexType + { + enum { result = false }; + }; +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template + struct IsComplexType > + { + enum { result = true }; + }; +#endif + + +//========================================================================== +// Constants +//========================================================================== + template + inline Value_t fp_const_pi() // CONSTANT_PI + { + return Value_t(3.1415926535897932384626433832795028841971693993751L); + } + + template + inline Value_t fp_const_e() // CONSTANT_E + { + return Value_t(2.7182818284590452353602874713526624977572L); + } + template + inline Value_t fp_const_einv() // CONSTANT_EI + { + return Value_t(0.367879441171442321595523770161460867445811131L); + } + template + inline Value_t fp_const_log2() // CONSTANT_L2, CONSTANT_L2EI + { + return Value_t(0.69314718055994530941723212145817656807550013436025525412L); + } + template + inline Value_t fp_const_log10() // CONSTANT_L10, CONSTANT_L10EI + { + return Value_t(2.302585092994045684017991454684364207601101488628772976L); + } + template + inline Value_t fp_const_log2inv() // CONSTANT_L2I, CONSTANT_L2E + { + return Value_t(1.442695040888963407359924681001892137426645954L); + } + template + inline Value_t fp_const_log10inv() // CONSTANT_L10I, CONSTANT_L10E + { + return Value_t(0.434294481903251827651128918916605082294397L); + } + + template + inline const Value_t& fp_const_deg_to_rad() // CONSTANT_DR + { + static const Value_t factor = fp_const_pi() / Value_t(180); // to rad from deg + return factor; + } + + template + inline const Value_t& fp_const_rad_to_deg() // CONSTANT_RD + { + static const Value_t factor = Value_t(180) / fp_const_pi(); // to deg from rad + return factor; + } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline MpfrFloat fp_const_pi() { return MpfrFloat::const_pi(); } + + template<> + inline MpfrFloat fp_const_e() { return MpfrFloat::const_e(); } + + template<> + inline MpfrFloat fp_const_einv() { return MpfrFloat(1) / MpfrFloat::const_e(); } + + template<> + inline MpfrFloat fp_const_log2() { return MpfrFloat::const_log2(); } + + /* + template<> + inline MpfrFloat fp_const_log10() { return fp_log(MpfrFloat(10)); } + + template<> + inline MpfrFloat fp_const_log2inv() { return MpfrFloat(1) / MpfrFloat::const_log2(); } + + template<> + inline MpfrFloat fp_const_log10inv() { return fp_log10(MpfrFloat::const_e()); } + */ +#endif + + +//========================================================================== +// Generic math functions +//========================================================================== + template + inline Value_t fp_abs(const Value_t& x) { return std::fabs(x); } + + template + inline Value_t fp_acos(const Value_t& x) { return std::acos(x); } + + template + inline Value_t fp_asin(const Value_t& x) { return std::asin(x); } + + template + inline Value_t fp_atan(const Value_t& x) { return std::atan(x); } + + template + inline Value_t fp_atan2(const Value_t& x, const Value_t& y) + { return std::atan2(x, y); } + + template + inline Value_t fp_ceil(const Value_t& x) { return std::ceil(x); } + + template + inline Value_t fp_cos(const Value_t& x) { return std::cos(x); } + + template + inline Value_t fp_cosh(const Value_t& x) { return std::cosh(x); } + + template + inline Value_t fp_exp(const Value_t& x) { return std::exp(x); } + + template + inline Value_t fp_floor(const Value_t& x) { return std::floor(x); } + + template + inline Value_t fp_log(const Value_t& x) { return std::log(x); } + + template + inline Value_t fp_mod(const Value_t& x, const Value_t& y) + { return std::fmod(x, y); } + + template + inline Value_t fp_sin(const Value_t& x) { return std::sin(x); } + + template + inline Value_t fp_sinh(const Value_t& x) { return std::sinh(x); } + + template + inline Value_t fp_sqrt(const Value_t& x) { return std::sqrt(x); } + + template + inline Value_t fp_tan(const Value_t& x) { return std::tan(x); } + + template + inline Value_t fp_tanh(const Value_t& x) { return std::tanh(x); } + +#if __cplusplus > 201100 + template + inline Value_t fp_asinh(const Value_t& x) { return std::asinh(x); } + + template + inline Value_t fp_acosh(const Value_t& x) { return std::acosh(x); } + + template + inline Value_t fp_atanh(const Value_t& x) { return std::atanh(x); } +#else + template + inline Value_t fp_asinh(const Value_t& x) + { return fp_log(x + fp_sqrt(x*x + Value_t(1))); } + + template + inline Value_t fp_acosh(const Value_t& x) + { return fp_log(x + fp_sqrt(x*x - Value_t(1))); } + + template + inline Value_t fp_atanh(const Value_t& x) + { + return fp_log( (Value_t(1)+x) / (Value_t(1)-x)) * Value_t(0.5); + // Note: x = +1 causes division by zero + // x = -1 causes log(0) + // Thus, x must not be +-1 + } +#endif // FP_SUPPORT_ASINH + +#if __cplusplus > 201100 + template + inline Value_t fp_hypot(const Value_t& x, const Value_t& y) + { return std::hypot(x,y); } +#else + template + inline Value_t fp_hypot(const Value_t& x, const Value_t& y) + { return fp_sqrt(x*x + y*y); } +#endif + + template + inline Value_t fp_pow_base(const Value_t& x, const Value_t& y) + { return std::pow(x, y); } + +#if __cplusplus > 201100 + template + inline Value_t fp_log2(const Value_t& x) { return std::log2(x); } +#else + template + inline Value_t fp_log2(const Value_t& x) + { + return fp_log(x) * fp_const_log2inv(); + } +#endif // FP_SUPPORT_LOG2 + + template + inline Value_t fp_log10(const Value_t& x) + { + return fp_log(x) * fp_const_log10inv(); + } + + template + inline Value_t fp_trunc(const Value_t& x) + { + return x < Value_t() ? fp_ceil(x) : fp_floor(x); + } + + template + 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 + 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 + 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 + inline Value_t fp_epsilon() + { + return FunctionParserBase::epsilon(); + } + + +#ifdef _GNU_SOURCE + inline void fp_sinCos(double& sin, double& cos, const double& a) + { + sincos(a, &sin, &cos); + } + inline void fp_sinCos(float& sin, float& cos, const float& a) + { + sincosf(a, &sin, &cos); + } + inline void fp_sinCos(long double& sin, long double& cos, + const long double& a) + { + sincosl(a, &sin, &cos); + } +#endif + + +// ------------------------------------------------------------------------- +// Long int +// ------------------------------------------------------------------------- + inline long fp_abs(const long& x) { return x < 0 ? -x : x; } + inline long fp_acos(const long&) { return 0; } + inline long fp_asin(const long&) { return 0; } + inline long fp_atan(const long&) { return 0; } + inline long fp_atan2(const long&, const long&) { return 0; } + inline long fp_cbrt(const long&) { return 0; } + inline long fp_ceil(const long& x) { return x; } + inline long fp_cos(const long&) { return 0; } + inline long fp_cosh(const long&) { return 0; } + inline long fp_exp(const long&) { return 0; } + inline long fp_exp2(const long&) { return 0; } + inline long fp_floor(const long& x) { return x; } + inline long fp_log(const long&) { return 0; } + inline long fp_log2(const long&) { return 0; } + inline long fp_log10(const long&) { return 0; } + inline long fp_mod(const long& x, const long& y) { return x % y; } + inline long fp_pow(const long&, const long&) { return 0; } + inline long fp_sin(const long&) { return 0; } + inline long fp_sinh(const long&) { return 0; } + inline long fp_sqrt(const long&) { return 1; } + inline long fp_tan(const long&) { return 0; } + inline long fp_tanh(const long&) { return 0; } + inline long fp_asinh(const long&) { return 0; } + inline long fp_acosh(const long&) { return 0; } + inline long fp_atanh(const long&) { return 0; } + inline long fp_pow_base(const long&, const long&) { return 0; } + inline void fp_sinCos(long&, long&, const long&) {} + inline void fp_sinhCosh(long&, long&, const long&) {} + + template<> inline long fp_epsilon() { return 0; } + + +// ------------------------------------------------------------------------- +// MpfrFloat +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + inline MpfrFloat fp_abs(const MpfrFloat& x) { return MpfrFloat::abs(x); } + inline MpfrFloat fp_acos(const MpfrFloat& x) { return MpfrFloat::acos(x); } + inline MpfrFloat fp_acosh(const MpfrFloat& x) { return MpfrFloat::acosh(x); } + inline MpfrFloat fp_asin(const MpfrFloat& x) { return MpfrFloat::asin(x); } + inline MpfrFloat fp_asinh(const MpfrFloat& x) { return MpfrFloat::asinh(x); } + inline MpfrFloat fp_atan(const MpfrFloat& x) { return MpfrFloat::atan(x); } + inline MpfrFloat fp_atan2(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::atan2(x, y); } + inline MpfrFloat fp_atanh(const MpfrFloat& x) { return MpfrFloat::atanh(x); } + inline MpfrFloat fp_cbrt(const MpfrFloat& x) { return MpfrFloat::cbrt(x); } + inline MpfrFloat fp_ceil(const MpfrFloat& x) { return MpfrFloat::ceil(x); } + inline MpfrFloat fp_cos(const MpfrFloat& x) { return MpfrFloat::cos(x); } + inline MpfrFloat fp_cosh(const MpfrFloat& x) { return MpfrFloat::cosh(x); } + inline MpfrFloat fp_exp(const MpfrFloat& x) { return MpfrFloat::exp(x); } + inline MpfrFloat fp_exp2(const MpfrFloat& x) { return MpfrFloat::exp2(x); } + inline MpfrFloat fp_floor(const MpfrFloat& x) { return MpfrFloat::floor(x); } + inline MpfrFloat fp_hypot(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::hypot(x, y); } + inline MpfrFloat fp_int(const MpfrFloat& x) { return MpfrFloat::round(x); } + inline MpfrFloat fp_log(const MpfrFloat& x) { return MpfrFloat::log(x); } + inline MpfrFloat fp_log2(const MpfrFloat& x) { return MpfrFloat::log2(x); } + inline MpfrFloat fp_log10(const MpfrFloat& x) { return MpfrFloat::log10(x); } + inline MpfrFloat fp_mod(const MpfrFloat& x, const MpfrFloat& y) { return x % y; } + inline MpfrFloat fp_sin(const MpfrFloat& x) { return MpfrFloat::sin(x); } + inline MpfrFloat fp_sinh(const MpfrFloat& x) { return MpfrFloat::sinh(x); } + inline MpfrFloat fp_sqrt(const MpfrFloat& x) { return MpfrFloat::sqrt(x); } + inline MpfrFloat fp_tan(const MpfrFloat& x) { return MpfrFloat::tan(x); } + inline MpfrFloat fp_tanh(const MpfrFloat& x) { return MpfrFloat::tanh(x); } + inline MpfrFloat fp_trunc(const MpfrFloat& x) { return MpfrFloat::trunc(x); } + + inline MpfrFloat fp_pow(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + inline MpfrFloat fp_pow_base(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + + + inline void fp_sinCos(MpfrFloat& sin, MpfrFloat& cos, const MpfrFloat& a) + { + MpfrFloat::sincos(a, sin, cos); + } + + inline void fp_sinhCosh(MpfrFloat& sinhvalue, MpfrFloat& coshvalue, + const MpfrFloat& param) + { + const MpfrFloat paramCopy = param; + sinhvalue = fp_sinh(paramCopy); + coshvalue = fp_cosh(paramCopy); + } + + template<> + inline MpfrFloat fp_epsilon() { return MpfrFloat::someEpsilon(); } +#endif // FP_SUPPORT_MPFR_FLOAT_TYPE + + +// ------------------------------------------------------------------------- +// GMP int +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_GMP_INT_TYPE + inline GmpInt fp_abs(const GmpInt& x) { return GmpInt::abs(x); } + inline GmpInt fp_acos(const GmpInt&) { return 0; } + inline GmpInt fp_acosh(const GmpInt&) { return 0; } + inline GmpInt fp_asin(const GmpInt&) { return 0; } + inline GmpInt fp_asinh(const GmpInt&) { return 0; } + inline GmpInt fp_atan(const GmpInt&) { return 0; } + inline GmpInt fp_atan2(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_atanh(const GmpInt&) { return 0; } + inline GmpInt fp_cbrt(const GmpInt&) { return 0; } + inline GmpInt fp_ceil(const GmpInt& x) { return x; } + inline GmpInt fp_cos(const GmpInt&) { return 0; } + inline GmpInt fp_cosh(const GmpInt&) { return 0; } + inline GmpInt fp_exp(const GmpInt&) { return 0; } + inline GmpInt fp_exp2(const GmpInt&) { return 0; } + inline GmpInt fp_floor(const GmpInt& x) { return x; } + inline GmpInt fp_hypot(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_int(const GmpInt& x) { return x; } + inline GmpInt fp_log(const GmpInt&) { return 0; } + inline GmpInt fp_log2(const GmpInt&) { return 0; } + inline GmpInt fp_log10(const GmpInt&) { return 0; } + inline GmpInt fp_mod(const GmpInt& x, const GmpInt& y) { return x % y; } + inline GmpInt fp_pow(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_sin(const GmpInt&) { return 0; } + inline GmpInt fp_sinh(const GmpInt&) { return 0; } + inline GmpInt fp_sqrt(const GmpInt&) { return 0; } + inline GmpInt fp_tan(const GmpInt&) { return 0; } + inline GmpInt fp_tanh(const GmpInt&) { return 0; } + inline GmpInt fp_trunc(const GmpInt& x) { return x; } + inline GmpInt fp_pow_base(const GmpInt&, const GmpInt&) { return 0; } + inline void fp_sinCos(GmpInt&, GmpInt&, const GmpInt&) {} + inline void fp_sinhCosh(GmpInt&, GmpInt&, const GmpInt&) {} + + template<> + inline GmpInt fp_epsilon() { return 0; } +#endif // FP_SUPPORT_GMP_INT_TYPE + + +#if __cplusplus > 201100 + template + inline Value_t fp_cbrt(const Value_t& x) { return std::cbrt(x); } +#else + template + 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 inline Value_t fp_arg(const Value_t& x); + template inline Value_t fp_exp2(const Value_t& x); + template inline Value_t fp_int(const Value_t& x); + template inline Value_t fp_trunc(const Value_t& x); + template + inline void fp_sinCos(Value_t& , Value_t& , const Value_t& ); + template + 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 + 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 + { enum { result = true }; }; + template<> struct FP_ProbablyHasFastLibcComplex + { enum { result = true }; }; + template<> struct FP_ProbablyHasFastLibcComplex + { enum { result = true }; }; +#endif + + template + inline const std::complex fp_make_imag(const std::complex& v) + { + return std::complex ( T(), v.real() ); + } + + template + inline std::complex fp_real(const std::complex& x) + { + return x.real(); + } + template + inline std::complex fp_imag(const std::complex& x) + { + return x.imag(); + } + template + inline std::complex fp_arg(const std::complex& x) + { + return std::arg(x); + } + template + inline std::complex fp_conj(const std::complex& x) + { + return std::conj(x); + } + template + inline std::complex fp_polar(const T& x, const T& y) + { + T si, co; fp_sinCos(si, co, y); + return std::complex (x*co, x*si); + } + template + inline std::complex fp_polar(const std::complex& x, const std::complex& y) + { + // x * cos(y) + i * x * sin(y) -- arguments are supposed to be REAL numbers + return fp_polar (x.real(), y.real()); + //return std::polar(x.real(), y.real()); + //return x * (fp_cos(y) + (std::complex(0,1) * fp_sin(y)); + } + + // These provide fallbacks in case there's no library function + template + inline std::complex fp_floor(const std::complex& x) + { + return std::complex (fp_floor(x.real()), fp_floor(x.imag())); + } + template + inline std::complex fp_trunc(const std::complex& x) + { + return std::complex (fp_trunc(x.real()), fp_trunc(x.imag())); + } + template + inline std::complex fp_int(const std::complex& x) + { + return std::complex (fp_int(x.real()), fp_int(x.imag())); + } + template + inline std::complex fp_ceil(const std::complex& x) + { + return std::complex (fp_ceil(x.real()), fp_ceil(x.imag())); + } + template + inline std::complex fp_abs(const std::complex& 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 + inline std::complex fp_exp(const std::complex& x) + { + if(FP_ProbablyHasFastLibcComplex::result) + return std::exp(x); + return fp_polar(fp_exp(x.real()), x.imag()); + } + template + inline std::complex fp_log(const std::complex& x) + { + if(FP_ProbablyHasFastLibcComplex::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( fp_log(fp_abs(x.real())), + fp_arg(x.real()) ); // Note: Uses real-value fp_arg() here! + return std::complex( + fp_log(std::norm(x)) * T(0.5), + fp_arg(x).real() ); + } + template + inline std::complex fp_sqrt(const std::complex& x) + { + if(FP_ProbablyHasFastLibcComplex::result) + return std::sqrt(x); + return fp_polar (fp_sqrt(fp_abs(x).real()), + T(0.5)*fp_arg(x).real()); + } + template + inline std::complex fp_acos(const std::complex& x) + { + // -i * log(x + i * sqrt(1 - x^2)) + const std::complex 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 + inline std::complex fp_asin(const std::complex& x) + { + // -i * log(i*x + sqrt(1 - x^2)) + const std::complex 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 + inline std::complex fp_atan(const std::complex& x) + { + // 0.5i * (log(1-i*x) - log(1+i*x)) + // -0.5i * log( (1+i*x) / (1-i*x) ) + const std::complex 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 + inline std::complex fp_cos(const std::complex& x) + { + return std::cos(x); + // // (exp(i*x) + exp(-i*x)) / (2) + // //const std::complex 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 ( + // fp_cos(x.real())*fp_cosh(x.imag()), + // -fp_sin(x.real())*fp_sinh(x.imag())); + } + template + inline std::complex fp_sin(const std::complex& x) + { + return std::sin(x); + // // (exp(i*x) - exp(-i*x)) / (2i) + // //const std::complex 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 ( + // fp_sin(x.real())*fp_cosh(x.imag()), + // fp_cos(x.real())*fp_sinh(x.imag())); + } + template + inline void fp_sinCos( + std::complex& sinvalue, + std::complex& cosvalue, + const std::complex& x) + { + //const std::complex 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(srx*cix, crx*six); + cosvalue = std::complex(crx*cix, -srx*six); + } + template + inline void fp_sinhCosh( + std::complex& sinhvalue, + std::complex& coshvalue, + const std::complex& x) + { + T srx, crx; fp_sinhCosh(srx, crx, x.real()); + T six, cix; fp_sinCos(six, cix, x.imag()); + sinhvalue = std::complex(srx*cix, crx*six); + coshvalue = std::complex(crx*cix, srx*six); + } + template + inline std::complex fp_tan(const std::complex& x) + { + return std::tan(x); + //std::complex si, co; + //fp_sinCos(si, co, x); + //return si/co; + // // (i-i*exp(2i*x)) / (exp(2i*x)+1) + // const std::complex 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 + inline std::complex fp_cosh(const std::complex& x) + { + return std::cosh(x); + // // (exp(x) + exp(-x)) * 0.5 + // // Also: cosh(Xr)*cos(Xi) + i*sinh(Xr)*sin(Xi) + // return std::complex ( + // fp_cosh(x.real())*fp_cos(x.imag()), + // fp_sinh(x.real())*fp_sin(x.imag())); + } + template + inline std::complex fp_sinh(const std::complex& x) + { + return std::sinh(x); + // // (exp(x) - exp(-x)) * 0.5 + // // Also: sinh(Xr)*cos(Xi) + i*cosh(Xr)*sin(Xi) + // return std::complex ( + // fp_sinh(x.real())*fp_cos(x.imag()), + // fp_cosh(x.real())*fp_sin(x.imag())); + } + template + inline std::complex fp_tanh(const std::complex& x) + { + return std::tanh(x); + //std::complex 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 exp2x=fp_exp(x+x); + // return (exp2x-T(1)) / (exp2x+T(1)); + } + +#if __cplusplus > 201100 + template + inline std::complex fp_acosh(const std::complex& x) + { return fp_log(x + fp_sqrt(x*x - std::complex(1))); } + template + inline std::complex fp_asinh(const std::complex& x) + { return fp_log(x + fp_sqrt(x*x + std::complex(1))); } + template + inline std::complex fp_atanh(const std::complex& x) + { return fp_log( (std::complex(1)+x) / (std::complex(1)-x)) + * std::complex(0.5); } +#endif + template + inline std::complex fp_pow(const std::complex& x, const std::complex& 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 = + (x.imag() != T()) + ? fp_log(x) + : std::complex (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 (fp_exp(y.real()*t.real()), y.real()*t.imag()); + } + template + inline std::complex fp_cbrt(const std::complex& 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(fp_log(x)); + return fp_polar (fp_exp(t.real() / T(3)), t.imag() / T(3)); + } + + template + inline std::complex fp_exp2(const std::complex& x) + { + // pow(2, x) + // polar(2^Xr, Xi*log(2)) + return fp_polar (fp_exp2(x.real()), x.imag()*fp_const_log2()); + } + template + inline std::complex fp_mod(const std::complex& x, const std::complex& 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 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 + inline std::ostream& operator<<(std::ostream& os, const std::complex& 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 + inline T fp_complexScalarize(const std::complex& x) + { + T res(std::norm(x)); + if(x.real() < T()) res = -res; + return res; + } + template + 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 \ + inline bool operator op (const std::complex& x, T y) \ + { return fp_complexScalarize(x) op fp_realComplexScalarize(y); } \ + template \ + inline bool operator op (const std::complex& x, const std::complex& y) \ + { return fp_complexScalarize(x) op \ + fp_complexScalarize(y); } \ + template \ + inline bool operator op (T x, const std::complex& y) \ + { return fp_realComplexScalarize(x) op fp_complexScalarize(y); } + d( < ) d( <= ) d( > ) d( >= ) + #undef d +#endif + + template + inline Value_t fp_real(const Value_t& x) { return x; } + template + inline Value_t fp_imag(const Value_t& ) { return Value_t(); } + template + inline Value_t fp_arg(const Value_t& x) + { return x < Value_t() ? -fp_const_pi() : Value_t(); } + template + inline Value_t fp_conj(const Value_t& x) { return x; } + template + 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 + inline std::complex fp_atan2(const std::complex& y, + const std::complex& x) + { + if(y == Value_t()) return fp_arg(x); + if(x == Value_t()) return fp_const_pi() * Value_t(-0.5); + // 2*atan(y / (sqrt(x^2+y^2) + x) ) + // 2*atan( (sqrt(x^2+y^2) - x) / y) + std::complex res( fp_atan(y / (fp_hypot(x,y) + x)) ); + return res+res; + } + +// ------------------------------------------------------------------------- +// Comparison +// ------------------------------------------------------------------------- + template + inline bool fp_equal(const Value_t& x, const Value_t& y) + { return IsIntType::result + ? (x == y) + : (fp_abs(x - y) <= fp_epsilon()); } + + template + inline bool fp_nequal(const Value_t& x, const Value_t& y) + { return IsIntType::result + ? (x != y) + : (fp_abs(x - y) > fp_epsilon()); } + + template + inline bool fp_less(const Value_t& x, const Value_t& y) + { return IsIntType::result + ? (x < y) + : (x < y - fp_epsilon()); } + + template + inline bool fp_lessOrEq(const Value_t& x, const Value_t& y) + { return IsIntType::result + ? (x <= y) + : (x <= y + fp_epsilon()); } + + + template + inline bool fp_greater(const Value_t& x, const Value_t& y) + { return fp_less(y, x); } + + template + inline bool fp_greaterOrEq(const Value_t& x, const Value_t& y) + { return fp_lessOrEq(y, x); } + + template + inline bool fp_truth(const Value_t& d) + { + return IsIntType::result + ? d != Value_t() + : fp_abs(d) >= Value_t(0.5); + } + + template + inline bool fp_absTruth(const Value_t& abs_d) + { + return IsIntType::result + ? abs_d > Value_t() + : abs_d >= Value_t(0.5); + } + + template + inline const Value_t& fp_min(const Value_t& d1, const Value_t& d2) + { return d1 + inline const Value_t& fp_max(const Value_t& d1, const Value_t& d2) + { return d1>d2 ? d1 : d2; } + + template + inline const Value_t fp_not(const Value_t& b) + { return Value_t(!fp_truth(b)); } + + template + inline const Value_t fp_notNot(const Value_t& b) + { return Value_t(fp_truth(b)); } + + template + inline const Value_t fp_absNot(const Value_t& b) + { return Value_t(!fp_absTruth(b)); } + + template + inline const Value_t fp_absNotNot(const Value_t& b) + { return Value_t(fp_absTruth(b)); } + + template + inline const Value_t fp_and(const Value_t& a, const Value_t& b) + { return Value_t(fp_truth(a) && fp_truth(b)); } + + template + inline const Value_t fp_or(const Value_t& a, const Value_t& b) + { return Value_t(fp_truth(a) || fp_truth(b)); } + + template + inline const Value_t fp_absAnd(const Value_t& a, const Value_t& b) + { return Value_t(fp_absTruth(a) && fp_absTruth(b)); } + + template + inline const Value_t fp_absOr(const Value_t& a, const Value_t& b) + { return Value_t(fp_absTruth(a) || fp_absTruth(b)); } + + template + 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 HasInvalidRangesOpcode(unsigned op); + + template + inline Value_t DegreesToRadians(const Value_t& degrees) + { + return degrees * fp_const_deg_to_rad(); + } + + template + inline Value_t RadiansToDegrees(const Value_t& radians) + { + return radians * fp_const_rad_to_deg(); + } + + template + inline long makeLongInteger(const Value_t& value) + { + return (long) fp_int(value); + } + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template + inline long makeLongInteger(const std::complex& value) + { + return (long) fp_int( std::abs(value) ); + } +#endif + + // Is value an integer that fits in "long" datatype? + template + inline bool isLongInteger(const Value_t& value) + { + return value == Value_t( makeLongInteger(value) ); + } + + template + 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 + inline bool isEvenInteger(const Value_t& value) + { + const Value_t halfValue = value * Value_t(0.5); + return fp_equal(halfValue, fp_floor(halfValue)); + } + + template + 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 + inline Value_t fp_pow_with_exp_log(const Value_t& x, const Value_t& y) + { + return fp_exp(fp_log(x) * y); + } + + template + 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 + 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 + inline Value_t fp_exp2(const Value_t& x) + { + return fp_pow(Value_t(2), x); + } +} // namespace FUNCTIONPARSERTYPES + +#endif // ONCE_FPARSER_H_ + + +#ifndef FP_DISABLE_DOUBLE_TYPE +# define FUNCTIONPARSER_INSTANTIATE_D(g) g(double) +#else +# define FUNCTIONPARSER_INSTANTIATE_D(g) +#endif + +#ifdef FP_SUPPORT_FLOAT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_F(g) g(float) +#else +# define FUNCTIONPARSER_INSTANTIATE_F(g) +#endif + +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +# define FUNCTIONPARSER_INSTANTIATE_LD(g) g(long double) +#else +# define FUNCTIONPARSER_INSTANTIATE_LD(g) +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_LI(g) g(long) +#else +# define FUNCTIONPARSER_INSTANTIATE_LI(g) +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_MF(g) g(MpfrFloat) +#else +# define FUNCTIONPARSER_INSTANTIATE_MF(g) +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_GI(g) g(GmpInt) +#else +# define FUNCTIONPARSER_INSTANTIATE_GI(g) +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +# define FUNCTIONPARSER_INSTANTIATE_CD(cd) cd(std::complex) +#else +# define FUNCTIONPARSER_INSTANTIATE_CD(cd) +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_CF(cd) cd(std::complex) +#else +# define FUNCTIONPARSER_INSTANTIATE_CF(cd) +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +# define FUNCTIONPARSER_INSTANTIATE_CLD(cd) cd(std::complex) +#else +# define FUNCTIONPARSER_INSTANTIATE_CLD(cd) +#endif + +/* Add 'FUNCTIONPARSER_INSTANTIATE_TYPES' at the end of all .cc files + containing FunctionParserBase implementations. + */ +#define FUNCTIONPARSER_INSTANTIATE_BASE(type) \ + template class FunctionParserBase; + +#define FUNCTIONPARSER_INSTANTIATE_TYPES \ + FUNCTIONPARSER_INSTANTIATE_D(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_F(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_LD(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_LI(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_MF(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_GI(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_CD(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_CF(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_CLD(FUNCTIONPARSER_INSTANTIATE_BASE) + +#endif // ONCE_FPARSER_AUX_H_ diff --git a/deal.II/contrib/functionparser/extrasrc/fptypes.hh b/deal.II/contrib/functionparser/extrasrc/fptypes.hh new file mode 100644 index 0000000000..4023c8b95f --- /dev/null +++ b/deal.II/contrib/functionparser/extrasrc/fptypes.hh @@ -0,0 +1,288 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_TYPES_H_ +#define ONCE_FPARSER_TYPES_H_ + +#include "../fpconfig.hh" +#include + +#ifdef ONCE_FPARSER_H_ +#include +#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 + 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 + class NamePtrsMap: public + std::map > + { + }; + + const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]); +#endif // ONCE_FPARSER_H_ +} + +#ifdef ONCE_FPARSER_H_ +#include + +template +struct FunctionParserBase::Data +{ + unsigned mReferenceCounter; + + char mDelimiterChar; + ParseErrorType mParseErrorType; + int mEvalErrorType; + bool mUseDegreeConversion; + bool mHasByteCodeFlags; + const char* mErrorLocation; + + unsigned mVariablesAmount; + std::string mVariablesString; + FUNCTIONPARSERTYPES::NamePtrsMap mNamePtrs; + + struct InlineVariable + { + FUNCTIONPARSERTYPES::NamePtr mName; + unsigned mFetchIndex; + }; + + typedef std::vector 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* mParserPtr; + unsigned mParams; + }; + + std::vector mFuncPtrs; + std::vector mFuncParsers; + + std::vector mByteCode; + std::vector mImmed; + +#if !defined(FP_USE_THREAD_SAFE_EVAL) && \ + !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) + std::vector 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/deal.II/contrib/functionparser/fparser.cc b/deal.II/contrib/functionparser/fparser.cc index d71f7e5f3a..77ffc69079 100644 --- a/deal.II/contrib/functionparser/fparser.cc +++ b/deal.II/contrib/functionparser/fparser.cc @@ -1,19 +1,27 @@ -//=============================== -// Function parser v2.83 by Warp -//=============================== - -#include "fpconfig.h" -#include "fparser.h" -#include "fptypes.h" -using namespace FUNCTIONPARSERTYPES; -using namespace fparser; - +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#include "fpconfig.hh" +#include "fparser.hh" + +#include #include #include #include #include +#include +#include -using namespace std; +#include "extrasrc/fptypes.hh" +#include "extrasrc/fpaux.hh" +using namespace FUNCTIONPARSERTYPES; #ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA #ifndef FP_USE_THREAD_SAFE_EVAL @@ -21,1279 +29,2838 @@ using namespace std; #endif #endif -#ifndef M_PI -#define M_PI 3.1415926535897932384626433832795 +#ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) (x) +# define unlikely(x) (x) #endif -namespace -{ - const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]); - +//========================================================================= +// Opcode analysis functions +//========================================================================= +// These functions are used by the Parse() bytecode optimizer (mostly from +// code in fp_opcode_add.inc). - // BCB4 does not implement the standard lower_bound function. - // This is used instead: - const FuncDefinition* fp_lower_bound(const FuncDefinition* first, - const FuncDefinition* last, - const FuncDefinition& value) - { - while(first < last) - { - const FuncDefinition* middle = first+(last-first)/2; - if(*middle < value) first = middle+1; - else last = middle; - } - return last; - } - - - // Returns a pointer to the FuncDefinition instance which 'name' is - // the same as the one given by 'F'. If no such function name exists, - // returns 0. - inline const FuncDefinition* FindFunction(const char* F) +bool FUNCTIONPARSERTYPES::IsLogicalOpcode(unsigned op) +{ + switch(op) { - FuncDefinition func = { F, 0, 0, 0 }; - while(isalnum(F[func.nameLength])) ++func.nameLength; - if(func.nameLength) - { - const FuncDefinition* found = - fp_lower_bound(Functions, Functions+FUNC_AMOUNT, func); - if(found == Functions+FUNC_AMOUNT || func < *found) - return 0; - return found; - } - return 0; + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; } + return false; } - -//--------------------------------------------------------------------------- -// Copy-on-write method -//--------------------------------------------------------------------------- -void FunctionParser::CopyOnWrite() +bool FUNCTIONPARSERTYPES::IsComparisonOpcode(unsigned op) { - if(data->referenceCounter > 1) + switch(op) { - Data* oldData = data; - data = new Data(*oldData); - --(oldData->referenceCounter); - data->referenceCounter = 1; + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; } + return false; } - -//--------------------------------------------------------------------------- -// Constructors and destructors -//--------------------------------------------------------------------------- -//=========================================================================== -FunctionParser::FunctionParser(): - parseErrorType(FP_NO_ERROR), evalErrorType(0), - data(new Data), - evalRecursionLevel(0) -{ - data->referenceCounter = 1; -} - -FunctionParser::~FunctionParser() +unsigned FUNCTIONPARSERTYPES::OppositeComparisonOpcode(unsigned op) { - if(--(data->referenceCounter) == 0) + switch(op) { - delete data; + case cLess: return cGreater; + case cGreater: return cLess; + case cLessOrEq: return cGreaterOrEq; + case cGreaterOrEq: return cLessOrEq; } + return op; } -FunctionParser::FunctionParser(const FunctionParser& cpy): - parseErrorType(cpy.parseErrorType), - evalErrorType(cpy.evalErrorType), - data(cpy.data), - evalRecursionLevel(0) -{ - ++(data->referenceCounter); -} - -FunctionParser& FunctionParser::operator=(const FunctionParser& cpy) +bool FUNCTIONPARSERTYPES::IsNeverNegativeValueOpcode(unsigned op) { - if(data != cpy.data) + switch(op) { - if(--(data->referenceCounter) == 0) delete data; - - parseErrorType = cpy.parseErrorType; - evalErrorType = cpy.evalErrorType; - data = cpy.data; - evalRecursionLevel = cpy.evalRecursionLevel; - - ++(data->referenceCounter); + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + case cSqrt: case cRSqrt: case cSqr: + case cHypot: + case cAbs: + case cAcos: case cCosh: + return true; + default: break; } - - return *this; -} - -void FunctionParser::ForceDeepCopy() -{ - CopyOnWrite(); -} - -FunctionParser::Data::Data(): - useDegreeConversion(false), - isOptimized(false), - ByteCode(0), ByteCodeSize(0), - Immed(0), ImmedSize(0), - Stack(0), StackSize(0) -{} - -FunctionParser::Data::~Data() -{ - if(ByteCode) { delete[] ByteCode; ByteCode=0; } - if(Immed) { delete[] Immed; Immed=0; } - if(Stack) { delete[] Stack; Stack=0; } -} - -// Makes a deep-copy of Data: -FunctionParser::Data::Data(const Data& cpy): - varAmount(cpy.varAmount), useDegreeConversion(cpy.useDegreeConversion), - Variables(cpy.Variables), Constants(cpy.Constants), Units(cpy.Units), - FuncPtrNames(cpy.FuncPtrNames), FuncPtrs(cpy.FuncPtrs), - FuncParserNames(cpy.FuncParserNames), FuncParsers(cpy.FuncParsers), - ByteCode(0), ByteCodeSize(cpy.ByteCodeSize), - Immed(0), ImmedSize(cpy.ImmedSize), - Stack(0), StackSize(cpy.StackSize) -{ - if(ByteCodeSize) ByteCode = new unsigned[ByteCodeSize]; - if(ImmedSize) Immed = new double[ImmedSize]; - if(StackSize) Stack = new double[StackSize]; - - for(unsigned i=0; i& dest) +bool FUNCTIONPARSERTYPES::IsUnaryOpcode(unsigned op) { - unsigned varNumber = VarBegin; - unsigned ind1 = 0, ind2; - - while(ind1 < Vars.size()) + switch(op) { - if(!isalpha(Vars[ind1]) && Vars[ind1]!='_') return false; - for(ind2=ind1+1; ind2Constants) != data->Constants.end()) - return USER_DEF_CONST; - - // Units are independent from the rest and thus the following check - // is actually not needed: - //if(FindConstant(n, data->Units) != data->Units.end()) - // return USER_DEF_UNIT; - - if(FindVariable(n, data->FuncParserNames) != data->FuncParserNames.end()) - return USER_DEF_FUNC_PARSER; - if(FindVariable(n, data->FuncPtrNames) != data->FuncPtrNames.end()) - return USER_DEF_FUNC_PTR; - - return VALID_NEW_NAME; + // See comment in declaration of FP_ParamGuardMask + return int(op) >= VarBegin; } - -// Constants: -bool FunctionParser::AddConstant(const string& name, double value) +bool FUNCTIONPARSERTYPES::IsCommutativeOrParamSwappableBinaryOpcode(unsigned op) { - int nameType = VarNameType(name); - if(nameType == VALID_NEW_NAME || nameType == USER_DEF_CONST) + switch(op) { - CopyOnWrite(); - data->Constants[name] = value; - return true; + case cAdd: + case cMul: + case cEqual: case cNEqual: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cMin: case cMax: case cHypot: + return true; + case cDiv: case cSub: case cRDiv: case cRSub: + return true; + case cLess: case cGreater: + case cLessOrEq: case cGreaterOrEq: return true; } return false; } -// Units: -bool FunctionParser::AddUnit(const std::string& name, double value) -{ - if(!varNameHasOnlyValidChars(name)) return false; - CopyOnWrite(); - data->Units[name] = value; - return true; -} - -// Function pointers -bool FunctionParser::AddFunction(const std::string& name, - FunctionPtr func, unsigned paramsAmount) +unsigned FUNCTIONPARSERTYPES::GetParamSwappedBinaryOpcode(unsigned op) { - int nameType = VarNameType(name); - if(nameType == VALID_NEW_NAME) + switch(op) { - CopyOnWrite(); - data->FuncPtrNames[name] = data->FuncPtrs.size(); - data->FuncPtrs.push_back(Data::FuncPtrData(func, paramsAmount)); - return true; + case cAdd: + case cMul: + case cEqual: case cNEqual: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cMin: case cMax: case cHypot: + return op; + case cDiv: return cRDiv; + case cSub: return cRSub; + case cRDiv: return cDiv; + case cRSub: return cSub; + case cLess: return cGreater; + case cGreater: return cLess; + case cLessOrEq: return cGreaterOrEq; + case cGreaterOrEq: return cLessOrEq; } - return false; + return op; // Error } -bool FunctionParser::CheckRecursiveLinking(const FunctionParser* fp) const +template +bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op) { - if(fp == this) return true; - for(unsigned i=0; idata->FuncParsers.size(); ++i) - if(CheckRecursiveLinking(fp->data->FuncParsers[i])) return true; + // Returns true, if the given opcode has a range of + // input values that gives an error. + if(ComplexType) + { + // COMPLEX: + switch(op) + { + case cAtan: // allowed range: x != +-1i + case cAtanh: // allowed range: x != +-1 + //case cCot: // allowed range: tan(x) != 0 + //case cCsc: // allowed range: sin(x) != 0 + case cLog: // allowed range: x != 0 + case cLog2: // allowed range: x != 0 + case cLog10: // allowed range: x != 0 + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by:// allowed range: x != 0 + #endif + //case cPow: // allowed when: x != 0 or y != 0 + //case cSec: // allowed range: cos(x) != 0 + //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2) + //case cTanh: // allowed range: log(x) != -1 --> x != +-(pi/2)i + case cRSqrt: // allowed range: x != 0 + //case cDiv: // allowed range: y != 0 + //case cRDiv: // allowed range: x != 0 + //case cInv: // allowed range: x != 0 + return true; + } + } + else + { + // REAL: + switch(op) + { + case cAcos: // allowed range: |x| <= 1 + case cAsin: // allowed range: |x| <= 1 + case cAcosh: // allowed range: x >= 1 + case cAtanh: // allowed range: |x| < 1 + //case cCot: // allowed range: tan(x) != 0 + //case cCsc: // allowed range: sin(x) != 0 + case cLog: // allowed range: x > 0 + case cLog2: // allowed range: x > 0 + case cLog10: // allowed range: x > 0 + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by:// allowed range: x > 0 + #endif + //case cPow: // allowed when: x > 0 or (x = 0 and y != 0) or (x<0) + // Technically, when (x<0 and y is not integer), + // it is not allowed, but we allow it anyway + // in order to make nontrivial roots work. + //case cSec: // allowed range: cos(x) != 0 + case cSqrt: // allowed range: x >= 0 + case cRSqrt: // allowed range: x > 0 + //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2) + //case cDiv: // allowed range: y != 0 + //case cRDiv: // allowed range: x != 0 + //case cInv: // allowed range: x != 0 + return true; + } + } return false; } -bool FunctionParser::AddFunction(const std::string& name, - FunctionParser& parser) +template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op); +template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op); + + +#if(0) // Implementation moved to fpaux.hh due to linker problems +//========================================================================= +// Mathematical template functions +//========================================================================= +/* fp_pow() is a wrapper for std::pow() + * that produces an identical value for + * exp(1) ^ 2.0 (0x4000000000000000) + * as exp(2.0) (0x4000000000000000) + * - std::pow() on x86_64 + * produces 2.0 (0x3FFFFFFFFFFFFFFF) instead! + * See comments below for other special traits. + */ +namespace { - int nameType = VarNameType(name); - if(nameType == VALID_NEW_NAME) + template + inline ValueT fp_pow_with_exp_log(const ValueT& x, const ValueT& y) { - if(CheckRecursiveLinking(&parser)) return false; - - CopyOnWrite(); + // Exponentiation using exp(log(x)*y). + // See http://en.wikipedia.org/wiki/Exponentiation#Real_powers + // Requirements: x > 0. + return fp_exp(fp_log(x) * y); + } - data->FuncParserNames[name] = data->FuncParsers.size(); - data->FuncParsers.push_back(&parser); - return true; + template + inline ValueT fp_powi(ValueT x, unsigned long y) + { + // Fast binary exponentiation algorithm + // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring + // Requirements: y is non-negative integer. + ValueT result(1); + while(y != 0) + { + if(y & 1) { result *= x; y -= 1; } + else { x *= x; y /= 2; } + } + return result; } - return false; } - - -// Main parsing function -// --------------------- -int FunctionParser::Parse(const std::string& Function, - const std::string& Vars, - bool useDegrees) +template +ValueT FUNCTIONPARSERTYPES::fp_pow(const ValueT& x, const ValueT& y) { - CopyOnWrite(); - - data->Variables.clear(); - - if(!ParseVars(Vars, data->Variables)) + if(x == ValueT(1)) return ValueT(1); + // y is now zero or positive + if(isLongInteger(y)) { - parseErrorType = INVALID_VARS; - return Function.size(); + // Use fast binary exponentiation algorithm + if(y >= ValueT(0)) + return fp_powi(x, makeLongInteger(y)); + else + return ValueT(1) / fp_powi(x, -makeLongInteger(y)); } - data->varAmount = data->Variables.size(); // this is for Eval() - - const char* Func = Function.c_str(); - - parseErrorType = FP_NO_ERROR; - - int Result = CheckSyntax(Func); - if(Result >= 0) return Result; - - data->useDegreeConversion = useDegrees; - Result = Compile(Func); - if(Result >= 0) return Result; - - data->Variables.clear(); - - parseErrorType = FP_NO_ERROR; - return -1; + if(y >= ValueT(0)) + { + // y is now positive. Calculate using exp(log(x)*y). + if(x > ValueT(0)) return fp_pow_with_exp_log(x, y); + if(x == ValueT(0)) return ValueT(0); + // At this point, y > 0.0 and x is known to be < 0.0, + // because positive and zero cases are already handled. + if(!isInteger(y*ValueT(16))) + return -fp_pow_with_exp_log(-x, y); + // ^This is not technically correct, but it allows + // functions such as cbrt(x^5), that is, x^(5/3), + // to be evaluated when x is negative. + // It is too complicated (and slow) to test whether y + // is a formed from a ratio of an integer to an odd integer. + // (And due to floating point inaccuracy, pointless too.) + // For example, x^1.30769230769... is + // actually x^(17/13), i.e. (x^17) ^ (1/13). + // (-5)^(17/13) gives us now -8.204227562330453. + // To see whether the result is right, we can test the given + // root: (-8.204227562330453)^13 gives us the value of (-5)^17, + // which proves that the expression was correct. + // + // The y*16 check prevents e.g. (-4)^(3/2) from being calculated, + // as it would confuse functioninfo when pow() returns no error + // but sqrt() does when the formula is converted into sqrt(x)*x. + // + // The errors in this approach are: + // (-2)^sqrt(2) should produce NaN + // or actually sqrt(2)I + 2^sqrt(2), + // produces -(2^sqrt(2)) instead. + // (Impact: Neglible) + // Thus, at worst, we're changing a NaN (or complex) + // result into a negative real number result. + } + else + { + // y is negative. Utilize the x^y = 1/(x^-y) identity. + if(x > ValueT(0)) return fp_pow_with_exp_log(ValueT(1) / x, -y); + if(x < ValueT(0)) + { + if(!isInteger(y*ValueT(-16))) + return -fp_pow_with_exp_log(ValueT(-1) / x, -y); + // ^ See comment above. + } + // Remaining case: 0.0 ^ negative number + } + // This is reached when: + // x=0, and y<0 + // x<0, and y*16 is either positive or negative integer + // It is used for producing error values and as a safe fallback. + return fp_pow_base(x, y); } +#endif + +//========================================================================= +// Elementary (atom) parsing functions +//========================================================================= namespace { - const char* const fpOperators[] = + const unsigned FP_ParamGuardMask = 1U << (sizeof(unsigned) * 8u - 1u); + // ^ This mask is used to prevent cFetch/other opcode's parameters + // from being confused into opcodes or variable indices within the + // bytecode optimizer. Because the way it is tested in bytecoderules.dat + // for speed reasons, it must also be the sign-bit of the "int" datatype. + // Perhaps an "assert(IsVarOpcode(X | FP_ParamGuardMask) == false)" + // might be justified to put somewhere in the code, just in case? + + + /* Reads an UTF8-encoded sequence which forms a valid identifier name from + the given input string and returns its length. If bit 31 is set, the + return value also contains the internal function opcode (defined in + fptypes.hh) that matches the name. + */ + unsigned readIdentifierCommon(const char* input) { - "+", "-", "*", "/", "%", "^", - "=", "!=", "<=", "<", ">=", ">", "&", "|", - 0 - }; + /* Assuming unsigned = 32 bits: + 76543210 76543210 76543210 76543210 + Return value if built-in function: + 1PPPPPPP PPPPPPPP LLLLLLLL LLLLLLLL + P = function opcode (15 bits) + L = function name length (16 bits) + Return value if not built-in function: + 0LLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL + L = identifier length (31 bits) + If unsigned has more than 32 bits, the other + higher order bits are to be assumed zero. + */ +#include "extrasrc/fp_identifier_parser.inc" + return 0; + } - // Is given char an operator? - // (Returns 0 if not, else the size of the operator) - inline int IsOperator(const char* F) + template + inline unsigned readIdentifier(const char* input) { - for(unsigned opInd = 0; fpOperators[opInd]; ++opInd) + const unsigned value = readIdentifierCommon(input); + if( (value & 0x80000000U) != 0) // Function? { - const char* op = fpOperators[opInd]; - for(unsigned n = 0; F[n] == *op; ++n) + // Verify that the function actually exists for this datatype + if(IsIntType::result + && !Functions[(value >> 16) & 0x7FFF].okForInt()) + { + // If it does not exist, return it as an identifier instead + return value & 0xFFFFu; + } + if(!IsComplexType::result + && Functions[(value >> 16) & 0x7FFF].complexOnly()) { - ++op; - if(*op == 0) return op-fpOperators[opInd]; + // If it does not exist, return it as an identifier instead + return value & 0xFFFFu; } } - return 0; + return value; } - // skip whitespace - inline void sws(const char* F, int& Ind) + // Returns true if the entire string is a valid identifier + template + bool containsOnlyValidIdentifierChars(const std::string& name) { - while(F[Ind] && isspace(F[Ind])) ++Ind; + if(name.empty()) return false; + return readIdentifier(name.c_str()) == (unsigned) name.size(); } -} -// Returns an iterator to the variable with the same name as 'F', or to -// Variables.end() if no such variable exists: -inline FunctionParser::Data::VarMap_t::const_iterator -FunctionParser::FindVariable(const char* F, const Data::VarMap_t& vars) const -{ - if(vars.size()) + + // ----------------------------------------------------------------------- + // Wrappers for strto... functions + // ----------------------------------------------------------------------- + template + inline Value_t fp_parseLiteral(const char* str, char** endptr) { - unsigned ind = 0; - while(isalnum(F[ind]) || F[ind] == '_') ++ind; - if(ind) - { - string name(F, ind); - return vars.find(name); - } + return std::strtod(str, endptr); } - return vars.end(); -} -inline FunctionParser::Data::ConstMap_t::const_iterator -FunctionParser::FindConstant(const char* F, - const Data::ConstMap_t& consts) const -{ - if(consts.size()) +#if defined(FP_USE_STRTOLD) || __cplusplus > 201100 + template<> + inline long double fp_parseLiteral(const char* str, + char** endptr) { - unsigned ind = 0; - while(isalnum(F[ind]) || F[ind] == '_') ++ind; - if(ind) - { - string name(F, ind); - return consts.find(name); - } + using namespace std; // Just in case strtold() is not inside std:: + return strtold(str, endptr); } - return consts.end(); -} +#endif -int FunctionParser::CheckForUnit(const char* Function, int Ind) const -{ - int c = Function[Ind]; - if(isalpha(c) || c == '_') +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline long fp_parseLiteral(const char* str, char** endptr) + { + return std::strtol(str, endptr, 10); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template + inline std::complex fp_parseComplexLiteral(const char* str, + char** endptr) { - Data::ConstMap_t::const_iterator uIter = - FindConstant(&Function[Ind], data->Units); - if(uIter != data->Units.end()) + T result = fp_parseLiteral (str,endptr); + const char* end = *endptr; + if( (*end == 'i' || *end == 'I') + && !std::isalnum(end[1]) ) { - Ind += uIter->first.size(); - sws(Function, Ind); + ++*endptr; + return std::complex (T(), result); } + return std::complex (result, T()); } - return Ind; -} - -//--------------------------------------------------------------------------- -// Check function string syntax -// ---------------------------- -int FunctionParser::CheckSyntax(const char* Function) -{ - const Data::VarMap_t& Variables = data->Variables; - const Data::ConstMap_t& Constants = data->Constants; - const Data::VarMap_t& FuncPtrNames = data->FuncPtrNames; - const Data::VarMap_t& FuncParserNames = data->FuncParserNames; - - vector functionParenthDepth; +#endif - int Ind=0, ParenthCnt=0, c; - char* Ptr; +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + template<> + inline std::complex fp_parseLiteral > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral (str,endptr); + } +#endif - while(true) +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + inline std::complex fp_parseLiteral > + (const char* str, char** endptr) { - sws(Function, Ind); - c=Function[Ind]; + return fp_parseComplexLiteral (str,endptr); + } +#endif -// Check for valid operand (must appear) +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + inline std::complex fp_parseLiteral > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral (str,endptr); + } +#endif - // Check for leading - or ! - if(c=='-' || c=='!') { sws(Function, ++Ind); c=Function[Ind]; } - if(c==0) { parseErrorType=PREMATURE_EOS; return Ind; } + // ----------------------------------------------------------------------- + // Hexadecimal floating point literal parsing + // ----------------------------------------------------------------------- + inline int testXdigit(unsigned c) + { + if((c-'0') < 10u) return c&15; // 0..9 + if(((c|0x20)-'a') < 6u) return 9+(c&15); // A..F or a..f + return -1; // Not a hex digit + } - // Check for math function - bool foundFunc = false; - const FuncDefinition* fptr = FindFunction(&Function[Ind]); - if(fptr) + template + inline void addXdigit(elem_t* buffer, unsigned nibble) + { + for(unsigned p=0; pnameLength; - foundFunc = true; + unsigned carry = unsigned( buffer[p] >> (elem_t)(limb_bits-4) ); + buffer[p] = (buffer[p] << 4) | nibble; + nibble = carry; } - else + } + + template + Value_t parseHexLiteral(const char* str, char** endptr) + { + const unsigned bits_per_char = 8; + + const int MantissaBits = + std::numeric_limits::radix == 2 + ? std::numeric_limits::digits + : (((sizeof(Value_t) * bits_per_char) &~ 3) - 4); + + typedef unsigned long elem_t; + const int ExtraMantissaBits = 4 + ((MantissaBits+3)&~3); // Store one digit more for correct rounding + const unsigned limb_bits = sizeof(elem_t) * bits_per_char; + const unsigned n_limbs = (ExtraMantissaBits + limb_bits-1) / limb_bits; + elem_t mantissa_buffer[n_limbs] = { 0 }; + + int n_mantissa_bits = 0; // Track the number of bits + int exponent = 0; // The exponent that will be used to multiply the mantissa + // Read integer portion + while(true) { - // Check for user-defined function - Data::VarMap_t::const_iterator fIter = - FindVariable(&Function[Ind], FuncPtrNames); - if(fIter != FuncPtrNames.end()) + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit (mantissa_buffer, xdigit); + ++str; + + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) { - Ind += fIter->first.size(); - foundFunc = true; + // Exhausted the precision. Parse the rest (until exponent) + // normally but ignore the actual digits. + for(; testXdigit(*str) >= 0; ++str) + exponent += 4; + // Read but ignore decimals + if(*str == '.') + for(++str; testXdigit(*str) >= 0; ++str) + {} + goto read_exponent; } - else + } + // Read decimals + if(*str == '.') + for(++str; ; ) { - Data::VarMap_t::const_iterator pIter = - FindVariable(&Function[Ind], FuncParserNames); - if(pIter != FuncParserNames.end()) + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit (mantissa_buffer, xdigit); + ++str; + + exponent -= 4; + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) { - Ind += pIter->first.size(); - foundFunc = true; + // Exhausted the precision. Skip the rest + // of the decimals, until the exponent. + while(testXdigit(*str) >= 0) + ++str; + break; } } - } - - if(foundFunc) - { - sws(Function, Ind); - c = Function[Ind]; - if(c!='(') { parseErrorType=EXPECT_PARENTH_FUNC; return Ind; } - - int Ind2 = Ind+1; - sws(Function, Ind2); - if(Function[Ind2] == ')') - { - Ind = Ind2+1; - sws(Function, Ind); - c = Function[Ind]; - // Ugly, but other methods would just be uglier... - goto CheckOperator; - } - - functionParenthDepth.push_back(ParenthCnt+1); - } - - // Check for opening parenthesis - if(c=='(') - { - ++ParenthCnt; - sws(Function, ++Ind); - if(Function[Ind]==')') { parseErrorType=EMPTY_PARENTH; return Ind;} - continue; - } - // Check for number - if(isdigit(c) || (c=='.' && isdigit(Function[Ind+1]))) + // Read exponent + read_exponent: + if(*str == 'p' || *str == 'P') { - strtod(&Function[Ind], &Ptr); - Ind += int(Ptr-&Function[Ind]); - sws(Function, Ind); - c = Function[Ind]; - } - else - { // Check for variable - Data::VarMap_t::const_iterator vIter = - FindVariable(&Function[Ind], Variables); - if(vIter != Variables.end()) - Ind += vIter->first.size(); - else + const char* str2 = str+1; + long p_exponent = strtol(str2, const_cast (&str2), 10); + if(str2 != str+1 && p_exponent == (long)(int)p_exponent) { - // Check for constant - Data::ConstMap_t::const_iterator cIter = - FindConstant(&Function[Ind], Constants); - if(cIter != Constants.end()) - Ind += cIter->first.size(); - else - { parseErrorType=SYNTAX_ERROR; return Ind; } + exponent += (int)p_exponent; + str = str2; } - sws(Function, Ind); - c = Function[Ind]; } - // Check for unit - Ind = CheckForUnit(Function, Ind); - c = Function[Ind]; + if(endptr) *endptr = const_cast (str); - // Check for closing parenthesis - while(c==')') + Value_t result = std::ldexp(Value_t(mantissa_buffer[0]), exponent); + for(unsigned p=1; p + long parseHexLiteral(const char* str, char** endptr) + { + return std::strtol(str, endptr, 16); + } +#endif -// If we get here, we have an operand and an operator; the next loop will -// check for another operand (must appear) - Ind += opSize; - } // while +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + template<> + std::complex + parseHexLiteral >(const char* str, char** endptr) + { + return parseHexLiteral (str, endptr); + } +#endif - // Check that all opened parentheses are also closed - if(ParenthCnt>0) { parseErrorType=MISSING_PARENTH; return Ind; } +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + std::complex + parseHexLiteral >(const char* str, char** endptr) + { + return parseHexLiteral (str, endptr); + } +#endif -// The string is ok - parseErrorType=FP_NO_ERROR; - return -1; +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + std::complex + parseHexLiteral >(const char* str, char** endptr) + { + return parseHexLiteral (str, endptr); + } +#endif } - -// Compile function string to bytecode -// ----------------------------------- -int FunctionParser::Compile(const char* Function) +//========================================================================= +// Utility functions +//========================================================================= +namespace { - if(data->ByteCode) { delete[] data->ByteCode; data->ByteCode=0; } - if(data->Immed) { delete[] data->Immed; data->Immed=0; } - if(data->Stack) { delete[] data->Stack; data->Stack=0; } - data->isOptimized = false; - - vector byteCode; byteCode.reserve(1024); - tempByteCode = &byteCode; + // ----------------------------------------------------------------------- + // Add a new identifier to the specified identifier map + // ----------------------------------------------------------------------- + // Return value will be false if the name already existed + template + bool addNewNameData(NamePtrsMap& namePtrs, + std::pair >& newName, + bool isVar) + { + typename NamePtrsMap::iterator nameIter = + namePtrs.lower_bound(newName.first); - vector immed; immed.reserve(1024); - tempImmed = &immed; + if(nameIter != namePtrs.end() && newName.first == nameIter->first) + { + // redefining a var is not allowed. + if(isVar) return false; - data->StackSize = StackPtr = 0; + // redefining other tokens is allowed, if the type stays the same. + if(nameIter->second.type != newName.second.type) + return false; - int ind = CompileExpression(Function, 0); - if(parseErrorType != FP_NO_ERROR) return ind; + // update the data + nameIter->second = newName.second; + return true; + } - data->ByteCodeSize = byteCode.size(); - data->ImmedSize = immed.size(); + if(!isVar) + { + // Allocate a copy of the name (pointer stored in the map key) + // However, for VARIABLEs, the pointer points to VariableString, + // which is managed separately. Thusly, only done when !IsVar. + char* namebuf = new char[newName.first.nameLength]; + memcpy(namebuf, newName.first.name, newName.first.nameLength); + newName.first.name = namebuf; + } - if(data->ByteCodeSize) - { - data->ByteCode = new unsigned[data->ByteCodeSize]; - memcpy(data->ByteCode, &byteCode[0], - sizeof(unsigned)*data->ByteCodeSize); - } - if(data->ImmedSize) - { - data->Immed = new double[data->ImmedSize]; - memcpy(data->Immed, &immed[0], - sizeof(double)*data->ImmedSize); + namePtrs.insert(nameIter, newName); + return true; } -#ifndef FP_USE_THREAD_SAFE_EVAL - if(data->StackSize) - data->Stack = new double[data->StackSize]; -#endif - - return -1; } -inline void FunctionParser::AddCompiledByte(unsigned c) -{ - tempByteCode->push_back(c); -} - -inline void FunctionParser::AddImmediate(double i) -{ - tempImmed->push_back(i); -} +//========================================================================= +// Data struct implementation +//========================================================================= +template +FunctionParserBase::Data::Data(): + mReferenceCounter(1), + mDelimiterChar(0), + mParseErrorType(NO_FUNCTION_PARSED_YET), + mEvalErrorType(0), + mUseDegreeConversion(false), + mErrorLocation(0), + mVariablesAmount(0), + mStackSize(0) +{} -inline void FunctionParser::AddFunctionOpcode(unsigned opcode) +template +FunctionParserBase::Data::Data(const Data& rhs): + mReferenceCounter(0), + mDelimiterChar(rhs.mDelimiterChar), + mParseErrorType(rhs.mParseErrorType), + mEvalErrorType(rhs.mEvalErrorType), + mUseDegreeConversion(rhs.mUseDegreeConversion), + mErrorLocation(rhs.mErrorLocation), + mVariablesAmount(rhs.mVariablesAmount), + mVariablesString(rhs.mVariablesString), + mNamePtrs(), + mFuncPtrs(rhs.mFuncPtrs), + mFuncParsers(rhs.mFuncParsers), + mByteCode(rhs.mByteCode), + mImmed(rhs.mImmed), +#ifndef FP_USE_THREAD_SAFE_EVAL + mStack(rhs.mStackSize), +#endif + mStackSize(rhs.mStackSize) { - if(data->useDegreeConversion) - switch(opcode) + for(typename NamePtrsMap::const_iterator i = rhs.mNamePtrs.begin(); + i != rhs.mNamePtrs.end(); + ++i) + { + if(i->second.type == NameData::VARIABLE) { - case cCos: - case cCosh: - case cCot: - case cCsc: - case cSec: - case cSin: - case cSinh: - case cTan: - case cTanh: - AddCompiledByte(cRad); + const std::size_t variableStringOffset = + i->first.name - rhs.mVariablesString.c_str(); + std::pair > tmp + (NamePtr(&mVariablesString[variableStringOffset], + i->first.nameLength), + i->second); + mNamePtrs.insert(mNamePtrs.end(), tmp); } - - AddCompiledByte(opcode); - - if(data->useDegreeConversion) - switch(opcode) + else { - case cAcos: -#ifndef NO_ASINH - case cAcosh: - case cAsinh: - case cAtanh: -#endif - case cAsin: - case cAtan: - case cAtan2: - AddCompiledByte(cDeg); + std::pair > tmp + (NamePtr(new char[i->first.nameLength], i->first.nameLength), + i->second ); + memcpy(const_cast(tmp.first.name), i->first.name, + tmp.first.nameLength); + mNamePtrs.insert(mNamePtrs.end(), tmp); } + } } -inline void FunctionParser::incStackPtr() +template +FunctionParserBase::Data::~Data() { - if(++StackPtr > data->StackSize) ++(data->StackSize); + for(typename NamePtrsMap::iterator i = mNamePtrs.begin(); + i != mNamePtrs.end(); + ++i) + { + if(i->second.type != NameData::VARIABLE) + delete[] i->first.name; + } } +template +void FunctionParserBase::incFuncWrapperRefCount +(FunctionWrapper* wrapper) +{ + ++wrapper->mReferenceCount; +} -// Compile if() -int FunctionParser::CompileIf(const char* F, int ind) +template +unsigned FunctionParserBase::decFuncWrapperRefCount +(FunctionWrapper* wrapper) { - int ind2 = CompileExpression(F, ind, true); // condition - sws(F, ind2); - if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; } - AddCompiledByte(cIf); - unsigned curByteCodeSize = tempByteCode->size(); - AddCompiledByte(0); // Jump index; to be set later - AddCompiledByte(0); // Immed jump index; to be set later + return --wrapper->mReferenceCount; +} - --StackPtr; +template +FunctionParserBase::Data::FuncWrapperPtrData::FuncWrapperPtrData(): + mRawFuncPtr(0), mFuncWrapperPtr(0), mParams(0) +{} - ind2 = CompileExpression(F, ind2+1, true); // then - sws(F, ind2); - if(F[ind2] != ',') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; } - AddCompiledByte(cJump); - unsigned curByteCodeSize2 = tempByteCode->size(); - unsigned curImmedSize2 = tempImmed->size(); - AddCompiledByte(0); // Jump index; to be set later - AddCompiledByte(0); // Immed jump index; to be set later +template +FunctionParserBase::Data::FuncWrapperPtrData::~FuncWrapperPtrData() +{ + if(mFuncWrapperPtr && + FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0) + delete mFuncWrapperPtr; +} - --StackPtr; +template +FunctionParserBase::Data::FuncWrapperPtrData::FuncWrapperPtrData +(const FuncWrapperPtrData& rhs): + mRawFuncPtr(rhs.mRawFuncPtr), + mFuncWrapperPtr(rhs.mFuncWrapperPtr), + mParams(rhs.mParams) +{ + if(mFuncWrapperPtr) + FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr); +} - ind2 = CompileExpression(F, ind2+1, true); // else - sws(F, ind2); - if(F[ind2] != ')') { parseErrorType=ILL_PARAMS_AMOUNT; return ind2; } +template +typename FunctionParserBase::Data::FuncWrapperPtrData& +FunctionParserBase::Data::FuncWrapperPtrData::operator= +(const FuncWrapperPtrData& rhs) +{ + if(&rhs != this) + { + if(mFuncWrapperPtr && + FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0) + delete mFuncWrapperPtr; + mRawFuncPtr = rhs.mRawFuncPtr; + mFuncWrapperPtr = rhs.mFuncWrapperPtr; + mParams = rhs.mParams; + if(mFuncWrapperPtr) + FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr); + } + return *this; +} - // Set jump indices - (*tempByteCode)[curByteCodeSize] = curByteCodeSize2+1; - (*tempByteCode)[curByteCodeSize+1] = curImmedSize2; - (*tempByteCode)[curByteCodeSize2] = tempByteCode->size()-1; - (*tempByteCode)[curByteCodeSize2+1] = tempImmed->size(); - return ind2+1; +//========================================================================= +// FunctionParser constructors, destructor and assignment +//========================================================================= +template +FunctionParserBase::FunctionParserBase(): + mData(new Data), + mStackPtr(0) +{ } -int FunctionParser::CompileFunctionParams(const char* F, int ind, - unsigned requiredParams) +template +FunctionParserBase::~FunctionParserBase() { - int ind2 = ind; - if(requiredParams > 0) - { - unsigned curStackPtr = StackPtr; - ind2 = CompileExpression(F, ind); + if(--(mData->mReferenceCounter) == 0) + delete mData; +} - if(StackPtr != curStackPtr+requiredParams) - { parseErrorType=ILL_PARAMS_AMOUNT; return ind; } +template +FunctionParserBase::FunctionParserBase(const FunctionParserBase& cpy): + mData(cpy.mData), + mStackPtr(0) +{ + ++(mData->mReferenceCounter); +} - StackPtr -= requiredParams - 1; - } - else +template +FunctionParserBase& +FunctionParserBase::operator=(const FunctionParserBase& cpy) +{ + if(mData != cpy.mData) { - incStackPtr(); + if(--(mData->mReferenceCounter) == 0) delete mData; + + mData = cpy.mData; + ++(mData->mReferenceCounter); } + return *this; +} - sws(F, ind2); - return ind2+1; // F[ind2] is ')' +template +typename FunctionParserBase::Data* +FunctionParserBase::getParserData() +{ + return mData; } -// Compiles element -int FunctionParser::CompileElement(const char* F, int ind) +template +void FunctionParserBase::setDelimiterChar(char c) { - sws(F, ind); - char c = F[ind]; + mData->mDelimiterChar = c; +} - if(c == '(') - { - ind = CompileExpression(F, ind+1); - sws(F, ind); - return ind+1; // F[ind] is ')' - } - if(isdigit(c) || c=='.' /*|| c=='-'*/) // Number +//--------------------------------------------------------------------------- +// Copy-on-write method +//--------------------------------------------------------------------------- +template +void FunctionParserBase::CopyOnWrite() +{ + if(mData->mReferenceCounter > 1) { - const char* startPtr = &F[ind]; - char* endPtr; - double val = strtod(startPtr, &endPtr); - AddImmediate(val); - AddCompiledByte(cImmed); - incStackPtr(); - return ind+(endPtr-startPtr); + Data* oldData = mData; + mData = new Data(*oldData); + --(oldData->mReferenceCounter); + mData->mReferenceCounter = 1; } +} - if(isalpha(c) || c == '_') // Function, variable or constant - { - const FuncDefinition* func = FindFunction(F+ind); - if(func) // is function - { - int ind2 = ind + func->nameLength; - sws(F, ind2); // F[ind2] is '(' - if(strcmp(func->name, "if") == 0) // "if" is a special case - { - return CompileIf(F, ind2+1); - } +template +void FunctionParserBase::ForceDeepCopy() +{ + CopyOnWrite(); +} -#ifndef DISABLE_EVAL - unsigned requiredParams = - strcmp(func->name, "eval") == 0 ? - data->Variables.size() : func->params; -#else - unsigned requiredParams = func->params; -#endif - ind2 = CompileFunctionParams(F, ind2+1, requiredParams); - AddFunctionOpcode(func->opcode); - return ind2; // F[ind2-1] is ')' - } - Data::VarMap_t::const_iterator vIter = - FindVariable(F+ind, data->Variables); - if(vIter != data->Variables.end()) // is variable - { - AddCompiledByte(vIter->second); - incStackPtr(); - return ind + vIter->first.size(); - } +//========================================================================= +// Epsilon +//========================================================================= +template<> double FunctionParserBase::sEpsilon = 1E-12; +template<> float FunctionParserBase::sEpsilon = 1E-5F; +template<> long double FunctionParserBase::sEpsilon = 1E-14L; +template<> long FunctionParserBase::sEpsilon = 0; - Data::ConstMap_t::const_iterator cIter = - FindConstant(F+ind, data->Constants); - if(cIter != data->Constants.end()) // is constant - { - AddImmediate(cIter->second); - AddCompiledByte(cImmed); - incStackPtr(); - return ind + cIter->first.size(); - } +template<> std::complex +FunctionParserBase >::sEpsilon = 1E-12; - Data::VarMap_t::const_iterator fIter = - FindVariable(F+ind, data->FuncPtrNames); - if(fIter != data->FuncPtrNames.end()) // is user-defined func pointer - { - unsigned index = fIter->second; +template<> std::complex +FunctionParserBase >::sEpsilon = 1E-5F; - int ind2 = ind + fIter->first.length(); - sws(F, ind2); // F[ind2] is '(' +template<> std::complex +FunctionParserBase >::sEpsilon = 1E-14L; - ind2 = CompileFunctionParams(F, ind2+1, - data->FuncPtrs[index].params); +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +template<> MpfrFloat +FunctionParserBase::sEpsilon(MpfrFloat::someEpsilon()); +#endif - AddCompiledByte(cFCall); - AddCompiledByte(index); - return ind2; - } +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> GmpInt FunctionParserBase::sEpsilon = 0; +#endif - Data::VarMap_t::const_iterator pIter = - FindVariable(F+ind, data->FuncParserNames); - if(pIter != data->FuncParserNames.end()) // is user-defined func parser - { - unsigned index = pIter->second; +template +Value_t FunctionParserBase::epsilon() +{ + return sEpsilon; +} + +template +void FunctionParserBase::setEpsilon(Value_t value) +{ + sEpsilon = value; +} - int ind2 = ind + pIter->first.length(); - sws(F, ind2); // F[ind2] is '(' - ind2 = CompileFunctionParams - (F, ind2+1, data->FuncParsers[index]->data->varAmount); +//========================================================================= +// User-defined identifier addition functions +//========================================================================= +template +bool FunctionParserBase::AddConstant(const std::string& name, + Value_t value) +{ + if(!containsOnlyValidIdentifierChars(name)) return false; - AddCompiledByte(cPCall); - AddCompiledByte(index); - return ind2; - } - } + CopyOnWrite(); + std::pair > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData(NameData::CONSTANT, value)); - parseErrorType = UNEXPECTED_ERROR; - return ind; + return addNewNameData(mData->mNamePtrs, newName, false); } -// Compiles a unit factor possibly appearing after an element -int FunctionParser::CompilePossibleUnit(const char* F, int ind) +template +bool FunctionParserBase::AddUnit(const std::string& name, + Value_t value) { - if(isalpha(F[ind]) || F[ind] == '_') - { - // If the syntax checker is bug-free, this should always work: - Data::ConstMap_t::const_iterator uIter = - FindConstant(F+ind, data->Units); + if(!containsOnlyValidIdentifierChars(name)) return false; - AddImmediate(uIter->second); - AddCompiledByte(cImmed); - incStackPtr(); - AddCompiledByte(cMul); - --StackPtr; - ind += uIter->first.size(); - sws(F, ind); - } - return ind; + CopyOnWrite(); + std::pair > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData(NameData::UNIT, value)); + return addNewNameData(mData->mNamePtrs, newName, false); } -// Compiles '^' -int FunctionParser::CompilePow(const char* F, int ind) +template +bool FunctionParserBase::AddFunction +(const std::string& name, FunctionPtr ptr, unsigned paramsAmount) { - int ind2 = CompileElement(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - ind2 = CompilePossibleUnit(F, ind2); + if(!containsOnlyValidIdentifierChars(name)) return false; - while(F[ind2] == '^') + CopyOnWrite(); + std::pair > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData(NameData::FUNC_PTR, + unsigned(mData->mFuncPtrs.size()))); + + const bool success = addNewNameData(mData->mNamePtrs, newName, false); + if(success) { - ind2 = CompileUnaryMinus(F, ind2+1); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - AddCompiledByte(cPow); - --StackPtr; + mData->mFuncPtrs.push_back(typename Data::FuncWrapperPtrData()); + mData->mFuncPtrs.back().mRawFuncPtr = ptr; + mData->mFuncPtrs.back().mParams = paramsAmount; } + return success; +} - return ind2; +template +bool FunctionParserBase::addFunctionWrapperPtr +(const std::string& name, FunctionWrapper* wrapper, unsigned paramsAmount) +{ + if(!AddFunction(name, FunctionPtr(0), paramsAmount)) return false; + mData->mFuncPtrs.back().mFuncWrapperPtr = wrapper; + return true; } -// Compiles unary '-' -int FunctionParser::CompileUnaryMinus(const char* F, int ind) +template +typename FunctionParserBase::FunctionWrapper* +FunctionParserBase::GetFunctionWrapper(const std::string& name) { - sws(F, ind); - if(F[ind] == '-' || F[ind] == '!') + CopyOnWrite(); + NamePtr namePtr(name.data(), unsigned(name.size())); + + typename NamePtrsMap::iterator nameIter = + mData->mNamePtrs.find(namePtr); + + if(nameIter != mData->mNamePtrs.end() && + nameIter->second.type == NameData::FUNC_PTR) { - int ind2 = ind+1; - sws(F, ind2); - ind2 = CompilePow(F, ind2); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); + return mData->mFuncPtrs[nameIter->second.index].mFuncWrapperPtr; + } + return 0; +} - // if we are negating a constant, negate the constant itself: - if(F[ind] == '-' && tempByteCode->back() == cImmed) - tempImmed->back() = -tempImmed->back(); +template +bool FunctionParserBase::CheckRecursiveLinking +(const FunctionParserBase* fp) const +{ + if(fp == this) return true; + for(unsigned i = 0; i < fp->mData->mFuncParsers.size(); ++i) + if(CheckRecursiveLinking(fp->mData->mFuncParsers[i].mParserPtr)) + return true; + return false; +} - // if we are negating a negation, we can remove both: - else if((F[ind] == '-' && tempByteCode->back() == cNeg)) - tempByteCode->pop_back(); +template +bool FunctionParserBase::AddFunction(const std::string& name, + FunctionParserBase& fp) +{ + if(!containsOnlyValidIdentifierChars(name) || + CheckRecursiveLinking(&fp)) + return false; - else - AddCompiledByte(F[ind] == '-' ? cNeg : cNot); + CopyOnWrite(); + std::pair > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData(NameData::PARSER_PTR, + unsigned(mData->mFuncParsers.size()))); - return ind2; + const bool success = addNewNameData(mData->mNamePtrs, newName, false); + if(success) + { + mData->mFuncParsers.push_back(typename Data::FuncParserPtrData()); + mData->mFuncParsers.back().mParserPtr = &fp; + mData->mFuncParsers.back().mParams = fp.mData->mVariablesAmount; } - - int ind2 = CompilePow(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - return ind2; + return success; } -// Compiles '*', '/' and '%' -int FunctionParser::CompileMult(const char* F, int ind) +template +bool FunctionParserBase::RemoveIdentifier(const std::string& name) { - int ind2 = CompileUnaryMinus(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - char op; + CopyOnWrite(); + + NamePtr namePtr(name.data(), unsigned(name.size())); - while((op = F[ind2]) == '*' || op == '/' || op == '%') + typename NamePtrsMap::iterator nameIter = + mData->mNamePtrs.find(namePtr); + + if(nameIter != mData->mNamePtrs.end()) { - ind2 = CompileUnaryMinus(F, ind2+1); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - switch(op) + if(nameIter->second.type == NameData::VARIABLE) { - case '*': AddCompiledByte(cMul); break; - case '/': AddCompiledByte(cDiv); break; - case '%': AddCompiledByte(cMod); break; + // Illegal attempt to delete variables + return false; } - --StackPtr; + delete[] nameIter->first.name; + mData->mNamePtrs.erase(nameIter); + return true; } - - return ind2; + return false; } -// Compiles '+' and '-' -int FunctionParser::CompileAddition(const char* F, int ind) + +//========================================================================= +// Function parsing +//========================================================================= +namespace { - int ind2 = CompileMult(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - char op; + // Error messages returned by ErrorMsg(): + const char* const ParseErrorMessage[]= + { + "Syntax error", // 0 + "Mismatched parenthesis", // 1 + "Missing ')'", // 2 + "Empty parentheses", // 3 + "Syntax error: Operator expected", // 4 + "Not enough memory", // 5 + "An unexpected error occurred. Please make a full bug report " + "to the author", // 6 + "Syntax error in parameter 'Vars' given to " + "FunctionParser::Parse()", // 7 + "Illegal number of parameters to function", // 8 + "Syntax error: Premature end of string", // 9 + "Syntax error: Expecting ( after function", // 10 + "Syntax error: Unknown identifier", // 11 + "(No function has been parsed yet)", + "" + }; + + template + inline typename FunctionParserBase::ParseErrorType + noCommaError(char c) + { + return c == ')' ? + FunctionParserBase::ILL_PARAMS_AMOUNT : + FunctionParserBase::SYNTAX_ERROR; + } + + template + inline typename FunctionParserBase::ParseErrorType + noParenthError(char c) + { + return c == ',' ? + FunctionParserBase::ILL_PARAMS_AMOUNT : + FunctionParserBase::MISSING_PARENTH; + } + + template + 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 + struct LiteralMask + { + enum { mask = + ( 1UL << ('.'-offset)) | + IntLiteralMask::mask }; + }; +#ifdef FP_SUPPORT_LONG_INT_TYPE + template + struct LiteralMask: public IntLiteralMask + { + }; +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE + template + struct LiteralMask: public IntLiteralMask + { + }; +#endif + + template + struct SimpleSpaceMask + { + enum { mask = + (1UL << ('\r'-offset)) | + (1UL << ('\n'-offset)) | + (1UL << ('\v'-offset)) | + (1UL << ('\t'-offset)) | + (1UL << (' ' -offset)) }; + }; - while((op = F[ind2]) == '+' || op == '-') + template + inline bool BeginsLiteral(unsigned byte) { - ind2 = CompileMult(F, ind2+1); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - AddCompiledByte(op=='+' ? cAdd : cSub); - --StackPtr; + enum { n = sizeof(unsigned long)>=8 ? 0 : '.' }; + byte -= n; + if(byte > (unsigned char)('9'-n)) return false; + unsigned long shifted = 1UL << byte; + const unsigned long mask = LiteralMask::mask; + return (mask & shifted) != 0; } - return ind2; + template + 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::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 +const char* FunctionParserBase::ErrorMsg() const +{ + return ParseErrorMessage[mData->mParseErrorType]; +} + +template +typename FunctionParserBase::ParseErrorType +FunctionParserBase::GetParseErrorType() const +{ + return mData->mParseErrorType; +} + +template +int FunctionParserBase::EvalError() const +{ + return mData->mEvalErrorType; } -// Compiles '=', '<' and '>' -int FunctionParser::CompileComparison(const char* F, int ind) + +// --------------------------------------------------------------------------- +// Parse variables +// --------------------------------------------------------------------------- +template +bool FunctionParserBase::ParseVariables +(const std::string& inputVarString) { - int ind2 = CompileAddition(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - char op; + if(mData->mVariablesString == inputVarString) return true; - while((op = F[ind2]) == '=' || op == '<' || op == '>' || op == '!') + /* Delete existing variables from mNamePtrs */ + for(typename NamePtrsMap::iterator i = + mData->mNamePtrs.begin(); + i != mData->mNamePtrs.end(); ) { - int opSize = (F[ind2+1] == '=' ? 2 : 1); - ind2 = CompileAddition(F, ind2+opSize); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - switch(op) + if(i->second.type == NameData::VARIABLE) { - case '=': - AddCompiledByte(cEqual); break; - case '<': - AddCompiledByte(opSize == 1 ? cLess : cLessOrEq); break; - case '>': - AddCompiledByte(opSize == 1 ? cGreater : cGreaterOrEq); break; - case '!': - AddCompiledByte(cNEqual); break; + typename NamePtrsMap::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(beginPtr); + if(nameLength == 0 || (nameLength & 0x80000000U)) return false; + const char* endPtr = beginPtr + nameLength; + SkipSpace(endPtr); + if(endPtr != finalPtr && *endPtr != ',') return false; + + std::pair > newName + (NamePtr(beginPtr, nameLength), + NameData(NameData::VARIABLE, varNumber++)); + + if(!addNewNameData(mData->mNamePtrs, newName, true)) + { + return false; } - --StackPtr; + + beginPtr = endPtr + 1; } - return ind2; + mData->mVariablesAmount = varNumber - VarBegin; + return true; } -// Compiles '&' -int FunctionParser::CompileAnd(const char* F, int ind) +// --------------------------------------------------------------------------- +// Parse() public interface functions +// --------------------------------------------------------------------------- +template +int FunctionParserBase::Parse(const char* Function, + const std::string& Vars, + bool useDegrees) { - int ind2 = CompileComparison(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); + CopyOnWrite(); - while(F[ind2] == '&') + if(!ParseVariables(Vars)) { - ind2 = CompileComparison(F, ind2+1); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - AddCompiledByte(cAnd); - --StackPtr; + mData->mParseErrorType = INVALID_VARS; + return int(strlen(Function)); } - return ind2; + return ParseFunction(Function, useDegrees); } -// Compiles '|' -int FunctionParser::CompileOr(const char* F, int ind) +template +int FunctionParserBase::Parse(const std::string& Function, + const std::string& Vars, + bool useDegrees) { - int ind2 = CompileAnd(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); + CopyOnWrite(); - while(F[ind2] == '|') + if(!ParseVariables(Vars)) { - ind2 = CompileAnd(F, ind2+1); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); - AddCompiledByte(cOr); - --StackPtr; + mData->mParseErrorType = INVALID_VARS; + return int(Function.size()); } - return ind2; + return ParseFunction(Function.c_str(), useDegrees); } -// Compiles ',' -int FunctionParser::CompileExpression(const char* F, int ind, bool stopAtComma) + +// --------------------------------------------------------------------------- +// Main parsing function +// --------------------------------------------------------------------------- +template +int FunctionParserBase::ParseFunction(const char* function, + bool useDegrees) { - int ind2 = CompileOr(F, ind); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); + mData->mUseDegreeConversion = useDegrees; + mData->mParseErrorType = FP_NO_ERROR; + + mData->mInlineVarNames.clear(); + mData->mByteCode.clear(); mData->mByteCode.reserve(128); + mData->mImmed.clear(); mData->mImmed.reserve(128); + mData->mStackSize = mStackPtr = 0; + + mData->mHasByteCodeFlags = false; + + const char* ptr = Compile(function); + mData->mInlineVarNames.clear(); + + if(mData->mHasByteCodeFlags) + { + for(unsigned i = unsigned(mData->mByteCode.size()); i-- > 0; ) + mData->mByteCode[i] &= ~FP_ParamGuardMask; + } - if(stopAtComma) return ind2; + if(mData->mParseErrorType != FP_NO_ERROR) + return int(mData->mErrorLocation - function); - while(F[ind2] == ',') + assert(ptr); // Should never be null at this point. It's a bug otherwise. + if(*ptr) { - ind2 = CompileOr(F, ind2+1); - if(parseErrorType != FP_NO_ERROR) return ind2; - sws(F, ind2); + if(mData->mDelimiterChar == 0 || *ptr != mData->mDelimiterChar) + mData->mParseErrorType = EXPECT_OPERATOR; + return int(ptr - function); } - return ind2; +#ifndef FP_USE_THREAD_SAFE_EVAL + mData->mStack.resize(mData->mStackSize); +#endif + + return -1; } -// Return parse error message -// -------------------------- -const char* FunctionParser::ErrorMsg() const +//========================================================================= +// Parsing and bytecode compiling functions +//========================================================================= +template +inline const char* FunctionParserBase::SetErrorType(ParseErrorType t, + const char* pos) { - if(parseErrorType != FP_NO_ERROR) return ParseErrorMessage[parseErrorType]; + mData->mParseErrorType = t; + mData->mErrorLocation = pos; return 0; } -//--------------------------------------------------------------------------- -// Function evaluation -//--------------------------------------------------------------------------- -//=========================================================================== +template +inline void FunctionParserBase::incStackPtr() +{ + if(++mStackPtr > mData->mStackSize) ++(mData->mStackSize); +} + namespace { - inline int doubleToInt(double d) + const unsigned char powi_factor_table[128] = { - return d<0 ? -int((-d)+.5) : int(d+.5); - } + 0,1,0,0,0,0,0,0, 0, 0,0,0,0,0,0,3,/* 0 - 15 */ + 0,0,0,0,0,0,0,0, 0, 5,0,3,0,0,3,0,/* 16 - 31 */ + 0,0,0,0,0,0,0,3, 0, 0,0,0,0,5,0,0,/* 32 - 47 */ + 0,0,5,3,0,0,3,5, 0, 3,0,0,3,0,0,3,/* 48 - 63 */ + 0,0,0,0,0,0,0,0, 0, 0,0,3,0,0,3,0,/* 64 - 79 */ + 0,9,0,0,0,5,0,3, 0, 0,5,7,0,0,0,5,/* 80 - 95 */ + 0,0,0,3,5,0,3,0, 0, 3,0,0,3,0,5,3,/* 96 - 111 */ + 0,0,3,5,0,9,0,7, 3,11,0,3,0,5,3,0,/* 112 - 127 */ + }; - inline double Min(double d1, double d2) + inline int get_powi_factor(long abs_int_exponent) { - return d1= int(sizeof(powi_factor_table))) return 0; + return powi_factor_table[abs_int_exponent]; } - inline double Max(double d1, double d2) + +#if 0 + int EstimatePowiComplexity(int abs_int_exponent) { - return d1>d2 ? d1 : d2; + int cost = 0; + while(abs_int_exponent > 1) + { + int factor = get_powi_factor(abs_int_exponent); + if(factor) + { + cost += EstimatePowiComplexity(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + cost += 3; // sqr + } + else + { + cost += 4; // dup+mul + abs_int_exponent -= 1; + } + } + return cost; } +#endif - - inline double DegreesToRadians(double degrees) + bool IsEligibleIntPowiExponent(long int_exponent) { - return degrees*(M_PI/180.0); + if(int_exponent == 0) return false; + long abs_int_exponent = int_exponent; + #if 0 + int cost = 0; + + if(abs_int_exponent < 0) + { + cost += 11; + abs_int_exponent = -abs_int_exponent; + } + + cost += EstimatePowiComplexity(abs_int_exponent); + + return cost < (10*3 + 4*4); + #else + if(abs_int_exponent < 0) abs_int_exponent = -abs_int_exponent; + + return (abs_int_exponent >= 1) + && (abs_int_exponent <= 46 || + (abs_int_exponent <= 1024 && + (abs_int_exponent & (abs_int_exponent - 1)) == 0)); + #endif } - inline double RadiansToDegrees(double radians) + + /* Needed by fp_opcode_add.inc if tracing is enabled */ + template + std::string findName(const NamePtrsMap& nameMap, + unsigned index, + typename NameData::DataType type) { - return radians*(180.0/M_PI); + for(typename NamePtrsMap::const_iterator + iter = nameMap.begin(); + iter != nameMap.end(); + ++iter) + { + if(iter->second.type == type && iter->second.index == index) + return std::string(iter->first.name, + iter->first.name + iter->first.nameLength); + } + return "?"; } } -double FunctionParser::Eval(const double* Vars) +template +inline void FunctionParserBase::AddImmedOpcode(Value_t value) { - const unsigned* const ByteCode = data->ByteCode; - const double* const Immed = data->Immed; - const unsigned ByteCodeSize = data->ByteCodeSize; - unsigned IP, DP=0; - int SP=-1; - -#ifdef FP_USE_THREAD_SAFE_EVAL -#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA - double* const Stack = (double*)alloca(data->StackSize*sizeof(double)); -#else - std::vector Stack(data->StackSize); -#endif -#else - double* const Stack = data->Stack; -#endif + mData->mImmed.push_back(value); + mData->mByteCode.push_back(cImmed); +} - for(IP=0; IP +inline void FunctionParserBase::CompilePowi(long abs_int_exponent) +{ + int num_muls=0; + while(abs_int_exponent > 1) { - switch(ByteCode[IP]) + long factor = get_powi_factor(abs_int_exponent); + if(factor) { -// Functions: - case cAbs: Stack[SP] = fabs(Stack[SP]); break; - case cAcos: if(Stack[SP] < -1 || Stack[SP] > 1) - { evalErrorType=4; return 0; } - Stack[SP] = acos(Stack[SP]); break; -#ifndef NO_ASINH - case cAcosh: Stack[SP] = acosh(Stack[SP]); break; -#endif - case cAsin: if(Stack[SP] < -1 || Stack[SP] > 1) - { evalErrorType=4; return 0; } - Stack[SP] = asin(Stack[SP]); break; -#ifndef NO_ASINH - case cAsinh: Stack[SP] = asinh(Stack[SP]); break; -#endif - case cAtan: Stack[SP] = atan(Stack[SP]); break; - case cAtan2: Stack[SP-1] = atan2(Stack[SP-1], Stack[SP]); - --SP; break; -#ifndef NO_ASINH - case cAtanh: Stack[SP] = atanh(Stack[SP]); break; -#endif - case cCeil: Stack[SP] = ceil(Stack[SP]); break; - case cCos: Stack[SP] = cos(Stack[SP]); break; - case cCosh: Stack[SP] = cosh(Stack[SP]); break; + CompilePowi(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + mData->mByteCode.push_back(cSqr); + // ^ Don't put AddFunctionOpcode here, + // it would slow down a great deal. + } + else + { + mData->mByteCode.push_back(cDup); + incStackPtr(); + abs_int_exponent -= 1; + ++num_muls; + } + } + if(num_muls > 0) + { + mData->mByteCode.resize(mData->mByteCode.size()+num_muls, cMul); + mStackPtr -= num_muls; + } +} + +template +inline bool FunctionParserBase::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 +inline void FunctionParserBase::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::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::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 >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex 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 >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex 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 >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex 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 +unsigned +FunctionParserBase::ParseIdentifier(const char* function) +{ + return readIdentifier(function); +} + +template +std::pair +FunctionParserBase::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(function+2, &endptr); + if(endptr == function+2) + return std::pair (function, Value_t()); + return std::pair (endptr, val); + } +#endif + Value_t val = fp_parseLiteral(function, &endptr); + + if(endptr == function+1 && function[0] == '0' && function[1] == 'x') + { + // Parse hexadecimal literal if fp_parseLiteral didn't already + val = parseHexLiteral(function+2, &endptr); + if(endptr == function+2) + return std::pair (function, Value_t()); + } + else if(endptr == function) + return std::pair (function, Value_t()); + + return std::pair (endptr, val); +} + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +template<> +std::pair +FunctionParserBase::ParseLiteral(const char* function) +{ + char* endPtr; + const MpfrFloat val = MpfrFloat::parseString(function, &endPtr); + if(endPtr == function) + return std::pair (function, MpfrFloat()); + return std::pair (endPtr, val); +} +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> +std::pair +FunctionParserBase::ParseLiteral(const char* function) +{ + char* endPtr; + const GmpInt val = GmpInt::parseString(function, &endPtr); + if(endPtr == function) + return std::pair (function, GmpInt()); + return std::pair (endPtr, val); +} +#endif + + +template +inline const char* +FunctionParserBase::CompileLiteral(const char* function) +{ + std::pair result = ParseLiteral(function); + + if(result.first == function) + return SetErrorType(SYNTAX_ERROR, result.first); + + AddImmedOpcode(result.second); + incStackPtr(); + SkipSpace(result.first); + return result.first; +} + +template +const char* FunctionParserBase::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(*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= 0.5, + // cAbsIf simply tests whether cond >= 0.5. + opcode = cAbsIf; + } + + mData->mByteCode.push_back(opcode); + const unsigned curByteCodeSize = unsigned(mData->mByteCode.size()); + PushOpcodeParam(0); // Jump index; to be set later + PushOpcodeParam (0); // Immed jump index; to be set later + + --mStackPtr; + + function = CompileExpression(function + 1); + if(!function) return 0; + if(*function != ',') + return SetErrorType(noCommaError(*function), function); + + mData->mByteCode.push_back(cJump); + const unsigned curByteCodeSize2 = unsigned(mData->mByteCode.size()); + const unsigned curImmedSize2 = unsigned(mData->mImmed.size()); + PushOpcodeParam(0); // Jump index; to be set later + PushOpcodeParam (0); // Immed jump index; to be set later + + --mStackPtr; + + function = CompileExpression(function + 1); + if(!function) return 0; + if(*function != ')') + return SetErrorType(noParenthError(*function), function); + + PutOpcodeParamAt ( 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( curByteCodeSize2+1, curByteCodeSize ); + PutOpcodeParamAt( curImmedSize2, curByteCodeSize+1 ); + PutOpcodeParamAt( unsigned(mData->mByteCode.size())-1, curByteCodeSize2); + PutOpcodeParamAt( unsigned(mData->mImmed.size()), curByteCodeSize2+1); + + ++function; + SkipSpace(function); + return function; +} + +template +const char* FunctionParserBase::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(*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(*function), function); + ++function; + SkipSpace(function); + return function; +} + +template +const char* FunctionParserBase::CompileElement(const char* function) +{ + if(BeginsLiteral( (unsigned char) *function)) + return CompileLiteral(function); + + unsigned nameLength = readIdentifier(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::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(iter->mFetchIndex); + } + incStackPtr(); + return endPtr; + } + } + + return SetErrorType(UNKNOWN_IDENTIFIER, function); + } + + const NameData* nameData = &nameIter->second; + switch(nameData->type) + { + case NameData::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::CONSTANT: // is constant + AddImmedOpcode(nameData->value); + incStackPtr(); + return endPtr; + + case NameData::UNIT: // is unit (error if appears here) + break; + + case NameData::FUNC_PTR: // is C++ function + function = CompileFunctionParams + (endPtr, mData->mFuncPtrs[nameData->index].mParams); + //if(!function) return 0; + mData->mByteCode.push_back(cFCall); + PushOpcodeParam(nameData->index); + return function; + + case NameData::PARSER_PTR: // is FunctionParser + function = CompileFunctionParams + (endPtr, mData->mFuncParsers[nameData->index].mParams); + //if(!function) return 0; + mData->mByteCode.push_back(cPCall); + PushOpcodeParam(nameData->index); + return function; + } + + // When it's an unit (or unrecognized type): + return SetErrorType(SYNTAX_ERROR, function); +} + +template +inline const char* FunctionParserBase::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 +inline const char* +FunctionParserBase::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 +const char* +FunctionParserBase::CompilePossibleUnit(const char* function) +{ + unsigned nameLength = readIdentifier(function); + if(nameLength & 0x80000000U) return function; // built-in function name + if(nameLength != 0) + { + NamePtr name(function, nameLength); + + typename NamePtrsMap::iterator nameIter = + mData->mNamePtrs.find(name); + if(nameIter != mData->mNamePtrs.end()) + { + const NameData* nameData = &nameIter->second; + if(nameData->type == NameData::UNIT) + { + AddImmedOpcode(nameData->value); + incStackPtr(); + AddFunctionOpcode(cMul); + --mStackPtr; + + const char* endPtr = function + nameLength; + SkipSpace(endPtr); + return endPtr; + } + } + } + + return function; +} + +template +inline const char* +FunctionParserBase::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()) + { 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::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::CompilePow(const char* function) +{ + function = CompileElement(function); + if(!function) return 0; + return CompilePossibleUnit(function); +} +#endif + +template +inline const char* +FunctionParserBase::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 +inline const char* +FunctionParserBase::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::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::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::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 +inline const char* +FunctionParserBase::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 +inline const char* +FunctionParserBase::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 +inline const char* FunctionParserBase::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 +const char* FunctionParserBase::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 +const char* FunctionParserBase::Compile(const char* function) +{ + while(true) + { + // Check if an identifier appears as first token: + SkipSpace(function); + unsigned nameLength = readIdentifier(function); + if(nameLength > 0 && !(nameLength & 0x80000000U)) + { + typename Data::InlineVariable inlineVar = + { NamePtr(function, nameLength), 0 }; + + // Check if it's an unknown identifier: + typename NamePtrsMap::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 template +inline void FunctionParserBase::PushOpcodeParam + (unsigned value) +{ + mData->mByteCode.push_back(value | (PutFlag ? FP_ParamGuardMask : 0u)); + if(PutFlag) mData->mHasByteCodeFlags = true; +} + +template template +inline void FunctionParserBase::PutOpcodeParamAt + (unsigned value, unsigned offset) +{ + mData->mByteCode[offset] = value | (PutFlag ? FP_ParamGuardMask : 0u); + if(PutFlag) mData->mHasByteCodeFlags = true; +} + +//=========================================================================== +// Function evaluation +//=========================================================================== +template +Value_t FunctionParserBase::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& Stack = mData->mStack; +#endif + + for(IP=0; IP::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::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::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::result + ? (Stack[SP] == Value_t(-1) || Stack[SP] == Value_t(1)) + : (Stack[SP] <= Value_t(-1) || Stack[SP] >= Value_t(1))) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_atanh(Stack[SP]); break; + + case cCbrt: Stack[SP] = fp_cbrt(Stack[SP]); break; + + case cCeil: Stack[SP] = fp_ceil(Stack[SP]); break; + + case cCos: Stack[SP] = fp_cos(Stack[SP]); break; + + case cCosh: Stack[SP] = fp_cosh(Stack[SP]); break; case cCot: { - double t = tan(Stack[SP]); - if(t == 0) { evalErrorType=1; return 0; } - Stack[SP] = 1/t; break; + const Value_t t = fp_tan(Stack[SP]); + if(t == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/t; break; } + case cCsc: { - double s = sin(Stack[SP]); - if(s == 0) { evalErrorType=1; return 0; } - Stack[SP] = 1/s; break; + const Value_t s = fp_sin(Stack[SP]); + if(s == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/s; break; } -#ifndef DISABLE_EVAL - case cEval: - { - double retVal = 0; - if(evalRecursionLevel == EVAL_MAX_REC_LEVEL) - { - evalErrorType = 5; - } + case cExp: Stack[SP] = fp_exp(Stack[SP]); break; + + case cExp2: Stack[SP] = fp_exp2(Stack[SP]); break; + + case cFloor: Stack[SP] = fp_floor(Stack[SP]); break; + + case cHypot: + Stack[SP-1] = fp_hypot(Stack[SP-1], Stack[SP]); + --SP; break; + + case cIf: + if(fp_truth(Stack[SP--])) + IP += 2; else { -#ifndef FP_USE_THREAD_SAFE_EVAL - data->Stack = new double[data->StackSize]; -#endif - ++evalRecursionLevel; - retVal = Eval(&Stack[SP-data->varAmount+1]); - --evalRecursionLevel; -#ifndef FP_USE_THREAD_SAFE_EVAL - delete[] data->Stack; - data->Stack = Stack; -#endif + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; } - SP -= data->varAmount-1; - Stack[SP] = retVal; break; - } -#endif - case cExp: Stack[SP] = exp(Stack[SP]); break; - case cFloor: Stack[SP] = floor(Stack[SP]); break; + case cInt: Stack[SP] = fp_int(Stack[SP]); break; + + case cLog: + if(IsComplexType::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::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log10(Stack[SP]); + break; - case cIf: - { - unsigned jumpAddr = ByteCode[++IP]; - unsigned immedAddr = ByteCode[++IP]; - if(doubleToInt(Stack[SP]) == 0) - { - IP = jumpAddr; - DP = immedAddr; - } - --SP; break; - } + case cLog2: + if(IsComplexType::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log2(Stack[SP]); + break; - case cInt: Stack[SP] = floor(Stack[SP]+.5); break; - case cLog: if(Stack[SP] <= 0) { evalErrorType=3; return 0; } - Stack[SP] = log(Stack[SP]); break; - case cLog10: if(Stack[SP] <= 0) { evalErrorType=3; return 0; } - Stack[SP] = log10(Stack[SP]); break; - case cMax: Stack[SP-1] = Max(Stack[SP-1], Stack[SP]); + case cMax: Stack[SP-1] = fp_max(Stack[SP-1], Stack[SP]); --SP; break; - case cMin: Stack[SP-1] = Min(Stack[SP-1], Stack[SP]); + + case cMin: Stack[SP-1] = fp_min(Stack[SP-1], Stack[SP]); --SP; break; + + case cPow: + // x:Negative ^ y:NonInteger is failure, + // except when the reciprocal of y forms an integer + /*if(IsComplexType::result == false + && Stack[SP-1] < Value_t(0) && + !isInteger(Stack[SP]) && + !isInteger(1.0 / Stack[SP])) + { mEvalErrorType=3; return Value_t(0); }*/ + // x:0 ^ y:negative is failure + if(Stack[SP-1] == Value_t(0) && + Stack[SP] < Value_t(0)) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP-1] = fp_pow(Stack[SP-1], Stack[SP]); + --SP; break; + + case cTrunc: Stack[SP] = fp_trunc(Stack[SP]); break; + case cSec: { - double c = cos(Stack[SP]); - if(c == 0) { evalErrorType=1; return 0; } - Stack[SP] = 1/c; break; + const Value_t c = fp_cos(Stack[SP]); + if(c == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/c; break; } - case cSin: Stack[SP] = sin(Stack[SP]); break; - case cSinh: Stack[SP] = sinh(Stack[SP]); break; - case cSqrt: if(Stack[SP] < 0) { evalErrorType=2; return 0; } - Stack[SP] = sqrt(Stack[SP]); break; - case cTan: Stack[SP] = tan(Stack[SP]); break; - case cTanh: Stack[SP] = tanh(Stack[SP]); break; + + case cSin: Stack[SP] = fp_sin(Stack[SP]); break; + + case cSinh: Stack[SP] = fp_sinh(Stack[SP]); break; + + case cSqrt: + if(IsComplexType::result == false && + Stack[SP] < Value_t(0)) + { mData->mEvalErrorType=2; return Value_t(0); } + Stack[SP] = fp_sqrt(Stack[SP]); break; + + case cTan: Stack[SP] = fp_tan(Stack[SP]); break; + + case cTanh: Stack[SP] = fp_tanh(Stack[SP]); break; // Misc: - case cImmed: Stack[++SP] = Immed[DP++]; break; - case cJump: DP = ByteCode[IP+2]; - IP = ByteCode[IP+1]; - break; + case cImmed: Stack[++SP] = immed[DP++]; break; + + case cJump: + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + break; + } // Operators: case cNeg: Stack[SP] = -Stack[SP]; break; case cAdd: Stack[SP-1] += Stack[SP]; --SP; break; case cSub: Stack[SP-1] -= Stack[SP]; --SP; break; case cMul: Stack[SP-1] *= Stack[SP]; --SP; break; - case cDiv: if(Stack[SP] == 0) { evalErrorType=1; return 0; } - Stack[SP-1] /= Stack[SP]; --SP; break; - case cMod: if(Stack[SP] == 0) { evalErrorType=1; return 0; } - Stack[SP-1] = fmod(Stack[SP-1], Stack[SP]); - --SP; break; - case cPow: Stack[SP-1] = pow(Stack[SP-1], Stack[SP]); - --SP; break; -#ifdef FP_EPSILON - case cEqual: Stack[SP-1] = - (fabs(Stack[SP-1]-Stack[SP]) <= FP_EPSILON); - --SP; break; - case cNEqual: Stack[SP-1] = - (fabs(Stack[SP-1] - Stack[SP]) >= FP_EPSILON); - --SP; break; - case cLess: Stack[SP-1] = (Stack[SP-1] < Stack[SP]-FP_EPSILON); - --SP; break; - case cLessOrEq: Stack[SP-1] = (Stack[SP-1] <= Stack[SP]+FP_EPSILON); - --SP; break; - case cGreater: Stack[SP-1] = (Stack[SP-1]-FP_EPSILON > Stack[SP]); - --SP; break; - case cGreaterOrEq: Stack[SP-1] = - (Stack[SP-1]+FP_EPSILON >= Stack[SP]); - --SP; break; -#else - case cEqual: Stack[SP-1] = (Stack[SP-1] == Stack[SP]); - --SP; break; - case cNEqual: Stack[SP-1] = (Stack[SP-1] != Stack[SP]); - --SP; break; - case cLess: Stack[SP-1] = (Stack[SP-1] < Stack[SP]); - --SP; break; - case cLessOrEq: Stack[SP-1] = (Stack[SP-1] <= Stack[SP]); - --SP; break; - case cGreater: Stack[SP-1] = (Stack[SP-1] > Stack[SP]); - --SP; break; - case cGreaterOrEq: Stack[SP-1] = (Stack[SP-1] >= Stack[SP]); - --SP; break; -#endif + case cDiv: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] /= Stack[SP]; --SP; break; - case cAnd: Stack[SP-1] = - (doubleToInt(Stack[SP-1]) && - doubleToInt(Stack[SP])); - --SP; break; - case cOr: Stack[SP-1] = - (doubleToInt(Stack[SP-1]) || - doubleToInt(Stack[SP])); - --SP; break; - case cNot: Stack[SP] = !doubleToInt(Stack[SP]); break; + case cMod: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] = fp_mod(Stack[SP-1], Stack[SP]); + --SP; break; + + case cEqual: + Stack[SP-1] = fp_equal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cNEqual: + Stack[SP-1] = fp_nequal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLess: + Stack[SP-1] = fp_less(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLessOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP-1], Stack[SP]); + --SP; break; + + case cGreater: + Stack[SP-1] = fp_less(Stack[SP], Stack[SP-1]); + --SP; break; + + case cGreaterOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP], Stack[SP-1]); + --SP; break; + + case cNot: Stack[SP] = fp_not(Stack[SP]); break; + + case cNotNot: Stack[SP] = fp_notNot(Stack[SP]); break; + + case cAnd: + Stack[SP-1] = fp_and(Stack[SP-1], Stack[SP]); + --SP; break; + + case cOr: + Stack[SP-1] = fp_or(Stack[SP-1], Stack[SP]); + --SP; break; // Degrees-radians conversion: case cDeg: Stack[SP] = RadiansToDegrees(Stack[SP]); break; @@ -1302,10 +2869,13 @@ double FunctionParser::Eval(const double* Vars) // User-defined function calls: case cFCall: { - unsigned index = ByteCode[++IP]; - unsigned params = data->FuncPtrs[index].params; - double retVal = - data->FuncPtrs[index].ptr(&Stack[SP-params+1]); + const unsigned index = byteCode[++IP]; + const unsigned params = mData->mFuncPtrs[index].mParams; + const Value_t retVal = + mData->mFuncPtrs[index].mRawFuncPtr ? + mData->mFuncPtrs[index].mRawFuncPtr(&Stack[SP-params+1]) : + mData->mFuncPtrs[index].mFuncWrapperPtr->callFunction + (&Stack[SP-params+1]); SP -= int(params)-1; Stack[SP] = retVal; break; @@ -1313,164 +2883,903 @@ double FunctionParser::Eval(const double* Vars) case cPCall: { - unsigned index = ByteCode[++IP]; - unsigned params = data->FuncParsers[index]->data->varAmount; - double retVal = - data->FuncParsers[index]->Eval(&Stack[SP-params+1]); + unsigned index = byteCode[++IP]; + unsigned params = mData->mFuncParsers[index].mParams; + Value_t retVal = + mData->mFuncParsers[index].mParserPtr->Eval + (&Stack[SP-params+1]); SP -= int(params)-1; Stack[SP] = retVal; + const int error = + mData->mFuncParsers[index].mParserPtr->EvalError(); + if(error) + { + mData->mEvalErrorType = error; + return 0; + } + break; + } + + + case cFetch: + { + unsigned stackOffs = byteCode[++IP]; + Stack[SP+1] = Stack[stackOffs]; ++SP; + break; + } + +#ifdef FP_SUPPORT_OPTIMIZER + case cPopNMov: + { + unsigned stackOffs_target = byteCode[++IP]; + unsigned stackOffs_source = byteCode[++IP]; + Stack[stackOffs_target] = Stack[stackOffs_source]; + SP = stackOffs_target; break; } + case cLog2by: + if(IsComplexType::result + ? Stack[SP-1] == Value_t(0) + : !(Stack[SP-1] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP-1] = fp_log2(Stack[SP-1]) * Stack[SP]; + --SP; + break; + + case cNop: break; +#endif // FP_SUPPORT_OPTIMIZER + + case cSinCos: + fp_sinCos(Stack[SP], Stack[SP+1], Stack[SP]); + ++SP; + break; + case cSinhCosh: + fp_sinhCosh(Stack[SP], Stack[SP+1], Stack[SP]); + ++SP; + break; + + case cAbsNot: + Stack[SP] = fp_absNot(Stack[SP]); break; + case cAbsNotNot: + Stack[SP] = fp_absNotNot(Stack[SP]); break; + case cAbsAnd: + Stack[SP-1] = fp_absAnd(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsOr: + Stack[SP-1] = fp_absOr(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsIf: + if(fp_absTruth(Stack[SP--])) + IP += 2; + else + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + } + break; -#ifdef SUPPORT_OPTIMIZER - case cVar: break; // Paranoia. These should never exist case cDup: Stack[SP+1] = Stack[SP]; ++SP; break; + case cInv: - if(Stack[SP] == 0.0) { evalErrorType=1; return 0; } - Stack[SP] = 1.0/Stack[SP]; + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/Stack[SP]; + break; + + case cSqr: + Stack[SP] = Stack[SP]*Stack[SP]; break; + + case cRDiv: + if(Stack[SP-1] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] = Stack[SP] / Stack[SP-1]; --SP; break; + + case cRSub: Stack[SP-1] = Stack[SP] - Stack[SP-1]; --SP; break; + + case cRSqrt: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1) / fp_sqrt(Stack[SP]); break; + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + case cReal: Stack[SP] = fp_real(Stack[SP]); break; + case cImag: Stack[SP] = fp_imag(Stack[SP]); break; + case cArg: Stack[SP] = fp_arg(Stack[SP]); break; + case cConj: Stack[SP] = fp_conj(Stack[SP]); break; + case cPolar: + Stack[SP-1] = fp_polar(Stack[SP-1], Stack[SP]); + --SP; break; #endif + // Variables: default: - Stack[++SP] = Vars[ByteCode[IP]-VarBegin]; + Stack[++SP] = Vars[byteCode[IP]-VarBegin]; } } - evalErrorType=0; + mData->mEvalErrorType=0; return Stack[SP]; } -#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT +//=========================================================================== +// Variable deduction +//=========================================================================== +namespace +{ + template + int deduceVariables(FunctionParserBase& fParser, + const char* funcStr, + std::string& destVarString, + int* amountOfVariablesFound, + std::vector* destVarNames, + bool useDegrees) + { + typedef std::set 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(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 +int FunctionParserBase::ParseAndDeduceVariables +(const std::string& function, + int* amountOfVariablesFound, + bool useDegrees) +{ + std::string varString; + return deduceVariables(*this, function.c_str(), varString, + amountOfVariablesFound, 0, useDegrees); +} + +template +int FunctionParserBase::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 +int FunctionParserBase::ParseAndDeduceVariables +(const std::string& function, + std::vector& resultVars, + bool useDegrees) +{ + std::string varString; + std::vector 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 +void FunctionParserBase::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 +#include namespace { inline void printHex(std::ostream& dest, unsigned n) { - dest.width(8); dest.fill('0'); std::hex(dest); //uppercase(dest); + std::ios::fmtflags flags = dest.flags(); + dest.width(4); dest.fill('0'); std::hex(dest); //uppercase(dest); dest << n; + dest.flags(flags); + } + + void padLine(std::ostringstream& dest, unsigned destLength) + { + for(std::size_t currentLength = dest.str().length(); + currentLength < destLength; + ++currentLength) + { + dest << ' '; + } + } + + const struct PowiMuliType + { + unsigned opcode_square; + unsigned opcode_cumulate; + unsigned opcode_invert; + unsigned opcode_half; + unsigned opcode_invhalf; + } iseq_powi = {cSqr,cMul,cInv,cSqrt,cRSqrt}, + iseq_muli = {~unsigned(0), cAdd,cNeg, ~unsigned(0),~unsigned(0) }; + + template + Value_t ParsePowiMuli( + const PowiMuliType& opcodes, + const std::vector& ByteCode, unsigned& IP, + unsigned limit, + std::size_t factor_stack_base, + std::vector& 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 + Value_t ParsePowiSequence(const std::vector& ByteCode, + unsigned& IP, unsigned limit, + std::size_t factor_stack_base, + bool IgnoreExcess = false) + { + std::vector stack; + stack.push_back(Value_t(1)); + return ParsePowiMuli(iseq_powi, ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); } + + template + Value_t ParseMuliSequence(const std::vector& ByteCode, + unsigned& IP, unsigned limit, + std::size_t factor_stack_base, + bool IgnoreExcess = false) + { + std::vector stack; + stack.push_back(Value_t(1)); + return ParsePowiMuli(iseq_muli, ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); + } + + struct IfInfo + { + std::pair condition; + std::pair thenbranch; + unsigned endif_location; + + IfInfo() : condition(), thenbranch(), endif_location() { } + }; } -void FunctionParser::PrintByteCode(std::ostream& dest) const +template +void FunctionParserBase::PrintByteCode(std::ostream& dest, + bool showExpression) const { - dest << "Size of stack: " << data->StackSize << "\n"; + dest << "Size of stack: " << mData->mStackSize << "\n"; - const unsigned* const ByteCode = data->ByteCode; - const double* const Immed = data->Immed; + std::ostringstream outputBuffer; + std::ostream& output = (showExpression ? outputBuffer : dest); - for(unsigned IP=0, DP=0; IPByteCodeSize; ++IP) - { - printHex(dest, IP); - dest << ": "; + const std::vector& ByteCode = mData->mByteCode; + const std::vector& Immed = mData->mImmed; - unsigned opcode = ByteCode[IP]; + std::vector > stack; + std::vector if_stack; - switch(opcode) + for(unsigned IP = 0, DP = 0; IP <= ByteCode.size(); ++IP) + { + after_powi_or_muli:; + std::string n; + bool out_params = false; + unsigned params = 2, produces = 1, opcode = 0; + + if(showExpression && !if_stack.empty() && + ( // Normal If termination rule: + if_stack.back().endif_location == IP + // This rule matches when cJumps are threaded: + || (IP < ByteCode.size() && ByteCode[IP] == cJump + && !if_stack.back().thenbranch.second.empty()) + )) { - case cIf: - dest << "jz\t"; - printHex(dest, ByteCode[IP+1]+1); - dest << endl; - IP += 2; - break; + printHex(output, IP); + if(if_stack.back().endif_location == IP) + output << ": ----- (phi)"; + else + output << ": ----- (phi+)"; + + stack.resize(stack.size()+2); + std::swap(stack[stack.size()-3], stack[stack.size()-1]); + std::swap(if_stack.back().condition, stack[stack.size()-3]); + std::swap(if_stack.back().thenbranch, stack[stack.size()-2]); + opcode = cIf; + params = 3; + --IP; + if_stack.pop_back(); + } + else + { + if(IP >= ByteCode.size()) break; + opcode = ByteCode[IP]; + + if(showExpression && ( + opcode == cSqr || opcode == cDup + || opcode == cInv + || opcode == cSqrt || opcode == cRSqrt + || opcode == cFetch + )) + { + unsigned changed_ip = IP; + Value_t exponent = + ParsePowiSequence + (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 + (ByteCode, changed_ip, + if_stack.empty() + ? (unsigned)ByteCode.size() + : if_stack.back().endif_location, + stack.size()-1); + if(factor == Value_t(1) || factor == Value_t(-1)) + goto not_powi_or_muli; + operation_prefix = "*"; + operation_value << factor; + prio = 3; + } + else + { + prio = 2; + operation_prefix = "^"; + operation_value << exponent; + } - case cJump: - dest << "jump\t"; - printHex(dest, ByteCode[IP+1]+1); - dest << endl; - IP += 2; - break; - case cImmed: - dest.precision(10); - dest << "push\t" << Immed[DP++] << endl; - break; + //unsigned explanation_before = changed_ip-2; + unsigned explanation_before = changed_ip-1; - case cFCall: + const char* explanation_prefix = "_"; + for(const unsigned first_ip = IP; IP < changed_ip; ++IP) + { + printHex(output, IP); + output << ": "; + + const char* sep = "|"; + if(first_ip+1 == changed_ip) + { sep = "="; explanation_prefix = " "; } + else if(IP == first_ip) sep = "\\"; + else if(IP+1 == changed_ip) sep = "/"; + else explanation_prefix = "="; + + switch(ByteCode[IP]) + { + case cInv: output << "inv"; break; + case cNeg: output << "neg"; break; + case cDup: output << "dup"; break; + case cSqr: output << "sqr"; break; + case cMul: output << "mul"; break; + case cAdd: output << "add"; break; + case cCbrt: output << "cbrt"; break; + case cSqrt: output << "sqrt"; break; + case cRSqrt: output << "rsqrt"; break; + case cFetch: + { + unsigned index = ByteCode[++IP]; + output << "cFetch(" << index << ")"; + break; + } + default: break; + } + padLine(outputBuffer, 20); + output << sep; + if(IP >= explanation_before) + { + explanation_before = (unsigned)ByteCode.size(); + output << explanation_prefix + << '[' << (stack.size()-1) << ']'; + std::string last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + output << last; + output << operation_prefix; + output << operation_value.str(); + } + else + { + unsigned p = first_ip; + Value_t exp = operation_prefix=="^" ? + ParsePowiSequence + (ByteCode, p, IP+1, stack.size()-1, true) : + ParseMuliSequence + (ByteCode, p, IP+1, stack.size()-1, true); + std::string last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + output << " ..." << last; + output << operation_prefix; + output << exp; + } + dest << outputBuffer.str() << std::endl; + outputBuffer.str(""); + } + + std::string& last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + last += operation_prefix; + last += operation_value.str(); + stack.back().first = prio; + + goto after_powi_or_muli; + } + not_powi_or_muli:; + printHex(output, IP); + output << ": "; + + switch(opcode) + { + case cIf: { - unsigned index = ByteCode[++IP]; - Data::VarMap_t::const_iterator iter = - data->FuncPtrNames.begin(); - while(iter->second != index) ++iter; - dest << "fcall\t" << iter->first - << " (" << data->FuncPtrs[index].params << ")" << endl; + unsigned label = ByteCode[IP+1]+1; + output << "jz "; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); break; } - - case cPCall: + case cAbsIf: { - unsigned index = ByteCode[++IP]; - Data::VarMap_t::const_iterator iter = - data->FuncParserNames.begin(); - while(iter->second != index) ++iter; - dest << "pcall\t" << iter->first - << " (" << data->FuncParsers[index]->data->varAmount - << ")" << endl; + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; + output << "jz_abs " << dp << ","; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); break; } - default: - if(opcode < VarBegin) + case cJump: { - string n; - unsigned params = 1; - switch(opcode) - { - case cNeg: n = "neg"; break; - case cAdd: n = "add"; break; - case cSub: n = "sub"; break; - case cMul: n = "mul"; break; - case cDiv: n = "div"; break; - case cMod: n = "mod"; break; - case cPow: n = "pow"; break; - case cEqual: n = "eq"; break; - case cNEqual: n = "neq"; break; - case cLess: n = "lt"; break; - case cLessOrEq: n = "le"; break; - case cGreater: n = "gt"; break; - case cGreaterOrEq: n = "ge"; break; - case cAnd: n = "and"; break; - case cOr: n = "or"; break; - case cNot: n = "not"; break; - case cDeg: n = "deg"; break; - case cRad: n = "rad"; break; - -#ifndef DISABLE_EVAL - case cEval: n = "call\t0"; break; -#endif - -#ifdef SUPPORT_OPTIMIZER - case cVar: n = "(var)"; break; - case cDup: n = "dup"; break; - case cInv: n = "inv"; break; -#endif + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; - default: - n = Functions[opcode-cAbs].name; - params = Functions[opcode-cAbs].params; + if(!if_stack.empty() && !stack.empty()) + { + std::swap(if_stack.back().thenbranch, stack.back()); + if_stack.back().endif_location = label; + stack.pop_back(); } - dest << n; - if(params != 1) dest << " (" << params << ")"; - dest << endl; + + output << "jump " << dp << ","; + printHex(output, label); + params = 0; + produces = 0; + IP += 2; + break; } - else + case cImmed: { - dest << "push\tVar" << opcode-VarBegin << endl; + if(showExpression) + { + std::ostringstream buf; + buf.precision(8); + buf << Immed[DP]; + stack.push_back( std::make_pair(0, buf.str()) ); + } + output.precision(8); + output << "push " << Immed[DP]; + ++DP; + produces = 0; + break; } + + case cFCall: + { + const unsigned index = ByteCode[++IP]; + params = mData->mFuncPtrs[index].mParams; + static std::string name; + name = "f:" + findName(mData->mNamePtrs, index, + NameData::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::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::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 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 sin = stack.back(); + std::pair 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 sinh = stack.back(); + std::pair 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& prev = + stack[stack.size() - params + a]; + if(prio > 0 && (prev.first > prio || + (prev.first==prio && !commutative))) + buf << '(' << prev.second << ')'; + else + buf << prev.second; + } + sep = paramsep; + } + if(stack.size() >= params) + stack.resize(stack.size() - params); + else + stack.clear(); + buf << suff; + stack.push_back(std::make_pair(prio, buf.str())); + //if(n.size() <= 4 && !out_params) padLine(outputBuffer, 20); + } + //padLine(outputBuffer, 20); + output << "= "; + if(((opcode == cIf || opcode == cAbsIf) && params != 3) + || opcode == cJump + #ifdef FP_SUPPORT_OPTIMIZER + || opcode == cNop + #endif + ) + output << "(void)"; + else if(stack.empty()) + output << "[?] ?"; + else + output << '[' << (stack.size()-1) << ']' + << stack.back().second; + } + + if(showExpression) + { + dest << outputBuffer.str() << std::endl; + outputBuffer.str(""); } + else + output << std::endl; } + dest << std::flush; } #endif - - -#ifndef SUPPORT_OPTIMIZER -void FunctionParser::MakeTree(void *) const {} -void FunctionParser::Optimize() +#ifndef FP_SUPPORT_OPTIMIZER +template +void FunctionParserBase::Optimize() { // Do nothing if no optimizations are supported. } #endif + +FUNCTIONPARSER_INSTANTIATE_TYPES diff --git a/deal.II/contrib/functionparser/fparser.h b/deal.II/contrib/functionparser/fparser.h deleted file mode 100644 index 9ef0d3dc85..0000000000 --- a/deal.II/contrib/functionparser/fparser.h +++ /dev/null @@ -1,176 +0,0 @@ -/***************************************************************************\ -|* Function parser v2.83 by Warp *| -|* ----------------------------- *| -|* Parses and evaluates the given function with the given variable values. *| -|* See fparser.txt for details. *| -|* *| -\***************************************************************************/ - -#ifndef ONCE_FPARSER_H_ -#define ONCE_FPARSER_H_ - -#include -#include -#include - -#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT -#include -#endif -namespace fparser { - -class FunctionParser -{ -public: - enum ParseErrorType - { - SYNTAX_ERROR=0, MISM_PARENTH, MISSING_PARENTH, EMPTY_PARENTH, - EXPECT_OPERATOR, OUT_OF_MEMORY, UNEXPECTED_ERROR, INVALID_VARS, - ILL_PARAMS_AMOUNT, PREMATURE_EOS, EXPECT_PARENTH_FUNC, - FP_NO_ERROR - }; - - - int Parse(const std::string& Function, const std::string& Vars, - bool useDegrees = false); - const char* ErrorMsg() const; - inline ParseErrorType GetParseErrorType() const { return parseErrorType; } - - double Eval(const double* Vars); - inline int EvalError() const { return evalErrorType; } - - bool AddConstant(const std::string& name, double value); - bool AddUnit(const std::string& name, double value); - - typedef double (*FunctionPtr)(const double*); - - bool AddFunction(const std::string& name, - FunctionPtr, unsigned paramsAmount); - bool AddFunction(const std::string& name, FunctionParser&); - - void Optimize(); - - - FunctionParser(); - ~FunctionParser(); - - // Copy constructor and assignment operator (implemented using the - // copy-on-write technique for efficiency): - FunctionParser(const FunctionParser&); - FunctionParser& operator=(const FunctionParser&); - - - void ForceDeepCopy(); - - -#ifdef FUNCTIONPARSER_SUPPORT_DEBUG_OUTPUT - // For debugging purposes only: - void PrintByteCode(std::ostream& dest) const; -#endif - - // Added by Luca Heltai. For consistency checking. - unsigned int NVars() { - return data->varAmount; - } - - - - - -//======================================================================== -private: -//======================================================================== - -// Private data: -// ------------ - ParseErrorType parseErrorType; - int evalErrorType; - - struct Data - { - unsigned referenceCounter; - - int varAmount; - bool useDegreeConversion, isOptimized; - - typedef std::map VarMap_t; - VarMap_t Variables; - - typedef std::map ConstMap_t; - ConstMap_t Constants; - ConstMap_t Units; - - VarMap_t FuncPtrNames; - struct FuncPtrData - { - FunctionPtr ptr; unsigned params; - FuncPtrData(FunctionPtr p, unsigned par): ptr(p), params(par) {} - }; - std::vector FuncPtrs; - - VarMap_t FuncParserNames; - std::vector FuncParsers; - - unsigned* ByteCode; - unsigned ByteCodeSize; - double* Immed; - unsigned ImmedSize; - double* Stack; - unsigned StackSize; - - Data(); - ~Data(); - Data(const Data&); - - Data& operator=(const Data&); // not implemented on purpose - }; - - Data* data; - unsigned evalRecursionLevel; - - // Temp data needed in Compile(): - unsigned StackPtr; - std::vector* tempByteCode; - std::vector* tempImmed; - - -// Private methods: -// --------------- - void CopyOnWrite(); - - - bool CheckRecursiveLinking(const FunctionParser*) const; - - bool ParseVars(const std::string& Vars, - std::map& dest); - int VarNameType(const std::string&) const; - Data::VarMap_t::const_iterator - FindVariable(const char*, const Data::VarMap_t&) const; - Data::ConstMap_t::const_iterator - FindConstant(const char*, const Data::ConstMap_t&) const; - int CheckForUnit(const char*, int) const; - int CheckSyntax(const char*); - int Compile(const char*); - bool IsVariable(int); - void AddCompiledByte(unsigned); - void AddImmediate(double); - void AddFunctionOpcode(unsigned); - inline void incStackPtr(); - int CompileIf(const char*, int); - int CompileFunctionParams(const char*, int, unsigned); - int CompileElement(const char*, int); - int CompilePossibleUnit(const char*, int); - int CompilePow(const char*, int); - int CompileUnaryMinus(const char*, int); - int CompileMult(const char*, int); - int CompileAddition(const char*, int); - int CompileComparison(const char*, int); - int CompileAnd(const char*, int); - int CompileOr(const char*, int); - int CompileExpression(const char*, int, bool=false); - - - void MakeTree(void*) const; -}; - -} -#endif diff --git a/deal.II/contrib/functionparser/fparser.hh b/deal.II/contrib/functionparser/fparser.hh new file mode 100644 index 0000000000..b2959a81d3 --- /dev/null +++ b/deal.II/contrib/functionparser/fparser.hh @@ -0,0 +1,224 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_H_ +#define ONCE_FPARSER_H_ + +#include +#include + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +#include +#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 class CodeTree; } + +template +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 + 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& 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; + +// Private data: +// ------------ + Data* mData; + unsigned mStackPtr; + static Value_t sEpsilon; + + +// Private methods: +// --------------- + void CopyOnWrite(); + bool CheckRecursiveLinking(const FunctionParserBase*) const; + bool NameExists(const char*, unsigned); + bool ParseVariables(const std::string&); + int ParseFunction(const char*, bool); + const char* SetErrorType(ParseErrorType, const char*); + + void AddFunctionOpcode(unsigned); + void AddImmedOpcode(Value_t v); + void incStackPtr(); + void CompilePowi(long); + bool TryCompilePowi(Value_t); + + const char* CompileIf(const char*); + const char* CompileFunctionParams(const char*, unsigned); + const char* CompileElement(const char*); + const char* CompilePossibleUnit(const char*); + const char* CompilePow(const char*); + const char* CompileUnaryMinus(const char*); + const char* CompileMult(const char*); + const char* CompileAddition(const char*); + const char* CompileComparison(const char*); + const char* CompileAnd(const char*); + const char* CompileExpression(const char*); + inline const char* CompileFunction(const char*, unsigned); + inline const char* CompileParenthesis(const char*); + inline const char* CompileLiteral(const char*); + template + inline void PushOpcodeParam(unsigned); + template + 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 ParseLiteral(const char*); + static unsigned ParseIdentifier(const char*); +}; + +class FunctionParser: public FunctionParserBase {}; +class FunctionParser_f: public FunctionParserBase {}; +class FunctionParser_ld: public FunctionParserBase {}; +class FunctionParser_li: public FunctionParserBase {}; + +#include +class FunctionParser_cd: public FunctionParserBase > {}; +class FunctionParser_cf: public FunctionParserBase > {}; +class FunctionParser_cld: public FunctionParserBase > {}; + + + +template +class FunctionParserBase::FunctionWrapper +{ + unsigned mReferenceCount; + friend class FunctionParserBase; + + 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 +template +bool FunctionParserBase::AddFunctionWrapper +(const std::string& name, const DerivedWrapper& wrapper, unsigned paramsAmount) +{ + return addFunctionWrapperPtr + (name, new DerivedWrapper(wrapper), paramsAmount); +} +#endif diff --git a/deal.II/contrib/functionparser/fparser.txt b/deal.II/contrib/functionparser/fparser.txt deleted file mode 100644 index 27803faa99..0000000000 --- a/deal.II/contrib/functionparser/fparser.txt +++ /dev/null @@ -1,897 +0,0 @@ - Function parser for C++ v2.83 by Warp. - ====================================== - - Optimization code contributed by Bisqwit (http://iki.fi/bisqwit/) - - - The usage license of this library is located at the end of this text file. - - - What's new in v2.83 - ------------------- - - Fixed bug in the optimizer which caused functions like "x-y*1" to crash. - - What's new in v2.82 - ------------------- - - Fixed bug in the optimizer which caused a crash with some functions. - - What's new in v2.81 - ------------------- - - Added support for units (see help on the AddUnit() method). - - Added support for optionally making the Eval() function thread-safe - with a precompiler constant. - - - Table of contents: - ----------------- - - Preface - - Usage - * Configuring the compilation - * Copying and assignment - * Short descriptions of FunctionParser methods - * Long descriptions of FunctionParser methods - - About thread safety - - The function string - - Contacting the author - - The algorithm used in the library - - Usage license - - - -============================================================================= - - Preface -============================================================================= - - Often people need to ask some mathematical expression from the user and -then evaluate values for that expression. The simplest example is a program -which draws the graphic of a user-defined function on screen. - - This library adds C-style function string parsing to the program. This -means that you can evaluate the string "sqrt(1-x^2+y^2)" with given values -of 'x' and 'y'. - - The library is intended to be very fast. It byte-compiles the function -string at parse time and interpretes this byte-code at evaluation time. -The evaluation is straightforward and no recursions are done (uses stack -arithmetic). - Empirical tests show that it indeed is very fast (specially compared to -libraries which evaluate functions by just interpreting the raw function -string). - - The library is made in ISO C++ and requires a standard-conforming C++ -compiler. - - -============================================================================= - - Usage -============================================================================= - - To use the FunctionParser class, you have to include "fparser.hh" in -your source code files which use the FunctionParser class. - - When compiling, you have to compile fparser.cc and fpoptimizer.cc and -link them to the main program. In some developement environments it's -enough to add those two files to your current project. - - If you are not going to use the optimizer (ie. you have commented out -SUPPORT_OPTIMIZER in fpconfig.hh), you can leave the latter file out. - - - * Configuring the compilation: - --------------------------- - - There is a set of precompiler options in the fpconfig.hh file - which can be used for setting certain features on or off: - - NO_ASINH : (Default on) - By default the library does not support the asinh(), acosh() - and atanh() functions because they are not part of the ISO C++ - standard. If your compiler supports them and you want the - parser to support them as well, comment out this line. - - DISABLE_EVAL : (Default off) - Even though the maximum recursion level of the eval() function - is limited, it is still possible to write functions which never - reach this maximum recursion level but take enormous amounts of - time to evaluate (this can be undesirable eg. in web server-side - applications). - Uncommenting this line will disable the eval() function completely, - thus removing the danger of exploitation. - - Note that you can also disable eval() by specifying the - DISABLE_EVAL precompiler constant in your compiler (eg. - with -DDISABLE_EVAL in gcc). - - EVAL_MAX_REC_LEVEL : (Default 1000) - Sets the maximum recursion level allowed for eval(). - - SUPPORT_OPTIMIZER : (Default on) - If you are not going to use the Optimize() method, you can comment - this line out to speed-up the compilation of fparser.cc a bit, as - well as making the binary a bit smaller. (Optimize() can still be - called, but it will not do anything.) - - You can also disable the optimizer by specifying the - NO_SUPPORT_OPTIMIZER precompiler constant in your compiler - (eg. with -DNO_SUPPORT_OPTIMIZER in gcc). - - FP_EPSILON : (Default 1e-14) - Epsilon value used in comparison operators. - If this line is commented out, then no epsilon will be used. - - FP_USE_THREAD_SAFE_EVAL : (Default off) - Define this precompiler constant to make Eval() thread-safe. - Refer to the thread safety section later in this document for - more information. - Note that defining this may make Eval() slightly slower. - - FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA : (Default off) - This like the previous, but makes Eval() use the alloca() function - (instead of std::vector). This will make it faster, but the alloca() - function is not standard and thus not supported by all compilers. - - - * Copying and assignment: - ---------------------- - - The class implements a safe copy constructor and assignment operator. - - It uses the copy-on-write technique for efficiency. This means that - when copying or assigning a FunctionParser instance, the internal data - (which in some cases can be quite lengthy) is not immediately copied - but only when the contents of the copy (or the original) are changed. - This means that copying/assigning is a very fast operation, and if - the copies are never modified then actual data copying never happens - either. - - The Eval() and EvalError() methods of the copy can be called without - the internal data being copied. - Calling Parse(), Optimize() or the user-defined constant/function adding - methods will cause a deep-copy. - - (C++ basics: The copy constructor is called when a new FunctionParser - instance is initialized with another, ie. like: - - FunctionParser fp2 = fp1; // or: FunctionParser fp2(fp1); - - or when a function takes a FunctionParser instance as parameter, eg: - - void foo(FunctionParser p) // takes an instance of FunctionParser - { ... } - - The assignment operator is called when a FunctionParser instance is - assigned to another, like "fp2 = fp1;".) - - - * Short descriptions of FunctionParser methods: - -------------------------------------------- - -int Parse(const std::string& Function, const std::string& Vars, - bool useDegrees = false); - - Parses the given function and compiles it to internal format. - Return value is -1 if successful, else the index value to the location - of the error. - - -const char* ErrorMsg(void) const; - - Returns an error message corresponding to the error in Parse(), or 0 if - no such error occurred. - - -ParseErrorType GetParseErrorType() const; - - Returns the type of parsing error which occurred. Possible return types - are described in the long description. - - -double Eval(const double* Vars); - - Evaluates the function given to Parse(). - - -int EvalError(void) const; - - Returns 0 if no error happened in the previous call to Eval(), else an - error code >0. - - -void Optimize(); - - Tries to optimize the bytecode for faster evaluation. - - -bool AddConstant(const std::string& name, double value); - - Add a constant to the parser. Returns false if the name of the constant - is invalid, else true. - - -bool AddUnit(const std::string& name, double value); - - Add a new unit to the parser. Returns false if the name of the unit - is invalid, else true. - - -bool AddFunction(const std::string& name, - double (*functionPtr)(const double*), - unsigned paramsAmount); - - Add a user-defined function to the parser (as a function pointer). - Returns false if the name of the function is invalid, else true. - - -bool AddFunction(const std::string& name, FunctionParser&); - - Add a user-defined function to the parser (as a FunctionParser instance). - Returns false if the name of the function is invalid, else true. - - - - * Long descriptions of FunctionParser methods: - ------------------------------------------- - ---------------------------------------------------------------------------- -int Parse(const std::string& Function, const std::string& Vars, - bool useDegrees = false); ---------------------------------------------------------------------------- - - Parses the given function (and compiles it to internal format). - Destroys previous function. Following calls to Eval() will evaluate - the given function. - The strings given as parameters are not needed anymore after parsing. - - Parameters: - Function : String containing the function to parse. - Vars : String containing the variable names, separated by commas. - Eg. "x,y", "VarX,VarY,VarZ,n" or "x1,x2,x3,x4,__VAR__". - useDegrees: (Optional.) Whether to use degrees or radians in - trigonometric functions. (Default: radians) - - Variables can have any size and they are case sensitive (ie. "var", - "VAR" and "Var" are *different* variable names). Letters, digits and - underscores can be used in variable names, but the name of a variable - can't begin with a digit. Each variable name can appear only once in - the 'Vars' string. Function names are not legal variable names. - - Using longer variable names causes no overhead whatsoever to the Eval() - method, so it's completely safe to use variable names of any size. - - The third, optional parameter specifies whether angles should be - interpreted as radians or degrees in trigonometrical functions. - If not specified, the default value is radians. - - Return values: - -On success the function returns -1. - -On error the function returns an index to where the error was found - (0 is the first character, 1 the second, etc). If the error was not - a parsing error returns an index to the end of the string + 1. - - Example: parser.Parse("3*x+y", "x,y"); - - ---------------------------------------------------------------------------- -const char* ErrorMsg(void) const; ---------------------------------------------------------------------------- - - Returns a pointer to an error message string corresponding to the error - caused by Parse() (you can use this to print the proper error message to - the user). If no such error has occurred, returns 0. - - ---------------------------------------------------------------------------- -ParseErrorType GetParseErrorType() const; ---------------------------------------------------------------------------- - - Returns the type of parse error which occurred. - - This method can be used to get the error type if ErrorMsg() is not - enough for printing the error message. In other words, this can be - used for printing customized error messages (eg. in another language). - If the default error messages suffice, then this method doesn't need - to be called. - - FunctionParser::ParseErrorType is an enumerated type inside the class - (ie. its values are accessed like "FunctionParser::SYNTAX_ERROR"). - - The possible values for FunctionParser::ParseErrorType are listed below, - along with their equivalent error message returned by the ErrorMsg() - method: - -FP_NO_ERROR : If no error occurred in the previous call to Parse(). -SYNTAX_ERROR : "Syntax error" -MISM_PARENTH : "Mismatched parenthesis" -MISSING_PARENTH : "Missing ')'" -EMPTY_PARENTH : "Empty parentheses" -EXPECT_OPERATOR : "Syntax error: Operator expected" -OUT_OF_MEMORY : "Not enough memory" -UNEXPECTED_ERROR : "An unexpected error occurred. Please make a full bug " - "report to the author" -INVALID_VARS : "Syntax error in parameter 'Vars' given to " - "FunctionParser::Parse()" -ILL_PARAMS_AMOUNT : "Illegal number of parameters to function" -PREMATURE_EOS : "Syntax error: Premature end of string" -EXPECT_PARENTH_FUNC: "Syntax error: Expecting ( after function" - - ---------------------------------------------------------------------------- -double Eval(const double* Vars); ---------------------------------------------------------------------------- - - Evaluates the function given to Parse(). - The array given as parameter must contain the same amount of values as - the amount of variables given to Parse(). Each value corresponds to each - variable, in the same order. - - Return values: - -On success returns the evaluated value of the function given to - Parse(). - -On error (such as division by 0) the return value is unspecified, - probably 0. - - Example: - - double Vars[] = {1, -2.5}; - double result = parser.Eval(Vars); - - ---------------------------------------------------------------------------- -int EvalError(void) const; ---------------------------------------------------------------------------- - - Used to test if the call to Eval() succeeded. - - Return values: - If there was no error in the previous call to Eval(), returns 0, - else returns a positive value as follows: - 1: division by zero - 2: sqrt error (sqrt of a negative value) - 3: log error (logarithm of a negative value) - 4: trigonometric error (asin or acos of illegal value) - 5: maximum recursion level in eval() reached - - ---------------------------------------------------------------------------- -void Optimize(); ---------------------------------------------------------------------------- - - This method can be called after calling the Parse() method. It will try - to simplify the internal bytecode so that it will evaluate faster (it - tries to reduce the amount of opcodes in the bytecode). - - For example, the bytecode for the function "5+x*y-25*4/8" will be - reduced to a bytecode equivalent to the function "x*y-7.5" (the original - 11 opcodes will be reduced to 5). Besides calculating constant expressions - (like in the example), it also performs other types of simplifications - with variable and function expressions. - - This method is quite slow and the decision of whether to use it or - not should depend on the type of application. If a function is parsed - once and evaluated millions of times, then calling Optimize() may speed-up - noticeably. However, if there are tons of functions to parse and each one - is evaluated once or just a few times, then calling Optimize() will only - slow down the program. - Also, if the original function is expected to be optimal, then calling - Optimize() would be useless. - - Note: Currently this method does not make any checks (like Eval() does) - and thus things like "1/0" will cause undefined behaviour. (On the other - hand, if such expression is given to the parser, Eval() will always give - an error code, no matter what the parameters.) If caching this type of - errors is important, a work-around is to call Eval() once before calling - Optimize() and checking EvalError(). - - If the destination application is not going to use this method, - the compiler constant SUPPORT_OPTIMIZER can be undefined in fpconfig.hh - to make the library smaller (Optimize() can still be called, but it will - not do anything). - - (If you are interested in seeing how this method optimizes the opcode, - you can call the PrintByteCode() method before and after the call to - Optimize() to see the difference.) - - ---------------------------------------------------------------------------- -bool AddConstant(const std::string& name, double value); ---------------------------------------------------------------------------- - - This method can be used to add constants to the parser. Syntactically - constants are identical to variables (ie. they follow the same naming - rules and they can be used in the function string in the same way as - variables), but internally constants are directly replaced with their - value at parse time. - - Constants used by a function must be added before calling Parse() - for that function. Constants are preserved between Parse() calls in - the current FunctionParser instance, so they don't need to be added - but once. (If you use the same constant in several instances of - FunctionParser, you will need to add it to all the instances separately.) - - Constants can be added at any time and the value of old constants can - be changed, but new additions and changes will only have effect the next - time Parse() is called. (That is, changing the value of a constant - after calling Parse() and before calling Eval() will have no effect.) - - The return value will be false if the 'name' of the constant was - illegal, else true. If the name was illegal, the method does nothing. - - Example: parser.AddConstant("pi", 3.1415926535897932); - - Now for example parser.Parse("x*pi", "x"); will be identical to the - call parser.Parse("x*3.1415926535897932", "x"); - - ---------------------------------------------------------------------------- -bool AddUnit(const std::string& name, double value); ---------------------------------------------------------------------------- - - In some applications it is desirable to have units of measurement. - A typical example is an application which creates a page layout to be - printed. When printing, distances are usually measured in points - (defined by the resolution of the printer). However, it is often more - useful for the user to be able to specify measurements in other units - such as centimeters or inches. - - A unit is simply a value by which the preceding element is multiplied. - For example, if the printing has been set up to 300 DPI, one inch is - then 300 points (dots). Thus saying eg. "5in" is the same as saying - "5*300" or "1500" (assuming "in" has been added as a unit with the - value 300). - - Note that units are slightly different from a multiplication in - that they have a higher precedence than any other operator (except - parentheses). Thus for example "5/2in" is parsed as "5/(2*300)". - (If 5/2 inches is what one wants, it has to be written "(5/2)in".) - - You can use the AddUnit() method to add a new unit. The unit can then - be used after any element in the function (and will work as a multiplier - for that element). An element is a float literal, a constant, a variable, - a function or any expression in parentheses. When the element is not a - float literal nor an expression in parentheses, there has to naturally - be at least one whitespace between the element and the unit (eg. "x in"). - To change the value of a unit, call AddUnit() again with the same unit - name and the new value. - - Note that units are independent from variables, constants and functions. - This means that a unit can have the same name as those (there isn't any - syntactical problem in that), thus for example "x x" is a valid function - if "x" is a variable or constant and "x" is a unit, although for the sake - of clarity that is usually not recommended. - - Example: parser.AddUnit("in", 300); - - Now for example the function "5in" will be identical to "(5*300)". - Other usage examples include "x in", "3in+2", "pow(x,2)in", "(x+2)in". - - ---------------------------------------------------------------------------- -bool AddFunction(const std::string& name, - double (*functionPtr)(const double*), - unsigned paramsAmount); ---------------------------------------------------------------------------- - - This method can be used to add new functions to the parser. For example, - if you would like to add a function "sqr(A)" which squares the value - of A, you can do it with this method (so that you don't need to touch - the source code of the parser). - - The method takes three parameters: - - - The name of the function. The name follows the same naming conventions - as variable names. - - - A C++ function, which will be called when evaluating the function - string (if the user-given function is called there). The C++ function - must have the form: - double functionName(const double* params); - - - The number of parameters the function takes. 0 is a valid value - in which case the function takes no parameters (such function - should simply ignore the double* it gets as a parameter). - - The return value will be false if the given name was invalid (either it - did not follow the variable naming conventions, or the name was already - reserved), else true. If the return value is false, nothing is added. - - Example: - Suppose we have a C++ function like this: - - double Square(const double* p) - { - return p[0]*p[0]; - } - - Now we can add this function to the parser like this: - - parser.AddFunction("sqr", Square, 1); - - parser.Parse("2*sqr(x)", "x"); - - - An example of a useful function taking no parameters is a function - returning a random value. For example: - - double Rand(const double*) - { - return drand48(); - } - - parser.AddFunction("rand", Rand, 0); - - - IMPORTANT NOTE: If you use the Optimize() method, it will assume that - the user-given function has no side-effects, that is, it always - returns the same value for the same parameters. The optimizer will - optimize the function call away in some cases, making this assumption. - (The Rand() function given as example above is one such problematic case.) - - ---------------------------------------------------------------------------- -bool AddFunction(const std::string& name, FunctionParser&); ---------------------------------------------------------------------------- - - This method is almost identical to the previous AddFunction(), but - instead of taking a C++ function, it takes another FunctionParser - instance. - - There are some important restrictions on making a FunctionParser instance - call another: - - - The FunctionParser instance given as parameter must be initialized - with a Parse() call before giving it as parameter. That is, if you - want to use the parser A in the parser B, you must call A.Parse() - before you can call B.AddFunction("name", A). - - - The amount of variables in the FunctionParser instance given as - parameter must not change after it has been given to the AddFunction() - of another instance. Changing the number of variables will result in - malfunction. - - - AddFunction() will fail (ie. return false) if a recursive loop is - formed. The method specifically checks that no such loop is built. - - Example: - - FunctionParser f1, f2; - f1.Parse("x*x", "x"); - f2.AddFunction("sqr", f1); - - This version of the AddFunction() method can be useful to eg. chain - user-given functions. For example, ask the user for a function F1, - and then ask the user another function F2, but now the user can - call F1 in this second function if he wants (and so on with a third - function F3, where he can call F1 and F2, etc). - - - - -============================================================================= - - About thread safety -============================================================================= - - None of the member functions of the FunctionParser class are thread-safe. -Most prominently, the Eval() function is not thread-safe. (In other words, -the Eval() function of a single FunctionParser instance cannot be safely -called simultaneously by two threads.) - - There are ways to use this library in a thread-safe way, though. If each -thread uses its own FunctionParser instance, no problems will obviously -happen. Note, however, that if these instances need to be a copy of a given -FunctionParser instance (eg. one where the user has entered a function), -a deep copy of this instance has to be performed for each thread. By -default FunctionParser uses shallow-copying (copy-on-write), which means -that a simple assignment of copy construction will not copy the data itself. -To force a deep copy you can all the ForceDeepCopy() function on each of -the instances of each thread after the assignment or copying has been done. - - Another possibility is to compile the FunctionParser library so that -its Eval() function will be thread-safe. (This can be done by defining -the FP_USE_THREAD_SAFE_EVAL or the FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA -precompiler constant.) As long as only one thread calls the other functions -of FunctionParser, the other threads can safely call the Eval() of this -one instance. - Note, however, that compiling the library like this can make Eval() -slightly slower. (The alloca version, if supported by the compiler, -will not be as slow.) - - -============================================================================= - - The function string -============================================================================= - - The function string understood by the class is very similar to the C-syntax. - Arithmetic float expressions can be created from float literals, variables -or functions using the following operators in this order of precedence: - - () expressions in parentheses first - A unit a unit multiplier (if one has been added) - A^B exponentiation (A raised to the power B) - -A unary minus - !A unary logical not (result is 1 if int(A) is 0, else 0) - A*B A/B A%B multiplication, division and modulo - A+B A-B addition and subtraction - A=B A!=B AB A>=B - comparison between A and B (result is either 0 or 1) - A&B result is 1 if int(A) and int(B) differ from 0, else 0 - A|B result is 1 if int(A) or int(B) differ from 0, else 0 - - Since the unary minus has higher precedence than any other operator, for - example the following expression is valid: x*-y - - The comparison operators use an epsilon value, so expressions which may - differ in very least-significant digits should work correctly. For example, - "0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 1" should always return 1, and - the same comparison done with ">" or "<" should always return 0. - (The epsilon value can be configured in the fpconfig.hh file.) - Without epsilon this comparison probably returns the wrong value. - - The class supports these functions: - - abs(A) : Absolute value of A. If A is negative, returns -A otherwise - returns A. - acos(A) : Arc-cosine of A. Returns the angle, measured in radians, - whose cosine is A. - acosh(A) : Same as acos() but for hyperbolic cosine. - asin(A) : Arc-sine of A. Returns the angle, measured in radians, whose - sine is A. - asinh(A) : Same as asin() but for hyperbolic sine. - atan(A) : Arc-tangent of (A). Returns the angle, measured in radians, - whose tangent is (A). - atan2(A,B): Arc-tangent of A/B. The two main differences to atan() is - that it will return the right angle depending on the signs of - A and B (atan() can only return values betwen -pi/2 and pi/2), - and that the return value of pi/2 and -pi/2 are possible. - atanh(A) : Same as atan() but for hyperbolic tangent. - ceil(A) : Ceiling of A. Returns the smallest integer greater than A. - Rounds up to the next higher integer. - cos(A) : Cosine of A. Returns the cosine of the angle A, where A is - measured in radians. - cosh(A) : Same as cos() but for hyperbolic cosine. - cot(A) : Cotangent of A (equivalent to 1/tan(A)). - csc(A) : Cosecant of A (equivalent to 1/sin(A)). - eval(...) : This a recursive call to the function to be evaluated. The - number of parameters must be the same as the number of parameters - taken by the function. Must be called inside if() to avoid - infinite recursion. - exp(A) : Exponential of A. Returns the value of e raised to the power - A where e is the base of the natural logarithm, i.e. the - non-repeating value approximately equal to 2.71828182846. - floor(A) : Floor of A. Returns the largest integer less than A. Rounds - down to the next lower integer. - if(A,B,C) : If int(A) differs from 0, the return value of this function is B, - else C. Only the parameter which needs to be evaluated is - evaluated, the other parameter is skipped; this makes it safe to - use eval() in them. - int(A) : Rounds A to the closest integer. 0.5 is rounded to 1. - log(A) : Natural (base e) logarithm of A. - log10(A) : Base 10 logarithm of A. - max(A,B) : If A>B, the result is A, else B. - min(A,B) : If A1, n*eval(n-1), 1)" - - Note that a recursive call has some overhead, which makes it a bit slower - than any other operation. It may be a good idea to avoid recursive functions - in very time-critical applications. Recursion also takes some memory, so - extremely deep recursions should be avoided (eg. millions of nested recursive - calls). - - Also note that even though the maximum recursion level of eval() is - limited, it is possible to write functions which never reach that level - but still take enormous amounts of time to evaluate. - This can sometimes be undesirable because it is prone to exploitation, - but you can disable the eval() function completely in the fpconfig.hh file. - - -============================================================================= - - Contacting the author -============================================================================= - - Any comments, bug reports, etc. should be sent to warp@iki.fi - - -============================================================================= - - The algorithm used in the library -============================================================================= - - The whole idea behind the algorithm is to convert the regular infix -format (the regular syntax for mathematical operations in most languages, -like C and the input of the library) to postfix format. The postfix format -is also called stack arithmetic since an expression in postfix format -can be evaluated using a stack and operating with the top of the stack. - - For example: - - infix postfix - 2+3 2 3 + - 1+2+3 1 2 + 3 + - 5*2+8/2 5 2 * 8 2 / + - (5+9)*3 5 9 + 3 * - - The postfix notation should be read in this way: - - Let's take for example the expression: 5 2 * 8 2 / + - - Put 5 on the stack - - Put 2 on the stack - - Multiply the two values on the top of the stack and put the result on - the stack (removing the two old values) - - Put 8 on the stack - - Put 2 on the stack - - Divide the two values on the top of the stack - - Add the two values on the top of the stack (which are in this case - the result of 5*2 and 8/2, that is, 10 and 4). - - At the end there's only one value in the stack, and that value is the -result of the expression. - - Why stack arithmetic? - - The last example above can give you a hint. - In infix format operators have precedence and we have to use parentheses to -group operations with lower precedence to be calculated before operations -with higher precedence. - This causes a problem when evaluating an infix expression, specially -when converting it to byte code. For example in this kind of expression: - (x+1)/(y+2) -we have to calculate first the two additions before we can calculate the -division. We have to also keep counting parentheses, since there can be -a countless amount of nested parentheses. This usually means that you -have to do some type of recursion. - - The most simple and efficient way of calculating this is to convert it -to postfix notation. - The postfix notation has the advantage that you can make all operations -in a straightforward way. You just evaluate the expression from left to -right, applying each operation directly and that's it. There are no -parentheses to worry about. You don't need recursion anywhere. - You have to keep a stack, of course, but that's extremely easily done. -Also you just operate with the top of the stack, which makes it very easy. -You never have to go deeper than 2 items in the stack. - And even better: Evaluating an expression in postfix format is never -slower than in infix format. All the contrary, in many cases it's a lot -faster (eg. because all parentheses are optimized away). - The above example could be expressed in postfix format: - x 1 + y 2 + / - - The good thing about the postfix notation is also the fact that it can -be extremely easily expressed in bytecode form. - You only need a byte value for each operation, for each variable and -to push a constant to the stack. - Then you can interpret this bytecode straightforwardly. You just interpret -it byte by byte, from the beginning to the end. You never have to go back, -make loops or anything. - - This is what makes byte-coded stack arithmetic so fast. - - - -============================================================================= - Usage license: -============================================================================= - -Copyright © 2003-2005 Juha Nieminen, Joel Yliluoma - - This library is distributed under two distinct usage licenses depending -on the software ("Software" below) which uses the Function Parser library -("Library" below). - The reason for having two distinct usage licenses is to make the library -compatible with the GPL license while still being usable in other non-GPL -(even commercial) software. - -A) If the Software using the Library is distributed under the GPL license, - then the Library can be used under the GPL license as well. - - The Library will be under the GPL license only when used with the - Software. If the Library is separated from the Software and used in - another different software under a different license, then the Library - will have the B) license below. - - Exception to the above: If the Library is modified for the GPL Software, - then the Library cannot be used with the B) license without the express - permission of the author of the modifications. A modified library will - be under the GPL license by default. That is, only the original, - unmodified version of the Library can be taken to another software - with the B) license below. - - The author of the Software should provide an URL to the original - version of the Library if the one used in the Software has been - modified. (http://iki.fi/warp/FunctionParser/) - - This text file must be distributed in its original intact form along - with the sources of the Library. (Documentation about possible - modifications to the library should be put in a different text file.) - -B) If the Software using the Library is not distributed under the GPL - license but under any other license, then the following usage license - applies to the Library: - - 1. This library is free for non-commercial usage. You can do whatever you - like with it as long as you don't claim you made it yourself. - - 2. It is possible to use this library in a commercial program, but in this - case you MUST contact me first (warp@iki.fi) and ask express permission - for this. (Read explanation at the end of the file.) - If you are making a free program or a shareware program with just a - nominal price (5 US dollars or less), you don't have to ask for - permission. - In any case, I DON'T WANT MONEY for the usage of this library. It is - free, period. - - 3. You can make any modifications you want to it so that it conforms your - needs. If you make modifications to it, you have, of course, credits for - the modified parts. - - 4. If you use this library in your own program, you don't have to provide - the source code if you don't want to (ie. the source code of your program - or this library). - If you DO include the source code for this library, this text file - must be included in its original intact form. - - 5. If you distribute a program which uses this library, and specially if you - provide the source code, proper credits MUST be included. Trying to - obfuscate the fact that this library is not made by you or that it is - free is expressly prohibited. When crediting the usage of this library, - it's enough to include my name and email address, that is: - "Juha Nieminen (warp@iki.fi)". Also a URL to the library download page - would be nice, although not required. The official URL is: - http://iki.fi/warp/FunctionParser/ - - 6. And the necessary "lawyer stuff": - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - The software is provided "as is", without warranty of any kind, - express or implied, including but not limited to the warranties of - merchantability, fitness for a particular purpose and noninfringement. - In no event shall the authors or copyright holders be liable for any - claim, damages or other liability, whether in an action of contract, - tort or otherwise, arising from, out of or in connection with the - software or the use or other dealings in the software. - - ---- Explanation of the section 2 of the B) license above: - - The section 2 tries to define "fair use" of the library in commercial -programs. - "Fair use" of the library means that the program is not heavily dependent -on the library, but the library only provides a minor secondary feature -to the program. - "Heavily dependent" means that the program depends so much on the library -that without it the functionality of the program would be seriously -degraded or the program would even become completely non-functional. - - In other words: If the program does not depend heavily on the library, -that is, the library only provides a minor secondary feature which could -be removed without the program being degraded in any considerable way, -then it's OK to use the library in the commercial program. - If, however, the program depends so heavily on the library that -removing it would make the program non-functional or degrade its -functionality considerably, then it's NOT OK to use the library. - - The ideology behind this is that it's not fair to use a free library -as a base for a commercial program, but it's fair if the library is -just a minor, unimportant extra. - - If you are going to ask me for permission to use the library in a -commercial program, please describe the feature which the library will -be providing and how important it is to the program. diff --git a/deal.II/contrib/functionparser/fparser_gmpint.hh b/deal.II/contrib/functionparser/fparser_gmpint.hh new file mode 100644 index 0000000000..fdb44502aa --- /dev/null +++ b/deal.II/contrib/functionparser/fparser_gmpint.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_GMPINT_H_ +#define ONCE_FPARSER_GMPINT_H_ + +#include "fparser.hh" +#include "mpfr/GmpInt.hh" + +class FunctionParser_gmpint: public FunctionParserBase {}; + +#endif diff --git a/deal.II/contrib/functionparser/fparser_mpfr.hh b/deal.II/contrib/functionparser/fparser_mpfr.hh new file mode 100644 index 0000000000..443ec96113 --- /dev/null +++ b/deal.II/contrib/functionparser/fparser_mpfr.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_MPFR_H_ +#define ONCE_FPARSER_MPFR_H_ + +#include "fparser.hh" +#include "mpfr/MpfrFloat.hh" + +class FunctionParser_mpfr: public FunctionParserBase {}; + +#endif diff --git a/deal.II/contrib/functionparser/fpconfig.h b/deal.II/contrib/functionparser/fpconfig.h deleted file mode 100644 index 1eda03e54c..0000000000 --- a/deal.II/contrib/functionparser/fpconfig.h +++ /dev/null @@ -1,67 +0,0 @@ -//=============================== -// Function parser v2.83 by Warp -//=============================== - -// Configuration file -// ------------------ - -// NOTE: -// This file is for the internal use of the function parser only. -// You don't need to include this file in your source files, just -// include "fparser.hh". - -/* - Comment out the following line if your compiler supports the (non-standard) - asinh, acosh and atanh functions and you want them to be supported. If - you are not sure, just leave it (those function will then not be supported). -*/ -#define NO_ASINH - - -/* - Uncomment the following line to disable the eval() function if it could - be too dangerous in the target application. - Note that even though the maximum recursion level of eval() is limited, - it is still possible to write functions using it which take enormous - amounts of time to evaluate even though the maximum recursion is never - reached. This may be undesirable in some applications. -*/ -//#define DISABLE_EVAL - - -/* - Maximum recursion level for eval() calls: -*/ -#define EVAL_MAX_REC_LEVEL 1000 - - -/* - Comment out the following lines out if you are not going to use the - optimizer and want a slightly smaller library. The Optimize() method - can still be called, but it will not do anything. - If you are unsure, just leave it. It won't slow down the other parts of - the library. -*/ -#ifndef NO_SUPPORT_OPTIMIZER -#define SUPPORT_OPTIMIZER -#endif - - -/* - Epsilon value used with the comparison operators (must be non-negative): - (Comment it out if you don't want to use epsilon in comparisons. Might - lead to marginally faster evaluation of the comparison operators, but - can introduce inaccuracies in comparisons.) -*/ -#define FP_EPSILON 1e-14 - - -/* - No member function of FunctionParser is thread-safe. Most prominently, - Eval() is not thread-safe. By uncommenting one of these lines the Eval() - function can be made thread-safe at the cost of a possible small overhead. - The second version requires that the compiler supports the alloca() function, - which is not standard, but is faster. - */ -//#define FP_USE_THREAD_SAFE_EVAL -//#define FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA diff --git a/deal.II/contrib/functionparser/fpconfig.hh b/deal.II/contrib/functionparser/fpconfig.hh new file mode 100644 index 0000000000..e729a12cc5 --- /dev/null +++ b/deal.II/contrib/functionparser/fpconfig.hh @@ -0,0 +1,82 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// Configuration file +// ------------------ + +/* NOTE: + This file is for the internal use of the function parser only. + You don't need to include this file in your source files, just + include "fparser.hh". +*/ + + +/* Uncomment any of these lines or define them in your compiler settings + to enable the correspondent version of the parser. (These are disabled + by default because they rely on C99 functions, and non-standard libraries + in the case pf MPFR and GMP, and they make compiling needlessly slower + and the resulting binary needlessly larger if they are not used in the + program.) +*/ +//#define FP_SUPPORT_FLOAT_TYPE +//#define FP_SUPPORT_LONG_DOUBLE_TYPE +//#define FP_SUPPORT_LONG_INT_TYPE +//#define FP_SUPPORT_MPFR_FLOAT_TYPE +//#define FP_SUPPORT_GMP_INT_TYPE +//#define FP_SUPPORT_COMPLEX_DOUBLE_TYPE +//#define FP_SUPPORT_COMPLEX_FLOAT_TYPE +//#define FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + +/* If you are using FunctionParser_ld or FunctionParser_cld and your compiler + supports the strtold() function, you should uncomment the following line. + */ +//#define FP_USE_STRTOLD + + +/* Uncomment this line or define it in your compiler settings if you want + to disable compiling the basic double version of the library, in case + one of the above types is used but not the double type. (If the double + type is not used, then disabling it makes compiling faster and the + resulting binary smaller.) + */ +//#define FP_DISABLE_DOUBLE_TYPE + +/* + Whether to use shortcut evaluation for the & and | operators: +*/ +#ifndef FP_DISABLE_SHORTCUT_LOGICAL_EVALUATION +#define FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION +#endif + +/* + Comment out the following lines out if you are not going to use the + optimizer and want a slightly smaller library. The Optimize() method + can still be called, but it will not do anything. + If you are unsure, just leave it. It won't slow down the other parts of + the library. +*/ +#ifndef FP_NO_SUPPORT_OPTIMIZER +#define FP_SUPPORT_OPTIMIZER +#endif + +#if defined(FP_SUPPORT_COMPLEX_DOUBLE_TYPE) || defined(FP_SUPPORT_COMPLEX_FLOAT_TYPE) || defined(FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE) +#define FP_SUPPORT_COMPLEX_NUMBERS +#endif + + +/* + No member function of FunctionParser is thread-safe. Most prominently, + Eval() is not thread-safe. By uncommenting one of these lines the Eval() + function can be made thread-safe at the cost of a possible small overhead. + The second version requires that the compiler supports the alloca() function, + which is not standard, but is faster. + */ +//#define FP_USE_THREAD_SAFE_EVAL +//#define FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA diff --git a/deal.II/contrib/functionparser/fpoptimizer.cc b/deal.II/contrib/functionparser/fpoptimizer.cc index 66207296c4..7c41f511ca 100644 --- a/deal.II/contrib/functionparser/fpoptimizer.cc +++ b/deal.II/contrib/functionparser/fpoptimizer.cc @@ -1,2094 +1,11763 @@ -//============================================ -// Function parser v2.82 optimizer by Bisqwit -//============================================ - -/* - NOTE! - ---- - Everything that goes into the #ifndef SUPPORT_OPTIMIZER part - (ie. when SUPPORT_OPTIMIZER is not defined) should be put in - the end of fparser.cc file, not in this file. - - Everything in this file should be inside the #ifdef SUPPORT_OPTIMIZER - block (except the #include "fpconfig.h" line). +/***************************************************************************\ +|* Function Parser for C++ v4.5 *| +|*-------------------------------------------------------------------------*| +|* Function optimizer *| +|*-------------------------------------------------------------------------*| +|* Copyright: Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +/* NOTE: + This file contains generated code (from the optimizer sources) and is + not intended to be modified by hand. If you want to modify the optimizer, + download the development version of the library. */ - -#include "fpconfig.h" - -#ifdef SUPPORT_OPTIMIZER - -#include "fparser.h" -#include "fptypes.h" -using namespace FUNCTIONPARSERTYPES; - -#include -#include +#include "fpconfig.hh" +#ifdef FP_SUPPORT_OPTIMIZER +#include "fparser.hh" +#include "extrasrc/fptypes.hh" +#include "extrasrc/fpaux.hh" +#define l64 y91 a), +#define l54 if(n5 iK3 +#define l44 ,{ReplaceParams, +#define l34 cTan iO +#define l24 "Found " +#define l14 ,cPow, +#define l04 stackpos +#define iZ3 sim.nY 1, +#define iY3 ,tree,info +#define iX3 "dup(%u) " +#define iW3 "%d, cost " +#define iV3 "PUSH "i13( +#define iU3 "immed "<< +#define iT3 mFuncParsers +#define iS3 e62{assert +#define iR3 stderr +#define iQ3 sep2=" " +#define iP3 FPHASH_CONST +#define iO3 .SetParamsMove( +#define iN3 cache_needed[ +#define iM3 fprintf +#define iL3 ::cout<<"Applying " +#define iK3 HANDLE_UNARY_CONST_FUNC +#define iJ3 1)i61){ +#define iI3 c_count +#define iH3 s_count +#define iG3 2)lS 2* +#define iF3 tmp.yH1 +#define iE3 tmp2.nJ +#define iD3 ,tZ 2, +#define iC3 (p0 n51&& +#define iB3 else nM +#define iA3 max.val +#define i93 eK2 if( +#define i83 tree c9 +#define i73 sim.x61 +#define i63 ].swap( +#define i53 codes[b +#define i43 whydump +#define i33 );}case +#define i23 :if(eQ3 +#define i13 ;DumpTree +#define i03 :{lX1 r +#define tZ3 nparams +#define tY3 cLog iO +#define tX3 l4 16,1, +#define tW3 l4 0,1, +#define tV3 0x12 nH +#define tU3 ,0,0x16},{ +#define tT3 nQ 0, +#define tS3 cAbs nQ +#define tR3 false;} +#define tQ3 nE1 cF1 +#define tP3 xF1++b) +#define tO3 =false; +#define tN3 {data-> +#define tM3 info. +#define tL3 b.Value) +#define tK3 b.Opcode +#define tJ3 ,tB info +#define tI3 tree xD +#define tH3 xD cMul); +#define tG3 ParamHolder +#define tF3 size() +#define tE3 .second +#define tD3 ]tE3 +#define tC3 ].first +#define tB3 Ne_Mask +#define tA3 Gt_Mask +#define t93 Lt_Mask +#define t83 opcode, +#define t73 resize( +#define t63 t33 nC1; +#define t53 xD cond nC +#define t43 );}else +#define t33 lE2 a) +#define t23 AddFrom( +#define t13 max.known +#define t03 =fp_pow( +#define eZ3 (tree)!= +#define eY3 );if( +#define eX3 public: +#define eW3 pclone +#define eV3 Others +#define eU3 --cN1. +#define eT3 cOr,l6 +#define eS3 newpow +#define eR3 if(p0 yN +#define eQ3 &*(*x5 n71){ +#define eP3 ,lT 1,0, +#define eO3 lE2 1) +#define eN3 (op1== +#define eM3 change +#define eL3 (count +#define eK3 133,2, +#define eJ3 Needs +#define eI3 byteCode +#define eH3 (p1 nC1 +#define eG3 lS1 nC== +#define eF3 cLog2by +#define eE3 factor_t +#define eD3 (*x5)[0].info +#define eC3 tree nC1 +#define eB3 value1 +#define eA3 Finite +#define e93 fp_mod( +#define e83 )const +#define e73 (e83{ +#define e63 else{if( +#define e53 xK());nD +#define e43 TreeCountItem +#define e33 if(op== +#define e23 yN val)< +#define e13 p yN val +#define e03 c9 ifp2 +#define cZ3 cAbsNot +#define cY3 stackptr +#define cX3 cLog);xL +#define cW3 switch(tM +#define cV3 p1 cK p1); +#define cU3 );p1 c9 ifp1 +#define cT3 .empty() +#define cS3 opcodes +#define cR3 did_muli +#define cQ3 xD data. +#define cP3 &Value){ +#define cO3 yH const +#define cN3 used[b] +#define cM3 sizeof( +#define cL3 cAbsIf, +#define cK3 cNotNot, +#define cJ3 18,2 eN1 +#define cI3 c22 iE, +#define cH3 450998, +#define cG3 cAtan2, +#define cF3 cExp2 nQ +#define cE3 lJ 2},0, +#define cD3 middle2 +#define cC3 ::string +#define cB3 fp_equal( +#define cA3 ;if(cB3 +#define c93 (iE2 l8 1)xC1 +#define c83 FP_GetOpcodeName( +#define c73 default: +#define c63 n31;case +#define c53 tG));nV +#define c43 range nJ3 +#define c33 range=x22 +#define tF2 .min.val +#define tE2 )?0:1))l7 +#define tD2 .n_int_sqrt +#define tC2 ;}else{x5=new +#define tB2 (half&63)-1; +#define tA2 ),0},{ +#define t92 ),Value +#define t82 data;data. +#define t72 MakeNEqual +#define t62 (exponent +#define t52 Dump(std:: +#define t42 isInteger( +#define t32 Comparison +#define t22 needs_flip +#define t12 value] +#define t02 ~size_t(0) +#define eZ2 xJ1 xS+1); +#define eY2 TopLevel) +#define eX2 +#define eU2 *)&*start_at; +#define eT2 Rule&rule, +#define eS2 >::res,b8< +#define eR2 continue;} +#define eQ2 c9 tree); +#define eP2 mul_item +#define eO2 innersub +#define eN2 cbrt_cost +#define eM2 best_cost +#define eL2 fp_min(yL +#define eK2 tree t31);} +#define eJ2 tree))cZ +#define eI2 condition +#define eH2 per_item +#define eG2 item_type +#define eF2 first2 +#define eE2 l4 18,1, +#define eD2 lJ 1},0, +#define eC2 Decision +#define eB2 not_tree +#define eA2 group_by +#define e92 exponent= +#define e82 ->second +#define e72 :xL iV2( +#define e62 eJ&tree) +#define e52 targetpos +#define e42 ParamSpec +#define e32 rhs.hash2;} +#define e22 rhs.hash1 +#define e12 struct +#define e02 Forget() +#define cZ2 &&cond e8)) +#define cY2 source_tree +#define cX2 nC==cLog2&& +#define cW2 ,eL1 0x1 nH +#define cV2 )lS 3*3* +#define cU2 (tK==eA3&& +#define cT2 );yF3 +#define cS2 ;iB.Remember( +#define cR2 +#define cQ2 );sim.nY 2, +#define cP2 )continue +#define cO2 CodeTree lW +#define cN2 p1_evenness +#define cM2 isNegative( +#define cL2 yN known&&( +#define cK2 neg_set +#define cJ2 cNop,cNop}} +#define cI2 cTanh,cNop, +#define cH2 NewHash +#define cG2 >e12 cA< +#define cF2 matches +#define cE2 .match_tree +#define cD2 cH1 void*)& +#define cC2 cSin iO +#define cB2 cTan nQ +#define cA2 ,cLog nQ +#define c92 cCos nQ +#define c82 long value +#define c72 (std::move( +#define c62 (xX l8 a)xF +#define c52 negated +#define c42 Specializer +#define c32 params +#define c22 18,2, +#define c12 coshtree +#define c02 sinhtree +#define yZ2 best_score +#define yY2 mulvalue +#define yX2 pow_item +#define yW2 subgroup +#define yV2 nC==cPow&&tO +#define yU2 PowiResult +#define yT2 ))y53 +#define yS2 0));c23 +#define yR2 maxValue +#define yQ2 minValue +#define yP2 div_tree +#define yO2 pow_tree +#define yN2 iV2 nT +#define yM2 preserve +#define yL2 PullResult() +#define yK2 dup_or_fetch +#define yJ2 nominator] +#define yI2 test_order +#define yH2 parampair +#define yG2 yH2, +#define yF2 .param_count +#define yE2 minimum_need +#define yD2 shift(index) +#define yC2 {std::cout<< +#define yB2 rulenumber +#define yA2 l2 16,2, +#define y92 cTanh nQ +#define y82 l14 l2 2,2, +#define y72 ,cPow iO +#define y62 cSinh nQ +#define y52 cIf,n91 3, +#define y42 cInv,lT 1, +#define y32 constraints= +#define y22 GetDepth() +#define y12 factor_immed +#define y02 changes +#define xZ2 c9 cond l8 +#define xY2 Become y91 +#define xX2 for(xK3 +#define xW2 exp_diff +#define xV2 ExponentInfo +#define xU2 lower_bound( +#define xT2 factor +#define xS2 is_logical +#define xR2 newrel_and +#define xQ2 )){data x7 lN +#define xP2 Suboptimal +#define xO2 eK[c eA +#define xN2 res_stackpos +#define xM2 half_pos +#define xL2 ifdata.ofs +#define xK2 i8 push_back( +#define xJ2 n31 true;} +#define xI2 >>1)):( +#define xH2 CodeTreeData +#define xG2 exponent) +#define xF2 yN known) +#define xE2 multiply( +#define xD2 )y3 cPow) +#define xC2 var_trees +#define xB2 nB OPCODE +#define xA2 CodeTree& +#define x92 parent_opcode +#define x82 GetParam(a eS +#define x72 {cW start_at; +#define x62 changed=true; +#define x52 log2_exponent +#define x42 iV2(2))); +#define x32 lR,tH)tH2 +#define x22 iV2(0.0)) +#define x12 dup_fetch_pos +#define x02 IsNever cL lC +#define nZ2 cSin nQ +#define nY2 Value_EvenInt +#define nX2 AddCollection +#define nW2 ConditionType +#define nV2 n31 Unknown;} +#define nU2 1 y7 i8 size( +#define nT2 (iF2 +#define nS2 iA|nT2) +#define nR2 SpecialOpcode +#define nQ2 =i e82. +#define nP2 yN known&&p +#define nO2 assimilated +#define nN2 denominator +#define nM2 fraction +#define nL2 DUP_BOTH(); +#define nK2 0x80000000u +#define nJ2 IsDescendantOf +#define nI2 TreeCounts +#define nH2 SetOpcode( +#define nG2 found_log2 +#define nF2 div_params +#define nE2 immed_sum +#define nD2 lE3++IP] +#define nC2 sim n92 +#define nB2 ;sim.Push( +#define nA2 ,cMul l3 +#define n92 .Eat(1, +#define n82 OPCODE(opcode) +#define n72 FactorStack xK +#define n62 Rehash(false); +#define n52 IsAlways cL lC +#define n42 cEqual, +#define n32 cNotNot nQ +#define n22 cNot nQ +#define n12 DumpHashesFrom +#define n02 replacing_slot +#define lZ2 RefParams +#define lY2 if_always[ +#define lX2 WhatDoWhenCase +#define lW2 exponent_immed +#define lV2 new_base_immed +#define lU2 base_immed +#define lT2 );std::cout<< +#define lS2 ||op1== +#define lR2 l8 0)); +#define lQ2 data[a tD3 +#define lP2 if(newrel_or== +#define lO2 .AddOperation( +#define lN2 DUP_ONE(apos); +#define lM2 flipped +#define lL2 .UseGetNeeded( +#define lK2 ,fp_max(yL); +#define lJ2 else if( +#define lI2 lJ2!nT3 +#define lH2 synth.PushImmed( +#define lG2 (*x5)[a].info +#define lF2 ,PowiCache&iB, +#define lE2 tree l8 +#define lD2 <(iV2(1), +#define t61 x22{xO +#define t51 (&*start_at){x5=( +#define t41 DelParam(a);} +#define t31 tK2 a +#define t21 a)i61) +#define t11 n82); +#define t01 0.5)xD2;lC +#define eZ1 std::cout<<"POP " +#define eY1 stack[iV1- +#define eX1 stack.push_back( +#define eW1 ,l0 2, +#define eV1 CollectionSet xK +#define eU1 xK())y3 cMul);lC +#define eT1 .Rehash(); +#define eS1 ParsePowiMuli +#define eR1 MaxChildDepth +#define eQ1 iF2 a +#define eP1 std::pair +#define eO1 cLess,l2 +#define eN1 ,n63 281856, +#define eM1 cNEqual, +#define eL1 cPow,lA +#define eK1 Sign_Negative +#define eJ1 Value_Logical +#define eI1 yD MakeFalse,{l5 +#define eH1 new_factor_immed +#define eG1 occurance_pos +#define eF1 exponent_hash +#define eE1 exponent_list +#define eD1 CollectMulGroup( +#define eC1 source_set +#define eB1 exponent,yT3 +#define eA1 operator +#define e91 FindAndDup(tree); +#define e81 ParamSpec_Extract +#define e71 retry_anyparams_3 +#define e61 retry_anyparams_2 +#define e51 needlist_cached_t +#define e41 lJ 2}lA2 +#define e31 lJ 1}lA2 +#define e21 CodeTreeImmed xK( +#define e11 by_float_exponent +#define e01 fp_equal t62 +#define cZ1 new_exp +#define cY1 end()&&i->first== +#define cX1 return BecomeZero; +#define cW1 return BecomeOne; +#define cV1 if(lQ.tF3<=n1) +#define cU1 addgroup +#define cT1 found_log2by +#define cS1 nC==cZ3) +#define cR1 if(keep_powi +#define cQ1 l22) +#define cP1 branch1_backup +#define cO1 branch2_backup +#define cN1 NeedList +#define cM1 tree.SetParam( +#define cL1 exponent_map +#define cK1 plain_set +#define cJ1 rangehalf +#define cI1 ;synth.StackTopIs( +#define cH1 (const +#define cG1 cH1 iV2& +#define cF1 eT1 tI3 op1);tree.DelParams() +#define cE1 .GetParamCount()== +#define cD1 LightWeight( +#define cC1 if(value +#define cB1 xW3 yX +#define cA1 xW3 static +#define c91 m yN set(fp_ceil);tV +#define c81 m yN val +#define c71 m yN known +#define c61 )yH2 tE3; +#define c51 ::MakeTrue +#define c41 should_regenerate=true; +#define c31 should_regenerate, +#define c21 Collection +#define c11 RelationshipResult +#define c01 Subdivide_Combine( +#define yZ1 e83 yR +#define yY1 rhs yZ1 hash1 +#define yX1 PositionalParams,0 +#define yW1 best_sep_factor +#define yV1 needlist_cached +#define yU1 inline iF2 +#define yT1 252421 nP 24830 +#define yS1 t83 bool pad +#define yR1 MakesInteger( +#define yQ1 mulgroup. +#define yP1 .AddParamMove( +#define yO1 =comp.AddItem(atree +#define yN1 tree i61 cL +#define yM1 ByteCodeSynth xK&synth) +#define yL1 lF3 FPoptimizer_Optimize +#define yK1 (long double) +#define yJ1 const iV2&value +#define yI1 best_sep_cost +#define yH1 AddParamMove(tree); +#define yG1 MultiplicationRange +#define yF1 pihalf_limits +#define yE1 n_stacked +#define yD1 cH2.hash1 +#define yC1 AnyParams_Rec +#define yB1 ):e2(),std xV3< +#define yA1 i13 cJ +#define y91 (lE2 +#define y81 Become(value l8 0)) +#define y71 always_sincostan +#define y61 Recheck_RefCount_Div +#define y51 Recheck_RefCount_Mul +#define y41 mulgroup;mulgroup xD +#define y31 MultiplyAndMakeLong( +#define y21 iV2(0) +#define y11 covers_plus1 +#define y01 if(synth.FindAndDup( +#define xZ1 SynthesizeParam( +#define xY1 grammar_func +#define xX1 cOr l3 16,1, +#define xW1 252180 nP 281854 +#define xV1 l2 0,2,165888 nP +#define xU1 l1 tV3 +#define xT1 Modulo_Radians}, +#define xS1 PositionType +#define xR1 CollectionResult +#define xQ1 ;m yN template set_if< +#define xP1 ByteCode,size_t&IP,size_t limit,size_t y1 +#define xO1 iT2))break;nT3*= +#define xN1 xW3 bool +#define xM1 const_offset +#define xL1 inline TriTruthValue +#define xK1 stacktop_desired +#define xJ1 SetStackTop( +#define xI1 }inline +#define xH1 FPoptimizer_ByteCode +#define xG1 1)?(poly^( +#define xF1 GetParamCount(); +#define xE1 public e2,public std xV3< +#define xD1 y21) +#define xC1 xF leaf2 l8 +#define xB1 c22 529654 nP +#define xA1 cond_type +#define x91 fphash_value_t +#define x81 Recheck_RefCount_RDiv +#define x71 cMul);tmp.nJ 0));tmp. +#define x61 SwapLastTwoInStack(); +#define x51 fPExponentIsTooLarge( +#define x41 CollectMulGroup_Item( +#define x31 pair +#define x21 nL xJ1 xS-1); +#define x11 covers_full_cycle +#define x01 AssembleSequence( +#define nZ1 <& +#define nR1 i31 xK3 +#define nQ1 has_good_balance_found +#define nP1 n_occurrences +#define nO1 found_log2_on_exponent +#define nN1 covers_minus1 +#define nM1 needs_resynth +#define nL1 immed_product +#define nK1 ,2,1 xN if(found[data. +#define nJ1 ;xW3 +#define nI1 yJ3 bitmask& +#define nH1 Sign_Positive +#define nG1 SetParamMove( +#define nF1 CodeTreeImmed(iV2( +#define nE1 changed_if +#define nD1 0,xG2;DelParam(1); +#define nC1 .GetImmed() +#define nB1 for iA1 a=0;a0;)if( +#define n31 ;return +#define n21 n31 xP2;} +#define n11 >::Optimize(){} +#define n01 n_as_tanh_param +#define lZ1 opposite= +#define lY1 x91( +#define lX1 MatchResultType +#define lW1 needs_sincos +#define lV1 resulting_exponent +#define lU1 val):Value(Value:: +#define lT1 Unknown:c73;} +#define lS1 GetParam(a) +#define lR1 inverse_nominator] +#define lQ1 cMul l3 0,1, +#define lP1 tree yP1 +#define lO1 AddFunctionOpcode( +#define lN1 SetParams(l02)); +#define lM1 o<<"("<){int mStackPtr=0; +#define l21 FPoptimizer_Grammar +#define l11 AddOperation(cInv,1,1 xN} +#define l01 GetPositivityInfo eZ3 +#define iZ ParamSpec_SubFunctionData +#define iY iA1 a=c8 a-->0;) +#define iX PositionalParams_Rec +#define iW yD MakeNotNotP1,l5:: +#define iV ,cMul x4 +#define iU eT1 tI3 iE2 nC);tree. +#define iT yD MakeNotNotP0,l5:: +#define iS lE3 xL2+ +#define iR DumpTreeWithIndent(*this); +#define iQ switch(type y33 cond_or: +#define iP ;if(eY2 tM3 SaveMatchedParamIndex( +#define iO ,l4 2,1, +#define iN CalculateResultBoundaries( +#define iM i31 iF2 Compare> +#define iL cE3 0x0},{{1, +#define iK edited_powgroup +#define iJ iA1 a=xF1 a +#define iI has_unknown_max +#define iH has_unknown_min +#define iG static const c23 +#define iF synthed_tree +#define iE 408964 nP 24963 +#define iD SelectedParams,0},0,0x0},{{ +#define iC collections +#define iB cache +#define iA ;xK2 nK2 +#define i9 )iA); +#define i8 ByteCode. +#define i7 ;pow xD cLog);tree tH3 +#define i6 goto ReplaceTreeWithOne;case +#define i5 ]);yE3 +#define i4 !=xB)return lY2 +#define i3 e11.data +#define i2 l53 xH2( +#define i1 needs_sinhcosh +#define i0 cAdd x4 +#define tZ cAdd l3 0, +#define tY tA2 iV2( +#define tX xW3 nA +#define tW int_exponent_t +#define tV return m;}case +#define tU MakeFalse,l5:: +#define tT lT2 std::endl;DumpHashes( +#define tS ,ByteCode,IP,limit,y1,stack); +#define tR matched_params +#define tQ [n1 tC3=true;lQ[n1 tD3 +#define tP l21::Grammar* +#define tO powgroup l8 +#define tN );p2 cK p2);tI3 l93 nC);cZ} +#define tM GetLogicalValue y91 +#define tL t02&&found[data. +#define tK valueType +#define tJ xE AnyParams, +#define tI =iN lE2 +#define tH eO3 nC1 +#define tG (tH) +#define tF nF1( +#define tE has_mulgroups_remaining +#define tD by_exponent +#define tC const iZ +#define tB MatchInfo xK& +#define tA Rehash();iA2.push_back( +#define t9 best_factor +#define t8 RootPowerTable xK::RootPowers[ +#define t7 MatchPositionSpec_AnyParams xK +#define t6 cLessOrEq,l2 +#define t5 lF3 FPoptimizer_CodeTree +#define t4 n_as_sinh_param +#define t3 n_as_cosh_param +#define t2 is_signed +#define t1 result_positivity +#define t0 yN known tO3 +#define eZ biggest_minimum +#define eY 142455 nP 141449, +#define eX cond_tree +#define eW else_tree +#define eV then_tree +#define eU sequencing +#define eT string c83 +#define eS );bool needs_cow=GetRefCount()>1; +#define eR nM iV2(-nR3 +#define eQ {AdoptChildrenWithSameOpcode(tree); +#define eP lJ3,l2 c22 +#define eO ;AddParamMove( +#define eN yN known&&p0 yN val<=fp_const_negativezero xK()) +#define eM tree.GetParamCount() +#define eL :goto ReplaceTreeWithZero;case +#define eK relationships +#define eJ CodeTree xK +#define eI ,2,122999 nP 139399, +#define eH std xV3 +#define eG if_stack +#define eF (l02));yQ1 Rehash(); +#define eE n_as_sin_param +#define eD n_as_cos_param +#define eC PowiResolver:: +#define eB cIf,tW3 +#define eA ].relationship +#define e9 PACKED_GRAMMAR_ATTRIBUTE; +#define e8 .BalanceGood +#define e7 AddParamMove(yW2 +#define e6 back().endif_location +#define e5 x91 key +#define e4 AddParamMove(mul); +#define e3 130,1, +#define e2 MatchPositionSpecBase +#define e1 l53 CodeTree( +#define e0 smallest_maximum +#define cZ goto redo; +#define cY ReplaceTreeWithParam0; +#define cX factor_needs_rehashing +#define cW MatchPositionSpecBaseP +#define cV xK3 tK1::yV3 +#define cU e81 xK(nN.param_list, +#define cT 243,244,245,246,249,250,251,253,255,256,257,258,259}};} +#define cS ];};extern"C"{ +#define cR 79,122,123,160,161,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240, +#define cQ 27,28,29,30,31,32,33,35,36, +#define cP const ParamSpec_SubFunction +#define cO const ParamSpec_ParamHolder +#define cN otherhalf +#define cM StackState +#define cL )return false; +#define cK eT1 lP1 +#define cJ (tree lT2"\n"; +#define cI const SequenceOpCode xK +#define cH paramholder_matches[nZ] +#define cG MatchPositionSpec_PositionalParams xK +#define cF lC2 tree,std::ostream&o +#define cE paramholder_matches. +#define cD iV2(1.5)*fp_const_pi xK() +#define cC xB,l5::Never yD xB,l5::Never} +#define cB CalculatePowiFactorCost( +#define cA ImmedHashGenerator +#define c9 .AddParam( +#define c8 eM; +#define c7 ::map > +#define c6 ComparisonSetBase:: +#define c5 AddParamMove(comp.cK1[a].value); +#define c4 ,yA2 528503 nP 24713, +#define c3 T1,xK3 T2>inline iG2()( +#define c2 has_nonlogical_values +#define c1 from_logical_context) +#define c0 AnyParams,0 l91 +#define yZ for iA1 a=xX.xF1 a-->0;) +#define yY POWI_CACHE_SIZE +#define yX static inline eJ +#define yW ++IP;eR2 if(iT1==cS3. +#define yV .FoundChild +#define yU BalanceResultType +#define yT xM3(0),Opcode( +#define yS );void lO1 iF2 t83 c42< +#define yR {return +#define yQ const yR data-> +#define yP +=fp_const_twopi xK(); +#define yO fp_const_twopi xK()eY3 +#define yN .max. +#define yM eJ tmp,tmp2;tmp2 xD +#define yL fp_sin(min),fp_sin(max)) +#define yK m.min. +#define yJ lO2 GetOpcode(), +#define yI for iA1 a=0;aParams +#define xX branch1 +#define xW );eR2 if(list.first nC1==iV2( +#define xV nN yF2 +#define xU =fp_cosh nU3;c81=fp_cosh(c81); +#define xT {nI2.erase(i);eR2 +#define xS StackTop +#define xR FPOPT_autoptr +#define xQ +=nT3 n31 nT3;}xW3 inline iV2 +#define xP int_exponent +#define xO tree.ReplaceWithImmed( +#define xN )cI1*this)n31;} +#define xM GetStackTop()- +#define xL sim.AddConst( +#define xK +#define xJ .SetParam(0,l93 lR2 eJ p1;p1 xD +#define xI newnode +#define xH has_highlevel_opcodes +#define xG eD2 0x0},{{ +#define xF .IsIdenticalTo( +#define xE ,cAdd, +#define xD .nH2 +#define xC {if(needs_cow){l61 goto +#define xB Unchanged +#define xA cF=std::cout +#define x9 best_selected_sep +#define x8 i31>void FunctionParserBase< +#define x7 ->Recalculate_Hash_NoRecursion();} +#define x6 xF1++a)if(ApplyGrammar(tX2,t33, +#define x5 position +#define x4 l3 2,1, +#define x3 ;iE3 0));tmp xD cInv);tmp yP1 tmp2)n31 +#define x2 nB1{c23 +#define x1 std xV3 +#define x0 TestImmedConstraints y23 constraints,tree)cL +#define nZ paramholder_index +#define nY x61 tQ2 +#define nX )){tree.FixIncompleteHashes();} +#define nW );cR1){nC2 cInv cT2 xL-1 xD2;lC +#define nV return true;case +#define nU occurance_counts +#define nT >p tI a)eY3 p. +#define nS -->0;){lC2 powgroup=lS1;if(powgroup +#define nR lT3 i61 +#define nQ ,l0 1, +#define nP ,{2, +#define nO const FPoptimizer_CodeTree::eJ&tree +#define nN model_tree +#define nM return c23( +#define nL ){using lF3 FUNCTIONPARSERTYPES; +#define nK eH&lZ2 +#define nJ AddParam y91 +#define nI ConstantFolding_LogicCommon(tree,c6 +#define nH },{{2, +#define nG nR1 Ref>inline void xR:: +#define nF AnyParams,1},0,0x0},{{ +#define nE ):data(new xH2 xK( +#define nD goto do_return;} +#define nC .GetOpcode() +#define nB FUNCTIONPARSERTYPES:: +#define nA xH2 xK::xH2( +#define n9 b;}};i31>e12 Comp(iV2( +#define n2 DumpParams xK y23 data.param_list,yL3 data yF2,o); +#define n1 restholder_index +#define n0 eJ exponent;exponent xD cMul tF1 c9 +#define lZ lR eY3 fp_nequal(tmp,xD1){xO iV2(1)/tmp);nD}lC +#define lY :if(ParamComparer xK()(Params[1],Params[0])){std::swap(Params[0],Params[1]);Opcode= +#define lX +#define lW xK tmp;tmp xD cPow);tmp.nJ 0));tmp.yC iV2( +#define lV tR1,0x0}, +#define lU AddParamMove(pow l8 1));pow tK2 1);pow eT1 tree.nG1 0,pow);goto NowWeAreMulGroup;} +#define lT GroupFunction,0},lV{{ +#define lS tG1 1)/iV2( +#define lR lE2 0)nC1 +#define lQ restholder_matches +#define lP yD1|=key;x91 crc=(key>>10)|(key<<(64-10))lF1((~lY1 crc))*3)^1234567;}}; +#define lO nE1;nE1 iP2 nE1.AddParamMove y91 0));nE1 c9 xX l8 +#define lN xW3 eJ::CodeTree( +#define lM cM1 0,lE2 0)lR2 cM1 1,CodeTreeImmed( +#define lL lX void ByteCodeSynth xK::lO1 iF2 t83 c42< +#define lK cMul,lT 2, +#define lJ cMul,AnyParams, +#define lI y91 0)i61&&eO3 i61){xO +#define lH iN tmp i33 +#define lG :eM3=comp.AddRelationship(atree l8 0),atree l8 1),c6 +#define lF cPow,l0 2 +#define lE xK3 iV2>inline iG2()cG1 xN3 iV2&b)yR a +#define lD {c23 m tI 0)); +#define lC break;case +#define lB tZ1 eJ:: +#define lA yX1},0, +#define l9 l1 0x0 nH +#define l8 .GetParam( +#define l7 ;eJ nE1;nE1 iP2 nE1 iO3 tree.l02));nE1 eT1 tI3 +#define l6 SelectedParams,0},0,0x0 nH +#define l5 RangeComparisonData +#define l4 yX1 l91 +#define l3 ,AnyParams,0}}l44 +#define l2 yX1}}l44 +#define l1 cMul,SelectedParams,0},0, +#define l0 lA 0x0},{{ +#ifdef _MSC_VER +typedef +iF2 +int +iZ1; +#else +#include +typedef +uint_least32_t +iZ1; +#endif +lF3 +crc32{enum{startvalue=0xFFFFFFFFUL,poly=0xEDB88320UL} +;i31 +iZ1 +crc>e12 +b8{enum{b1=(crc&xG1 +crc +xI2 +crc>>1),b2=(b1&xG1 +b1 +xI2 +b1>>1),b3=(b2&xG1 +b2 +xI2 +b2>>1),b4=(b3&xG1 +b3 +xI2 +b3>>1),b5=(b4&xG1 +b4 +xI2 +b4>>1),b6=(b5&xG1 +b5 +xI2 +b5>>1),b7=(b6&xG1 +b6 +xI2 +b6>>1),res=(b7&xG1 +b7 +xI2 +b7>>1)} +;} +;inline +iZ1 +update(iZ1 +crc,iF2 +b){ +#define B4(n) b8::res +#define R(n) B4(n),B4(n+4),B4(n+8),B4(n+12) +static +const +iZ1 +table[256]={R(0x00),R(0x10),R(0x20),R(0x30),R(0x40),R(0x50),R(0x60),R(0x70),R(0x80),R(0x90),R(0xA0),R(0xB0),R(0xC0),R(0xD0),R(0xE0),R(0xF0)} +; +#undef R +#undef B4 +return((crc>>8))^table[(crc^b)&0xFF];xI1 +iZ1 +calc_upd(iZ1 +c,const +iF2 +char*buf,size_t +size){iZ1 +value=c;for +iA1 +p=0;pclass +xR{eX3 +xR():p(0){} +xR(Ref*b):p(b){xL3} +xR +cH1 +xR&b):p(b.p){xL3 +xI1 +Ref&eA1*(yZ1*p;xI1 +Ref*eA1->(yZ1 +p;} +xR&eA1=(Ref*b){Set(b)n31*this;} +xR&eA1=cH1 +xR&b){Set(b.p)n31*this;} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +xR(xR&&b):p(b.p){b.p=0;} +xR&eA1=(xR&&b){if(p!=b.p){e02;p=b.p;b.p=0;} +return*this;} +#endif +~xR(){e02 +lL3 +UnsafeSetP(Ref*newp){p=newp +lL3 +swap(xR&b){Ref*tmp=p;p=b.p;b.p=tmp;} +private:inline +static +void +Have(Ref*p2);inline +void +e02;inline +void +xL3 +inline +void +Set(Ref*p2);private:Ref*p;} +;nG +e02{if(!p)return;p->xM3-=1;if(!p->xM3)delete +p;} +nG +Have(Ref*p2){if(p2)++(p2->xM3);} +nG +Birth(){Have(p);} +nG +Set(Ref*p2){Have(p2);e02;p=p2;} +#endif #include -#include -using namespace std; - +e12 +Compare2ndRev{nR1 +T>inline +iG2()cH1 +T&xN3 +T&b +yZ1 +a +tE3>b +tE3;} +} +;e12 +Compare1st{nR1 +c3 +const +nS1 +xN3 +nS1 +b +yZ1 +a.first +typedef +uint_fast64_t +x91; +#define FPHASH_CONST(x) x##ULL +#endif +lF3 +FUNCTIONPARSERTYPES{e12 +fphash_t{x91 +hash1,hash2;fphash_t():hash1(0),hash2(0){} +fphash_t +cH1 +x91&xN3 +x91&b):hash1(a),hash2(b){} +iG2==cH1 +fphash_t&yY1==e22&&hash2==e32 +iG2!=cH1 +fphash_t&yY1!=e22||hash2!=e32 +iG2 +#include +lF3 +l21{e12 +Grammar;} +lF3 +xH1{xW3 +class +ByteCodeSynth;} +t5{xW3 +class +CodeTree +nJ1 +e12 +xH2 +nJ1 +class +CodeTree{typedef +xRDataP;DataP +data;eX3 +CodeTree();~CodeTree();e12 +OpcodeTag{} +;e1 +xB2 +o,OpcodeTag);e12 +FuncOpcodeTag{} +;e1 +xB2 +o,iF2 +f,FuncOpcodeTag);e12 +xO3{} +;e1 +const +iV2&v,xO3); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +e1 +iV2&&v,xO3); +#endif +e12 +VarTag{} +;e1 +iF2 +varno,VarTag);e12 +CloneTag{} +;e1 +lG3 +b,CloneTag);void +GenerateFrom +cH1 +xK3 +FunctionParserBase +xK::Data&data,bool +keep_powi=false);void +GenerateFrom +cH1 +xK3 +FunctionParserBase +xK::Data&data,const +x1&xC2,bool +keep_powi=false);void +SynthesizeByteCode(std +xV3&eI3,std +xV3 +xK&immed,size_t&stacktop_max);void +SynthesizeByteCode(xH1 +yG3&synth,bool +MustPopTemps=true +e83;size_t +SynthCommonSubExpressions(xH1::yM1 +const;void +SetParams +cH1 +x1&xP3 +SetParamsMove(x1&tA1 +CodeTree +GetUniqueRef(); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +void +SetParams(x1&&tA1 +#endif +void +SetParam +iA1 +which,lG3 +b);void +nG1 +size_t +which,xA2 +b);void +AddParam +cH1 +xA2 +param);void +AddParamMove(xA2 +param);void +AddParams +cH1 +x1&xP3 +AddParamsMove(x1&xP3 +AddParamsMove(x1&lZ2,size_t +n02);void +DelParam +iA1 +index);void +DelParams();void +Become +cH1 +xA2 +b);inline +size_t +GetParamCount(yZ1 +l02).tF3;xI1 +xA2 +GetParam +iA1 +n)yR +l02)[n];xI1 +lG3 +GetParam +iA1 +n +yZ1 +l02)[n];xI1 +void +nH2 +xB2 +o)tN3 +Opcode=o;xI1 +xB2 +GetOpcode()yQ +Opcode;xI1 +nB +fphash_t +GetHash()yQ +Hash;xI1 +const +x1&l02 +yZ1 +xY;xI1 +x1&l02)yR +xY;xI1 +size_t +y22 +yQ +Depth;xI1 +const +iV2&GetImmed()yQ +Value;xI1 +iF2 +GetVar()yQ +l12 +xI1 +iF2 +GetFuncNo()yQ +l12 +xI1 +bool +IsDefined(yZ1 +GetOpcode()!=nB +cNop;xI1 +bool +IsImmed(yZ1 +GetOpcode()==nB +cImmed;xI1 +bool +IsVar(yZ1 +GetOpcode()==nB +l03;xI1 +iF2 +GetRefCount()yQ +xM3 +lL3 +ReplaceWithImmed +cG1 +i);void +Rehash(bool +constantfolding=true);void +Sort();inline +void +Mark_Incompletely_Hashed()tN3 +Depth=0;xI1 +bool +Is_Incompletely_Hashed()yQ +Depth==0;xI1 +const +tP +GetOptimizedUsing()yQ +l32;xI1 +void +SetOptimizedUsing +cH1 +tP +g)tN3 +l32=g;} +bool +RecreateInversionsAndNegations(bool +prefer_base2=false);void +FixIncompleteHashes();void +swap(xA2 +b){data.swap(b.data);} +bool +IsIdenticalTo +cH1 +xA2 +b +e83;void +l61} +nJ1 +e12 +xH2{int +xM3;xB2 +Opcode +iU2 +Value;iF2 +l12 +eH +Params;nB +fphash_t +Hash;size_t +Depth;const +tP +l32;xH2();xH2 +cH1 +xH2&b);i2 +xB2 +o);i2 +xB2 +o,iF2 +f);i2 +const +iV2&i); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +i2 +iV2&&i);xH2(xH2&&b); +#endif +bool +IsIdenticalTo +cH1 +xH2&b +e83;void +Sort();void +Recalculate_Hash_NoRecursion();private:void +eA1=cH1 +xH2&b);} +nJ1 +yX +CodeTreeImmed +cG1 +i)yR +eJ(i +yA +xO3());} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +cB1 +CodeTreeImmed(iV2&&i)yR +eJ +c72 +i)yA +xO3());} +#endif +cB1 +CodeTreeOp(xB2 +opcode)yR +eJ(opcode +yA +OpcodeTag());} +cB1 +CodeTreeFuncOp(xB2 +t83 +iF2 +f)yR +eJ(t83 +f +yA +FuncOpcodeTag());} +cB1 +CodeTreeVar +nT2 +varno)yR +eJ(varno +yA +VarTag());} +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +tZ1 +DumpHashes(xA)xR3 +DumpTree(xA)xR3 +DumpTreeWithIndent(xA,const +std +cC3&indent="\\" +); +#endif +} +#endif +#endif +#ifndef FPOptimizer_GrammarHH +#define FPOptimizer_GrammarHH +#include +t5{xW3 +class +CodeTree;} +lF3 +l21{enum +ImmedConstraint_Value{ValueMask=0x07,Value_AnyNum=0x0,nY2=0x1,Value_OddInt=0x2,tS1=0x3,Value_NonInteger=0x4,eJ1=0x5 +xF3 +ImmedConstraint_Sign{SignMask=0x18,Sign_AnySign=0x00,nH1=0x08,eK1=0x10,Sign_NoIdea=0x18 +xF3 +ImmedConstraint_Oneness{OnenessMask=0x60,Oneness_Any=0x00,Oneness_One=0x20,Oneness_NotOne=0x40 +xF3 +ImmedConstraint_Constness{ConstnessMask=0x180,Constness_Any=0x00,tR1=0x80,Constness_NotConst=0x100 +xF3 +Modulo_Mode{Modulo_None=0,Modulo_Radians=1 +xF3 +Situation_Flags{LogicalContextOnly=0x01,NotForIntegers=0x02,OnlyForIntegers=0x04,OnlyForComplex=0x08,NotForComplex=0x10 +xF3 +nR2{NumConstant,tG3,SubFunction +xF3 +ParamMatchingType{PositionalParams,SelectedParams,AnyParams,GroupFunction +xF3 +RuleType{ProduceNewTree,ReplaceParams} +; +#ifdef __GNUC__ +# define PACKED_GRAMMAR_ATTRIBUTE __attribute__((packed)) +#else +# define PACKED_GRAMMAR_ATTRIBUTE +#endif +typedef +std::paire42 +nJ1 +e42 +e81 +nT2 +paramlist,nA1)nJ1 +bool +ParamSpec_Compare +cH1 +void*xN3 +void*b,nR2 +type);iF2 +ParamSpec_GetDepCode +cH1 +e42&b);e12 +ParamSpec_ParamHolder{nA1:8;iF2 +constraints:9;iF2 +depcode:15;} +e9 +xW3 +e12 +ParamSpec_NumConstant{iV2 +constvalue;iF2 +modulo;} +;e12 +iZ{iF2 +param_count:2;iF2 +param_list:30;xB2 +subfunc_opcode:8;ParamMatchingType +match_type:3;iF2 +n1:5;} +e9 +e12 +ParamSpec_SubFunction{iZ +data;iF2 +constraints:9;iF2 +depcode:7;} +e9 +e12 +Rule{RuleType +ruletype:2;iF2 +situation_flags:5;iF2 +repl_param_count:2+9;iF2 +repl_param_list:30;iZ +match_tree;} +e9 +e12 +Grammar{iF2 +rule_count;iF2 +short +rule_list[999 +cS +extern +const +Rule +grammar_rules[];} +tZ1 +DumpParam +cH1 +e42&p,std::ostream&o=std::cout)xR3 +DumpParams +nT2 +paramlist,iF2 +count,std::ostream&o=std::cout);} +#endif #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 #endif - -#define CONSTANT_E 2.71828182845904509080 // exp(1) -#define CONSTANT_PI M_PI // atan2(0,-1) -#define CONSTANT_L10 2.30258509299404590109 // log(10) -#define CONSTANT_L10I 0.43429448190325176116 // 1/log(10) -#define CONSTANT_L10E CONSTANT_L10I // log10(e) -#define CONSTANT_L10EI CONSTANT_L10 // 1/log10(e) -#define CONSTANT_DR (180.0 / M_PI) // 180/pi -#define CONSTANT_RD (M_PI / 180.0) // pi/180 - -// Debugging in optimizer? Not recommended for production use. -//#define TREE_DEBUG -#ifdef TREE_DEBUG -// Debug verbosely? -#include +#define CONSTANT_POS_INF HUGE_VAL +#define CONSTANT_NEG_INF (-HUGE_VAL) +lF3 +FUNCTIONPARSERTYPES{xW3 +inline +iV2 +fp_const_pihalf()yR +fp_const_pi +xK()*iV2(0.5);} +xW3 +inline +iV2 +fp_const_twopi(tO2 +fp_const_pi +xK());lH3 +fp_const_twoe(tO2 +fp_const_e +xK());lH3 +fp_const_twoeinv(tO2 +fp_const_einv +xK());lH3 +fp_const_negativezero()yR-fp_epsilon +xK();} +} +#ifdef FP_SUPPORT_OPTIMIZER +#include +#include +#include +yL1{using +lF3 +l21;using +t5;using +lF3 +FUNCTIONPARSERTYPES +nJ1 +class +MatchInfo{eX3 +std +xV3 >lQ;eH +paramholder_matches;std +xV3tR;eX3 +MatchInfo():lQ(),paramholder_matches(),tR(){} +eX3 +bool +SaveOrTestRestHolder +nT2 +n1,iH2&iF1){cV1{lQ.t73 +n1+1);lQ +tQ=iF1 +xJ2 +if(lQ[n1 +tC3==false){lQ +tQ=iF1 +xJ2 +iH2&found=lQ[n1 +tD3;if(iF1.tF3!=found.tF3 +cL +for +iA1 +a=0;an1&&lQ[n1 +tC3==true;} +iH2&GetRestHolderValues +nT2 +n1 +e83{static +iH2 +empty_result;cV1 +return +empty_result +n31 +lQ[n1 +tD3;} +const +std +xV3&GetMatchedParamIndexes(yZ1 +tR +lL3 +swap(tB +b){lQ.swap(b.lQ);cE +swap(b.paramholder_matches);tR.swap(b.tR);} +tB +eA1=cH1 +tB +b){lQ=b.lQ;paramholder_matches=b.paramholder_matches;tR=b.tR +n31*this;} +} +;class +e2;typedef +xRcW;class +e2{eX3 +int +xM3;eX3 +e2():xM3(0){} +virtual~e2(){} +} +;e12 +lX1{bool +found;cW +specs;lX1(bool +f):found(f),specs(){} +lX1(bool +f,const +cW&s):found(f),specs(s){} +} +xR3 +SynthesizeRule +cH1 +eT2 +eJ&tree +tJ3)nJ1 +lX1 +TestParam +cH1 +e42&yG2 +lC2 +tree,const +cW&start_at +tJ3)nJ1 +lX1 +TestParams(tC&nN,lC2 +tree,const +cW&start_at +tJ3,bool +eY2 +nJ1 +bool +ApplyGrammar +cH1 +Grammar&tX2,FPoptimizer_CodeTree::eJ&tree,bool +from_logical_context=false)xR3 +ApplyGrammars(FPoptimizer_CodeTree::e62 +nJ1 +bool +IsLogisticallyPlausibleParamsMatch(tC&c32,lC2 +tree);} +lF3 +l21{tZ1 +DumpMatch +cH1 +eT2 +nO,const +FPoptimizer_Optimize::tB +info,bool +DidMatch,std::ostream&o=std::cout)xR3 +DumpMatch +cH1 +eT2 +nO,const +FPoptimizer_Optimize::tB +info,nH3 +i43,std::ostream&o=std::cout);} +#endif +#include +nI3 +l21::nR2 +yS1=false);nI3 +xB2 +yS1=false); +#include +#include +#include +#include +using +lF3 +l21;using +lF3 +FUNCTIONPARSERTYPES;nI3 +l21::nR2 +yS1){ +#if 1 +nH3 +p=0;switch(opcode +y33 +NumConstant:p="NumConstant" +;lC +tG3:p="ParamHolder" +;lC +SubFunction:p="SubFunction" +;yF3 +std::ostringstream +tmp;assert(p);tmp<d2 ? d1 : d2; +nI3 +xB2 +yS1){ +#if 1 +nH3 +p=0;switch(opcode +y33 +cAbs:p="cAbs" +;lC +cAcos:p="cAcos" +;lC +cAcosh:p="cAcosh" +;lC +cArg:p="cArg" +;lC +cAsin:p="cAsin" +;lC +cAsinh:p="cAsinh" +;lC +cAtan:p="cAtan" +;lC +cAtan2:p="cAtan2" +;lC +cAtanh:p="cAtanh" +;lC +cCbrt:p="cCbrt" +;lC +cCeil:p="cCeil" +;lC +cConj:p="cConj" +;lC +cCos:p="cCos" +;lC +cCosh:p="cCosh" +;lC +cCot:p="cCot" +;lC +cCsc:p="cCsc" +;lC +cExp:p="cExp" +;lC +cExp2:p="cExp2" +;lC +cFloor:p="cFloor" +;lC +cHypot:p="cHypot" +;lC +cIf:p="cIf" +;lC +cImag:p="cImag" +;lC +cInt:p="cInt" +;lC +cLog:p="cLog" +;lC +cLog2:p="cLog2" +;lC +cLog10:p="cLog10" +;lC +cMax:p="cMax" +;lC +cMin:p="cMin" +;lC +cPolar:p="cPolar" +;lC +cPow:p="cPow" +;lC +cReal:p="cReal" +;lC +cSec:p="cSec" +;lC +cSin:p="cSin" +;lC +cSinh:p="cSinh" +;lC +cSqrt:p="cSqrt" +;lC +cTan:p="cTan" +;lC +cTanh:p="cTanh" +;lC +cTrunc:p="cTrunc" +;lC +cImmed:p="cImmed" +;lC +cJump:p="cJump" +;lC +cNeg:p="cNeg" +;lC +cAdd:p="cAdd" +;lC +cSub:p="cSub" +;lC +cMul:p="cMul" +;lC +cDiv:p="cDiv" +;lC +cMod:p="cMod" +;lC +cEqual:p="cEqual" +;lC +cNEqual:p="cNEqual" +;lC +cLess:p="cLess" +;lC +cLessOrEq:p="cLessOrEq" +;lC +cGreater:p="cGreater" +;lC +cGreaterOrEq:p="cGreaterOrEq" +;lC +cNot:p="cNot" +;lC +cAnd:p="cAnd" +;lC +cOr:p="cOr" +;lC +cDeg:p="cDeg" +;lC +cRad:p="cRad" +;lC +cFCall:p="cFCall" +;lC +cPCall:p="cPCall" +;break; +#ifdef FP_SUPPORT_OPTIMIZER +case +cFetch:p="cFetch" +;lC +cPopNMov:p="cPopNMov" +;lC +eF3:p="cLog2by" +;lC +cNop:p="cNop" +;break; +#endif +case +cSinCos:p="cSinCos" +;lC +cSinhCosh:p="cSinhCosh" +;lC +cZ3:p="cAbsNot" +;lC +cAbsNotNot:p="cAbsNotNot" +;lC +cAbsAnd:p="cAbsAnd" +;lC +cAbsOr:p="cAbsOr" +;lC +cAbsIf:p="cAbsIf" +;lC +cDup:p="cDup" +;lC +cInv:p="cInv" +;lC +cSqr:p="cSqr" +;lC +cRDiv:p="cRDiv" +;lC +cRSub:p="cRSub" +;lC +cNotNot:p="cNotNot" +;lC +cRSqrt:p="cRSqrt" +;lC +l03:p="VarBegin" +;yF3 +std::ostringstream +tmp;assert(p);tmp< () const { return tree; } - const CodeTree& operator* () const { return *tree; } - struct CodeTree* operator-> () { return tree; } - struct CodeTree& operator* () { return *tree; } - - bool operator< (const SubTree& b) const; - bool operator== (const SubTree& b) const; - void Negate(); // Note: Parent must be cAdd - void Invert(); // Note: Parent must be cMul - - void CheckConstNeg(); - void CheckConstInv(); -}; - -bool IsNegate(const SubTree &p1, const SubTree &p2); -bool IsInverse(const SubTree &p1, const SubTree &p2); - -typedef list paramlist; - -#ifdef TREE_DEBUG -struct CodeTreeData; -std::ostream& operator << (std::ostream& str, const CodeTreeData& tree); -std::ostream& operator << (std::ostream& str, const CodeTree& tree); +#ifdef FP_SUPPORT_OPTIMIZER +#include +#include +#ifndef FP_GENERATING_POWI_TABLE +enum{MAX_POWI_BYTECODE_LENGTH=20} +; +#else +enum{MAX_POWI_BYTECODE_LENGTH=999} +; #endif - -struct CodeTreeData -{ - paramlist args; - -private: - unsigned op; // Operation - double value; // In case of cImmed - unsigned var; // In case of cVar - unsigned funcno; // In case of cFCall, cPCall - -public: - CodeTreeData() : op(cAdd) {} - ~CodeTreeData() {} - - void SetOp(unsigned newop) { op=newop; } - void SetFuncNo(unsigned newno) { funcno=newno; } - - inline unsigned GetOp() const { return op; } - inline double GetImmed() const { return value; } - inline unsigned GetVar() const { return var; } - inline unsigned GetFuncNo() const { return funcno; } - - bool IsFunc() const { return op == cFCall || op == cPCall; } - bool IsImmed() const { return op == cImmed; } - bool IsVar() const { return op == cVar; } - - void AddParam(const SubTree &p) - { - args.push_back(p); - } - void SetVar(unsigned v) - { - args.clear(); - op = cVar; - var = v; - } - void SetImmed(double v) - { - args.clear(); - op = cImmed; - value = orig = v; - inverted = negated = false; - } - void NegateImmed() - { - negated = !negated; - UpdateValue(); - } - void InvertImmed() - { - inverted = !inverted; - UpdateValue(); - } - - bool IsOriginal() const { return !(IsInverted() || IsNegated()); } - bool IsInverted() const { return inverted; } - bool IsNegated() const { return negated; } - bool IsInvertedOriginal() const { return IsInverted() && !IsNegated(); } - bool IsNegatedOriginal() const { return !IsInverted() && IsNegated(); } - -private: - void UpdateValue() - { - value = orig; - if(IsInverted()) { value = 1.0 / value; - // FIXME: potential divide by zero. - } - if(IsNegated()) value = -value; - } - - double orig; - bool inverted; - bool negated; -protected: - // Ensure we don't accidentally copy this - void operator=(const CodeTreeData &b); -}; - - -class CodeTreeDataPtr -{ - typedef pair p_t; - typedef p_t* pp; - mutable pp p; - - void Alloc() const { ++p->second; } - void Dealloc() const { if(!--p->second) delete p; p = 0; } - - void PrepareForWrite() - { - // We're ready if we're the only owner. - if(p->second == 1) return; - - // Then make a clone. - p_t *newtree = new p_t(p->first, 1); - // Forget the old - Dealloc(); - // Keep the new - p = newtree; - } - -public: - CodeTreeDataPtr() : p(new p_t) { p->second = 1; } - CodeTreeDataPtr(const CodeTreeDataPtr &b): p(b.p) { Alloc(); } - ~CodeTreeDataPtr() { Dealloc(); } - const CodeTreeDataPtr &operator= (const CodeTreeDataPtr &b) - { - b.Alloc(); - Dealloc(); - p = b.p; - return *this; - } - const CodeTreeData *operator-> () const { return &p->first; } - const CodeTreeData &operator* () const { return p->first; } - CodeTreeData *operator-> () { PrepareForWrite(); return &p->first; } - CodeTreeData &operator* () { PrepareForWrite(); return p->first; } - - void Shock(); -}; - - -#define CHECKCONSTNEG(item, op) \ - ((op)==cMul) \ - ? (item).CheckConstInv() \ - : (item).CheckConstNeg() - -struct CodeTree -{ - CodeTreeDataPtr data; - -private: - typedef paramlist::iterator pit; - typedef paramlist::const_iterator pcit; - - /* - template inline void chk() const - { - } - */ - -public: - const pcit GetBegin() const { return data->args.begin(); } - const pcit GetEnd() const { return data->args.end(); } - const pit GetBegin() { return data->args.begin(); } - const pit GetEnd() { return data->args.end(); } - const SubTree& getp0() const { /*chk<1>();*/pcit tmp=GetBegin(); return *tmp; } - const SubTree& getp1() const { /*chk<2>();*/pcit tmp=GetBegin(); ++tmp; return *tmp; } - const SubTree& getp2() const { /*chk<3>();*/pcit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; } - unsigned GetArgCount() const { return data->args.size(); } - void Erase(const pit p) { data->args.erase(p); } - - SubTree& getp0() { /*chk<1>();*/pit tmp=GetBegin(); return *tmp; } - SubTree& getp1() { /*chk<2>();*/pit tmp=GetBegin(); ++tmp; return *tmp; } - SubTree& getp2() { /*chk<3>();*/pit tmp=GetBegin(); ++tmp; ++tmp; return *tmp; } - - // set - void SetImmed(double v) { data->SetImmed(v); } - void SetOp(unsigned op) { data->SetOp(op); } - void SetVar(unsigned v) { data->SetVar(v); } - // get - double GetImmed() const { return data->GetImmed(); } - unsigned GetVar() const { return data->GetVar(); } - unsigned GetOp() const { return data->GetOp(); } - // test - bool IsImmed() const { return data->IsImmed(); } - bool IsVar() const { return data->IsVar(); } - // act - void AddParam(const SubTree &p) { data->AddParam(p); } - void NegateImmed() { data->NegateImmed(); } // don't use when op!=cImmed - void InvertImmed() { data->InvertImmed(); } // don't use when op!=cImmed - - compres NonZero() const { if(!IsImmed()) return maybe; - return GetImmed() != 0.0; } - compres IsPositive() const { if(!IsImmed()) return maybe; - return GetImmed() > 0.0; } - -private: - struct ConstList - { - double voidvalue; - list cp; - double value; - unsigned size() const { return cp.size(); } - }; - struct ConstList BuildConstList(); - void KillConst(const ConstList &cl) - { - for(list::const_iterator i=cl.cp.begin(); i!=cl.cp.end(); ++i) - Erase(*i); - } - void FinishConst(const ConstList &cl, bool has_voidvalue) - { - if(has_voidvalue) - { - if(cl.value != cl.voidvalue) - { - if(cl.size() == 1) return; // nothing to do - AddParam(cl.value); // add the resulting constant - } - } - else - { - if(cl.size() <= 0) return; // nothing to do - AddParam(cl.value); // add the resulting constant - } - KillConst(cl); // remove all listed constants - } - -public: - CodeTree() {} - CodeTree(double v) { SetImmed(v); } - - CodeTree(unsigned op, const SubTree &p) - { - SetOp(op); - AddParam(p); - } - CodeTree(unsigned op, const SubTree &p1, const SubTree &p2) - { - SetOp(op); - AddParam(p1); - AddParam(p2); - } - - bool operator== (const CodeTree& b) const; - bool operator< (const CodeTree& b) const; - -private: - bool IsSortable() const - { - switch(GetOp()) - { - case cAdd: case cMul: - case cEqual: - case cAnd: case cOr: - case cMax: case cMin: - return true; - default: - return false; - } - } - void SortIfPossible() - { - if(IsSortable()) - { - data->args.sort(); - } - } - - void ReplaceWithConst(double value) - { - SetImmed(value); - - /* REMEMBER TO CALL CheckConstInv / CheckConstNeg - * FOR PARENT SubTree, OR MAYHEM HAPPENS - */ - } - - void ReplaceWith(const CodeTree &b) - { - // If b is child of *this, mayhem - // happens. So we first make a clone - // and then proceed with copy. - CodeTreeDataPtr tmp = b.data; - tmp.Shock(); - data = tmp; - } - - void ReplaceWith(unsigned op, const SubTree &p) - { - ReplaceWith(CodeTree(op, p)); - } - - void ReplaceWith(unsigned op, const SubTree &p1, const SubTree &p2) - { - ReplaceWith(CodeTree(op, p1, p2)); - } - - void OptimizeConflict() - { - // This optimization does this: x-x = 0, x/x = 1, a+b-a = b. - - if(GetOp() == cAdd || GetOp() == cMul) - { - Redo: - pit a, b; - for(a=GetBegin(); a!=GetEnd(); ++a) - { - for(b=a; ++b != GetEnd(); ) - { - const SubTree &p1 = *a; - const SubTree &p2 = *b; - - if(GetOp() == cMul ? IsInverse(p1,p2) - : IsNegate(p1,p2)) - { - // These parameters complement each others out - Erase(b); - Erase(a); - goto Redo; - } - } - } - } - OptimizeRedundant(); - } - - void OptimizeRedundant() - { - // This optimization does this: min()=0, max()=0, add()=0, mul()=1 - - if(!GetArgCount()) - { - if(GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax) - ReplaceWithConst(0); - else if(GetOp() == cMul) - ReplaceWithConst(1); - return; - } - - // And this: mul(x) = x, min(x) = x, max(x) = x, add(x) = x - - if(GetArgCount() == 1) - { - if(GetOp() == cMul || GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax) - if(!getp0().getsign()) - ReplaceWith(*getp0()); - } - - OptimizeDoubleNegations(); - } - - void OptimizeDoubleNegations() - { - if(GetOp() == cAdd) - { - // Eschew double negations - - // If any of the elements is !cAdd of cMul - // and has a numeric constant, negate - // the constant and negate sign. - - for(pit a=GetBegin(); a!=GetEnd(); ++a) - { - SubTree &pa = *a; - if(pa.getsign() - && pa->GetOp() == cMul) - { - // Before doing the check, ensure that - // we are not changing a x*1 into x*-1. - pa->OptimizeConstantMath1(); - - // OptimizeConstantMath1() may have changed - // the type of the expression (but not its sign), - // so verify that we're still talking about a cMul group. - if(pa->GetOp() == cMul) - { - CodeTree &p = *pa; - for(pit b=p.GetBegin(); - b!=p.GetEnd(); ++b) - { - SubTree &pb = *b; - if(pb->IsImmed()) - { - pb.Negate(); - pa.Negate(); - break; - } - } - } - } - } - } - - if(GetOp() == cMul) - { - // If any of the elements is !cMul of cPow - // and has a numeric exponent, negate - // the exponent and negate sign. - - for(pit a=GetBegin(); a!=GetEnd(); ++a) - { - SubTree &pa = *a; - if(pa.getsign() && pa->GetOp() == cPow) - { - CodeTree &p = *pa; - if(p.getp1()->IsImmed()) - { - // negate ok for pow when op=cImmed - p.getp1().Negate(); - pa.Negate(); - } - } - } - } - } - - void OptimizeConstantMath1() - { - // This optimization does three things: - // - For adding groups: - // Constants are added together. - // - For multiplying groups: - // Constants are multiplied together. - // - For function calls: - // If all parameters are constants, - // the call is replaced with constant value. - - // First, do this: - OptimizeAddMulFlat(); - -#ifdef TREE_DEBUG - cout << "BEFORE MATH1 :" << *this << endl; -#endif - switch(GetOp()) - { - case cAdd: - { - ConstList cl = BuildConstList(); - FinishConst(cl, true); - break; - } - case cMul: - { - ConstList cl = BuildConstList(); - - if(cl.value == 0.0) ReplaceWithConst(0.0); - else FinishConst(cl, true); - - break; - } - case cMin: - case cMax: - { - ConstList cl = BuildConstList(); - FinishConst(cl, false); // No "default" value - break; - } - - #define ConstantUnaryFun(token, fun) \ - case token: { const SubTree &p0 = getp0(); \ - if(p0->IsImmed()) ReplaceWithConst(fun(p0->GetImmed())); \ - break; } - #define ConstantBinaryFun(token, fun) \ - case token: { const SubTree &p0 = getp0(); \ - const SubTree &p1 = getp1(); \ - if(p0->IsImmed() && \ - p1->IsImmed()) ReplaceWithConst(fun(p0->GetImmed(), p1->GetImmed())); \ - break; } - - // FIXME: potential invalid parameters for functions - // can cause exceptions here - - ConstantUnaryFun(cAbs, fabs); - ConstantUnaryFun(cAcos, acos); - ConstantUnaryFun(cAsin, asin); - ConstantUnaryFun(cAtan, atan); - ConstantUnaryFun(cCeil, ceil); - ConstantUnaryFun(cCos, cos); - ConstantUnaryFun(cCosh, cosh); - ConstantUnaryFun(cFloor, floor); - ConstantUnaryFun(cLog, log); - ConstantUnaryFun(cSin, sin); - ConstantUnaryFun(cSinh, sinh); - ConstantUnaryFun(cTan, tan); - ConstantUnaryFun(cTanh, tanh); - ConstantBinaryFun(cAtan2, atan2); - ConstantBinaryFun(cMod, fmod); // not a func, but belongs here too - ConstantBinaryFun(cPow, pow); - - case cNeg: - case cSub: - case cDiv: - /* Unreached (nonexistent operator) - * TODO: internal error here? - */ - break; - - case cCot: - case cCsc: - case cSec: - case cDeg: - case cRad: - case cLog10: - case cSqrt: - case cExp: - /* Unreached (nonexistent function) - * TODO: internal error here? - */ - break; - } -#ifdef TREE_DEBUG - cout << "AFTER MATH1 A :" << *this << endl; +enum{MAX_MULI_BYTECODE_LENGTH=3} +;lF3 +xH1{xW3 +class +ByteCodeSynth{eX3 +ByteCodeSynth():ByteCode(),Immed(),cM(),xS(0),StackMax(0){i8 +xS3 +64);Immed.xS3 +8);cM.xS3 +16 +lI3 +Pull(std +xV3&bc,std +xV3 +xK&imm,size_t&StackTop_max){for(eQ1=0;aoffset){cM +l62 +first=true;cM +l62 +second=tree;} +} +bool +IsStackTop(nO,int +offset=0 +yZ1(int)xS>offset&&cM +l62 +first&&cM +l62 +second +xF +tree);xI1 +void +EatNParams +nT2 +eat_count){xS-=eat_count +lL3 +ProducedNParams +nT2 +produce_count){xJ1 +xS+produce_count +lI3 +DoPopNMov +iA1 +e52,size_t +srcpos +nL +xK2 +cPopNMov)nS2 +e52)nS2 +srcpos);xJ1 +srcpos+1);cM[e52]=cM[srcpos];xJ1 +e52+1 +lI3 +DoDup +iA1 +xT3 +nL +if(xT3==xS-1){xK2 +cDup +t43{xK2 +cFetch)nS2 +xT3);} +eZ2 +cM[xS-1]=cM[xT3];} +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +i31 +int>void +Dump(){std::ostream&o=std::cout;o<<"Stack state now(" +<0;)if(cM[a +tC3&&cM[a +tD3 +xF +tree +nE3 +a +n31 +t02;} +bool +Find(nO +yZ1 +xU3 +tree)!=t02;} +bool +FindAndDup(nO){size_t +pos=xU3 +tree +eY3 +pos!=t02){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<lN3{StackMax=xS;cM.t73 +lN3;} +} +protected:std +xV3ByteCode;std +xV3 +xK +Immed;std +xV3 >cM;size_t +xS;size_t +StackMax;private:void +incStackPtr(){if(xS+2>lN3 +cM.t73 +StackMax=xS+2);} +i31 +bool +IsIntType,bool +IsComplexType>e12 +c42{} +;eX3 +void +AddOperation +nT2 +t83 +iF2 +eat_count,iF2 +produce_count=1){EatNParams(eat_count);lO1 +opcode);ProducedNParams(produce_count +lI3 +lO1 +iF2 +t83 +c42yS +false,true>yS +true,false>yS +true,true>);inline +void +lO1 +iF2 +opcode){lO1 +t83 +c42());} +} +nJ1 +e12 +SequenceOpCode +nJ1 +e12 +tN1{static +cI +AddSequence;static +cI +MulSequence;} +xR3 +x01 +long +count,cI&eU,yM1;} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +using +lF3 +FUNCTIONPARSERTYPES;lF3 +xH1{xW3 +e12 +SequenceOpCode{iV2 +basevalue;iF2 +op_flip;iF2 +op_normal,op_normal_flip;iF2 +op_inverse,op_inverse_flip;} +nJ1 +cI +tN1 +xK::AddSequence={y21,cNeg +xE +cAdd,cSub,cRSub} +nJ1 +cI +tN1 +xK::MulSequence={iV2(1),cInv,cMul,cMul,cDiv,cRDiv} +; +#define findName(a,b,c) "var" +#define TryCompilePowi(o) false +#define mData this +#define mByteCode ByteCode +#define mImmed Immed +xY3 +false,false +l31 +# define FP_FLOAT_VERSION 1 +# define FP_COMPLEX_VERSION 0 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +xY3 +true,false +l31 +# define FP_FLOAT_VERSION 0 +# define FP_COMPLEX_VERSION 0 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +#ifdef FP_SUPPORT_COMPLEX_NUMBERS +xY3 +false,true +l31 +# define FP_FLOAT_VERSION 1 +# define FP_COMPLEX_VERSION 1 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +xY3 +true,true +l31 +# define FP_FLOAT_VERSION 0 +# define FP_COMPLEX_VERSION 1 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION +} +#endif +#undef findName +#undef mImmed +#undef mByteCode +#undef mData +#undef TryCompilePowi +} +using +lF3 +xH1; +#define POWI_TABLE_SIZE 256 +#define POWI_WINDOW_SIZE 3 +lF3 +xH1{ +#ifndef FP_GENERATING_POWI_TABLE +extern +const +iF2 +char +powi_table[POWI_TABLE_SIZE];const +#endif +iF2 +char +powi_table[POWI_TABLE_SIZE]={0,1,1,1,2,1,2,1,y63 +4,1,2,y73 +2,1,y63 +8,eK3 +y83 +15,1,16,1,2,1,4,1,2,y73 +2,1,4,eK3 +1,16,1,25,y83 +27,5,8,3,2,1,30,1,31,3,32,1,2,1,y63 +8,1,2,y83 +39,1,16,137,2,1,4,eK3 +y73 +45,135,4,31,2,5,32,1,2,131,50,1,51,1,8,3,2,1,54,1,55,3,16,1,57,133,4,137,2,135,60,1,61,3,62,133,63,1,iG1 +131,iG1 +139,l82 +e3 +30,1,130,137,2,31,l82 +e3 +e3 +130,eK3 +1,e3 +e3 +2,1,130,133,iG1 +61,130,133,62,139,130,137,e3 +l82 +e3 +e3 +iG1 +131,e3 +e3 +130,131,2,133,l82 +130,141,e3 +130,eK3 +1,e3 +5,135,e3 +l82 +e3 +l82 +130,133,130,141,130,131,e3 +e3 +2,131} +;} +static +xC3 +yY=256; +#define FPO(x) +lF3{class +PowiCache{private:int +iB[yY];int +iH1[yY];eX3 +PowiCache():iB(),iH1(){iB[1]=1;} +bool +Plan_Add(c82,int +count){cC1>=yY +cL +iH1[t12+=count +n31 +iB[t12!=0 +lL3 +lO3 +c82){cC1=0){FPO(iM3(iR3,"* I found %ld from cache (%u,%d)\n",value,(unsigned)cache[value],iN3 value]))n31 +iB[t12;eW2-1 +lL3 +Remember(c82,size_t +l04){cC1>=yY)return;FPO(iM3(iR3,"* Remembering that %ld can be found at %u (%d uses remain)\n",value,(unsigned)l04,iN3 value]));iB[t12=(int)l04 +lL3 +DumpContents +e73 +FPO(for(int a=1;a=0||iN3 a]>0){iM3(iR3,"== cache: sp=%d, val=%d, needs=%d\n",cache[a],a,iN3 a]);})} +int +UseGetNeeded(c82){cC1>=0&&value32)throw +false; +#endif +if(iB.Plan_Add(value,need_count +nE3;long +yA3 +1;cC1cN||half<0)std::swap(half,cN);FPO(iM3(iR3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,otherhalf))lM3==cN){l41 +half,iB,2,l51+1 +t43{l41 +half +y93 +l41 +cN>0?cN:-cN +y93} +iB.lO3 +value);} +xW3 +size_t +y8 +c82 +lF2 +cI&eU,yM1{int +yB3=iB.Find(value +eY3 +yB3>=0)yR +yB3;} +long +yA3 +1;cC10||xM2!=tY1){iI1 +xM2)cS2 +half,tY1);} +x01 +value/half,eU,iS2 +size_t +l04=tY1 +cS2 +value,l04);iB.DumpContents()n31 +l04;} +lJ2 +half&64){yA3-tB2} +} +else +cC1&1)yA3 +value&((1<cN||half<0)std::swap(half,cN);FPO(iM3(iR3,"* I want %ld, my plan is %ld + %ld\n",value,half,value-half))lM3==cN){size_t +xM2=y8 +half +tX1 +c01 +xM2,half,xM2,half,iB,eU.op_normal,eU.op_normal_flip,iS2} +else{long +part1=half;long +part2=cN>0?cN:-cN;size_t +part1_pos=y8 +part1 +tX1 +size_t +part2_pos=y8 +part2 +tX1 +FPO(iM3(iR3,"Subdivide(%ld: %ld, %ld)\n",value,half,otherhalf));c01 +part1_pos,part1,part2_pos,part2,iB,cN>0?eU.op_normal:eU.op_inverse,cN>0?eU.op_normal_flip:eU.op_inverse_flip,iS2} +size_t +l04=tY1 +cS2 +value,l04);iB.DumpContents()n31 +l04;} +tZ1 +c01 +size_t +apos,long +aval,size_t +bpos,long +bval +lF2 +iF2 +cumulation_opcode,iF2 +cumulation_opcode_flip,yM1{int +a_needed=iB +lL2 +aval);int +yC3=iB +lL2 +bval);bool +lM2 +tO3 +#define DUP_BOTH() do{if(apos "iX3 iX3"op\n",(unsigned)apos,(unsigned)bpos));iI1 apos);iI1 apos==bpos?tY1:bpos);}while(0) +#define DUP_ONE(p) do{FPO(iM3(iR3,"-> "iX3"op\n",(unsigned)p));iI1 p);}while(0) +if(a_needed>0){if(yC3>0){nL2} +e63 +bpos!=tY1)nL2 +else{lN2 +lM2=!lM2;} +} +} +lJ2 +yC3>0){if(apos!=tY1)nL2 +else +DUP_ONE(bpos);} +e63 +apos==bpos&&apos==tY1)lN2 +iR2 +tY1&&bpos==yD3 +2){FPO(iM3(iR3,"-> op\n"));lM2=!lM2;} +iR2 +yD3 +2&&bpos==tY1)FPO(iM3(iR3,"-> op\n"));iR2 +tY1)DUP_ONE(bpos);lJ2 +bpos==tY1){lN2 +lM2=!lM2;} +else +nL2} +yE3 +lM2?cumulation_opcode_flip:cumulation_opcode,2);} +tZ1 +cD1 +long +count,cI&eU,yM1{while +eL3<256){int +yA3 +xH1::powi_table[count]lM3&128){half&=127;cD1 +half,eU,iS2 +count/=half;} +else +yF3 +if +eL3==1)return;if(!eL3&1)){yE3 +cSqr,1);cD1 +count/2,eU,iS2} +else{iI1 +tY1);cD1 +count-1,eU,iS2 +yE3 +cMul,2);} +} +} +lF3 +xH1{tZ1 +x01 +long +count,cI&eU,yM1{if +eL3==0)lH2 +eU.basevalue);else{bool +t22 +tO3 +if +eL3<0){t22=true;count=-count;} +if(false)cD1 +count,eU,iS2 +lJ2 +count>1){PowiCache +iB;l41 +count,iB,1);size_t +xK1=synth.GetStackTop();iB.Start(tY1);FPO(iM3(iR3,"Calculating result for %ld...\n",count));size_t +xN2=y8 +count +tX1 +size_t +n_excess=yD3 +xK1;if(n_excess>0||xN2!=xK1-1){synth.DoPopNMov(xK1-1,xN2);} +} +if(t22)yE3 +eU.op_flip,1);} +} +} +#endif +#ifndef FPOptimizer_ValueRangeHH +#define FPOptimizer_ValueRangeHH +t5{lF3 +lP3{iM +e12 +Comp{} +;i31>e12 +CompxZ3xZ3<=n9 +cGreater>xZ3>n9 +cGreaterOrEq>xZ3>=n9 +cEqual>xZ3==n9 +cNEqual>xZ3!=b;} +} +;} +xW3 +e12 +cJ1{iV2 +val;bool +known;cJ1():val(),known(false){} +cJ1 +cG1 +v):val(v),known(true){xI1 +void +set +cG1 +v){known=true;val=v +lL3 +set(iV2(iJ1(iV2),cJ1 +y9)val=iI2 +void +set(iV2(iJ1 +cG1),cJ1 +y9)val=iI2 +iM +void +set_if(iV2 +v +tG1 +iJ1(iV2),cJ1 +y9&&lP3::Comp()(val,v))val=iI2 +iM +void +set_if +cG1 +v +tG1 +iJ1 +cG1),cJ1 +y9&&lP3::Comp()(val,v))val=iI2} +nJ1 +e12 +range{cJ1 +xK +min,max;range():min(),max(){} +range(iV2 +mi,iV2 +ma):min(mi),max(ma){} +range(bool,iV2 +ma):min(),max(ma){} +range(iV2 +mi,bool):min(mi),max(){} +void +set_abs();void +set_neg();} +nJ1 +bool +IsLogicalTrueValue +cH1 +c23&p +tR2 +nJ1 +bool +IsLogicalFalseValue +cH1 +c23&p +tR2;} +#endif +#ifndef FPOptimizer_RangeEstimationHH +#define FPOptimizer_RangeEstimationHH +t5{enum +TriTruthValue{IsAlways,IsNever,Unknown} +nJ1 +c23 +iN +lC2 +tree)nJ1 +bool +IsLogicalValue +cH1 +e62 +nJ1 +TriTruthValue +GetIntegerInfo +cH1 +e62 +nJ1 +xL1 +GetEvennessInfo +cH1 +e62{if(!tree +i61)return +Unknown;yJ1=eC3;if(isEvenInteger(value +nF3 +isOddInteger(value +nG3 +xW3 +xL1 +GetPositivityInfo +cH1 +e62{c23 +p=iN +tree +eY3 +p +n51&&p +tF2>=iV2(nF3 +p +yN +known +lH1 +nG3 +xW3 +xL1 +GetLogicalValue +lQ3 +tree +tR2{c23 +p=iN +tree +eY3 +IsLogicalTrueValue(p,abs +nF3 +IsLogicalFalseValue(p,abs +nG3} +#endif +#ifndef FPOptimizer_ConstantFoldingHH +#define FPOptimizer_ConstantFoldingHH +t5{tZ1 +ConstantFolding(e62;} +#endif +lF3{using +lF3 +FUNCTIONPARSERTYPES;using +t5;e12 +ComparisonSetBase{enum{t93=0x1,Eq_Mask=0x2,Le_Mask=0x3,tA3=0x4,tB3=0x5,Ge_Mask=0x6} +;static +int +Swap_Mask(int +m)yR(m&Eq_Mask)|((m&t93)?tA3:0)|((m&tA3)?t93:0);} +enum +c11{Ok,BecomeZero,BecomeOne,xP2 +xF3 +nW2{cond_or,iK2,iL2,iM2} +;} +nJ1 +e12 +ComparisonSet:public +ComparisonSetBase{e12 +t32{eJ +a;eJ +b;int +relationship;t32():a(),b(),relationship(){} +} +;std +xV3eK;e12 +Item{eJ +value;bool +c52;Item():value(),c52(false){} +} +;std +xV3cK1;int +xM1;ComparisonSet():eK(),cK1(),xM1(0){} +c11 +AddItem +lQ3 +a,bool +c52,nW2 +type){for +iA1 +c=0;cbool +ConstantFolding_LogicCommon(eJ&tree,CondType +xA1,bool +xS2){bool +should_regenerate +tO3 +ComparisonSet +xK +comp;nB1{xK3 +c6 +c11 +eM3=c6 +Ok;lC2 +atree=t33;switch(atree +nC +y33 +cEqual +lG +Eq_Mask,xA1);lC +cNEqual +lG +tB3,xA1);lC +cLess +lG +t93,xA1);lC +cLessOrEq +lG +Le_Mask,xA1);lC +cGreater +lG +tA3,xA1);lC +cGreaterOrEq +lG +Ge_Mask,xA1);lC +cNot:eM3 +yO1 +l8 +0),true,xA1);lC +cNotNot:eM3 +yO1 +l8 +0),false,xA1);break;c73 +if(xS2||IsLogicalValue(atree))eM3 +yO1,false,xA1);l73 +eM3){ReplaceTreeWithZero:xO +0)n31 +true;ReplaceTreeWithOne:xO +1);nV +c6 +Ok:lC +c6 +BecomeZero +eL +c6 +BecomeOne:i6 +c6 +xP2:c41 +yF3} +if(should_regenerate){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantFolding_LogicCommon: " +yA1 +#endif +if(xS2){tree.DelParams(t43{for +iY{lC2 +atree=lE2 +a +eY3 +IsLogicalValue(atree))eK2} +for +iA1 +a=0;a +#include +#include +lF3{using +lF3 +FUNCTIONPARSERTYPES;using +t5;e12 +CollectionSetBase{enum +xR1{Ok,xP2} +;} +nJ1 +e12 +CollectionSet:public +CollectionSetBase{e12 +c21{eJ +value;eJ +xT2;bool +cX;c21():value(),xT2(),cX(false){} +c21 +lQ3 +v,lC2 +f):value(v),xT2(f),cX(false){} +} +;std::multimapiC;typedef +xK3 +std::multimap::yV3 +xS1;CollectionSet():iC(){} +xS1 +FindIdenticalValueTo +lQ3 +value){fphash_t +hash=value.GetHash();for(xS1 +i=iC.xU2 +hash);i!=iC.cY1 +hash;++i){cC1 +xF +i +e82.value +nE3 +i;} +return +iC.end();} +bool +Found +cH1 +xS1&b)yR +b!=iC.end();} +xR1 +AddCollectionTo +lQ3 +xT2,const +xS1&into_which){c21&c=into_which +e82;if(c.cX)c.xT2 +c9 +xT2);else{eJ +add;add +xD +cAdd);add +yP1 +c.xT2);add +c9 +xT2);c.xT2.swap(add);c.cX=true;} +return +xP2;} +xR1 +nX2 +lQ3 +value,lC2 +xT2){const +fphash_t +hash=value.GetHash();xS1 +i=iC.xU2 +hash);for(;i!=iC.cY1 +hash;++i){if(i +e82.value +xF +value +nE3 +AddCollectionTo(xT2,i);} +iC.yR3,std::make_pair(hash,c21(value,xT2)))n31 +Ok;} +xR1 +nX2 +lQ3 +a)yR +nX2(a,nF1 +1)));} +} +nJ1 +e12 +ConstantExponentCollection{typedef +eH +yT3;typedef +std::x31 +xV2;std +xV3data;ConstantExponentCollection():data(){} +void +MoveToSet_Unique +cG1 +eB1&eC1){data.push_back(std::x31(eB1()));data.back()tE3.swap(eC1 +lI3 +MoveToSet_NonUnique +cG1 +eB1&eC1){xK3 +std +xV3::yV3 +i=std::xU2 +data.iN2 +data.end(),exponent,Compare1st()eY3 +i!=data.cY1 +xG2{i +e82.yR3 +e82.end(),eC1.iN2 +eC1.end()t43{data.yR3,std::x31 +t62,eC1));} +} +bool +Optimize(){bool +changed +tO3 +std::sort(data.iN2 +data.end(),Compare1st());redo:for +iA1 +a=0;a=fp_abs(exp_a))break +iU2 +exp_diff_still_probable_integer=xW2*iV2(16 +eY3 +t42 +exp_diff_still_probable_integer)&&!(t42 +exp_b)&&!t42 +xW2))){yT3&a_set=lQ2;yT3&b_set=data[b +tD3; +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantExponentCollection iteration:\n" +;t52 +cout); +#endif +if(isEvenInteger(exp_b)&&!isEvenInteger(xW2+exp_a)){eJ +tmp2;tmp2 +tH3 +tmp2 +iO3 +b_set);tmp2 +eT1 +t81 +cAbs);tmp +yP1 +tmp2);tmp +eT1 +b_set.t73 +1);b_set[0].i72} +a_set.insert(a_set.end(),b_set.iN2 +b_set.end());yT3 +b_copy=b_set;data.erase(data.begin()+b);MoveToSet_NonUnique(xW2,b_copy);x62 +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"After ConstantExponentCollection iteration:\n" +;t52 +cout); +#endif +cZ} +eW2 +changed;} +#ifdef DEBUG_SUBSTITUTIONS +void +t52 +ostream&out){for +iA1 +a=0;a0)out<<'*'i13(lQ2[b],out);} +out<eE1;typedef +std::multimapcL1;cL1 +tD;xX2 +eV1::xS1 +j=mul.iC.yU3 +j!=mul.iC.end();++j){eJ&value=j +e82.value;eJ&e92 +j +e82.xT2;if(j +e82.cX)exponent +eT1 +const +fphash_t +eF1=exponent.GetHash();xK3 +cL1::yV3 +i=tD.xU2 +eF1);for(;i!=tD.cY1 +eF1;++i)if(i +e82.first +xF +xG2){if(!exponent +i61||!e01 +nC1 +tG1 +1)))c41 +i +e82 +tE3.push_back(value);goto +skip_b;} +tD.yR3,std::make_pair(eF1,std::make_pair +t62,eH +iA1(1),value))));skip_b:;} +#ifdef FP_MUL_COMBINE_EXPONENTS +ConstantExponentCollection +xK +e11;xX2 +cL1::yV3 +j,i=tD.yU3 +i!=tD.end();i=j){j=i;++j;eE1&list=i +e82;if(list.first +l71 +e92 +list.first +nC1;if(!t62==xD1)e11.MoveToSet_Unique +t62,list +iO2;tD.erase(i);} +} +if(e11.Optimize())c41 +#endif +if(should_regenerate){eJ +before=tree;before.l61 +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantFolding_MulGrouping: " +i13(before +lT2"\n" +; +#endif +tree.DelParams();xX2 +cL1::yV3 +i=tD.yU3 +i!=tD.end();++i){eE1&list=i +e82; +#ifndef FP_MUL_COMBINE_EXPONENTS +if(list.first +l71 +e92 +list.first +nC1;if +t62==xD1 +continue;if(e01 +xE3 +tree.AddParamsMove(list +iO2;eR2} +#endif +eJ +mul;mul +tH3 +mul +iO3 +list +iO2;mul +eT1 +if(xH&&list.first +i51 +list.first +nC1==iV2(1)/iV2(3)){eJ +cbrt;cbrt +xD +cCbrt);cbrt.e4 +cbrt +cK +cbrt +xW +0.5)){eJ +sqrt;sqrt +xD +cSqrt);sqrt.e4 +sqrt +cK +sqrt +xW-0.5)){eJ +rsqrt;rsqrt +xD +cRSqrt);rsqrt.e4 +rsqrt +cK +rsqrt +xW-1)){eJ +inv;inv +xD +cInv);inv.e4 +inv +cK +inv);eR2} +eJ +pow;pow +xD +cPow);pow.e4 +pow +yP1 +list.first);pow +cK +pow);} +#ifdef FP_MUL_COMBINE_EXPONENTS +tD.clear()yM3 +0;a0){if(tE>1){std +xV3 >nU;std::multimapeG1;bool +lS3 +tO3 +nB1 +iC1{i81 +t33.tP3{lC2 +p=t33 +l8 +b);const +fphash_t +p_hash=p.GetHash();for(std::multimap::const_iterator +i=eG1.xU2 +p_hash);i!=eG1.cY1 +p_hash;++i){if(nU[i +e82 +tC3 +xF +p)){nU[i +e82 +tD3+=1;lS3=true;goto +found_mulgroup_item_dup;} +} +nU.push_back(std::make_pair(p,size_t(1)));eG1.insert(std::make_pair(p_hash,nU.tF3-1));found_mulgroup_item_dup:;} +} +if(lS3){eJ +eA2;{size_t +max=0;for +iA1 +p=0;pmax){eA2=nU[p +tC3;max=nU[p +tD3;} +} +} +eJ +group_add;group_add +xD +cAdd); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Duplicate across some trees: " +i13(eA2 +lT2" in " +yA1 +#endif +nB1 +iC1 +i81 +t33.tP3 +if(eA2 +xF +t33 +l8 +b))){eJ +tmp +y91 +a)yA +CloneTag());tmp +tK2 +b);tmp +eT1 +group_add +yP1 +tmp);remaining[a]tO3 +yF3 +group_add +eT1 +eJ +group;group +tH3 +group +yP1 +eA2);group +yP1 +group_add);group +eT1 +add.nX2(group);c41} +} +nB1 +iC1{if(add.nX2 +y91 +a))==CollectionSetBase::xP2)c41} +} +if(should_regenerate){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantFolding_AddGrouping: " +yA1 +#endif +tree.DelParams();xX2 +eV1::xS1 +j=add.iC.yU3 +j!=add.iC.end();++j){eJ&value=j +e82.value;eJ&coeff=j +e82.xT2;if(j +e82.cX)coeff +eT1 +if(coeff +i51 +cB3 +coeff +nC1,xD1 +cP2 +cA3 +coeff +nC1 +xE3 +lP1 +value);eR2} +eJ +mul;mul +tH3 +mul +yP1 +value);mul +yP1 +coeff);mul +cK +mul);} +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"After ConstantFolding_AddGrouping: " +yA1 +#endif +return +true;} +return +tR3} +lF3{using +lF3 +FUNCTIONPARSERTYPES;using +t5 +nJ1 +bool +ConstantFolding_IfOperations(iS3(tree.GetOpcode()==cIf||tree.GetOpcode()==cAbsIf);for(;;){lT3 +nC==cNot){tI3 +cIf);lE2 +0).xY2 +0)lR2 +eO3.swap +y91 +2)t43 +lT3 +cS1{tI3 +yW3;lE2 +0).xY2 +0)lR2 +eO3.swap +y91 +2)t43 +yJ3 +tM +0),i01==yW3)l92 +tree.xY2 +1));nV +lC3 +tree.xY2 +2));nV +lT1 +lT3 +nC==cIf||lE2 +0)nC==yW3{eJ +cond=lE2 +0);eJ +lU3;lU3 +t53==cIf?cNotNot:cAbsNotNot);lU3 +xZ2 +1));ConstantFolding(lU3);eJ +lV3;lV3 +t53==cIf?cNotNot:cAbsNotNot);lV3 +xZ2 +2));ConstantFolding(lV3 +eY3 +lU3 +i61||lV3 +i61){eJ +eV;eV +t53);eV +xZ2 +1));eV.nJ +1));eV.nJ +2));eV +eT1 +eJ +eW;eW +t53);eW +xZ2 +2));eW.nJ +1));eW.nJ +2));eW +eT1 +tree +t53);cM1 +0,cond +lR2 +tree.nG1 +1,eV);tree.nG1 +2,eW)xJ2} +if +y91 +1)nC==lE2 +2)nC&&y91 +1)nC==cIf||eO3 +nC==yW3){eJ&iE2=eO3;eJ&leaf2=lE2 +2 +eY3 +iE2 +l8 +0)xC1 +0))&&c93 +1))||iE2 +l8 +2)xC1 +2)))){eJ +eV;eV +iP2 +eV.nJ +0));eV +c9 +iE2 +l8 +1));eV +c9 +leaf2 +l8 +1));eV +eT1 +eJ +eW;eW +iP2 +eW.nJ +0));eW +c9 +iE2 +l8 +2));eW +c9 +leaf2 +l8 +2));eW +iU +SetParam(0,iE2 +lR2 +tree.nG1 +1,eV);tree.nG1 +2,eW)xJ2 +if +c93 +1))&&iE2 +l8 +2)xC1 +2))){eJ +eX;eX +iP2 +eX.AddParamMove +y91 +0));eX +c9 +iE2 +lR2 +eX +c9 +leaf2 +lR2 +eX +iU +nG1 +0,eX);cM1 +2,iE2 +l8 +2));cM1 +1,iE2 +l8 +1))xJ2 +if +c93 +2))&&iE2 +l8 +2)xC1 +1))){eJ +eB2;eB2 +xD +leaf2 +nC==cIf?cNot:cZ3);eB2 +c9 +leaf2 +lR2 +eB2 +eT1 +eJ +eX;eX +iP2 +eX.AddParamMove +y91 +0));eX +c9 +iE2 +lR2 +eX +yP1 +eB2);eX +iU +nG1 +0,eX);cM1 +2,iE2 +l8 +2));cM1 +1,iE2 +l8 +1))xJ2} +eJ&xX=eO3;eJ&y6=lE2 +2 +eY3 +xX +xF +y6)){tree.xY2 +1))xJ2 +const +OPCODE +op1=xX +nC;const +OPCODE +op2=y6 +nC;if +eN3 +op2){if(xX +cE1 +1){eJ +lO +0));lW3 +lR2 +tQ3 +n4 +if(xX +cE1 +2&&y6 +cE1 +2){if(xX +l8 +0)xF +y6 +l8 +0))){eJ +param0=xX +l8 +0);eJ +lO +1));lW3 +l8 +1));tQ3;lP1 +param0)n4 +if(xX +l8 +1)xF +y6 +l8 +1))){eJ +param1=xX +l8 +1);eJ +lO +0));lW3 +lR2 +tQ3;lP1 +nE1);lP1 +param1)xJ2} +if +eN3 +yZ3 +cMul +lS2 +cAnd +lS2 +cOr +lS2 +cAbsAnd +lS2 +cAbsOr +lS2 +cMin +lS2 +cMax){eH +lX3;yZ{for +iA1 +b=y6.xF1 +b-->0;){if +c62 +y6 +l8 +b))){if(lX3 +cT3){xX.l61 +y6.l61} +lX3.push_back(xX +x13 +y6 +tK2 +b);xX +t31 +cT2} +} +if(!lX3 +cT3){xX +eT1 +y6.Rehash()l7 +op1);tree +iO3 +lX3)n4} +} +if +eN3 +yZ3 +cMul||eN3 +cAnd +nT1 +y6))||eN3 +cOr +nT1 +y6))){yZ +if +c62 +y6)){xX.l61 +xX +t31);xX +eT1 +eJ +cO1=y6;y6=tF +op1==yZ3 +cOr +tE2 +op1);lP1 +cO1)n4} +if(eN3 +cAnd +lS2 +cOr)&&op2==cNotNot){eJ&lY3=y6 +l8 +0);yZ +if +c62 +lY3)){xX.l61 +xX +t31);xX +eT1 +eJ +cO1=lY3;y6=tF +op1 +yY3 +op1);lP1 +cO1)n4} +if(op2==cAdd||op2==cMul||(op2==cAnd +nT1 +xX))||(op2==cOr +nT1 +xX))){for +iA1 +a=y6 +n41 +y6 +l8 +a)xF +xX)){y6.l61 +y6 +t31);y6 +eT1 +eJ +cP1=xX;xX=tF +op2==cAdd||op2 +yY3 +op2);lP1 +cP1)n4} +if((op2==cAnd||op2==cOr)&&op1==cNotNot){eJ&lZ3=xX +l8 +0)yM3 +y6 +n41 +y6 +l8 +a)xF +lZ3)){y6.l61 +y6 +t31);y6 +eT1 +eJ +cP1=lZ3;xX=tF +op2 +yY3 +op2);lP1 +cP1)n4} +return +tR3} +#include +lF3{using +lF3 +FUNCTIONPARSERTYPES;using +t5 +nJ1 +int +maxFPExponent()yR +std::numeric_limits +xK::max_exponent;} +xN1 +x51 +iV2 +base,iV2 +xG2{if(base=iV2(maxFPExponent +xK())/fp_log2(base);} +xN1 +ConstantFolding_PowOperations(iS3(tree.GetOpcode()==cPow);nR&&eO3 +l71 +const_value +t03 +lR,tH);xO +const_value)n31 +tR3 +tM2 +cB3 +tH +xE3 +tree.xY2 +0))xJ2 +nR&&cB3 +lR +xE3 +xO +1)n31 +tR3 +nR&&eO3 +nC==cMul){bool +y02=false +iU2 +lU2=lR;eJ +mulgroup=eO3 +yM3 +mulgroup +n41 +mulgroup +l8 +a)l71 +imm=mulgroup +l8 +a)nC1;{if(x51 +lU2,imm))break +iU2 +lV2 +t03 +lU2,imm)cA3 +lV2,xD1)break;if(!y02){y02=true;yQ1 +l61} +lU2=lV2;yQ1 +DelParam(a +cT2} +if(y02){yQ1 +Rehash(); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before pow-mul change: " +yA1 +#endif +lE2 +0).Become(e21 +lU2));eO3.Become +lR3); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"After pow-mul change: " +yA1 +#endif +} +} +tM2 +lE2 +0)nC==cMul +tJ2 +lW2=tH +iU2 +y12=1.0;bool +y02 +tO3 +eJ&mulgroup=lE2 +0)yM3 +mulgroup +n41 +mulgroup +l8 +a)l71 +imm=mulgroup +l8 +a)nC1;{if(x51 +imm,lW2))break +iU2 +eH1 +t03 +imm,lW2)cA3 +eH1,xD1)break;if(!y02){y02=true;yQ1 +l61} +y12*=eH1;yQ1 +DelParam(a +cT2} +if(y02){yQ1 +Rehash();eJ +eS3;eS3 +xD +cPow);eS3 +iO3 +tree.l02));eS3.n62 +tree +tH3 +lP1 +eS3);i83 +e21 +y12))xJ2} +lT3 +nC==cPow&&eO3 +i61&&lE2 +0)l8 +1)l71 +a=lE2 +0)l8 +1)nC1 +iU2 +b=tH +iU2 +c=a*b;if(isEvenInteger(a)&&!isEvenInteger(c)){eJ +n03;n03 +xD +cAbs);n03.nJ +0)lR2 +n03 +eT1 +tree.nG1 +0,n03 +t43 +cM1 +0,lE2 +0)lR2 +cM1 +1,e21 +c));} +return +tR3} +lF3{using +lF3 +FUNCTIONPARSERTYPES;using +t5;e12 +l5{enum +eC2{MakeFalse=0,MakeTrue=1,t72=2,n23=3,MakeNotNotP0=4,MakeNotNotP1=5,MakeNotP0=6,MakeNotP1=7,xB=8 +xF3 +lX2{Never=0,Eq0=1,Eq1=2,c03=3,c13=4} +;eC2 +if_identical;eC2 +lY2 +4];e12{eC2 +what:4;lX2 +when:4;} +iK1,iL1,iM1,iN1 +nJ1 +eC2 +Analyze +lQ3 +a,lC2 +b +e83{if(a +xF +b +nE3 +if_identical;c23 +p0=iN +a);c23 +p1=iN +b);eR3 +known&&p1 +n51){eR3 +valp1 +yN +val&&lY2 +2]i4 +2];if(p0 +tF2>=p1 +yN +val&&lY2 +3]i4 +3];} +if(IsLogicalValue(a)){if(iK1 +tP2 +iK1.when,p1 +nE3 +iK1.what;if(iM1 +tP2 +iM1.when,p1 +nE3 +iM1.what;} +if(IsLogicalValue(b)){if(iL1 +tP2 +iL1.when,p0 +nE3 +iL1.what;if(iN1 +tP2 +iN1.when,p0 +nE3 +iN1.what;} +return +xB;} +cA1 +bool +TestCase(lX2 +when,const +c23&p){if(!p +n51||!p +yN +known +cL +switch(when +y33 +Eq0 +nV1==iV2(0.0)&&e13==p +tF2;case +Eq1 +nV1==iV2(1.0)&&e13==e13;case +c03 +nV1>y21&&e13<=iV2(1);case +c13 +nV1>=y21 +lH1 +1);c73;} +return +tR3} +;lF3 +RangeComparisonsData{static +const +l5 +Data[6]={{l5 +c51,{l5::tU +xB,l5::tU +xB +iT +Eq1 +iW +Eq1 +nX1 +Eq0 +nY1 +Eq0} +eI1 +c51,l5::xB,l5 +c51,l5::xB +iT +Eq0 +iW +Eq0 +nX1 +Eq1 +nY1 +Eq1} +eI1 +c51,l5::t72,l5::tU +MakeFalse +nX1 +c03 +iW +c13 +yD +cC +yD +n13{l5::xB,l5 +c51,l5::tU +n23 +nX1 +c13 +iW +c03 +yD +cC +eI1::tU +tU +n13 +l5::t72 +iT +c13 +nY1 +c03 +yD +cC +yD +n13{l5::tU +n23,l5::xB,l5 +c51 +iT +c03 +nY1 +c13 +yD +cC} +} +;} +xN1 +ConstantFolding_Comparison(e62{using +lF3 +RangeComparisonsData;assert(tree.GetOpcode()>=cEqual&&tree.GetOpcode()<=cGreaterOrEq);switch(Data[i01-cEqual].Analyze +y91 +0),eO3)y33 +l5::MakeFalse:xO +0);nV +l5 +c51:xO +1)yN3 +n23:tI3 +cEqual)yN3 +t72:tI3 +cNEqual)yN3 +MakeNotNotP0:tI3 +cNotNot)yO3 +1)yN3 +MakeNotNotP1:tI3 +cNotNot)yO3 +0)yN3 +MakeNotP0:tI3 +cNot)yO3 +1)yN3 +MakeNotP1:tI3 +cNot)yO3 +0)yN3 +xB:;} +if +y91 +1)i61)switch +y91 +0)nC +y33 +cAsin:lM +fp_sin +c53 +cAcos:lM +fp_cos +tG));tI3 +i01==cLess?cGreater:i01==cLessOrEq?cGreaterOrEq:i01==cGreater?cLess:i01==cGreaterOrEq?cLessOrEq:i01);nV +cAtan:lM +fp_tan +c53 +cLog:lM +fp_exp +c53 +cSinh:lM +fp_asinh +c53 +cTanh:if(fp_less(fp_abs +tG +xE3 +lM +fp_atanh +tG))xJ2 +break;c73 +yF3 +return +tR3} +#include +#include +#ifdef FP_SUPPORT_OPTIMIZER +using +lF3 +FUNCTIONPARSERTYPES;lF3{ +#ifdef DEBUG_SUBSTITUTIONS +yE +double +d){union{double +d;uint_least64_t +h;} +t82 +d=d;lM1 +h +nZ1 +#ifdef FP_SUPPORT_FLOAT_TYPE +yE +float +f){union{float +f;uint_least32_t +h;} +t82 +f=f;lM1 +h +nZ1 +#endif +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +yE +long +double +ld){union{long +double +ld;e12{uint_least64_t +a;iF2 +short +b;} +s;} +t82 +ld=ld;lM1 +s.b<IsIdenticalTo(*b.data);} +xN1 +xH2 +xK::IsIdenticalTo +cH1 +xH2 +xK&b +e83{if(Hash!=b.Hash +cL +if(Opcode!=tK3 +cL +switch(Opcode +y33 +cImmed:return +cB3 +Value,tL3;case +l03:return +l22==b.l12 +case +cFCall:case +cPCall:if(l22!=b.l22 +cL +break;c73 +yF3 +if(xX3!=b.xX3 +cL +for +iA1 +a=0;a1)data=new +xH2 +xK(*data);} +xW3 +eJ +eJ::GetUniqueRef(){if(GetRefCount()>1)return +eJ(*this,CloneTag())n31*this;} +tX):yT +cNop +t92(),n8 +tX +const +xH2&b):yT +tK3 +t92(tL3,l22(b.cQ1,Params(b.Params),Hash(b.Hash),Depth(b.Depth),tP1 +b.l32){} +tX +const +iV2&i):yT +cImmed +t92(i),n8 +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +tX +xH2 +xK&&b):yT +tK3 +t92 +c72 +tL3),l22(b.cQ1,Params +c72 +b.Params)),Hash(b.Hash),Depth(b.Depth),tP1 +b.l32){} +tX +iV2&&i):yT +cImmed +t92 +c72 +i)),n8 +#endif +tX +xB2 +o):yT +o +t92(),n8 +tX +xB2 +o,iF2 +f):yT +o +t92(),l22(f),Params(),Hash(),Depth(1),tP1 +0){} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +#include +#include +#include +#include +#include +using +lF3 +FUNCTIONPARSERTYPES; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +lF3{tZ1 +n12(nO,std +c7&done,std::ostream&o){nB1 +n12 +l64 +done,o);std::ostringstream +buf +i13(tree,buf);done[tree.GetHash()].insert(buf.str());} +} +#endif +t5{ +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +tZ1 +DumpHashes(cF){std +c7 +done;n12(tree,done,o);for(std +c7::const_iterator +i=done.yU3 +i!=done.end();++i){const +std::set&flist=i +e82;if(flist.tF3!=1)o<<"ERROR - HASH COLLISION?\n" +;for(std::set::const_iterator +j=flist.yU3 +j!=flist.end();++j){o<<'['<first.hash1<<','<first.hash2<<']'<0)o<<' 'i13 +l64 +o +eY3 +a+1 +lF3 +l21{iF2 +ParamSpec_GetDepCode +cH1 +e42&b +y13 +b.first +y33 +tG3:{cO*s=(cO*)b +tE3 +n31 +s->depcode;} +case +SubFunction:{cP*s=(cP*)b +tE3 +n31 +s->depcode;} +c73 +yF3 +return +0;} +tZ1 +DumpParam +cH1 +e42&yG2 +std::ostream&o){static +const +char +ParamHolderNames[][2]={"%" +,"&" +,"x" +,"y" +,"z" +,"a" +,"b" +,"c" +} +;iF2 +y32 +0;switch(yH2.first +y33 +NumConstant:{const +ParamSpec_NumConstant +xK +yK3 +cH1 +ParamSpec_NumConstant +xK*c61 +using +lF3 +FUNCTIONPARSERTYPES;o.precision(12);o<';yF +PositionalParams)o<<"]" +;yF +SelectedParams)o<<"}" +;o<<')';} +yF3 +l73 +ImmedConstraint_Value(constraints&ValueMask)y33 +ValueMask:lC +Value_AnyNum:lC +nY2:o<<"@E" +;lC +Value_OddInt:o<<"@O" +;lC +tS1:o<<"@I" +;lC +Value_NonInteger:o<<"@F" +;lC +eJ1:o<<"@L" +;yJ3 +ImmedConstraint_Sign(constraints&SignMask)y33 +SignMask:lC +Sign_AnySign:lC +nH1:o<<"@P" +;lC +eK1:o<<"@N" +;yJ3 +ImmedConstraint_Oneness(constraints&OnenessMask)y33 +OnenessMask:lC +Oneness_Any:lC +Oneness_One:o<<"@1" +;lC +Oneness_NotOne:o<<"@M" +;yJ3 +ImmedConstraint_Constness(constraints&ConstnessMask)y33 +ConstnessMask:lC +tR1:if(yH2.first==tG3){cO +yK3(cO*c61 +if +y23 +index<2)yF3 +o<<"@C" +;lC +Constness_NotConst:o<<"@V" +;lC +Oneness_Any:yF3} +tZ1 +DumpParams +nT2 +paramlist,iF2 +count,std::ostream&o){for(eQ1=0;a0)o<<' ';const +e42¶m=e81 +xK(paramlist,a);DumpParam +xK(param,o);iF2 +depcode=ParamSpec_GetDepCode(param +eY3 +depcode!=0)o<<"@D" +< +using +lF3 +l21;using +lF3 +FUNCTIONPARSERTYPES;lF3{cO +plist_p[37]={{2,0,0x0} +nP +0,0x4} +nP +nH1,0x0} +nP +eK1|Constness_NotConst,0x0} +nP +Sign_NoIdea,0x0} +nP +eJ1,0x0} +,{3,Sign_NoIdea,0x0} +,{3,0,0x0} +,{3,eJ1,0x0} +,{3,0,0x8} +,{3,Value_OddInt,0x0} +,{3,Value_NonInteger,0x0} +,{3,nY2,0x0} +,{3,nH1,0x0} +,{0,eK1|lV{0,lV{0,nH1|lV{0,nY2|lV{0,tR1,0x1} +,{0,tS1|nH1|lV{0,tT1 +tR1,0x1} +,{0,tT1 +lV{0,Oneness_One|lV{0,eJ1|lV{1,lV{1,nY2|lV{1,tT1 +lV{1,tS1|lV{1,nH1|lV{1,eK1|lV{6,0,0x0} +,{4,0,0x0} +,{4,tS1,0x0} +,{4,lV{4 +tU3 +5,0,0x0} +,{5,lV} +nJ1 +e12 +plist_n_container{static +const +ParamSpec_NumConstant +xK +plist_n[20];} +nJ1 +const +ParamSpec_NumConstant +xK +plist_n_container +xK::plist_n[20]={{iV2(-2 +tY-1 +tY-0.5 +tY-0.25 +tY +0 +tA2 +fp_const_deg_to_rad +xK(tA2 +fp_const_einv +xK(tA2 +fp_const_log10inv +xK(tY +0.5 +tA2 +fp_const_log2 +xK(tY +1 +tA2 +fp_const_log2inv +xK(tY +2 +tA2 +fp_const_log10 +xK(tA2 +fp_const_e +xK(tA2 +fp_const_rad_to_deg +xK(tA2-fp_const_pihalf +xK(),xT1{y21,xT1{fp_const_pihalf +xK(),xT1{fp_const_pi +xK(),xT1} +;cP +plist_s[517]={{{1,15,tS2 +398,tS2 +477,tS2 +15,cNeg,GroupFunction,0} +,tR1,0x1} +,{{1,15,y42 +24,y42 +465,y42 +466,y42 +498,cInv,lT +2,327995 +xE +l0 +2,48276 +xE +l6 +260151 +xE +l6 +470171 +xE +l6 +169126 +xE +l6 +48418 +xE +l6 +1328 +xE +l6 +283962 +xE +l6 +169275 +xE +l6 +39202 +xE +l6 +283964 +xE +l6 +283973 +xE +l6 +476619 +xE +l6 +296998 +xE +l6 +47 +xE +SelectedParams,0} +,0,0x4 +nH +161839 +xE +l6 +25036 +xE +l6 +35847 +xE +l6 +60440 +xE +l6 +30751 +xE +l6 +270599 +xE +l6 +60431 +xE +l6 +259119 +xE +l6 +183474 +xE +l6 +332066 +xE +l6 +7168 +xE +l6 +197632 +xE +l6 +291840 +xE +l6 +283648 +xE +l6 +238866 +xE +l6 +239902 +xE +l6 +31751 +xE +l6 +244743 +xE +l6 +384022 +xE +SelectedParams,0} +,0,0x4 +nH +385262 +xE +l6 +386086 +xE +l6 +393254 +xE +SelectedParams,0} +,0,0x5 +nH +393254 +xE +l6 +386095 +xE +l6 +387312 +xE +l6 +18662 +xE +l6 +61670 +xE +l6 +387397 +xE +l6 +247855 +xE +SelectedParams,0} +,0,0x1 +nH +342063 +xE +l6 +297007 +xE +l6 +15820 +xE +l6 +393263 +xE +l6 +393263 +xE +SelectedParams,0} +,0,0x5 +nH +161847 +xE +l6 +258103 +xE +l6 +249073 +xE +l6 +249076 +xE +iD +0,0 +xE +nF +0,0 +tU1 +1,45 +xE +nF +1,53 +xE +nF +1,54 +xE +nF +1,55 +xE +nF +1,56 +xE +nF +1,26 +xE +nF +1,259 +tJ +1} +tU3{1,253 +xE +nF +1,272 +tU1 +1,323 +tJ +1} +tU3{1,0 +xE +nF +1,21 +xE +nF +1,447 +tJ +1} +lA2 +449 +tJ +1} +lA2 +0 +tJ +1} +lA2 +0 +tJ +2} +lA2 +15 +xE +nF +1,24 +tJ +2} +,0,0x0 +nH +58392 +tU1 +0,0 +tJ +1} +,nH1,0x0 +nH +24591 +yI3 +33807 +yI3 +48143 +yI3 +285720 +yI3 +290840 +yI3 +305152,l9 +312400,l9 +39202,l9 +121894,l9 +421926,l9 +429094,l9 +443430,l9 +317834,l9 +329098,l9 +7633,l9 +7706,l9 +7730,l9 +38,l9 +50587,l9 +406528,l9 +24583,l9 +31751,l9 +405511,l9 +321551,xU1 +327713,l9 +322596,l9 +88361,l9 +335174,l9 +327050,l9 +493606,l9 +496678,l9 +503846,l9 +516134,l9 +7217,l9 +333875,l9 +336896,l9 +524326,l9 +509952,l9 +286727,l9 +90127,l9 +131087,l9 +296976,tB1 +324623,l1 +0x14 +nH +332815,l1 +0x10} +,{{3,7340056,tB1 +289092,l9 +92176,xU1 +337935 +lB2 +7340060,l1 +tT2 +7340176,l9 +338959 +lB2 +7340061,xU1 +7206,l9 +xJ3 +l9 +357414,l9 +368678,l9 +370745,l1 +0x7} +,{{3,7340177,l9 +39277,tB1 +426398,l1 +tT2 +40272286,xU1 +490910,l1 +tT2 +40336798,xU1 +50600,l9 +426462,xU1 +490974,xU1 +370726,l1 +0x6 +nH +371750,l1 +0x6 +nH +428070 +lB2 +40336862,xU1 +38378,l9 +50671 +lB2 +47662080,l9 +477184,l9 +568320,l9 +371727,l1 +0x7} +,{{3,15779306,l9 +370703,l1 +0x7 +nH +39277,l9 +39279,l1 +0x4} +,{{3,15779238,l9 +39338,tB1 +436262,l9 +508966,l9 +39409,tB1 +296998,tB1 +35847,l9 +15,tB1 +377894,l9 +386063,l1 +0x1 +nH +15,l9 +7192,l9 +122904,l9 +121880,l9 +30751,l9 +57,l9 +7456,l9 +15674 +lB2 +67579935,l9 +39237,l9 +58768,l9 +62924,l9 +121856,l9 +15760 +lB2 +64009216,l1 +0x0} +,{{0,0,xG +0,0,iL +2,e31 +2,e41 +3,e31 +3,e41 +38,xG +1,38,iL +14,xG +1,57,xG +1,16,eD2 +0x0 +nH +471103,eD2 +0x1} +,{{1,303,xG +1,323,cE3 +0x0 +nH +471363,eD2 +0x16} +,{{1,293,e31 +294,e41 +295,xG +1,296,iL +400,xG +1,0,xG +1,460,xG +1,465,xG +1,16,eD2 +0x1} +,{{1,57,cE3 +0x1} +,{{1,0,iL +21,xG +1,15,eD2 +0x0 +nH +24591,xG +1,24,iL +517,cE3 +0x0 +nH +46095,lK +46104,lK +15397,lK +287789,lK +66584,lK +404763,lK +62504,lK +15409,lK +39951,lK +24591,lK +33807,lK +50200,lK +62509,lK +50176,lF,178176,eL1 +tV3 +283648,lF,19456,lF,27648,lF,89088,lF,86016,lF,488448,lF,14342,lF,58375,lF,46147 +xZ +46151,lF,284679,lF,7183,lF,46159 +xZ +38993 +xZ +50265,lF,50249,lF,283808,lF,284835,lF,24822,lF,10240,lF,11264,lF,7170,lF,xJ3 +lF,17408,lF,164864,lF,237568,lF,242688,eL1 +0x14 +nH +476160,lF,25607,lF,121871,lF,50252,lF,39374,lF,50183,lF,7192,lF,121887,lF,252979,lF,46155,lF,38919,lF,50267,lF,50268,lF,50253,lF,46190,lF,50295,lF,7563,eL1 +0x10 +nH +416811,lF,416819,lF,40046,lF,46191 +xZ +415795,lF,40047 +xZ +415787,lF,39015,eL1 +0x5 +nH +39326 +xZ +39326,lF,39332,eL1 +0x5 +nH +39333 +cW2 +50590 +xZ +50590,lF,39338 +xZ +39338,lF,39335,eL1 +0x5 +nH +15786 +xZ +146858,lF,39372,lF,39379,lF,39380,lF,39390 +xZ +50654 +xZ +50654,lF,24,eL1 +0x6 +nH +62,lF,24,lF,62,eL1 +0x6 +nH +43,lF,43 +xZ +51,lF,51 +xZ +50269,lF,50176 +xZ +50270,lF,39159,lF,39183 +xZ +7168 +xZ +31744,lF,99328,lF,31746,lF,100376,lF,39409 +xZ +39411 +xZ +39411,lF,39420,lF,39420 +xZ +15,lF,39025,eL1 +0x5 +nH +39422,lF,16384,lF,62853,lF,15360,lF,15 +cW2 +16,lF,7183 +cW2 +7172 +l14 +yX1} +,nH1,0x0 +nH +24591 +l14 +lT +2,50200 +l14 +lT +2,63521 +l14 +lT +2,62500 +l14 +lT +2,50453 +l14 +lT +2,62488,cPow +eP3 +tS3 +7,tS3 +194,tS3 +0,cAcos +tT3 +cAcosh +tT3 +cAsin +tT3 +cAsinh +nQ +119,cAsinh +tT3 +cAtan +eW1 +306176,cAtan2 +eW1 +xJ3 +cAtan2 +tT3 +cAtanh +nQ +246,cCeil +tT3 +cCeil,l13 +0,c92 +0,cCos,l13 +7,c92 +91,c92 +92,c92 +119,c92 +236,c92 +255,c92 +214,l23 +236,l23 +464,l23 +0,cCosh,l13 +0,l23 +0,cExp +nQ +7,cExp +nQ +91,cExp +tT3 +cF3 +7,cF3 +91,cF3 +246,cFloor +tT3 +cFloor,lA +0x4 +nH +309540,cHypot +eW1 +316708,cHypot +eW1 +316724,cHypot,l0 +3,32513024,y52 +34627584 +n61 +31493120,y52 +89213952 +n61 +149042176 +n61 +246647808 +n61 +301234176 +n61 +494360576 +n61 +498558976 +n61 +62933520 +n61 +62933520,y52 +62933526 +n61 +62933526,y52 +24670208 +n61 +579378176 +n61 +573578240 +n61 +32513024 +n61 +566254592 +n61 +7900160 +n61 +588822528,cIf +nQ +119,cInt +nQ +246 +cA2 +0 +cA2 +7 +cA2 +31 +cA2 +194 +cA2 +363 +cA2 +15,cLog,lT +1,24,cLog +eP3 +cLog10 +tT3 +cLog2 +eW1 +xJ3 +cMax +eW1 +35847,cMax +eW1 +30751,cMax +tT3 +cMax,AnyParams,1} +,0,0x4 +nH +xJ3 +cMin +eW1 +35847,cMin +eW1 +30751,cMin +tT3 +cMin,AnyParams,1} +,0,0x4 +nH +24591,cMin +eP3 +nZ2 +7,nZ2 +91,nZ2 +92,nZ2 +119,nZ2 +149,nZ2 +231,cSin,lA +0x5} +,{{1,246,nZ2 +255,nZ2 +254,nZ2 +0,cSin,l13 +273,cSin,lA +0x1} +,{{1,214,y62 +231,cSinh,lA +0x5} +,{{1,246,y62 +254,y62 +255,y62 +464,y62 +0,cSinh,l13 +0,y62 +15,cSqrt +eP3 +cB2 +0,cTan,l13 +115,cTan,l13 +116,cB2 +231,cB2 +246,cB2 +273,cB2 +254,cB2 +255,cB2 +0,y92 +0,cTanh,l13 +213,y92 +231,y92 +246,y92 +254,y92 +255,y92 +0,cTrunc +eW1 +15384,cSub,lT +2,15384,cDiv,lT +2,476626,cDiv,lT +2,121913,tU2 +xJ3 +n42 +lA +tV3 +xJ3 +tU2 +31744,n42 +lA +0x20 +nH +31751,n42 +lA +0x24 +nH +31751,tU2 +121913,eM1 +l0 +2,xJ3 +cLess,lA +tV3 +41984,cLess,lA +0x4 +nH +41984,cLess +eW1 +7,cLess +eW1 +xJ3 +cLessOrEq +eW1 +296182,cLessOrEq +eW1 +7168 +lJ3,lA +tV3 +41984 +lJ3,lA +0x4 +nH +41984 +lJ3 +eW1 +7 +lJ3 +eW1 +xJ3 +yB +l0 +2,296182,cGreaterOrEq +tT3 +n22 +245,n22 +7,n22 +550,n22 +553,n22 +554,n22 +556,n22 +31,n22 +559,n22 +15,n22 +560,cNot +eW1 +7706,n33 +xJ3 +n33 +35847,n33 +30751,n33 +463903,n33 +466975,cAnd,iD +0,0,cAnd,nF +2,xJ3 +eT3 +7706,eT3 +35847,eT3 +463903,eT3 +466975,eT3 +30751,cOr,iD +1,0,n32 +91,n32 +131,n32 +245,n32 +215,n32 +246,cDeg +nQ +246,cRad +eW1 +xJ3 +cAbsAnd,l6 +xJ3 +cAbsOr,iD +1,0,cZ3 +tT3 +cAbsNotNot,l0 +3,32513024,cL3 +lA +0x0} +,} +;} +lF3 +l21{const +Rule +grammar_rules[262]={{ProduceNewTree,17,1,0,{1,0,cAbs,eE2 +409,{1,146,cAtan,eE2 +403 +nP +1324,cG3 +eE2 +405 +nP +307201,cG3 +l2 +c22 +253174 +nP +255224,cG3 +l2 +c22 +259324 +nP +257274,cG3 +eE2 +152,{1,252,cCeil +iO +486,{1,68,tW2 +482,{1,122,tW2 +483,{1,124,tW2 +151,{1,125,tW2 +419,{1,123,tW2 +0,{1,403,cCos,l2 +2,1,246,{1,252,cCos,l2 +18,1,0,{1,400,tW2 +301,{1,406,cCosh,l2 +2,1,246,{1,252,cCosh,l2 +18,1,0,{1,400,cCosh +iO +458,{1,121,cFloor,eE2 +150,{1,252,cFloor,tW3 +156,{3,7382016,eB +549,{3,8430592,eB +556,{3,8436736,eB +157,{3,42998784,eB +550,{3,42999808,eB +562,{3,43039744,eB +557,{3,49291264,eB +538,{3,49325056,eB +469,{3,1058318,eB +473,{3,1058324,eB +473,{3,9438734,eB +469,{3,9438740,cIf,l2 +0,3,32542225,{3,36732434,cIf,l2 +0,3,32542231,{3,36732440,cIf,tX3 +573,{3,32513026,cIf,tX3 +515,{3,455505423,cIf,tX3 +515,{3,433506837,cIf +iO +78,{1,256,tY3 +69,{1,258,tY3 +404,{1,72,tY3 +159,{1,147,cLog,l2 +0,1,0 +nP +487425,cMax +l3 +16,1,445 +nP +cH3 +cMax +l3 +0,1,0 +nP +483329,cMin +l3 +16,1,446 +nP +cH3 +cMin,c0 +0,1,153 +nP +24832 +l14 +tW3 +153 +nP +25854 +l14 +tW3 +154 +nP +129039 +nX3 +32055 +nX3 +32056 +nX3 +32057 +tV2 +166288 +nP +32137 +nX3 +33082 +tV2 +7168 +nP +12688 +tV2 +7434 +nP +12553 +y72 +435 +nP +46146 +y72 +436 +nP +46154 +y72 +437 +nP +46150 +y72 +169 +nP +83983 +y72 +168 +nP +130082 +y72 +175 +nP +133154 +y82 +476160 +nP +471055 +y82 +274432 +nP +273423 +y82 +251904 +nP +266274 +y82 +251904 +nP +263186 +y72 +171,{1,252,cC2 +421,{1,68,cC2 +151,{1,122,cC2 +419,{1,124,cC2 +170,{1,125,cC2 +482,{1,123,cC2 +0,{1,405,cC2 +172,{1,252,cSinh +iO +328,{1,404,cSinh +iO +173,{1,252,l34 +0,{1,408,l34 +176,{1,410,l34 +177,{1,252,cTanh,l2 +0,1,442 +nP +449551,tZ +1,441 +nP +cH3 +tZ +1,167 +nP +268549,tZ +1,181 +nP +276749,tZ +1,180 +nP +276500 +iD3 +190770 +nP +189622 +iD3 +194748 +nP +193723 +iD3 +202943 +nP +196795 +iD3 +59699 +nP +298148 +iD3 +59714 +nP +325815 +iD3 +59724 +nP +343224 +xE +c0 +2,1,337,{1,333 +tJ +1 +l33 +336,{1,338 +tJ +1} +} +l44 +2,1,340 +nP +1363,i0 +342 +nP +1365,i0 +463 +nP +472524,i0 +47 +nP +356711,i0 +349 +nP +200751,i0 +360 +nP +199727,i0 +480 +nP +207053,i0 +481 +nP +208077,i0 +417 +nP +211144,i0 +209 +nP +211145,i0 +418 +nP +215240,i0 +212 +nP +212329,i0 +204 +nP +373097,i0 +211 +nP +372944,i0 +217 +nP +201944,i0 +221 +nP +223448,i0 +367 +nP +508329,i0 +219 +nP +508126,i0 +224 +nP +225705,i0 +223 +nP +225776,i0 +365 +nP +230825,i0 +426 +nP +377057,i0 +497 +nP +377054,i0 +497 +nP +204201,i0 +426 +nP +375280,i0 +224 +nP +375006,cAdd +l3 +2,2,407781 +nP +233698,cAdd +l3 +2,2,59763 +nP +233842,tZ +1,372 +nP +1397,lQ1 +95 +nP +24705,lQ1 +96 +nP +24708,lQ1 +444 +nP +449551,lQ1 +443 +nP +cH3 +lQ1 +100 +nP +101750,lQ1 +108 +nP +106821,lQ1 +105 +nP +103749 +nA2 +0,2,110607 +nP +108869 +nA2 +0,2,107535 +nP +109893,lJ +0 +l33 +112 +nP +111634,cMul,SelectedParams,0 +l33 +567,{1,52,lJ +1 +l33 +568,{1,42,lJ +1} +} +l44 +2,1,467 +nP +45516 +iV +356 +nP +51555 +iV +468 +nP +49612 +iV +357 +nP +47459 +iV +429 +nP +438699 +iV +432 +nP +441774 +iV +486 +nP +498726 +iV +494 +nP +504870 +iV +382 +nP +435579 +iV +497 +nP +435709 +iV +426 +nP +508287 +iV +414 +nP +500092 +iV +499 +nP +352744 +iV +345 +nP +367092 +iV +381 +nP +425318 +iV +478 +nP +425460 +iV +47 +nP +512501 +iV +505 +nP +355817 +iV +47 +nP +516598 +iV +507 +nP +518182 +iV +508 +nP +358896 +iV +351 +nP +388605 +iV +511 +nP +360939 +iV +503 +nP +354788 +iV +514 +nP +525350 +iV +510 +nP +394342 +iV +386 +nP +351346 +nA2 +2,2,363004 +nP +361968 +nA2 +16,1,117 +nP +1157 +nA2 +16,1,118 +nP +1158 +nA2 +16,1,402 +nP +411024 +nA2 +16,2,58768 +nP +1472 +nA2 +16,2,15760 +nP +1474 +nA2 +17,1,0,{1,400 +nA2 +17,1,57,{1,14,lJ +0 +l91 +4 +n43 +41,n42 +l4 +4,1,0 +nP +5167,n42 +yA2 +41984 +nP +409641,cEqual +c4 +n42 +yA2 +eY +n42 +l43 +n42 +l2 +xB1 +24849 +tN2 +iE +tN2 +n63 +281873 +tN2 +lA1 +tN2 +lB1 +n42 +l4 +4 +y43 +41,eM1 +l4 +4 +n43 +5167,eM1 +yA2 +41984 +nP +409641,cNEqual +c4 +eM1 +yA2 +eY +eM1 +l43 +eM1 +l2 +xB1 +24849,eM1 +l2 +cI3 +eM1 +l2 +c22 +n63 +281873,eM1 +l2 +c22 +lA1,eM1 +l2 +c22 +lB1 +cNEqual +c4 +eO1 +16,2,eY +eO1 +16 +eI +cLess,eE2 +571 +nP +46080,eO1 +xB1 +24832,eO1 +c22 +yT1,eO1 +cI3 +eO1 +cJ3 +eO1 +c22 +xW1,eO1 +c22 +lA1,eO1 +c22 +lB1 +cLess,l4 +20 +y43 +409641,cLess +c4 +t6 +16,2,eY +t6 +16 +eI +cLessOrEq,eE2 +565 +nP +409615,t6 +xB1 +24832,t6 +c22 +yT1,t6 +cI3 +t6 +cJ3 +t6 +c22 +xW1,t6 +c22 +lA1,t6 +c22 +lB1 +cLessOrEq,l4 +20 +y43 +409647,cLessOrEq +c4 +lK3 +yA2 +eY +lK3 +l43 +lK3 +eE2 +539 +nP +409615 +eP +529654 +nP +24832 +eP +yT1 +eP +iE +eP +n63 +281856 +eP +xW1 +eP +lA1 +eP +lB1 +lK3 +l4 +20 +n43 +409647 +lJ3 +c4 +yB +yA2 +eY +yB +l43 +yB +eE2 +572 +nP +46080,yB +l2 +xB1 +24832,yB +l2 +c22 +yT1,yB +l2 +cI3 +yB +l2 +cJ3 +yB +l2 +c22 +xW1,yB +l2 +c22 +lA1,yB +l2 +c22 +lB1 +yB +l4 +20 +n43 +409641,yB +l4 +4,1,519,{1,137,cNot,tX3 +571,{1,2,cNot,l2 +0,1,452 +nP +cH3 +n73 +0,2,537097,{3,547892744,cAnd,c0 +16,1,566,{1,5,cAnd,AnyParams,1} +} +l44 +16,1,569 +nP +13314,n73 +16,1,544 +nP +553498,n73 +16,1,546 +nP +462369,n73 +16,1,548 +nP +466465,n73 +0,1,457 +nP +cH3 +xX1 +570 +nP +13314,xX1 +563 +nP +8197,xX1 +541 +nP +553498,xX1 +542 +nP +462369,xX1 +543 +nP +466465,xX1 +564 +nP +143365,cOr,c0 +4,1,525,{1,137,cK3 +tX3 +572,{1,2,cK3 +l4 +17,1,0,{1,0,cK3 +eE2 +537,{1,256,cAbsNotNot,c0 +18,1,531,{1,254,cAbsNotNot,c0 +0,1,572,{3,43039744,cL3 +tW3 +571,{3,49325056,cL3 +tX3 +454,{3,32513586,cL3 +l2 +16,3,32542225,{3,36732434,cL3 +yX1} +} +,} +;e12 +grammar_optimize_abslogical_type{y2 +9 +cS +grammar_optimize_abslogical_type +grammar_optimize_abslogical={9,{34,192,228,238,242,247,254,260,261} +} +;} +e12 +grammar_optimize_ignore_if_sideeffects_type{y2 +59 +cS +grammar_optimize_ignore_if_sideeffects_type +grammar_optimize_ignore_if_sideeffects={59,{0,20,21,22,23,24,25,26,cQ +iO1 +78,cR +cT +e12 +grammar_optimize_nonshortcut_logical_evaluation_type{y2 +56 +cS +grammar_optimize_nonshortcut_logical_evaluation_type +grammar_optimize_nonshortcut_logical_evaluation={56,{0,25,cQ +iO1 +78,cR +241,243,244,245,246,248,249,250,251,252,253,255,256,257,258,259} +} +;} +e12 +grammar_optimize_recreate_type{y2 +22 +cS +grammar_optimize_recreate_type +grammar_optimize_recreate={22,{18,55,56,57,80,81,82,83,84,85,117,118,120,121,130,131,132,133,134,135,136,137} +} +;} +e12 +grammar_optimize_round1_type{y2 +125 +cS +grammar_optimize_round1_type +grammar_optimize_round1={125,{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,19,25,cQ +37,38,iO1 +45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,63,64,65,66,67,68,69,70,71,78,79,80,81,82,83,84,85,86,87,88,93,94,95,96,97,98,99,100,101,117,118,119,120,121,122,123,124,125,126,127,128,129,138,160,161,162,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240,cT +e12 +grammar_optimize_round2_type{y2 +103 +cS +grammar_optimize_round2_type +grammar_optimize_round2={103,{0,15,16,17,25,cQ +39,40,iO1 +45,46,47,48,49,50,51,52,53,54,59,60,72,73,78,79,86,87,88,89,90,91,92,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,119,122,123,124,125,126,127,128,139,159,160,161,162,163,164,165,166,167,168,169,178,179,180,200,204,212,216,224,236,237,239,240,cT +e12 +grammar_optimize_round3_type{y2 +79 +cS +grammar_optimize_round3_type +grammar_optimize_round3={79,{74,75,76,77,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,170,171,172,173,174,175,176,177,181,182,183,184,185,186,187,188,189,190,191,193,194,195,196,197,198,199,201,202,203,205,206,207,208,209,210,211,213,214,215,217,218,219,220,221,222,223,225,226,227,229,230,231,232,233,234,235} +} +;} +e12 +grammar_optimize_round4_type{y2 +12 +cS +grammar_optimize_round4_type +grammar_optimize_round4={12,{18,55,56,57,130,131,132,133,134,135,136,137} +} +;} +e12 +grammar_optimize_shortcut_logical_evaluation_type{y2 +53 +cS +grammar_optimize_shortcut_logical_evaluation_type +grammar_optimize_shortcut_logical_evaluation={53,{0,25,cQ +iO1 +78,cR +cT} +lF3 +l21{xW3 +e42 +e81 +nT2 +paramlist,nA1){index=(paramlist>>(index*10))&1023;if(index>=57)return +e42(SubFunction,cD2 +plist_s[index-57]eY3 +index>=37)return +e42(NumConstant,cD2 +plist_n_container +xK::plist_n[index-37])n31 +e42(tG3,cD2 +plist_p[index]);} +} +#ifdef FP_SUPPORT_OPTIMIZER +#include +#include +#include +#include +using +lF3 +FUNCTIONPARSERTYPES;using +lF3 +l21;using +t5;using +yL1;lF3{nR1 +It,xK3 +T,xK3 +Comp>eP1 +MyEqualRange(It +first,It +last,const +T&val,Comp +comp){size_t +len=last-first;while(len>0){size_t +yA3 +len/2;It +xG3(first);xG3+=half;if(comp(*xG3,val)){first=xG3;++first;len=len-half-1;} +lJ2 +comp(val,*xG3)){len=half;} +else{It +left(first);{It&eF2=left;It +last2(xG3);size_t +len2=last2-eF2;while(len2>0){size_t +half2=len2/2;It +cD3(eF2);cD3+=half2;if(comp(*cD3,val)){eF2=cD3;++eF2;len2=len2-half2-1;} +else +len2=half2;} +} +first+=len;It +right(++xG3);{It&eF2=right;It&last2=first;size_t +len2=last2-eF2;while(len2>0){size_t +half2=len2/2;It +cD3(eF2);cD3+=half2;if(comp(val,*cD3))len2=half2;else{eF2=cD3;++eF2;len2=len2-half2-1;} +eW2 +eP1(left,right);eW2 +eP1(first,first);} +xW3 +e12 +OpcodeRuleCompare{iG2()lQ3 +tree,iF2 +yB2 +e83{const +Rule&rule=grammar_rules[yB2]n31 +i01range=MyEqualRange(tX2.rule_list,tX2.rule_list+tX2.rule_count,tree,OpcodeRuleCompare +xK());std +xV3rules;rules.xS3 +range +tE3-range.first);for +y5 +if(IsLogisticallyPlausibleParamsMatch(tD1 +cE2,tree))rules.push_back(*r);} +range.first=!rules +cT3?&rules[0]:0;range +tE3=!rules +cT3?&rules[rules.tF3-1]+1:0;if(range.first!=range +iO2{ +#ifdef DEBUG_SUBSTITUTIONS +if(range.first!=range +iO2 +yC2"Input (" +< +#include +#include +#include +#include /* for auto_ptr */ +using +lF3 +FUNCTIONPARSERTYPES;using +lF3 +l21;using +t5;using +yL1;lF3{xN1 +TestImmedConstraints +nT2 +bitmask,lC2 +tree +y13 +bitmask&ValueMask +y33 +Value_AnyNum:case +ValueMask:lC +nY2:if(GetEvennessInfo +eZ3 +n52 +Value_OddInt:if(GetEvennessInfo +eZ3 +x02 +tS1:if(GetIntegerInfo +eZ3 +n52 +Value_NonInteger:if(GetIntegerInfo +eZ3 +x02 +eJ1:if(!IsLogicalValue(tree)cL +nI1 +SignMask +y33 +Sign_AnySign:lC +nH1:if(l01 +n52 +eK1:if(l01 +x02 +Sign_NoIdea:if(l01 +Unknown +cL +nI1 +OnenessMask +y33 +Oneness_Any:case +OnenessMask:lC +Oneness_One:if(!yN1 +if(!cB3 +fp_abs(eC3)tG1 +1))cL +lC +Oneness_NotOne:if(!yN1 +if(cB3 +fp_abs(eC3)tG1 +1))cL +nI1 +ConstnessMask +y33 +Constness_Any:lC +tR1:if(!yN1 +lC +Constness_NotConst:if(yN1 +yF3 +return +true;} +i31 +iF2 +extent,iF2 +nbits,xK3 +eG2=iF2 +int>e12 +nbitmap{private:static +const +iF2 +bits_in_char=8;static +const +iF2 +eH2=(cM3 +eG2)*bits_in_char)/nbits;eG2 +data[(extent+eH2-1)/eH2];eX3 +void +inc(nA1,int +by=1){data[pos(index)]+=by*eG2(1<>yD2)&mask()yH3 +pos(nA1)yR +index/eH2 +yH3 +shift(nA1)yR +nbits*(index%eH2)yH3 +mask()yR(1<SubTreesDetail;eJ3(){std::memset(this,0,cM3*this));} +eJ3 +cH1 +eJ3&b){std::memcpy(this,&b,cM3 +b));} +eJ3&eA1=cH1 +eJ3&b){std::memcpy(this,&b,cM3 +b))n31*this;} +} +nJ1 +eJ3 +CreateNeedList_uncached(tC&c32){eJ3 +cN1;for(eQ1=0;ae51;static +e51 +yV1;e51::yV3 +i=yV1.xU2&c32 +eY3 +i!=yV1.cY1&c32)return +i +e82 +n31 +yV1.yR3,std::make_pair(&c32,CreateNeedList_uncached +xK(c32)))e82;} +xW3 +eJ +CalculateGroupFunction +cH1 +e42&yG2 +const +tB +info +y13 +yH2.first +y33 +NumConstant:{const +ParamSpec_NumConstant +xK +yK3 +cH1 +ParamSpec_NumConstant +xK*)yH2 +tE3 +n31 +CodeTreeImmed +y23 +constvalue +i33 +tG3:{cO +yK3(cO*)yH2 +tE3 +n31 +tM3 +GetParamHolderValueIfFound +y23 +index +i33 +SubFunction:{cP +yK3(cP*c61 +eJ +nT3;nT3 +xD +yL3 +l81);nT3.l02).xS3 +yL3 +data +yF2);for(eQ1=0;a0)eU3 +Immeds;else +eU3 +eV3;lC +l03:case +cFCall:case +cPCall:eU3 +eV3;break;c73 +assert(opcode0&&cN1.SubTreesDetail.get(opcode)>0){eU3 +SubTrees;cN1.SubTreesDetail.dec(opcode +t43 +eU3 +eV3;} +} +if(cN1.Immeds>0||cN1.SubTrees>0||cN1.eV3>0)n93} +if(c32.match_type!=AnyParams){if(0||cN1.SubTrees<0||cN1.eV3<0)n93 +eW2 +true;} +xW3 +lX1 +TestParam +cH1 +e42&yG2 +lC2 +tree,const +cW&start_at +tJ3 +y13 +yH2.first +y33 +NumConstant:{const +ParamSpec_NumConstant +xK +yK3 +cH1 +ParamSpec_NumConstant +xK*c61 +if(!yN1 +iV2 +imm=eC3;switch +y23 +modulo +y33 +Modulo_None:lC +Modulo_Radians:imm=e93 +imm,yO +immfp_const_pi +xK())imm-=fp_const_twopi +xK(cT2 +return +cB3 +imm,yL3 +constvalue +i33 +tG3:{cO +yK3(cO*c61 +if(!x0 +return +tM3 +SaveOrTestParamHolder +y23 +index,tree +i33 +SubFunction:{cP +yK3(cP*c61 +yF +GroupFunction){if(!x0 +eJ +xY1=CalculateGroupFunction(yG2 +info); +#ifdef DEBUG_SUBSTITUTIONS +DumpHashes(xY1 +lT2*cH1 +void**)&xY1 +nC1;std::cout<<"\n" +;std::cout<<*cH1 +void**)&eC3;std::cout<<"\n" +;DumpHashes(tree +lT2"Comparing " +i13(xY1 +lT2" and " +i13(tree +lT2": " +;std::cout<<(xY1 +xF +tree)?"true" +:"false" +lT2"\n" +; +#endif +return +xY1 +xF +tree);} +e63!&*start_at){if(!x0 +if(i01!=yL3 +l81 +cL} +return +TestParams +y23 +data,tree,start_at,info,false);} +eW2 +tR3 +xW3 +e12 +iX +x72 +MatchInfo +xK +info;iX():start_at(),info(){} +} +nJ1 +class +MatchPositionSpec_PositionalParams:xE1 +iX +xK>{eX3 +l53 +MatchPositionSpec_PositionalParams +iA1 +n +yB1 +iX +xK>(n){} +} +;e12 +iQ1 +x72 +iQ1():start_at(){} +} +;class +yG:xE1 +iQ1>{eX3 +iF2 +trypos;l53 +yG +iA1 +n +yB1 +iQ1>(n),trypos(0){} +} +nJ1 +lX1 +TestParam_AnyWhere +cH1 +e42&yG2 +lC2 +tree,const +cW&start_at +tJ3,std::eV2&used,bool +eY2{xRx5;tY2 +yG +eU2 +a=x5->trypos;goto +retry_anywhere_2 +tC2 +yG(eM);a=0;} +for(;atrypos=a +n31 +lX1(true,&*x5);} +} +retry_anywhere_2 +i23 +goto +retry_anywhere;eW2 +tR3 +xW3 +e12 +yC1 +x72 +MatchInfo +xK +info;std::eV2 +used;l53 +yC1 +iA1 +tZ3):start_at(),info(),used(tZ3){} +} +nJ1 +class +MatchPositionSpec_AnyParams:xE1 +yC1 +xK>{eX3 +l53 +MatchPositionSpec_AnyParams +iA1 +n,size_t +m +yB1 +yC1 +xK>(n,yC1 +xK(m)){} +} +nJ1 +lX1 +TestParams(tC&nN,lC2 +tree,const +cW&start_at +tJ3,bool +eY2{if(nN.match_type!=AnyParams){if(xV!=eM +cL} +if(!IsLogisticallyPlausibleParamsMatch(nN,tree))n93 +l73 +nN.match_type +y33 +PositionalParams:{xRx5;tY2 +cG +eU2 +a=xV-1;goto +lD1 +tC2 +cG(xV);a=0;} +for(;a +eX2{lG2=info;retry_positionalparams +i03=TestParam(cU +a),t33,(i02);iB1 +eR2} +lD1 +i23 +info=lG2;goto +retry_positionalparams;} +if(a>0){--a;goto +lD1;} +info=eD3 +n31 +tR3 +if(eY2 +for(tZ2 +tM3 +SaveMatchedParamIndex(a)n31 +lX1(true,&*x5 +i33 +SelectedParams:case +AnyParams:{xRx5;std::eV2 +used(eM);std +xV3l63(xV);std +xV3yI2(xV);for(tZ2{const +e42 +yH2=cU +a);l63[a]=ParamSpec_GetDepCode(yH2);} +{iF2 +b=0;for(tZ2 +if(l63[a]!=0)yI2[b++]=a;for(tZ2 +if(l63[a]==0)yI2[b++]=a;} +tY2 +t7 +eU2 +if(xV==0){a=0;goto +retry_anyparams_4;} +a=xV-1;goto +e61 +tC2 +t7(xV,eM);a=0;if(xV!=0){eD3=info;(*x5)[0].used=used;} +} +for(;a +eX2{if(a>0){lG2=info;(*x5)[a].used=used;} +retry_anyparams +i03=TestParam_AnyWhere +xK(cU +yI2[a]),tree,(i02,used,eY2;iB1 +eR2} +e61 +i23 +info=lG2;used=(*x5)[a].used;goto +retry_anyparams;} +e71:if(a>0){--a;goto +e61;} +info=eD3 +n31 +tR3 +retry_anyparams_4:if(nN.n1!=0){if(!TopLevel||!tM3 +HasRestHolder(nN.n1)){eH +cF2;cF2.xS3 +eM);for +nT2 +b=0;b +#include +using +t5;using +yL1;lF3{xW3 +eJ +xZ1 +const +e42&yG2 +tB +info,bool +inner=true +y13 +yH2.first +y33 +NumConstant:{const +ParamSpec_NumConstant +xK +yK3 +cH1 +ParamSpec_NumConstant +xK*)yH2 +tE3 +n31 +CodeTreeImmed +y23 +constvalue +i33 +tG3:{cO +yK3(cO*)yH2 +tE3 +n31 +tM3 +GetParamHolderValue +y23 +index +i33 +SubFunction:{cP +yK3(cP*c61 +eJ +tree;tI3 +yL3 +l81);for(eQ1=0;alist=tM3 +GetMatchedParamIndexes();std::sort(list.iN2 +list.end())yM3 +list.tF3;a-->0;)tree +tK2 +list[a]);for(eQ1=0;a +#include +using +lF3 +FUNCTIONPARSERTYPES;using +lF3 +l21;using +t5;using +yL1;lF3 +l21{tZ1 +DumpMatch +cH1 +eT2 +lC2 +tree,const +tB +info,bool +DidMatch,std::ostream&o){DumpMatch(rule +iY3,DidMatch?l24"match" +:l24"mismatch" +,o);} +tZ1 +DumpMatch +cH1 +eT2 +lC2 +tree,const +tB +info,nH3 +i43,std::ostream&o){static +const +char +ParamHolderNames[][2]={"%" +,"&" +,"x" +,"y" +,"z" +,"a" +,"b" +,"c" +} +;o< = " +i13(tM3 +lQ[b +tD3[a],o);o< +#include +#ifdef FP_SUPPORT_OPTIMIZER +using +lF3 +FUNCTIONPARSERTYPES;lF3{xN1 +MarkIncompletes(FPoptimizer_CodeTree::e62{if(tree.Is_Incompletely_Hashed(tI1;bool +iR1 +tO3 +nB1 +iR1|=MarkIncompletes +y91 +a)eY3 +iR1)tree.Mark_Incompletely_Hashed()n31 +iR1;} +tZ1 +FixIncompletes(FPoptimizer_CodeTree::e62{if(tree.Is_Incompletely_Hashed()){nB1 +FixIncompletes +y91 +a));tree +eT1} +} +} +t5{lB +Sort()tN3 +Sort();} +lB +Rehash(bool +constantfolding){if(constantfolding)ConstantFolding(*this);else +Sort();data +x7 +xW3 +e12 +cA{cO3 +iV2 +cP3 +yD1=0; +#if 0 +long +double +value=Value;e5=crc32::calc(cH1 +iF2 +char*)&value,cM3 +value));key^=(key<<24); +#elif 0 +union{e12{iF2 +char +filler1[16]iU2 +v;iF2 +char +filler2[16];} +buf2;e12{iF2 +char +filler3[cM3 +iV2)+16-c +M3 +x91)];e5;} +buf1;} +data;memset(&data,0,cM3 +data));data.buf2.v=Value;e5=data.buf1.key; +#else +int +exponent +iU2 +nM2=std::frexp(Value,&xG2;e5=nT2 +t62+0x8000)&0xFFFF +eY3 +nM2<0){nM2=-nM2;key=key^0xFFFF;} +else +key+=0x10000;nM2-=iV2(0.5);key<<=39;key|=lY1(nM2+nM2)*iV2(1u<<31))<<8; +#endif +lP +#ifdef FP_SUPPORT_COMPLEX_NUMBERS +nR1 +T +cG2 +std::complex >{cO3 +std::complexcP3 +cA::nA3 +cH2,Value.real());nB +fphash_t +temp;cA::nA3 +temp,Value.imag());yD1^=temp.hash2;cH2.hash2^=temp.hash1;} +} +; +#endif +#ifdef FP_SUPPORT_LONG_INT_TYPE +i31 +cG2 +long>{yH +long +Value){e5=Value;lP +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE +i31 +cG2 +GmpInt>{cO3 +GmpInt +cP3 +e5=Value.toInt();lP +#endif +tZ1 +xH2 +xK::Recalculate_Hash_NoRecursion(){fphash_t +cH2(lY1 +Opcode)<<56,Opcode*iP3(0x1131462E270012B));Depth=1;switch(Opcode +y33 +cImmed:{cA +xK::nA3 +cH2,Value +cT2 +case +l03:{yD1|=lY1 +cQ1<<48 +lF1((lY1 +cQ1)*11)^iP3(0x3A83A83A83A83A0);yF3 +case +cFCall:case +cPCall:{yD1|=lY1 +cQ1<<48 +lF1((~lY1 +cQ1)*7)^3456789;} +c73{size_t +eR1=0 +yM3 +0;aeR1)eR1=iZ2 +y22;yD1+=((iZ2 +i12 +hash1*(a+1))>>12)lF1 +iZ2 +i12 +hash1 +lF1(3)*iP3(0x9ABCD801357);cH2.hash2*=iP3(0xECADB912345)lF1(~iZ2 +i12 +hash2)^4567890;} +Depth+=eR1;} +} +if(Hash!=cH2){Hash=cH2;l32=0;} +} +lB +FixIncompleteHashes(){MarkIncompletes(*this);FixIncompletes(*this);} +} +#endif +#include +#include +#include +#ifdef FP_SUPPORT_OPTIMIZER +using +lF3 +FUNCTIONPARSERTYPES;lF3{using +t5 +nJ1 +bool +x01 +lC2 +tree,long +count,const +xH1::SequenceOpCode +xK&eU,xH1 +yG3&synth,size_t +max_bytecode_grow_length);static +const +e12 +SinCosTanDataType{OPCODE +whichopcode;OPCODE +inverse_opcode;enum{nominator,nN2,inverse_nominator,lG1} +;OPCODE +codes[4];} +SinCosTanData[12]={{cTan,cCot,{cSin,cCos,cCsc,cSec} +} +,{cCot,cCot,{cCos,cSin,cSec,cCsc} +} +,{cCos,cSec,{cSin,cTan,cCsc,cCot} +} +,{cSec,cCos,{cTan,cSin,cCot,cCsc} +} +,{cSin,cCsc,{cCos,cCot,cSec,cTan} +} +,{cCsc,cSin,{cCot,cCos,cTan,cSec} +} +,{cI2{cSinh,cCosh,cJ2,{cSinh,cNop,{cI2 +cNop,cCosh} +} +,{cCosh,cNop,{cSinh,cI2 +cNop} +} +,{cNop,cTanh,{cCosh,cSinh,cJ2,{cNop,cSinh,{cNop,cTanh,cCosh,cNop} +} +,{cNop,cCosh,{cTanh,cSinh,cJ2} +;} +t5{lB +SynthesizeByteCode(std +xV3&ByteCode,std +xV3 +xK&Immed,size_t&stacktop_max){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Making bytecode for:\n" +;iR +#endif +while(RecreateInversionsAndNegations()){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"One change issued, produced:\n" +;iR +#endif +FixIncompleteHashes();using +yL1;using +lF3 +l21;const +void*g=cD2 +grammar_optimize_recreate;while(ApplyGrammar(*cH1 +Grammar*)g,*this)){FixIncompleteHashes();} +} +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Actually synthesizing, after recreating inv/neg:\n" +;iR +#endif +xH1 +yG3 +synth;SynthesizeByteCode(synth,false);synth.Pull(ByteCode,Immed,stacktop_max);} +lB +SynthesizeByteCode(xH1 +yG3&synth,bool +MustPopTemps +e83{y01*this))yR;} +for +iA1 +a=0;a<12;++a){const +SinCosTanDataType&data=SinCosTanData[a];if(data.whichopcode!=cNop)iD1!=data.whichopcode +cP2;CodeTree +nB3;nB3.lN1 +nB3 +cQ3 +inverse_opcode);nB3.n62 +y01 +nB3)){synth.l11 +else +iD1!=cInv +cP2;if(GetParam(0)nC!=data.inverse_opcode +cP2;y01 +GetParam(0))){synth.l11 +size_t +found[4];i81 +4;++b){CodeTree +tree;if(data.i53]==cNop){tI3 +cInv);CodeTree +nC3;nC3.lN1 +nC3 +cQ3 +i53^2]);nC3.n62 +lP1 +nC3 +t43{tree.lN1 +tree +cQ3 +i53]);} +tree.n62 +found[b]=synth.xU3 +tree);} +if(found[data.yJ2!=tL +nN2]y4 +yJ2);n81 +nN2 +i5 +cDiv +nK1 +yJ2!=tL +lG1]y4 +yJ2);n81 +lG1 +i5 +cMul +nK1 +lR1!=tL +lG1]y4 +lR1);n81 +lG1 +i5 +cRDiv +nK1 +lR1!=tL +nN2]y4 +lR1);n81 +nN2 +i5 +cMul,2,1);synth.l11 +size_t +n_subexpressions_synthesized=SynthCommonSubExpressions(iS2 +switch(iS1{case +l03:synth.PushVar(GetVar());lC +cImmed:lH2 +GetImmed());lC +cAdd:case +cMul:case +cMin:case +cMax:case +cAnd:case +cOr:case +cAbsAnd:case +cAbsOr:iD1==cMul){bool +cR3 +tO3 +yI +lS1 +i61&&isLongInteger(lS1 +nC1)){c82=makeLongInteger(lS1 +nC1);CodeTree +tmp(*this,xK3 +CodeTree::CloneTag());tmp +t31);tmp +eT1 +if(x01 +tmp,value,xH1::tN1 +xK::AddSequence,synth,MAX_MULI_BYTECODE_LENGTH)){cR3=true;yF3} +} +if(cR3)yF3 +int +yE1=0;std::eV2 +done(GetParamCount(),false);CodeTree +iF;iF +xD +iS1;for(;;){bool +found +tO3 +yI +done[a]cP2;if(synth.IsStackTop(lS1)){found=true;done[a]=true;lS1.n7 +iF +c9 +lS1 +eY3++yE1>1){synth +yJ +2);iF.Rehash(false)cI1 +iF);yE1=yE1-2+1;} +} +} +if(!found)yF3 +yI +done[a]cP2;lS1.n7 +iF +c9 +lS1 +eY3++yE1>1){synth +yJ +2);iF.Rehash(false)cI1 +iF);yE1=yE1-2+1;} +} +if(yE1==0 +y13 +iS1{case +cAdd:case +cOr:case +cAbsOr:lH2 +0);lC +cMul:case +cAnd:case +cAbsAnd:lH2 +1);lC +cMin:case +cMax:lH2 +0);break;c73 +yF3++yE1;} +assert(n_stacked==1);yF3 +case +cPow:{lG3 +p0=GetParam(0);lG3 +p1=GetParam(1 +eY3!p1 +i61||!isLongInteger +eH3)||!x01 +p0,makeLongInteger +eH3),xH1::tN1 +xK::MulSequence,synth,MAX_POWI_BYTECODE_LENGTH)){p0.n7 +p1.n7 +synth +yJ +2);i91 +cIf:case +cAbsIf:{xK3 +xH1 +yG3::IfData +ifdata;GetParam(0).n7 +synth.SynthIfStep1(ifdata,iS1;GetParam(1).n7 +synth.SynthIfStep2(ifdata);GetParam(2).n7 +synth.SynthIfStep3(ifdata +cT2 +case +cFCall:case +cPCall:{for +iA1 +a=0;a0){size_t +top=synth.GetStackTop();synth.DoPopNMov(top-1-n_subexpressions_synthesized,top-1);} +} +} +lF3{xN1 +x01 +lC2 +tree,long +count,const +xH1::SequenceOpCode +xK&eU,xH1 +yG3&synth,size_t +max_bytecode_grow_length){if +eL3!=0){xH1 +yG3 +backup=synth;tree.n7 +size_t +bytecodesize_backup=synth.GetByteCodeSize();xH1::x01 +count,eU,iS2 +size_t +bytecode_grow_amount=synth.GetByteCodeSize()-bytecodesize_backup;if(bytecode_grow_amount>max_bytecode_grow_length){synth=backup +n31 +tR3 +return +true;} +else{xH1::x01 +count,eU,synth)xJ2} +} +#endif +#include +#include +#ifdef FP_SUPPORT_OPTIMIZER +using +lF3 +FUNCTIONPARSERTYPES;lF3{using +t5; +#define FactorStack std xV3 +const +e12 +PowiMuliType{iF2 +opcode_square;iF2 +opcode_cumulate;iF2 +opcode_invert;iF2 +opcode_half;iF2 +opcode_invhalf;} +iseq_powi={cSqr,cMul,cInv,cSqrt,cRSqrt} +,iseq_muli={iP1 +xE +cNeg,iP1,iP1} +nJ1 +iV2 +eS1 +cH1 +PowiMuliType&cS3,const +std +xV3&xP1,n72&stack +tO2 +1);while(IPy21&&isEvenInteger +xO1 +iV2(0.5);yW +opcode_invhalf){if +iT2>y21&&isEvenInteger +xO1 +iV2(-0.5);++IP;eR2 +size_t +x12=IP +iU2 +lhs(1 +eY3 +iT1==cFetch){nA1=nD2;if(index=iV1){IP=x12;yF3 +lhs=stack[index-y1];goto +yK2;} +if(iT1==cDup){lhs=nT3;goto +yK2;yK2:eX1 +nT3);++IP +iU2 +subexponent=eS1(cS3 +tS +if(IP>=limit||iT1!=cS3.opcode_cumulate){IP=x12;yF3++IP;stack.pop_back();nT3+=lhs*subexponent;eR2 +yF3 +return +nT3;} +xW3 +iV2 +ParsePowiSequence +cH1 +std +xV3&xP1){n72 +stack;eX1 +iV2(1))n31 +eS1(iseq_powi +tS} +xW3 +iV2 +ParseMuliSequence +cH1 +std +xV3&xP1){n72 +stack;eX1 +iV2(1))n31 +eS1(iseq_muli +tS} +xW3 +class +CodeTreeParserData{eX3 +l53 +CodeTreeParserData(bool +k_powi):stack(),clones(),keep_powi(k_powi){} +void +Eat +iA1 +tZ3,OPCODE +opcode){eJ +xI;xI +xD +opcode);eH +c32=Pop(tZ3)tQ1 +c32 +eY3!keep_powi)switch(opcode +y33 +cTanh:{eJ +sinh,cosh;sinh +xD +cSinh);sinh +c9 +xI +lR2 +sinh +eT1 +cosh +xD +cCosh);cosh +yP1 +xI +lR2 +cosh +eT1 +eJ +pow;pow +xD +cPow);pow +yP1 +cosh);pow.yC +iV2(-1)));pow +eT1 +xI +tH3 +xI.nG1 +0,sinh);xI +yP1 +pow +cT2 +case +cTan:{eJ +sin,cos;sin +xD +cSin);sin +c9 +xI +lR2 +sin +eT1 +cos +xD +cCos);cos +yP1 +xI +lR2 +cos +eT1 +eJ +pow;pow +xD +cPow);pow +yP1 +cos);pow.yC +iV2(-1)));pow +eT1 +xI +tH3 +xI.nG1 +0,sin);xI +yP1 +pow +cT2 +case +cPow:{lC2 +p0=xI +l8 +0);lC2 +p1=xI +l8 +1 +eY3 +p1 +nC==cAdd){eH +mulgroup(p1.GetParamCount())yM3 +0;a" +<void +Push(T +tree){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<0;){eZ1 +i13 +iT2[n]tT +nT3[n]);} +#endif +stack.t73 +iV1-n_pop)n31 +nT3;} +size_t +GetStackTop(yZ1 +iV1;} +private:void +FindClone(eJ&,bool=true)yR;} +private:eH +stack;std::multimapclones;bool +keep_powi;private:CodeTreeParserData +cH1 +CodeTreeParserData&);CodeTreeParserData&eA1=cH1 +CodeTreeParserData&);} +nJ1 +e12 +IfInfo{eJ +eI2;eJ +thenbranch;size_t +endif_location;IfInfo():eI2(),thenbranch(),endif_location(){} +} +;} +t5{lB +GenerateFrom +cH1 +xK3 +FunctionParserBase +xK::Data&xH3,bool +keep_powi){eH +xC2;xC2.xS3 +xH3.mVariablesAmount);for +nT2 +n=0;n&ByteCode=xH3.mByteCode;const +std +xV3 +xK&Immed=xH3.mImmed; +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"ENTERS GenerateFrom()\n" +; +#endif +CodeTreeParserData +xK +sim(keep_powi);std +xV3eG;for +iA1 +IP=0,DP=0;;++IP){i22:while(!eG +cT3&&(eG.e6==IP||(IP=i8 +tF3)break;iF2 +opcode=iT1;if((opcode==cSqr||opcode==cDup||(opcode==cInv&&!IsIntType +xK::nT3)||opcode==cNeg||opcode==cSqrt||opcode==cRSqrt||opcode==cFetch)){size_t +was_ip=IP +iU2 +e92 +ParsePowiSequence +xK(ByteCode,IP,eG +cT3?i8 +tF3:eG.e6,sim.xM +1);if +t62!=iV2(1.0)){xL +exponent +xD2;goto +i22;} +if(opcode==cDup||opcode==cFetch||opcode==cNeg +tJ2 +xT2=ParseMuliSequence +xK(ByteCode,IP,eG +cT3?i8 +tF3:eG.e6,sim.xM +1 +eY3 +xT2!=iV2(1.0)){xL +xT2)y3 +cMul);goto +i22;} +} +IP=was_ip;} +if(n82>=l03){nA1=opcode-l03 +nB2 +xC2[index]t43{switch(n82 +y33 +cIf:case +cAbsIf:{eG.t73 +eG.tF3+1);CodeTree +res(sim.yL2);eG.back().eI2.swap(res);eG.e6=i8 +tF3;IP+=2;eR2 +case +cJump:{CodeTree +res(sim.yL2);eG.tE1.swap(res);eG.e6=lE3 +IP+1]+1;IP+=2;eR2 +case +cImmed:xL +Immed[DP++]);lC +cDup:sim.Dup();lC +cNop:lC +cFCall:{iF2 +funcno=nD2;assert(funcno +#ifdef FP_SUPPORT_OPTIMIZER +#include +#define FP_MUL_COMBINE_EXPONENTS +lF3{using +lF3 +FUNCTIONPARSERTYPES;using +t5 +nJ1 +static +void +AdoptChildrenWithSameOpcode(e62{ +#ifdef DEBUG_SUBSTITUTIONS +bool +nO2 +tO3 +#endif +for +iY +if +y91 +a)nC==i01){ +#ifdef DEBUG_SUBSTITUTIONS +if(!nO2)yC2"Before assimilation: " +yA1 +nO2=true;} +#endif +tree.AddParamsMove +y91 +a).GetUniqueRef().l02),a);} +#ifdef DEBUG_SUBSTITUTIONS +if(nO2)yC2"After assimilation: " +yA1} +#endif +} +} +t5{tZ1 +ConstantFolding(e62{tree.Sort(); +#ifdef DEBUG_SUBSTITUTIONS +void*cY3=0;std::cout<<"[" +<<(&cY3)<<"]Runs ConstantFolding for: " +yA1 +DumpHashes(tree +lT2 +std::flush; #endif - - OptimizeConflict(); - -#ifdef TREE_DEBUG - cout << "AFTER MATH1 B :" << *this << endl; +if(false){redo:;tree.Sort(); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"[" +<<(&cY3)<<"]Re-runs ConstantFolding: " +yA1 +DumpHashes(tree); #endif - } - - void OptimizeAddMulFlat() - { - // This optimization flattens the topography of the tree. - // Examples: - // x + (y+z) = x+y+z - // x * (y/z) = x*y/z - // x / (y/z) = x/y*z - // min(x, min(y,z)) = min(x,y,z) - // max(x, max(y,z)) = max(x,y,z) - - if(GetOp() == cAdd - || GetOp() == cMul - || GetOp() == cMin - || GetOp() == cMax) - { - // If children are same type as parent add them here - for(pit b, a=GetBegin(); a!=GetEnd(); a=b) - { - const SubTree &pa = *a; b=a; ++b; - if(pa->GetOp() != GetOp()) continue; - - // Child is same type - for(pcit c=pa->GetBegin(); - c!=pa->GetEnd(); - ++c) - { - const SubTree &pb = *c; - if(pa.getsign()) - { - // +a -(+b +c) - // means b and c will be negated - - SubTree tmp = pb; - if(GetOp() == cMul) - tmp.Invert(); - else - tmp.Negate(); - AddParam(tmp); - } - else - AddParam(pb); - } - Erase(a); - - // Note: OptimizeConstantMath1() would be a good thing to call next. - } - } - } - - void OptimizeLinearCombine() - { - // This optimization does the following: - // - // x*x*x*x -> x^4 - // x+x+x+x -> x*4 - // x*x -> x^2 - // x/z/z -> - // - // min(x,x,y) -> min(x,y) - // max(x,x,y) -> max(x,y) - // max(x,x) -> max(x) - - // Remove conflicts first, so we don't have to worry about signs. - OptimizeConflict(); - - bool didchanges = false; - bool FactorIsImportant = true; - unsigned ReplacementOpcode = GetOp(); - - switch(GetOp()) - { - case cAdd: - FactorIsImportant = true; - ReplacementOpcode = cMul; - goto Redo; - case cMul: - FactorIsImportant = true; - ReplacementOpcode = cPow; - goto Redo; - case cMin: - FactorIsImportant = false; - goto Redo; - case cMax: - FactorIsImportant = false; - goto Redo; - default: break; - Redo: - for(pit a=GetBegin(); a!=GetEnd(); ++a) - { - const SubTree &pa = *a; - - list poslist; - - for(pit b=a; ++b!=GetEnd(); ) - { - const SubTree &pb = *b; - if(*pa == *pb) - poslist.push_back(b); - } - - unsigned min = 2; - if(poslist.size() >= min) - { - SubTree arvo = pa; - bool negate = arvo.getsign(); - - double factor = poslist.size() + 1; - - if(negate) - { - arvo.Negate(); - factor = -factor; - } - - if(FactorIsImportant) - { - CodeTree tmp; - tmp.SetOp(ReplacementOpcode); - tmp.AddParam(arvo); - tmp.AddParam(factor); - - list::const_iterator j; - for(j=poslist.begin(); j!=poslist.end(); ++j) - Erase(*j); - poslist.clear(); - *a = tmp; - } - else - { - list::const_iterator j; - bool first=true; - for(j=poslist.begin(); j!=poslist.end(); ++j, first=false) - if(!first) - Erase(*j); - } - didchanges = true; - goto Redo; - } - } - } - - if(didchanges) - { - // As a result, there might be need for this: - OptimizeAddMulFlat(); - // And this: - OptimizeRedundant(); - } - } - - void OptimizeLogarithm() - { - /* - This is basic logarithm math: - pow(X,Y)/log(Y) = X - log(X)/log(Y) = logY(X) - log(X^Y) = log(X)*Y - log(X*Y) = log(X)+log(Y) - exp(log(X)*Y) = X^Y - - This function does these optimizations: - pow(const_E, log(x)) = x - pow(const_E, log(x)*y) = x^y - pow(10, log(x)*const_L10I*y) = x^y - pow(z, log(x)/log(z)*y) = x^y - - And this: - log(x^z) = z * log(x) - Which automatically causes these too: - log(pow(const_E, x)) = x - log(pow(y, x)) = x * log(y) - log(pow(pow(const_E, y), x)) = x*y - - And it does this too: - log(x) + log(y) + log(z) = log(x * y * z) - log(x * exp(y)) = log(x) + y - - */ - - // Must be already in exponential form. - - // Optimize exponents before doing something. - OptimizeExponents(); - - if(GetOp() == cLog) - { - // We should have one parameter for log() function. - // If we don't, we're screwed. - - const SubTree &p = getp0(); - - if(p->GetOp() == cPow) - { - // Found log(x^y) - SubTree p0 = p->getp0(); // x - SubTree p1 = p->getp1(); // y - - // Build the new logarithm. - CodeTree tmp(GetOp(), p0); // log(x) - - // Become log(x) * y - ReplaceWith(cMul, tmp, p1); - } - else if(p->GetOp() == cMul) - { - // Redefine &p nonconst - SubTree &p = getp0(); - - p->OptimizeAddMulFlat(); - p->OptimizeExponents(); - - p.CheckConstInv(); - - list adds; - - for(pit b, a = p->GetBegin(); - a != p->GetEnd(); a=b) - { - SubTree &pa = *a; b=a; ++b; - if(pa->GetOp() == cPow - && pa->getp0()->IsImmed() - && pa->getp0()->GetImmed() == CONSTANT_E) - { - adds.push_back(pa->getp1()); - p->Erase(a); - continue; - } - } - if(adds.size()) - { - CodeTree tmp(cAdd, *this); - - list::const_iterator i; - for(i=adds.begin(); i!=adds.end(); ++i) - tmp.AddParam(*i); - - ReplaceWith(tmp); - } - } - } - if(GetOp() == cAdd) - { - // Check which ones are logs. - list poslist; - - for(pit a=GetBegin(); a!=GetEnd(); ++a) - { - const SubTree &pa = *a; - if(pa->GetOp() == cLog) - poslist.push_back(a); - } - - if(poslist.size() >= 2) - { - CodeTree tmp(cMul, 1.0); // eek - - list::const_iterator j; - for(j=poslist.begin(); j!=poslist.end(); ++j) - { - const SubTree &pb = **j; - // Take all of its children - for(pcit b=pb->GetBegin(); - b!=pb->GetEnd(); - ++b) - { - SubTree tmp2 = *b; - if(pb.getsign()) tmp2.Negate(); - tmp.AddParam(tmp2); - } - Erase(*j); - } - poslist.clear(); - - AddParam(CodeTree(cLog, tmp)); - } - // Done, hopefully - } - if(GetOp() == cPow) - { - const SubTree &p0 = getp0(); - SubTree &p1 = getp1(); - - if(p0->IsImmed() && p0->GetImmed() == CONSTANT_E - && p1->GetOp() == cLog) - { - // pow(const_E, log(x)) = x - ReplaceWith(*(p1->getp0())); - } - else if(p1->GetOp() == cMul) - { - //bool didsomething = true; - - pit poslogpos; bool foundposlog = false; - pit neglogpos; bool foundneglog = false; - - ConstList cl = p1->BuildConstList(); - - for(pit a=p1->GetBegin(); a!=p1->GetEnd(); ++a) - { - const SubTree &pa = *a; - if(pa->GetOp() == cLog) - { - if(!pa.getsign()) - { - foundposlog = true; - poslogpos = a; - } - else if(*p0 == *(pa->getp0())) - { - foundneglog = true; - neglogpos = a; - } - } - } - - if(p0->IsImmed() - && p0->GetImmed() == 10.0 - && cl.value == CONSTANT_L10I - && foundposlog) - { - SubTree base = (*poslogpos)->getp0(); - p1->KillConst(cl); - p1->Erase(poslogpos); - p1->OptimizeRedundant(); - SubTree mul = p1; - - ReplaceWith(cPow, base, mul); - - // FIXME: what optimizations should be done now? - return; - } - - // Put back the constant - FinishConst(cl, true); - - if(p0->IsImmed() - && p0->GetImmed() == CONSTANT_E - && foundposlog) - { - SubTree base = (*poslogpos)->getp0(); - p1->Erase(poslogpos); - - p1->OptimizeRedundant(); - SubTree mul = p1; - - ReplaceWith(cPow, base, mul); - - // FIXME: what optimizations should be done now? - return; - } - - if(foundposlog - && foundneglog - && *((*neglogpos)->getp0()) == *p0) - { - SubTree base = (*poslogpos)->getp0(); - p1->Erase(poslogpos); - p1->Erase(neglogpos); - - p1->OptimizeRedundant(); - SubTree mul = p1; - - ReplaceWith(cPow, base, mul); - - // FIXME: what optimizations should be done now? - return; - } - } - } - } - - void OptimizeFunctionCalls() - { - /* Goals: sin(asin(x)) = x - * cos(acos(x)) = x - * tan(atan(x)) = x - * NOTE: - * Do NOT do these: - * asin(sin(x)) - * acos(cos(x)) - * atan(tan(x)) - * Because someone might want to wrap the angle. - */ - // FIXME: TODO - } - - void OptimizePowMulAdd() - { - // x^3 * x -> x^4 - // x*3 + x -> x*4 - // FIXME: Do those - - // x^1 -> x - if(GetOp() == cPow) - { - const SubTree &base = getp0(); - const SubTree &exponent = getp1(); - - if(exponent->IsImmed()) - { - if(exponent->GetImmed() == 1.0) - ReplaceWith(*base); - else if(exponent->GetImmed() == 0.0 - && base->NonZero()) - ReplaceWithConst(1.0); - } - } - } - - void OptimizeExponents() - { - /* Goals: - * (x^y)^z -> x^(y*z) - * x^y * x^z -> x^(y+z) - */ - // First move to exponential form. - OptimizeLinearCombine(); - - bool didchanges = false; - - Redo: - if(GetOp() == cPow) - { - // (x^y)^z -> x^(y*z) - - const SubTree &p0 = getp0(); - const SubTree &p1 = getp1(); - if(p0->GetOp() == cPow) - { - CodeTree tmp(cMul, p0->getp1(), p1); - tmp.Optimize(); - - ReplaceWith(cPow, p0->getp0(), tmp); - - didchanges = true; - goto Redo; - } - } - if(GetOp() == cMul) - { - // x^y * x^z -> x^(y+z) - - for(pit a=GetBegin(); a!=GetEnd(); ++a) - { - const SubTree &pa = *a; - - if(pa->GetOp() != cPow) continue; - - list poslist; - - for(pit b=a; ++b != GetEnd(); ) - { - const SubTree &pb = *b; - if(pb->GetOp() == cPow - && *(pa->getp0()) - == *(pb->getp0())) - { - poslist.push_back(b); - } - } - - if(poslist.size() >= 1) - { - poslist.push_back(a); - - CodeTree base = *(pa->getp0()); - - CodeTree exponent(cAdd, 0.0); //eek - - // Collect all exponents to cAdd - list::const_iterator i; - for(i=poslist.begin(); i!=poslist.end(); ++i) - { - const SubTree &pb = **i; - - SubTree tmp2 = pb->getp1(); - if(pb.getsign()) tmp2.Invert(); - - exponent.AddParam(tmp2); - } - - exponent.Optimize(); - - CodeTree result(cPow, base, exponent); - - for(i=poslist.begin(); i!=poslist.end(); ++i) - Erase(*i); - poslist.clear(); - - AddParam(result); // We're cMul, remember - - didchanges = true; - goto Redo; - } - } - } - - OptimizePowMulAdd(); - - if(didchanges) - { - // As a result, there might be need for this: - OptimizeConflict(); - } - } - - void OptimizeLinearExplode() - { - // x^2 -> x*x - // But only if x is just a simple thing - - // Won't work on anything else. - if(GetOp() != cPow) return; - - // TODO TODO TODO - } - - void OptimizePascal() - { -#if 0 // Too big, too specific, etc - - // Won't work on anything else. - if(GetOp() != cAdd) return; - - // Must be done after OptimizeLinearCombine(); - - // Don't need pascal triangle - // Coefficient for x^a * y^b * z^c = 3! / (a! * b! * c!) - - // We are greedy and want other than just binomials - // FIXME - - // note: partial ones are also nice - // x*x + x*y + y*y - // = (x+y)^2 - x*y - // - // x x * x y * + y y * + - // -> x y + dup * x y * - -#endif - } - -public: - - void Optimize(); - - void Assemble(vector &byteCode, - vector &immed, - size_t& stacktop_cur, - size_t& stacktop_max) const; - - void FinalOptimize() - { - // First optimize each parameter. - for(pit a=GetBegin(); a!=GetEnd(); ++a) - (*a)->FinalOptimize(); - - /* These things are to be done: - * - * x * CONSTANT_DR -> cDeg(x) - * x * CONSTANT_RD -> cRad(x) - * pow(x, 0.5) -> sqrt(x) - * log(x) * CONSTANT_L10I -> log10(x) - * pow(CONSTANT_E, x) -> exp(x) - * inv(sin(x)) -> csc(x) - * inv(cos(x)) -> sec(x) - * inv(tan(x)) -> cot(x) - */ - - - if(GetOp() == cPow) - { - const SubTree &p0 = getp0(); - const SubTree &p1 = getp1(); - if(p0->GetOp() == cImmed - && p0->GetImmed() == CONSTANT_E) - { - ReplaceWith(cExp, p1); - } - else if(p1->GetOp() == cImmed - && p1->GetImmed() == 0.5) - { - ReplaceWith(cSqrt, p0); - } - } - if(GetOp() == cMul) - { - if(GetArgCount() == 1 && getp0().getsign()) - { - /***/if(getp0()->GetOp() == cSin)ReplaceWith(cCsc, getp0()->getp0()); - else if(getp0()->GetOp() == cCos)ReplaceWith(cSec, getp0()->getp0()); - else if(getp0()->GetOp() == cTan)ReplaceWith(cCot, getp0()->getp0()); - } - } - // Separate "if", because op may have just changed - if(GetOp() == cMul) - { - /* NOTE: Not gcov'd yet */ - - CodeTree *found_log = 0; - - ConstList cl = BuildConstList(); - - for(pit a=GetBegin(); a!=GetEnd(); ++a) - { - SubTree &pa = *a; - if(pa->GetOp() == cLog && !pa.getsign()) - found_log = &*pa; - } - if(cl.value == CONSTANT_L10I && found_log) - { - // Change the log() to log10() - found_log->SetOp(cLog10); - // And forget the constant - KillConst(cl); - } - else if(cl.value == CONSTANT_DR) - { - KillConst(cl); - OptimizeRedundant(); -#ifdef TREE_DEBUG - cout << "PRE_REP :" << (*this) << endl; -#endif - ReplaceWith(cDeg, *this); -#ifdef TREE_DEBUG - cout << "POST_REP :" << (*this) << endl; -#endif - } - else if(cl.value == CONSTANT_RD) - { - KillConst(cl); - OptimizeRedundant(); - ReplaceWith(cRad, *this); - } - else FinishConst(cl, true); - } - - SortIfPossible(); - } -}; - -#ifdef TREE_DEBUG -std::ostream& operator << (std::ostream& str, const CodeTree& tree) -{ - const CodeTreeData& data = *tree.data; - switch( (FUNCTIONPARSERTYPES::OPCODE) data.GetOp()) - { - case cImmed: str << data.GetImmed(); return str; - case cVar: str << "Var" << data.GetVar(); return str; - case cFCall: str << "FCall(Func" << data.GetFuncNo() << ")"; break; - case cPCall: str << "PCall(Func" << data.GetFuncNo() << ")"; break; - - case cAbs: str << "cAbs"; break; - case cAcos: str << "cAcos"; break; -#ifndef NO_ASINH - case cAcosh: str << "cAcosh"; break; -#endif - case cAsin: str << "cAsin"; break; -#ifndef NO_ASINH - case cAsinh: str << "cAsinh"; break; -#endif - case cAtan: str << "cAtan"; break; - case cAtan2: str << "cAtan2"; break; -#ifndef NO_ASINH - case cAtanh: str << "cAtanh"; break; -#endif - case cCeil: str << "cCeil"; break; - case cCos: str << "cCos"; break; - case cCosh: str << "cCosh"; break; - case cCot: str << "cCot"; break; - case cCsc: str << "cCsc"; break; -#ifndef DISABLE_EVAL - case cEval: str << "cEval"; break; -#endif - case cExp: str << "cExp"; break; - case cFloor: str << "cFloor"; break; - case cIf: str << "cIf"; break; - case cInt: str << "cInt"; break; - case cLog: str << "cLog"; break; - case cLog10: str << "cLog10"; break; - case cMax: str << "cMax"; break; - case cMin: str << "cMin"; break; - case cSec: str << "cSec"; break; - case cSin: str << "cSin"; break; - case cSinh: str << "cSinh"; break; - case cSqrt: str << "cSqrt"; break; - case cTan: str << "cTan"; break; - case cTanh: str << "cTanh"; break; - - // These do not need any ordering: - case cJump: str << "cJump"; break; - case cNeg: str << "cNeg"; break; - case cAdd: str << "cAdd"; break; - case cSub: str << "cSub"; break; - case cMul: str << "cMul"; break; - case cDiv: str << "cDiv"; break; - case cMod: str << "cMod"; break; - case cPow: str << "cPow"; break; - case cEqual: str << "cEqual"; break; - case cNEqual: str << "cNEqual"; break; - case cLess: str << "cLess"; break; - case cLessOrEq: str << "cLessOrEq"; break; - case cGreater: str << "cGreater"; break; - case cGreaterOrEq: str << "cGreaterOrEq"; break; - case cNot: str << "cNot"; break; - case cAnd: str << "cAnd"; break; - case cOr: str << "cOr"; break; - case cDeg: str << "cDeg"; break; - case cRad: str << "cRad"; break; - case cDup: str << "cDup"; break; - case cInv: str << "cInv"; break; - case VarBegin: str << "VarBegin"; break; - } - str << '('; - - bool first = true; - for(paramlist::const_iterator - i = data.args.begin(); i != data.args.end(); ++i) - { - if(first) first=false; else str << ", "; - const SubTree& sub = *i; - if(sub.getsign()) str << '!'; - str << *sub; - } - str << ')'; - - return str; } +if(i01!=cImmed){c23 +p=iN +tree +eY3 +p +n51&&p +nP2 +tF2==e13){xO +p +tF2);nD} +if(false){ReplaceTreeWithOne:xO +iV2(1));goto +do_return;ReplaceTreeWithZero:xO +xD1;goto +do_return;ReplaceTreeWithParam0: +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before replace: " +;std::cout<args; - for(paramlist::iterator i=p2.begin(); i!=p2.end(); ++i) - { - (*i)->data.Shock(); - } - */ +tree.xY2 +0)); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"After replace: " +;std::cout<1||(iW1==1&&cB3 +nL1 +tG1 +1))))nM1=true;if(nM1){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"cMul: Will add new " +iU3 +nL1<<"\n" +; +#endif +for +iY +if +y91 +t21{ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<" - For that, deleting " +iU3 +t63 +std::cout<<"\n" +; +#endif +i93!cB3 +nL1 +tG1 +1)))i83 +e21 +nL1));l73 +eM +y33 +0:i6 +1:nY3 +c73 +if(ConstantFolding_MulGrouping(eJ2 +if(ConstantFolding_MulLogicItems(eJ2 +i91 +cAdd:eQ +iV2 +nE2=0.0;size_t +iW1=0;bool +nM1 +tO3 +nB1{if(!lE2 +t21 +continue +iU2 +immed=t63 +nE2+=immed;++iW1;} +if(iW1>1||(iW1==1&&nE2==xD1)nM1=true;if(nM1){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"cAdd: Will add new " +iU3 +nE2<<"\n" +;std::cout<<"In: " +yA1 +#endif +for +iY +if +y91 +t21{ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<" - For that, deleting " +iU3 +t63 +std::cout<<"\n" +; +#endif +i93!(nE2==x22)i83 +e21 +nE2));l73 +eM +y33 +0 +eL +1:nY3 +c73 +if(ConstantFolding_AddGrouping(eJ2 +if(ConstantFolding_AddLogicItems(eJ2 +i91 +cMin:eQ +size_t +yM2=0;c23 +e0;nB1{while(a+1 &cp = result.cp; - for(pit b, a=GetBegin(); a!=GetEnd(); a=b) - { - SubTree &pa = *a; b=a; ++b; - if(!pa->IsImmed()) continue; - - double thisvalue = pa->GetImmed(); - if(thisvalue == result.voidvalue) - { - // This value is no good, forget it - Erase(a); - continue; - } - switch(GetOp()) - { - case cMul: - result.value *= thisvalue; - break; - case cAdd: - result.value += thisvalue; - break; - case cMin: - if(first || thisvalue < result.value) result.value = thisvalue; - break; - case cMax: - if(first || thisvalue > result.value) result.value = thisvalue; - break; - default: break; /* Unreached */ - } - cp.push_back(a); - first = false; - } - if(GetOp() == cMul) - { - /* - If one of the values is -1 and it's not the only value, - then some other value will be negated. - */ - for(bool done=false; cp.size() > 1 && !done; ) - { - done = true; - for(list::iterator b,a=cp.begin(); a!=cp.end(); a=b) - { - b=a; ++b; - if((**a)->GetImmed() == -1.0) - { - Erase(*a); - cp.erase(a); - - // take randomly something - (**cp.begin())->data->NegateImmed(); - if(cp.size() < 2)break; - done = false; - } - } - } - } - return result; +if(e0 +xF2 +for +iY{c33 +min +lB3 +a!=yM2&&p +tF2>=e0 +yN +val)i93 +eM==1){nY3 +i91 +cMax:eQ +size_t +yM2=0;c23 +eZ;nB1{while(a+1eZ +tF2)){eZ +tF2=p +tF2;eZ +n51=true;yM2=a;} } - -void CodeTree::Assemble - (vector &byteCode, - vector &immed, - size_t& stacktop_cur, - size_t& stacktop_max) const -{ - #define AddCmd(op) byteCode.push_back((op)) - #define AddConst(v) do { \ - byteCode.push_back(cImmed); \ - immed.push_back((v)); \ - } while(0) - #define SimuPush(n) stacktop_cur += (n) - #define SimuPop(n) do { \ - if(stacktop_cur > stacktop_max) stacktop_max = stacktop_cur; \ - stacktop_cur -= (n); \ - } while(0) - - if(IsVar()) - { - SimuPush(1); - AddCmd(GetVar()); - return; - } - if(IsImmed()) - { - SimuPush(1); - AddConst(GetImmed()); - return; - } - - switch(GetOp()) - { - case cAdd: - case cMul: - case cMin: - case cMax: - { - unsigned opcount = 0; - for(pcit a=GetBegin(); a!=GetEnd(); ++a) - { - const SubTree &pa = *a; - - if(opcount < 2) ++opcount; - - bool pnega = pa.getsign(); - - bool done = false; - if(pa->IsImmed()) - { - if(GetOp() == cMul - && pa->data->IsInverted() - && (pnega || opcount==2) - ) - { - CodeTree tmp = *pa; - tmp.data->InvertImmed(); - tmp.Assemble(byteCode, immed, - stacktop_cur, stacktop_max); - pnega = !pnega; - done = true; - } - else if(GetOp() == cAdd - && (pa->data->IsNegatedOriginal() - // || pa->GetImmed() < 0 - ) - && (pnega || opcount==2) - ) - { - CodeTree tmp = *pa; - tmp.data->NegateImmed(); - tmp.Assemble(byteCode, immed, - stacktop_cur, stacktop_max); - pnega = !pnega; - done = true; - } - } - if(!done) - pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max); - - if(opcount == 2) - { - unsigned tmpop = GetOp(); - if(pnega) // negation in non-first operand - { - tmpop = (tmpop == cMul) ? cDiv : cSub; - } - SimuPop(1); - AddCmd(tmpop); - } - else if(pnega) // negation in the first operand - { - if(GetOp() == cMul) AddCmd(cInv); - else AddCmd(cNeg); - } - } - break; - } - case cIf: - { - // If the parameter amount is != 3, we're screwed. - getp0()->Assemble(byteCode, immed, stacktop_cur, stacktop_max); // expression - SimuPop(1); - - unsigned ofs = byteCode.size(); - AddCmd(cIf); - AddCmd(0); // code index - AddCmd(0); // immed index - - getp1()->Assemble(byteCode, immed, stacktop_cur, stacktop_max); // true branch - SimuPop(1); - - byteCode[ofs+1] = byteCode.size()+2; - byteCode[ofs+2] = immed.size(); - - ofs = byteCode.size(); - AddCmd(cJump); - AddCmd(0); // code index - AddCmd(0); // immed index - - getp2()->Assemble(byteCode, immed, stacktop_cur, stacktop_max); // false branch - SimuPop(1); - - byteCode[ofs+1] = byteCode.size()-1; - byteCode[ofs+2] = immed.size(); - - SimuPush(1); - - break; - } - case cFCall: - { - // If the parameter count is invalid, we're screwed. - size_t was_stacktop = stacktop_cur; - for(pcit a=GetBegin(); a!=GetEnd(); ++a) - { - const SubTree &pa = *a; - pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max); - } - AddCmd(GetOp()); - AddCmd(data->GetFuncNo()); - SimuPop(stacktop_cur - was_stacktop - 1); - break; - } - case cPCall: - { - // If the parameter count is invalid, we're screwed. - size_t was_stacktop = stacktop_cur; - for(pcit a=GetBegin(); a!=GetEnd(); ++a) - { - const SubTree &pa = *a; - pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max); - } - AddCmd(GetOp()); - AddCmd(data->GetFuncNo()); - SimuPop(stacktop_cur - was_stacktop - 1); - break; - } - default: - { - // If the parameter count is invalid, we're screwed. - size_t was_stacktop = stacktop_cur; - for(pcit a=GetBegin(); a!=GetEnd(); ++a) - { - const SubTree &pa = *a; - pa->Assemble(byteCode, immed, stacktop_cur, stacktop_max); - } - AddCmd(GetOp()); - SimuPop(stacktop_cur - was_stacktop - 1); - break; - } - } +if(eZ +n51){for +iY{c33 +max +lB3 +a!=yM2&&(e13)Optimize(); - CHECKCONSTNEG(*a, GetOp()); - } - continue; - } - if(phase == 0 || phase == 2) - { - // Do local optimizations. - - OptimizeConstantMath1(); - OptimizeLogarithm(); - OptimizeFunctionCalls(); - OptimizeExponents(); - OptimizeLinearExplode(); - OptimizePascal(); - - /* Optimization paths: - - doublenegations= - redundant= * doublenegations - conflict= * redundant - addmulflat= - constantmath1= addmulflat * conflict - linearcombine= conflict * addmulflat¹ redundant¹ - powmuladd= - exponents= linearcombine * powmuladd conflict¹ - logarithm= exponents * - functioncalls= IDLE - linearexplode= IDLE - pascal= IDLE - - * = actions here - ¹ = only if made changes - */ - } - } +if(eM==1){nY3 +i91 +cEqual:case +cNEqual:case +cLess:case +cGreater:case +cLessOrEq:case +cGreaterOrEq:if(ConstantFolding_Comparison(eJ2 +lC +cAbs:{c23 +p0 +tI +0));if +tG2 +nY3 +if(p0 +eN{tree +tH3 +tree.yC +iV2(1)));goto +NowWeAreMulGroup;} +lT3 +nC==cMul){lC2 +p=lE2 +0);eH +x03;eH +cK2 +yM3 +0;aIsFunc()) - if(data->GetFuncNo() != b.data->GetFuncNo()) return false; - return data->args == b.data->args; +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Abs: mul group has " +< b.GetArgCount(); - - if(GetOp() != b.GetOp()) - { - // sort immeds last - if(IsImmed() != b.IsImmed()) return IsImmed() < b.IsImmed(); - - return GetOp() < b.GetOp(); - } - - if(IsImmed()) - { - if(GetImmed() != b.GetImmed()) return GetImmed() < b.GetImmed(); - } - if(IsVar() && GetVar() != b.GetVar()) - { - return GetVar() < b.GetVar(); - } - if(data->IsFunc() && data->GetFuncNo() != b.data->GetFuncNo()) - { - return data->GetFuncNo() < b.data->GetFuncNo(); - } - - pcit i = GetBegin(), j = b.GetBegin(); - for(; i != GetEnd(); ++i, ++j) - { - const SubTree &pa = *i, &pb = *j; - - if(!(pa == pb)) - return pa < pb; - } - return false; +yF3 +#define HANDLE_UNARY_CONST_FUNC(funcname) nR){xO funcname(lR));nD +case +cLog:iK3(fp_log);lT3 +nC==cPow){eJ +pow=lE2 +0 +eY3 +GetPositivityInfo(pow +l8 +0))==IsAlways){pow.CopyOnWrite()i7 +tree.lU +if(GetEvennessInfo(pow +l8 +1))==IsAlways){pow.l61 +eJ +abs;abs +xD +cAbs);abs +yP1 +pow +lR2 +abs.Rehash()i7 +pow.nG1 +0,abs);tree.lU} +else +lT3 +nC==cAbs){eJ +pow=lE2 +0)l8 +0 +eY3 +pow +nC==cPow){pow.l61 +eJ +abs;abs +xD +cAbs);abs +yP1 +pow +lR2 +abs.Rehash()i7 +pow.nG1 +0,abs);tree.lU} +lC +cAcosh:iK3(fp_acosh);lC +cAsinh:iK3(fp_asinh);lC +cAtanh:iK3(fp_atanh);lC +cAcos:iK3(fp_acos);lC +cAsin:iK3(fp_asin);lC +cAtan:iK3(fp_atan);lC +cCosh:iK3(fp_cosh);lC +cSinh:iK3(fp_sinh);lC +cTanh:iK3(fp_tanh);lC +cSin:iK3(fp_sin);lC +cCos:iK3(fp_cos);lC +cTan:iK3(fp_tan);lC +cCeil:l54(fp_ceil);lC +cTrunc:l54(fp_trunc);lC +cFloor:l54(fp_floor);lC +cInt:l54(fp_int);lC +cCbrt:iK3(fp_cbrt);lC +cSqrt:iK3(fp_sqrt);lC +cExp:iK3(fp_exp);lC +cLog2:iK3(fp_log2);lC +cLog10:iK3(fp_log10);lC +eF3:if +lI +fp_log2(lR)*tH +tH2 +cArg:iK3(fp_arg);lC +cConj:iK3(fp_conj);lC +cImag:iK3(fp_imag);lC +cReal:iK3(fp_real);lC +cPolar:if +lI +fp_polar(x32 +cMod:if +lI +e93 +x32 +cAtan2:{c23 +p0 +tI +yS2 +p1 +tI +1));nR&&cB3 +lR,xD1){if(p1 +cL2 +p1 +e23 +xD1{xO +fp_const_pi +e53 +if(p1 +n51&&p1 +tF2>=t61 +xD1;nD} +tM2 +cB3 +tH,xD1){if(p0 +cL2 +p0 +e23 +xD1{xO-fp_const_pihalf +e53 +if +iC3 +p0 +tF2>xD1{xO +fp_const_pihalf +e53} +if +lI +fp_atan2(lR,tH));nD +if((p1 +n51&&p1 +tF2>xD1||(p1 +cL2 +p1 +e23 +fp_const_negativezero +xK())){eJ +yO2;yO2 +xD +cPow);yO2.AddParamMove +y91 +1));yO2.yC +iV2(-1)));yO2 +eT1 +eJ +yP2;yP2 +tH3 +yP2.AddParamMove +y91 +0));yP2 +yP1 +yO2);yP2 +eT1 +tI3 +cAtan);tree.nG1 +0,yP2)yO3 +1);i91 +cPow:{if(ConstantFolding_PowOperations(eJ2 +yF3 +case +cDiv:nR&&eO3 +i61&&tH!=t61 +lR/tH +tH2 +cInv:nR&&lR!=t61 +iV2(1)/lR +tH2 +cSub:if +lI +lR-tH +tH2 +cNeg:nR){xO-lR +tH2 +cRad:nR){xO +RadiansToDegrees(lR)tH2 +cDeg:nR){xO +DegreesToRadians(lR)tH2 +cSqr:nR){xO +lR*lR +tH2 +cExp2:iK3(fp_exp2);lC +cRSqrt:nR){xO +iV2(1)/fp_sqrt(lR)tH2 +cCot:tI2 +fp_tan(lZ +cSec:tI2 +fp_cos(lZ +cCsc:tI2 +fp_sin(lZ +cHypot:if +lI +fp_hypot(x32 +cRDiv:case +cRSub:case +cDup:case +cFetch:case +cPopNMov:case +cSinCos:case +cSinhCosh:case +cNop:case +cJump:lC +cPCall:case +cFCall:yF3 +do_return:; +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"[" +<<(&cY3)<<"]Done ConstantFolding, result: " +yA1 +DumpHashes(tree); +#endif } - - -bool IsNegate(const SubTree &p1, const SubTree &p2) /*const */ -{ - if(p1->IsImmed() && p2->IsImmed()) - { - return p1->GetImmed() == -p2->GetImmed(); - } - if(p1.getsign() == p2.getsign()) return false; - return *p1 == *p2; -} -bool IsInverse(const SubTree &p1, const SubTree &p2) /*const*/ -{ - if(p1->IsImmed() && p2->IsImmed()) - { - // FIXME: potential divide by zero. - return p1->GetImmed() == 1.0 / p2->GetImmed(); - } - if(p1.getsign() == p2.getsign()) return false; - return *p1 == *p2; } - -SubTree::SubTree() : tree(new CodeTree), sign(false) -{ +#endif +#ifdef FP_SUPPORT_OPTIMIZER +t5{tZ1 +c23::set_abs(nL +bool +has_negative=!min.known||min.valiV2();bool +crosses_axis=has_negative&&has_positive;cJ1 +xK +newmax;if(min +lB3 +t13)newmax.set(fp_max(tV1,tW1 +eY3 +crosses_axis)min.set(iV2());e63 +min +lB3 +t13)min.set(fp_min(tV1,tW1);lJ2 +min.known)min.set(tV1);else +min.set(tW1;} +max=newmax;} +tZ1 +c23::set_neg(){std::swap(min,max);min.val=-min.val;iA3=-iA3;} +xN1 +IsLogicalTrueValue +cH1 +c23&p +tR2{if(nB +IsIntType +xK::nT3){if(p +n51&&p +tF2>=iV2(1 +tI1;if(!abs&&p +nP2 +yN +val<=iV2(-1 +tI1;} +e63 +p +n51&&p +tF2>=iV2(0.5 +tI1;if(!abs&&p +nP2 +yN +val<=iV2(-0.5 +tI1;} +return +tR3 +xN1 +IsLogicalFalseValue +cH1 +c23&p +tR2{if(nB +IsIntType +xK::nT3){if(abs)return +p +yN +known +lH1 +1);else +return +p +n51&&p +nP2 +tF2>iV2(-1)lH1 +1);} +e63 +abs)return +p +yN +known +lH1 +0.5);else +return +p +n51&&p +nP2 +tF2>iV2(-0.5)lH1 +0.5);} } - -SubTree::SubTree(const SubTree &b) : tree(new CodeTree(*b.tree)), sign(b.sign) -{ } - -#define SubTreeDecl(p1, p2) \ - SubTree::SubTree p1 : tree(new CodeTree p2), sign(false) { } - -SubTreeDecl( (const CodeTree &b), (b) ) -SubTreeDecl( (double value), (value) ) - -#undef SubTreeDecl - -SubTree::~SubTree() -{ - delete tree; tree=0; +#endif +#ifdef FP_SUPPORT_OPTIMIZER +using +lF3 +FUNCTIONPARSERTYPES;using +t5;t5{xW3 +c23 +iN +lC2 +tree) +#ifdef DEBUG_SUBSTITUTIONS_extra_verbose +{using +lF3 +FUNCTIONPARSERTYPES;c23 +tmp=CalculateResultBoundaries_do(tree +lT2"Estimated boundaries: " +;if(tmp +n51)std::cout<=iV2(-1))?fp_acos +nU3:fp_const_pi +xK()i33 +cAsin:lD +yK +n3-1),fp_asin,yF1 +tF2)xQ1 +cLess +t71 +fp_asin,yF1 +yN +val);tV +cAtan:lD +yK +set(fp_atan,yF1 +tF2);m +yN +set(fp_atan,yF1 +yN +val);tV +cAtan2:{nR&&cB3 +lR,xD1)yR +abs_pi_limits;} +tM2 +cB3 +tH,xD1)yR +yF1;} +return +pi_limits;} +case +cSin:lD +bool +x11=!x43||!c71||(c81-yK +val)>=(yO +x11)eR +iV2 +min=e93 +yK +val,yO +min=fp_const_pihalf +xK());bool +nN1=(min<=cD&&max>=cD +eY3 +y11&&nN1)eR +if(nN1)nM +iV2(-1)lK2 +if(y11)nM +eL2 +tG1 +1));nM +eL2 +lK2} +case +cCos:lD +if(x43)yK +val+=fp_const_pihalf +xK(eY3 +c71)c81+=fp_const_pihalf +xK();bool +x11=!x43||!c71||(c81-yK +val)>=(yO +x11)eR +iV2 +min=e93 +yK +val,yO +min=fp_const_pihalf +xK());bool +nN1=(min<=cD&&max>=cD +eY3 +y11&&nN1)eR +if(nN1)nM +iV2(-1)lK2 +if(y11)nM +eL2 +tG1 +1));nM +eL2 +lK2} +case +cTan:{nM +i33 +cCeil:lD +c91 +cFloor:lD +tH1 +tV +cTrunc:lD +tH1 +c91 +cInt:lD +tH1 +c91 +cSinh:lD +yK +set(fp_sinh);m +yN +set(fp_sinh);tV +cTanh:lD +yK +set(fp_tanh,plusminus1_limits.min);m +yN +set(fp_tanh,plusminus1_limits.max);tV +cCosh:lD +if(x43){if(c71){if(yK +val>=y21&&c81>=xD1{yK +val +xU} +lJ2 +nU3=xD1{iV2 +tmp +xU +if(tmp>c81)c81=tmp;yK +val=iV2(1 +t43{yK +val +xU +std::swap(yK +val,c81);} } - -const SubTree &SubTree::operator= (const SubTree &b) -{ - sign = b.sign; - CodeTree *oldtree = tree; - tree = new CodeTree(*b.tree); - delete oldtree; - return *this; -} -const SubTree &SubTree::operator= (const CodeTree &b) -{ - sign = false; - CodeTree *oldtree = tree; - tree = new CodeTree(b); - delete oldtree; - return *this; +e63 +yK +val>=xD1{m +t0 +yK +val=fp_cosh +nU3;} +else{m +t0 +yK +val=iV2(1);} } - -bool SubTree::operator< (const SubTree& b) const -{ - if(getsign() != b.getsign()) return getsign() < b.getsign(); - return *tree < *b.tree; -} -bool SubTree::operator== (const SubTree& b) const -{ - return sign == b.sign && *tree == *b.tree; -} -void SubTree::Negate() // Note: Parent must be cAdd -{ - flipsign(); - CheckConstNeg(); -} -void SubTree::CheckConstNeg() -{ - if(tree->IsImmed() && getsign()) - { - tree->NegateImmed(); - sign = false; - } -} -void SubTree::Invert() // Note: Parent must be cMul -{ - flipsign(); - CheckConstInv(); -} -void SubTree::CheckConstInv() -{ - if(tree->IsImmed() && getsign()) - { - tree->InvertImmed(); - sign = false; - } } - -}//namespace - -void FunctionParser::MakeTree(void *r) const -{ - // Dirty hack. Should be fixed. - CodeTree* result = static_cast(r); - - vector stack(1); - - #define GROW(n) do { \ - stacktop += n; \ - if(stack.size() <= stacktop) stack.resize(stacktop+1); \ - } while(0) - - #define EAT(n, opcode) do { \ - unsigned newstacktop = stacktop-(n); \ - if((n) == 0) GROW(1); \ - stack[stacktop].SetOp((opcode)); \ - for(unsigned a=0, b=(n); a labels; - - const unsigned* const ByteCode = data->ByteCode; - const unsigned ByteCodeSize = data->ByteCodeSize; - const double* const Immed = data->Immed; - - for(unsigned IP=0, DP=0; ; ++IP) - { - while(labels.size() > 0 - && *labels.begin() == IP) - { - // The "else" of an "if" ends here - EAT(3, cIf); - labels.erase(labels.begin()); - } - - if(IP >= ByteCodeSize) - { - break; - } - - unsigned opcode = ByteCode[IP]; - - if(opcode == cIf) - { - IP += 2; - } - else if(opcode == cJump) - { - labels.push_front(ByteCode[IP+1]+1); - IP += 2; - } - else if(opcode == cImmed) - { - ADDCONST(Immed[DP++]); - } - else if(opcode < VarBegin) - { - switch(opcode) - { - // Unary operators - case cNeg: - { - EAT(1, cAdd); // Unary minus is negative adding. - stack[stacktop-1].getp0().Negate(); - break; - } - // Binary operators - case cSub: - { - EAT(2, cAdd); // Minus is negative adding - stack[stacktop-1].getp1().Negate(); - break; - } - case cDiv: - { - EAT(2, cMul); // Divide is inverse multiply - stack[stacktop-1].getp1().Invert(); - break; - } - - // ADD ALL TWO PARAMETER NON-FUNCTIONS HERE - case cAdd: case cMul: - case cMod: case cPow: - case cEqual: case cLess: case cGreater: - case cNEqual: case cLessOrEq: case cGreaterOrEq: - case cAnd: case cOr: - EAT(2, opcode); - break; - - // ADD ALL UNARY NON-FUNCTIONS HERE - case cNot: - EAT(1, opcode); - break; - - case cFCall: - { - unsigned index = ByteCode[++IP]; - unsigned params = data->FuncPtrs[index].params; - EAT(params, opcode); - stack[stacktop-1].data->SetFuncNo(index); - break; - } - case cPCall: - { - unsigned index = ByteCode[++IP]; - unsigned params = - data->FuncParsers[index]->data->varAmount; - EAT(params, opcode); - stack[stacktop-1].data->SetFuncNo(index); - break; - } - - // Converted to cMul on fly - case cDeg: - ADDCONST(CONSTANT_DR); - EAT(2, cMul); - break; - - // Converted to cMul on fly - case cRad: - ADDCONST(CONSTANT_RD); - EAT(2, cMul); - break; - - // Functions - default: - { - //assert(opcode >= cAbs); - unsigned funcno = opcode-cAbs; - assert(funcno < sizeof(Functions)/sizeof(Functions[0])); - const FuncDefinition& func = Functions[funcno]; - - //const FuncDefinition& func = Functions[opcode-cAbs]; - - unsigned paramcount = func.params; -#ifndef DISABLE_EVAL - if(opcode == cEval) paramcount = data->varAmount; -#endif - if(opcode == cSqrt) - { - // Converted on fly: sqrt(x) = x^0.5 - opcode = cPow; - paramcount = 2; - ADDCONST(0.5); - } - if(opcode == cExp) - { - // Converted on fly: exp(x) = CONSTANT_E^x - - opcode = cPow; - paramcount = 2; - // reverse the parameters... kludgey - stack[stacktop] = stack[stacktop-1]; - stack[stacktop-1].SetImmed(CONSTANT_E); - GROW(1); - } - bool do_inv = false; - if(opcode == cCot) { do_inv = true; opcode = cTan; } - if(opcode == cCsc) { do_inv = true; opcode = cSin; } - if(opcode == cSec) { do_inv = true; opcode = cCos; } - - bool do_log10 = false; - if(opcode == cLog10) - { - // Converted on fly: log10(x) = log(x) * CONSTANT_L10I - opcode = cLog; - do_log10 = true; - } - EAT(paramcount, opcode); - if(do_log10) - { - ADDCONST(CONSTANT_L10I); - EAT(2, cMul); - } - if(do_inv) - { - // Unary cMul, inverted. No need for "1.0" - EAT(1, cMul); - stack[stacktop-1].getp0().Invert(); - } - break; - } - } - } - else - { - stack[stacktop].SetVar(opcode); - GROW(1); - } - } - - if(!stacktop) - { - // ERROR: Stack does not have any values! - return; - } - - --stacktop; // Ignore the last element, it is always nop (cAdd). - - if(stacktop > 0) - { - // ERROR: Stack has too many values! - return; - } - - // Okay, the tree is now stack[0] - *result = stack[0]; +else{x43=true;yK +val=iV2(1 +eY3 +c71){yK +val=fp_cosh(c81);m +t0} +else +m +t0} +tV +cIf:case +cAbsIf:{c23 +res1 +tI +1));c23 +res2 +tI +2)eY3!res2 +n51)res1 +n51 +tO3 +lJ2 +res1 +n51&&(res2 +tF2)res1 +yN +val)res1 +yN +val=res2 +yN +val +n31 +res1;} +case +cMin:{bool +iH +tO3 +bool +iI +tO3 +c43;x2 +m +tI +a)eY3!x43)iH +x53 +n51||nU3nK3)nK3=yK +val;if(!c71)iI +x53 +yN +known||c81>nL3)nL3=c81;} +if(iH)nM3 +iI)nT3 +t0 +return +nT3;} +case +cAdd:{c43(y21,xD1;x2 +item +tI +a)eY3 +item +n51)nK3+=item +tF2;else +nM3 +item +xF2 +nL3+=item +yN +val;else +nT3 +t0 +if(!nP3&&!nT3 +xF2 +yF3 +if +iT2 +n51&&nQ3&&nK3>nL3)std::swap +iT2 +tF2,nL3)n31 +nT3;} +case +cMul:{e12 +Value{enum +x73{eA3,iX1,iW2} +;x73 +tK +iU2 +value;Value(x73 +t):tK(t),value(0){} +Value(iV2 +v):tK(eA3),value(v){} +bool +cM2 +yZ1 +tK==iX1||cU2 +valueisOptimized) return; - CopyOnWrite(); - - CodeTree tree; - MakeTree(&tree); - -#ifdef TREE_DEBUG - cout << "BEFORE OPT :" << tree << endl; +;e12 +yG1{Value +yQ2,yR2;yG1():yQ2(Value::iW2),yR2(Value::iX1){} +void +xE2 +Value +eB3,const +Value&value2){eB3*=value2;if(eB3nL3)std::swap +iT2 +tF2,nL3)n31 +nT3;} +case +cMod:{c23 +x +tI +yS2 +y +tI +1)eY3 +y +xF2{if(y +yN +val>=xD1{if(!x +n51||(x +tF2)=xD1 +nM +y +yN +val,-y +yN +val);iB3 +y +yN +val,fp_const_negativezero +xK());} +} +iB3 +i33 +cPow:{tM2 +tH==xD1{nM +iV2(nR3} +nR&&lR==xD1{nM +y21,xD1;} +nR&&cB3 +lR +xE3 +nM +iV2(nR3} +tM2 +tH>y21&&GetEvennessInfo +y91 +1))==IsAlways +tJ2 +e92 +tH;c23 +tmp +tI +yS2 +nT3;nP3=true;nK3=0;if(tmp +n51&&tmp +tF2>=xD1 +nK3 +t03 +tmp +tF2,xG2;lJ2 +tmp +yN +known&&tmp +yN +val<=xD1 +nK3 +t03 +tmp +yN +val,xG2;nT3 +t0 +if(tmp +n51&&tmp +xF2{nQ3=true;nL3=fp_max(fp_abs(tmp +tF2),fp_abs(tmp +yN +val));nL3=fp_pow +iT2 +yN +val,xG2;} +return +nT3;} +c23 +p0 +tI +yS2 +p1 +tI +1));TriTruthValue +p0_positivity=iC3(p0 +tF2)>=xD1?IsAlways:(p0 +cL2 +p0 +e23 +y21?lC3 +Unknown);TriTruthValue +cN2=GetEvennessInfo +y91 +1));TriTruthValue +t1=Unknown;switch(p0_positivity)l92 +t1=IsAlways;lC +lC3{t1=cN2;yF3 +c73 +switch(cN2)l92 +t1=IsAlways;lC +lC3 +lC +Unknown:{tM2!isInteger +tG&&tH>=xD1{t1=IsAlways;} +yF3} +l73 +t1)l92{iV2 +min=y21;if +iC3 +p1 +n51){min +t03 +p0 +tF2,p1 +tF2 +eY3 +p0 +tF2=xD1&&min>=xD1 +min=y21;} +if +iC3 +p0 +tF2>=y21&&p0 +yN +known&&p1 +xF2{iV2 +max +t03 +p0 +yN +val,p1 +yN +val +eY3 +min>max)std::swap(min,max);nM +min,max);} +nM +min,false +i33 +lC3{nM +false,fp_const_negativezero +xK());} +c73{yF3 +i91 +cNeg:lD +m.set_neg();tV +cSub:{yM +cNeg);iE3 +1));tmp +xD +cAdd);tmp.nJ +0));tmp +yP1 +tmp2 +y53 +cInv:{cO2-1 +yT2 +cDiv:{yM +cInv);iE3 +1));tmp +xD +x71 +AddParamMove(tmp2 +y53 +cRad:{t81 +x71 +yC +fp_const_rad_to_deg +xK(yT2 +cDeg:{t81 +x71 +yC +fp_const_deg_to_rad +xK(yT2 +cSqr:{cO2 +2 +yT2 +cExp:{t81 +cPow);tmp.yC +fp_const_e +xK()));tmp.nJ +0)y53 +cExp2:{t81 +cPow);tmp.yC +x42 +tmp.nJ +0)y53 +cCbrt:lD +yK +set(fp_cbrt);m +yN +set(fp_cbrt);tV +cSqrt:lD +if(x43)yK +val=nU3 #endif - // Now rebuild from the tree. - - vector byteCode; - vector immed; - -#if 0 - byteCode.resize(Comp.ByteCodeSize); - for(unsigned a=0; a0){t81 +cCbrt);iF3 +tmp +eT1 +tree.i72--i62;} +while(i52>0){t81 +cSqrt +eY3 +lD3){tmp +xD +cRSqrt);lD3 +tO3} +iF3 +tmp +eT1 +tree.i72--i52;} +if(lD3){t81 +cInv);iF3 +tree.i72} +} +xW3 +e12 +RootPowerTable{static +const +iV2 +RootPowers[(1+4)*(1+3)];} +nJ1 +const +iV2 +t8(1+4)*(1+3)]={iV2(1)lS +iG3 +iG3 +2*iG3 +i11)lS +3*2)lS +3*2*2)lS +3*i11*2*i11*3 +cV2 +2 +cV2 +2*2 +cV2 +i11*3*2*i11*3*3 +cV2 +3*2 +cV2 +3*2*2 +cV2 +3*i11*3*3*2*2*2*2)} +;e12 +PowiResolver{static +const +iF2 +MaxSep=4;static +xC3 +MaxOp=5;typedef +int +eE3;typedef +long +xI3;typedef +long +tW;e12 +yU2{yU2():n_int_sqrt(0),n_int_cbrt(0),sep_list(),lV1(0){} +int +n_int_sqrt;int +n_int_cbrt;int +tL1 +MaxSep];tW +lV1;} +nJ1 +static +yU2 +CreatePowiResult(iV2 +xG2{yU2 +nT3;eE3 +t9=FindIntegerFactor(xG2;if(t9==0){ +#ifdef DEBUG_POWI +i82"no factor found for %Lg\n" +,yK1 +xG2; +#endif +return +nT3;} +nT3.lV1=y31 +exponent,t9);xI3 +eM2=EvaluateFactorCost(t9,0,0,0)+cB +nT3.lV1);int +iH3=0;int +iI3=0;int +mul_count=0; +#ifdef DEBUG_POWI +i82"orig = %Lg\n" +,yK1 +xG2;i82"plain factor = " +iW3"%ld\n" +,(int)t9,(long)eM2); +#endif +for +nT2 +n_s=0;n_s=MaxOp)break; +#endif +int +n_sqrt=s%MaxOp;int +n_cbrt=s/MaxOp;if(n_sqrt+n_cbrt>4 +cP2 +iU2 +lI1=exponent;lI1-=t8 +s];i41=FindIntegerFactor(lI1 +eY3 +xT2!=0){tW +xP=y31 +lI1,xT2);xI3 +cost=EvaluateFactorCost(xT2,iH3+n_sqrt,iI3+n_cbrt,mul_count+1)+cB +xP); +#ifdef DEBUG_POWI +i82"Candidate sep %u (%d*sqrt %d*cbrt)factor = " +iW3"%ld (for %Lg to %ld)\n" +,s,n_sqrt,n_cbrt,xT2,(long)cost,yK1 +lI1,(long)xP); +#endif +if(cost%Lg\n" +,x9,x9%MaxOp,x9/MaxOp,yW1,yI1,yK1(xG2,yK1 +t62-t8 +x9])); +#endif +nT3.tL1 +n_s]=x9;exponent-=t8 +x9];iH3+=x9%MaxOp;iI3+=x9/MaxOp;eM2=yI1;t9=yW1;mul_count+=1;} +nT3.lV1=y31 +exponent,t9); +#ifdef DEBUG_POWI +i82"resulting exponent is %ld (from exponent=%Lg, best_factor=%Lg)\n" +,nT3.lV1,yK1 +exponent,yK1 +t9); +#endif +while(t9%2==0){++nT3 +tD2;t9/=2;} +while(t9%3==0){++nT3.n_int_cbrt;t9/=3;} +return +nT3;} +private:static +xI3 +cB +tW +xP){static +std::map +cR2 +iB;if(xP<0){xI3 +cost=22 +n31 +cost+cB-xP);} +std::map +cR2::yV3 +i=iB.xU2 +xP +eY3 +i!=iB.cY1 +xP)return +i +e82;std::pair +cR2 +nT3(xP,0.0);xI3&cost=nT3 +tE3;while(xP>1){int +xT2=0;if(xP<256){xT2=xH1::powi_table[xP];if(xT2&128)xT2&=127;else +xT2=0;if(xT2&64)xT2=-(xT2&63)-1;} +if(xT2){cost+=cB +xT2);xP/=xT2;eR2 +if(!(xP&1)){xP/=2;cost+=6;} +else{cost+=7;xP-=1;} +} +iB.yR3,nT3)n31 +cost;} +cA1 +tW +y31 +yJ1,i41)yR +makeLongInteger(value*iV2(xT2));} +cA1 +bool +yR1 +yJ1,i41 +tJ2 +v=value*iV2(xT2)n31 +isLongInteger(v);} +cA1 +eE3 +FindIntegerFactor(yJ1){i41=(2*2*2*2); +#ifdef CBRT_IS_SLOW #else - byteCode.clear(); immed.clear(); - size_t stacktop_cur = 0; - size_t stacktop_max = 0; - tree.Assemble(byteCode, immed, stacktop_cur, stacktop_max); - - if(data->StackSize < stacktop_max) - { - delete[] data->Stack; - data->Stack = new double[stacktop_max]; - data->StackSize = stacktop_max; - } +xT2*=(3*3*3); #endif - - delete[] data->ByteCode; data->ByteCode = 0; - if((data->ByteCodeSize = byteCode.size()) > 0) - { - data->ByteCode = new unsigned[data->ByteCodeSize]; - for(unsigned a=0; aByteCode[a] = byteCode[a]; - } - - delete[] data->Immed; data->Immed = 0; - if((data->ImmedSize = immed.size()) > 0) - { - data->Immed = new double[data->ImmedSize]; - for(unsigned a=0; aImmed[a] = immed[a]; - } - - data->isOptimized = true; +eE3 +nT3=0;if(yR1 +value,xT2)){nT3=xT2;while((xT2%2)==0&&yR1 +value,xT2/2))nT3=xT2/=2;while((xT2%3)==0&&yR1 +value,xT2/3))nT3=xT2/=3;} +#ifdef CBRT_IS_SLOW +if +iT2==0){if(yR1 +value,3 +nE3 +3;} +#endif +return +nT3;} +static +int +EvaluateFactorCost(int +xT2,int +s,int +c,int +nmuls){xC3 +xD3=6; +#ifdef CBRT_IS_SLOW +xC3 +eN2=25; +#else +xC3 +eN2=8; +#endif +int +nT3=s*xD3+c*eN2;while(xT2%2==0){xT2/=2;nT3+=xD3;} +while(xT2%3==0){xT2/=3;nT3+=eN2;} +nT3+=nmuls +n31 +nT3;} } +;} +t5{xN1 +eJ::RecreateInversionsAndNegations(bool +prefer_base2){bool +changed=false +yM3 +0;a0;){eJ&powgroup=lS1;if(powgroup +yV2 +0)cX2 +tO +iJ3 +eJ&log2=tO +0);log2.l61 +log2 +xD +eF3);log2.yC +fp_pow(immeds +tG1 +1)/x52)));log2 +eT1 +yF3} +} +} +yP3 +yV2 +iJ3 +lC2 +exp_param=tO +1)iU2 +e92 +exp_param +nC1;if(e01 +tG1-1))){l61 +nF2.push_back(lS1 +lR2 +t41 +lJ2 +exponent=i21.y22){nH2 +cDiv)eO +nN3 +eO +i21 +t43{nH2 +cRDiv)eO +i21)eO +nN3;} +} +} +if(nG2.t91 +eJ +y41 +iS1;yQ1 +SetParamsMove +eF +while(yQ1 +RecreateInversionsAndNegations(prefer_base2))yQ1 +FixIncompleteHashes();nH2 +eF3)eO +nG2)eO +nN3;x62} +if(cT1.t91 +eJ +y41 +cMul);mulgroup +yP1 +cT1 +l8 +1));yQ1 +AddParamsMove +eF +while(yQ1 +RecreateInversionsAndNegations(prefer_base2))yQ1 +FixIncompleteHashes();DelParams();nH2 +eF3)eO +cT1 +l8 +0))eO +nN3;x62 +i91 +cAdd:{eH +iA2;for +iJ-->0;)if(eG3 +cMul){nV3 +y51:;eJ&mulgroup=x82 +for +iA1 +b=yQ1 +xF1 +b-->0;){if +lR3 +l8 +b)l71 +xT2=mulgroup +l8 +b)nC1 +cA3 +xT2 +i92 +y51;} +yQ1 +l61 +yQ1 +DelParam(b);nW3 +lJ2 +cB3 +xT2 +tG1-2)))xC +y51;} +yQ1 +l61 +yQ1 +DelParam(b);yQ1 +yC +x42 +nW3} +} +if(t2){yQ1 +tA +nN3;t41} +lJ2 +eG3 +cDiv&&!IsIntType +xK::nT3){nV3 +y61:;eJ&i21=x82 +if(i21 +l8 +0)i51 +cB3 +i21 +l8 +0)nC1 +i92 +y61;} +i21.l61 +i21 +tK2 +0);i21 +xD +cInv);nW3} +if(t2)xC +y61;} +i21.tA +i21);t41} +lJ2 +eG3 +cRDiv&&!IsIntType +xK::nT3){nV3 +x81:;eJ&i21=x82 +if(i21 +l8 +1)i51 +cB3 +i21 +l8 +1)nC1 +i92 +x81;} +i21.l61 +i21 +tK2 +1);i21 +xD +cInv);nW3} +if(t2)xC +x81;} +i21.tA +i21);t41} +if(!iA2 +cT3){ +#ifdef DEBUG_SUBSTITUTIONS +i82"Will make a Sub conversion in:\n" +);fflush(stdout);iR +#endif +eJ +yW2;yW2 +xD +cAdd);yW2 +iO3 +iA2);yW2 +eT1 +eJ +cU1;cU1 +xD +cAdd);cU1 +iO3 +l02));cU1 +eT1 +if(cU1 +i61&&cB3 +cU1 +nC1,xD1){nH2 +cNeg);e7);} +e63 +cU1.y22==1){nH2 +cRSub);e7)eO +cU1);} +lJ2 +yW2 +nC==cAdd){nH2 +cSub)eO +cU1);e7 +lR2 +for +iA1 +a=1;a0){iY1=true;} +#ifdef DEBUG_POWI +i82"Will resolve powi %Lg as powi(chain(%d,%d),%ld)" +,yK1 +fp_abs +eH3),r +tD2,r.n_int_cbrt,r.lV1);for +nT2 +n=0;nx22{if(prefer_base2 +tJ2 +yY2=fp_log2(p0 +nC1)cA3 +yY2 +xE3 +DelParam(0 +t43{n0 +e21 +yY2)tF1 +c9 +p1 +tF1 +eT1 +nG1 +nD1} +nH2 +cExp2);x62} +else{iV2 +yY2=fp_log(p0 +nC1)cA3 +yY2 +xE3 +DelParam(0 +t43{n0 +e21 +yY2)tF1 +c9 +p1 +tF1 +eT1 +nG1 +nD1} +nH2 +cExp);x62} +} +lJ2 +GetPositivityInfo(p0)==IsAlways){if(prefer_base2){eJ +log;log +xD +cLog2);log +c9 +p0);log +eT1 +n0 +p1 +tF1 +yP1 +log +tF1 +eT1 +nH2 +cExp2);nG1 +nD1 +x62} +else{eJ +log;log +xD +cLog);log +c9 +p0);log +eT1 +n0 +p1 +tF1 +yP1 +log +tF1 +eT1 +nH2 +cExp);nG1 +nD1 +x62} +} +i91 +cDiv:{if(GetParam(0)i61&&cB3 +GetParam(0)nC1 +xE3 +nH2 +cInv);DelParam(0);} +yF3 +c73 +yF3 +if(changed)goto +exit_changed +n31 +changed;} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +using +lF3 +FUNCTIONPARSERTYPES;lF3{using +t5;class +e43{size_t +nP1;size_t +eD;size_t +eE;size_t +lJ1;size_t +t3;size_t +t4;size_t +n01;eX3 +e43():nP1(0),eD(0),eE(0),lJ1(0),t3(0),t4(0),n01(0){} +void +t23 +OPCODE +op){nP1+=1;e33 +cCos)++eD;e33 +cSin)++eE;e33 +cSec)++eD;e33 +cCsc)++eE;e33 +cTan)++lJ1;e33 +cCot)++lJ1;e33 +cSinh)++t4;e33 +cCosh)++t3;e33 +cTanh)++n01;} +size_t +GetCSEscore +e73 +size_t +nT3=nP1 +n31 +nT3;} +int +NeedsSinCos +e73 +bool +y71=(nP1==(eD+eE+lJ1)eY3(lJ1&&(eE||eD))||(eE&&eD)){if(y71)return +1 +n31 +2;} +return +0;} +int +NeedsSinhCosh +e73 +bool +y71=(nP1==(t3+t4+n01)eY3(n01&&(t4||t3))||(t4&&t3)){if(y71)return +1 +n31 +2;} +return +0;} +size_t +MinimumDepth +e73 +size_t +n_sincos=std::min(eD,eE);size_t +n_sinhcosh=std::min(t3,t4 +eY3 +n_sincos==0&&n_sinhcosh==0)return +2 +n31 +1;} +} +nJ1 +class +TreeCountType:public +std::multimap >{} +xR3 +FindTreeCounts(tK1&nI2,lC2 +tree,OPCODE +x92,bool +skip_root=false){cV +i=nI2.xU2 +tree.GetHash()eY3!skip_root){bool +found +tO3 +for(;i!=nI2.cY1 +tree.GetHash();++i){if(tree +xF +i +e82 +iO2){i +e82.first.t23 +x92);found=true;yF3} +if(!found){e43 +count;count.t23 +x92);nI2.yR3,std::make_pair(tree.GetHash(),std::make_pair +eL3,tree)));} +} +nB1 +FindTreeCounts(nI2,t33,i01);} +e12 +yU{bool +BalanceGood;bool +FoundChild;} +nJ1 +yU +lK1 +lC2 +root,lC2 +child){if(root +xF +child)){yU +nT3={true,true} +n31 +nT3;} +yU +nT3={true,false} +;if(root +nC==cIf||root +nC==yW3{yU +cond=lK1 +root +l8 +0 +nO3 +yU +xX=lK1 +root +l8 +1 +nO3 +yU +y6=lK1 +root +l8 +2 +nO3 +if +y03||xX +yV||y6 +yV){nT3 +yV=true;} +nT3 +e8=((xX +yV==y6 +yV)||y03 +cZ2&&(cond +e8||(xX +yV&&y6 +yV))&&(xX +e8||y03 +cZ2&&(y6 +e8||y03 +cZ2;} +else{bool +iE1 +tO3 +bool +nQ1 +tO3 +for +iA1 +b=root.GetParamCount(),a=0;afirst!=leaf.GetHash()cP2;const +e43&occ +nQ2 +first;size_t +score=occ.GetCSEscore();lC2 +candidate +nQ2 +second;if(tM1 +candidate)cP2;if(leaf.y22yZ2){yZ2=score;cs_it=i;} +} +if(yZ2<=0){ +#ifdef DEBUG_SUBSTITUTIONS_CSE +std::cout<<"No more CSE candidates.\n" +<(lT2"Done with Common Subexpression:" +i13 +xK(tree +lT2 +std::endl; +#endif +#if 0 +if(lW1){if(lW1==2||i1){synth.e91} +yE3 +cSinCos,1,2)cI1 +iC2,1)cI1 +iD2,0);} +if(i1){if(lW1)synth.e91 +if(i1==2){synth.e91} +yE3 +cSinhCosh,1,2)cI1 +c02,1)cI1 +c12,0);} +#endif +} +return +yD3 +stacktop_before;} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +tZ1 +FunctionParserBase +xK::Optimize(){using +t5;l61 +eJ +tree;tree.GenerateFrom(*mData);FPoptimizer_Optimize::ApplyGrammars(tree);std +xV3eI3;std +xV3 +xK +immed;size_t +stacktop_max=0;tree.SynthesizeByteCode(eI3,immed,stacktop_max +eY3 +mData->mStackSize!=stacktop_max){mData->mStackSize=iF2(stacktop_max); +#if !defined(FP_USE_THREAD_SAFE_EVAL) && \ + !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) +mData->mStack.t73 +stacktop_max); +#endif +} +mData->mByteCode.swap(eI3);mData->mImmed.swap(immed);} +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +x8 +MpfrFloat +n11 +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE +x8 +GmpInt +n11 +#endif +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +x8 +std::complexn11 +#endif +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +x8 +std::complexn11 +#endif +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +x8 +std::complexn11 +#endif +FUNCTIONPARSER_INSTANTIATE_TYPES +#endif - -#endif // #ifdef SUPPORT_OPTIMIZER +#endif diff --git a/deal.II/contrib/functionparser/fptypes.h b/deal.II/contrib/functionparser/fptypes.h deleted file mode 100644 index a3534912cb..0000000000 --- a/deal.II/contrib/functionparser/fptypes.h +++ /dev/null @@ -1,117 +0,0 @@ -//=============================== -// Function parser v2.83 by Warp -//=============================== - -// NOTE: -// This file contains only internal types for the function parser library. -// You don't need to include this file in your code. Include "fparser.hh" -// only. - - - -namespace FUNCTIONPARSERTYPES -{ -// The functions must be in alphabetical order: - enum OPCODE - { - cAbs, cAcos, -#ifndef NO_ASINH - cAcosh, -#endif - cAsin, -#ifndef NO_ASINH - cAsinh, -#endif - cAtan, - cAtan2, -#ifndef NO_ASINH - cAtanh, -#endif - cCeil, cCos, cCosh, cCot, cCsc, -#ifndef DISABLE_EVAL - cEval, -#endif - cExp, cFloor, cIf, cInt, cLog, cLog10, cMax, cMin, - cSec, cSin, cSinh, cSqrt, cTan, cTanh, - -// These do not need any ordering: - cImmed, cJump, - cNeg, cAdd, cSub, cMul, cDiv, cMod, cPow, - cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq, - cNot, cAnd, cOr, - - cDeg, cRad, - - cFCall, cPCall, - -#ifdef SUPPORT_OPTIMIZER - cVar, cDup, cInv, -#endif - - VarBegin - }; - - struct FuncDefinition - { - const char* name; - unsigned nameLength; - unsigned opcode; - unsigned params; - - // This is basically strcmp(), but taking 'nameLength' as string - // length (not ending '\0'): - bool operator<(const FuncDefinition& rhs) const - { - for(unsigned i = 0; i < nameLength; ++i) - { - if(i == rhs.nameLength) return false; - const char c1 = name[i], c2 = rhs.name[i]; - if(c1 < c2) return true; - if(c2 < c1) return false; - } - return nameLength < rhs.nameLength; - } - }; - - -// This list must be in alphabetical order: - const FuncDefinition Functions[]= - { - { "abs", 3, cAbs, 1 }, - { "acos", 4, cAcos, 1 }, -#ifndef NO_ASINH - { "acosh", 5, cAcosh, 1 }, -#endif - { "asin", 4, cAsin, 1 }, -#ifndef NO_ASINH - { "asinh", 5, cAsinh, 1 }, -#endif - { "atan", 4, cAtan, 1 }, - { "atan2", 5, cAtan2, 2 }, -#ifndef NO_ASINH - { "atanh", 5, cAtanh, 1 }, -#endif - { "ceil", 4, cCeil, 1 }, - { "cos", 3, cCos, 1 }, - { "cosh", 4, cCosh, 1 }, - { "cot", 3, cCot, 1 }, - { "csc", 3, cCsc, 1 }, -#ifndef DISABLE_EVAL - { "eval", 4, cEval, 0 }, -#endif - { "exp", 3, cExp, 1 }, - { "floor", 5, cFloor, 1 }, - { "if", 2, cIf, 0 }, - { "int", 3, cInt, 1 }, - { "log", 3, cLog, 1 }, - { "log10", 5, cLog10, 1 }, - { "max", 3, cMax, 2 }, - { "min", 3, cMin, 2 }, - { "sec", 3, cSec, 1 }, - { "sin", 3, cSin, 1 }, - { "sinh", 4, cSinh, 1 }, - { "sqrt", 4, cSqrt, 1 }, - { "tan", 3, cTan, 1 }, - { "tanh", 4, cTanh, 1 } - }; -} diff --git a/deal.II/contrib/functionparser/lgpl-3.0.txt b/deal.II/contrib/functionparser/lgpl-3.0.txt new file mode 100644 index 0000000000..65c5ca88a6 --- /dev/null +++ b/deal.II/contrib/functionparser/lgpl-3.0.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/deal.II/contrib/functionparser/mpfr/GmpInt.cc b/deal.II/contrib/functionparser/mpfr/GmpInt.cc new file mode 100644 index 0000000000..490add4b98 --- /dev/null +++ b/deal.II/contrib/functionparser/mpfr/GmpInt.cc @@ -0,0 +1,710 @@ +#include "GmpInt.hh" +#include +#include +#include +#include +#include + +//=========================================================================== +// Shared data +//=========================================================================== +namespace +{ + unsigned long gIntDefaultNumberOfBits = 256; + + std::vector& intString() + { + static std::vector 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 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& 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 str; + + unsigned startIndex = 0; + while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex; + if(!value[startIndex]) { *endptr = const_cast(value); return; } + + unsigned endIndex = startIndex; + if(value[endIndex] == '-') ++endIndex; + if(!std::isdigit(value[endIndex])) + { *endptr = const_cast(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(value + endIndex); +} + +GmpInt GmpInt::parseString(const char* str, char** endptr) +{ + GmpInt retval(kNoInitialization); + retval.parseValue(str, endptr); + return retval; +} + +//=========================================================================== +// Operator functions +//=========================================================================== +GmpInt operator+(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs); + else + mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + return retval; +} + +GmpInt operator-(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger); + else + { + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + mpz_neg(retval.mData->mInteger, retval.mData->mInteger); + } + return retval; +} + +GmpInt operator*(long lhs, const GmpInt& rhs) +{ + return rhs * lhs; +} + +GmpInt operator/(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) / rhs; +} + +GmpInt operator%(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) % rhs; +} diff --git a/deal.II/contrib/functionparser/mpfr/GmpInt.hh b/deal.II/contrib/functionparser/mpfr/GmpInt.hh new file mode 100644 index 0000000000..1c1c1712dc --- /dev/null +++ b/deal.II/contrib/functionparser/mpfr/GmpInt.hh @@ -0,0 +1,148 @@ +#ifndef ONCE_FP_GMP_INT_HH_ +#define ONCE_FP_GMP_INT_HH_ + +#include + +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 .) + 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 + void get_raw_mpfr_data(Mpz_t& dest_mpz_t); + + + // Note that the returned char* points to an internal (shared) buffer + // which will be valid until the next time this function is called + // (by any object). + const char* getAsString(int base = 10) const; + long toInt() const; + + GmpInt& operator+=(const GmpInt&); + GmpInt& operator+=(long); + GmpInt& operator-=(const GmpInt&); + GmpInt& operator-=(long); + GmpInt& operator*=(const GmpInt&); + GmpInt& operator*=(long); + GmpInt& operator/=(const GmpInt&); + GmpInt& operator/=(long); + GmpInt& operator%=(const GmpInt&); + GmpInt& operator%=(long); + + GmpInt& operator<<=(unsigned long); + GmpInt& operator>>=(unsigned long); + + // Equivalent to "+= value1 * value2;" + void addProduct(const GmpInt& value1, const GmpInt& value2); + void addProduct(const GmpInt& value1, unsigned long value2); + + // Equivalent to "-= value1 * value2;" + void subProduct(const GmpInt& value1, const GmpInt& value2); + void subProduct(const GmpInt& value1, unsigned long value2); + + void negate(); + void abs(); + static GmpInt abs(const GmpInt&); + + GmpInt operator+(const GmpInt&) const; + GmpInt operator+(long) const; + GmpInt operator-(const GmpInt&) const; + GmpInt operator-(long) const; + GmpInt operator*(const GmpInt&) const; + GmpInt operator*(long) const; + GmpInt operator/(const GmpInt&) const; + GmpInt operator/(long) const; + GmpInt operator%(const GmpInt&) const; + GmpInt operator%(long) const; + + GmpInt operator-() const; + + GmpInt operator<<(unsigned long) const; + GmpInt operator>>(unsigned long) const; + + bool operator<(const GmpInt&) const; + bool operator<(long) const; + bool operator<=(const GmpInt&) const; + bool operator<=(long) const; + bool operator>(const GmpInt&) const; + bool operator>(long) const; + bool operator>=(const GmpInt&) const; + bool operator>=(long) const; + bool operator==(const GmpInt&) const; + bool operator==(long) const; + bool operator!=(const GmpInt&) const; + bool operator!=(long) const; + + void parseValue(const char* value); + void parseValue(const char* value, char** endptr); + static GmpInt parseString(const char* str, char** endptr); + + + private: + struct GmpIntData; + class GmpIntDataContainer; + + GmpIntData* mData; + + enum DummyType { kNoInitialization }; + GmpInt(DummyType); + + void copyIfShared(); + static GmpIntDataContainer& gmpIntDataContainer(); + + friend GmpInt operator+(long lhs, const GmpInt& rhs); + friend GmpInt operator-(long lhs, const GmpInt& rhs); +}; + +GmpInt operator+(long lhs, const GmpInt& rhs); +GmpInt operator-(long lhs, const GmpInt& rhs); +GmpInt operator*(long lhs, const GmpInt& rhs); +GmpInt operator/(long lhs, const GmpInt& rhs); +GmpInt operator%(long lhs, const GmpInt& rhs); + +inline bool operator<(long lhs, const GmpInt& rhs) { return rhs > lhs; } +inline bool operator<=(long lhs, const GmpInt& rhs) { return rhs >= lhs; } +inline bool operator>(long lhs, const GmpInt& rhs) { return rhs < lhs; } +inline bool operator>=(long lhs, const GmpInt& rhs) { return rhs <= lhs; } +inline bool operator==(long lhs, const GmpInt& rhs) { return rhs == lhs; } +inline bool operator!=(long lhs, const GmpInt& rhs) { return rhs != lhs; } + +inline std::ostream& operator<<(std::ostream& os, const GmpInt& value) +{ + os << value.getAsString(); + return os; +} + +#endif diff --git a/deal.II/contrib/functionparser/mpfr/MpfrFloat.cc b/deal.II/contrib/functionparser/mpfr/MpfrFloat.cc new file mode 100644 index 0000000000..112c684aec --- /dev/null +++ b/deal.II/contrib/functionparser/mpfr/MpfrFloat.cc @@ -0,0 +1,976 @@ +#include "MpfrFloat.hh" +#include +#include +#include +#include +#include +#include + +//=========================================================================== +// 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 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& 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 str; + str.resize(precision+30); + mpfr_snprintf(&(str[0]), precision+30, "%.*RNg", precision, mData->mFloat); + return &(str[0]); +#endif +} + +bool MpfrFloat::isInteger() const +{ + return mpfr_integer_p(mData->mFloat) != 0; +} + +long MpfrFloat::toInt() const +{ + return mpfr_get_si(mData->mFloat, GMP_RNDN); +} + +double MpfrFloat::toDouble() const +{ + return mpfr_get_d(mData->mFloat, GMP_RNDN); +} + + +//=========================================================================== +// Modifying operators +//=========================================================================== +MpfrFloat& MpfrFloat::operator+=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_add(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator+=(double value) +{ + copyIfShared(); + mpfr_add_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator-=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_sub(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator-=(double value) +{ + copyIfShared(); + mpfr_sub_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator*=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_mul(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator*=(double value) +{ + copyIfShared(); + mpfr_mul_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator/=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_div(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator/=(double value) +{ + copyIfShared(); + mpfr_div_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator%=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_fmod(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + + +//=========================================================================== +// Modifying functions +//=========================================================================== +void MpfrFloat::negate() +{ + copyIfShared(); + mpfr_neg(mData->mFloat, mData->mFloat, GMP_RNDN); +} + +void MpfrFloat::abs() +{ + copyIfShared(); + mpfr_abs(mData->mFloat, mData->mFloat, GMP_RNDN); +} + + +//=========================================================================== +// Non-modifying operators +//=========================================================================== +MpfrFloat MpfrFloat::operator+(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_add(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator+(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_add_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_sub(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_sub_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator*(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_mul(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator*(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_mul_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator/(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_div(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator/(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_div_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator%(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_fmod(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-() const +{ + MpfrFloat retval(kNoInitialization); + mpfr_neg(retval.mData->mFloat, mData->mFloat, GMP_RNDN); + return retval; +} + + + +//=========================================================================== +// Comparison operators +//=========================================================================== +bool MpfrFloat::operator<(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) < 0; +} + +bool MpfrFloat::operator<(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) < 0; +} + +bool MpfrFloat::operator<=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) <= 0; +} + +bool MpfrFloat::operator<=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) <= 0; +} + +bool MpfrFloat::operator>(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) > 0; +} + +bool MpfrFloat::operator>(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) > 0; +} + +bool MpfrFloat::operator>=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) >= 0; +} + +bool MpfrFloat::operator>=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) >= 0; +} + +bool MpfrFloat::operator==(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) == 0; +} + +bool MpfrFloat::operator==(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) == 0; +} + +bool MpfrFloat::operator!=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) != 0; +} + +bool MpfrFloat::operator!=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) != 0; +} + + +//=========================================================================== +// Operator functions +//=========================================================================== +MpfrFloat operator+(double lhs, const MpfrFloat& rhs) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_add_d(retval.mData->mFloat, rhs.mData->mFloat, lhs, GMP_RNDN); + return retval; +} + +MpfrFloat operator-(double lhs, const MpfrFloat& rhs) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_d_sub(retval.mData->mFloat, lhs, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat operator*(double lhs, const MpfrFloat& rhs) +{ + return rhs * lhs; +} + +MpfrFloat operator/(double lhs, const MpfrFloat& rhs) +{ + return MpfrFloat(lhs) / rhs; +} + +MpfrFloat operator%(double lhs, const MpfrFloat& rhs) +{ + return MpfrFloat(lhs) % rhs; +} + +std::ostream& operator<<(std::ostream& os, const MpfrFloat& value) +{ + os << value.getAsString(unsigned(os.precision())); + return os; +} + +//=========================================================================== +// Static functions +//=========================================================================== +MpfrFloat MpfrFloat::log(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::log2(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::log10(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp2(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp10(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cos(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sin(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::tan(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_tan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sec(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sec(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::csc(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_csc(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cot(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cot(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +void MpfrFloat::sincos(const MpfrFloat& value, + MpfrFloat& sin, + MpfrFloat& cos) +{ + sin.copyIfShared(); + cos.copyIfShared(); + mpfr_sin_cos + (sin.mData->mFloat, cos.mData->mFloat, value.mData->mFloat, GMP_RNDN); +} + +MpfrFloat MpfrFloat::acos(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asin(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan2(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan2(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::hypot(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_hypot(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::tanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_tanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::acosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sqrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sqrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cbrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cbrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::root(const MpfrFloat& value, unsigned long root) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_root(retval.mData->mFloat, value.mData->mFloat, root, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value, long exponent) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow_si(retval.mData->mFloat, value.mData->mFloat, exponent, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::abs(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_abs(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::dim(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_dim(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::round(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_round(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::ceil(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_ceil(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::floor(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_floor(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::trunc(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_trunc(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::parseString(const char* str, char** endptr) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_strtofr(retval.mData->mFloat, str, endptr, 0, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::const_pi() +{ + return mpfrFloatDataContainer().const_pi(); +} + +MpfrFloat MpfrFloat::const_e() +{ + return mpfrFloatDataContainer().const_e(); +} + +MpfrFloat MpfrFloat::const_log2() +{ + return mpfrFloatDataContainer().const_log2(); +} + +MpfrFloat MpfrFloat::someEpsilon() +{ + return mpfrFloatDataContainer().const_epsilon(); +} diff --git a/deal.II/contrib/functionparser/mpfr/MpfrFloat.hh b/deal.II/contrib/functionparser/mpfr/MpfrFloat.hh new file mode 100644 index 0000000000..d455d24ce4 --- /dev/null +++ b/deal.II/contrib/functionparser/mpfr/MpfrFloat.hh @@ -0,0 +1,206 @@ +#ifndef ONCE_FP_MPFR_FLOAT_ +#define ONCE_FP_MPFR_FLOAT_ + +#include + +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 .) + 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 + 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 diff --git a/deal.II/source/base/function_parser.cc b/deal.II/source/base/function_parser.cc index b431ef753e..ea574f5bd2 100644 --- a/deal.II/source/base/function_parser.cc +++ b/deal.II/source/base/function_parser.cc @@ -16,7 +16,10 @@ #include #ifdef HAVE_FUNCTIONPARSER -# include +namespace fparser +{ +# include +} #else namespace fparser @@ -128,7 +131,8 @@ void FunctionParser::initialize (const std::string &variables, // problems with the number of // variables... } - +/* +TODO: Remove or port to fparser 4.5 // Now we define how many variables // we expect to read in. We // distinguish between two cases: @@ -153,6 +157,7 @@ void FunctionParser::initialize (const std::string &variables, ExcDimensionMismatch(n_vars,fp[0].NVars())); // Now set the initialization bit. +*/ initialized = true; } -- 2.39.5