From: Shamus Hammons Date: Fri, 10 Sep 2010 21:50:44 +0000 (+0000) Subject: Adding fparser v4.3... X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7fbafaddba531f7acc44477d97cf07906da343b;p=architektonas Adding fparser v4.3... --- diff --git a/architektonas.pro b/architektonas.pro index 39e1022..a28d4a5 100644 --- a/architektonas.pro +++ b/architektonas.pro @@ -19,7 +19,7 @@ RCC_DIR = obj UI_DIR = obj INCLUDEPATH += \ - fparser-4.3 \ + fparser \ dxflib/include \ src/mainapp \ src/actions \ @@ -28,7 +28,7 @@ INCLUDEPATH += \ src/forms HEADERS = \ - fparser-4.3/fparser.hh + fparser/fparser.hh HEADERS += \ src/base/actioninterface.h \ @@ -109,8 +109,8 @@ HEADERS += \ src/base/vectorsolutions.h SOURCES = \ - fparser-4.3/fparser.cc \ - fparser-4.3/fpoptimizer.cc + fparser/fparser.cc \ + fparser/fpoptimizer.cc SOURCES += \ src/base/actioninterface.cpp \ diff --git a/fparser/docs/fparser.html b/fparser/docs/fparser.html new file mode 100644 index 0000000..1b10066 --- /dev/null +++ b/fparser/docs/fparser.html @@ -0,0 +1,1629 @@ + + + + + + Function Parser for C++ v4.3 : Documentation + + + +

Function Parser for C++ v4.3

+ +

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

+ +

What's new in v4.2 +

+ +

What's new in v4.1 +

+ + + + +

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, + 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 (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 same directory +as fparser.cc. + +

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 all the other parser types + use either C99 standard libraries not yet available in the official C++ + standard or the third-party libraries GMP and MPFR. It also makes + compilation faster and the resulting binary smaller when unused classes + are not compiled in.). + +

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

Note that this version of the class uses C99 standard math functions + not yet available in all C++ compilers. Also the ld version + of the class described below use such functions. +

+ +

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

+ +

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_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_SUPPORT_TR1_MATH_FUNCS : (Default off)

+

Define this precompiler constant to make the library use additional + math functions defined in the C99 standard and the C++ TR1 standard + proposal (but not yet in the official C++ standard). This can make + evaluation faster when these functions are involved. +

The C++ TR1 math functions in question are: asinh(), + acosh(), atanh(), exp2() and + log2(). +

+ +

FP_ENABLE_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). For this reason this function is disabled by default. + You can add support for the eval() function by + defining this precompiler constant. +

+ +

FP_EVAL_MAX_REC_LEVEL : (Default 1000)

+

Sets the maximum recursion level allowed for eval(). +

+ +

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

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

+ +

FP_NO_EVALUATION_CHECKS : (Default off)

+

If this precompiler constant is defined, no evaluation-time checks + will be performed. This may give a slight boost in speed in certain + situations. Consult the evaluation + checks section below for more information on this subject. +

+
+ + + + +

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


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


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


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

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

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 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.
cbrt(A)Cube root of A. Returns the value whose cube is A.
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.
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.
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. Equidistant values are rounded up. + E.g. -2.9 is rounded to -3.0; -2.5 and -2.1 are rounded to -2.0, + and 2.9 and 2.5 are rounded to 3.0; 2.1 is rounded to 2.0.
log(A)Natural (base e) logarithm of A.
log10(A)Base 10 logarithm of A.
max(A,B)If A>B, the result is A, else B.
min(A,B)If A<B, the result is A, else B.
pow(A,B)Exponentiation (A raised to the power B).
sec(A)Secant of A (equivalent to 1/cos(A)).
sin(A)Sine of A. Returns the sine of the angle A, where A is + measured in radians.
sinh(A)Same as sin() but for hyperbolic sine.
sqrt(A)Square root of A. Returns the value whose square is A.
tan(A)Tangent of A. Returns the tangent of the angle A, where A + is measured in radians.
tanh(A)Same as tan() but for hyperbolic tangent.
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 evaluation-time checks

+ +

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

Since not all error situations can be caught, and since the sanity checks +only slow down the evaluation (although only very slightly), the precompiler +constant FP_NO_EVALUATION_CHECKS can be used to turn all the +checks off. This might make the evaluation slightly faster in certain +situations. + +

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-2010 Juha Nieminen, Joel Yliluoma + +

This Library is distributed under the + Lesser General Public + License (LGPL) version 3. + + + diff --git a/fparser/docs/gpl.txt b/fparser/docs/gpl.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/fparser/docs/gpl.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + 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/fparser/docs/lgpl.txt b/fparser/docs/lgpl.txt new file mode 100644 index 0000000..cca7fc2 --- /dev/null +++ b/fparser/docs/lgpl.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/fparser/docs/style.css b/fparser/docs/style.css new file mode 100644 index 0000000..d5141d3 --- /dev/null +++ b/fparser/docs/style.css @@ -0,0 +1,80 @@ +html +{ + background-color: #E0E0E0; +} + +body +{ + background-color: white; + margin-left: 7%; + margin-top: 16px; + margin-right: 7%; + padding-top: 2em; + padding-left: 7%; + padding-right: 7%; + padding-bottom: 2%; + border-color: black; + border: solid; + border-width: 1px; +} + +h1 +{ + text-align: center; + background-color: #FFEEBB; + padding-bottom: 0.2em; + padding-top: 0.1em; +} + +h2 +{ + background-color: #FFFFCC; + padding-left: 0.5em; +} + +h3 +{ + background-color: #FFFFEE; +} + +blockquote +{ + padding-left: 2em; + padding-right: 2em; + font-style: italic; + background-color: #FFFAF0; +} + +li +{ + padding-top: 0.3em; +} + +pre +{ + background-color: #E8E8E8; + padding-left: 1em; + padding-top: 0.5em; + padding-bottom: 0.5em; +} + +code +{ + font-family: monospace; + color: #900040; +} + +.small +{ + font-size: 80%; +} + +.codecomment +{ + color: green; +} + +.highlight +{ + background: #C0D0FF; +} diff --git a/fparser/examples/example.cc b/fparser/examples/example.cc new file mode 100644 index 0000000..b4ab5f4 --- /dev/null +++ b/fparser/examples/example.cc @@ -0,0 +1,55 @@ +// Simple example file for the function parser +// =========================================== + +/* When running the program, try for example with these values: + +f(x) = x^2 +min x: -5 +max x: 5 +step: 1 + +*/ + +#include "../fparser.hh" + +#include +#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/fparser/examples/example2.cc b/fparser/examples/example2.cc new file mode 100644 index 0000000..958b9a1 --- /dev/null +++ b/fparser/examples/example2.cc @@ -0,0 +1,85 @@ +// Simple example file for the function parser +// =========================================== +/* Note that the library has to be compiled with + FP_SUPPORT_FLOAT_TYPE, FP_SUPPORT_LONG_DOUBLE_TYPE and + FP_SUPPORT_LONG_INT_TYPE + preprocessor macros defined for this example to work. + + Try with these input values with the different floating point parser + types to see the difference in accuracy: + +f(x) = x + 1.234567890123456789 +min x: 0 +max x: 2 +step: 1 +*/ + +#include "../fparser.hh" + +#include +#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/fparser/fp_identifier_parser.inc b/fparser/fp_identifier_parser.inc new file mode 100644 index 0000000..7a903c1 --- /dev/null +++ b/fparser/fp_identifier_parser.inc @@ -0,0 +1,415 @@ +/* NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + Part of this file is generated code (by using the make_function_name_parser +utility, found in the development version of this library). It's not intended +to be modified by hand. +*/ + + unsigned nameLength = 0; + const unsigned maximumNameLength = 0x80000000U-8; + /* + Due to the manner the identifier lengths are returned from + the readOpcode() function, the maximum supported length for + identifiers is 0x7FFFFFFF bytes. We minus 8 here to add some + buffer, because of the multibyteness of UTF-8. + Function names are limited to 0xFFFF bytes instead, but because + function names that long just are not defined, the point is moot. + */ + const unsigned char* const uptr = (const unsigned char*) input; + typedef signed char schar; + while(likely(nameLength < maximumNameLength)) + { + unsigned char byte = uptr[nameLength+0]; + /* Handle the common case of A-Za-z first */ + if(byte >= 0x40) + { + if(byte < 0x80) // 0x40..0x7F - most common case + { + // Valid characters in 40..7F: A-Za-z_ + // Valid bitmask for 40..5F: 01111111111111111111111111100001 + // Valid bitmask for 60..7F: 01111111111111111111111111100000 + if(sizeof(unsigned long) == 8) + { + const unsigned n = sizeof(unsigned long)*8-32; + // ^ avoids compiler warning when not 64-bit + unsigned long masklow6bits = 1UL << (byte & 0x3F); + if(masklow6bits & ~((1UL << 0) | (0x0FUL << (0x1B )) + | (1UL << n) | (0x1FUL << (0x1B+n)))) + { ++nameLength; continue; } + } + else + { + unsigned masklow5bits = 1 << (byte & 0x1F); + if((masklow5bits & ~(1 | (0x1F << 0x1B))) || byte == '_') + { ++nameLength; continue; } + } + break; + } + if(byte < 0xF0) + { + if(byte < 0xE0) + { + if(byte < 0xC2) break; // 0x80..0xC1 + if(byte == 0xC2 && uptr[nameLength+1]==0xA0) break; // skip nbsp + // C2-DF - next common case when >= 0x40 + // Valid sequence: C2-DF 80-BF + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + nameLength += 2; + continue; + } + if(byte == 0xE0) // E0 + { + // Valid sequence: E0 A0-BF 80-BF + if((unsigned char)(uptr[nameLength+1] - 0xA0) > (0xBF-0xA0)) break; + } + else + { + if(byte == 0xED) break; // ED is invalid + // Valid sequence: E1-EC 80-BF 80-BF + // And: EE-EF 80-BF 80-BF + if(byte == 0xE2) + { + // break on various space characters + if(uptr[nameLength+1] == 0x80 + && (schar(uptr[nameLength+2]) <= schar(0x8B) + || (uptr[nameLength+2] == 0xAF))) break; + if(uptr[nameLength+1] == 0x81 + && uptr[nameLength+2] == 0x9F) break; + } else + if(byte == 0xE3 && uptr[nameLength+1] == 0x80 + && uptr[nameLength+2] == 0x80) break; // this too + + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + } + if(schar(uptr[nameLength+2]) > schar(0xBF)) break; + nameLength += 3; + continue; + } + if(byte == 0xF0) // F0 + { + // Valid sequence: F0 90-BF 80-BF 80-BF + if((unsigned char)(uptr[nameLength+1] - 0x90) > (0xBF-0x90)) break; + } + else + { + if(byte > 0xF4) break; // F5-FF are invalid + if(byte == 0xF4) // F4 + { + // Valid sequence: F4 80-8F + if(schar(uptr[nameLength+1]) > schar(0x8F)) break; + } + else + { + // F1-F3 + // Valid sequence: F1-F3 80-BF 80-BF 80-BF + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + } + } + if(schar(uptr[nameLength+2]) > schar(0xBF)) break; + if(schar(uptr[nameLength+3]) > schar(0xBF)) break; + nameLength += 4; + continue; + } + if(nameLength > 0) + { + if(sizeof(unsigned long) == 8) + { + // Valid bitmask for 00..1F: 00000000000000000000000000000000 + // Valid bitmask for 20..3F: 00000000000000001111111111000000 + const unsigned n = sizeof(unsigned long)*8-32; + // ^ avoids compiler warning when not 64-bit + unsigned long masklow6bits = 1UL << byte; + if(masklow6bits & (((1UL << 10)-1UL) << (16+n))) + { ++nameLength; continue; } + } + else + { + if(byte >= '0' && byte <= '9') + { ++nameLength; continue; } + } + } + break; + } + + /* This function generated with make_function_name_parser.cc */ +#define lN l7 lB +#define lM l2 lB +#define lL l3 lB +#define lK if('i'l4 +#define lJ uptr +#define lI l5 3]={ +#define lH 'n'l4 +#define lG l6 3;}lB +#define lF return +#define lE 0x80000003U:3; +#define lD 0x80000005U:5; +#define lC std::memcmp(lJ+ +#define lB case +#define lA switch( +#define l9 <<16)| +#define l8 lC 1,tmp, +#define l7 lD lF 5;} +#define l6 default:lF +#define l5 static const char tmp[ +#define l4 ==lJ[ +#define l3 lE lF 3; +#define l2 0x80000004U:4;lF 4; +#define l1 .enabled()?( +#define l0 lF Functions[ +lA +nameLength){lB +2:lK +0]&&'f'l4 +1])l0 +cIf]l1 +cIf +l9 +0x80000002U:2;lF +2;lB +3:lA +lJ[0]){lB'a':if('b'l4 +1]&&'s'l4 +2])l0 +cAbs]l1 +cAbs +l9 +lL'c':lA +lJ[1]){lB'o':lA +lJ[2]){lB's':l0 +cCos]l1 +cCos +l9 +lE +lB't':l0 +cCot]l1 +cCot +l9 +lE +lG's':if('c'l4 +2])l0 +cCsc]l1 +cCsc +l9 +l3 +lG'e':if('x'l4 +1]&&'p'l4 +2])l0 +cExp]l1 +cExp +l9 +lL'i':if(lH +1]&&'t'l4 +2])l0 +cInt]l1 +cInt +l9 +lL'l':if('o'l4 +1]&&'g'l4 +2])l0 +cLog]l1 +cLog +l9 +lL'm':lA +lJ[1]){lB'a':if('x'l4 +2])l0 +cMax]l1 +cMax +l9 +lL'i':if(lH +2])l0 +cMin]l1 +cMin +l9 +l3 +lG'p':if('o'l4 +1]&&'w'l4 +2])l0 +cPow]l1 +cPow +l9 +lL's':lA +lJ[1]){lB'e':if('c'l4 +2])l0 +cSec]l1 +cSec +l9 +lL'i':if(lH +2])l0 +cSin]l1 +cSin +l9 +l3 +lG't':if('a'l4 +1]&&lH +2])l0 +cTan]l1 +cTan +l9 +l3 +lG +4:lA +lJ[0]){lB'a':lA +lJ[1]){lB'c':if('o'l4 +2]&&'s'l4 +3])l0 +cAcos]l1 +cAcos +l9 +lM's':lK +2]&&lH +3])l0 +cAsin]l1 +cAsin +l9 +lM't':if('a'l4 +2]&&lH +3])l0 +cAtan]l1 +cAtan +l9 +l2 +l6 +4;} +lB'c':lA +lJ[1]){lB'b':if('r'l4 +2]&&'t'l4 +3])l0 +cCbrt]l1 +cCbrt +l9 +lM'e':lK +2]&&'l'l4 +3])l0 +cCeil]l1 +cCeil +l9 +lM'o':if('s'l4 +2]&&'h'l4 +3])l0 +cCosh]l1 +cCosh +l9 +l2 +l6 +4;} +lB'e':lA +lJ[1]){lB'v':if('a'l4 +2]&&'l'l4 +3])l0 +cEval]l1 +cEval +l9 +lM'x':if('p'l4 +2]&&'2'l4 +3])l0 +cExp2]l1 +cExp2 +l9 +l2 +l6 +4;} +lB'l':{lI'o','g','2'} +;if(l8 +3)==0)l0 +cLog2]l1 +cLog2 +l9 +l2} +lB's':lA +lJ[1]){lB'i':if(lH +2]&&'h'l4 +3])l0 +cSinh]l1 +cSinh +l9 +lM'q':if('r'l4 +2]&&'t'l4 +3])l0 +cSqrt]l1 +cSqrt +l9 +l2 +l6 +4;} +lB't':{lI'a','n','h'} +;if(l8 +3)==0)l0 +cTanh]l1 +cTanh +l9 +l2} +l6 +4;} +lB +5:lA +lJ[0]){lB'a':lA +lJ[1]){lB'c':{lI'o','s','h'} +;if(lC +2,tmp,3)==0)l0 +cAcosh]l1 +cAcosh +l9 +lN's':{lI'i','n','h'} +;if(lC +2,tmp,3)==0)l0 +cAsinh]l1 +cAsinh +l9 +lN't':if('a'l4 +2]){if(lH +3]){lA +lJ[4]){lB'2':l0 +cAtan2]l1 +cAtan2 +l9 +lD +lB'h':l0 +cAtanh]l1 +cAtanh +l9 +lD +l6 +5;} +} +lF +5;} +lF +5;l6 +5;} +lB'f':{l5 +4]={'l','o','o','r'} +;if(l8 +4)==0)l0 +cFloor]l1 +cFloor +l9 +lN'h':{l5 +4]={'y','p','o','t'} +;if(l8 +4)==0)l0 +cHypot]l1 +cHypot +l9 +lN'l':{l5 +4]={'o','g','1','0'} +;if(l8 +4)==0)l0 +cLog10]l1 +cLog10 +l9 +lN't':{l5 +4]={'r','u','n','c'} +;if(l8 +4)==0)l0 +cTrunc]l1 +cTrunc +l9 +l7 +l6 +5;} +default:break;} +lF +nameLength; \ No newline at end of file diff --git a/fparser/fp_opcode_add.inc b/fparser/fp_opcode_add.inc new file mode 100644 index 0000000..5b4b03d --- /dev/null +++ b/fparser/fp_opcode_add.inc @@ -0,0 +1,4214 @@ +/* Function Parser for C++ v4.3 + + NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + This file contains generated code and is thus not intended to be to +be modified by hand. It was generated by util/bytecoderules_parser, which +is available in the development package. +*/ +#define FP_TRACE_BYTECODE_OPTIMIZATION(srcline,from,to,with) \ + /*std::cout << "Changing \"" from "\"\t(line " #srcline ")\n" \ + " into \"" to "\"\n" with << std::flush*/ +#define FP_TRACE_OPCODENAME(op) \ + (op < VarBegin \ + ? FP_GetOpcodeName(OPCODE(op)) \ + : findName(data->namePtrs,op,NameData::VARIABLE)) +#define FP_TRACE_BYTECODE_ADD(opcode) \ + /*std::cout << "Adding opcode: " << FP_TRACE_OPCODENAME(opcode) \ + << ", bytecode length " << data->ByteCode.size() \ + << ", pointer is " << (void*)ByteCodePtr \ + << ", code is " << (data->ByteCode.empty() \ + ? (void*)0 \ + : (void*)&data->ByteCode[0]) \ + << std::endl*/ +#define q91 wR","aD +#define q81 w5 wL aY +#define q71 w5"x"wE +#define q61 <<", C "oY +#define q51 q21 aD +#define q41 q21 wS q21 aF +#define q31 wR","w9 +#define q21 <<"," +#define q11 wR","aF +#define q01 "B[B>=VarBegin] " +#define mZ "= "<< +#define mY (y dF +#define mX g0 3] +#define mW wY" " +#define mV );g6 +#define mU gU Lqc +#define mT g8=q7; +#define mS gU Lnn; +#define mR x hI oW +#define mQ cInv:oW +#define mP "cTan " +#define mO "cSec " +#define mN "cCeil" +#define mM "cDup" +#define mL oH oW +#define mK gN oW +#define mJ "[-x] " +#define mI "y"wB +#define mH "y " +#define mG (x mV +#define mF ){oW +#define mE dM>qY oW +#define mD mT qG d1 g1 +#define mC qF hK:oW +#define mB "cFloor" +#define mA "cExp" +#define m9 hH qC oW +#define m8 wG wB w2 +#define m7 h1==gF){ +#define m6 wQ"cSub" +#define m5 wX wB wG +#define m4 "cSqrt" +#define m3 "cLess" +#define m2 wT" " +#define m1 aX m4 +#define m0 "cMin" +#define aZ "cMax" +#define aY "cDiv" +#define aX wG" " +#define aW a9" " +#define aV mA" " +#define aU "[y*x]" +#define aT "cPow" +#define aS "cLog" +#define aR "cGreater" +#define aQ "A "wY wE +#define aP "cCosh" +#define aO "A[A>=VarBegin]" +#define aN aO wE +#define aM aO" " +#define aL " "wJ"cInv" +#define aK "cAbsNot" +#define aJ " cNot" +#define aI oK B==A mF +#define aH "cLessOrEq" +#define aG "cAbs" +#define aF " "w0 +#define aE " "wM +#define aD " "wQ oY +#define aC "[ y+x] " +#define aB "cRDiv"wB w2 +#define aA " "aT +#define a9 "cNeg" +#define a8 =g8 oK qX oW +#define a7 =g8 oK gK oW +#define a6 q8 g1 +#define a5 "[-x]"w5 +#define a4 "cLog10" +#define a3 "cNotNot" +#define a2 "cLog2" +#define a1 "cExp2" +#define a0 "cGreaterOrEq" +#define wZ "cEqual" +#define wY "[x]" +#define wX "cRSub" +#define wW ==gF){h1 qC oW +#define wV oC a8 +#define wU w5 aO +#define wT "cSqr" +#define wS wB mZ x +#define wR " "oX +#define wQ "B " +#define wP aM aY +#define wO "B[B==A] " +#define wN "cNEqual" +#define wM "with"w9 +#define wL "x[x!=Value_t(0)] " +#define wK "B[B>=VarBegin] cSub"wB wG +#define wJ mM" " +#define wI "x[isInteger(x)]"aA +#define wH "x[x>Value_t(0)]" +#define wG "cAdd" +#define wF wB"A[IsComparisonOpcode(A)]" +#define wE " "w2 +#define wD "B[IsNeverNegativeValueOpcode(B)] " +#define wC "x[x==Value_t(1)] " +#define wB " x " +#define wA <<"\n" +#define w9 " A "oY +#define w8 "B[IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] "oZ +#define w7 "A[IsNeverNegativeValueOpcode(A)] " +#define w6 wR"\n" +#define w5 wE" " +#define w4 "A[A>=VarBegin&&mData->mByteCode.size()>2] " +#define w3 "x[x==Value_t(0)] " +#define w2 "cMul" +#define w1 FP_TRACE_BYTECODE_ADD +#define w0 mH mZ y wA +#define oZ "A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] "w3 w2 +#define oY mZ FP_TRACE_OPCODENAME +#define oX " with"wS<< +#define oW FP_TRACE_BYTECODE_OPTIMIZATION +#define oV cLog10 +#define oU cTanh: +#define oT cSinh: +#define oS cAbs){ +#define oR *x;qS +#define oQ qH y*x +#define oP qH x); +#define oO qF gC +#define oN oM gJ +#define oM q5 Ldl; +#define oL incStackPtr();g4 +#define oK ;if( +#define oJ gE oK +#define oI qO if( +#define oH hH qO +#define oG qB oH +#define oF B h3){ +#define oE =q0 gQ +#define oD oC oE +#define oC g7 A +#define oB tmp--> +#define oA qD-1)&&x +#define o9 qD 1) +#define o8 qQ d1 g1 +#define o7 qH qD +#define o6 hV gH +#define o5 Lcf; +#define o4 qA h4 +#define o3 2;qJ +#define o2 cPow +#define o1 cTan +#define o0 Lap; +#define dZ fp_pow( +#define dY hB qS 3 +#define dX cGreater +#define dW qN 3]qO +#define dV cRDiv: +#define dU qR A); +#define dT cNEqual +#define dS cLess: +#define dR cEqual +#define dQ gX 1)){ +#define dP h1 hM +#define dO .size() +#define dN cRSub +#define dM if(x +#define dL Default6 +#define dK Default5 +#define dJ Default2 +#define dI Default1 +#define dH mImmed +#define dG fp_log( +#define dF dD Lba; +#define dE cGreaterOrEq +#define dD ,x gU +#define dC cExp2 +#define dB cNotNot +#define dA fp_log10( +#define d9 cAbs); +#define d8 fp_abs(x) +#define d7 gZ]qC +#define d6 [0]=cDup; +#define d5 qL cAdd); +#define d4 cLessOrEq +#define d3 qU 2){ +#define d2 cAbs: +#define d1 gF); +#define d0 fp_log2( +#define hZ q7:gI +#define hY h7 hZ +#define hX cSinCos +#define hW 0.5)){ +#define hV }if( +#define hU 4 qR d1 +#define hT Default4;h7 +#define hS pop_back(); +#define hR mData-> +#define hQ switch( +#define hP Value_t +#define hO gZ gS +#define hN qI q7 gU +#define hM ==cDup){ +#define hL 3]hM +#define hK cSqr +#define hJ hV x== +#define hI ==o9){ +#define hH qN 1] +#define hG g5 y+x;qS +#define hF TailCall_cTan +#define hE TailCall_cSub +#define hD TailCall_cNeg +#define hC unsigned +#define hB q9 2;oB 0;) +#define hA q9 o3 q0-=2; +#define h9 hO hI +#define h8 dD o0 +#define h7 case +#define h6 ,y gU Lba; +#define h5 cAdd: +#define h4 cDup: +#define h3 >=VarBegin +#define h2 isEvenInteger( +#define h1 qN 2] +#define h0 =q0[0]oK +#define gZ if(q0[0 +#define gY oC h0 +#define gX hJ qD +#define gW fp_const_deg_to_rad()){ +#define gV fp_const_rad_to_deg()){ +#define gU );q5 +#define gT ,y gU o0 +#define gS ]qC dM +#define gR h7 gF:qN 1 gS>qY +#define gQ [0];qV +#define gP gO oF +#define gO B=oJ +#define gN gO B==A){ +#define gM gQ){qP h4 gN +#define gL DegreesToRadians(x); +#define gK IsLogicalOpcode(A)){ +#define gJ }break; +#define gI y=q2[-1]; +#define gH IsUnaryOpcode( +#define gG IsAlwaysIntegerOpcode(A)){ +#define gF cMul +#define gE g0 2] +#define gD hQ gE){h7 +#define gC cNeg: +#define gB q2[0]= +#define gA gB-x; +#define g9 IsNeverNegativeValueOpcode(B)){ +#define g8 g0 1] +#define g7 default: +#define g6 return; +#define g5 q2[-1]= +#define g4 --mStackPtr;q5 +#define g3 &&!HasInvalidRangesOpcode( +#define g2 hR mByteCode +#define g1 opcode= +#define g0 q0[- +#define qZ FP_ReDefinePointers(); +#define qY qD 0)){ +#define qX IsNeverNegativeValueOpcode(A)){ +#define qW g2 q6 q5 +#define qV if(A h3 +#define qU &&g2 dO> +#define qT hR dH q6 +#define qS qT q9 +#define qR ;oB q3 q1 +#define qQ q9 2 qR +#define qP hQ g8){h7 +#define qO ==q7){gI +#define qN if(g0 +#define qM if(!q0){q4 +#define qL AddFunctionOpcode( +#define qK q5 Default0; +#define qJ oB q3 hS +#define qI g2.push_back( +#define qH hR dH.push_back( +#define qG g2.q1 +#define qF gJ h7 +#define qE }}qK +#define qD hP( +#define qC ==q7){x=q2[0]; +#define qB h7 q7:x=q2[0]; +#define qA hQ q0[0]){h7 +#define q9 for(hC tmp= +#define q8 g2 q6 q0-=1; +#define q7 cImmed +#define q6 .hS +#define q5 goto +#define q4 q5 Laa;}h7 +#define q3 0;)g2. +#define q2 ImmedPtr +#define q1 hS qL +#define q0 ByteCodePtr +hC*q0;hP*q2; +#define FP_ReDefinePointers() q0=!g2.empty()?&g2[0]+g2 dO-1:0;q2=!hR dH.empty()?&hR dH[0]+hR dH dO-1:0; +qZ +w1(opcode); +#if(!FP_FLOAT_VERSION) +hP +x;hC +A;hP +y;hC +B;hC +C;hC +D;hQ +opcode){TailCall_cAbs:qM +d2 +qA +gC +oW(246,aW +aG,aG,);q5 +Lab;qB +oW(48,"x " +aG,"[fp_abs(x)]" +,w6);q5 +Lac;gY +qX +oW(307,w7 +aG,"A" +,aE(A)wA);g6 +qE +TailCall_cAdd:qM +h5 +o4 +qP +h5 +dP +oW(194,wJ +aX +wJ +wG,"[Value_t(4)]" +wE,);q5 +Lad;qF +gF:h1==cAdd){qN +hL +oW(195,wJ +wG +w5 +wJ +wG,w2" [Value_t(4)]" +wE,);q5 +Lae;} +gJ} +q5 +dI;h7 +gF:hH +qC +dP +oW(197,wJ"x" +w5 +wG,"[x+Value_t(1)]" +wE,w6);q5 +Laf;} +} +q5 +dI;h7 +gC +oW(253,aW +wG,"cSub" +,);q5 +Lag;qB +qP +h5 +h1 +qO +oW(187,mH +wG +wB +wG,"[y+x] " +wG,q11);q5 +Lah;qF +dN:gD +h5 +dW +oW(129,mH +aX +m5,aC +aX +wX,q11);q5 +Lai;oO +oW(130,aW +m5,mJ +aX +wX,w6);q5 +Laj;hY +oW(128,mH +m5,aC +wX,q11);q5 +Lak;qF +cSub:gP +hQ +mX){h7 +h5 +qN +4]qO +oW(123,mH +aX +wK,aC +aX +m6,q91(B)q21 +aF);q5 +Lal;oO +oW(124,aW +wK,mJ +aX +m6,q91(B)wA);q5 +Lam;hY +oW(122,mH +wK,aC +m6,q91(B)q21 +aF);q5 +Lan;} +qF +hZ +oW(84,mI +wG,"[y+x]" +,q11);q5 +Lao;hJ +qY +oW(83,w3 +wG,,w6);q5 +o0 +gJ +g7 +dI:;A +oE){hH==dN){h1 +qC +oW(121,"x " +wX" " +aM +wG,"[DO_STACKPLUS1] A " +mW +aX +wX,aE(A)q21 +wS +wA);oL +Laq;} +oW(126,wX" " +aM +wG,"[DO_STACKPLUS1] A " +aX +wX,aE(A)wA);oL +Lba;} +qE +TailCall_cAnd:qM +cAnd:o4 +oW(426,wJ"cAnd" +,a3,);q5 +Lbb;oG +oW(177,mI"cAnd" +,"[fp_and(x,y)]" +,q11);q5 +Lbc;gJ} +qK +TailCall_cCos:qM +cCos:A +oE +d3 +qP +cSec:mK(434,wO +mO +w4"cCos" +,wQ"cSec" +aL,aE(A)q51(B)wA);q5 +Lbd;qF +cSin:mK(428,wO"cSin " +w4"cCos" +,wQ"cSinCos" +,aE(A)q51(B)wA);q5 +Lbe;gJ +qE +TailCall_cCot:qM +cCot:A +oE +d3 +hH==o1){mK(432,wO +mP +w4"cCot" +,wQ"cTan" +aL,aE(A)q51(B)wA);q5 +Lbd;} +qE +TailCall_cCsc:qM +cCsc:A +oE +d3 +hH==cSin){mK(430,wO"cSin " +w4"cCsc" +,wQ"cSin" +aL,aE(A)q51(B)wA);q5 +Lbd;} +qE +TailCall_cDiv:qM +cDiv:o4 +oW(167,wJ +aY,"[Value_t(0)]" +w5"[Value_t(1)] " +wG,);q5 +Lbf;h7 +hX:oW(436,"cSinCos " +aY,"cTan" +,);q5 +Lbg;qB +dM!=qY +qP +gC +oW(185,aW +wL +aY,mJ +aY,w6);q5 +Lbh;hY +oW(81,mH +wL +aY,"[y/x]" +,q11);q5 +Lbi;} +dQ +oW(80,wC +aY,,w6);q5 +o0 +gJ} +qK +TailCall_cEqual:qM +dR:h9 +A +a7(335,"A[IsLogicalOpcode(A)] " +wC +wZ,"A" +,q31(A)wA);q5 +o0} +} +mL(175,mI +wZ,"[fp_equal(y,x)]" +,q11);q5 +Lbj;hJ +qY +qP +d2 +oW(265,aG" " +w3 +wZ,mW +wZ,w6);q5 +Lbk;h7 +hK:oW(267,m2 +w3 +wZ,mW +wZ,w6);q5 +Lbk;} +oW(325,w3 +wZ,"cNot" +,w6);q5 +Lbl;qE +TailCall_cGreater:qM +dX:hO==qY +qP +d2 +oW(327,aG" " +w3 +aR,a3,w6);q5 +Lbm;wV(331,w7 +w3 +aR,"A " +a3,q31(A)wA);q5 +Lbn;} +} +} +mL(173,mI +aR,"[fp_less(x,y)]" +,q11);q5 +Lbo;qE +TailCall_cGreaterOrEq:qM +dE:h9 +qP +d2 +oW(328,aG" " +wC +a0,a3,w6);q5 +Lbm;wV(332,w7 +wC +a0,"A " +a3,q31(A)wA);q5 +Lbn;} +} +} +mL(174,mI +a0,"[fp_lessOrEq(x,y)]" +,q11);q5 +Lbp;qE +TailCall_cInv:qM +cInv:qA +cSqrt:oW(75,m4" cInv" +,"cRSqrt" +,);q5 +Lbq;qB +dM!=qY +oW(77,wL"cInv" +,"[Value_t(1)/x]" +,w6);q5 +Lca;gJ} +qK +TailCall_cLess:qM +dS +hO==qY +A +a8(132,w7 +w3 +m3,aQ,q31(A)wA);q5 +Lcb;} +dQ +qP +d2 +oW(329,aG" " +wC +m3,"cNot" +,w6);q5 +Lcc;wV(333,w7 +wC +m3,"A" +aJ,q31(A)wA);q5 +Lbl;} +} +} +mL(171,mI +m3,"[fp_less(y,x)]" +,q11);q5 +Lcd;qE +TailCall_cLessOrEq:qM +d4:hO==qY +qP +d2 +oW(330,aG" " +w3 +aH,"cNot" +,w6);q5 +Lcc;wV(334,w7 +w3 +aH,"A" +aJ,q31(A)wA);q5 +Lbl;} +} +} +mL(172,mI +aH,"[fp_lessOrEq(y,x)]" +,q11);q5 +Lce;qE +TailCall_cMax:qM +cMax:o4 +oW(157,wJ +aZ,,);q5 +o5 +oG +oW(90,mI +aZ,"[fp_max(x,y)]" +,q11);q5 +Lcg;gJ +oC=q0 +gM +oW(159,wO +wJ +aM +aZ,wQ +mM,aE(A)q51(B)wA);q5 +o5 +qF +cMax:mK(161,wO +aZ" " +aM +aZ,wQ +aZ,aE(A)q51(B)wA);q5 +o5 +gJ} +qE +TailCall_cMin:qM +cMin:o4 +oW(156,wJ +m0,,);q5 +o5 +oG +oW(89,mI +m0,"[fp_min(x,y)]" +,q11);q5 +Lch;gJ +oC=q0 +gM +oW(158,wO +wJ +aM +m0,wQ +mM,aE(A)q51(B)wA);q5 +o5 +qF +cMin:mK(160,wO +m0" " +aM +m0,wQ +m0,aE(A)q51(B)wA);q5 +o5 +gJ} +qE +TailCall_cMod:qM +cMod:hO!=qY +mL(82,mH +wL"cMod" +,"[fp_mod(y,x)]" +,q11);q5 +Lci;} +qE +TailCall_cMul:qM +gF:o4 +oW(402,mM +wE,wT,);q5 +Lcj;h7 +gC +qP +h4 +oW(394,wJ +a9 +wE,m2 +a9,);q5 +Lck;oC=g8;qV){m7 +B=mX +aI(400,"B[B==A]" +wU" " +a9 +wE,wQ +wT +w5 +a9,aE(A)q51(B)wA);q5 +Lcl;} +} +} +} +q5 +dJ;h7 +o2:hH +qC +dP +oW(198,mM +wB +aT +wE,"[x+Value_t(1)]" +aA,w6);q5 +Lcm;} +} +q5 +dJ;qB +dM==qY +qP +gF:A=gE;qV +mF(141,aO +w5 +w3 +w2,wY +wE,q31(A)wA);q5 +Lcn;} +q5 +Default3;g7 +Default3:;A=g8 +oK +IsBinaryOpcode(A)g3 +A)){gD +hZ +oW(140,mH +oZ,wY +wE,q31(A)q21 +aF);q5 +Lco;g7 +gO +IsBinaryOpcode(B)g3 +B)){hQ +mX){hY +oW(144,mH +w8,aQ,q31(A)q51(B)q21 +aF);q5 +Lcp;g7 +C=mX +oK +C +h3 +mF(142,"C[C>=VarBegin] " +w8,aQ,q31(A)q51(B)q61(C)wA);q5 +Lcq;o6 +C)g3 +C)mF(143,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +w8,wQ +aQ,q31(A)q51(B)q61(C)wA);q5 +Lda;} +} +hV +oF +oW(138,q01 +oZ,wY +wE,q31(A)q51(B)wA);q5 +Lcn;o6 +B)g3 +B)mF(139,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +oZ,aQ,q31(A)q51(B)wA);q5 +Ldb;} +} +} +qV +mF(136,aM +w3 +w2,wY,q31(A)wA);q5 +Ldc;o6 +A)g3 +A)mF(137,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +w3 +w2,wY +wE,q31(A)wA);q5 +Ldd;} +} +} +qP +h5 +gD +h4 +oW(203,wJ +m8,"[x+x]" +wE,w6);q5 +Lde;h7 +gF:dW +A=g0 +4];qV +mF(292,aM"y" +w5 +m8,wY +w5"A " +aU +w5 +wG,wR", " +mH +mZ +y +q21 +w9(A)wA);q5 +Ldf;} +qF +hZ +oW(291,mH +m8,wY +w5 +aU" " +wG,q11);q5 +Ldg;qF +gF:gD +h5 +qN +hL +oW(205,wJ +wG +q71,w2" [x+x]" +wE,w6);q5 +Ldh;qF +hZ +if(y*mR(192,"y[y*x==Value_t(1)]" +q71,,q11);q5 +Ldi;} +oW(193,"y" +q71,aU +wE,q11);q5 +Ldj;oO +oW(182,a9 +wB +w2,"[-x]" +wE,w6);q5 +Ldk;h7 +cSub:m7 +dW +A=g0 +4];qV +mF(293,aM"y" +w5"cSub" +wB +w2,wY +w5"A " +aU +w5"cSub" +,wR", " +mH +mZ +y +q21 +w9(A)wA);oM} +} +qF +hZ +oW(79,mI +w2,aU,q11);q5 +Ldm;dQ +oW(78,wC +w2,,w6);q5 +o0 +gX +2)mF(146,"x[x==Value_t(2)]" +wE,wJ +wG,w6);q5 +Ldn;gX-1)mF(184,"x[x==Value_t(-1)]" +wE,a9,w6);q5 +Ldo;gJ +g7 +dJ:;A +oE){qP +gF:gD +gC +B=mX +aI(397,wO +a9 +wU +wE,wQ +wT +w5 +a9,aE(A)q51(B)wA);q5 +Lcl;} +q5 +Default4;g7 +Default4:;mK(388,"B[B==A]" +wU +wE,wQ +wT +wE,aE(A)q51(B)wA);q5 +Ldp;} +} +q5 +dK;h7 +gC +mK(391,wO +aW +aN,wQ +m2 +a9,aE(A)q51(B)wA);q5 +Lck;} +q5 +dK;g7 +dK:;B=g8 +aI(385,wO +aN,wQ +wT,aE(A)q51(B)wA);q5 +Lcj;} +} +o6 +A)){B=g8 +oK +B +h3 +qU +1){m7 +C=mX +oK +C==A){D=g0 +4]oK +D==B +mF(408,"D[D==B] C[C==A]" +w5"B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wE,"D C " +wT +wE,aE(A)q51(B)q61(C)<<", D " +oY(D)wA);q5 +Ldq;} +} +} +} +qE +TailCall_cNEqual:qM +dT:h9 +A +a7(336,"A[IsLogicalOpcode(A)] " +wC +wN,"A" +aJ,q31(A)wA);q5 +Lbl;} +} +mL(176,mI +wN,"[fp_nequal(y,x)]" +,q11);q5 +Lea;hJ +qY +qP +d2 +oW(266,aG" " +w3 +wN,mW +wN,w6);q5 +Leb;h7 +hK:oW(268,m2 +w3 +wN,mW +wN,w6);q5 +Leb;} +oW(326,w3 +wN,a3,w6);q5 +Lbn;qE +hD:qM +gC +qA +gF:m9(183,"x" +w5 +a9,"[-x]" +wE,w6);q5 +Lec;oO +oW(248,aW +a9,,);q5 +o5 +qB +oW(76,"x " +a9,"[-x]" +,w6);q5 +Led;} +qK +TailCall_cNot:qM +cNot:qA +d2 +oW(296,aG +aJ,"cNot" +,);q5 +Lee;h7 +cAbsNot:A +a7(303,"A[IsLogicalOpcode(A)] " +aK +aJ,"A" +,aE(A)wA);q5 +o5 +hV +A!=q7 +mF(304,"A[A!=cImmed] " +aK +aJ,"A cAbsNotNot" +,aE(A)wA);q5 +Lef;} +q5 +dL;h7 +cAbsNotNot:oW(299,"cAbsNotNot" +aJ,aK,);q5 +Leg;h7 +h5 +m9(338,"x " +wG +aJ,mJ +wZ,w6);q5 +Leh;} +q5 +dL;h7 +dR:oW(262,wZ +aJ,wN,);q5 +Lei;h7 +dX:oW(260,aR +aJ,aH,);q5 +Lej;h7 +dE:oW(261,a0 +aJ,m3,);q5 +Lek;h7 +dS +oW(258,m3 +aJ,a0,);q5 +Lel;h7 +d4:oW(259,aH +aJ,aR,);q5 +Lem;h7 +dT:oW(263,wN +aJ,wZ,);q5 +Len;h7 +gC +oW(295,a9 +aJ,"cNot" +,);q5 +Lee;h7 +cNot:oW(297,"cNot" +aJ,a3,);q5 +Lbb;h7 +dB:oW(298,a3 +aJ,"cNot" +,);q5 +Lee;qB +oW(93,"x" +aJ,"[fp_not(x)]" +,w6);q5 +Leo;g7 +dL:;A +h0 +qX +oW(305,w7"cNot" +,"A " +aK,aE(A)wA);q5 +Lep;qE +TailCall_cNotNot:qM +dB:qA +h5 +m9(337,"x " +aX +a3,mJ +wN,w6);q5 +Leq;qF +cNot:oW(300,"cNot " +a3,"cNot" +,);g6} +qK +TailCall_cOr:qM +cOr:o4 +oW(425,wJ"cOr" +,a3,);q5 +Lbb;oG +oW(178,mI"cOr" +,"[fp_or(x,y)]" +,q11);q5 +Lfa;gJ} +qK +TailCall_cRDiv:qM +dV +qA +hX:oW(437,"cSinCos cRDiv" +,"cCot" +,);q5 +Lfb;qB +dM +hI +oW(99,wC"cRDiv" +,"cInv" +,w6);q5 +Lfc;gJ} +qK +TailCall_cRSub:qM +dN:gZ]hM +oW(200,wJ +wX,"[Value_t(0)]" +wE,);q5 +Lfd;} +qK +TailCall_cSec:qM +cSec:A +oE +d3 +qP +cCos:mK(431,wO"cCos " +w4"cSec" +,wQ"cCos" +aL,aE(A)q51(B)wA);q5 +Lbd;qF +cSin:mK(429,wO"cSin " +w4"cSec" +,wQ"cSinCos cInv" +,aE(A)q51(B)wA);q5 +Lfe;gJ +qE +TailCall_cSin:qM +cSin:A +oE +d3 +hH==cCsc){mK(433,wO"cCsc " +w4"cSin" +,wQ"cCsc" +aL,aE(A)q51(B)wA);q5 +Lbd;} +qE +TailCall_cSqr:qM +hK:qA +d2 +oW(404,aG" " +wT,wT,);q5 +Lff;h7 +gC +oW(403,aW +wT,wT,);q5 +Lff;} +qK +TailCall_cSqrt:qM +cSqrt:gZ]==cAdd){hH==hK){A=gE;qV){qN +3]==hK +mF(439,m2 +aM +m2 +m1,"A cHypot" +,aE(A)wA);q5 +Lfg;} +} +gO +gH +B)){A=mX;qV){qN +4]==hK +mF(440,m2 +aM"B[IsUnaryOpcode(B)] " +m2 +m1,"A " +wQ"cHypot" +," with" +aD(B)q21 +w9(A)wA);q5 +Lfh;} +} +} +qE +hE:qM +cSub:o4 +oW(199,wJ"cSub" +,"[Value_t(0)]" +wE,);q5 +Lfd;h7 +gC +oW(254,aW"cSub" +,wG,);q5 +Lfi;qB +dM==qY +oW(85,w3"cSub" +,,w6);q5 +o0} +mL(86,mI"cSub" +,"[y-x]" +,q11);q5 +Lfj;} +oW(216,"x cSub" +,mJ +wG,w6);q5 +Lfk;oD){hH==dN){h1 +qC +oW(120,"x " +wX" " +aM"cSub" +,"A " +aX +mW +wX,aE(A)q21 +wS +wA);q5 +Lfl;} +oW(127,wX" " +aM"cSub" +,"[DO_STACKPLUS1] A cSub " +wX,aE(A)wA);oL +Lfm;} +qE +hF:qM +o1:A +oE +d3 +hH==cCot){mK(435,wO"cCot " +w4"cTan" +,wQ"cCot" +aL,aE(A)q51(B)wA);q5 +Lbd;} +qE +g7 +Default0:;A=opcode +oK +IsComparisonOpcode(A)){d7 +qP +h5 +h1 +qO +oW(270,mH +wG +wF,"[x-y] A" +,aE(A)q41);q5 +Lfn;oO +oW(271,a9 +wF,mJ"{OppositeComparisonOpcode(A)}" +,aE(A)q21 +wS +wA);q5 +Lfo;} +} +} +qV +qU +0){B +h0 +B==A +mF(406,wO"A[A>=VarBegin&&mData->mByteCode.size()>0]" +,wQ +mM,aE(A)q51(B)wA);q5 +Lfp;} +o6 +A)){B +h0 +B +h3 +qU +1){C=g8 +oK +C==A){D=oJ +D==B +mF(407,"D[D==B] C[C==A] B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C " +mM,aE(A)q51(B)q61(C)<<", D " +oY(D)wA);q5 +Lfq;} +} +} +} +} +q5 +Laa;Laa:qI +opcode +mV +Lab:q8 +w1(cAbs);q5 +TailCall_cAbs;Lac:gB +d8;g6 +Lad:o7 +4));gE=q7;hA +Lga:g1 +gF;Lgb:qZ +Lgc:w1(cMul);q5 +TailCall_cMul;Lae:q9 +hU +o7 +4));hN +Lga;Laf:gB +x+o9;gE=q7;hA +Lcb:g1 +gF;q5 +Lgc;Lag:a6 +cSub;Lgd:w1(cSub);q5 +hE;Lah:hG +o3 +Lge:qZ +Lgf:w1(cAdd);q5 +TailCall_cAdd;Lai:hG +3;qJ +Lgg:d5 +Lgh:g1 +dN;qZ +w1(cRSub);q5 +TailCall_cRSub;Laj:gA +gE=q7;q9 +o3 +q5 +Lgg;Lak:hG +o3 +q5 +Lgh;Lal:hG +4;qJ +Lgi:d5 +Lgj:qL +B);Lgk:g1 +cSub;qZ +q5 +Lgd;Lam:gA +mX=q7;q9 +3;qJ +q5 +Lgi;Lan:hG +3;qJ +q5 +Lgj;Lao:g5 +y+x;Lap:qT +Lcf:g2 +q6 +g6 +Laq:qS +3 +dU +oP +hN +Lgg;Lba:qQ +A +gU +Lgg;Lbb:a6 +dB;Lgl:w1(cNotNot);q5 +TailCall_cNotNot;Lbc:g5 +fp_and(x +gT +Lbd:q0 +d6 +g1 +cInv;Lgm:w1(cInv);q5 +TailCall_cInv;Lbe:qQ +hX +mV +Lbf:o7 +0));q0[0]=q7;qL +d1 +o7 +1));Lgn:qI +q7);Lgo:g1 +cAdd;q5 +Lge;Lbg:a6 +o1;w1(cTan);q5 +hF;Lbh:gA +mT +q8 +w1(cDiv);q5 +TailCall_cDiv;Lbi:g5 +y/x;q5 +o0 +Lbj:g5 +fp_equal(y +h8 +Lbk:mT +q8 +Lgp:w1(cEqual);q5 +TailCall_cEqual;Lbl:qT +g2 +q6 +Lgq:g1 +cNot;qZ +Lha:w1(cNot);q5 +TailCall_cNot;Lbm:qS +o3 +Lhb:g1 +dB;qZ +q5 +Lgl;Lbn:qT +qW +Lhb;Lbo:g5 +fp_less(x +gT +Lbp:g5 +fp_lessOrEq(x +gT +Lbq:qG +cRSqrt +mV +Lca:gB +o9/x;g6 +Lcc:qS +o3 +q5 +Lgq;Lcd:g5 +fp_less(y +h8 +Lce:g5 +fp_lessOrEq(y +h8 +Lcg:g5 +fp_max(x +gT +Lch:g5 +fp_min(x +gT +Lci:g5 +fp_mod(y +h8 +Lcj:a6 +hK;Lhc:w1(cSqr);q5 +TailCall_cSqr;Lck:qQ +hK);Lhd:g1 +cNeg;qZ +w1(cNeg);q5 +hD;Lcl:q9 +3 +qR +hK);qL +gF +gU +Lhd;Lcm:gB +x+o9;gE=q7;qQ +o2 +mV +Lcn:gE=q7;hA +q5 +Lgc;Lco:g5 +x;Lhe:qS +o3 +q5 +Lgb;Lcp:hB +qT +Lhf:q9 +4;qJ +Lhg:qL +A);oP +Lhh:hN +Lgb;Lcq:qT +q5 +Lhf;Lda:qS +4 +qR +B +gU +Lhg;Ldb:qS +3;qJ +q5 +Lhg;Ldc:mT +q5 +o5 +Ldd:mT +q8 +q5 +Lgc;Lde:gB +x+x;q5 +Lcn;Ldf:g5 +x;g0 +4]=q7;qS +hU +qL +A);oQ);qI +q7);qL +gF +gU +Lgo;Ldg:g5 +x;qT +qQ +d1 +oQ +gU +Lgn;Ldh:qS +hU +qH +x+x +gU +Lhh;Ldi:dY;qJ +g6 +Ldj:g5 +y*x;q5 +Lhe;Ldk:gA +q5 +Ldd;Ldl:g5 +x;g0 +4]=q7;qS +hU +qL +A);oQ);qI +q7);qL +gF +gU +Lgk;Ldm:g5 +y*x;q5 +o0 +Ldn:q0 +d6 +q2-=1;qT +Lhi:g1 +cAdd;q5 +Lgf;Ldo:qT +qW +Lhd;Ldp:q9 +o3 +Lhj:qL +hK +gU +Lgb;Ldq:q9 +3;qJ +q5 +Lhj;Lea:g5 +fp_nequal(y +h8 +Leb:mT +q8 +Lhk:w1(cNEqual);q5 +TailCall_cNEqual;Lec:gA +q8 +q5 +Lcb;Led:gA +g6 +Lee:q8 +q5 +Lha;Lef:qG +cAbsNotNot +mV +Leg:g2 +q6 +Lep:qL +cAbsNot +mV +Leh:gA +Len:a6 +dR;q5 +Lgp;Lei:a6 +dT;q5 +Lhk;Lej:a6 +d4;w1(cLessOrEq);q5 +TailCall_cLessOrEq;Lek:a6 +cLess;w1(cLess);q5 +TailCall_cLess;Lel:a6 +dE;w1(cGreaterOrEq);q5 +TailCall_cGreaterOrEq;Lem:a6 +dX;w1(cGreater);q5 +TailCall_cGreater;Leo:gB +fp_not +mG +Leq:gA +q5 +Lei;Lfa:g5 +fp_or(x +gT +Lfb:a6 +cCot;w1(cCot);q5 +TailCall_cCot;Lfc:qT +g2 +q6 +Lhl:g1 +cInv;qZ +q5 +Lgm;Lfd:o7 +0));q0[0]=q7;q5 +Lga;Lfe:qQ +hX +gU +Lhl;Lff:q8 +q5 +Lhc;Lfg:q9 +4 +dU +Lhm:qL +cHypot +mV +Lfh:q9 +5 +dU +qL +B +gU +Lhm;Lfi:q8 +q5 +Lhi;Lfj:g5 +y-x;q5 +o0 +Lfk:gA +q5 +Lhi;Lfl:qS +3 +dU +d5 +oP +hN +Lgh;Lfm:qQ +A);qL +cSub +gU +Lgh;Lfn:g5 +x-y;qT +qQ +A +mV +Lfo:gA +mT +qG +OppositeComparisonOpcode(A)mV +Lfp:qI +cDup +mV +Lfq:q0 +d6 +g6 +g6 +q5 +TailCall_cAnd;q5 +TailCall_cCos;q5 +TailCall_cCsc;q5 +TailCall_cMax;q5 +TailCall_cMin;q5 +TailCall_cMod;q5 +hD;q5 +TailCall_cOr;q5 +TailCall_cRDiv;q5 +TailCall_cSec;q5 +TailCall_cSin;q5 +TailCall_cSqrt;q5 +hE;q5 +hF; +#endif +#if(FP_FLOAT_VERSION) +hP +x;hC +A;hP +y;hC +B;hC +C;hC +D;hQ +opcode){TailCall_cAbs:qM +d2 +qA +gC +oW(246,aW +aG,aG,);q5 +Lab;qB +oW(48,"x " +aG,"[fp_abs(x)]" +,w6);q5 +Lac;gY +qX +oW(307,w7 +aG,"A" +,aE(A)wA);g6 +qE +TailCall_cAcos:qM +cAcos:hO>=oA<=o9 +mF(52,"x[x>=Value_t(-1)&&x<=Value_t(1)] cAcos" +,"[fp_acos(x)]" +,w6);q5 +Lad;qE +TailCall_cAcosh:qM +cAcosh:hO>=o9 +mF(49,"x[x>=Value_t(1)] cAcosh" +,"[fp_acosh(x)]" +,w6);q5 +Lae;qE +TailCall_cAdd:qM +h5 +o4 +qP +h5 +dP +oW(194,wJ +aX +wJ +wG,"[Value_t(4)]" +wE,);q5 +Laf;qF +gF:h1==cAdd){qN +hL +oW(195,wJ +wG +w5 +wJ +wG,w2" [Value_t(4)]" +wE,);q5 +Lag;} +gJ} +q5 +dI;h7 +gF:hH +qC +dP +oW(197,wJ"x" +w5 +wG,"[x+Value_t(1)]" +wE,w6);q5 +Lah;} +} +q5 +dI;h7 +gC +oW(253,aW +wG,"cSub" +,);q5 +Lai;qB +qP +h5 +h1 +qO +oW(187,mH +wG +wB +wG,"[y+x] " +wG,q11);q5 +Laj;qF +dN:gD +h5 +dW +oW(129,mH +aX +m5,aC +aX +wX,q11);q5 +Lak;oO +oW(130,aW +m5,mJ +aX +wX,w6);q5 +Lal;hY +oW(128,mH +m5,aC +wX,q11);q5 +Lam;qF +cSub:gP +hQ +mX){h7 +h5 +qN +4]qO +oW(123,mH +aX +wK,aC +aX +m6,q91(B)q21 +aF);q5 +Lan;oO +oW(124,aW +wK,mJ +aX +m6,q91(B)wA);q5 +Lao;hY +oW(122,mH +wK,aC +m6,q91(B)q21 +aF);q5 +o0} +qF +hZ +oW(84,mI +wG,"[y+x]" +,q11);q5 +Laq;hJ +qY +oW(83,w3 +wG,,w6);q5 +Lba;gJ +g7 +dI:;A +oE){hH==dN){h1 +qC +oW(121,"x " +wX" " +aM +wG,"[DO_STACKPLUS1] A " +mW +aX +wX,aE(A)q21 +wS +wA);oL +Lbb;} +oW(126,wX" " +aM +wG,"[DO_STACKPLUS1] A " +aX +wX,aE(A)wA);oL +Lbc;} +qE +TailCall_cAnd:qM +cAnd:o4 +oW(426,wJ"cAnd" +,a3,);q5 +Lbd;oG +oW(177,mI"cAnd" +,"[fp_and(x,y)]" +,q11);q5 +Lbe;gJ} +qK +TailCall_cAsin:qM +cAsin:hO>=oA<=o9 +mF(53,"x[x>=Value_t(-1)&&x<=Value_t(1)] cAsin" +,"[fp_asin(x)]" +,w6);q5 +Lbf;qE +TailCall_cAsinh:qM +cAsinh:d7 +oW(50,"x cAsinh" +,"[fp_asinh(x)]" +,w6);q5 +Lbg;} +qK +TailCall_cAtan:qM +cAtan:d7 +oW(54,"x cAtan" +,"[fp_atan(x)]" +,w6);q5 +Lbh;} +qK +TailCall_cAtan2:qM +cAtan2:d7 +mL(91,mI"cAtan2" +,"[fp_atan2(y,x)]" +,q11);q5 +Lbi;qE +TailCall_cAtanh:qM +cAtanh:hO>oAValue_t(-1)&&x()]" +q81,"cDeg" +,q11);q5 +Lcq;hV(y/x)==gW +oW(208,"y[(y/x)==fp_const_deg_to_rad()]" +q81,"cRad" +,q11);q5 +Lda;} +oW(209,"y" +q81,"[y/x]" +wE,q11);q5 +Ldb;oO +oW(185,aW +wL +aY,mJ +aY,w6);q5 +Ldc;hY +oW(81,mH +wL +aY,"[y/x]" +,q11);q5 +Ldd;} +oW(211,wL +aY,"[Value_t(1)/x]" +wE,w6);q5 +Lde;gJ +oD){qP +cDiv:gP +oW(102,q01 +aY" " +wP,"[DO_STACKPLUS1] " +wQ"A" +w5 +aY,aE(A)q51(B)wA);oL +Ldf;qF +dV +hQ +gE){qB +oW(97,"x cRDiv " +wP,"A" +w5 +mW"cRDiv" +,aE(A)q21 +wS +wA);q5 +Ldg;g7 +gP +oW(96,"B[B>=VarBegin] cRDiv " +wP,"A" +w5 +wQ"cRDiv" +,aE(A)q51(B)wA);q5 +Ldh;} +gJ} +qE +TailCall_cEqual:qM +dR:hO==qY +qP +d2 +oW(265,aG" " +w3 +wZ,mW +wZ,w6);q5 +Ldi;h7 +hK:oW(267,m2 +w3 +wZ,mW +wZ,w6);q5 +Ldi;} +} +mL(175,mI +wZ,"[fp_equal(y,x)]" +,q11);q5 +Ldj;qE +TailCall_cExp:qM +cExp:qA +h5 +m9(318,"x " +aX +mA,aV"[fp_exp(x)]" +wE,w6);q5 +Ldk;qF +cLog:A +a8(231,w7 +aS" " +mA,"A" +,aE(A)wA);oN +qB +oW(59,"x " +mA,"[fp_exp(x)]" +,w6);q5 +Ldm;} +qK +TailCall_cExp2:qM +dC:qA +h5 +m9(319,"x " +aX +a1,a1" [fp_exp2(x)]" +wE,w6);q5 +Ldn;qF +cLog2:A +a8(232,w7 +a2" " +a1,"A" +,aE(A)wA);oN +qB +oW(60,"x " +a1,"[fp_exp2(x)]" +,w6);q5 +Ldo;} +oW(410,a1,"[DO_STACKPLUS1] [fp_log(Value_t(2))]" +w5 +mA,);oL +Ldp;TailCall_cFloor:qM +cFloor:qA +gC +oW(315,aW +mB,mN" " +a9,);q5 +Ldq;qB +oW(61,"x " +mB,"[fp_floor(x)]" +,w6);q5 +Lea;gY +gG +oW(309,"A[IsAlwaysIntegerOpcode(A)] " +mB,"A" +,aE(A)wA);g6 +qE +TailCall_cGreater:qM +dX:d7 +mL(173,mI +aR,"[fp_less(x,y)]" +,q11);q5 +Leb;gX-hW +oW(345,"x[x==Value_t(-0.5)] " +aR,aW +aK,w6);q5 +Lec;qE +TailCall_cGreaterOrEq:qM +dE:hO!=qY +hH==oS +oW(341,aG" " +wL +a0,"[Value_t(0.5)/x]" +w5 +a3,w6);q5 +Led;} +} +mL(174,mI +a0,"[fp_lessOrEq(x,y)]" +,q11);q5 +Lee;gX +hW +oW(344,"x[x==Value_t(0.5)] " +a0,"cAbsNotNot" +,w6);q5 +Lef;qE +TailCall_cInt:qM +cInt:qA +q7:x=q2[0];oW(62,"x cInt" +,"[fp_int(x)]" +,w6);q5 +Leg;gY +gG +oW(311,"A[IsAlwaysIntegerOpcode(A)] cInt" +,"A" +,aE(A)wA);g6 +qE +TailCall_cInv:qM +cInv:qA +cCos:oW(374,"cCos cInv" +,"cSec" +,);q5 +Leh;h7 +cCot:oW(378,"cCot cInv" +,"cTan" +,);q5 +Lco;h7 +cCsc:oW(376,"cCsc cInv" +,"cSin" +,);q5 +Lei;h7 +mQ(247,"cInv cInv" +,,);oM +h7 +o2:oW(249,aT" cInv" +,a9 +aA,);q5 +Lej;h7 +cSec:oW(377,mO"cInv" +,"cCos" +,);q5 +Lek;h7 +cSin:oW(373,"cSin cInv" +,"cCsc" +,);q5 +Lel;h7 +cSqrt:oW(75,m4" cInv" +,"cRSqrt" +,);q5 +Lem;h7 +o1:oW(375,mP"cInv" +,"cCot" +,);q5 +Len;qB +dM!=qY +oW(77,wL"cInv" +,"[Value_t(1)/x]" +,w6);q5 +Leo;gJ} +qK +TailCall_cLess:qM +dS +hO==qY +A +a8(132,w7 +w3 +m3,aQ,q31(A)wA);q5 +Lep;} +hV +x!=qY +hH==oS +oW(340,aG" " +wL +m3,"[Value_t(0.5)/x]" +w5"cNot" +,w6);q5 +Leq;} +} +mL(171,mI +m3,"[fp_less(y,x)]" +,q11);q5 +Lfa;gX +hW +oW(343,"x[x==Value_t(0.5)] " +m3,aK,w6);q5 +Lfb;qE +TailCall_cLessOrEq:qM +d4:d7 +mL(172,mI +aH,"[fp_lessOrEq(y,x)]" +,q11);q5 +Lfc;gX-hW +oW(346,"x[x==Value_t(-0.5)] " +aH,aW"cAbsNotNot" +,w6);q5 +Lfd;qE +TailCall_cLog:qM +cLog:qA +cExp:oW(234,aV +aS,,);oM +gR +oW(422,wH +w5 +aS,aS" [fp_log(x)] " +wG,w6);q5 +Lfe;} +mC(149,m2 +aS,aG" " +aS" " +wJ +wG,);q5 +Lff;qB +mE(63,wH" " +aS,"[fp_log(x)]" +,w6);q5 +Lfg;gJ} +qK +TailCall_cLog10:qM +oV:qA +cExp:oW(412,aV +a4,"[DO_STACKPLUS1] [fp_log10(fp_const_e())]" +wE,);oL +Lfh;gR +oW(423,wH +w5 +a4,a4" [fp_log10(x)] " +wG,w6);q5 +Lfi;} +mC(151,m2 +a4,aG" " +a4" " +wJ +wG,);q5 +Lfj;qB +mE(64,wH" " +a4,"[fp_log10(x)]" +,w6);q5 +Lfk;gJ} +qK +TailCall_cLog2:qM +cLog2:qA +cExp:oW(411,aV +a2,"[DO_STACKPLUS1] [fp_log2(fp_const_e())]" +wE,);oL +Lfl;h7 +dC:oW(235,a1" " +a2,,);oM +gR +oW(421,wH +w5 +a2,a2" [fp_log2(x)] " +wG,w6);q5 +Lfm;} +mC(150,m2 +a2,aG" " +a2" " +wJ +wG,);q5 +Lfn;qB +mE(65,wH" " +a2,"[fp_log2(x)]" +,w6);q5 +Lfo;gJ} +qK +TailCall_cMax:qM +cMax:o4 +oW(157,wJ +aZ,,);oM +oG +oW(90,mI +aZ,"[fp_max(x,y)]" +,q11);q5 +Lfp;gJ +oC=q0 +gM +oW(159,wO +wJ +aM +aZ,wQ +mM,aE(A)q51(B)wA);oM +qF +cMax:mK(161,wO +aZ" " +aM +aZ,wQ +aZ,aE(A)q51(B)wA);oN} +qE +TailCall_cMin:qM +cMin:o4 +oW(156,wJ +m0,,);oM +oG +oW(89,mI +m0,"[fp_min(x,y)]" +,q11);q5 +Lfq;gJ +oC=q0 +gM +oW(158,wO +wJ +aM +m0,wQ +mM,aE(A)q51(B)wA);oM +qF +cMin:mK(160,wO +m0" " +aM +m0,wQ +m0,aE(A)q51(B)wA);oN} +qE +TailCall_cMod:qM +cMod:hO!=qY +mL(82,mH +wL"cMod" +,"[fp_mod(y,x)]" +,q11);q5 +Lga;} +qE +TailCall_cMul:qM +gF:o4 +oW(402,mM +wE,wT,);q5 +Lgb;h7 +mQ(252,"cInv" +wE,aY,);q5 +Lgc;h7 +gC +qP +h4 +oW(394,wJ +a9 +wE,m2 +a9,);q5 +Lgd;oC=g8;qV){m7 +B=mX +aI(400,"B[B==A]" +wU" " +a9 +wE,wQ +wT +w5 +a9,aE(A)q51(B)wA);q5 +Lge;} +} +} +} +q5 +dJ;h7 +o2:hH +qC +dP +oW(198,mM +wB +aT +wE,"[x+Value_t(1)]" +aA,w6);q5 +Lgf;} +} +q5 +dJ;qB +dM==qY +qP +gF:A=gE;qV +mF(141,aO +w5 +w3 +w2,wY +wE,q31(A)wA);q5 +Lgg;} +q5 +Default3;g7 +Default3:;A=g8 +oK +IsBinaryOpcode(A)g3 +A)){gD +hZ +oW(140,mH +oZ,wY +wE,q31(A)q21 +aF);q5 +Lgh;g7 +gO +IsBinaryOpcode(B)g3 +B)){hQ +mX){hY +oW(144,mH +w8,aQ,q31(A)q51(B)q21 +aF);q5 +Lgi;g7 +C=mX +oK +C +h3 +mF(142,"C[C>=VarBegin] " +w8,aQ,q31(A)q51(B)q61(C)wA);q5 +Lgj;o6 +C)g3 +C)mF(143,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +w8,wQ +aQ,q31(A)q51(B)q61(C)wA);q5 +Lgk;} +} +hV +oF +oW(138,q01 +oZ,wY +wE,q31(A)q51(B)wA);q5 +Lgg;o6 +B)g3 +B)mF(139,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +oZ,aQ,q31(A)q51(B)wA);q5 +Lgl;} +} +} +qV +mF(136,aM +w3 +w2,wY,q31(A)wA);q5 +Lgm;o6 +A)g3 +A)mF(137,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +w3 +w2,wY +wE,q31(A)wA);q5 +Lgn;} +} +} +qP +h5 +gD +h4 +dM+mR(202,"cDup[x+x==Value_t(1)] " +m8,,w6);q5 +Lgo;} +oW(203,wJ +m8,"[x+x]" +wE,w6);q5 +Lgp;h7 +gF:dW +A=g0 +4];qV +mF(292,aM"y" +w5 +m8,wY +w5"A " +aU +w5 +wG,wR", " +mH +mZ +y +q21 +w9(A)wA);q5 +Lgq;} +qF +hZ +oW(291,mH +m8,wY +w5 +aU" " +wG,q11);q5 +Lha;qF +cDeg:oW(152,"cDeg" +wB +w2,"[RadiansToDegrees(x)]" +wE,w6);q5 +Lhb;h7 +cDiv:gP +hQ +mX){h7 +gF:qN +4]qO +oW(109,"y" +w5 +q01 +aY +wB +w2,aU +w5 +wQ +aY,q91(B)q21 +aF);q5 +Lhc;oO +oW(110,aW +q01 +aY +wB +w2,a5 +wQ +aY,q91(B)wA);q5 +Lhd;hY +oW(108,mH +q01 +aY +wB +w2,aU" " +wQ +aY,q91(B)q21 +aF);q5 +Lhe;} +qF +gF:gD +h5 +qN +hL +dM+mR(204,"cDup[x+x==Value_t(1)] " +wG +q71,w2,w6);q5 +Lhf;} +oW(205,wJ +wG +q71,w2" [x+x]" +wE,w6);q5 +Lhg;qF +hZ +if((y*x)==gV +oW(189,"y[(y*x)==fp_const_rad_to_deg()]" +q71,"cDeg" +,q11);q5 +Lcq;hV(y*x)==gW +oW(190,"y[(y*x)==fp_const_deg_to_rad()]" +q71,"cRad" +,q11);q5 +Lda;hV +y*mR(192,"y[y*x==Value_t(1)]" +q71,,q11);q5 +Lhh;} +oW(193,"y" +q71,aU +wE,q11);q5 +Lhi;oO +oW(182,a9 +wB +w2,"[-x]" +wE,w6);q5 +Lhj;h7 +dV +gD +gF:dW +oW(116,"y" +w5 +aB,aU +w5"cRDiv" +,q11);q5 +Lhk;oO +oW(117,aW +aB,a5"cRDiv" +,w6);q5 +Lhl;hY +oW(115,mH +aB,aU" cRDiv" +,q11);q5 +Lhm;qF +cRad:oW(153,"cRad" +wB +w2,"[DegreesToRadians(x)]" +wE,w6);q5 +Lhn;h7 +cSub:m7 +dW +A=g0 +4];qV +mF(293,aM"y" +w5"cSub" +wB +w2,wY +w5"A " +aU +w5"cSub" +,wR", " +mH +mZ +y +q21 +w9(A)wA);q5 +Lho;} +} +qF +hZ +oW(79,mI +w2,aU,q11);q5 +Lhp;dQ +oW(78,wC +w2,,w6);q5 +Lba;gX +2)mF(146,"x[x==Value_t(2)]" +wE,wJ +wG,w6);q5 +Lhq;hJ +gV +oW(147,"x[x==fp_const_rad_to_deg()]" +wE,"cDeg" +,w6);q5 +Lia;hJ +gW +oW(148,"x[x==fp_const_deg_to_rad()]" +wE,"cRad" +,w6);q5 +Lib;gX-1)mF(184,"x[x==Value_t(-1)]" +wE,a9,w6);q5 +Lic;gJ +g7 +dJ:;A +oE){qP +cDiv:gP +oW(105,q01 +aY" " +aN,"[DO_STACKPLUS1] A" +w5 +wQ +aY,aE(A)q51(B)wA);oL +Lid;} +q5 +hT +gF:gD +gC +B=mX +aI(397,wO +a9 +wU +wE,wQ +wT +w5 +a9,aE(A)q51(B)wA);q5 +Lge;} +q5 +dK;g7 +dK:;mK(388,"B[B==A]" +wU +wE,wQ +wT +wE,aE(A)q51(B)wA);q5 +Lie;} +} +q5 +hT +gC +mK(391,wO +aW +aN,wQ +m2 +a9,aE(A)q51(B)wA);q5 +Lgd;} +q5 +hT +dV +h1 +qC +oW(98,"x cRDiv " +aN,"[DO_STACKPLUS1] A " +wY +w5"cRDiv" +,aE(A)q21 +wS +wA);oL +Lif;} +oW(112,"cRDiv " +aN,"[DO_STACKPLUS1] A" +w5"cRDiv" +,aE(A)wA);oL +Lig;g7 +Default4:;B=g8 +aI(385,wO +aN,wQ +wT,aE(A)q51(B)wA);q5 +Lgb;} +} +o6 +A)){B=g8 +oK +B +h3 +qU +1){m7 +C=mX +oK +C==A){D=g0 +4]oK +D==B +mF(408,"D[D==B] C[C==A]" +w5"B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wE,"D C " +wT +wE,aE(A)q51(B)q61(C)<<", D " +oY(D)wA);q5 +Lih;} +} +} +} +qE +TailCall_cNEqual:qM +dT:hO==qY +qP +d2 +oW(266,aG" " +w3 +wN,mW +wN,w6);q5 +Lii;h7 +hK:oW(268,m2 +w3 +wN,mW +wN,w6);q5 +Lii;} +} +mL(176,mI +wN,"[fp_nequal(y,x)]" +,q11);q5 +Lij;qE +hD:qM +gC +qA +gF:m9(183,"x" +w5 +a9,"[-x]" +wE,w6);q5 +Lik;oO +oW(248,aW +a9,,);oM +h7 +cSin:hH +wW(359,"x" +w5"cSin " +a9,a5"cSin" +,w6);q5 +Lil;} +qF +oT +hH +wW(360,"x" +w5"cSinh " +a9,a5"cSinh" +,w6);q5 +Lim;} +qF +o1:hH +wW(361,"x" +w5 +mP +a9,a5"cTan" +,w6);q5 +Lin;} +qF +oU +hH +wW(362,"x" +w5"cTanh " +a9,a5"cTanh" +,w6);q5 +Lio;} +gJ +qB +oW(76,"x " +a9,"[-x]" +,w6);q5 +Lip;} +qK +TailCall_cNot:qM +cNot:qA +d2 +oW(296,aG +aJ,"cNot" +,);q5 +Liq;h7 +cAbsNot:A +a7(303,"A[IsLogicalOpcode(A)] " +aK +aJ,"A" +,aE(A)wA);oM +hV +A!=q7 +mF(304,"A[A!=cImmed] " +aK +aJ,"A cAbsNotNot" +,aE(A)wA);q5 +Lja;} +q5 +dL;h7 +cAbsNotNot:oW(299,"cAbsNotNot" +aJ,aK,);q5 +Ljb;h7 +dR:oW(262,wZ +aJ,wN,);q5 +Ljc;h7 +dX:oW(260,aR +aJ,aH,);q5 +Ljd;h7 +dE:oW(261,a0 +aJ,m3,);q5 +Lje;h7 +dS +oW(258,m3 +aJ,a0,);q5 +Ljf;h7 +d4:oW(259,aH +aJ,aR,);q5 +Ljg;h7 +dT:oW(263,wN +aJ,wZ,);q5 +Ljh;h7 +gC +oW(295,a9 +aJ,"cNot" +,);q5 +Liq;h7 +cNot:oW(297,"cNot" +aJ,a3,);q5 +Lbd;h7 +dB:oW(298,a3 +aJ,"cNot" +,);q5 +Liq;qB +oW(93,"x" +aJ,"[fp_not(x)]" +,w6);q5 +Lji;g7 +dL:;A +h0 +qX +oW(305,w7"cNot" +,"A " +aK,aE(A)wA);q5 +Ljj;qE +TailCall_cNotNot:qM +dB:gZ]==cNot +mF(300,"cNot " +a3,"cNot" +,);g6} +qK +TailCall_cOr:qM +cOr:o4 +oW(425,wJ"cOr" +,a3,);q5 +Lbd;oG +oW(178,mI"cOr" +,"[fp_or(x,y)]" +,q11);q5 +Ljk;gJ} +qK +TailCall_cPow:qM +o2:d7 +if(!h2 +x+x)){hH==hK +mF(22,m2"x[!isEvenInteger(x+x)]" +aA,aG" [x+x]" +aA,w6);q5 +Ljl;} +hV +isInteger(x)){qP +cExp:oW(43,aV +wI,wY +w5 +mA,w6);q5 +Ljm;h7 +dC:oW(44,a1" " +wI,wY +w5 +a1,w6);q5 +Ljn;h7 +o2:h1 +oI!isInteger(y)mF(42,"y[!isInteger(y)]" +aA" " +wI,aU +aA,q11);q5 +Ljo;} +} +oW(45,aT" " +wI,wY +w5 +aT,w6);q5 +Ljp;} +hV +h2 +x)){qP +d2 +oW(348,aG" x[isEvenInteger(x)]" +aA,wY +aA,w6);q5 +Ljq;h7 +gF:h1==oS +oW(349,aG +w5"x[isEvenInteger(x)]" +aA,w2" " +wY +aA,w6);q5 +Lka;gJ} +hJ +qY +oW(169,w3 +aT,"[Value_t(0)]" +w5"[Value_t(1)] " +wG,w6);q5 +Lkb;gX +hW +oW(223,"x[x==Value_t(0.5)]" +aA,m4,w6);q5 +Lkc;gX +1)/qD +3)mF(224,"x[x==Value_t(1)/Value_t(3)]" +aA,"cCbrt" +,w6);q5 +Lkd;gX +1)/qD-3)mF(225,"x[x==Value_t(1)/Value_t(-3)]" +aA,"cCbrt cInv" +,w6);q5 +Lke;gX-hW +oW(226,"x[x==Value_t(-0.5)]" +aA,"cRSqrt" +,w6);q5 +Lkf;gX-1)mF(227,"x[x==Value_t(-1)]" +aA,"cInv" +,w6);q5 +Lkg;} +qP +o2:h1 +oI +h2 +y)&&!h2 +x*y)mF(21,"y[isEvenInteger(y)&&!isEvenInteger(x*y)]" +aA +wB +aT,aG" " +aU +aA,q11);q5 +Lkh;} +oW(221,"y" +aA +wB +aT,aU +aA,q11);q5 +Ljo;mC(46,wT +wB +aT,"[x+x]" +aA,w6);q5 +Lki;hY +if(y!=qD +0)||x>=qY +oW(92,"y[y!=Value_t(0)||x>=Value_t(0)]" +wB +aT,"[fp_pow(y,x)]" +,q11);q5 +Lkj;gJ} +oW(382,"x" +aA,"[DO_POWI]" +,w6)oK +TryCompilePowi(x))g6} +qK +TailCall_cRDiv:qM +dV +qA +hX:oW(437,"cSinCos cRDiv" +,"cCot" +,);q5 +Len;qB +dM +hI +oW(99,wC"cRDiv" +,"cInv" +,w6);q5 +Lkg;gJ} +qK +TailCall_cRSub:qM +dN:gZ]hM +oW(200,wJ +wX,"[Value_t(0)]" +wE,);q5 +Lkk;} +qK +TailCall_cRad:qM +cRad:qA +gF:m9(154,"x" +w5"cRad" +,"[DegreesToRadians(x)]" +wE,w6);q5 +Lkl;gJ +qB +oW(74,"x cRad" +,"[DegreesToRadians(x)]" +,w6);q5 +Lkm;} +qK +TailCall_cSec:qM +cSec:A +oE +d3 +qP +cCos:mK(431,wO"cCos " +w4"cSec" +,wQ"cCos" +aL,aE(A)q51(B)wA);q5 +Lbp;qF +cSin:mK(429,wO"cSin " +w4"cSec" +,wQ"cSinCos cInv" +,aE(A)q51(B)wA);q5 +Lkn;gJ +qE +TailCall_cSin:qM +cSin:qA +gC +oW(355,aW"cSin" +,"cSin " +a9,);q5 +Lko;qB +oW(66,"x cSin" +,"[fp_sin(x)]" +,w6);q5 +Lkp;oD +d3 +hH==cCsc){mK(433,wO"cCsc " +w4"cSin" +,wQ"cCsc" +aL,aE(A)q51(B)wA);q5 +Lbp;} +} +qE +TailCall_cSinh:qM +oT +qA +cAcosh:oW(364,"cAcosh cSinh" +,"[DO_STACKPLUS1] " +m2"[Value_t(-1)] " +m1,);oL +Lkq;h7 +cAsinh:oW(240,"cAsinh cSinh" +,,);oM +h7 +gC +oW(356,aW"cSinh" +,"cSinh " +a9,);q5 +Lla;qB +oW(67,"x cSinh" +,"[fp_sinh(x)]" +,w6);q5 +Llb;} +qK +TailCall_cSqr:qM +hK:qA +d2 +oW(404,aG" " +wT,wT,);q5 +Llc;h7 +gC +oW(403,aW +wT,wT,);q5 +Llc;h7 +cSqrt:A +a8(229,w7 +m4" " +wT,"A" +,aE(A)wA);oN} +qK +TailCall_cSqrt:qM +cSqrt:qA +h5 +hH==hK){A=gE;qV){qN +3]==hK +mF(439,m2 +aM +m2 +m1,"A cHypot" +,aE(A)wA);q5 +Lld;} +} +gO +gH +B)){A=mX;qV){qN +4]==hK +mF(440,m2 +aM"B[IsUnaryOpcode(B)] " +m2 +m1,"A " +wQ"cHypot" +," with" +aD(B)q21 +w9(A)wA);q5 +Lle;} +} +} +mC(23,m2 +m4,aG,);q5 +Llf;qB +dM>=qY +oW(68,"x[x>=Value_t(0)] " +m4,"[fp_sqrt(x)]" +,w6);q5 +Llg;gJ} +qK +hE:qM +cSub:o4 +oW(199,wJ"cSub" +,"[Value_t(0)]" +wE,);q5 +Lkk;h7 +gC +oW(254,aW"cSub" +,wG,);q5 +Llh;qB +dM==qY +oW(85,w3"cSub" +,,w6);q5 +Lba;} +mL(86,mI"cSub" +,"[y-x]" +,q11);q5 +Lli;} +oW(216,"x cSub" +,mJ +wG,w6);q5 +Llj;oD){hH==dN){h1 +qC +oW(120,"x " +wX" " +aM"cSub" +,"A " +aX +mW +wX,aE(A)q21 +wS +wA);q5 +Llk;} +oW(127,wX" " +aM"cSub" +,"[DO_STACKPLUS1] A cSub " +wX,aE(A)wA);oL +Lll;} +qE +hF:qM +o1:qA +cAtan2:oW(245,"cAtan2 cTan" +,aY,);q5 +Lgc;h7 +gC +oW(357,aW"cTan" +,mP +a9,);q5 +Llm;qB +oW(70,"x cTan" +,"[fp_tan(x)]" +,w6);q5 +Lln;oD +d3 +hH==cCot){mK(435,wO"cCot " +w4"cTan" +,wQ"cCot" +aL,aE(A)q51(B)wA);q5 +Lbp;} +} +qE +TailCall_cTanh:qM +oU +qA +gC +oW(358,aW"cTanh" +,"cTanh " +a9,);q5 +Llo;qB +oW(71,"x cTanh" +,"[fp_tanh(x)]" +,w6);q5 +Llp;} +qK +TailCall_cTrunc:qM +cTrunc:qA +q7:x=q2[0];oW(72,"x cTrunc" +,"[fp_trunc(x)]" +,w6);q5 +Llq;gY +gG +oW(308,"A[IsAlwaysIntegerOpcode(A)] cTrunc" +,"A" +,aE(A)wA);g6 +qE +g7 +Default0:;A=opcode +oK +IsComparisonOpcode(A)){d7 +qP +h5 +h1 +qO +oW(270,mH +wG +wF,"[x-y] A" +,aE(A)q41);q5 +Lma;qF +cAtan:if(d8()*qD +hW +oW(286,"cAtan[fp_abs(x)()*Value_t(0.5)]" +wF,"[fp_tan(x)] A" +,aE(A)q21 +wS +wA);q5 +Lmb;qF +cExp:mE(276,"cExp[x>Value_t(0)]" +wF,"[fp_log(x)] A" +,aE(A)q21 +wS +wA);q5 +Lmc;qF +dC:mE(277,"cExp2[x>Value_t(0)]" +wF,"[fp_log2(x)] A" +,aE(A)q21 +wS +wA);q5 +Lmd;qF +cLog:gO +g9 +oW(279,wD +aS +wF,wQ"[fp_exp(x)] A" +,aE(A)q21 +wS +q51(B)wA);q5 +Lme;qF +oV:gO +g9 +oW(281,wD +a4 +wF,wQ"[fp_pow(Value_t(10),x)] A" +,aE(A)q21 +wS +q51(B)wA);q5 +Lmf;qF +cLog2:gO +g9 +oW(280,wD +a2 +wF,wQ"[fp_exp2(x)] A" +,aE(A)q21 +wS +q51(B)wA);q5 +Lmg;qF +gF:h1 +oI +y>qY +oW(272,"y[y>Value_t(0)]" +w5"x A[IsComparisonOpcode(A)]" +,"[x/y] A" +,aE(A)q41);q5 +Lmh;hV +yqY +h1 +oI +y>qY +oW(274,"y[y>Value_t(0)] cPow[x>Value_t(0)]" +wF,"[fp_pow(x,1/y)] A" +,aE(A)q41);q5 +Lmk;} +} +qF +oT +oW(287,"cSinh" +wF,"[fp_asinh(x)] A" +,aE(A)q21 +wS +wA);q5 +Lml;h7 +hK:mE(275,"cSqr[x>Value_t(0)]" +wF,aG" [fp_sqrt(x)] A" +,aE(A)q21 +wS +wA);q5 +Lmm;qF +oU +if(d8=VarBegin&&mData->mByteCode.size()>0]" +,wQ +mM,aE(A)q51(B)wA);q5 +Lmo;} +o6 +A)){B +h0 +B +h3 +qU +1){C=g8 +oK +C==A){D=oJ +D==B +mF(407,"D[D==B] C[C==A] B[B>=VarBegin&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C " +mM,aE(A)q51(B)q61(C)<<", D " +oY(D)wA);q5 +Lmp;} +} +} +} +} +q5 +Laa;Laa:qI +opcode +mV +Lab:q8 +Lmq:w1(cAbs);q5 +TailCall_cAbs;Lac:gB +d8;g6 +Lad:gB +fp_acos +mG +Lae:gB +fp_acosh +mG +Laf:o7 +4));gE=q7;hA +Lna:g1 +gF;Lnb:qZ +Lnc:w1(cMul);q5 +TailCall_cMul;Lag:q9 +hU +o7 +4));Lnd:hN +Lna;Lah:gB +x+o9;gE=q7;hA +Lep:g1 +gF;q5 +Lnc;Lai:a6 +cSub;Lne:w1(cSub);q5 +hE;Laj:hG +o3 +Lnf:qZ +Lng:w1(cAdd);q5 +TailCall_cAdd;Lak:hG +3;qJ +Lnh:d5 +Lni:g1 +dN;qZ +w1(cRSub);q5 +TailCall_cRSub;Lal:gA +gE=q7;q9 +o3 +q5 +Lnh;Lam:hG +o3 +q5 +Lni;Lan:hG +4;qJ +Lnj:d5 +Lnk:qL +B);Lnl:g1 +cSub;qZ +q5 +Lne;Lao:gA +mX=q7;q9 +3;qJ +q5 +Lnj;Lap:hG +3;qJ +q5 +Lnk;Laq:g5 +y+x;Lba:qT +Ldl:g2 +q6 +g6 +Lbb:qS +3 +dU +oP +hN +Lnh;Lbc:qQ +A +gU +Lnh;Lbd:a6 +dB;Lnm:w1(cNotNot);q5 +TailCall_cNotNot;Lbe:g5 +fp_and(x +h6 +Lbf:gB +fp_asin +mG +Lbg:gB +fp_asinh +mG +Lbh:gB +fp_atan +mG +Lbi:g5 +fp_atan2 +mY +Lbj:gB +fp_atanh +mG +Lbk:gB +fp_cbrt +mG +Lbl:qG +cFloor);Lnn:g1 +cNeg;qZ +w1(cNeg);q5 +hD;Lbm:gB +fp_ceil +mG +Lbn:q8 +Lno:w1(cCos);q5 +TailCall_cCos;Lbo:gB +fp_cos +mG +Lbp:q0 +d6 +g1 +cInv;Lnp:w1(cInv);q5 +TailCall_cInv;Lbq:qQ +hX +mV +Lca:q8 +w1(cCosh);q5 +TailCall_cCosh;Lcb:qG +hK);o7 +1));Lnq:qI +q7);d5 +Loa:g1 +cSqrt;qZ +w1(cSqrt);q5 +TailCall_cSqrt;Lcc:gB +fp_cosh +mG +Lcd:gB +RadiansToDegrees +mG +Lce:qG +cSec +gU +Lna;Lcf:qG +o1 +gU +Lna;Lcg:qG +cSin +gU +Lna;Lch:o7 +0));q0[0]=q7;Lob:qL +d1 +o7 +1));Loc:qI +q7);Lod:g1 +cAdd;q5 +Lnf;Lci:qG +cNeg);qL +cExp +gU +Lna;Lcj:qG +cNeg);qL +dC +gU +Lna;Lck:q8 +q5 +Lep;Lcl:qG +cNeg);qL +o2 +gU +Lna;Lcm:qG +cCos +gU +Lna;Lcn:qG +cCsc +gU +Lna;Lco:a6 +o1;Loe:w1(cTan);q5 +hF;Lcp:qG +cCot +gU +Lna;Lcq:dY;qJ +Lof:g1 +cDeg;qZ +w1(cDeg);q5 +TailCall_cDeg;Lda:dY;qJ +Log:g1 +cRad;qZ +w1(cRad);q5 +TailCall_cRad;Ldb:g5 +y/x;qS +o3 +q5 +Lna;Ldc:gA +mT +q8 +Loh:w1(cDiv);q5 +TailCall_cDiv;Ldd:g5 +y/x;q5 +Lba;Lde:gB +o9/x;q5 +Lep;Ldf:qQ +A);qL +d1 +Loi:qZ +q5 +Loh;Ldg:qS +3 +dU +qL +d1 +oP +qI +q7);Loj:g1 +cRDiv;qZ +w1(cRDiv);q5 +TailCall_cRDiv;Ldh:q9 +3 +dU +qL +d1 +qL +B +gU +Loj;Ldi:mT +q8 +Lok:w1(cEqual);q5 +TailCall_cEqual;Ldj:g5 +fp_equal +mY +Ldk:qT +qQ +cExp);qH +fp_exp(x)gU +Lnd;Ldm:gB +fp_exp +mG +Ldn:qT +qQ +dC);qH +fp_exp2(x)gU +Lnd;Ldo:gB +fp_exp2 +mG +Ldp:qH +dG +qD +2)));qI +q7);Lol:qL +d1 +g1 +cExp;qZ +w1(cExp);q5 +TailCall_cExp;Ldq:qG +cCeil +mS +Lea:gB +fp_floor +mG +Leb:g5 +fp_less(x +h6 +Lec:qT +qG +cNeg);Ljj:qL +cAbsNot +mV +Led:gB +qD +0.5)/x;mD +dB;qZ +q5 +Lnm;Lee:g5 +fp_lessOrEq(x +h6 +Lef:qT +Lja:g2 +q6 +Lom:qL +cAbsNotNot +mV +Leg:gB +fp_int +mG +Leh:a6 +cSec;w1(cSec);q5 +TailCall_cSec;Lei:a6 +cSin;Lon:w1(cSin);q5 +TailCall_cSin;Lej:qG +cNeg);g1 +o2;Loo:qZ +Lop:w1(cPow);q5 +TailCall_cPow;Lek:a6 +cCos;q5 +Lno;Lel:a6 +cCsc;w1(cCsc);q5 +TailCall_cCsc;Lem:qG +cRSqrt +mV +Len:a6 +cCot;w1(cCot);q5 +TailCall_cCot;Leo:gB +o9/x;g6 +Leq:gB +qD +0.5)/x;mD +cNot;qZ +Loq:w1(cNot);q5 +TailCall_cNot;Lfa:g5 +fp_less +mY +Lfb:qT +Ljb:qW +Ljj;Lfc:g5 +fp_lessOrEq +mY +Lfd:qT +qG +cNeg +gU +Lom;Lfe:qT +qQ +cLog);qH +dG +x)gU +Loc;Lff:qG +d9 +qL +cLog);Lpa:qI +cDup +gU +Lod;Lfg:gB +dG +x +mV +Lfh:qH +dA +fp_const_e()));Lpb:q0[0]=q7;q5 +Lna;Lfi:qT +qQ +oV);qH +dA +x)gU +Loc;Lfj:qG +d9 +qL +oV +gU +Lpa;Lfk:gB +dA +x +mV +Lfl:qH +d0 +fp_const_e())gU +Lpb;Lfm:qT +qQ +cLog2);qH +d0 +x)gU +Loc;Lfn:qG +d9 +qL +cLog2 +gU +Lpa;Lfo:gB +d0 +x +mV +Lfp:g5 +fp_max(x +h6 +Lfq:g5 +fp_min(x +h6 +Lga:g5 +fp_mod +mY +Lgb:a6 +hK;Lpc:w1(cSqr);q5 +TailCall_cSqr;Lgc:a6 +cDiv;q5 +Loh;Lgd:qQ +hK +mS +Lge:q9 +3 +qR +hK);qL +gF +mS +Lgf:gB +x+o9;gE=q7;hA +g1 +o2;q5 +Lop;Lgg:gE=q7;hA +q5 +Lnc;Lgh:g5 +x;Lpd:qS +o3 +q5 +Lnb;Lgi:hB +qT +Lpe:q9 +4;qJ +Lpf:qL +A);oP +Lpg:hN +Lnb;Lgj:qT +q5 +Lpe;Lgk:qS +4 +qR +B +gU +Lpf;Lgl:qS +3;qJ +q5 +Lpf;Lgm:mT +oM +Lgn:mT +q8 +q5 +Lnc;Lgo:qT +Lph:q9 +3;qJ +g6 +Lgp:gB +x+x;q5 +Lgg;Lgq:g5 +x;g0 +4]=q7;qS +hU +qL +A);oQ);qI +q7);qL +gF +gU +Lod;Lha:g5 +x;qT +qQ +d1 +oQ +gU +Loc;Lhb:gB +RadiansToDegrees(x +gU +Lgn;Lhc:g5 +y +oR +4;qJ +Lpi:qL +d1 +Lpj:qL +B);g1 +cDiv;q5 +Loi;Lhd:gA +mX=q7;q9 +3;qJ +q5 +Lpi;Lhe:g5 +y +oR +3;qJ +q5 +Lpj;Lhf:qS +4;qJ +q5 +Lnb;Lhg:qS +hU +qH +x+x +gU +Lpg;Lhh:hB +qT +q5 +Lph;Lhi:g5 +y*x;q5 +Lpd;Lhj:gA +q5 +Lgn;Lhk:g5 +y +oR +3;qJ +Lpk:qL +gF +gU +Loj;Lhl:gA +gE=q7;q9 +o3 +q5 +Lpk;Lhm:g5 +y +oR +o3 +q5 +Loj;Lhn:gB +gL +q5 +Lgn;Lho:g5 +x;g0 +4]=q7;qS +hU +qL +A);oQ);qI +q7);qL +gF +gU +Lnl;Lhp:g5 +y*x;q5 +Lba;Lhq:q0 +d6 +q2-=1;qT +Lpl:g1 +cAdd;q5 +Lng;Lia:qT +qW +Lof;Lib:qT +qW +Log;Lic:qT +qW +Lnn;Lid:q9 +3 +qR +A +gU +Lpi;Lie:q9 +o3 +Lpm:qL +hK +gU +Lnb;Lif:qS +3 +dU +oP +hN +Lpk;Lig:qQ +A +gU +Lpk;Lih:q9 +3;qJ +q5 +Lpm;Lii:mT +q8 +Lpn:w1(cNEqual);q5 +TailCall_cNEqual;Lij:g5 +fp_nequal +mY +Lik:gA +q5 +Lck;Lil:gA +o8 +cSin;qZ +q5 +Lon;Lim:gA +o8 +cSinh;qZ +w1(cSinh);q5 +TailCall_cSinh;Lin:gA +o8 +o1;qZ +q5 +Loe;Lio:gA +o8 +cTanh;qZ +w1(cTanh);q5 +TailCall_cTanh;Lip:gA +g6 +Liq:q8 +q5 +Loq;Ljc:a6 +dT;q5 +Lpn;Ljd:a6 +d4;w1(cLessOrEq);q5 +TailCall_cLessOrEq;Lje:a6 +cLess;w1(cLess);q5 +TailCall_cLess;Ljf:a6 +dE;w1(cGreaterOrEq);q5 +TailCall_cGreaterOrEq;Ljg:a6 +dX;w1(cGreater);q5 +TailCall_cGreater;Ljh:a6 +dR;q5 +Lok;Lji:gB +fp_not +mG +Ljk:g5 +fp_or(x +h6 +Ljl:qT +qQ +d9 +qH +x+x);Lpo:hN +Loo;Ljm:mT +qW +Lol;Ljn:mD +dC;qZ +w1(cExp2);q5 +TailCall_cExp2;Ljo:g5 +y +oR +o3 +q5 +Loo;Ljp:mT +qG +gF +gU +Loo;Ljq:mT +q8 +q5 +Lop;Lka:qS +3 +qR +d1 +qH +x +gU +Lpo;Lkb:gB +qD +0 +gU +Lob;Lkc:qT +qW +Loa;Lkd:qT +g2 +q6 +g1 +cCbrt;qZ +w1(cCbrt);q5 +TailCall_cCbrt;Lke:qT +qG +cCbrt);Lpp:g1 +cInv;qZ +q5 +Lnp;Lkf:qT +q5 +Lem;Lkg:qT +qW +Lpp;Lkh:dY +qR +d9 +oQ +gU +Lpo;Lki:gB +x+x;q5 +Ljq;Lkj:g5 +dZ +y +dF +Lkk:o7 +0)gU +Lpb;Lkl:gB +gL +q5 +Lck;Lkm:gB +gL +g6 +Lkn:qQ +hX +gU +Lpp;Lko:qG +cSin +mS +Lkp:gB +fp_sin +mG +Lkq:qG +hK);o7-1)gU +Lnq;Lla:qG +cSinh +mS +Llb:gB +fp_sinh +mG +Llc:q8 +q5 +Lpc;Lld:q9 +4 +dU +Lpq:qL +cHypot +mV +Lle:q9 +5 +dU +qL +B +gU +Lpq;Llf:a6 +cAbs;q5 +Lmq;Llg:gB +fp_sqrt +mG +Llh:q8 +q5 +Lpl;Lli:g5 +y-x;q5 +Lba;Llj:gA +q5 +Lpl;Llk:qS +3 +dU +d5 +oP +hN +Lni;Lll:qQ +A);qL +cSub +gU +Lni;Llm:qG +o1 +mS +Lln:gB +fp_tan +mG +Llo:qG +cTanh +mS +Llp:gB +fp_tanh +mG +Llq:gB +fp_trunc +mG +Lma:g5 +x-y;Lqa:qS +o3 +Lqb:qL +A +mV +Lmb:gB +fp_tan(x);Lqc:mT +qW +Lqb;Lmc:gB +dG +x +mU;Lmd:gB +d0 +x +mU;Lme:gB +fp_exp(x +mU;Lmf:gB +dZ +qD +10)dD +Lqc;Lmg:gB +fp_exp2(x +mU;Lmh:g5 +x/y;q5 +Lqa;Lmi:g5 +x/y;qS +o3 +Lqd:qL +OppositeComparisonOpcode(A)mV +Lmj:gA +mT +qW +Lqd;Lmk:g5 +dZ +x,1/y +gU +Lqa;Lml:gB +fp_asinh(x +mU;Lmm:qT +qQ +d9 +qH +fp_sqrt(x));hN +Lqb;Lmn:gB +fp_atanh(x +mU;Lmo:qI +cDup +mV +Lmp:q0 +d6 +g6 +g6 +q5 +TailCall_cAcos;q5 +TailCall_cAcosh;q5 +TailCall_cAnd;q5 +TailCall_cAsin;q5 +TailCall_cAsinh;q5 +TailCall_cAtan;q5 +TailCall_cAtan2;q5 +TailCall_cAtanh;q5 +TailCall_cCeil;q5 +TailCall_cFloor;q5 +TailCall_cInt;q5 +TailCall_cLog;q5 +TailCall_cLog10;q5 +TailCall_cLog2;q5 +TailCall_cMax;q5 +TailCall_cMin;q5 +TailCall_cMod;q5 +TailCall_cOr;q5 +TailCall_cRDiv;q5 +TailCall_cRad;q5 +TailCall_cSec;q5 +TailCall_cSin;q5 +TailCall_cSinh;q5 +TailCall_cSqrt;q5 +hE;q5 +hF;q5 +TailCall_cTanh;q5 +TailCall_cTrunc; +#endif +#undef FP_ReDefinePointers +#undef FP_TRACE_BYTECODE_OPTIMIZATION +#undef FP_TRACE_OPCODENAME diff --git a/fparser/fparser.cc b/fparser/fparser.cc new file mode 100644 index 0000000..49e6ae0 --- /dev/null +++ b/fparser/fparser.cc @@ -0,0 +1,3482 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#include "fpconfig.hh" +#include "fparser.hh" + +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include "fptypes.hh" +using namespace FUNCTIONPARSERTYPES; + +#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA +#ifndef FP_USE_THREAD_SAFE_EVAL +#define FP_USE_THREAD_SAFE_EVAL +#endif +#endif + +#ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif + + +//========================================================================= +// Opcode analysis functions +//========================================================================= +// These functions are used by the Parse() bytecode optimizer (mostly from +// code in fp_opcode_add.inc). + +bool FUNCTIONPARSERTYPES::IsLogicalOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsComparisonOpcode(unsigned op) +{ + switch(op) + { + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; + } + return false; +} + +unsigned FUNCTIONPARSERTYPES::OppositeComparisonOpcode(unsigned op) +{ + switch(op) + { + case cLess: return cGreater; + case cGreater: return cLess; + case cLessOrEq: return cGreaterOrEq; + case cGreaterOrEq: return cLessOrEq; + } + return op; +} + +bool FUNCTIONPARSERTYPES::IsNeverNegativeValueOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + case cSqrt: case cRSqrt: case cSqr: + case cHypot: + case cAbs: + case cAcos: case cCosh: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsAlwaysIntegerOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + case cInt: case cFloor: case cCeil: case cTrunc: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsUnaryOpcode(unsigned op) +{ + switch(op) + { + case cInv: case cNeg: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cSqr: case cRSqrt: + case cDeg: case cRad: + return true; + } + return (op < FUNC_AMOUNT && Functions[op].params == 1); +} + +bool FUNCTIONPARSERTYPES::IsBinaryOpcode(unsigned op) +{ + switch(op) + { + case cAdd: case cSub: case cRSub: + case cMul: case cDiv: case cRDiv: + case cMod: + case cEqual: case cNEqual: case cLess: + case cLessOrEq: case cGreater: case cGreaterOrEq: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + return true; + } + return (op < FUNC_AMOUNT && Functions[op].params == 2); +} + +bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op) +{ +#ifndef FP_NO_EVALUATION_CHECKS + // Returns true, if the given opcode has a range of + // input values that gives an error. + switch(op) + { + case cAcos: // allowed range: |x| <= 1 + case cAsin: // allowed range: |x| <= 1 + case cAcosh: // allowed range: x >= 1 + case cAtanh: // allowed range: |x| < 1 + //case cCot: // note: no range, just separate values + //case cCsc: // note: no range, just separate values + case cLog: // allowed range: x > 0 + case cLog2: // allowed range: x > 0 + case cLog10: // allowed range: x > 0 +#ifdef FP_SUPPORT_OPTIMIZER + case cLog2by: // allowed range: x > 0 +#endif + //case cPow: // note: no range, just separate values + //case cSec: // note: no range, just separate values + case cSqrt: // allowed range: x >= 0 + case cRSqrt: // allowed range: x > 0 + //case cDiv: // note: no range, just separate values + //case cRDiv: // note: no range, just separate values + //case cInv: // note: no range, just separate values + return true; + } +#endif + return false; +} + + +//========================================================================= +// Mathematical template functions +//========================================================================= +/* fp_pow() is a wrapper for std::pow() + * that produces an identical value for + * exp(1) ^ 2.0 (0x4000000000000000) + * as exp(2.0) (0x4000000000000000) + * - std::pow() on x86_64 + * produces 2.0 (0x3FFFFFFFFFFFFFFF) instead! + * See comments below for other special traits. + */ +namespace +{ + template + inline ValueT fp_pow_with_exp_log(const ValueT& x, const ValueT& y) + { + // Exponentiation using exp(log(x)*y). + // See http://en.wikipedia.org/wiki/Exponentiation#Real_powers + // Requirements: x > 0. + return fp_exp(fp_log(x) * y); + } + + template + inline ValueT fp_powi(ValueT x, unsigned long y) + { + // Fast binary exponentiation algorithm + // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring + // Requirements: y is non-negative integer. + ValueT result(1); + while(y != 0) + { + if(y & 1) { result *= x; y -= 1; } + else { x *= x; y /= 2; } + } + return result; + } +} + +template +ValueT FUNCTIONPARSERTYPES::fp_pow(const ValueT& x, const ValueT& y) +{ + if(x == ValueT(1)) return ValueT(1); + // y is now zero or positive + if(isLongInteger(y)) + { + // Use fast binary exponentiation algorithm + if(y >= ValueT(0)) + return fp_powi(x, makeLongInteger(y)); + else + return ValueT(1) / fp_powi(x, -makeLongInteger(y)); + } + if(y >= ValueT(0)) + { + // y is now positive. Calculate using exp(log(x)*y). + if(x > ValueT(0)) return fp_pow_with_exp_log(x, y); + if(x == ValueT(0)) return ValueT(0); + // At this point, y > 0.0 and x is known to be < 0.0, + // because positive and zero cases are already handled. + if(!isInteger(y*ValueT(16))) + return -fp_pow_with_exp_log(-x, y); + // ^This is not technically correct, but it allows + // functions such as cbrt(x^5), that is, x^(5/3), + // to be evaluated when x is negative. + // It is too complicated (and slow) to test whether y + // is a formed from a ratio of an integer to an odd integer. + // (And due to floating point inaccuracy, pointless too.) + // For example, x^1.30769230769... is + // actually x^(17/13), i.e. (x^17) ^ (1/13). + // (-5)^(17/13) gives us now -8.204227562330453. + // To see whether the result is right, we can test the given + // root: (-8.204227562330453)^13 gives us the value of (-5)^17, + // which proves that the expression was correct. + // + // The y*16 check prevents e.g. (-4)^(3/2) from being calculated, + // as it would confuse functioninfo when pow() returns no error + // but sqrt() does when the formula is converted into sqrt(x)*x. + // + // The errors in this approach are: + // (-2)^sqrt(2) should produce NaN + // or actually sqrt(2)I + 2^sqrt(2), + // produces -(2^sqrt(2)) instead. + // (Impact: Neglible) + // Thus, at worst, we're changing a NaN (or complex) + // result into a negative real number result. + } + else + { + // y is negative. Utilize the x^y = 1/(x^-y) identity. + if(x > ValueT(0)) return fp_pow_with_exp_log(ValueT(1) / x, -y); + if(x < ValueT(0)) + { + if(!isInteger(y*ValueT(-16))) + return -fp_pow_with_exp_log(ValueT(-1) / x, -y); + // ^ See comment above. + } + // Remaining case: 0.0 ^ negative number + } + // This is reached when: + // x=0, and y<0 + // x<0, and y*16 is either positive or negative integer + // It is used for producing error values and as a safe fallback. + return fp_pow_base(x, y); +} + + +//========================================================================= +// Elementary (atom) parsing functions +//========================================================================= +namespace +{ + /* Reads an UTF8-encoded sequence which forms a valid identifier name from + the given input string and returns its length. If bit 31 is set, the + return value also contains the internal function opcode (defined in + fptypes.hh) that matches the name. + */ + unsigned readIdentifierForFloatType(const char* input) + { + /* Assuming unsigned = 32 bits: + 76543210 76543210 76543210 76543210 + Return value if built-in function: + 1PPPPPPP PPPPPPPP LLLLLLLL LLLLLLLL + P = function opcode (15 bits) + L = function name length (16 bits) + Return value if not built-in function: + 0LLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL + L = identifier length (31 bits) + If unsigned has more than 32 bits, the other + higher order bits are to be assumed zero. + */ +#include "fp_identifier_parser.inc" + return 0; + } + + inline unsigned readIdentifierForIntType(const char* input) + { + const unsigned value = readIdentifierForFloatType(input); + if((value & 0x80000000U) != 0 && + !Functions[(value >> 16) & 0x7FFF].okForInt()) + return value & 0xFFFF; + return value; + } + + template + inline unsigned readIdentifier(const char* input) + { + return IsIntType::result + ? readIdentifierForIntType(input) + : readIdentifierForFloatType(input); + } + + // Returns true if the entire string is a valid identifier + template + bool containsOnlyValidIdentifierChars(const std::string& name) + { + if(name.empty()) return false; + return readIdentifier(name.c_str()) == (unsigned) name.size(); + } + + + // ----------------------------------------------------------------------- + // Wrappers for strto... functions + // ----------------------------------------------------------------------- + template + inline Value_t fp_parseLiteral(const char* str, char** endptr) + { + return strtod(str, endptr); + } + +#ifdef FP_SUPPORT_FLOAT_TYPE + template<> + inline float fp_parseLiteral(const char* str, char** endptr) + { + return strtof(str, endptr); + } +#endif + +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + template<> + inline long double fp_parseLiteral(const char* str, + char** endptr) + { + return strtold(str, endptr); + } +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline long fp_parseLiteral(const char* str, char** endptr) + { + return strtol(str, endptr, 10); + } +#endif + + + // ----------------------------------------------------------------------- + // Hexadecimal floating point literal parsing + // ----------------------------------------------------------------------- + inline int testXdigit(unsigned c) + { + if((c-'0') < 10u) return c&15; // 0..9 + if(((c|0x20)-'a') < 6u) return 9+(c&15); // A..F or a..f + return -1; // Not a hex digit + } + + template + inline void addXdigit(elem_t* buffer, unsigned nibble) + { + for(unsigned p=0; p> (elem_t)(limb_bits-4) ); + buffer[p] = (buffer[p] << 4) | nibble; + nibble = carry; + } + } + + 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) + { + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit (mantissa_buffer, xdigit); + ++str; + + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) + { + // Exhausted the precision. Parse the rest (until exponent) + // normally but ignore the actual digits. + for(; testXdigit(*str) >= 0; ++str) + exponent += 4; + // Read but ignore decimals + if(*str == '.') + for(++str; testXdigit(*str) >= 0; ++str) + {} + goto read_exponent; + } + } + // Read decimals + if(*str == '.') + for(++str; ; ) + { + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit (mantissa_buffer, xdigit); + ++str; + + exponent -= 4; + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) + { + // Exhausted the precision. Skip the rest + // of the decimals, until the exponent. + while(testXdigit(*str) >= 0) + ++str; + break; + } + } + + // Read exponent + read_exponent: + if(*str == 'p' || *str == 'P') + { + const char* str2 = str+1; + long p_exponent = strtol(str2, (char**) &str2, 10); + if(str2 != str+1 && p_exponent == (long)(int)p_exponent) + { + exponent += (int)p_exponent; + str = str2; + } + } + + if(endptr) *endptr = (char*) str; + + Value_t result = ldexp(Value_t(mantissa_buffer[0]), exponent); + for(unsigned p=1; p + long parseHexLiteral(const char* str, char** endptr) + { + return strtol(str, endptr, 16); + } +#endif +} + +//========================================================================= +// Utility functions +//========================================================================= +namespace +{ + // ----------------------------------------------------------------------- + // Add a new identifier to the specified identifier map + // ----------------------------------------------------------------------- + // Return value will be false if the name already existed + template + bool addNewNameData(NamePtrsMap& namePtrs, + std::pair >& newName, + bool isVar) + { + typename NamePtrsMap::iterator nameIter = + namePtrs.lower_bound(newName.first); + + if(nameIter != namePtrs.end() && newName.first == nameIter->first) + { + // redefining a var is not allowed. + if(isVar) return false; + + // redefining other tokens is allowed, if the type stays the same. + if(nameIter->second.type != newName.second.type) + return false; + + // update the data + nameIter->second = newName.second; + return true; + } + + if(!isVar) + { + // Allocate a copy of the name (pointer stored in the map key) + // However, for VARIABLEs, the pointer points to VariableString, + // which is managed separately. Thusly, only done when !IsVar. + char* namebuf = new char[newName.first.nameLength]; + memcpy(namebuf, newName.first.name, newName.first.nameLength); + newName.first.name = namebuf; + } + + namePtrs.insert(nameIter, newName); + return true; + } +} + + +//========================================================================= +// Data struct implementation +//========================================================================= +template +FunctionParserBase::Data::Data(): + mReferenceCounter(1), + mVariablesAmount(0), + mStackSize(0) +{} + +template +FunctionParserBase::Data::Data(const Data& rhs): + mReferenceCounter(0), + mVariablesAmount(rhs.mVariablesAmount), + mVariablesString(rhs.mVariablesString), + mNamePtrs(), + mFuncPtrs(rhs.mFuncPtrs), + mFuncParsers(rhs.mFuncParsers), + mByteCode(rhs.mByteCode), + mImmed(rhs.mImmed), +#ifndef FP_USE_THREAD_SAFE_EVAL + mStack(rhs.mStackSize), +#endif + mStackSize(rhs.mStackSize) +{ + for(typename NamePtrsMap::const_iterator i = rhs.mNamePtrs.begin(); + i != rhs.mNamePtrs.end(); + ++i) + { + if(i->second.type == NameData::VARIABLE) + { + const 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); + } + else + { + 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); + } + } +} + +template +FunctionParserBase::Data::~Data() +{ + for(typename NamePtrsMap::iterator i = mNamePtrs.begin(); + i != mNamePtrs.end(); + ++i) + { + if(i->second.type != NameData::VARIABLE) + delete[] i->first.name; + } +} + + +//========================================================================= +// FunctionParser constructors, destructor and assignment +//========================================================================= +template +FunctionParserBase::FunctionParserBase(): + mDelimiterChar(0), + mParseErrorType(NO_FUNCTION_PARSED_YET), mEvalErrorType(0), + mData(new Data), + mUseDegreeConversion(false), + mEvalRecursionLevel(0), + mStackPtr(0), mErrorLocation(0) +{ +} + +template +FunctionParserBase::~FunctionParserBase() +{ + if(--(mData->mReferenceCounter) == 0) + delete mData; +} + +template +FunctionParserBase::FunctionParserBase(const FunctionParserBase& cpy): + mDelimiterChar(cpy.mDelimiterChar), + mParseErrorType(cpy.mParseErrorType), + mEvalErrorType(cpy.mEvalErrorType), + mData(cpy.mData), + mUseDegreeConversion(cpy.mUseDegreeConversion), + mEvalRecursionLevel(0), + mStackPtr(0), mErrorLocation(0) +{ + ++(mData->mReferenceCounter); +} + +template +FunctionParserBase& +FunctionParserBase::operator=(const FunctionParserBase& cpy) +{ + if(mData != cpy.mData) + { + if(--(mData->mReferenceCounter) == 0) delete mData; + + mDelimiterChar = cpy.mDelimiterChar; + mParseErrorType = cpy.mParseErrorType; + mEvalErrorType = cpy.mEvalErrorType; + mData = cpy.mData; + mUseDegreeConversion = cpy.mUseDegreeConversion; + mEvalRecursionLevel = cpy.mEvalRecursionLevel; + + ++(mData->mReferenceCounter); + } + + return *this; +} + + +template +void FunctionParserBase::setDelimiterChar(char c) +{ + mDelimiterChar = c; +} + + +//--------------------------------------------------------------------------- +// Copy-on-write method +//--------------------------------------------------------------------------- +template +void FunctionParserBase::CopyOnWrite() +{ + if(mData->mReferenceCounter > 1) + { + Data* oldData = mData; + mData = new Data(*oldData); + --(oldData->mReferenceCounter); + mData->mReferenceCounter = 1; + } +} + +template +void FunctionParserBase::ForceDeepCopy() +{ + CopyOnWrite(); +} + + +//========================================================================= +// User-defined identifier addition functions +//========================================================================= +template +bool FunctionParserBase::AddConstant(const std::string& name, + Value_t value) +{ + if(!containsOnlyValidIdentifierChars(name)) return false; + + CopyOnWrite(); + std::pair > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData(NameData::CONSTANT, value)); + + return addNewNameData(mData->mNamePtrs, newName, false); +} + +template +bool FunctionParserBase::AddUnit(const std::string& name, + Value_t value) +{ + if(!containsOnlyValidIdentifierChars(name)) return false; + + CopyOnWrite(); + std::pair > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData(NameData::UNIT, value)); + return addNewNameData(mData->mNamePtrs, newName, false); +} + +template +bool FunctionParserBase::AddFunction +(const std::string& name, FunctionPtr ptr, unsigned paramsAmount) +{ + if(!containsOnlyValidIdentifierChars(name)) return false; + + 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) + { + mData->mFuncPtrs.push_back(typename Data::FuncPtrData()); + mData->mFuncPtrs.back().mFuncPtr = ptr; + mData->mFuncPtrs.back().mParams = paramsAmount; + } + return success; +} + +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; +} + +template +bool FunctionParserBase::AddFunction(const std::string& name, + FunctionParserBase& fp) +{ + if(!containsOnlyValidIdentifierChars(name) || + CheckRecursiveLinking(&fp)) + return false; + + CopyOnWrite(); + std::pair > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData(NameData::PARSER_PTR, + unsigned(mData->mFuncParsers.size()))); + + const bool success = addNewNameData(mData->mNamePtrs, newName, false); + if(success) + { + mData->mFuncParsers.push_back(typename Data::FuncPtrData()); + mData->mFuncParsers.back().mParserPtr = &fp; + mData->mFuncParsers.back().mParams = fp.mData->mVariablesAmount; + } + return success; +} + +template +bool FunctionParserBase::RemoveIdentifier(const std::string& name) +{ + CopyOnWrite(); + + NamePtr namePtr(name.data(), unsigned(name.size())); + + typename NamePtrsMap::iterator + nameIter = mData->mNamePtrs.find(namePtr); + + if(nameIter != mData->mNamePtrs.end()) + { + if(nameIter->second.type == NameData::VARIABLE) + { + // Illegal attempt to delete variables + return false; + } + delete[] nameIter->first.name; + mData->mNamePtrs.erase(nameIter); + return true; + } + return false; +} + + +//========================================================================= +// Function parsing +//========================================================================= +namespace +{ + // Error messages returned by ErrorMsg(): + const char* const ParseErrorMessage[]= + { + "Syntax error", // 0 + "Mismatched parenthesis", // 1 + "Missing ')'", // 2 + "Empty parentheses", // 3 + "Syntax error: Operator expected", // 4 + "Not enough memory", // 5 + "An unexpected error occurred. Please make a full bug report " + "to the author", // 6 + "Syntax error in parameter 'Vars' given to " + "FunctionParser::Parse()", // 7 + "Illegal number of parameters to function", // 8 + "Syntax error: Premature end of string", // 9 + "Syntax error: Expecting ( after function", // 10 + "Syntax error: Unknown identifier", // 11 + "(No function has been parsed yet)", + "" + }; + + template + 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)) }; + }; + + template + inline bool BeginsLiteral(unsigned byte) + { + const unsigned n = sizeof(unsigned long)>=8 ? 0 : '.'; + byte -= n; + if(byte > (unsigned char)('9'-n)) return false; + unsigned long shifted = 1UL << byte; + const unsigned long mask = LiteralMask::mask; + return (mask & shifted) != 0; + } + + 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) + { + const unsigned n = sizeof(unsigned long)>=8 ? 0 : '\t'; + typedef signed char schar; + unsigned byte = (unsigned char)*function; + byte -= n; + // ^Note: values smaller than n intentionally become + // big values here due to integer wrap. The + // comparison below thus excludes them, making + // the effective range 0x09..0x20 (32-bit) + // or 0x00..0x20 (64-bit) within the if-clause. + if(byte <= (unsigned char)(' '-n)) + { + unsigned long shifted = 1UL << byte; + const unsigned long mask = SimpleSpaceMask::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[mParseErrorType]; +} + + +// --------------------------------------------------------------------------- +// Parse variables +// --------------------------------------------------------------------------- +template +bool FunctionParserBase::ParseVariables +(const std::string& inputVarString) +{ + if(mData->mVariablesString == inputVarString) return true; + + /* Delete existing variables from mNamePtrs */ + for(typename NamePtrsMap::iterator i = + mData->mNamePtrs.begin(); + i != mData->mNamePtrs.end(); ) + { + if(i->second.type == NameData::VARIABLE) + { + 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; + } + + beginPtr = endPtr + 1; + } + + mData->mVariablesAmount = varNumber - VarBegin; + return true; +} + +// --------------------------------------------------------------------------- +// Parse() public interface functions +// --------------------------------------------------------------------------- +template +int FunctionParserBase::Parse(const char* Function, + const std::string& Vars, + bool useDegrees) +{ + CopyOnWrite(); + + if(!ParseVariables(Vars)) + { + mParseErrorType = INVALID_VARS; + return int(strlen(Function)); + } + + return ParseFunction(Function, useDegrees); +} + +template +int FunctionParserBase::Parse(const std::string& Function, + const std::string& Vars, + bool useDegrees) +{ + CopyOnWrite(); + + if(!ParseVariables(Vars)) + { + mParseErrorType = INVALID_VARS; + return int(Function.size()); + } + + return ParseFunction(Function.c_str(), useDegrees); +} + + +// --------------------------------------------------------------------------- +// Main parsing function +// --------------------------------------------------------------------------- +template +int FunctionParserBase::ParseFunction(const char* function, + bool useDegrees) +{ + mUseDegreeConversion = useDegrees; + mParseErrorType = FP_NO_ERROR; + + mData->mInlineVarNames.clear(); + mData->mByteCode.clear(); mData->mByteCode.reserve(128); + mData->mImmed.clear(); mData->mImmed.reserve(128); + mData->mStackSize = mStackPtr = 0; + + mHasByteCodeFlags = false; + + const char* ptr = Compile(function); + mData->mInlineVarNames.clear(); + + if(mHasByteCodeFlags) + { + for(unsigned i = unsigned(mData->mByteCode.size()); i-- > 0; ) + mData->mByteCode[i] &= ~0x80000000U; + } + + if(mParseErrorType != FP_NO_ERROR) return int(mErrorLocation - function); + + assert(ptr); // Should never be null at this point. It's a bug otherwise. + if(*ptr) + { + if(mDelimiterChar == 0 || *ptr != mDelimiterChar) + mParseErrorType = EXPECT_OPERATOR; + return int(ptr - function); + } + +#ifndef FP_USE_THREAD_SAFE_EVAL + mData->mStack.resize(mData->mStackSize); +#endif + + return -1; +} + + +//========================================================================= +// Parsing and bytecode compiling functions +//========================================================================= +template +inline const char* FunctionParserBase::SetErrorType(ParseErrorType t, + const char* pos) +{ + mParseErrorType = t; + mErrorLocation = pos; + return 0; +} + +template +inline void FunctionParserBase::incStackPtr() +{ + if(++mStackPtr > mData->mStackSize) ++(mData->mStackSize); +} + +namespace +{ + const unsigned char powi_factor_table[128] = + { + 0,1,0,0,0,0,0,0, 0, 0,0,0,0,0,0,3,/* 0 - 15 */ + 0,0,0,0,0,0,0,0, 0, 5,0,3,0,0,3,0,/* 16 - 31 */ + 0,0,0,0,0,0,0,3, 0, 0,0,0,0,5,0,0,/* 32 - 47 */ + 0,0,5,3,0,0,3,5, 0, 3,0,0,3,0,0,3,/* 48 - 63 */ + 0,0,0,0,0,0,0,0, 0, 0,0,3,0,0,3,0,/* 64 - 79 */ + 0,9,0,0,0,5,0,3, 0, 0,5,7,0,0,0,5,/* 80 - 95 */ + 0,0,0,3,5,0,3,0, 0, 3,0,0,3,0,5,3,/* 96 - 111 */ + 0,0,3,5,0,9,0,7, 3,11,0,3,0,5,3,0,/* 112 - 127 */ + }; + + inline int get_powi_factor(long abs_int_exponent) + { + if(abs_int_exponent >= int(sizeof(powi_factor_table))) return 0; + return powi_factor_table[abs_int_exponent]; + } + +#if 0 + int EstimatePowiComplexity(int abs_int_exponent) + { + int cost = 0; + while(abs_int_exponent > 1) + { + int factor = get_powi_factor(abs_int_exponent); + if(factor) + { + cost += EstimatePowiComplexity(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + cost += 3; // sqr + } + else + { + cost += 4; // dup+mul + abs_int_exponent -= 1; + } + } + return cost; + } +#endif + + bool IsEligibleIntPowiExponent(long int_exponent) + { + if(int_exponent == 0) return false; + long abs_int_exponent = int_exponent; + #if 0 + int cost = 0; + + if(abs_int_exponent < 0) + { + cost += 11; + abs_int_exponent = -abs_int_exponent; + } + + cost += EstimatePowiComplexity(abs_int_exponent); + + return cost < (10*3 + 4*4); + #else + if(abs_int_exponent < 0) abs_int_exponent = -abs_int_exponent; + + return (abs_int_exponent >= 1) + && (abs_int_exponent <= 46 || + (abs_int_exponent <= 1024 && + (abs_int_exponent & (abs_int_exponent - 1)) == 0)); + #endif + } + +#ifdef FP_EPSILON + const double EpsilonOrZero = FP_EPSILON; +#else + const double EpsilonOrZero = 0.0; +#endif + +} + +template +inline void FunctionParserBase::AddImmedOpcode(Value_t value) +{ + mData->mImmed.push_back(value); + mData->mByteCode.push_back(cImmed); +} + +template +inline void FunctionParserBase::CompilePowi(long abs_int_exponent) +{ + int num_muls=0; + while(abs_int_exponent > 1) + { + long factor = get_powi_factor(abs_int_exponent); + if(factor) + { + CompilePowi(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + mData->mByteCode.push_back(cSqr); + // ^ Don't put AddFunctionOpcode here, + // it would slow down a great deal. + } + else + { + mData->mByteCode.push_back(cDup); + incStackPtr(); + abs_int_exponent -= 1; + ++num_muls; + } + } + if(num_muls > 0) + { + mData->mByteCode.resize(mData->mByteCode.size()+num_muls, cMul); + mStackPtr -= num_muls; + } +} + +template +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 +#include "fp_opcode_add.inc" +#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 +#include "fp_opcode_add.inc" +#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 +#include "fp_opcode_add.inc" +#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; +#ifndef FP_DISABLE_EVAL + if(func_opcode == cEval) + requiredParams = mData->mVariablesAmount; +#endif + + function = CompileFunctionParams(function, requiredParams); + if(!function) return 0; + + if(mUseDegreeConversion) + { + if(funcDef.flags & FuncDefinition::AngleIn) + AddFunctionOpcode(cRad); + + AddFunctionOpcode(func_opcode); + + if(funcDef.flags & FuncDefinition::AngleOut) + AddFunctionOpcode(cDeg); + } + else + { + AddFunctionOpcode(func_opcode); + } + return function; +} + +template +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 GmpIng, for safety + reasons. + - With long int almost any power, except for very small ones, would + overflow the result, so the usefulness of this is rather questionable. + - With GmpInt the power operator could be easily abused to make the program + run out of memory (think of a function like "10^10^10^10^1000000"). +*/ +#ifdef FP_SUPPORT_LONG_INT_TYPE +template<> +inline const char* +FunctionParserBase::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) +{ + 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) +{ + 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 ? 0x80000000U : 0u)); + if(PutFlag) mHasByteCodeFlags = true; +} + +template template +inline void FunctionParserBase::PutOpcodeParamAt + (unsigned value, unsigned offset) +{ + mData->mByteCode[offset] = value | (PutFlag ? 0x80000000U : 0u); + if(PutFlag) mHasByteCodeFlags = true; +} + +//=========================================================================== +// Function evaluation +//=========================================================================== +template +Value_t FunctionParserBase::Eval(const Value_t* Vars) +{ + if(mParseErrorType != FP_NO_ERROR) return Value_t(0); + + const unsigned* const byteCode = &(mData->mByteCode[0]); + const Value_t* const immed = mData->mImmed.empty() ? 0 : &(mData->mImmed[0]); + const unsigned byteCodeSize = unsigned(mData->mByteCode.size()); + unsigned IP, DP=0; + int SP=-1; + +#ifdef FP_USE_THREAD_SAFE_EVAL + /* If Eval() may be called by multiple threads simultaneously, + * then Eval() must allocate its own stack. + */ +#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA + /* alloca() allocates room from the hardware stack. + * It is automatically freed when the function returns. + */ + Value_t* const Stack = (Value_t*)alloca(mData->mStackSize*sizeof(Value_t)); +#else + /* Allocate from the heap. Ensure that it is freed + * automatically no matter which exit path is taken. + */ + struct AutoDealloc + { + Value_t* ptr; + ~AutoDealloc() { delete[] ptr; } + } AutoDeallocStack = { new Value_t[mData->mStackSize] }; + Value_t*& Stack = AutoDeallocStack.ptr; +#endif +#else + /* No thread safety, so use a global stack. */ + std::vector& Stack = mData->mStack; +#endif + + for(IP=0; IP Value_t(1)) + { mEvalErrorType=4; return Value_t(0); } +# endif + Stack[SP] = fp_acos(Stack[SP]); break; + + case cAcosh: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP] < Value_t(1)) + { mEvalErrorType=4; return Value_t(0); } +# endif + Stack[SP] = fp_acosh(Stack[SP]); break; + + case cAsin: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1)) + { mEvalErrorType=4; return Value_t(0); } +# endif + Stack[SP] = fp_asin(Stack[SP]); break; + + case cAsinh: Stack[SP] = fp_asinh(Stack[SP]); break; + + case cAtan: Stack[SP] = fp_atan(Stack[SP]); break; + + case cAtan2: Stack[SP-1] = fp_atan2(Stack[SP-1], Stack[SP]); + --SP; break; + + case cAtanh: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP] <= Value_t(-1) || Stack[SP] >= Value_t(1)) + { mEvalErrorType=4; return Value_t(0); } +# endif + Stack[SP] = fp_atanh(Stack[SP]); break; + + case cCbrt: Stack[SP] = fp_cbrt(Stack[SP]); break; + + case cCeil: Stack[SP] = fp_ceil(Stack[SP]); break; + + case cCos: Stack[SP] = fp_cos(Stack[SP]); break; + + case cCosh: Stack[SP] = fp_cosh(Stack[SP]); break; + + case cCot: + { + const Value_t t = fp_tan(Stack[SP]); +# ifndef FP_NO_EVALUATION_CHECKS + if(t == Value_t(0)) { mEvalErrorType=1; return Value_t(0); } +# endif + Stack[SP] = Value_t(1)/t; break; + } + + case cCsc: + { + const Value_t s = fp_sin(Stack[SP]); +# ifndef FP_NO_EVALUATION_CHECKS + if(s == 0) { mEvalErrorType=1; return Value_t(0); } +# endif + Stack[SP] = Value_t(1)/s; break; + } + + +# ifndef FP_DISABLE_EVAL + case cEval: + { + const unsigned varAmount = mData->mVariablesAmount; + Value_t retVal = Value_t(0); + if(mEvalRecursionLevel == FP_EVAL_MAX_REC_LEVEL) + { + mEvalErrorType = 5; + } + else + { + ++mEvalRecursionLevel; +# ifndef FP_USE_THREAD_SAFE_EVAL + /* Eval() will use mData->mStack for its storage. + * Swap the current stack with an empty one. + * This is the not-thread-safe method. + */ + std::vector tmpStack(Stack.size()); + mData->mStack.swap(tmpStack); + retVal = Eval(&tmpStack[SP - varAmount + 1]); + mData->mStack.swap(tmpStack); +# else + /* Thread safety mode. We don't need to + * worry about stack reusing here, because + * each instance of Eval() will allocate + * their own stack. + */ + retVal = Eval(&Stack[SP - varAmount + 1]); +# endif + --mEvalRecursionLevel; + } + SP -= varAmount-1; + Stack[SP] = retVal; + break; + } +# endif + + case cExp: Stack[SP] = fp_exp(Stack[SP]); break; + + case cExp2: Stack[SP] = fp_exp2(Stack[SP]); break; + + case cFloor: Stack[SP] = fp_floor(Stack[SP]); break; + + case cHypot: + Stack[SP-1] = fp_hypot(Stack[SP-1], Stack[SP]); + --SP; break; + + case cIf: + if(fp_truth(Stack[SP--])) + IP += 2; + else + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + } + break; + + case cInt: Stack[SP] = fp_int(Stack[SP]); break; + + case cLog: +# ifndef FP_NO_EVALUATION_CHECKS + if(!(Stack[SP] > Value_t(0))) + { mEvalErrorType=3; return Value_t(0); } +# endif + Stack[SP] = fp_log(Stack[SP]); break; + + case cLog10: +# ifndef FP_NO_EVALUATION_CHECKS + if(!(Stack[SP] > Value_t(0))) + { mEvalErrorType=3; return Value_t(0); } +# endif + Stack[SP] = fp_log10(Stack[SP]); + break; + + case cLog2: +# ifndef FP_NO_EVALUATION_CHECKS + if(!(Stack[SP] > Value_t(0))) + { mEvalErrorType=3; return Value_t(0); } +# endif + Stack[SP] = fp_log2(Stack[SP]); + break; + + case cMax: Stack[SP-1] = fp_max(Stack[SP-1], Stack[SP]); + --SP; break; + + case cMin: Stack[SP-1] = fp_min(Stack[SP-1], Stack[SP]); + --SP; break; + + case cPow: +# ifndef FP_NO_EVALUATION_CHECKS + // x:Negative ^ y:NonInteger is failure, + // except when the reciprocal of y forms an integer + /*if(Stack[SP-1] < Value_t(0) && + !isInteger(Stack[SP]) && + !isInteger(1.0 / Stack[SP])) + { mEvalErrorType=3; return Value_t(0); }*/ + // x:0 ^ y:negative is failure + if(Stack[SP-1] == Value_t(0) && + Stack[SP] < Value_t(0)) + { mEvalErrorType=3; return Value_t(0); } +# endif + Stack[SP-1] = fp_pow(Stack[SP-1], Stack[SP]); + --SP; break; + + case cTrunc: Stack[SP] = fp_trunc(Stack[SP]); break; + + case cSec: + { + const Value_t c = fp_cos(Stack[SP]); +# ifndef FP_NO_EVALUATION_CHECKS + if(c == Value_t(0)) { mEvalErrorType=1; return Value_t(0); } +# endif + Stack[SP] = Value_t(1)/c; break; + } + + case cSin: Stack[SP] = fp_sin(Stack[SP]); break; + + case cSinh: Stack[SP] = fp_sinh(Stack[SP]); break; + + case cSqrt: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP] < Value_t(0)) { mEvalErrorType=2; return Value_t(0); } +# endif + Stack[SP] = fp_sqrt(Stack[SP]); break; + + case cTan: Stack[SP] = fp_tan(Stack[SP]); break; + + case cTanh: Stack[SP] = fp_tanh(Stack[SP]); break; + + +// Misc: + case cImmed: Stack[++SP] = immed[DP++]; break; + + case cJump: + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + break; + } + +// Operators: + case cNeg: Stack[SP] = -Stack[SP]; break; + case cAdd: Stack[SP-1] += Stack[SP]; --SP; break; + case cSub: Stack[SP-1] -= Stack[SP]; --SP; break; + case cMul: Stack[SP-1] *= Stack[SP]; --SP; break; + + case cDiv: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } +# else + if(IsIntType::result && Stack[SP] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } +# endif + Stack[SP-1] /= Stack[SP]; --SP; break; + + case cMod: + if(Stack[SP] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] = fp_mod(Stack[SP-1], Stack[SP]); + --SP; break; + + case cEqual: + Stack[SP-1] = fp_equal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cNEqual: + Stack[SP-1] = fp_nequal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLess: + Stack[SP-1] = fp_less(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLessOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP-1], Stack[SP]); + --SP; break; + + case cGreater: + Stack[SP-1] = fp_less(Stack[SP], Stack[SP-1]); + --SP; break; + + case cGreaterOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP], Stack[SP-1]); + --SP; break; + + case cNot: Stack[SP] = fp_not(Stack[SP]); break; + + case cNotNot: Stack[SP] = fp_notNot(Stack[SP]); break; + + case cAnd: + Stack[SP-1] = fp_and(Stack[SP-1], Stack[SP]); + --SP; break; + + case cOr: + Stack[SP-1] = fp_or(Stack[SP-1], Stack[SP]); + --SP; break; + +// Degrees-radians conversion: + case cDeg: Stack[SP] = RadiansToDegrees(Stack[SP]); break; + case cRad: Stack[SP] = DegreesToRadians(Stack[SP]); break; + +// User-defined function calls: + case cFCall: + { + unsigned index = byteCode[++IP]; + unsigned params = mData->mFuncPtrs[index].mParams; + Value_t retVal = + mData->mFuncPtrs[index].mFuncPtr(&Stack[SP-params+1]); + SP -= int(params)-1; + Stack[SP] = retVal; + break; + } + + case cPCall: + { + unsigned index = byteCode[++IP]; + unsigned params = mData->mFuncParsers[index].mParams; + Value_t retVal = + mData->mFuncParsers[index].mParserPtr->Eval + (&Stack[SP-params+1]); + SP -= int(params)-1; + Stack[SP] = retVal; + const int error = + mData->mFuncParsers[index].mParserPtr->EvalError(); + if(error) + { + mEvalErrorType = error; + return 0; + } + break; + } + + + case cFetch: + { + unsigned stackOffs = byteCode[++IP]; + Stack[SP+1] = Stack[stackOffs]; ++SP; + break; + } + +#ifdef FP_SUPPORT_OPTIMIZER + case cPopNMov: + { + unsigned stackOffs_target = byteCode[++IP]; + unsigned stackOffs_source = byteCode[++IP]; + Stack[stackOffs_target] = Stack[stackOffs_source]; + SP = stackOffs_target; + break; + } + + case cLog2by: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP-1] <= Value_t(0)) + { mEvalErrorType=3; return Value_t(0); } +# endif + Stack[SP-1] = fp_log2(Stack[SP-1]) * Stack[SP]; + --SP; + break; + + case cNop: break; +#endif // FP_SUPPORT_OPTIMIZER + + case cSinCos: + fp_sinCos(Stack[SP], Stack[SP+1], Stack[SP]); + ++SP; + break; + + case cAbsNot: + Stack[SP] = fp_absNot(Stack[SP]); break; + case cAbsNotNot: + Stack[SP] = fp_absNotNot(Stack[SP]); break; + case cAbsAnd: + Stack[SP-1] = fp_absAnd(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsOr: + Stack[SP-1] = fp_absOr(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsIf: + if(fp_absTruth(Stack[SP--])) + IP += 2; + else + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + } + break; + + case cDup: Stack[SP+1] = Stack[SP]; ++SP; break; + + case cInv: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } +# else + if(IsIntType::result && Stack[SP] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } +# endif + Stack[SP] = Value_t(1)/Stack[SP]; + break; + + case cSqr: + Stack[SP] = Stack[SP]*Stack[SP]; + break; + + case cRDiv: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP-1] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } +# else + if(IsIntType::result && Stack[SP-1] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } +# endif + Stack[SP-1] = Stack[SP] / Stack[SP-1]; --SP; break; + + case cRSub: Stack[SP-1] = Stack[SP] - Stack[SP-1]; --SP; break; + + case cRSqrt: +# ifndef FP_NO_EVALUATION_CHECKS + if(Stack[SP] == Value_t(0)) + { mEvalErrorType=1; return Value_t(0); } +# endif + Stack[SP] = Value_t(1) / fp_sqrt(Stack[SP]); break; + + +// Variables: + default: + Stack[++SP] = Vars[byteCode[IP]-VarBegin]; + } + } + + mEvalErrorType=0; + return Stack[SP]; +} + + +//=========================================================================== +// Variable deduction +//=========================================================================== +namespace +{ + template + 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) + { + std::ios::fmtflags flags = dest.flags(); + dest.width(4); dest.fill('0'); std::hex(dest); //uppercase(dest); + dest << n; + dest.flags(flags); + } + + void padLine(std::ostringstream& dest, unsigned destLength) + { + for(size_t currentLength = dest.str().length(); + currentLength < destLength; + ++currentLength) + { + dest << ' '; + } + } + + template + std::string findName(const NamePtrsMap& nameMap, + unsigned index, + typename NameData::DataType type) + { + 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 "?"; + } + + 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, + 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 + || 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, + 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, + 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() { } + }; +} + +template +void FunctionParserBase::PrintByteCode(std::ostream& dest, + bool showExpression) const +{ + dest << "Size of stack: " << mData->mStackSize << "\n"; + + std::ostringstream outputBuffer; + std::ostream& output = (showExpression ? outputBuffer : dest); + + const std::vector& ByteCode = mData->mByteCode; + const std::vector& Immed = mData->mImmed; + + std::vector > stack; + std::vector if_stack; + + for(unsigned IP = 0, DP = 0; IP <= ByteCode.size(); ++IP) + { + after_powi_or_muli:; + std::string n; + bool out_params = false; + unsigned params = 2, produces = 1, opcode = 0; + + if(showExpression && !if_stack.empty() && + ( // Normal If termination rule: + if_stack.back().endif_location == IP + // This rule matches when cJumps are threaded: + || (IP < ByteCode.size() && ByteCode[IP] == cJump + && !if_stack.back().thenbranch.second.empty()) + )) + { + printHex(output, IP); + if(if_stack.back().endif_location == IP) + output << ": ----- (phi)"; + else + output << ": ----- (phi+)"; + + stack.resize(stack.size()+2); + std::swap(stack[stack.size()-3], stack[stack.size()-1]); + std::swap(if_stack.back().condition, stack[stack.size()-3]); + std::swap(if_stack.back().thenbranch, stack[stack.size()-2]); + opcode = cIf; + params = 3; + --IP; + if_stack.pop_back(); + } + else + { + if(IP >= ByteCode.size()) break; + opcode = ByteCode[IP]; + + if(showExpression && ( + opcode == cSqr || opcode == cDup + || opcode == cInv + || opcode == cSqrt || opcode == cRSqrt + || opcode == cFetch + )) + { + unsigned changed_ip = IP; + Value_t exponent = + ParsePowiSequence + (ByteCode, changed_ip, + if_stack.empty() + ? (unsigned)ByteCode.size() + : if_stack.back().endif_location, + stack.size()-1); + std::string operation_prefix; + std::ostringstream operation_value; + int prio = 0; + if(exponent == 1.0) + { + if(opcode != cDup) goto not_powi_or_muli; + Value_t factor = + ParseMuliSequence + (ByteCode, changed_ip, + if_stack.empty() + ? (unsigned)ByteCode.size() + : if_stack.back().endif_location, + stack.size()-1); + if(factor == Value_t(1) || factor == Value_t(-1)) + goto not_powi_or_muli; + operation_prefix = "*"; + operation_value << factor; + prio = 3; + } + else + { + prio = 2; + operation_prefix = "^"; + operation_value << exponent; + } + + //unsigned explanation_before = changed_ip-2; + unsigned explanation_before = changed_ip-1; + + const char* explanation_prefix = "_"; + for(const unsigned first_ip = IP; IP < changed_ip; ++IP) + { + printHex(output, IP); + output << ": "; + + const char* sep = "|"; + if(first_ip+1 == changed_ip) + { sep = "="; explanation_prefix = " "; } + else if(IP == first_ip) sep = "\\"; + else if(IP+1 == changed_ip) sep = "/"; + else explanation_prefix = "="; + + switch(ByteCode[IP]) + { + case cInv: output << "inv"; break; + case cNeg: output << "neg"; break; + case cDup: output << "dup"; break; + case cSqr: output << "sqr"; break; + case cMul: output << "mul"; break; + case cAdd: output << "add"; break; + case cCbrt: output << "cbrt"; break; + case cSqrt: output << "sqrt"; break; + case cRSqrt: output << "rsqrt"; break; + case cFetch: + { + unsigned index = ByteCode[++IP]; + output << "cFetch(" << index << ")"; + break; + } + default: break; + } + padLine(outputBuffer, 20); + output << sep; + if(IP >= explanation_before) + { + explanation_before = (unsigned)ByteCode.size(); + output << explanation_prefix + << '[' << (stack.size()-1) << ']'; + std::string last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + output << last; + output << operation_prefix; + output << operation_value.str(); + } + else + { + unsigned p = first_ip; + Value_t exp = operation_prefix=="^" ? + ParsePowiSequence + (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 label = ByteCode[IP+1]+1; + output << "jz "; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); + break; + } + case cAbsIf: + { + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; + output << "jz_abs " << dp << ","; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); + break; + } + + case cJump: + { + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; + + if(!if_stack.empty() && !stack.empty()) + { + std::swap(if_stack.back().thenbranch, stack.back()); + if_stack.back().endif_location = label; + stack.pop_back(); + } + + output << "jump " << dp << ","; + printHex(output, label); + params = 0; + produces = 0; + IP += 2; + break; + } + case cImmed: + { + if(showExpression) + { + std::ostringstream buf; + buf.precision(8); + buf << Immed[DP]; + stack.push_back( std::make_pair(0, buf.str()) ); + } + output.precision(8); + output << "push " << Immed[DP]; + ++DP; + produces = 0; + break; + } + + case cFCall: + { + const unsigned index = ByteCode[++IP]; + params = mData->mFuncPtrs[index].mParams; + static std::string name; + name = "f:" + findName(mData->mNamePtrs, index, + NameData::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(OPCODE(opcode) < VarBegin) + { + switch(opcode) + { + case cNeg: n = "neg"; params = 1; break; + case cAdd: n = "add"; break; + case cSub: n = "sub"; break; + case cMul: n = "mul"; break; + case cDiv: n = "div"; break; + case cMod: n = "mod"; break; + case cPow: n = "pow"; break; + case cEqual: n = "eq"; break; + case cNEqual: n = "neq"; break; + case cLess: n = "lt"; break; + case cLessOrEq: n = "le"; break; + case cGreater: n = "gt"; break; + case cGreaterOrEq: n = "ge"; break; + case cAnd: n = "and"; break; + case cOr: n = "or"; break; + case cNot: n = "not"; params = 1; break; + case cNotNot: n = "notnot"; params = 1; break; + case cDeg: n = "deg"; params = 1; break; + case cRad: n = "rad"; params = 1; break; + + #ifndef FP_DISABLE_EVAL + case cEval: n = "eval"; params = mData->mVariablesAmount; + #endif + + case cFetch: + { + unsigned index = ByteCode[++IP]; + if(showExpression && index < stack.size()) + stack.push_back(stack[index]); + output << "cFetch(" << index << ")"; + produces = 0; + break; + } + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by: n = "log2by"; params = 2; out_params = 1; break; + case cPopNMov: + { + size_t a = ByteCode[++IP]; + size_t b = ByteCode[++IP]; + if(showExpression && b < stack.size()) + { + std::pair 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 cAbsAnd: n = "abs_and"; break; + case cAbsOr: n = "abs_or"; break; + case cAbsNot: n = "abs_not"; params = 1; break; + case cAbsNotNot: n = "abs_notnot"; params = 1; break; + case cDup: + { + if(showExpression) + stack.push_back(stack.back()); + output << "dup"; + produces = 0; + break; + } + case cInv: n = "inv"; params = 1; break; + case cSqr: n = "sqr"; params = 1; break; + case cRDiv: n = "rdiv"; break; + case cRSub: n = "rsub"; break; + case cRSqrt: n = "rsqrt"; params = 1; break; + + default: + n = Functions[opcode-cAbs].name; + params = Functions[opcode-cAbs].params; + out_params = params != 1; + } + } + else + { + if(showExpression) + { + stack.push_back(std::make_pair(0, + (findName(mData->mNamePtrs, opcode, + NameData::VARIABLE)))); + } + output << "push Var" << opcode-VarBegin; + produces = 0; + } + } + } + if(produces) output << n; + if(out_params) output << " (" << params << ")"; + if(showExpression) + { + padLine(outputBuffer, 20); + + if(produces > 0) + { + std::ostringstream buf; + const char *paramsep = ",", *suff = ""; + int prio = 0; bool commutative = false; + switch(opcode) + { + case cIf: buf << "if("; suff = ")"; + break; + case cAbsIf: buf << "if("; suff = ")"; + break; + case cOr: prio = 6; paramsep = "|"; commutative = true; + break; + case cAnd: prio = 5; paramsep = "&"; commutative = true; + break; + case cAdd: prio = 4; paramsep = "+"; commutative = true; + break; + case cSub: prio = 4; paramsep = "-"; + break; + case cMul: prio = 3; paramsep = "*"; commutative = true; + break; + case cDiv: prio = 3; paramsep = "/"; + break; + case cPow: prio = 2; paramsep = "^"; + break; + case cAbsOr: prio = 6; paramsep = "|"; commutative = true; + break; + case cAbsAnd: prio = 5; paramsep = "&"; commutative = true; + break; + case cSqr: prio = 2; suff = "^2"; + break; + case cNeg: buf << "(-("; suff = "))"; + break; + case cNot: buf << "(!("; suff = "))"; + break; + default: buf << n << '('; suff = ")"; + } + + const char* sep = ""; + for(unsigned a=0; a& prev = + stack[stack.size() - params + a]; + if(prio > 0 && (prev.first > prio || + (prev.first==prio && !commutative))) + buf << '(' << prev.second << ')'; + else + buf << prev.second; + } + sep = paramsep; + } + if(stack.size() >= params) + stack.resize(stack.size() - params); + else + stack.clear(); + buf << suff; + stack.push_back(std::make_pair(prio, buf.str())); + //if(n.size() <= 4 && !out_params) padLine(outputBuffer, 20); + } + //padLine(outputBuffer, 20); + output << "= "; + if(((opcode == cIf || opcode == cAbsIf) && params != 3) + || opcode == cJump + #ifdef FP_SUPPORT_OPTIMIZER + || opcode == cNop + #endif + ) + output << "(void)"; + else if(stack.empty()) + output << "[?] ?"; + else + output << '[' << (stack.size()-1) << ']' + << stack.back().second; + } + + if(showExpression) + { + dest << outputBuffer.str() << std::endl; + outputBuffer.str(""); + } + else + output << std::endl; + } + dest << std::flush; +} +#endif + + +#ifndef FP_SUPPORT_OPTIMIZER +template +void FunctionParserBase::Optimize() +{ + // Do nothing if no optimizations are supported. +} +#endif + +FUNCTIONPARSER_INSTANTIATE_TYPES diff --git a/fparser/fparser.hh b/fparser/fparser.hh new file mode 100644 index 0000000..2157c3b --- /dev/null +++ b/fparser/fparser.hh @@ -0,0 +1,179 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_H_ +#define ONCE_FPARSER_H_ + +#include +#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); + + const char* ErrorMsg() const; + inline ParseErrorType GetParseErrorType() const { return mParseErrorType; } + + Value_t Eval(const Value_t* Vars); + inline int EvalError() const { return mEvalErrorType; } + + bool AddConstant(const std::string& name, Value_t value); + bool AddUnit(const std::string& name, Value_t value); + + typedef Value_t (*FunctionPtr)(const Value_t*); + + bool AddFunction(const std::string& name, + FunctionPtr, unsigned paramsAmount); + bool AddFunction(const std::string& name, FunctionParserBase&); + + bool RemoveIdentifier(const std::string& name); + + void Optimize(); + + + int ParseAndDeduceVariables(const std::string& function, + int* amountOfVariablesFound = 0, + bool useDegrees = false); + int ParseAndDeduceVariables(const std::string& function, + std::string& resultVarString, + int* amountOfVariablesFound = 0, + bool useDegrees = false); + int ParseAndDeduceVariables(const std::string& function, + std::vector& resultVars, + bool useDegrees = false); + + + FunctionParserBase(); + ~FunctionParserBase(); + + // Copy constructor and assignment operator (implemented using the + // copy-on-write technique for efficiency): + FunctionParserBase(const FunctionParserBase&); + FunctionParserBase& operator=(const FunctionParserBase&); + + + void ForceDeepCopy(); + + + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + // For debugging purposes only. + // Performs no sanity checks or anything. If the values are wrong, the + // library will crash. Do not use unless you know what you are doing. + void InjectRawByteCode(const unsigned* bytecode, unsigned bytecodeAmount, + const Value_t* immed, unsigned immedAmount, + unsigned stackSize); + + void PrintByteCode(std::ostream& dest, bool showExpression = true) const; +#endif + + + +//======================================================================== +private: +//======================================================================== + + friend class FPoptimizer_CodeTree::CodeTree; + +// Private data: +// ------------ + char mDelimiterChar; + ParseErrorType mParseErrorType; + int mEvalErrorType; + + struct Data; + Data* mData; + + bool mUseDegreeConversion; + bool mHasByteCodeFlags; + unsigned mEvalRecursionLevel; + unsigned mStackPtr; + const char* mErrorLocation; + + +// Private methods: +// --------------- + void CopyOnWrite(); + bool CheckRecursiveLinking(const FunctionParserBase*) const; + bool NameExists(const char*, unsigned); + bool ParseVariables(const std::string&); + int ParseFunction(const char*, bool); + const char* SetErrorType(ParseErrorType, const char*); + + void AddFunctionOpcode(unsigned); + void AddImmedOpcode(Value_t v); + void incStackPtr(); + void CompilePowi(long); + bool TryCompilePowi(Value_t); + + const char* CompileIf(const char*); + const char* CompileFunctionParams(const char*, unsigned); + const char* CompileElement(const char*); + const char* CompilePossibleUnit(const char*); + const char* CompilePow(const char*); + const char* CompileUnaryMinus(const char*); + const char* CompileMult(const char*); + const char* CompileAddition(const char*); + const char* CompileComparison(const char*); + const char* CompileAnd(const char*); + const char* CompileExpression(const char*); + inline const char* CompileFunction(const char*, unsigned); + inline const char* CompileParenthesis(const char*); + inline const char* CompileLiteral(const char*); + template + inline void PushOpcodeParam(unsigned); + template + inline void PutOpcodeParamAt(unsigned, unsigned offset); + const char* Compile(const char*); + +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 {}; + +#endif diff --git a/fparser/fparser_gmpint.hh b/fparser/fparser_gmpint.hh new file mode 100644 index 0000000..ba4f049 --- /dev/null +++ b/fparser/fparser_gmpint.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_GMPINT_H_ +#define ONCE_FPARSER_GMPINT_H_ + +#include "fparser.hh" +#include "mpfr/GmpInt.hh" + +class FunctionParser_gmpint: public FunctionParserBase {}; + +#endif diff --git a/fparser/fparser_mpfr.hh b/fparser/fparser_mpfr.hh new file mode 100644 index 0000000..8807847 --- /dev/null +++ b/fparser/fparser_mpfr.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_MPFR_H_ +#define ONCE_FPARSER_MPFR_H_ + +#include "fparser.hh" +#include "mpfr/MpfrFloat.hh" + +class FunctionParser_mpfr: public FunctionParserBase {}; + +#endif diff --git a/fparser/fpaux.hh b/fparser/fpaux.hh new file mode 100644 index 0000000..fe9dcd9 --- /dev/null +++ b/fparser/fpaux.hh @@ -0,0 +1,796 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_AUX_H_ +#define ONCE_FPARSER_AUX_H_ + +#include +#include + +#include "fptypes.hh" + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +#include "mpfr/MpfrFloat.hh" +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +#include "mpfr/GmpInt.hh" +#endif + +#ifdef ONCE_FPARSER_H_ +namespace FUNCTIONPARSERTYPES +{ + template + struct IsIntType + { + enum { result = false }; + }; + template<> + struct IsIntType + { + enum { result = true }; + }; +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + struct IsIntType + { + enum { result = true }; + }; +#endif + +//========================================================================== +// Math funcs +//========================================================================== + template + ValueT fp_pow(const ValueT& x, const ValueT& y); + + template + inline void fp_sinCos(Value_t& sin, Value_t& cos, const Value_t& a) + { + // Assuming that "cos" and "a" don't overlap, but "sin" and "a" may. + cos = fp_cos(a); + sin = fp_sin(a); + } + + template + inline Value_t fp_hypot(Value_t x, Value_t y) { return fp_sqrt(x*x + y*y); } + + template + inline Value_t fp_asinh(Value_t x) + { return fp_log(x + fp_sqrt(x*x + Value_t(1))); } + template + inline Value_t fp_acosh(Value_t x) + { return fp_log(x + fp_sqrt(x*x - Value_t(1))); } + template + inline Value_t fp_atanh(Value_t x) + { return fp_log( (Value_t(1)+x) / (Value_t(1)-x)) * Value_t(0.5); } + + + template + inline Value_t fp_const_pi() // CONSTANT_PI + { + return Value_t(3.1415926535897932384626433832795028841971693993751L); + } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline MpfrFloat fp_const_pi() { return MpfrFloat::const_pi(); } +#endif + + 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_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 + + +// ------------------------------------------------------------------------- +// double +// ------------------------------------------------------------------------- + inline double fp_abs(double x) { return fabs(x); } + inline double fp_acos(double x) { return acos(x); } + inline double fp_asin(double x) { return asin(x); } + inline double fp_atan(double x) { return atan(x); } + inline double fp_atan2(double x, double y) { return atan2(x, y); } +#ifdef FP_SUPPORT_CBRT + inline double fp_cbrt(double x) { return cbrt(x); } +#else + inline double fp_cbrt(double x) { return x>0 ? exp(log( x)/3.0) + : x<0 ? -exp(log(-x)/3.0) + : 0.0; } +#endif + inline double fp_ceil(double x) { return ceil(x); } + inline double fp_cos(double x) { return cos(x); } + inline double fp_cosh(double x) { return cosh(x); } + inline double fp_exp(double x) { return exp(x); } + inline double fp_floor(double x) { return floor(x); } + inline double fp_int(double x) { return floor(x + .5); } + inline double fp_log(double x) { return log(x); } + inline double fp_log10(double x) + { return log(x) * + 0.434294481903251827651128918916605082294397005803666566; } + inline double fp_mod(double x, double y) { return fmod(x, y); } + inline double fp_sin(double x) { return sin(x); } + inline double fp_sinh(double x) { return sinh(x); } + inline double fp_sqrt(double x) { return sqrt(x); } + inline double fp_tan(double x) { return tan(x); } + inline double fp_tanh(double x) { return tanh(x); } + +#ifdef FP_SUPPORT_ASINH + inline double fp_asinh(double x) { return asinh(x); } + inline double fp_acosh(double x) { return acosh(x); } + inline double fp_atanh(double x) { return atanh(x); } +#endif // FP_SUPPORT_ASINH +#ifdef FP_SUPPORT_HYPOT + inline double fp_hypot(double x, double y) { return hypot(x,y); } +#endif + + inline double fp_trunc(double x) { return x<0.0 ? ceil(x) : floor(x); } + + inline double fp_pow_base(double x, double y) { return pow(x, y); } + +#ifndef FP_SUPPORT_LOG2 + inline double fp_log2(double x) + { return log(x) * 1.4426950408889634073599246810018921374266459541529859; } +#else + inline double fp_log2(double x) { return log2(x); } +#endif // FP_SUPPORT_LOG2 + + inline double fp_exp2(double x) { return fp_pow(2.0, x); } + +#ifdef FP_EPSILON + template + inline Value_t fp_epsilon() { return FP_EPSILON; } +#else + template + inline Value_t fp_epsilon() { return 0.0; } +#endif + + #ifdef _GNU_SOURCE + template<> + inline void fp_sinCos(double& sin, double& cos, const double& a) + { + sincos(a, &sin, &cos); + } + #endif + +// ------------------------------------------------------------------------- +// float +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_FLOAT_TYPE + inline float fp_abs(float x) { return fabsf(x); } + inline float fp_acos(float x) { return acosf(x); } + inline float fp_asin(float x) { return asinf(x); } + inline float fp_atan(float x) { return atanf(x); } + inline float fp_atan2(float x, float y) { return atan2f(x, y); } +#ifdef FP_SUPPORT_CBRT + inline float fp_cbrt(float x) { return cbrtf(x); } +#else + inline float fp_cbrt(float x) { return x>0 ? expf(logf( x)/3.0f) + : x<0 ? -expf(logf(-x)/3.0f) + : 0.0f; } +#endif + inline float fp_ceil(float x) { return ceilf(x); } + inline float fp_cos(float x) { return cosf(x); } + inline float fp_cosh(float x) { return coshf(x); } + inline float fp_exp(float x) { return expf(x); } + inline float fp_floor(float x) { return floorf(x); } + inline float fp_int(float x) { return floorf(x + .5F); } + inline float fp_log(float x) { return logf(x); } + inline float fp_log10(float x) + { return logf(x) * + 0.434294481903251827651128918916605082294397005803666566F; } + inline float fp_mod(float x, float y) { return fmodf(x, y); } + inline float fp_sin(float x) { return sinf(x); } + inline float fp_sinh(float x) { return sinhf(x); } + inline float fp_sqrt(float x) { return sqrtf(x); } + inline float fp_tan(float x) { return tanf(x); } + inline float fp_tanh(float x) { return tanhf(x); } + +#ifdef FP_SUPPORT_ASINH + inline float fp_asinh(float x) { return asinhf(x); } + inline float fp_acosh(float x) { return acoshf(x); } + inline float fp_atanh(float x) { return atanhf(x); } +#endif // FP_SUPPORT_ASINH +#ifdef FP_SUPPORT_HYPOT + inline float fp_hypot(float x, float y) { return hypotf(x,y); } +#endif + + inline float fp_trunc(float x) { return x<0.0F ? ceilf(x) : floorf(x); } + + inline float fp_pow_base(float x, float y) { return powf(x, y); } + +#ifndef FP_SUPPORT_LOG2 + inline float fp_log2(float x) + { return logf(x) * + 1.4426950408889634073599246810018921374266459541529859F; } +#else + inline float fp_log2(float x) { return log2f(x); } +#endif // FP_SUPPORT_LOG2 + + inline float fp_exp2(float x) { return fp_pow(2.0F, x); } + +#ifdef FP_EPSILON + template<> + inline float fp_epsilon() { return 1e-6F; } +#else + template<> + inline float fp_epsilon() { return 0.0F; } +#endif + +#endif // FP_SUPPORT_FLOAT_TYPE + #ifdef _GNU_SOURCE + template<> + inline void fp_sinCos(float& sin, float& cos, const float& a) + { + sincosf(a, &sin, &cos); + } + #endif + + + +// ------------------------------------------------------------------------- +// long double +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + inline long double fp_abs(long double x) { return fabsl(x); } + inline long double fp_acos(long double x) { return acosl(x); } + inline long double fp_asin(long double x) { return asinl(x); } + inline long double fp_atan(long double x) { return atanl(x); } + inline long double fp_atan2(long double x, long double y) + { return atan2l(x, y); } +#ifdef FP_SUPPORT_CBRT + inline long double fp_cbrt(long double x) { return cbrtl(x); } +#else + inline long double fp_cbrt(long double x) + { return x>0 ? expl(logl( x)/3.0l) + : x<0 ? -expl(logl(-x)/3.0l) + : 0.0l; } +#endif + inline long double fp_ceil(long double x) { return ceill(x); } + inline long double fp_cos(long double x) { return cosl(x); } + inline long double fp_cosh(long double x) { return coshl(x); } + inline long double fp_exp(long double x) { return expl(x); } + inline long double fp_floor(long double x) { return floorl(x); } + inline long double fp_int(long double x) { return floorl(x + .5L); } + inline long double fp_log(long double x) { return logl(x); } + inline long double fp_log10(long double x) + { return logl(x) * + 0.434294481903251827651128918916605082294397005803666566L; } + inline long double fp_mod(long double x, long double y) + { return fmodl(x, y); } + inline long double fp_sin(long double x) { return sinl(x); } + inline long double fp_sinh(long double x) { return sinhl(x); } + inline long double fp_sqrt(long double x) { return sqrtl(x); } + inline long double fp_tan(long double x) { return tanl(x); } + inline long double fp_tanh(long double x) { return tanhl(x); } + +#ifdef FP_SUPPORT_ASINH + inline long double fp_asinh(long double x) { return asinhl(x); } + inline long double fp_acosh(long double x) { return acoshl(x); } + inline long double fp_atanh(long double x) { return atanhl(x); } +#endif // FP_SUPPORT_ASINH +#ifdef FP_SUPPORT_HYPOT + inline long double fp_hypot(long double x, long double y) { return hypotl(x,y); } +#endif + + inline long double fp_trunc(long double x) + { return x<0.0L ? ceill(x) : floorl(x); } + + inline long double fp_pow_base(long double x, long double y) + { return powl(x, y); } + +#ifndef FP_SUPPORT_LOG2 + inline long double fp_log2(long double x) + { return fp_log(x) * 1.4426950408889634073599246810018921374266459541529859L; } +#else + inline long double fp_log2(long double x) { return log2l(x); } +#endif // FP_SUPPORT_LOG2 + + inline long double fp_exp2(long double x) { return fp_pow(2.0L, x); } + +#endif // FP_SUPPORT_LONG_DOUBLE_TYPE + + #ifdef _GNU_SOURCE + template<> + inline void fp_sinCos(long double& sin, long double& cos, const long double& a) + { + sincosl(a, &sin, &cos); + } + #endif + + +// ------------------------------------------------------------------------- +// Long int +// ------------------------------------------------------------------------- + inline long fp_abs(long x) { return x < 0 ? -x : x; } + inline long fp_acos(long) { return 0; } + inline long fp_asin(long) { return 0; } + inline long fp_atan(long) { return 0; } + inline long fp_atan2(long, long) { return 0; } + inline long fp_cbrt(long) { return 0; } + inline long fp_ceil(long x) { return x; } + inline long fp_cos(long) { return 0; } + inline long fp_cosh(long) { return 0; } + inline long fp_exp(long) { return 0; } + inline long fp_floor(long x) { return x; } + inline long fp_int(long x) { return x; } + inline long fp_log(long) { return 0; } + inline long fp_log10(long) { return 0; } + inline long fp_mod(long x, long y) { return x % y; } + inline long fp_pow(long, long) { return 0; } + inline long fp_sin(long) { return 0; } + inline long fp_sinh(long) { return 0; } + inline long fp_sqrt(long) { return 1; } + inline long fp_tan(long) { return 0; } + inline long fp_tanh(long) { return 0; } + inline long fp_asinh(long) { return 0; } + inline long fp_acosh(long) { return 0; } + inline long fp_atanh(long) { return 0; } + inline long fp_trunc(long x) { return x; } + inline long fp_pow_base(long, long) { return 0; } + inline long fp_log2(long) { return 0; } + inline long fp_exp2(long) { return 0; } + + template<> + inline long fp_epsilon() { return 0; } + + +// ------------------------------------------------------------------------- +// MpfrFloat +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + inline MpfrFloat fp_abs(const MpfrFloat& x) { return MpfrFloat::abs(x); } + inline MpfrFloat fp_acos(const MpfrFloat& x) { return MpfrFloat::acos(x); } + inline MpfrFloat fp_asin(const MpfrFloat& x) { return MpfrFloat::asin(x); } + inline MpfrFloat fp_atan(const MpfrFloat& x) { return MpfrFloat::atan(x); } + inline MpfrFloat fp_atan2(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::atan2(x, y); } + inline MpfrFloat fp_cbrt(const MpfrFloat& x) { return MpfrFloat::cbrt(x); } + inline MpfrFloat fp_ceil(const MpfrFloat& x) { return MpfrFloat::ceil(x); } + inline MpfrFloat fp_cos(const MpfrFloat& x) { return MpfrFloat::cos(x); } + inline MpfrFloat fp_cosh(const MpfrFloat& x) { return MpfrFloat::cosh(x); } + inline MpfrFloat fp_exp(const MpfrFloat& x) { return MpfrFloat::exp(x); } + inline MpfrFloat fp_floor(const MpfrFloat& x) { return MpfrFloat::floor(x); } + inline MpfrFloat fp_hypot(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::hypot(x, y); } + inline MpfrFloat fp_int(const MpfrFloat& x) { return MpfrFloat::round(x); } + inline MpfrFloat fp_log(const MpfrFloat& x) { return MpfrFloat::log(x); } + inline MpfrFloat fp_log10(const MpfrFloat& x) { return MpfrFloat::log10(x); } + inline MpfrFloat fp_mod(const MpfrFloat& x, const MpfrFloat& y) { return x % y; } + inline MpfrFloat fp_sin(const MpfrFloat& x) { return MpfrFloat::sin(x); } + inline MpfrFloat fp_sinh(const MpfrFloat& x) { return MpfrFloat::sinh(x); } + inline MpfrFloat fp_sqrt(const MpfrFloat& x) { return MpfrFloat::sqrt(x); } + inline MpfrFloat fp_tan(const MpfrFloat& x) { return MpfrFloat::tan(x); } + inline MpfrFloat fp_tanh(const MpfrFloat& x) { return MpfrFloat::tanh(x); } + inline MpfrFloat fp_asinh(const MpfrFloat& x) { return MpfrFloat::asinh(x); } + inline MpfrFloat fp_acosh(const MpfrFloat& x) { return MpfrFloat::acosh(x); } + inline MpfrFloat fp_atanh(const MpfrFloat& x) { return MpfrFloat::atanh(x); } + inline MpfrFloat fp_trunc(const MpfrFloat& x) { return MpfrFloat::trunc(x); } + + inline MpfrFloat fp_pow(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + inline MpfrFloat fp_pow_base(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + + inline MpfrFloat fp_log2(const MpfrFloat& x) { return MpfrFloat::log2(x); } + inline MpfrFloat fp_exp2(const MpfrFloat& x) { return MpfrFloat::exp2(x); } + + template<> + inline void fp_sinCos(MpfrFloat& sin, MpfrFloat& cos, const MpfrFloat& a) + { + MpfrFloat::sincos(a, sin, cos); + } + + 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(GmpInt x) { return GmpInt::abs(x); } + inline GmpInt fp_acos(GmpInt) { return 0; } + inline GmpInt fp_asin(GmpInt) { return 0; } + inline GmpInt fp_atan(GmpInt) { return 0; } + inline GmpInt fp_atan2(GmpInt, GmpInt) { return 0; } + inline GmpInt fp_cbrt(GmpInt) { return 0; } + inline GmpInt fp_ceil(GmpInt x) { return x; } + inline GmpInt fp_cos(GmpInt) { return 0; } + inline GmpInt fp_cosh(GmpInt) { return 0; } + inline GmpInt fp_exp(GmpInt) { return 0; } + inline GmpInt fp_floor(GmpInt x) { return x; } + inline GmpInt fp_hypot(GmpInt, GmpInt) { return 0; } + inline GmpInt fp_int(GmpInt x) { return x; } + inline GmpInt fp_log(GmpInt) { return 0; } + inline GmpInt fp_log10(GmpInt) { return 0; } + inline GmpInt fp_mod(GmpInt x, GmpInt y) { return x % y; } + inline GmpInt fp_pow(GmpInt, GmpInt) { return 0; } + inline GmpInt fp_sin(GmpInt) { return 0; } + inline GmpInt fp_sinh(GmpInt) { return 0; } + inline GmpInt fp_sqrt(GmpInt) { return 0; } + inline GmpInt fp_tan(GmpInt) { return 0; } + inline GmpInt fp_tanh(GmpInt) { return 0; } + inline GmpInt fp_asinh(GmpInt) { return 0; } + inline GmpInt fp_acosh(GmpInt) { return 0; } + inline GmpInt fp_atanh(GmpInt) { return 0; } + inline GmpInt fp_trunc(GmpInt x) { return x; } + inline GmpInt fp_pow_base(GmpInt, GmpInt) { return 0; } + inline GmpInt fp_log2(GmpInt) { return 0; } + inline GmpInt fp_exp2(GmpInt) { return 0; } + + template<> + inline GmpInt fp_epsilon() { return 0; } +#endif // FP_SUPPORT_GMP_INT_TYPE + + +// ------------------------------------------------------------------------- +// Comparison +// ------------------------------------------------------------------------- +#ifdef FP_EPSILON + 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()); } +#else // FP_EPSILON + template + inline bool fp_equal(const Value_t& x, const Value_t& y) { return x == y; } + + template + inline bool fp_nequal(const Value_t& x, const Value_t& y) { return x != y; } + + template + inline bool fp_less(const Value_t& x, const Value_t& y) { return x < y; } + + template + inline bool fp_lessOrEq(const Value_t& x, const Value_t& y) { return x <= y; } +#endif // 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 != 0 + : fp_abs(d) >= Value_t(0.5); + } + + template + inline bool fp_absTruth(const Value_t& abs_d) + { + return IsIntType::result + ? abs_d > 0 + : 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)); } + + ///////////// + /* Opcode analysis functions are used by fp_opcode_add.inc */ + /* Moved here from fparser.cc because fp_opcode_add.inc + * is also now included by fpoptimizer.cc + */ + bool IsLogicalOpcode(unsigned op); + bool IsComparisonOpcode(unsigned op); + unsigned OppositeComparisonOpcode(unsigned op); + bool IsNeverNegativeValueOpcode(unsigned op); + bool IsAlwaysIntegerOpcode(unsigned op); + bool IsUnaryOpcode(unsigned op); + bool IsBinaryOpcode(unsigned op); + bool HasInvalidRangesOpcode(unsigned op); + + template + inline Value_t DegreesToRadians(Value_t degrees) + { + return degrees * fp_const_deg_to_rad(); + } + + template + inline Value_t RadiansToDegrees(Value_t radians) + { + return radians * fp_const_rad_to_deg(); + } + + template + inline bool isEvenInteger(Value_t value) + { + const Value_t halfValue = value * Value_t(0.5); + return fp_equal(halfValue, fp_floor(halfValue)); + } + + template + inline bool isInteger(Value_t value) + { + return fp_equal(value, fp_floor(value)); + } + + // Is value an integer that fits in "long" datatype? + template + inline bool isLongInteger(Value_t value) + { + return value == Value_t( makeLongInteger(value) ); + } + + template + inline long makeLongInteger(Value_t value) + { + return (long) fp_int(value); + } + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline bool isEvenInteger(long value) + { + return value%2 == 0; + } + + template<> + inline bool isInteger(long) { return true; } + + template<> + inline bool isLongInteger(long) { return true; } + + template<> + inline long makeLongInteger(long value) + { + return value; + } +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline bool isInteger(MpfrFloat value) { return value.isInteger(); } + + template<> + inline bool isEvenInteger(MpfrFloat value) + { + return isInteger(value) && value%2 == 0; + } + + template<> + inline long makeLongInteger(MpfrFloat value) + { + return (long) value.toInt(); + } +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool isEvenInteger(GmpInt value) + { + return value%2 == 0; + } + + template<> + inline bool isInteger(GmpInt) { return true; } + + template<> + inline long makeLongInteger(GmpInt value) + { + return (long) value.toInt(); + } +#endif + + template + inline bool isOddInteger(Value_t value) + { + const Value_t halfValue = (value + Value_t(1)) * Value_t(0.5); + return fp_equal(halfValue, fp_floor(halfValue)); + } + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline bool isOddInteger(long value) + { + return value%2 != 0; + } +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline bool isOddInteger(MpfrFloat value) + { + return value.isInteger() && value%2 != 0; + } +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool isOddInteger(GmpInt value) + { + return value%2 != 0; + } +#endif +} // namespace FUNCTIONPARSERTYPES + +#endif // ONCE_FPARSER_H_ + + +#ifndef FP_DISABLE_DOUBLE_TYPE +# define FUNCTIONPARSER_INSTANTIATE_D(g) g(double) +#else +# define FUNCTIONPARSER_INSTANTIATE_D(g) +#endif + +#ifdef FP_SUPPORT_FLOAT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_F(g) g(float) +#else +# define FUNCTIONPARSER_INSTANTIATE_F(g) +#endif + +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +# define FUNCTIONPARSER_INSTANTIATE_LD(g) g(long double) +#else +# define FUNCTIONPARSER_INSTANTIATE_LD(g) +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_LI(g) g(long) +#else +# define FUNCTIONPARSER_INSTANTIATE_LI(g) +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_MF(g) g(MpfrFloat) +#else +# define FUNCTIONPARSER_INSTANTIATE_MF(g) +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +# define FUNCTIONPARSER_INSTANTIATE_GI(g) g(GmpInt) +#else +# define FUNCTIONPARSER_INSTANTIATE_GI(g) +#endif + +/* Add 'FUNCTIONPARSER_INSTANTIATE_TYPES' at the end of all .cc files + containing FunctionParserBase implementations. + */ +#define FUNCTIONPARSER_INSTANTIATE_BASE(type) \ + template class FunctionParserBase; + +#define FUNCTIONPARSER_INSTANTIATE_TYPES \ + FUNCTIONPARSER_INSTANTIATE_D(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_F(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_LD(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_LI(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_MF(FUNCTIONPARSER_INSTANTIATE_BASE) \ + FUNCTIONPARSER_INSTANTIATE_GI(FUNCTIONPARSER_INSTANTIATE_BASE) + +#endif // ONCE_FPARSER_AUX_H_ diff --git a/fparser/fpconfig.hh b/fparser/fpconfig.hh new file mode 100644 index 0000000..9607a79 --- /dev/null +++ b/fparser/fpconfig.hh @@ -0,0 +1,132 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// Configuration file +// ------------------ + +/* NOTE: + This file is for the internal use of the function parser only. + You don't need to include this file in your source files, just + include "fparser.hh". +*/ + + +/* Uncomment any of these lines or define them in your compiler settings + to enable the correspondent version of the parser. (These are disabled + by default because they rely on C99 functions, and non-standard libraries + in the case pf MPFR and GMP, and they make compiling needlessly slower + and the resulting binary needlessly larger if they are not used in the + program.) +*/ +//#define FP_SUPPORT_FLOAT_TYPE +//#define FP_SUPPORT_LONG_DOUBLE_TYPE +//#define FP_SUPPORT_LONG_INT_TYPE +//#define FP_SUPPORT_MPFR_FLOAT_TYPE +//#define FP_SUPPORT_GMP_INT_TYPE + +/* Uncomment this line of define it in your compiler settings if you want + to disable compiling the basic double version of the library, in case + one of the above types is used but not the double type. (If the double + type is not used, then disabling it makes compiling faster and the + resulting binary smaller.) + */ +//#define FP_DISABLE_DOUBLE_TYPE + +/* + Note that these do not change what FunctionParser supports, they only + change how the function is evaluated, potentially making it faster when + these functions are involved. + These will make the source code use asinh(), acosh(), atanh(), exp2() + and log2(). +*/ +//#define FP_SUPPORT_TR1_MATH_FUNCS + +#ifdef FP_SUPPORT_TR1_MATH_FUNCS +#define FP_SUPPORT_ASINH +#define FP_SUPPORT_EXP2 +#define FP_SUPPORT_LOG2 +#define FP_SUPPORT_CBRT +#define FP_SUPPORT_HYPOT +#endif + +/* + Comment out the following line to enable the eval() function, which can + be used in the function string to recursively call the same function. + Note that enabling this function may be dangerous even if the maximum + recursion level is limited because it is still possible to write functions + using it which take enormous amounts of time to evaluate even though the + maximum recursion is never reached. This may be undesirable in some + applications. + Alternatively you can define the FP_ENABLE_EVAL precompiler constant in + your compiler settings. +*/ +#ifndef FP_ENABLE_EVAL +#define FP_DISABLE_EVAL +#endif + + +/* + Maximum recursion level for eval() calls: +*/ +#define FP_EVAL_MAX_REC_LEVEL 1000 + + +/* + Whether to use shortcut evaluation for the & and | operators: +*/ +#ifndef FP_DISABLE_SHORTCUT_LOGICAL_EVALUATION +#define FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION +#endif + +/* + Whether to enable optimizations that may ignore side effects + of if() calls, such as changing if(x,!y,0) into x&!y. + This is basically the polar opposite of "shortcut logical evaluation". + Disabled by default, because it makes eval() rather unsafe. +*/ +#ifdef FP_ENABLE_IGNORE_IF_SIDEEFFECTS +#endif + +/* + Comment out the following lines out if you are not going to use the + optimizer and want a slightly smaller library. The Optimize() method + can still be called, but it will not do anything. + If you are unsure, just leave it. It won't slow down the other parts of + the library. +*/ +#ifndef FP_NO_SUPPORT_OPTIMIZER +#define FP_SUPPORT_OPTIMIZER +#endif + + +/* + Epsilon value used with the comparison operators (must be non-negative): + (Comment it out if you don't want to use epsilon in comparisons. Might + lead to marginally faster evaluation of the comparison operators, but + can introduce inaccuracies in comparisons.) +*/ +#define FP_EPSILON 1e-14 + + +/* + No member function of FunctionParser is thread-safe. Most prominently, + Eval() is not thread-safe. By uncommenting one of these lines the Eval() + function can be made thread-safe at the cost of a possible small overhead. + The second version requires that the compiler supports the alloca() function, + which is not standard, but is faster. + */ +//#define FP_USE_THREAD_SAFE_EVAL +//#define FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA + +/* + Uncomment (or define in your compiler options) to disable evaluation checks. + (Consult the documentation for details.) + */ +//#define FP_NO_EVALUATION_CHECKS diff --git a/fparser/fpoptimizer.cc b/fparser/fpoptimizer.cc new file mode 100644 index 0000000..5245eb7 --- /dev/null +++ b/fparser/fpoptimizer.cc @@ -0,0 +1,10839 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Function optimizer *| +|*-------------------------------------------------------------------------*| +|* Copyright: Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +/* NOTE: + This file contains generated code (from the optimizer sources) and is + not intended to be modified by hand. If you want to modify the optimizer, + download the development version of the library. +*/ + +#include "fpconfig.hh" +#ifdef FP_SUPPORT_OPTIMIZER +#include "fparser.hh" +#include "fptypes.hh" +#define i43 nW1 a), +#define i33 info.yH +#define i23 ,cAtan2 +#define i13 =false; +#define i03 cAbsIf +#define tZ3 "Found " +#define tY3 },{{2, +#define tX3 {if(apos +#define tW3 stackpos +#define tV3 "dup(%u) " +#define tU3 GetOpcode +#define tT3 eR{assert +#define tS3 "%d, cost " +#define tR3 "immed "<< +#define tQ3 mFuncParsers +#define tP3 "PUSH ";xE3( +#define tO3 stderr +#define tN3 sep2=" " +#define tM3 FPHASH_CONST +#define tL3 cache_needed[ +#define tK3 fprintf +#define tJ3 ::cout<<"Applying " +#define tI3 ||tree.tU3 +#define tH3 HANDLE_UNARY_CONST_FUNC +#define tG3 within, +#define tF3 y21){if +#define tE3 c_count +#define tD3 s_count +#define tC3 MaxOp +#define tB3 2)lS 2* +#define tA3 x11.cG3 +#define t93 l7 0,2, +#define t83 +#define cW3 .eW1 n] +#define cV3 eG cK1); +#define cU3 eG yR1 +#define cT3 if(eY1== +#define cS3 ),has_max( +#define cR3 (count +#define cQ3 .empty() +#define cP3 .iH1 a); +#define cO3 GetParamCount(nQ +#define cN3 GetParamCount(); +#define cM3 ;}case +#define cL3 pclone +#define cK3 sim.x3 +#define cJ3 fpdata +#define cI3 cCosh nR +#define cH3 cCosh, +#define cG3 Immeds +#define cF3 l6 1, +#define cE3 x8(tB2 +#define cD3 newpow +#define cC3 change +#define cB3 133,2, +#define cA3 i01 x2 +#define c93 Params +#define c83 Needs +#define c73 byteCode +#define c63 eT1&occ= +#define c53 child) +#define c43 AddFrom( +#define c33 lT1 nE== +#define c23 ;for xK2 +#define c13 tC1 lY1 +#define c03 factor_t +#define yZ3 tree.xJ1 +#define yY3 yA tmp2) +#define yX3 value1 +#define yW3 model. +#define yV3 true;n31 +#define yU3 &&p0.max +#define yT3 p2 eT ifp2 +#define yS3 yJ p2;p2 +#define yR3 cAbsNot +#define yQ3 switch(tX +#define yP3 tZ case +#define yO3 IsNever +#define yN3 }switch +#define yM3 stackptr +#define yL3 nN[++IP] +#define yK3 const xH +#define yJ3 yE cPow) +#define yI3 default_function_handling +#define yH3 cLog);x9 +#define yG3 ;sim.Push( +#define yF3 eS1(0.5) +#define yE3 iJ 1, +#define yD3 [funcno]. +#define yC3 :start_at() +#define yB3 Rehash(tT yA +#define yA3 .size() +#define y93 IsLogicalValue nW1 +#define y83 (tree))e5 +#define y73 stack[stack yA3- +#define y63 stack yL +#define y53 tmp yC 0)) +#define y43 ));tmp tU +#define y33 ,(long tG1 +#define y23 );tmp2 yC +#define y13 cMul);xK +#define y03 1),eS1(1)) +#define xZ3 constvalue +#define xY3 lD 0)); +#define xX3 )nG1 xK +#define xW3 nN[IP]== +#define xV3 opcodes +#define xU3 did_muli +#define xT3 switch(lF3.first iY2 +#define xS3 ;for iL1 +#define xR3 Ge0Lt1 +#define xQ3 &&p.max +#define xP3 :tree. +#define xO3 =y6 a));if( +#define xN3 used[b] +#define xM3 e8(),yG< +#define xL3 size_t n +#define xK3 sizeof( +#define xJ3 cNotNot, +#define xI3 cOr yF +#define xH3 359463, +#define xG3 2,7168, +#define xF3 param. +#define xE3 DumpTree +#define xD3 Gt0Le1 +#define xC3 y21){eS1 +#define xB3 base,eS1 +#define xA3 ==cOr)l9 +#define x93 cAdd iU1 +#define x83 (cM2 lD +#define x73 lD 2)); +#define x63 eT cond +#define x53 iX2 0;b< +#define x43 {}range( +#define x33 .n_int_sqrt +#define x23 ,cPow,xJ +#define x13 ,{1,218, +#define x03 lD 1)) +#define nZ3 tmp yA tree +#define nY3 eS1(1))) +#define nX3 iterator +#define nW3 begin(); +#define nV3 TreeSet +#define nU3 parent +#define nT3 insert(i +#define nS3 newrel +#define nR3 eS1(2))); +#define nQ3 {eS1 tmp +#define nP3 iU.hash1 +#define nO3 (tree)!= +#define nN3 )n5 lC +#define nM3 break;} +#define nL3 b_needed +#define nK3 cachepos +#define nJ3 half= +#define nI3 src_pos +#define nH3 reserve( +#define nG3 treeptr +#define nF3 iC2 size() +#define nE3 .resize( +#define nD3 eU1 void +#define nC3 ImmedTag +#define nB3 a,const +#define nA3 RefCount +#define n93 Birth(); +#define n83 mulgroup +#define n73 template +#define n63 cost_t +#define n53 n72 nZ +#define n43 middle +#define n33 ))break;eS1 +#define n23 };enum +#define n13 if(op== +#define n03 (p1.xJ1 +#define lZ3 cLog2by); +#define lY3 sqrt_cost +#define lX3 const int +#define lW3 mul_count +#define lV3 maxValue1 +#define lU3 minValue1 +#define lT3 maxValue0 +#define lS3 minValue0 +#define lR3 ValueType +#define lQ3 >(eS1(1), +#define lP3 abs_mul +#define lO3 pos_set +#define lN3 goto e3 +#define lM3 nF1);}if( +#define lL3 yE cAdd); +#define lK3 subtree +#define lJ3 invtree +#define lI3 lV1=r.specs;if(r.found){ +#define lH3 ,lV1,info +#define lG3 a;if(&t91 +#define lF3 parampair +#define lE3 rulenumit +#define lD3 cIf,l6 3, +#define lC3 MakeEqual +#define lB3 nH1,l4:: +#define lA3 nH1,{l4:: +#define l93 newbase +#define l83 branch1op +#define l73 branch2op +#define l63 overlap +#define l53 truth_a +#define l43 ),Value( +#define l33 );nW l4:: +#define l23 if nW1 0) +#define l13 found_dup +#define l03 &1)?(poly^( +#define iZ2 (xF3 +#define iY2 ){case +#define iX2 size_t b= +#define iW2 i0 xQ3 +#define iV2 has_min +#define iU2 Plan_Has( +#define iT2 ;if(half +#define iS2 ;}void +#define iR2 )iS2 +#define iQ2 const nI2 +#define iP2 yV1 class +#define iO2 namespace +#define iN2 rhs.hash2;} +#define iM2 rhs.hash1 +#define iL2 ::res,b8< +#define iK2 inverted +#define iJ2 has_max= +#define iI2 has_max) +#define iH2 iftree +#define iG2 depcodes +#define iF2 explicit +#define iE2 VarBegin +#define iD2 cM3 lZ2 +#define iC2 c93. +#define iB2 ].data); +#define iA2 y4)));nW +#define i92 .what eX +#define i82 ;if(fp_equal( +#define i72 x02 yJ +#define i62 begin(), +#define i52 cond_add +#define i42 cond_mul +#define i32 cond_and +#define i22 yG n91 +#define i12 bool e31 +#define i02 unsigned +#define tZ2 costree +#define tY2 sintree +#define tX2 leaf_count +#define tW2 =GetParam( +#define tV2 sub_params +#define tU2 printf( +#define tT2 cbrt_count +#define tS2 sqrt_count +#define tR2 Finite +#define tQ2 p1 eT ifp1 +#define tP2 pcall_tree +#define tO2 after_powi +#define tN2 grammar +#define tM2 lE 0,1, +#define tL2 cCos,xJ +#define tK2 cEqual, +#define tJ2 ,eO3 507 tS +#define tI2 ,t71 l7 2,2, +#define tH2 cLog nR +#define tG2 l0 2, +#define tF2 cPow,nU +#define tE2 cAdd,xZ 2, +#define tD2 cInv,xZ 1, +#define tC2 cNeg,xZ 1, +#define tB2 ),0},{ +#define tA2 x11.SubTrees +#define t92 x11.Others +#define t82 param=*i01 +#define t72 std::move( +#define t62 nM3 switch( +#define t52 constraints= +#define t42 .constraints +#define t32 data;data. +#define t22 MakeNEqual +#define t12 for yS eC1 +#define t02 yA mul) +#define eZ2 Dump(std:: +#define eY2 isInteger( +#define eX2 (cond.cI cA2 +#define eW2 yA3;++ +#define eV2 nG1 r;r tU +#define eU2 Comparison +#define eT2 needs_flip +#define eS2 {data xB lM +#define eR2 ,eQ,synth); +#define eQ2 (half&63)-1; +#define eP2 value] +#define eO2 ));TriTruthValue +#define eN2 );range.nN2 +#define eM2 ,2,1,4,1,2, +#define eL2 >StackMax) +#define eK2 ~size_t(0) +#define eJ2 );t4=!t4;} +#define eI2 ;}yV1 static +#define eH2 info.lQ[b]. +#define eG2 const std::eO +#define eF2 Rule&rule, +#define eE2 .GetHash(). +#define eD2 (list.first +#define eC2 ;iU.hash2+= +#define eB2 ,xA1);lC +#define eA2 ,const e1& +#define e92 struct +#define e82 cGreater, +#define e72 tree lD 0) +#define e62 const eS1& +#define e52 mul_item +#define e42 innersub +#define e32 cbrt_cost +#define e22 best_cost +#define e12 )))l81 lH +#define e02 result i0 +#define cZ2 fp_mod(m. +#define cY2 Compare> +#define cX2 (*x6)[a].info +#define cW2 tree y21 yI +#define cV2 tree nE== +#define cU2 condition +#define cT2 per_item +#define cS2 item_type +#define cR2 first2 +#define cQ2 ,l8 0,2, +#define cP2 tS 396676 +#define cO2 Decision +#define cN2 not_tree +#define cM2 leaf1 +#define cL2 =tree lD +#define cK2 group_by +#define cJ2 ->second +#define cI2 targetpos +#define cH2 eat_count +#define cG2 ParamSpec +#define cF2 Forget() +#define cE2 exponent +#define cD2 ,bool abs){ +#define cC2 synth.Find( +#define cB2 params +#define cA2 &&cond eH)) +#define c92 source_tree +#define c82 nE==cLog2&& +#define c72 =lT1;bool iQ +#define c62 +#define c52 p1_evenness +#define c42 c32 i13 if( +#define c32 tC1 iV2 +#define c22 isNegative( +#define c12 n73 i5 +#define c02 neg_set +#define yZ2 StackTopIs( +#define yY2 cNop,cNop}} +#define yX2 synth.PushImmed( +#define yW2 FPoptimizer_ByteCode yU2 +#define yV2 FPoptimizer_ByteCode:: +#define yU2 ::ByteCodeSynth x8 +#define yT2 cTanh,cNop, +#define yS2 matches +#define yR2 goto fail;} +#define yQ2 cSin,xJ +#define yP2 cTan nR +#define yO2 cCos nR +#define yN2 negated +#define yM2 i7,1,iX+1); +#define yL2 CodeTree +#define yK2 yL2 x8 +#define yJ2 ifdata +#define yI2 best_score +#define yH2 mulvalue +#define yG2 pow_item +#define yF2 nE==cPow&&tJ +#define yE2 PowiResult +#define yD2 maxValue +#define yC2 minValue +#define yB2 ;pow tU cPow);pow +#define yA2 result cM3 +#define y92 fp_min(xA, +#define y82 set_min_max( +#define y72 div_tree +#define y62 pow_tree +#define y52 preserve +#define y42 PullResult() +#define y32 dup_or_fetch +#define y22 nominator] +#define y12 Rehash(false +#define y02 test_order +#define xZ2 lF3, +#define xY2 .param_count +#define xX2 shift(index) +#define xW2 rulenumber +#define xV2 cTanh nR +#define xU2 (tree nE +#define xT2 GetDepth() +#define xS2 factor_immed +#define xR2 changes +#define xQ2 tU tree nE); +#define xP2 tU cond nE +#define xO2 Become nW1 +#define xN2 },0,0x1},{{1, +#define xM2 ,lJ 0x7 tY3 +#define xL2 ;n41 eT y9 lD +#define xK2 (size_t a= +#define xJ2 ;}static yN1 +#define xI2 tree lD a) +#define xH2 for(typename +#define xG2 exp_diff +#define xF2 ExponentInfo +#define xE2 lower_bound( +#define xD2 factor +#define xC2 is_logical +#define xB2 newrel_and +#define xA2 Suboptimal +#define x92 cW[c tO +#define x82 IsAlways;if( +#define x72 n73 nA1 +#define x62 res_stackpos +#define x52 half_pos +#define x42 ;}else{x6=new +#define x32 )lS 3* +#define x22 {e1 start_at; +#define x12 ,(long double) +#define x02 .Rehash() +#define nZ2 )return +#define nY2 );cK3 iJ 2, +#define nX2 return false;} +#define nW2 );nM3 +#define nV2 xD1 tA+1); +#define nU2 ;i7.Remember( +#define nT2 .match_tree +#define nS2 l81 true;} +#define nR2 nD OPCODE +#define nQ2 yG x8&immed, +#define nP2 >>1)):( +#define nO2 CodeTreeData +#define nN2 multiply( +#define nM2 i0 i13 +#define nL2 .n73 +#define nK2 var_trees +#define nJ2 cOr,lP 2, +#define nI2 yL2& +#define nH2 ::Optimize(){ +#define nG2 second eE3; +#define nF2 second.first; +#define nE2 log2_exponent +#define nD2 tT.swap(tmp); +#define nC2 Value(Value:: +#define nB2 dup_fetch_pos +#define nA2 nN,size_t&l31 +#define n92 *)&*start_at; +#define n82 yO3 yI lC +#define n72 ,tree)) +#define n62 ContainsOtherCandidates( +#define n52 ,cPow l7 2,2, +#define n42 cSin nR +#define n32 lK 2},0,iR 1, +#define n22 lK 1},0,iR 1, +#define n12 Value_EvenInt +#define n02 Sign_Negative +#define lZ2 SubFunction:{ +#define lY2 ParamHolder:{ +#define lX2 MakeFalse,{l4 +#define lW2 if(xW lD a)iA +#define lV2 ConditionType +#define lU2 SpecialOpcode +#define lT2 synth_it +#define lS2 fp_max(xA); +#define lR2 assimilated +#define lQ2 fraction +#define lP2 0x12},{{ +#define lO2 DUP_BOTH(); +#define lN2 -1-offset]. +#define lM2 tU3() +#define lL2 parent_opcode) +#define lK2 TreeCounts +#define lJ2 bool t4 i13 +#define lI2 SetOpcode( +#define lH2 found_log2 +#define lG2 div_params +#define lF2 .CopyOnWrite() +#define lE2 immed_sum +#define lD2 OPCODE(opcode) +#define lC2 std::cout<<"POP " +#define lB2 (stack yA3- +#define lA2 break;result*= +#define l92 FactorStack x8 +#define l82 IsAlways yI lC +#define l72 l7 2,2,lB1 +#define l62 248024 tS +#define l52 cAnd,lP 2, +#define l42 cNot nR +#define l32 cMul,xZ 2, +#define l22 DumpHashesFrom +#define l12 replacing_slot +#define l02 RefParams +#define iZ1 if_always[ +#define iY1 WhatDoWhenCase +#define iX1 exponent_immed +#define iW1 new_base_immed +#define iV1 base_immed +#define iU1 ||op1== +#define iT1 (size_t a xX +#define iS1 data[a eD3 +#define iR1 AddCollection( +#define iQ1 if(newrel_or== +#define iP1 DUP_ONE(apos); +#define iO1 flipped +#define iN1 .UseGetNeeded( +#define iM1 e9 2,131, +#define iL1 (i02 +#define iK1 OptimizedUsing +#define iJ1 Var_or_Funcno +#define iI1 iJ1; +#define iH1 DelParam( +#define iG1 typename nX1::nX3 +#define iF1 )nZ2 true +#define iE1 GetParams( +#define iD1 crc32_t +#define iC1 fphash_value_t +#define iB1 signed_chain +#define iA1 IsDefined()) +#define i91 MinusInf +#define i81 n_immeds +#define i71 FindClone(xK +#define i61 denominator] +#define i51 needs_rehash +#define i41 AnyWhere_Rec +#define i31 minimum_need +#define i21 ~i02(0) +#define i11 tC1 min +#define i01 (const +#define tZ1 ,i01 void*)& +#define tY1 41,42,43,44, +#define tX1 constraints& +#define tW1 tT.iH1 +#define tV1 p1_logical_b +#define tU1 p0_logical_b +#define tT1 p1_logical_a +#define tS1 p0_logical_a +#define tR1 ,PowiCache&i7, +#define tQ1 synth.DoDup( +#define tP1 else if( +#define tO1 cache_needed +#define tN1 e9 2,1,e9 2, +#define tM1 treelist +#define tL1 IsDescendantOf( +#define tK1 has_bad_balance +#define tJ1 (tree,std::cout) +#define tI1 .SetParamsMove( +#define tH1 c03 xD2 +#define tG1 double)cE2 +#define tF1 {case IsAlways: +#define tE1 e02=false +#define tD1 ;cE2.Rehash( +#define tC1 result. +#define tB1 range x8 result +#define tA1 TopLevel) +#define t91 *start_at){x6=( +#define t81 (rule,tree,info +#define t71 cNEqual +#define t61 ,cEqual l7 2,2, +#define t51 cAdd,AnyParams, +#define t41 lP2 xG3 +#define t31 ,cNotNot nR +#define t21 ,cLess l7 2,2, +#define t11 Oneness_NotOne| +#define t01 Value_IsInteger +#define eZ1 iK1( +#define eY1 reltype +#define eX1 SequenceOpcodes +#define eW1 sep_list[ +#define eV1 );eG n83); +#define eU1 l02); +#define eT1 TreeCountItem +#define eS1 Value_t +#define eR1 divgroup +#define eQ1 ,eS1(-1)))xF +#define eP1 set_min(fp_floor +#define eO1 pihalf_limits +#define eN1 y41 p0.min>=0.0) +#define eM1 MaxChildDepth +#define eL1 situation_flags& +#define eK1 i02 opcode) +#define eJ1 =yM|i02(nN yA3 +#define eI1 std::pair +#define eH1 eO3 483 tS +#define eG1 ,l8 0,1, +#define eF1 tG2 7168, +#define eE1 Value_Logical +#define eD1 new_factor_immed +#define eC1 if(remaining[a]) +#define eB1 occurance_pos +#define eA1 exponent_hash +#define e91 exponent_list +#define e81 CollectionSet x8 +#define e71 CollectMulGroup( +#define e61 source_set +#define e51 cE2,nV3 +#define e41 produce_count +#define e31 operator +#define e21 )yJ3;lC +#define e11 back().thenbranch +#define e01 ParamSpec_Extract +#define cZ1 retry_anyparams_3 +#define cY1 retry_anyparams_2 +#define cX1 needlist_cached_t +#define cW1 grammar_rules[*r] +#define cV1 tF2 0x1 tY3 +#define cU1 CodeTreeImmed x8( +#define cT1 GetParamCount()== +#define cS1 by_float_exponent +#define cR1 fp_equal(cE2 +#define cQ1 new_exp +#define cP1 end()&&i->first== +#define cO1 yB3 r);} +#define cN1 return BecomeZero; +#define cM1 return BecomeOne; +#define cL1 if(lQ yA3<=n2) +#define cK1 addgroup +#define cJ1 found_log2by +#define cI1 ())yE cMul);lC +#define cH1 >=eS1(0) +#define cG1 nE==yR3) +#define cF1 ParsePowiMuli( +#define cE1 branch1_backup +#define cD1 branch2_backup +#define cC1 exponent_map +#define cB1 plain_set +#define cA1 LightWeight( +#define c91 }nM3 case +#define c81 cN3++b) +#define c71 synth.x5 1 +#define c61 ,i7 eR2 +#define c51 if(value +#define c41 set_max(fp_ceil cY +#define c31 e62 v,n7 +#define c21 {eS1 cE2= +#define c11 should_regenerate=true; +#define c01 should_regenerate, +#define yZ1 Collection +#define yY1 RelationshipResult +#define yX1 Subdivide_Combine( +#define yW1 long value +#define yV1 n73 lT +#define yU1 yV1 cA +#define yT1 yV1 e92 +#define yS1 eP nE3 StackMax +#define yR1 subgroup +#define yQ1 best_sep_factor +#define yP1 tP1!result +#define yO1 needlist_cached +#define yN1 inline i02 +#define yM1 221646 tS 24803 +#define yL1 Constness_Const +#define yK1 opcode,bool pad +#define yJ1 n_occurrences +#define yI1 changed=true; +#define yH1 iH1 a);} +#define yG1 MakesInteger( +#define yF1 e62 value +#define yE1 best_sep_cost +#define yD1 MultiplicationRange +#define yC1 ;p1.yB3 p1 +#define yB1 yV1 eS1 +#define yA1 n_stacked +#define y91 AnyParams_Rec +#define y81 continue; +#define y71 Become(value lD 0)) +#define y61 ,cGreater l7 2,2, +#define y51 yV1 inline TriTruthValue +#define y41 .iV2&& +#define y31 ));n41 y3 op1 tT.DelParams( +#define y21 .IsImmed() +#define y11 =comp.AddItem(atree +#define y01 needs_sincos +#define xZ1 Recheck_RefCount_Div +#define xY1 Recheck_RefCount_Mul +#define xX1 n83. +#define xW1 n83;n83 tU +#define xV1 MultiplyAndMakeLong( +#define xU1 cMul);y53;tmp +#define xT1 covers_plus1 +#define xS1 lD2); +#define xR1 if(synth.FindAndDup( +#define xQ1 SynthesizeParam( +#define xP1 public e8,public yG< +#define xO1 grammar_func +#define xN1 221426 tS 237795 +#define xM1 t93 165888 tS +#define xL1 Modulo_Radians}, +#define xK1 tT.SetParam( +#define xJ1 GetImmed() +#define xI1 PositionType +#define xH1 CollectionResult +#define xG1 yV1 bool +#define xF1 const_offset +#define xE1 stacktop_desired +#define xD1 SetStackTop( +#define xC1 ,cLessOrEq l7 2,2, +#define xB1 yV1 void +#define xA1 cond_type +#define x91 Recheck_RefCount_RDiv +#define x81 static const range x8 +#define x71 fPExponentIsTooLarge( +#define x61 CollectMulGroup_Item( +#define x51 pair +#define x41 covers_full_cycle +#define x31 AssembleSequence( +#define x21 x8(rule.repl_param_list, +#define x11 NeedList +#define x01 )lF3 eE3 +#define nZ1 < +#define nU1 std::pair& +#define nT1 n73& +#define n81 yG&c73, +#define n71 void ByteCodeSynth x8:: +#define n61 )const{return +#define n51 rhs n61 hash1 +#define n41 changed_if +#define n31 min=eS1(0); +#define n21 opposite= +#define n11 7168 tS 279818, +#define n01 l81 xA2; +#define lZ1 MatchResultType +#define lY1 resulting_exponent +#define lX1 Unknown:default:;} +#define lW1 ,lE 2,1, +#define lV1 (*x6)[a].start_at +#define lU1 ,cAdd,SelectedParams,0},0, +#define lT1 GetParam(a) +#define lS1 inverse_nominator] +#define lR1 void FunctionParserBase +#define lQ1 ,nN,IP,limit,y1,stack); +#define lP1 ByteCodeSynth x8&synth) +#define lO1 xS3 a=0;a1; +#define iP );nC1 0,cE2);iH1 1); +#define iO DumpTreeWithIndent(*this); +#define iN switch(type iY2 cond_or: +#define iM CalculateResultBoundaries( +#define iL e62 v,eS1(lN +#define iK AddFunctionOpcode_Integer( +#define iJ sim.Eat( +#define iI edited_powgroup +#define iH has_unknown_max +#define iG has_unknown_min +#define iF if(keep_powi +#define iE synthed_tree +#define iD 356668 tS 24852 +#define iC +2]=yM|i02(Immed yA3); +#define iB matched_params +#define iA .IsIdenticalTo( +#define i9 by_exponent +#define i8 collections +#define i7 cache +#define i6 }inline +#define i5 lT void range x8:: +#define i4 yA comp.cB1[a].value); +#define i3 AnyParams,2},0,0x0},{{ +#define i2 cS1.data +#define i1 iF2 nO2( +#define i0 .has_max +#define tZ goto ReplaceTreeWithZero; +#define tY :goto ReplaceTreeWithOne;case +#define tX GetLogicalValue nW1 +#define tW lN1 std::endl;DumpHashes( +#define tV ;p2.yB3 p2);tH iH2 nE);e5} +#define tU .lI2 +#define tT );tree +#define tS ,{2, +#define tR lZ 0x0},{{ +#define tQ yV1 nA +#define tP MakeFalse,l4:: +#define tO ].relationship +#define tN <=fp_const_negativezero x8()) +#define tM .hash1|=key;iC1 n9 +#define tL [n2 eC3=true;lQ[n2 eD3 +#define tK l41::Grammar* +#define tJ powgroup lD +#define tI ;pow tU cLog);tH cMul); +#define tH tree tU +#define tG eK2&&found[data. +#define tF },{l4::MakeNotNotP1,l4:: +#define tE },{l4::MakeNotNotP0,l4:: +#define tD cN3 a-->0;)if( +#define tC nB1( +#define tB has_mulgroups_remaining +#define tA StackTop +#define t9 MatchInfo x8& +#define t8 int_exponent_t +#define t7 RootPowerTable x8::RootPowers[ +#define t6 MatchPositionSpec_AnyParams x8 +#define t5 iO2 FPoptimizer_ByteCode +#define t4 is_signed +#define t3 iE1));xX1 Rehash(); +#define t2 result_positivity +#define t1 biggest_minimum +#define t0 const iW +#define eZ ParamSpec_NumConstant x8 +#define eY yK2&tree,std::ostream&o +#define eX !=Unchanged)if(TestCase( +#define eW cond_tree +#define eV else_tree +#define eU then_tree +#define eT .AddParam( +#define eS ;xE3(tree)lN1"\n"; +#define eR yK2&tree) +#define eQ sequencing +#define eP StackState +#define eO string FP_GetOpcodeName( +#define eN if_stack +#define eM {return yK2( +#define eL n_as_sin_param +#define eK n_as_cos_param +#define eJ PowiResolver:: +#define eI ];};extern"C"{ +#define eH .BalanceGood +#define eG AddParamMove( +#define eF valueType +#define eE best_factor +#define eD back().endif_location +#define eC iC1(iJ1) +#define eB iC1 key +#define eA l8 2,1, +#define e9 130,1, +#define e8 MatchPositionSpecBase +#define e7 iF2 yL2( +#define e6 smallest_maximum +#define e5 goto redo; +#define e4 ++IP;y81}if(xW3 xV3. +#define e3 ReplaceTreeWithParam0; +#define e2 factor_needs_rehashing +#define e1 MatchPositionSpecBaseP +#define e0 nL eS1(-y03; +#define cZ 79,112,113,117,118,123,124,127,128, +#define cY )l81 m cM3 +#define cX e01 x8(nM.param_list, +#define cW relationships +#define cV 28,29,30,31,32,33,34,35,36, +#define cU cIf,l0 3, +#define cT lK 2},0,0x0},{{ +#define cS data.subfunc_opcode +#define cR }if eD2.xJ1==eS1( +#define cQ otherhalf +#define cP :{AdoptChildrenWithSameOpcode(tree); +#define cO map > +#define cN const SequenceOpCode x8 +#define cM =fp_cosh(m.min);m.max=fp_cosh(m.max); +#define cL MatchPositionSpec_PositionalParams x8 +#define cK eS1(1.5)*fp_const_pi x8() +#define cJ !=Unchanged nZ2 iZ1 +#define cI FoundChild +#define cH CalculatePowiFactorCost( +#define cG T1,typename T2>inline i12()( +#define cF yK2 tmp;tmp tU +#define cE has_nonlogical_values +#define cD from_logical_context) +#define cC for xK2 xW.cN3 a-->0;) +#define cB POWI_CACHE_SIZE +#define cA static inline yK2 +#define c9 BalanceResultType +#define c8 cIf,eL3 +#define c7 nA3(0),Opcode( +#define c6 const{return data-> +#define c5 +=fp_const_twopi x8(); +#define c4 .AddOperation(lM2, +#define c3 for xK2 0;ae92 Comp< +#define yT eT CodeTreeImmed( +#define yS xK2 0;a(eS1(0), +#define y6 iM tree lD +#define y5 =y6 0));range x8 +#define y4 tree lD 1).xJ1 +#define y3 x02;tH +#define y2 lX&&tree lD 1)y21 +#define y1 factor_stack_base +#define y0 cPow,l6 2, +#define xZ GroupFunction,0},n0{{ +#define xY data->c93 +#define xX =0;a0;) +#define xT nM xY2 +#define xS i02 c;i02 char l[ +#define xR 158,167,168,169,178,179,191,195,203,207,215,227,229,232,233,234,235,236,239,240,241,242,245,246,247,248,250,251}};}e92 +#define xQ using iO2 FUNCTIONPARSERTYPES; +#define xP const eY=std::cout +#define xO IsIdenticalTo(leaf2 lD +#define xN FPOPT_autoptr +#define xM +=result l81 result;}yV1 inline eS1 +#define xL int_exponent +#define xK newnode +#define xJ l3 2,1, +#define xI ParamSpec_SubFunction +#define xH ParamSpec_ParamHolder +#define xG has_highlevel_opcodes +#define xF {if(needs_cow){iY goto +#define xE ;if(fp_nequal(tmp,eS1(0)))lL eS1(1)/tmp)n5}lC +#define xD },{l4::Unchanged,l4::Never},{l4::Unchanged,l4::Never}} +#define xC best_selected_sep +#define xB ->Recalculate_Hash_NoRecursion();} +#define xA fp_sin(min),fp_sin(max)) +#define x9 sim.AddConst( +#define x8 +#define x7 :nG1 tmp,tmp2;tmp2 tU +#define x6 position +#define x5 GetStackTop()- +#define x4 for yS{range x8 +#define x3 SwapLastTwoInStack(); +#define x2 FPoptimizer_CodeTree::yK2&tree +#define x1 SetParam(0,iH2 lD 0))yJ p1;p1 tU +#define x0 TestImmedConstraints(param t42,tree)yI +#define nZ {tree.FixIncompleteHashes();} +#define nY {yE3 cInv nW2 x9-1 e21 +#define nX paramholder_index +#define nW return true;case +#define nV occurance_counts +#define nU PositionalParams,0},0, +#define nT xQ xD1 tA-1); +#define nS ;synth.yZ2*this)l81;} +#define nR ,l0 1, +#define nQ );a-->0;){lM1&powgroup=lT1;if(powgroup +#define nP ;ap xO3 p. +#define nH nT1 Ref>inline void xN:: +#define nG ;tmp2 yC 0 y43 cInv);tmp yY3 l81 +#define nF ):data(new nO2 x8( +#define nE .lM2 +#define nD FUNCTIONPARSERTYPES:: +#define nC iJ1(),c93(),Hash(),Depth(1),eZ1 0){} +#define nB SynthesizeByteCode(synth); +#define nA nO2 x8::nO2( +#define n9 crc=(key>>10)|(key<<(64-10))eC2((~iC1(crc))*3)^1234567;}}; +#define n8 GetIntegerInfo nW1 0))==IsAlways)lN3 +#define n7 eS1(*const func)(eS1),range x8 model){ +#define n6 e72.xJ1 +#define n5 ;goto do_return;} +#define n4 while(ApplyGrammar(i01 Grammar&) +#define n3 DumpParams x8 iZ2 data.param_list,xF3 data xY2,o); +#define n2 restholder_index +#define n1 yK2 cE2;cE2 e53 cE2 eT +#define n0 yL1,0x0}, +#define lZ t51 1},0, +#define lY ;tree yA n41)nS2 +#define lX l23 y21 +#define lW eG pow x03;pow.iH1 1);pow.Rehash(tT.nC1 0,pow);goto NowWeAreMulGroup;} +#define lV {cF cPow);y53;tmp yT eS1( +#define lU :if(ParamComparer x8()(c93[1],c93[0])){std::swap(c93[0],c93[1]);Opcode= +#define lT +#define lS ,eS1(1)/eS1( +#define lR SetParam(0,e72 lD 0)xK1 1,CodeTreeImmed( +#define lQ restholder_matches +#define lP SelectedParams,0},0,0x0},{{ +#define lO n41;n41 xQ2 n41 yA e72);n41 eT xW lD +#define lN *const func)(eS1),range x8 model=range x8()); +#define lM yV1 yK2::yL2( +#define lL {tree.ReplaceWithImmed( +#define lK cMul,AnyParams, +#define lJ cMul,SelectedParams,0},0, +#define lI cPow,l0 2 +#define lH iM tmp)cM3 +#define lG :cC3=comp.AddRelationship(atree lD 0),atree lD 1),yB +#define lF typename eS1>i12()i01 eS1&a,e62 b){return a +#define lE t51 0 l1 +#define lD .GetParam( +#define lC break;case +#define lB {range x8 m=y6 0)); +#define lA xB1 yK2:: +#define l9 ?0:1))yJ n41;n41 xQ2 n41 tI1 tree.iE1));n41 y3 +#define l8 lK 0 l1 +#define l7 ,PositionalParams,0 l1 +#define l6 nU iR +#define l5 cAdd,lP 2, +#define l4 RangeComparisonData +#define l3 PositionalParams,0}},{ProduceNewTree, +#define l2 lJ 0x0},{{ +#define l1 }},{ReplaceParams, +#define l0 nU 0x0},{{ +#ifdef _MSC_VER +typedef +i02 +int +iD1; +#else +#include +typedef +uint_least32_t +iD1; +#endif +iO2 +crc32{enum{startvalue=0xFFFFFFFFUL,poly=0xEDB88320UL} +;n73e92 +b8{enum{b1=(crc +l03 +crc +nP2 +crc>>1),b2=(b1 +l03 +b1 +nP2 +b1>>1),b3=(b2 +l03 +b2 +nP2 +b2>>1),b4=(b3 +l03 +b3 +nP2 +b3>>1),b5=(b4 +l03 +b4 +nP2 +b4>>1),b6=(b5 +l03 +b5 +nP2 +b5>>1),b7=(b6 +l03 +b6 +nP2 +b6>>1),res=(b7 +l03 +b7 +nP2 +b7>>1)} +;} +;inline +iD1 +update(iD1 +crc,i02 +b){ +#define B4(n) b8iL2 n+1>iL2 n+2>iL2 n+3>::res +#define R(n) B4(n),B4(n+4),B4(n+8),B4(n+12) +static +const +iD1 +table[256]={R(0x00),R(0x10),R(0x20),R(0x30),R(0x40),R(0x50),R(0x60),R(0x70),R(0x80),R(0x90),R(0xA0),R(0xB0),R(0xC0),R(0xD0),R(0xE0),R(0xF0)} +; +#undef R +#undef B4 +return((crc>>8))^table[(crc^b)&0xFF];i6 +iD1 +calc_upd(iD1 +c,const +i02 +char*buf,size_t +size){iD1 +value=c;for(size_t +p=0;pclass +xN{e13 +xN():p(0){} +xN(Ref*b):p(b){n93} +xN +i01 +xN&b):p(b.p){n93 +i6 +Ref&e31*(n61*p;i6 +Ref*e31->(n61 +p;} +xN&e31=(Ref*b){Set(b)l81*this;} +xN&e31=i01 +xN&b){Set(b.p)l81*this;} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +xN(xN&&b):p(b.p){b.p=0;} +xN&e31=(xN&&b){if(p!=b.p){cF2;p=b.p;b.p=0;} +return*this;} +#endif +~xN(){cF2 +iS2 +UnsafeSetP(Ref*newp){p=newp +iS2 +swap(xN&b){Ref*tmp=p;p=b.p;b.p=tmp;} +private:inline +static +void +Have(Ref*p2);inline +void +cF2;inline +void +n93 +inline +void +Set(Ref*p2);private:Ref*p;} +;nH +cF2{if(!p +nZ2;p->nA3-=1;if(!p->nA3)delete +p;} +nH +Have(Ref*p2){if(p2)++(p2->nA3);} +nH +Birth(){Have(p);} +nH +Set(Ref*p2){Have(p2);cF2;p=p2;} +#endif +#include +e92 +Compare2ndRev{nT1 +T>inline +i12()i01 +T&nB3 +T&b +n61 +a +eE3>b +eE3;} +} +;e92 +Compare1st{nT1 +cG +const +nU1 +nB3 +nU1 +b +n61 +a.first +typedef +uint_fast64_t +iC1; +#define FPHASH_CONST(x) x##ULL +#endif +iO2 +FUNCTIONPARSERTYPES{e92 +fphash_t{iC1 +hash1,hash2;fphash_t():hash1(0),hash2(0){} +fphash_t +i01 +iC1&nB3 +iC1&b):hash1(a),hash2(b){} +i12==i01 +fphash_t&n51==iM2&&hash2==iN2 +i12!=i01 +fphash_t&n51!=iM2||hash2!=iN2 +i12 +#include +iO2 +l41{e92 +Grammar;} +t5{iP2 +ByteCodeSynth;} +iO2 +FPoptimizer_CodeTree{iP2 +yL2;yT1 +nO2;iP2 +yL2{typedef +xNDataP;DataP +data;e13 +yL2();~yL2();e92 +OpcodeTag{} +;e7 +nR2 +o,OpcodeTag);e92 +FuncOpcodeTag{} +;e7 +nR2 +o,i02 +f,FuncOpcodeTag);e92 +nC3{} +;e7 +e62 +v,nC3); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +e7 +eS1&&v,nC3); +#endif +e92 +VarTag{} +;e7 +i02 +varno,VarTag);e92 +CloneTag{} +;e7 +iQ2 +b,CloneTag);void +GenerateFrom +i01 +n81 +const +nQ2 +const +typename +FunctionParserBase +x8::Data&data,bool +keep_powi=false);void +GenerateFrom +i01 +n81 +const +nQ2 +const +typename +FunctionParserBase +x8::Data&data,const +i22 +nK2,bool +keep_powi=false);void +SynthesizeByteCode(n81 +nQ2 +size_t&stacktop_max);void +SynthesizeByteCode(yW2&synth,bool +MustPopTemps=true)const;size_t +SynthCommonSubExpressions(yV2 +lP1 +const;void +SetParams +i01 +i22 +nD3 +SetParamsMove(i22 +eU1 +yL2 +GetUniqueRef(); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +void +SetParams(yG&&eU1 +#endif +void +SetParam(size_t +which,iQ2 +b);void +nC1 +size_t +which,nI2 +b);void +AddParam +i01 +nI2 +param);void +eG +nI2 +param);void +AddParams +i01 +i22 +nD3 +AddParamsMove(i22 +nD3 +AddParamsMove(i22 +l02,size_t +l12);void +iH1 +size_t +index);void +DelParams();void +Become +i01 +nI2 +b);inline +size_t +GetParamCount(n61 +iE1)yA3;i6 +nI2 +GetParam(xL3){return +iE1)[n];i6 +iQ2 +GetParam(xL3 +n61 +iE1)[n];i6 +void +lI2 +nR2 +o)cX3 +Opcode=o;i6 +nR2 +lM2 +c6 +Opcode;i6 +nD +fphash_t +GetHash()c6 +Hash;i6 +const +i22 +iE1 +n61 +xY;i6 +i22 +iE1){return +xY;i6 +size_t +xT2 +c6 +Depth;i6 +e62 +xJ1 +c6 +Value;i6 +i02 +GetVar()c6 +iI1 +i6 +i02 +GetFuncNo()c6 +iI1 +i6 +bool +IsDefined(n61 +lM2!=nD +cNop;i6 +bool +IsImmed(n61 +lM2==nD +cImmed;i6 +bool +IsVar(n61 +lM2==nD +iE2;i6 +i02 +GetRefCount()c6 +nA3 +iS2 +ReplaceWithImmed +i01 +eS1&i);void +Rehash(bool +constantfolding=true);void +Sort();inline +void +Mark_Incompletely_Hashed()cX3 +Depth=0;i6 +bool +Is_Incompletely_Hashed()c6 +Depth==0;i6 +const +tK +GetOptimizedUsing()c6 +iK1;i6 +void +SetOptimizedUsing +i01 +tK +g)cX3 +iK1=g;} +bool +RecreateInversionsAndNegations(bool +prefer_base2=false);void +FixIncompleteHashes();void +swap(nI2 +b){data.swap(b.data);} +bool +IsIdenticalTo +i01 +nI2 +b)const;void +iY} +;yT1 +nO2{int +nA3;nR2 +Opcode;eS1 +Value;i02 +iI1 +yG +nV1 +c93;nD +fphash_t +Hash;size_t +Depth;const +tK +iK1;nO2();nO2 +i01 +nO2&b);i1 +nR2 +o);i1 +nR2 +o,i02 +f);i1 +e62 +i); +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +i1 +eS1&&i);nO2(nO2&&b); +#endif +bool +IsIdenticalTo +i01 +nO2&b)const;void +Sort();void +Recalculate_Hash_NoRecursion();private:void +e31=i01 +nO2&b);} +;yU1 +CodeTreeImmed +i01 +eS1&i)eM +i +yO +nC3());} +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +yU1 +CodeTreeImmed(eS1&&i)eM +t72 +i)yO +nC3());} +#endif +yU1 +CodeTreeOp(nR2 +opcode)eM +opcode +yO +OpcodeTag());} +yU1 +CodeTreeFuncOp(nR2 +opcode,i02 +f)eM +opcode,f +yO +FuncOpcodeTag());} +yU1 +CodeTreeVar +iL1 +varno)eM +varno +yO +VarTag());} +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +xB1 +DumpHashes(xP);xB1 +xE3(xP);xB1 +DumpTreeWithIndent(xP,const +std::string&indent="\\" +); +#endif +} +#endif +#endif +#ifndef FPOPT_NAN_CONST +#include +#define FPOPT_NAN_CONST (-1712345.25) +iO2 +FPoptimizer_CodeTree{iP2 +yL2;} +iO2 +l41{enum +ImmedConstraint_Value{ValueMask=0x07,Value_AnyNum=0x0,n12=0x1,Value_OddInt=0x2,t01=0x3,Value_NonInteger=0x4,eE1=0x5 +n23 +ImmedConstraint_Sign{SignMask=0x18,Sign_AnySign=0x00,nJ1=0x08,n02=0x10,Sign_NoIdea=0x18 +n23 +ImmedConstraint_Oneness{OnenessMask=0x60,Oneness_Any=0x00,Oneness_One=0x20,Oneness_NotOne=0x40 +n23 +ImmedConstraint_Constness{ConstnessMask=0x180,Constness_Any=0x00,yL1=0x80,Constness_NotConst=0x100 +n23 +Modulo_Mode{Modulo_None=0,Modulo_Radians=1 +n23 +Situation_Flags{LogicalContextOnly=0x01,NotForIntegers=0x02,OnlyForIntegers=0x04 +n23 +lU2{NumConstant,ParamHolder,SubFunction +n23 +ParamMatchingType{PositionalParams,SelectedParams,AnyParams,GroupFunction +n23 +RuleType{ProduceNewTree,ReplaceParams} +; +#ifdef __GNUC__ +# define PACKED_GRAMMAR_ATTRIBUTE __attribute__((packed)) +#else +# define PACKED_GRAMMAR_ATTRIBUTE +#endif +typedef +std::paircG2;yV1 +cG2 +e01 +iL1 +paramlist,lC1);xG1 +ParamSpec_Compare +i01 +void*nB3 +void*b,lU2 +type);i02 +ParamSpec_GetDepCode +i01 +cG2&b);e92 +xH{lC1:8;i02 +constraints:9;i02 +depcode:15;yY +yT1 +ParamSpec_NumConstant{eS1 +xZ3;i02 +modulo;yY +e92 +iW{i02 +param_count:2;i02 +param_list:30;nR2 +subfunc_opcode:8;ParamMatchingType +match_type:3;i02 +n2:5;yY +e92 +xI{iW +data;i02 +constraints:9;i02 +depcode:7;yY +e92 +Rule{RuleType +ruletype:2;i02 +situation_flags:3;i02 +repl_param_count:2+11;i02 +repl_param_list:30;iW +match_tree;yY +e92 +Grammar{i02 +rule_count;i02 +char +rule_list[999 +eI +extern +const +Rule +grammar_rules[];} +xB1 +DumpParam +i01 +cG2&p,std::ostream&o=std::cout);xB1 +DumpParams +iL1 +paramlist,i02 +count,std::ostream&o=std::cout);} +#endif +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif +#define CONSTANT_POS_INF HUGE_VAL +#define CONSTANT_NEG_INF (-HUGE_VAL) +iO2 +FUNCTIONPARSERTYPES{yV1 +inline +eS1 +fp_const_pihalf(){return +fp_const_pi +x8()*yF3;} +yV1 +inline +eS1 +fp_const_twopi(){eS1 +cY3 +fp_const_pi +x8());e03 +fp_const_twoe(){eS1 +cY3 +fp_const_e +x8());e03 +fp_const_twoeinv(){eS1 +cY3 +fp_const_einv +x8());e03 +fp_const_negativezero(){ +#ifdef FP_EPSILON +return-fp_epsilon +x8(); +#else +return +eS1(-1e-14); +#endif +} +} +#ifdef FP_SUPPORT_OPTIMIZER +#include +#include +#include +iO2 +FPoptimizer_Optimize{using +iO2 +l41;using +iO2 +FPoptimizer_CodeTree;xQ +iP2 +MatchInfo{e13 +yG >lQ;yG +nV1 +yH;yGiB;e13 +MatchInfo():lQ(),yH(),iB(){} +e13 +bool +SaveOrTestRestHolder +iL1 +n2,lL1&tM1){cL1{lQ +nE3 +n2+1);lQ +tL=tM1 +nS2 +if(lQ[n2 +eC3==false){lQ +tL=tM1 +nS2 +lL1&found=lQ[n2 +eD3;if(tM1 +yA3!=found +yA3 +yI +for +xK2 +0;an2&&lQ[n2 +eC3==true;} +lL1&GetRestHolderValues +iL1 +n2)const{static +lL1 +empty_result;cL1 +return +empty_result +l81 +lQ[n2 +eD3;} +const +yG&GetMatchedParamIndexes(n61 +iB +iS2 +swap(t9 +b){lQ.swap(b.lQ);yH.swap(b.yH);iB.swap(b.iB);} +t9 +e31=i01 +t9 +b){lQ=b.lQ;yH=b.yH;iB=b.iB +l81*this;} +} +;class +e8;typedef +xNe1;class +e8{e13 +int +nA3;e13 +e8():nA3(0){} +virtual~e8(){} +} +;e92 +lZ1{bool +found;e1 +specs;lZ1(bool +f):found(f),specs(){} +lZ1(bool +f +eA2 +s):found(f),specs(s){} +} +;xB1 +SynthesizeRule +eX3 +yK2&tree,t9 +info);yV1 +lZ1 +TestParam +i01 +cG2&xZ2 +lM1&tree +eA2 +start_at,t9 +info);yV1 +lZ1 +TestParams(t0&nM,lM1&tree +eA2 +start_at,t9 +info,bool +tA1;xG1 +ApplyGrammar +i01 +Grammar&tN2,x2,bool +from_logical_context=false);xB1 +ApplyGrammars(x2);xG1 +IsLogisticallyPlausibleParamsMatch(t0&cB2,const +eR;} +iO2 +l41{xB1 +DumpMatch +eX3 +const +x2,const +FPoptimizer_Optimize::t9 +info,bool +DidMatch,std::ostream&o=std::cout);xB1 +DumpMatch +eX3 +const +x2,const +FPoptimizer_Optimize::t9 +info,const +char*eY3,std::ostream&o=std::cout);} +#endif +#include +eG2 +l41::lU2 +yK1=false);eG2 +nR2 +yK1=false); +#include +#include +#include +#include +using +iO2 +l41;xQ +eG2 +l41::lU2 +yK1){ +#if 1 +const +char*p=0;switch(opcode +iY2 +NumConstant:p="NumConstant" +;lC +ParamHolder:p="ParamHolder" +;lC +SubFunction:p="SubFunction" +;nM3 +std::ostringstream +tmp;assert(p);tmp< +#include +#ifndef FP_GENERATING_POWI_TABLE +enum{MAX_POWI_BYTECODE_LENGTH=20} +; +#else +enum{MAX_POWI_BYTECODE_LENGTH=999} +; +#endif +enum{MAX_MULI_BYTECODE_LENGTH=3} +;t5{iP2 +ByteCodeSynth{e13 +ByteCodeSynth():nN(),Immed(),eP(),tA(0),StackMax(0){nN.nH3 +64);Immed.nH3 +8);eP.nH3 +16 +iR2 +Pull(yG&bc,yG +x8&imm,size_t&StackTop_max){for +iL1 +a=0;aoffset){eP[tA +lN2 +first=true;eP[tA +lN2 +second=tree;} +} +bool +IsStackTop +cA3,int +offset=0 +n61(int)tA>offset&&eP[tA +lN2 +first&&eP[tA +lN2 +second +iA +tree);i6 +void +EatNParams +iL1 +cH2){tA-=cH2 +iS2 +ProducedNParams +iL1 +e41){xD1 +tA+e41 +iR2 +AddOperation +iL1 +opcode,i02 +cH2,i02 +e41=1){EatNParams(cH2);xQ +AddFunctionOpcode(opcode);ProducedNParams(e41 +iR2 +DoPopNMov(size_t +cI2,size_t +srcpos){xQ +e23 +cPopNMov);e23 +yM|iL1)cI2);e23 +yM|iL1)srcpos);xD1 +srcpos+1);eP[cI2]=eP[srcpos];xD1 +cI2+1 +iR2 +DoDup(size_t +nI3){xQ +if(nI3==tA-1){e23 +cDup);} +else{e23 +cFetch);e23 +yM|iL1)nI3);} +nV2 +eP[tA-1]=eP[nI3];} +size_t +e33 +cA3)const{for +xK2 +tA;a-->0;)if(eP[a +eC3&&eP[a +eD3 +iA +tree)nZ2 +a +l81 +eK2;} +bool +Find +cA3 +n61 +e33 +nO3 +eK2;} +bool +FindAndDup +cA3){size_t +pos=e33(tree);if(pos!=eK2){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<nN;yG +x8 +Immed;yG >eP;size_t +tA;size_t +StackMax;} +;yT1 +SequenceOpCode;yT1 +eX1{static +cN +AddSequence;static +cN +MulSequence;} +;xB1 +x31 +long +count,cN&eQ,lP1;} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +xQ +t5{yT1 +SequenceOpCode{eS1 +basevalue;i02 +op_flip;i02 +op_normal,op_normal_flip;i02 +op_inverse,op_inverse_flip;} +;yV1 +cN +eX1 +x8::AddSequence={eS1(0),cNeg,cAdd,cAdd,cSub,cRSub} +;yV1 +cN +eX1 +x8::MulSequence={eS1(1),cInv,cMul,cMul,cDiv,cRDiv} +;yV1 +n71 +l51 +eK1{int +mStackPtr=0; +#define incStackPtr() do{if(tA+2 eL2 yS1=tA+2);}while(0) +#define findName(a,b,c) "var" +#define TryCompilePowi(o) false +#define mData this +#define mByteCode nN +#define mImmed Immed +# define FP_FLOAT_VERSION 1 +# include "fp_opcode_add.inc" +# undef FP_FLOAT_VERSION +#undef mImmed +#undef mByteCode +#undef mData +#undef TryCompilePowi +#undef incStackPtr +} +yV1 +n71 +iK +eK1{int +mStackPtr=0; +#define incStackPtr() do{if(tA+2 eL2 yS1=tA+2);}while(0) +#define findName(a,b,c) "var" +#define TryCompilePowi(o) false +#define mData this +#define mByteCode nN +#define mImmed Immed +# define FP_FLOAT_VERSION 0 +# include "fp_opcode_add.inc" +# undef FP_FLOAT_VERSION +#undef mImmed +#undef mByteCode +#undef mData +#undef TryCompilePowi +#undef incStackPtr +} +yV1 +n71 +AddFunctionOpcode(eK1{if(IsIntType +x8::result)iK +opcode);else +l51 +opcode);} +} +using +t5; +#define POWI_TABLE_SIZE 256 +#define POWI_WINDOW_SIZE 3 +t5{ +#ifndef FP_GENERATING_POWI_TABLE +extern +const +i02 +char +powi_table[POWI_TABLE_SIZE];const +#endif +i02 +char +powi_table[POWI_TABLE_SIZE]={0,1,1,1,2,1 +eM2 +1,4,1,2,e43 +eM2 +1,8,cB3 +e73 +15,1,16,1 +eM2 +e43,2,1,4,cB3 +1,16,1,25,e73 +27,5,8,3,2,1,30,1,31,3,32,1 +eM2 +1,8,1,2,e73 +39,1,16,137,2,1,4,cB3 +e43,45,135,4,31,2,5,32,1,2,131,50,1,51,1,8,3,2,1,54,1,55,3,16,1,57,133,4,137,2,135,60,1,61,3,62,133,63,1,tN1 +131,tN1 +139,iM1 +e9 +30,1,130,137,2,31,iM1 +e9 +e9 +130,cB3 +1,e9 +e9 +2,1,130,133,tN1 +61,130,133,62,139,130,137,e9 +iM1 +e9 +e9 +tN1 +131,e9 +e9 +130,131,2,133,iM1 +130,141,e9 +130,cB3 +1,e9 +5,135,e9 +iM1 +e9 +iM1 +130,133,130,141,130,131,e9 +e9 +2,131} +;} +static +lX3 +cB=256; +#define FPO(x) +iO2{class +PowiCache{private:int +i7[cB];int +tO1[cB];e13 +PowiCache():i7(),tO1(){i7[1]=1;} +bool +Plan_Add(yW1,int +count){c51>=cB +yI +tO1[eP2+=count +l81 +i7[eP2!=0 +iS2 +iU2 +yW1){c51=0){FPO(tK3(tO3,"* I found %ld from cache (%u,%d)\n",value,(unsigned)cache[value],tL3 value]))l81 +i7[eP2;} +} +return-1 +iS2 +Remember(yW1,size_t +tW3){c51>=cB +nZ2;FPO(tK3(tO3,"* Remembering that %ld can be found at %u (%d uses remain)\n",value,(unsigned)tW3,tL3 value]));i7[eP2=(int)tW3 +iS2 +DumpContents()const{FPO(for(int a=1;a=0||tL3 a]>0){tK3(tO3,"== cache: sp=%d, val=%d, needs=%d\n",cache[a],a,tL3 a]);})} +int +UseGetNeeded(yW1){c51>=0&&value32)throw +false; +#endif +if(i7.Plan_Add(value,need_count)nZ2;long +nJ3 +1;c51cQ||half<0)std::swap(half,cQ);FPO(tK3(tO3,"value=%ld, half=%ld, otherhalf=%ld\n",value,half,otherhalf))iT2==cQ){l61 +half,i7,2,iX+1);} +else{l61 +half,yM2 +l61 +cQ>0?cQ:-cQ,yM2} +i7.iU2 +value);} +yV1 +size_t +yN +yW1 +tR1 +cN&eQ,lP1{int +nK3=i7.Find(value);if(nK3>=0){return +nK3;} +long +nJ3 +1;c510||x52!=c71){tQ1 +x52)nU2 +half,c71);} +x31 +value/half +eR2 +size_t +tW3=c71 +nU2 +value,tW3);i7.DumpContents()l81 +tW3;} +tP1 +half&64){nJ3-eQ2} +} +else +c51&1)nJ3 +value&((1<cQ||half<0)std::swap(half,cQ);FPO(tK3(tO3,"* I want %ld, my plan is %ld + %ld\n",value,half,value-half))iT2==cQ){size_t +x52=yN +half +c61 +yX1 +x52,half,x52,half,i7,eQ.op_normal,eQ.op_normal_flip,synth);} +else{long +part1=half;long +part2=cQ>0?cQ:-cQ;size_t +part1_pos=yN +part1 +c61 +size_t +part2_pos=yN +part2 +c61 +FPO(tK3(tO3,"Subdivide(%ld: %ld, %ld)\n",value,half,otherhalf));yX1 +part1_pos,part1,part2_pos,part2,i7,cQ>0?eQ.op_normal:eQ.op_inverse,cQ>0?eQ.op_normal_flip:eQ.op_inverse_flip,synth);} +size_t +tW3=c71 +nU2 +value,tW3);i7.DumpContents()l81 +tW3;} +xB1 +yX1 +size_t +apos,long +aval,size_t +bpos,long +bval +tR1 +i02 +cumulation_opcode,i02 +cumulation_opcode_flip,lP1{int +a_needed=i7 +iN1 +aval);int +nL3=i7 +iN1 +bval);bool +iO1 +i13 +#define DUP_BOTH() do tX3 "tV3 tV3"op\n",(unsigned)apos,(unsigned)bpos));tQ1 apos);tQ1 apos==bpos?c71:bpos);}while(0) +#define DUP_ONE(p) do{FPO(tK3(tO3,"-> "tV3"op\n",(unsigned)p));tQ1 p);}while(0) +if(a_needed>0){if(nL3>0){lO2} +else{if(bpos!=c71)lO2 +else{iP1 +iO1=!iO1;} +} +} +tP1 +nL3>0)tX3!=c71)lO2 +else +DUP_ONE(bpos);} +else +tX3==bpos&&apos==c71)iP1 +tP1 +apos==c71&&bpos==synth.x5 +2){FPO(tK3(tO3,"-> op\n"));iO1=!iO1;} +tP1 +apos==synth.x5 +2&&bpos==c71)FPO(tK3(tO3,"-> op\n"));tP1 +apos==c71)DUP_ONE(bpos);tP1 +bpos==c71){iP1 +iO1=!iO1;} +else +lO2} +lK1 +iO1?cumulation_opcode_flip:cumulation_opcode,2);} +xB1 +cA1 +long +count,cN&eQ,lP1{while +cR3<256){int +nJ3 +yV2 +powi_table[count]iT2&128){half&=127;cA1 +half +eR2 +count/=half;} +else +nM3 +if +cR3==1 +nZ2;if(!cR3&1)){lK1 +cSqr,1);cA1 +count/2 +eR2} +else{tQ1 +c71);cA1 +count-1 +eR2 +lK1 +cMul,2);} +} +} +t5{xB1 +x31 +long +count,cN&eQ,lP1{if +cR3==0)yX2 +eQ.basevalue +t73 +bool +eT2 +i13 +if +cR3<0){eT2=true;count=-count;} +if(false)cA1 +count +eR2 +tP1 +count>1){PowiCache +i7;l61 +count,i7,1);size_t +xE1 +t13 +GetStackTop();i7.Start(c71);FPO(tK3(tO3,"Calculating result for %ld...\n",count));size_t +x62=yN +count +c61 +size_t +n_excess +t13 +x5 +xE1;if(n_excess>0||x62!=xE1-1){synth.DoPopNMov(xE1-1,x62);} +} +if(eT2)lK1 +eQ.op_flip,1);} +} +} +#endif +#ifndef FPOptimizer_RangeEstimationHH +#define FPOptimizer_RangeEstimationHH +iO2 +FPoptimizer_CodeTree{enum +TriTruthValue{IsAlways,yO3,Unknown} +;yT1 +range{eS1 +min,max;bool +iV2,has_max;range():min(),max(),iV2(false +cS3 +false)x43 +eS1 +mi,eS1 +ma):min(mi),max(ma),iV2(true +cS3 +true)x43 +bool,eS1 +ma):min(),max(ma),iV2(false +cS3 +true)x43 +eS1 +mi,bool):min(mi),max(),iV2(true +cS3 +false){} +void +set_abs();void +set_neg();x72 +set_min_max_if(iL +x72 +set_min_if(iL +x72 +set_max_if(iL +void +set_min(eS1(lN +void +set_max(eS1(lN +void +y82 +eS1(lN} +;yV1 +inline +bool +IsLogicalTrueValue +i01 +range +x8&p +cD2 +if(p +y41 +p.min>=0.5 +nZ2 +true;if(!abs&&p +iW2<=-0.5 +nZ2 +true +l81 +false;} +yV1 +inline +bool +IsLogicalFalseValue +i01 +range +x8&p +cD2 +if(abs +nZ2 +p +iW2<0.5;else +return +p +y41 +p +i0&&p.min>-0.5 +xQ3<0.5;} +yV1 +range +x8 +iM +const +eR;xG1 +IsLogicalValue +i01 +eR;yV1 +TriTruthValue +GetIntegerInfo +i01 +eR;y51 +GetEvennessInfo +i01 +eR{if(!tree +y21 +nZ2 +Unknown;yF1=yZ3;if(isEvenInteger(value)nZ2 +x82 +isOddInteger(value)nZ2 +l71 +y51 +GetPositivityInfo +i01 +eR{range +x8 +p=iM +tree);if(p +y41 +p.min +cH1 +nZ2 +x82 +p +iW2 +t83 +nZ2 +l71 +y51 +GetLogicalValue(lM1&tree +cD2 +range +x8 +p=iM +tree);if(IsLogicalTrueValue(p,abs)nZ2 +x82 +IsLogicalFalseValue(p,abs)nZ2 +l71} +#endif +#ifndef FPOptimizer_ConstantFoldingHH +#define FPOptimizer_ConstantFoldingHH +iO2 +FPoptimizer_CodeTree{xB1 +ConstantFolding(eR;} +#endif +iO2{xQ +using +iO2 +FPoptimizer_CodeTree;e92 +ComparisonSetBase{enum{e93=0x1,Eq_Mask=0x2,Le_Mask=0x3,eA3=0x4,eB3=0x5,Ge_Mask=0x6} +;static +int +Swap_Mask(int +m){return(m&Eq_Mask)|((m&e93)?eA3:0)|((m&eA3)?e93:0);} +enum +yY1{Ok,BecomeZero,BecomeOne,xA2 +n23 +lV2{cond_or,i32,i42,i52} +;} +;yT1 +ComparisonSet:public +ComparisonSetBase{e92 +eU2 +nG1 +a +yJ +b;int +relationship;eU2():a(),b(),relationship(){} +} +;yGcW;e92 +Item +nG1 +value;bool +yN2;Item():value(),yN2(false){} +} +;yGcB1;int +xF1;ComparisonSet():cW(),cB1(),xF1(0){} +yY1 +AddItem(lM1&a,bool +yN2,lV2 +type){for(size_t +c=0;cbool +ConstantFolding_LogicCommon(yK2&tree,CondType +xA1,bool +xC2){bool +should_regenerate +i13 +ComparisonSet +x8 +comp +eV3 +typename +yB +yY1 +cC3=yB +Ok;lM1&atree=xI2;switch(atree +nE +iY2 +cEqual +lG +Eq_Mask +eB2 +t71 +lG +eB3 +eB2 +cLess +lG +e93 +eB2 +cLessOrEq +lG +Le_Mask +eB2 +cGreater +lG +eA3 +eB2 +cGreaterOrEq +lG +Ge_Mask +eB2 +cNot:cC3 +y11 +lD +0),true +eB2 +cNotNot:cC3 +y11 +lD +0),false,xA1);break;default:if(xC2||IsLogicalValue(atree))cC3 +y11,false,xA1);yN3(cC3){ReplaceTreeWithZero +xP3 +ReplaceWithImmed(0)l81 +true;ReplaceTreeWithOne +xP3 +ReplaceWithImmed(1);nW +yB +Ok:lC +yB +BecomeZero:yP3 +yB +BecomeOne +tY +yB +xA2:c11 +nM3} +if(should_regenerate){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantFolding_LogicCommon: " +eS +#endif +if(xC2){tree.DelParams();} +else{for +xU{lM1&atree=xI2;if(IsLogicalValue(atree))nF1);} +} +for +xK2 +0;a +#include +#include +iO2{xQ +using +iO2 +FPoptimizer_CodeTree;e92 +CollectionSetBase{enum +xH1{Ok,xA2} +;} +;yT1 +CollectionSet:public +CollectionSetBase{e92 +yZ1 +nG1 +value +yJ +xD2;bool +e2;yZ1():value(),xD2(),e2(false){} +yZ1(lM1&v,lM1&f):value(v),xD2(f),e2(false){} +} +;std::multimapi8;typedef +typename +std::multimap::nX3 +xI1;CollectionSet():i8(){} +xI1 +FindIdenticalValueTo(lM1&value){fphash_t +hash=value.GetHash();for(xI1 +i=i8.xE2 +hash);i!=i8.cP1 +hash;++i){c51 +iA +i +cJ2.value)nZ2 +i;} +return +i8.end();} +bool +Found +i01 +xI1&b){return +b!=i8.end();} +xH1 +AddCollectionTo(lM1&xD2,const +xI1&into_which){yZ1&c=into_which +cJ2;if(c.e2)c.xD2 +eT +xD2);else +nG1 +add;add +tU +cAdd);add +yA +c.xD2);add +eT +xD2);c.xD2.swap(add);c.e2=true;} +return +xA2;} +xH1 +iR1 +lM1&value,lM1&xD2){const +fphash_t +hash=value.GetHash();xI1 +i=i8.xE2 +hash);for(;i!=i8.cP1 +hash;++i){if(i +cJ2.value +iA +value)nZ2 +AddCollectionTo(xD2,i);} +i8.nT3,std::make_pair(hash,yZ1(value,xD2)))l81 +Ok;} +xH1 +iR1 +lM1&a){return +iR1 +a,nB1 +1)));} +} +;yT1 +ConstantExponentCollection{typedef +yG +nV1 +nV3;typedef +std::x51 +xF2;yGdata;ConstantExponentCollection():data(){} +void +MoveToSet_Unique +i01 +eS1&e51&e61){data +yL +std::x51(e51()));data.back()eE3.swap(e61 +iR2 +MoveToSet_NonUnique +i01 +eS1&e51&e61){typename +yG::nX3 +i=std::xE2 +data.i62 +data.end(),cE2,Compare1st());if(i!=data.cP1 +cE2){i +cJ2.nT3 +cJ2.end(),e61.i62 +e61.end());} +else{data.nT3,std::x51(cE2,e61));} +} +bool +Optimize(){bool +changed +i13 +std::sort(data.i62 +data.end(),Compare1st());redo:for +xK2 +0;a=fp_abs(exp_a +n33 +exp_diff_still_probable_integer=xG2*eS1(16);if(eY2 +exp_diff_still_probable_integer)&&!(eY2 +exp_b)&&!eY2 +xG2))){nV3&a_set=iS1;nV3&b_set=data[b +eD3; +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantExponentCollection iteration:\n" +;eZ2 +cout); +#endif +if(isEvenInteger(exp_b)&&!isEvenInteger(xG2+exp_a))nG1 +tmp2;tmp2 +e53 +tmp2 +tI1 +b_set);tmp2 +i72 +tmp;tmp +tU +cAbs);tmp +yY3;tmp +x02;b_set +nE3 +1);b_set[0 +t23 +tmp);} +a_set.insert(a_set.end(),b_set.i62 +b_set.end());nV3 +b_copy=b_set;data.erase(data.begin()+b);MoveToSet_NonUnique(xG2,b_copy);yI1 +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"After ConstantExponentCollection iteration:\n" +;eZ2 +cout); +#endif +e5} +} +} +return +changed;} +#ifdef DEBUG_SUBSTITUTIONS +void +eZ2 +ostream&out){for +xK2 +0;a0)out<<'*';xE3(iS1[b],out);} +out<e91;typedef +std::multimapcC1;cC1 +i9;xH2 +e81::xI1 +j=mul.i8.nW3 +j!=mul.i8.end();++j)nG1&value=j +cJ2.value +yJ&cE2=j +cJ2.xD2;if(j +cJ2.e2)cE2 +x02;const +fphash_t +eA1=cE2.GetHash();typename +cC1::nX3 +i=i9.xE2 +eA1);for(;i!=i9.cP1 +eA1;++i)if(i +cJ2.first +iA +cE2)){if(!cE2 +y21||!cR1.xJ1,nY3 +c11 +i +cJ2 +eE3 +yL +value);goto +skip_b;} +i9.nT3,std::make_pair(eA1,std::make_pair(cE2,yG +nV1(size_t(1),value))));skip_b:;} +#ifdef FP_MUL_COMBINE_EXPONENTS +ConstantExponentCollection +x8 +cS1;xH2 +cC1::nX3 +j,i=i9.nW3 +i!=i9.end();i=j){j=i;++j;e91&list=i +cJ2;if +eD2 +y21)c21 +list.first.xJ1;if(!(cE2==eS1(0)))cS1.MoveToSet_Unique(cE2,list +eE3);i9.erase(i);} +} +if(cS1.Optimize())c11 +#endif +if(should_regenerate)nG1 +before=tree;before.iY +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantFolding_MulGrouping: " +;xE3(before)lN1"\n" +; +#endif +tree.DelParams();xH2 +cC1::nX3 +i=i9.nW3 +i!=i9.end();++i){e91&list=i +cJ2; +#ifndef FP_MUL_COMBINE_EXPONENTS +if +eD2 +y21)c21 +list.first.xJ1;if(cE2==eS1(0))y81 +if(cR1,nY3{tree.AddParamsMove(list +eE3);y81} +} +#endif +yK2 +mul;mul +e53 +mul +tI1 +list +eE3);mul +x02;if(xG&&list.first +tF3 +eD2.xJ1==eS1(1)/eS1(3))nG1 +cbrt;cbrt +tU +cCbrt);cbrt +t02;cbrt.yB3 +cbrt);y81 +cR +0.5))nG1 +sqrt;sqrt +tU +cSqrt);sqrt +t02;sqrt.yB3 +sqrt);y81 +cR-0.5))nG1 +rsqrt;rsqrt +tU +cRSqrt);rsqrt +t02;rsqrt.yB3 +rsqrt);y81 +cR-1))nG1 +inv;inv +tU +cInv);inv +t02;inv.yB3 +inv);y81} +} +yK2 +pow +yB2 +t02;pow +yA +list.first);pow.yB3 +pow);} +#ifdef FP_MUL_COMBINE_EXPONENTS +i9.clear()c23 +0;aremaining(iT);size_t +tB=0 +eV3 +lM1&n83=xI2;if(n83 +nE==cMul){eW3 +xX1 +c81{if(n83 +lD +b)y21)y81 +typename +e81::xI1 +c=add.FindIdenticalValueTo(n83 +lD +b));if(add.Found(c))nG1 +tmp(n83 +yO +CloneTag());tmp.iH1 +b);tmp +x02;add.AddCollectionTo(tmp,c);c11 +goto +done_a;} +} +remaining[a]=true;tB+=1;done_a:;} +} +if(tB>0){if(tB>1){yG >nV;std::multimapeB1;bool +l13 +i13 +t12{eW3 +xI2.c81{lM1&p=xI2 +lD +b);const +fphash_t +p_hash=p.GetHash();for(std::multimap::const_iterator +i=eB1.xE2 +p_hash);i!=eB1.cP1 +p_hash;++i){if(nV[i +cJ2 +eC3 +iA +p)){nV[i +cJ2 +eD3+=1;l13=true;goto +found_mulgroup_item_dup;} +} +nV +yL +std::make_pair(p,size_t(1)));eB1.insert(std::make_pair(p_hash,nV +yA3-1));found_mulgroup_item_dup:;} +} +if(l13)nG1 +cK2;{size_t +max=0;for(size_t +p=0;pmax){cK2=nV[p +eC3;max=nV[p +eD3;} +} +} +yK2 +group_add;group_add +tU +cAdd); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Duplicate across some trees: " +;xE3(cK2)lN1" in " +eS +#endif +t12 +eW3 +xI2.c81 +if(cK2 +iA +xI2 +lD +b)))nG1 +tmp +nW1 +a)yO +CloneTag());tmp.iH1 +b);tmp +x02;group_add +yA +tmp);remaining[a]i13 +nM3 +group_add +i72 +group;group +e53 +group +yA +cK2);group +yA +group_add);group +x02;add.iR1 +group);c11} +} +t12{if(add.AddCollection +nW1 +a))==CollectionSetBase::xA2)c11} +} +if(should_regenerate){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before ConstantFolding_AddGrouping: " +eS +#endif +tree.DelParams();xH2 +e81::xI1 +j=add.i8.nW3 +j!=add.i8.end();++j)nG1&value=j +cJ2.value +yJ&coeff=j +cJ2.xD2;if(j +cJ2.e2)coeff +x02;if(coeff +tF3(fp_equal(coeff.xJ1,eS1(0)))y81 +if(fp_equal(coeff.xJ1,nY3{tree +yA +value);y81} +} +yK2 +mul;mul +e53 +mul +yA +value);mul +yA +coeff);mul.Rehash(tT +t02;} +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"After ConstantFolding_AddGrouping: " +eS +#endif +return +true;} +nX2} +iO2{xQ +using +iO2 +FPoptimizer_CodeTree;xG1 +ConstantFolding_IfOperations(tT3(tree.tU3()==cIf +tI3()==i03);for(;;){l23 +nE==cNot){tH +cIf +tT +lD +0).xO2 +0)lD +0)tT +lD +1).swap +nW1 +2));} +else +l23 +cG1{tH +i03 +tT +lD +0).xO2 +0)lD +0)tT +lD +1).swap +nW1 +2));} +else +t62 +tX +0),cV2 +i03))tF1 +tree.xO2 +1));nW +yO3 +xP3 +xO2 +2));nW +lX1 +l23 +nE==cIf||e72 +nE==i03)nG1 +cond +cL2 +0)yJ +l53;l53 +xP2==cIf?cNotNot:cAbsNotNot);l53 +x63 +x03;ConstantFolding(l53)yJ +truth_b;truth_b +xP2==cIf?cNotNot:cAbsNotNot);truth_b +x63 +x73 +ConstantFolding(truth_b);if(l53 +y21||truth_b +y21)nG1 +eU;eU +xP2);eU +x63 +x03;eU +yC +1));eU +yC +2));eU +i72 +eV;eV +xP2);eV +x63 +x73 +eV +yC +1));eV +yC +2));eV +y3 +cond +nE +xK1 +0,cond +lD +0)tT.nC1 +1,eU +tT.nC1 +2,eV)nS2} +if +nW1 +1)nE==tree +lD +2)nE&&nW1 +1)nE==cIf||tree +lD +1)nE==i03))nG1&cM2 +cL2 +1)yJ&leaf2 +cL2 +2);if +x83 +0).xO +0))&&x83 +1).xO +1))||cM2 +lD +2).xO +2))))nG1 +eU;eU +xQ2 +eU +yC +0));eU +eT +cM2 +x03;eU +eT +leaf2 +x03;eU +i72 +eV;eV +xQ2 +eV +yC +0));eV +eT +cM2 +x73 +eV +eT +leaf2 +x73 +eV +y3 +cM2 +nE +xK1 +0 +eF3 +0)tT.nC1 +1,eU +tT.nC1 +2,eV)nS2 +if +x83 +1).xO +1))&&cM2 +lD +2).xO +2)))nG1 +eW;eW +xQ2 +eW +yA +e72);eW +eT +cM2 +xY3 +eW +eT +leaf2 +xY3 +eW +y3 +cM2 +nE +tT.nC1 +0,eW +xK1 +2 +eF3 +2)xK1 +1,cM2 +x03 +nS2 +if +x83 +1).xO +2))&&cM2 +lD +2).xO +1)))nG1 +cN2;cN2 +tU +leaf2 +nE==cIf?cNot:yR3);cN2 +eT +leaf2 +xY3 +cN2 +i72 +eW;eW +xQ2 +eW +yA +e72);eW +eT +cM2 +xY3 +eW +yA +cN2);eW +y3 +cM2 +nE +tT.nC1 +0,eW +xK1 +2 +eF3 +2)xK1 +1,cM2 +x03 +nS2} +yK2&xW +cL2 +1)yJ&y9 +cL2 +2);if(xW +iA +y9)){tree.xO2 +1))nS2 +const +OPCODE +op1=xW +nE;const +OPCODE +op2=y9 +nE;if(op1==op2){if(xW.cT1 +1)nG1 +lO +0))xL2 +0 +y31)lY +if(xW.cT1 +2&&y9.cT1 +2){if(xW +lD +0)iA +y9 +lD +0)))nG1 +param0=xW +lD +0)yJ +lO +1))xL2 +1 +y31 +tT +yA +param0)lY +if(xW +lD +1)iA +y9 +x03)nG1 +param1=xW +lD +1)yJ +lO +0))xL2 +0 +y31 +tT +yA +n41 +tT +yA +param1)nS2} +if(op1==x93 +cMul +iU1 +cAnd +iU1 +cOr +iU1 +cAbsAnd +iU1 +cAbsOr +iU1 +cMin +iU1 +cMax){yG +nV1 +l63;cC{for(iX2 +y9.cN3 +b-->0;){lW2 +y9 +lD +b))){if(l63 +cQ3){xW.iY +y9.iY} +l63 +yL +xW +lD +a));y9.iH1 +b);xW.iH1 +a +nW2} +} +if(!l63 +cQ3){xW +x02;y9 +i72 +n41;n41 +xQ2 +n41 +tI1 +tree.iE1));n41 +y3 +op1 +tT +tI1 +l63)lY} +} +if(op1==x93 +cMul||(op1==cAnd +nY1 +y9))||(op1==cOr +nY1 +y9))){cC +lW2 +y9)){xW.iY +xW +cP3 +xW +i72 +cD1=y9;y9=tC +op1==x93 +cOr)l9 +op1 +tT +yA +cD1)lY} +if((op1==cAnd +iU1 +cOr)&&op2==cNotNot)nG1&l73=y9 +lD +0);cC +lW2 +l73)){xW.iY +xW +cP3 +xW +i72 +cD1=l73;y9=tC +op1 +xA3 +op1 +tT +yA +cD1)lY} +if(op2==cAdd||op2==cMul||(op2==cAnd +nY1 +xW))||(op2==cOr +nY1 +xW))){for +xK2 +y9.tD +y9 +lD +a)iA +xW)){y9.iY +y9 +cP3 +y9 +i72 +cE1=xW;xW=tC +op2==cAdd||op2 +xA3 +op2 +tT +yA +cE1)lY} +if((op2==cAnd||op2==cOr)&&op1==cNotNot)nG1&l83=xW +lD +0)c23 +y9.tD +y9 +lD +a)iA +l83)){y9.iY +y9 +cP3 +y9 +i72 +cE1=l83;xW=tC +op2 +xA3 +op2 +tT +yA +cE1)lY} +nX2} +#include +iO2{xQ +using +iO2 +FPoptimizer_CodeTree;yV1 +int +maxFPExponent(){return +std::numeric_limits +x8::max_exponent;} +xG1 +x71 +eS1 +xB3 +cE2){if(base=eS1(maxFPExponent +x8())/fp_log2(base);} +xG1 +ConstantFolding_PowOperations(tT3(tree.tU3()==cPow);y2){eS1 +const_value=eG3 +n6,y4 +tT.ReplaceWithImmed(const_value)l81 +false;} +if(nE1 +fp_equal(y4,nY3{tree.xO2 +0))nS2 +lX&&fp_equal(n6,nY3 +lL +1)l81 +false;} +lX&&tree +lD +1)nE==cMul){bool +xR2 +i13 +eS1 +iV1=n6 +yJ +n83 +cL2 +1)c23 +xX1 +tD +n83 +lD +a)xC3 +imm=n83 +lD +a).xJ1;{if(x71 +iV1,imm +n33 +iW1=eG3 +iV1,imm)i82 +iW1,eS1(0)))break;if(!xR2){xR2=true;xX1 +iY} +iV1=iW1;xX1 +iH1 +a +nW2} +if(xR2){xX1 +Rehash(); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before pow-mul change: " +eS +#endif +e72.Become(cU1 +iV1)tT +lD +1).Become(n83); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"After pow-mul change: " +eS +#endif +} +} +if(nE1 +e72 +nE==cMul){eS1 +iX1=y4;eS1 +xS2=1.0;bool +xR2=false +yJ&n83 +cL2 +0)c23 +xX1 +tD +n83 +lD +a)xC3 +imm=n83 +lD +a).xJ1;{if(x71 +imm,iX1 +n33 +eD1=eG3 +imm,iX1)i82 +eD1,eS1(0)))break;if(!xR2){xR2=true;xX1 +iY} +xS2*=eD1;xX1 +iH1 +a +nW2} +if(xR2){xX1 +Rehash()yJ +cD3;cD3 +tU +cPow);cD3 +tI1 +tree.iE1));cD3.y12);tH +cMul +tT +yA +cD3 +tT +eT +cU1 +xS2))nS2} +l23 +nE==cPow&&nE1 +e72 +lD +1)xC3 +a +cL2 +0)lD +1).xJ1;eS1 +b=y4;eS1 +c=a*b;if(isEvenInteger(a)&&!isEvenInteger(c))nG1 +l93;l93 +tU +cAbs);l93 +yC +0)xY3 +l93.Rehash(tT.nC1 +0,l93);} +else +tree.SetParam(0,e72 +lD +0)xK1 +1,cU1 +c));} +nX2} +iO2{xQ +using +iO2 +FPoptimizer_CodeTree;e92 +l4{enum +cO2{MakeFalse=0,MakeTrue=1,t22=2,lC3=3,MakeNotNotP0=4,MakeNotNotP1=5,MakeNotP0=6,MakeNotP1=7,Unchanged=8 +n23 +iY1{Never=0,Eq0=1,Eq1=2,xD3=3,xR3=4} +;cO2 +if_identical;cO2 +iZ1 +4];e92{cO2 +what:4;iY1 +when:4;} +tS1,tT1,tU1,tV1;yV1 +cO2 +Analyze(lM1&a,lM1&b)const{if(a +iA +b)nZ2 +if_identical;range +x8 +p0=iM +a);range +x8 +p1=iM +b);if(p0 +i0&&p1.iV2){if(p0.maxp1.max&&iZ1 +2]cJ +2];if(p0.min>=p1.max&&iZ1 +3]cJ +3];} +if(IsLogicalValue(a)){if(tS1 +i92 +tS1.when,p1)nZ2 +tS1.what;if(tU1 +i92 +tU1.when,p1)nZ2 +tU1.what;} +if(IsLogicalValue(b)){if(tT1 +i92 +tT1.when,p0)nZ2 +tT1.what;if(tV1 +i92 +tV1.when,p0)nZ2 +tV1.what;} +return +Unchanged +eI2 +bool +TestCase(iY1 +when,const +range +x8&p){if(!p.iV2||!p +i0 +yI +switch(when +iY2 +Eq0:return +p.min==0.0 +xQ3==p.min;case +Eq1:return +p.min==1.0 +xQ3==p.max;case +xD3:return +p.min>0 +xQ3<=1;case +xR3:return +p.min>=0 +xQ3<1;default:;} +nX2} +;iO2 +RangeComparisonsData{static +const +l4 +Data[6]={{l4 +lA3 +tP +Unchanged,l4::tP +Unchanged +tE +Eq1 +tF +Eq1 +nD1 +Eq0} +,l91 +Eq0} +} +,{l4::lX2 +lB3 +Unchanged,l4 +lB3 +Unchanged +tE +Eq0 +tF +Eq0 +nD1 +Eq1} +,l91 +Eq1} +} +,{l4::lX2 +lB3 +t22,l4::tP +MakeFalse +nD1 +xD3 +tF +xR3 +xD,{l4 +lA3 +Unchanged,l4 +lB3 +tP +lC3 +nD1 +xR3 +tF +xD3 +xD,{l4::lX2::tP +tP +MakeTrue,l4::t22 +tE +xR3} +,l91 +xD3 +xD,{l4 +lA3 +tP +lC3,l4::Unchanged,l4 +nH1 +tE +xD3} +,l91 +xR3 +xD} +;} +xG1 +ConstantFolding_Comparison(eR{using +iO2 +RangeComparisonsData;assert(tree.tU3()>=cEqual&&tree.tU3()<=cGreaterOrEq);switch(Data[tree +nE-cEqual].Analyze +nW1 +0),tree +x03 +iY2 +l4::MakeFalse +xP3 +ReplaceWithImmed(0);nW +l4 +nH1 +xP3 +ReplaceWithImmed(1 +l33 +lC3:tH +cEqual +l33 +t22:tH +t71 +l33 +MakeNotNotP0:tH +cNotNot +tW1 +1 +l33 +MakeNotNotP1:tH +cNotNot +tW1 +0 +l33 +MakeNotP0:tH +cNot +tW1 +1 +l33 +MakeNotP1:tH +cNot +tW1 +0 +l33 +Unchanged:;} +if +nW1 +1)y21)switch +nW1 +0)nE +iY2 +cAsin +xP3 +lR +fp_sin(iA2 +cAcos +xP3 +lR +fp_cos(y4)));tH +cV2 +cLess?cGreater:cV2 +cLessOrEq?cGreaterOrEq:cV2 +cGreater?cLess:cV2 +cGreaterOrEq?cLessOrEq:tree +nE);nW +cAtan +xP3 +lR +fp_tan(iA2 +cLog +xP3 +lR +fp_exp(iA2 +cSinh +xP3 +lR +fp_asinh(iA2 +cTanh:if(fp_less(fp_abs(y4),nY3{tree.lR +fp_atanh(y4)))nS2 +break;default:nM3 +nX2} +#include +#include +#ifdef FP_SUPPORT_OPTIMIZER +xQ +iO2{ +#ifdef DEBUG_SUBSTITUTIONS +yW +double +d){union{double +d;uint_least64_t +h;} +t32 +d=d;lH1 +h +nZ1 +#ifdef FP_SUPPORT_FLOAT_TYPE +yW +float +f){union{float +f;uint_least32_t +h;} +t32 +f=f;lH1 +h +nZ1 +#endif +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +yW +long +double +ld){union{long +double +ld;e92{uint_least64_t +a;i02 +short +b;} +s;} +t32 +ld=ld;lH1 +s.b<IsIdenticalTo(*b.data);} +xG1 +nO2 +x8::IsIdenticalTo +i01 +nO2 +x8&b)const{if(Hash!=b.Hash +yI +if(Opcode!=t43 +yI +switch(Opcode +iY2 +cImmed:return +fp_equal(Value,t53;case +iE2:return +iJ1==b.iI1 +case +cFCall:case +cPCall:if(iJ1!=b.iJ1 +yI +break;default:nM3 +if(nF3!=b.nF3 +yI +for +xK2 +0;a1)data=new +nO2 +x8(*data);} +yV1 +yK2 +yK2::GetUniqueRef(){if(GetRefCount()>1 +nZ2 +yK2(*this,CloneTag())l81*this;} +tQ):c7 +cNop +l43),nC +tQ +const +nO2&b):c7 +t43 +l43 +t53,iJ1(b.iJ1),c93(b.c93),Hash(b.Hash),Depth(b.Depth),eZ1 +b.iK1){} +tQ +e62 +i):c7 +cImmed +l43 +i),nC +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +tQ +nO2 +x8&&b):c7 +t43 +l43 +t72 +t53),iJ1(b.iJ1),c93(t72 +b.c93)),Hash(b.Hash),Depth(b.Depth),eZ1 +b.iK1){} +tQ +eS1&&i):c7 +cImmed +l43 +t72 +i)),nC +#endif +tQ +nR2 +o):c7 +o +l43),nC +tQ +nR2 +o,i02 +f):c7 +o +l43),iJ1(f),c93(),Hash(),Depth(1),eZ1 +0){} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +#include +#include +#include +#include +#include +xQ +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +iO2{xB1 +l22 +cA3,eH3&done,std::ostream&o){for +yS +l22 +i43 +done,o);std::ostringstream +buf;xE3(tree,buf);done[tree.GetHash()].insert(buf.str());} +} +#endif +iO2 +FPoptimizer_CodeTree{ +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +xB1 +DumpHashes +i01 +eY){eH3 +done;l22(tree,done,o);for(eH3::const_iterator +i=done.nW3 +i!=done.end();++i){const +std::set&flist=i +cJ2;if(flist +yA3!=1)o<<"ERROR - HASH COLLISION?\n" +;for(std::set::const_iterator +j=flist.nW3 +j!=flist.end();++j){o<<'['<first.hash1<<','<first.hash2<<']'<0)o<<' ';xE3 +i43 +o);if(a+1 +iO2 +l41{xG1 +ParamSpec_Compare +i01 +void*aa,const +void*bb,lU2 +type){switch(type +iY2 +lY2 +xH&a=*(xH*)aa;xH&b=*(xH*)bb +l81 +a +t42==b +t42&&a.index==b.index&&a.depcode==b.depcode +cM3 +NumConstant:{eZ&a=*(eZ*)aa;eZ&b=*(eZ*)bb +l81 +fp_equal(a.xZ3,b.xZ3)&&a.modulo==b.modulo +iD2 +xI&a=*(xI*)aa;xI&b=*(xI*)bb +l81 +a +t42==b +t42&&a.cS==b.cS&&a.data.match_type==b.data.match_type&&a.data +xY2==b.data +xY2&&a.data.param_list==b.data.param_list&&a.data.n2==b.data.n2&&a.depcode==b.depcode;} +} +return +true;} +i02 +ParamSpec_GetDepCode +i01 +cG2&b){switch(b.first +iY2 +lY2 +yK3*s=i01 +xH*)b +eE3 +l81 +s->depcode +iD2 +const +xI*s=i01 +xI*)b +eE3 +l81 +s->depcode;} +default:nM3 +return +0;} +xB1 +DumpParam +i01 +cG2&xZ2 +std::ostream&o){static +const +char +ParamHolderNames[][2]={"%" +,"&" +,"x" +,"y" +,"z" +,"a" +,"b" +,"c" +} +;i02 +t52 +0;xT3 +NumConstant:{const +eZ&t82 +eZ*x01;o.precision(12);o<';yZ +PositionalParams)o<<"]" +;yZ +SelectedParams)o<<"}" +;o<<')';} +nM3 +yN3(ImmedConstraint_Value(tX1 +ValueMask)iY2 +ValueMask:lC +Value_AnyNum:lC +n12:o<<"@E" +;lC +Value_OddInt:o<<"@O" +;lC +t01:o<<"@I" +;lC +Value_NonInteger:o<<"@F" +;lC +eE1:o<<"@L" +;t62 +ImmedConstraint_Sign(tX1 +SignMask)iY2 +SignMask:lC +Sign_AnySign:lC +nJ1:o<<"@P" +;lC +n02:o<<"@N" +;t62 +ImmedConstraint_Oneness(tX1 +OnenessMask)iY2 +OnenessMask:lC +Oneness_Any:lC +Oneness_One:o<<"@1" +;lC +Oneness_NotOne:o<<"@M" +;t62 +ImmedConstraint_Constness(tX1 +ConstnessMask)iY2 +ConstnessMask:lC +yL1:if(lF3.first==ParamHolder){yK3&t82 +xH*x01;if +iZ2 +index<2)nM3 +o<<"@C" +;lC +Constness_NotConst:o<<"@V" +;lC +Oneness_Any:nM3} +xB1 +DumpParams +iL1 +paramlist,i02 +count,std::ostream&o){for +iL1 +a=0;a0)o<<' ';const +cG2¶m=e01 +x8(paramlist,a);DumpParam +x8(param,o);i02 +depcode=ParamSpec_GetDepCode(param);if(depcode!=0)o<<"@D" +< +using +iO2 +l41;xQ +iO2{yK3 +plist_p[36]={{2,0,0x0} +tS +0,0x4} +tS +nJ1,0x0} +tS +n02|Constness_NotConst,0x0} +tS +Sign_NoIdea,0x0} +tS +eE1,0x0} +,{3,Sign_NoIdea,0x0} +,{3,0,0x0} +,{3,eE1,0x0} +,{3,0,0x8} +,{3,Value_OddInt,0x0} +,{3,Value_NonInteger,0x0} +,{3,n12,0x0} +,{3,nJ1,0x0} +,{0,n02|n0{0,n0{0,nJ1|n0{0,n12|n0{0,yL1,0x1} +,{0,t01|nJ1|n0{0,t11 +yL1,0x1} +,{0,t11 +n0{0,Oneness_One|n0{0,eE1|n0{1,n0{1,n12|n0{1,t11 +n0{1,t01|n0{1,nJ1|n0{6,0,0x0} +,{4,0,0x0} +,{4,t01,0x0} +,{4,n0{4,0,0x16} +,{5,0,0x0} +,{5,n0} +;yT1 +plist_n_container{static +const +eZ +plist_n[19];} +;yV1 +const +eZ +plist_n_container +x8::plist_n[19]={{eS1(-2 +iZ-1 +iZ-0.5 +iZ +0 +tB2 +fp_const_deg_to_rad +cE3 +fp_const_einv +cE3 +fp_const_log10inv +x8(iZ +0.5 +tB2 +fp_const_log2 +x8(iZ +1 +tB2 +fp_const_log2inv +x8(iZ +2 +tB2 +fp_const_log10 +cE3 +fp_const_e +cE3 +fp_const_rad_to_deg +cE3-fp_const_pihalf +x8(),xL1{eS1(0),xL1{fp_const_pihalf +x8(),xL1{fp_const_pi +x8(),xL1} +;const +xI +plist_s[464]={{{1,15,tC2 +15,cNeg,GroupFunction,0} +,yL1,0x1} +,{{1,422,tC2 +423,tC2 +15,tD2 +24,tD2 +410,tD2 +411,cInv,xZ +2,301330,cAdd,tG2 +271397 +lU1 +0x5 +tY3 +271397,l5 +45 +lU1 +iR +2,58413,l5 +140333,l5 +194605 +lU1 +0x1 +tY3 +224301,l5 +270373,l5 +270381,l5 +271405,l5 +271405 +lU1 +0x5 +tY3 +140341,l5 +223285,l5 +286757,l5 +286765,l5 +322605,l5 +232501,l5 +7168,l5 +30727,l5 +141312,l5 +179207,l5 +58383,l5 +59407,l5 +285718 +lU1 +iR +2,59416,l5 +29726,l5 +34823,l5 +18597,l5 +46264,l5 +15764,l5 +57509,l5 +293049,l5 +292026,l5 +161979,l5 +161980,l5 +172265,l5 +173308,l5 +243951,l5 +247024,l5 +38152,l5 +46344,l5 +293147,l5 +1332,l5 +24980,l5 +183473,l5 +183570,l5 +418001,l5 +420248,cAdd,lP +0,0,tR +0,0,cAdd,i3 +1,43,tR +1,51,tR +1,52,tR +1,53,tR +1,54,tR +1,0,lZ +iR +1,0,t51 +2} +,0,iR +1,0,tR +1,21,tR +1,15,tR +1,26,tR +1,24,cAdd,i3 +2,56344,cAdd,i3 +1,219,tR +1,230,cAdd,i3 +1,245,lZ +0x16} +,{{1,329,lZ +0x16} +,{{1,399,lZ +iR +1,401,lZ +iR +0,0,t51 +1} +,nJ1,0x0 +tY3 +46095,tE2 +24591,tE2 +32783,tE2 +37,c1 +7205,c1 +114725,c1 +288805,lJ +0x6 +tY3 +347173,lJ +0x6 +tY3 +331813,c1 +350245,c1 +372773,c1 +377893,c1 +378917,c1 +383013,c1 +388133,c1 +439333,c1 +442405,c1 +447525,c1 +450597,c1 +459813,c1 +468005,c1 +305201,l2 +3,61910016,c1 +7168,c1 +114688,c1 +512000,l2 +3,45508608,c1 +15,c1 +30727,c1 +71695,c1 +130063,c1 +286735,lJ +0x1 +tY3 +29726,c1 +34823,c1 +115736,c1 +114712,c1 +299008,c1 +288783 +xM2 +300032,c1 +347151 +xM2 +357376,l2 +3,65425438,c1 +420864,c1 +280611,c1 +358407,c1 +301088,c1 +55,c1 +38143,c1 +38143,lJ +iR +2,38145,lJ +iR +2,38152,c1 +38171,c1 +15631,c1 +15711,c1 +56671,c1 +38262,lJ +iR +2,60820,c1 +38325,lJ +iR +3,15777143,c1 +37303,c1 +48505,l2 +3,15777207,c1 +347191 +xM2 +48571,c1 +103714,c1 +104739,c1 +266538,c1 +307547,c1 +304475,c1 +353627,c1 +48490,c1 +310338,c1 +376173,lJ +lP2 +3,39173485,lJ +lP2 +2,436589,lJ +lP2 +2,7578,c1 +376232,lJ +lP2 +2,436648,lJ +lP2 +3,39233901,lJ +lP2 +3,39233960,lJ +lP2 +2,7651,c1 +7675,l2 +0,0,nO +0,0,cT +1,37,nO +1,37,cT +1,2,n22 +2,n32 +3,n22 +3,n32 +0,nO +1,0,n32 +0,cT +1,14,nO +1,16,nO +1,16,lK +1 +xN2 +21,nO +1,15,nO +1,24,cT +2,24591,nO +1,55,nO +1,55,lK +2 +xN2 +275,n22 +278,n32 +284,cT +1,287,nO +1,288,nO +1,289,cT +1,462,cT +2,413757,lK +1 +xN2 +295,nO +1,329,cT +2,414025,lK +1} +,0,0x16} +,{{1,351,nO +1,404,nO +1,410,nO +2,60459,l32 +44047,l32 +24591,l32 +32783,l32 +44056,l32 +41,lI,41,y0 +49,lI,49,y0 +365609,lI,222257,lI,365617,lI,366633,lI,366641,lI,48128,lI,15,lI,15,cV1 +16,lI,10240,lI,11264,lI,7170,lI,7168,lI,7168,y0 +7183,cV1 +17408,lI,19456,lI,16384,lI,15360,lI,27648,lI,30720,lI,30722,lI,24,tF2 +0x6 +tY3 +24,lI,7192,lI,68608,lI,83968,lI,86040,lI,87040,lI,88064,lI,90112,lI,432128,lI,433152,lI,37895,lI,14342,lI,25607,lI,7183,lI,56327,lI,114703,lI,114718,lI,257024,lI,419840,lI,260103,lI,37953,tF2 +0x5 +tY3 +37956,y0 +37961,tF2 +0x5 +tY3 +38105,lI,38114,y0 +38984,y0 +44103,y0 +44104,y0 +38991,lI,44111,lI,44135,lI,44124,y0 +44136,lI,48240,lI,60693,lI,38253,y0 +38253,lI,38259,tF2 +0x5 +tY3 +38260,cV1 +38262,y0 +38262,lI,48493,y0 +48493,lI,15734,y0 +137590,lI,38264,tF2 +0x5 +tY3 +38292,lI,38294,lI,38300,lI,38301,lI,38312,y0 +38325,y0 +38332,y0 +38332,lI,38341,lI,38341,y0 +38343,lI,60,lI,60,tF2 +0x6 +tY3 +48552,y0 +48552,lI,257198,lI,260274,lI,24792,lI,7172,cPow,PositionalParams,0} +,nJ1,0x0 +tY3 +24591,cPow,xZ +2,60440,cPow,xZ +2,60451,cPow,xZ +2,61472,cPow,xZ +1,0,eI3 +7,eI3 +157,eI3 +0,cAcos +eJ3 +cAcosh +eJ3 +cAsin +eJ3 +cAsinh +nR +112,cAsinh +eJ3 +cAtan,eF1 +cAtan2,tG2 +303104 +i23 +eJ3 +cAtanh +eJ3 +cCeil,cF3 +216,cCeil +eJ3 +yO2 +0,cCos,cF3 +7,yO2 +81,yO2 +83,yO2 +112,yO2 +180,yO2 +234,yO2 +0,cH3 +cF3 +0,cI3 +176,cI3 +180,cI3 +409,cI3 +0,cFloor,cF3 +216,cFloor,tG2 +308523,eK3 +tG2 +352555,eK3 +tG2 +352599,eK3 +l0 +3,31464448,cU +507534336,cU +508566528,cU +33579008,cU +30443520,lD3 +31464448,lD3 +7836672,cU +24612864,cU +93415424,cU +142744576,cU +174234624,cU +265547776,cU +435585024,cU +439783424,cU +519553024,cU +526900224,cU +58739160,cU +58739160,lD3 +58739166,cU +58739166,cIf,cF3 +112,cInt +eJ3 +tH2 +7,tH2 +30,tH2 +157,tH2 +216,tH2 +282,tH2 +15,cLog,xZ +1,24,cLog,xZ +1,0,cLog10 +eJ3 +cLog2,eF1 +cMax,tG2 +29726,cMax,tG2 +34823,cMax +eJ3 +cMax,AnyParams,1} +,0,iR +xG3 +cMin,tG2 +29726,cMin,tG2 +34823,cMin +eJ3 +cMin,AnyParams,1} +,0,iR +2,46095,cMin,xZ +2,24591,cMin,xZ +1,0,n42 +0,cSin,cF3 +7,n42 +81,n42 +83,n42 +112,n42 +139,n42 +161,cSin,nU +0x5} +,{{1,216,n42 +227,n42 +231,cSin,nU +0x1} +,{{1,234,n42 +0,cSinh,cF3 +0,cSinh +nR +161,cSinh,nU +0x5} +,{{1,176,cSinh +nR +216,cSinh +nR +227,cSinh +nR +234,cSinh +nR +409,cSinh +eJ3 +yP2 +0,cTan,cF3 +75,cTan,cF3 +76,yP2 +161,yP2 +216,yP2 +231,yP2 +227,yP2 +234,yP2 +0,xV2 +0,cTanh,cF3 +160,xV2 +161,xV2 +216,xV2 +227,xV2 +234,xV2 +0,cTrunc,tG2 +15384,cSub,xZ +2,15384,cDiv,xZ +2,420251,cDiv,xZ +xG3 +tK2 +nU +t41 +tK2 +tG2 +30720,tK2 +nU +0x20 +tY3 +30727,tK2 +nU +0x24 +tY3 +30727,tK2 +tG2 +114743,tK2 +tG2 +114743,t71,tG2 +39936,cLess,l6 +2,39936,cLess,tG2 +7,cLess,eF1 +cLess,nU +t41 +cLessOrEq,tG2 +256216,cLessOrEq,tG2 +39936,e82 +l6 +2,39936,e82 +tG2 +7,e82 +eF1 +e82 +nU +t41 +cGreaterOrEq,tG2 +256216,cGreaterOrEq +eJ3 +l42 +7,l42 +15,l42 +30,l42 +156,l42 +494,l42 +497,l42 +498,l42 +501,l42 +504,l42 +505,cNot,eF1 +l52 +29726,l52 +34823,l52 +394270,l52 +398366,l52 +7651,cAnd,lP +0,0,cAnd,AnyParams,1} +,0,0x0} +,{{xG3 +nJ2 +29726,nJ2 +34823,nJ2 +394270,nJ2 +398366,nJ2 +7651,cOr,lP +1,0 +t31 +81 +t31 +121 +t31 +156 +t31 +159 +t31 +216,cDeg +nR +216,cRad,eF1 +cAbsAnd,lP +xG3 +cAbsOr,lP +1,0,yR3 +eJ3 +cAbsNotNot,l0 +3,31464448,eP3 +nU +0x0} +,} +;} +iO2 +l41{const +Rule +grammar_rules[253]={{ProduceNewTree,1,1,0,{1,0,cAbs,xJ +361,{1,172,cAtan,xJ +354 +tS +1337 +i23,xJ +356 +tS +320513 +i23 +l7 +2,2,222424 +tS +226524 +i23 +l7 +2,2,224474 +tS +228574 +i23,xJ +148 +x13 +cCeil,xJ +435,{1,80,tL2 +429,{1,115,tL2 +430,{1,117,tL2 +146,{1,118,tL2 +370,{1,116,tL2 +0,{1,354,cCos +l7 +2,1,0,{1,351,cCos +l7 +2,1,216 +x13 +tL2 +314,{1,357,cCosh +l7 +2,1,0,{1,351,cCosh +l7 +2,1,216 +x13 +cH3 +xJ +144 +x13 +cFloor,xJ +403,{1,114,cFloor,eL3 +214,{3,7379968,c8 +518,{3,31464450,c8 +499,{3,8428544,c8 +501,{3,8434688,c8 +215,{3,40901632,c8 +494,{3,40902656,c8 +507,{3,40940544,c8 +506,{3,47194112,c8 +483,{3,47225856,c8 +414,{3,1058266,c8 +418,{3,1058272,c8 +418,{3,9438682,c8 +414,{3,9438688,c8 +460,{3,396733911,c8 +460,{3,381020637,cIf +l7 +0,3,31492569,{3,35682779,cIf +l7 +0,3,31492575,{3,35682785,cIf,xJ +111,{1,228,eM3 +110,{1,244,eM3 +355,{1,106,eM3 +204,{1,205,cLog +l7 +0,1,395 +cP2,cMax +yF +0 +tS +431105,cMax +yF +396 +cP2,cMin +yF +0 +tS +427009,cMin,AnyParams,0} +} +,{ProduceNewTree,0,1,203 +tS +24804,cPow,eL3 +203 +tS +25827,cPow,eL3 +202 +tS +126991,cPow +xM1 +30988,cPow +xM1 +30989,cPow +xM1 +30990,cPow +t93 +166239 +tS +31066,cPow +xM1 +32015,cPow +t93 +7168 +tS +12639,cPow +t93 +7392 +tS +12535 +x23 +380 +tS +44095 +x23 +381 +tS +44141 +x23 +382 +tS +44140 +x23 +201 +tS +109583 +x23 +200 +tS +132129 +x23 +155 +tS +133153 +n52 +419840 +tS +413711 +n52 +254976 +tS +253967 +n52 +221184 +tS +251937 +n52 +221184 +tS +248850 +x23 +150 +x13 +yQ2 +372,{1,80,yQ2 +146,{1,115,yQ2 +370,{1,117,yQ2 +149,{1,118,yQ2 +429,{1,116,yQ2 +0,{1,356,yQ2 +152 +x13 +cSinh,xJ +312,{1,355,cSinh,xJ +153 +x13 +eN3 +0,{1,359,eN3 +170,{1,360,eN3 +154 +x13 +cTanh +l7 +0,1,392 +tS +395279,tM2 +391 +cP2,tM2 +199 +tS +242924,tM2 +198 +tS +230636,tM2 +164 +tS +240869,tM2 +163 +tS +240660,t51 +0 +nM1 +263,{1,311,t51 +1 +nM1 +262,{1,310,t51 +1 +l1 +2,1,261 +tS +1333 +lW1 +259 +tS +1331 +lW1 +407 +tS +415124 +lW1 +45 +tS +331093 +lW1 +324 +tS +146477 +lW1 +342 +tS +145453 +lW1 +427 +tS +213202 +lW1 +428 +tS +217298 +lW1 +368 +tS +216270 +lW1 +145 +tS +216271 +lW1 +369 +tS +218318 +lW1 +197 +tS +144665 +lW1 +194 +tS +348441 +lW1 +193 +tS +348300 +lW1 +195 +tS +200875 +lW1 +192 +tS +177323 +lW1 +257 +tS +446837 +lW1 +181 +tS +446653 +lW1 +151 +tS +187765 +lW1 +147 +tS +187828 +lW1 +255 +tS +195957 +lW1 +374 +tS +264383 +lW1 +437 +tS +264381 +lW1 +437 +tS +186741 +lW1 +374 +tS +262580 +lW1 +151 +tS +262333,tM2 +98 +tS +1155 +eG1 +97 +tS +1156 +eG1 +305 +tS +1330 +eG1 +99 +tS +24704 +eG1 +100 +tS +24698 +eG1 +394 +tS +395279 +eG1 +393 +cP2 +eG1 +353 +tS +360799 +eG1 +96 +tS +89360 +eG1 +105 +tS +80155 +eG1 +95 +tS +79131 +cQ2 +56671 +tS +1424 +cQ2 +15711 +tS +1426 +cQ2 +107535 +tS +93467 +cQ2 +97295 +tS +96539,l8 +1,1,0,{1,351,l8 +1,1,55,{1,14,lK +0 +nM1 +93 +tS +70674,cMul,SelectedParams,0 +nM1 +512,{1,50,lK +1 +nM1 +513,{1,40,lK +1 +l1 +2,1,435 +tS +443429,eA +442 +tS +451621,eA +336 +tS +382285,eA +437 +tS +382406,eA +374 +tS +446801,eA +365 +tS +435534,eA +444 +tS +325033,eA +318 +tS +340413,eA +335 +tS +375116,eA +424 +tS +375229,eA +45 +tS +456126,eA +450 +tS +328114,eA +45 +tS +460223,eA +452 +tS +461861,eA +453 +tS +329140,eA +322 +tS +341446,eA +456 +tS +335286,eA +448 +tS +327087,eA +459 +tS +469029,eA +455 +tS +311360,eA +338 +tS +309322,eA +412 +tS +43412,eA +330 +tS +49480,eA +413 +tS +47508,eA +331 +tS +45384,l8 +2,2,334277 +tS +333236 +cQ2 +39936 +tS +xH3 +cEqual +yP +cEqual +yQ +cEqual +yR +cEqual +lA1 +24807 +t61 +iD +t61 +l62 +237799 +t61 +n11 +cEqual +l72 +tK2 +eH1 +39,tK2 +eO3 +0 +tS +5165,cEqual +t93 +39936 +tS +xH3 +t71 +yP +t71 +yQ +t71 +yR +t71 +lA1 +24807 +tI2 +iD +tI2 +l62 +237799 +tI2 +n11 +t71 +l72 +t71 +tJ2 +39,t71,eH1 +5165,t71 +yP +cLess +yQ +cLess +yR +cLess,xJ +516 +tS +44032,cLess +lA1 +24804 +t21 +yM1 +t21 +iD +t21 +l62 +237796 +t21 +xN1 +t21 +n11 +cLess +l72 +cLess +tJ2 +xH3 +cLess +yP +cLessOrEq +yQ +cLessOrEq +yR +cLessOrEq,xJ +510 +tS +359439,cLessOrEq +lA1 +24804 +xC1 +yM1 +xC1 +iD +xC1 +l62 +237796 +xC1 +xN1 +xC1 +n11 +cLessOrEq +l72 +cLessOrEq +tJ2 +359469,cLessOrEq +yP +cGreater +yQ +cGreater +yR +e82 +xJ +487 +tS +359439,cGreater +lA1 +24804 +y61 +yM1 +y61 +iD +y61 +l62 +237796 +y61 +xN1 +y61 +n11 +cGreater +l72 +e82 +eH1 +359469,cGreater +yP +cGreaterOrEq +yQ +cGreaterOrEq +yR +cGreaterOrEq,xJ +517 +tS +44032 +yX +473304 +tS +24804 +yX +yM1 +yX +iD +yX +l62 +237796 +yX +xN1 +yX +7168 +tS +279818 +yX +lB1 +cGreaterOrEq,eH1 +xH3 +cGreaterOrEq,eL3 +516,{1,2,cNot,eO3 +469,{1,123,cNot,eL3 +511,{1,5,cAnd,AnyParams,1 +l1 +0,1,514 +tS +13314,cAnd +yF +397 +cP2,cAnd +yF +491 +tS +496099,cAnd +yF +492 +tS +399846,cAnd +yF +493 +tS +393702,cAnd,AnyParams,0 +l1 +0,2,479697,{3,489115088,cAnd +yF +515 +tS +13314,xI3 +508 +tS +8197,xI3 +398 +cP2,xI3 +488 +tS +496099,xI3 +489 +tS +399846,xI3 +490 +tS +393702,xI3 +509 +tS +136197,cOr,AnyParams,0} +} +,{ProduceNewTree,0,1,517,{1,2,xJ3 +l3 +1,1,0,{1,0,xJ3 +eO3 +470,{1,123,xJ3 +xJ +482,{1,228,cAbsNotNot,AnyParams,0 +nM1 +476,{1,227,cAbsNotNot,AnyParams,0} +} +,{ProduceNewTree,0,1,383,{3,31464955,eP3 +eL3 +517,{3,40940544,eP3 +eL3 +516,{3,47225856,i03 +l7 +0,3,31492569,{3,35682779,eP3 +PositionalParams,0} +} +,} +;e92 +grammar_optimize_abslogical_type{xS +9 +eI +grammar_optimize_abslogical_type +grammar_optimize_abslogical={9,{21,183,219,228,231,237,244,249,252} +} +;} +e92 +grammar_optimize_ignore_if_sideeffects_type{xS +59 +eI +grammar_optimize_ignore_if_sideeffects_type +grammar_optimize_ignore_if_sideeffects={59,{0,20,22,23,24,25,26,27,cV +tY1 +78,cZ +xR +grammar_optimize_nonshortcut_logical_evaluation_type{xS +56 +eI +grammar_optimize_nonshortcut_logical_evaluation_type +grammar_optimize_nonshortcut_logical_evaluation={56,{0,26,cV +tY1 +78,cZ +158,167,168,169,178,179,191,195,203,207,215,227,229,230,232,233,234,235,236,238,239,240,241,242,243,245,246,247,248,250,251} +} +;} +e92 +grammar_optimize_round1_type{xS +118 +eI +grammar_optimize_round1_type +grammar_optimize_round1={118,{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,18,26,cV +37,38,tY1 +45,46,47,48,49,50,51,52,53,54,58,59,60,61,62,63,64,65,66,67,68,69,70,71,78,79,80,81,82,83,88,89,90,91,92,93,94,95,96,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,132,xR +grammar_optimize_round2_type{xS +100 +eI +grammar_optimize_round2_type +grammar_optimize_round2={100,{0,15,16,17,26,cV +39,40,tY1 +45,46,47,48,49,50,51,52,53,54,59,60,72,73,78,79,84,85,86,87,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,117,118,119,120,121,122,123,124,125,126,127,128,133,157,xR +grammar_optimize_round3_type{xS +79 +eI +grammar_optimize_round3_type +grammar_optimize_round3={79,{74,75,76,77,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,159,160,161,162,163,164,165,166,170,171,172,173,174,175,176,177,180,181,182,184,185,186,187,188,189,190,192,193,194,196,197,198,199,200,201,202,204,205,206,208,209,210,211,212,213,214,216,217,218,220,221,222,223,224,225,226} +} +;} +e92 +grammar_optimize_round4_type{xS +10 +eI +grammar_optimize_round4_type +grammar_optimize_round4={10,{19,55,56,57,130,131,153,154,155,156} +} +;} +e92 +grammar_optimize_shortcut_logical_evaluation_type{xS +53 +eI +grammar_optimize_shortcut_logical_evaluation_type +grammar_optimize_shortcut_logical_evaluation={53,{0,26,cV +tY1 +78,cZ +158,167,168,169,178,179,191,195,203,207,215,227,229,232,233,234,235,236,239,240,241,242,245,246,247,248,250,251} +} +;} +} +iO2 +l41{yV1 +cG2 +e01 +iL1 +paramlist,lC1){index=(paramlist>>(index*10))&1023;if(index>=55 +nZ2 +cG2(SubFunction +tZ1 +plist_s[index-55]);if(index>=36 +nZ2 +cG2(NumConstant +tZ1 +plist_n_container +x8::plist_n[index-36])l81 +cG2(ParamHolder +tZ1 +plist_p[index]);} +} +#ifdef FP_SUPPORT_OPTIMIZER +#include +#include +#include +#include +xQ +using +iO2 +l41;using +iO2 +FPoptimizer_CodeTree;using +iO2 +FPoptimizer_Optimize;iO2{nT1 +It,typename +T,typename +Comp>eI1 +MyEqualRange(It +first,It +last,const +T&val,Comp +comp){size_t +len=last-first;while(len>0){size_t +nJ3 +len/2;It +n43(first);n43+=half;if(comp(*n43,val)){first=n43;++first;len=len-half-1;} +tP1 +comp(val,*n43)){len=half;} +else{It +left(first);{It&cR2=left;It +last2(n43);size_t +len2=last2-cR2;while(len2>0){size_t +half2=len2/2;It +middle2(cR2);middle2+=half2;if(comp(*middle2,val)){cR2=middle2;++cR2;len2=len2-half2-1;} +else +len2=half2;} +} +first+=len;It +right(++n43);{It&cR2=right;It&last2=first;size_t +len2=last2-cR2;while(len2>0){size_t +half2=len2/2;It +middle2(cR2);middle2+=half2;if(comp(val,*middle2))len2=half2;else{cR2=middle2;++cR2;len2=len2-half2-1;} +} +} +return +eI1(left,right);} +} +return +eI1(first,first);} +yT1 +OpcodeRuleCompare{i12()(lM1&tree,i02 +xW2)const{const +Rule&rule=grammar_rules[xW2]l81 +tree +nErange=MyEqualRange(tN2.rule_list,tN2.rule_list+tN2.rule_count,tree,OpcodeRuleCompare +x8());if(range.eQ3 +range +eE3){ +#ifdef DEBUG_SUBSTITUTIONS +yGrules;rules.nH3 +range +eE3-range.first);yD +if(IsLogisticallyPlausibleParamsMatch(cW1 +nT2 +n72 +rules +yL*r);} +range.first=&rules[0];range +eE3=&rules[rules +yA3-1]+1;if(range.eQ3 +range +eE3){std::cout<<"Input (" +< +#include +#include +#include +#include /* for auto_ptr */ +xQ +using +iO2 +l41;using +iO2 +FPoptimizer_CodeTree;using +iO2 +FPoptimizer_Optimize;iO2{xG1 +TestImmedConstraints +iL1 +bitmask,const +eR{switch(bitmask&ValueMask +iY2 +Value_AnyNum:case +ValueMask:lC +n12:if(GetEvennessInfo +nO3 +l82 +Value_OddInt:if(GetEvennessInfo +nO3 +n82 +t01:if(GetIntegerInfo +nO3 +l82 +Value_NonInteger:if(GetIntegerInfo +nO3 +n82 +eE1:if(!IsLogicalValue(tree)yI +nK1 +SignMask +iY2 +Sign_AnySign:lC +nJ1:if(l01 +l82 +n02:if(l01 +n82 +Sign_NoIdea:if(l01 +Unknown +yI +nK1 +OnenessMask +iY2 +Oneness_Any:case +OnenessMask:lC +Oneness_One:if(!cW2 +if(!fp_equal(fp_abs(yZ3),eS1(1))yI +lC +Oneness_NotOne:if(!cW2 +if(fp_equal(fp_abs(yZ3),eS1(1))yI +nK1 +ConstnessMask +iY2 +Constness_Any:lC +yL1:if(!cW2 +lC +Constness_NotConst:if(cW2 +nM3 +return +true;} +n73e92 +nbitmap{private:static +const +i02 +bits_in_char=8;static +const +i02 +cT2=(xK3 +cS2)*bits_in_char)/nbits;cS2 +data[(extent+cT2-1)/cT2];e13 +void +inc(lC1,int +by=1){data[pos(index)]+=by*cS2(1<>xX2)&mask()xJ2 +pos(lC1){return +index/cT2 +xJ2 +shift(lC1){return +nbits*(index%cT2)xJ2 +mask(){return(1<SubTreesDetail;c83(){std::memset(this,0,xK3*this));} +c83 +i01 +c83&b){std::memcpy(this,&b,xK3 +b));} +c83&e31=i01 +c83&b){std::memcpy(this,&b,xK3 +b))l81*this;} +} +;yV1 +c83 +CreateNeedList_uncached(t0&cB2){c83 +x11 +xS3 +a=0;acX1;static +cX1 +yO1;cX1::nX3 +i=yO1.xE2&cB2);if(i!=yO1.cP1&cB2 +nZ2 +i +cJ2 +l81 +yO1.nT3,std::make_pair(&cB2,CreateNeedList_uncached +x8(cB2)))cJ2;} +yV1 +yK2 +CalculateGroupFunction +i01 +cG2&xZ2 +const +t9 +info){xT3 +NumConstant:{const +eZ&t82 +eZ*x01 +l81 +CodeTreeImmed +iZ2 +xZ3)cM3 +lY2 +yK3&t82 +xH*x01 +l81 +info.GetParamHolderValueIfFound +iZ2 +index)iD2 +const +xI&t82 +xI*x01 +yJ +result;result +tU +xF3 +cS);tC1 +iE1).reserve +iZ2 +data +xY2)xS3 +a=0;a0)--tA3;else--t92;lC +iE2:case +cFCall:case +cPCall:--t92;break;default:assert(opcode0&&x11.SubTreesDetail.get(opcode)>0){--tA2;x11.SubTreesDetail.dec(opcode);} +else--t92;} +} +if(tA3>0||tA2>0||t92>0){nX2 +if(cB2.match_type!=AnyParams){if(0||tA2<0||t92<0){nX2} +return +true;} +yV1 +lZ1 +TestParam +i01 +cG2&xZ2 +lM1&tree +eA2 +start_at,t9 +info){xT3 +NumConstant:{const +eZ&t82 +eZ*x01;if(!cW2 +eS1 +imm=yZ3;switch +iZ2 +modulo +iY2 +Modulo_None:lC +Modulo_Radians:imm=fp_mod(imm,y8 +imm<0)imm +c5 +if(imm>fp_const_pi +x8())imm-=fp_const_twopi +x8(nW2 +return +fp_equal(imm,xF3 +xZ3)cM3 +lY2 +yK3&t82 +xH*x01;if(!x0 +return +info.SaveOrTestParamHolder +iZ2 +index,tree)iD2 +const +xI&t82 +xI*x01;yZ +GroupFunction){if(!x0 +yK2 +xO1=CalculateGroupFunction(xZ2 +info); +#ifdef DEBUG_SUBSTITUTIONS +DumpHashes(xO1)lN1*i01 +void**)&xO1.xJ1 +lN1"\n" +lN1*i01 +void**)&yZ3 +lN1"\n" +;DumpHashes(tree)lN1"Comparing " +;xE3(xO1)lN1" and " +;xE3(tree)lN1": " +lN1(xO1 +iA +tree)?"true" +:"false" +)lN1"\n" +; +#endif +return +xO1 +iA +tree);} +else{if(!&*start_at){if(!x0 +if +xU2!=xF3 +cS +yI} +return +TestParams +iZ2 +data,tree,start_at,info,false);} +} +} +nX2 +yT1 +iS +x22 +MatchInfo +x8 +info;iS()yC3,info(){} +} +;iP2 +MatchPositionSpec_PositionalParams:xP1 +iS +x8>{e13 +iF2 +MatchPositionSpec_PositionalParams(xL3):xM3 +iS +x8>(n){} +} +;e92 +i41 +x22 +i41()yC3{} +} +;class +c0:xP1 +i41>{e13 +i02 +trypos;iF2 +c0(xL3):xM3 +i41>(n),trypos(0){} +} +;yV1 +lZ1 +TestParam_AnyWhere +i01 +cG2&xZ2 +lM1&tree +eA2 +start_at,t9 +info,yG&used,bool +tA1{xNx6;i02 +lG3 +c0 +n92 +a=x6->trypos;goto +retry_anywhere_2 +x42 +c0(iT);a=0;} +eS3 +iT;++a){if(used[a])y81 +retry_anywhere:{lZ1 +r=TestParam(xZ2 +xI2 +lH3);lI3 +used[a]=true;if(tA1 +eT3 +a);x6->trypos=a +l81 +lZ1(true,&*x6);} +} +retry_anywhere_2:if(&*lV1){goto +retry_anywhere;} +} +nX2 +yT1 +y91 +x22 +MatchInfo +x8 +info;yGused;iF2 +y91(size_t +eR3)yC3,info(),used(eR3){} +} +;iP2 +MatchPositionSpec_AnyParams:xP1 +y91 +x8>{e13 +iF2 +MatchPositionSpec_AnyParams(xL3,size_t +m):xM3 +y91 +x8>(n,y91 +x8(m)){} +} +;yV1 +lZ1 +TestParams(t0&nM,lM1&tree +eA2 +start_at,t9 +info,bool +tA1{if(nM.match_type!=AnyParams){if(xT!=iT +yI} +if(!IsLogisticallyPlausibleParamsMatch(nM +n72{nX2 +switch(nM.match_type +iY2 +PositionalParams:{xNx6;i02 +lG3 +cL +n92 +a=xT-1;goto +lD1 +x42 +cL(xT);a=0;} +eS3 +xT;++a){cX2=info;retry_positionalparams:{lZ1 +r=TestParam(cX +a),xI2 +lH3);lI3 +y81} +} +lD1:if(&*lV1){info=cX2;goto +retry_positionalparams;} +if(a>0){--a;goto +lD1;} +info=(*x6)[0].info +l81 +false;} +if(tA1 +for +iL1 +a=0;ax6;yGused(iT);yGiG2(xT);yGy02(xT)lO1{const +cG2 +lF3=cX +a);iG2[a]=ParamSpec_GetDepCode(lF3);} +{i02 +b=0 +lO1 +if(iG2[a]!=0)y02[b++]=a +lO1 +if(iG2[a]==0)y02[b++]=a;} +i02 +lG3 +t6 +n92 +if(xT==0){a=0;goto +retry_anyparams_4;} +a=xT-1;goto +cY1 +x42 +t6(xT,iT);a=0;if(xT!=0){(*x6)[0].info=info;(*x6)[0].used=used;} +} +eS3 +xT;++a){if(a>0){cX2=info;(*x6)[a].used=used;} +retry_anyparams:{lZ1 +r=TestParam_AnyWhere +x8(cX +y02[a]),tree +lH3,used,tA1;lI3 +y81} +} +cY1:if(&*lV1){info=cX2;used=(*x6)[a].used;goto +retry_anyparams;} +cZ1:if(a>0){--a;goto +cY1;} +info=(*x6)[0].info +l81 +false;} +retry_anyparams_4:if(nM.n2!=0){if(!TopLevel||!info.HasRestHolder(nM.n2)){yG +nV1 +yS2;yS2.nH3 +iT)xS3 +b=0;b +#include +using +iO2 +FPoptimizer_CodeTree;using +iO2 +FPoptimizer_Optimize;iO2{yV1 +yK2 +xQ1 +const +cG2&xZ2 +t9 +info,bool +inner=true){xT3 +NumConstant:{const +eZ&t82 +eZ*x01 +l81 +CodeTreeImmed +iZ2 +xZ3)cM3 +lY2 +yK3&t82 +xH*x01 +l81 +info.GetParamHolderValue +iZ2 +index)iD2 +const +xI&t82 +xI*x01 +yJ +tree;tH +xF3 +cS)xS3 +a=0;alist=info.GetMatchedParamIndexes();std::sort(list.i62 +list.end())c23 +list +yA3;a-->0;)tree.iH1 +list[a])xS3 +a=0;a +#include +xQ +using +iO2 +l41;using +iO2 +FPoptimizer_CodeTree;using +iO2 +FPoptimizer_Optimize;iO2 +l41{xB1 +DumpMatch +eX3 +lM1&tree,const +t9 +info,bool +DidMatch,std::ostream&o){DumpMatch +t81,DidMatch?tZ3"match" +:tZ3"mismatch" +,o);} +xB1 +DumpMatch +eX3 +lM1&tree,const +t9 +info,const +char*eY3,std::ostream&o){static +const +char +ParamHolderNames[][2]={"%" +,"&" +,"x" +,"y" +,"z" +,"a" +,"b" +,"c" +} +;o< = " +;xE3(eH2 +second[a],o);o< +#include +#ifdef FP_SUPPORT_OPTIMIZER +xQ +iO2{xG1 +MarkIncompletes(x2){if(tree.Is_Incompletely_Hashed(iF1;bool +i51 +i13 +for +yS +i51|=MarkIncompletes +nW1 +a));if(i51)tree.Mark_Incompletely_Hashed()l81 +i51;} +xB1 +FixIncompletes(x2){if(tree.Is_Incompletely_Hashed()){for +yS +FixIncompletes +nW1 +a)tT +x02;} +} +} +iO2 +FPoptimizer_CodeTree{lA +Sort()cX3 +Sort();} +lA +Rehash(bool +constantfolding){if(constantfolding)ConstantFolding(*this);else +Sort();data +xB +yV1 +l11{c2 +e62 +eZ3 +nP3=0; +#if 0 +long +double +value=Value;eB=crc32::calc(i01 +i02 +char*)&value,xK3 +value));key^=(key<<24); +#elif 0 +union{e92{i02 +char +filler1[16];eS1 +v;i02 +char +filler2[16];} +buf2;e92{i02 +char +filler3[xK3 +eS1)+16-x +K3 +iC1)];eB;} +buf1;} +data;memset(&data,0,xK3 +data));data.buf2.v=Value;eB=data.buf1.key; +#else +int +cE2;eS1 +lQ2=std::frexp(Value,&cE2);eB=iL1(cE2+0x8000)&0xFFFF);if(lQ2<0){lQ2=-lQ2;key=key^0xFFFF;} +else +key+=0x10000;lQ2-=yF3;key<<=39;key|=iC1((lQ2+lQ2)*eS1(1u<<31))<<8; +#endif +iU +tM +#ifdef FP_SUPPORT_LONG_INT_TYPE +n73<>l11{c2 +long +eZ3 +eB=Value;iU +tM +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE +n73<>l11{c2 +const +GmpInt&eZ3 +eB=Value.toInt();iU +tM +#endif +xB1 +nO2 +x8::Recalculate_Hash_NoRecursion(){fphash_t +iU(iC1(Opcode)<<56,Opcode*tM3(0x1131462E270012B));Depth=1;switch(Opcode +iY2 +cImmed:{ImmedHashGenerator +x8::MakeHash(iU,Value +nW2 +case +iE2:{nP3|=eC<<48 +eC2((eC)*11)^tM3(0x3A83A83A83A83A0);nM3 +case +cFCall:case +cPCall:{nP3|=eC<<48 +eC2((~eC)*7)^3456789;} +default:{size_t +eM1=0 +c23 +0;aeM1)eM1=c93[a].xT2;nP3+=((c93[a]eE2 +hash1*(a+1))>>12)eC2 +c93[a]eE2 +hash1 +eC2(3)*tM3(0x9ABCD801357);iU.hash2*=tM3(0xECADB912345)eC2(~c93[a]eE2 +hash2)^4567890;} +Depth+=eM1;} +} +if(Hash!=iU){Hash=iU;iK1=0;} +} +lA +FixIncompleteHashes(){MarkIncompletes(*this);FixIncompletes(*this);} +} +#endif +#include +#include +#include +#ifdef FP_SUPPORT_OPTIMIZER +xQ +iO2{using +iO2 +FPoptimizer_CodeTree;xG1 +x31 +lM1&tree,long +count,const +yV2 +SequenceOpCode +x8&eQ,yW2&synth,size_t +max_bytecode_grow_length);static +const +e92 +SinCosTanDataType{OPCODE +whichopcode;OPCODE +inverse_opcode;enum{nominator,denominator,inverse_nominator,inverse_denominator} +;OPCODE +codes[4];} +SinCosTanData[12]={{cTan,cCot,{cSin,cCos,cCsc,cSec} +} +,{cCot,cCot,{cCos,cSin,cSec,cCsc} +} +,{cCos,cSec,{cSin,cTan,cCsc,cCot} +} +,{cSec,cCos,{cTan,cSin,cCot,cCsc} +} +,{cSin,cCsc,{cCos,cCot,cSec,cTan} +} +,{cCsc,cSin,{cCot,cCos,cTan,cSec} +} +,{yT2{cSinh,cH3 +yY2,{cSinh,cNop,{yT2 +cNop,cCosh} +} +,{cH3 +cNop,{cSinh,yT2 +cNop} +} +,{cNop,cTanh,{cH3 +cSinh,yY2,{cNop,cSinh,{cNop,cTanh,cH3 +cNop} +} +,{cNop,cH3{cTanh,cSinh,yY2} +;} +iO2 +FPoptimizer_CodeTree{lA +SynthesizeByteCode(yG&nN,yG +x8&Immed,size_t&stacktop_max){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Making bytecode for:\n" +;iO +#endif +while(RecreateInversionsAndNegations()){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"One change issued, produced:\n" +;iO +#endif +FixIncompleteHashes();} +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Actually synthesizing, after recreating inv/neg:\n" +;iO +#endif +yW2 +synth;SynthesizeByteCode(synth,false +eU3.Pull(nN,Immed,stacktop_max);} +lA +SynthesizeByteCode(yW2&synth,bool +MustPopTemps)const{xR1*this)){return;} +for +xK2 +0;a<12;++a){const +SinCosTanDataType&data=SinCosTanData[a];if(data.whichopcode!=cNop){if(lM2!=data.whichopcode)y81 +yL2 +lJ3;lJ3.lI1 +lJ3 +tU +data.inverse_opcode);lJ3.y12);xR1 +lJ3)){synth.l21 +else{if(lM2!=cInv)y81 +if(GetParam(0)nE!=data.inverse_opcode)y81 +xR1 +GetParam(0))){synth.l21 +size_t +found[4];eW3 +4;++b){yL2 +tree;if(data.t03]==cNop){tH +cInv);yL2 +lK3;lK3.lI1 +lK3 +tU +data.t03^2]);lK3.y12 +tT +yA +lK3);} +else{tree.lI1 +tH +data.t03]);} +tree.y12);found[b]t13 +e33(tree);} +if(found[data.y22!=tG +i61 +yK +y22);lJ1 +i61);lK1 +cDiv +nL1 +y22!=tG +iV +yK +y22);lJ1 +iV);lK1 +cMul +nL1 +lS1!=tG +iV +yK +lS1);lJ1 +iV);lK1 +cRDiv +nL1 +lS1!=tG +i61 +yK +lS1);lJ1 +i61);lK1 +cMul,2,1 +eU3.l21 +size_t +n_subexpressions_synthesized=SynthCommonSubExpressions(synth);switch(lM2 +iY2 +iE2:synth.PushVar(GetVar());lC +cImmed:yX2 +xJ1);lC +cAdd:case +cMul:case +cMin:case +cMax:case +cAnd:case +cOr:case +cAbsAnd:case +cAbsOr:{if(lM2==cMul){bool +xU3 +i13 +c3 +lT1 +y21&&isLongInteger(lT1.xJ1)){yW1=makeLongInteger(lT1.xJ1);yL2 +tmp(*this,typename +yL2::CloneTag());tmp +cP3 +tmp +x02;if(x31 +tmp,value,yV2 +eX1 +x8::AddSequence,synth,MAX_MULI_BYTECODE_LENGTH)){xU3=true;nM3} +} +if(xU3)nM3 +int +yA1=0;yGdone(GetParamCount(),false);yL2 +iE;iE +tU +lM2);for(;;){bool +found +i13 +c3 +done[a])y81 +if(synth.IsStackTop(lT1)){found=true;done[a]=true;lT1.nB +iE +eT +lT1);if(++yA1>1){synth +c4 +2);iE.y12 +eU3.yZ2 +iE);yA1=yA1-2+1;} +} +} +if(!found)nM3 +c3 +done[a])y81 +lT1.nB +iE +eT +lT1);if(++yA1>1){synth +c4 +2);iE.y12 +eU3.yZ2 +iE);yA1=yA1-2+1;} +} +if(yA1==0){switch(lM2 +iY2 +cAdd:case +cOr:case +cAbsOr:yX2 +0);lC +cMul:case +cAnd:case +cAbsAnd:yX2 +1);lC +cMin:case +cMax:yX2 +0);break;default:nM3++yA1;} +assert(n_stacked==1);nM3 +case +cPow:{iQ2 +p0 +tW2 +0);iQ2 +p1 +tW2 +1);if(!p1 +y21||!isLongInteger +n03)||!x31 +p0,makeLongInteger +n03),yV2 +eX1 +x8::MulSequence,synth,MAX_POWI_BYTECODE_LENGTH)){p0.nB +p1 +t33 +c4 +2);c91 +cIf:case +i03:{typename +yW2::IfData +yJ2;GetParam(0)t33.SynthIfStep1(yJ2,lM2);GetParam(1)t33.SynthIfStep2(yJ2);GetParam(2)t33.SynthIfStep3(yJ2 +nW2 +case +cFCall:case +cPCall:{for +xK2 +0;a0){size_t +top +t13 +GetStackTop(eU3.DoPopNMov(top-1-n_subexpressions_synthesized,top-1);} +} +} +iO2{xG1 +x31 +lM1&tree,long +count,const +yV2 +SequenceOpCode +x8&eQ,yW2&synth,size_t +max_bytecode_grow_length){if +cR3!=0){yW2 +backup=synth;tree.nB +size_t +bytecodesize_backup +t13 +GetByteCodeSize();yV2 +x31 +count +eR2 +size_t +bytecode_grow_amount +t13 +GetByteCodeSize()-bytecodesize_backup;if(bytecode_grow_amount>max_bytecode_grow_length){synth=backup +l81 +false;} +return +true;} +else{yV2 +x31 +count,eQ,synth)nS2} +} +#endif +#include +#include +#ifdef FP_SUPPORT_OPTIMIZER +xQ +iO2{using +iO2 +FPoptimizer_CodeTree; +#define FactorStack yG +const +e92 +PowiMuliType{i02 +opcode_square;i02 +opcode_cumulate;i02 +opcode_invert;i02 +opcode_half;i02 +opcode_invhalf;} +iseq_powi={cSqr,cMul,cInv,cSqrt,cRSqrt} +,iseq_muli={i21,cAdd,cNeg,i21,i21} +;yB1 +cF1 +const +PowiMuliType&xV3,const +yG&nA2,l92&stack){eS1 +cY3 +1);while(IPeS1(0)&&isEvenInteger(cZ3 +yF3;e4 +opcode_invhalf){if(result>eS1(0)&&isEvenInteger(cZ3 +eS1(-0.5);++IP;y81} +size_t +nB2=IP;eS1 +lhs(1);if(xW3 +cFetch){lC1=yL3;if(index=stack +yA3){IP=nB2;nM3 +lhs=stack[index-y1];goto +y32;} +if(xW3 +cDup){lhs=result;goto +y32;y32:y63 +result);++IP;eS1 +subexponent=cF1 +xV3 +lQ1 +if(IP>=limit||nN[IP]!=xV3.opcode_cumulate){IP=nB2;nM3++IP;stack.pop_back();result+=lhs*subexponent;y81} +nM3 +return +result;} +yB1 +ParsePowiSequence +i01 +yG&nA2){l92 +stack;y63 +eS1(1))l81 +cF1 +iseq_powi +lQ1} +yB1 +ParseMuliSequence +i01 +yG&nA2){l92 +stack;y63 +eS1(1))l81 +cF1 +iseq_muli +lQ1} +iP2 +CodeTreeParserData{e13 +iF2 +CodeTreeParserData(bool +k_powi):stack(),clones(),keep_powi(k_powi){} +void +Eat(size_t +eR3,OPCODE +opcode +xX3;xK +tU +opcode);yG +nV1 +cB2=Pop(eR3);xK +tI1 +cB2);if(!keep_powi)switch(opcode +iY2 +cTanh:nG1 +sinh,cosh;sinh +tU +cSinh);sinh +eT +xK +xY3 +sinh +x02;cosh +tU +cCosh);cosh +yA +xK +xY3 +cosh +i72 +pow +yB2 +yA +cosh);pow +yT +eS1(-1)));pow +x02;xK +tU +y13.nC1 +0,sinh);xK +yA +pow +nW2 +case +cTan:nG1 +sin,cos;sin +tU +cSin);sin +eT +xK +xY3 +sin +x02;cos +tU +cCos);cos +yA +xK +xY3 +cos +i72 +pow +yB2 +yA +cos);pow +yT +eS1(-1)));pow +x02;xK +tU +y13.nC1 +0,sin);xK +yA +pow +nW2 +case +cPow:{lM1&p0=xK +lD +0);lM1&p1=xK +lD +1);if(p1 +nE==cAdd){yG +nV1 +n83(p1.GetParamCount())c23 +0;a" +<void +Push(T +tree){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<0;){lC2;xE3(result[n])tW +result[n]);} +#endif +stack.resize +lB2 +n_pop)l81 +result;} +size_t +GetStackTop(n61 +stack +yA3;} +private:void +FindClone(yK2&,bool=true){return;} +private:yG +nV1 +stack;std::multimapclones;bool +keep_powi;private:CodeTreeParserData +i01 +CodeTreeParserData&);CodeTreeParserData&e31=i01 +CodeTreeParserData&);} +;yT1 +IfInfo +nG1 +cU2 +yJ +thenbranch;size_t +endif_location;IfInfo():cU2(),thenbranch(),endif_location(){} +} +;} +iO2 +FPoptimizer_CodeTree{lA +GenerateFrom +i01 +yG&nN,const +yG +x8&Immed,const +typename +FunctionParserBase +x8::Data&cJ3,bool +keep_powi){yG +nV1 +nK2;nK2.nH3 +cJ3.mVariablesAmount)xS3 +n=0;n&nN,const +yG +x8&Immed,const +typename +FunctionParserBase +x8::Data&cJ3,const +i22 +nK2,bool +keep_powi){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"ENTERS GenerateFrom()\n" +; +#endif +CodeTreeParserData +x8 +sim(keep_powi);yGeN;for(size_t +IP=0,DP=0;;++IP){tO2:while(!eN +cQ3&&(eN.eD==IP||(IP=nN +yA3)break;i02 +opcode=nN[IP];if((opcode==cSqr||opcode==cDup||(opcode==cInv&&!IsIntType +x8::result)||opcode==cNeg||opcode==cSqrt||opcode==cRSqrt||opcode==cFetch)){size_t +was_ip=IP;eS1 +cE2=ParsePowiSequence +x8(nN,IP,eN +cQ3?nN +yA3:eN.eD,sim.x5 +1);if(cE2!=1.0){x9 +cE2)yJ3;goto +tO2;} +if(opcode==cDup||opcode==cFetch||opcode==cNeg){eS1 +xD2=ParseMuliSequence +x8(nN,IP,eN +cQ3?nN +yA3:eN.eD,sim.x5 +1);if(xD2!=1.0){x9 +xD2)yE +cMul);goto +tO2;} +} +IP=was_ip;} +if(lD2>=iE2){sim.Push(nK2[opcode-iE2]);} +else{switch(lD2 +iY2 +cIf:case +i03:{eN +nE3 +eN +yA3+1);yL2 +res(sim.y42);eN.back().cU2.swap(res);eN.eD=nN +yA3;IP+=2;y81} +case +cJump:{yL2 +res(sim.y42);eN.e11.swap(res);eN.eD=nN[IP+1]+1;IP+=2;y81} +case +cImmed:x9 +Immed[DP++]);lC +cDup:sim.Dup();lC +cNop:lC +cFCall:{i02 +funcno=yL3;assert(funcnoparamlist=sim.Pop(cB2);yL2 +tP2;tP2.GenerateFrom(p.mData->mByteCode,p.mData->mImmed,*p.mData,paramlist)yG3 +tP2 +nW2 +case +cInv:x9 +1 +nY2 +cDiv);lC +cNeg:yE3 +cNeg);break;x9 +0 +nY2 +cSub);lC +cSqr:x9 +2 +e21 +cSqrt:x9 +yF3 +e21 +cRSqrt:x9 +eS1(-0.5)e21 +cCbrt:x9 +eS1(1)/eS1(3)e21 +cDeg:x9 +fp_const_rad_to_deg +x8 +cI1 +cRad:x9 +fp_const_deg_to_rad +x8 +cI1 +cExp:iF)goto +yI3;x9 +fp_const_e +x8()nY2 +cPow);lC +cExp2:iF)goto +yI3;x9 +2.0 +nY2 +cPow);lC +cCot:yE3 +cTan);iF)nY +cCsc:yE3 +cSin);iF)nY +cSec:yE3 +cCos);iF)nY +cInt: +#ifndef __x86_64 +iF){yE3 +cInt +nW2 +#endif +x9 +yF3)lL3 +yE3 +cFloor);lC +cLog10:yE3 +yH3 +fp_const_log10inv +x8 +cI1 +cLog2:yE3 +yH3 +fp_const_log2inv +x8 +cI1 +cLog2by:cK3 +yE3 +yH3 +fp_const_log2inv +x8());iJ +3,cMul);lC +cHypot:x9 +2)yJ3;cK3 +x9 +2)yJ3 +lL3 +x9 +yF3 +e21 +cSinCos:sim.Dup();yE3 +cSin);cK3 +yE3 +cCos);lC +cRSub:cK3 +case +cSub:iF){iJ +2,cSub +nW2 +x9-1)yE +cMul)lL3 +lC +cRDiv:cK3 +case +cDiv:iF||IsIntType +x8::result){iJ +2,cDiv +nW2 +x9-1)yJ3 +yE +cMul);lC +cAdd:case +cMul:case +cMod:case +cPow:case +cEqual:case +cLess:case +cGreater:case +t71:case +cLessOrEq:case +cGreaterOrEq:case +cAnd:case +cOr:case +cAbsAnd:case +cAbsOr:iJ +2,xS1 +lC +cNot:case +cNotNot:case +yR3:case +cAbsNotNot:yE3 +xS1 +lC +cFetch:sim.Fetch(yL3);lC +cPopNMov:{i02 +stackOffs_target=yL3;i02 +stackOffs_source=yL3;sim.PopNMov(stackOffs_target,stackOffs_source +nW2 +#ifndef FP_DISABLE_EVAL +case +cEval:{size_t +paramcount=cJ3.mVariablesAmount;iJ +paramcount,xS1 +nM3 +#endif +default:yI3:;i02 +funcno=opcode-cAbs;assert(funcno +#ifdef FP_SUPPORT_OPTIMIZER +#include +#define FP_MUL_COMBINE_EXPONENTS +iO2{xQ +using +iO2 +FPoptimizer_CodeTree;yV1 +static +void +AdoptChildrenWithSameOpcode(eR{ +#ifdef DEBUG_SUBSTITUTIONS +bool +lR2 +i13 +#endif +for +xU +if +nW1 +a)nE==tree +nE){ +#ifdef DEBUG_SUBSTITUTIONS +if(!lR2){std::cout<<"Before assimilation: " +eS +lR2=true;} +#endif +tree.AddParamsMove +nW1 +a).GetUniqueRef().iE1),a);} +#ifdef DEBUG_SUBSTITUTIONS +if(lR2){std::cout<<"After assimilation: " +eS} +#endif +} +} +iO2 +FPoptimizer_CodeTree{xB1 +ConstantFolding(eR{tree.Sort(); +#ifdef DEBUG_SUBSTITUTIONS +void*yM3=0 +lN1"[" +<<(&yM3)<<"]Runs ConstantFolding for: " +eS +DumpHashes(tree); +#endif +if(false){redo:;tree.Sort(); +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"[" +<<(&yM3)<<"]Re-runs ConstantFolding: " +eS +DumpHashes(tree); +#endif +} +if +xU2!=cImmed){range +x8 +p=iM +tree);if(p +y41 +p +i0&&p.min==p.max)lL +p.min)n5} +if(false){ReplaceTreeWithOne +xP3 +ReplaceWithImmed(eS1(1));goto +do_return;ReplaceTreeWithZero +xP3 +ReplaceWithImmed(eS1(0));goto +do_return;ReplaceTreeWithParam0: +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"Before replace: " +lN1 +std::hex<<'['<1||(i81==1&&fp_equal(nN1,nY3)nO1=true;if(nO1){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"cMul: Will add new " +tR3 +nN1<<"\n" +; +#endif +for +xU +if +nW1 +a)y21){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<" - For that, deleting " +tR3 +xI2.xJ1 +lN1"\n" +; +#endif +lM3!fp_equal(nN1,nY3 +tree +eT +cU1 +nN1));yN3(iT +iY2 +0 +tY +1:lN3 +default:if(ConstantFolding_MulGrouping +y83 +if(ConstantFolding_MulLogicItems +y83 +c91 +cAdd +cP +eS1 +lE2=0.0;size_t +i81=0;bool +nO1=false +eV3 +if(!xI2 +y21)y81 +eS1 +immed=xI2.xJ1;lE2+=immed;++i81;} +if(i81>1||(i81==1&&lE2==0.0))nO1=true;if(nO1){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<"cAdd: Will add new " +tR3 +lE2<<"\n" +lN1"In: " +eS +#endif +for +xU +if +nW1 +a)y21){ +#ifdef DEBUG_SUBSTITUTIONS +std::cout<<" - For that, deleting " +tR3 +xI2.xJ1 +lN1"\n" +; +#endif +lM3!(lE2==0.0))tree +eT +cU1 +lE2));yN3(iT +iY2 +0:yP3 +1:lN3 +default:if(ConstantFolding_AddGrouping +y83 +if(ConstantFolding_AddLogicItems +y83 +c91 +cMin +cP +size_t +y52=0;range +x8 +e6 +eV3 +while(a+1=e6.max)lM3 +iT==1){lN3 +c91 +cMax +cP +size_t +y52=0;range +x8 +t1 +eV3 +while(a+1t1.min)){t1.min=p.min;t1.iV2=true;y52=a;} +} +if(t1.iV2){for +xU{range=0.0)lL +eS1(0))n5} +if(nE1 +fp_equal(y4,eS1(0))){if(p0 +i0&&(p0.max)<0)lL-fp_const_pihalf +x8())n5 +if(p0 +y41 +p0.min>0)lL +fp_const_pihalf +x8())n5} +y2)lL +fp_atan2(n6,y4))n5 +if((p1 +y41 +p1.min>0.0)||(p1 +i0&&(p1.max)e92 +Comp{n73{n73{n73yU +cGreaterOrEq>{n73=yU +cEqual>{n73{n73=max){max=-min;n31} +else{n31} +} +c12 +set_neg(){std::swap(iV2,iI2;std::swap(min,max);min=-min;max=-max;} +yV +set_min_if(c31 +if(iV2&&Comp(eS1(-1),fp_atanh);m +nL2 +set_max_if=eS1(-1))?fp_acos(m.min):fp_const_pi +x8())cM3 +cAsin:lB +m +nL2 +set_min_if(eS1(-1),fp_asin,eO1);m +nL2 +set_max_if=(y8 +x41)e0 +eS1 +min=cZ2 +min,y8 +min +t83)min +c5 +eS1 +max=cZ2 +max,y8 +max +t83)max +c5 +if(max=fp_const_pihalf +x8());bool +nP1=(min<=cK&&max>=cK);if(xT1&&nP1)e0 +if(nP1)nL +eS1(-1),lS2 +if(xT1)nL +y92 +eS1(1));nL +y92 +lS2} +case +cCos:lB +if(m.iV2)m.min+=fp_const_pihalf +x8();if(m +i0)m.max+=fp_const_pihalf +x8();bool +x41=!m.iV2||!m +i0||(m.max-m.min)>=(y8 +x41)e0 +eS1 +min=cZ2 +min,y8 +min +t83)min +c5 +eS1 +max=cZ2 +max,y8 +max +t83)max +c5 +if(max=fp_const_pihalf +x8());bool +nP1=(min<=cK&&max>=cK);if(xT1&&nP1)e0 +if(nP1)nL +eS1(-1),lS2 +if(xT1)nL +y92 +eS1(1));nL +y92 +lS2} +case +cTan:{nL)cM3 +cCeil:lB +m.c41 +cFloor:lB +m.eP1 +cY +cTrunc:lB +m.eP1);m.c41 +cInt:lB +m.eP1);m.c41 +cSinh:lB +m.y82 +fp_sinh +cY +cTanh:lB +m.y82 +fp_tanh,range +x8(eS1(-y03 +cY +cCosh:lB +if(m.iV2){if(m +i0){if(m.min +cH1&&m.max +cH1){m.min +cM} +tP1(m.min)t83&&m.max +cH1)nQ3 +cM +if(tmp>m.max)m.max=tmp;m.min=eS1(1);} +else{m.min +cM +std::swap(m.min,m.max);} +} +else{if(m.min +cH1){m +nM2 +m.min=fp_cosh(m.min);} +else{m +nM2 +m.min=eS1(1);} +} +} +else{m.iV2=true;m.min=eS1(1);if(m +i0){m.min=fp_cosh(m.max);m +nM2} +else +m +nM2} +return +m +cM3 +cIf:case +i03:{range +x8 +res1=y6 +1));range +x8 +res2=y6 +2));if(!res2.iV2)res1.iV2 +i13 +tP1 +res1 +y41(res2.min)res1.max)res1.max=res2.max +l81 +res1 +cM3 +cMin:{bool +iG +i13 +bool +iH +i13 +tB1;x4 +m +xO3!m.iV2)iG=true;yP1.iV2||(m.min)i11)i11=m.min;if(!m +i0)iH=true;yP1 +i0||m.max>e63)e63=m.max;} +if(iG)c42 +iH)tE1 +l81 +yA2 +cAdd:{tB1(eS1(0),eS1(0));x4 +item +xO3 +item.iV2)i11+=item.min;else +c42 +item +i0)e63+=item.max;else +tE1;if(!result +y41!e02)nM3 +if(result +y41 +e02&&i11>e63)std::swap(i11,e63)l81 +yA2 +cMul:{e92 +Value{enum +lR3{tR2,i91,PlusInf} +;lR3 +eF;eS1 +value;Value(lR3 +t):eF(t),value(0){} +Value(eS1 +v):eF(tR2),value(v){} +bool +c22 +n61 +eF==i91||(eF==tR2&&value +t83 +iR2 +e31*=i01 +Value&rhs){if(eF==tR2&&rhs.eF==tR2)value*=rhs.value;else +eF=(c22)!=rhs.c22)?i91:PlusInf);} +i12e63)std::swap(i11,e63)l81 +yA2 +cMod:{range +x8 +x +y5 +y=y6 +1));if(y +i0){if(y.max +cH1){if(!x.iV2||(x.min)<0)nL-y.max,y.max);else +nL +eS1(0),y.max);} +else{if(!x +i0||(x.max)>=0)nL +y.max,-y.max);else +nL +y.max,fp_const_negativezero +x8());} +} +else +nL)cM3 +cPow:{if(nE1 +y4==eS1(0))e83 +y03;} +lX&&n6==eS1(0))e83 +0),eS1(0));} +lX&&fp_equal(n6,nY3 +e83 +y03;} +if(nE1 +y4>0&&GetEvennessInfo +nW1 +1))==IsAlways)c21 +y4;range +x8 +tmp +y5 +result;c32=true;i11=0;if(tmp +y41 +tmp.min>=0)i11=eG3 +tmp.min,cE2);tP1 +tmp +i0&&tmp.max<=0)i11=eG3 +tmp.max,cE2);tE1;if(tmp +y41 +tmp +i0){e02=true;e63=std::max(fp_abs(tmp.min),fp_abs(tmp.max));e63=eG3 +e63,cE2);} +return +result;} +range +x8 +p0 +y5 +p1=y6 +1 +eO2 +p0_positivity=(p0 +y41(p0.min)cH1)?IsAlways:(p0 +i0&&(p0.max)t83?yO3:Unknown);TriTruthValue +c52=GetEvennessInfo +nW1 +1 +eO2 +t2=Unknown;switch(p0_positivity)tF1 +t2=IsAlways;lC +yO3:{t2=c52;nM3 +default:switch(c52)tF1 +t2=IsAlways;lC +yO3:lC +Unknown:{if(nE1!eY2 +y4)&&y4 +cH1){t2=IsAlways;} +nM3} +yN3(t2)tF1{eS1 +n31 +if(p0 +y41 +p1.iV2){min=eG3 +p0.min,p1.min);if(p0.min +t83&&(!p1 +i0||p1.max +cH1)&&min +cH1)n31} +if(p0 +y41 +p0.min +cH1&&p0 +i0&&p1 +i0){eS1 +max=eG3 +p0.max,p1.max);if(min>max)std::swap(min,max);nL +min,max);} +nL +min,false)cM3 +yO3:{nL +false,fp_const_negativezero +x8());} +default:{nM3 +c91 +cNeg:lB +m.set_neg(cY +cSub +x7 +cNeg +y23 +1 +y43 +cAdd);y53;tmp +yY3 +l81 +lH +cInv:lV-1 +e12 +cDiv +x7 +cInv +y23 +1 +y43 +xU1 +yY3 +l81 +lH +cRad:{cF +xU1 +yT +fp_const_rad_to_deg +x8(e12 +cDeg:{cF +xU1 +yT +fp_const_deg_to_rad +x8(e12 +cSqr:lV +2 +e12 +cExp:{cF +cPow);tmp +yT +fp_const_e +x8()));y53 +l81 +lH +cExp2:{cF +cPow);tmp +yT +nR3 +y53 +l81 +lH +cCbrt:lB +m.y82 +fp_cbrt +cY +cSqrt:lB +if(m.iV2)m.min=(m.min)<0?0:fp_sqrt(m.min);if(m +i0)m.max=(m.max)<0?0:fp_sqrt(m.max +cY +cRSqrt:lV-0.5 +e12 +cHypot:nG1 +xsqr,ysqr,add,sqrt;xsqr +yC +0));xsqr +yT +nR3 +ysqr +yC +1));ysqr +yT +nR3 +xsqr +tU +cPow);ysqr +tU +cPow);add +yA +xsqr);add +yA +ysqr);add +tU +cAdd);sqrt +yA +add);sqrt +tU +cSqrt)l81 +iM +sqrt)cM3 +cLog2by +x7 +cLog2 +y23 +0 +y43 +cMul);tmp +yY3;tmp +yC +1))l81 +lH +cCot +x7 +cTan)nG +lH +cSec +x7 +cCos)nG +lH +cCsc +x7 +cSin)nG +iM +tmp);} +lC +cRDiv:case +cRSub:case +cDup:case +cFetch:case +cPopNMov:case +cSinCos:case +cNop:case +cJump:case +iE2:lC +cPCall:lC +cFCall:lC +cEval:nM3 +nL);} +yV1 +TriTruthValue +GetIntegerInfo +i01 +eR{switch +xU2 +iY2 +cImmed:return +eY2 +yZ3)?IsAlways:yO3;case +cFloor:case +cCeil:case +cTrunc:case +cInt:return +IsAlways;case +cAnd:case +cOr:case +cNot:case +cNotNot:case +cEqual:case +t71:case +cLess:case +cLessOrEq:case +cGreater:case +cGreaterOrEq:return +IsAlways;case +cIf:{TriTruthValue +a=GetIntegerInfo +nW1 +1 +eO2 +b=GetIntegerInfo +nW1 +2));if(a==b +nZ2 +a +l81 +Unknown +cM3 +cAdd:case +cMul:{for +xU +if(GetIntegerInfo +nW1 +a))!=IsAlways +nZ2 +Unknown +l81 +IsAlways;} +default:nM3 +return +Unknown;} +xG1 +IsLogicalValue +i01 +eR{switch +xU2 +iY2 +cImmed:return +fp_equal(yZ3,eS1(0))||fp_equal(yZ3,eS1(1));case +cAnd:case +cOr:case +cNot:case +cNotNot:case +cAbsAnd:case +cAbsOr:case +yR3:case +cAbsNotNot:case +cEqual:case +t71:case +cLess:case +cLessOrEq:case +cGreater:case +cGreaterOrEq:nW +cMul:{for +xU +if(!y93 +a))yI +return +true +cM3 +cIf:case +i03:{return +y93 +1))&&y93 +2));} +default:nM3 +nX2} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +xQ +#if defined(__x86_64) || !defined(FP_SUPPORT_CBRT) +# define CBRT_IS_SLOW +#endif +#if defined(DEBUG_POWI) || defined(DEBUG_SUBSTITUTIONS) +#include +#endif +t5{extern +const +i02 +char +powi_table[256];} +iO2{using +iO2 +FPoptimizer_CodeTree;xG1 +IsOptimizableUsingPowi(long +immed,long +penalty=0){yW2 +synth;synth.PushVar(iE2);size_t +bytecodesize_backup +t13 +GetByteCodeSize();yV2 +x31 +immed,yV2 +eX1 +x8::MulSequence,synth);size_t +bytecode_grow_amount +t13 +GetByteCodeSize()-bytecodesize_backup +l81 +bytecode_grow_amount0){cF +cCbrt);nZ3);tmp.Rehash(nD2--tT2;} +while(tS2>0){cF +cSqrt);if(iK2){tmp +tU +cRSqrt);iK2 +i13} +nZ3);tmp.Rehash(nD2--tS2;} +if(iK2){cF +cInv);nZ3 +nD2} +} +yT1 +RootPowerTable{static +const +eS1 +RootPowers[(1+4)*(1+3)];} +;yV1 +const +eS1 +t7(1+4)*(1+3)]={eS1(1)lS +tB3 +tB3 +2*tB3 +2*2*2)lS +3 +x32 +2 +x32 +2*2 +x32 +2*2*2 +x32 +2*2*2*2 +x32 +3 +x32 +3*2 +x32 +3*2*2 +x32 +3*2*2*2 +x32 +3*2*2*2*2 +x32 +3*3 +x32 +3*3*2 +x32 +3*3*2*2 +x32 +3*3*2*2*2 +x32 +3*3*2*2*2*2)} +;e92 +PowiResolver{static +const +i02 +MaxSep=4;static +lX3 +tC3=5;typedef +int +c03;typedef +long +n63;typedef +long +t8;e92 +yE2{yE2():n_int_sqrt(0),n_int_cbrt(0),sep_list(),lY1(0){} +int +n_int_sqrt;int +n_int_cbrt;int +eW1 +MaxSep];t8 +lY1;} +;yV1 +static +yE2 +CreatePowiResult(eS1 +cE2){yE2 +result;c03 +eE=FindIntegerFactor(cE2);if(eE==0){ +#ifdef DEBUG_POWI +tU2"no factor found for %Lg\n" +y33); +#endif +return +result;} +c13=xV1 +cE2,eE);n63 +e22=EvaluateFactorCost(eE,0,0,0)+cH +c13);int +tD3=0;int +tE3=0;int +lW3=0; +#ifdef DEBUG_POWI +tU2"orig = %Lg\n" +y33);tU2"plain factor = " +tS3"%ld\n" +,(int)eE,(long)e22); +#endif +for +iL1 +n_s=0;n_s=tC3)break; +#endif +int +n_sqrt=s%tC3;int +n_cbrt=s/tC3;if(n_sqrt+n_cbrt>4)y81 +eS1 +lE1=cE2;lE1-=t7 +s];tH1=FindIntegerFactor(lE1);if(xD2!=0){t8 +xL=xV1 +lE1,xD2);n63 +cost=EvaluateFactorCost(xD2,tD3+n_sqrt,tE3+n_cbrt,lW3+1)+cH +xL); +#ifdef DEBUG_POWI +tU2"Candidate sep %u (%d*sqrt %d*cbrt)factor = " +tS3"%ld (for %Lg to %ld)\n" +,s,n_sqrt,n_cbrt,xD2,(long)cost +x12 +lE1,(long)xL); +#endif +if(cost%Lg\n" +,xC,xC%tC3,xC/tC3,yQ1,yE1 +x12(cE2)x12(cE2-t7 +xC])); +#endif +tC1 +eW1 +n_s]=xC;cE2-=t7 +xC];tD3+=xC%tC3;tE3+=xC/tC3;e22=yE1;eE=yQ1;lW3+=1;} +c13=xV1 +cE2,eE); +#ifdef DEBUG_POWI +tU2"resulting exponent is %ld (from exponent=%Lg, best_factor=%Lg)\n" +,c13 +y33 +x12 +eE); +#endif +while(eE%2==0){++tC1 +n_int_sqrt;eE/=2;} +while(eE%3==0){++tC1 +n_int_cbrt;eE/=3;} +return +result;} +private:static +n63 +cH +t8 +xL){static +std::map +c62 +i7;if(xL<0){n63 +cost=22 +l81 +cost+cH-xL);} +std::map +c62::nX3 +i=i7.xE2 +xL);if(i!=i7.cP1 +xL +nZ2 +i +cJ2;std::pair +c62 +cY3 +xL,0.0);n63&cost=tC1 +second;while(xL>1){int +xD2=0;if(xL<256){xD2=yV2 +powi_table[xL];if(xD2&128)xD2&=127;else +xD2=0;if(xD2&64)xD2=-(xD2&63)-1;} +if(xD2){cost+=cH +xD2);xL/=xD2;y81} +if(!(xL&1)){xL/=2;cost+=6;} +else{cost+=7;xL-=1;} +} +i7.nT3,result)l81 +cost +eI2 +t8 +xV1 +yF1,tH1){return +makeLongInteger(value*eS1(xD2))eI2 +bool +yG1 +yF1,tH1){eS1 +v=value*eS1(xD2)l81 +isLongInteger(v)eI2 +c03 +FindIntegerFactor(yF1){tH1=(2*2*2*2); +#ifdef CBRT_IS_SLOW +#else +xD2*=(3*3*3); +#endif +c03 +result=0;if(yG1 +value,xD2)){result=xD2;while((xD2%2)==0&&yG1 +value,xD2/2))result=xD2/=2;while((xD2%3)==0&&yG1 +value,xD2/3))result=xD2/=3;} +#ifdef CBRT_IS_SLOW +if(result==0){if(yG1 +value,3)nZ2 +3;} +#endif +return +result;} +static +int +EvaluateFactorCost(int +xD2,int +s,int +c,int +nmuls){lX3 +lY3=6; +#ifdef CBRT_IS_SLOW +lX3 +e32=25; +#else +lX3 +e32=8; +#endif +int +result=s*lY3+c*e32;while(xD2%2==0){xD2/=2;result+=lY3;} +while(xD2%3==0){xD2/=3;result+=e32;} +result+=nmuls +l81 +result;} +} +;} +iO2 +FPoptimizer_CodeTree{xG1 +yK2::RecreateInversionsAndNegations(bool +prefer_base2){bool +changed=false +c23 +0;a0;)nG1&powgroup=lT1;if(powgroup +yF2 +0)c82 +tJ +1)y21)nG1&log2=tJ +0);log2.iY +log2 +tU +lZ3 +log2 +yT +eG3 +immeds,eS1(1)/nE2)));log2.Rehash(nW2} +} +} +for +xK2 +cO3 +yF2 +1)y21){lM1&exp_param=tJ +1);eS1 +cE2=exp_param.xJ1;if(cR1,eS1(-1))){iY +lG2 +yL +lT1 +xY3 +yH1 +tP1 +cE2<0&&eY2 +cE2))nG1 +iI;iI +tU +cPow);iI +eT +tJ +0));iI +yT-cE2));iI +x02;lG2 +yL +iI);iY +yH1} +tP1 +powgroup +c82!lH2.iA1{lH2=tJ +0);iY +yH1 +tP1 +powgroup +nE==cLog2by&&!cJ1.iA1{cJ1=powgroup;iY +yH1} +if(!lG2 +cQ3){changed=true +yJ +eR1;eR1 +e53 +eR1 +tI1 +lG2);eR1 +i72 +xW1 +cMul);xX1 +SetParamsMove(t3 +if(xX1 +IsImmed()&&fp_equal(xX1 +xJ1,nY3{lI2 +cInv);eG +eR1);} +else{if(xX1 +xT2>=eR1.xT2){lI2 +cDiv +eV1 +eG +eR1);} +else{lI2 +cRDiv);eG +eR1 +eV1} +} +} +if(lH2.iA1 +nG1 +xW1 +lM2);xX1 +SetParamsMove(t3 +while(xX1 +RecreateInversionsAndNegations(prefer_base2))xX1 +FixIncompleteHashes();lI2 +lZ3 +eG +lH2 +eV1 +yI1} +if(cJ1.iA1 +nG1 +xW1 +cMul);n83 +yA +cJ1 +x03;xX1 +AddParamsMove(t3 +while(xX1 +RecreateInversionsAndNegations(prefer_base2))xX1 +FixIncompleteHashes();DelParams();lI2 +lZ3 +eG +cJ1 +lD +0)eV1 +yI1 +c91 +cAdd:{yG +nV1 +tV2 +c23 +tD +c33 +cMul){lJ2 +xY1:yJ&n83 +c72 +for(iX2 +xX1 +cN3 +b-->0;){if(n83 +lD +b)xC3 +xD2=n83 +lD +b).xJ1 +i82 +xD2 +eQ1 +xY1;} +xX1 +iY +xX1 +iH1 +b +eJ2 +tP1 +fp_equal(xD2,eS1(-2)))xF +xY1;} +xX1 +iY +xX1 +iH1 +b);n83 +yT +eS1(2))eJ2} +} +if(t4){xX1 +nR1 +n83);yH1} +tP1 +c33 +cDiv&&!IsIntType +x8::result){lJ2 +xZ1:yJ&eR1 +c72 +if(eR1 +lD +0)tF3(fp_equal(eR1 +lD +0).xJ1 +eQ1 +xZ1;} +eR1.iY +eR1.iH1 +0);eR1 +tU +cInv +eJ2} +if(t4)xF +xZ1;} +eR1.nR1 +eR1);yH1} +tP1 +c33 +cRDiv&&!IsIntType +x8::result){lJ2 +x91:yJ&eR1 +c72 +if(eR1 +lD +1)tF3(fp_equal(eR1 +lD +1).xJ1 +eQ1 +x91;} +eR1.iY +eR1.iH1 +1);eR1 +tU +cInv +eJ2} +if(t4)xF +x91;} +eR1.nR1 +eR1);yH1} +if(!tV2 +cQ3){ +#ifdef DEBUG_SUBSTITUTIONS +tU2"Will make a Sub conversion in:\n" +);fflush(stdout);iO +#endif +yK2 +yR1;yR1 +tU +cAdd);yR1 +tI1 +tV2);yR1 +i72 +cK1;cK1 +tU +cAdd);cK1 +tI1 +iE1));cK1 +x02;if(cK1 +y21&&fp_equal(cK1.xJ1,eS1(0))){lI2 +cNeg);cU3);} +else{if(cK1.xT2==1){lI2 +cRSub);cU3);cV3} +tP1 +yR1 +nE==cAdd){lI2 +cSub);cV3 +cU3 +xY3 +for +xK2 +1;a0){iB1=true;} +#ifdef DEBUG_POWI +tU2"Will resolve powi %Lg as powi(chain(%d,%d),%ld)" +x12 +fp_abs +n03),r +x33,r.n_int_cbrt,r.lY1)xS3 +n=0;n0.0){if(prefer_base2){eS1 +yH2=fp_log2(p0.xJ1)i82 +yH2,nY3{iH1 +0);} +else{n1 +cU1 +yH2));cE2 +eT +p1)tD1 +iP} +lI2 +cExp2);yI1} +else{eS1 +yH2=fp_log(p0.xJ1)i82 +yH2,nY3{iH1 +0);} +else{n1 +cU1 +yH2));cE2 +eT +p1)tD1 +iP} +lI2 +cExp);yI1} +} +tP1 +GetPositivityInfo(p0)==IsAlways){if(prefer_base2)nG1 +log;log +tU +cLog2);log +eT +p0);log +x02;n1 +p1);cE2 +yA +log)tD1);lI2 +cExp2 +iP +yI1} +else +nG1 +log;log +tU +cLog);log +eT +p0);log +x02;n1 +p1);cE2 +yA +log)tD1);lI2 +cExp +iP +yI1} +} +c91 +cDiv:{if(GetParam(0)y21&&fp_equal(GetParam(0).xJ1,nY3{lI2 +cInv);iH1 +0);} +nM3 +default:nM3 +if(changed)goto +exit_changed +l81 +changed;} +} +#endif +#ifdef FP_SUPPORT_OPTIMIZER +xQ +iO2{using +iO2 +FPoptimizer_CodeTree;class +eT1{size_t +yJ1;size_t +eK;size_t +eL;size_t +lF1;e13 +eT1():yJ1(0),eK(0),eL(0),lF1(0){} +void +c43 +OPCODE +op){yJ1+=1;n13 +cCos)++eK;n13 +cSin)++eL;n13 +cSec)++eK;n13 +cCsc)++eL;n13 +cTan)++lF1;n13 +cCot)++lF1;} +size_t +GetCSEscore()const{size_t +result=yJ1 +l81 +result;} +int +NeedsSinCos()const{bool +always_sincostan=(yJ1==(eK+eL+lF1));if((lF1&&(eL||eK))||(eL&&eK)){if(always_sincostan +nZ2 +1 +l81 +2;} +return +0;} +size_t +MinimumDepth()const{size_t +n_sincos=std::min(eK,eL);if(n_sincos==0 +nZ2 +2 +l81 +1;} +} +;iP2 +TreeCountType:public +std::multimap >{} +;xB1 +FindTreeCounts(nX1&lK2,lM1&tree,OPCODE +lL2{iG1 +i=lK2.xE2 +tree.GetHash());bool +found +i13 +for(;i!=lK2.cP1 +tree.GetHash();++i){if(tree +iA +i +cJ2 +eE3)){i +cJ2.first.c43 +lL2;found=true;nM3} +if(!found){eT1 +count;count.c43 +lL2;lK2.nT3,std::make_pair(tree.GetHash(),std::make_pair +cR3 +n72);} +for +yS +FindTreeCounts(lK2,xI2,tree +nE);} +e92 +c9{bool +BalanceGood;bool +cI;} +;yV1 +c9 +lG1 +lM1&root,lM1&c53{if(root +iA +c53){c9 +result={true,true} +l81 +result;} +c9 +result={true,false} +;if(root +nE==cIf||root +nE==i03){c9 +cond=lG1 +root +lD +0),c53;c9 +xW=lG1 +root +lD +1),c53;c9 +y9=lG1 +root +lD +2),c53;if(cond.cI||xW.cI||y9.cI){tC1 +cI=true;} +result +eH=((xW.cI==y9.cI)||eX2&&(cond +eH||(xW.cI&&y9.cI))&&(xW +eH||eX2&&(y9 +eH||eX2;} +else{bool +tK1 +i13 +bool +nS1 +i13 +for(iX2 +root.GetParamCount(),a=0;aeQ3 +leaf.GetHash())y81 +const +c63 +i->nF2 +size_t +score=occ.GetCSEscore();lM1&candidate=i->nG2 +if(cC2 +candidate))y81 +if(leaf.xT2nF2 +size_t +score=occ.GetCSEscore();lM1&tree=i->nG2 +#ifdef DEBUG_SUBSTITUTIONS_CSE +std::cout<<"Score " +<yI2){yI2=score;lT2=i;} +} +if(yI2<=0)break;const +c63 +lT2->nF2 +lM1&tree=lT2->nG2 +#ifdef DEBUG_SUBSTITUTIONS_CSE +std::cout<mByteCode,mData->mImmed,*mData);FPoptimizer_Optimize::ApplyGrammars(tree);yGc73;yG +x8 +immed;size_t +stacktop_max=0;tree.SynthesizeByteCode(c73,immed,stacktop_max);if(mData->mStackSize!=stacktop_max){mData->mStackSize=i02(stacktop_max); +#if !defined(FP_USE_THREAD_SAFE_EVAL) && \ + !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) +mData->mStack +nE3 +stacktop_max); +#endif +} +mData->mByteCode.swap(c73);mData->mImmed.swap(immed);} +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +n73<>lR1nH2} +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE +n73<>lR1nH2} +#endif +FUNCTIONPARSER_INSTANTIATE_TYPES +#endif + +#endif diff --git a/fparser/fptypes.hh b/fparser/fptypes.hh new file mode 100644 index 0000000..ef6357e --- /dev/null +++ b/fparser/fptypes.hh @@ -0,0 +1,282 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.3 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_TYPES_H_ +#define ONCE_FPARSER_TYPES_H_ + +#include "fpconfig.hh" +#include + +#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, + cAsin, cAsinh, + cAtan, cAtan2, cAtanh, + cCbrt, cCeil, + cCos, cCosh, cCot, cCsc, + cEval, + cExp, cExp2, cFloor, cHypot, + cIf, cInt, cLog, cLog10, cLog2, cMax, cMin, + cPow, cSec, cSin, cSinh, cSqrt, cTan, cTanh, + cTrunc, + +// These do not need any ordering: +// Except that if you change the order of {eq,neq,lt,le,gt,ge}, you +// must also change the order in ConstantFolding_ComparisonOperations(). + cImmed, cJump, + cNeg, cAdd, cSub, cMul, cDiv, cMod, + cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq, + cNot, cAnd, cOr, + cNotNot, /* Protects the double-not sequence from optimizations */ + + cDeg, cRad, /* Multiplication and division by 180 / pi */ + + cFCall, cPCall, + +#ifdef FP_SUPPORT_OPTIMIZER + cPopNMov, /* cPopNMov(x,y) moves [y] to [x] and deletes anything + * above [x]. Used for disposing of temporaries. + */ + cLog2by, /* log2by(x,y) = log2(x) * y */ + cNop, /* Used by fpoptimizer internally; should not occur in bytecode */ +#endif + cSinCos, /* sin(x) followed by cos(x) (two values are pushed to stack) */ + cAbsAnd, /* As cAnd, but assume both operands are absolute values */ + cAbsOr, /* As cOr, but assume both operands are absolute values */ + cAbsNot, /* As cAbsNot, but assume the operand is an absolute value */ + cAbsNotNot, /* As cAbsNotNot, but assume the operand is an absolute value */ + cAbsIf, /* As cAbsIf, but assume the 1st operand is an absolute value */ + + cDup, /* Duplicates the last value in the stack: Push [Stacktop] */ + cFetch, /* Same as Dup, except with absolute index + * (next value is index) */ + cInv, /* Inverts the last value in the stack (x = 1/x) */ + cSqr, /* squares the last operand in the stack, no push/pop */ + cRDiv, /* reverse division (not x/y, but y/x) */ + cRSub, /* reverse subtraction (not x-y, but y-x) */ + cRSqrt, /* inverse square-root (1/sqrt(x)) */ + + VarBegin + }; + +#ifdef ONCE_FPARSER_H_ + struct FuncDefinition + { + enum FunctionFlags + { + Enabled = 0x01, + AngleIn = 0x02, + AngleOut = 0x04, + OkForInt = 0x08 + }; + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + const char name[8]; +#else + struct name { } name; +#endif + unsigned params : 8; + unsigned flags : 8; + + inline bool enabled() const { return flags != 0; } + inline bool okForInt() const { return (flags & OkForInt) != 0; } + }; + +#ifndef FP_DISABLE_EVAL +# define FP_EVAL_FUNCTION_ENABLED \ + FuncDefinition::Enabled | FuncDefinition::OkForInt +#else +# define FP_EVAL_FUNCTION_ENABLED 0 +#endif +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +# define FP_FNAME(n) n +#else +# define FP_FNAME(n) {} +#endif +// This list must be in the same order as that in OPCODE enum, +// because the opcode value is used to index this array, and +// the pointer to array element is used for generating the opcode. + const FuncDefinition Functions[]= + { + /*cAbs */ { FP_FNAME("abs"), 1, + FuncDefinition::Enabled | FuncDefinition::OkForInt }, + /*cAcos */ { FP_FNAME("acos"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleOut }, + /*cAcosh*/ { FP_FNAME("acosh"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleOut }, + /*cAsin */ { FP_FNAME("asin"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleOut }, + /*cAsinh*/ { FP_FNAME("asinh"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleOut }, + /*cAtan */ { FP_FNAME("atan"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleOut }, + /*cAtan2*/ { FP_FNAME("atan2"), 2, + FuncDefinition::Enabled | FuncDefinition::AngleOut }, + /*cAtanh*/ { FP_FNAME("atanh"), 1, FuncDefinition::Enabled }, + /*cCbrt */ { FP_FNAME("cbrt"), 1, FuncDefinition::Enabled }, + /*cCeil */ { FP_FNAME("ceil"), 1, FuncDefinition::Enabled }, + /*cCos */ { FP_FNAME("cos"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cCosh */ { FP_FNAME("cosh"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cCot */ { FP_FNAME("cot"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cCsc */ { FP_FNAME("csc"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cEval */ { FP_FNAME("eval"), 0, FP_EVAL_FUNCTION_ENABLED }, + /*cExp */ { FP_FNAME("exp"), 1, FuncDefinition::Enabled }, + /*cExp2 */ { FP_FNAME("exp2"), 1, FuncDefinition::Enabled }, + /*cFloor*/ { FP_FNAME("floor"), 1, FuncDefinition::Enabled }, + /*cHypot*/ { FP_FNAME("hypot"), 2, FuncDefinition::Enabled }, + /*cIf */ { FP_FNAME("if"), 0, + FuncDefinition::Enabled | FuncDefinition::OkForInt }, + /*cInt */ { FP_FNAME("int"), 1, FuncDefinition::Enabled }, + /*cLog */ { FP_FNAME("log"), 1, FuncDefinition::Enabled }, + /*cLog10*/ { FP_FNAME("log10"), 1, FuncDefinition::Enabled }, + /*cLog2 */ { FP_FNAME("log2"), 1, FuncDefinition::Enabled }, + /*cMax */ { FP_FNAME("max"), 2, + FuncDefinition::Enabled | FuncDefinition::OkForInt }, + /*cMin */ { FP_FNAME("min"), 2, + FuncDefinition::Enabled | FuncDefinition::OkForInt }, + /*cPow */ { FP_FNAME("pow"), 2, FuncDefinition::Enabled }, + /*cSec */ { FP_FNAME("sec"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cSin */ { FP_FNAME("sin"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cSinh */ { FP_FNAME("sinh"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cSqrt */ { FP_FNAME("sqrt"), 1, + FuncDefinition::Enabled }, + /*cTan */ { FP_FNAME("tan"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cTanh */ { FP_FNAME("tanh"), 1, + FuncDefinition::Enabled | FuncDefinition::AngleIn }, + /*cTrunc*/ { FP_FNAME("trunc"), 1, + FuncDefinition::Enabled } + }; +#undef FP_FNAME + + struct NamePtr + { + const char* name; + unsigned nameLength; + + NamePtr(const char* n, unsigned l): name(n), nameLength(l) {} + + inline bool operator==(const NamePtr& rhs) const + { + return nameLength == rhs.nameLength + && std::memcmp(name, rhs.name, nameLength) == 0; + } + inline bool operator<(const NamePtr& rhs) const + { + for(unsigned i = 0; i < nameLength; ++i) + { + if(i == rhs.nameLength) return false; + const char c1 = name[i], c2 = rhs.name[i]; + if(c1 < c2) return true; + if(c2 < c1) return false; + } + return nameLength < rhs.nameLength; + } + }; + + template + 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; + + unsigned mVariablesAmount; + std::string mVariablesString; + FUNCTIONPARSERTYPES::NamePtrsMap mNamePtrs; + + struct InlineVariable + { + FUNCTIONPARSERTYPES::NamePtr mName; + unsigned mFetchIndex; + }; + + typedef std::vector InlineVarNamesContainer; + InlineVarNamesContainer mInlineVarNames; + + struct FuncPtrData + { + union + { + FunctionPtr mFuncPtr; + 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/fparser/mpfr/GmpInt.cc b/fparser/mpfr/GmpInt.cc new file mode 100644 index 0000000..490add4 --- /dev/null +++ b/fparser/mpfr/GmpInt.cc @@ -0,0 +1,710 @@ +#include "GmpInt.hh" +#include +#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/fparser/mpfr/GmpInt.hh b/fparser/mpfr/GmpInt.hh new file mode 100644 index 0000000..1c1c171 --- /dev/null +++ b/fparser/mpfr/GmpInt.hh @@ -0,0 +1,148 @@ +#ifndef ONCE_FP_GMP_INT_HH_ +#define ONCE_FP_GMP_INT_HH_ + +#include + +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/fparser/mpfr/MpfrFloat.cc b/fparser/mpfr/MpfrFloat.cc new file mode 100644 index 0000000..387d1e8 --- /dev/null +++ b/fparser/mpfr/MpfrFloat.cc @@ -0,0 +1,974 @@ +#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_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) +{ + mpfr_sin_cos( + sin.mData->mFloat, cos.mData->mFloat, value.mData->mFloat, GMP_RNDN); +} + +MpfrFloat MpfrFloat::acos(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asin(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan2(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan2(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::hypot(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_hypot(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::tanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_tanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::acosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sqrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sqrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cbrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cbrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::root(const MpfrFloat& value, unsigned long root) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_root(retval.mData->mFloat, value.mData->mFloat, root, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value, long exponent) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow_si(retval.mData->mFloat, value.mData->mFloat, exponent, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::abs(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_abs(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::dim(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_dim(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::round(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_round(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::ceil(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_ceil(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::floor(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_floor(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::trunc(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_trunc(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::parseString(const char* str, char** endptr) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_strtofr(retval.mData->mFloat, str, endptr, 0, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::const_pi() +{ + return mpfrFloatDataContainer().const_pi(); +} + +MpfrFloat MpfrFloat::const_e() +{ + return mpfrFloatDataContainer().const_e(); +} + +MpfrFloat MpfrFloat::const_log2() +{ + return mpfrFloatDataContainer().const_log2(); +} + +MpfrFloat MpfrFloat::someEpsilon() +{ + return mpfrFloatDataContainer().const_epsilon(); +} diff --git a/fparser/mpfr/MpfrFloat.hh b/fparser/mpfr/MpfrFloat.hh new file mode 100644 index 0000000..d455d24 --- /dev/null +++ b/fparser/mpfr/MpfrFloat.hh @@ -0,0 +1,206 @@ +#ifndef ONCE_FP_MPFR_FLOAT_ +#define ONCE_FP_MPFR_FLOAT_ + +#include + +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