diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2018-08-25 21:08:35 +0200 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2018-08-25 21:08:35 +0200 |
commit | 8f8b19149d0136d58f0ebc6928fe7cbd376ef8bc (patch) | |
tree | 587ac9c23581f81a9bc8e21a7ba8019fa0c4c696 |
Import fparserc++_4.5.2.orig.tar.gz
[dgit import orig fparserc++_4.5.2.orig.tar.gz]
1075 files changed, 67533 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9370c23 --- /dev/null +++ b/Makefile @@ -0,0 +1,403 @@ +#=========================================================================== +# This Makefile uses quite heavily GNU Make extensions, so it's probably +# hopeless to try to use it with other Make programs which do not have the +# same extensions. +# +# Also requires: rm, grep, sed and g++ (regardless of what CXX and LD are). +# The optimizer code generator requires bison. +#=========================================================================== + +RELEASE_VERSION=4.5.2 + +# The FP_FEATURE_FLAGS is set by run_full_release_testing.sh, but can be +# used otherwise as well. +ifeq ($(FP_FEATURE_FLAGS),) +FEATURE_FLAGS = +FEATURE_FLAGS += -DFP_ENABLE_EVAL +#FEATURE_FLAGS += -DFP_NO_SUPPORT_OPTIMIZER +#FEATURE_FLAGS += -DFP_USE_THREAD_SAFE_EVAL +#FEATURE_FLAGS += -DFP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA +#FEATURE_FLAGS += -D_GLIBCXX_DEBUG +#FEATURE_FLAGS += -DFP_DISABLE_SHORTCUT_LOGICAL_EVALUATION +FEATURE_FLAGS += -DFP_SUPPORT_FLOAT_TYPE +FEATURE_FLAGS += -DFP_SUPPORT_LONG_DOUBLE_TYPE +FEATURE_FLAGS += -DFP_SUPPORT_LONG_INT_TYPE +#FEATURE_FLAGS += -DFP_SUPPORT_MPFR_FLOAT_TYPE +#FEATURE_FLAGS += -DFP_SUPPORT_GMP_INT_TYPE +FEATURE_FLAGS += -DFP_SUPPORT_COMPLEX_DOUBLE_TYPE +FEATURE_FLAGS += -DFP_SUPPORT_COMPLEX_FLOAT_TYPE +FEATURE_FLAGS += -DFP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +FEATURE_FLAGS += -DFP_USE_STRTOLD +#FEATURE_FLAGS += -DFP_SUPPORT_CPLUSPLUS11_MATH_FUNCS +else +FEATURE_FLAGS = $(FP_FEATURE_FLAGS) +endif + +OPTIMIZATION=-O3 -ffast-math -march=native +# -ffunction-sections -fdata-sections + +# For GCC (not clang): +OPTIMIZATION += -fexpensive-optimizations -fvpt -fomit-frame-pointer -ffunction-cse + +#OPTIMIZATION+=-g +#OPTIMIZATION=-g -O0 -fno-inline +#OPTIMIZATION=-g -O0 -fno-inline -fno-inline-functions -fno-default-inline +#OPTIMIZATION=-g -O2 -fno-inline -fno-inline-functions -fno-default-inline +#OPTIMIZATION=-g -pg -fprofile -fprofile-values -fprofile-generate -ftest-coverage +#OPTIMIZATION=-g -pg + +CXX=g++ +#CXX=clang++ +# -m32 -mfpmath=sse +# -m32 -mfpmath=387 + +LD=g++ +#LD=clang++ +#LD=g++ -g +# -m32 -mfpmath=sse +# -m32 -mfpmath=387 + +#OPTIMIZATION += -finline -finline-functions -fdefault-inline +#OPTIMIZATION += -finline-limit=300000 +#OPTIMIZATION += --param max-inline-insns-auto=300000 +#OPTIMIZATION += --param max-inline-recursive-depth-auto=30 +#OPTIMIZATION += --param max-inline-insns-single=300000 +#OPTIMIZATION += --param inline-unit-growth=9000 +#OPTIMIZATION += --param max-early-inliner-iterations=30 +#OPTIMIZATION += --param early-inlining-insns=90000 +#OPTIMIZATION += -fkeep-inline-functions +#OPTIMIZATION += -fimplement-inlines + +FEATURE_FLAGS += -DFUNCTIONPARSER_SUPPORT_DEBUGGING + +#LD += -fprofile -fprofile-values -fprofile-generate -ftest-coverage + +CPPFLAGS=$(FEATURE_FLAGS) +CXXFLAGS=-Wall -W -Wno-long-long -pedantic -ansi $(OPTIMIZATION) +#CXXFLAGS += -Wunreachable-code +#CXXFLAGS += -std=c++0x + +#CXXFLAGS += -Weffc++ + +ifneq (,$(findstring -DFP_SUPPORT_MPFR_FLOAT_TYPE,$(FEATURE_FLAGS))) +LDFLAGS += -lgmp -lmpfr +ADDITIONAL_MODULES = mpfr/MpfrFloat.o +ifneq (,$(findstring -DFP_SUPPORT_GMP_INT_TYPE,$(FEATURE_FLAGS))) +ADDITIONAL_MODULES += mpfr/GmpInt.o +endif +else +ifneq (,$(findstring -DFP_SUPPORT_GMP_INT_TYPE,$(FEATURE_FLAGS))) +LDFLAGS += -lgmp +ADDITIONAL_MODULES = mpfr/GmpInt.o +endif +endif + +ifneq (,$(findstring -DFP_USE_THREAD_SAFE_EVAL,$(FEATURE_FLAGS))) +BOOST_THREAD_LIB = -lboost_thread-mt -lboost_system +else +ifneq (,$(findstring -DFP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA,$(FEATURE_FLAGS))) +BOOST_THREAD_LIB = -lboost_thread-mt -lboost_system +endif +endif + +ifneq (,$(findstring -DFP_SUPPORT_CPLUSPLUS11_MATH_FUNCS,$(FEATURE_FLAGS))) +CXXFLAGS += -std=c++0x +endif + +#LD += -Xlinker --gc-sections +#LD += -Xlinker --print-gc-sections +# ^Use this option to list everything that GC removed. + + +# For compilation with ICC: +#OPTIMIZATION=-O3 -xT -inline-level=2 -w1 -openmp -mssse3 +#CXX=icc +#LD=icc -L/opt/intel/Compiler/11.1/059/bin/intel64/lib -lirc -lstdc++ -openmp -lguide -lpthread +#CXXFLAGS=-Wall $(OPTIMIZATION) $(FEATURE_FLAGS) + +CPPFLAGS += -I"`pwd`" + +all: testbed speedtest functioninfo + +FP_MODULES = fparser.o \ + fpoptimizer/grammar_data.o \ + fpoptimizer/optimize_main.o \ + fpoptimizer/readbytecode.o \ + fpoptimizer/makebytecode.o \ + fpoptimizer/codetree.o \ + fpoptimizer/grammar.o \ + fpoptimizer/optimize.o \ + fpoptimizer/optimize_match.o \ + fpoptimizer/optimize_synth.o \ + fpoptimizer/optimize_debug.o \ + fpoptimizer/constantfolding.o \ + fpoptimizer/valuerange.o \ + fpoptimizer/rangeestimation.o \ + fpoptimizer/opcodename.o \ + fpoptimizer/bytecodesynth.o \ + fpoptimizer/transformations.o \ + fpoptimizer/cse.o \ + fpoptimizer/debug.o \ + fpoptimizer/hash.o \ + $(ADDITIONAL_MODULES) + +RELEASE_PACK_FILES = examples/example.cc examples/example2.cc fparser.cc \ + fparser.hh fparser_mpfr.hh fparser_gmpint.hh \ + fpoptimizer.cc fpconfig.hh extrasrc/fptypes.hh extrasrc/fpaux.hh \ + mpfr/MpfrFloat.hh mpfr/MpfrFloat.cc mpfr/GmpInt.hh mpfr/GmpInt.cc \ + extrasrc/fp_opcode_add.inc \ + extrasrc/fp_identifier_parser.inc \ + docs/fparser.html docs/style.css docs/lgpl.txt docs/gpl.txt + +testbed: testbed.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) $(BOOST_THREAD_LIB) + +fpoptimizer.o: fpoptimizer.cc + +testbed_release: testbed.o fparser.o fpoptimizer.o $(ADDITIONAL_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) $(BOOST_THREAD_LIB) + +speedtest: util/speedtest.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) + +speedtest_release: util/speedtest.o fparser.o fpoptimizer.o + $(LD) -o $@ $^ $(LDFLAGS) + +examples/example: examples/example.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) + +examples/example2: examples/example2.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) + +ftest: util/ftest.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) + +powi_speedtest: util/powi_speedtest.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) + +koe: koe.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) + +functioninfo: util/functioninfo.o $(FP_MODULES) + $(LD) -o $@ $^ $(LDFLAGS) + +fpoptimizer/grammar_data.cc: \ + util/tree_grammar_parser \ + fpoptimizer/treerules.dat + util/tree_grammar_parser < fpoptimizer/treerules.dat > $@ + +extrasrc/fp_opcode_add.inc: \ + util/bytecoderules_parser \ + util/bytecoderules.dat \ + util/bytecoderules_header.txt \ + util/cpp_compress + cat util/bytecoderules_header.txt > $@ + util/bytecoderules_parser \ + < util/bytecoderules.dat \ + | util/cpp_compress \ + >> $@ + +tests/make_tests: \ + tests/make_tests.o util/cpp_compress.o + $(LD) -o $@ $^ $(LDFLAGS) + +testbed_tests.inc: tests/make_tests + tests/make_tests tests/*/* -o $@ + +FPOPTIMIZER_CC_FILES=\ + lib/crc32.hh \ + lib/autoptr.hh \ + lib/functional.hh \ + fpoptimizer/hash.hh \ + fpoptimizer/codetree.hh \ + fpoptimizer/grammar.hh \ + fpoptimizer/consts.hh \ + fpoptimizer/optimize.hh \ + fpoptimizer/opcodename.hh \ + fpoptimizer/opcodename.cc \ + fpoptimizer/bytecodesynth.hh \ + fpoptimizer/bytecodesynth.cc \ + fpoptimizer/valuerange.hh \ + fpoptimizer/rangeestimation.hh \ + fpoptimizer/constantfolding.hh \ + fpoptimizer/logic_boolgroups.hh \ + fpoptimizer/logic_collections.hh \ + fpoptimizer/logic_ifoperations.hh \ + fpoptimizer/logic_powoperations.hh \ + fpoptimizer/logic_comparisons.hh \ + fpoptimizer/codetree.cc \ + fpoptimizer/debug.cc \ + fpoptimizer/grammar.cc \ + fpoptimizer/grammar_data.cc \ + fpoptimizer/optimize.cc \ + fpoptimizer/optimize_match.cc \ + fpoptimizer/optimize_synth.cc \ + fpoptimizer/optimize_debug.cc \ + fpoptimizer/hash.cc \ + fpoptimizer/makebytecode.cc \ + fpoptimizer/readbytecode.cc \ + fpoptimizer/constantfolding.cc \ + fpoptimizer/valuerange.cc \ + fpoptimizer/rangeestimation.cc \ + fpoptimizer/transformations.cc \ + fpoptimizer/cse.cc \ + fpoptimizer/optimize_main.cc + +fpoptimizer.cc: fpoptimizer/fpoptimizer_header.txt \ + fpoptimizer/fpoptimizer_footer.txt \ + $(FPOPTIMIZER_CC_FILES) \ + util/cpp_compress + rm -f fpoptimizer.cc + cat fpoptimizer/fpoptimizer_header.txt > $@ + for file in $(FPOPTIMIZER_CC_FILES); do \ + echo "#line 1 \"$$file\""; \ + sed -r "s@^(#include \".*)@// line removed for fpoptimizer.cc: \\1@" < "$$file"; \ + echo; \ + done | sed 's@BEGIN_EXPLICIT_INSTANTATION.*@@;s@.*END_EXPLICIT_INSTANTATION@@' \ + | util/cpp_compress "lnxyceti" >> $@ + # >> $@ + cat fpoptimizer/fpoptimizer_footer.txt >> $@ + +util/tree_grammar_parser: \ + util/tree_grammar_parser.o \ + fpoptimizer/opcodename.o + $(LD) -o $@ $^ $(LDFLAGS) + +util/tree_grammar_parser.cc: \ + util/tree_grammar_parser.y + bison --output=$@ $< + sed -i 's/ *$$//' $@ + +util/cpp_compress: \ + util/cpp_compress.o util/cpp_compress_main.o + $(LD) -o $@ $^ $(LDFLAGS) + +util/bytecoderules_parser: util/bytecoderules_parser.o + $(LD) -o $@ $^ $(LDFLAGS) + + +util/version_changer: util/version_changer.cc + g++ -O3 $^ -s -o $@ $(LDFLAGS) $(CXXFLAGS) $(CPPFLAGS) + +util/make_function_name_parser: util/make_function_name_parser.cc util/cpp_compress.o + g++ -O3 $^ -s -o $@ $(LDFLAGS) $(CXXFLAGS) $(CPPFLAGS) + +util/powi_opt: \ + util/powi_opt.o \ + fpoptimizer/hash.o \ + fpoptimizer/constantfolding.o \ + fpoptimizer/codetree.o \ + fpoptimizer/valuerange.o \ + fpoptimizer/rangeestimation.o + g++ -O3 $^ -s -o $@ $(LDFLAGS) $(CXXFLAGS) $(CPPFLAGS) + +util/create_testrules_for_optimization_rules: \ + util/create_testrules_for_optimization_rules.cc \ + fpoptimizer/grammar_data.o \ + fpoptimizer/opcodename.o \ + fpoptimizer/grammar.o + g++ -O3 $^ -s -o $@ $(LDFLAGS) $(CXXFLAGS) $(CPPFLAGS) + +fpoptimizer_tests.sh: util/create_testrules_for_optimization_rules + ./$< > $@ + chmod +x $@ + +set_version_string: util/version_changer + util/version_changer $(RELEASE_VERSION) fparser.cc \ + fparser.hh fparser_mpfr.hh fparser_gmpint.hh fpconfig.hh \ + fpoptimizer.cc extrasrc/fptypes.hh extrasrc/fpaux.hh \ + extrasrc/fp_opcode_add.inc \ + fpoptimizer/fpoptimizer_header.txt \ + util/bytecoderules_header.txt \ + docs/fparser.html webpage/index.html + +pack: set_version_string distro_pack devel_pack + +distro_pack: $(RELEASE_PACK_FILES) + zip -9 fparser$(RELEASE_VERSION).zip $(RELEASE_PACK_FILES) + # Use KZIP&ZIPMIX (advsys.net/ken), if possible, to create a smaller zip file + if which kzip; then \ + rm -rf fparser-$(RELEASE_VERSION);\ + mkdir fparser-$(RELEASE_VERSION); \ + tar cf - $(RELEASE_PACK_FILES) | tar -x -v -C fparser-$(RELEASE_VERSION) -f -; \ + for s in -b0 -b128 -b256 -b512 -b1024 \ + -rn -rn -rn -rn -rn -rn -rn -rn \ + -rn -rn -rn -rn -rn -rn -rn -rn; do \ + (cd fparser-$(RELEASE_VERSION); \ + kzip -r -y "$$s" ../fparser$(RELEASE_VERSION)-tmp.zip * );\ + DeflOpt ../fparser$(RELEASE_VERSION)-tmp.zip; \ + zipmix -y fparser$(RELEASE_VERSION).zip \ + fparser$(RELEASE_VERSION)-tmp.zip \ + fparser$(RELEASE_VERSION)-tmp2.zip; \ + if [ -f fparser$(RELEASE_VERSION)-tmp2.zip ]; then \ + mv -f fparser$(RELEASE_VERSION)-tmp2.zip fparser$(RELEASE_VERSION).zip; \ + fi; \ + ls -al fparser$(RELEASE_VERSION)*.zip; \ + done; \ + rm -f fparser$(RELEASE_VERSION)-tmp.zip; \ + fi + +devel_pack: + tar --exclude='*~' \ + --transform="s|^|fparser_$(RELEASE_VERSION)_devel/|" \ + -cjvf fparser$(RELEASE_VERSION)_devel.tar.bz2 \ + Makefile examples/example.cc examples/example2.cc fparser.cc \ + fparser.hh fparser_mpfr.hh fparser_gmpint.hh \ + fpconfig.hh extrasrc/fptypes.hh extrasrc/fpaux.hh \ + extrasrc/fp_opcode_add.inc \ + extrasrc/fp_identifier_parser.inc \ + testbed_tests.inc \ + util/speedtest.cc testbed.cc \ + tests/*.cc tests/*.txt tests/*/* \ + util/*.cc util/*.hh util/*.dat util/*.txt util/*.y \ + docs/fparser.html docs/style.css docs/lgpl.txt docs/gpl.txt \ + fpoptimizer/*.hh fpoptimizer/*.cc \ + fpoptimizer/*.dat \ + fpoptimizer/*.txt \ + lib/*.hh \ + mpfr/MpfrFloat.hh mpfr/MpfrFloat.cc \ + mpfr/GmpInt.hh mpfr/GmpInt.cc \ + run_full_release_testing.sh \ + util/functioninfo.cc + +clean: + rm -f testbed testbed_release \ + speedtest speedtest_release \ + functioninfo \ + examples/example examples/example2 ftest powi_speedtest \ + util/tree_grammar_parser \ + tests/make_tests \ + util/bytecoderules_parser \ + util/cpp_compress \ + util/make_function_name_parser \ + examples/*.o \ + fpoptimizer/*.o \ + tests/*.o \ + mpfr/*.o \ + util/*.o \ + *.o \ + .dep \ + util/tree_grammar_parser.output + +release_clean: + rm -f testbed_release speedtest_release \ + testbed.o fparser.o fpoptimizer.o + +distclean: clean + rm -f *~ + +TESTBED_TEST_FILES = $(wildcard tests/*/*) +testbed_tests.inc: $(TESTBED_TEST_FILES) + +.dep: + echo -n '' > .dep + - g++ -MM -MG $(CPPFLAGS) $(wildcard *.cc) >> .dep + - g++ -MM $(CPPFLAGS) $(wildcard examples/*.cc) | sed 's|^.*.o:|examples/&|' >> .dep + - g++ -MM $(CPPFLAGS) $(wildcard fpoptimizer/*.cc) | sed 's|^.*.o:|fpoptimizer/&|' >> .dep + - g++ -MM $(CPPFLAGS) $(wildcard tests/*.cc) | sed 's|^.*.o:|tests/&|' >> .dep + - g++ -MM $(CPPFLAGS) $(wildcard util/*.cc) | sed 's|^.*.o:|util/&|' >> .dep + - g++ -MM $(CPPFLAGS) $(wildcard mpfr/*.cc) | sed 's|^.*.o:|mpfr/&|' >> .dep + - g++ -MM $(CPPFLAGS) $(wildcard lib/*.cc) | sed 's|^.*.o:|lib/&|' >> .dep + sed -i "s@`pwd`/@@" .dep + +-include .dep diff --git a/docs/fparser.html b/docs/fparser.html new file mode 100644 index 0000000..eb94d19 --- /dev/null +++ b/docs/fparser.html @@ -0,0 +1,1841 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> + <link href="style.css" rel="stylesheet" type="text/css" title="normal" media=screen> + <title>Function Parser for C++ v4.5.2 : Documentation</title> +</head> + +<body> +<h1>Function Parser for C++ v4.5.2 </h1> + +<p>Authors: Juha Nieminen +(<a href="http://iki.fi/warp/">http://iki.fi/warp/</a>), +Joel Yliluoma +(<a href="http://iki.fi/bisqwit/">http://iki.fi/bisqwit/</a>). + +<p>The usage license of this library is located at the end of this file. + +<h2>Table of contents:</h2> + +<ul> + <li><a href="#whatsnew">What's new</a> + <li><a href="#preface">Preface</a> + <li><a href="#usage">Usage</a> + <ul> + <li><a href="#parsertypes">Parser types</a> + <li><a href="#configuring">Configuring the compilation</a> + <li><a href="#copyassignment">Copying and assignment</a> + <li><a href="#shortdesc">Short descriptions of FunctionParser methods</a> + <li><a href="#longdesc">Long descriptions of FunctionParser methods</a> + <ul> + <li><a href="#longdesc_Parse"><code>Parse()</code></a> + <li><a href="#longdesc_setDelimiterChar"><code>setDelimiterChar()</code></a> + <li><a href="#longdesc_ErrorMsg"><code>ErrorMsg()</code></a> + <li><a href="#longdesc_GetParseErrorType"><code>GetParseErrorType()</code></a> + <li><a href="#longdesc_Eval"><code>Eval()</code></a> + <li><a href="#longdesc_EvalError"><code>EvalError()</code></a> + <li><a href="#longdesc_Optimize"><code>Optimize()</code></a> + <li><a href="#longdesc_AddConstant"><code>AddConstant()</code></a> + <li><a href="#longdesc_AddUnit"><code>AddUnit()</code></a> + <li><a href="#longdesc_AddFunction1"><code>AddFunction()</code></a> (C++ function) + <li><a href="#longdesc_AddFunction2"><code>AddFunction()</code></a> (FunctionParser) + <li><a href="#longdesc_AddFunction3"><code>AddFunctionWrapper()</code></a> + <li><a href="#longdesc_RemoveIdentifier"><code>RemoveIdentifier()</code></a> + <li><a href="#longdesc_ParseAndDeduceVariables"><code>ParseAndDeduceVariables()</code></a> + </ul> + <li><a href="#functionobjects">Specialized function objects</a> + <li><a href="#base">FunctionParserBase</a> + </ul> + <li>Syntax + <ul> + <li><a href="#literals">Numeric literals</a> + <li><a href="#identifiers">Identifier names</a> + <li><a href="#functionsyntax">The function string syntax</a> + <li><a href="#inlinevars">Inline variables</a> + <li><a href="#whitespace">Whitespace</a> + </ul> + <li>Miscellaneous + <ul> + <li><a href="#fpaccuracy">About floating point accuracy</a> + <li><a href="#evaluationchecks">About evaluation-time checks</a> + <li><a href="#threadsafety">About thread safety</a> + <li><a href="#tipsandtricks">Tips and tricks</a> + <li><a href="#contact">Contacting the author</a> + </ul> +<!-- <li><a href="#algorithm">The algorithm used in the library</a> --> + <li><a href="#license">Usage license</a> +</ul> + +<a name="whatsnew"></a> +<h2>What's new</h2> + +<p>What's new in v4.5.2 + <ul> + <li>Fixed several optimizer bugs. + <li>Fixed compilation problems with Visual Studio 2013 and gcc. + </ul> + + + +<!-- -------------------------------------------------------------------- --> +<a name="preface"></a> +<h2>Preface</h2> + +<p>This C++ library offers a class which can be used to parse and evaluate a +mathematical function from a string (which might be eg. requested from the +user). The syntax of the function string is similar to mathematical expressions +written in C/C++ (the exact syntax is specified later in this document). +The function can then be evaluated with different values of variables. + +<p>For example, a function like "<code>sin(sqrt(x*x+y*y))</code>" can be +parsed from a string (either <code>std::string</code> or a C-style string) +and then evaluated with different values of <code>x</code> and <code>y</code>. +This library can be useful for evaluating user-inputted functions, or in +some cases interpreting mathematical expressions in a scripting language. + +<p>This library aims for maximum speed in both parsing and evaluation, while +keeping maximum portability. The library should compile and work with any +standard-conforming C++ compiler. + +<p>Different numerical types are supported: <code>double</code>, + <code>float</code>, <code>long double</code>, <code>long int</code>, + <code>std::complex</code> (of types <code>double</code>, + <code>float</code> and <code>long double</code>), + multiple-precision floating point numbers using the MPFR library, and + arbitrary precision integers using the GMP library. (Note that it's + not necessary for these two libraries to exist in the system in order + to use the Function Parser library with the other numerical types. Support + for these libraries is optionally compiled in using preprocessor settings.) + + +<!-- -------------------------------------------------------------------- --> +<a name="usage"></a> +<h2>Usage</h2> + +<p>To use the <code>FunctionParser</code> class, you have to include +<code>"fparser.hh"</code> in your source code files which use the +<code>FunctionParser</code> class. + +<p>If you are going to use the MPFR version of the library, you need to +include <code>"fparser_mpfr.hh"</code>. If you are going to use the GMP +version of the library, you need to include <code>"fparser_gmpint.hh"</code>. +(Note that support for these special parser versions needs to be specified +with preprocessor macros. See the <a href="#parsertypes">documentation +below</a> for details.) + +<p>When compiling, you have to compile <code>fparser.cc</code> and +<code>fpoptimizer.cc</code> and link them to the main program. In many +developement environments it's enough to add those two files to your +current project (usually header files don't have to be added to the +project for the compilation to work). + +<p>If you are going to use the MPFR or the GMP versions of the library, +you also need to add <code>mpfr/MpfrFloat.cc</code> or +<code>mpfr/GmpInt.cc</code> files to your project, respectively. Otherwise +they should not be added to the project. + +<p>Note that part of the library source code is inside several +<code>.inc</code> files inside the <code>extrasrc</code> subdirectory +(these files contain auto-generated C++ code), provided in the library +package. These files are used by <code>fparser.cc</code> and don't need +to be added explicitly to the project in most IDEs (such as Visual Studio). +Basically, you don't need to do anything with these files, other than keep +them in the <code>extrasrc</code> subdirectory. + +<p>Simple usage example of the library: + +<pre> + FunctionParser fp; + fp.Parse("sqrt(x*x + y*y)", "x,y"); + double variables[2] = { 1.5, 2.9 }; + double result = fp.Eval(variables); +</pre> + +<!-- -------------------------------------------------------------------- --> +<a name="parsertypes"></a> +<h3>Parser types</h3> + +<p>Different versions of the function parser class are supported, using + different floating point or integral types for function evaluation. + +<p>All the classes other than the default one, <code>FunctionParser</code>, + need to be enabled at compile time by defining a preprocessor macro + (specified below) either in the <code>fpconfig.hh</code> file or your + compiler settings. (The reason for this is that every parser that is + included in the compilation process will make the compilation slower + and increase the size of the executable, so they are compiled only on + demand. Also, the GMP and MPFR versions of the parser require for those + libraries to be available, which is often not the case.) + +<p>Note that if you try to use the other class types without enabling them + with the correspondent preprocessor macro, you will get a linker error + (rather than a compiler error) because those classes will not have been + instantiated when the library was compiled. + +<p>Currently the <code>Optimize()</code> method works only for the + <code>FunctionParser</code>, <code>FunctionParser_f</code> and + <code>FunctionParser_ld</code> classes. For the other types it can be + called but it does nothing. + +<p> +<dl> + <dt><p><code>FunctionParser</code></dt> + <dd> + <p>This is the default class, which uses <code>double</code> as its + numerical type. This is the only class enabled by default. + <p>If you use some other type than this one, and you don't want this + version of the class compiled into the library, you can define the + preprocessor macro <code>FP_DISABLE_DOUBLE_TYPE</code>. + </dd> + + <dt><p><code>FunctionParser_f</code></dt> + <dd> + <p>This parser uses <code>float</code> as its numerical type. + <p>The <code>FP_SUPPORT_FLOAT_TYPE</code> preprocessor macro needs to be + defined for this class to be enabled. + </dd> + + <dt><p><code>FunctionParser_ld</code></dt> + <dd> + <p>This parser uses <code>long double</code> as its numerical type. + <p>The <code>FP_SUPPORT_LONG_DOUBLE_TYPE</code> preprocessor macro needs + to be defined for this class to be enabled. + <p>Note that the <code>FP_USE_STRTOLD</code> preprocessor macro should + also be defined when using this version of the parser if the compiler + supports the (C99) function <code>strtold()</code>. (See + <a href="#configuring">documentation</a> below.) + </dd> + + <dt><p><code>FunctionParser_li</code></dt> + <dd> + <p>This parser uses <code>long int</code> as its numerical type. + <p>The <code>FP_SUPPORT_LONG_INT_TYPE</code> preprocessor macro needs + to be defined for this class to be enabled. + <p>Note that this version of the class uses a reduced function syntax + with support only for functions which are feasible to be used with + integral types (namely <code>abs()</code>, <code>eval()</code>, + <code>if()</code>, <code>min()</code> and <code>max()</code>, besides + basic arithmetic operators, except for the power operator). + </dd> + + <dt><p><code>FunctionParser_cd</code>, <code>FunctionParser_cf</code>, + <code>FunctionParser_cld</code></dt> + <dd> + <p>These parsers use <code>std::complex<double></code>, + <code>std::complex<float></code> and + <code>std::complex<long double></code> as their numerical type, + respectively. + <p>The preprocessor macros to enable them are + <code>FP_SUPPORT_COMPLEX_DOUBLE_TYPE</code>, + <code>FP_SUPPORT_COMPLEX_FLOAT_TYPE</code> and + <code>FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE</code>. + <p>If <code>FunctionParser_cld</code> is used, the + <code>FP_USE_STRTOLD</code> macro should also be defined if the compiler + supports the <code>strtold()</code> function. + </dd> + + <dt><p><code>FunctionParser_mpfr</code></dt> + <dd> + <p>This parser uses <code>MpfrFloat</code> as its numerical type. + <p>The <code>FP_SUPPORT_MPFR_FLOAT_TYPE</code> preprocessor macro needs + to be defined for this class to be enabled. + <p>Note that to use this version of the parser, + <code>"fparser_mpfr.hh"</code> needs to be included. + <p><code>MpfrFloat</code> is an auxiliary class which uses the MPFR + library for multiple-precision floating point numbers. The class + behaves largely like a floating point type, and is declared in the + <code>mpfr/MpfrFloat.hh</code> file (see that file for info about + the public interface of the class). + <p>If this class is enabled, <code>mpfr/MpfrFloat.cc</code> + needs to be compiled into the project, as well as the GMP and MPFR + libraries. (With the gcc compiler this means using the linker options + "<code>-lgmp -lmpfr</code>".) + </dd> + + <dt><p><code>FunctionParser_gmpint</code></dt> + <dd> + <p>This parser uses <code>GmpInt</code> as its numerical type. + <p>The <code>FP_SUPPORT_GMP_INT_TYPE</code> preprocessor macro needs + to be defined for this class to be enabled. + <p>Note that to use this version of the parser, + <code>"fparser_gmpint.hh"</code> needs to be included. + <p><code>GmpInt</code> is an auxiliary class which uses the GMP + library for arbitrary-precision integer numbers. The class + behaves largely like an integer type, and is declared in the + <code>mpfr/GmpInt.hh</code> file (see that file for info about + the public interface of the class). + <p>If this class is enabled, <code>mpfr/GmpInt.cc</code> + needs to be compiled into the project, as well as the GMP library. + <p>This version of the class also uses a reduced version of the syntax, + like the <code>long int</code> version. + <p><b>Note:</b> Since there's no upper limit to the size of GMP + integers, this version of the class should be used with care in + situations where malicious users might be able to exploit it to + make the program run out of memory. An example of this would be + a server-side application usable through the WWW. + </dd> +</dl> + +<p>Note that these different classes are completely independent and + instances of different classes cannot be given to each other using the + <code>AddFunction()</code> method. Only objects of the same type can + be given to that method. + +<p>The rest of the documentation assumes that <code>FunctionParser</code> + (which uses the <code>double</code> type) is used. The usage of the other + classes is identical except that <code>double</code> is replaced with the + correspondent type used by that class. (In other words, whenever the + rest of this documentation uses the type keyword '<code>double</code>', + the correspondent type should be used instead, when using another version + of the class.) + +<!-- -------------------------------------------------------------------- --> +<a name="configuring"></a> +<h3>Configuring the compilation</h3> + +<p>There is a set of precompiler options in the <code>fpconfig.hh</code> file +which can be used for setting certain features on or off. All of these options +can also be specified from the outside, using precompiler settings (eg. the +<code>-D</code> option in gcc), and thus it's not necessary to modify this +file. + +<dl> + <dt><p><code>FP_USE_STRTOLD</code> : (Default off)</dt> + <dd><p>If <code>FunctionParser_ld</code> or <code>FunctionParser_cld</code> + are used, this preprocessor macro should be defined if the compiler + supports the (C99) function <code>strtold()</code>. If not, then numeric + literals will be parsed with double precision only, which in most + systems is less accurate than long double precision, which will cause + small rounding errors. (This setting has no effect on the other parser + types.) Note that <code>strtold()</code> will also be automatically used + if <code>__cplusplus</code> indicates that C++11 is in use. + </dd> + + <dt><p><code>FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS</code> : (Default off)</dt> + <dd><p>Use C++11 math functions where applicable. (These are ostensibly + faster than the equivalent formulas using C++98 math functions.) Note + that not all compilers support these functions (even if they otherwise + support C++11.) + + <dt><p><code>FP_SUPPORT_OPTIMIZER</code> : (Default on)</dt> + <dd><p>If you are not going to use the <code>Optimize()</code> method, you + can comment this line out to speed-up the compilation a bit, as + well as making the binary a bit smaller. (<code>Optimize()</code> can + still be called, but it will not do anything.) + + <p>You can also disable the optimizer by specifying the + <code>FP_NO_SUPPORT_OPTIMIZER</code> precompiler constant in your + compiler settings. + </dd> + + <dt><p><code>FP_USE_THREAD_SAFE_EVAL</code> : (Default off)</dt> + <dd><p>Define this precompiler constant to make <code>Eval()</code> + thread-safe. Refer to the <a href="#threadsafety">thread safety + section</a> later in this document for more information. + Note that defining this may make <code>Eval()</code> slightly slower. + <p>Also note that the MPFR and GMP versions of the library cannot be + made thread-safe, and thus this setting has no effect on them. + </dd> + + <dt><p><code>FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA</code> : (Default off)</dt> + <dd><p>This is like the previous, but makes <code>Eval()</code> use the + <code>alloca()</code> function (instead of <code>std::vector</code>). + This will make it faster, but the <code>alloca()</code> + function is not standard and thus not supported by all compilers. + </dd> +</dl> + + +<!-- -------------------------------------------------------------------- --> +<a name="copyassignment"></a> +<h3>Copying and assignment</h3> + +<p>The class implements a safe copy constructor and assignment operator. + +<p>It uses the copy-on-write technique for efficiency. This means that + when copying or assigning a FunctionParser instance, the internal data + (which in some cases can be quite lengthy) is not immediately copied + but only when the contents of the copy (or the original) are changed. + +<p>This means that copying/assigning is a very fast operation, and if + the copies are never modified then actual data copying never happens + either. + +<p>The <code>Eval()</code> and <code>EvalError()</code> methods of the +copy can be called without the internal data being copied. + +<p>Calling <code>Parse()</code>, <code>Optimize()</code> or the user-defined +constant/function adding methods will cause a deep-copy. + + +<!-- -------------------------------------------------------------------- --> +<a name="shortdesc"></a> +<h3>Short descriptions of FunctionParser methods</h3> + +<pre> +int Parse(const std::string& Function, const std::string& Vars, + bool useDegrees = false); + +int Parse(const char* Function, const std::string& Vars, + bool useDegrees = false); +</pre> + +<p>Parses the given function and compiles it to internal format. + Return value is -1 if successful, else the index value to the location + of the error. + +<hr> +<pre> +void setDelimiterChar(char); +</pre> + +<p>Sets an ending delimiter character for the function string. (See the + long description for more details.) + +<hr> +<pre> +static double epsilon(); +static void setEpsilon(double); +</pre> + +<p>Setter and getter for the epsilon value used with comparison operators. + +<hr> +<pre> +const char* ErrorMsg(void) const; +</pre> + +<p>Returns an error message corresponding to the error in +<code>Parse()</code>, or an empty string if no such error occurred. + +<hr> +<pre> +ParseErrorType GetParseErrorType() const; +</pre> + +<p>Returns the type of parsing error which occurred. Possible return types + are described in the long description. + +<hr> +<pre> +double Eval(const double* Vars); +</pre> + +<p>Evaluates the function given to <code>Parse()</code>. + +<hr> +<pre> +int EvalError(void) const; +</pre> + +<p>Returns <code>0</code> if no error happened in the previous call to +<code>Eval()</code>, else an error code <code>>0</code>. + +<hr> +<pre> +void Optimize(); +</pre> + +<p>Tries to optimize the bytecode for faster evaluation. + +<hr> +<pre> +bool AddConstant(const std::string& name, double value); +</pre> + +<p>Add a constant to the parser. Returns <code>false</code> if the name of +the constant is invalid, else <code>true</code>. + +<hr> +<pre> +bool AddUnit(const std::string& name, double value); +</pre> + +<p>Add a new unit to the parser. Returns <code>false</code> if the name of +the unit is invalid, else <code>true</code>. + +<hr> +<pre> +bool AddFunction(const std::string& name, + double (*functionPtr)(const double*), + unsigned paramsAmount); +</pre> + +<p>Add a user-defined function to the parser (as a function pointer). +Returns <code>false</code> if the name of the function is invalid, else +<code>true</code>. + +<hr> +<pre> +bool AddFunction(const std::string& name, FunctionParser&); +</pre> + +<p>Add a user-defined function to the parser (as a <code>FunctionParser</code> +instance). Returns <code>false</code> if the name of the function is invalid, +else <code>true</code>. + +<hr> +<pre> +bool RemoveIdentifier(const std::string& name); +</pre> + +<p>Removes the constant, unit or user-defined function with the specified +name from the parser. + +<hr> +<pre> +int ParseAndDeduceVariables(const std::string& function, + int* amountOfVariablesFound = 0, + bool useDegrees = false); +int ParseAndDeduceVariables(const std::string& function, + std::string& resultVarString, + int* amountOfVariablesFound = 0, + bool useDegrees = false); +int ParseAndDeduceVariables(const std::string& function, + std::vector<std::string>& resultVars, + bool useDegrees = false); +</pre> + +<p>Like <code>Parse()</code>, but the variables in the function are deduced +automatically. The amount of found variables and the variable names themselves +are returned by the different versions of the function. + +<!-- -------------------------------------------------------------------- --> +<a name="longdesc"></a> +<h3>Long descriptions of FunctionParser methods</h3> + +<hr> +<a name="longdesc_Parse"></a> +<pre> +int Parse(const std::string& Function, const std::string& Vars, + bool useDegrees = false); + +int Parse(const char* Function, const std::string& Vars, + bool useDegrees = false); +</pre> + +<p>Parses the given function (and compiles it to internal format). +Destroys previous function. Following calls to <code>Eval()</code> will evaluate +the given function. + +<p>The strings given as parameters are not needed anymore after parsing. + +<p>Parameters: + +<table border=2> + <tr> + <td><code>Function</code></td> + <td>String containing the function to parse.</td> + </tr><tr> + <td><code>Vars</code></td> + <td>String containing the variable names, separated by commas.<br> + Eg. <code>"x,y"</code>, <code>"VarX,VarY,VarZ,n"</code> or + <code>"x1,x2,x3,x4,__VAR__"</code>. + </tr><tr> + <td><code>useDegrees</code></td> + <td>(Optional.) Whether to use degrees or radians in + trigonometric functions. (Default: radians)</td> + </tr> +</table> + +<p>If a <code>char*</code> is given as the <code>Function</code> parameter, +it must be a null-terminated string. + +<p>Variables can have any size and they are case sensitive (ie. +<code>"var"</code>, <code>"VAR"</code> and <code>"Var"</code> are +<em>different</em> variable names). Letters, digits, underscores and +UTF8-encoded characters can be used in variable names, but the name of +a variable can't begin with a digit. Each variable name can appear only +once in the '<code>Vars</code>' string. Function names are not legal +variable names. + +<p>Using longer variable names causes no overhead whatsoever to the +<code>Eval()</code> method, so it's completely safe to use variable names +of any size. + +<p>The third, optional parameter specifies whether angles should be + interpreted as radians or degrees in trigonometrical functions. + If not specified, the default value is radians. + +<p>Return values: + +<ul> + <li>On success the function returns <code>-1</code>. + <li>On error the function returns an index to where the error was found + (<code>0</code> is the first character, <code>1</code> the second, etc). + If the error was not a parsing error returns an index to the end of the + string. +</ul> + +<p>Example: <code>parser.Parse("3*x+y", "x,y");</code> + + +<hr> +<a name="longdesc_setDelimiterChar"></a> +<pre> +void setDelimiterChar(char); +</pre> + +<p>By default the parser expects the entire function string to be valid +(ie. the entire contents of the given <code>std::string</code>, or a C string +ending in the null character <code>'\0'</code>). + +<p>If a delimiter character is specified with this function, then if it's +encountered at the outermost parsing level by the <code>Parse()</code> +function, and the input function has been valid so far, <code>Parse()</code> +will return an index to this character inside the input string, but rather +than set an error code, <code>FP_NO_ERROR</code> will be set. + +<p>The idea is that this can be used to more easily parse functions which +are embedded inside larger strings, containing surrounding data, without +having to explicitly extract the function to a separate string. + +<p>For example, suppose you are writing an interpreter for a scripting + language, which can have commands like this: + +<p><code>let MyFunction(x,y) = { sin(x*x+y*y) } // A 2-dimensional function</code> + +<p>Normally when parsing such a line you would have to extract the part +inside the curly brackets into a separate string and parse it that way. +With this feature what you can do instead is to set <code>'}'</code> as +the delimiter character and then simply give a pointer to the character +which comes after the <code>'{'</code>. If all goes well, the +<code>Parse()</code> function will return an index to the <code>'}'</code> +character (from the given starting point) and <code>GetParseErrorType()</code> +will return <code>FP_NO_ERROR</code>. You can use the return +value (if it's not <code>-1</code>) to jump forward in the string to the +delimiter character. + +<p>Note that a null character (<code>'\0'</code>) or the end of the +<code>std::string</code> (if one was given) will still be a valid end of +the function string even if a delimiter character was specified. (In this +case <code>Parse()</code> will return <code>-1</code> if there was no error, +as usual.) + +<p>Also note that the delimiter character cannot be any valid operator +or alphanumeric (including the underscore) character, nor the other +characters defined in the function syntax. It must be a character not +supported by the function parser (such as <code>'}'</code>, +<code>'"'</code>, <code>']'</code>, etc). + + +<hr> +<a name="longdesc_Epsilon"></a> +<pre> +static double epsilon(); +static void setEpsilon(double); +</pre> + +<p>Comparison operators (for the non-integral versions of the parser) use an +epsilon value to account for floating point calculation rounding errors. +This epsilon value can be set and read with these functions. (Note that the +specified value will be used by all instances of FunctionParser.) If not +specified, the default values are: + +<ul> + <li>double: 1e-12 + <li>float: 1e-5 + <li>long double: 1e-14 + <li>MpfrFloat: The value of MpfrFloat::someEpsilon() +</ul> + + +<hr> +<a name="longdesc_ErrorMsg"></a> +<pre> +const char* ErrorMsg(void) const; +</pre> + +<p>Returns a pointer to an error message string corresponding to the error +caused by <code>Parse()</code> (you can use this to print the proper error +message to the user). If no such error has occurred, returns an empty string. + + +<hr> +<a name="longdesc_GetParseErrorType"></a> +<pre> +ParseErrorType GetParseErrorType() const; +</pre> + +<p>Returns the type of parse error which occurred. + +<p>This method can be used to get the error type if <code>ErrorMsg()</code> +is not enough for printing the error message. In other words, this can be +used for printing customized error messages (eg. in another language). +If the default error messages suffice, then this method doesn't need +to be called. + +<code>FunctionParser::ParseErrorType</code> is an enumerated type inside +the class (ie. its values are accessed like +"<code>FunctionParser::SYNTAX_ERROR</code>"). + +<p>The possible values for FunctionParser::ParseErrorType are listed below, +along with their equivalent error message returned by the +<code>ErrorMsg()</code> method: + +<p><table border=2> +<tr> + <td><code>FP_NO_ERROR</code></td> + <td>If no error occurred in the previous call to <code>Parse()</code>.</td> +</tr><tr> + <td><code>SYNTAX_ERROR</code></td> + <td>"Syntax error"</td> +</tr><tr> + <td><code>MISM_PARENTH</code></td> + <td>"Mismatched parenthesis"</td> +</tr><tr> + <td><code>MISSING_PARENTH</code></td> + <td>"Missing ')'"</td> +</tr><tr> + <td><code>EMPTY_PARENTH</code></td> + <td>"Empty parentheses"</td> +</tr><tr> + <td><code>EXPECT_OPERATOR</code></td> + <td>"Syntax error: Operator expected"</td> +</tr><tr> + <td><code>OUT_OF_MEMORY</code></td> + <td>"Not enough memory"</td> +</tr><tr> + <td><code>UNEXPECTED_ERROR</code></td> + <td>"An unexpected error occurred. Please make a full bug report to the + author"</td> +</tr><tr> + <td><code>INVALID_VARS</code></td> + <td>"Syntax error in parameter 'Vars' given to FunctionParser::Parse()"</td> +</tr><tr> + <td><code>ILL_PARAMS_AMOUNT</code></td> + <td>"Illegal number of parameters to function"</td> +</tr><tr> + <td><code>PREMATURE_EOS</code></td> + <td>"Syntax error: Premature end of string"</td> +</tr><tr> + <td><code>EXPECT_PARENTH_FUNC</code></td> + <td>"Syntax error: Expecting ( after function"</td> +</tr><tr> + <td><code>UNKNOWN_IDENTIFIER</code></td> + <td>"Syntax error: Unknown identifier"</td> +</tr><tr> + <td><code>NO_FUNCTION_PARSED_YET</code></td> + <td>"(No function has been parsed yet)"</td> +</tr> +</table> + + +<hr> +<a name="longdesc_Eval"></a> +<pre> +double Eval(const double* Vars); +</pre> + +<p>Evaluates the function given to <code>Parse()</code>. +The array given as parameter must contain the same amount of values as +the amount of variables given to <code>Parse()</code>. Each value corresponds +to each variable, in the same order. + +<p>Return values: +<ul> + <li>On success returns the evaluated value of the function given to + <code>Parse()</code>. + <li>On error (such as division by 0) the return value is unspecified, + probably 0. +</ul> + +<p>Example: + +<p><code>double Vars[] = {1, -2.5};</code><br> +<code>double result = parser.Eval(Vars);</code> + + +<hr> +<a name="longdesc_EvalError"></a> +<pre> +int EvalError(void) const; +</pre> + +<p>Used to test if the call to <code>Eval()</code> succeeded. + +<p>Return values: + +<p>If there was no error in the previous call to <code>Eval()</code>, +returns <code>0</code>, else returns a positive value as follows: +<ul> + <li>1: division by zero + <li>2: sqrt error (sqrt of a negative value) + <li>3: log error (logarithm of a negative value) + <li>4: trigonometric error (asin or acos of illegal value) + <li>5: maximum recursion level in <code>eval()</code> reached +</ul> + + +<hr> +<a name="longdesc_Optimize"></a> +<pre> +void Optimize(); +</pre> + +<p>This method can be called after calling the <code>Parse()</code> method. +It will try to simplify the internal bytecode so that it will evaluate faster +(it tries to reduce the amount of opcodes in the bytecode). + +<p>For example, the bytecode for the function <code>"5+x*y-25*4/8"</code> will +be reduced to a bytecode equivalent to the function <code>"x*y-7.5"</code> (the +original 11 opcodes will be reduced to 5). Besides calculating constant +expressions (like in the example), it also performs other types of +simplifications with variable and function expressions. + +<p>This method is quite slow and the decision of whether to use it or +not should depend on the type of application. If a function is parsed +once and evaluated millions of times, then calling <code>Optimize()</code> +may speed-up noticeably. However, if there are tons of functions to parse +and each one is evaluated once or just a few times, then calling +<code>Optimize()</code> will only slow down the program. + +<p>Also, if the original function is expected to be optimal, then calling +<code>Optimize()</code> would be useless. + +<p>Note: Currently this method does not make any checks (like +<code>Eval()</code> does) and thus things like <code>"1/0"</code> will cause +undefined behaviour. (On the other hand, if such expression is given to the +parser, <code>Eval()</code> will always give an error code, no matter what +the parameters.) If caching this type of errors is important, a work-around +is to call <code>Eval()</code> once before calling <code>Optimize()</code> +and checking <code>EvalError()</code>. + +<p>If the destination application is not going to use this method, +the compiler constant <code>FP_SUPPORT_OPTIMIZER</code> can be undefined in +<code>fpconfig.hh</code> to make the library smaller (<code>Optimize()</code> +can still be called, but it will not do anything). + +<p>(If you are interested in seeing how this method optimizes the opcode, +you can call the <code>PrintByteCode()</code> method before and after the +call to <code>Optimize()</code> to see the difference.) + + +<hr> +<a name="longdesc_AddConstant"></a> +<pre> +bool AddConstant(const std::string& name, double value); +</pre> + +<p>This method can be used to add constants to the parser. Syntactically + constants are identical to variables (ie. they follow the same naming + rules and they can be used in the function string in the same way as + variables), but internally constants are directly replaced with their + value at parse time. + +<p>Constants used by a function must be added before calling +<code>Parse()</code> for that function. Constants are preserved between +<code>Parse()</code> calls in the current FunctionParser instance, so +they don't need to be added but once. (If you use the same constant in +several instances of FunctionParser, you will need to add it to all the +instances separately.) + +<p>Constants can be added at any time and the value of old constants can +be changed, but new additions and changes will only have effect the next +time <code>Parse()</code> is called. (That is, changing the value of a constant +after calling <code>Parse()</code> and before calling <code>Eval()</code> +will have no effect.) + +<p>The return value will be <code>false</code> if the '<code>name</code>' of +the constant was illegal, else <code>true</code>. If the name was illegal, +the method does nothing. + +<p>Example: <code>parser.AddConstant("pi", 3.1415926535897932);</code> + +<p>Now for example <code>parser.Parse("x*pi", "x");</code> will be identical +to the call <code>parser.Parse("x*3.1415926535897932", "x");</code> + + +<hr> +<a name="longdesc_AddUnit"></a> +<pre> +bool AddUnit(const std::string& name, double value); +</pre> + +<p>In some applications it is desirable to have units of measurement. +A typical example is an application which creates a page layout to be +printed. When printing, distances are usually measured in points +(defined by the resolution of the printer). However, it is often more +useful for the user to be able to specify measurements in other units +such as centimeters or inches. + +<p>A unit is simply a value by which the preceding element is multiplied. +For example, if the printing has been set up to 300 DPI, one inch is +then 300 points (dots). Thus saying eg. <code>"5in"</code> is the same as saying +<code>"5*300"</code> or <code>"1500"</code> (assuming <code>"in"</code> has +been added as a unit with the value 300). + +<p>Note that units are slightly different from a multiplication in +that they have a higher precedence than any other operator (except +parentheses). Thus for example <code>"5/2in"</code> is parsed as +<code>"5/(2*300)"</code>. +(If 5/2 inches is what one wants, it has to be written <code>"(5/2)in"</code>.) + +<p>You can use the <code>AddUnit()</code> method to add a new unit. The +unit can then be used after any element in the function (and will work as +a multiplier for that element). An element is a float literal, a constant, +a variable, a function or any expression in parentheses. When the element +is not a float literal nor an expression in parentheses, there has to naturally +be at least one whitespace between the element and the unit (eg. +<code>"x in"</code>). To change the value of a unit, call +<code>AddUnit()</code> again with the same unit name and the new value. + +<p>Unit names share the same namespace as constants, functions and + variables, and thus should be distinct from those. + +<p>Example: <code>parser.AddUnit("in", 300);</code> + +<p>Now for example the function <code>"5in"</code> will be identical to +<code>"(5*300)"</code>. Other usage examples include <code>"x in"</code>, +<code>"3in+2"</code>, <code>"pow(x,2)in"</code>, <code>"(x+2)in"</code>. + + +<hr> +<a name="longdesc_AddFunction1"></a> +<pre> +bool AddFunction(const std::string& name, + double (*functionPtr)(const double*), + unsigned paramsAmount); +</pre> + +This method can be used to add new functions to the parser. For example, +if you would like to add a function "<code>sqr(A)</code>" which squares the +value of <code>A</code>, you can do it with this method (so that you don't +need to touch the source code of the parser). + +<p>The method takes three parameters: + +<ul> + <li>The name of the function. The name follows the same naming conventions + as variable names. + + <li>A C++ function, which will be called when evaluating the function + string (if the user-given function is called there). The C++ function + must have the form: + <p><code>double functionName(const double* params);</code> + + <li>The number of parameters the function takes. 0 is a valid value + in which case the function takes no parameters (such function + should simply ignore the <code>double*</code> it gets as a parameter). +</ul> + +<p>The return value will be <code>false</code> if the given name was invalid +(either it did not follow the variable naming conventions, or the name was +already reserved), else <code>true</code>. If the return value is +<code>false</code>, nothing is added. + +<p>Example: Suppose we have a C++ function like this: + +<p><code>double Square(const double* p)</code><br> +<code>{</code><br> +<code> return p[0]*p[0];</code><br> +<code>}</code> + +<p>Now we can add this function to the parser like this: + +<p><code>parser.AddFunction("sqr", Square, 1);</code><br> +<code>parser.Parse("2*sqr(x)", "x");</code> + +<p>An example of a useful function taking no parameters is a function + returning a random value. For example: + +<p><code>double Rand(const double*)</code><br> +<code>{</code><br> +<code> return drand48();</code><br +<code>}</code> + +<p><code>parser.AddFunction("rand", Rand, 0);</code> + +<p><em>Important note</em>: If you use the <code>Optimize()</code> method, +it will assume that the user-given function has no side-effects, that is, +it always returns the same value for the same parameters. The optimizer will +optimize the function call away in some cases, making this assumption. +(The <code>Rand()</code> function given as example above is one such +problematic case.) + + +<hr> +<a name="longdesc_AddFunction2"></a> +<pre> +bool AddFunction(const std::string& name, FunctionParser&); +</pre> + +<p>This method is almost identical to the previous <code>AddFunction()</code>, +but instead of taking a C++ function, it takes another FunctionParser +instance. + +<p>There are some important restrictions on making a FunctionParser instance + call another: + +<ul> + <li>The FunctionParser instance given as parameter must be initialized + with a <code>Parse()</code> call before giving it as parameter. That + is, if you want to use the parser <code>A</code> in the parser + <code>B</code>, you must call <code>A.Parse()</code> before you can + call <code>B.AddFunction("name", A)</code>. + + <li>The amount of variables in the FunctionParser instance given as + parameter must not change after it has been given to the + <code>AddFunction()</code> + of another instance. Changing the number of variables will result in + malfunction. + + <li><code>AddFunction()</code> will fail (ie. return <code>false</code>) + if a recursive loop is + formed. The method specifically checks that no such loop is built. + + <li>The FunctionParser instance given as parameter will <em>not</em> be + copied internally, only referenced. Thus the FunctionParser instance + given as parameter must exist for as long as the other FunctionParser + instance uses it. +</ul> + +<p>Example: + +<p><code>FunctionParser f1, f2;</code><br> +<p><code>f1.Parse("x*x", "x");</code><br> +<p><code>f2.AddFunction("sqr", f1);</code> + +<p>This version of the <code>AddFunction()</code> method can be useful to +eg. chain user-given functions. For example, ask the user for a function F1, + and then ask the user another function F2, but now the user can + call F1 in this second function if he wants (and so on with a third + function F3, where he can call F1 and F2, etc). + +<hr> +<a name="longdesc_AddFunction3"></a> +<pre> +template<typename DerivedWrapper> +bool AddFunctionWrapper(const std::string& name, const DerivedWrapper&, + unsigned paramsAmount); +</pre> + +<p>See section on <a href="#functionobjects">specialized function objects</a>. + +<hr> +<a name="longdesc_RemoveIdentifier"></a> +<pre> +bool RemoveIdentifier(const std::string& name); +</pre> + +<p>If a constant, unit or user-defined function with the specified name +exists in the parser, it will be removed and the return value will be +<code>true</code>, else nothing will be done and the return value will be +<code>false</code>. + +<p>(Note: If you want to remove <em>everything</em> from an existing +FunctionParser instance, simply assign a fresh instance to it, ie. like +"<code>parser = FunctionParser();</code>") + +<hr> +<a name="longdesc_ParseAndDeduceVariables"></a> +<pre> +int ParseAndDeduceVariables(const std::string& function, + int* amountOfVariablesFound = 0, + bool useDegrees = false); +int ParseAndDeduceVariables(const std::string& function, + std::string& resultVarString, + int* amountOfVariablesFound = 0, + bool useDegrees = false); +int ParseAndDeduceVariables(const std::string& function, + std::vector<std::string>& resultVars, + bool useDegrees = false); +</pre> + +<p>These functions work in the same way as the <code>Parse()</code> function, +but the variables in the input function string are deduced automatically. The +parameters are: + +<ul> + <li><code>function</code>: The input function string, as with + <code>Parse()</code>. + <li><code>amountOfVariablesFound</code>: If non-null, the amount of found + variables will be assigned here. + <li><code>resultVarString</code>: The found variables will be written to + this string, in the same format as accepted by the <code>Parse()</code> + function. The variable names will be sorted using the <code><</code> + operator of <code>std::string</code>. + <li><code>resultVars</code>: The found variables will be written to this + vector, each element being one variable name. They will be sorted using + the <code><</code> operator of <code>std::string</code>. (The amount + of found variables can be retrieved, rather obviously, with the + <code>size()</code> method of the vector.) + <li><code>useDegrees</code>: As with <code>Parse()</code>. +</ul> + +<p>As with <code>Parse()</code>, the return value will be <code>-1</code> if +the parsing succeeded, else an index to the location of the error. None of +the specified return values will be modified in case of error. + +<!-- -------------------------------------------------------------------- --> +<a name="functionobjects"></a> +<h3>Specialized function objects</h3> + +<p>The <code>AddFunction()</code> method can be used to add a new user-defined +function to the parser, its implementation being called through a C++ function +pointer. Sometimes this might not be enough, though. For example, one might +want to use <code>boost::function</code> or other similar specialized stateful +function objects instead of raw function pointers. This library provides a +mechanism to achieve this. + +<h4>Creating and adding a specialized function object</h4> + +<p>In order to create a specialized function object, create a class derived +from the <code>FunctionParser::FunctionWrapper</code> class. This class +declares a virtual function named <code>callFunction</code> that the derived +class must implement. For example: + +<pre> +class MyFunctionWrapper: + public FunctionParser::FunctionWrapper +{ + public: + virtual double callFunction(const double* values) + { + // Perform the actual function call here, like: + return someFunctionSomewhere(values); + + // In principle the result could also be + // calculated here, like for example: + return values[0] * values[0]; + } +}; +</pre> + +<p>You can then add an instance of this class to <code>FunctionParser</code> +using the <code>AddFunctionWrapper()</code> method, which works like +<code>AddFunction()</code>, but takes a wrapper object instead of a function +pointer as parameter. For example: + +<pre> +MyFunctionWrapper wrapper; +parser.AddFunctionWrapper("funcName", wrapper, 1); +</pre> + +<p>Note that <code>FunctionParser</code> will internally create a copy of +the wrapper object, managing the lifetime of this copy, and thus the object +given as parameter does not need to exist for as long as the +<code>FunctionParser</code> instance. Hence the above could also be written as: + +<pre> +parser.AddFunctionWrapper("funcName", MyFunctionWrapper(), 1); +</pre> + +<p>Note that this also means that the wrapper class must have a working +copy constructor. + +<p>Also note that if the <code>FunctionParser</code> instance is copied, all +the copies will share the same function wrapper objects given to the original. + +<h4>Retrieving specialized function objects</h4> + +<p>As noted, the library will internally make a copy of the wrapper object, +and thus it will be separate from the one which was given as parameter to +<code>AddFunctionWrapper()</code>. In some cases it may be necessary to +retrieve this wrapper object (for example to read or change its state). +This can be done with the <code>GetFunctionWrapper()</code> method, which +takes the name of the function and returns a pointer to the wrapper object, +or null if no such object exists with that name. + +<p>Note that the returned pointer will be of type +<code>FunctionParser::FunctionWrapper</code>. In order to get a pointer to +the actual derived type, the calling code should perform a +<code>dynamic_cast</code>, for example like this: + +<pre> +MyFunctionWrapper* wrapper = + dynamic_cast<MyFunctionWrapper*> + (parser.GetFunctionWrapper("funcName")); + +if(!wrapper) { /* oops, the retrieval failed */ } +else ... +</pre> + +<p>(Using dynamic cast rather than a static cast adds safety because if you +accidentally try to downcast to the wrong type, the pointer will become null.) + +<p>The calling code is free to modify the object in any way it wants, but it +must not delete it (because <code>FunctionParser</code> itself handles this). + + +<!-- -------------------------------------------------------------------- --> +<a name="base"></a> +<h3>FunctionParserBase</h3> + +<p>All the different parser types are derived from a templated base class +named <code>FunctionParserBase</code>. In normal use it's not necessary to +directly refer to this base class in the calling code. However, if the calling +code also needs to be templated (with respect to the numerical type), then +using <code>FunctionParserBase</code> directly is the easiest way to achieve +this. + +<p>For example, if you want to make a function that handles more than one +type of parser, it can be done like this: + +<pre> +template<typename Value_t> +void someFunction(FunctionParserBase<Value_t>& parser) +{ + // do something with 'parser' here +} +</pre> + +<p>Now it's convenient to call that function with more than one type of +parser, for example: + +<pre> +FunctionParser realParser; +FunctionParser_cd complexParser; + +someFunction(realParser); +someFunction(complexParser); +</pre> + +<p>Another example is a class that inherits from <code>FunctionParser</code> +which also wants to support different numerical types. Such class can be +declared as: + +<pre> +template<typename Value_t> +class SpecializedParser: public FunctionParserBase<Value_t> +{ + ... +}; +</pre> + + +<!-- -------------------------------------------------------------------- --> +<h2>Syntax</h2> + +<a name="literals"></a> +<h3>Numeric literals</h3> + +<p>A numeric literal is a fixed numerical value in the input function string + (either a floating point value or an integer value, depending on the parser + type). + +<p>An integer literal can consist solely of numerical digits (possibly with + a preceding unary minus). For example, "<code>12345</code>". + +<p>If the literal is preceded by the characters "<code>0x</code>", it + will be interpreted as a hexadecimal literal, where digits can also include + the letters from '<code>A</code>' to '<code>F</code>' (in either uppercase + or lowercase). For example, "<code>0x89ABC</code>" (which corresponds to the + value 563900). + +<p>A floating point literal (only supported by the floating point type parsers) + may additionally include a decimal point followed by the decimal part of the + value, such as for example "<code>12.34</code>", optionally followed by a + decimal exponent. + +<p>A decimal exponent consists of an '<code>E</code>' or '<code>e</code>', + followed by an optional plus or minus sign, followed by decimal digits, and + indicates multiplication by a power of 10. For example, "<code>1.2e5</code>" + (which is equivalent to the value 120000). + +<p>If a floating point literal is preceded by the characters "<code>0x</code>" + it will be interpreted in hexadecimal. A hexadecimal floating point + literal consists of a hexadecimal value, with an optional decimal point, + followed optionally by a binary exponent in base 10 (in other words, the + exponent is not in hexadecimal). + +<p>A binary exponent has the same format as a decimal exponent, except that + '<code>P</code>' or '<code>p</code>' is used. A binary exponent indicates + multiplication by a power of 2. For example, "<code>0xA.Bp10</code>" + (which is equivalent to the value 10944). + +<p>With the complex versions of the library, the imaginary part of a numeric + literal is written as a regular numeric literal with an '<code>i</code>' + appended, for example "<code>5i</code>". Note that when also specifying + the real part of a complex literal, parentheses should be used to avoid + precedence problems. (For example, "<code>(2+5i) * x</code>" + is not the same thing as "<code>2+5i * x</code>". The latter + would be equivalent to "<code>2 + (5i * x)</code>".) + +<a name="identifiers"></a> +<h3>Identifier names</h3> + +<p>An identifier is the name of a function (internal or user-defined), + variable, constant or unit. New identifiers can be specified with the + functions described in the earlier subsections in this document. + +<p>The name of an identifier can use any alphanumeric characters, the + underscore character and any UTF8-encoded unicode character, excluding + those denoting whitespace. + The first character of the name cannot be a numeric digit, though. + +<p>All functions, variables, constants and units must use unique names. + It's not possible to add two different identifiers with the same name. + + +<!-- -------------------------------------------------------------------- --> +<a name="functionsyntax"></a> +<h3>The function string syntax</h3> + +<p>The function string understood by the class is very similar (but not +completely identical in all aspects) to mathematical expressions in the +C/C++ languages. +Arithmetic float expressions can be created from float literals, variables +or functions using the following operators in this order of precedence: + +<p><table border=2> + <tr> + <td><code>()</code></td> + <td>expressions in parentheses first</td> + </tr><tr> + <td><code>A unit</code></td> + <td>a unit multiplier (if one has been added)</td> + </tr><tr> + <td><code>A^B</code></td> + <td>exponentiation (A raised to the power B)</td> + </tr><tr> + <td><code>-A</code></td> + <td>unary minus</td> + </tr><tr> + <td><code>!A</code></td> + <td>unary logical not (result is 1 if <code>int(A)</code> is 0, else 0)</td> + </tr><tr> + <td><code>A*B A/B A%B</code></td> + <td>multiplication, division and modulo</td> + </tr><tr> + <td><code>A+B A-B</code></td> + <td>addition and subtraction</td> + </tr><tr> + <td><code>A=B A<B A<=B<br>A!=B A>B A>=B</code></td> + <td>comparison between A and B (result is either 0 or 1)</td> + </tr><tr> + <td><code>A&B</code></td> + <td>result is 1 if <code>int(A)</code> and <code>int(B)</code> differ from + 0, else 0.<br> + Note: Regardless of the values, both operands are always + evaluated. However, if the expression is optimized, it may + be changed such that only one of the operands is evaluated, + according to standard shortcut logical operation semantics.</td> + </tr><tr> + <td><code>A|B</code></td> + <td>result is 1 if <code>int(A)</code> or <code>int(B)</code> differ from 0, + else 0.<br> + Note: Regardless of the values, both operands are always + evaluated. However, if the expression is optimized, it may + be changed such that only one of the operands is evaluated, + according to standard shortcut logical operation semantics.</td> + </tr> +</table> + +<p>(Note that currently the exponentiation operator is not supported for + <code>FunctionParser_li</code> nor <code>FunctionParser_gmpint</code>. + With the former the result would very easily overflow, making its + usefulness questionable. With the latter it could be easily abused to + make the program run out of memory; think of a function like + "10^10^10^100000".) + +<p>Since the unary minus has higher precedence than any other operator, for + example the following expression is valid: <code>x*-y</code> + +<p>The comparison operators use an epsilon value, so expressions which may +differ in very least-significant digits should work correctly. For example, +<code>"0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 1"</code> should always +return 1, and the same comparison done with "<code>></code>" or +"<code><</code>" should always return 0. (The epsilon value can be +configured in the <code>fpconfig.hh</code> file.) +Without epsilon this comparison probably returns the wrong value. + +<p>The class supports these functions: + +<p><table border=2> +<tr> + <td><code>abs(A)</code></td> + <td>Absolute value (magnitude) of A. + With real numbers, if A is negative, returns -A otherwise returns A. + With complex numbers, equivalent to <code>hypot(real(x),imag(x))</code>.</td> +</tr><tr> + <td><code>acos(A)</code></td> + <td>Arc-cosine of A. Returns the angle, measured in radians, whose cosine is A.</td> +</tr><tr> + <td><code>acosh(A)</code></td> + <td>Same as acos() but for hyperbolic cosine.</td> +</tr><tr> + <td><code>arg(A)</code></td> + <td>Phase angle of complex number A. Equivalent to <code>atan2(imag(x),real(x))</code>.</td> +</tr><tr> + <td><code>asin(A)</code></td> + <td>Arc-sine of A. Returns the angle, measured in radians, whose sine is A.</td> +</tr><tr> + <td><code>asinh(A)</code></td> + <td>Same as asin() but for hyperbolic sine.</td> +</tr><tr> + <td><code>atan(A)</code></td> + <td>Arc-tangent of (A). Returns the angle, measured in radians, + whose tangent is A.</td> +</tr><tr> + <td><code>atan2(A,B)</code></td> + <td>Principal arc-tangent of A/B, using the signs of the + two arguments to determine the quadrant of the result. + Returns the solution to the two expressions + hypot(A,B)*sin(x)=A, hypot(A,B)*cos(x)=B. + The return value is in range -pi to pi, inclusive.</td> +</tr><tr> + <td><code>atanh(A)</code></td> + <td>Same as atan() but for hyperbolic tangent.</td> +</tr><tr> + <td><code>cbrt(A)</code></td> + <td>Cube root of A. Returns a solution to expression pow(x,3)=A.</td> +</tr><tr> + <td><code>conj(A)</code></td> + <td>Complex conjugate of A. Equivalent to <code>real(x) - 1i*imag(x)</code> or <code>polar(abs(x),-arg(x))</code>.</td> +</tr><tr> + <td><code>ceil(A)</code></td> + <td>Ceiling of A. Returns the smallest integer not smaller than A. + Rounds up to the next higher integer. E.g. -2.9, -2.5 and -2.1 are + rounded to -2.0, and 2.9, 2.5 and 2.1 are rounded to 3.0.</td> +</tr><tr> + <td><code>cos(A)</code></td> + <td>Cosine of A. Returns the cosine of the angle A, where A is + measured in radians.</td> +</tr><tr> + <td><code>cosh(A)</code></td> + <td>Same as cos() but for hyperbolic cosine.</td> +</tr><tr> + <td><code>cot(A)</code></td> + <td>Cotangent of A. Equivalent to <code>1/tan(A)</code>.</td> +</tr><tr> + <td><code>csc(A)</code></td> + <td>Cosecant of A. Equivalent to <code>1/sin(A)</code>.</td> +</tr><tr> + <td><code>eval(...)</code></td> + <td>This a recursive call to the function to be evaluated. The + number of parameters must be the same as the number of parameters + taken by the function. Must be called inside <code>if()</code> to avoid + infinite recursion.</td> +</tr><tr> + <td><code>exp(A)</code></td> + <td>Exponential of A. Returns the value of e raised to the power + A where e is the base of the natural logarithm, i.e. the + non-repeating value approximately equal to 2.71828182846.</td> +</tr><tr> + <td><code>exp2(A)</code></td> + <td>Base 2 exponential of A. Equivalent to <code>pow(2,A)</code>.</td> +</tr><tr> + <td><code>floor(A)</code></td> + <td>Floor of A. Returns the largest integer not greater than A. Rounds + down to the next lower integer. + E.g. -2.9, -2.5 and -2.1 are rounded to -3.0, + and 2.9, 2.5 and 2.1 are rounded to 2.0.</td> +</tr><tr> + <td><code>hypot(A,B)</code></td> + <td>Euclidean distance function. Equivalent to <code>sqrt(A^2+B^2)</code>.</td> +</tr><tr> + <td><code>if(A,B,C)</code></td> + <td>If int(A) differs from 0, the return value of this function is B, + else C. Only the parameter which needs to be evaluated is + evaluated, the other parameter is skipped; this makes it safe to + use <code>eval()</code> in them.</td> +</tr><tr> + <td><code>imag(A)</code></td> + <td>Return the imaginary part of complex number A. Equivalent to <code>abs(A)*sin(arg(A))</code>.</td> +</tr><tr> + <td><code>int(A)</code></td> + <td>Rounds A to the closest integer. Equidistant values are rounded away from + zero. E.g. -2.9 and -2.5 are rounded to -3.0; -2.1 is rounded to -2.0, + and 2.9 and 2.5 are rounded to 3.0; 2.1 is rounded to 2.0.</td> +</tr><tr> + <td><code>log(A)</code></td> + <td>Natural (base e) logarithm of A. Returns the solution to expression exp(x)=A.</td> +</tr><tr> + <td><code>log2(A)</code></td> + <td>Base 2 logarithm of A. Equivalent to <code>log(A)/log(2)</code>.</td> +</tr><tr> + <td><code>log10(A)</code></td> + <td>Base 10 logarithm of A.</td> +</tr><tr> + <td><code>max(A,B)</code></td> + <td>If A>B, the result is A, else B.</td> +</tr><tr> + <td><code>min(A,B)</code></td> + <td>If A<B, the result is A, else B.</td> +</tr><tr> + <td><code>polar(A,B)</code></td> + <td>Returns a complex number from magnitude A, phase angle B (in radians). + Equivalent to <code>real(A)*(cos(real(B))+1i*sin(real(B)))</code>.</td> +</tr><tr> + <td><code>pow(A,B)</code></td> + <td>Exponentiation (A raised to the power B).</td> +</tr><tr> + <td><code>real(A)</code></td> + <td>Return the real part of complex number A. Equivalent to <code>abs(A)*cos(arg(A))</code>.</td> +</tr><tr> + <td><code>sec(A)</code></td> + <td>Secant of A. Equivalent to <code>1/cos(A)</code>.</td> +</tr><tr> + <td><code>sin(A)</code></td> + <td>Sine of A. Returns the sine of the angle A, where A is + measured in radians.</td> +</tr><tr> + <td><code>sinh(A)</code></td> + <td>Same as sin() but for hyperbolic sine.</td> +</tr><tr> + <td><code>sqrt(A)</code></td> + <td>Square root of A. Returns a solution to expression pow(x,2)=A.</td> +</tr><tr> + <td><code>tan(A)</code></td> + <td>Tangent of A. Returns the tangent of the angle A, where A + is measured in radians.</td> +</tr><tr> + <td><code>tanh(A)</code></td> + <td>Same as tan() but for hyperbolic tangent.</td> +</tr><tr> + <td><code>trunc(A)</code></td> + <td>Truncated value of A. Returns an integer corresponding to the value + of A without its fractional part. + E.g. -2.9, -2.5 and -2.1 are rounded to -2.0, + and 2.9, 2.5 and 2.1 are rounded to 2.0.</td> +</tr> +</table> + +<p>(Note that for <code>FunctionParser_li</code> and + <code>FunctionParser_gmpint</code> only the functions + <code>abs()</code>, <code>eval()</code>, <code>if()</code>, + <code>min()</code> and <code>max()</code> are supported.) + +<p>Examples of function string understood by the class: + +<p><code>"1+2"</code><br> +<code>"x-1"</code><br> +<code>"-sin(sqrt(x^2+y^2))"</code><br> +<code>"sqrt(XCoord*XCoord + YCoord*YCoord)"</code><br> + +<p>An example of a recursive function is the factorial function: + +<code>"if(n>1, n*eval(n-1), 1)"</code> + +<p>Note that a recursive call has some overhead, which makes it a bit slower + than any other operation. It may be a good idea to avoid recursive functions + in very time-critical applications. Recursion also takes some memory, so + extremely deep recursions should be avoided (eg. millions of nested recursive + calls). + +<p>Also note that even though the maximum recursion level of +<code>eval()</code> is limited, it is possible to write functions which +never reach that level but still take enormous amounts of time to evaluate. +This can sometimes be undesirable because it is prone to exploitation, +which is why <code>eval()</code> is disabled by default. It can be enabled +in the <code>fpconfig.hh</code> file. + + +<!-- -------------------------------------------------------------------- --> +<a name="inlinevars"></a> +<h3>Inline variables</h3> + +<p>The function syntax supports defining new variables inside the function +string itself. This can be done with the following syntax: + +<p><code>"<variable name> := <expression>; <function>"</code> + +<p>For example: + +<p><code>"length := sqrt(x*x+y*y); 2*length*sin(length)"</code> + +<p>(Spaces around the '<code>:=</code>' operator are optional.) + +<p>The obvious benefit of this is that if a long expression needs to be +used in the function several times, this allows writing it only once and +using a named variable from that point forward. + +<p>The variable name must be an unused identifier (in other words, not an +existing function, variable or unit name). + +<p>The <code><function></code> part can have further inline variable +definitions, and thus it's possible to have any amount of them, for example: + +<p><code>"A := x^2; B := y^2; C := z^2; sqrt(A+B+C)"</code> + +<p>The expressions in subsequent inline variable definitions can use any +of the previous inline variables. It is also possible to redefine an inline +variable. For example: + +<p><code>"A := x^2; A := 2*A; sqrt(A)"</code> + + +<!-- -------------------------------------------------------------------- --> +<a name="whitespace"></a> +<h3>Whitespace</h3> + +<p>Arbitrary amounts of whitespace can optionally be included between + elements in the function string. + The following unicode characters are interpreted as whitespace: +<table> + <tr> + <th>Character number</th> + <th>Character name</th> + <th>UTF-8 byte sequence</th> + </tr> + <tr><td>U+0009</td><td>HORIZONTAL TABULATION </td><td>09</td></tr> + <tr><td>U+000A</td><td>LINE FEED </td><td>0A</td></tr> + <tr><td>U+000B</td><td>VERTICAL TABULATION </td><td>0B</td></tr> + <tr><td>U+000D</td><td>CARRIAGE RETURN </td><td>0D</td></tr> + <tr><td>U+0020</td><td>SPACE </td><td>20</td></tr> + <tr><td>U+00A0</td><td>NO-BREAK SPACE </td><td>C2 A0</td></tr> + <tr><td>U+2000</td><td>EN QUAD </td><td>E2 80 80</td></tr> + <tr><td>U+2001</td><td>EM QUAD </td><td>E2 80 81</td></tr> + <tr><td>U+2002</td><td>EN SPACE </td><td>E2 80 82</td></tr> + <tr><td>U+2003</td><td>EM SPACE </td><td>E2 80 83</td></tr> + <tr><td>U+2004</td><td>THREE-PER-EM SPACE </td><td>E2 80 84</td></tr> + <tr><td>U+2005</td><td>FOUR-PER-EM SPACE </td><td>E2 80 85</td></tr> + <tr><td>U+2006</td><td>SIX-PER-EM SPACE </td><td>E2 80 86</td></tr> + <tr><td>U+2007</td><td>FIGURE SPACE </td><td>E2 80 87</td></tr> + <tr><td>U+2008</td><td>PUNCTUATION SPACE </td><td>E2 80 88</td></tr> + <tr><td>U+2009</td><td>THIN SPACE </td><td>E2 80 89</td></tr> + <tr><td>U+200A</td><td>HAIR SPACE </td><td>E2 80 8A</td></tr> + <tr><td>U+200B</td><td>ZERO WIDTH SPACE </td><td>E2 80 8B</td></tr> + <tr><td>U+202F</td><td>NARROW NO-BREAK SPACE </td><td>E2 80 AF</td></tr> + <tr><td>U+205F</td><td>MEDIUM MATHEMATICAL SPACE</td><td>E2 81 9F</td></tr> + <tr><td>U+3000</td><td>IDEOGRAPHIC SPACE </td><td>E3 80 80</td></tr> +</table> + +<!-- -------------------------------------------------------------------- --> +<h2>Miscellaneous</h2> + +<a name="fpaccuracy"></a> +<h3>About floating point accuracy</h3> + +<p>Note that if you are using <code>FunctionParser_ld</code> or +<code>FunctionParser_cld</code> and you want calculations to be as accurate +as the <code>long double</code> type allows, you should pay special attention +to floating point literals in your own code. For example, this is a very +typical mistake: + +<pre>FunctionParser_ld parser; +parser.AddConstant("pi", 3.14159265358979323846);</pre> + +<p>The mistake might not be immediately apparent. The mistake is that a +literal of type <code>double</code> is passed to the <code>AddConstant()</code> +function even though it expects a value of type <code>long double</code>. +In most systems the latter has more bits of precision than the former, which +means that the value will have its least-significant bits clipped, +introducing a rounding error. The proper way of making the above calls is: + +<pre>FunctionParser_ld parser; +parser.AddConstant("pi", 3.14159265358979323846L);</pre> + +<p>The same principle should be used everywhere in your own code, if you are +using the <code>long double</code> type. + +<p>This is especially important if you are using the <code>MpfrFloat</code> +type (in which case its string-parsing constructor or its +<code>ParseValue()</code> or <code>parseString()</code> member functions +should be used instead of using numerical literals). + +<a name="evaluationchecks"></a> +<h3>About evaluation-time checks</h3> + +<p><code>FunctionParser::Eval()</code> will perform certain sanity +checks before performing certain operations. For example, before calling the +<code>sqrt</code> function, it will check if the parameter is negative, and +if so, it will set the proper error code instead of calling the function. +These checks include: + +<ul> + <li>Division by (the exact value of) zero. + <li>Square root of a negative value. + <li>Logarithm of a non-positive value. + <li>Arcsine or arccosine of a value not in the range [-1, 1]. (This includes + hyperbolic versions of the functions.) +</ul> + +<p>However, the library <em>can not</em> guarantee that it will catch all +possible floating point errors before performing them, because this is +impossible to do with standard C++. For example, dividing a very large +value by a value which is very close to zero, or calculating the logarithm +of a very small value may overflow the result, as well as multiplying two +very large values. Raising a negative number to a non-integral power may +cause a <em>NaN</em> result, etc. + +<p>As a rule of thumb, the library will (by default) detect invalid operations +if they are invalid for a range of values. For example, square root is undefined +for all negative values, and arc sine is undefined only values outside the range +[-1, 1]. In general, operations which are invalid for only one single value +(rather than a contiguous range of values) will not be detected (division by +the exact value of zero is an exception to this rule) nor will +overflow/underflow situations. + +<p>The library cannot guarantee that floating point +errors will never happen during evaluation. This can make the library to +return the floating point values <em>inf</em> and <em>NaN</em>. Moreover, +if floating point errors cause an interrupt in the target computer +architecture and/or when using certain compiler settings, this library +cannot guarantee that it will never happen. + +<p>Note that the optimizer never performs any sanity checks. + + +<!-- -------------------------------------------------------------------- --> +<a name="threadsafety"></a> +<h3>About thread safety</h3> + +<p>None of the member functions of the FunctionParser class are thread-safe. +Most prominently, the <code>Eval()</code> function is not thread-safe. +(In other words, the <code>Eval()</code> function of a single FunctionParser +instance cannot be safely called simultaneously by two threads.) + +<p>There are ways to use this library in a thread-safe way, though. If each +thread uses its own FunctionParser instance, no problems will obviously +happen. Note, however, that if these instances need to be a copy of a given +FunctionParser instance (eg. one where the user has entered a function), +a deep copy of this instance has to be performed for each thread. By +default FunctionParser uses shallow-copying (copy-on-write), which means +that a simple assignment of copy construction will not copy the data itself. +To force a deep copy you can all the <code>ForceDeepCopy()</code> function on +each of the instances of each thread after the assignment or copying has been +done. + +<p>Another possibility is to compile the FunctionParser library so that +its <code>Eval()</code> function will be thread-safe. (This can be done by +defining the <code>FP_USE_THREAD_SAFE_EVAL</code> or the +<code>FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA</code> +precompiler constant.) As long as only one thread calls the other functions +of FunctionParser, the other threads can safely call the <code>Eval()</code> +of this one instance. + +<p>Note, however, that compiling the library like this can make +<code>Eval()</code> slightly slower. (The <code>alloca</code> version, if +supported by the compiler, will not be as slow.) + +<p>Also note that the MPFR and GMP versions of the library cannot be + made thread-safe, and thus this setting has no effect on them. + + +<!-- -------------------------------------------------------------------- --> +<a name="tipsandtricks"></a> +<h3>Tips and tricks</h3> + +<h4>Add constants automatically to all parser objects</h4> + +<p>Often the same constants (such as <em>pi</em> and <em>e</em>) and other +user-defined identifiers (such as units) are always used in all the +<code>FunctionParser</code> objects throughout the program. It would be +troublesome to always have to manually add these constants every time a +new parser object is created. + +<p>There is, however, a simple way to always add these user-defined identifiers +to all instances. Write a class like this: + +<pre> + class ParserWithConsts: public FunctionParser + { + public: + ParserWithConsts() + { + AddConstant("pi", 3.14159265358979323846); + AddConstant("e", 2.71828182845904523536); + } + }; +</pre> + +<p>Now instead of using <code>FunctionParser</code>, always use +<code>ParserWithConsts</code>. It will behave identically except that the +constants (and possibly other user-defined identifiers) will always be +automatically defined. (Objects of this type even survive +<a href="http://en.wikipedia.org/wiki/Object_slicing">slicing</a>, so +they are completely safe to use anywhere.) + + +<!-- -------------------------------------------------------------------- --> +<a name="contact"></a> +<h3>Contacting the author</h3> + +<p>Any comments, bug reports, etc. should be sent to warp@iki.fi + + +<!-- -------------------------------------------------------------------- --> +<!-- +<a name="algorithm"></a> +<h2>The algorithm used in the library</h2> + +<p>The whole idea behind the algorithm is to convert the regular infix +format (the regular syntax for mathematical operations in most languages, +like C and the input of the library) to postfix format. The postfix format +is also called stack arithmetic since an expression in postfix format +can be evaluated using a stack and operating with the top of the stack. + +<p>For example: + +<p><table border=2> +<tr><th>infix</th> <th>postfix</th></tr> +<tr><td><code>2+3</code></td><td><code>2 3 +</code></td></tr> +<tr><td><code>1+2+3</code></td><td><code>1 2 + 3 +</code></td></tr> +<tr><td><code>5*2+8/2</code></td><td><code>5 2 * 8 2 / +</code></td></tr> +<tr><td><code>(5+9)*3</code></td><td><code>5 9 + 3 *</code></td></tr> +</table> + +<p>The postfix notation should be read in this way: + +<p>Let's take for example the expression: <code>5 2 * 8 2 / +</code> +<ul> + <li>Put 5 on the stack + <li>Put 2 on the stack + <li>Multiply the two values on the top of the stack and put the result on + the stack (removing the two old values) + <li>Put 8 on the stack + <li>Put 2 on the stack + <li>Divide the two values on the top of the stack + <li>Add the two values on the top of the stack (which are in this case + the result of 5*2 and 8/2, that is, 10 and 4). +</ul> + +<p>At the end there's only one value in the stack, and that value is the +result of the expression. + +<p>Why stack arithmetic? + +<p>The last example above can give you a hint. + In infix format operators have precedence and we have to use parentheses to +group operations with lower precedence to be calculated before operations +with higher precedence. + This causes a problem when evaluating an infix expression, specially +when converting it to byte code. For example in this kind of expression: + <code>(x+1)/(y+2)</code> +we have to calculate first the two additions before we can calculate the +division. We have to also keep counting parentheses, since there can be +a countless amount of nested parentheses. This usually means that you +have to do some type of recursion. + +<p>The simplest and mostefficient way of calculating this is to convert it +to postfix notation. + The postfix notation has the advantage that you can make all operations +in a straightforward way. You just evaluate the expression from left to +right, applying each operation directly and that's it. There are no +parentheses to worry about. You don't need recursion anywhere. + You have to keep a stack, of course, but that's extremely easily done. +Also you just operate with the top of the stack, which makes it very easy. +You never have to go deeper than 2 items in the stack. + And even better: Evaluating an expression in postfix format is never +slower than in infix format. All the contrary, in many cases it's a lot +faster (eg. because all parentheses are optimized away). + The above example could be expressed in postfix format: + <code>x 1 + y 2 + /</code> + +<p>The good thing about the postfix notation is also the fact that it can +be extremely easily expressed in bytecode form. + You only need a byte value for each operation, for each variable and +to push a constant to the stack. + Then you can interpret this bytecode straightforwardly. You just interpret +it byte by byte, from the beginning to the end. You never have to go back, +make loops or anything. + +<p>This is what makes byte-coded stack arithmetic so fast. +--> + + +<!-- -------------------------------------------------------------------- --> +<a name="license"></a> +<h2>Usage license</h2> + +<p>Copyright © 2003-2011 Juha Nieminen, Joel Yliluoma + +<p>This Library is distributed under the + <a href="http://www.gnu.org/copyleft/lesser.html">Lesser General Public + License</a> (LGPL) version 3. + +</body> +</html> diff --git a/docs/gpl.txt b/docs/gpl.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/docs/gpl.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/docs/lgpl.txt b/docs/lgpl.txt new file mode 100644 index 0000000..cca7fc2 --- /dev/null +++ b/docs/lgpl.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/docs/style.css b/docs/style.css new file mode 100644 index 0000000..d5141d3 --- /dev/null +++ b/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/examples/example.cc b/examples/example.cc new file mode 100644 index 0000000..b4ab5f4 --- /dev/null +++ b/examples/example.cc @@ -0,0 +1,55 @@ +// Simple example file for the function parser
+// ===========================================
+
+/* When running the program, try for example with these values:
+
+f(x) = x^2
+min x: -5
+max x: 5
+step: 1
+
+*/
+
+#include "../fparser.hh"
+
+#include <iostream>
+#include <string>
+
+int main()
+{
+ std::string function;
+ double minx, maxx, step;
+ FunctionParser fparser;
+
+ fparser.AddConstant("pi", 3.1415926535897932);
+
+ while(true)
+ {
+ std::cout << "f(x) = ";
+ std::getline(std::cin, function);
+ if(std::cin.fail()) return 0;
+
+ int res = fparser.Parse(function, "x");
+ if(res < 0) break;
+
+ std::cout << std::string(res+7, ' ') << "^\n"
+ << fparser.ErrorMsg() << "\n\n";
+ }
+
+ std::cout << "min x: ";
+ std::cin >> minx;
+ std::cout << "max x: ";
+ std::cin >> maxx;
+ std::cout << "step: ";
+ std::cin >> step;
+ if(std::cin.fail()) return 0;
+
+ double vals[] = { 0 };
+ for(vals[0] = minx; vals[0] <= maxx; vals[0] += step)
+ {
+ std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals)
+ << std::endl;
+ }
+
+ return 0;
+}
diff --git a/examples/example2.cc b/examples/example2.cc new file mode 100644 index 0000000..958b9a1 --- /dev/null +++ b/examples/example2.cc @@ -0,0 +1,85 @@ +// Simple example file for the function parser +// =========================================== +/* Note that the library has to be compiled with + FP_SUPPORT_FLOAT_TYPE, FP_SUPPORT_LONG_DOUBLE_TYPE and + FP_SUPPORT_LONG_INT_TYPE + preprocessor macros defined for this example to work. + + Try with these input values with the different floating point parser + types to see the difference in accuracy: + +f(x) = x + 1.234567890123456789 +min x: 0 +max x: 2 +step: 1 +*/ + +#include "../fparser.hh" + +#include <iostream> +#include <iomanip> +#include <string> + +template<typename Parser> +void runExample(const char* valueTypeName) +{ + typedef typename Parser::value_type Value_t; + + std::cout << "Using " << valueTypeName << " parser." << std::endl; + + Parser fparser; + std::string function; + Value_t minx, maxx, step; + + fparser.AddConstant("pi", Value_t(3.1415926535897932)); + + std::cin.ignore(); + while(true) + { + std::cout << "f(x) = "; + std::getline(std::cin, function); + if(std::cin.fail()) return; + + int res = fparser.Parse(function, "x"); + if(res < 0) break; + + std::cout << std::string(res+7, ' ') << "^\n" + << fparser.ErrorMsg() << "\n\n"; + } + + std::cout << "min x: "; + std::cin >> minx; + std::cout << "max x: "; + std::cin >> maxx; + std::cout << "step: "; + std::cin >> step; + if(std::cin.fail()) return; + + Value_t vals[] = { 0 }; + for(vals[0] = minx; vals[0] <= maxx; vals[0] += step) + { + std::cout << std::setprecision(20); + std::cout << "f(" << vals[0] << ") = " << fparser.Eval(vals) + << std::endl; + } +} + +int main() +{ + int choice = 0; + do + { + std::cout << "1 = double, 2 = float, 3 = long double, 4 = long int: "; + std::cin >> choice; + } while(choice < 1 || choice > 4); + + switch(choice) + { + case 1: runExample<FunctionParser>("double"); break; + case 2: runExample<FunctionParser_f>("float"); break; + case 3: runExample<FunctionParser_ld>("long double"); break; + case 4: runExample<FunctionParser_li>("long int"); break; + } + + return 0; +} diff --git a/extrasrc/fp_identifier_parser.inc b/extrasrc/fp_identifier_parser.inc new file mode 100644 index 0000000..7489fd0 --- /dev/null +++ b/extrasrc/fp_identifier_parser.inc @@ -0,0 +1,379 @@ +/* NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + Part of this file is generated code (by using the make_function_name_parser +utility, found in the development version of this library). It's not intended +to be modified by hand. +*/ + + unsigned nameLength = 0; + const unsigned maximumNameLength = 0x80000000U-8; + /* + Due to the manner the identifier lengths are returned from + the readOpcode() function, the maximum supported length for + identifiers is 0x7FFFFFFF bytes. We minus 8 here to add some + buffer, because of the multibyteness of UTF-8. + Function names are limited to 0xFFFF bytes instead, but because + function names that long just are not defined, the point is moot. + */ + const unsigned char* const uptr = (const unsigned char*) input; + typedef signed char schar; + while(likely(nameLength < maximumNameLength)) + { + unsigned char byte = uptr[nameLength+0]; + /* Handle the common case of A-Za-z first */ + if(byte >= 0x40) + { + if(byte < 0x80) // 0x40..0x7F - most common case + { + // Valid characters in 40..7F: A-Za-z_ + // Valid bitmask for 40..5F: 01111111111111111111111111100001 + // Valid bitmask for 60..7F: 01111111111111111111111111100000 + if(sizeof(unsigned long) == 8) + { + const unsigned n = sizeof(unsigned long)*8-32; + // ^ avoids compiler warning when not 64-bit + unsigned long masklow6bits = 1UL << (byte & 0x3F); + if(masklow6bits & ~((1UL << 0) | (0x0FUL << (0x1B )) + | (1UL << n) | (0x1FUL << (0x1B+n)))) + { ++nameLength; continue; } + } + else + { + unsigned masklow5bits = 1 << (byte & 0x1F); + if((masklow5bits & ~(1 | (0x1F << 0x1B))) || byte == '_') + { ++nameLength; continue; } + } + break; + } + if(byte < 0xF0) + { + if(byte < 0xE0) + { + if(byte < 0xC2) break; // 0x80..0xC1 + if(byte == 0xC2 && uptr[nameLength+1]==0xA0) break; // skip nbsp + // C2-DF - next common case when >= 0x40 + // Valid sequence: C2-DF 80-BF + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + nameLength += 2; + continue; + } + if(byte == 0xE0) // E0 + { + // Valid sequence: E0 A0-BF 80-BF + if((unsigned char)(uptr[nameLength+1] - 0xA0) > (0xBF-0xA0)) break; + } + else + { + if(byte == 0xED) break; // ED is invalid + // Valid sequence: E1-EC 80-BF 80-BF + // And: EE-EF 80-BF 80-BF + if(byte == 0xE2) + { + // break on various space characters + if(uptr[nameLength+1] == 0x80 + && (schar(uptr[nameLength+2]) <= schar(0x8B) + || (uptr[nameLength+2] == 0xAF))) break; + if(uptr[nameLength+1] == 0x81 + && uptr[nameLength+2] == 0x9F) break; + } else + if(byte == 0xE3 && uptr[nameLength+1] == 0x80 + && uptr[nameLength+2] == 0x80) break; // this too + + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + } + if(schar(uptr[nameLength+2]) > schar(0xBF)) break; + nameLength += 3; + continue; + } + if(byte == 0xF0) // F0 + { + // Valid sequence: F0 90-BF 80-BF 80-BF + if((unsigned char)(uptr[nameLength+1] - 0x90) > (0xBF-0x90)) break; + } + else + { + if(byte > 0xF4) break; // F5-FF are invalid + if(byte == 0xF4) // F4 + { + // Valid sequence: F4 80-8F + if(schar(uptr[nameLength+1]) > schar(0x8F)) break; + } + else + { + // F1-F3 + // Valid sequence: F1-F3 80-BF 80-BF 80-BF + if(schar(uptr[nameLength+1]) > schar(0xBF)) break; + } + } + if(schar(uptr[nameLength+2]) > schar(0xBF)) break; + if(schar(uptr[nameLength+3]) > schar(0xBF)) break; + nameLength += 4; + continue; + } + if(nameLength > 0) + { + if(sizeof(unsigned long) == 8) + { + // Valid bitmask for 00..1F: 00000000000000000000000000000000 + // Valid bitmask for 20..3F: 00000000000000001111111111000000 + const unsigned n = sizeof(unsigned long)*8-32; + // ^ avoids compiler warning when not 64-bit + unsigned long masklow6bits = 1UL << byte; + if(masklow6bits & (((1UL << 10)-1UL) << (16+n))) + { ++nameLength; continue; } + } + else + { + if(byte >= '0' && byte <= '9') + { ++nameLength; continue; } + } + } + break; + } + + /* This function generated with make_function_name_parser.cc */ +#define lO l3 lH +#define lN switch( +#define lM l4 lH +#define lL if('i' l5 +#define lK 'n' l5 +#define lJ 0x80000003U; +#define lI l1 3]={ +#define lH case +#define lG 0x80000005U; +#define lF )==0)l0( +#define lE l8 3;}lH +#define lD std::memcmp(uptr+ +#define lC l2 3 lF +#define lB lA 1]){lH +#define lA :lN uptr[ +#define l9 'a' lB +#define l8 default:l0 +#define l7 lG l0 5;}lH +#define l6 <<16)| +#define l5 ==uptr[ +#define l4 lJ l0 3; +#define l3 0x80000004U;l0 4; +#define l2 lD 1,tmp, +#define l1 static const char tmp[ +#define l0 return +lN +nameLength){lH +2:lL +0]&&'f' l5 +1])l0(cIf +l6 +0x80000002U;l0 +2;lH +3 +lA +0]){lH +l9'b':if('s' l5 +2])l0(cAbs +l6 +lM'r':if('g' l5 +2])l0(cArg +l6 +l4 +lE'c' lB'o' lA +2]){lH's':l0(cCos +l6 +lJ +lH't':l0(cCot +l6 +lJ +lE's':if('c' l5 +2])l0(cCsc +l6 +l4 +lE'e':if('x' l5 +1]&&'p' l5 +2])l0(cExp +l6 +lM'i':if(lK +1]&&'t' l5 +2])l0(cInt +l6 +lM'l':if('o' l5 +1]&&'g' l5 +2])l0(cLog +l6 +lM'm' lB'a':if('x' l5 +2])l0(cMax +l6 +lM'i':if(lK +2])l0(cMin +l6 +l4 +lE'p':if('o' l5 +1]&&'w' l5 +2])l0(cPow +l6 +lM's' lB'e':if('c' l5 +2])l0(cSec +l6 +lM'i':if(lK +2])l0(cSin +l6 +l4 +lE't':if('a' l5 +1]&&lK +2])l0(cTan +l6 +l4 +lE +4 +lA +0]){lH +l9'c':if('o' l5 +2]&&'s' l5 +3])l0(cAcos +l6 +lO's':lL +2]&&lK +3])l0(cAsin +l6 +lO't':if('a' l5 +2]&&lK +3])l0(cAtan +l6 +l3 +l8 +4;} +lH'c' lB'b':if('r' l5 +2]&&'t' l5 +3])l0(cCbrt +l6 +lO'e':lL +2]&&'l' l5 +3])l0(cCeil +l6 +lO'o' lA +2]){lH'n':if('j' l5 +3])l0(cConj +l6 +lO's':if('h' l5 +3])l0(cCosh +l6 +l3 +l8 +4;} +l8 +4;} +lH'e':{lI'x','p','2'} +;if(lC +cExp2 +l6 +l3} +lH'i':{lI'm','a','g'} +;if(lC +cImag +l6 +l3} +lH'l':{lI'o','g','2'} +;if(lC +cLog2 +l6 +l3} +lH'r':{lI'e','a','l'} +;if(lC +cReal +l6 +l3} +lH's' lB'i':if(lK +2]&&'h' l5 +3])l0(cSinh +l6 +lO'q':if('r' l5 +2]&&'t' l5 +3])l0(cSqrt +l6 +l3 +l8 +4;} +lH't':{lI'a','n','h'} +;if(lC +cTanh +l6 +l3} +l8 +4;} +lH +5 +lA +0]){lH +l9'c':{lI'o','s','h'} +;if(lD +2,tmp,3 +lF +cAcosh +l6 +l7's':{lI'i','n','h'} +;if(lD +2,tmp,3 +lF +cAsinh +l6 +l7't':if('a' l5 +2]){if(lK +3]){lN +uptr[4]){lH'2':l0(cAtan2 +l6 +lG +lH'h':l0(cAtanh +l6 +lG +l8 +5;} +} +l0 +5;} +l0 +5;l8 +5;} +lH'f':{l1 +4]={'l','o','o','r'} +;if(l2 +4 +lF +cFloor +l6 +l7'h':{l1 +4]={'y','p','o','t'} +;if(l2 +4 +lF +cHypot +l6 +l7'l':{l1 +4]={'o','g','1','0'} +;if(l2 +4 +lF +cLog10 +l6 +l7'p':{l1 +4]={'o','l','a','r'} +;if(l2 +4 +lF +cPolar +l6 +l7't':{l1 +4]={'r','u','n','c'} +;if(l2 +4 +lF +cTrunc +l6 +lG +l0 +5;} +l8 +5;} +default:break;} +l0 +nameLength; diff --git a/extrasrc/fp_opcode_add.inc b/extrasrc/fp_opcode_add.inc new file mode 100644 index 0000000..331ef49 --- /dev/null +++ b/extrasrc/fp_opcode_add.inc @@ -0,0 +1,7696 @@ +/* Function Parser for C++ v4.5.2 + + NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + This file contains generated code and is thus not intended to be to +be modified by hand. It was generated by util/bytecoderules_parser, which +is available in the development package. +*/ +#define HasInvalidRangesOpcode HasInvalidRangesOpcode<IsComplexType<Value_t>::result> +#define FP_TRACE_BYTECODE_OPTIMIZATION(srcline,from,to,with) \ + /*std::cout << "Changing \"" from "\"\t(line " #srcline ")\n" \ + " into \"" to "\"\n" with << std::flush*/ +#define FP_TRACE_OPCODENAME(op) \ + (op < VarBegin \ + ? FP_GetOpcodeName(OPCODE(op)) \ + : findName(mData->mNamePtrs,op,NameData<Value_t>::VARIABLE)) +#define FP_TRACE_BYTECODE_ADD(opcode) \ + /*std::cout << "Adding opcode: " << FP_TRACE_OPCODENAME(opcode) \ + << ", bytecode length " << data->ByteCode.size() \ + << ", pointer is " << (void*)ByteCodePtr \ + << ", code is " << (data->ByteCode.empty() \ + ? (void*)0 \ + : (void*)&data->ByteCode[0]) \ + << std::endl*/ +#define qH1 " B" mF +#define qG1 gT y*x; +#define qF1 hV 2;qI +#define qE1 <<"," aD +#define qD1 <<"," aB +#define qC1 "cNeg" +#define qB1 wA"," aD +#define qA1 "x[x!=Value_t(0)] " +#define q91 <<"," a8 +#define q81 wA"," a1 +#define q71 );qW q6 +#define q61 "cPow " +#define q51 "cSqrt" +#define q41 "cSqr " +#define q31 " cExp2" +#define q21 "cExp " +#define q11 ){hD wB +#define q01 "cCeil" +#define mZ "cImag" +#define mY "cConj" +#define mX "cDup " +#define mW hO wB +#define mV "cAbs" +#define mU wQ wH" " +#define mT qS w2 wB +#define mS "cFloor" +#define mR "cTan" +#define mQ " cDup" +#define mP "cSin" +#define mO (y hX; +#define mN "[ y+x]" +#define mM hV 2 gC +#define mL " cExp" +#define mK "A " wX +#define mJ "cLess" +#define mI "[-x]" wH +#define mH "cDiv" a7 +#define mG "cLog" +#define mF " cDiv" +#define mE " " a6 +#define mD " " aF +#define mC "cMin" +#define mB "cMax" +#define mA aY"x " +#define m9 gN wB +#define m8 "x cPow" +#define m7 g1 oG wB +#define m6 (x);gJ +#define m5 "B cSqr" +#define m4 oH dE wB +#define m3 "[y*x]" wH +#define m2 "cGreater" +#define m1 mV" " wL +#define m0 "cNeg " +#define aZ " cAdd" +#define aY "y " +#define aX "B[IsVarOpcode(B)] " +#define aW " cSub" +#define aV gY if(dO wB +#define aU "cInv" +#define aT mX aU +#define aS "cAbsNot" +#define aR "cLessOrEq" +#define aQ "cAdd " q51 +#define aP "[y*x] cPow" +#define aO "cCos" +#define aN "cLog2" +#define aM "cCosh" +#define aL "cLog10" +#define aK "B[B==A]" +#define aJ "cNotNot" +#define aI " " a2 +#define aH "cDup" aZ +#define aG "cGreaterOrEq" +#define aF "x" aZ +#define aE "cEqual" +#define aD " " aC +#define aC "A" wY +#define aB " " wU +#define aA " cNeg" +#define a9 " cRDiv" +#define a8 " B" wY +#define a7 " x" wH +#define a6 "cRSub" +#define a5 "A[IsVarOpcode(A)]" +#define a4 "x[x!=Value_t()] " +#define a3 " " a5" " +#define a2 " with" aD +#define a1 " " wG +#define a0 " cNot" +#define wZ "x[x==Value_t()]" wH +#define wY " " wC +#define wX "[x]" wH +#define wW "cNEqual" +#define wV a5 mF +#define wU "x = "<<x +#define wT "x[isInteger(x)] cPow" +#define wS a5 wH +#define wR "x[x!=Value_t(0)]" mF +#define wQ "x[x>Value_t(0)]" +#define wP "B[IsNeverNegativeValueOpcode(B)] " +#define wO "x[x==Value_t(1)] " +#define wN wA"\n" +#define wM <<"\n" +#define wL "x[x==Value_t(0)] " +#define wK "B[IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " wD +#define wJ "A[IsNeverNegativeValueOpcode(A)] " +#define wI "A[IsVarOpcode(A)&&mData->mByteCode.size()>2] " +#define wH " cMul" +#define wG aY"= "<<y wM +#define wF " x A[IsComparisonOpcode(A)]" +#define wE FP_TRACE_BYTECODE_ADD +#define wD "A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " wZ +#define wC "= "<<FP_TRACE_OPCODENAME +#define wB FP_TRACE_BYTECODE_OPTIMIZATION +#define wA " with" aB<< +#define w9 qT q6: +#define w8 cEqual +#define w7 Lbd gY +#define w6 Lcb gY +#define w5 opcode +#define w4 B==A){ +#define w3 q5 q4 +#define w2 cExp: +#define w1 qO A qP +#define w0 qO h2 +#define oZ qF g1 +#define oY if dC +#define oX fp_pow( +#define oW fp_log( +#define oV 3 gC A +#define oU x==g1 oG +#define oT gX Lml; +#define oS q4 Lbo +#define oR 3 gH +#define oQ cSinh: +#define oP g1 0) +#define oO 0.5)){ +#define oN Ldn;qT +#define oM ]==h3){ +#define oL qY g8 0 +#define oK .size() +#define oJ );qE +#define oI A oJ dU +#define oH g7 A= +#define oG 1)){ +#define oF qU hI +#define oE Lbo oF +#define oD qT hM hB +#define oC qL 3] +#define oB :hC qQ oC +#define oA cSub oB d3 hJ +#define o9 q7=-x +#define o8 gX Loi; +#define o7 );qF +#define o6 qE A o7 +#define o5 h3 d4 qL +#define o4 fp_log2( +#define o3 ==cSqr){ +#define o2 qT cSqr: +#define o1 cGreater +#define o0 Default6 +#define dZ Default5 +#define dY Default2 +#define dX Default1 +#define dW ImmedPtr +#define dV gA qZ qC +#define dU h3); +#define dT gC dU +#define dS cNotNot +#define dR fp_log10( +#define dQ cAbs); +#define dP fp_abs(x) +#define dO x>oP){ +#define dN mImmed +#define dM qE h3 gX +#define dL qK dJ w3 +#define dK cGreaterOrEq +#define dJ =q6; +#define dI qK dJ g6 +#define dH Value_t +#define dG q8 2 gH q4 +#define dF q0[0] +#define dE qK qR qX +#define dD qK qR IsLogicalOpcode(h2 +#define dC (qK== +#define dB hB oY +#define dA qY g8 oG +#define d9 pop_back() +#define d8 q6;q1 h3 gI +#define d7 q8 2 gC +#define d6 hR Lba; +#define d5 Default4 qU +#define d4 :if( +#define d3 qV hS d4 qL +#define d2 h3 gM if +#define d1 IsVarOpcode( +#define d0 mData-> +#define hZ ]qR w4 +#define hY gX Llq +#define hX ,x gX Lap +#define hW gT y+x;q8 +#define hV for qA +#define hU gQ cAbs: +#define hT unsigned +#define hS cAdd +#define hR ,y gX +#define hQ qL 3 hZ +#define hP y=q3-1]qR +#define hO y gO +#define hN qY if(dP +#define hM q6:qC +#define hL :if gF +#define hK qQ h9 hS hL +#define hJ 4 qZ mW(292,aY"cAdd B[IsVarOpcode(B)]" aW mD,mN aZ" B" aW,wA"," a8(B)<<"," a1);q4 +#define hI cNeg: +#define hH :qS cDup: +#define hG hS hH hK h1 wB(310,aH" " aH,"[Value_t(4)]" wH,);q4 +#define hF (x!=g1 +#define hE qL 2] +#define hD B g4 w4 +#define hC B=hE qO B)){ +#define hB if hF 0)){ +#define hA gX Lng; +#define h9 qK qV +#define h8 }break; +#define h7 <dH>()){ +#define h6 hR Lap; +#define h5 isEvenInteger( +#define h4 DegreesToRadians(x +#define h3 cMul +#define h2 A)){ +#define h1 ]==cDup){ +#define h0 hI wB(201,m0 mV,mV,);q4 Lab qU qB +#define gZ 3 h1 wB(311,aH wH" " aH,"cMul [Value_t(4)]" wH,);q4 +#define gY qU hM +#define gX );q4 +#define gW y,x gX Lba; +#define gV IsUnaryOpcode( +#define gU g6 w5= +#define gT q3-1]= +#define gS gR qR IsAlwaysIntegerOpcode(h2 +#define gR ;oH dF +#define gQ )){qQ h9 +#define gP break gR qO A gQ +#define gO =q3-1]; +#define gN qJ hO +#define gM :qJ qC +#define gL d2(dO +#define gK ]=q6 q9 2 gH +#define gJ return; +#define gI );w5= +#define gH ;qI q5 +#define gG qL 2 gK q0-=2; +#define gF (qL 2 +#define gE y;hT B;hT +#define gD d0 mByteCode +#define gC ;qI q1 +#define gB q9 2 gC h3 gI +#define gA ){if gF +#define g9 oY h3 dV +#define g8 if(x==g1 +#define g7 default: +#define g6 q5 q0-=1; +#define g5 if(!q0){q2 +#define g4 =hE qR +#define g3 B g4 IsNeverNegativeValueOpcode(B)){ +#define g2 &&!HasInvalidRangesOpcode( +#define g1 dH( +#define g0 FP_ReDefinePointers(); +#define qZ ]==q6){ +#define qY if(q0[0 qZ qC +#define qX IsNeverNegativeValueOpcode(h2 +#define qW gD qD +#define qV ){case +#define qU ;case +#define qT }break qU +#define qS qQ dF qV +#define qR ;if( +#define qQ switch( +#define qP )&&gD oK> +#define qO qR d1 +#define qN dF w1 2){ +#define qM d0 dN.d9; +#define qL q0[- +#define qK qL 1] +#define qJ oY q6){ +#define qI tmp-->0;) +#define qH q4 Default0; +#define qG }}qH +#define qF d0 dN qD +#define qE AddFunctionOpcode( +#define qD .push_back( +#define qC x=q7; +#define qB hM wB(132,"x " mV,"[fp_abs(x)]",wN);q4 Lac; +#define qA (hT tmp= +#define q9 ;hV +#define q8 d0 dN.d9 q9 +#define q7 q3 0] +#define q6 cImmed +#define q5 gD.d9; +#define q4 goto +#define q3 dW[ +#define q2 q4 Laa;}case +#define q1 q5 qE +#define q0 ByteCodePtr +hT*q0;dH*dW; +#define FP_ReDefinePointers() q0=!gD.empty()?&gD[0]+gD oK-1:0;dW=!d0 dN.empty()?&d0 dN[0]+d0 dN oK-1:0; +g0 +wE(opcode); +#if(!(FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION)) +dH +x;hT +A;dH +gE +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0 +oH +dF +qR +qX +wB(393,wJ +mV,"A" +,aI(A)wM);gJ +qG +TailCall_cAdd:g5 +hG +Lad;qT +h3 +hL]==hS){if(qL +gZ +Lae;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Laf;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lag +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Lah;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lai;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Laj +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lak;qT +oA +Lal;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lam +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lan;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Lao;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lap;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Laq;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lba;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +Lbb +gY +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbc;h8} +qH +TailCall_cDiv:g5 +cDiv +hH +wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +w7 +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Lbe +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Lbf;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lap;h8} +qH +TailCall_cEqual:g5 +w8:dA +A=dD +wB(421,"A[IsLogicalOpcode(A)] " +wO +aE,"A" +,qB1(A)wM);q4 +Lap;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Lbg;} +g8 +0 +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Lbh +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Lbh;} +wB(411,wL +aE,"cNot" +,wN);q4 +Lbi;qG +TailCall_cGreater:g5 +o1:oL +hU +wB(413,m1 +m2,aJ,wN);q4 +Lbj;m4(417,wJ +wL +m2,"A " +aJ,qB1(A)wM);q4 +Lbk;} +} +} +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Lbl;qG +TailCall_cGreaterOrEq:g5 +dK:qY +g8 +1 +hU +wB(414,mV" " +wO +aG,aJ,wN);q4 +Lbj;m4(418,wJ +wO +aG,"A " +aJ,qB1(A)wM);q4 +Lbk;} +} +} +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Lbm;qG +TailCall_cInv:g5 +cInv:qY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Lbn;qG +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);oS;} +} +g8 +1 +hU +wB(415,mV" " +wO +mJ,"cNot" +,wN);q4 +Lbp;m4(419,wJ +wO +mJ,"A" +a0,qB1(A)wM);q4 +Lbi;} +} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lbq;qG +TailCall_cLessOrEq:g5 +cLessOrEq:oL +hU +wB(416,m1 +aR,"cNot" +,wN);q4 +Lbp;m4(420,wJ +wL +aR,"A" +a0,qB1(A)wM);q4 +Lbi;} +} +} +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lca;qG +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);q4 +w6 +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lcc;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);q4 +Lcb;qT +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);q4 +Lcb;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);q4 +w6 +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lcd;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);q4 +Lcb;qT +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);q4 +Lcb;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lce;} +qG +TailCall_cMul:g5 +h3 +hH +wB(202,"cDup" +wH,"cSqr" +,);q4 +Lcf +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lcg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lci;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lcj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lck;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lcl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcn;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lcj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lco;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lcp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lcq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup:wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lda +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldb;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Ldc;qT +h3:qQ +hE +d3 +3 +h1 +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Ldd;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lde;} +wB(128,"y" +wH +a7,m3,q81);q4 +Ldf;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Ldg +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldh;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Ldi;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lap;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Ldj;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Ldk;h8 +g7 +dY:;A=dF +qO +A +gQ +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +q4 +Default4;g7 +Default4:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Ldl;} +} +q4 +dZ +oF +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lcg;} +q4 +dZ;g7 +dZ:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lcf;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Ldm;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:dA +A=dD +wB(422,"A[IsLogicalOpcode(A)] " +wO +wW,"A" +a0,qB1(A)wM);q4 +Lbi;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Ldn;} +g8 +0 +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Ldo +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Ldo;} +wB(412,wL +wW,aJ,wN);q4 +Lbk;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Ldp;qT +hI +wB(61,qC1 +aA,,);q4 +w6 +wB(100,"x" +aA,"[-x]" +,wN);q4 +Ldq;} +qH +TailCall_cNot:g5 +cNot:qS +cAbs:wB(227,mV +a0,"cNot" +,);q4 +Lea +qU +cAbsNot:A=dD +wB(389,"A[IsLogicalOpcode(A)] " +aS +a0,"A" +,aI(A)wM);q4 +Lcb;} +if(A!=q6){wB(390,"A[A!=cImmed] " +aS +a0,"A cAbsNotNot" +,aI(A)wM);q4 +Leb;} +q4 +o0 +qU +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Lec +qU +hS +gM +wB(424,aF +a0,"[-x] " +aE,wN);q4 +Led;} +q4 +o0 +qU +w8:wB(220,aE +a0,wW,);q4 +Lee +qU +o1:wB(218,m2 +a0,aR,);q4 +Lef +qU +dK:wB(219,aG +a0,mJ,);q4 +Leg +qU +cLess:wB(216,mJ +a0,aG,);q4 +Leh +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Lei +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Lej +oF +wB(226,qC1 +a0,"cNot" +,);q4 +Lea +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbb +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Lea +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Lek;g7 +o0:;A=dF +qR +qX +wB(391,wJ"cNot" +,"A " +aS,aI(A)wM);q4 +Lel;qG +TailCall_cNotNot:g5 +dS:qS +hS +gM +wB(423,aF" " +aJ,"[-x] " +wW,wN);q4 +Lem;qT +cNot:wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +Lbb +gY +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Len;h8} +qH +TailCall_cRDiv:g5 +cRDiv:dA +wB(268,wO"cRDiv" +,aU,wN);q4 +Leo;qG +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Lep;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Leq +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Leq;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Lep +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Lfa +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lap;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Lfb;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lfc +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Lfd;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lfe;} +qG +g7 +Default0:;A=w5 +qR +IsComparisonOpcode(h2 +qY +hK +qZ +mW(364,aY"cAdd" +wF,"[x-y] A" +,aI(A)qD1<<"," +a1);q4 +Lff;qT +hI +wB(365,qC1 +wF,"[-x] {OppositeComparisonOpcode(A)}" +,aI(A)qD1 +wM);q4 +Lfg;} +} +} +if(d1 +A +qP +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lfh;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lfi;} +} +} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:oZ +4));gG +Lfj:w5=h3;Lfk:g0 +Lfl:wE(cMul);q4 +TailCall_cMul;Lae:hV +4 +dT +oZ +4)q71 +gX +Lfj;Laf:q7=x+g1 +1);gG +Lbo:w5=h3;q4 +Lfl;Lag:gU +cSub;Lfm:wE(cSub);q4 +TailCall_cSub;Lah:hW +2 +gH +Lfn:g0 +Lfo:wE(cAdd);q4 +TailCall_cAdd;Lai:hW +oR +Lfp:qE +hS);Lfq:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Laj:o9;qL +2 +gK +q4 +Lfp;Lak:hW +2 +gH +q4 +Lfq;Lal:hW +4 +gH +Lga:qE +hS);Lgb:qE +B);Lgc:w5=cSub;g0 +q4 +Lfm;Lam:o9;oC=q6 +q9 +oR +q4 +Lga;Lan:hW +oR +q4 +Lgb;Lao:gT +y+x;Lap:qM +Lcb:q5 +gJ +Laq:q8 +oV +o7 +x +q71 +gX +Lfp;Lba:mM +A +gX +Lfp;Lbb:gU +dS;Lgd:wE(cNotNot);q4 +TailCall_cNotNot;Lbc:gT +fp_and(x +h6 +Lbd:oZ));dF +dJ +qE +dU +oZ +1));Lge:qW +q6);Lgf:w5=hS;q4 +Lfn;Lbe:o9;dI +wE(cDiv);q4 +TailCall_cDiv;Lbf:gT +y/x;q4 +Lap;Lbg:gT +fp_equal +mO +Lbh:dI +Lgg:wE(cEqual);q4 +TailCall_cEqual;Lbi:qM +q5 +Lgh:w5=cNot;g0 +Lgi:wE(cNot);q4 +TailCall_cNot;Lbj:q8 +2 +gH +Lgj:w5=dS;g0 +q4 +Lgd;Lbk:qM +w3 +Lgj;Lbl:gT +fp_less(x +h6 +Lbm:gT +fp_lessOrEq(x +h6 +Lbn:q7=g1 +1)/x;gJ +Lbp:dG +Lgh;Lbq:gT +fp_less +mO +Lca:gT +fp_lessOrEq +mO +Lcc:gT +fp_max(x +h6 +Lcd:gT +fp_min(x +h6 +Lce:gT +fp_mod +mO +Lcf:gU +cSqr;Lgk:wE(cSqr);q4 +TailCall_cSqr;Lcg:mM +cSqr);Lgl:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lch:hV +3 +gC +cSqr);dM +Lgl;Lci:q7=x+g1 +1);hE=q6 +q9 +2 +gC +cPow);gJ +Lcj:gG +q4 +Lfl;Lck:gT +x;Lgm:dG +Lfk;Lcl:qF1 +qM +Lgn:hV +4 +gH +Lgo:o6 +x);Lgp:qW +q6 +gX +Lfk;Lcm:qM +q4 +Lgn;Lcn:q8 +4 +gC +B +gX +Lgo;Lco:q8 +oR +q4 +Lgo;Lcp:qK +dJ +q4 +Lcb;Lcq:dI +q4 +Lfl;Lda:q7=x+x;q4 +Lcj;Ldb:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lgf;Ldc:gT +x;d7 +dU +qF +y*x +gX +Lge;Ldd:q8 +4 +dT +qF +x+x +gX +Lgp;Lde:qF1 +q8 +oR +gJ +Ldf:qG1 +q4 +Lgm;Ldg:o9;q4 +Lcq;Ldh:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lgc;Ldi:qG1 +q4 +Lap;Ldj:qM +w3 +Lgl;Ldk:dF=cDup;dW-=1;qM +Lgq:w5=hS;q4 +Lfo;Ldl:hV +2 +gH +Lha:qE +cSqr +gX +Lfk;Ldm:hV +oR +q4 +Lha;Ldn:gT +fp_nequal +mO +Ldo:dI +Lhb:wE(cNEqual);q4 +TailCall_cNEqual;Ldp:o9;g6 +oS;Ldq:o9;gJ +Lea:g6 +q4 +Lgi;Leb:q1 +cAbsNotNot);gJ +Lec:q5 +Lel:qE +cAbsNot);gJ +Led:o9;Lej:gU +w8;q4 +Lgg;Lee:gU +cNEqual;q4 +Lhb;Lef:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Leg:gU +cLess;wE(cLess);q4 +TailCall_cLess;Leh:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Lei:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Lek:q7=fp_not +m6 +Lem:o9;q4 +Lee;Len:gT +fp_or(x +h6 +Leo:qM +q5 +w5=cInv;g0 +wE(cInv);q4 +TailCall_cInv;Lep:oZ));dF +dJ +q4 +Lfj;Leq:g6 +q4 +Lgk;Lfa:g6 +q4 +Lgq;Lfb:gT +y-x;q4 +Lap;Lfc:o9;q4 +Lgq;Lfd:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lfq;Lfe:mM +A +oJ +cSub +gX +Lfq;Lff:gT +x-y;d7 +A);gJ +Lfg:o9;qK +dJ +q1 +OppositeComparisonOpcode(A));gJ +Lfh:qW +cDup);gJ +Lfi:dF=cDup;gJ +gJ +q4 +TailCall_cAnd;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cNeg;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cSub; +#endif +#if((FP_COMPLEX_VERSION) && !(FP_FLOAT_VERSION)) +dH +x;dH +gE +A;hT +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0} +qH +TailCall_cAdd:g5 +hG +Lad;qT +h3 +hL]==hS){if(qL +gZ +Lae;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Laf;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lag +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Lah;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lai;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Laj +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lak;qT +oA +Lal;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lam +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lan;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Lao;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lap;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Laq;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lba;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +Lbb +gY +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbc;h8} +qH +TailCall_cConj:g5 +cConj:qS +cConj:wB(63,mY" " +mY,,);q4 +w7 +wB(193,"x " +mY,"[fp_conj(x)]" +,wN);q4 +Lbe;} +qH +TailCall_cDiv:g5 +cDiv +hH +wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lbf +gY +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Lbg +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Lbh;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lap;h8} +qH +TailCall_cEqual:g5 +w8:dA +A=dD +wB(421,"A[IsLogicalOpcode(A)] " +wO +aE,"A" +,qB1(A)wM);q4 +Lap;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Lbi;} +g8 +0 +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Lbj +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Lbj;} +wB(411,wL +aE,"cNot" +,wN);q4 +Lbk;qG +TailCall_cGreater:g5 +o1:qY +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Lbl;qG +TailCall_cGreaterOrEq:g5 +dK:qY +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Lbm;qG +TailCall_cImag:g5 +cImag:qS +cAbs:wB(81,mV" " +mZ,"[Value_t()]" +wH,);q4 +Lbn +qU +cReal:wB(80,"cReal " +mZ,"[Value_t()]" +wH,);q4 +Lbn +gY +wB(192,"x " +mZ,"[fp_imag(x)]" +,wN);oS;} +qH +TailCall_cInv:g5 +cInv:qY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Lbp;qG +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);q4 +Lbq;} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lca;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lcb;qG +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);q4 +w7 +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lcc;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);q4 +Lbd;qT +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);q4 +Lbd;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);q4 +w7 +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lcd;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);q4 +Lbd;qT +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);q4 +Lbd;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lce;} +qG +TailCall_cMul:g5 +h3 +hH +wB(202,"cDup" +wH,"cSqr" +,);q4 +Lcf +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lcg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lci;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lcj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lck;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lcl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lcn;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lcj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lco;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lcp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lcq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup:wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lda +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldb;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Ldc;qT +h3:qQ +hE +d3 +3 +h1 +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Ldd;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lde;} +wB(128,"y" +wH +a7,m3,q81);q4 +Ldf;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Ldg +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Ldh;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Ldi;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lap;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Ldj;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Ldk;h8 +g7 +dY:;A=dF +qO +A +gQ +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lch;} +q4 +Default4;g7 +Default4:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Ldl;} +} +q4 +dZ +oF +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lcg;} +q4 +dZ;g7 +dZ:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lcf;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Ldm;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:dA +A=dD +wB(422,"A[IsLogicalOpcode(A)] " +wO +wW,"A" +a0,qB1(A)wM);q4 +Lbk;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Ldn;} +g8 +0 +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Ldo +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Ldo;} +wB(412,wL +wW,aJ,wN);q4 +Ldp;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Ldq;qT +hI +wB(61,qC1 +aA,,);q4 +w7 +wB(100,"x" +aA,"[-x]" +,wN);q4 +Lea;} +qH +TailCall_cNot:g5 +cNot:qS +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Leb +qU +hS +gM +wB(424,aF +a0,"[-x] " +aE,wN);q4 +Lec;qT +w8:wB(220,aE +a0,wW,);q4 +Led +qU +o1:wB(218,m2 +a0,aR,);q4 +Lee +qU +dK:wB(219,aG +a0,mJ,);q4 +Lef +qU +cLess:wB(216,mJ +a0,aG,);q4 +Leg +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Leh +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Lei +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbb +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Lej +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Lek;} +qH +TailCall_cNotNot:g5 +dS:qS +hS +gM +wB(423,aF" " +aJ,"[-x] " +wW,wN);q4 +Lel;qT +cNot:wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +Lbb +gY +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Lem;h8} +qH +TailCall_cRDiv:g5 +cRDiv:dA +wB(268,wO"cRDiv" +,aU,wN);q4 +Len;qG +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Lbn;} +qH +TailCall_cReal:g5 +cReal:qY +wB(191,"x cReal" +,"[fp_real(x)]" +,wN);q4 +Leo;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Lep +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Lep;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Lbn +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Leq +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lap;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Lfa;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lfb +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Lfc;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lfd;} +qG +g7 +Default0:;A=w5 +w1 +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lfe;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lff;} +} +} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:oZ +4));gG +Lfg:w5=h3;Lfh:g0 +Lfi:wE(cMul);q4 +TailCall_cMul;Lae:hV +4 +dT +oZ +4)q71 +gX +Lfg;Laf:q7=x+g1 +1);gG +Lbq:w5=h3;q4 +Lfi;Lag:gU +cSub;Lfj:wE(cSub);q4 +TailCall_cSub;Lah:hW +2 +gH +Lfk:g0 +Lfl:wE(cAdd);q4 +TailCall_cAdd;Lai:hW +oR +Lfm:qE +hS);Lfn:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Laj:o9;qL +2 +gK +q4 +Lfm;Lak:hW +2 +gH +q4 +Lfn;Lal:hW +4 +gH +Lfo:qE +hS);Lfp:qE +B);Lfq:w5=cSub;g0 +q4 +Lfj;Lam:o9;oC=q6 +q9 +oR +q4 +Lfo;Lan:hW +oR +q4 +Lfp;Lao:gT +y+x;Lap:qM +Lbd:q5 +gJ +Laq:q8 +oV +o7 +x +q71 +gX +Lfm;Lba:mM +A +gX +Lfm;Lbb:gU +dS;Lga:wE(cNotNot);q4 +TailCall_cNotNot;Lbc:gT +fp_and(x +h6 +Lbe:q7=fp_conj +m6 +Lbf:oZ));dF +dJ +qE +dU +oZ +1));Lgb:qW +q6);Lgc:w5=hS;q4 +Lfk;Lbg:o9;dI +wE(cDiv);q4 +TailCall_cDiv;Lbh:gT +y/x;q4 +Lap;Lbi:gT +fp_equal +mO +Lbj:dI +Lgd:wE(cEqual);q4 +TailCall_cEqual;Lbk:qM +q5 +w5=cNot;g0 +Lge:wE(cNot);q4 +TailCall_cNot;Lbl:gT +fp_less(x +h6 +Lbm:gT +fp_lessOrEq(x +h6 +Lbn:oZ));dF +dJ +q4 +Lfg;Lbo:q7=fp_imag +m6 +Lbp:q7=g1 +1)/x;gJ +Lca:gT +fp_less +mO +Lcb:gT +fp_lessOrEq +mO +Lcc:gT +fp_max(x +h6 +Lcd:gT +fp_min(x +h6 +Lce:gT +fp_mod +mO +Lcf:gU +cSqr;Lgf:wE(cSqr);q4 +TailCall_cSqr;Lcg:mM +cSqr);Lgg:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lch:hV +3 +gC +cSqr);dM +Lgg;Lci:q7=x+g1 +1);hE=q6 +q9 +2 +gC +cPow);gJ +Lcj:gG +q4 +Lfi;Lck:gT +x;Lgh:dG +Lfh;Lcl:qF1 +qM +Lgi:hV +4 +gH +Lgj:o6 +x);Lgk:qW +q6 +gX +Lfh;Lcm:qM +q4 +Lgi;Lcn:q8 +4 +gC +B +gX +Lgj;Lco:q8 +oR +q4 +Lgj;Lcp:qK +dJ +q4 +Lbd;Lcq:dI +q4 +Lfi;Lda:q7=x+x;q4 +Lcj;Ldb:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lgc;Ldc:gT +x;d7 +dU +qF +y*x +gX +Lgb;Ldd:q8 +4 +dT +qF +x+x +gX +Lgk;Lde:qF1 +q8 +oR +gJ +Ldf:qG1 +q4 +Lgh;Ldg:o9;q4 +Lcq;Ldh:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lfq;Ldi:qG1 +q4 +Lap;Ldj:qM +w3 +Lgg;Ldk:dF=cDup;dW-=1;qM +Lgl:w5=hS;q4 +Lfl;Ldl:hV +2 +gH +Lgm:qE +cSqr +gX +Lfh;Ldm:hV +oR +q4 +Lgm;Ldn:gT +fp_nequal +mO +Ldo:dI +Lgn:wE(cNEqual);q4 +TailCall_cNEqual;Ldp:qM +q5 +w5=dS;g0 +q4 +Lga;Ldq:o9;g6 +q4 +Lbq;Lea:o9;gJ +Leb:q1 +cAbsNot);gJ +Lec:o9;Lei:gU +w8;q4 +Lgd;Led:gU +cNEqual;q4 +Lgn;Lee:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Lef:gU +cLess;wE(cLess);q4 +TailCall_cLess;Leg:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Leh:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Lej:g6 +q4 +Lge;Lek:q7=fp_not +m6 +Lel:o9;q4 +Led;Lem:gT +fp_or(x +h6 +Len:qM +q5 +w5=cInv;g0 +wE(cInv);q4 +TailCall_cInv;Leo:q7=fp_real +m6 +Lep:g6 +q4 +Lgf;Leq:g6 +q4 +Lgl;Lfa:gT +y-x;q4 +Lap;Lfb:o9;q4 +Lgl;Lfc:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lfn;Lfd:mM +A +oJ +cSub +gX +Lfn;Lfe:qW +cDup);gJ +Lff:dF=cDup;gJ +gJ +q4 +TailCall_cAnd;q4 +TailCall_cConj;q4 +TailCall_cImag;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cNeg;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cReal;q4 +TailCall_cSub; +#endif +#if((FP_FLOAT_VERSION) && !(FP_COMPLEX_VERSION)) +dH +x;hT +A;dH +gE +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0 +oH +dF +qR +qX +wB(393,wJ +mV,"A" +,aI(A)wM);gJ +qG +TailCall_cAcos:g5 +cAcos:hN<=m7(148,"x[fp_abs(x)<=Value_t(1)] cAcos" +,"[fp_acos(x)]" +,wN);q4 +Lad;qG +TailCall_cAcosh:g5 +cAcosh:qY +if(x>=m7(145,"x[x>=Value_t(1)] cAcosh" +,"[fp_acosh(x)]" +,wN);q4 +Lae;qG +TailCall_cAdd:g5 +hG +Laf;qT +h3 +hL]==hS){if(qL +gZ +Lag;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Lah;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lai +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Laj;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lak;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Lal +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lam;qT +oA +Lan;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lao +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lap;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Laq;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lba;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lbb;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lbc;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +w7 +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbe;h8} +qH +TailCall_cAsin:g5 +cAsin:hN<=m7(149,"x[fp_abs(x)<=Value_t(1)] cAsin" +,"[fp_asin(x)]" +,wN);q4 +Lbf;qG +TailCall_cAsinh:g5 +cAsinh:qY +wB(146,"x cAsinh" +,"[fp_asinh(x)]" +,wN);q4 +Lbg;} +qH +TailCall_cAtan:g5 +cAtan:qY +wB(150,"x cAtan" +,"[fp_atan(x)]" +,wN);q4 +Lbh;} +qH +TailCall_cAtan2:g5 +cAtan2:qY +m9(139,mA"cAtan2" +,"[fp_atan2(y,x)]" +,q81);q4 +Lbi;qG +TailCall_cAtanh:g5 +cAtanh:hN<m7(147,"x[fp_abs(x)<Value_t(1)] cAtanh" +,"[fp_atanh(x)]" +,wN);q4 +Lbj;qG +TailCall_cCbrt:g5 +cCbrt:qY +wB(151,"x cCbrt" +,"[fp_cbrt(x)]" +,wN);q4 +Lbk;} +qH +TailCall_cCeil:g5 +cCeil:qS +hI +wB(402,m0 +q01,mS +aA,);q4 +Lbl +gY +wB(135,"x " +q01,"[fp_ceil(x)]" +,wN);q4 +Lbm +gS +wB(396,"A[IsAlwaysIntegerOpcode(A)] " +q01,"A" +,aI(A)wM);gJ +qG +TailCall_cCos:g5 +cCos:qS +cAbs:wB(235,mV" " +aO,aO,);q4 +Lbn +oF +wB(238,m0 +aO,aO,);q4 +Lbn +gY +wB(152,"x " +aO,"[fp_cos(x)]" +,wN);oS;oH +qN +qQ +h9 +cSec:hD +wB(500,aK" cSec " +wI +aO,"B cSec " +aT,aI(A)q91(B)wM);q4 +Lbp;qT +cSin:hD +wB(494,aK" " +mP" " +wI +aO,"B cSinCos" +,aI(A)q91(B)wM);q4 +Lbq;h8} +qG +TailCall_cCosh:g5 +cCosh:qS +cAbs:wB(236,mV" " +aM,aM,);q4 +Lca +qU +cAsinh:wB(450,"cAsinh " +aM,"[DO_STACKPLUS1] " +q41"[Value_t(1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lcb +oF +wB(239,m0 +aM,aM,);q4 +Lca +gY +wB(153,"x " +aM,"[fp_cosh(x)]" +,wN);q4 +Lcc;oH +qN +oY +cSinh +q11(507,aK" cSinh " +wI +aM,"B cSinhCosh" +,aI(A)q91(B)wM);q4 +Lcd;} +} +qG +TailCall_cCot:g5 +cCot:A=qN +oY +cTan +q11(498,aK" " +mR" " +wI"cCot" +,"B " +mR" " +aT,aI(A)q91(B)wM);q4 +Lbp;} +qG +TailCall_cCsc:g5 +cCsc:A=qN +oY +cSin +q11(496,aK" " +mP" " +wI"cCsc" +,"B " +mP" " +aT,aI(A)q91(B)wM);q4 +Lbp;} +qG +TailCall_cDeg:g5 +cDeg:qY +wB(133,"x cDeg" +,"[RadiansToDegrees(x)]" +,wN);q4 +Lce;} +qH +TailCall_cDiv:g5 +cDiv:qS +cCos:wB(250,aO +mF,"cSec" +wH,);q4 +Lcf +qU +cCot:wB(254,"cCot" +mF,mR +wH,);q4 +Lcg +qU +cCsc:wB(252,"cCsc" +mF,mP +wH,);q4 +Lch +qU +cDup:wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lci +qU +w2 +wB(408,"cExp" +mF,m0"cExp" +wH,);q4 +Lcj +qU +cExp2:wB(409,"cExp2" +mF,m0"cExp2" +wH,);q4 +Lck +qU +cInv:wB(213,aU +mF,"cMul" +,);q4 +Lcl +qU +cPow:wB(407,"cPow" +mF,m0"cPow" +wH,);q4 +Lcm +qU +cSec:wB(253,"cSec" +mF,aO +wH,);q4 +Lcn +qU +cSin:wB(249,mP +mF,"cCsc" +wH,);q4 +Lco +qU +cSinCos:wB(502,"cSinCos" +mF,mR,);q4 +Lcp +qU +cSinhCosh:wB(509,"cSinhCosh" +mF,"cTanh" +,);q4 +Lcq +qU +cTan:wB(251,mR +mF,"cCot" +wH,);q4 +Lda +gY +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Ldb +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Ldc;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lba;} +dB +h3 +gA +qZ +hP(y/x)==fp_const_rad_to_deg +h7 +wB(321,"y[(y/x)==fp_const_rad_to_deg<Value_t>()]" +wH" " +wR,"cDeg" +,q81);q4 +Ldd;} +if((y/x)==fp_const_deg_to_rad +h7 +wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]" +wH" " +wR,"cRad" +,q81);q4 +Lde;} +wB(323,"y" +wH" " +wR,"[y/x]" +wH,q81);q4 +Ldf;} +} +wB(325,wR,"[Value_t(1)/x]" +wH,wN);q4 +Ldg;} +gP +cDiv:hC +wB(271,aX"cDiv " +wV,"[DO_STACKPLUS1] B A" +wH +mF,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Ldh;qT +cRDiv:qQ +hE +qV +hM +wB(266,"x" +a9" " +wV,"A" +wH" [x]" +a9,aI(A)qD1 +wM);q4 +Ldi;g7 +hC +wB(265,"B[IsVarOpcode(B)]" +a9" " +wV,"A" +wH" B" +a9,aI(A)q91(B)wM);q4 +Ldj;} +h8} +qG +TailCall_cEqual:g5 +w8:oL +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Ldk +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Ldk;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Ldl;qG +TailCall_cExp:g5 +w2 +qS +hS +gM +wB(404,aF +mL,q21"[fp_exp(x)]" +wH,wN);q4 +Ldm;qT +cLog:A=dE +wB(340,wJ +mG +mL,"A" +,aI(A)wM);q4 +oN +hM +wB(154,"x" +mL,"[fp_exp(x)]" +,wN);q4 +Ldo;} +qH +TailCall_cExp2:g5 +cExp2:qS +hS +gM +wB(405,aF +q31,"cExp2 [fp_exp2(x)]" +wH,wN);q4 +Ldp;qT +cLog2:A=dE +wB(341,wJ +aN +q31,"A" +,aI(A)wM);q4 +oN +hM +wB(155,"x" +q31,"[fp_exp2(x)]" +,wN);q4 +Ldq;} +wB(479,"cExp2" +,"[DO_STACKPLUS1] [fp_log(Value_t(2))]" +wH +mL,);incStackPtr();--mStackPtr;q4 +Lea;TailCall_cFloor:g5 +cFloor:qS +hI +wB(401,m0 +mS,q01 +aA,);q4 +Leb +gY +wB(136,"x " +mS,"[fp_floor(x)]" +,wN);q4 +Lec +gS +wB(395,"A[IsAlwaysIntegerOpcode(A)] " +mS,"A" +,aI(A)wM);gJ +qG +TailCall_cGreater:g5 +o1:qY +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Led;} +g8-oO +wB(431,"x[x==Value_t(-0.5)] " +m2,m0 +aS,wN);q4 +Lee;qG +TailCall_cGreaterOrEq:g5 +dK:qY +dB +cAbs){wB(427,mV" x[x!=Value_t(0)] " +aG,"[Value_t(0.5)/x]" +wH" " +aJ,wN);q4 +Lef;} +} +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Leg;} +g8 +oO +wB(430,"x[x==Value_t(0.5)] " +aG,"cAbsNotNot" +,wN);q4 +Leh;qG +TailCall_cHypot:g5 +cHypot +d4 +dF==cSinCos){wB(84,"cSinCos cHypot" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lci;} +qH +TailCall_cInt:g5 +cInt:qS +hM +wB(137,"x cInt" +,"[fp_int(x)]" +,wN);q4 +Lei +gS +wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt" +,"A" +,aI(A)wM);gJ +qG +TailCall_cInv:g5 +cInv:qS +cCos:wB(256,aO" " +aU,"cSec" +,);q4 +Lej +qU +cCot:wB(260,"cCot " +aU,mR,);q4 +Lcp +qU +cCsc:wB(258,"cCsc " +aU,mP,);q4 +Lek +qU +cInv:wB(62,aU" " +aU,,);q4 +Ldn +qU +cPow:wB(355,q61 +aU,m0"cPow" +,);q4 +Lel +qU +cSec:wB(259,"cSec " +aU,aO,);q4 +Lem +qU +cSin:wB(255,mP" " +aU,"cCsc" +,);q4 +Len +qU +cSqrt:wB(206,q51" " +aU,"cRSqrt" +,);q4 +Leo +qU +cTan:wB(257,mR" " +aU,"cCot" +,);q4 +Lep +gY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Leq;h8} +qH +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);q4 +Lfa;} +} +dB +cAbs){wB(426,mV" x[x!=Value_t(0)] " +mJ,"[Value_t(0.5)/x]" +wH +a0,wN);q4 +Lfb;} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lfc;} +g8 +oO +wB(429,"x[x==Value_t(0.5)] " +mJ,aS,wN);q4 +Lfd;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lfe;} +g8-oO +wB(432,"x[x==Value_t(-0.5)] " +aR,m0"cAbsNotNot" +,wN);q4 +Lff;qG +TailCall_cLog:g5 +cLog:mT(343,q21 +mG,,);q4 +Ldn +qU +gL +wB(491,mU +mG,mG" [fp_log(x)]" +aZ,wN);q4 +Lfg;} +o2 +wB(303,q41 +mG,mV" " +mG" " +aH,);q4 +Lfh +aV(156,wQ" " +mG,"[fp_log(x)]" +,wN);q4 +Lfi;h8} +qH +TailCall_cLog10:g5 +cLog10:mT(481,q21 +aL,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfj +qU +gL +wB(492,mU +aL,aL" [fp_log10(x)]" +aZ,wN);q4 +Lfk;} +o2 +wB(305,q41 +aL,mV" " +aL" " +aH,);q4 +Lfl +aV(157,wQ" " +aL,"[fp_log10(x)]" +,wN);q4 +Lfm;h8} +qH +TailCall_cLog2:g5 +cLog2:mT(480,q21 +aN,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfn +qU +cExp2:wB(344,"cExp2 " +aN,,);q4 +Ldn +qU +gL +wB(490,mU +aN,aN" [fp_log2(x)]" +aZ,wN);q4 +Lfo;} +o2 +wB(304,q41 +aN,mV" " +aN" " +aH,);q4 +Lfp +aV(158,wQ" " +aN,"[fp_log2(x)]" +,wN);q4 +Lfq;h8} +qH +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);q4 +Ldn +gY +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lga;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);q4 +oN +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);q4 +Ldn;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);q4 +Ldn +gY +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lgb;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);q4 +oN +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);q4 +Ldn;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lgc;} +qG +TailCall_cMul:g5 +h3:qS +cCsc:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(508,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc" +wH,"B cCot" +,aI(A)q91(B)wM);q4 +Lgd;} +} +} +q4 +dY +qU +cDup:wB(202,"cDup" +wH,"cSqr" +,);q4 +Lge +qU +cInv:wB(214,aU +wH,"cDiv" +,);q4 +Lgf +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lgg;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgh;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lgi;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lgj;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lgk;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lgl;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgm;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgn;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lgj;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lgo;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lgp;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lgq;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup +d4 +x+oU +wB(316,"cDup[x+x==Value_t(1)]" +aZ +a7,,wN);q4 +Lha;} +wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lhb +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lhc;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Lhd;qT +cDeg:wB(209,"cDeg" +a7,"[RadiansToDegrees(x)]" +wH,wN);q4 +Lhe +qU +cDiv +oB +qV +o5 +4 +qZ +mW(278,"y" +wH" " +aX +mH,m3 +qH1,wA"," +a8(B)<<"," +a1);q4 +Lhf;qT +hI +wB(279,m0 +aX +mH,mI +qH1,wA"," +a8(B)wM);q4 +Lhg +qU +q6:mW(277,aY +aX +mH,"[y*x] B" +mF,wA"," +a8(B)<<"," +a1);q4 +Lhh;} +qT +h3:qQ +hE +d3 +3 +h1 +if(x+oU +wB(318,"cDup[x+x==Value_t(1)]" +aZ +wH +a7,"cMul" +,wN);q4 +Lhi;} +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Lhj;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lhk;} +if((y*x)==fp_const_rad_to_deg +h7 +wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]" +wH +a7,"cDeg" +,q81);q4 +Ldd;} +if((y*x)==fp_const_deg_to_rad +h7 +wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]" +wH +a7,"cRad" +,q81);q4 +Lde;} +wB(128,"y" +wH +a7,m3,q81);q4 +Lhl;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Lhm +qU +cRDiv:qQ +hE +qV +o5 +3 +qZ +mW(285,"y" +wH +a9 +a7,m3 +a9,q81);q4 +Lhn;qT +hI +wB(286,qC1 +a9 +a7,mI +a9,wN);q4 +Lho +qU +q6:mW(284,"y" +a9 +a7,"[y*x]" +a9,q81);q4 +Lhp;qT +cRad:wB(210,"cRad" +a7,"[DegreesToRadians(x)]" +wH,wN);q4 +Lhq +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lia;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Lib;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lba;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Lic;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Lid;} +if(x==fp_const_rad_to_deg +h7 +wB(207,"x[x==fp_const_rad_to_deg<Value_t>()]" +wH,"cDeg" +,wN);q4 +Lie;} +if(x==fp_const_deg_to_rad +h7 +wB(208,"x[x==fp_const_deg_to_rad<Value_t>()]" +wH,"cRad" +,wN);q4 +Lif;h8 +g7 +dY:;A=dF +qO +A +gQ +cDiv:hC +wB(274,aX"cDiv " +wS,"[DO_STACKPLUS1] A" +wH +qH1,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Lig;} +q4 +d5 +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgh;} +q4 +dZ;g7 +dZ:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Lih;} +} +q4 +d5 +hI +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lgg;} +q4 +d5 +cRDiv +hL +qZ +qC +wB(267,"x" +a9" " +wS,"[DO_STACKPLUS1] " +mK +a9,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lii;} +wB(281,"cRDiv " +wS,"[DO_STACKPLUS1] A" +wH +a9,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lij;g7 +Default4:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lge;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lik;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:oL +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Lil +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Lil;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Lim;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Lin;qT +hI +wB(61,qC1 +aA,,);q4 +Ldn +qU +cSin:g9 +wB(244,"x" +wH" " +mP +aA,mI" " +mP,wN);q4 +Lio;} +qT +oQ +g9 +wB(245,"x" +wH" cSinh" +aA,mI" cSinh" +,wN);q4 +Lip;} +qT +cTan:g9 +wB(246,"x" +wH" " +mR +aA,mI" " +mR,wN);q4 +Liq;} +qT +cTanh:g9 +wB(247,"x" +wH" cTanh" +aA,mI" cTanh" +,wN);q4 +Lja;} +qT +hM +wB(100,"x" +aA,"[-x]" +,wN);q4 +Ljb;} +qH +TailCall_cNot:g5 +cNot:qS +cAbs:wB(227,mV +a0,"cNot" +,);q4 +Ljc +qU +cAbsNot:A=dD +wB(389,"A[IsLogicalOpcode(A)] " +aS +a0,"A" +,aI(A)wM);q4 +Ldn;} +if(A!=q6){wB(390,"A[A!=cImmed] " +aS +a0,"A cAbsNotNot" +,aI(A)wM);q4 +Ljd;} +q4 +o0 +qU +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Lje +qU +w8:wB(220,aE +a0,wW,);q4 +Ljf +qU +o1:wB(218,m2 +a0,aR,);q4 +Ljg +qU +dK:wB(219,aG +a0,mJ,);q4 +Ljh +qU +cLess:wB(216,mJ +a0,aG,);q4 +Lji +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Ljj +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Ljk +oF +wB(226,qC1 +a0,"cNot" +,);q4 +Ljc +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbd +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Ljc +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Ljl;g7 +o0:;A=dF +qR +qX +wB(391,wJ"cNot" +,"A " +aS,aI(A)wM);q4 +Ljm;qG +TailCall_cNotNot:g5 +dS +d4 +dF==cNot){wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +w7 +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Ljn;h8} +qH +TailCall_cPow:g5 +cPow:qY +if(!h5 +x+x)){oY +cSqr){wB(22,q41"x[!isEvenInteger(x+x)] cPow" +,mV" [x+x] cPow" +,wN);q4 +Ljo;} +} +if(isInteger(x +gQ +w2 +wB(43,q21 +wT,wX +mL,wN);q4 +Ljp +qU +cExp2:wB(44,"cExp2 " +wT,wX +q31,wN);q4 +Ljq +qU +cPow +hL +qZ +hP!isInteger(y)){wB(42,"y[!isInteger(y)] " +q61 +wT,aP,q81);q4 +Lka;} +} +wB(45,q61 +wT,wX" cPow" +,wN);q4 +Lkb;} +} +if(h5 +x +hU +wB(434,mV" x[isEvenInteger(x)] cPow" +,"[x] cPow" +,wN);q4 +Lkc +qU +h3 +hL]==cAbs){wB(435,mV +wH" x[isEvenInteger(x)] cPow" +,"cMul [x] cPow" +,wN);q4 +Lkd;h8} +} +g8)){wB(83,"x[x==Value_t()] cPow" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,wN);q4 +Lke;} +g8 +oO +wB(332,"x[x==Value_t(0.5)] cPow" +,q51,wN);q4 +Lkf;} +g8 +1)/g1 +3)){wB(333,"x[x==Value_t(1)/Value_t(3)] cPow" +,"cCbrt" +,wN);q4 +Lkg;} +g8 +1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)] cPow" +,"cCbrt " +aU,wN);q4 +Lkh;} +g8-oO +wB(335,"x[x==Value_t(-0.5)] cPow" +,"cRSqrt" +,wN);q4 +Lki;} +g8-oG +wB(336,"x[x==Value_t(-1)] cPow" +,aU,wN);q4 +Lkj;} +qQ +h9 +cPow +hL +qZ +hP +h5 +y)&&!h5 +x*y)){wB(21,"y[isEvenInteger(y)&&!isEvenInteger(x*y)] " +q61 +m8,mV" " +aP,q81);q4 +Lkk;} +wB(330,aY +q61 +m8,aP,q81);q4 +Lka;o2 +wB(46,q41 +m8,"[x+x] cPow" +,wN);q4 +Lkl +qU +q6:hP +y!=oP||x>=oP){wB(165,"y[y!=Value_t(0)||x>=Value_t(0)] " +m8,"[fp_pow(y,x)]" +,q81);q4 +Lkm;h8} +wB(455,m8,"[DO_POWI]" +,wN)qR +TryCompilePowi(x))gJ} +qH +TailCall_cRDiv:g5 +cRDiv:qS +cSinCos:wB(503,"cSinCos" +a9,"cCot" +,);q4 +Lep +qU +cSinhCosh:wB(510,"cSinhCosh" +a9,"cTanh " +aU,);q4 +Lkn +gY +g8 +oG +wB(268,wO"cRDiv" +,aU,wN);q4 +Lkj;h8} +qH +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Lko;} +qH +TailCall_cRad:g5 +cRad:qS +h3 +gM +wB(211,"x" +wH" cRad" +,"[DegreesToRadians(x)]" +wH,wN);q4 +Lkp;qT +hM +wB(134,"x cRad" +,"[DegreesToRadians(x)]" +,wN);q4 +Lkq;} +qH +TailCall_cSec:g5 +cSec:A=qN +qQ +h9 +cCos:hD +wB(497,aK" " +aO" " +wI"cSec" +,"B " +aO" " +aT,aI(A)q91(B)wM);q4 +Lbp;qT +cSin:hD +wB(495,aK" " +mP" " +wI"cSec" +,"B cSinCos " +aU,aI(A)q91(B)wM);q4 +Lla;h8 +qG +TailCall_cSin:g5 +cSin:qS +hI +wB(240,m0 +mP,mP +aA,);q4 +Llb +gY +wB(159,"x " +mP,"[fp_sin(x)]" +,wN);q4 +Llc;oH +qN +oY +cCsc +q11(499,aK" cCsc " +wI +mP,"B cCsc " +aT,aI(A)q91(B)wM);q4 +Lbp;} +} +qG +TailCall_cSinh:g5 +oQ +qS +cAcosh:wB(437,"cAcosh cSinh" +,"[DO_STACKPLUS1] " +q41"[Value_t(-1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lld +qU +cAsinh:wB(349,"cAsinh cSinh" +,,);q4 +Ldn +oF +wB(241,m0"cSinh" +,"cSinh" +aA,);q4 +Lle +gY +wB(160,"x cSinh" +,"[fp_sinh(x)]" +,wN);q4 +Llf;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Llg +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Llg +qU +cSqrt:A=dE +wB(338,wJ +q51" cSqr" +,"A" +,aI(A)wM);q4 +Ldn;h8} +qH +TailCall_cSqrt:g5 +cSqrt:qS +hS +d4 +qK +o3 +A=hE +w0 +if(oC +o3 +wB(512,"cSqr" +a3 +q41 +aQ,"A cHypot" +,aI(A)wM);q4 +Llh;} +} +B +g4 +gV +B)){A=oC +w0 +if(qL +4]o3 +wB(513,"cSqr" +a3"B[IsUnaryOpcode(B)] " +q41 +aQ,"A B cHypot" +," with" +a8(B)qE1(A)wM);q4 +Lli;} +} +} +o2 +wB(23,q41 +q51,mV,);q4 +Llj +gY +if(x>=oP){wB(161,"x[x>=Value_t(0)] " +q51,"[fp_sqrt(x)]" +,wN);q4 +Llk;h8} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Lko +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Lll +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lba;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Llm;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lln +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Llo;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Llp;} +qG +TailCall_cTan:g5 +cTan:qS +cAtan2:wB(354,"cAtan2 " +mR,"cDiv" +,);q4 +Lgf +oF +wB(242,m0 +mR,mR +aA,);q4 +Llq +gY +wB(163,"x " +mR,"[fp_tan(x)]" +,wN);q4 +Lma;oH +qN +oY +cCot +q11(501,aK" cCot " +wI +mR,"B cCot " +aT,aI(A)q91(B)wM);q4 +Lbp;} +} +qG +TailCall_cTanh:g5 +cTanh:qS +hI +wB(243,m0"cTanh" +,"cTanh" +aA,);q4 +Lmb +gY +wB(164,"x cTanh" +,"[fp_tanh(x)]" +,wN);q4 +Lmc;} +qH +TailCall_cTrunc:g5 +cTrunc:qS +hM +wB(138,"x cTrunc" +,"[fp_trunc(x)]" +,wN);q4 +Lmd +gS +wB(394,"A[IsAlwaysIntegerOpcode(A)] cTrunc" +,"A" +,aI(A)wM);gJ +qG +g7 +Default0:;A=w5 +qR +IsComparisonOpcode(h2 +qY +hK +qZ +mW(364,aY"cAdd" +wF,"[x-y] A" +,aI(A)qD1<<"," +a1);q4 +Lme;qT +cAtan +d4 +dP<fp_const_pi<dH>()*g1 +oO +wB(380,"cAtan[fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)]" +wF,"[fp_tan(x)] A" +,aI(A)qD1 +wM);q4 +Lmf;qT +cExp +d4 +dO +wB(370,"cExp[x>Value_t(0)]" +wF,"[fp_log(x)] A" +,aI(A)qD1 +wM);q4 +Lmg;qT +cExp2 +d4 +dO +wB(371,"cExp2[x>Value_t(0)]" +wF,"[fp_log2(x)] A" +,aI(A)qD1 +wM);q4 +Lmh;qT +cLog:g3 +wB(373,wP +mG +wF,"B [fp_exp(x)] A" +,aI(A)qD1 +q91(B)wM);q4 +Lmi;qT +cLog10:g3 +wB(375,wP +aL +wF,"B [fp_pow(Value_t(10),x)] A" +,aI(A)qD1 +q91(B)wM);q4 +Lmj;qT +cLog2:g3 +wB(374,wP +aN +wF,"B [fp_exp2(x)] A" +,aI(A)qD1 +q91(B)wM);q4 +Lmk;qT +h3 +hL +qZ +hP +y>oP){wB(366,"y[y>Value_t(0)]" +wH +wF,"[x/y] A" +,aI(A)qD1<<"," +a1);q4 +Lml;} +if(y<oP){wB(367,"y[y<Value_t(0)]" +wH +wF,"[x/y] {OppositeComparisonOpcode(A)}" +,aI(A)qD1<<"," +a1);q4 +Lmm;} +qT +hI +wB(365,qC1 +wF,"[-x] {OppositeComparisonOpcode(A)}" +,aI(A)qD1 +wM);q4 +Lmn +qU +cPow +d4 +x>oP +gA +qZ +hP +y>oP){wB(368,"y[y>Value_t(0)] cPow[x>Value_t(0)]" +wF,"[fp_pow(x,Value_t(1)/y)] A" +,aI(A)qD1<<"," +a1);q4 +Lmo;} +} +qT +oQ +wB(381,"cSinh" +wF,"[fp_asinh(x)] A" +,aI(A)qD1 +wM);q4 +Lmp +qU +cSqr +d4 +dO +wB(369,"cSqr[x>Value_t(0)]" +wF,mV" [fp_sqrt(x)] A" +,aI(A)qD1 +wM);q4 +Lmq;qT +cTanh +d4 +dP<m7(382,"cTanh[fp_abs(x)<Value_t(1)]" +wF,"[fp_atanh(x)] A" +,aI(A)qD1 +wM);q4 +Lna;h8} +} +} +if(d1 +A +qP +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lnb;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lnc;} +} +} +} +C=w5 +qR +IsCommutativeOrParamSwappableBinaryOpcode(C)){qS +cSin:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(505,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] " +mP" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinCos {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Lnd;} +} +qT +oQ +A=qK +w1 +3 +gA]==cCosh){B=hQ +wB(506,aK" " +aM" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Lne;} +} +h8} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +Lnf:wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:q7=fp_acos +m6 +Lae:q7=fp_acosh +m6 +Laf:oZ +4));gG +Lng:w5=h3;Lnh:g0 +Lni:wE(cMul);q4 +TailCall_cMul;Lag:hV +4 +dT +oZ +4));Lnj:qW +q6 +hA +Lah:q7=x+g1 +1);gG +Lfa:w5=h3;q4 +Lni;Lai:gU +cSub;Lnk:wE(cSub);q4 +TailCall_cSub;Laj:hW +2 +gH +Lnl:g0 +Lnm:wE(cAdd);q4 +TailCall_cAdd;Lak:hW +oR +Lnn:qE +hS);Lno:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Lal:o9;qL +2 +gK +q4 +Lnn;Lam:hW +2 +gH +q4 +Lno;Lan:hW +4 +gH +Lnp:qE +hS);Lnq:qE +B);Loa:w5=cSub;g0 +q4 +Lnk;Lao:o9;oC=q6 +q9 +oR +q4 +Lnp;Lap:hW +oR +q4 +Lnq;Laq:gT +y+x;Lba:qM +Ldn:q5 +gJ +Lbb:q8 +oV +o7 +x +q71 +gX +Lnn;Lbc:mM +A +gX +Lnn;Lbd:gU +dS;Lob:wE(cNotNot);q4 +TailCall_cNotNot;Lbe:gT +fp_and(x +d6 +Lbf:q7=fp_asin +m6 +Lbg:q7=fp_asinh +m6 +Lbh:q7=fp_atan +m6 +Lbi:gT +fp_atan2(gW +Lbj:q7=fp_atanh +m6 +Lbk:q7=fp_cbrt +m6 +Lbl:q1 +cFloor);Loc:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lbm:q7=fp_ceil +m6 +Lbn:g6 +Lod:wE(cCos);q4 +TailCall_cCos;Lbo:q7=fp_cos +m6 +Lbp:dF=cDup;w5=cInv;Loe:wE(cInv);q4 +TailCall_cInv;Lbq:mM +cSinCos);gJ +Lca:g6 +wE(cCosh);q4 +TailCall_cCosh;Lcb:q1 +cSqr +o7 +g1 +1));Lof:qW +q6 +oJ +hS);Log:w5=cSqrt;g0 +wE(cSqrt);q4 +TailCall_cSqrt;Lcc:q7=fp_cosh +m6 +Lcd:mM +cSinhCosh);gJ +Lce:q7=RadiansToDegrees +m6 +Lcf:q1 +cSec +hA +Lcg:q1 +cTan +hA +Lch:q1 +cSin +hA +Lci:oZ));dF +dJ +Loh:qE +dU +oZ +1));Loi:qW +q6);Loj:w5=hS;q4 +Lnl;Lcj:q1 +cNeg +oJ +cExp +hA +Lck:q1 +cNeg +oJ +cExp2 +hA +Lcl:g6 +q4 +Lfa;Lcm:q1 +cNeg +oJ +cPow +hA +Lcn:q1 +cCos +hA +Lco:q1 +cCsc +hA +Lcp:gU +cTan;Lok:wE(cTan);q4 +TailCall_cTan;Lcq:gU +cTanh;Lol:wE(cTanh);q4 +TailCall_cTanh;Lda:q1 +cCot +hA +Ldb:o9;dI +Lom:wE(cDiv);q4 +TailCall_cDiv;Ldc:gT +y/x;q4 +Lba;Ldd:qF1 +q8 +oR +Lon:w5=cDeg;g0 +wE(cDeg);q4 +TailCall_cDeg;Lde:qF1 +q8 +oR +Loo:w5=cRad;g0 +wE(cRad);q4 +TailCall_cRad;Ldf:gT +y/x;dG +Lng;Ldg:q7=g1 +1)/x;q4 +Lfa;Ldh:mM +oI +Lop:g0 +q4 +Lom;Ldi:q8 +3 +gC +oI +qF +x +q71);Loq:w5=cRDiv;g0 +wE(cRDiv);q4 +TailCall_cRDiv;Ldj:hV +3 +gC +oI +qE +B +gX +Loq;Ldk:dI +Lpa:wE(cEqual);q4 +TailCall_cEqual;Ldl:gT +fp_equal(gW +Ldm:d7 +cExp +o7 +fp_exp(x)gX +Lnj;Ldo:q7=fp_exp +m6 +Ldp:d7 +cExp2 +o7 +fp_exp2(x)gX +Lnj;Ldq:q7=fp_exp2 +m6 +Lea:qF +oW +g1 +2))q71);Lpb:qE +h3 +gI +cExp;g0 +wE(cExp);q4 +TailCall_cExp;Leb:q1 +cCeil +gX +Loc;Lec:q7=fp_floor +m6 +Led:gT +fp_less(x +d6 +Lee:qM +q1 +cNeg);Ljm:qE +cAbsNot);gJ +Lef:q7=g1 +0.5)/x;qK=d8 +dS;g0 +q4 +Lob;Leg:gT +fp_lessOrEq(x +d6 +Leh:qM +Ljd:q5 +Lpc:qE +cAbsNotNot);gJ +Lei:q7=fp_int +m6 +Lej:gU +cSec;wE(cSec);q4 +TailCall_cSec;Lek:gU +cSin;Lpd:wE(cSin);q4 +TailCall_cSin;Lel:q1 +cNeg +gI +cPow;Lpe:g0 +Lpf:wE(cPow);q4 +TailCall_cPow;Lem:gU +cCos;q4 +Lod;Len:gU +cCsc;wE(cCsc);q4 +TailCall_cCsc;Leo:q1 +cRSqrt);gJ +Lep:g6 +Lpg:w5=cCot;wE(cCot);q4 +TailCall_cCot;Leq:q7=g1 +1)/x;gJ +Lfb:q7=g1 +0.5)/x;qK=d8 +cNot;g0 +Lph:wE(cNot);q4 +TailCall_cNot;Lfc:gT +fp_less(gW +Lfd:qM +Lje:w3 +Ljm;Lfe:gT +fp_lessOrEq(gW +Lff:qM +q1 +cNeg +gX +Lpc;Lfg:d7 +cLog +o7 +oW +x)o8 +Lfh:q1 +dQ +qE +cLog);Lpi:qW +cDup +gX +Loj;Lfi:q7=oW +x);gJ +Lfj:qF +dR +fp_const_e<dH>()));Lpj:dF +dJ +q4 +Lng;Lfk:d7 +cLog10 +o7 +dR +x)o8 +Lfl:q1 +dQ +qE +cLog10 +gX +Lpi;Lfm:q7=dR +x);gJ +Lfn:qF +o4 +fp_const_e<dH>())gX +Lpj;Lfo:d7 +cLog2 +o7 +o4 +x)o8 +Lfp:q1 +dQ +qE +cLog2 +gX +Lpi;Lfq:q7=o4 +x);gJ +Lga:gT +fp_max(x +d6 +Lgb:gT +fp_min(x +d6 +Lgc:gT +fp_mod(gW +Lgd:hV +oR +q0-=3;q4 +Lpg;Lge:gU +cSqr;Lpk:wE(cSqr);q4 +TailCall_cSqr;Lgf:gU +cDiv;q4 +Lom;Lgg:mM +cSqr +gX +Loc;Lgh:hV +3 +gC +cSqr);dM +Loc;Lgi:q7=x+g1 +1);gG +w5=cPow;q4 +Lpf;Lgj:gG +q4 +Lni;Lgk:gT +x;Lpl:dG +Lnh;Lgl:qF1 +qM +Lpm:hV +4 +gH +Lpn:o6 +x);Lpo:qW +q6 +gX +Lnh;Lgm:qM +q4 +Lpm;Lgn:q8 +4 +gC +B +gX +Lpn;Lgo:q8 +oR +q4 +Lpn;Lgp:qK +dJ +q4 +Ldn;Lgq:dI +q4 +Lni;Lha:qM +Lpp:hV +oR +gJ +Lhb:q7=x+x;q4 +Lgj;Lhc:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Loj;Lhd:gT +x;d7 +dU +qF +y*x +o8 +Lhe:q7=RadiansToDegrees(x +gX +Lgq;Lhf:qG1 +q8 +4 +gH +Lpq:qE +dU +Lqa:qE +B +gI +cDiv;q4 +Lop;Lhg:o9;oC=q6 +q9 +oR +q4 +Lpq;Lhh:qG1 +q8 +oR +q4 +Lqa;Lhi:q8 +4 +gH +q4 +Lnh;Lhj:q8 +4 +dT +qF +x+x +gX +Lpo;Lhk:qF1 +qM +q4 +Lpp;Lhl:qG1 +q4 +Lpl;Lhm:o9;q4 +Lgq;Lhn:qG1 +q8 +oR +Lqb:dM +Loq;Lho:o9;qL +2 +gK +q4 +Lqb;Lhp:qG1 +dG +Loq;Lhq:q7=h4 +gX +Lgq;Lia:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Loa;Lib:qG1 +q4 +Lba;Lic:qM +w3 +Loc;Lid:dF=cDup;dW-=1;qM +Lqc:w5=hS;q4 +Lnm;Lie:qM +w3 +Lon;Lif:qM +w3 +Loo;Lig:hV +oV +gX +Lpq;Lih:hV +2 +gH +Lqd:qE +cSqr +gX +Lnh;Lii:q8 +oV +o7 +x +q71 +gX +Lqb;Lij:mM +A +gX +Lqb;Lik:hV +oR +q4 +Lqd;Lil:dI +Lqe:wE(cNEqual);q4 +TailCall_cNEqual;Lim:gT +fp_nequal(gW +Lin:o9;q4 +Lcl;Lio:o9 +gB +cSin;g0 +q4 +Lpd;Lip:o9 +gB +cSinh;g0 +wE(cSinh);q4 +TailCall_cSinh;Liq:o9 +gB +cTan;g0 +q4 +Lok;Lja:o9 +gB +cTanh;g0 +q4 +Lol;Ljb:o9;gJ +Ljc:g6 +q4 +Lph;Ljf:gU +cNEqual;q4 +Lqe;Ljg:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Ljh:gU +cLess;wE(cLess);q4 +TailCall_cLess;Lji:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Ljj:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Ljk:gU +w8;q4 +Lpa;Ljl:q7=fp_not +m6 +Ljn:gT +fp_or(x +d6 +Ljo:d7 +dQ +qF +x+x);Lqf:qW +q6 +gX +Lpe;Ljp:dL +Lpb;Ljq:qK=d8 +cExp2;g0 +wE(cExp2);q4 +TailCall_cExp2;Lka:qG1 +dG +Lpe;Lkb:qK +dJ +q1 +h3 +gX +Lpe;Lkc:dI +q4 +Lpf;Lkd:q8 +3 +dT +qF +x +gX +Lqf;Lke:q7=g1 +gX +Loh;Lkf:qM +w3 +Log;Lkg:qM +q5 +w5=cCbrt;g0 +wE(cCbrt);q4 +TailCall_cCbrt;Lkh:qM +q1 +cCbrt);Lqg:w5=cInv;g0 +q4 +Loe;Lki:qM +q4 +Leo;Lkj:qM +w3 +Lqg;Lkk:qF1 +q8 +3 +gC +dQ +qF +y*x +gX +Lqf;Lkl:q7=x+x;q4 +Lkc;Lkm:gT +oX +gW +Lkn:q1 +cTanh +gX +Lqg;Lko:oZ)gX +Lpj;Lkp:q7=h4 +gX +Lcl;Lkq:q7=h4);gJ +Lla:mM +cSinCos +gX +Lqg;Llb:q1 +cSin +gX +Loc;Llc:q7=fp_sin +m6 +Lld:q1 +cSqr +o7 +g1-1)gX +Lof;Lle:q1 +cSinh +gX +Loc;Llf:q7=fp_sinh +m6 +Llg:g6 +q4 +Lpk;Llh:hV +4 +gC +A);Lqh:w5=cHypot;g0 +wE(cHypot);q4 +TailCall_cHypot;Lli:hV +5 +gC +A +oJ +B +gX +Lqh;Llj:gU +cAbs;q4 +Lnf;Llk:q7=fp_sqrt +m6 +Lll:g6 +q4 +Lqc;Llm:gT +y-x;q4 +Lba;Lln:o9;q4 +Lqc;Llo:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lno;Llp:mM +A +oJ +cSub +gX +Lno;Llq:q1 +cTan +gX +Loc;Lma:q7=fp_tan +m6 +Lmb:q1 +cTanh +gX +Loc;Lmc:q7=fp_tanh +m6 +Lmd:q7=fp_trunc +m6 +Lme:gT +x-y;Lqi:q8 +2 +gH +Lqj:qE +A);gJ +Lmf:q7=fp_tan(x);Lqk:dL +Lqj;Lmg:q7=oW +x +gX +Lqk;Lmh:q7=o4 +x +gX +Lqk;Lmi:q7=fp_exp(x +gX +Lqk;Lmj:q7=oX +g1 +10),x +gX +Lqk;Lmk:q7=fp_exp2(x +gX +Lqk;Lml:gT +x/y;q4 +Lqi;Lmm:gT +x/y;q8 +2 +gH +Lql:qE +OppositeComparisonOpcode(A));gJ +Lmn:o9;dL +Lql;Lmo:gT +oX +x,g1 +1)/y +gX +Lqi;Lmp:q7=fp_asinh(x +gX +Lqk;Lmq:d7 +dQ +qF +fp_sqrt(x)q71 +gX +Lqj;Lna:q7=fp_atanh(x +gX +Lqk;Lnb:qW +cDup);gJ +Lnc:dF=cDup;gJ +Lnd:hV +3 +gC +cSinCos);Lqm:qE +GetParamSwappedBinaryOpcode(C));gJ +Lne:hV +3 +gC +cSinhCosh +gX +Lqm;gJ +q4 +TailCall_cAcos;q4 +TailCall_cAcosh;q4 +TailCall_cAnd;q4 +TailCall_cAsin;q4 +TailCall_cAsinh;q4 +TailCall_cAtan;q4 +TailCall_cAtan2;q4 +TailCall_cAtanh;q4 +TailCall_cCeil;q4 +TailCall_cFloor;q4 +TailCall_cInt;q4 +TailCall_cLog;q4 +TailCall_cLog10;q4 +TailCall_cLog2;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cOr;q4 +TailCall_cRDiv;q4 +TailCall_cRad;q4 +TailCall_cSec;q4 +TailCall_cSin;q4 +TailCall_cSinh;q4 +TailCall_cSqrt;q4 +TailCall_cSub;q4 +TailCall_cTan;q4 +TailCall_cTanh;q4 +TailCall_cTrunc; +#endif +#if((FP_COMPLEX_VERSION) && (FP_FLOAT_VERSION)) +dH +x;dH +gE +A;hT +C;hT +D;qQ +w5){TailCall_cAbs:g5 +cAbs:qS +h0} +qH +TailCall_cAcos:g5 +cAcos:qY +wB(172,"x cAcos" +,"[fp_acos(x)]" +,wN);q4 +Lad;} +qH +TailCall_cAcosh:g5 +cAcosh:qY +wB(169,"x cAcosh" +,"[fp_acosh(x)]" +,wN);q4 +Lae;} +qH +TailCall_cAdd:g5 +hG +Laf;qT +h3 +hL]==hS){if(qL +gZ +Lag;} +h8} +q4 +dX +qU +d2 +gF +h1 +wB(313,"cDup" +a7 +aZ,"[x+Value_t(1)]" +wH,wN);q4 +Lah;} +} +q4 +dX +oF +wB(199,qC1 +aZ,"cSub" +,);q4 +Lai +gY +hK +qZ +mW(127,aY"cAdd" +mD,"[y+x]" +aZ,q81);q4 +Laj;qT +cRSub:qQ +hE +d3 +3 +qZ +mW(298,aY"cAdd" +mE +mD,mN +aZ +mE,q81);q4 +Lak;qT +hI +wB(299,m0 +a6 +mD,"[-x]" +aZ +mE,wN);q4 +Lal +qU +q6:mW(297,aY +a6 +mD,mN +mE,q81);q4 +Lam;qT +oA +Lan;qT +hI +wB(293,m0"B[IsVarOpcode(B)]" +aW +mD,"[-x]" +aZ" B" +aW,wA"," +a8(B)wM);q4 +Lao +qU +q6:mW(291,aY"B[IsVarOpcode(B)]" +aW +mD,mN" B" +aW,wA"," +a8(B)<<"," +a1);q4 +Lap;} +w9 +mW(105,aY +aF,"[y+x]" +,q81);q4 +Laq;} +g8)){wB(57,"x[x==Value_t()]" +aZ,,wN);q4 +Lba;h8 +g7 +dX:;A=dF +w0 +oY +cRSub +dV +wB(290,"x" +mE +a3"cAdd" +,"[DO_STACKPLUS1] A [x]" +aZ +mE,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lbb;} +wB(295,a6 +a3"cAdd" +,"[DO_STACKPLUS1] A" +aZ +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lbc;} +qG +TailCall_cAnd:g5 +cAnd +hH +wB(224,mX"cAnd" +,aJ,);q4 +w7 +m9(117,mA"cAnd" +,"[fp_and(x,y)]" +,q81);q4 +Lbe;h8} +qH +TailCall_cArg:g5 +cArg:qY +wB(190,"x cArg" +,"[fp_arg(x)]" +,wN);q4 +Lbf;} +qH +TailCall_cAsin:g5 +cAsin:qY +wB(173,"x cAsin" +,"[fp_asin(x)]" +,wN);q4 +Lbg;} +qH +TailCall_cAsinh:g5 +cAsinh:qY +wB(170,"x cAsinh" +,"[fp_asinh(x)]" +,wN);q4 +Lbh;} +qH +TailCall_cAtan:g5 +cAtan:qY +if(g1 +x.real(),fp_abs(x.imag()))!=g1 +0,oG +wB(174,"x[Value_t(x.real(),fp_abs(x.imag()))!=Value_t(0,1)] cAtan" +,"[fp_atan(x)]" +,wN);q4 +Lbi;qG +TailCall_cAtan2:g5 +cAtan2:qY +m9(139,mA"cAtan2" +,"[fp_atan2(y,x)]" +,q81);q4 +Lbj;qG +TailCall_cAtanh:g5 +cAtanh:qY +if(g1 +fp_abs(x.real()),x.imag())!=g1 +1,0)){wB(171,"x[Value_t(fp_abs(x.real()),x.imag())!=Value_t(1,0)] cAtanh" +,"[fp_atanh(x)]" +,wN);q4 +Lbk;qG +TailCall_cCbrt:g5 +cCbrt:qY +wB(175,"x cCbrt" +,"[fp_cbrt(x)]" +,wN);q4 +Lbl;} +qH +TailCall_cCeil:g5 +cCeil:qS +hI +wB(402,m0 +q01,mS +aA,);q4 +Lbm +gY +wB(135,"x " +q01,"[fp_ceil(x)]" +,wN);q4 +Lbn +gS +wB(396,"A[IsAlwaysIntegerOpcode(A)] " +q01,"A" +,aI(A)wM);gJ +qG +TailCall_cConj:g5 +cConj:qS +cConj:wB(63,mY" " +mY,,);oS +gY +wB(193,"x " +mY,"[fp_conj(x)]" +,wN);q4 +Lbp;} +qH +TailCall_cCos:g5 +cCos:qS +cAcos:wB(346,"cAcos " +aO,,);q4 +oE +wB(238,m0 +aO,aO,);q4 +Lbq +gY +wB(176,"x " +aO,"[fp_cos(x)]" +,wN);q4 +Lca;oH +qN +qQ +h9 +cSec:hD +wB(500,aK" cSec " +wI +aO,"B cSec " +aT,aI(A)q91(B)wM);q4 +Lcb;qT +cSin:hD +wB(494,aK" " +mP" " +wI +aO,"B cSinCos" +,aI(A)q91(B)wM);q4 +Lcc;h8} +qG +TailCall_cCosh:g5 +cCosh:qS +cAsinh:wB(450,"cAsinh " +aM,"[DO_STACKPLUS1] " +q41"[Value_t(1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lcd +oF +wB(239,m0 +aM,aM,);q4 +Lce +gY +wB(177,"x " +aM,"[fp_cosh(x)]" +,wN);q4 +Lcf;oH +qN +oY +cSinh +q11(507,aK" cSinh " +wI +aM,"B cSinhCosh" +,aI(A)q91(B)wM);q4 +Lcg;} +} +qG +TailCall_cCot:g5 +cCot:A=qN +oY +cTan +q11(498,aK" " +mR" " +wI"cCot" +,"B " +mR" " +aT,aI(A)q91(B)wM);q4 +Lcb;} +qG +TailCall_cCsc:g5 +cCsc:A=qN +oY +cSin +q11(496,aK" " +mP" " +wI"cCsc" +,"B " +mP" " +aT,aI(A)q91(B)wM);q4 +Lcb;} +qG +TailCall_cDeg:g5 +cDeg:qY +wB(133,"x cDeg" +,"[RadiansToDegrees(x)]" +,wN);q4 +Lch;} +qH +TailCall_cDiv:g5 +cDiv:qS +cCos:wB(250,aO +mF,"cSec" +wH,);q4 +Lci +qU +cCot:wB(254,"cCot" +mF,mR +wH,);q4 +Lcj +qU +cCsc:wB(252,"cCsc" +mF,mP +wH,);q4 +Lck +qU +cDup:wB(78,"cDup" +mF,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lcl +qU +w2 +wB(408,"cExp" +mF,m0"cExp" +wH,);q4 +Lcm +qU +cExp2:wB(409,"cExp2" +mF,m0"cExp2" +wH,);q4 +Lcn +qU +cInv:wB(213,aU +mF,"cMul" +,);q4 +Lco +qU +cPow:wB(407,"cPow" +mF,m0"cPow" +wH,);q4 +Lcp +qU +cSec:wB(253,"cSec" +mF,aO +wH,);q4 +Lcq +qU +cSin:wB(249,mP +mF,"cCsc" +wH,);q4 +Lda +qU +cSinCos:wB(502,"cSinCos" +mF,mR,);q4 +Ldb +qU +cSinhCosh:wB(509,"cSinhCosh" +mF,"cTanh" +,);q4 +Ldc +qU +cTan:wB(251,mR +mF,"cCot" +wH,);q4 +Ldd +gY +if +hF +gQ +hI +wB(125,m0 +a4"cDiv" +,"[-x]" +mF,wN);q4 +Lde +qU +q6:mW(103,aY +a4"cDiv" +,"[y/x]" +,q81);q4 +Ldf;} +} +g8 +oG +wB(56,wO"cDiv" +,,wN);q4 +Lba;} +dB +h3 +gA +qZ +hP(y/x)==fp_const_rad_to_deg +h7 +wB(321,"y[(y/x)==fp_const_rad_to_deg<Value_t>()]" +wH" " +wR,"cDeg" +,q81);q4 +Ldg;} +if((y/x)==fp_const_deg_to_rad +h7 +wB(322,"y[(y/x)==fp_const_deg_to_rad<Value_t>()]" +wH" " +wR,"cRad" +,q81);q4 +Ldh;} +wB(323,"y" +wH" " +wR,"[y/x]" +wH,q81);q4 +Ldi;} +} +wB(325,wR,"[Value_t(1)/x]" +wH,wN);q4 +Ldj;} +gP +cDiv:hC +wB(271,aX"cDiv " +wV,"[DO_STACKPLUS1] B A" +wH +mF,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Ldk;qT +cRDiv:qQ +hE +qV +hM +wB(266,"x" +a9" " +wV,"A" +wH" [x]" +a9,aI(A)qD1 +wM);q4 +Ldl;g7 +hC +wB(265,"B[IsVarOpcode(B)]" +a9" " +wV,"A" +wH" B" +a9,aI(A)q91(B)wM);q4 +Ldm;} +h8} +qG +TailCall_cEqual:g5 +w8:oL +hU +wB(359,m1 +aE,"[x] " +aE,wN);q4 +Ldn +qU +cSqr:wB(361,q41 +wL +aE,"[x] " +aE,wN);q4 +Ldn;} +} +m9(115,mA +aE,"[fp_equal(y,x)]" +,q81);q4 +Ldo;qG +TailCall_cExp:g5 +w2 +qS +hS +gM +wB(404,aF +mL,q21"[fp_exp(x)]" +wH,wN);q4 +Ldp;qT +cLog:A=dE +wB(340,wJ +mG +mL,"A" +,aI(A)wM);oS;qT +hM +wB(178,"x" +mL,"[fp_exp(x)]" +,wN);q4 +Ldq;} +qH +TailCall_cExp2:g5 +cExp2:qS +hS +gM +wB(405,aF +q31,"cExp2 [fp_exp2(x)]" +wH,wN);q4 +Lea;qT +cLog2:A=dE +wB(341,wJ +aN +q31,"A" +,aI(A)wM);oS;qT +hM +wB(179,"x" +q31,"[fp_exp2(x)]" +,wN);q4 +Leb;} +wB(479,"cExp2" +,"[DO_STACKPLUS1] [fp_log(Value_t(2))]" +wH +mL,);incStackPtr();--mStackPtr;q4 +Lec;TailCall_cFloor:g5 +cFloor:qS +hI +wB(401,m0 +mS,q01 +aA,);q4 +Led +gY +wB(136,"x " +mS,"[fp_floor(x)]" +,wN);q4 +Lee +gS +wB(395,"A[IsAlwaysIntegerOpcode(A)] " +mS,"A" +,aI(A)wM);gJ +qG +TailCall_cGreater:g5 +o1:qY +m9(113,mA +m2,"[fp_less(x,y)]" +,q81);q4 +Lef;qG +TailCall_cGreaterOrEq:g5 +dK:qY +m9(114,mA +aG,"[fp_lessOrEq(x,y)]" +,q81);q4 +Leg;qG +TailCall_cHypot:g5 +cHypot +d4 +dF==cSinCos){wB(84,"cSinCos cHypot" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,);q4 +Lcl;} +qH +TailCall_cImag:g5 +cImag:qS +cAbs:wB(81,mV" " +mZ,"[Value_t()]" +wH,);q4 +Leh +qU +cReal:wB(80,"cReal " +mZ,"[Value_t()]" +wH,);q4 +Leh +gY +wB(192,"x " +mZ,"[fp_imag(x)]" +,wN);q4 +Lei;} +qH +TailCall_cInt:g5 +cInt:qS +hM +wB(137,"x cInt" +,"[fp_int(x)]" +,wN);q4 +Lej +gS +wB(397,"A[IsAlwaysIntegerOpcode(A)] cInt" +,"A" +,aI(A)wM);gJ +qG +TailCall_cInv:g5 +cInv:qS +cCos:wB(256,aO" " +aU,"cSec" +,);q4 +Lek +qU +cCot:wB(260,"cCot " +aU,mR,);q4 +Ldb +qU +cCsc:wB(258,"cCsc " +aU,mP,);q4 +Lel +qU +cInv:wB(62,aU" " +aU,,);oS +qU +cPow:wB(355,q61 +aU,m0"cPow" +,);q4 +Lem +qU +cSec:wB(259,"cSec " +aU,aO,);q4 +Len +qU +cSin:wB(255,mP" " +aU,"cCsc" +,);q4 +Leo +qU +cSqrt:wB(206,q51" " +aU,"cRSqrt" +,);q4 +Lep +qU +cTan:wB(257,mR" " +aU,"cCot" +,);q4 +Leq +gY +if +hF)){wB(101,a4 +aU,"[Value_t(1)/x]" +,wN);q4 +Lfa;h8} +qH +TailCall_cLess:g5 +cLess:oL)){A=dE +wB(301,wJ +wL +mJ,mK,qB1(A)wM);q4 +Lfb;} +} +m9(111,mA +mJ,"[fp_less(y,x)]" +,q81);q4 +Lfc;qG +TailCall_cLessOrEq:g5 +cLessOrEq:qY +m9(112,mA +aR,"[fp_lessOrEq(y,x)]" +,q81);q4 +Lfd;qG +TailCall_cLog:g5 +cLog:mT(343,q21 +mG,,);oS +qU +gL +wB(491,mU +mG,mG" [fp_log(x)]" +aZ,wN);q4 +Lfe;} +oD +wB(180,qA1 +mG,"[fp_log(x)]" +,wN);q4 +Lff;h8} +qH +TailCall_cLog10:g5 +cLog10:mT(481,q21 +aL,"[DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfg +qU +gL +wB(492,mU +aL,aL" [fp_log10(x)]" +aZ,wN);q4 +Lfh;} +oD +wB(181,qA1 +aL,"[fp_log10(x)]" +,wN);q4 +Lfi;h8} +qH +TailCall_cLog2:g5 +cLog2:mT(480,q21 +aN,"[DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())]" +wH,);incStackPtr();--mStackPtr;q4 +Lfj +qU +cExp2:wB(344,"cExp2 " +aN,,);oS +qU +gL +wB(490,mU +aN,aN" [fp_log2(x)]" +aZ,wN);q4 +Lfk;} +oD +wB(182,qA1 +aN,"[fp_log2(x)]" +,wN);q4 +Lfl;h8} +qH +TailCall_cMax:g5 +cMax +hH +wB(60,mX +mB,,);oS +gY +m9(141,mA +mB,"[fp_max(x,y)]" +,q81);q4 +Lfm;} +gP +cDup:hD +wB(66,aK +mQ +a3 +mB,"B" +mQ,aI(A)q91(B)wM);oS;qT +cMax:hD +wB(68,aK" " +mB +a3 +mB,"B " +mB,aI(A)q91(B)wM);oS;h8} +qG +TailCall_cMin:g5 +cMin +hH +wB(59,mX +mC,,);oS +gY +m9(140,mA +mC,"[fp_min(x,y)]" +,q81);q4 +Lfn;} +gP +cDup:hD +wB(65,aK +mQ +a3 +mC,"B" +mQ,aI(A)q91(B)wM);oS;qT +cMin:hD +wB(67,aK" " +mC +a3 +mC,"B " +mC,aI(A)q91(B)wM);oS;h8} +qG +TailCall_cMod:g5 +cMod:qY +if +hF)){m9(104,aY +a4"cMod" +,"[fp_mod(y,x)]" +,q81);q4 +Lfo;} +qG +TailCall_cMul:g5 +h3:qS +cCsc:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(508,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cCsc" +wH,"B cCot" +,aI(A)q91(B)wM);q4 +Lfp;} +} +} +q4 +dY +qU +cDup:wB(202,"cDup" +wH,"cSqr" +,);q4 +Lfq +qU +cInv:wB(214,aU +wH,"cDiv" +,);q4 +Lga +oF +qQ +h9 +cDup:wB(467,"cDup" +aA +wH,"cSqr" +aA,);q4 +Lgb;oH +qK +qO +A)gA +oM +B=hQ +wB(473,aK +wH +a3 +qC1 +wH,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgc;} +} +} +} +q4 +dY +qU +cPow +gM +if +gF +h1 +wB(314,mX +m8 +wH,"[x+Value_t(1)] cPow" +,wN);q4 +Lgd;} +} +q4 +dY +gY +g8 +gQ +h3:A=hE +w0 +wB(93,wS" " +wZ,wX,qB1(A)wM);q4 +Lge;} +q4 +Default3;g7 +Default3:;A=qK +qR +IsBinaryOpcode(A)g2 +h2 +qQ +hE +qV +q6:mW(92,aY +wD,wX,qB1(A)<<"," +a1);q4 +Lgf;g7 +B +g4 +IsBinaryOpcode(B)g2 +B)){qQ +oC +qV +q6:mW(96,aY +wK,mK,qB1(A)q91(B)<<"," +a1);q4 +Lgg;g7 +C=oC +qO +C)){wB(94,"C[IsVarOpcode(C)] " +wK,mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgh;} +if(gV +C)g2 +C)){wB(95,"C[IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] " +wK,"B " +mK,qB1(A)q91(B)<<", C" +wY(C)wM);q4 +Lgi;} +} +} +if(d1 +B)){wB(90,aX +wD,wX,qB1(A)q91(B)wM);q4 +Lge;} +if(gV +B)g2 +B)){wB(91,"B[IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] " +wD,mK,qB1(A)q91(B)wM);q4 +Lgj;} +} +} +if(d1 +h2 +wB(88,a5" " +wZ,"[x]" +,qB1(A)wM);q4 +Lgk;} +if(gV +A)g2 +h2 +wB(89,"A[IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] " +wZ,wX,qB1(A)wM);q4 +Lgl;} +} +} +qQ +h9 +hS:qQ +hE +qV +cDup +d4 +x+oU +wB(316,"cDup[x+x==Value_t(1)]" +aZ +a7,,wN);q4 +Lgm;} +wB(317,aH +a7,"[x+x]" +wH,wN);q4 +Lgn +qU +o5 +3 +qZ +hO +A=qL +4]w0 +wB(386,a5" y" +wH +aZ +a7,wX" A " +m3 +aZ,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lgo;} +w9 +mW(385,aY"cAdd" +a7,wX" [y*x]" +aZ,q81);q4 +Lgp;qT +cDeg:wB(209,"cDeg" +a7,"[RadiansToDegrees(x)]" +wH,wN);q4 +Lgq +qU +cDiv +oB +qV +o5 +4 +qZ +mW(278,"y" +wH" " +aX +mH,m3 +qH1,wA"," +a8(B)<<"," +a1);q4 +Lha;qT +hI +wB(279,m0 +aX +mH,mI +qH1,wA"," +a8(B)wM);q4 +Lhb +qU +q6:mW(277,aY +aX +mH,"[y*x] B" +mF,wA"," +a8(B)<<"," +a1);q4 +Lhc;} +qT +h3:qQ +hE +d3 +3 +h1 +if(x+oU +wB(318,"cDup[x+x==Value_t(1)]" +aZ +wH +a7,"cMul" +,wN);q4 +Lhd;} +wB(319,aH +wH +a7,"cMul [x+x]" +wH,wN);q4 +Lhe;w9 +hP +y*oU +wB(70,"y[y*x==Value_t(1)]" +wH +a7,,q81);q4 +Lhf;} +if((y*x)==fp_const_rad_to_deg +h7 +wB(307,"y[(y*x)==fp_const_rad_to_deg<Value_t>()]" +wH +a7,"cDeg" +,q81);q4 +Ldg;} +if((y*x)==fp_const_deg_to_rad +h7 +wB(308,"y[(y*x)==fp_const_deg_to_rad<Value_t>()]" +wH +a7,"cRad" +,q81);q4 +Ldh;} +wB(128,"y" +wH +a7,m3,q81);q4 +Lhg;qT +hI +wB(122,qC1 +a7,mI,wN);q4 +Lhh +qU +cRDiv:qQ +hE +qV +o5 +3 +qZ +mW(285,"y" +wH +a9 +a7,m3 +a9,q81);q4 +Lhi;qT +hI +wB(286,qC1 +a9 +a7,mI +a9,wN);q4 +Lhj +qU +q6:mW(284,"y" +a9 +a7,"[y*x]" +a9,q81);q4 +Lhk;qT +cRad:wB(210,"cRad" +a7,"[DegreesToRadians(x)]" +wH,wN);q4 +Lhl +qU +cSub +hL +oM +if(qL +3 +qZ +hO +A=qL +4]w0 +wB(387,a5" y" +wH +aW +a7,wX" A " +m3 +aW,wA", " +aY"= " +<<y +qE1(A)wM);q4 +Lhm;} +} +w9 +mW(102,"y" +a7,"[y*x]" +,q81);q4 +Lhn;} +g8 +oG +wB(55,"x[x==Value_t(1)]" +wH,,wN);q4 +Lba;} +g8-oG +wB(124,"x[x==Value_t(-1)]" +wH,qC1,wN);q4 +Lho;} +g8 +2)){wB(198,"x[x==Value_t(2)]" +wH,aH,wN);q4 +Lhp;} +if(x==fp_const_rad_to_deg +h7 +wB(207,"x[x==fp_const_rad_to_deg<Value_t>()]" +wH,"cDeg" +,wN);q4 +Lhq;} +if(x==fp_const_deg_to_rad +h7 +wB(208,"x[x==fp_const_deg_to_rad<Value_t>()]" +wH,"cRad" +,wN);q4 +Lia;h8 +g7 +dY:;A=dF +qO +A +gQ +cDiv:hC +wB(274,aX"cDiv " +wS,"[DO_STACKPLUS1] A" +wH +qH1,aI(A)q91(B)wM);incStackPtr();--mStackPtr;q4 +Lib;} +q4 +d5 +h3:qQ +hE +qV +hI +B=hQ +wB(470,aK +aA +wH" " +wS,m5 +wH +aA,aI(A)q91(B)wM);q4 +Lgc;} +q4 +dZ;g7 +dZ:;hD +wB(461,aK +wH" " +wS,m5 +wH,aI(A)q91(B)wM);q4 +Lic;} +} +q4 +d5 +hI +hD +wB(464,aK +aA" " +wS,m5 +aA,aI(A)q91(B)wM);q4 +Lgb;} +q4 +d5 +cRDiv +hL +qZ +qC +wB(267,"x" +a9" " +wS,"[DO_STACKPLUS1] " +mK +a9,aI(A)qD1 +wM);incStackPtr();--mStackPtr;q4 +Lid;} +wB(281,"cRDiv " +wS,"[DO_STACKPLUS1] A" +wH +a9,aI(A)wM);incStackPtr();--mStackPtr;q4 +Lie;g7 +Default4:;B=qK +qR +w4 +wB(458,aK" " +wS,m5,aI(A)q91(B)wM);q4 +Lfq;} +} +} +if(gV +h2 +B=qK +qO +B +qP +1 +gA +oM +C=oC +qR +C==A){D=qL +4]qR +D==B){wB(477,"D[D==B] C[C==A]" +wH" B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +wH,"D C cSqr" +wH,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Lif;} +} +} +} +qG +TailCall_cNEqual:g5 +cNEqual:oL +hU +wB(360,m1 +wW,"[x] " +wW,wN);q4 +Lig +qU +cSqr:wB(362,q41 +wL +wW,"[x] " +wW,wN);q4 +Lig;} +} +m9(116,mA +wW,"[fp_nequal(y,x)]" +,q81);q4 +Lih;qG +TailCall_cNeg:g5 +hI +qS +h3 +gM +wB(123,"x" +wH +aA,mI,wN);q4 +Lii;qT +hI +wB(61,qC1 +aA,,);oS +qU +cSin:g9 +wB(244,"x" +wH" " +mP +aA,mI" " +mP,wN);q4 +Lij;} +qT +oQ +g9 +wB(245,"x" +wH" cSinh" +aA,mI" cSinh" +,wN);q4 +Lik;} +qT +cTan:g9 +wB(246,"x" +wH" " +mR +aA,mI" " +mR,wN);q4 +Lil;} +qT +cTanh:g9 +wB(247,"x" +wH" cTanh" +aA,mI" cTanh" +,wN);q4 +Lim;} +qT +hM +wB(100,"x" +aA,"[-x]" +,wN);q4 +Lin;} +qH +TailCall_cNot:g5 +cNot:qS +cAbsNotNot:wB(231,"cAbsNotNot" +a0,aS,);q4 +Lio +qU +w8:wB(220,aE +a0,wW,);q4 +Lip +qU +o1:wB(218,m2 +a0,aR,);q4 +Liq +qU +dK:wB(219,aG +a0,mJ,);q4 +Lja +qU +cLess:wB(216,mJ +a0,aG,);q4 +Ljb +qU +cLessOrEq:wB(217,aR +a0,m2,);q4 +Ljc +qU +cNEqual:wB(221,wW +a0,aE,);q4 +Ljd +qU +cNot:wB(229,"cNot" +a0,aJ,);q4 +Lbd +qU +dS:wB(230,aJ +a0,"cNot" +,);q4 +Lje +gY +wB(107,"x" +a0,"[fp_not(x)]" +,wN);q4 +Ljf;} +qH +TailCall_cNotNot:g5 +dS +d4 +dF==cNot){wB(232,"cNot " +aJ,"cNot" +,);gJ} +qH +TailCall_cOr:g5 +cOr +hH +wB(223,mX"cOr" +,aJ,);q4 +w7 +m9(118,mA"cOr" +,"[fp_or(x,y)]" +,q81);q4 +Ljg;h8} +qH +TailCall_cPolar:g5 +cPolar +d4 +q0[0 +qZ +y=q7;qJ +x +gO +wB(194,"x " +aY"cPolar" +,"[fp_polar(x,y)]" +," with " +aY"= " +<<y +qD1 +wM);q4 +Ljh;qG +TailCall_cPow:g5 +cPow:qY +if(isInteger(x +gQ +w2 +wB(43,q21 +wT,wX +mL,wN);q4 +Lji +qU +cExp2:wB(44,"cExp2 " +wT,wX +q31,wN);q4 +Ljj +qU +cPow +hL +qZ +hP!isInteger(y)){wB(42,"y[!isInteger(y)] " +q61 +wT,aP,q81);q4 +Ljk;} +} +wB(45,q61 +wT,wX" cPow" +,wN);q4 +Ljl;} +} +g8)){wB(83,"x[x==Value_t()] cPow" +,"[Value_t()]" +wH" [Value_t(1)]" +aZ,wN);q4 +Ljm;} +g8 +oO +wB(332,"x[x==Value_t(0.5)] cPow" +,q51,wN);q4 +Ljn;} +g8 +1)/g1 +3)){wB(333,"x[x==Value_t(1)/Value_t(3)] cPow" +,"cCbrt" +,wN);q4 +Ljo;} +g8 +1)/g1-3)){wB(334,"x[x==Value_t(1)/Value_t(-3)] cPow" +,"cCbrt " +aU,wN);q4 +Ljp;} +g8-oO +wB(335,"x[x==Value_t(-0.5)] cPow" +,"cRSqrt" +,wN);q4 +Ljq;} +g8-oG +wB(336,"x[x==Value_t(-1)] cPow" +,aU,wN);q4 +Lka;} +qQ +h9 +cPow +hL +qZ +mW(330,aY +q61 +m8,aP,q81);q4 +Ljk;o2 +wB(46,q41 +m8,"[x+x] cPow" +,wN);q4 +Lkb +qU +q6:mW(189,aY +m8,"[fp_pow(y,x)]" +,q81);q4 +Lkc;} +wB(455,m8,"[DO_POWI]" +,wN)qR +TryCompilePowi(x))gJ} +qH +TailCall_cRDiv:g5 +cRDiv:qS +cSinCos:wB(503,"cSinCos" +a9,"cCot" +,);q4 +Leq +qU +cSinhCosh:wB(510,"cSinhCosh" +a9,"cTanh " +aU,);q4 +Lkd +gY +g8 +oG +wB(268,wO"cRDiv" +,aU,wN);q4 +Lka;h8} +qH +TailCall_cRSub:g5 +cRSub +d4 +q0[0 +h1 +wB(77,"cDup" +mE,"[Value_t()]" +wH,);q4 +Leh;} +qH +TailCall_cRad:g5 +cRad:qS +h3 +gM +wB(211,"x" +wH" cRad" +,"[DegreesToRadians(x)]" +wH,wN);q4 +Lke;qT +hM +wB(134,"x cRad" +,"[DegreesToRadians(x)]" +,wN);q4 +Lkf;} +qH +TailCall_cReal:g5 +cReal:qY +wB(191,"x cReal" +,"[fp_real(x)]" +,wN);q4 +Lkg;} +qH +TailCall_cSec:g5 +cSec:A=qN +qQ +h9 +cCos:hD +wB(497,aK" " +aO" " +wI"cSec" +,"B " +aO" " +aT,aI(A)q91(B)wM);q4 +Lcb;qT +cSin:hD +wB(495,aK" " +mP" " +wI"cSec" +,"B cSinCos " +aU,aI(A)q91(B)wM);q4 +Lkh;h8 +qG +TailCall_cSin:g5 +cSin:qS +cAsin:wB(345,"cAsin " +mP,,);q4 +oE +wB(240,m0 +mP,mP +aA,);q4 +Lki +gY +wB(183,"x " +mP,"[fp_sin(x)]" +,wN);q4 +Lkj;oH +qN +oY +cCsc +q11(499,aK" cCsc " +wI +mP,"B cCsc " +aT,aI(A)q91(B)wM);q4 +Lcb;} +} +qG +TailCall_cSinh:g5 +oQ +qS +cAcosh:wB(437,"cAcosh cSinh" +,"[DO_STACKPLUS1] " +q41"[Value_t(-1)] " +aQ,);incStackPtr();--mStackPtr;q4 +Lkk +qU +cAsinh:wB(349,"cAsinh cSinh" +,,);q4 +oE +wB(241,m0"cSinh" +,"cSinh" +aA,);q4 +Lkl +gY +wB(184,"x cSinh" +,"[fp_sinh(x)]" +,wN);q4 +Lkm;} +qH +TailCall_cSqr:g5 +cSqr:qS +cAbs:wB(204,mV" cSqr" +,"cSqr" +,);q4 +Lkn +oF +wB(203,m0"cSqr" +,"cSqr" +,);q4 +Lkn +qU +cSqrt:A=dE +wB(338,wJ +q51" cSqr" +,"A" +,aI(A)wM);oS;h8} +qH +TailCall_cSqrt:g5 +cSqrt:qS +hS +d4 +qK +o3 +A=hE +w0 +if(oC +o3 +wB(512,"cSqr" +a3 +q41 +aQ,"A cHypot" +,aI(A)wM);q4 +Lko;} +} +B +g4 +gV +B)){A=oC +w0 +if(qL +4]o3 +wB(513,"cSqr" +a3"B[IsUnaryOpcode(B)] " +q41 +aQ,"A B cHypot" +," with" +a8(B)qE1(A)wM);q4 +Lkp;} +} +} +o2 +wB(23,q41 +q51,mV,);q4 +Lkq +gY +wB(185,"x " +q51,"[fp_sqrt(x)]" +,wN);q4 +Lla;} +qH +TailCall_cSub:g5 +cSub +hH +wB(76,"cDup" +aW,"[Value_t()]" +wH,);q4 +Leh +oF +wB(200,qC1 +aW,"cAdd" +,);q4 +Llb +gY +g8)){wB(58,"x[x==Value_t()]" +aW,,wN);q4 +Lba;} +m9(106,aY"x" +aW,"[y-x]" +,q81);q4 +Llc;} +wB(51,"x" +aW,"[-x]" +aZ,wN);q4 +Lld +gR +w0 +oY +cRSub +dV +wB(289,"x" +mE +a3"cSub" +,"A" +aZ" [x]" +mE,aI(A)qD1 +wM);q4 +Lle;} +wB(296,a6 +a3"cSub" +,"[DO_STACKPLUS1] A" +aW +mE,aI(A)wM);incStackPtr();--mStackPtr;q4 +Llf;} +qG +TailCall_cTan:g5 +cTan:qS +cAtan2:wB(354,"cAtan2 " +mR,"cDiv" +,);q4 +Lga +oF +wB(242,m0 +mR,mR +aA,);q4 +Llg +gY +wB(187,"x " +mR,"[fp_tan(x)]" +,wN);q4 +Llh;oH +qN +oY +cCot +q11(501,aK" cCot " +wI +mR,"B cCot " +aT,aI(A)q91(B)wM);q4 +Lcb;} +} +qG +TailCall_cTanh:g5 +cTanh:qS +cAtanh:wB(352,"cAtanh cTanh" +,,);q4 +oE +wB(243,m0"cTanh" +,"cTanh" +aA,);q4 +Lli +gY +wB(188,"x cTanh" +,"[fp_tanh(x)]" +,wN);q4 +Llj;} +qH +TailCall_cTrunc:g5 +cTrunc:qS +hM +wB(138,"x cTrunc" +,"[fp_trunc(x)]" +,wN);q4 +Llk +gS +wB(394,"A[IsAlwaysIntegerOpcode(A)] cTrunc" +,"A" +,aI(A)wM);gJ +qG +g7 +Default0:;A=w5 +w1 +0){B=q0[0 +hZ +wB(475,aK" A[IsVarOpcode(A)&&mData->mByteCode.size()>0]" +,"B" +mQ,aI(A)q91(B)wM);q4 +Lll;} +} +if(gV +h2 +B=dF +qO +B +qP +1){C=qK +qR +C==A){D +g4 +D==B){wB(476,"D[D==B] C[C==A] B[IsVarOpcode(B)&&mData->mByteCode.size()>1] A[IsUnaryOpcode(A)]" +,"D C" +mQ,aI(A)q91(B)<<", C" +wY(C)<<", D" +wY(D)wM);q4 +Llm;} +} +} +} +C=w5 +qR +IsCommutativeOrParamSwappableBinaryOpcode(C)){qS +cSin:A=qK +w1 +3 +gA]==cCos){B=hQ +wB(505,aK" " +aO" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] " +mP" C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinCos {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Lln;} +} +qT +oQ +A=qK +w1 +3 +gA]==cCosh){B=hQ +wB(506,aK" " +aM" A[IsVarOpcode(A)&&mData->mByteCode.size()>3] cSinh C[IsCommutativeOrParamSwappableBinaryOpcode(C)]" +,"B cSinhCosh {GetParamSwappedBinaryOpcode(C)}" +," with C" +wY(C)qE1(A)q91(B)wM);q4 +Llo;} +} +h8} +} +} +q4 +Laa;Laa:qW +w5);gJ +Lab:g6 +Llp:wE(cAbs);q4 +TailCall_cAbs;Lac:q7=dP;gJ +Lad:q7=fp_acos +m6 +Lae:q7=fp_acosh +m6 +Laf:oZ +4));gG +Llq:w5=h3;Lma:g0 +Lmb:wE(cMul);q4 +TailCall_cMul;Lag:hV +4 +dT +oZ +4));Lmc:qW +q6 +hY;Lah:q7=x+g1 +1);gG +Lfb:w5=h3;q4 +Lmb;Lai:gU +cSub;Lmd:wE(cSub);q4 +TailCall_cSub;Laj:hW +2 +gH +Lme:g0 +Lmf:wE(cAdd);q4 +TailCall_cAdd;Lak:hW +oR +Lmg:qE +hS);Lmh:w5=cRSub;g0 +wE(cRSub);q4 +TailCall_cRSub;Lal:o9;qL +2 +gK +q4 +Lmg;Lam:hW +2 +gH +q4 +Lmh;Lan:hW +4 +gH +Lmi:qE +hS);Lmj:qE +B);Lmk:w5=cSub;g0 +q4 +Lmd;Lao:o9;oC=q6 +q9 +oR +q4 +Lmi;Lap:hW +oR +q4 +Lmj;Laq:gT +y+x;Lba:qM +Lbo:q5 +gJ +Lbb:q8 +oV +o7 +x +q71 +gX +Lmg;Lbc:mM +A +gX +Lmg;Lbd:gU +dS;wE(cNotNot);q4 +TailCall_cNotNot;Lbe:gT +fp_and(x +d6 +Lbf:q7=fp_arg +m6 +Lbg:q7=fp_asin +m6 +Lbh:q7=fp_asinh +m6 +Lbi:q7=fp_atan +m6 +Lbj:gT +fp_atan2(gW +Lbk:q7=fp_atanh +m6 +Lbl:q7=fp_cbrt +m6 +Lbm:q1 +cFloor);Lml:w5=cNeg;g0 +wE(cNeg);q4 +TailCall_cNeg;Lbn:q7=fp_ceil +m6 +Lbp:q7=fp_conj +m6 +Lbq:g6 +Lmm:wE(cCos);q4 +TailCall_cCos;Lca:q7=fp_cos +m6 +Lcb:dF=cDup;w5=cInv;Lmn:wE(cInv);q4 +TailCall_cInv;Lcc:mM +cSinCos);gJ +Lcd:q1 +cSqr +o7 +g1 +1));Lmo:qW +q6 +oJ +hS);Lmp:w5=cSqrt;g0 +wE(cSqrt);q4 +TailCall_cSqrt;Lce:g6 +wE(cCosh);q4 +TailCall_cCosh;Lcf:q7=fp_cosh +m6 +Lcg:mM +cSinhCosh);gJ +Lch:q7=RadiansToDegrees +m6 +Lci:q1 +cSec +hY;Lcj:q1 +cTan +hY;Lck:q1 +cSin +hY;Lcl:oZ));dF +dJ +Lmq:qE +dU +oZ +1));Lna:qW +q6);Lnb:w5=hS;q4 +Lme;Lcm:q1 +cNeg +oJ +cExp +hY;Lcn:q1 +cNeg +oJ +cExp2 +hY;Lco:g6 +q4 +Lfb;Lcp:q1 +cNeg +oJ +cPow +hY;Lcq:q1 +cCos +hY;Lda:q1 +cCsc +hY;Ldb:gU +cTan;Lnc:wE(cTan);q4 +TailCall_cTan;Ldc:gU +cTanh;Lnd:wE(cTanh);q4 +TailCall_cTanh;Ldd:q1 +cCot +hY;Lde:o9;dI +Lne:wE(cDiv);q4 +TailCall_cDiv;Ldf:gT +y/x;q4 +Lba;Ldg:qF1 +q8 +oR +Lnf:w5=cDeg;g0 +wE(cDeg);q4 +TailCall_cDeg;Ldh:qF1 +q8 +oR +Lng:w5=cRad;g0 +wE(cRad);q4 +TailCall_cRad;Ldi:gT +y/x;dG +Llq;Ldj:q7=g1 +1)/x;q4 +Lfb;Ldk:mM +oI +Lnh:g0 +q4 +Lne;Ldl:q8 +3 +gC +oI +qF +x +q71);Lni:w5=cRDiv;g0 +wE(cRDiv);q4 +TailCall_cRDiv;Ldm:hV +3 +gC +oI +qE +B +gX +Lni;Ldn:dI +Lnj:wE(cEqual);q4 +TailCall_cEqual;Ldo:gT +fp_equal(gW +Ldp:d7 +cExp +o7 +fp_exp(x)gX +Lmc;Ldq:q7=fp_exp +m6 +Lea:d7 +cExp2 +o7 +fp_exp2(x)gX +Lmc;Leb:q7=fp_exp2 +m6 +Lec:qF +oW +g1 +2))q71);Lnk:qE +h3 +gI +cExp;g0 +wE(cExp);q4 +TailCall_cExp;Led:q1 +cCeil +oT +Lee:q7=fp_floor +m6 +Lef:gT +fp_less(x +d6 +Leg:gT +fp_lessOrEq(x +d6 +Leh:oZ));Lnl:dF +dJ +q4 +Llq;Lei:q7=fp_imag +m6 +Lej:q7=fp_int +m6 +Lek:gU +cSec;wE(cSec);q4 +TailCall_cSec;Lel:gU +cSin;Lnm:wE(cSin);q4 +TailCall_cSin;Lem:q1 +cNeg +gI +cPow;Lnn:g0 +Lno:wE(cPow);q4 +TailCall_cPow;Len:gU +cCos;q4 +Lmm;Leo:gU +cCsc;wE(cCsc);q4 +TailCall_cCsc;Lep:q1 +cRSqrt);gJ +Leq:g6 +Lnp:w5=cCot;wE(cCot);q4 +TailCall_cCot;Lfa:q7=g1 +1)/x;gJ +Lfc:gT +fp_less(gW +Lfd:gT +fp_lessOrEq(gW +Lfe:d7 +cLog +o7 +oW +x)gX +Lna;Lff:q7=oW +x);gJ +Lfg:qF +dR +fp_const_e<dH>())gX +Lnl;Lfh:d7 +cLog10 +o7 +dR +x)gX +Lna;Lfi:q7=dR +x);gJ +Lfj:qF +o4 +fp_const_e<dH>())gX +Lnl;Lfk:d7 +cLog2 +o7 +o4 +x)gX +Lna;Lfl:q7=o4 +x);gJ +Lfm:gT +fp_max(x +d6 +Lfn:gT +fp_min(x +d6 +Lfo:gT +fp_mod(gW +Lfp:hV +oR +q0-=3;q4 +Lnp;Lfq:gU +cSqr;Lnq:wE(cSqr);q4 +TailCall_cSqr;Lga:gU +cDiv;q4 +Lne;Lgb:mM +cSqr +oT +Lgc:hV +3 +gC +cSqr);dM +Lml;Lgd:q7=x+g1 +1);gG +w5=cPow;q4 +Lno;Lge:gG +q4 +Lmb;Lgf:gT +x;Loa:dG +Lma;Lgg:qF1 +qM +Lob:hV +4 +gH +Loc:o6 +x);Lod:qW +q6 +gX +Lma;Lgh:qM +q4 +Lob;Lgi:q8 +4 +gC +B +gX +Loc;Lgj:q8 +oR +q4 +Loc;Lgk:qK +dJ +oS;Lgl:dI +q4 +Lmb;Lgm:qM +Loe:hV +oR +gJ +Lgn:q7=x+x;q4 +Lge;Lgo:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lnb;Lgp:gT +x;d7 +dU +qF +y*x +gX +Lna;Lgq:q7=RadiansToDegrees(x +gX +Lgl;Lha:qG1 +q8 +4 +gH +Lof:qE +dU +Log:qE +B +gI +cDiv;q4 +Lnh;Lhb:o9;oC=q6 +q9 +oR +q4 +Lof;Lhc:qG1 +q8 +oR +q4 +Log;Lhd:q8 +4 +gH +q4 +Lma;Lhe:q8 +4 +dT +qF +x+x +gX +Lod;Lhf:qF1 +qM +q4 +Loe;Lhg:qG1 +q4 +Loa;Lhh:o9;q4 +Lgl;Lhi:qG1 +q8 +oR +Loh:dM +Lni;Lhj:o9;qL +2 +gK +q4 +Loh;Lhk:qG1 +dG +Lni;Lhl:q7=h4 +gX +Lgl;Lhm:gT +x;qL +4]dJ +q8 +4 +dT +o6 +y*x +q71);dM +Lmk;Lhn:qG1 +q4 +Lba;Lho:qM +w3 +Lml;Lhp:dF=cDup;dW-=1;qM +Loi:w5=hS;q4 +Lmf;Lhq:qM +w3 +Lnf;Lia:qM +w3 +Lng;Lib:hV +oV +gX +Lof;Lic:hV +2 +gH +Loj:qE +cSqr +gX +Lma;Lid:q8 +oV +o7 +x +q71 +gX +Loh;Lie:mM +A +gX +Loh;Lif:hV +oR +q4 +Loj;Lig:dI +Lok:wE(cNEqual);q4 +TailCall_cNEqual;Lih:gT +fp_nequal(gW +Lii:o9;q4 +Lco;Lij:o9 +gB +cSin;g0 +q4 +Lnm;Lik:o9 +gB +cSinh;g0 +wE(cSinh);q4 +TailCall_cSinh;Lil:o9 +gB +cTan;g0 +q4 +Lnc;Lim:o9 +gB +cTanh;g0 +q4 +Lnd;Lin:o9;gJ +Lio:q1 +cAbsNot);gJ +Lip:gU +cNEqual;q4 +Lok;Liq:gU +cLessOrEq;wE(cLessOrEq);q4 +TailCall_cLessOrEq;Lja:gU +cLess;wE(cLess);q4 +TailCall_cLess;Ljb:gU +dK;wE(cGreaterOrEq);q4 +TailCall_cGreaterOrEq;Ljc:gU +o1;wE(cGreater);q4 +TailCall_cGreater;Ljd:gU +w8;q4 +Lnj;Lje:g6 +wE(cNot);q4 +TailCall_cNot;Ljf:q7=fp_not +m6 +Ljg:gT +fp_or(x +d6 +Ljh:gT +fp_polar(x +d6 +Lji:dL +Lnk;Ljj:qK=d8 +cExp2;g0 +wE(cExp2);q4 +TailCall_cExp2;Ljk:qG1 +dG +Lnn;Ljl:qK +dJ +q1 +h3 +gX +Lnn;Ljm:q7=g1 +gX +Lmq;Ljn:qM +w3 +Lmp;Ljo:qM +q5 +w5=cCbrt;g0 +wE(cCbrt);q4 +TailCall_cCbrt;Ljp:qM +q1 +cCbrt);Lol:w5=cInv;g0 +q4 +Lmn;Ljq:qM +q4 +Lep;Lka:qM +w3 +Lol;Lkb:q7=x+x;dI +q4 +Lno;Lkc:gT +oX +gW +Lkd:q1 +cTanh +gX +Lol;Lke:q7=h4 +gX +Lco;Lkf:q7=h4);gJ +Lkg:q7=fp_real +m6 +Lkh:mM +cSinCos +gX +Lol;Lki:q1 +cSin +oT +Lkj:q7=fp_sin +m6 +Lkk:q1 +cSqr +o7 +g1-1)gX +Lmo;Lkl:q1 +cSinh +oT +Lkm:q7=fp_sinh +m6 +Lkn:g6 +q4 +Lnq;Lko:hV +4 +gC +A);Lom:w5=cHypot;g0 +wE(cHypot);q4 +TailCall_cHypot;Lkp:hV +5 +gC +A +oJ +B +gX +Lom;Lkq:gU +cAbs;q4 +Llp;Lla:q7=fp_sqrt +m6 +Llb:g6 +q4 +Loi;Llc:gT +y-x;q4 +Lba;Lld:o9;q4 +Loi;Lle:q8 +oV +oJ +hS +o7 +x +q71 +gX +Lmh;Llf:mM +A +oJ +cSub +gX +Lmh;Llg:q1 +cTan +oT +Llh:q7=fp_tan +m6 +Lli:q1 +cTanh +oT +Llj:q7=fp_tanh +m6 +Llk:q7=fp_trunc +m6 +Lll:qW +cDup);gJ +Llm:dF=cDup;gJ +Lln:hV +3 +gC +cSinCos);Lon:qE +GetParamSwappedBinaryOpcode(C));gJ +Llo:hV +3 +gC +cSinhCosh +gX +Lon;gJ +q4 +TailCall_cAcos;q4 +TailCall_cAcosh;q4 +TailCall_cAnd;q4 +TailCall_cArg;q4 +TailCall_cAsin;q4 +TailCall_cAsinh;q4 +TailCall_cAtan;q4 +TailCall_cAtan2;q4 +TailCall_cAtanh;q4 +TailCall_cCeil;q4 +TailCall_cConj;q4 +TailCall_cFloor;q4 +TailCall_cImag;q4 +TailCall_cInt;q4 +TailCall_cLog;q4 +TailCall_cLog10;q4 +TailCall_cLog2;q4 +TailCall_cMax;q4 +TailCall_cMin;q4 +TailCall_cMod;q4 +TailCall_cOr;q4 +TailCall_cPolar;q4 +TailCall_cRDiv;q4 +TailCall_cRad;q4 +TailCall_cReal;q4 +TailCall_cSec;q4 +TailCall_cSin;q4 +TailCall_cSinh;q4 +TailCall_cSqrt;q4 +TailCall_cSub;q4 +TailCall_cTan;q4 +TailCall_cTanh;q4 +TailCall_cTrunc; +#endif +#undef FP_ReDefinePointers +#undef FP_TRACE_BYTECODE_OPTIMIZATION +#undef FP_TRACE_OPCODENAME diff --git a/extrasrc/fpaux.hh b/extrasrc/fpaux.hh new file mode 100644 index 0000000..f035c33 --- /dev/null +++ b/extrasrc/fpaux.hh @@ -0,0 +1,1249 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_AUX_H_ +#define ONCE_FPARSER_AUX_H_ + +#include "fptypes.hh" + +#include <cmath> + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +#include "mpfr/MpfrFloat.hh" +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +#include "mpfr/GmpInt.hh" +#endif + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS +#include <complex> +#endif + +#ifdef ONCE_FPARSER_H_ +namespace FUNCTIONPARSERTYPES +{ + template<typename> + struct IsIntType + { + enum { result = false }; + }; + template<> + struct IsIntType<long> + { + enum { result = true }; + }; +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + struct IsIntType<GmpInt> + { + enum { result = true }; + }; +#endif + + template<typename> + struct IsComplexType + { + enum { result = false }; + }; +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename T> + struct IsComplexType<std::complex<T> > + { + enum { result = true }; + }; +#endif + + +//========================================================================== +// Constants +//========================================================================== + template<typename Value_t> + inline Value_t fp_const_pi() // CONSTANT_PI + { + return Value_t(3.1415926535897932384626433832795028841971693993751L); + } + + template<typename Value_t> + inline Value_t fp_const_e() // CONSTANT_E + { + return Value_t(2.7182818284590452353602874713526624977572L); + } + template<typename Value_t> + inline Value_t fp_const_einv() // CONSTANT_EI + { + return Value_t(0.367879441171442321595523770161460867445811131L); + } + template<typename Value_t> + inline Value_t fp_const_log2() // CONSTANT_L2, CONSTANT_L2EI + { + return Value_t(0.69314718055994530941723212145817656807550013436025525412L); + } + template<typename Value_t> + inline Value_t fp_const_log10() // CONSTANT_L10, CONSTANT_L10EI + { + return Value_t(2.302585092994045684017991454684364207601101488628772976L); + } + template<typename Value_t> + inline Value_t fp_const_log2inv() // CONSTANT_L2I, CONSTANT_L2E + { + return Value_t(1.442695040888963407359924681001892137426645954L); + } + template<typename Value_t> + inline Value_t fp_const_log10inv() // CONSTANT_L10I, CONSTANT_L10E + { + return Value_t(0.434294481903251827651128918916605082294397L); + } + + template<typename Value_t> + inline const Value_t& fp_const_deg_to_rad() // CONSTANT_DR + { + static const Value_t factor = fp_const_pi<Value_t>() / Value_t(180); // to rad from deg + return factor; + } + + template<typename Value_t> + inline const Value_t& fp_const_rad_to_deg() // CONSTANT_RD + { + static const Value_t factor = Value_t(180) / fp_const_pi<Value_t>(); // to deg from rad + return factor; + } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline MpfrFloat fp_const_pi<MpfrFloat>() { return MpfrFloat::const_pi(); } + + template<> + inline MpfrFloat fp_const_e<MpfrFloat>() { return MpfrFloat::const_e(); } + + template<> + inline MpfrFloat fp_const_einv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_e(); } + + template<> + inline MpfrFloat fp_const_log2<MpfrFloat>() { return MpfrFloat::const_log2(); } + + /* + template<> + inline MpfrFloat fp_const_log10<MpfrFloat>() { return fp_log(MpfrFloat(10)); } + + template<> + inline MpfrFloat fp_const_log2inv<MpfrFloat>() { return MpfrFloat(1) / MpfrFloat::const_log2(); } + + template<> + inline MpfrFloat fp_const_log10inv<MpfrFloat>() { return fp_log10(MpfrFloat::const_e()); } + */ +#endif + + +//========================================================================== +// Generic math functions +//========================================================================== + template<typename Value_t> + inline Value_t fp_abs(const Value_t& x) { return std::fabs(x); } + + template<typename Value_t> + inline Value_t fp_acos(const Value_t& x) { return std::acos(x); } + + template<typename Value_t> + inline Value_t fp_asin(const Value_t& x) { return std::asin(x); } + + template<typename Value_t> + inline Value_t fp_atan(const Value_t& x) { return std::atan(x); } + + template<typename Value_t> + inline Value_t fp_atan2(const Value_t& x, const Value_t& y) + { return std::atan2(x, y); } + + template<typename Value_t> + inline Value_t fp_ceil(const Value_t& x) { return std::ceil(x); } + + template<typename Value_t> + inline Value_t fp_cos(const Value_t& x) { return std::cos(x); } + + template<typename Value_t> + inline Value_t fp_cosh(const Value_t& x) { return std::cosh(x); } + + template<typename Value_t> + inline Value_t fp_exp(const Value_t& x) { return std::exp(x); } + + template<typename Value_t> + inline Value_t fp_floor(const Value_t& x) { return std::floor(x); } + + template<typename Value_t> + inline Value_t fp_log(const Value_t& x) { return std::log(x); } + + template<typename Value_t> + inline Value_t fp_mod(const Value_t& x, const Value_t& y) + { return std::fmod(x, y); } + + template<typename Value_t> + inline Value_t fp_sin(const Value_t& x) { return std::sin(x); } + + template<typename Value_t> + inline Value_t fp_sinh(const Value_t& x) { return std::sinh(x); } + + template<typename Value_t> + inline Value_t fp_sqrt(const Value_t& x) { return std::sqrt(x); } + + template<typename Value_t> + inline Value_t fp_tan(const Value_t& x) { return std::tan(x); } + + template<typename Value_t> + inline Value_t fp_tanh(const Value_t& x) { return std::tanh(x); } + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_asinh(const Value_t& x) { return std::asinh(x); } + + template<typename Value_t> + inline Value_t fp_acosh(const Value_t& x) { return std::acosh(x); } + + template<typename Value_t> + inline Value_t fp_atanh(const Value_t& x) { return std::atanh(x); } +#else + template<typename Value_t> + inline Value_t fp_asinh(const Value_t& x) + { return fp_log(x + fp_sqrt(x*x + Value_t(1))); } + + template<typename Value_t> + inline Value_t fp_acosh(const Value_t& x) + { return fp_log(x + fp_sqrt(x*x - Value_t(1))); } + + template<typename Value_t> + inline Value_t fp_atanh(const Value_t& x) + { + return fp_log( (Value_t(1)+x) / (Value_t(1)-x)) * Value_t(0.5); + // Note: x = +1 causes division by zero + // x = -1 causes log(0) + // Thus, x must not be +-1 + } +#endif // FP_SUPPORT_ASINH + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_hypot(const Value_t& x, const Value_t& y) + { return std::hypot(x,y); } + + template<typename Value_t> + inline std::complex<Value_t> fp_hypot + (const std::complex<Value_t>& x, const std::complex<Value_t>& y) + { return fp_sqrt(x*x + y*y); } +#else + template<typename Value_t> + inline Value_t fp_hypot(const Value_t& x, const Value_t& y) + { return fp_sqrt(x*x + y*y); } +#endif + + template<typename Value_t> + inline Value_t fp_pow_base(const Value_t& x, const Value_t& y) + { return std::pow(x, y); } + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_log2(const Value_t& x) { return std::log2(x); } + + template<typename Value_t> + inline std::complex<Value_t> fp_log2(const std::complex<Value_t>& x) + { + return fp_log(x) * fp_const_log2inv<Value_t>(); + } +#else + template<typename Value_t> + inline Value_t fp_log2(const Value_t& x) + { + return fp_log(x) * fp_const_log2inv<Value_t>(); + } +#endif // FP_SUPPORT_LOG2 + + template<typename Value_t> + inline Value_t fp_log10(const Value_t& x) + { + return fp_log(x) * fp_const_log10inv<Value_t>(); + } + + template<typename Value_t> + inline Value_t fp_trunc(const Value_t& x) + { + return x < Value_t() ? fp_ceil(x) : fp_floor(x); + } + + template<typename Value_t> + inline Value_t fp_int(const Value_t& x) + { + return x < Value_t() ? + fp_ceil(x - Value_t(0.5)) : fp_floor(x + Value_t(0.5)); + } + + template<typename Value_t> + inline void fp_sinCos(Value_t& sinvalue, Value_t& cosvalue, + const Value_t& param) + { + // Assuming that "cosvalue" and "param" do not + // overlap, but "sinvalue" and "param" may. + cosvalue = fp_cos(param); + sinvalue = fp_sin(param); + } + + template<typename Value_t> + inline void fp_sinhCosh(Value_t& sinhvalue, Value_t& coshvalue, + const Value_t& param) + { + const Value_t ex(fp_exp(param)), emx(fp_exp(-param)); + sinhvalue = Value_t(0.5)*(ex-emx); + coshvalue = Value_t(0.5)*(ex+emx); + } + + template<typename Value_t> + struct Epsilon + { + static Value_t value; + static Value_t defaultValue() { return 0; } + }; + + template<> inline double Epsilon<double>::defaultValue() { return 1E-12; } + template<> inline float Epsilon<float>::defaultValue() { return 1E-5F; } + template<> inline long double Epsilon<long double>::defaultValue() { return 1E-14L; } + + template<> inline std::complex<double> + Epsilon<std::complex<double> >::defaultValue() { return 1E-12; } + + template<> inline std::complex<float> + Epsilon<std::complex<float> >::defaultValue() { return 1E-5F; } + + template<> inline std::complex<long double> + Epsilon<std::complex<long double> >::defaultValue() { return 1E-14L; } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> inline MpfrFloat + Epsilon<MpfrFloat>::defaultValue() { return MpfrFloat::someEpsilon(); } +#endif + + template<typename Value_t> Value_t Epsilon<Value_t>::value = + Epsilon<Value_t>::defaultValue(); + + +#ifdef _GNU_SOURCE + inline void fp_sinCos(double& sin, double& cos, const double& a) + { + sincos(a, &sin, &cos); + } + inline void fp_sinCos(float& sin, float& cos, const float& a) + { + sincosf(a, &sin, &cos); + } + inline void fp_sinCos(long double& sin, long double& cos, + const long double& a) + { + sincosl(a, &sin, &cos); + } +#endif + + +// ------------------------------------------------------------------------- +// Long int +// ------------------------------------------------------------------------- + inline long fp_abs(const long& x) { return x < 0 ? -x : x; } + inline long fp_acos(const long&) { return 0; } + inline long fp_asin(const long&) { return 0; } + inline long fp_atan(const long&) { return 0; } + inline long fp_atan2(const long&, const long&) { return 0; } + inline long fp_cbrt(const long&) { return 0; } + inline long fp_ceil(const long& x) { return x; } + inline long fp_cos(const long&) { return 0; } + inline long fp_cosh(const long&) { return 0; } + inline long fp_exp(const long&) { return 0; } + inline long fp_exp2(const long&) { return 0; } + inline long fp_floor(const long& x) { return x; } + inline long fp_log(const long&) { return 0; } + inline long fp_log2(const long&) { return 0; } + inline long fp_log10(const long&) { return 0; } + inline long fp_mod(const long& x, const long& y) { return x % y; } + inline long fp_pow(const long&, const long&) { return 0; } + inline long fp_sin(const long&) { return 0; } + inline long fp_sinh(const long&) { return 0; } + inline long fp_sqrt(const long&) { return 1; } + inline long fp_tan(const long&) { return 0; } + inline long fp_tanh(const long&) { return 0; } + inline long fp_asinh(const long&) { return 0; } + inline long fp_acosh(const long&) { return 0; } + inline long fp_atanh(const long&) { return 0; } + inline long fp_pow_base(const long&, const long&) { return 0; } + inline void fp_sinCos(long&, long&, const long&) {} + inline void fp_sinhCosh(long&, long&, const long&) {} + + //template<> inline long fp_epsilon<long>() { return 0; } + + +// ------------------------------------------------------------------------- +// MpfrFloat +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + inline MpfrFloat fp_abs(const MpfrFloat& x) { return MpfrFloat::abs(x); } + inline MpfrFloat fp_acos(const MpfrFloat& x) { return MpfrFloat::acos(x); } + inline MpfrFloat fp_acosh(const MpfrFloat& x) { return MpfrFloat::acosh(x); } + inline MpfrFloat fp_asin(const MpfrFloat& x) { return MpfrFloat::asin(x); } + inline MpfrFloat fp_asinh(const MpfrFloat& x) { return MpfrFloat::asinh(x); } + inline MpfrFloat fp_atan(const MpfrFloat& x) { return MpfrFloat::atan(x); } + inline MpfrFloat fp_atan2(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::atan2(x, y); } + inline MpfrFloat fp_atanh(const MpfrFloat& x) { return MpfrFloat::atanh(x); } + inline MpfrFloat fp_cbrt(const MpfrFloat& x) { return MpfrFloat::cbrt(x); } + inline MpfrFloat fp_ceil(const MpfrFloat& x) { return MpfrFloat::ceil(x); } + inline MpfrFloat fp_cos(const MpfrFloat& x) { return MpfrFloat::cos(x); } + inline MpfrFloat fp_cosh(const MpfrFloat& x) { return MpfrFloat::cosh(x); } + inline MpfrFloat fp_exp(const MpfrFloat& x) { return MpfrFloat::exp(x); } + inline MpfrFloat fp_exp2(const MpfrFloat& x) { return MpfrFloat::exp2(x); } + inline MpfrFloat fp_floor(const MpfrFloat& x) { return MpfrFloat::floor(x); } + inline MpfrFloat fp_hypot(const MpfrFloat& x, const MpfrFloat& y) + { return MpfrFloat::hypot(x, y); } + inline MpfrFloat fp_int(const MpfrFloat& x) { return MpfrFloat::round(x); } + inline MpfrFloat fp_log(const MpfrFloat& x) { return MpfrFloat::log(x); } + inline MpfrFloat fp_log2(const MpfrFloat& x) { return MpfrFloat::log2(x); } + inline MpfrFloat fp_log10(const MpfrFloat& x) { return MpfrFloat::log10(x); } + inline MpfrFloat fp_mod(const MpfrFloat& x, const MpfrFloat& y) { return x % y; } + inline MpfrFloat fp_sin(const MpfrFloat& x) { return MpfrFloat::sin(x); } + inline MpfrFloat fp_sinh(const MpfrFloat& x) { return MpfrFloat::sinh(x); } + inline MpfrFloat fp_sqrt(const MpfrFloat& x) { return MpfrFloat::sqrt(x); } + inline MpfrFloat fp_tan(const MpfrFloat& x) { return MpfrFloat::tan(x); } + inline MpfrFloat fp_tanh(const MpfrFloat& x) { return MpfrFloat::tanh(x); } + inline MpfrFloat fp_trunc(const MpfrFloat& x) { return MpfrFloat::trunc(x); } + + inline MpfrFloat fp_pow(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + inline MpfrFloat fp_pow_base(const MpfrFloat& x, const MpfrFloat& y) { return MpfrFloat::pow(x, y); } + + + inline void fp_sinCos(MpfrFloat& sin, MpfrFloat& cos, const MpfrFloat& a) + { + MpfrFloat::sincos(a, sin, cos); + } + + inline void fp_sinhCosh(MpfrFloat& sinhvalue, MpfrFloat& coshvalue, + const MpfrFloat& param) + { + const MpfrFloat paramCopy = param; + sinhvalue = fp_sinh(paramCopy); + coshvalue = fp_cosh(paramCopy); + } +#endif // FP_SUPPORT_MPFR_FLOAT_TYPE + + +// ------------------------------------------------------------------------- +// GMP int +// ------------------------------------------------------------------------- +#ifdef FP_SUPPORT_GMP_INT_TYPE + inline GmpInt fp_abs(const GmpInt& x) { return GmpInt::abs(x); } + inline GmpInt fp_acos(const GmpInt&) { return 0; } + inline GmpInt fp_acosh(const GmpInt&) { return 0; } + inline GmpInt fp_asin(const GmpInt&) { return 0; } + inline GmpInt fp_asinh(const GmpInt&) { return 0; } + inline GmpInt fp_atan(const GmpInt&) { return 0; } + inline GmpInt fp_atan2(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_atanh(const GmpInt&) { return 0; } + inline GmpInt fp_cbrt(const GmpInt&) { return 0; } + inline GmpInt fp_ceil(const GmpInt& x) { return x; } + inline GmpInt fp_cos(const GmpInt&) { return 0; } + inline GmpInt fp_cosh(const GmpInt&) { return 0; } + inline GmpInt fp_exp(const GmpInt&) { return 0; } + inline GmpInt fp_exp2(const GmpInt&) { return 0; } + inline GmpInt fp_floor(const GmpInt& x) { return x; } + inline GmpInt fp_hypot(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_int(const GmpInt& x) { return x; } + inline GmpInt fp_log(const GmpInt&) { return 0; } + inline GmpInt fp_log2(const GmpInt&) { return 0; } + inline GmpInt fp_log10(const GmpInt&) { return 0; } + inline GmpInt fp_mod(const GmpInt& x, const GmpInt& y) { return x % y; } + inline GmpInt fp_pow(const GmpInt&, const GmpInt&) { return 0; } + inline GmpInt fp_sin(const GmpInt&) { return 0; } + inline GmpInt fp_sinh(const GmpInt&) { return 0; } + inline GmpInt fp_sqrt(const GmpInt&) { return 0; } + inline GmpInt fp_tan(const GmpInt&) { return 0; } + inline GmpInt fp_tanh(const GmpInt&) { return 0; } + inline GmpInt fp_trunc(const GmpInt& x) { return x; } + inline GmpInt fp_pow_base(const GmpInt&, const GmpInt&) { return 0; } + inline void fp_sinCos(GmpInt&, GmpInt&, const GmpInt&) {} + inline void fp_sinhCosh(GmpInt&, GmpInt&, const GmpInt&) {} +#endif // FP_SUPPORT_GMP_INT_TYPE + + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename Value_t> + inline Value_t fp_cbrt(const Value_t& x) { return std::cbrt(x); } +#else + template<typename Value_t> + inline Value_t fp_cbrt(const Value_t& x) + { + return (x > Value_t() ? fp_exp(fp_log( x) / Value_t(3)) : + x < Value_t() ? -fp_exp(fp_log(-x) / Value_t(3)) : + Value_t()); + } +#endif + +// ------------------------------------------------------------------------- +// Synthetic functions and fallbacks for when an optimized +// implementation or a library function is not available +// ------------------------------------------------------------------------- + template<typename Value_t> inline Value_t fp_arg(const Value_t& x); + template<typename Value_t> inline Value_t fp_exp2(const Value_t& x); + template<typename Value_t> inline Value_t fp_int(const Value_t& x); + template<typename Value_t> inline Value_t fp_trunc(const Value_t& x); + template<typename Value_t> + inline void fp_sinCos(Value_t& , Value_t& , const Value_t& ); + template<typename Value_t> + inline void fp_sinhCosh(Value_t& , Value_t& , const Value_t& ); + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + /* NOTE: Complex multiplication of a and b can be done with: + tmp = b.real * (a.real + a.imag) + result.real = tmp - a.imag * (b.real + b.imag) + result.imag = tmp + a.real * (b.imag - b.real) + This has fewer multiplications than the standard + algorithm. Take note, if you support mpfr complex one day. + */ + + template<typename T> + struct FP_ProbablyHasFastLibcComplex + { enum { result = false }; }; + /* The generic sqrt() etc. implementations in libstdc++ + * are very plain and non-optimized; however, it contains + * callbacks to libc complex math functions where possible, + * and I suspect that those may actually be well optimized. + * So we use std:: functions when we suspect they may be fast, + * and otherwise we use our own optimized implementations. + */ +#ifdef __GNUC__ + template<> struct FP_ProbablyHasFastLibcComplex<float> + { enum { result = true }; }; + template<> struct FP_ProbablyHasFastLibcComplex<double> + { enum { result = true }; }; + template<> struct FP_ProbablyHasFastLibcComplex<long double> + { enum { result = true }; }; +#endif + + template<typename T> + inline const std::complex<T> fp_make_imag(const std::complex<T>& v) + { + return std::complex<T> ( T(), v.real() ); + } + + template<typename T> + inline std::complex<T> fp_real(const std::complex<T>& x) + { + return x.real(); + } + template<typename T> + inline std::complex<T> fp_imag(const std::complex<T>& x) + { + return x.imag(); + } + template<typename T> + inline std::complex<T> fp_arg(const std::complex<T>& x) + { + return std::arg(x); + } + template<typename T> + inline std::complex<T> fp_conj(const std::complex<T>& x) + { + return std::conj(x); + } + template<typename T, bool> + inline std::complex<T> fp_polar(const T& x, const T& y) + { + T si, co; fp_sinCos(si, co, y); + return std::complex<T> (x*co, x*si); + } + template<typename T> + inline std::complex<T> fp_polar(const std::complex<T>& x, const std::complex<T>& y) + { + // x * cos(y) + i * x * sin(y) -- arguments are supposed to be REAL numbers + return fp_polar<T,true> (x.real(), y.real()); + //return std::polar(x.real(), y.real()); + //return x * (fp_cos(y) + (std::complex<T>(0,1) * fp_sin(y)); + } + + // These provide fallbacks in case there's no library function + template<typename T> + inline std::complex<T> fp_floor(const std::complex<T>& x) + { + return std::complex<T> (fp_floor(x.real()), fp_floor(x.imag())); + } + template<typename T> + inline std::complex<T> fp_trunc(const std::complex<T>& x) + { + return std::complex<T> (fp_trunc(x.real()), fp_trunc(x.imag())); + } + template<typename T> + inline std::complex<T> fp_int(const std::complex<T>& x) + { + return std::complex<T> (fp_int(x.real()), fp_int(x.imag())); + } + template<typename T> + inline std::complex<T> fp_ceil(const std::complex<T>& x) + { + return std::complex<T> (fp_ceil(x.real()), fp_ceil(x.imag())); + } + template<typename T> + inline std::complex<T> fp_abs(const std::complex<T>& x) + { + return std::abs(x); + //T extent = fp_max(fp_abs(x.real()), fp_abs(x.imag())); + //if(extent == T()) return x; + //return extent * fp_hypot(x.real() / extent, x.imag() / extent); + } + template<typename T> + inline std::complex<T> fp_exp(const std::complex<T>& x) + { + if(FP_ProbablyHasFastLibcComplex<T>::result) + return std::exp(x); + return fp_polar<T,true>(fp_exp(x.real()), x.imag()); + } + template<typename T> + inline std::complex<T> fp_log(const std::complex<T>& x) + { + if(FP_ProbablyHasFastLibcComplex<T>::result) + return std::log(x); + // log(abs(x)) + i*arg(x) + // log(Xr^2+Xi^2)*0.5 + i*arg(x) + if(x.imag()==T()) + return std::complex<T>( fp_log(fp_abs(x.real())), + fp_arg(x.real()) ); // Note: Uses real-value fp_arg() here! + return std::complex<T>( + fp_log(std::norm(x)) * T(0.5), + fp_arg(x).real() ); + } + template<typename T> + inline std::complex<T> fp_sqrt(const std::complex<T>& x) + { + if(FP_ProbablyHasFastLibcComplex<T>::result) + return std::sqrt(x); + return fp_polar<T,true> (fp_sqrt(fp_abs(x).real()), + T(0.5)*fp_arg(x).real()); + } + template<typename T> + inline std::complex<T> fp_acos(const std::complex<T>& x) + { + // -i * log(x + i * sqrt(1 - x^2)) + const std::complex<T> i (T(), T(1)); + return -i * fp_log(x + i * fp_sqrt(T(1) - x*x)); + // Note: Real version of acos() cannot handle |x| > 1, + // because it would cause sqrt(negative value). + } + template<typename T> + inline std::complex<T> fp_asin(const std::complex<T>& x) + { + // -i * log(i*x + sqrt(1 - x^2)) + const std::complex<T> i (T(), T(1)); + return -i * fp_log(i*x + fp_sqrt(T(1) - x*x)); + // Note: Real version of asin() cannot handle |x| > 1, + // because it would cause sqrt(negative value). + } + template<typename T> + inline std::complex<T> fp_atan(const std::complex<T>& x) + { + // 0.5i * (log(1-i*x) - log(1+i*x)) + // -0.5i * log( (1+i*x) / (1-i*x) ) + const std::complex<T> i (T(), T(1)); + return (T(-0.5)*i) * fp_log( (T(1)+i*x) / (T(1)-i*x) ); + // Note: x = -1i causes division by zero + // x = +1i causes log(0) + // Thus, x must not be +-1i + } + template<typename T> + inline std::complex<T> fp_cos(const std::complex<T>& x) + { + return std::cos(x); + // // (exp(i*x) + exp(-i*x)) / (2) + // //const std::complex<T> i (T(), T(1)); + // //return (fp_exp(i*x) + fp_exp(-i*x)) * T(0.5); + // // Also: cos(Xr)*cosh(Xi) - i*sin(Xr)*sinh(Xi) + // return std::complex<T> ( + // fp_cos(x.real())*fp_cosh(x.imag()), + // -fp_sin(x.real())*fp_sinh(x.imag())); + } + template<typename T> + inline std::complex<T> fp_sin(const std::complex<T>& x) + { + return std::sin(x); + // // (exp(i*x) - exp(-i*x)) / (2i) + // //const std::complex<T> i (T(), T(1)); + // //return (fp_exp(i*x) - fp_exp(-i*x)) * (T(-0.5)*i); + // // Also: sin(Xr)*cosh(Xi) + cos(Xr)*sinh(Xi) + // return std::complex<T> ( + // fp_sin(x.real())*fp_cosh(x.imag()), + // fp_cos(x.real())*fp_sinh(x.imag())); + } + template<typename T> + inline void fp_sinCos( + std::complex<T>& sinvalue, + std::complex<T>& cosvalue, + const std::complex<T>& x) + { + //const std::complex<T> i (T(), T(1)), expix(fp_exp(i*x)), expmix(fp_exp((-i)*x)); + //cosvalue = (expix + expmix) * T(0.5); + //sinvalue = (expix - expmix) * (i*T(-0.5)); + // The above expands to the following: + T srx, crx; fp_sinCos(srx, crx, x.real()); + T six, cix; fp_sinhCosh(six, cix, x.imag()); + sinvalue = std::complex<T>(srx*cix, crx*six); + cosvalue = std::complex<T>(crx*cix, -srx*six); + } + template<typename T> + inline void fp_sinhCosh( + std::complex<T>& sinhvalue, + std::complex<T>& coshvalue, + const std::complex<T>& x) + { + T srx, crx; fp_sinhCosh(srx, crx, x.real()); + T six, cix; fp_sinCos(six, cix, x.imag()); + sinhvalue = std::complex<T>(srx*cix, crx*six); + coshvalue = std::complex<T>(crx*cix, srx*six); + } + template<typename T> + inline std::complex<T> fp_tan(const std::complex<T>& x) + { + return std::tan(x); + //std::complex<T> si, co; + //fp_sinCos(si, co, x); + //return si/co; + // // (i-i*exp(2i*x)) / (exp(2i*x)+1) + // const std::complex<T> i (T(), T(1)), exp2ix=fp_exp((2*i)*x); + // return (i-i*exp2ix) / (exp2ix+T(1)); + // // Also: sin(x)/cos(y) + // // return fp_sin(x)/fp_cos(x); + } + template<typename T> + inline std::complex<T> fp_cosh(const std::complex<T>& x) + { + return std::cosh(x); + // // (exp(x) + exp(-x)) * 0.5 + // // Also: cosh(Xr)*cos(Xi) + i*sinh(Xr)*sin(Xi) + // return std::complex<T> ( + // fp_cosh(x.real())*fp_cos(x.imag()), + // fp_sinh(x.real())*fp_sin(x.imag())); + } + template<typename T> + inline std::complex<T> fp_sinh(const std::complex<T>& x) + { + return std::sinh(x); + // // (exp(x) - exp(-x)) * 0.5 + // // Also: sinh(Xr)*cos(Xi) + i*cosh(Xr)*sin(Xi) + // return std::complex<T> ( + // fp_sinh(x.real())*fp_cos(x.imag()), + // fp_cosh(x.real())*fp_sin(x.imag())); + } + template<typename T> + inline std::complex<T> fp_tanh(const std::complex<T>& x) + { + return std::tanh(x); + //std::complex<T> si, co; + //fp_sinhCosh(si, co, x); + //return si/co; + // // (exp(2*x)-1) / (exp(2*x)+1) + // // Also: sinh(x)/tanh(x) + // const std::complex<T> exp2x=fp_exp(x+x); + // return (exp2x-T(1)) / (exp2x+T(1)); + } + +#ifdef FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + template<typename T> + inline std::complex<T> fp_acosh(const std::complex<T>& x) + { return fp_log(x + fp_sqrt(x*x - std::complex<T>(1))); } + template<typename T> + inline std::complex<T> fp_asinh(const std::complex<T>& x) + { return fp_log(x + fp_sqrt(x*x + std::complex<T>(1))); } + template<typename T> + inline std::complex<T> fp_atanh(const std::complex<T>& x) + { return fp_log( (std::complex<T>(1)+x) / (std::complex<T>(1)-x)) + * std::complex<T>(0.5); } +#endif + template<typename T> + inline std::complex<T> fp_pow(const std::complex<T>& x, const std::complex<T>& y) + { + // return std::pow(x,y); + + // With complex numbers, pow(x,y) can be solved with + // the general formula: exp(y*log(x)). It handles + // all special cases gracefully. + // It expands to the following: + // A) + // t1 = log(x) + // t2 = y * t1 + // res = exp(t2) + // B) + // t1.r = log(x.r * x.r + x.i * x.i) * 0.5 \ fp_log() + // t1.i = atan2(x.i, x.r) / + // t2.r = y.r*t1.r - y.i*t1.i \ multiplication + // t2.i = y.r*t1.i + y.i*t1.r / + // rho = exp(t2.r) \ fp_exp() + // theta = t2.i / + // res.r = rho * cos(theta) \ fp_polar(), called from + // res.i = rho * sin(theta) / fp_exp(). Uses sincos(). + // Aside from the common "norm" calculation in atan2() + // and in the log parameter, both of which are part of fp_log(), + // there does not seem to be any incentive to break this + // function down further; it would not help optimizing it. + // However, we do handle the following special cases: + // + // When x is real (positive or negative): + // t1.r = log(abs(x.r)) + // t1.i = x.r<0 ? -pi : 0 + // When y is real: + // t2.r = y.r * t1.r + // t2.i = y.r * t1.i + const std::complex<T> t = + (x.imag() != T()) + ? fp_log(x) + : std::complex<T> (fp_log(fp_abs(x.real())), + fp_arg(x.real())); // Note: Uses real-value fp_arg() here! + return y.imag() != T() + ? fp_exp(y * t) + : fp_polar<T,true> (fp_exp(y.real()*t.real()), y.real()*t.imag()); + } + template<typename T> + inline std::complex<T> fp_cbrt(const std::complex<T>& x) + { + // For real numbers, prefer giving a real solution + // rather than a complex solution. + // For example, cbrt(-3) has the following three solutions: + // A) 0.7211247966535 + 1.2490247864016i + // B) 0.7211247966535 - 1.2490247864016i + // C) -1.442249593307 + // exp(log(x)/3) gives A, but we prefer to give C. + if(x.imag() == T()) return fp_cbrt(x.real()); + const std::complex<T> t(fp_log(x)); + return fp_polar<T,true> (fp_exp(t.real() / T(3)), t.imag() / T(3)); + } + + template<typename T> + inline std::complex<T> fp_exp2(const std::complex<T>& x) + { + // pow(2, x) + // polar(2^Xr, Xi*log(2)) + return fp_polar<T,true> (fp_exp2(x.real()), x.imag()*fp_const_log2<T>()); + } + template<typename T> + inline std::complex<T> fp_mod(const std::complex<T>& x, const std::complex<T>& y) + { + // Modulo function is probably not defined for complex numbers. + // But we do our best to calculate it the same way as it is done + // with real numbers, so that at least it is in some way "consistent". + if(y.imag() == 0) return fp_mod(x.real(), y.real()); // optimization + std::complex<T> n = fp_trunc(x / y); + return x - n * y; + } + + /* libstdc++ already defines a streaming operator for complex values, + * but we redefine our own that it is compatible with the input + * accepted by fparser. I.e. instead of (5,3) we now get (5+3i), + * and instead of (-4,0) we now get -4. + */ + template<typename T> + inline std::ostream& operator<<(std::ostream& os, const std::complex<T>& value) + { + if(value.imag() == T()) return os << value.real(); + if(value.real() == T()) return os << value.imag() << 'i'; + if(value.imag() < T()) + return os << '(' << value.real() << "-" << -value.imag() << "i)"; + else + return os << '(' << value.real() << "+" << value.imag() << "i)"; + } + + /* Less-than or greater-than operators are not technically defined + * for Complex types. However, in fparser and its tool set, these + * operators are widely required to be present. + * Our implementation here is based on converting the complex number + * into a scalar and the doing a scalar comparison on the value. + * The means by which the number is changed into a scalar is based + * on the following principles: + * - Does not introduce unjustified amounts of extra inaccuracy + * - Is transparent to purely real values + * (this disqualifies something like x.real() + x.imag()) + * - Does not ignore the imaginary value completely + * (this may be relevant especially in testbed) + * - Is not so complicated that it would slow down a great deal + * + * Basically our formula here is the same as std::abs(), + * except that it keeps the sign of the original real number, + * and it does not do a sqrt() calculation that is not really + * needed because we are only interested in the relative magnitudes. + * + * Equality and nonequality operators must not need to be overloaded. + * They are already implemented in standard, and we must + * not introduce flawed equality assumptions. + */ + template<typename T> + inline T fp_complexScalarize(const std::complex<T>& x) + { + T res(std::norm(x)); + if(x.real() < T()) res = -res; + return res; + } + template<typename T> + inline T fp_realComplexScalarize(const T& x) + { + T res(x*x); + if(x < T()) res = -res; + return res; + } + // { return x.real() * (T(1.0) + fp_abs(x.imag())); } + #define d(op) \ + template<typename T> \ + inline bool operator op (const std::complex<T>& x, T y) \ + { return fp_complexScalarize(x) op fp_realComplexScalarize(y); } \ + template<typename T> \ + inline bool operator op (const std::complex<T>& x, const std::complex<T>& y) \ + { return fp_complexScalarize(x) op \ + fp_complexScalarize(y); } \ + template<typename T> \ + inline bool operator op (T x, const std::complex<T>& y) \ + { return fp_realComplexScalarize(x) op fp_complexScalarize(y); } + d( < ) d( <= ) d( > ) d( >= ) + #undef d +#endif + + template<typename Value_t> + inline Value_t fp_real(const Value_t& x) { return x; } + template<typename Value_t> + inline Value_t fp_imag(const Value_t& ) { return Value_t(); } + template<typename Value_t> + inline Value_t fp_arg(const Value_t& x) + { return x < Value_t() ? -fp_const_pi<Value_t>() : Value_t(); } + template<typename Value_t> + inline Value_t fp_conj(const Value_t& x) { return x; } + template<typename Value_t> + inline Value_t fp_polar(const Value_t& x, const Value_t& y) + { return x * fp_cos(y); } // This is of course a meaningless function. + + template<typename Value_t> + inline std::complex<Value_t> fp_atan2(const std::complex<Value_t>& y, + const std::complex<Value_t>& x) + { + if(y == Value_t()) return fp_arg(x); + if(x == Value_t()) return fp_const_pi<Value_t>() * Value_t(-0.5); + // 2*atan(y / (sqrt(x^2+y^2) + x) ) + // 2*atan( (sqrt(x^2+y^2) - x) / y) + std::complex<Value_t> res( fp_atan(y / (fp_hypot(x,y) + x)) ); + return res+res; + } + +// ------------------------------------------------------------------------- +// Comparison +// ------------------------------------------------------------------------- + template<typename Value_t> + inline bool fp_equal(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x == y) + : (fp_abs(x - y) <= Epsilon<Value_t>::value); } + + template<typename Value_t> + inline bool fp_nequal(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x != y) + : (fp_abs(x - y) > Epsilon<Value_t>::value); } + + template<typename Value_t> + inline bool fp_less(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x < y) + : (x < y - Epsilon<Value_t>::value); } + + template<typename Value_t> + inline bool fp_lessOrEq(const Value_t& x, const Value_t& y) + { return IsIntType<Value_t>::result + ? (x <= y) + : (x <= y + Epsilon<Value_t>::value); } + + + template<typename Value_t> + inline bool fp_greater(const Value_t& x, const Value_t& y) + { return fp_less(y, x); } + + template<typename Value_t> + inline bool fp_greaterOrEq(const Value_t& x, const Value_t& y) + { return fp_lessOrEq(y, x); } + + template<typename Value_t> + inline bool fp_truth(const Value_t& d) + { + return IsIntType<Value_t>::result + ? d != Value_t() + : fp_abs(d) >= Value_t(0.5); + } + + template<typename Value_t> + inline bool fp_absTruth(const Value_t& abs_d) + { + return IsIntType<Value_t>::result + ? abs_d > Value_t() + : abs_d >= Value_t(0.5); + } + + template<typename Value_t> + inline const Value_t& fp_min(const Value_t& d1, const Value_t& d2) + { return d1<d2 ? d1 : d2; } + + template<typename Value_t> + inline const Value_t& fp_max(const Value_t& d1, const Value_t& d2) + { return d1>d2 ? d1 : d2; } + + template<typename Value_t> + inline const Value_t fp_not(const Value_t& b) + { return Value_t(!fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_notNot(const Value_t& b) + { return Value_t(fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_absNot(const Value_t& b) + { return Value_t(!fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_absNotNot(const Value_t& b) + { return Value_t(fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_and(const Value_t& a, const Value_t& b) + { return Value_t(fp_truth(a) && fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_or(const Value_t& a, const Value_t& b) + { return Value_t(fp_truth(a) || fp_truth(b)); } + + template<typename Value_t> + inline const Value_t fp_absAnd(const Value_t& a, const Value_t& b) + { return Value_t(fp_absTruth(a) && fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_absOr(const Value_t& a, const Value_t& b) + { return Value_t(fp_absTruth(a) || fp_absTruth(b)); } + + template<typename Value_t> + inline const Value_t fp_make_imag(const Value_t& ) // Imaginary 1. In real mode, always zero. + { + return Value_t(); + } + + ///////////// + /* Opcode analysis functions are used by fp_opcode_add.inc */ + /* Moved here from fparser.cc because fp_opcode_add.inc + * is also now included by fpoptimizer.cc + */ + bool IsLogicalOpcode(unsigned op); + bool IsComparisonOpcode(unsigned op); + unsigned OppositeComparisonOpcode(unsigned op); + bool IsNeverNegativeValueOpcode(unsigned op); + bool IsAlwaysIntegerOpcode(unsigned op); + bool IsUnaryOpcode(unsigned op); + bool IsBinaryOpcode(unsigned op); + bool IsVarOpcode(unsigned op); + bool IsCommutativeOrParamSwappableBinaryOpcode(unsigned op); + unsigned GetParamSwappedBinaryOpcode(unsigned op); + + template<bool ComplexType> + bool HasInvalidRangesOpcode(unsigned op); + + template<typename Value_t> + inline Value_t DegreesToRadians(const Value_t& degrees) + { + return degrees * fp_const_deg_to_rad<Value_t>(); + } + + template<typename Value_t> + inline Value_t RadiansToDegrees(const Value_t& radians) + { + return radians * fp_const_rad_to_deg<Value_t>(); + } + + template<typename Value_t> + inline long makeLongInteger(const Value_t& value) + { + return (long) fp_int(value); + } + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename T> + inline long makeLongInteger(const std::complex<T>& value) + { + return (long) fp_int( std::abs(value) ); + } +#endif + + // Is value an integer that fits in "long" datatype? + template<typename Value_t> + inline bool isLongInteger(const Value_t& value) + { + return value == Value_t( makeLongInteger(value) ); + } + + template<typename Value_t> + inline bool isOddInteger(const Value_t& value) + { + const Value_t halfValue = (value + Value_t(1)) * Value_t(0.5); + return fp_equal(halfValue, fp_floor(halfValue)); + } + + template<typename Value_t> + inline bool isEvenInteger(const Value_t& value) + { + const Value_t halfValue = value * Value_t(0.5); + return fp_equal(halfValue, fp_floor(halfValue)); + } + + template<typename Value_t> + inline bool isInteger(const Value_t& value) + { + return fp_equal(value, fp_floor(value)); + } + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline bool isEvenInteger(const long& value) + { + return value%2 == 0; + } + + template<> + inline bool isInteger(const long&) { return true; } + + template<> + inline bool isLongInteger(const long&) { return true; } + + template<> + inline long makeLongInteger(const long& value) + { + return value; + } +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline bool isInteger(const MpfrFloat& value) { return value.isInteger(); } + + template<> + inline bool isEvenInteger(const MpfrFloat& value) + { + return isInteger(value) && value%2 == 0; + } + + template<> + inline long makeLongInteger(const MpfrFloat& value) + { + return (long) value.toInt(); + } +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool isEvenInteger(const GmpInt& value) + { + return value%2 == 0; + } + + template<> + inline bool isInteger(const GmpInt&) { return true; } + + template<> + inline long makeLongInteger(const GmpInt& value) + { + return (long) value.toInt(); + } +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline bool isOddInteger(const long& value) + { + return value%2 != 0; + } +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline bool isOddInteger(const MpfrFloat& value) + { + return value.isInteger() && value%2 != 0; + } +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool isOddInteger(const GmpInt& value) + { + return value%2 != 0; + } +#endif + + +// ------------------------------------------------------------------------- +// fp_pow +// ------------------------------------------------------------------------- + // Commented versions in fparser.cc + template<typename Value_t> + inline Value_t fp_pow_with_exp_log(const Value_t& x, const Value_t& y) + { + return fp_exp(fp_log(x) * y); + } + + template<typename Value_t> + inline Value_t fp_powi(Value_t x, unsigned long y) + { + Value_t result(1); + while(y != 0) + { + if(y & 1) { result *= x; y -= 1; } + else { x *= x; y /= 2; } + } + return result; + } + + template<typename Value_t> + Value_t fp_pow(const Value_t& x, const Value_t& y) + { + if(x == Value_t(1)) return Value_t(1); + if(isLongInteger(y)) + { + if(y >= Value_t(0)) + return fp_powi(x, makeLongInteger(y)); + else + return Value_t(1) / fp_powi(x, -makeLongInteger(y)); + } + if(y >= Value_t(0)) + { + if(x > Value_t(0)) return fp_pow_with_exp_log(x, y); + if(x == Value_t(0)) return Value_t(0); + if(!isInteger(y*Value_t(16))) + return -fp_pow_with_exp_log(-x, y); + } + else + { + if(x > Value_t(0)) return fp_pow_with_exp_log(Value_t(1) / x, -y); + if(x < Value_t(0)) + { + if(!isInteger(y*Value_t(-16))) + return -fp_pow_with_exp_log(Value_t(-1) / x, -y); + } + } + return fp_pow_base(x, y); + } + + template<typename Value_t> + inline Value_t fp_exp2(const Value_t& x) + { + return fp_pow(Value_t(2), x); + } +} // namespace FUNCTIONPARSERTYPES + +#endif // ONCE_FPARSER_H_ +#endif // ONCE_FPARSER_AUX_H_ diff --git a/extrasrc/fptypes.hh b/extrasrc/fptypes.hh new file mode 100644 index 0000000..ea28cbc --- /dev/null +++ b/extrasrc/fptypes.hh @@ -0,0 +1,286 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// NOTE: +// This file contains only internal types for the function parser library. +// You don't need to include this file in your code. Include "fparser.hh" +// only. + +#ifndef ONCE_FPARSER_TYPES_H_ +#define ONCE_FPARSER_TYPES_H_ + +#include "../fpconfig.hh" +#include <cstring> + +#ifdef ONCE_FPARSER_H_ +#include <map> +#endif + +namespace FUNCTIONPARSERTYPES +{ + enum OPCODE + { +// The order of opcodes in the function list must +// match that which is in the Functions[] array. + cAbs, + cAcos, cAcosh, + cArg, /* get the phase angle of a complex value */ + cAsin, cAsinh, + cAtan, cAtan2, cAtanh, + cCbrt, cCeil, + cConj, /* get the complex conjugate of a complex value */ + cCos, cCosh, cCot, cCsc, + cExp, cExp2, cFloor, cHypot, + cIf, + cImag, /* get imaginary part of a complex value */ + cInt, cLog, cLog10, cLog2, cMax, cMin, + cPolar, /* create a complex number from polar coordinates */ + cPow, + cReal, /* get real part of a complex value */ + cSec, cSin, cSinh, cSqrt, cTan, cTanh, + cTrunc, + +// These do not need any ordering: +// Except that if you change the order of {eq,neq,lt,le,gt,ge}, you +// must also change the order in ConstantFolding_ComparisonOperations(). + cImmed, cJump, + cNeg, cAdd, cSub, cMul, cDiv, cMod, + cEqual, cNEqual, cLess, cLessOrEq, cGreater, cGreaterOrEq, + cNot, cAnd, cOr, + cNotNot, /* Protects the double-not sequence from optimizations */ + + cDeg, cRad, /* Multiplication and division by 180 / pi */ + + cFCall, cPCall, + +#ifdef FP_SUPPORT_OPTIMIZER + cPopNMov, /* cPopNMov(x,y) moves [y] to [x] and deletes anything + * above [x]. Used for disposing of temporaries. + */ + cLog2by, /* log2by(x,y) = log2(x) * y */ + cNop, /* Used by fpoptimizer internally; should not occur in bytecode */ +#endif + cSinCos, /* sin(x) followed by cos(x) (two values are pushed to stack) */ + cSinhCosh, /* hyperbolic equivalent of sincos */ + cAbsAnd, /* As cAnd, but assume both operands are absolute values */ + cAbsOr, /* As cOr, but assume both operands are absolute values */ + cAbsNot, /* As cAbsNot, but assume the operand is an absolute value */ + cAbsNotNot, /* As cAbsNotNot, but assume the operand is an absolute value */ + cAbsIf, /* As cAbsIf, but assume the 1st operand is an absolute value */ + + cDup, /* Duplicates the last value in the stack: Push [Stacktop] */ + cFetch, /* Same as Dup, except with absolute index + * (next value is index) */ + cInv, /* Inverts the last value in the stack (x = 1/x) */ + cSqr, /* squares the last operand in the stack, no push/pop */ + cRDiv, /* reverse division (not x/y, but y/x) */ + cRSub, /* reverse subtraction (not x-y, but y-x) */ + cRSqrt, /* inverse square-root (1/sqrt(x)) */ + + VarBegin + }; + +#ifdef ONCE_FPARSER_H_ + struct FuncDefinition + { + enum FunctionFlags + { + Enabled = 0x01, + AngleIn = 0x02, + AngleOut = 0x04, + OkForInt = 0x08, + ComplexOnly = 0x10 + }; + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + const char name[8]; +#endif + unsigned params : 8; + unsigned flags : 8; + + inline bool okForInt() const { return (flags & OkForInt) != 0; } + inline bool complexOnly() const { return (flags & ComplexOnly) != 0; } + }; + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +# define FP_FNAME(n) n, +#else +# define FP_FNAME(n) +#endif +// This list must be in the same order as that in OPCODE enum, +// because the opcode value is used to index this array, and +// the pointer to array element is used for generating the opcode. + const FuncDefinition Functions[]= + { + /*cAbs */ { FP_FNAME("abs") 1, FuncDefinition::OkForInt }, + /*cAcos */ { FP_FNAME("acos") 1, FuncDefinition::AngleOut }, + /*cAcosh*/ { FP_FNAME("acosh") 1, FuncDefinition::AngleOut }, + /*cArg */ { FP_FNAME("arg") 1, FuncDefinition::AngleOut | FuncDefinition::ComplexOnly }, + /*cAsin */ { FP_FNAME("asin") 1, FuncDefinition::AngleOut }, + /*cAsinh*/ { FP_FNAME("asinh") 1, FuncDefinition::AngleOut }, + /*cAtan */ { FP_FNAME("atan") 1, FuncDefinition::AngleOut }, + /*cAtan2*/ { FP_FNAME("atan2") 2, FuncDefinition::AngleOut }, + /*cAtanh*/ { FP_FNAME("atanh") 1, 0 }, + /*cCbrt */ { FP_FNAME("cbrt") 1, 0 }, + /*cCeil */ { FP_FNAME("ceil") 1, 0 }, + /*cConj */ { FP_FNAME("conj") 1, FuncDefinition::ComplexOnly }, + /*cCos */ { FP_FNAME("cos") 1, FuncDefinition::AngleIn }, + /*cCosh */ { FP_FNAME("cosh") 1, FuncDefinition::AngleIn }, + /*cCot */ { FP_FNAME("cot") 1, FuncDefinition::AngleIn }, + /*cCsc */ { FP_FNAME("csc") 1, FuncDefinition::AngleIn }, + /*cExp */ { FP_FNAME("exp") 1, 0 }, + /*cExp2 */ { FP_FNAME("exp2") 1, 0 }, + /*cFloor*/ { FP_FNAME("floor") 1, 0 }, + /*cHypot*/ { FP_FNAME("hypot") 2, 0 }, + /*cIf */ { FP_FNAME("if") 0, FuncDefinition::OkForInt }, + /*cImag */ { FP_FNAME("imag") 1, FuncDefinition::ComplexOnly }, + /*cInt */ { FP_FNAME("int") 1, 0 }, + /*cLog */ { FP_FNAME("log") 1, 0 }, + /*cLog10*/ { FP_FNAME("log10") 1, 0 }, + /*cLog2 */ { FP_FNAME("log2") 1, 0 }, + /*cMax */ { FP_FNAME("max") 2, FuncDefinition::OkForInt }, + /*cMin */ { FP_FNAME("min") 2, FuncDefinition::OkForInt }, + /*cPolar */{ FP_FNAME("polar") 2, FuncDefinition::ComplexOnly | FuncDefinition::AngleIn }, + /*cPow */ { FP_FNAME("pow") 2, 0 }, + /*cReal */ { FP_FNAME("real") 1, FuncDefinition::ComplexOnly }, + /*cSec */ { FP_FNAME("sec") 1, FuncDefinition::AngleIn }, + /*cSin */ { FP_FNAME("sin") 1, FuncDefinition::AngleIn }, + /*cSinh */ { FP_FNAME("sinh") 1, FuncDefinition::AngleIn }, + /*cSqrt */ { FP_FNAME("sqrt") 1, 0 }, + /*cTan */ { FP_FNAME("tan") 1, FuncDefinition::AngleIn }, + /*cTanh */ { FP_FNAME("tanh") 1, FuncDefinition::AngleIn }, + /*cTrunc*/ { FP_FNAME("trunc") 1, 0 } + }; +#undef FP_FNAME + + struct NamePtr + { + const char* name; + unsigned nameLength; + + NamePtr(const char* n, unsigned l): name(n), nameLength(l) {} + + inline bool operator==(const NamePtr& rhs) const + { + return nameLength == rhs.nameLength + && std::memcmp(name, rhs.name, nameLength) == 0; + } + inline bool operator<(const NamePtr& rhs) const + { + for(unsigned i = 0; i < nameLength; ++i) + { + if(i == rhs.nameLength) return false; + const char c1 = name[i], c2 = rhs.name[i]; + if(c1 < c2) return true; + if(c2 < c1) return false; + } + return nameLength < rhs.nameLength; + } + }; + + template<typename Value_t> + struct NameData + { + enum DataType { CONSTANT, UNIT, FUNC_PTR, PARSER_PTR, VARIABLE }; + DataType type; + unsigned index; + Value_t value; + + NameData(DataType t, unsigned v) : type(t), index(v), value() { } + NameData(DataType t, Value_t v) : type(t), index(), value(v) { } + NameData() { } + }; + + template<typename Value_t> + class NamePtrsMap: public + std::map<FUNCTIONPARSERTYPES::NamePtr, + FUNCTIONPARSERTYPES::NameData<Value_t> > + { + }; + + const unsigned FUNC_AMOUNT = sizeof(Functions)/sizeof(Functions[0]); +#endif // ONCE_FPARSER_H_ +} + +#ifdef ONCE_FPARSER_H_ +#include <vector> + +template<typename Value_t> +struct FunctionParserBase<Value_t>::Data +{ + unsigned mReferenceCounter; + + char mDelimiterChar; + ParseErrorType mParseErrorType; + int mEvalErrorType; + bool mUseDegreeConversion; + bool mHasByteCodeFlags; + const char* mErrorLocation; + + unsigned mVariablesAmount; + std::string mVariablesString; + FUNCTIONPARSERTYPES::NamePtrsMap<Value_t> mNamePtrs; + + struct InlineVariable + { + FUNCTIONPARSERTYPES::NamePtr mName; + unsigned mFetchIndex; + }; + + typedef std::vector<InlineVariable> InlineVarNamesContainer; + InlineVarNamesContainer mInlineVarNames; + + struct FuncWrapperPtrData + { + /* Only one of the pointers will point to a function, the other + will be null. (The raw function pointer could be implemented + as a FunctionWrapper specialization, but it's done like this + for efficiency.) */ + FunctionPtr mRawFuncPtr; + FunctionWrapper* mFuncWrapperPtr; + unsigned mParams; + + FuncWrapperPtrData(); + ~FuncWrapperPtrData(); + FuncWrapperPtrData(const FuncWrapperPtrData&); + FuncWrapperPtrData& operator=(const FuncWrapperPtrData&); + }; + + struct FuncParserPtrData + { + FunctionParserBase<Value_t>* mParserPtr; + unsigned mParams; + }; + + std::vector<FuncWrapperPtrData> mFuncPtrs; + std::vector<FuncParserPtrData> mFuncParsers; + + std::vector<unsigned> mByteCode; + std::vector<Value_t> mImmed; + +#if !defined(FP_USE_THREAD_SAFE_EVAL) && \ + !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) + std::vector<Value_t> mStack; + // Note: When mStack exists, + // mStack.size() and mStackSize are mutually redundant. +#endif + + unsigned mStackSize; + + Data(); + Data(const Data&); + Data& operator=(const Data&); // not implemented on purpose + ~Data(); +}; +#endif + +//#include "fpaux.hh" + +#endif diff --git a/fparser.cc b/fparser.cc new file mode 100644 index 0000000..5e77ba5 --- /dev/null +++ b/fparser.cc @@ -0,0 +1,3800 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#include "fpconfig.hh" +#include "fparser.hh" + +#include <set> +#include <cstdlib> +#include <cstring> +#include <cctype> +#include <cmath> +#include <cassert> +#include <limits> + +#include "extrasrc/fptypes.hh" +#include "extrasrc/fpaux.hh" +using namespace FUNCTIONPARSERTYPES; + +#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA +#ifndef FP_USE_THREAD_SAFE_EVAL +#define FP_USE_THREAD_SAFE_EVAL +#endif +#endif + +#ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +#endif + +//========================================================================= +// Opcode analysis functions +//========================================================================= +// These functions are used by the Parse() bytecode optimizer (mostly from +// code in fp_opcode_add.inc). + +bool FUNCTIONPARSERTYPES::IsLogicalOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsComparisonOpcode(unsigned op) +{ + switch(op) + { + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + return true; + default: break; + } + return false; +} + +unsigned FUNCTIONPARSERTYPES::OppositeComparisonOpcode(unsigned op) +{ + switch(op) + { + case cLess: return cGreater; + case cGreater: return cLess; + case cLessOrEq: return cGreaterOrEq; + case cGreaterOrEq: return cLessOrEq; + } + return op; +} + +bool FUNCTIONPARSERTYPES::IsNeverNegativeValueOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + case cSqrt: case cRSqrt: case cSqr: + case cHypot: + case cAbs: + case cAcos: case cCosh: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsAlwaysIntegerOpcode(unsigned op) +{ + switch(op) + { + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cEqual: case cNEqual: + case cLess: case cLessOrEq: + case cGreater: case cGreaterOrEq: + case cInt: case cFloor: case cCeil: case cTrunc: + return true; + default: break; + } + return false; +} + +bool FUNCTIONPARSERTYPES::IsUnaryOpcode(unsigned op) +{ + switch(op) + { + case cInv: case cNeg: + case cNot: case cAbsNot: + case cNotNot: case cAbsNotNot: + case cSqr: case cRSqrt: + case cDeg: case cRad: + return true; + } + return (op < FUNC_AMOUNT && Functions[op].params == 1); +} + +bool FUNCTIONPARSERTYPES::IsBinaryOpcode(unsigned op) +{ + switch(op) + { + case cAdd: case cSub: case cRSub: + case cMul: case cDiv: case cRDiv: + case cMod: + case cEqual: case cNEqual: case cLess: + case cLessOrEq: case cGreater: case cGreaterOrEq: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + return true; + } + return (op < FUNC_AMOUNT && Functions[op].params == 2); +} + +bool FUNCTIONPARSERTYPES::IsVarOpcode(unsigned op) +{ + // See comment in declaration of FP_ParamGuardMask + return int(op) >= VarBegin; +} + +bool FUNCTIONPARSERTYPES::IsCommutativeOrParamSwappableBinaryOpcode(unsigned op) +{ + switch(op) + { + case cAdd: + case cMul: + case cEqual: case cNEqual: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cMin: case cMax: case cHypot: + return true; + case cDiv: case cSub: case cRDiv: case cRSub: + return true; + case cLess: case cGreater: + case cLessOrEq: case cGreaterOrEq: return true; + } + return false; +} + +unsigned FUNCTIONPARSERTYPES::GetParamSwappedBinaryOpcode(unsigned op) +{ + switch(op) + { + case cAdd: + case cMul: + case cEqual: case cNEqual: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cMin: case cMax: case cHypot: + return op; + case cDiv: return cRDiv; + case cSub: return cRSub; + case cRDiv: return cDiv; + case cRSub: return cSub; + case cLess: return cGreater; + case cGreater: return cLess; + case cLessOrEq: return cGreaterOrEq; + case cGreaterOrEq: return cLessOrEq; + } + return op; // Error +} + +template<bool ComplexType> +bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode(unsigned op) +{ + // Returns true, if the given opcode has a range of + // input values that gives an error. + if(ComplexType) + { + // COMPLEX: + switch(op) + { + case cAtan: // allowed range: x != +-1i + case cAtanh: // allowed range: x != +-1 + //case cCot: // allowed range: tan(x) != 0 + //case cCsc: // allowed range: sin(x) != 0 + case cLog: // allowed range: x != 0 + case cLog2: // allowed range: x != 0 + case cLog10: // allowed range: x != 0 + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by:// allowed range: x != 0 + #endif + //case cPow: // allowed when: x != 0 or y != 0 + //case cSec: // allowed range: cos(x) != 0 + //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2) + //case cTanh: // allowed range: log(x) != -1 --> x != +-(pi/2)i + case cRSqrt: // allowed range: x != 0 + //case cDiv: // allowed range: y != 0 + //case cRDiv: // allowed range: x != 0 + //case cInv: // allowed range: x != 0 + return true; + } + } + else + { + // REAL: + switch(op) + { + case cAcos: // allowed range: |x| <= 1 + case cAsin: // allowed range: |x| <= 1 + case cAcosh: // allowed range: x >= 1 + case cAtanh: // allowed range: |x| < 1 + //case cCot: // allowed range: tan(x) != 0 + //case cCsc: // allowed range: sin(x) != 0 + case cLog: // allowed range: x > 0 + case cLog2: // allowed range: x > 0 + case cLog10: // allowed range: x > 0 + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by:// allowed range: x > 0 + #endif + //case cPow: // allowed when: x > 0 or (x = 0 and y != 0) or (x<0) + // Technically, when (x<0 and y is not integer), + // it is not allowed, but we allow it anyway + // in order to make nontrivial roots work. + //case cSec: // allowed range: cos(x) != 0 + case cSqrt: // allowed range: x >= 0 + case cRSqrt: // allowed range: x > 0 + //case cTan: // allowed range: cos(x) != 0 --> x != +-(pi/2) + //case cDiv: // allowed range: y != 0 + //case cRDiv: // allowed range: x != 0 + //case cInv: // allowed range: x != 0 + return true; + } + } + return false; +} + +template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode<false>(unsigned op); +template bool FUNCTIONPARSERTYPES::HasInvalidRangesOpcode<true>(unsigned op); + + +#if(0) // Implementation moved to fpaux.hh due to linker problems +//========================================================================= +// Mathematical template functions +//========================================================================= +/* fp_pow() is a wrapper for std::pow() + * that produces an identical value for + * exp(1) ^ 2.0 (0x4000000000000000) + * as exp(2.0) (0x4000000000000000) + * - std::pow() on x86_64 + * produces 2.0 (0x3FFFFFFFFFFFFFFF) instead! + * See comments below for other special traits. + */ +namespace +{ + template<typename ValueT> + inline ValueT fp_pow_with_exp_log(const ValueT& x, const ValueT& y) + { + // Exponentiation using exp(log(x)*y). + // See http://en.wikipedia.org/wiki/Exponentiation#Real_powers + // Requirements: x > 0. + return fp_exp(fp_log(x) * y); + } + + template<typename ValueT> + inline ValueT fp_powi(ValueT x, unsigned long y) + { + // Fast binary exponentiation algorithm + // See http://en.wikipedia.org/wiki/Exponentiation_by_squaring + // Requirements: y is non-negative integer. + ValueT result(1); + while(y != 0) + { + if(y & 1) { result *= x; y -= 1; } + else { x *= x; y /= 2; } + } + return result; + } +} + +template<typename ValueT> +ValueT FUNCTIONPARSERTYPES::fp_pow(const ValueT& x, const ValueT& y) +{ + if(x == ValueT(1)) return ValueT(1); + // y is now zero or positive + if(isLongInteger(y)) + { + // Use fast binary exponentiation algorithm + if(y >= ValueT(0)) + return fp_powi(x, makeLongInteger(y)); + else + return ValueT(1) / fp_powi(x, -makeLongInteger(y)); + } + if(y >= ValueT(0)) + { + // y is now positive. Calculate using exp(log(x)*y). + if(x > ValueT(0)) return fp_pow_with_exp_log(x, y); + if(x == ValueT(0)) return ValueT(0); + // At this point, y > 0.0 and x is known to be < 0.0, + // because positive and zero cases are already handled. + if(!isInteger(y*ValueT(16))) + return -fp_pow_with_exp_log(-x, y); + // ^This is not technically correct, but it allows + // functions such as cbrt(x^5), that is, x^(5/3), + // to be evaluated when x is negative. + // It is too complicated (and slow) to test whether y + // is a formed from a ratio of an integer to an odd integer. + // (And due to floating point inaccuracy, pointless too.) + // For example, x^1.30769230769... is + // actually x^(17/13), i.e. (x^17) ^ (1/13). + // (-5)^(17/13) gives us now -8.204227562330453. + // To see whether the result is right, we can test the given + // root: (-8.204227562330453)^13 gives us the value of (-5)^17, + // which proves that the expression was correct. + // + // The y*16 check prevents e.g. (-4)^(3/2) from being calculated, + // as it would confuse functioninfo when pow() returns no error + // but sqrt() does when the formula is converted into sqrt(x)*x. + // + // The errors in this approach are: + // (-2)^sqrt(2) should produce NaN + // or actually sqrt(2)I + 2^sqrt(2), + // produces -(2^sqrt(2)) instead. + // (Impact: Neglible) + // Thus, at worst, we're changing a NaN (or complex) + // result into a negative real number result. + } + else + { + // y is negative. Utilize the x^y = 1/(x^-y) identity. + if(x > ValueT(0)) return fp_pow_with_exp_log(ValueT(1) / x, -y); + if(x < ValueT(0)) + { + if(!isInteger(y*ValueT(-16))) + return -fp_pow_with_exp_log(ValueT(-1) / x, -y); + // ^ See comment above. + } + // Remaining case: 0.0 ^ negative number + } + // This is reached when: + // x=0, and y<0 + // x<0, and y*16 is either positive or negative integer + // It is used for producing error values and as a safe fallback. + return fp_pow_base(x, y); +} +#endif + + +//========================================================================= +// Elementary (atom) parsing functions +//========================================================================= +namespace +{ + const unsigned FP_ParamGuardMask = 1U << (sizeof(unsigned) * 8u - 1u); + // ^ This mask is used to prevent cFetch/other opcode's parameters + // from being confused into opcodes or variable indices within the + // bytecode optimizer. Because the way it is tested in bytecoderules.dat + // for speed reasons, it must also be the sign-bit of the "int" datatype. + // Perhaps an "assert(IsVarOpcode(X | FP_ParamGuardMask) == false)" + // might be justified to put somewhere in the code, just in case? + + + /* Reads an UTF8-encoded sequence which forms a valid identifier name from + the given input string and returns its length. If bit 31 is set, the + return value also contains the internal function opcode (defined in + fptypes.hh) that matches the name. + */ + unsigned readIdentifierCommon(const char* input) + { + /* Assuming unsigned = 32 bits: + 76543210 76543210 76543210 76543210 + Return value if built-in function: + 1PPPPPPP PPPPPPPP LLLLLLLL LLLLLLLL + P = function opcode (15 bits) + L = function name length (16 bits) + Return value if not built-in function: + 0LLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL + L = identifier length (31 bits) + If unsigned has more than 32 bits, the other + higher order bits are to be assumed zero. + */ +#include "extrasrc/fp_identifier_parser.inc" + return 0; + } + + template<typename Value_t> + inline unsigned readIdentifier(const char* input) + { + const unsigned value = readIdentifierCommon(input); + if( (value & 0x80000000U) != 0) // Function? + { + // Verify that the function actually exists for this datatype + if(IsIntType<Value_t>::result + && !Functions[(value >> 16) & 0x7FFF].okForInt()) + { + // If it does not exist, return it as an identifier instead + return value & 0xFFFFu; + } + if(!IsComplexType<Value_t>::result + && Functions[(value >> 16) & 0x7FFF].complexOnly()) + { + // If it does not exist, return it as an identifier instead + return value & 0xFFFFu; + } + } + return value; + } + + // Returns true if the entire string is a valid identifier + template<typename Value_t> + bool containsOnlyValidIdentifierChars(const std::string& name) + { + if(name.empty()) return false; + return readIdentifier<Value_t>(name.c_str()) == (unsigned) name.size(); + } + + + // ----------------------------------------------------------------------- + // Wrappers for strto... functions + // ----------------------------------------------------------------------- + template<typename Value_t> + inline Value_t fp_parseLiteral(const char* str, char** endptr) + { + return std::strtod(str, endptr); + } + +#if defined(FP_USE_STRTOLD) || defined(FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS) + template<> + inline long double fp_parseLiteral<long double>(const char* str, + char** endptr) + { + using namespace std; // Just in case strtold() is not inside std:: + return strtold(str, endptr); + } +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + inline long fp_parseLiteral<long>(const char* str, char** endptr) + { + return std::strtol(str, endptr, 10); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename T> + inline std::complex<T> fp_parseComplexLiteral(const char* str, + char** endptr) + { + T result = fp_parseLiteral<T> (str,endptr); + const char* end = *endptr; + if( (*end == 'i' || *end == 'I') + && !std::isalnum(end[1]) ) + { + ++*endptr; + return std::complex<T> (T(), result); + } + return std::complex<T> (result, T()); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + template<> + inline std::complex<double> fp_parseLiteral<std::complex<double> > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral<double> (str,endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + inline std::complex<float> fp_parseLiteral<std::complex<float> > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral<float> (str,endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + inline std::complex<long double> fp_parseLiteral<std::complex<long double> > + (const char* str, char** endptr) + { + return fp_parseComplexLiteral<long double> (str,endptr); + } +#endif + + // ----------------------------------------------------------------------- + // Hexadecimal floating point literal parsing + // ----------------------------------------------------------------------- + inline int testXdigit(unsigned c) + { + if((c-'0') < 10u) return c&15; // 0..9 + if(((c|0x20)-'a') < 6u) return 9+(c&15); // A..F or a..f + return -1; // Not a hex digit + } + + template<typename elem_t, unsigned n_limbs, unsigned limb_bits> + inline void addXdigit(elem_t* buffer, unsigned nibble) + { + for(unsigned p=0; p<n_limbs; ++p) + { + unsigned carry = unsigned( buffer[p] >> (elem_t)(limb_bits-4) ); + buffer[p] = (buffer[p] << 4) | nibble; + nibble = carry; + } + } + + template<typename Value_t> + Value_t parseHexLiteral(const char* str, char** endptr) + { + const unsigned bits_per_char = 8; + + const int MantissaBits = + std::numeric_limits<Value_t>::radix == 2 + ? std::numeric_limits<Value_t>::digits + : (((sizeof(Value_t) * bits_per_char) &~ 3) - 4); + + typedef unsigned long elem_t; + const int ExtraMantissaBits = 4 + ((MantissaBits+3)&~3); // Store one digit more for correct rounding + const unsigned limb_bits = sizeof(elem_t) * bits_per_char; + const unsigned n_limbs = (ExtraMantissaBits + limb_bits-1) / limb_bits; + elem_t mantissa_buffer[n_limbs] = { 0 }; + + int n_mantissa_bits = 0; // Track the number of bits + int exponent = 0; // The exponent that will be used to multiply the mantissa + // Read integer portion + while(true) + { + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit<elem_t,n_limbs,limb_bits> (mantissa_buffer, xdigit); + ++str; + + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) + { + // Exhausted the precision. Parse the rest (until exponent) + // normally but ignore the actual digits. + for(; testXdigit(*str) >= 0; ++str) + exponent += 4; + // Read but ignore decimals + if(*str == '.') + for(++str; testXdigit(*str) >= 0; ++str) + {} + goto read_exponent; + } + } + // Read decimals + if(*str == '.') + for(++str; ; ) + { + int xdigit = testXdigit(*str); + if(xdigit < 0) break; + addXdigit<elem_t,n_limbs,limb_bits> (mantissa_buffer, xdigit); + ++str; + + exponent -= 4; + n_mantissa_bits += 4; + if(n_mantissa_bits >= ExtraMantissaBits) + { + // Exhausted the precision. Skip the rest + // of the decimals, until the exponent. + while(testXdigit(*str) >= 0) + ++str; + break; + } + } + + // Read exponent + read_exponent: + if(*str == 'p' || *str == 'P') + { + const char* str2 = str+1; + long p_exponent = strtol(str2, const_cast<char**> (&str2), 10); + if(str2 != str+1 && p_exponent == (long)(int)p_exponent) + { + exponent += (int)p_exponent; + str = str2; + } + } + + if(endptr) *endptr = const_cast<char*> (str); + + Value_t result = std::ldexp(Value_t(mantissa_buffer[0]), exponent); + for(unsigned p=1; p<n_limbs; ++p) + { + exponent += limb_bits; + result += ldexp(Value_t(mantissa_buffer[p]), exponent); + } + return result; + } + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + long parseHexLiteral<long>(const char* str, char** endptr) + { + return std::strtol(str, endptr, 16); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + template<> + std::complex<double> + parseHexLiteral<std::complex<double> >(const char* str, char** endptr) + { + return parseHexLiteral<double> (str, endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + std::complex<float> + parseHexLiteral<std::complex<float> >(const char* str, char** endptr) + { + return parseHexLiteral<float> (str, endptr); + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + std::complex<long double> + parseHexLiteral<std::complex<long double> >(const char* str, char** endptr) + { + return parseHexLiteral<long double> (str, endptr); + } +#endif +} + +//========================================================================= +// Utility functions +//========================================================================= +namespace +{ + // ----------------------------------------------------------------------- + // Add a new identifier to the specified identifier map + // ----------------------------------------------------------------------- + // Return value will be false if the name already existed + template<typename Value_t> + bool addNewNameData(NamePtrsMap<Value_t>& namePtrs, + std::pair<NamePtr, NameData<Value_t> >& newName, + bool isVar) + { + typename NamePtrsMap<Value_t>::iterator nameIter = + namePtrs.lower_bound(newName.first); + + if(nameIter != namePtrs.end() && newName.first == nameIter->first) + { + // redefining a var is not allowed. + if(isVar) return false; + + // redefining other tokens is allowed, if the type stays the same. + if(nameIter->second.type != newName.second.type) + return false; + + // update the data + nameIter->second = newName.second; + return true; + } + + if(!isVar) + { + // Allocate a copy of the name (pointer stored in the map key) + // However, for VARIABLEs, the pointer points to VariableString, + // which is managed separately. Thusly, only done when !IsVar. + char* namebuf = new char[newName.first.nameLength]; + memcpy(namebuf, newName.first.name, newName.first.nameLength); + newName.first.name = namebuf; + } + + namePtrs.insert(nameIter, newName); + return true; + } +} + + +//========================================================================= +// Data struct implementation +//========================================================================= +template<typename Value_t> +FunctionParserBase<Value_t>::Data::Data(): + mReferenceCounter(1), + mDelimiterChar(0), + mParseErrorType(NO_FUNCTION_PARSED_YET), + mEvalErrorType(0), + mUseDegreeConversion(false), + mErrorLocation(0), + mVariablesAmount(0), + mStackSize(0) +{} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::Data(const Data& rhs): + mReferenceCounter(0), + mDelimiterChar(rhs.mDelimiterChar), + mParseErrorType(rhs.mParseErrorType), + mEvalErrorType(rhs.mEvalErrorType), + mUseDegreeConversion(rhs.mUseDegreeConversion), + mErrorLocation(rhs.mErrorLocation), + mVariablesAmount(rhs.mVariablesAmount), + mVariablesString(rhs.mVariablesString), + mNamePtrs(), + mFuncPtrs(rhs.mFuncPtrs), + mFuncParsers(rhs.mFuncParsers), + mByteCode(rhs.mByteCode), + mImmed(rhs.mImmed), +#ifndef FP_USE_THREAD_SAFE_EVAL + mStack(rhs.mStackSize), +#endif + mStackSize(rhs.mStackSize) +{ + for(typename NamePtrsMap<Value_t>::const_iterator i = rhs.mNamePtrs.begin(); + i != rhs.mNamePtrs.end(); + ++i) + { + if(i->second.type == NameData<Value_t>::VARIABLE) + { + const std::size_t variableStringOffset = + i->first.name - rhs.mVariablesString.c_str(); + std::pair<NamePtr, NameData<Value_t> > tmp + (NamePtr(&mVariablesString[variableStringOffset], + i->first.nameLength), + i->second); + mNamePtrs.insert(mNamePtrs.end(), tmp); + } + else + { + std::pair<NamePtr, NameData<Value_t> > tmp + (NamePtr(new char[i->first.nameLength], i->first.nameLength), + i->second ); + memcpy(const_cast<char*>(tmp.first.name), i->first.name, + tmp.first.nameLength); + mNamePtrs.insert(mNamePtrs.end(), tmp); + } + } +} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::~Data() +{ + for(typename NamePtrsMap<Value_t>::iterator i = mNamePtrs.begin(); + i != mNamePtrs.end(); + ++i) + { + if(i->second.type != NameData<Value_t>::VARIABLE) + delete[] i->first.name; + } +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::incFuncWrapperRefCount +(FunctionWrapper* wrapper) +{ + ++wrapper->mReferenceCount; +} + +template<typename Value_t> +unsigned FunctionParserBase<Value_t>::decFuncWrapperRefCount +(FunctionWrapper* wrapper) +{ + return --wrapper->mReferenceCount; +} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::FuncWrapperPtrData(): + mRawFuncPtr(0), mFuncWrapperPtr(0), mParams(0) +{} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::~FuncWrapperPtrData() +{ + if(mFuncWrapperPtr && + FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0) + delete mFuncWrapperPtr; +} + +template<typename Value_t> +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::FuncWrapperPtrData +(const FuncWrapperPtrData& rhs): + mRawFuncPtr(rhs.mRawFuncPtr), + mFuncWrapperPtr(rhs.mFuncWrapperPtr), + mParams(rhs.mParams) +{ + if(mFuncWrapperPtr) + FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr); +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::Data::FuncWrapperPtrData& +FunctionParserBase<Value_t>::Data::FuncWrapperPtrData::operator= +(const FuncWrapperPtrData& rhs) +{ + if(&rhs != this) + { + if(mFuncWrapperPtr && + FunctionParserBase::decFuncWrapperRefCount(mFuncWrapperPtr) == 0) + delete mFuncWrapperPtr; + mRawFuncPtr = rhs.mRawFuncPtr; + mFuncWrapperPtr = rhs.mFuncWrapperPtr; + mParams = rhs.mParams; + if(mFuncWrapperPtr) + FunctionParserBase::incFuncWrapperRefCount(mFuncWrapperPtr); + } + return *this; +} + + +//========================================================================= +// FunctionParser constructors, destructor and assignment +//========================================================================= +template<typename Value_t> +FunctionParserBase<Value_t>::FunctionParserBase(): + mData(new Data), + mStackPtr(0) +{ +} + +template<typename Value_t> +FunctionParserBase<Value_t>::~FunctionParserBase() +{ + if(--(mData->mReferenceCounter) == 0) + delete mData; +} + +template<typename Value_t> +FunctionParserBase<Value_t>::FunctionParserBase(const FunctionParserBase& cpy): + mData(cpy.mData), + mStackPtr(0) +{ + ++(mData->mReferenceCounter); +} + +template<typename Value_t> +FunctionParserBase<Value_t>& +FunctionParserBase<Value_t>::operator=(const FunctionParserBase& cpy) +{ + if(mData != cpy.mData) + { + if(--(mData->mReferenceCounter) == 0) delete mData; + + mData = cpy.mData; + ++(mData->mReferenceCounter); + } + return *this; +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::Data* +FunctionParserBase<Value_t>::getParserData() +{ + return mData; +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::setDelimiterChar(char c) +{ + mData->mDelimiterChar = c; +} + + +//--------------------------------------------------------------------------- +// Copy-on-write method +//--------------------------------------------------------------------------- +template<typename Value_t> +void FunctionParserBase<Value_t>::CopyOnWrite() +{ + if(mData->mReferenceCounter > 1) + { + Data* oldData = mData; + mData = new Data(*oldData); + --(oldData->mReferenceCounter); + mData->mReferenceCounter = 1; + } +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::ForceDeepCopy() +{ + CopyOnWrite(); +} + + +//========================================================================= +// Epsilon +//========================================================================= +template<typename Value_t> +Value_t FunctionParserBase<Value_t>::epsilon() +{ + return Epsilon<Value_t>::value; +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::setEpsilon(Value_t value) +{ + Epsilon<Value_t>::value = value; +} + + +//========================================================================= +// User-defined identifier addition functions +//========================================================================= +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddConstant(const std::string& name, + Value_t value) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::CONSTANT, value)); + + return addNewNameData(mData->mNamePtrs, newName, false); +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddUnit(const std::string& name, + Value_t value) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::UNIT, value)); + return addNewNameData(mData->mNamePtrs, newName, false); +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddFunction +(const std::string& name, FunctionPtr ptr, unsigned paramsAmount) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name)) return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::FUNC_PTR, + unsigned(mData->mFuncPtrs.size()))); + + const bool success = addNewNameData(mData->mNamePtrs, newName, false); + if(success) + { + mData->mFuncPtrs.push_back(typename Data::FuncWrapperPtrData()); + mData->mFuncPtrs.back().mRawFuncPtr = ptr; + mData->mFuncPtrs.back().mParams = paramsAmount; + } + return success; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::addFunctionWrapperPtr +(const std::string& name, FunctionWrapper* wrapper, unsigned paramsAmount) +{ + if(!AddFunction(name, FunctionPtr(0), paramsAmount)) return false; + mData->mFuncPtrs.back().mFuncWrapperPtr = wrapper; + return true; +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::FunctionWrapper* +FunctionParserBase<Value_t>::GetFunctionWrapper(const std::string& name) +{ + CopyOnWrite(); + NamePtr namePtr(name.data(), unsigned(name.size())); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(namePtr); + + if(nameIter != mData->mNamePtrs.end() && + nameIter->second.type == NameData<Value_t>::FUNC_PTR) + { + return mData->mFuncPtrs[nameIter->second.index].mFuncWrapperPtr; + } + return 0; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::CheckRecursiveLinking +(const FunctionParserBase* fp) const +{ + if(fp == this) return true; + for(unsigned i = 0; i < fp->mData->mFuncParsers.size(); ++i) + if(CheckRecursiveLinking(fp->mData->mFuncParsers[i].mParserPtr)) + return true; + return false; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::AddFunction(const std::string& name, + FunctionParserBase& fp) +{ + if(!containsOnlyValidIdentifierChars<Value_t>(name) || + CheckRecursiveLinking(&fp)) + return false; + + CopyOnWrite(); + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(name.data(), unsigned(name.size())), + NameData<Value_t>(NameData<Value_t>::PARSER_PTR, + unsigned(mData->mFuncParsers.size()))); + + const bool success = addNewNameData(mData->mNamePtrs, newName, false); + if(success) + { + mData->mFuncParsers.push_back(typename Data::FuncParserPtrData()); + mData->mFuncParsers.back().mParserPtr = &fp; + mData->mFuncParsers.back().mParams = fp.mData->mVariablesAmount; + } + return success; +} + +template<typename Value_t> +bool FunctionParserBase<Value_t>::RemoveIdentifier(const std::string& name) +{ + CopyOnWrite(); + + NamePtr namePtr(name.data(), unsigned(name.size())); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(namePtr); + + if(nameIter != mData->mNamePtrs.end()) + { + if(nameIter->second.type == NameData<Value_t>::VARIABLE) + { + // Illegal attempt to delete variables + return false; + } + delete[] nameIter->first.name; + mData->mNamePtrs.erase(nameIter); + return true; + } + return false; +} + + +//========================================================================= +// Function parsing +//========================================================================= +namespace +{ + // Error messages returned by ErrorMsg(): + const char* const ParseErrorMessage[]= + { + "Syntax error", // 0 + "Mismatched parenthesis", // 1 + "Missing ')'", // 2 + "Empty parentheses", // 3 + "Syntax error: Operator expected", // 4 + "Not enough memory", // 5 + "An unexpected error occurred. Please make a full bug report " + "to the author", // 6 + "Syntax error in parameter 'Vars' given to " + "FunctionParser::Parse()", // 7 + "Illegal number of parameters to function", // 8 + "Syntax error: Premature end of string", // 9 + "Syntax error: Expecting ( after function", // 10 + "Syntax error: Unknown identifier", // 11 + "(No function has been parsed yet)", + "" + }; + + template<typename Value_t> + inline typename FunctionParserBase<Value_t>::ParseErrorType + noCommaError(char c) + { + return c == ')' ? + FunctionParserBase<Value_t>::ILL_PARAMS_AMOUNT : + FunctionParserBase<Value_t>::SYNTAX_ERROR; + } + + template<typename Value_t> + inline typename FunctionParserBase<Value_t>::ParseErrorType + noParenthError(char c) + { + return c == ',' ? + FunctionParserBase<Value_t>::ILL_PARAMS_AMOUNT : + FunctionParserBase<Value_t>::MISSING_PARENTH; + } + + template<unsigned offset> + struct IntLiteralMask + { + enum { mask = + // ( 1UL << ('-'-offset)) | + (0x3FFUL << ('0'-offset)) }; /* 0x3FF = 10 bits worth "1" */ + // Note: If you change fparser to support negative numbers parsing + // (as opposed to parsing them as cNeg followed by literal), + // enable the '-' line above, and change the offset value + // in BeginsLiteral() to '-' instead of '.'. + }; + + template<typename Value_t, unsigned offset> + struct LiteralMask + { + enum { mask = + ( 1UL << ('.'-offset)) | + IntLiteralMask<offset>::mask }; + }; +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<unsigned offset> + struct LiteralMask<long, offset>: public IntLiteralMask<offset> + { + }; +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<unsigned offset> + struct LiteralMask<GmpInt, offset>: public IntLiteralMask<offset> + { + }; +#endif + + template<unsigned offset> + struct SimpleSpaceMask + { + enum { mask = + (1UL << ('\r'-offset)) | + (1UL << ('\n'-offset)) | + (1UL << ('\v'-offset)) | + (1UL << ('\t'-offset)) | + (1UL << (' ' -offset)) }; + }; + + template<typename Value_t> + inline bool BeginsLiteral(unsigned byte) + { + enum { n = sizeof(unsigned long)>=8 ? 0 : '.' }; + byte -= n; + if(byte > (unsigned char)('9'-n)) return false; + unsigned long shifted = 1UL << byte; + const unsigned long mask = LiteralMask<Value_t, n>::mask; + return (mask & shifted) != 0; + } + + template<typename CharPtr> + inline void SkipSpace(CharPtr& function) + { +/* + Space characters in unicode: +U+0020 SPACE Depends on font, often adjusted (see below) +U+00A0 NO-BREAK SPACE As a space, but often not adjusted +U+2000 EN QUAD 1 en (= 1/2 em) +U+2001 EM QUAD 1 em (nominally, the height of the font) +U+2002 EN SPACE 1 en (= 1/2 em) +U+2003 EM SPACE 1 em +U+2004 THREE-PER-EM SPACE 1/3 em +U+2005 FOUR-PER-EM SPACE 1/4 em +U+2006 SIX-PER-EM SPACE 1/6 em +U+2007 FIGURE SPACE Tabular width, the width of digits +U+2008 PUNCTUATION SPACE The width of a period . +U+2009 THIN SPACE 1/5 em (or sometimes 1/6 em) +U+200A HAIR SPACE Narrower than THIN SPACE +U+200B ZERO WIDTH SPACE Nominally no width, but may expand +U+202F NARROW NO-BREAK SPACE Narrower than NO-BREAK SPACE (or SPACE) +U+205F MEDIUM MATHEMATICAL SPACE 4/18 em +U+3000 IDEOGRAPHIC SPACE The width of ideographic (CJK) characters. + Also: +U+000A \n +U+000D \r +U+0009 \t +U+000B \v + As UTF-8 sequences: + 09 + 0A + 0B + 0D + 20 + C2 A0 + E2 80 80-8B + E2 80 AF + E2 81 9F + E3 80 80 +*/ + while(true) + { + enum { n = sizeof(unsigned long)>=8 ? 0 : '\t' }; + typedef signed char schar; + unsigned byte = (unsigned char)*function; + byte -= n; + // ^Note: values smaller than n intentionally become + // big values here due to integer wrap. The + // comparison below thus excludes them, making + // the effective range 0x09..0x20 (32-bit) + // or 0x00..0x20 (64-bit) within the if-clause. + if(byte <= (unsigned char)(' '-n)) + { + unsigned long shifted = 1UL << byte; + const unsigned long mask = SimpleSpaceMask<n>::mask; + if(mask & shifted) + { ++function; continue; } // \r, \n, \t, \v and space + break; + } + if(likely(byte < 0xC2-n)) break; + + if(byte == 0xC2-n && function[1] == char(0xA0)) + { function += 2; continue; } // U+00A0 + if(byte == 0xE3-n && + function[1] == char(0x80) && function[2] == char(0x80)) + { function += 3; continue; } // U+3000 + if(byte == 0xE2-n) + { + if(function[1] == char(0x81)) + { + if(function[2] != char(0x9F)) break; + function += 3; // U+205F + continue; + } + if(function[1] == char(0x80)) + if(function[2] == char(0xAF) || // U+202F + schar(function[2]) <= schar(0x8B) // U+2000..U+200B + ) + { + function += 3; + continue; + } + } + break; + } // while(true) + } // SkipSpace(CharPtr& function) +} + +// --------------------------------------------------------------------------- +// Return parse error message +// --------------------------------------------------------------------------- +template<typename Value_t> +const char* FunctionParserBase<Value_t>::ErrorMsg() const +{ + return ParseErrorMessage[mData->mParseErrorType]; +} + +template<typename Value_t> +typename FunctionParserBase<Value_t>::ParseErrorType +FunctionParserBase<Value_t>::GetParseErrorType() const +{ + return mData->mParseErrorType; +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::EvalError() const +{ + return mData->mEvalErrorType; +} + + +// --------------------------------------------------------------------------- +// Parse variables +// --------------------------------------------------------------------------- +template<typename Value_t> +bool FunctionParserBase<Value_t>::ParseVariables +(const std::string& inputVarString) +{ + if(mData->mVariablesString == inputVarString) return true; + + /* Delete existing variables from mNamePtrs */ + for(typename NamePtrsMap<Value_t>::iterator i = + mData->mNamePtrs.begin(); + i != mData->mNamePtrs.end(); ) + { + if(i->second.type == NameData<Value_t>::VARIABLE) + { + typename NamePtrsMap<Value_t>::iterator j (i); + ++i; + mData->mNamePtrs.erase(j); + } + else ++i; + } + mData->mVariablesString = inputVarString; + + const std::string& vars = mData->mVariablesString; + const unsigned len = unsigned(vars.size()); + + unsigned varNumber = VarBegin; + + const char* beginPtr = vars.c_str(); + const char* finalPtr = beginPtr + len; + while(beginPtr < finalPtr) + { + SkipSpace(beginPtr); + unsigned nameLength = readIdentifier<Value_t>(beginPtr); + if(nameLength == 0 || (nameLength & 0x80000000U)) return false; + const char* endPtr = beginPtr + nameLength; + SkipSpace(endPtr); + if(endPtr != finalPtr && *endPtr != ',') return false; + + std::pair<NamePtr, NameData<Value_t> > newName + (NamePtr(beginPtr, nameLength), + NameData<Value_t>(NameData<Value_t>::VARIABLE, varNumber++)); + + if(!addNewNameData(mData->mNamePtrs, newName, true)) + { + return false; + } + + beginPtr = endPtr + 1; + } + + mData->mVariablesAmount = varNumber - VarBegin; + return true; +} + +// --------------------------------------------------------------------------- +// Parse() public interface functions +// --------------------------------------------------------------------------- +template<typename Value_t> +int FunctionParserBase<Value_t>::Parse(const char* Function, + const std::string& Vars, + bool useDegrees) +{ + CopyOnWrite(); + + if(!ParseVariables(Vars)) + { + mData->mParseErrorType = INVALID_VARS; + return int(strlen(Function)); + } + + return ParseFunction(Function, useDegrees); +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::Parse(const std::string& Function, + const std::string& Vars, + bool useDegrees) +{ + CopyOnWrite(); + + if(!ParseVariables(Vars)) + { + mData->mParseErrorType = INVALID_VARS; + return int(Function.size()); + } + + return ParseFunction(Function.c_str(), useDegrees); +} + + +// --------------------------------------------------------------------------- +// Main parsing function +// --------------------------------------------------------------------------- +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseFunction(const char* function, + bool useDegrees) +{ + mData->mUseDegreeConversion = useDegrees; + mData->mParseErrorType = FP_NO_ERROR; + + mData->mInlineVarNames.clear(); + mData->mByteCode.clear(); mData->mByteCode.reserve(128); + mData->mImmed.clear(); mData->mImmed.reserve(128); + mData->mStackSize = mStackPtr = 0; + + mData->mHasByteCodeFlags = false; + + const char* ptr = Compile(function); + mData->mInlineVarNames.clear(); + + if(mData->mHasByteCodeFlags) + { + for(unsigned i = unsigned(mData->mByteCode.size()); i-- > 0; ) + mData->mByteCode[i] &= ~FP_ParamGuardMask; + } + + if(mData->mParseErrorType != FP_NO_ERROR) + return int(mData->mErrorLocation - function); + + assert(ptr); // Should never be null at this point. It's a bug otherwise. + if(*ptr) + { + if(mData->mDelimiterChar == 0 || *ptr != mData->mDelimiterChar) + mData->mParseErrorType = EXPECT_OPERATOR; + return int(ptr - function); + } + +#ifndef FP_USE_THREAD_SAFE_EVAL + mData->mStack.resize(mData->mStackSize); +#endif + + return -1; +} + + +//========================================================================= +// Parsing and bytecode compiling functions +//========================================================================= +template<typename Value_t> +inline const char* FunctionParserBase<Value_t>::SetErrorType(ParseErrorType t, + const char* pos) +{ + mData->mParseErrorType = t; + mData->mErrorLocation = pos; + return 0; +} + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::incStackPtr() +{ + if(++mStackPtr > mData->mStackSize) ++(mData->mStackSize); +} + +namespace +{ + const unsigned char powi_factor_table[128] = + { + 0,1,0,0,0,0,0,0, 0, 0,0,0,0,0,0,3,/* 0 - 15 */ + 0,0,0,0,0,0,0,0, 0, 5,0,3,0,0,3,0,/* 16 - 31 */ + 0,0,0,0,0,0,0,3, 0, 0,0,0,0,5,0,0,/* 32 - 47 */ + 0,0,5,3,0,0,3,5, 0, 3,0,0,3,0,0,3,/* 48 - 63 */ + 0,0,0,0,0,0,0,0, 0, 0,0,3,0,0,3,0,/* 64 - 79 */ + 0,9,0,0,0,5,0,3, 0, 0,5,7,0,0,0,5,/* 80 - 95 */ + 0,0,0,3,5,0,3,0, 0, 3,0,0,3,0,5,3,/* 96 - 111 */ + 0,0,3,5,0,9,0,7, 3,11,0,3,0,5,3,0,/* 112 - 127 */ + }; + + inline int get_powi_factor(long abs_int_exponent) + { + if(abs_int_exponent >= int(sizeof(powi_factor_table))) return 0; + return powi_factor_table[abs_int_exponent]; + } + +#if 0 + int EstimatePowiComplexity(int abs_int_exponent) + { + int cost = 0; + while(abs_int_exponent > 1) + { + int factor = get_powi_factor(abs_int_exponent); + if(factor) + { + cost += EstimatePowiComplexity(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + cost += 3; // sqr + } + else + { + cost += 4; // dup+mul + abs_int_exponent -= 1; + } + } + return cost; + } +#endif + + bool IsEligibleIntPowiExponent(long int_exponent) + { + if(int_exponent == 0) return false; + long abs_int_exponent = int_exponent; + #if 0 + int cost = 0; + + if(abs_int_exponent < 0) + { + cost += 11; + abs_int_exponent = -abs_int_exponent; + } + + cost += EstimatePowiComplexity(abs_int_exponent); + + return cost < (10*3 + 4*4); + #else + if(abs_int_exponent < 0) abs_int_exponent = -abs_int_exponent; + + return (abs_int_exponent >= 1) + && (abs_int_exponent <= 46 || + (abs_int_exponent <= 1024 && + (abs_int_exponent & (abs_int_exponent - 1)) == 0)); + #endif + } + + /* Needed by fp_opcode_add.inc if tracing is enabled */ + template<typename Value_t> + std::string findName(const NamePtrsMap<Value_t>& nameMap, + unsigned index, + typename NameData<Value_t>::DataType type) + { + for(typename NamePtrsMap<Value_t>::const_iterator + iter = nameMap.begin(); + iter != nameMap.end(); + ++iter) + { + if(iter->second.type == type && iter->second.index == index) + return std::string(iter->first.name, + iter->first.name + iter->first.nameLength); + } + return "?"; + } +} + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::AddImmedOpcode(Value_t value) +{ + mData->mImmed.push_back(value); + mData->mByteCode.push_back(cImmed); +} + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::CompilePowi(long abs_int_exponent) +{ + int num_muls=0; + while(abs_int_exponent > 1) + { + long factor = get_powi_factor(abs_int_exponent); + if(factor) + { + CompilePowi(factor); + abs_int_exponent /= factor; + continue; + } + if(!(abs_int_exponent & 1)) + { + abs_int_exponent /= 2; + mData->mByteCode.push_back(cSqr); + // ^ Don't put AddFunctionOpcode here, + // it would slow down a great deal. + } + else + { + mData->mByteCode.push_back(cDup); + incStackPtr(); + abs_int_exponent -= 1; + ++num_muls; + } + } + if(num_muls > 0) + { + mData->mByteCode.resize(mData->mByteCode.size()+num_muls, cMul); + mStackPtr -= num_muls; + } +} + +template<typename Value_t> +inline bool FunctionParserBase<Value_t>::TryCompilePowi(Value_t original_immed) +{ + Value_t changed_immed = original_immed; + for(int sqrt_count=0; /**/; ++sqrt_count) + { + long int_exponent = makeLongInteger(changed_immed); + if(isLongInteger(changed_immed) && + IsEligibleIntPowiExponent(int_exponent)) + { + long abs_int_exponent = int_exponent; + if(abs_int_exponent < 0) + abs_int_exponent = -abs_int_exponent; + + mData->mImmed.pop_back(); mData->mByteCode.pop_back(); + --mStackPtr; + // ^Though the above is accounted for by the procedure + // that generates cPow, we need it for correct cFetch + // indexes in CompilePowi(). + + while(sqrt_count > 0) + { + int opcode = cSqrt; + if(sqrt_count == 1 && int_exponent < 0) + { + opcode = cRSqrt; + int_exponent = -int_exponent; + } + mData->mByteCode.push_back(opcode); + --sqrt_count; + } + if((abs_int_exponent & 1) == 0) + { + // This special rule fixes the optimization + // shortcoming of (-x)^2 with minimal overhead. + AddFunctionOpcode(cSqr); + abs_int_exponent >>= 1; + } + CompilePowi(abs_int_exponent); + if(int_exponent < 0) mData->mByteCode.push_back(cInv); + ++mStackPtr; // Needed because cPow adding will assume this. + return true; + } + if(sqrt_count >= 4) break; + changed_immed += changed_immed; + } + + // When we don't know whether x >= 0, we still know that + // x^y can be safely converted into exp(y * log(x)) + // when y is _not_ integer, because we know that x >= 0. + // Otherwise either expression will give a NaN. + if(/*!isInteger(original_immed) ||*/ + IsNeverNegativeValueOpcode(mData->mByteCode[mData->mByteCode.size()-2])) + { + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + //--mStackPtr; - accounted for by the procedure that generates cPow + AddFunctionOpcode(cLog); + AddImmedOpcode(original_immed); + //incStackPtr(); - this and the next are redundant because... + AddFunctionOpcode(cMul); + //--mStackPtr; - ...because the cImmed was popped earlier. + AddFunctionOpcode(cExp); + return true; + } + return false; +} + +//#include "fpoptimizer/opcodename.hh" +// ^ needed only if FP_TRACE_BYTECODE_OPTIMIZATION() is used + +template<typename Value_t> +inline void FunctionParserBase<Value_t>::AddFunctionOpcode(unsigned opcode) +{ +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 0 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} + +#ifdef FP_SUPPORT_LONG_INT_TYPE +template<> +inline void FunctionParserBase<long>::AddFunctionOpcode(unsigned opcode) +{ + typedef long Value_t; +#define FP_FLOAT_VERSION 0 +#define FP_COMPLEX_VERSION 0 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> +inline void FunctionParserBase<GmpInt>::AddFunctionOpcode(unsigned opcode) +{ + typedef GmpInt Value_t; +#define FP_FLOAT_VERSION 0 +#define FP_COMPLEX_VERSION 0 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +template<> +inline void FunctionParserBase<std::complex<double> >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex<double> Value_t; +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 1 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +template<> +inline void FunctionParserBase<std::complex<float> >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex<float> Value_t; +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 1 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +template<> +inline void FunctionParserBase<std::complex<long double> >::AddFunctionOpcode(unsigned opcode) +{ + typedef std::complex<long double> Value_t; +#define FP_FLOAT_VERSION 1 +#define FP_COMPLEX_VERSION 1 +#include "extrasrc/fp_opcode_add.inc" +#undef FP_COMPLEX_VERSION +#undef FP_FLOAT_VERSION +} +#endif + +template<typename Value_t> +unsigned +FunctionParserBase<Value_t>::ParseIdentifier(const char* function) +{ + return readIdentifier<Value_t>(function); +} + +template<typename Value_t> +std::pair<const char*, Value_t> +FunctionParserBase<Value_t>::ParseLiteral(const char* function) +{ + char* endptr; +#if 0 /* Profile the hex literal parser */ + if(function[0]=='0' && function[1]=='x') + { + // Parse hexadecimal literal if fp_parseLiteral didn't already + Value_t val = parseHexLiteral<Value_t>(function+2, &endptr); + if(endptr == function+2) + return std::pair<const char*,Value_t> (function, Value_t()); + return std::pair<const char*, Value_t> (endptr, val); + } +#endif + Value_t val = fp_parseLiteral<Value_t>(function, &endptr); + + if(endptr == function+1 && function[0] == '0' && function[1] == 'x') + { + // Parse hexadecimal literal if fp_parseLiteral didn't already + val = parseHexLiteral<Value_t>(function+2, &endptr); + if(endptr == function+2) + return std::pair<const char*,Value_t> (function, Value_t()); + } + else if(endptr == function) + return std::pair<const char*,Value_t> (function, Value_t()); + + return std::pair<const char*,Value_t> (endptr, val); +} + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +template<> +std::pair<const char*, MpfrFloat> +FunctionParserBase<MpfrFloat>::ParseLiteral(const char* function) +{ + char* endPtr; + const MpfrFloat val = MpfrFloat::parseString(function, &endPtr); + if(endPtr == function) + return std::pair<const char*,MpfrFloat> (function, MpfrFloat()); + return std::pair<const char*,MpfrFloat> (endPtr, val); +} +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> +std::pair<const char*, GmpInt> +FunctionParserBase<GmpInt>::ParseLiteral(const char* function) +{ + char* endPtr; + const GmpInt val = GmpInt::parseString(function, &endPtr); + if(endPtr == function) + return std::pair<const char*,GmpInt> (function, GmpInt()); + return std::pair<const char*,GmpInt> (endPtr, val); +} +#endif + + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileLiteral(const char* function) +{ + std::pair<const char*, Value_t> result = ParseLiteral(function); + + if(result.first == function) + return SetErrorType(SYNTAX_ERROR, result.first); + + AddImmedOpcode(result.second); + incStackPtr(); + SkipSpace(result.first); + return result.first; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileIf(const char* function) +{ + if(*function != '(') return SetErrorType(EXPECT_PARENTH_FUNC, function); + + function = CompileExpression(function+1); + if(!function) return 0; + if(*function != ',') + return SetErrorType(noCommaError<Value_t>(*function), function); + + OPCODE opcode = cIf; + if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back(); + if(IsNeverNegativeValueOpcode(mData->mByteCode.back())) + { + // If we know that the condition to be tested is always + // a positive value (such as when produced by "x<y"), + // we can use the faster opcode to evaluate it. + // cIf tests whether fabs(cond) >= 0.5, + // cAbsIf simply tests whether cond >= 0.5. + opcode = cAbsIf; + } + + mData->mByteCode.push_back(opcode); + const unsigned curByteCodeSize = unsigned(mData->mByteCode.size()); + PushOpcodeParam<false>(0); // Jump index; to be set later + PushOpcodeParam<true> (0); // Immed jump index; to be set later + + --mStackPtr; + + function = CompileExpression(function + 1); + if(!function) return 0; + if(*function != ',') + return SetErrorType(noCommaError<Value_t>(*function), function); + + mData->mByteCode.push_back(cJump); + const unsigned curByteCodeSize2 = unsigned(mData->mByteCode.size()); + const unsigned curImmedSize2 = unsigned(mData->mImmed.size()); + PushOpcodeParam<false>(0); // Jump index; to be set later + PushOpcodeParam<true> (0); // Immed jump index; to be set later + + --mStackPtr; + + function = CompileExpression(function + 1); + if(!function) return 0; + if(*function != ')') + return SetErrorType(noParenthError<Value_t>(*function), function); + + PutOpcodeParamAt<true> ( mData->mByteCode.back(), unsigned(mData->mByteCode.size()-1) ); + // ^Necessary for guarding against if(x,1,2)+1 being changed + // into if(x,1,3) by fp_opcode_add.inc + + // Set jump indices + PutOpcodeParamAt<false>( curByteCodeSize2+1, curByteCodeSize ); + PutOpcodeParamAt<false>( curImmedSize2, curByteCodeSize+1 ); + PutOpcodeParamAt<false>( unsigned(mData->mByteCode.size())-1, curByteCodeSize2); + PutOpcodeParamAt<false>( unsigned(mData->mImmed.size()), curByteCodeSize2+1); + + ++function; + SkipSpace(function); + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileFunctionParams +(const char* function, unsigned requiredParams) +{ + if(*function != '(') return SetErrorType(EXPECT_PARENTH_FUNC, function); + + if(requiredParams > 0) + { + const char* function_end = CompileExpression(function+1); + if(!function_end) + { + // If an error occurred, verify whether it was caused by () + ++function; + SkipSpace(function); + if(*function == ')') + return SetErrorType(ILL_PARAMS_AMOUNT, function); + // Not caused by (), use the error message given by CompileExpression() + return 0; + } + function = function_end; + + for(unsigned i = 1; i < requiredParams; ++i) + { + if(*function != ',') + return SetErrorType(noCommaError<Value_t>(*function), function); + + function = CompileExpression(function+1); + if(!function) return 0; + } + // No need for incStackPtr() because each parse parameter calls it + mStackPtr -= requiredParams-1; + } + else + { + incStackPtr(); // return value of function is pushed onto the stack + ++function; + SkipSpace(function); + } + + if(*function != ')') + return SetErrorType(noParenthError<Value_t>(*function), function); + ++function; + SkipSpace(function); + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileElement(const char* function) +{ + if(BeginsLiteral<Value_t>( (unsigned char) *function)) + return CompileLiteral(function); + + unsigned nameLength = readIdentifier<Value_t>(function); + if(nameLength == 0) + { + // No identifier found + if(*function == '(') return CompileParenthesis(function); + if(*function == ')') return SetErrorType(MISM_PARENTH, function); + return SetErrorType(SYNTAX_ERROR, function); + } + + // Function, variable or constant + if(nameLength & 0x80000000U) // Function + { + OPCODE func_opcode = OPCODE( (nameLength >> 16) & 0x7FFF ); + return CompileFunction(function + (nameLength & 0xFFFF), func_opcode); + } + + NamePtr name(function, nameLength); + const char* endPtr = function + nameLength; + SkipSpace(endPtr); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(name); + if(nameIter == mData->mNamePtrs.end()) + { + // Check if it's an inline variable: + for(typename Data::InlineVarNamesContainer::reverse_iterator iter = + mData->mInlineVarNames.rbegin(); + iter != mData->mInlineVarNames.rend(); + ++iter) + { + if(name == iter->mName) + { + if( iter->mFetchIndex+1 == mStackPtr) + { + mData->mByteCode.push_back(cDup); + } + else + { + mData->mByteCode.push_back(cFetch); + PushOpcodeParam<true>(iter->mFetchIndex); + } + incStackPtr(); + return endPtr; + } + } + + return SetErrorType(UNKNOWN_IDENTIFIER, function); + } + + const NameData<Value_t>* nameData = &nameIter->second; + switch(nameData->type) + { + case NameData<Value_t>::VARIABLE: // is variable + if(unlikely(!mData->mByteCode.empty() && + mData->mByteCode.back() == nameData->index)) + mData->mByteCode.push_back(cDup); + else + mData->mByteCode.push_back(nameData->index); + incStackPtr(); + return endPtr; + + case NameData<Value_t>::CONSTANT: // is constant + AddImmedOpcode(nameData->value); + incStackPtr(); + return endPtr; + + case NameData<Value_t>::UNIT: // is unit (error if appears here) + break; + + case NameData<Value_t>::FUNC_PTR: // is C++ function + function = CompileFunctionParams + (endPtr, mData->mFuncPtrs[nameData->index].mParams); + //if(!function) return 0; + mData->mByteCode.push_back(cFCall); + PushOpcodeParam<true>(nameData->index); + return function; + + case NameData<Value_t>::PARSER_PTR: // is FunctionParser + function = CompileFunctionParams + (endPtr, mData->mFuncParsers[nameData->index].mParams); + //if(!function) return 0; + mData->mByteCode.push_back(cPCall); + PushOpcodeParam<true>(nameData->index); + return function; + } + + // When it's an unit (or unrecognized type): + return SetErrorType(SYNTAX_ERROR, function); +} + +template<typename Value_t> +inline const char* FunctionParserBase<Value_t>::CompileFunction +(const char* function, unsigned func_opcode) +{ + SkipSpace(function); + const FuncDefinition& funcDef = Functions[func_opcode]; + + if(func_opcode == cIf) // "if" is a special case + return CompileIf(function); + + unsigned requiredParams = funcDef.params; + + function = CompileFunctionParams(function, requiredParams); + if(!function) return 0; + + if(mData->mUseDegreeConversion) + { + if(funcDef.flags & FuncDefinition::AngleIn) + AddFunctionOpcode(cRad); + + AddFunctionOpcode(func_opcode); + + if(funcDef.flags & FuncDefinition::AngleOut) + AddFunctionOpcode(cDeg); + } + else + { + AddFunctionOpcode(func_opcode); + } + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileParenthesis(const char* function) +{ + ++function; // Skip '(' + + SkipSpace(function); + if(*function == ')') return SetErrorType(EMPTY_PARENTH, function); + function = CompileExpression(function); + if(!function) return 0; + + if(*function != ')') return SetErrorType(MISSING_PARENTH, function); + ++function; // Skip ')' + + SkipSpace(function); + return function; +} + +template<typename Value_t> +const char* +FunctionParserBase<Value_t>::CompilePossibleUnit(const char* function) +{ + unsigned nameLength = readIdentifier<Value_t>(function); + if(nameLength & 0x80000000U) return function; // built-in function name + if(nameLength != 0) + { + NamePtr name(function, nameLength); + + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(name); + if(nameIter != mData->mNamePtrs.end()) + { + const NameData<Value_t>* nameData = &nameIter->second; + if(nameData->type == NameData<Value_t>::UNIT) + { + AddImmedOpcode(nameData->value); + incStackPtr(); + AddFunctionOpcode(cMul); + --mStackPtr; + + const char* endPtr = function + nameLength; + SkipSpace(endPtr); + return endPtr; + } + } + } + + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompilePow(const char* function) +{ + function = CompileElement(function); + if(!function) return 0; + function = CompilePossibleUnit(function); + + if(*function == '^') + { + ++function; + SkipSpace(function); + + unsigned op = cPow; + if(mData->mByteCode.back() == cImmed) + { + if(mData->mImmed.back() == fp_const_e<Value_t>()) + { op = cExp; mData->mByteCode.pop_back(); + mData->mImmed.pop_back(); --mStackPtr; } + else if(mData->mImmed.back() == Value_t(2)) + { op = cExp2; mData->mByteCode.pop_back(); + mData->mImmed.pop_back(); --mStackPtr; } + } + + function = CompileUnaryMinus(function); + if(!function) return 0; + + // add opcode + AddFunctionOpcode(op); + + if(op == cPow) --mStackPtr; + } + return function; +} + +/* Currently the power operator is skipped for integral types because its + usefulness with them is questionable, and in the case of GmpInt, for safety + reasons: + - With long int almost any power, except for very small ones, would + overflow the result, so the usefulness of this is rather questionable. + - With GmpInt the power operator could be easily abused to make the program + run out of memory (think of a function like "10^10^10^10^1000000"). +*/ +#ifdef FP_SUPPORT_LONG_INT_TYPE +template<> +inline const char* +FunctionParserBase<long>::CompilePow(const char* function) +{ + function = CompileElement(function); + if(!function) return 0; + return CompilePossibleUnit(function); +} +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +template<> +inline const char* +FunctionParserBase<GmpInt>::CompilePow(const char* function) +{ + function = CompileElement(function); + if(!function) return 0; + return CompilePossibleUnit(function); +} +#endif + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileUnaryMinus(const char* function) +{ + char op = *function; + switch(op) + { + case '-': + case '!': + ++function; + SkipSpace(function); + + function = CompileUnaryMinus(function); + if(!function) return 0; + + AddFunctionOpcode(op=='-' ? cNeg : cNot); + + return function; + default: break; + } + return CompilePow(function); +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileMult(const char* function) +{ + function = CompileUnaryMinus(function); + if(!function) return 0; + + Value_t pending_immed(1); + #define FP_FlushImmed(do_reset) \ + if(pending_immed != Value_t(1)) \ + { \ + unsigned op = cMul; \ + if(!IsIntType<Value_t>::result && mData->mByteCode.back() == cInv) \ + { \ + /* (...) cInv 5 cMul -> (...) 5 cRDiv */ \ + /* ^ ^ | */ \ + mData->mByteCode.pop_back(); \ + op = cRDiv; \ + } \ + AddImmedOpcode(pending_immed); \ + incStackPtr(); \ + AddFunctionOpcode(op); \ + --mStackPtr; \ + if(do_reset) pending_immed = Value_t(1); \ + } + while(true) + { + char c = *function; + if(c == '%') + { + FP_FlushImmed(true); + ++function; + SkipSpace(function); + function = CompileUnaryMinus(function); + if(!function) return 0; + AddFunctionOpcode(cMod); + --mStackPtr; + continue; + } + if(c != '*' && c != '/') break; + + bool safe_cumulation = (c == '*' || !IsIntType<Value_t>::result); + if(!safe_cumulation) + { + FP_FlushImmed(true); + } + + ++function; + SkipSpace(function); + if(mData->mByteCode.back() == cImmed + && (safe_cumulation + || mData->mImmed.back() == Value_t(1))) + { + // 5 (...) cMul --> (...) ||| 5 cMul + // 5 (...) cDiv --> (...) cInv ||| 5 cMul + // ^ | ^ + pending_immed *= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + --mStackPtr; + function = CompileUnaryMinus(function); + if(!function) return 0; + if(c == '/') + AddFunctionOpcode(cInv); + continue; + } + if(safe_cumulation + && mData->mByteCode.back() == cMul + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) 5 cMul (...) cMul -> (:::) (...) cMul ||| 5 cMul + // (:::) 5 cMul (...) cDiv -> (:::) (...) cDiv ||| 5 cMul + // ^ ^ + pending_immed *= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + // cDiv is not tested here because the bytecode + // optimizer will convert this kind of cDivs into cMuls. + bool lhs_inverted = false; + if(!IsIntType<Value_t>::result && c == '*' + && mData->mByteCode.back() == cInv) + { + // (:::) cInv (...) cMul -> (:::) (...) cRDiv + // (:::) cInv (...) cDiv -> (:::) (...) cMul cInv + // ^ ^ | + mData->mByteCode.pop_back(); + lhs_inverted = true; + } + function = CompileUnaryMinus(function); + if(!function) return 0; + if(safe_cumulation + && mData->mByteCode.back() == cMul + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cMul cMul -> (:::) (...) cMul ||| 5 Mul + // (:::) (...) 5 cMul cDiv -> (:::) (...) cDiv ||| /5 Mul + // ^ ^ + if(c == '*') + pending_immed *= mData->mImmed.back(); + else + pending_immed /= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + else + if(safe_cumulation + && mData->mByteCode.back() == cRDiv + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cRDiv cMul -> (:::) (...) cDiv ||| 5 cMul + // (:::) (...) 5 cRDiv cDiv -> (:::) (...) cMul ||| /5 cMul + // ^ ^ + if(c == '*') + { c = '/'; pending_immed *= mData->mImmed.back(); } + else + { c = '*'; pending_immed /= mData->mImmed.back(); } + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + if(!lhs_inverted) // if (/x/y) was changed to /(x*y), add missing cInv + { + AddFunctionOpcode(c == '*' ? cMul : cDiv); + --mStackPtr; + } + else if(c == '*') // (/x)*y -> rdiv(x,y) + { + AddFunctionOpcode(cRDiv); + --mStackPtr; + } + else // (/x)/y -> /(x*y) + { + AddFunctionOpcode(cMul); + --mStackPtr; + AddFunctionOpcode(cInv); + } + } + FP_FlushImmed(false); + #undef FP_FlushImmed + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileAddition(const char* function) +{ + function = CompileMult(function); + if(!function) return 0; + + Value_t pending_immed(0); + #define FP_FlushImmed(do_reset) \ + if(pending_immed != Value_t(0)) \ + { \ + unsigned op = cAdd; \ + if(mData->mByteCode.back() == cNeg) \ + { \ + /* (...) cNeg 5 cAdd -> (...) 5 cRSub */ \ + /* ^ ^ | */ \ + mData->mByteCode.pop_back(); \ + op = cRSub; \ + } \ + AddImmedOpcode(pending_immed); \ + incStackPtr(); \ + AddFunctionOpcode(op); \ + --mStackPtr; \ + if(do_reset) pending_immed = Value_t(0); \ + } + while(true) + { + char c = *function; + if(c != '+' && c != '-') break; + ++function; + SkipSpace(function); + if(mData->mByteCode.back() == cImmed) + { + // 5 (...) cAdd --> (...) ||| 5 cAdd + // 5 (...) cSub --> (...) cNeg ||| 5 cAdd + // ^ | ^ + pending_immed += mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + --mStackPtr; + function = CompileMult(function); + if(!function) return 0; + if(c == '-') + AddFunctionOpcode(cNeg); + continue; + } + if(mData->mByteCode.back() == cAdd + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) 5 cAdd (...) cAdd -> (:::) (...) cAdd ||| 5 cAdd + // (:::) 5 cAdd (...) cSub -> (:::) (...) cSub ||| 5 cAdd + // ^ ^ + pending_immed += mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + // cSub is not tested here because the bytecode + // optimizer will convert this kind of cSubs into cAdds. + bool lhs_negated = false; + if(mData->mByteCode.back() == cNeg) + { + // (:::) cNeg (...) cAdd -> (:::) (...) cRSub + // (:::) cNeg (...) cSub -> (:::) (...) cAdd cNeg + // ^ ^ | + mData->mByteCode.pop_back(); + lhs_negated = true; + } + function = CompileMult(function); + if(!function) return 0; + if(mData->mByteCode.back() == cAdd + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cAdd cAdd -> (:::) (...) cAdd ||| 5 Add + // (:::) (...) 5 cAdd cSub -> (:::) (...) cSub ||| -5 Add + // ^ ^ + if(c == '+') + pending_immed += mData->mImmed.back(); + else + pending_immed -= mData->mImmed.back(); + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + else + if(mData->mByteCode.back() == cRSub + && mData->mByteCode[mData->mByteCode.size()-2] == cImmed) + { + // (:::) (...) 5 cRSub cAdd -> (:::) (...) cSub ||| 5 cAdd + // (:::) (...) 5 cRSub cSub -> (:::) (...) cAdd ||| -5 cAdd + // ^ ^ + if(c == '+') + { c = '-'; pending_immed += mData->mImmed.back(); } + else + { c = '+'; pending_immed -= mData->mImmed.back(); } + mData->mImmed.pop_back(); + mData->mByteCode.pop_back(); + mData->mByteCode.pop_back(); + } + if(!lhs_negated) // if (-x-y) was changed to -(x+y), add missing cNeg + { + AddFunctionOpcode(c == '+' ? cAdd : cSub); + --mStackPtr; + } + else if(c == '+') // (-x)+y -> rsub(x,y) + { + AddFunctionOpcode(cRSub); + --mStackPtr; + } + else // (-x)-y -> -(x+y) + { + AddFunctionOpcode(cAdd); + --mStackPtr; + AddFunctionOpcode(cNeg); + } + } + FP_FlushImmed(false); + #undef FP_FlushImmed + return function; +} + +template<typename Value_t> +inline const char* +FunctionParserBase<Value_t>::CompileComparison(const char* function) +{ + unsigned op=0; + while(true) + { + function = CompileAddition(function); + if(!function) return 0; + + if(op) + { + AddFunctionOpcode(op); + --mStackPtr; + } + switch(*function) + { + case '=': + ++function; op = cEqual; break; + case '!': + if(function[1] == '=') + { function += 2; op = cNEqual; break; } + // If '=' does not follow '!', a syntax error will + // be generated at the outermost parsing level + return function; + case '<': + if(function[1] == '=') + { function += 2; op = cLessOrEq; break; } + ++function; op = cLess; break; + case '>': + if(function[1] == '=') + { function += 2; op = cGreaterOrEq; break; } + ++function; op = cGreater; break; + default: return function; + } + SkipSpace(function); + } + return function; +} + +template<typename Value_t> +inline const char* FunctionParserBase<Value_t>::CompileAnd(const char* function) +{ + std::size_t param0end=0; + while(true) + { + function = CompileComparison(function); + if(!function) return 0; + + if(param0end) + { + if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back(); + + AddFunctionOpcode(cAnd); + --mStackPtr; + } + if(*function != '&') break; + ++function; + SkipSpace(function); + param0end = mData->mByteCode.size(); + } + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::CompileExpression(const char* function) +{ + std::size_t param0end=0; + while(true) + { + SkipSpace(function); + function = CompileAnd(function); + if(!function) return 0; + + if(param0end) + { + if(mData->mByteCode.back() == cNotNot) mData->mByteCode.pop_back(); + + AddFunctionOpcode(cOr); + --mStackPtr; + } + if(*function != '|') break; + ++function; + param0end = mData->mByteCode.size(); + } + return function; +} + +template<typename Value_t> +const char* FunctionParserBase<Value_t>::Compile(const char* function) +{ + while(true) + { + // Check if an identifier appears as first token: + SkipSpace(function); + unsigned nameLength = readIdentifier<Value_t>(function); + if(nameLength > 0 && !(nameLength & 0x80000000U)) + { + typename Data::InlineVariable inlineVar = + { NamePtr(function, nameLength), 0 }; + + // Check if it's an unknown identifier: + typename NamePtrsMap<Value_t>::iterator nameIter = + mData->mNamePtrs.find(inlineVar.mName); + if(nameIter == mData->mNamePtrs.end()) + { + const char* function2 = function + nameLength; + SkipSpace(function2); + + // Check if ":=" follows the unknown identifier: + if(function2[0] == ':' && function2[1] == '=') + { + // Parse the expression that follows and create the + // inline variable: + function2 = CompileExpression(function2 + 2); + if(!function2) return 0; + if(*function2 != ';') return function2; + + inlineVar.mFetchIndex = mStackPtr - 1; + mData->mInlineVarNames.push_back(inlineVar); + + // Continue with the expression after the ';': + function = function2 + 1; + continue; + } + } + } + break; + } + + return CompileExpression(function); +} + +template<typename Value_t> template<bool PutFlag> +inline void FunctionParserBase<Value_t>::PushOpcodeParam + (unsigned value) +{ + mData->mByteCode.push_back(value | (PutFlag ? FP_ParamGuardMask : 0u)); + if(PutFlag) mData->mHasByteCodeFlags = true; +} + +template<typename Value_t> template<bool PutFlag> +inline void FunctionParserBase<Value_t>::PutOpcodeParamAt + (unsigned value, unsigned offset) +{ + mData->mByteCode[offset] = value | (PutFlag ? FP_ParamGuardMask : 0u); + if(PutFlag) mData->mHasByteCodeFlags = true; +} + +//=========================================================================== +// Function evaluation +//=========================================================================== +template<typename Value_t> +Value_t FunctionParserBase<Value_t>::Eval(const Value_t* Vars) +{ + if(mData->mParseErrorType != FP_NO_ERROR) return Value_t(0); + + const unsigned* const byteCode = &(mData->mByteCode[0]); + const Value_t* const immed = mData->mImmed.empty() ? 0 : &(mData->mImmed[0]); + const unsigned byteCodeSize = unsigned(mData->mByteCode.size()); + unsigned IP, DP=0; + int SP=-1; + +#ifdef FP_USE_THREAD_SAFE_EVAL + /* If Eval() may be called by multiple threads simultaneously, + * then Eval() must allocate its own stack. + */ +#ifdef FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA + /* alloca() allocates room from the hardware stack. + * It is automatically freed when the function returns. + */ + Value_t* const Stack = (Value_t*)alloca(mData->mStackSize*sizeof(Value_t)); +#else + /* Allocate from the heap. Ensure that it is freed + * automatically no matter which exit path is taken. + */ + struct AutoDealloc + { + Value_t* ptr; + ~AutoDealloc() { delete[] ptr; } + } AutoDeallocStack = { new Value_t[mData->mStackSize] }; + Value_t*& Stack = AutoDeallocStack.ptr; +#endif +#else + /* No thread safety, so use a global stack. */ + std::vector<Value_t>& Stack = mData->mStack; +#endif + + for(IP=0; IP<byteCodeSize; ++IP) + { + switch(byteCode[IP]) + { +// Functions: + case cAbs: Stack[SP] = fp_abs(Stack[SP]); break; + + case cAcos: + if(IsComplexType<Value_t>::result == false + && (Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1))) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_acos(Stack[SP]); break; + + case cAcosh: + if(IsComplexType<Value_t>::result == false + && Stack[SP] < Value_t(1)) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_acosh(Stack[SP]); break; + + case cAsin: + if(IsComplexType<Value_t>::result == false + && (Stack[SP] < Value_t(-1) || Stack[SP] > Value_t(1))) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_asin(Stack[SP]); break; + + case cAsinh: Stack[SP] = fp_asinh(Stack[SP]); break; + + case cAtan: Stack[SP] = fp_atan(Stack[SP]); break; + + case cAtan2: Stack[SP-1] = fp_atan2(Stack[SP-1], Stack[SP]); + --SP; break; + + case cAtanh: + if(IsComplexType<Value_t>::result + ? (Stack[SP] == Value_t(-1) || Stack[SP] == Value_t(1)) + : (Stack[SP] <= Value_t(-1) || Stack[SP] >= Value_t(1))) + { mData->mEvalErrorType=4; return Value_t(0); } + Stack[SP] = fp_atanh(Stack[SP]); break; + + case cCbrt: Stack[SP] = fp_cbrt(Stack[SP]); break; + + case cCeil: Stack[SP] = fp_ceil(Stack[SP]); break; + + case cCos: Stack[SP] = fp_cos(Stack[SP]); break; + + case cCosh: Stack[SP] = fp_cosh(Stack[SP]); break; + + case cCot: + { + const Value_t t = fp_tan(Stack[SP]); + if(t == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/t; break; + } + + case cCsc: + { + const Value_t s = fp_sin(Stack[SP]); + if(s == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/s; break; + } + + + case cExp: Stack[SP] = fp_exp(Stack[SP]); break; + + case cExp2: Stack[SP] = fp_exp2(Stack[SP]); break; + + case cFloor: Stack[SP] = fp_floor(Stack[SP]); break; + + case cHypot: + Stack[SP-1] = fp_hypot(Stack[SP-1], Stack[SP]); + --SP; break; + + case cIf: + if(fp_truth(Stack[SP--])) + IP += 2; + else + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + } + break; + + case cInt: Stack[SP] = fp_int(Stack[SP]); break; + + case cLog: + if(IsComplexType<Value_t>::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log(Stack[SP]); break; + + case cLog10: + if(IsComplexType<Value_t>::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log10(Stack[SP]); + break; + + case cLog2: + if(IsComplexType<Value_t>::result + ? Stack[SP] == Value_t(0) + : !(Stack[SP] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP] = fp_log2(Stack[SP]); + break; + + case cMax: Stack[SP-1] = fp_max(Stack[SP-1], Stack[SP]); + --SP; break; + + case cMin: Stack[SP-1] = fp_min(Stack[SP-1], Stack[SP]); + --SP; break; + + case cPow: + // x:Negative ^ y:NonInteger is failure, + // except when the reciprocal of y forms an integer + /*if(IsComplexType<Value_t>::result == false + && Stack[SP-1] < Value_t(0) && + !isInteger(Stack[SP]) && + !isInteger(1.0 / Stack[SP])) + { mEvalErrorType=3; return Value_t(0); }*/ + // x:0 ^ y:negative is failure + if(Stack[SP-1] == Value_t(0) && + Stack[SP] < Value_t(0)) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP-1] = fp_pow(Stack[SP-1], Stack[SP]); + --SP; break; + + case cTrunc: Stack[SP] = fp_trunc(Stack[SP]); break; + + case cSec: + { + const Value_t c = fp_cos(Stack[SP]); + if(c == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/c; break; + } + + case cSin: Stack[SP] = fp_sin(Stack[SP]); break; + + case cSinh: Stack[SP] = fp_sinh(Stack[SP]); break; + + case cSqrt: + if(IsComplexType<Value_t>::result == false && + Stack[SP] < Value_t(0)) + { mData->mEvalErrorType=2; return Value_t(0); } + Stack[SP] = fp_sqrt(Stack[SP]); break; + + case cTan: Stack[SP] = fp_tan(Stack[SP]); break; + + case cTanh: Stack[SP] = fp_tanh(Stack[SP]); break; + + +// Misc: + case cImmed: Stack[++SP] = immed[DP++]; break; + + case cJump: + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + break; + } + +// Operators: + case cNeg: Stack[SP] = -Stack[SP]; break; + case cAdd: Stack[SP-1] += Stack[SP]; --SP; break; + case cSub: Stack[SP-1] -= Stack[SP]; --SP; break; + case cMul: Stack[SP-1] *= Stack[SP]; --SP; break; + + case cDiv: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] /= Stack[SP]; --SP; break; + + case cMod: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] = fp_mod(Stack[SP-1], Stack[SP]); + --SP; break; + + case cEqual: + Stack[SP-1] = fp_equal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cNEqual: + Stack[SP-1] = fp_nequal(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLess: + Stack[SP-1] = fp_less(Stack[SP-1], Stack[SP]); + --SP; break; + + case cLessOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP-1], Stack[SP]); + --SP; break; + + case cGreater: + Stack[SP-1] = fp_less(Stack[SP], Stack[SP-1]); + --SP; break; + + case cGreaterOrEq: + Stack[SP-1] = fp_lessOrEq(Stack[SP], Stack[SP-1]); + --SP; break; + + case cNot: Stack[SP] = fp_not(Stack[SP]); break; + + case cNotNot: Stack[SP] = fp_notNot(Stack[SP]); break; + + case cAnd: + Stack[SP-1] = fp_and(Stack[SP-1], Stack[SP]); + --SP; break; + + case cOr: + Stack[SP-1] = fp_or(Stack[SP-1], Stack[SP]); + --SP; break; + +// Degrees-radians conversion: + case cDeg: Stack[SP] = RadiansToDegrees(Stack[SP]); break; + case cRad: Stack[SP] = DegreesToRadians(Stack[SP]); break; + +// User-defined function calls: + case cFCall: + { + const unsigned index = byteCode[++IP]; + const unsigned params = mData->mFuncPtrs[index].mParams; + const Value_t retVal = + mData->mFuncPtrs[index].mRawFuncPtr ? + mData->mFuncPtrs[index].mRawFuncPtr(&Stack[SP-params+1]) : + mData->mFuncPtrs[index].mFuncWrapperPtr->callFunction + (&Stack[SP-params+1]); + SP -= int(params)-1; + Stack[SP] = retVal; + break; + } + + case cPCall: + { + unsigned index = byteCode[++IP]; + unsigned params = mData->mFuncParsers[index].mParams; + Value_t retVal = + mData->mFuncParsers[index].mParserPtr->Eval + (&Stack[SP-params+1]); + SP -= int(params)-1; + Stack[SP] = retVal; + const int error = + mData->mFuncParsers[index].mParserPtr->EvalError(); + if(error) + { + mData->mEvalErrorType = error; + return 0; + } + break; + } + + + case cFetch: + { + unsigned stackOffs = byteCode[++IP]; + Stack[SP+1] = Stack[stackOffs]; ++SP; + break; + } + +#ifdef FP_SUPPORT_OPTIMIZER + case cPopNMov: + { + unsigned stackOffs_target = byteCode[++IP]; + unsigned stackOffs_source = byteCode[++IP]; + Stack[stackOffs_target] = Stack[stackOffs_source]; + SP = stackOffs_target; + break; + } + + case cLog2by: + if(IsComplexType<Value_t>::result + ? Stack[SP-1] == Value_t(0) + : !(Stack[SP-1] > Value_t(0))) + { mData->mEvalErrorType=3; return Value_t(0); } + Stack[SP-1] = fp_log2(Stack[SP-1]) * Stack[SP]; + --SP; + break; + + case cNop: break; +#endif // FP_SUPPORT_OPTIMIZER + + case cSinCos: + fp_sinCos(Stack[SP], Stack[SP+1], Stack[SP]); + ++SP; + break; + case cSinhCosh: + fp_sinhCosh(Stack[SP], Stack[SP+1], Stack[SP]); + ++SP; + break; + + case cAbsNot: + Stack[SP] = fp_absNot(Stack[SP]); break; + case cAbsNotNot: + Stack[SP] = fp_absNotNot(Stack[SP]); break; + case cAbsAnd: + Stack[SP-1] = fp_absAnd(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsOr: + Stack[SP-1] = fp_absOr(Stack[SP-1], Stack[SP]); + --SP; break; + case cAbsIf: + if(fp_absTruth(Stack[SP--])) + IP += 2; + else + { + const unsigned* buf = &byteCode[IP+1]; + IP = buf[0]; + DP = buf[1]; + } + break; + + case cDup: Stack[SP+1] = Stack[SP]; ++SP; break; + + case cInv: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1)/Stack[SP]; + break; + + case cSqr: + Stack[SP] = Stack[SP]*Stack[SP]; + break; + + case cRDiv: + if(Stack[SP-1] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP-1] = Stack[SP] / Stack[SP-1]; --SP; break; + + case cRSub: Stack[SP-1] = Stack[SP] - Stack[SP-1]; --SP; break; + + case cRSqrt: + if(Stack[SP] == Value_t(0)) + { mData->mEvalErrorType=1; return Value_t(0); } + Stack[SP] = Value_t(1) / fp_sqrt(Stack[SP]); break; + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + case cReal: Stack[SP] = fp_real(Stack[SP]); break; + case cImag: Stack[SP] = fp_imag(Stack[SP]); break; + case cArg: Stack[SP] = fp_arg(Stack[SP]); break; + case cConj: Stack[SP] = fp_conj(Stack[SP]); break; + case cPolar: + Stack[SP-1] = fp_polar(Stack[SP-1], Stack[SP]); + --SP; break; +#endif + + +// Variables: + default: + Stack[++SP] = Vars[byteCode[IP]-VarBegin]; + } + } + + mData->mEvalErrorType=0; + return Stack[SP]; +} + + +//=========================================================================== +// Variable deduction +//=========================================================================== +namespace +{ + template<typename Value_t> + int deduceVariables(FunctionParserBase<Value_t>& fParser, + const char* funcStr, + std::string& destVarString, + int* amountOfVariablesFound, + std::vector<std::string>* destVarNames, + bool useDegrees) + { + typedef std::set<std::string> StrSet; + StrSet varNames; + + int oldIndex = -1; + + while(true) + { + destVarString.clear(); + for(StrSet::iterator iter = varNames.begin(); + iter != varNames.end(); + ++iter) + { + if(iter != varNames.begin()) destVarString += ","; + destVarString += *iter; + } + + const int index = + fParser.Parse(funcStr, destVarString, useDegrees); + if(index < 0) break; + if(index == oldIndex) return index; + + unsigned nameLength = readIdentifier<Value_t>(funcStr + index); + if(nameLength & 0x80000000U) return index; + if(nameLength == 0) return index; + + varNames.insert(std::string(funcStr + index, nameLength)); + oldIndex = index; + } + + if(amountOfVariablesFound) + *amountOfVariablesFound = int(varNames.size()); + + if(destVarNames) + destVarNames->assign(varNames.begin(), varNames.end()); + + return -1; + } +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseAndDeduceVariables +(const std::string& function, + int* amountOfVariablesFound, + bool useDegrees) +{ + std::string varString; + return deduceVariables(*this, function.c_str(), varString, + amountOfVariablesFound, 0, useDegrees); +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseAndDeduceVariables +(const std::string& function, + std::string& resultVarString, + int* amountOfVariablesFound, + bool useDegrees) +{ + std::string varString; + const int index = + deduceVariables(*this, function.c_str(), varString, + amountOfVariablesFound, 0, useDegrees); + if(index < 0) resultVarString = varString; + return index; +} + +template<typename Value_t> +int FunctionParserBase<Value_t>::ParseAndDeduceVariables +(const std::string& function, + std::vector<std::string>& resultVars, + bool useDegrees) +{ + std::string varString; + std::vector<std::string> vars; + const int index = + deduceVariables(*this, function.c_str(), varString, + 0, &vars, useDegrees); + if(index < 0) resultVars.swap(vars); + return index; +} + + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +//=========================================================================== +// Bytecode injection +//=========================================================================== +template<typename Value_t> +void FunctionParserBase<Value_t>::InjectRawByteCode +(const unsigned* bytecode, unsigned bytecodeAmount, + const Value_t* immed, unsigned immedAmount, unsigned stackSize) +{ + CopyOnWrite(); + + mData->mByteCode.assign(bytecode, bytecode + bytecodeAmount); + mData->mImmed.assign(immed, immed + immedAmount); + mData->mStackSize = stackSize; + +#ifndef FP_USE_THREAD_SAFE_EVAL + mData->mStack.resize(stackSize); +#endif +} + +//=========================================================================== +// Debug output +//=========================================================================== +#include <iomanip> +#include <sstream> +namespace +{ + inline void printHex(std::ostream& dest, unsigned n) + { + std::ios::fmtflags flags = dest.flags(); + dest.width(4); dest.fill('0'); std::hex(dest); //uppercase(dest); + dest << n; + dest.flags(flags); + } + + void padLine(std::ostringstream& dest, unsigned destLength) + { + for(std::size_t currentLength = dest.str().length(); + currentLength < destLength; + ++currentLength) + { + dest << ' '; + } + } + + const struct PowiMuliType + { + unsigned opcode_square; + unsigned opcode_cumulate; + unsigned opcode_invert; + unsigned opcode_half; + unsigned opcode_invhalf; + } iseq_powi = {cSqr,cMul,cInv,cSqrt,cRSqrt}, + iseq_muli = {~unsigned(0), cAdd,cNeg, ~unsigned(0),~unsigned(0) }; + + template<typename Value_t> + Value_t ParsePowiMuli( + const PowiMuliType& opcodes, + const std::vector<unsigned>& ByteCode, unsigned& IP, + unsigned limit, + std::size_t factor_stack_base, + std::vector<Value_t>& stack, + bool IgnoreExcess) + { + Value_t result = Value_t(1); + while(IP < limit) + { + if(ByteCode[IP] == opcodes.opcode_square) + { + if(!isInteger(result)) break; + result *= Value_t(2); + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_invert) + { + if(result < Value_t(0)) break; + result = -result; + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_half) + { + if(result > Value_t(0) && isEvenInteger(result)) + break; + if(isInteger(result * Value_t(0.5))) break; + result *= Value_t(0.5); + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_invhalf) + { + if(result > Value_t(0) && isEvenInteger(result)) + break; + if(isInteger(result * Value_t(-0.5))) break; + result *= Value_t(-0.5); + ++IP; + continue; + } + + unsigned dup_fetch_pos = IP; + Value_t lhs = Value_t(1); + + if(ByteCode[IP] == cFetch) + { + unsigned index = ByteCode[++IP]; + if(index < factor_stack_base + || std::size_t(index-factor_stack_base) >= stack.size()) + { + // It wasn't a powi-fetch after all + IP = dup_fetch_pos; + break; + } + lhs = stack[index - factor_stack_base]; + // Note: ^This assumes that cFetch of recentmost + // is always converted into cDup. + goto dup_or_fetch; + } + + if(ByteCode[IP] == cDup) + { + lhs = result; + goto dup_or_fetch; + + dup_or_fetch: + stack.push_back(result); + ++IP; + Value_t subexponent = ParsePowiMuli + (opcodes, + ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); + if(IP >= limit && IgnoreExcess) + return lhs*subexponent; + if(IP >= limit || ByteCode[IP] != opcodes.opcode_cumulate) + { + // It wasn't a powi-dup after all + IP = dup_fetch_pos; + break; + } + ++IP; // skip opcode_cumulate + stack.pop_back(); + result += lhs*subexponent; + continue; + } + break; + } + return result; + } + + template<typename Value_t> + Value_t ParsePowiSequence(const std::vector<unsigned>& ByteCode, + unsigned& IP, unsigned limit, + std::size_t factor_stack_base, + bool IgnoreExcess = false) + { + std::vector<Value_t> stack; + stack.push_back(Value_t(1)); + return ParsePowiMuli(iseq_powi, ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); + } + + template<typename Value_t> + Value_t ParseMuliSequence(const std::vector<unsigned>& ByteCode, + unsigned& IP, unsigned limit, + std::size_t factor_stack_base, + bool IgnoreExcess = false) + { + std::vector<Value_t> stack; + stack.push_back(Value_t(1)); + return ParsePowiMuli(iseq_muli, ByteCode, IP, limit, + factor_stack_base, stack, + IgnoreExcess); + } + + struct IfInfo + { + std::pair<int,std::string> condition; + std::pair<int,std::string> thenbranch; + unsigned endif_location; + + IfInfo() : condition(), thenbranch(), endif_location() { } + }; +} + +template<typename Value_t> +void FunctionParserBase<Value_t>::PrintByteCode(std::ostream& dest, + bool showExpression) const +{ + dest << "Size of stack: " << mData->mStackSize << "\n"; + + std::ostringstream outputBuffer; + std::ostream& output = (showExpression ? outputBuffer : dest); + + const std::vector<unsigned>& ByteCode = mData->mByteCode; + const std::vector<Value_t>& Immed = mData->mImmed; + + std::vector<std::pair<int,std::string> > stack; + std::vector<IfInfo> if_stack; + + for(unsigned IP = 0, DP = 0; IP <= ByteCode.size(); ++IP) + { + after_powi_or_muli:; + std::string n; + bool out_params = false; + unsigned params = 2, produces = 1, opcode = 0; + + if(showExpression && !if_stack.empty() && + ( // Normal If termination rule: + if_stack.back().endif_location == IP + // This rule matches when cJumps are threaded: + || (IP < ByteCode.size() && ByteCode[IP] == cJump + && !if_stack.back().thenbranch.second.empty()) + )) + { + printHex(output, IP); + if(if_stack.back().endif_location == IP) + output << ": ----- (phi)"; + else + output << ": ----- (phi+)"; + + stack.resize(stack.size()+2); + std::swap(stack[stack.size()-3], stack[stack.size()-1]); + std::swap(if_stack.back().condition, stack[stack.size()-3]); + std::swap(if_stack.back().thenbranch, stack[stack.size()-2]); + opcode = cIf; + params = 3; + --IP; + if_stack.pop_back(); + } + else + { + if(IP >= ByteCode.size()) break; + opcode = ByteCode[IP]; + + if(showExpression && ( + opcode == cSqr || opcode == cDup + || opcode == cInv + || opcode == cSqrt || opcode == cRSqrt + || opcode == cFetch + )) + { + unsigned changed_ip = IP; + Value_t exponent = + ParsePowiSequence<Value_t> + (ByteCode, changed_ip, + if_stack.empty() + ? (unsigned)ByteCode.size() + : if_stack.back().endif_location, + stack.size()-1); + std::string operation_prefix; + std::ostringstream operation_value; + int prio = 0; + if(exponent == Value_t(1.0)) + { + if(opcode != cDup) goto not_powi_or_muli; + Value_t factor = + ParseMuliSequence<Value_t> + (ByteCode, changed_ip, + if_stack.empty() + ? (unsigned)ByteCode.size() + : if_stack.back().endif_location, + stack.size()-1); + if(factor == Value_t(1) || factor == Value_t(-1)) + goto not_powi_or_muli; + operation_prefix = "*"; + operation_value << factor; + prio = 3; + } + else + { + prio = 2; + operation_prefix = "^"; + operation_value << exponent; + } + + //unsigned explanation_before = changed_ip-2; + unsigned explanation_before = changed_ip-1; + + const char* explanation_prefix = "_"; + for(const unsigned first_ip = IP; IP < changed_ip; ++IP) + { + printHex(output, IP); + output << ": "; + + const char* sep = "|"; + if(first_ip+1 == changed_ip) + { sep = "="; explanation_prefix = " "; } + else if(IP == first_ip) sep = "\\"; + else if(IP+1 == changed_ip) sep = "/"; + else explanation_prefix = "="; + + switch(ByteCode[IP]) + { + case cInv: output << "inv"; break; + case cNeg: output << "neg"; break; + case cDup: output << "dup"; break; + case cSqr: output << "sqr"; break; + case cMul: output << "mul"; break; + case cAdd: output << "add"; break; + case cCbrt: output << "cbrt"; break; + case cSqrt: output << "sqrt"; break; + case cRSqrt: output << "rsqrt"; break; + case cFetch: + { + unsigned index = ByteCode[++IP]; + output << "cFetch(" << index << ")"; + break; + } + default: break; + } + padLine(outputBuffer, 20); + output << sep; + if(IP >= explanation_before) + { + explanation_before = (unsigned)ByteCode.size(); + output << explanation_prefix + << '[' << (stack.size()-1) << ']'; + std::string last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + output << last; + output << operation_prefix; + output << operation_value.str(); + } + else + { + unsigned p = first_ip; + Value_t exp = operation_prefix=="^" ? + ParsePowiSequence<Value_t> + (ByteCode, p, IP+1, stack.size()-1, true) : + ParseMuliSequence<Value_t> + (ByteCode, p, IP+1, stack.size()-1, true); + std::string last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + output << " ..." << last; + output << operation_prefix; + output << exp; + } + dest << outputBuffer.str() << std::endl; + outputBuffer.str(""); + } + + std::string& last = stack.back().second; + if(stack.back().first >= prio) + last = "(" + last + ")"; + last += operation_prefix; + last += operation_value.str(); + stack.back().first = prio; + + goto after_powi_or_muli; + } + not_powi_or_muli:; + printHex(output, IP); + output << ": "; + + switch(opcode) + { + case cIf: + { + unsigned label = ByteCode[IP+1]+1; + output << "jz "; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); + break; + } + case cAbsIf: + { + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; + output << "jz_abs " << dp << ","; + printHex(output, label); + params = 1; + produces = 0; + IP += 2; + + if_stack.resize(if_stack.size() + 1); + std::swap( if_stack.back().condition, stack.back() ); + if_stack.back().endif_location = (unsigned) ByteCode.size(); + stack.pop_back(); + break; + } + + case cJump: + { + unsigned dp = ByteCode[IP+2]; + unsigned label = ByteCode[IP+1]+1; + + if(!if_stack.empty() && !stack.empty()) + { + std::swap(if_stack.back().thenbranch, stack.back()); + if_stack.back().endif_location = label; + stack.pop_back(); + } + + output << "jump " << dp << ","; + printHex(output, label); + params = 0; + produces = 0; + IP += 2; + break; + } + case cImmed: + { + if(showExpression) + { + std::ostringstream buf; + buf.precision(8); + buf << Immed[DP]; + stack.push_back( std::make_pair(0, buf.str()) ); + } + output.precision(8); + output << "push " << Immed[DP]; + ++DP; + produces = 0; + break; + } + + case cFCall: + { + const unsigned index = ByteCode[++IP]; + params = mData->mFuncPtrs[index].mParams; + static std::string name; + name = "f:" + findName(mData->mNamePtrs, index, + NameData<Value_t>::FUNC_PTR); + n = name.c_str(); + out_params = true; + break; + } + + case cPCall: + { + const unsigned index = ByteCode[++IP]; + params = mData->mFuncParsers[index].mParams; + static std::string name; + name = "p:" + findName(mData->mNamePtrs, index, + NameData<Value_t>::PARSER_PTR); + n = name.c_str(); + out_params = true; + break; + } + + default: + if(IsVarOpcode(opcode)) + { + if(showExpression) + { + stack.push_back(std::make_pair(0, + (findName(mData->mNamePtrs, opcode, + NameData<Value_t>::VARIABLE)))); + } + output << "push Var" << opcode-VarBegin; + produces = 0; + } + else + { + switch(OPCODE(opcode)) + { + case cNeg: n = "neg"; params = 1; break; + case cAdd: n = "add"; break; + case cSub: n = "sub"; break; + case cMul: n = "mul"; break; + case cDiv: n = "div"; break; + case cMod: n = "mod"; break; + case cPow: n = "pow"; break; + case cEqual: n = "eq"; break; + case cNEqual: n = "neq"; break; + case cLess: n = "lt"; break; + case cLessOrEq: n = "le"; break; + case cGreater: n = "gt"; break; + case cGreaterOrEq: n = "ge"; break; + case cAnd: n = "and"; break; + case cOr: n = "or"; break; + case cNot: n = "not"; params = 1; break; + case cNotNot: n = "notnot"; params = 1; break; + case cDeg: n = "deg"; params = 1; break; + case cRad: n = "rad"; params = 1; break; + + case cFetch: + { + unsigned index = ByteCode[++IP]; + if(showExpression && index < stack.size()) + stack.push_back(stack[index]); + output << "cFetch(" << index << ")"; + produces = 0; + break; + } + #ifdef FP_SUPPORT_OPTIMIZER + case cLog2by: n = "log2by"; params = 2; out_params = 1; break; + case cPopNMov: + { + std::size_t a = ByteCode[++IP]; + std::size_t b = ByteCode[++IP]; + if(showExpression && b < stack.size()) + { + std::pair<int, std::string> stacktop(0, "?"); + if(b < stack.size()) stacktop = stack[b]; + stack.resize(a); + stack.push_back(stacktop); + } + output << "cPopNMov(" << a << ", " << b << ")"; + produces = 0; + break; + } + case cNop: + output << "nop"; params = 0; produces = 0; + break; + #endif + case cSinCos: + { + if(showExpression) + { + std::pair<int, std::string> sin = stack.back(); + std::pair<int, std::string> cos( + 0, "cos(" + sin.second + ")"); + sin.first = 0; + sin.second = "sin(" + sin.second + ")"; + stack.back() = sin; + stack.push_back(cos); + } + output << "sincos"; + produces = 0; + break; + } + case cSinhCosh: + { + if(showExpression) + { + std::pair<int, std::string> sinh = stack.back(); + std::pair<int, std::string> cosh( + 0, "cosh(" + sinh.second + ")"); + sinh.first = 0; + sinh.second = "sinh(" + sinh.second + ")"; + stack.back() = sinh; + stack.push_back(cosh); + } + output << "sinhcosh"; + produces = 0; + break; + } + case cAbsAnd: n = "abs_and"; break; + case cAbsOr: n = "abs_or"; break; + case cAbsNot: n = "abs_not"; params = 1; break; + case cAbsNotNot: n = "abs_notnot"; params = 1; break; + case cDup: + { + if(showExpression) + stack.push_back(stack.back()); + output << "dup"; + produces = 0; + break; + } + case cInv: n = "inv"; params = 1; break; + case cSqr: n = "sqr"; params = 1; break; + case cRDiv: n = "rdiv"; break; + case cRSub: n = "rsub"; break; + case cRSqrt: n = "rsqrt"; params = 1; break; + + default: + n = Functions[opcode-cAbs].name; + params = Functions[opcode-cAbs].params; + out_params = params != 1; + } + } + } + } + if(produces) output << n; + if(out_params) output << " (" << params << ")"; + if(showExpression) + { + padLine(outputBuffer, 20); + + if(produces > 0) + { + std::ostringstream buf; + const char *paramsep = ",", *suff = ""; + int prio = 0; bool commutative = false; + switch(opcode) + { + case cIf: buf << "if("; suff = ")"; + break; + case cAbsIf: buf << "if("; suff = ")"; + break; + case cOr: prio = 6; paramsep = "|"; commutative = true; + break; + case cAnd: prio = 5; paramsep = "&"; commutative = true; + break; + case cAdd: prio = 4; paramsep = "+"; commutative = true; + break; + case cSub: prio = 4; paramsep = "-"; + break; + case cMul: prio = 3; paramsep = "*"; commutative = true; + break; + case cDiv: prio = 3; paramsep = "/"; + break; + case cPow: prio = 2; paramsep = "^"; + break; + case cAbsOr: prio = 6; paramsep = "|"; commutative = true; + break; + case cAbsAnd: prio = 5; paramsep = "&"; commutative = true; + break; + case cSqr: prio = 2; suff = "^2"; + break; + case cNeg: buf << "(-("; suff = "))"; + break; + case cNot: buf << "(!("; suff = "))"; + break; + default: buf << n << '('; suff = ")"; + } + + const char* sep = ""; + for(unsigned a=0; a<params; ++a) + { + buf << sep; + if(stack.size() + a < params) + buf << "?"; + else + { + const std::pair<int,std::string>& prev = + stack[stack.size() - params + a]; + if(prio > 0 && (prev.first > prio || + (prev.first==prio && !commutative))) + buf << '(' << prev.second << ')'; + else + buf << prev.second; + } + sep = paramsep; + } + if(stack.size() >= params) + stack.resize(stack.size() - params); + else + stack.clear(); + buf << suff; + stack.push_back(std::make_pair(prio, buf.str())); + //if(n.size() <= 4 && !out_params) padLine(outputBuffer, 20); + } + //padLine(outputBuffer, 20); + output << "= "; + if(((opcode == cIf || opcode == cAbsIf) && params != 3) + || opcode == cJump + #ifdef FP_SUPPORT_OPTIMIZER + || opcode == cNop + #endif + ) + output << "(void)"; + else if(stack.empty()) + output << "[?] ?"; + else + output << '[' << (stack.size()-1) << ']' + << stack.back().second; + } + + if(showExpression) + { + dest << outputBuffer.str() << std::endl; + outputBuffer.str(""); + } + else + output << std::endl; + } + dest << std::flush; +} +#endif + + +#ifndef FP_SUPPORT_OPTIMIZER +template<typename Value_t> +void FunctionParserBase<Value_t>::Optimize() +{ + // Do nothing if no optimizations are supported. +} +#endif + + +#define FUNCTIONPARSER_INSTANTIATE_CLASS(type) \ + template class FunctionParserBase< type >; + +#ifndef FP_DISABLE_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(double) +#endif + +#ifdef FP_SUPPORT_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(float) +#endif + +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(long double) +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(long) +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(MpfrFloat) +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(GmpInt) +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<double>) +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<float>) +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_CLASS(std::complex<long double>) +#endif diff --git a/fparser.hh b/fparser.hh new file mode 100644 index 0000000..7033a8d --- /dev/null +++ b/fparser.hh @@ -0,0 +1,223 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen, Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_H_ +#define ONCE_FPARSER_H_ + +#include <string> +#include <vector> + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +#include <iostream> +#endif + +#ifdef _MSC_VER +// Visual Studio's warning about missing definitions for the explicit +// FunctionParserBase instantiations is irrelevant here. +#pragma warning(disable : 4661) +#endif + +namespace FPoptimizer_CodeTree { template<typename Value_t> class CodeTree; } + +template<typename Value_t> +class FunctionParserBase +{ + public: + enum ParseErrorType + { + SYNTAX_ERROR=0, MISM_PARENTH, MISSING_PARENTH, EMPTY_PARENTH, + EXPECT_OPERATOR, OUT_OF_MEMORY, UNEXPECTED_ERROR, INVALID_VARS, + ILL_PARAMS_AMOUNT, PREMATURE_EOS, EXPECT_PARENTH_FUNC, + UNKNOWN_IDENTIFIER, + NO_FUNCTION_PARSED_YET, + FP_NO_ERROR + }; + + typedef Value_t value_type; + + + int Parse(const char* Function, const std::string& Vars, + bool useDegrees = false); + int Parse(const std::string& Function, const std::string& Vars, + bool useDegrees = false); + + void setDelimiterChar(char); + + static Value_t epsilon(); + static void setEpsilon(Value_t); + + const char* ErrorMsg() const; + ParseErrorType GetParseErrorType() const; + + Value_t Eval(const Value_t* Vars); + int EvalError() const; + + bool AddConstant(const std::string& name, Value_t value); + bool AddUnit(const std::string& name, Value_t value); + + typedef Value_t (*FunctionPtr)(const Value_t*); + + bool AddFunction(const std::string& name, + FunctionPtr, unsigned paramsAmount); + bool AddFunction(const std::string& name, FunctionParserBase&); + + class FunctionWrapper; + + template<typename DerivedWrapper> + bool AddFunctionWrapper(const std::string& name, const DerivedWrapper&, + unsigned paramsAmount); + + FunctionWrapper* GetFunctionWrapper(const std::string& name); + + bool RemoveIdentifier(const std::string& name); + + void Optimize(); + + + int ParseAndDeduceVariables(const std::string& function, + int* amountOfVariablesFound = 0, + bool useDegrees = false); + int ParseAndDeduceVariables(const std::string& function, + std::string& resultVarString, + int* amountOfVariablesFound = 0, + bool useDegrees = false); + int ParseAndDeduceVariables(const std::string& function, + std::vector<std::string>& resultVars, + bool useDegrees = false); + + + FunctionParserBase(); + ~FunctionParserBase(); + + // Copy constructor and assignment operator (implemented using the + // copy-on-write technique for efficiency): + FunctionParserBase(const FunctionParserBase&); + FunctionParserBase& operator=(const FunctionParserBase&); + + + void ForceDeepCopy(); + + + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + // For debugging purposes only. + // Performs no sanity checks or anything. If the values are wrong, the + // library will crash. Do not use unless you know what you are doing. + void InjectRawByteCode(const unsigned* bytecode, unsigned bytecodeAmount, + const Value_t* immed, unsigned immedAmount, + unsigned stackSize); + + void PrintByteCode(std::ostream& dest, bool showExpression = true) const; +#endif + + + +//======================================================================== + protected: +//======================================================================== + // A derived class can implement its own evaluation logic by using + // the parser data (found in fptypes.hh). + struct Data; + Data* getParserData(); + + +//======================================================================== + private: +//======================================================================== + + friend class FPoptimizer_CodeTree::CodeTree<Value_t>; + +// Private data: +// ------------ + Data* mData; + unsigned mStackPtr; + + +// Private methods: +// --------------- + void CopyOnWrite(); + bool CheckRecursiveLinking(const FunctionParserBase*) const; + bool NameExists(const char*, unsigned); + bool ParseVariables(const std::string&); + int ParseFunction(const char*, bool); + const char* SetErrorType(ParseErrorType, const char*); + + void AddFunctionOpcode(unsigned); + void AddImmedOpcode(Value_t v); + void incStackPtr(); + void CompilePowi(long); + bool TryCompilePowi(Value_t); + + const char* CompileIf(const char*); + const char* CompileFunctionParams(const char*, unsigned); + const char* CompileElement(const char*); + const char* CompilePossibleUnit(const char*); + const char* CompilePow(const char*); + const char* CompileUnaryMinus(const char*); + const char* CompileMult(const char*); + const char* CompileAddition(const char*); + const char* CompileComparison(const char*); + const char* CompileAnd(const char*); + const char* CompileExpression(const char*); + inline const char* CompileFunction(const char*, unsigned); + inline const char* CompileParenthesis(const char*); + inline const char* CompileLiteral(const char*); + template<bool SetFlag> + inline void PushOpcodeParam(unsigned); + template<bool SetFlag> + inline void PutOpcodeParamAt(unsigned, unsigned offset); + const char* Compile(const char*); + + bool addFunctionWrapperPtr(const std::string&, FunctionWrapper*, unsigned); + static void incFuncWrapperRefCount(FunctionWrapper*); + static unsigned decFuncWrapperRefCount(FunctionWrapper*); + +protected: + // Parsing utility functions + static std::pair<const char*, Value_t> ParseLiteral(const char*); + static unsigned ParseIdentifier(const char*); +}; + +class FunctionParser: public FunctionParserBase<double> {}; +class FunctionParser_f: public FunctionParserBase<float> {}; +class FunctionParser_ld: public FunctionParserBase<long double> {}; +class FunctionParser_li: public FunctionParserBase<long> {}; + +#include <complex> +class FunctionParser_cd: public FunctionParserBase<std::complex<double> > {}; +class FunctionParser_cf: public FunctionParserBase<std::complex<float> > {}; +class FunctionParser_cld: public FunctionParserBase<std::complex<long double> > {}; + + + +template<typename Value_t> +class FunctionParserBase<Value_t>::FunctionWrapper +{ + unsigned mReferenceCount; + friend class FunctionParserBase<Value_t>; + + public: + FunctionWrapper(): mReferenceCount(1) {} + FunctionWrapper(const FunctionWrapper&): mReferenceCount(1) {} + virtual ~FunctionWrapper() {} + FunctionWrapper& operator=(const FunctionWrapper&) { return *this; } + + virtual Value_t callFunction(const Value_t*) = 0; +}; + +template<typename Value_t> +template<typename DerivedWrapper> +bool FunctionParserBase<Value_t>::AddFunctionWrapper +(const std::string& name, const DerivedWrapper& wrapper, unsigned paramsAmount) +{ + return addFunctionWrapperPtr + (name, new DerivedWrapper(wrapper), paramsAmount); +} +#endif diff --git a/fparser_gmpint.hh b/fparser_gmpint.hh new file mode 100644 index 0000000..d9d3b5f --- /dev/null +++ b/fparser_gmpint.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_GMPINT_H_ +#define ONCE_FPARSER_GMPINT_H_ + +#include "fparser.hh" +#include "mpfr/GmpInt.hh" + +class FunctionParser_gmpint: public FunctionParserBase<GmpInt> {}; + +#endif diff --git a/fparser_mpfr.hh b/fparser_mpfr.hh new file mode 100644 index 0000000..322b05d --- /dev/null +++ b/fparser_mpfr.hh @@ -0,0 +1,15 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +\***************************************************************************/ + +#ifndef ONCE_FPARSER_MPFR_H_ +#define ONCE_FPARSER_MPFR_H_ + +#include "fparser.hh" +#include "mpfr/MpfrFloat.hh" + +class FunctionParser_mpfr: public FunctionParserBase<MpfrFloat> {}; + +#endif diff --git a/fpconfig.hh b/fpconfig.hh new file mode 100644 index 0000000..17e6c7d --- /dev/null +++ b/fpconfig.hh @@ -0,0 +1,88 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Copyright: Juha Nieminen *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +// Configuration file +// ------------------ + +/* NOTE: + This file is for the internal use of the function parser only. + You don't need to include this file in your source files, just + include "fparser.hh". +*/ + + +/* Uncomment any of these lines or define them in your compiler settings + to enable the correspondent version of the parser. (These are disabled + by default because they rely on C99 functions, and non-standard libraries + in the case pf MPFR and GMP, and they make compiling needlessly slower + and the resulting binary needlessly larger if they are not used in the + program.) +*/ +//#define FP_SUPPORT_FLOAT_TYPE +//#define FP_SUPPORT_LONG_DOUBLE_TYPE +//#define FP_SUPPORT_LONG_INT_TYPE +//#define FP_SUPPORT_MPFR_FLOAT_TYPE +//#define FP_SUPPORT_GMP_INT_TYPE +//#define FP_SUPPORT_COMPLEX_DOUBLE_TYPE +//#define FP_SUPPORT_COMPLEX_FLOAT_TYPE +//#define FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + +/* If you are using FunctionParser_ld or FunctionParser_cld and your compiler + supports the strtold() function, you should uncomment the following line. + */ +//#define FP_USE_STRTOLD + + +/* Uncomment this line or define it in your compiler settings if you want + to disable compiling the basic double version of the library, in case + one of the above types is used but not the double type. (If the double + type is not used, then disabling it makes compiling faster and the + resulting binary smaller.) + */ +//#define FP_DISABLE_DOUBLE_TYPE + +/* Uncomment this line or define it in your compiler settings to make the + parser use C++11 math functions. (Note that these may not be supported + by all compilers.) +*/ +//#define FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS + +/* + Whether to use shortcut evaluation for the & and | operators: +*/ +#ifndef FP_DISABLE_SHORTCUT_LOGICAL_EVALUATION +#define FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION +#endif + +/* + Comment out the following lines out if you are not going to use the + optimizer and want a slightly smaller library. The Optimize() method + can still be called, but it will not do anything. + If you are unsure, just leave it. It won't slow down the other parts of + the library. +*/ +#ifndef FP_NO_SUPPORT_OPTIMIZER +#define FP_SUPPORT_OPTIMIZER +#endif + +#if defined(FP_SUPPORT_COMPLEX_DOUBLE_TYPE) || defined(FP_SUPPORT_COMPLEX_FLOAT_TYPE) || defined(FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE) +#define FP_SUPPORT_COMPLEX_NUMBERS +#endif + + +/* + No member function of FunctionParser is thread-safe. Most prominently, + Eval() is not thread-safe. By uncommenting one of these lines the Eval() + function can be made thread-safe at the cost of a possible small overhead. + The second version requires that the compiler supports the alloca() function, + which is not standard, but is faster. + */ +//#define FP_USE_THREAD_SAFE_EVAL +//#define FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA diff --git a/fpoptimizer/bytecodesynth.cc b/fpoptimizer/bytecodesynth.cc new file mode 100644 index 0000000..f5073c0 --- /dev/null +++ b/fpoptimizer/bytecodesynth.cc @@ -0,0 +1,638 @@ +#include "bytecodesynth.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include "opcodename.hh" +#include "codetree.hh" + +using namespace FUNCTIONPARSERTYPES; + +namespace FPoptimizer_ByteCode +{ + template<typename Value_t> + struct SequenceOpCode + { + Value_t basevalue; + unsigned op_flip; + unsigned op_normal, op_normal_flip; + unsigned op_inverse, op_inverse_flip; + }; + + template<typename Value_t> + const SequenceOpCode<Value_t> + SequenceOpcodes<Value_t>::AddSequence = { Value_t(0), cNeg, cAdd, cAdd, cSub, cRSub }; + + template<typename Value_t> + const SequenceOpCode<Value_t> + SequenceOpcodes<Value_t>::MulSequence = { Value_t(1), cInv, cMul, cMul, cDiv, cRDiv }; + + /*******/ +#define findName(a,b,c) "var" +#define TryCompilePowi(o) false +#define mData this +#define mByteCode ByteCode +#define mImmed Immed + + template<typename Value_t> + void ByteCodeSynth<Value_t>::AddFunctionOpcode(unsigned opcode, + Specializer<false,false>) + { + int mStackPtr=0; +# define FP_FLOAT_VERSION 1 +# define FP_COMPLEX_VERSION 0 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION + } + + template<typename Value_t> + void ByteCodeSynth<Value_t>::AddFunctionOpcode(unsigned opcode, + Specializer<true,false>) + { + int mStackPtr=0; +# define FP_FLOAT_VERSION 0 +# define FP_COMPLEX_VERSION 0 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION + } + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename Value_t> + void ByteCodeSynth<Value_t>::AddFunctionOpcode(unsigned opcode, + Specializer<false,true>) + { + int mStackPtr=0; +# define FP_FLOAT_VERSION 1 +# define FP_COMPLEX_VERSION 1 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION + } + + template<typename Value_t> + void ByteCodeSynth<Value_t>::AddFunctionOpcode(unsigned opcode, + Specializer<true,true>) + { + int mStackPtr=0; +# define FP_FLOAT_VERSION 0 +# define FP_COMPLEX_VERSION 1 +# include "extrasrc/fp_opcode_add.inc" +# undef FP_COMPLEX_VERSION +# undef FP_FLOAT_VERSION + } +#endif + +#undef findName +#undef mImmed +#undef mByteCode +#undef mData +#undef TryCompilePowi + /*******/ +} + +using namespace FPoptimizer_ByteCode; + +#define POWI_TABLE_SIZE 256 +#define POWI_WINDOW_SIZE 3 +namespace FPoptimizer_ByteCode +{ + #ifndef FP_GENERATING_POWI_TABLE + extern const + unsigned char powi_table[POWI_TABLE_SIZE]; + const + #endif + unsigned char powi_table[POWI_TABLE_SIZE] = + { + 0, 1, 1, 1, 2, 1, 2, 1, /* 0 - 7 */ + 4, 1, 2, 1, 4, 1, 2, 131, /* 8 - 15 */ + 8, 1, 2, 1, 4, 1, 2, 1, /* 16 - 23 */ + 8, 133, 2, 131, 4, 1, 15, 1, /* 24 - 31 */ + 16, 1, 2, 1, 4, 1, 2, 131, /* 32 - 39 */ + 8, 1, 2, 1, 4, 133, 2, 1, /* 40 - 47 */ + 16, 1, 25, 131, 4, 1, 27, 5, /* 48 - 55 */ + 8, 3, 2, 1, 30, 1, 31, 3, /* 56 - 63 */ + 32, 1, 2, 1, 4, 1, 2, 1, /* 64 - 71 */ + 8, 1, 2, 131, 4, 1, 39, 1, /* 72 - 79 */ + 16, 137, 2, 1, 4, 133, 2, 131, /* 80 - 87 */ + 8, 1, 45, 135, 4, 31, 2, 5, /* 88 - 95 */ + 32, 1, 2, 131, 50, 1, 51, 1, /* 96 - 103 */ + 8, 3, 2, 1, 54, 1, 55, 3, /* 104 - 111 */ + 16, 1, 57, 133, 4, 137, 2, 135, /* 112 - 119 */ + 60, 1, 61, 3, 62, 133, 63, 1, /* 120 - 127 */ + 130, 1, 2, 1, 130, 1, 2, 131, /* 128 - 135 */ + 130, 1, 2, 1, 130, 1, 2, 139, /* 136 - 143 */ + 130, 1, 2, 131, 130, 1, 30, 1, /* 144 - 151 */ + 130, 137, 2, 31, 130, 1, 2, 131, /* 152 - 159 */ + 130, 1, 130, 1, 130, 133, 2, 1, /* 160 - 167 */ + 130, 1, 130, 1, 2, 1, 130, 133, /* 168 - 175 */ + 130, 1, 2, 1, 130, 1, 2, 61, /* 176 - 183 */ + 130, 133, 62, 139, 130, 137, 130, 1, /* 184 - 191 */ + 130, 1, 2, 131, 130, 1, 130, 1, /* 192 - 199 */ + 130, 1, 2, 1, 130, 1, 2, 131, /* 200 - 207 */ + 130, 1, 130, 1, 130, 131, 2, 133, /* 208 - 215 */ + 130, 1, 2, 131, 130, 141, 130, 1, /* 216 - 223 */ + 130, 133, 2, 1, 130, 1, 5, 135, /* 224 - 231 */ + 130, 1, 130, 1, 2, 131, 130, 1, /* 232 - 239 */ + 130, 1, 2, 131, 130, 133, 130, 141, /* 240 - 247 */ + 130, 131, 130, 1, 130, 1, 2, 131 /* 248 - 255 */ + }; /* as in gcc, but custom-optimized for stack calculation */ +} +static const int POWI_CACHE_SIZE = 256; + +#define FPO(x) /**/ +//#define FPO(x) x +//#include <stdio.h> + + +namespace +{ + class PowiCache + { + private: + int cache[POWI_CACHE_SIZE]; + int cache_needed[POWI_CACHE_SIZE]; + + public: + PowiCache() + : cache(), cache_needed() /* Assume we have no factors in the cache */ + { + /* Decide which factors we would need multiple times. + * Output: + * cache[] = these factors were generated + * cache_needed[] = number of times these factors were desired + */ + cache[1] = 1; // We have this value already. + } + + bool Plan_Add(long value, int count) + { + if(value >= POWI_CACHE_SIZE) return false; + //FPO(fprintf(stderr, "%ld will be needed %d times more\n", count, need_count)); + cache_needed[value] += count; + return cache[value] != 0; + } + + void Plan_Has(long value) + { + if(value < POWI_CACHE_SIZE) + cache[value] = 1; // This value has been generated + } + + void Start(size_t value1_pos) + { + for(int n=2; n<POWI_CACHE_SIZE; ++n) + cache[n] = -1; /* Stack location for each component */ + + Remember(1, value1_pos); + + DumpContents(); + } + + int Find(long value) const + { + if(value < POWI_CACHE_SIZE) + { + if(cache[value] >= 0) + { + // found from the cache + FPO(fprintf(stderr, "* I found %ld from cache (%u,%d)\n", + value, (unsigned)cache[value], cache_needed[value])); + return cache[value]; + } + } + return -1; + } + + void Remember(long value, size_t stackpos) + { + if(value >= POWI_CACHE_SIZE) return; + + FPO(fprintf(stderr, "* Remembering that %ld can be found at %u (%d uses remain)\n", + value, (unsigned)stackpos, cache_needed[value])); + cache[value] = (int) stackpos; + } + + void DumpContents() const + { + FPO(for(int a=1; a<POWI_CACHE_SIZE; ++a) + if(cache[a] >= 0 || cache_needed[a] > 0) + { + fprintf(stderr, "== cache: sp=%d, val=%d, needs=%d\n", + cache[a], a, cache_needed[a]); + }) + } + + int UseGetNeeded(long value) + { + if(value >= 0 && value < POWI_CACHE_SIZE) + return --cache_needed[value]; + return 0; + } + }; + + template<typename Value_t> + size_t AssembleSequence_Subdivide( + long count, + PowiCache& cache, + const SequenceOpCode<Value_t>& sequencing, + ByteCodeSynth<Value_t>& synth); + + template<typename Value_t> + void Subdivide_Combine( + size_t apos, long aval, + size_t bpos, long bval, + PowiCache& cache, + + unsigned cumulation_opcode, + unsigned cimulation_opcode_flip, + + ByteCodeSynth<Value_t>& synth); + + void PlanNtimesCache + (long value, + PowiCache& cache, + int need_count, + int recursioncount=0) + { + if(value < 1) return; + + #ifdef FP_GENERATING_POWI_TABLE + if(recursioncount > 32) throw false; + #endif + + if(cache.Plan_Add(value, need_count)) return; + + long half = 1; + if(value < POWI_TABLE_SIZE) + { + half = powi_table[value]; + if(half & 128) + { + half &= 127; + if(half & 64) + half = -(half & 63) - 1; + + FPO(fprintf(stderr, "value=%ld, half=%ld, otherhalf=%ld\n", value,half,value/half)); + + PlanNtimesCache(half, cache, 1, recursioncount+1); + cache.Plan_Has(half); + return; + } + else if(half & 64) + { + half = -(half & 63) - 1; + } + } + else if(value & 1) + half = value & ((1 << POWI_WINDOW_SIZE) - 1); // that is, value & 7 + else + half = value / 2; + + long otherhalf = value-half; + if(half > otherhalf || half<0) std::swap(half,otherhalf); + + FPO(fprintf(stderr, "value=%ld, half=%ld, otherhalf=%ld\n", value,half,otherhalf)); + + if(half == otherhalf) + { + PlanNtimesCache(half, cache, 2, recursioncount+1); + } + else + { + PlanNtimesCache(half, cache, 1, recursioncount+1); + PlanNtimesCache(otherhalf>0?otherhalf:-otherhalf, + cache, 1, recursioncount+1); + } + cache.Plan_Has(value); + } + + template<typename Value_t> + size_t AssembleSequence_Subdivide( + long value, + PowiCache& cache, + const SequenceOpCode<Value_t>& sequencing, + ByteCodeSynth<Value_t>& synth) + { + int cachepos = cache.Find(value); + if(cachepos >= 0) + { + // found from the cache + return cachepos; + } + + long half = 1; + if(value < POWI_TABLE_SIZE) + { + half = powi_table[value]; + if(half & 128) + { + half &= 127; + if(half & 64) + half = -(half & 63) - 1; + + FPO(fprintf(stderr, "* I want %ld, my plan is %ld * %ld\n", value, half, value/half)); + size_t half_pos = AssembleSequence_Subdivide(half, cache, sequencing, synth); + if(cache.UseGetNeeded(half) > 0 + || half_pos != synth.GetStackTop()-1) + { + synth.DoDup(half_pos); + cache.Remember(half, synth.GetStackTop()-1); + } + AssembleSequence(value/half, sequencing, synth); + size_t stackpos = synth.GetStackTop()-1; + cache.Remember(value, stackpos); + cache.DumpContents(); + return stackpos; + } + else if(half & 64) + { + half = -(half & 63) - 1; + } + } + else if(value & 1) + half = value & ((1 << POWI_WINDOW_SIZE) - 1); // that is, value & 7 + else + half = value / 2; + + long otherhalf = value-half; + if(half > otherhalf || half<0) std::swap(half,otherhalf); + + FPO(fprintf(stderr, "* I want %ld, my plan is %ld + %ld\n", value, half, value-half)); + + if(half == otherhalf) + { + size_t half_pos = AssembleSequence_Subdivide(half, cache, sequencing, synth); + + // self-cumulate the subdivide result + Subdivide_Combine(half_pos,half, half_pos,half, cache, + sequencing.op_normal, sequencing.op_normal_flip, + synth); + } + else + { + long part1 = half; + long part2 = otherhalf>0?otherhalf:-otherhalf; + + size_t part1_pos = AssembleSequence_Subdivide(part1, cache, sequencing, synth); + size_t part2_pos = AssembleSequence_Subdivide(part2, cache, sequencing, synth); + + FPO(fprintf(stderr, "Subdivide(%ld: %ld, %ld)\n", value, half, otherhalf)); + + Subdivide_Combine(part1_pos,part1, part2_pos,part2, cache, + otherhalf>0 ? sequencing.op_normal : sequencing.op_inverse, + otherhalf>0 ? sequencing.op_normal_flip : sequencing.op_inverse_flip, + synth); + } + + size_t stackpos = synth.GetStackTop()-1; + cache.Remember(value, stackpos); + cache.DumpContents(); + return stackpos; + } + + template<typename Value_t> + void Subdivide_Combine( + size_t apos, long aval, + size_t bpos, long bval, + PowiCache& cache, + unsigned cumulation_opcode, + unsigned cumulation_opcode_flip, + ByteCodeSynth<Value_t>& synth) + { + /*FPO(fprintf(stderr, "== making result for (sp=%u, val=%d, needs=%d) and (sp=%u, val=%d, needs=%d), stacktop=%u\n", + (unsigned)apos, aval, aval>=0 ? cache_needed[aval] : -1, + (unsigned)bpos, bval, bval>=0 ? cache_needed[bval] : -1, + (unsigned)synth.GetStackTop()));*/ + + // Figure out whether we can trample a and b + int a_needed = cache.UseGetNeeded(aval); + int b_needed = cache.UseGetNeeded(bval); + + bool flipped = false; + + #define DUP_BOTH() do { \ + if(apos < bpos) { size_t tmp=apos; apos=bpos; bpos=tmp; flipped=!flipped; } \ + FPO(fprintf(stderr, "-> dup(%u) dup(%u) op\n", (unsigned)apos, (unsigned)bpos)); \ + synth.DoDup(apos); \ + synth.DoDup(apos==bpos ? synth.GetStackTop()-1 : bpos); } while(0) + #define DUP_ONE(p) do { \ + FPO(fprintf(stderr, "-> dup(%u) op\n", (unsigned)p)); \ + synth.DoDup(p); \ + } while(0) + + if(a_needed > 0) + { + if(b_needed > 0) + { + // If they must both be preserved, make duplicates + // First push the one that is at the larger stack + // address. This increases the odds of possibly using cDup. + DUP_BOTH(); + + //SCENARIO 1: + // Input: x B A x x + // Temp: x B A x x A B + // Output: x B A x x R + //SCENARIO 2: + // Input: x A B x x + // Temp: x A B x x B A + // Output: x A B x x R + } + else + { + // A must be preserved, but B can be trampled over + + // SCENARIO 1: + // Input: x B x x A + // Temp: x B x x A A B (dup both, later first) + // Output: x B x x A R + // SCENARIO 2: + // Input: x A x x B + // Temp: x A x x B A + // Output: x A x x R -- only commutative cases + // SCENARIO 3: + // Input: x x x B A + // Temp: x x x B A A B (dup both, later first) + // Output: x x x B A R + // SCENARIO 4: + // Input: x x x A B + // Temp: x x x A B A -- only commutative cases + // Output: x x x A R + // SCENARIO 5: + // Input: x A B x x + // Temp: x A B x x A B (dup both, later first) + // Output: x A B x x R + + // if B is not at the top, dup both. + if(bpos != synth.GetStackTop()-1) + DUP_BOTH(); // dup both + else + { + DUP_ONE(apos); // just dup A + flipped=!flipped; + } + } + } + else if(b_needed > 0) + { + // B must be preserved, but A can be trampled over + // This is a mirror image of the a_needed>0 case, so I'll cut the chase + if(apos != synth.GetStackTop()-1) + DUP_BOTH(); + else + DUP_ONE(bpos); + } + else + { + // Both can be trampled over. + // SCENARIO 1: + // Input: x B x x A + // Temp: x B x x A B + // Output: x B x x R + // SCENARIO 2: + // Input: x A x x B + // Temp: x A x x B A + // Output: x A x x R -- only commutative cases + // SCENARIO 3: + // Input: x x x B A + // Output: x x x R -- only commutative cases + // SCENARIO 4: + // Input: x x x A B + // Output: x x x R + // SCENARIO 5: + // Input: x A B x x + // Temp: x A B x x A B (dup both, later first) + // Output: x A B x x R + // SCENARIO 6: + // Input: x x x C + // Temp: x x x C C (c is both A and B) + // Output: x x x R + + if(apos == bpos && apos == synth.GetStackTop()-1) + DUP_ONE(apos); // scenario 6 + else if(apos == synth.GetStackTop()-1 && bpos == synth.GetStackTop()-2) + { + FPO(fprintf(stderr, "-> op\n")); // scenario 3 + flipped=!flipped; + } + else if(apos == synth.GetStackTop()-2 && bpos == synth.GetStackTop()-1) + FPO(fprintf(stderr, "-> op\n")); // scenario 4 + else if(apos == synth.GetStackTop()-1) + DUP_ONE(bpos); // scenario 1 + else if(bpos == synth.GetStackTop()-1) + { + DUP_ONE(apos); // scenario 2 + flipped=!flipped; + } + else + DUP_BOTH(); // scenario 5 + } + // Add them together. + synth.AddOperation(flipped ? cumulation_opcode_flip : cumulation_opcode, 2); + } + + template<typename Value_t> + void LightWeight( + long count, + const SequenceOpCode<Value_t>& sequencing, + ByteCodeSynth<Value_t>& synth) + { + while(count < 256) + { + int half = FPoptimizer_ByteCode::powi_table[count]; + if(half & 128) + { + half &= 127; + LightWeight(half, sequencing, synth); + count /= half; + } + else break; + } + if(count == 1) return; + if(!(count & 1)) + { + synth.AddOperation(cSqr, 1); + LightWeight(count/2, sequencing, synth); + } + else + { + synth.DoDup(synth.GetStackTop()-1); + LightWeight(count-1, sequencing, synth); + synth.AddOperation(cMul, 2); + } + } +} + +namespace FPoptimizer_ByteCode +{ + template<typename Value_t> + void AssembleSequence( + long count, + const SequenceOpCode<Value_t>& sequencing, + ByteCodeSynth<Value_t>& synth) + { + if(count == 0) + synth.PushImmed(sequencing.basevalue); + else + { + bool needs_flip = false; + if(count < 0) + { + needs_flip = true; + count = -count; + } + + if(false) + LightWeight(count,sequencing,synth); + else if(count > 1) + { + /* To prevent calculating the same factors over and over again, + * we use a cache. */ + PowiCache cache; + PlanNtimesCache(count, cache, 1); + + size_t stacktop_desired = synth.GetStackTop(); + + cache.Start( synth.GetStackTop()-1 ); + + FPO(fprintf(stderr, "Calculating result for %ld...\n", count)); + size_t res_stackpos = AssembleSequence_Subdivide( + count, cache, sequencing, + synth); + + size_t n_excess = synth.GetStackTop() - stacktop_desired; + if(n_excess > 0 || res_stackpos != stacktop_desired-1) + { + // Remove the cache values + synth.DoPopNMov(stacktop_desired-1, res_stackpos); + } + } + + if(needs_flip) + synth.AddOperation(sequencing.op_flip, 1); + } + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_ByteCode +{ +#define FP_INSTANTIATE(type) \ + template struct SequenceOpcodes<type>; \ + template void ByteCodeSynth<type>::AddFunctionOpcode(unsigned); \ + template void ByteCodeSynth<type>::AddFunctionOpcode(unsigned, \ + Specializer< bool(FUNCTIONPARSERTYPES::IsIntType<type>::result), \ + bool(FUNCTIONPARSERTYPES::IsComplexType<type>::result) \ + > ); \ + template void AssembleSequence( \ + long count, \ + const SequenceOpCode<type>& sequencing, \ + ByteCodeSynth<type>& synth); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/bytecodesynth.hh b/fpoptimizer/bytecodesynth.hh new file mode 100644 index 0000000..e4ff506 --- /dev/null +++ b/fpoptimizer/bytecodesynth.hh @@ -0,0 +1,323 @@ +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include <vector> +#include <utility> + +#include "codetree.hh" + +#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 }; + +namespace FPoptimizer_ByteCode +{ + template<typename Value_t> + class ByteCodeSynth + { + public: + ByteCodeSynth() + : ByteCode(), Immed(), StackState(), StackTop(0), StackMax(0) + { + /* estimate the initial requirements as such */ + ByteCode.reserve(64); + Immed.reserve(8); + StackState.reserve(16); + } + + void Pull(std::vector<unsigned>& bc, + std::vector<Value_t>& imm, + size_t& StackTop_max) + { + /* The bitmask 0x80000000u was added to each non-opcode + * value within ByteCode[] (opcode parameters) to prevent + * them being interpreted as opcodes by fp_opcode_add.inc. + * fparser uses cNop for the same purpose. + */ + for(unsigned a=0; a<ByteCode.size(); ++a) + { + ByteCode[a] &= ~0x80000000u; + } + ByteCode.swap(bc); + Immed.swap(imm); + StackTop_max = StackMax; + } + + size_t GetByteCodeSize() const { return ByteCode.size(); } + size_t GetStackTop() const { return StackTop; } + + void PushVar(unsigned varno) + { + ByteCode.push_back(varno); + SetStackTop(StackTop+1); + } + + void PushImmed(Value_t immed) + { + using namespace FUNCTIONPARSERTYPES; + ByteCode.push_back(cImmed); + Immed.push_back(immed); + SetStackTop(StackTop+1); + } + + void StackTopIs(const FPoptimizer_CodeTree::CodeTree<Value_t>& tree, int offset = 0) + { + if((int)StackTop > offset) + { + StackState[StackTop-1-offset].first = true; + StackState[StackTop-1-offset].second = tree; + } + } + + bool IsStackTop(const FPoptimizer_CodeTree::CodeTree<Value_t>& tree, int offset = 0) const + { + return (int)StackTop > offset + && StackState[StackTop-1-offset].first + && StackState[StackTop-1-offset].second.IsIdenticalTo(tree); + } + + inline void EatNParams(unsigned eat_count) + { + StackTop -= eat_count; + } + + void ProducedNParams(unsigned produce_count) + { + SetStackTop(StackTop + produce_count); + } + + void DoPopNMov(size_t targetpos, size_t srcpos) + { + using namespace FUNCTIONPARSERTYPES; + ByteCode.push_back(cPopNMov); + ByteCode.push_back( 0x80000000u | (unsigned) targetpos); + ByteCode.push_back( 0x80000000u | (unsigned) srcpos); + + SetStackTop(srcpos+1); + StackState[targetpos] = StackState[srcpos]; + SetStackTop(targetpos+1); + } + + void DoDup(size_t src_pos) + { + using namespace FUNCTIONPARSERTYPES; + if(src_pos == StackTop-1) + { + ByteCode.push_back(cDup); + } + else + { + ByteCode.push_back(cFetch); + ByteCode.push_back( 0x80000000u | (unsigned) src_pos); + } + SetStackTop(StackTop + 1); + StackState[StackTop-1] = StackState[src_pos]; + } + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + template<int/*defer*/> + void Dump() + { + std::ostream& o = std::cout; + o << "Stack state now(" << StackTop << "):\n"; + for(size_t a=0; a<StackTop; ++a) + { + o << a << ": "; + if(StackState[a].first) + { + const FPoptimizer_CodeTree::CodeTree<Value_t> + & tree = StackState[a].second; + o << '[' << std::hex << (void*)(&tree.GetParams()) + << std::dec + << ',' << tree.GetRefCount() + << ']'; + DumpTree(tree, o); + } + else + o << "?"; + o << "\n"; + } + o << std::flush; + } +#endif + + size_t FindPos(const FPoptimizer_CodeTree::CodeTree<Value_t>& tree) const + { + for(size_t a=StackTop; a-->0; ) + if(StackState[a].first && StackState[a].second.IsIdenticalTo(tree)) + return a; + return ~size_t(0); + } + + bool Find(const FPoptimizer_CodeTree::CodeTree<Value_t>& tree) const + { + return FindPos(tree) != ~size_t(0); + } + + bool FindAndDup(const FPoptimizer_CodeTree::CodeTree<Value_t>& tree) + { + size_t pos = FindPos(tree); + if(pos != ~size_t(0)) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Found duplicate at [" << pos <<"]: "; + DumpTree(tree); + std::cout << " -- issuing cDup or cFetch\n"; + #endif + DoDup(pos); + return true; + } + return false; + } + + struct IfData + { + size_t ofs; + }; + + void SynthIfStep1(IfData& ifdata, FUNCTIONPARSERTYPES::OPCODE op) + { + using namespace FUNCTIONPARSERTYPES; + SetStackTop(StackTop-1); // the If condition was popped. + + ifdata.ofs = ByteCode.size(); + ByteCode.push_back(op); + ByteCode.push_back(0x80000000u); // code index + ByteCode.push_back(0x80000000u); // Immed index + } + void SynthIfStep2(IfData& ifdata) + { + using namespace FUNCTIONPARSERTYPES; + SetStackTop(StackTop-1); // ignore the pushed then-branch result. + + ByteCode[ifdata.ofs+1] = 0x80000000u | unsigned( ByteCode.size()+2 ); + ByteCode[ifdata.ofs+2] = 0x80000000u | unsigned( Immed.size() ); + + ifdata.ofs = ByteCode.size(); + ByteCode.push_back(cJump); + ByteCode.push_back(0x80000000u); // code index + ByteCode.push_back(0x80000000u); // Immed index + } + void SynthIfStep3(IfData& ifdata) + { + using namespace FUNCTIONPARSERTYPES; + SetStackTop(StackTop-1); // ignore the pushed else-branch result. + + ByteCode.back() |= 0x80000000u; + // ^Necessary for guarding against if(x,1,2)+1 being changed + // into if(x,1,3) by fp_opcode_add.inc + + ByteCode[ifdata.ofs+1] = 0x80000000u | unsigned( ByteCode.size()-1 ); + ByteCode[ifdata.ofs+2] = 0x80000000u | unsigned( Immed.size() ); + + SetStackTop(StackTop+1); // one or the other was pushed. + + /* Threading jumps: + * If there are any cJumps that point + * to the cJump instruction we just changed, + * change them to point to this target as well. + * This screws up PrintByteCode() majorly. + */ + for(size_t a=0; a<ifdata.ofs; ++a) + { + if(ByteCode[a] == cJump + && ByteCode[a+1] == (0x80000000u | (ifdata.ofs-1))) + { + ByteCode[a+1] = 0x80000000u | unsigned( ByteCode.size()-1 ); + ByteCode[a+2] = 0x80000000u | unsigned( Immed.size() ); + } + switch(ByteCode[a]) + { + case cAbsIf: + case cIf: + case cJump: + case cPopNMov: a += 2; break; + case cFCall: + case cPCall: + case cFetch: a += 1; break; + default: break; + } + } + } + + protected: + void SetStackTop(size_t value) + { + StackTop = value; + if(StackTop > StackMax) + { + StackMax = StackTop; + StackState.resize(StackMax); + } + } + + protected: + std::vector<unsigned> ByteCode; + std::vector<Value_t> Immed; + + std::vector< + std::pair<bool/*known*/, + FPoptimizer_CodeTree::CodeTree<Value_t>/*tree*/> + > StackState; + size_t StackTop; + size_t StackMax; + private: + void incStackPtr() + { + if(StackTop+2 > StackMax) StackState.resize(StackMax=StackTop+2); + } + + template<bool IsIntType, bool IsComplexType> + struct Specializer { }; + public: + void AddOperation(unsigned opcode, unsigned eat_count, unsigned produce_count = 1) + { + EatNParams(eat_count); + AddFunctionOpcode(opcode); + ProducedNParams(produce_count); + } + + void AddFunctionOpcode(unsigned opcode, Specializer<false,false>); + void AddFunctionOpcode(unsigned opcode, Specializer<false,true>); + void AddFunctionOpcode(unsigned opcode, Specializer<true,false>); + void AddFunctionOpcode(unsigned opcode, Specializer<true,true>); + inline void AddFunctionOpcode(unsigned opcode) + { + AddFunctionOpcode + (opcode, + Specializer< bool(FUNCTIONPARSERTYPES::IsIntType<Value_t>::result), + bool(FUNCTIONPARSERTYPES::IsComplexType<Value_t>::result) + > () + ); + } + }; + + template<typename Value_t> + struct SequenceOpCode; + template<typename Value_t> + struct SequenceOpcodes + { + /* Multiplication implemented with adds */ + static const SequenceOpCode<Value_t> AddSequence; + /* Exponentiation implemented with muls */ + static const SequenceOpCode<Value_t> MulSequence; + }; + + /* Generate a sequence that multiplies or exponentifies the + * last operand in the stack by the given constant integer + * amount (positive or negative). + */ + template<typename Value_t> + void AssembleSequence( + long count, + const SequenceOpCode<Value_t>& sequencing, + ByteCodeSynth<Value_t>& synth); +} + +#endif diff --git a/fpoptimizer/codetree.cc b/fpoptimizer/codetree.cc new file mode 100644 index 0000000..ef91f25 --- /dev/null +++ b/fpoptimizer/codetree.cc @@ -0,0 +1,456 @@ +#include <list> +#include <algorithm> + +#include "rangeestimation.hh" +#include "optimize.hh" // for DEBUG_SUBSTITUTIONS +#include "codetree.hh" +#include "consts.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +using namespace FUNCTIONPARSERTYPES; +//using namespace FPoptimizer_Grammar; + +namespace +{ +#ifdef DEBUG_SUBSTITUTIONS + void OutFloatHex(std::ostream& o, double d) + { + union { double d; uint_least64_t h; } data; + data.d = d; + o << "(" << std::hex << data.h << std::dec << ")"; + } + #ifdef FP_SUPPORT_FLOAT_TYPE + void OutFloatHex(std::ostream& o, float f) + { + union { float f; uint_least32_t h; } data; + data.f = f; + o << "(" << std::hex << data.h << std::dec << ")"; + } + #endif + #ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + void OutFloatHex(std::ostream& o, long double ld) + { + union { long double ld; + struct { uint_least64_t a; unsigned short b; } s; } data; + data.ld = ld; + o << "(" << std::hex << data.s.b << data.s.a << std::dec << ")"; + } + #endif + #ifdef FP_SUPPORT_LONG_INT_TYPE + void OutFloatHex(std::ostream& o, long ld) + { + o << "(" << std::hex << ld << std::dec << ")"; + } + #endif + +#endif +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + CodeTree<Value_t>::CodeTree() + : data(new CodeTreeData<Value_t> ()) // sets opcode to cNop + { + } + + template<typename Value_t> + CodeTree<Value_t>::CodeTree(const Value_t& i, typename CodeTree<Value_t>::ImmedTag) + : data(new CodeTreeData<Value_t>(i)) + { + data->Recalculate_Hash_NoRecursion(); + } + +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + template<typename Value_t> + CodeTree<Value_t>::CodeTree(Value_t&& i, typename CodeTree<Value_t>::ImmedTag) + : data(new CodeTreeData<Value_t>(std::move(i))) + { + data->Recalculate_Hash_NoRecursion(); + } +#endif + + template<typename Value_t> + CodeTree<Value_t>::CodeTree(unsigned v, typename CodeTree<Value_t>::VarTag) + : data(new CodeTreeData<Value_t> (VarBegin, v)) + { + data->Recalculate_Hash_NoRecursion(); + } + + template<typename Value_t> + CodeTree<Value_t>::CodeTree(FUNCTIONPARSERTYPES::OPCODE o, typename CodeTree<Value_t>::OpcodeTag) + : data(new CodeTreeData<Value_t> (o)) + { + data->Recalculate_Hash_NoRecursion(); + } + + template<typename Value_t> + CodeTree<Value_t>::CodeTree(FUNCTIONPARSERTYPES::OPCODE o, unsigned f, typename CodeTree<Value_t>::FuncOpcodeTag) + : data(new CodeTreeData<Value_t> (o, f)) + { + data->Recalculate_Hash_NoRecursion(); + } + + template<typename Value_t> + CodeTree<Value_t>::CodeTree(const CodeTree<Value_t>& b, typename CodeTree<Value_t>::CloneTag) + : data(new CodeTreeData<Value_t>(*b.data)) + { + } + + template<typename Value_t> + CodeTree<Value_t>::~CodeTree() + { + } + + template<typename Value_t> + void CodeTree<Value_t>::ReplaceWithImmed(const Value_t& i) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Replacing "; DumpTree(*this); + if(IsImmed()) + OutFloatHex(std::cout, GetImmed()); + std::cout << " with const value " << i; + OutFloatHex(std::cout, i); + std::cout << "\n"; + #endif + data = new CodeTreeData<Value_t> (i); + } + + template<typename Value_t> + struct ParamComparer + { + bool operator() (const CodeTree<Value_t>& a, const CodeTree<Value_t>& b) const + { + if(a.GetDepth() != b.GetDepth()) + return a.GetDepth() < b.GetDepth(); + return a.GetHash() < b.GetHash(); + } + }; + + template<typename Value_t> + void CodeTreeData<Value_t>::Sort() + { + /* If the tree is commutative, order the parameters + * in a set order in order to make equality tests + * efficient in the optimizer + */ + switch(Opcode) + { + case cAdd: + case cMul: + case cMin: + case cMax: + case cAnd: case cAbsAnd: + case cOr: case cAbsOr: + case cHypot: + case cEqual: + case cNEqual: + std::sort(Params.begin(), Params.end(), ParamComparer<Value_t>()); + break; + case cLess: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cGreater; } + break; + case cLessOrEq: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cGreaterOrEq; } + break; + case cGreater: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cLess; } + break; + case cGreaterOrEq: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cLessOrEq; } + break; + /* + case cDiv: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cRDiv; } + break; + case cRDiv: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cDiv; } + break; + case cSub: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cRSub; } + break; + case cRSub: + if(ParamComparer<Value_t>() (Params[1], Params[0])) + { std::swap(Params[0], Params[1]); Opcode = cSub; } + break; + */ + default: + break; + } + } + + template<typename Value_t> + void CodeTree<Value_t>::AddParam(const CodeTree<Value_t>& param) + { + //std::cout << "AddParam called\n"; + data->Params.push_back(param); + } + template<typename Value_t> + void CodeTree<Value_t>::AddParamMove(CodeTree<Value_t>& param) + { + data->Params.push_back(CodeTree<Value_t>()); + data->Params.back().swap(param); + } + template<typename Value_t> + void CodeTree<Value_t>::SetParam(size_t which, const CodeTree<Value_t>& b) + { + DataP slot_holder ( data->Params[which].data ); + data->Params[which] = b; + } + template<typename Value_t> + void CodeTree<Value_t>::SetParamMove(size_t which, CodeTree<Value_t>& b) + { + DataP slot_holder ( data->Params[which].data ); + data->Params[which].swap(b); + } + + template<typename Value_t> + void CodeTree<Value_t>::AddParams(const std::vector<CodeTree<Value_t> >& RefParams) + { + data->Params.insert(data->Params.end(), RefParams.begin(), RefParams.end()); + } + template<typename Value_t> + void CodeTree<Value_t>::AddParamsMove(std::vector<CodeTree<Value_t> >& RefParams) + { + size_t endpos = data->Params.size(), added = RefParams.size(); + data->Params.resize(endpos + added, CodeTree<Value_t>()); + for(size_t p=0; p<added; ++p) + data->Params[endpos+p].swap( RefParams[p] ); + } + template<typename Value_t> + void CodeTree<Value_t>::AddParamsMove(std::vector<CodeTree<Value_t> >& RefParams, size_t replacing_slot) + { + DataP slot_holder ( data->Params[replacing_slot].data ); + DelParam(replacing_slot); + AddParamsMove(RefParams); + /* + const size_t n_added = RefParams.size(); + const size_t oldsize = data->Params.size(); + const size_t newsize = oldsize + n_added - 1; + if(RefParams.empty()) + DelParam(replacing_slot); + else + { + // 0 1 2 3 4 5 6 7 8 9 10 11 + // a a a a X b b b b b + // a a a a Y Y Y b b b b b + // + // replacing_slot = 4 + // n_added = 3 + // oldsize = 10 + // newsize = 12 + // tail_length = 5 + + data->Params.resize(newsize); + data->Params[replacing_slot].data = 0; + const size_t tail_length = oldsize - replacing_slot -1; + for(size_t tail=0; tail<tail_length; ++tail) + data->Params[newsize-1-tail].data.UnsafeSetP( + &*data->Params[newsize-1-tail-(n_added-1)].data); + for(size_t head=1; head<n_added; ++head) + data->Params[replacing_slot+head].data.UnsafeSetP( 0 ); + for(size_t p=0; p<n_added; ++p) + data->Params[replacing_slot+p].swap( RefParams[p] ); + } + */ + } + + template<typename Value_t> + void CodeTree<Value_t>::SetParams(const std::vector<CodeTree<Value_t> >& RefParams) + { + //std::cout << "SetParams called" << (do_clone ? ", clone" : ", no clone") << "\n"; + std::vector<CodeTree<Value_t> > tmp(RefParams); + data->Params.swap(tmp); + } + + template<typename Value_t> + void CodeTree<Value_t>::SetParamsMove(std::vector<CodeTree<Value_t> >& RefParams) + { + data->Params.swap(RefParams); + RefParams.clear(); + } + +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + template<typename Value_t> + void CodeTree<Value_t>::SetParams(std::vector<CodeTree<Value_t> >&& RefParams) + { + //std::cout << "SetParams&& called\n"; + SetParamsMove(RefParams); + } +#endif + + template<typename Value_t> + void CodeTree<Value_t>::DelParam(size_t index) + { + std::vector<CodeTree<Value_t> >& Params = data->Params; + //std::cout << "DelParam(" << index << ") called\n"; + #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + /* rvalue reference semantics makes this optimal */ + Params.erase( Params.begin() + index ); + #else + /* This labor evades the need for refcount +1/-1 shuffling */ + Params[index].data = 0; + for(size_t p=index; p+1<Params.size(); ++p) + Params[p].data.UnsafeSetP( Params[p+1].data.get() ); + Params[Params.size()-1].data.UnsafeSetP( 0 ); + Params.resize(Params.size()-1); + #endif + } + + template<typename Value_t> + void CodeTree<Value_t>::DelParams() + { + data->Params.clear(); + } + + template<typename Value_t> + bool CodeTree<Value_t>::IsIdenticalTo(const CodeTree<Value_t>& b) const + { + //if(data.isnull() != b.data.isnull()) return false; + if(data.get() == b.data.get()) return true; + return data->IsIdenticalTo(*b.data); + } + + template<typename Value_t> + bool CodeTreeData<Value_t>::IsIdenticalTo(const CodeTreeData<Value_t>& b) const + { + if(Hash != b.Hash) return false; // a quick catch-all + if(Opcode != b.Opcode) return false; + switch(Opcode) + { + case cImmed: return fp_equal(Value, b.Value); + case VarBegin: return Var_or_Funcno == b.Var_or_Funcno; + case cFCall: + case cPCall: if(Var_or_Funcno != b.Var_or_Funcno) return false; break; + default: break; + } + if(Params.size() != b.Params.size()) return false; + for(size_t a=0; a<Params.size(); ++a) + { + if(!Params[a].IsIdenticalTo(b.Params[a])) return false; + } + return true; + } + + template<typename Value_t> + void CodeTree<Value_t>::Become(const CodeTree<Value_t>& b) + { + if(&b != this && data.get() != b.data.get()) + { + DataP tmp = b.data; + CopyOnWrite(); + data.swap(tmp); + } + } + + template<typename Value_t> + void CodeTree<Value_t>::CopyOnWrite() + { + if(GetRefCount() > 1) + data = new CodeTreeData<Value_t>(*data); + } + + template<typename Value_t> + CodeTree<Value_t> CodeTree<Value_t>::GetUniqueRef() + { + if(GetRefCount() > 1) + return CodeTree<Value_t>(*this, CloneTag()); + return *this; + } + + template<typename Value_t> + CodeTreeData<Value_t>::CodeTreeData() + : RefCount(0), + Opcode(cNop), + Value(), Var_or_Funcno(), + Params(), Hash(), Depth(1), OptimizedUsing(0) + { + } + + template<typename Value_t> + CodeTreeData<Value_t>::CodeTreeData(const CodeTreeData& b) + : RefCount(0), + Opcode(b.Opcode), + Value(b.Value), + Var_or_Funcno(b.Var_or_Funcno), + Params(b.Params), + Hash(b.Hash), + Depth(b.Depth), + OptimizedUsing(b.OptimizedUsing) + { + } + + template<typename Value_t> + CodeTreeData<Value_t>::CodeTreeData(const Value_t& i) + : RefCount(0), + Opcode(cImmed), + Value(i), Var_or_Funcno(), + Params(), Hash(), Depth(1), OptimizedUsing(0) + { + } + +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + template<typename Value_t> + CodeTreeData<Value_t>::CodeTreeData(CodeTreeData<Value_t>&& b) + : RefCount(0), + Opcode(b.Opcode), + Value(std::move(b.Value)), + Var_or_Funcno(b.Var_or_Funcno), + Params(std::move(b.Params)), + Hash(b.Hash), + Depth(b.Depth), + OptimizedUsing(b.OptimizedUsing) + { + } + + template<typename Value_t> + CodeTreeData<Value_t>::CodeTreeData(Value_t&& i) + : RefCount(0), + Opcode(cImmed), + Value(std::move(i)), Var_or_Funcno(), + Params(), Hash(), Depth(1), OptimizedUsing(0) + { + } +#endif + + template<typename Value_t> + CodeTreeData<Value_t>::CodeTreeData(FUNCTIONPARSERTYPES::OPCODE o) + : RefCount(0), + Opcode(o), + Value(), Var_or_Funcno(), + Params(), Hash(), Depth(1), OptimizedUsing(0) + { + } + + template<typename Value_t> + CodeTreeData<Value_t>::CodeTreeData(FUNCTIONPARSERTYPES::OPCODE o, unsigned f) + : RefCount(0), + Opcode(o), + Value(), Var_or_Funcno(f), + Params(), Hash(), Depth(1), OptimizedUsing(0) + { + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template class CodeTree<type>; \ + template struct CodeTreeData<type>; + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif + diff --git a/fpoptimizer/codetree.hh b/fpoptimizer/codetree.hh new file mode 100644 index 0000000..9fffdb2 --- /dev/null +++ b/fpoptimizer/codetree.hh @@ -0,0 +1,242 @@ +#ifndef FPOptimizer_CodeTreeHH +#define FPOptimizer_CodeTreeHH + +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" +#include "extrasrc/fpaux.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include <vector> +#include <utility> + +#include "hash.hh" +#include "../lib/autoptr.hh" + +namespace FPoptimizer_Grammar +{ + struct Grammar; +} + +namespace FPoptimizer_ByteCode +{ + template<typename Value_t> + class ByteCodeSynth; +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + class CodeTree; + + template<typename Value_t> + struct CodeTreeData; + + template<typename Value_t> + class CodeTree + { + typedef FPOPT_autoptr<CodeTreeData<Value_t> > DataP; + DataP data; + + public: + CodeTree(); + ~CodeTree(); + + struct OpcodeTag { }; + explicit CodeTree(FUNCTIONPARSERTYPES::OPCODE o, OpcodeTag); // produce an opcode + struct FuncOpcodeTag { }; + explicit CodeTree(FUNCTIONPARSERTYPES::OPCODE o, unsigned f, FuncOpcodeTag); + struct ImmedTag { }; + explicit CodeTree(const Value_t& v, ImmedTag); // produce an immed +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + explicit CodeTree(Value_t&& v, ImmedTag); // produce an immed +#endif + struct VarTag { }; + explicit CodeTree(unsigned varno, VarTag); // produce a var reference + struct CloneTag { }; + explicit CodeTree(const CodeTree& b, CloneTag); + + /* Generates a CodeTree from the given bytecode */ + void GenerateFrom( + const typename FunctionParserBase<Value_t>::Data& data, + bool keep_powi = false); + + void GenerateFrom( + const typename FunctionParserBase<Value_t>::Data& data, + const std::vector<CodeTree>& var_trees, + bool keep_powi = false); + + void SynthesizeByteCode( + std::vector<unsigned>& byteCode, + std::vector<Value_t>& immed, + size_t& stacktop_max); + + void SynthesizeByteCode( + FPoptimizer_ByteCode::ByteCodeSynth<Value_t>& synth, + bool MustPopTemps=true) const; + + size_t SynthCommonSubExpressions( + FPoptimizer_ByteCode::ByteCodeSynth<Value_t>& synth) const; + + void SetParams(const std::vector<CodeTree>& RefParams); + void SetParamsMove(std::vector<CodeTree>& RefParams); + + CodeTree GetUniqueRef(); + // ^use this when CodeTree tmp=x; tmp.CopyOnWrite(); does not do exactly what you want + +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + void SetParams(std::vector<CodeTree>&& RefParams); +#endif + void SetParam(size_t which, const CodeTree& b); + void SetParamMove(size_t which, CodeTree& b); + void AddParam(const CodeTree& param); + void AddParamMove(CodeTree& param); + void AddParams(const std::vector<CodeTree>& RefParams); + void AddParamsMove(std::vector<CodeTree>& RefParams); + void AddParamsMove(std::vector<CodeTree>& RefParams, size_t replacing_slot); + void DelParam(size_t index); + void DelParams(); + + void Become(const CodeTree& b); + + inline size_t GetParamCount() const { return GetParams().size(); } + inline CodeTree& GetParam(size_t n) { return GetParams()[n]; } + inline const CodeTree& GetParam(size_t n) const { return GetParams()[n]; } + inline void SetOpcode(FUNCTIONPARSERTYPES::OPCODE o) { data->Opcode = o; } + inline FUNCTIONPARSERTYPES::OPCODE GetOpcode() const { return data->Opcode; } + inline FUNCTIONPARSERTYPES::fphash_t GetHash() const { return data->Hash; } + inline const std::vector<CodeTree>& GetParams() const { return data->Params; } + inline std::vector<CodeTree>& GetParams() { return data->Params; } + inline size_t GetDepth() const { return data->Depth; } + inline const Value_t& GetImmed() const { return data->Value; } + inline unsigned GetVar() const { return data->Var_or_Funcno; } + inline unsigned GetFuncNo() const { return data->Var_or_Funcno; } + inline bool IsDefined() const { return GetOpcode() != FUNCTIONPARSERTYPES::cNop; } + + inline bool IsImmed() const { return GetOpcode() == FUNCTIONPARSERTYPES::cImmed; } + inline bool IsVar() const { return GetOpcode() == FUNCTIONPARSERTYPES::VarBegin; } + inline unsigned GetRefCount() const { return data->RefCount; } + + void ReplaceWithImmed(const Value_t& i); + void Rehash(bool constantfolding = true); + void Sort(); + inline void Mark_Incompletely_Hashed() { data->Depth=0; } + inline bool Is_Incompletely_Hashed() const { return data->Depth == 0; } + + inline const FPoptimizer_Grammar::Grammar* GetOptimizedUsing() const + { return data->OptimizedUsing; } + inline void SetOptimizedUsing(const FPoptimizer_Grammar::Grammar* g) + { data->OptimizedUsing = g; } + + bool RecreateInversionsAndNegations(bool prefer_base2 = false); + void FixIncompleteHashes(); + + void swap(CodeTree& b) { data.swap(b.data); } + bool IsIdenticalTo(const CodeTree& b) const; + void CopyOnWrite(); + }; + + template<typename Value_t> + struct CodeTreeData + { + int RefCount; + + /* Describing the codetree node */ + FUNCTIONPARSERTYPES::OPCODE Opcode; + Value_t Value; // In case of cImmed: value of the immed + unsigned Var_or_Funcno; // In case of VarBegin: variable number + // In case of cFCall or cPCall: function number + + // Parameters for the function + // These use the sign: + // For cAdd: operands to add together (0 to n) + // sign indicates that the value is negated before adding (0-x) + // For cMul: operands to multiply together (0 to n) + // sign indicates that the value is inverted before multiplying (1/x) + // For cAnd: operands to bitwise-and together (0 to n) + // sign indicates that the value is inverted before anding (!x) + // For cOr: operands to bitwise-or together (0 to n) + // sign indicates that the value is inverted before orring (!x) + // These don't use the sign (sign is always false): + // For cMin: operands to select the minimum of + // For cMax: operands to select the maximum of + // For cImmed, not used + // For VarBegin, not used + // For cIf: operand 1 = condition, operand 2 = yes-branch, operand 3 = no-branch + // For anything else: the parameters required by the operation/function + std::vector<CodeTree<Value_t> > Params; + + /* Internal operation */ + FUNCTIONPARSERTYPES::fphash_t Hash; + size_t Depth; + const FPoptimizer_Grammar::Grammar* OptimizedUsing; + + CodeTreeData(); + CodeTreeData(const CodeTreeData& b); + explicit CodeTreeData(FUNCTIONPARSERTYPES::OPCODE o); + explicit CodeTreeData(FUNCTIONPARSERTYPES::OPCODE o, unsigned f); + explicit CodeTreeData(const Value_t& i); +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + explicit CodeTreeData(Value_t&& i); + CodeTreeData(CodeTreeData&& b); +#endif + + bool IsIdenticalTo(const CodeTreeData& b) const; + void Sort(); + void Recalculate_Hash_NoRecursion(); + + private: + void operator=(const CodeTreeData& b); + }; + + /* Utility functions for creating different kind of CodeTrees */ + template<typename Value_t> + static inline CodeTree<Value_t> CodeTreeImmed(const Value_t& i) + { + return CodeTree<Value_t> (i, typename CodeTree<Value_t>::ImmedTag()); + } + +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L + template<typename Value_t> + static inline CodeTree<Value_t> CodeTreeImmed(Value_t&& i) + { + return CodeTree<Value_t> (std::move(i), + typename CodeTree<Value_t>::ImmedTag()); + } +#endif + + template<typename Value_t> + static inline CodeTree<Value_t> CodeTreeOp(FUNCTIONPARSERTYPES::OPCODE opcode) + { + return CodeTree<Value_t> (opcode, typename CodeTree<Value_t>::OpcodeTag()); + } + + template<typename Value_t> + static inline CodeTree<Value_t> CodeTreeFuncOp(FUNCTIONPARSERTYPES::OPCODE opcode, unsigned f) + { + return CodeTree<Value_t> (opcode, f, typename CodeTree<Value_t>::FuncOpcodeTag()); + } + + template<typename Value_t> + static inline CodeTree<Value_t> CodeTreeVar(unsigned varno) + { + return CodeTree<Value_t> (varno, typename CodeTree<Value_t>::VarTag()); + } + + /* Debugging functions */ +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + template<typename Value_t> + void DumpHashes(const CodeTree<Value_t>& tree, std::ostream& o = std::cout); + + template<typename Value_t> + void DumpTree(const CodeTree<Value_t>& tree, std::ostream& o = std::cout); + + template<typename Value_t> + void DumpTreeWithIndent(const CodeTree<Value_t>& tree, std::ostream& o = std::cout, const std::string& indent = "\\"); +#endif +} + +#endif + +#endif diff --git a/fpoptimizer/constantfolding.cc b/fpoptimizer/constantfolding.cc new file mode 100644 index 0000000..e3f24df --- /dev/null +++ b/fpoptimizer/constantfolding.cc @@ -0,0 +1,941 @@ +#include <algorithm> + +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include "codetree.hh" +#include "optimize.hh" +#include "consts.hh" + +#include <assert.h> + +#include "rangeestimation.hh" +#include "constantfolding.hh" + + +#include "logic_boolgroups.hh" +/* ^For ConstantFolding_AndLogic() + * ConstantFolding_OrLogic() + * ConstantFolding_MulLogicItems() + * ConstantFolding_AddLogicItems() + */ + +#include "logic_collections.hh" +/* ^For ConstantFolding_MulGrouping() + * ConstantFolding_AddGrouping() + */ + +#include "logic_ifoperations.hh" +/* ^For ConstantFolding_IfOperations() + */ + +#include "logic_powoperations.hh" +/* ^For ConstantFolding_PowOperations() + */ + +#include "logic_comparisons.hh" +/* ^For ConstantFolding_Comparison() + */ + +#define FP_MUL_COMBINE_EXPONENTS + +namespace +{ + using namespace FUNCTIONPARSERTYPES; + using namespace FPoptimizer_CodeTree; + + /*************************************/ + /* ADOPTING SAME-TYPE CHILDREN */ + /*************************************/ + + template<typename Value_t> + static void AdoptChildrenWithSameOpcode(CodeTree<Value_t>& tree) + { + /* If the list contains another list of the same kind, assimilate it */ + #ifdef DEBUG_SUBSTITUTIONS + bool assimilated = false; + #endif + for(size_t a=tree.GetParamCount(); a-- > 0; ) + if(tree.GetParam(a).GetOpcode() == tree.GetOpcode()) + { + #ifdef DEBUG_SUBSTITUTIONS + if(!assimilated) + { + std::cout << "Before assimilation: "; DumpTree(tree); + std::cout << "\n"; + assimilated = true; + } + #endif + // Assimilate its children and remove it + tree.AddParamsMove(tree.GetParam(a).GetUniqueRef().GetParams(), a); + } + #ifdef DEBUG_SUBSTITUTIONS + if(assimilated) + { + std::cout << "After assimilation: "; DumpTree(tree); + std::cout << "\n"; + } + #endif + } +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + void ConstantFolding(CodeTree<Value_t>& tree) + { + tree.Sort(); // Otherwise "0 <= acos(x)" does not get properly optimized + #ifdef DEBUG_SUBSTITUTIONS + void* stackptr=0; + std::cout << "[" << (&stackptr) << "]Runs ConstantFolding for: "; + DumpTree(tree); + std::cout << "\n"; + DumpHashes(tree); std::cout << std::flush; + #endif + if(false) + { + redo:; + tree.Sort(); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "[" << (&stackptr) << "]Re-runs ConstantFolding: "; + DumpTree(tree); + std::cout << "\n"; + DumpHashes(tree); + #endif + } + + // Insert here any hardcoded constant-folding optimizations + // that you want to be done whenever a new subtree is generated. + /* Not recursive. */ + + if(tree.GetOpcode() != cImmed) + { + range<Value_t> p = CalculateResultBoundaries(tree); + if(p.min.known && p.max.known && p.min.val == p.max.val) + { + // Replace us with this immed + tree.ReplaceWithImmed(p.min.val); + goto do_return; + } + } + + if(false) + { + ReplaceTreeWithOne: tree.ReplaceWithImmed(Value_t(1)); goto do_return; + ReplaceTreeWithZero: tree.ReplaceWithImmed(Value_t(0)); goto do_return; + ReplaceTreeWithParam0: + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Before replace: "; + std::cout << std::hex + << '[' << tree.GetHash().hash1 + << ',' << tree.GetHash().hash2 + << ']' << std::dec; + DumpTree(tree); + std::cout << "\n"; + #endif + tree.Become(tree.GetParam(0)); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "After replace: "; + std::cout << std::hex + << '[' << tree.GetHash().hash1 + << ',' << tree.GetHash().hash2 + << ']' << std::dec; + DumpTree(tree); + std::cout << "\n"; + #endif + goto redo; + } + + /* Constant folding */ + switch(tree.GetOpcode()) + { + case cImmed: + break; // nothing to do + case VarBegin: + break; // nothing to do + + case cAnd: + case cAbsAnd: + { + AdoptChildrenWithSameOpcode(tree); + bool has_nonlogical_values = false; + for(size_t a=tree.GetParamCount(); a-- > 0; ) + { + if(!IsLogicalValue(tree.GetParam(a))) has_nonlogical_values = true; + switch(GetLogicalValue(tree.GetParam(a), tree.GetOpcode()==cAbsAnd)) + { + case IsNever: goto ReplaceTreeWithZero; + case IsAlways: tree.DelParam(a); break; // x & y & 1 = x & y; x & 1 = !!x + case Unknown: default: ; + } + } + switch(tree.GetParamCount()) + { + case 0: goto ReplaceTreeWithOne; + case 1: tree.SetOpcode(tree.GetOpcode()==cAnd ? cNotNot : cAbsNotNot); goto redo; // Replace self with the single operand + default: + if(tree.GetOpcode()==cAnd || !has_nonlogical_values) + if(ConstantFolding_AndLogic(tree)) goto redo; + } + break; + } + case cOr: + case cAbsOr: + { + AdoptChildrenWithSameOpcode(tree); + bool has_nonlogical_values = false; + for(size_t a=tree.GetParamCount(); a-- > 0; ) + { + if(!IsLogicalValue(tree.GetParam(a))) has_nonlogical_values = true; + switch(GetLogicalValue(tree.GetParam(a), tree.GetOpcode()==cAbsOr)) + { + case IsAlways: goto ReplaceTreeWithOne; + case IsNever: tree.DelParam(a); break; + case Unknown: default: ; + } + } + switch(tree.GetParamCount()) + { + case 0: goto ReplaceTreeWithZero; + case 1: tree.SetOpcode(tree.GetOpcode()==cOr ? cNotNot : cAbsNotNot); goto redo; // Replace self with the single operand + default: + if(tree.GetOpcode()==cOr || !has_nonlogical_values) + if(ConstantFolding_OrLogic(tree)) goto redo; + } + break; + } + case cNot: + case cAbsNot: + { + unsigned opposite = 0; + switch(tree.GetParam(0).GetOpcode()) + { + case cEqual: opposite = cNEqual; break; + case cNEqual: opposite = cEqual; break; + case cLess: opposite = cGreaterOrEq; break; + case cGreater: opposite = cLessOrEq; break; + case cLessOrEq: opposite = cGreater; break; + case cGreaterOrEq: opposite = cLess; break; + case cNotNot: opposite = cNot; break; + case cNot: opposite = cNotNot; break; + case cAbsNot: opposite = cAbsNotNot; break; + case cAbsNotNot: opposite = cAbsNot; break; + default: break; + } + if(opposite) + { + tree.SetOpcode(OPCODE(opposite)); + tree.SetParamsMove(tree.GetParam(0).GetUniqueRef().GetParams()); + goto redo; + } + + // If the sub-expression evaluates to approx. zero, yield one. + // If the sub-expression evaluates to approx. nonzero, yield zero. + switch(GetLogicalValue(tree.GetParam(0), tree.GetOpcode()==cAbsNot)) + { + case IsAlways: goto ReplaceTreeWithZero; + case IsNever: goto ReplaceTreeWithOne; + case Unknown: default: ; + } + if(tree.GetOpcode() == cNot && GetPositivityInfo(tree.GetParam(0)) == IsAlways) + tree.SetOpcode(cAbsNot); + + if(tree.GetParam(0).GetOpcode() == cIf + || tree.GetParam(0).GetOpcode() == cAbsIf) + { + CodeTree<Value_t> iftree = tree.GetParam(0); + const CodeTree<Value_t>& ifp1 = iftree.GetParam(1); + const CodeTree<Value_t>& ifp2 = iftree.GetParam(2); + if(ifp1.GetOpcode() == cNot + || ifp1.GetOpcode() == cAbsNot) + { + // cNot [(cIf [x (cNot[y]) z])] -> cIf [x (cNotNot[y]) (cNot[z])] + tree.SetParam(0, iftree.GetParam(0)); // condition + CodeTree<Value_t> p1; + p1.SetOpcode(ifp1.GetOpcode()==cNot ? cNotNot : cAbsNotNot); + p1.AddParam(ifp1.GetParam(0)); + p1.Rehash(); + tree.AddParamMove(p1); + CodeTree<Value_t> p2; + p2.SetOpcode(tree.GetOpcode()); + p2.AddParam(ifp2); + p2.Rehash(); + tree.AddParamMove(p2); + tree.SetOpcode(iftree.GetOpcode()); + goto redo; + } + if(ifp2.GetOpcode() == cNot + || ifp2.GetOpcode() == cAbsNot) + { + // cNot [(cIf [x y (cNot[z])])] -> cIf [x (cNot[y]) (cNotNot[z])] + tree.SetParam(0, iftree.GetParam(0)); // condition + CodeTree<Value_t> p1; + p1.SetOpcode(tree.GetOpcode()); + p1.AddParam(ifp1); + p1.Rehash(); + tree.AddParamMove(p1); + CodeTree<Value_t> p2; + p2.SetOpcode(ifp2.GetOpcode()==cNot ? cNotNot : cAbsNotNot); + p2.AddParam(ifp2.GetParam(0)); + p2.Rehash(); + tree.AddParamMove(p2); + tree.SetOpcode(iftree.GetOpcode()); + goto redo; + } + } + break; + } + case cNotNot: + case cAbsNotNot: + { + // The function of cNotNot is to protect a logical value from + // changing. If the parameter is already a logical value, + // then the cNotNot opcode is redundant. + if(IsLogicalValue(tree.GetParam(0))) + goto ReplaceTreeWithParam0; + + // If the sub-expression evaluates to approx. zero, yield zero. + // If the sub-expression evaluates to approx. nonzero, yield one. + switch(GetLogicalValue(tree.GetParam(0), tree.GetOpcode()==cAbsNotNot)) + { + case IsNever: goto ReplaceTreeWithZero; + case IsAlways: goto ReplaceTreeWithOne; + case Unknown: default: ; + } + if(tree.GetOpcode() == cNotNot && GetPositivityInfo(tree.GetParam(0)) == IsAlways) + tree.SetOpcode(cAbsNotNot); + + if(tree.GetParam(0).GetOpcode() == cIf + || tree.GetParam(0).GetOpcode() == cAbsIf) + { + CodeTree<Value_t> iftree = tree.GetParam(0); + const CodeTree<Value_t>& ifp1 = iftree.GetParam(1); + const CodeTree<Value_t>& ifp2 = iftree.GetParam(2); + if(ifp1.GetOpcode() == cNot + || ifp1.GetOpcode() == cAbsNot) + { + // cNotNot [(cIf [x (cNot[y]) z])] -> cIf [x (cNot[y]) (cNotNot[z])] + tree.SetParam(0, iftree.GetParam(0)); // condition + tree.AddParam(ifp1); + CodeTree<Value_t> p2; + p2.SetOpcode(tree.GetOpcode()); + p2.AddParam(ifp2); + p2.Rehash(); + tree.AddParamMove(p2); + tree.SetOpcode(iftree.GetOpcode()); + goto redo; + } + if(ifp2.GetOpcode() == cNot + || ifp2.GetOpcode() == cAbsNot) + { + // cNotNot [(cIf [x y (cNot[z])])] -> cIf [x (cNotNot[y]) (cNot[z])] + tree.SetParam(0, iftree.GetParam(0)); // condition + CodeTree<Value_t> p1; + p1.SetOpcode(tree.GetOpcode()); + p1.AddParam(ifp1); + p1.Rehash(); + tree.AddParamMove(p1); + tree.AddParam(ifp2); + tree.SetOpcode(iftree.GetOpcode()); + goto redo; + } + } + break; + } + case cIf: + case cAbsIf: + { + if(ConstantFolding_IfOperations(tree)) + goto redo; + break; + } + case cMul: + { + NowWeAreMulGroup: ; + AdoptChildrenWithSameOpcode(tree); + // If one sub-expression evalutes to exact zero, yield zero. + Value_t immed_product = Value_t(1); + size_t n_immeds = 0; bool needs_resynth=false; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + if(!tree.GetParam(a).IsImmed()) continue; + // ^ Only check constant values + Value_t immed = tree.GetParam(a).GetImmed(); + if(immed == Value_t(0) ) goto ReplaceTreeWithZero; + immed_product *= immed; ++n_immeds; + } + // Merge immeds. + if(n_immeds > 1 || (n_immeds == 1 && fp_equal(immed_product, Value_t(1)))) + needs_resynth = true; + if(needs_resynth) + { + // delete immeds and add new ones + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "cMul: Will add new immed " << immed_product << "\n"; + #endif + for(size_t a=tree.GetParamCount(); a-->0; ) + if(tree.GetParam(a).IsImmed()) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << " - For that, deleting immed " << tree.GetParam(a).GetImmed(); + std::cout << "\n"; + #endif + tree.DelParam(a); + } + if(!fp_equal(immed_product, Value_t(1))) + tree.AddParam( CodeTreeImmed<Value_t> (immed_product) ); + } + switch(tree.GetParamCount()) + { + case 0: goto ReplaceTreeWithOne; + case 1: goto ReplaceTreeWithParam0; // Replace self with the single operand + default: + if(ConstantFolding_MulGrouping(tree)) goto redo; + if(ConstantFolding_MulLogicItems(tree)) goto redo; + } + break; + } + case cAdd: + { + AdoptChildrenWithSameOpcode(tree); + Value_t immed_sum = 0.0; + size_t n_immeds = 0; bool needs_resynth=false; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + if(!tree.GetParam(a).IsImmed()) continue; + // ^ Only check constant values + Value_t immed = tree.GetParam(a).GetImmed(); + immed_sum += immed; ++n_immeds; + } + // Merge immeds. + if(n_immeds > 1 || (n_immeds == 1 && immed_sum == Value_t(0))) + needs_resynth = true; + if(needs_resynth) + { + // delete immeds and add new ones + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "cAdd: Will add new immed " << immed_sum << "\n"; + std::cout << "In: "; DumpTree(tree); + std::cout << "\n"; + #endif + for(size_t a=tree.GetParamCount(); a-->0; ) + if(tree.GetParam(a).IsImmed()) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << " - For that, deleting immed " << tree.GetParam(a).GetImmed(); + std::cout << "\n"; + #endif + tree.DelParam(a); + } + if(!(immed_sum == Value_t(0.0))) + tree.AddParam( CodeTreeImmed<Value_t> (immed_sum) ); + } + switch(tree.GetParamCount()) + { + case 0: goto ReplaceTreeWithZero; + case 1: goto ReplaceTreeWithParam0; // Replace self with the single operand + default: + if(ConstantFolding_AddGrouping(tree)) goto redo; + if(ConstantFolding_AddLogicItems(tree)) goto redo; + } + break; + } + case cMin: + { + AdoptChildrenWithSameOpcode(tree); + /* Goal: If there is any pair of two operands, where + * their ranges form a disconnected set, i.e. as below: + * xxxxx + * yyyyyy + * Then remove the larger one. + * + * Algorithm: 1. figure out the smallest maximum of all operands. + * 2. eliminate all operands where their minimum is + * larger than the selected maximum. + */ + size_t preserve=0; + range<Value_t> smallest_maximum; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + while(a+1 < tree.GetParamCount() && tree.GetParam(a).IsIdenticalTo(tree.GetParam(a+1))) + tree.DelParam(a+1); + range<Value_t> p = CalculateResultBoundaries( tree.GetParam(a) ); + if(p.max.known && (!smallest_maximum.max.known || (p.max.val) < smallest_maximum.max.val)) + { + smallest_maximum.max.val = p.max.val; + smallest_maximum.max.known = true; + preserve=a; + } } + if(smallest_maximum.max.known) + for(size_t a=tree.GetParamCount(); a-- > 0; ) + { + range<Value_t> p = CalculateResultBoundaries( tree.GetParam(a) ); + if(p.min.known && a != preserve && p.min.val >= smallest_maximum.max.val) + tree.DelParam(a); + } + //fprintf(stderr, "Remains: %u\n", (unsigned)tree.GetParamCount()); + if(tree.GetParamCount() == 1) + { + // Replace self with the single operand + goto ReplaceTreeWithParam0; + } + break; + } + case cMax: + { + AdoptChildrenWithSameOpcode(tree); + /* Goal: If there is any pair of two operands, where + * their ranges form a disconnected set, i.e. as below: + * xxxxx + * yyyyyy + * Then remove the smaller one. + * + * Algorithm: 1. figure out the biggest minimum of all operands. + * 2. eliminate all operands where their maximum is + * smaller than the selected minimum. + */ + size_t preserve=0; + range<Value_t> biggest_minimum; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + while(a+1 < tree.GetParamCount() && tree.GetParam(a).IsIdenticalTo(tree.GetParam(a+1))) + tree.DelParam(a+1); + range<Value_t> p = CalculateResultBoundaries( tree.GetParam(a) ); + if(p.min.known && (!biggest_minimum.min.known || p.min.val > biggest_minimum.min.val)) + { + biggest_minimum.min.val = p.min.val; + biggest_minimum.min.known = true; + preserve=a; + } } + if(biggest_minimum.min.known) + { + //fprintf(stderr, "Removing all where max < %g\n", biggest_minimum.min.val); + for(size_t a=tree.GetParamCount(); a-- > 0; ) + { + range<Value_t> p = CalculateResultBoundaries( tree.GetParam(a) ); + if(p.max.known && a != preserve && (p.max.val) < biggest_minimum.min.val) + { + //fprintf(stderr, "Removing %g\n", p.max.val); + tree.DelParam(a); + } + } + } + //fprintf(stderr, "Remains: %u\n", (unsigned)tree.GetParamCount()); + if(tree.GetParamCount() == 1) + { + // Replace self with the single operand + goto ReplaceTreeWithParam0; + } + break; + } + + case cEqual: + case cNEqual: + case cLess: + case cGreater: + case cLessOrEq: + case cGreaterOrEq: + if(ConstantFolding_Comparison(tree)) goto redo; + break; + + case cAbs: + { + /* If we know the operand is always positive, cAbs is redundant. + * If we know the operand is always negative, use actual negation. + */ + range<Value_t> p0 = CalculateResultBoundaries( tree.GetParam(0) ); + if(p0.min.known && p0.min.val >= Value_t(0.0)) + goto ReplaceTreeWithParam0; + if(p0.max.known && p0.max.val <= fp_const_negativezero<Value_t>()) + { + /* abs(negative) = negative*-1 */ + tree.SetOpcode(cMul); + tree.AddParam( CodeTreeImmed(Value_t(1)) ); + /* The caller of ConstantFolding() will do Sort() and Rehash() next. + * Thus, no need to do it here. */ + /* We were changed into a cMul group. Do cMul folding. */ + goto NowWeAreMulGroup; + } + /* If the operand is a cMul group, find elements + * that are always positive and always negative, + * and move them out, e.g. abs(p*n*x*y) = p*(-n)*abs(x*y) + */ + if(tree.GetParam(0).GetOpcode() == cMul) + { + const CodeTree<Value_t>& p = tree.GetParam(0); + std::vector<CodeTree<Value_t> > pos_set; + std::vector<CodeTree<Value_t> > neg_set; + for(size_t a=0; a<p.GetParamCount(); ++a) + { + p0 = CalculateResultBoundaries( p.GetParam(a) ); + if(p0.min.known && p0.min.val >= Value_t(0.0)) + { pos_set.push_back(p.GetParam(a)); } + if(p0.max.known && p0.max.val <= fp_const_negativezero<Value_t>()) + { neg_set.push_back(p.GetParam(a)); } + } + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Abs: mul group has " << pos_set.size() + << " pos, " << neg_set.size() << "neg\n"; + #endif + if(!pos_set.empty() || !neg_set.empty()) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "AbsReplace-Before: "; + DumpTree(tree); + std::cout << "\n" << std::flush; + DumpHashes(tree, std::cout); + #endif + CodeTree<Value_t> pclone; + pclone.SetOpcode(cMul); + for(size_t a=0; a<p.GetParamCount(); ++a) + { + p0 = CalculateResultBoundaries( p.GetParam(a) ); + if((p0.min.known && p0.min.val >= Value_t(0.0)) + || (p0.max.known && p0.max.val <= fp_const_negativezero<Value_t>())) + {/*pclone.DelParam(a);*/} + else + pclone.AddParam( p.GetParam(a) ); + /* Here, p*n*x*y -> x*y. + * p is saved in pos_set[] + * n is saved in neg_set[] + */ + } + pclone.Rehash(); + CodeTree<Value_t> abs_mul; + abs_mul.SetOpcode(cAbs); + abs_mul.AddParamMove(pclone); + abs_mul.Rehash(); + CodeTree<Value_t> mulgroup; + mulgroup.SetOpcode(cMul); + mulgroup.AddParamMove(abs_mul); // cAbs[whatever remains in p] + mulgroup.AddParamsMove(pos_set); + /* Now: + * mulgroup = p * Abs(x*y) + */ + if(!neg_set.empty()) + { + if(neg_set.size() % 2) + mulgroup.AddParam( CodeTreeImmed(Value_t(-1)) ); + mulgroup.AddParamsMove(neg_set); + /* Now: + * mulgroup = p * n * -1 * Abs(x*y) + */ + } + tree.Become(mulgroup); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "AbsReplace-After: "; + DumpTree(tree, std::cout); + std::cout << "\n" << std::flush; + DumpHashes(tree, std::cout); + #endif + /* We were changed into a cMul group. Do cMul folding. */ + goto NowWeAreMulGroup; + } + } + break; + } + + #define HANDLE_UNARY_CONST_FUNC(funcname) \ + if(tree.GetParam(0).IsImmed()) \ + { tree.ReplaceWithImmed( funcname(tree.GetParam(0).GetImmed()) ); \ + goto do_return; } + + case cLog: + HANDLE_UNARY_CONST_FUNC(fp_log); + if(tree.GetParam(0).GetOpcode() == cPow) + { + CodeTree<Value_t> pow = tree.GetParam(0); + if(GetPositivityInfo(pow.GetParam(0)) == IsAlways) // log(posi ^ y) = y*log(posi) + { + pow.CopyOnWrite(); + pow.SetOpcode(cLog); + tree.SetOpcode(cMul); + tree.AddParamMove(pow.GetParam(1)); + pow.DelParam(1); + pow.Rehash(); + tree.SetParamMove(0, pow); + goto NowWeAreMulGroup; + } + if(GetEvennessInfo(pow.GetParam(1)) == IsAlways) // log(x ^ even) = even*log(abs(x)) + { + pow.CopyOnWrite(); + CodeTree<Value_t> abs; + abs.SetOpcode(cAbs); + abs.AddParamMove(pow.GetParam(0)); + abs.Rehash(); + pow.SetOpcode(cLog); + tree.SetOpcode(cMul); + pow.SetParamMove(0, abs); + tree.AddParamMove(pow.GetParam(1)); + pow.DelParam(1); + pow.Rehash(); + tree.SetParamMove(0, pow); + goto NowWeAreMulGroup; + } + } + else if(tree.GetParam(0).GetOpcode() == cAbs) + { + // log(abs(x^y)) = y*log(abs(x)) + CodeTree<Value_t> pow = tree.GetParam(0).GetParam(0); + if(pow.GetOpcode() == cPow) + { + pow.CopyOnWrite(); + CodeTree<Value_t> abs; + abs.SetOpcode(cAbs); + abs.AddParamMove(pow.GetParam(0)); + abs.Rehash(); + pow.SetOpcode(cLog); + tree.SetOpcode(cMul); + pow.SetParamMove(0, abs); + tree.AddParamMove(pow.GetParam(1)); + pow.DelParam(1); + pow.Rehash(); + tree.SetParamMove(0, pow); + goto NowWeAreMulGroup; + } + } + break; + case cAcosh: HANDLE_UNARY_CONST_FUNC(fp_acosh); break; + case cAsinh: HANDLE_UNARY_CONST_FUNC(fp_asinh); break; + case cAtanh: HANDLE_UNARY_CONST_FUNC(fp_atanh); break; + case cAcos: HANDLE_UNARY_CONST_FUNC(fp_acos); break; + case cAsin: HANDLE_UNARY_CONST_FUNC(fp_asin); break; + case cAtan: HANDLE_UNARY_CONST_FUNC(fp_atan); break; + case cCosh: HANDLE_UNARY_CONST_FUNC(fp_cosh); break; + case cSinh: HANDLE_UNARY_CONST_FUNC(fp_sinh); break; + case cTanh: HANDLE_UNARY_CONST_FUNC(fp_tanh); break; + case cSin: HANDLE_UNARY_CONST_FUNC(fp_sin); break; + case cCos: HANDLE_UNARY_CONST_FUNC(fp_cos); break; + case cTan: HANDLE_UNARY_CONST_FUNC(fp_tan); break; + case cCeil: + if(GetIntegerInfo(tree.GetParam(0)) == IsAlways) goto ReplaceTreeWithParam0; + HANDLE_UNARY_CONST_FUNC(fp_ceil); break; + case cTrunc: + if(GetIntegerInfo(tree.GetParam(0)) == IsAlways) goto ReplaceTreeWithParam0; + HANDLE_UNARY_CONST_FUNC(fp_trunc); break; + case cFloor: + if(GetIntegerInfo(tree.GetParam(0)) == IsAlways) goto ReplaceTreeWithParam0; + HANDLE_UNARY_CONST_FUNC(fp_floor); break; + case cInt: + if(GetIntegerInfo(tree.GetParam(0)) == IsAlways) goto ReplaceTreeWithParam0; + HANDLE_UNARY_CONST_FUNC(fp_int); break; + case cCbrt: HANDLE_UNARY_CONST_FUNC(fp_cbrt); break; // converted into cPow x 0.33333 + case cSqrt: HANDLE_UNARY_CONST_FUNC(fp_sqrt); break; // converted into cPow x 0.5 + case cExp: HANDLE_UNARY_CONST_FUNC(fp_exp); break; // convered into cPow CONSTANT_E x + case cLog2: HANDLE_UNARY_CONST_FUNC(fp_log2); break; + case cLog10: HANDLE_UNARY_CONST_FUNC(fp_log10); break; + + case cLog2by: + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).IsImmed()) + { tree.ReplaceWithImmed( fp_log2(tree.GetParam(0).GetImmed()) * tree.GetParam(1).GetImmed() ); + goto do_return; } + break; + + case cArg: HANDLE_UNARY_CONST_FUNC(fp_arg); break; + case cConj: HANDLE_UNARY_CONST_FUNC(fp_conj); break; + case cImag: HANDLE_UNARY_CONST_FUNC(fp_imag); break; + case cReal: HANDLE_UNARY_CONST_FUNC(fp_real); break; + case cPolar: + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).IsImmed()) + { tree.ReplaceWithImmed( fp_polar(tree.GetParam(0).GetImmed(), tree.GetParam(1).GetImmed() ) ); + goto do_return; } + break; + + case cMod: /* Can more be done than this? */ + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).IsImmed()) + { tree.ReplaceWithImmed( fp_mod(tree.GetParam(0).GetImmed(), tree.GetParam(1).GetImmed()) ); + goto do_return; } + break; + + case cAtan2: + { + /* Range based optimizations for (y,x): + * If y is +0 and x <= -0, +pi is returned + * If y is -0 and x <= -0, -pi is returned (assumed never happening) + * If y is +0 and x >= +0, +0 is returned + * If y is -0 and x >= +0, -0 is returned (assumed never happening) + * If x is +-0 and y < 0, -pi/2 is returned + * If x is +-0 and y > 0, +pi/2 is returned + * Otherwise, perform constant folding when available + * If we know x <> 0, convert into atan(y / x) + * TODO: Figure out whether the above step is wise + * It allows e.g. atan2(6*x, 3*y) -> atan(2*x/y) + * when we know y != 0 + */ + range<Value_t> p0 = CalculateResultBoundaries( tree.GetParam(0) ); + range<Value_t> p1 = CalculateResultBoundaries( tree.GetParam(1) ); + if(tree.GetParam(0).IsImmed() + && fp_equal(tree.GetParam(0).GetImmed(), Value_t(0))) // y == 0 + { + if(p1.max.known && (p1.max.val) < Value_t(0)) // y == 0 && x < 0 + { tree.ReplaceWithImmed( fp_const_pi<Value_t>() ); goto do_return; } + if(p1.min.known && p1.min.val >= Value_t(0.0)) // y == 0 && x >= 0.0 + { tree.ReplaceWithImmed( Value_t(0) ); goto do_return; } + } + if(tree.GetParam(1).IsImmed() + && fp_equal(tree.GetParam(1).GetImmed(), Value_t(0))) // x == 0 + { + if(p0.max.known && (p0.max.val) < Value_t(0)) // y < 0 && x == 0 + { tree.ReplaceWithImmed( -fp_const_pihalf<Value_t>() ); goto do_return; } + if(p0.min.known && p0.min.val > Value_t(0)) // y > 0 && x == 0 + { tree.ReplaceWithImmed( fp_const_pihalf<Value_t>() ); goto do_return; } + } + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).IsImmed()) + { tree.ReplaceWithImmed( fp_atan2(tree.GetParam(0).GetImmed(), + tree.GetParam(1).GetImmed()) ); + goto do_return; } + if((p1.min.known && p1.min.val > Value_t(0)) // p1 != 0.0 + || (p1.max.known && (p1.max.val) < fp_const_negativezero<Value_t>())) // become atan(p0 / p1) + { + CodeTree<Value_t> pow_tree; + pow_tree.SetOpcode(cPow); + pow_tree.AddParamMove(tree.GetParam(1)); + pow_tree.AddParam(CodeTreeImmed(Value_t(-1))); + pow_tree.Rehash(); + CodeTree<Value_t> div_tree; + div_tree.SetOpcode(cMul); + div_tree.AddParamMove(tree.GetParam(0)); + div_tree.AddParamMove(pow_tree); + div_tree.Rehash(); + tree.SetOpcode(cAtan); + tree.SetParamMove(0, div_tree); + tree.DelParam(1); + } + break; + } + + case cPow: + { + if(ConstantFolding_PowOperations(tree)) goto redo; + break; + } + + /* The following opcodes are processed by GenerateFrom() + * within fpoptimizer_bytecode_to_codetree.cc and thus + * they will never occur in the calling context for the + * most of the parsing context. They may however occur + * at the late phase, so we deal with them. + */ + case cDiv: // converted into cPow y -1 + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).IsImmed() + && tree.GetParam(1).GetImmed() != Value_t(0.0)) + { tree.ReplaceWithImmed( tree.GetParam(0).GetImmed() / tree.GetParam(1).GetImmed() ); + goto do_return; } + break; + case cInv: // converted into cPow y -1 + if(tree.GetParam(0).IsImmed() + && tree.GetParam(0).GetImmed() != Value_t(0.0)) + { tree.ReplaceWithImmed( Value_t(1) / tree.GetParam(0).GetImmed() ); + goto do_return; } + // Note: Could use (mulgroup)^immed optimization from cPow + break; + case cSub: // converted into cMul y -1 + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).IsImmed()) + { tree.ReplaceWithImmed( tree.GetParam(0).GetImmed() - tree.GetParam(1).GetImmed() ); + goto do_return; } + break; + case cNeg: // converted into cMul x -1 + if(tree.GetParam(0).IsImmed()) + { tree.ReplaceWithImmed( -tree.GetParam(0).GetImmed() ); + goto do_return; } + break; + case cRad: // converted into cMul x CONSTANT_RD + if(tree.GetParam(0).IsImmed()) + { tree.ReplaceWithImmed( RadiansToDegrees( tree.GetParam(0).GetImmed() ) ); + goto do_return; } + break; + case cDeg: // converted into cMul x CONSTANT_DR + if(tree.GetParam(0).IsImmed()) + { tree.ReplaceWithImmed( DegreesToRadians( tree.GetParam(0).GetImmed() ) ); + goto do_return; } + break; + case cSqr: // converted into cMul x x + if(tree.GetParam(0).IsImmed()) + { tree.ReplaceWithImmed( tree.GetParam(0).GetImmed() * tree.GetParam(0).GetImmed() ); + goto do_return; } + break; + case cExp2: // converted into cPow 2.0 x + HANDLE_UNARY_CONST_FUNC(fp_exp2); break; + case cRSqrt: // converted into cPow x -0.5 + if(tree.GetParam(0).IsImmed()) + { tree.ReplaceWithImmed( Value_t(1) / fp_sqrt(tree.GetParam(0).GetImmed()) ); + goto do_return; } + break; + case cCot: // converted into cMul (cPow (cTan x) -1) + if(tree.GetParam(0).IsImmed()) + { Value_t tmp = fp_tan(tree.GetParam(0).GetImmed()); + if(fp_nequal(tmp, Value_t(0))) + { tree.ReplaceWithImmed( Value_t(1) / tmp ); + goto do_return; } } + break; + case cSec: // converted into cMul (cPow (cCos x) -1) + if(tree.GetParam(0).IsImmed()) + { Value_t tmp = fp_cos(tree.GetParam(0).GetImmed()); + if(fp_nequal(tmp, Value_t(0))) + { tree.ReplaceWithImmed( Value_t(1) / tmp ); + goto do_return; } } + break; + case cCsc: // converted into cMul (cPow (cSin x) -1) + if(tree.GetParam(0).IsImmed()) + { Value_t tmp = fp_sin(tree.GetParam(0).GetImmed()); + if(fp_nequal(tmp, Value_t(0))) + { tree.ReplaceWithImmed( Value_t(1) / tmp ); + goto do_return; } } + break; + case cHypot: // converted into cSqrt(cAdd(cMul(x x), cMul(y y))) + if(tree.GetParam(0).IsImmed() && tree.GetParam(1).IsImmed()) + { + tree.ReplaceWithImmed( fp_hypot(tree.GetParam(0).GetImmed(), + tree.GetParam(1).GetImmed()) ); + goto do_return; + } + break; + + /* Opcodes that do not occur in the tree for other reasons */ + case cRDiv: // version of cDiv + case cRSub: // version of cSub + case cDup: + case cFetch: + case cPopNMov: + case cSinCos: + case cSinhCosh: + case cNop: + case cJump: + break; /* Should never occur */ + + /* Opcodes that we can't do anything about */ + case cPCall: + case cFCall: + break; + } + do_return:; +#ifdef DEBUG_SUBSTITUTIONS + std::cout << "[" << (&stackptr) << "]Done ConstantFolding, result: "; + DumpTree(tree); + std::cout << "\n"; + DumpHashes(tree); +#endif + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template void ConstantFolding(CodeTree<type>& ); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/constantfolding.hh b/fpoptimizer/constantfolding.hh new file mode 100644 index 0000000..2027d83 --- /dev/null +++ b/fpoptimizer/constantfolding.hh @@ -0,0 +1,12 @@ +#ifndef FPOptimizer_ConstantFoldingHH +#define FPOptimizer_ConstantFoldingHH + +#include "codetree.hh" + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + void ConstantFolding(CodeTree<Value_t>& tree); +} + +#endif diff --git a/fpoptimizer/consts.hh b/fpoptimizer/consts.hh new file mode 100644 index 0000000..b6e8f88 --- /dev/null +++ b/fpoptimizer/consts.hh @@ -0,0 +1,52 @@ +#include "fparser.hh" +#include "extrasrc/fpaux.hh" + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +/* +#define CONSTANT_L10B 0.3010299956639811952137 // log10(2) +#define CONSTANT_L10BI 3.3219280948873623478703 // 1/log10(2) +#define CONSTANT_LB10 CONSTANT_L10BI // log2(10) +#define CONSTANT_LB10I CONSTANT_L10B // 1/log2(10) +*/ + +#define CONSTANT_POS_INF HUGE_VAL // positive infinity, from math.h +#define CONSTANT_NEG_INF (-HUGE_VAL) // negative infinity + +namespace FUNCTIONPARSERTYPES +{ + template<typename Value_t> + inline Value_t fp_const_pihalf() // CONSTANT_PIHALF + { + return fp_const_pi<Value_t>() * Value_t(0.5); + } + template<typename Value_t> + inline Value_t fp_const_twopi() // CONSTANT_TWOPI + { + Value_t result( fp_const_pi<Value_t>() ); + result += result; + return result; + } + template<typename Value_t> + inline Value_t fp_const_twoe() // CONSTANT_2E + { + Value_t result( fp_const_e<Value_t>() ); + result += result; + return result; + } + template<typename Value_t> + inline Value_t fp_const_twoeinv() // CONSTANT_2EI + { + Value_t result( fp_const_einv<Value_t>() ); + result += result; + return result; + } + + template<typename Value_t> + inline Value_t fp_const_negativezero() + { + return -Epsilon<Value_t>::value; + } +} diff --git a/fpoptimizer/cse.cc b/fpoptimizer/cse.cc new file mode 100644 index 0000000..6068b7d --- /dev/null +++ b/fpoptimizer/cse.cc @@ -0,0 +1,501 @@ +#include "bytecodesynth.hh" +#include "codetree.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +using namespace FUNCTIONPARSERTYPES; +//using namespace FPoptimizer_Grammar; + +//#define DEBUG_SUBSTITUTIONS_CSE + +namespace +{ + using namespace FPoptimizer_CodeTree; + + class TreeCountItem + { + size_t n_occurrences; + size_t n_as_cos_param; + size_t n_as_sin_param; + size_t n_as_tan_param; + size_t n_as_cosh_param; + size_t n_as_sinh_param; + size_t n_as_tanh_param; + public: + TreeCountItem() : + n_occurrences(0), + n_as_cos_param(0), + n_as_sin_param(0), + n_as_tan_param(0), + n_as_cosh_param(0), + n_as_sinh_param(0), + n_as_tanh_param(0) { } + + void AddFrom(OPCODE op) + { + n_occurrences += 1; + if(op == cCos) ++n_as_cos_param; + if(op == cSin) ++n_as_sin_param; + if(op == cSec) ++n_as_cos_param; + if(op == cCsc) ++n_as_sin_param; + if(op == cTan) ++n_as_tan_param; + if(op == cCot) ++n_as_tan_param; + if(op == cSinh) ++n_as_sinh_param; + if(op == cCosh) ++n_as_cosh_param; + if(op == cTanh) ++n_as_tanh_param; + } + + size_t GetCSEscore() const + { + //size_t n_sincos = std::min(n_as_cos_param, n_as_sin_param); + size_t result = n_occurrences;// - n_sincos; + return result; + } + + /* Calculate whether a sincos() would be useful. + * Return values: 0 = not useful + * 1,2 = yes + * 1 = the tree is always a sin/cos parameter, + * so once a sincos() is synthesized, the + * tree itself does not need to be synthesized + */ + int NeedsSinCos() const + { + bool always_sincostan = + (n_occurrences == (n_as_cos_param + n_as_sin_param + n_as_tan_param)); + if((n_as_tan_param && (n_as_sin_param || n_as_cos_param)) + || (n_as_sin_param && n_as_cos_param)) + { + if(always_sincostan) + return 1; + return 2; + } + return 0; + } + + /* Calculate whether a sinhcosh() would be useful. + */ + int NeedsSinhCosh() const + { + bool always_sincostan = + (n_occurrences == (n_as_cosh_param + n_as_sinh_param + n_as_tanh_param)); + if((n_as_tanh_param && (n_as_sinh_param || n_as_cosh_param)) + || (n_as_sinh_param && n_as_cosh_param)) + { + if(always_sincostan) + return 1; + return 2; + } + return 0; + } + + size_t MinimumDepth() const + { + size_t n_sincos = std::min(n_as_cos_param, n_as_sin_param); + size_t n_sinhcosh = std::min(n_as_cosh_param, n_as_sinh_param); + if(n_sincos == 0 && n_sinhcosh == 0) + return 2; + return 1; + } + }; + + template<typename Value_t> + class TreeCountType: + public std::multimap<fphash_t, std::pair<TreeCountItem, CodeTree<Value_t> > > + { + }; + + template<typename Value_t> + void FindTreeCounts( + TreeCountType<Value_t>& TreeCounts, + const CodeTree<Value_t>& tree, + OPCODE parent_opcode, + bool skip_root = false) + { + typename TreeCountType<Value_t>::iterator + i = TreeCounts.lower_bound(tree.GetHash()); + if(!skip_root) + { + bool found = false; + for(; i != TreeCounts.end() && i->first == tree.GetHash(); ++i) + { + if(tree.IsIdenticalTo( i->second.second ) ) + { + i->second.first.AddFrom(parent_opcode); + found = true; + break; + } + } + if(!found) + { + TreeCountItem count; + count.AddFrom(parent_opcode); + TreeCounts.insert(i, std::make_pair(tree.GetHash(), + std::make_pair(count, tree))); + } + } + for(size_t a=0; a<tree.GetParamCount(); ++a) + FindTreeCounts(TreeCounts, tree.GetParam(a), + tree.GetOpcode()); + } + + struct BalanceResultType + { + bool BalanceGood; + bool FoundChild; + }; + + template<typename Value_t> + BalanceResultType IfBalanceGood(const CodeTree<Value_t>& root, + const CodeTree<Value_t>& child) + { + if(root.IsIdenticalTo(child)) + { + BalanceResultType result = {true,true}; + return result; + } + + BalanceResultType result = {true,false}; + + if(root.GetOpcode() == cIf + || root.GetOpcode() == cAbsIf) + { + BalanceResultType cond = IfBalanceGood(root.GetParam(0), child); + BalanceResultType branch1 = IfBalanceGood(root.GetParam(1), child); + BalanceResultType branch2 = IfBalanceGood(root.GetParam(2), child); + + if(cond.FoundChild || branch1.FoundChild || branch2.FoundChild) + { result.FoundChild = true; } + + // balance is good if: + // branch1.found = branch2.found OR (cond.found AND cond.goodbalance) + // AND cond.goodbalance OR (branch1.found AND branch2.found) + // AND branch1.goodbalance OR (cond.found AND cond.goodbalance) + // AND branch2.goodbalance OR (cond.found AND cond.goodbalance) + + result.BalanceGood = + ( (branch1.FoundChild == branch2.FoundChild) + || (cond.FoundChild && cond.BalanceGood) ) + && (cond.BalanceGood || (branch1.FoundChild && branch2.FoundChild)) + && (branch1.BalanceGood || (cond.FoundChild && cond.BalanceGood)) + && (branch2.BalanceGood || (cond.FoundChild && cond.BalanceGood)); + } + else + { + bool has_bad_balance = false; + bool has_good_balance_found = false; + + // Balance is bad if one of the children has bad balance + // Unless one of the children has good balance & found + + for(size_t b=root.GetParamCount(), a=0; a<b; ++a) + { + BalanceResultType tmp = IfBalanceGood(root.GetParam(a), child); + if(tmp.FoundChild) + result.FoundChild = true; + + if(tmp.BalanceGood == false) + has_bad_balance = true; + else if(tmp.FoundChild) + has_good_balance_found = true; + + // if the expression is + // if(x, sin(x), 0) + sin(x) + // then sin(x) is a good subexpression + // even though it occurs in unbalance. + } + if(has_bad_balance && !has_good_balance_found) + result.BalanceGood = false; + } + return result; + } + + template<typename Value_t> + bool ContainsOtherCandidates( + const CodeTree<Value_t>& within, + const CodeTree<Value_t>& tree, + const FPoptimizer_ByteCode::ByteCodeSynth<Value_t>& synth, + const TreeCountType<Value_t>& TreeCounts) + { + for(size_t b=tree.GetParamCount(), a=0; a<b; ++a) + { + const CodeTree<Value_t>& leaf = tree.GetParam(a); + + typename TreeCountType<Value_t>::iterator synth_it; + for(typename TreeCountType<Value_t>::const_iterator + i = TreeCounts.begin(); + i != TreeCounts.end(); + ++i) + { + if(i->first != leaf.GetHash()) + continue; + + const TreeCountItem& occ = i->second.first; + size_t score = occ.GetCSEscore(); + const CodeTree<Value_t>& candidate = i->second.second; + + // It must not yet have been synthesized + if(synth.Find(candidate)) + continue; + + // And it must not be a simple expression + // Because cImmed, VarBegin are faster than cFetch + if(leaf.GetDepth() < occ.MinimumDepth()) + continue; + + // It must always occur at least twice + if(score < 2) + continue; + + // And it must either appear on both sides + // of a cIf, or neither + if(IfBalanceGood(within, leaf).BalanceGood == false) + continue; + + return true; + } + if(ContainsOtherCandidates(within, leaf, synth, TreeCounts)) + return true; + } + return false; + } + + template<typename Value_t> + bool IsDescendantOf(const CodeTree<Value_t>& parent, const CodeTree<Value_t>& expr) + { + for(size_t a=0; a<parent.GetParamCount(); ++a) + if(parent.GetParam(a).IsIdenticalTo(expr)) + return true; + + for(size_t a=0; a<parent.GetParamCount(); ++a) + if(IsDescendantOf(parent.GetParam(a), expr)) + return true; + + return false; + } + + template<typename Value_t> + bool GoodMomentForCSE(const CodeTree<Value_t>& parent, const CodeTree<Value_t>& expr) + { + if(parent.GetOpcode() == cIf) + return true; + + // Good if it's one of our direct children + // Bad if it is a descendant of only one of our children + + for(size_t a=0; a<parent.GetParamCount(); ++a) + if(parent.GetParam(a).IsIdenticalTo(expr)) + return true; + + size_t leaf_count = 0; + for(size_t a=0; a<parent.GetParamCount(); ++a) + if(IsDescendantOf(parent.GetParam(a), expr)) + ++leaf_count; + + return leaf_count != 1; + } + +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + size_t CodeTree<Value_t>::SynthCommonSubExpressions( + FPoptimizer_ByteCode::ByteCodeSynth<Value_t>& synth) const + { + if(GetParamCount() == 0) return 0; // No subexpressions to synthesize. + + size_t stacktop_before = synth.GetStackTop(); + + /* Find common subtrees */ + TreeCountType<Value_t> TreeCounts; + FindTreeCounts(TreeCounts, *this, GetOpcode(), true); + + /* Synthesize some of the most common ones */ + for(;;) + { + size_t best_score = 0; + #ifdef DEBUG_SUBSTITUTIONS_CSE + std::cout << "Finding a CSE candidate, root is:" << std::endl; + DumpHashes(*this); + #endif + typename TreeCountType<Value_t>::iterator cs_it ( TreeCounts.end() ); + for(typename TreeCountType<Value_t>::iterator + j = TreeCounts.begin(); + j != TreeCounts.end(); ) + { + typename TreeCountType<Value_t>::iterator i( j++ ); + + const TreeCountItem& occ = i->second.first; + size_t score = occ.GetCSEscore(); + const CodeTree<Value_t>& tree = i->second.second; + + #ifdef DEBUG_SUBSTITUTIONS_CSE + std::cout << "Score " << score << ":\n" << std::flush; + DumpTreeWithIndent(tree); + #endif + + // It must not yet have been synthesized + if(synth.Find(tree)) + { + TreeCounts.erase(i); + continue; + } + + // And it must not be a simple expression + // Because cImmed, VarBegin are faster than cFetch + if(tree.GetDepth() < occ.MinimumDepth()) + { + TreeCounts.erase(i); + continue; + } + + // It must always occur at least twice + if(score < 2) + { + TreeCounts.erase(i); + continue; + } + + // And it must either appear on both sides + // of a cIf, or neither + if(IfBalanceGood(*this, tree).BalanceGood == false) + { + TreeCounts.erase(i); + continue; + } + + // It must not contain other candidates + if(ContainsOtherCandidates(*this, tree, synth, TreeCounts)) + { + // Don't erase it; it may be a proper candidate later + continue; + } + + if(!GoodMomentForCSE(*this, tree)) + { + TreeCounts.erase(i); + continue; + } + + // Is a candidate. + score *= tree.GetDepth(); + if(score > best_score) + { best_score = score; cs_it = i; } + } + + if(best_score <= 0) + { + #ifdef DEBUG_SUBSTITUTIONS_CSE + std::cout << "No more CSE candidates.\n" << std::flush; + #endif + break; // Didn't find anything. + } + + //const TreeCountItem& occ = cs_it->second.first; + const CodeTree<Value_t>& tree = cs_it->second.second; + #ifdef DEBUG_SUBSTITUTIONS_CSE + std::cout << "Found Common Subexpression:"; DumpTree<Value_t>(tree); std::cout << std::endl; + #endif + #if 0 + int needs_sincos = occ.NeedsSinCos(); + int needs_sinhcosh = occ.NeedsSinhCosh(); + CodeTree<Value_t> sintree, costree, sinhtree, coshtree; + if(needs_sincos) + { + sintree.AddParam(tree); + sintree.SetOpcode(cSin); + sintree.Rehash(); + costree.AddParam(tree); + costree.SetOpcode(cCos); + costree.Rehash(); + if(synth.Find(sintree) || synth.Find(costree)) + { + if(needs_sincos == 2) + { + // sin, cos already found, and we don't + // actually need _this_ tree by itself + TreeCounts.erase(cs_it); + continue; + } + needs_sincos = 0; + } + } + if(needs_sinhcosh) + { + sinhtree.AddParam(tree); + sinhtree.SetOpcode(cSinh); + sinhtree.Rehash(); + coshtree.AddParam(tree); + coshtree.SetOpcode(cCosh); + coshtree.Rehash(); + if(synth.Find(sinhtree) || synth.Find(coshtree)) + { + if(needs_sinhcosh == 2) + { + // sinh, cosh already found, and we don't + // actually need _this_ tree by itself + TreeCounts.erase(cs_it); + continue; + } + needs_sinhcosh = 0; + } + } + #endif + + /* Synthesize the selected tree */ + tree.SynthesizeByteCode(synth, false); + TreeCounts.erase(cs_it); + #ifdef DEBUG_SUBSTITUTIONS_CSE + synth.template Dump<0> (); + std::cout << "Done with Common Subexpression:"; DumpTree<Value_t>(tree); std::cout << std::endl; + #endif + #if 0 + if(needs_sincos) + { + if(needs_sincos == 2 || needs_sinhcosh) + { + // make a duplicate of the value, since it + // is also needed in addition to the sin/cos. + synth.FindAndDup(tree); + } + synth.AddOperation(cSinCos, 1, 2); + + synth.StackTopIs(sintree, 1); + synth.StackTopIs(costree, 0); + } + if(needs_sinhcosh) + { + if(needs_sincos) synth.FindAndDup(tree); + if(needs_sinhcosh == 2) + { + // make a duplicate of the value, since it + // is also needed in addition to the sin/cos. + synth.FindAndDup(tree); + } + synth.AddOperation(cSinhCosh, 1, 2); + + synth.StackTopIs(sinhtree, 1); + synth.StackTopIs(coshtree, 0); + } + #endif + } + + return synth.GetStackTop() - stacktop_before; + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template \ + size_t CodeTree<type>::SynthCommonSubExpressions( \ + FPoptimizer_ByteCode::ByteCodeSynth<type>& synth) const; + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/debug.cc b/fpoptimizer/debug.cc new file mode 100644 index 0000000..7a87d36 --- /dev/null +++ b/fpoptimizer/debug.cc @@ -0,0 +1,153 @@ +#include "codetree.hh" +#include "opcodename.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include <sstream> +#include <string> +#include <map> +#include <set> +#include <iostream> + +using namespace FUNCTIONPARSERTYPES; + +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING +namespace +{ + template<typename Value_t> + void DumpHashesFrom( + const FPoptimizer_CodeTree::CodeTree<Value_t>& tree, + std::map<fphash_t, std::set<std::string> >& done, + std::ostream& o) + { + for(size_t a=0; a<tree.GetParamCount(); ++a) + DumpHashesFrom(tree.GetParam(a), done, o); + + std::ostringstream buf; + DumpTree(tree, buf); + done[tree.GetHash()].insert(buf.str()); + } +} +#endif + +namespace FPoptimizer_CodeTree +{ +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + template<typename Value_t> + void DumpHashes(const CodeTree<Value_t>& tree, std::ostream& o) + { + std::map<fphash_t, std::set<std::string> > done; + DumpHashesFrom(tree, done, o); + + for(std::map<fphash_t, std::set<std::string> >::const_iterator + i = done.begin(); + i != done.end(); + ++i) + { + const std::set<std::string>& flist = i->second; + if(flist.size() != 1) o << "ERROR - HASH COLLISION?\n"; + for(std::set<std::string>::const_iterator + j = flist.begin(); + j != flist.end(); + ++j) + { + o << '[' << std::hex << i->first.hash1 + << ',' << i->first.hash2 + << ']' << std::dec; + o << ": " << *j << "\n"; + } + } + } + + template<typename Value_t> + void DumpTree(const CodeTree<Value_t>& tree, std::ostream& o) + { + //o << "/*" << tree.Depth << "*/"; + const char* sep2 = " "; + /* + o << '[' << std::hex << tree.Hash.hash1 + << ',' << tree.Hash.hash2 + << ']' << std::dec; + */ + switch(tree.GetOpcode()) + { + case cImmed: + o << tree.GetImmed(); + /* + o << "(" << std::hex + << *(const uint_least64_t*)&tree.GetImmed() + << std::dec << ")"; + */ + return; + case VarBegin: o << "Var" << (tree.GetVar() - VarBegin); return; + case cAdd: sep2 = " +"; break; + case cMul: sep2 = " *"; break; + case cAnd: sep2 = " &"; break; + case cOr: sep2 = " |"; break; + case cPow: sep2 = " ^"; break; + default: + sep2 = " "; + o << FP_GetOpcodeName(tree.GetOpcode()); + if(tree.GetOpcode() == cFCall || tree.GetOpcode() == cPCall) + o << ':' << tree.GetFuncNo(); + } + o << '('; + if(tree.GetParamCount() <= 1 && sep2[1]) o << (sep2+1) << ' '; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + if(a > 0) o << ' '; + + DumpTree(tree.GetParam(a), o); + + if(a+1 < tree.GetParamCount()) o << sep2; + } + o << ')'; + } + + template<typename Value_t> + void DumpTreeWithIndent(const CodeTree<Value_t>& tree, std::ostream& o, const std::string& indent) + { + o << '[' << std::hex << (void*)(&tree.GetParams()) + << std::dec + << ',' << tree.GetRefCount() + << ']'; + o << indent << '_'; + + switch(tree.GetOpcode()) + { + case cImmed: o << "cImmed " << tree.GetImmed(); o << '\n'; return; + case VarBegin: o << "VarBegin " << (tree.GetVar() - VarBegin); o << '\n'; return; + default: + o << FP_GetOpcodeName(tree.GetOpcode()); + if(tree.GetOpcode() == cFCall || tree.GetOpcode() == cPCall) + o << ':' << tree.GetFuncNo(); + o << '\n'; + } + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + std::string ind = indent; + for(size_t p=0; p < ind.size(); p+=2) + if(ind[p] == '\\') + ind[p] = ' '; + ind += (a+1 < tree.GetParamCount()) ? " |" : " \\"; + DumpTreeWithIndent(tree.GetParam(a), o, ind); + } + o << std::flush; + } +#endif +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template void DumpHashes(const CodeTree<type>& tree, std::ostream& o); \ + template void DumpTree(const CodeTree<type>& tree, std::ostream& o); \ + template void DumpTreeWithIndent(const CodeTree<type>& tree, std::ostream& o, const std::string& indent); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/explicit_instantations.txt b/fpoptimizer/explicit_instantations.txt new file mode 100644 index 0000000..e532d0f --- /dev/null +++ b/fpoptimizer/explicit_instantations.txt @@ -0,0 +1,37 @@ +Functions / Classes needing explicit instantations, per module: + +codetree: CodeTree<> + +readbytecode: CodeTree::GenerateFrom() + +makebytecode: CodeTree::SynthesizeByteCode() + +cse: CodeTree::SynthCommonSubExpressions() + +transformations: CodeTree::RecreateInversionsAndNegations() + +hash: CodeTree::Rehash() + CodeTree::FixIncompleteHashes() + CodeTreeData::Recalculate_Hash_NoRecursion() + -- ^needed because of linker bug + +optimize: ApplyGrammars() +optimize_debug: DumpMatch() +optimize_match: TestParams() +optimize_synth: SynthesizeRule() + +rangeestimation: CalculateResultBoundaries() + +constantfolding: ConstantFolding() + +bytecodesynth: SequenceOpcodes[] + AssembleSequence() + +debug: DumpHashes() + DumpTree() + DumpTreeWithIndent() + +grammar: DumpParams() + ParamSpec_Compare() + +grammar_data: ParamSpec_Extract() - NOTE: FROM .y FILE diff --git a/fpoptimizer/fpoptimizer.txt b/fpoptimizer/fpoptimizer.txt new file mode 100644 index 0000000..35bb70b --- /dev/null +++ b/fpoptimizer/fpoptimizer.txt @@ -0,0 +1,357 @@ +FILES: + fpoptimizer.hh - C++ structures + fpoptimizer.dat - Optimization operations + +PLAN: +1. Convert fpoptimizer.dat into code that initializes Grammar + - either automatically or manually + - avoid runtime parsing of .dat file + - prefer static const structs over constructor code + *DONE: See fpoptimizer_grammar_gen.y . + Produces fpoptimizer_grammar.cc . + +2. Augment the CodeTree mechanism the following ways: + - Add mechanism that generates a hash value for the contents + of the tree, for easy comparison of identical subtrees + *DONE + - Any time a CodeTree changes in any way that may affect the + hash, update the hash value for this node and recursively + to all parents + (Note: Ensure that a CodeTree may only have one parent.) + +2. Create code that matches a given CodeTree node to Grammar, + and finds the rules that match (only one should match at most, + but it can match a number of different ways, but that does not + matter; only utilize the first way) + - If a matching rule is found, replace either the matched params + or the entire node as instructed in the rule. Ensure that the + node gets its hash updated, along with its parents recursively. + - The matching can be optimized by grouping the rules by the Opcode + Note: The matching can get really complex and/or heavy in the + cases where the same operand (or worse, the same set of operands) + is expected to be found in two different subtrees. It may require + some O(n!) algorithms. However, those rules can be safely skipped + if the runtime sees that it would be too costly to check them. + +3. Algorithm for matching trees: + First, + match all nodes in the entire tree. (Do this only once.) + Any time a hash of a node is updated, + match that node. + (When the hashes are changed recursively for a node and all + its parents, match all those affected nodes after the hashes + have been regenerated.) + Repeat until no substitutions are done. + + Overall, first apply this algorithm using the [ENTRY] rules only. + Then, apply the rules with [INTERMEDIATE] rules only. + Finally, apply the rules with [FINAL] rules only. + +3.5. Algorithm for matching nodes: + TODO + +4a. Algorithm for handling bytecode: + First, convert the bytecode into a CodeTree. + Then run the matching algorithm. + Last, convert the produced CodeTree back into bytecode. + + When generating the bytecode, additional optimizations can be performed: + - Converting raise-to-integer-powers into sequences of cInv/cDup/cFetch/cMul + using the powi algorithm already existing in fpoptimizer.cc + (be wary of generating too long sequences, though) + *DONE + - Converting multiply-by-integers into sequences of cNeg/cDup/cFetch/cAdd + using the powi algorithm already existing in fpoptimizer.cc + (be wary of generating too long sequences, though) + *DONE + - Reordering cMul operands such that inverted operands + don't come first, to avoid creating cInv unless necessary. + When inverted operands come in non-head positions, use cDiv instead of cMul. + *DONE + - Reordering cAdd operands such that negated operands + don't come first, to avoid creating cNeg unless necessary. + When negated operands come in non-head positions, use cSub instead of cAdd. + *DONE + - When an identical subtree is synthesized into bytecode more than + once in a row, use cDup for the subsequential occurrences. + To that point, reorder any commutative operands so as to + increase the chances of cDup being utilized. + *TODO + +4b. Optional algorithm if an SSA evaluator is supported + (possibly only if a JIT backend exists): + 1. First, convert the bytecode into a CodeTree. + 2. Then run the matching algorithm. + 3. Then convert the produced CodeTree into SSA format. + SSA is a medium-level intermediate language (chapter 4.3 in [1], [2]), + in which each instruction takes one of the following forms: + target = command source1 source2 <...> + - commands such as add, mul, pow, cos, max, less + jump <label> + branch <label> if source == 0 + target = phi source1 source2 + - phi is used after two branches merge, to select + either result from the branches into one variable; + it is not a fparser function. + and in which every variable is written to only once, + i.e. "x = x+5" never occurs, but is instead written + as "x2 = x1+5" + <label> can be a pointer to another codeblock. + 4. Then run generic optimizations on the SSA code, such + as common subexpression elimination (CSE, described + in chapter 13.1 in [1]). + Try also global value numbering (GVN, see [3]). + Note: After CSE, it's difficult to convert + the code back into bytecode. + Note: Due to the hashing, it is possible that some + of the CSE can be done automatically in the SSA + generation phase by peeling the CodeTree depth-first, + storing identical trees only once. + 5a. (Apply this option if we do not have JIT.) + Eliminate the "single assignment" property of SSA + by mapping out the lifetimes of the variables and + reusing the same variables where possible. This + decreases the memory usage of the evaluator and + improves the cache efficiency. + 5b. (Apply this option if we do have JIT.) + Perform register allocation for the SSA code, + as per chapter 16 in [1]. Doing this before + actual JIT will make the JIT more straightforward. + Doing code scheduling could be useful as well, + though it gets somewhat complex. (Chapter 17 in [1].) + If there's a library we can use from step 3 forward, it'd be great. + Note: There are many typical optimizations that we don't need to do. + For instance, we don't need to do "dead code elimination", because + dead code is never produced in the first place. + +[1] = Advanced Compiler Design & Implementation by Steven S. Muchnick, ISBN 1-55860-320-4 +[2] = http://en.wikipedia.org/wiki/Static_single_assignment_form +[3] = http://en.wikipedia.org/wiki/Global_value_numbering + + + + +---------------------------------------- +------------------------------------------------------ +CODETREE - A REPRESENTATION OF MATHEMATICAL EXPRESSION +------------------------------------------------------ +FPoptimizer changes the bytecode expression into tree format. + +An FPoptimizer expression is called a CodeTree. + +A CodeTree node has: + - 0 to N children + - Type (Opcode) + - Type-dependent other fields + Different type of nodes: + cVar: + Has a type-dependent field "Var", which + identifies the var number + cImmed: + Has a type-dependent field "Value", which + describes the constant value of this node + cFCall and cPCall: + Has a type-dependent field "FuncNo", which + describes the function number called + Anything else: + Has a number of children which describe + the parameters to the operation. + For example, if the type (Opcode) is cSin, + it has a single child, which is a CodeTree + that describes the parameter of the sin() call. + If the type (Opcode) is cAdd, it has an arbitrary + number of children, which are all added together. + Examples of some expressions in tree format: + Expression: sin(x)*cos(y) + Tree: Opcode=cMul + Child[0]: + Opcode=cSin + Child[0]: + Opcode=cVar + Var=0 + Child[1]: + Opcode=cCos + Child[0]: + Opcode=cVar + Var=1 + Expression: 1.0 + 2.0 - 3.0 - (4.0 + -5.5) + Actual expression (converted by bytecode reader): + 1.0 + 2.0 + (-1 * 3.0) + (-1 * (4.0 + -5.5)) + Tree: Opcode=cAdd + Child[0]: + Opcode=cImmed + Value=1.0 + Child[1]: + Opcode=cImmed + Value=2.0 + Child[2]: + Opcode=cMul + Child[0]: + Opcode=cImmed + Value=-1.0 + Child[1]: + Opcode=cImmed + Value=3.0 + Child[3]: + Opcode=cMul + Child[0]: + Opcode=cImmed + Value=-1.0 + Child[1]: + Opcode=cAdd + Child[0]: + Opcode=cImmed + Value=4.0 + Child[1]: + Opcode=cImmed + Value=-5.5 + +------------------------------------------------------ +GRAMMAR RULE - A TREE SUBSTITUTION RULE DESCRIPTION +------------------------------------------------------ +The Grammar describes changes (optimizations) that +can be performed to the CodeTree. + +The Grammar is composed of Rules, each of which describes +a matching-tree, and a replacement. + +A matching-tree node (ParamSpec) has: + ------- + - Opcode + - Method of parameter matching + - 0 to N params (ParamSpec) + Different types of methods: + PositionalParams: + Indicates that the tree given must match + the params given, in exactly that order; + there may not be other children in the tree. + SelectedParams: + Indicates that the tree given must match + the params given, in any order; + there may not be other children in the tree. + AnyParams: + Indicates that the tree given must match + the params given; in any order; + the tree may additionally have other children, + too. If the parameter list contains a RestHolder, + those other children are captured there. + +List of parameters (an index to MatchedParams) + - Single parent + - Type (opcode) + - 0 to N children + - Type-dependent other fields + Different types of nodes: + NumConstant: + Indicates that a CodeTree + with type=cImmed and + a particular Value is matched. + The value is found in pack.clist[node.index]. + ImmedHolder: + Indicates that a CodeTree + with type=cImmed and + some Value is matched. + The ImmedHolder fields are enumerated + such that in a single CodeTree matching + operation, all ImmedHolders having the + same index value must match CodeTrees + evaluating to the same numeric value. + For example, if an ImmedHolder with index=0 + happens to match a CodeTree with Value=1.443, + all other ImmedHolders with index=0 must + also match a CodeTree with Value=1.443. + NamedHolder + Indicates that any CodeTree is matched regardless of type. + The NamedHolder fields are enumerated + such that in a single CodeTree matching + operation, all NamedHolders having the + same index value must match CodeTrees + that are identical to the first one. + For example, if an NamedHolder with index=0 + happens to match a CodeTree representing + the expression sin(x), + all other NamedHolders with index=0 must + also match a CodeTree representing + the expression sin(x). + SubFunction + Indicates a subtree that must be matched. + RestHolder + Within the target CodeTree, matches anything not + matched by the other rules in the parent ParamSpec. + Anything else: + Indicates a mathematical expression whose + value is treated by the NumConstant rules above. + +Example rules: + Grammar file syntax: cMin x x + Internal structure: Function.opcode = cMin + Function.index refers to MatchedParams where + MatchedParams.type = AnyParams + MatchedParams.count = 2 + MatchedParams.index refers to ParamSpec where + ParamSpec[0].opcode = NamedHolder + ParamSpec[0].index = 0 -- "x" is namedholder 0 + ParamSpec[1].opcode = NamedHolder + ParamSpec[1].index = 0 -- another x + Explanation: + This rule matches a CodeTree + where the opcode = cMin and that + tree has two identical subtrees. + + Grammar file syntax: cMul x <1> (cPow [(cMul x <2>) -1]) + Internal structure: Function.opcode = cMul + Function.index refers to MatchedParams where + MatchedParams.type = AnyParams + MatchedParams.count = 3 + MatchedParams.index refers to ParamSpec where + ParamSpec[0].opcode = NamedHolder + ParamSpec[0].index = 0 -- "x" is namedholder 0 + ParamSpec[1].opcode = RestHolder + ParamSpec[1].index = 1 -- RestHolder #1 captures anything else within that cMul group + ParamSpec[2].opcode = SubFunction + ParamSpec[2].index refers to Function where + Function.opcode = cPow + Function.index refers to MatchedParams where + MatchedParams.type = PositionalParams + MatchedParams.count = 2 + MatchedParams.index refers to ParamSpec where + ParamSpec[0].opcode = SubFunction + ParamSpec[0].index refers to Function where + Function.opcode = cMul + Function.index refers to MatchedParams where + MatchedParams.type = AnyParams + MatchedParams.count = 2 + MatchedParams.index refers to ParamSpec where + ParamSpec[0].opcode = NamedHolder + ParamSpec[0].index = 0 -- must match a subtree identical to that of "x" earlier + ParamSpec[1].opcode = RestHolder + ParamSpec[1].index = 2 -- RestHolder #2 captures anything else within that cMul group + ParamSpec[1].opcode = NumConstant + ParamSpec[1].value = -1 + Explanation: + This rule matches a CodeTree of type cMul, + where there exists at least two children, + where one of them is an arbitrary expression, + call that "x", + and one of them is a CodeTree of type cPow, + where there are exactly two children, + where the first child is a CodeTree of type cMul, + where there exists at least one child, + where that one child is an arbitrary expression, + which must match the "x" captured earlier, + and anything else from that inner cMul codetree + is captured into restholder <2>; + and the second child of the cPow codetree + is a CodeTree of type cImmed, where its Value equals -1; + and anything else from that outer cMul codetree + is captured into restholder <1>. + This rule matches expressions such as: + sin(z)*5*( (sin(z)*7) ^ (-1)) + sin(z) is captured into NamedHolder x + 5 is captured into RestHolder <1> + 7 is captured into RestHolder <2> + Or + 6*((6*w)^(-1)) + value 6 is captured into NamedHolder x + nothing is captured into RestHolder <1> + w is captured into RestHolder <2>. diff --git a/fpoptimizer/fpoptimizer_footer.txt b/fpoptimizer/fpoptimizer_footer.txt new file mode 100644 index 0000000..ddd5dae --- /dev/null +++ b/fpoptimizer/fpoptimizer_footer.txt @@ -0,0 +1,2 @@ + +#endif diff --git a/fpoptimizer/fpoptimizer_header.txt b/fpoptimizer/fpoptimizer_header.txt new file mode 100644 index 0000000..d1e7227 --- /dev/null +++ b/fpoptimizer/fpoptimizer_header.txt @@ -0,0 +1,24 @@ +/***************************************************************************\ +|* Function Parser for C++ v4.5.2 *| +|*-------------------------------------------------------------------------*| +|* Function optimizer *| +|*-------------------------------------------------------------------------*| +|* Copyright: Joel Yliluoma *| +|* *| +|* This library is distributed under the terms of the *| +|* GNU Lesser General Public License version 3. *| +|* (See lgpl.txt and gpl.txt for the license text.) *| +\***************************************************************************/ + +/* NOTE: + This file contains generated code (from the optimizer sources) and is + not intended to be modified by hand. If you want to modify the optimizer, + download the development version of the library. +*/ + +#include "fpconfig.hh" +#ifdef FP_SUPPORT_OPTIMIZER +#include "fparser.hh" +#include "extrasrc/fptypes.hh" +#include "extrasrc/fpaux.hh" +#pragma GCC diagnostic ignored "-Wunused-variable" diff --git a/fpoptimizer/grammar.cc b/fpoptimizer/grammar.cc new file mode 100644 index 0000000..86c5ab3 --- /dev/null +++ b/fpoptimizer/grammar.cc @@ -0,0 +1,154 @@ +#include "fparser.hh" +#include "extrasrc/fptypes.hh" +#include "grammar.hh" +#include "optimize.hh" + +#include "opcodename.hh" +using namespace FPoptimizer_Grammar; +using namespace FUNCTIONPARSERTYPES; + +#include <cctype> + +namespace FPoptimizer_Grammar +{ + unsigned ParamSpec_GetDepCode(const ParamSpec& b) + { + switch(b.first) + { + case ParamHolder: + { + const ParamSpec_ParamHolder* s = (const ParamSpec_ParamHolder*) b.second; + return s->depcode; + } + case SubFunction: + { + const ParamSpec_SubFunction* s = (const ParamSpec_SubFunction*) b.second; + return s->depcode; + } + default: break; + } + return 0; + } + + template<typename Value_t> + void DumpParam(const ParamSpec& parampair, std::ostream& o) + { + static const char ParamHolderNames[][2] = {"%","&", "x","y","z","a","b","c"}; + + //o << "/*p" << (&p-pack.plist) << "*/"; + unsigned constraints = 0; + switch(parampair.first) + { + case NumConstant: + { const ParamSpec_NumConstant<Value_t>& param = *(const ParamSpec_NumConstant<Value_t>*) parampair.second; + using namespace FUNCTIONPARSERTYPES; + o.precision(12); + o << param.constvalue; break; } + case ParamHolder: + { const ParamSpec_ParamHolder& param = *(const ParamSpec_ParamHolder*) parampair.second; + o << ParamHolderNames[param.index]; + constraints = param.constraints; + break; } + case SubFunction: + { const ParamSpec_SubFunction& param = *(const ParamSpec_SubFunction*) parampair.second; + constraints = param.constraints; + if(param.data.match_type == GroupFunction) + { + if(param.data.subfunc_opcode == cNeg) + { o << "-"; DumpParams<Value_t>(param.data.param_list, param.data.param_count, o); } + else if(param.data.subfunc_opcode == cInv) + { o << "/"; DumpParams<Value_t>(param.data.param_list, param.data.param_count, o); } + else + { + std::string opcode = FP_GetOpcodeName + ( (FUNCTIONPARSERTYPES::OPCODE) param.data.subfunc_opcode) + .substr(1); + for(size_t a=0; a<opcode.size(); ++a) opcode[a] = (char) std::toupper(opcode[a]); + o << opcode << "( "; + DumpParams<Value_t>(param.data.param_list, param.data.param_count, o); + o << " )"; + } + } + else + { + o << '(' << FP_GetOpcodeName + ( (FUNCTIONPARSERTYPES::OPCODE) param.data.subfunc_opcode) + << ' '; + if(param.data.match_type == PositionalParams) o << '['; + if(param.data.match_type == SelectedParams) o << '{'; + DumpParams<Value_t>(param.data.param_list, param.data.param_count, o); + if(param.data.restholder_index != 0) + o << " <" << param.data.restholder_index << '>'; + if(param.data.match_type == PositionalParams) o << "]"; + if(param.data.match_type == SelectedParams) o << "}"; + o << ')'; + } + break; } + } + switch( ImmedConstraint_Value(constraints & ValueMask) ) + { + case ValueMask: break; + case Value_AnyNum: break; + case Value_EvenInt: o << "@E"; break; + case Value_OddInt: o << "@O"; break; + case Value_IsInteger: o << "@I"; break; + case Value_NonInteger:o << "@F"; break; + case Value_Logical: o << "@L"; break; + } + switch( ImmedConstraint_Sign(constraints & SignMask) ) + { + case SignMask: break; + case Sign_AnySign: break; + case Sign_Positive: o << "@P"; break; + case Sign_Negative: o << "@N"; break; + } + switch( ImmedConstraint_Oneness(constraints & OnenessMask) ) + { + case OnenessMask: break; + case Oneness_Any: break; + case Oneness_One: o << "@1"; break; + case Oneness_NotOne: o << "@M"; break; + } + switch( ImmedConstraint_Constness(constraints & ConstnessMask) ) + { + case ConstnessMask: break; + case Constness_Const: + if(parampair.first == ParamHolder) + { + const ParamSpec_ParamHolder& param = *(const ParamSpec_ParamHolder*) parampair.second; + if(param.index < 2) break; + } + o << "@C"; + break; + case Constness_NotConst: o << "@V"; break; + case Oneness_Any: break; + } + } + + template<typename Value_t> + void DumpParams(unsigned paramlist, unsigned count, std::ostream& o) + { + for(unsigned a=0; a<count; ++a) + { + if(a > 0) o << ' '; + const ParamSpec& param = ParamSpec_Extract<Value_t> (paramlist,a); + DumpParam<Value_t> (param, o); + unsigned depcode = ParamSpec_GetDepCode(param); + if(depcode != 0) + o << "@D" << depcode; + } + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +#include <complex> +namespace FPoptimizer_Grammar +{ +#define FP_INSTANTIATE(type) \ + template void DumpParams<type>(unsigned, unsigned, std::ostream& ); \ + template void DumpParam<type>(const ParamSpec&, std::ostream& ); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ diff --git a/fpoptimizer/grammar.hh b/fpoptimizer/grammar.hh new file mode 100644 index 0000000..8c1e1ea --- /dev/null +++ b/fpoptimizer/grammar.hh @@ -0,0 +1,254 @@ +#ifndef FPOptimizer_GrammarHH +#define FPOptimizer_GrammarHH + +#include <iostream> + +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + class CodeTree; +} + +namespace FPoptimizer_Grammar +{ + enum ImmedConstraint_Value + { + ValueMask = 0x07, + Value_AnyNum = 0x0, // any value + Value_EvenInt = 0x1, // any even integer (0,2,4, etc) + Value_OddInt = 0x2, // any odd integer (1,3, etc) + Value_IsInteger = 0x3, // any integer-value (excludes e.g. 0.2) + Value_NonInteger = 0x4, // any non-integer (excludes e.g. 1 or 5) + Value_Logical = 0x5 // a result of cNot,cNotNot,cAnd,cOr or comparators + }; + enum ImmedConstraint_Sign + { + SignMask = 0x18, + Sign_AnySign = 0x00, // - or + + Sign_Positive = 0x08, // positive only + Sign_Negative = 0x10, // negative only + Sign_NoIdea = 0x18 // where sign cannot be guessed + }; + enum ImmedConstraint_Oneness + { + OnenessMask = 0x60, + Oneness_Any = 0x00, + Oneness_One = 0x20, // +1 or -1 + Oneness_NotOne = 0x40 // anything but +1 or -1 + }; + enum ImmedConstraint_Constness + { + ConstnessMask = 0x180, + Constness_Any = 0x00, + Constness_Const = 0x80, + Constness_NotConst=0x100 + }; + enum Modulo_Mode + { + Modulo_None = 0, + Modulo_Radians = 1 + }; + enum Situation_Flags + { + LogicalContextOnly = 0x01, + NotForIntegers = 0x02, + OnlyForIntegers = 0x04, + OnlyForComplex = 0x08, + NotForComplex = 0x10 + }; + + /* The param_opcode field of the ParamSpec has the following + * possible values (from enum SpecialOpcode): + * NumConstant: + * this describes a specific constant value (constvalue) + * that must be matched / synthesized. + * ParamHolder: + * this describes any node + * that must be matched / synthesized. + * "index" is the ID of the NamedHolder: + * In matching, all NamedHolders having the same ID + * must match the identical node. + * In synthesizing, the node matched by + * a NamedHolder with this ID must be synthesized. + * SubFunction: + * this describes a subtree + * that must be matched / synthesized. + * The subtree is described in subfunc_opcode,param_begin..+param_count. + * If the type is GroupFunction, the tree is expected + * to yield a constant value which is tested. + */ + enum SpecialOpcode + { + NumConstant, // Holds a particular value (syntax-time constant) + ParamHolder, // Holds a particular named param + SubFunction // Holds an opcode and the params + }; + + enum ParamMatchingType + { + PositionalParams, // this set of params in this order + SelectedParams, // this set of params in any order + AnyParams, // these params are included + GroupFunction // this function represents a constant value + }; + + enum RuleType + { + ProduceNewTree, // replace self with the first (and only) from replaced_param + ReplaceParams // replace indicate params with replaced_params + }; + +#ifdef __GNUC__ +# define PACKED_GRAMMAR_ATTRIBUTE __attribute__((packed)) +#else +# define PACKED_GRAMMAR_ATTRIBUTE +#endif + + /* A ParamSpec object describes + * either a parameter (leaf, node) that must be matched, + * or a parameter (leaf, node) that must be synthesized. + */ + typedef std::pair<SpecialOpcode, const void*> ParamSpec; + + template<typename Value_t> + ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index); + + template<typename Value_t> + bool ParamSpec_Compare(const void* a, const void* b, SpecialOpcode type); + + unsigned ParamSpec_GetDepCode(const ParamSpec& b); + + struct ParamSpec_ParamHolder + { + unsigned index : 8; // holder ID + unsigned constraints : 9; // constraints + unsigned depcode :15; + } PACKED_GRAMMAR_ATTRIBUTE; + + template<typename Value_t> + struct ParamSpec_NumConstant + { + Value_t constvalue; // the value + unsigned modulo; // modulo mode + };// PACKED_GRAMMAR_ATTRIBUTE; + + struct ParamSpec_SubFunctionData + { + /* Expected parameters (leaves) of the tree: */ + unsigned param_count : 2; + unsigned param_list : 30; + /* The opcode that the tree must have when SubFunction */ + FUNCTIONPARSERTYPES::OPCODE subfunc_opcode : 8; + + /* When matching, type describes the method of matching. + * + * Sample input tree: (cOr 2 3) (cOr 2 4) (cOr 3 2) (cOr 4 2 3) (cOr 2) + * Possible methods: + * PositionalParams, e.g. (cOr [2 3]): match no match no match no match no match + * The nodes described here are + * to be matched, in this order. + * SelectedParams, e.g. (cOr {2 3}): match no match match no match no match + * The nodes described here are + * to be matched, in any order. + * AnyParams, e.g. (cOr 2 3 ): match no match match match no match + * At least the nodes described here + * are to be matched, in any order. + * When synthesizing, the type is ignored. + */ + ParamMatchingType match_type : 3; /* When SubFunction */ + /* Note: match_type needs 2, but we specify 3 because + * otherwise Microsoft VC++ borks things up + * as it interprets the value as signed. + */ + /* Optional restholder index for capturing the rest of parameters (0=not used) + * Only valid when match_type = AnyParams + */ + unsigned restholder_index : 5; + } PACKED_GRAMMAR_ATTRIBUTE; // size: 2+30+6+2+8=48 bits=6 bytes + + struct ParamSpec_SubFunction + { + ParamSpec_SubFunctionData data; + unsigned constraints : 9; // constraints + unsigned depcode : 7; + } PACKED_GRAMMAR_ATTRIBUTE; // 8 bytes + + /* Theoretical minimal sizes in each param_opcode cases: + * Assume param_opcode needs 3 bits. + * NumConstant: 3 + 64 (or 3+4 if just use index to clist[]) + * ParamHolder: 3 + 7 + 2 (7 for constraints, 2 for immed index) + * SubFunction: 3 + 7 + 2 + 2 + 3*9 = 41 + */ + + /* A rule describes a pattern for matching + * and the method how to reconstruct the + * matched node(s) in the tree. + */ + struct Rule + { + /* If the rule matched, this field describes how to perform + * the replacement. + * When type==ProduceNewTree, + * the source tree is replaced entirely with + * the new tree described at repl_param_begin[0]. + * When type==ReplaceParams, + * the matching leaves in the source tree are removed + * and new leaves are constructedfrom the trees + * described at repl_param_begin[0..repl_param_count]. + * Other leaves remain intact. + */ + RuleType ruletype : 2; + unsigned situation_flags : 5; + + /* The replacement parameters (if NewTree, begin[0] represents the new tree) */ + unsigned repl_param_count : 2+9; /* Assumed to be 1 when type == ProduceNewTree */ + unsigned repl_param_list : 30; + + /* The function that we must match. Always a SubFunction. */ + ParamSpec_SubFunctionData match_tree; + } PACKED_GRAMMAR_ATTRIBUTE; // size: 2+1+13+2+30 + 48 = 96 bits = 12 bytes + + /* Grammar is a set of rules for tree substitutions. */ + struct Grammar + { + /* The rules of this grammar */ + unsigned rule_count; + unsigned short rule_list[999]; // maximum limit... + /* Note: Changing the limit has no effect to performance of + * fparser. The limit is only actually used within grammar_parser. + * A too low limit causes a memory corruption during the parse. + * A too high limit just may cause inconvenience. + * The actual grammar items linked to fparser are optimized for size, + * and the size of the Grammar object may be considerably smaller + * than what is indicated by this prototype. + */ + }; + + extern "C" { + extern const Rule grammar_rules[]; + /* BEGIN_EXPLICIT_INSTANTATIONS */ + extern const Grammar grammar_optimize_round1; + extern const Grammar grammar_optimize_round2; + extern const Grammar grammar_optimize_round3; + extern const Grammar grammar_optimize_round4; + extern const Grammar grammar_optimize_recreate; + extern const Grammar grammar_optimize_shortcut_logical_evaluation; + extern const Grammar grammar_optimize_nonshortcut_logical_evaluation; + extern const Grammar grammar_optimize_ignore_if_sideeffects; + extern const Grammar grammar_optimize_abslogical; + extern const Grammar grammar_optimize_base2_expand; + /* END_EXPLICIT_INSTANTATIONS */ + } + + template<typename Value_t> + void DumpParam(const ParamSpec& p, std::ostream& o = std::cout); + + template<typename Value_t> + void DumpParams(unsigned paramlist, unsigned count, std::ostream& o = std::cout); +} + +#endif diff --git a/fpoptimizer/grammar_data.cc b/fpoptimizer/grammar_data.cc new file mode 100644 index 0000000..cc10dea --- /dev/null +++ b/fpoptimizer/grammar_data.cc @@ -0,0 +1,1597 @@ +/* This file is automatically generated. Do not edit... */ +#include "../fpoptimizer/consts.hh" +#include "fpconfig.hh" +#include "extrasrc/fptypes.hh" +#include <algorithm> + +/* BEGIN_EXPLICIT_INSTANTATIONS */ +#define grammar_optimize_abslogical grammar_optimize_abslogical_tweak +#define grammar_optimize_ignore_if_sideeffects grammar_optimize_ignore_if_sideeffects_tweak +#define grammar_optimize_nonshortcut_logical_evaluation grammar_optimize_nonshortcut_logical_evaluation_tweak +#define grammar_optimize_recreate grammar_optimize_recreate_tweak +#define grammar_optimize_round1 grammar_optimize_round1_tweak +#define grammar_optimize_round2 grammar_optimize_round2_tweak +#define grammar_optimize_round3 grammar_optimize_round3_tweak +#define grammar_optimize_round4 grammar_optimize_round4_tweak +#define grammar_optimize_shortcut_logical_evaluation grammar_optimize_shortcut_logical_evaluation_tweak +#include "../fpoptimizer/grammar.hh" +#undef grammar_optimize_abslogical +#undef grammar_optimize_ignore_if_sideeffects +#undef grammar_optimize_nonshortcut_logical_evaluation +#undef grammar_optimize_recreate +#undef grammar_optimize_round1 +#undef grammar_optimize_round2 +#undef grammar_optimize_round3 +#undef grammar_optimize_round4 +#undef grammar_optimize_shortcut_logical_evaluation +/* END_EXPLICIT_INSTANTATIONS */ + +using namespace FPoptimizer_Grammar; +using namespace FUNCTIONPARSERTYPES; + +namespace +{ + const ParamSpec_ParamHolder plist_p[37] = + { + /* 0 */ {2, 0, 0x0}, /* x */ + /* 1 */ {2, 0, 0x4}, /* x */ + /* 2 */ {2, Sign_Positive, 0x0}, /* x@P */ + /* 3 */ {2, Sign_Negative | Constness_NotConst, 0x0}, /* x@N@V */ + /* 4 */ {2, Sign_NoIdea, 0x0}, /* x */ + /* 5 */ {2, Value_Logical, 0x0}, /* x@L */ + /* 6 */ {3, Sign_NoIdea, 0x0}, /* y */ + /* 7 */ {3, 0, 0x0}, /* y */ + /* 8 */ {3, Value_Logical, 0x0}, /* y@L */ + /* 9 */ {3, 0, 0x8}, /* y */ + /* 10 */ {3, Value_OddInt, 0x0}, /* y@O */ + /* 11 */ {3, Value_NonInteger, 0x0}, /* y@F */ + /* 12 */ {3, Value_EvenInt, 0x0}, /* y@E */ + /* 13 */ {3, Sign_Positive, 0x0}, /* y@P */ + /* 14 */ {0, Sign_Negative | Constness_Const, 0x0}, /* %@N */ + /* 15 */ {0, Constness_Const, 0x0}, /* % */ + /* 16 */ {0, Sign_Positive | Constness_Const, 0x0}, /* %@P */ + /* 17 */ {0, Value_EvenInt | Constness_Const, 0x0}, /* %@E */ + /* 18 */ {0, Constness_Const, 0x1}, /* % */ + /* 19 */ {0, Value_IsInteger | Sign_Positive | Constness_Const, 0x0}, /* %@I@P */ + /* 20 */ {0, Oneness_NotOne | Constness_Const, 0x1}, /* %@M */ + /* 21 */ {0, Oneness_NotOne | Constness_Const, 0x0}, /* %@M */ + /* 22 */ {0, Oneness_One | Constness_Const, 0x0}, /* %@1 */ + /* 23 */ {0, Value_Logical | Constness_Const, 0x0}, /* %@L */ + /* 24 */ {1, Constness_Const, 0x0}, /* & */ + /* 25 */ {1, Value_EvenInt | Constness_Const, 0x0}, /* &@E */ + /* 26 */ {1, Oneness_NotOne | Constness_Const, 0x0}, /* &@M */ + /* 27 */ {1, Value_IsInteger | Constness_Const, 0x0}, /* &@I */ + /* 28 */ {1, Sign_Positive | Constness_Const, 0x0}, /* &@P */ + /* 29 */ {1, Sign_Negative | Constness_Const, 0x0}, /* &@N */ + /* 30 */ {6, 0, 0x0}, /* b */ + /* 31 */ {4, 0, 0x0}, /* z */ + /* 32 */ {4, Value_IsInteger, 0x0}, /* z@I */ + /* 33 */ {4, Constness_Const, 0x0}, /* z@C */ + /* 34 */ {4, 0, 0x16}, /* z */ + /* 35 */ {5, 0, 0x0}, /* a */ + /* 36 */ {5, Constness_Const, 0x0}, /* a@C */ + }; + + template<typename Value_t> + struct plist_n_container + { + static const ParamSpec_NumConstant<Value_t> plist_n[20]; + }; + template<typename Value_t> + const ParamSpec_NumConstant <Value_t> plist_n_container<Value_t>::plist_n[20] = + { + /* 37 */ {Value_t(-2), 0}, /* -2 */ + /* 38 */ {Value_t(-1), 0}, /* -1 */ + /* 39 */ {Value_t(-0.5), 0}, /* -0.5 */ + /* 40 */ {Value_t(-0.25), 0}, /* -0.25 */ + /* 41 */ {Value_t(0), 0}, /* 0 */ + /* 42 */ {fp_const_deg_to_rad<Value_t>(), 0}, /* 0.0174532925199 */ + /* 43 */ {fp_const_einv<Value_t>(), 0}, /* 0.367879441171 */ + /* 44 */ {fp_const_log10inv<Value_t>(), 0}, /* 0.434294481903 */ + /* 45 */ {Value_t(0.5), 0}, /* 0.5 */ + /* 46 */ {fp_const_log2<Value_t>(), 0}, /* 0.69314718056 */ + /* 47 */ {Value_t(1), 0}, /* 1 */ + /* 48 */ {fp_const_log2inv<Value_t>(), 0}, /* 1.44269504089 */ + /* 49 */ {Value_t(2), 0}, /* 2 */ + /* 50 */ {fp_const_log10<Value_t>(), 0}, /* 2.30258509299 */ + /* 51 */ {fp_const_e<Value_t>(), 0}, /* 2.71828182846 */ + /* 52 */ {fp_const_rad_to_deg<Value_t>(), 0}, /* 57.2957795131 */ + /* 53 */ {-fp_const_pihalf<Value_t>(), Modulo_Radians}, /* -1.57079632679 */ + /* 54 */ {Value_t(0), Modulo_Radians}, /* 0 */ + /* 55 */ {fp_const_pihalf<Value_t>(), Modulo_Radians}, /* 1.57079632679 */ + /* 56 */ {fp_const_pi<Value_t>(), Modulo_Radians}, /* 3.14159265359 */ + }; + + const ParamSpec_SubFunction plist_s[517] = + { + /* 57 */ {{1,/*15 */15 , cNeg ,GroupFunction ,0}, Constness_Const, 0x0}, /* -%@C */ + /* 58 */ {{1,/*398 */398 , cNeg ,GroupFunction ,0}, Constness_Const, 0x0}, /* -POW( MUL( % 0.5 )@C 2 )@C@C */ + /* 59 */ {{1,/*477 */477 , cNeg ,GroupFunction ,0}, Constness_Const, 0x0}, /* -MIN( % & )@C@C */ + /* 60 */ {{1,/*15 */15 , cNeg ,GroupFunction ,0}, Constness_Const, 0x1}, /* -%@C */ + /* 61 */ {{1,/*15 */15 , cInv ,GroupFunction ,0}, Constness_Const, 0x0}, /* /%@C */ + /* 62 */ {{1,/*24 */24 , cInv ,GroupFunction ,0}, Constness_Const, 0x0}, /* /&@C */ + /* 63 */ {{1,/*465 */465 , cInv ,GroupFunction ,0}, Constness_Const, 0x0}, /* /LOG( % )@C@C */ + /* 64 */ {{1,/*466 */466 , cInv ,GroupFunction ,0}, Constness_Const, 0x0}, /* /LOG( & )@C@C */ + /* 65 */ {{1,/*498 */498 , cInv ,GroupFunction ,0}, Constness_Const, 0x0}, /* /SQRT( % )@C@C */ + /* 66 */ {{2,/*315,320 */327995 , cAdd ,PositionalParams,0}, 0, 0x0}, /* (cAdd [(cPow [x %@E]) (cPow [y &@E])]) */ + /* 67 */ {{2,/*148,47 */48276 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {(cPow [x 2]) -1}) 1}) */ + /* 68 */ {{2,/*55,254 */260151 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1.57079632679 (cMul %@N <1>)}) */ + /* 69 */ {{2,/*155,459 */470171 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {LOG( % )@C y}) (cLog [(cMul <1>)])}) */ + /* 70 */ {{2,/*166,165 */169126 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {a@C (cPow [x %@E])}) (cMul {z@C (cPow [y &@E])})}) */ + /* 71 */ {{2,/*290,47 */48418 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [x 2]) 1}) */ + /* 72 */ {{2,/*304,1 */1328 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [(cAdd {-1 (cPow [x 2])}) 0.5])@D4 x@D4}) */ + /* 73 */ {{2,/*314,277 */283962 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [x y]) MUL( % 0.5 )@C}) */ + /* 74 */ {{2,/*315,165 */169275 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [x %@E]) (cMul {z@C (cPow [y &@E])})}) */ + /* 75 */ {{2,/*290,38 */39202 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [x 2]) -1}) */ + /* 76 */ {{2,/*316,277 */283964 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [x (cMul {y &})]) MUL( % 0.5 )@C}) */ + /* 77 */ {{2,/*325,277 */283973 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [& y]) MUL( % 0.5 )@C}) */ + /* 78 */ {{2,/*459,465 */476619 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cLog [(cMul <1>)]) LOG( % )@C}) */ + /* 79 */ {{2,/*38,290 */296998 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {-1 (cPow [x 2])}) */ + /* 80 */ {{2,/*47,0 */47 , cAdd ,SelectedParams ,0}, 0, 0x4}, /* (cAdd {1 x}) */ + /* 81 */ {{2,/*47,158 */161839 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1 (cMul {-1 x})}) */ + /* 82 */ {{2,/*460,24 */25036 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cLog [x]) &}) */ + /* 83 */ {{2,/*7,35 */35847 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {y a}) */ + /* 84 */ {{2,/*24,59 */60440 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {& -MIN( % & )@C@C}) */ + /* 85 */ {{2,/*31,30 */30751 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {z b}) */ + /* 86 */ {{2,/*178,179 */183474 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {x SQRT( % )@C}) (cMul {y MUL( 0.5 MUL( & /SQRT( % )@C@C )@C )@C})}) */ + /* 87 */ {{2,/*246,253 */259318 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul <1>) (cMul -1 <2>)}) */ + /* 88 */ {{2,/*263,264 */270599 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul (cPow [x (cAdd {% -MIN( % & )@C@C})]) <1>) (cMul (cPow [x (cAdd {& -MIN( % & )@C@C})]) <2>)}) */ + /* 89 */ {{2,/*15,59 */60431 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {% -MIN( % & )@C@C}) */ + /* 90 */ {{2,/*47,253 */259119 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1 (cMul -1 <2>)}) */ + /* 91 */ {{2,/*290,324 */332066 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [x 2]) (cPow [y 2])}) */ + /* 92 */ {{2,/*0,7 */7168 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {x y}) */ + /* 93 */ {{2,/*0,193 */197632 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {x (cMul {-1 y})}) */ + /* 94 */ {{2,/*0,285 */291840 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {x MUL( % -0.5 )@C}) */ + /* 95 */ {{2,/*0,277 */283648 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {x MUL( % 0.5 )@C}) */ + /* 96 */ {{2,/*274,233 */238866 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul % & <1>) (cMul {& (cAdd <2>)})}) */ + /* 97 */ {{2,/*286,234 */239902 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {MUL( % & )@C (cMul {& (cAdd <1>)})}) */ + /* 98 */ {{2,/*7,31 */31751 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {y z}) */ + /* 99 */ {{2,/*7,239 */244743 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})}) */ + /* 100 */ {{2,/*22,375 */384022 , cAdd ,SelectedParams ,0}, 0, 0x4}, /* (cAdd {%@1 (cPow [x z])}) */ + /* 101 */ {{2,/*238,376 */385262 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {(cPow [x y]) %}) (cPow [x (cAdd {y z})])}) */ + /* 102 */ {{2,/*38,377 */386086 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {-1 (cPow [x@P z])}) */ + /* 103 */ {{2,/*38,384 */393254 , cAdd ,SelectedParams ,0}, 0, 0x5}, /* (cAdd {-1 (cPow [% x])}) */ + /* 104 */ {{2,/*38,384 */393254 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {-1 (cPow [% x])}) */ + /* 105 */ {{2,/*47,377 */386095 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1 (cPow [x@P z])}) */ + /* 106 */ {{2,/*240,378 */387312 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {(cPow [& y]) -1}) (cPow [& (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})})])}) */ + /* 107 */ {{2,/*230,18 */18662 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {% (cPow [x@P z])})@D1 %@D1}) */ + /* 108 */ {{2,/*230,60 */61670 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {% (cPow [x@P z])})@D1 -%@C@D1}) */ + /* 109 */ {{2,/*325,378 */387397 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cPow [& y]) (cPow [& (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})})])}) */ + /* 110 */ {{2,/*47,242 */247855 , cAdd ,SelectedParams ,0}, 0, 0x1}, /* (cAdd {1 (cMul {(cLog [x]) /%@C})}) */ + /* 111 */ {{2,/*47,334 */342063 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1 (cPow [(cAdd <1>) 2])}) */ + /* 112 */ {{2,/*47,290 */297007 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1 (cPow [x 2])}) */ + /* 113 */ {{2,/*460,15 */15820 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cLog [x]) %}) */ + /* 114 */ {{2,/*47,384 */393263 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1 (cPow [% x])}) */ + /* 115 */ {{2,/*47,384 */393263 , cAdd ,SelectedParams ,0}, 0, 0x5}, /* (cAdd {1 (cPow [% x])}) */ + /* 116 */ {{2,/*55,158 */161847 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1.57079632679 (cMul {-1 x})}) */ + /* 117 */ {{2,/*55,252 */258103 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {1.57079632679 (cMul -1 <1>)}) */ + /* 118 */ {{2,/*241,243 */249073 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {(cAbs [x]) -%@C}) (cMul {x (cAdd <1>)})}) */ + /* 119 */ {{2,/*244,243 */249076 , cAdd ,SelectedParams ,0}, 0, 0x0}, /* (cAdd {(cMul {(cAbs [x]) %}) (cMul {x (cAdd <1>)})}) */ + /* 120 */ {{0,/* */0 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd <1>) */ + /* 121 */ {{0,/* */0 , cAdd ,AnyParams ,2}, 0, 0x0}, /* (cAdd <2>) */ + /* 122 */ {{1,/*45 */45 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd 0.5 <1>) */ + /* 123 */ {{1,/*53 */53 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd -1.57079632679 <1>) */ + /* 124 */ {{1,/*54 */54 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd 0 <1>) */ + /* 125 */ {{1,/*55 */55 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd 1.57079632679 <1>) */ + /* 126 */ {{1,/*56 */56 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd 3.14159265359 <1>) */ + /* 127 */ {{1,/*26 */26 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd &@M <1>) */ + /* 128 */ {{1,/*259 */259 , cAdd ,AnyParams ,1}, 0, 0x16}, /* (cAdd (cMul (cPow [(cLog [z]) -1]) <2>) <1>) */ + /* 129 */ {{1,/*272 */272 , cAdd ,AnyParams ,2}, 0, 0x0}, /* (cAdd (cMul %@M <1>) <2>) */ + /* 130 */ {{1,/*323 */323 , cAdd ,AnyParams ,1}, 0, 0x16}, /* (cAdd (cPow [(cLog [z]) -1]) <1>) */ + /* 131 */ {{1,/*0 */0 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd x <1>) */ + /* 132 */ {{1,/*21 */21 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd %@M <1>) */ + /* 133 */ {{1,/*447 */447 , cAdd ,AnyParams ,1}, 0, 0x4}, /* (cAdd (cIf [(cLess [x 0]) %@D1 -%@C@D1]) <1>) */ + /* 134 */ {{1,/*449 */449 , cAdd ,AnyParams ,1}, 0, 0x4}, /* (cAdd (cIf [(cGreater [x 0]) %@D1 -%@C@D1]) <1>) */ + /* 135 */ {{1,/*0 */0 , cAdd ,AnyParams ,1}, 0, 0x4}, /* (cAdd x <1>) */ + /* 136 */ {{1,/*0 */0 , cAdd ,AnyParams ,2}, 0, 0x4}, /* (cAdd x <2>) */ + /* 137 */ {{1,/*15 */15 , cAdd ,AnyParams ,1}, 0, 0x0}, /* (cAdd % <1>) */ + /* 138 */ {{1,/*24 */24 , cAdd ,AnyParams ,2}, 0, 0x0}, /* (cAdd & <2>) */ + /* 139 */ {{2,/*24,57 */58392 , cAdd ,AnyParams ,2}, 0, 0x0}, /* (cAdd & -%@C <2>) */ + /* 140 */ {{0,/* */0 , cAdd ,AnyParams ,1}, Sign_Positive, 0x0}, /* (cAdd <1>)@P */ + /* 141 */ {{2,/*15,24 */24591 , cAdd ,GroupFunction ,0}, Constness_Const, 0x0}, /* ADD( % & )@C */ + /* 142 */ {{2,/*15,33 */33807 , cAdd ,GroupFunction ,0}, Constness_Const, 0x0}, /* ADD( % z@C )@C */ + /* 143 */ {{2,/*15,47 */48143 , cAdd ,GroupFunction ,0}, Constness_Const, 0x0}, /* ADD( % 1 )@C */ + /* 144 */ {{2,/*24,279 */285720 , cAdd ,GroupFunction ,0}, Constness_Const, 0x0}, /* ADD( & MUL( -2 % )@C )@C */ + /* 145 */ {{2,/*24,284 */290840 , cAdd ,GroupFunction ,0}, Constness_Const, 0x0}, /* ADD( & MUL( 2 % )@C )@C */ + /* 146 */ {{2,/*0,298 */305152 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x (cPow [y %@N])}) */ + /* 147 */ {{2,/*80,305 */312400 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cAdd {1 x})@D4 (cPow [(cAdd {1 (cMul {-1 x})}) -1])@D4}) */ + /* 148 */ {{2,/*290,38 */39202 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cPow [x 2]) -1}) */ + /* 149 */ {{2,/*38,120 */122918 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cAdd <1>)}) */ + /* 150 */ {{2,/*38,412 */421926 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cCeil [(cMul <1>)])}) */ + /* 151 */ {{2,/*38,419 */429094 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cCos [(cAdd <1>)])}) */ + /* 152 */ {{2,/*38,433 */443430 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cFloor [(cMul <1>)])}) */ + /* 153 */ {{2,/*394,310 */317834 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {POW( % & )@C (cPow [(cMul <1>) &])}) */ + /* 154 */ {{2,/*394,321 */329098 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {POW( % & )@C (cPow [% (cAdd <1>)])}) */ + /* 155 */ {{2,/*465,7 */7633 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {LOG( % )@C y}) */ + /* 156 */ {{2,/*538,7 */7706 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cNot [x]) y}) */ + /* 157 */ {{2,/*562,7 */7730 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cNotNot [x]) y}) */ + /* 158 */ {{2,/*38,0 */38 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 x}) */ + /* 159 */ {{2,/*411,49 */50587 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cAtanh [x]) 2}) */ + /* 160 */ {{2,/*0,397 */406528 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x POW( a@C /%@C )@C}) */ + /* 161 */ {{2,/*7,24 */24583 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {y &}) */ + /* 162 */ {{2,/*7,31 */31751 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {y z}) */ + /* 163 */ {{2,/*7,396 */405511 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {y POW( z@C /&@C )@C}) */ + /* 164 */ {{2,/*15,314 */321551 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {% (cPow [x y])}) */ + /* 165 */ {{2,/*33,320 */327713 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {z@C (cPow [y &@E])}) */ + /* 166 */ {{2,/*36,315 */322596 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {a@C (cPow [x %@E])}) */ + /* 167 */ {{2,/*297,88 */90409 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cPow [x MIN( % & )@C]) (cAdd {(cMul (cPow [x (cAdd {% -MIN( % & )@C@C})]) <1>) (cMul (cPow [x (cAdd {& -MIN( % & )@C@C})]) <2>)})}) */ + /* 168 */ {{2,/*326,327 */335174 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cPow [z (cAdd <1>)]) (cPow [2.71828182846 (cMul <2>)])}) */ + /* 169 */ {{2,/*394,319 */327050 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {POW( % & )@C (cPow [x LOG( % )@C])}) */ + /* 170 */ {{2,/*38,482 */493606 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cSin [(cAdd <1>)])}) */ + /* 171 */ {{2,/*38,485 */496678 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cSin [(cMul <1>)])}) */ + /* 172 */ {{2,/*38,492 */503846 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cSinh [(cMul <1>)])}) */ + /* 173 */ {{2,/*38,504 */516134 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cTan [(cMul <1>)])}) */ + /* 174 */ {{2,/*49,7 */7217 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {2 y}) */ + /* 175 */ {{2,/*51,326 */333875 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {2.71828182846 (cPow [z (cAdd <1>)])}) */ + /* 176 */ {{2,/*0,329 */336896 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x (cPow [y -1])}) */ + /* 177 */ {{2,/*38,512 */524326 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cTanh [(cMul <1>)])}) */ + /* 178 */ {{2,/*0,498 */509952 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x SQRT( % )@C}) */ + /* 179 */ {{2,/*7,280 */286727 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {y MUL( 0.5 MUL( & /SQRT( % )@C@C )@C )@C}) */ + /* 180 */ {{2,/*15,87 */89103 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {% (cAdd {(cMul <1>) (cMul -1 <2>)})}) */ + /* 181 */ {{2,/*15,90 */92175 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {% (cAdd {1 (cMul -1 <2>)})}) */ + /* 182 */ {{2,/*16,290 */296976 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {%@P (cPow [x 2])}) */ + /* 183 */ {{2,/*15,317 */324623 , cMul ,SelectedParams ,0}, 0, 0x14}, /* (cMul {% (cPow [x (cMul {& y})])}) */ + /* 184 */ {{2,/*15,325 */332815 , cMul ,SelectedParams ,0}, 0, 0x10}, /* (cMul {% (cPow [& y])}) */ + /* 185 */ {{3,/*24,0,7 */7340056 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {& x y}) */ + /* 186 */ {{2,/*324,282 */289092 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cPow [y 2]) MUL( MUL( -0.25 /%@C )@C POW( & 2 )@C )@C}) */ + /* 187 */ {{2,/*16,91 */93200 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {%@P (cAdd {(cPow [x 2]) (cPow [y 2])})}) */ + /* 188 */ {{2,/*15,330 */337935 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {% (cPow [(cAdd {x y}) 2])}) */ + /* 189 */ {{3,/*28,0,7 */7340060 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {&@P x y}) */ + /* 190 */ {{3,/*144,0,7 */7340176 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {ADD( & MUL( -2 % )@C )@C x y}) */ + /* 191 */ {{2,/*15,331 */338959 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {% (cPow [(cAdd {x (cMul {-1 y})}) 2])}) */ + /* 192 */ {{3,/*29,0,7 */7340061 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {&@N x y}) */ + /* 193 */ {{2,/*38,7 */7206 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 y}) */ + /* 194 */ {{2,/*0,7 */7168 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x y}) */ + /* 195 */ {{2,/*38,349 */357414 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cPow [(cCos [x]) 2])}) */ + /* 196 */ {{2,/*38,360 */368678 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cPow [(cSin [x]) 2])}) */ + /* 197 */ {{2,/*57,362 */370745 , cMul ,SelectedParams ,0}, 0, 0x7}, /* (cMul {-%@C (cPow [/&@C x])}) */ + /* 198 */ {{3,/*145,0,7 */7340177 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {ADD( & MUL( 2 % )@C )@C x y}) */ + /* 199 */ {{2,/*365,38 */39277 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {(cPow [0.367879441171 x]) -1}) */ + /* 200 */ {{2,/*414,416 */426398 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {(cCos [x]) (cCos [y])}) */ + /* 201 */ {{3,/*414,416,38 */40272286 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {(cCos [x]) (cCos [y]) -1}) */ + /* 202 */ {{2,/*414,479 */490910 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {(cCos [x]) (cSin [y])}) */ + /* 203 */ {{3,/*414,479,38 */40336798 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {(cCos [x]) (cSin [y]) -1}) */ + /* 204 */ {{2,/*424,49 */50600 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cCosh [(cLog [(cPow [& x])])]) 2}) */ + /* 205 */ {{2,/*478,416 */426462 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {(cSin [x]) (cCos [y])}) */ + /* 206 */ {{2,/*478,479 */490974 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {(cSin [x]) (cSin [y])}) */ + /* 207 */ {{2,/*38,362 */370726 , cMul ,SelectedParams ,0}, 0, 0x6}, /* (cMul {-1 (cPow [/&@C x])}) */ + /* 208 */ {{2,/*38,363 */371750 , cMul ,SelectedParams ,0}, 0, 0x6}, /* (cMul {-1 (cPow [& x])}) */ + /* 209 */ {{2,/*38,418 */428070 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cCos [(cAdd {x (cMul {-1 y})})])}) */ + /* 210 */ {{3,/*478,479,38 */40336862 , cMul ,SelectedParams ,0}, 0, 0x12}, /* (cMul {(cSin [x]) (cSin [y]) -1}) */ + /* 211 */ {{2,/*490,37 */38378 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cSinh [(cMul {x LOG( & )@C})]) -2}) */ + /* 212 */ {{2,/*495,49 */50671 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cSinh [(cLog [(cPow [& x])])]) 2}) */ + /* 213 */ {{3,/*0,465,45 */47662080 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x LOG( % )@C 0.5}) */ + /* 214 */ {{2,/*0,466 */477184 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x LOG( & )@C}) */ + /* 215 */ {{2,/*0,555 */568320 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x (cAnd <1>)}) */ + /* 216 */ {{2,/*15,363 */371727 , cMul ,SelectedParams ,0}, 0, 0x7}, /* (cMul {% (cPow [& x])}) */ + /* 217 */ {{3,/*490,49,15 */15779306 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cSinh [(cMul {x LOG( & )@C})]) 2 %}) */ + /* 218 */ {{2,/*15,362 */370703 , cMul ,SelectedParams ,0}, 0, 0x7}, /* (cMul {% (cPow [/&@C x])}) */ + /* 219 */ {{2,/*365,38 */39277 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cPow [0.367879441171 x]) -1}) */ + /* 220 */ {{2,/*367,38 */39279 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {(cPow [2.71828182846 x]) -1}) */ + /* 221 */ {{3,/*422,49,15 */15779238 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cCosh [(cMul {x LOG( & )@C})]) 2 %}) */ + /* 222 */ {{2,/*426,38 */39338 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {(cCosh [x]) -1}) */ + /* 223 */ {{2,/*38,426 */436262 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cCosh [x])}) */ + /* 224 */ {{2,/*38,497 */508966 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cSinh [x])}) */ + /* 225 */ {{2,/*497,38 */39409 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {(cSinh [x]) -1}) */ + /* 226 */ {{2,/*38,290 */296998 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {-1 (cPow [x 2])}) */ + /* 227 */ {{2,/*7,35 */35847 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {y a}) */ + /* 228 */ {{2,/*15,0 */15 , cMul ,SelectedParams ,0}, 0, 0x4}, /* (cMul {% x}) */ + /* 229 */ {{2,/*38,369 */377894 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-1 (cPow [(cAdd {x MUL( % -0.5 )@C}) 2])}) */ + /* 230 */ {{2,/*15,377 */386063 , cMul ,SelectedParams ,0}, 0, 0x1}, /* (cMul {% (cPow [x@P z])}) */ + /* 231 */ {{2,/*15,0 */15 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {% x}) */ + /* 232 */ {{2,/*24,7 */7192 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {& y}) */ + /* 233 */ {{2,/*24,121 */123928 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {& (cAdd <2>)}) */ + /* 234 */ {{2,/*24,120 */122904 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {& (cAdd <1>)}) */ + /* 235 */ {{2,/*31,30 */30751 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {z b}) */ + /* 236 */ {{2,/*57,0 */57 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {-%@C x}) */ + /* 237 */ {{2,/*288,7 */7456 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {MUL( & 2 )@C y}) */ + /* 238 */ {{2,/*314,15 */15674 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cPow [x y]) %}) */ + /* 239 */ {{3,/*31,460,64 */67579935 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {z (cLog [x]) /LOG( & )@C@C}) */ + /* 240 */ {{2,/*325,38 */39237 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cPow [& y]) -1}) */ + /* 241 */ {{2,/*400,57 */58768 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cAbs [x]) -%@C}) */ + /* 242 */ {{2,/*460,61 */62924 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cLog [x]) /%@C}) */ + /* 243 */ {{2,/*0,120 */122880 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x (cAdd <1>)}) */ + /* 244 */ {{2,/*400,15 */15760 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {(cAbs [x]) %}) */ + /* 245 */ {{3,/*0,45,61 */64009216 , cMul ,SelectedParams ,0}, 0, 0x0}, /* (cMul {x 0.5 /%@C}) */ + /* 246 */ {{0,/* */0 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul <1>) */ + /* 247 */ {{0,/* */0 , cMul ,AnyParams ,2}, 0, 0x0}, /* (cMul <2>) */ + /* 248 */ {{1,/*2 */2 , cMul ,AnyParams ,1}, 0, 0x4}, /* (cMul x@P <1>) */ + /* 249 */ {{1,/*2 */2 , cMul ,AnyParams ,2}, 0, 0x4}, /* (cMul x@P <2>) */ + /* 250 */ {{1,/*3 */3 , cMul ,AnyParams ,1}, 0, 0x4}, /* (cMul x@N@V <1>) */ + /* 251 */ {{1,/*3 */3 , cMul ,AnyParams ,2}, 0, 0x4}, /* (cMul x@N@V <2>) */ + /* 252 */ {{1,/*38 */38 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul -1 <1>) */ + /* 253 */ {{1,/*38 */38 , cMul ,AnyParams ,2}, 0, 0x0}, /* (cMul -1 <2>) */ + /* 254 */ {{1,/*14 */14 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul %@N <1>) */ + /* 255 */ {{1,/*57 */57 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul -%@C <1>) */ + /* 256 */ {{1,/*16 */16 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul %@P <1>) */ + /* 257 */ {{2,/*63,460 */471103 , cMul ,AnyParams ,1}, 0, 0x1}, /* (cMul /LOG( % )@C@C (cLog [x]) <1>) */ + /* 258 */ {{1,/*303 */303 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul (cPow [% y]) <1>) */ + /* 259 */ {{1,/*323 */323 , cMul ,AnyParams ,2}, 0, 0x0}, /* (cMul (cPow [(cLog [z]) -1]) <2>) */ + /* 260 */ {{2,/*323,460 */471363 , cMul ,AnyParams ,1}, 0, 0x16}, /* (cMul (cPow [(cLog [z]) -1]) (cLog [x]) <1>) */ + /* 261 */ {{1,/*293 */293 , cMul ,AnyParams ,1}, 0, 0x4}, /* (cMul (cPow [x %@I@P]) <1>) */ + /* 262 */ {{1,/*294 */294 , cMul ,AnyParams ,2}, 0, 0x4}, /* (cMul (cPow [x &@I]) <2>) */ + /* 263 */ {{1,/*295 */295 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul (cPow [x (cAdd {% -MIN( % & )@C@C})]) <1>) */ + /* 264 */ {{1,/*296 */296 , cMul ,AnyParams ,2}, 0, 0x0}, /* (cMul (cPow [x (cAdd {& -MIN( % & )@C@C})]) <2>) */ + /* 265 */ {{1,/*400 */400 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul (cAbs [x]) <1>) */ + /* 266 */ {{1,/*0 */0 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul x <1>) */ + /* 267 */ {{1,/*460 */460 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul (cLog [x]) <1>) */ + /* 268 */ {{1,/*465 */465 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul LOG( % )@C <1>) */ + /* 269 */ {{1,/*16 */16 , cMul ,AnyParams ,1}, 0, 0x1}, /* (cMul %@P <1>) */ + /* 270 */ {{1,/*57 */57 , cMul ,AnyParams ,2}, 0, 0x1}, /* (cMul -%@C <2>) */ + /* 271 */ {{1,/*0 */0 , cMul ,AnyParams ,2}, 0, 0x0}, /* (cMul x <2>) */ + /* 272 */ {{1,/*21 */21 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul %@M <1>) */ + /* 273 */ {{1,/*15 */15 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul % <1>) */ + /* 274 */ {{2,/*15,24 */24591 , cMul ,AnyParams ,1}, 0, 0x0}, /* (cMul % & <1>) */ + /* 275 */ {{1,/*24 */24 , cMul ,AnyParams ,2}, 0, 0x0}, /* (cMul & <2>) */ + /* 276 */ {{1,/*517 */517 , cMul ,AnyParams ,2}, 0, 0x0}, /* (cMul DIV( & % )@C <2>) */ + /* 277 */ {{2,/*15,45 */46095 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( % 0.5 )@C */ + /* 278 */ {{2,/*24,45 */46104 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( & 0.5 )@C */ + /* 279 */ {{2,/*37,15 */15397 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( -2 % )@C */ + /* 280 */ {{2,/*45,281 */287789 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( 0.5 MUL( & /SQRT( % )@C@C )@C )@C */ + /* 281 */ {{2,/*24,65 */66584 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( & /SQRT( % )@C@C )@C */ + /* 282 */ {{2,/*283,395 */404763 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( MUL( -0.25 /%@C )@C POW( & 2 )@C )@C */ + /* 283 */ {{2,/*40,61 */62504 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( -0.25 /%@C )@C */ + /* 284 */ {{2,/*49,15 */15409 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( 2 % )@C */ + /* 285 */ {{2,/*15,39 */39951 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( % -0.5 )@C */ + /* 286 */ {{2,/*15,24 */24591 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( % & )@C */ + /* 287 */ {{2,/*15,33 */33807 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( % z@C )@C */ + /* 288 */ {{2,/*24,49 */50200 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( & 2 )@C */ + /* 289 */ {{2,/*45,61 */62509 , cMul ,GroupFunction ,0}, Constness_Const, 0x0}, /* MUL( 0.5 /%@C )@C */ + /* 290 */ {{2,/*0,49 */50176 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x 2]) */ + /* 291 */ {{2,/*0,174 */178176 , cPow ,PositionalParams,0}, 0, 0x12}, /* (cPow [x (cMul {2 y})]) */ + /* 292 */ {{2,/*0,277 */283648 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x MUL( % 0.5 )@C]) */ + /* 293 */ {{2,/*0,19 */19456 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x %@I@P]) */ + /* 294 */ {{2,/*0,27 */27648 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x &@I]) */ + /* 295 */ {{2,/*0,89 */91136 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x (cAdd {% -MIN( % & )@C@C})]) */ + /* 296 */ {{2,/*0,84 */86016 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x (cAdd {& -MIN( % & )@C@C})]) */ + /* 297 */ {{2,/*0,477 */488448 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x MIN( % & )@C]) */ + /* 298 */ {{2,/*6,14 */14342 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [y %@N]) */ + /* 299 */ {{2,/*7,57 */58375 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [y -%@C]) */ + /* 300 */ {{2,/*67,45 */46147 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cAdd {(cMul {(cPow [x 2]) -1}) 1}) 0.5]) */ + /* 301 */ {{2,/*71,45 */46151 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {(cPow [x 2]) 1}) 0.5]) */ + /* 302 */ {{2,/*7,278 */284679 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [y MUL( & 0.5 )@C]) */ + /* 303 */ {{2,/*15,7 */7183 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [% y]) */ + /* 304 */ {{2,/*79,45 */46159 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cAdd {-1 (cPow [x 2])}) 0.5]) */ + /* 305 */ {{2,/*81,38 */38993 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cAdd {1 (cMul {-1 x})}) -1]) */ + /* 306 */ {{2,/*86,49 */50262 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {(cMul {x SQRT( % )@C}) (cMul {y MUL( 0.5 MUL( & /SQRT( % )@C@C )@C )@C})}) 2]) */ + /* 307 */ {{2,/*73,49 */50249 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {(cPow [x y]) MUL( % 0.5 )@C}) 2]) */ + /* 308 */ {{2,/*160,277 */283808 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cMul {x POW( a@C /%@C )@C}) MUL( % 0.5 )@C]) */ + /* 309 */ {{2,/*163,278 */284835 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cMul {y POW( z@C /&@C )@C}) MUL( & 0.5 )@C]) */ + /* 310 */ {{2,/*246,24 */24822 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cMul <1>) &]) */ + /* 311 */ {{2,/*0,10 */10240 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x y@O]) */ + /* 312 */ {{2,/*0,11 */11264 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x y@F]) */ + /* 313 */ {{2,/*2,7 */7170 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x@P y]) */ + /* 314 */ {{2,/*0,7 */7168 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x y]) */ + /* 315 */ {{2,/*0,17 */17408 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x %@E]) */ + /* 316 */ {{2,/*0,161 */164864 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x (cMul {y &})]) */ + /* 317 */ {{2,/*0,232 */237568 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x (cMul {& y})]) */ + /* 318 */ {{2,/*0,237 */242688 , cPow ,PositionalParams,0}, 0, 0x14}, /* (cPow [x (cMul {MUL( & 2 )@C y})]) */ + /* 319 */ {{2,/*0,465 */476160 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x LOG( % )@C]) */ + /* 320 */ {{2,/*7,25 */25607 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [y &@E]) */ + /* 321 */ {{2,/*15,120 */122895 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [% (cAdd <1>)]) */ + /* 322 */ {{2,/*76,49 */50252 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {(cPow [x (cMul {y &})]) MUL( % 0.5 )@C}) 2]) */ + /* 323 */ {{2,/*462,38 */39374 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cLog [z]) -1]) */ + /* 324 */ {{2,/*7,49 */50183 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [y 2]) */ + /* 325 */ {{2,/*24,7 */7192 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [& y]) */ + /* 326 */ {{2,/*31,120 */122911 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [z (cAdd <1>)]) */ + /* 327 */ {{2,/*51,247 */252979 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [2.71828182846 (cMul <2>)]) */ + /* 328 */ {{2,/*75,45 */46155 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {(cPow [x 2]) -1}) 0.5]) */ + /* 329 */ {{2,/*7,38 */38919 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [y -1]) */ + /* 330 */ {{2,/*92,49 */50268 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {x y}) 2]) */ + /* 331 */ {{2,/*93,49 */50269 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {x (cMul {-1 y})}) 2]) */ + /* 332 */ {{2,/*77,49 */50253 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {(cPow [& y]) MUL( % 0.5 )@C}) 2]) */ + /* 333 */ {{2,/*111,45 */46191 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])}) 0.5]) */ + /* 334 */ {{2,/*120,49 */50296 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd <1>) 2]) */ + /* 335 */ {{2,/*395,7 */7563 , cPow ,PositionalParams,0}, 0, 0x10}, /* (cPow [POW( & 2 )@C y]) */ + /* 336 */ {{2,/*43,407 */416811 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [0.367879441171 (cAsinh [(cAdd <1>)])]) */ + /* 337 */ {{2,/*51,407 */416819 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [2.71828182846 (cAsinh [(cAdd <1>)])]) */ + /* 338 */ {{2,/*111,39 */40047 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])}) -0.5]) */ + /* 339 */ {{2,/*112,45 */46192 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cAdd {1 (cPow [x 2])}) 0.5]) */ + /* 340 */ {{2,/*51,406 */415795 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [2.71828182846 (cAsinh [x])]) */ + /* 341 */ {{2,/*112,39 */40048 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cAdd {1 (cPow [x 2])}) -0.5]) */ + /* 342 */ {{2,/*43,406 */415787 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [0.367879441171 (cAsinh [x])]) */ + /* 343 */ {{2,/*104,38 */39016 , cPow ,PositionalParams,0}, 0, 0x5}, /* (cPow [(cAdd {-1 (cPow [% x])}) -1]) */ + /* 344 */ {{2,/*414,38 */39326 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cCos [x]) -1]) */ + /* 345 */ {{2,/*414,38 */39326 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cCos [x]) -1]) */ + /* 346 */ {{2,/*420,38 */39332 , cPow ,PositionalParams,0}, 0, 0x5}, /* (cPow [(cCos [(cMul {-%@C x})]) -1]) */ + /* 347 */ {{2,/*421,38 */39333 , cPow ,PositionalParams,0}, 0, 0x1}, /* (cPow [(cCos [(cMul -%@C <1>)]) -1]) */ + /* 348 */ {{2,/*414,49 */50590 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cCos [x]) 2]) */ + /* 349 */ {{2,/*414,49 */50590 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cCos [x]) 2]) */ + /* 350 */ {{2,/*426,38 */39338 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cCosh [x]) -1]) */ + /* 351 */ {{2,/*426,38 */39338 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cCosh [x]) -1]) */ + /* 352 */ {{2,/*423,38 */39335 , cPow ,PositionalParams,0}, 0, 0x5}, /* (cPow [(cCosh [(cMul {-%@C x})]) -1]) */ + /* 353 */ {{2,/*426,15 */15786 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cCosh [x]) %]) */ + /* 354 */ {{2,/*426,143 */146858 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cCosh [x]) ADD( % 1 )@C]) */ + /* 355 */ {{2,/*460,38 */39372 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cLog [x]) -1]) */ + /* 356 */ {{2,/*467,38 */39379 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cLog10 [x]) -1]) */ + /* 357 */ {{2,/*468,38 */39380 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cLog2 [x]) -1]) */ + /* 358 */ {{2,/*478,38 */39390 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cSin [x]) -1]) */ + /* 359 */ {{2,/*478,49 */50654 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cSin [x]) 2]) */ + /* 360 */ {{2,/*478,49 */50654 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cSin [x]) 2]) */ + /* 361 */ {{2,/*24,0 */24 , cPow ,PositionalParams,0}, 0, 0x6}, /* (cPow [& x]) */ + /* 362 */ {{2,/*62,0 */62 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [/&@C x]) */ + /* 363 */ {{2,/*24,0 */24 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [& x]) */ + /* 364 */ {{2,/*62,0 */62 , cPow ,PositionalParams,0}, 0, 0x6}, /* (cPow [/&@C x]) */ + /* 365 */ {{2,/*43,0 */43 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [0.367879441171 x]) */ + /* 366 */ {{2,/*43,0 */43 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [0.367879441171 x]) */ + /* 367 */ {{2,/*51,0 */51 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [2.71828182846 x]) */ + /* 368 */ {{2,/*51,0 */51 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [2.71828182846 x]) */ + /* 369 */ {{2,/*94,49 */50270 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {x MUL( % -0.5 )@C}) 2]) */ + /* 370 */ {{2,/*0,49 */50176 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [x 2]) */ + /* 371 */ {{2,/*95,49 */50271 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cAdd {x MUL( % 0.5 )@C}) 2]) */ + /* 372 */ {{2,/*247,38 */39159 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cMul <2>) -1]) */ + /* 373 */ {{2,/*271,38 */39183 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cMul x <2>) -1]) */ + /* 374 */ {{2,/*0,7 */7168 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [x y]) */ + /* 375 */ {{2,/*0,31 */31744 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x z]) */ + /* 376 */ {{2,/*0,98 */100352 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x (cAdd {y z})]) */ + /* 377 */ {{2,/*2,31 */31746 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x@P z]) */ + /* 378 */ {{2,/*24,99 */101400 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [& (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})})]) */ + /* 379 */ {{2,/*497,38 */39409 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cSinh [x]) -1]) */ + /* 380 */ {{2,/*499,38 */39411 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cTan [x]) -1]) */ + /* 381 */ {{2,/*499,38 */39411 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cTan [x]) -1]) */ + /* 382 */ {{2,/*508,38 */39420 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cTanh [x]) -1]) */ + /* 383 */ {{2,/*508,38 */39420 , cPow ,PositionalParams,0}, 0, 0x4}, /* (cPow [(cTanh [x]) -1]) */ + /* 384 */ {{2,/*15,0 */15 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [% x]) */ + /* 385 */ {{2,/*114,38 */39026 , cPow ,PositionalParams,0}, 0, 0x5}, /* (cPow [(cAdd {1 (cPow [% x])}) -1]) */ + /* 386 */ {{2,/*510,38 */39422 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cTanh [(cMul {x LOG( % )@C 0.5})]) -1]) */ + /* 387 */ {{2,/*0,16 */16384 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x %@P]) */ + /* 388 */ {{2,/*389,61 */62853 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [(cPow [x %]) /%@C]) */ + /* 389 */ {{2,/*0,15 */15360 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [x %]) */ + /* 390 */ {{2,/*15,0 */15 , cPow ,PositionalParams,0}, 0, 0x1}, /* (cPow [% x]) */ + /* 391 */ {{2,/*16,0 */16 , cPow ,PositionalParams,0}, 0, 0x0}, /* (cPow [%@P x]) */ + /* 392 */ {{2,/*15,7 */7183 , cPow ,PositionalParams,0}, 0, 0x1}, /* (cPow [% y]) */ + /* 393 */ {{2,/*4,7 */7172 , cPow ,PositionalParams,0}, Sign_Positive, 0x0}, /* (cPow [x y])@P */ + /* 394 */ {{2,/*15,24 */24591 , cPow ,GroupFunction ,0}, Constness_Const, 0x0}, /* POW( % & )@C */ + /* 395 */ {{2,/*24,49 */50200 , cPow ,GroupFunction ,0}, Constness_Const, 0x0}, /* POW( & 2 )@C */ + /* 396 */ {{2,/*33,62 */63521 , cPow ,GroupFunction ,0}, Constness_Const, 0x0}, /* POW( z@C /&@C )@C */ + /* 397 */ {{2,/*36,61 */62500 , cPow ,GroupFunction ,0}, Constness_Const, 0x0}, /* POW( a@C /%@C )@C */ + /* 398 */ {{2,/*277,49 */50453 , cPow ,GroupFunction ,0}, Constness_Const, 0x0}, /* POW( MUL( % 0.5 )@C 2 )@C */ + /* 399 */ {{2,/*24,61 */62488 , cPow ,GroupFunction ,0}, Constness_Const, 0x0}, /* POW( & /%@C )@C */ + /* 400 */ {{1,/*0 */0 , cAbs ,PositionalParams,0}, 0, 0x0}, /* (cAbs [x]) */ + /* 401 */ {{1,/*7 */7 , cAbs ,PositionalParams,0}, 0, 0x0}, /* (cAbs [y]) */ + /* 402 */ {{1,/*194 */194 , cAbs ,PositionalParams,0}, 0, 0x0}, /* (cAbs [(cMul {x y})]) */ + /* 403 */ {{1,/*0 */0 , cAcos ,PositionalParams,0}, 0, 0x0}, /* (cAcos [x]) */ + /* 404 */ {{1,/*0 */0 , cAcosh ,PositionalParams,0}, 0, 0x0}, /* (cAcosh [x]) */ + /* 405 */ {{1,/*0 */0 , cAsin ,PositionalParams,0}, 0, 0x0}, /* (cAsin [x]) */ + /* 406 */ {{1,/*0 */0 , cAsinh ,PositionalParams,0}, 0, 0x0}, /* (cAsinh [x]) */ + /* 407 */ {{1,/*120 */120 , cAsinh ,PositionalParams,0}, 0, 0x0}, /* (cAsinh [(cAdd <1>)]) */ + /* 408 */ {{1,/*0 */0 , cAtan ,PositionalParams,0}, 0, 0x0}, /* (cAtan [x]) */ + /* 409 */ {{2,/*0,299 */306176 , cAtan2 ,PositionalParams,0}, 0, 0x0}, /* (cAtan2 [x (cPow [y -%@C])]) */ + /* 410 */ {{2,/*0,7 */7168 , cAtan2 ,PositionalParams,0}, 0, 0x0}, /* (cAtan2 [x y]) */ + /* 411 */ {{1,/*0 */0 , cAtanh ,PositionalParams,0}, 0, 0x0}, /* (cAtanh [x]) */ + /* 412 */ {{1,/*246 */246 , cCeil ,PositionalParams,0}, 0, 0x0}, /* (cCeil [(cMul <1>)]) */ + /* 413 */ {{1,/*0 */0 , cCeil ,PositionalParams,0}, 0, 0x4}, /* (cCeil [x]) */ + /* 414 */ {{1,/*0 */0 , cCos ,PositionalParams,0}, 0, 0x0}, /* (cCos [x]) */ + /* 415 */ {{1,/*0 */0 , cCos ,PositionalParams,0}, 0, 0x4}, /* (cCos [x]) */ + /* 416 */ {{1,/*7 */7 , cCos ,PositionalParams,0}, 0, 0x0}, /* (cCos [y]) */ + /* 417 */ {{1,/*92 */92 , cCos ,PositionalParams,0}, 0, 0x0}, /* (cCos [(cAdd {x y})]) */ + /* 418 */ {{1,/*93 */93 , cCos ,PositionalParams,0}, 0, 0x0}, /* (cCos [(cAdd {x (cMul {-1 y})})]) */ + /* 419 */ {{1,/*120 */120 , cCos ,PositionalParams,0}, 0, 0x0}, /* (cCos [(cAdd <1>)]) */ + /* 420 */ {{1,/*236 */236 , cCos ,PositionalParams,0}, 0, 0x0}, /* (cCos [(cMul {-%@C x})]) */ + /* 421 */ {{1,/*255 */255 , cCos ,PositionalParams,0}, 0, 0x0}, /* (cCos [(cMul -%@C <1>)]) */ + /* 422 */ {{1,/*214 */214 , cCosh ,PositionalParams,0}, 0, 0x0}, /* (cCosh [(cMul {x LOG( & )@C})]) */ + /* 423 */ {{1,/*236 */236 , cCosh ,PositionalParams,0}, 0, 0x0}, /* (cCosh [(cMul {-%@C x})]) */ + /* 424 */ {{1,/*464 */464 , cCosh ,PositionalParams,0}, 0, 0x0}, /* (cCosh [(cLog [(cPow [& x])])]) */ + /* 425 */ {{1,/*0 */0 , cCosh ,PositionalParams,0}, 0, 0x4}, /* (cCosh [x]) */ + /* 426 */ {{1,/*0 */0 , cCosh ,PositionalParams,0}, 0, 0x0}, /* (cCosh [x]) */ + /* 427 */ {{1,/*0 */0 , cExp ,PositionalParams,0}, 0, 0x0}, /* (cExp [x]) */ + /* 428 */ {{1,/*7 */7 , cExp ,PositionalParams,0}, 0, 0x0}, /* (cExp [y]) */ + /* 429 */ {{1,/*92 */92 , cExp ,PositionalParams,0}, 0, 0x0}, /* (cExp [(cAdd {x y})]) */ + /* 430 */ {{1,/*0 */0 , cExp2 ,PositionalParams,0}, 0, 0x0}, /* (cExp2 [x]) */ + /* 431 */ {{1,/*7 */7 , cExp2 ,PositionalParams,0}, 0, 0x0}, /* (cExp2 [y]) */ + /* 432 */ {{1,/*92 */92 , cExp2 ,PositionalParams,0}, 0, 0x0}, /* (cExp2 [(cAdd {x y})]) */ + /* 433 */ {{1,/*246 */246 , cFloor ,PositionalParams,0}, 0, 0x0}, /* (cFloor [(cMul <1>)]) */ + /* 434 */ {{1,/*0 */0 , cFloor ,PositionalParams,0}, 0, 0x4}, /* (cFloor [x]) */ + /* 435 */ {{2,/*292,302 */309540 , cHypot ,PositionalParams,0}, 0, 0x0}, /* (cHypot [(cPow [x MUL( % 0.5 )@C]) (cPow [y MUL( & 0.5 )@C])]) */ + /* 436 */ {{2,/*292,309 */316708 , cHypot ,PositionalParams,0}, 0, 0x0}, /* (cHypot [(cPow [x MUL( % 0.5 )@C]) (cPow [(cMul {y POW( z@C /&@C )@C}) MUL( & 0.5 )@C])]) */ + /* 437 */ {{2,/*308,309 */316724 , cHypot ,PositionalParams,0}, 0, 0x0}, /* (cHypot [(cPow [(cMul {x POW( a@C /%@C )@C}) MUL( % 0.5 )@C]) (cPow [(cMul {y POW( z@C /&@C )@C}) MUL( & 0.5 )@C])]) */ + /* 438 */ {{3,/*0,7,31 */32513024 , cIf ,PositionalParams,0}, 0, 0x4}, /* (cIf [x y z]) */ + /* 439 */ {{3,/*0,24,33 */34627584 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x & z@C]) */ + /* 440 */ {{3,/*0,35,30 */31493120 , cIf ,PositionalParams,0}, 0, 0x4}, /* (cIf [x a b]) */ + /* 441 */ {{3,/*0,83,85 */89213952 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cAdd {y a}) (cAdd {z b})]) */ + /* 442 */ {{3,/*0,141,142 */149042176 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x ADD( % & )@C ADD( % z@C )@C]) */ + /* 443 */ {{3,/*0,227,235 */246647808 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cMul {y a}) (cMul {z b})]) */ + /* 444 */ {{3,/*0,286,287 */301234176 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x MUL( % & )@C MUL( % z@C )@C]) */ + /* 445 */ {{3,/*0,470,471 */494360576 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cMax [y a]) (cMax [z b])]) */ + /* 446 */ {{3,/*0,474,475 */498558976 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cMin [y a]) (cMin [z b])]) */ + /* 447 */ {{3,/*528,18,60 */62933520 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [(cLess [x 0]) %@D1 -%@C@D1]) */ + /* 448 */ {{3,/*528,18,60 */62933520 , cIf ,PositionalParams,0}, 0, 0x4}, /* (cIf [(cLess [x 0]) %@D1 -%@C@D1]) */ + /* 449 */ {{3,/*534,18,60 */62933526 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [(cGreater [x 0]) %@D1 -%@C@D1]) */ + /* 450 */ {{3,/*534,18,60 */62933526 , cIf ,PositionalParams,0}, 0, 0x4}, /* (cIf [(cGreater [x 0]) %@D1 -%@C@D1]) */ + /* 451 */ {{3,/*0,540,23 */24670208 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cNot [y]) %@L]) */ + /* 452 */ {{3,/*0,551,552 */579378176 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cAnd {y a}) (cAnd {z b})]) */ + /* 453 */ {{3,/*0,7,547 */573578240 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x y (cNot [%])]) */ + /* 454 */ {{3,/*0,7,31 */32513024 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x y z]) */ + /* 455 */ {{3,/*0,23,540 */566254592 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x %@L (cNot [y])]) */ + /* 456 */ {{3,/*0,547,7 */7900160 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cNot [%]) y]) */ + /* 457 */ {{3,/*0,558,561 */588822528 , cIf ,PositionalParams,0}, 0, 0x0}, /* (cIf [x (cOr {y a}) (cOr {z b})]) */ + /* 458 */ {{1,/*120 */120 , cInt ,PositionalParams,0}, 0, 0x0}, /* (cInt [(cAdd <1>)]) */ + /* 459 */ {{1,/*246 */246 , cLog ,PositionalParams,0}, 0, 0x0}, /* (cLog [(cMul <1>)]) */ + /* 460 */ {{1,/*0 */0 , cLog ,PositionalParams,0}, 0, 0x0}, /* (cLog [x]) */ + /* 461 */ {{1,/*7 */7 , cLog ,PositionalParams,0}, 0, 0x0}, /* (cLog [y]) */ + /* 462 */ {{1,/*31 */31 , cLog ,PositionalParams,0}, 0, 0x0}, /* (cLog [z]) */ + /* 463 */ {{1,/*194 */194 , cLog ,PositionalParams,0}, 0, 0x0}, /* (cLog [(cMul {x y})]) */ + /* 464 */ {{1,/*363 */363 , cLog ,PositionalParams,0}, 0, 0x0}, /* (cLog [(cPow [& x])]) */ + /* 465 */ {{1,/*15 */15 , cLog ,GroupFunction ,0}, Constness_Const, 0x0}, /* LOG( % )@C */ + /* 466 */ {{1,/*24 */24 , cLog ,GroupFunction ,0}, Constness_Const, 0x0}, /* LOG( & )@C */ + /* 467 */ {{1,/*0 */0 , cLog10 ,PositionalParams,0}, 0, 0x0}, /* (cLog10 [x]) */ + /* 468 */ {{1,/*0 */0 , cLog2 ,PositionalParams,0}, 0, 0x0}, /* (cLog2 [x]) */ + /* 469 */ {{2,/*0,7 */7168 , cMax ,PositionalParams,0}, 0, 0x0}, /* (cMax [x y]) */ + /* 470 */ {{2,/*7,35 */35847 , cMax ,PositionalParams,0}, 0, 0x0}, /* (cMax [y a]) */ + /* 471 */ {{2,/*31,30 */30751 , cMax ,PositionalParams,0}, 0, 0x0}, /* (cMax [z b]) */ + /* 472 */ {{1,/*0 */0 , cMax ,AnyParams ,1}, 0, 0x4}, /* (cMax x <1>) */ + /* 473 */ {{2,/*0,7 */7168 , cMin ,PositionalParams,0}, 0, 0x0}, /* (cMin [x y]) */ + /* 474 */ {{2,/*7,35 */35847 , cMin ,PositionalParams,0}, 0, 0x0}, /* (cMin [y a]) */ + /* 475 */ {{2,/*31,30 */30751 , cMin ,PositionalParams,0}, 0, 0x0}, /* (cMin [z b]) */ + /* 476 */ {{1,/*0 */0 , cMin ,AnyParams ,1}, 0, 0x4}, /* (cMin x <1>) */ + /* 477 */ {{2,/*15,24 */24591 , cMin ,GroupFunction ,0}, Constness_Const, 0x0}, /* MIN( % & )@C */ + /* 478 */ {{1,/*0 */0 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [x]) */ + /* 479 */ {{1,/*7 */7 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [y]) */ + /* 480 */ {{1,/*92 */92 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [(cAdd {x y})]) */ + /* 481 */ {{1,/*93 */93 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [(cAdd {x (cMul {-1 y})})]) */ + /* 482 */ {{1,/*120 */120 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [(cAdd <1>)]) */ + /* 483 */ {{1,/*149 */149 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [(cMul {-1 (cAdd <1>)})]) */ + /* 484 */ {{1,/*231 */231 , cSin ,PositionalParams,0}, 0, 0x5}, /* (cSin [(cMul {% x})]) */ + /* 485 */ {{1,/*246 */246 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [(cMul <1>)]) */ + /* 486 */ {{1,/*255 */255 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [(cMul -%@C <1>)]) */ + /* 487 */ {{1,/*254 */254 , cSin ,PositionalParams,0}, 0, 0x0}, /* (cSin [(cMul %@N <1>)]) */ + /* 488 */ {{1,/*0 */0 , cSin ,PositionalParams,0}, 0, 0x4}, /* (cSin [x]) */ + /* 489 */ {{1,/*273 */273 , cSin ,PositionalParams,0}, 0, 0x1}, /* (cSin [(cMul % <1>)]) */ + /* 490 */ {{1,/*214 */214 , cSinh ,PositionalParams,0}, 0, 0x0}, /* (cSinh [(cMul {x LOG( & )@C})]) */ + /* 491 */ {{1,/*231 */231 , cSinh ,PositionalParams,0}, 0, 0x5}, /* (cSinh [(cMul {% x})]) */ + /* 492 */ {{1,/*246 */246 , cSinh ,PositionalParams,0}, 0, 0x0}, /* (cSinh [(cMul <1>)]) */ + /* 493 */ {{1,/*254 */254 , cSinh ,PositionalParams,0}, 0, 0x0}, /* (cSinh [(cMul %@N <1>)]) */ + /* 494 */ {{1,/*255 */255 , cSinh ,PositionalParams,0}, 0, 0x0}, /* (cSinh [(cMul -%@C <1>)]) */ + /* 495 */ {{1,/*464 */464 , cSinh ,PositionalParams,0}, 0, 0x0}, /* (cSinh [(cLog [(cPow [& x])])]) */ + /* 496 */ {{1,/*0 */0 , cSinh ,PositionalParams,0}, 0, 0x4}, /* (cSinh [x]) */ + /* 497 */ {{1,/*0 */0 , cSinh ,PositionalParams,0}, 0, 0x0}, /* (cSinh [x]) */ + /* 498 */ {{1,/*15 */15 , cSqrt ,GroupFunction ,0}, Constness_Const, 0x0}, /* SQRT( % )@C */ + /* 499 */ {{1,/*0 */0 , cTan ,PositionalParams,0}, 0, 0x0}, /* (cTan [x]) */ + /* 500 */ {{1,/*0 */0 , cTan ,PositionalParams,0}, 0, 0x4}, /* (cTan [x]) */ + /* 501 */ {{1,/*116 */116 , cTan ,PositionalParams,0}, 0, 0x4}, /* (cTan [(cAdd {1.57079632679 (cMul {-1 x})})]) */ + /* 502 */ {{1,/*117 */117 , cTan ,PositionalParams,0}, 0, 0x0}, /* (cTan [(cAdd {1.57079632679 (cMul -1 <1>)})]) */ + /* 503 */ {{1,/*231 */231 , cTan ,PositionalParams,0}, 0, 0x0}, /* (cTan [(cMul {% x})]) */ + /* 504 */ {{1,/*246 */246 , cTan ,PositionalParams,0}, 0, 0x0}, /* (cTan [(cMul <1>)]) */ + /* 505 */ {{1,/*273 */273 , cTan ,PositionalParams,0}, 0, 0x0}, /* (cTan [(cMul % <1>)]) */ + /* 506 */ {{1,/*254 */254 , cTan ,PositionalParams,0}, 0, 0x0}, /* (cTan [(cMul %@N <1>)]) */ + /* 507 */ {{1,/*255 */255 , cTan ,PositionalParams,0}, 0, 0x0}, /* (cTan [(cMul -%@C <1>)]) */ + /* 508 */ {{1,/*0 */0 , cTanh ,PositionalParams,0}, 0, 0x0}, /* (cTanh [x]) */ + /* 509 */ {{1,/*0 */0 , cTanh ,PositionalParams,0}, 0, 0x4}, /* (cTanh [x]) */ + /* 510 */ {{1,/*213 */213 , cTanh ,PositionalParams,0}, 0, 0x0}, /* (cTanh [(cMul {x LOG( % )@C 0.5})]) */ + /* 511 */ {{1,/*231 */231 , cTanh ,PositionalParams,0}, 0, 0x0}, /* (cTanh [(cMul {% x})]) */ + /* 512 */ {{1,/*246 */246 , cTanh ,PositionalParams,0}, 0, 0x0}, /* (cTanh [(cMul <1>)]) */ + /* 513 */ {{1,/*254 */254 , cTanh ,PositionalParams,0}, 0, 0x0}, /* (cTanh [(cMul %@N <1>)]) */ + /* 514 */ {{1,/*255 */255 , cTanh ,PositionalParams,0}, 0, 0x0}, /* (cTanh [(cMul -%@C <1>)]) */ + /* 515 */ {{1,/*0 */0 , cTrunc ,PositionalParams,0}, 0, 0x0}, /* (cTrunc [x]) */ + /* 516 */ {{2,/*24,15 */15384 , cSub ,GroupFunction ,0}, Constness_Const, 0x0}, /* SUB( & % )@C */ + /* 517 */ {{2,/*24,15 */15384 , cDiv ,GroupFunction ,0}, Constness_Const, 0x0}, /* DIV( & % )@C */ + /* 518 */ {{2,/*466,465 */476626 , cDiv ,GroupFunction ,0}, Constness_Const, 0x0}, /* DIV( LOG( & )@C LOG( % )@C )@C */ + /* 519 */ {{2,/*57,120 */122937 , cEqual ,PositionalParams,0}, 0, 0x0}, /* (cEqual [-%@C (cAdd <1>)]) */ + /* 520 */ {{2,/*0,7 */7168 , cEqual ,PositionalParams,0}, 0, 0x12}, /* (cEqual [x y]) */ + /* 521 */ {{2,/*0,7 */7168 , cEqual ,PositionalParams,0}, 0, 0x0}, /* (cEqual [x y]) */ + /* 522 */ {{2,/*0,31 */31744 , cEqual ,PositionalParams,0}, 0, 0x20}, /* (cEqual [x z]) */ + /* 523 */ {{2,/*7,31 */31751 , cEqual ,PositionalParams,0}, 0, 0x24}, /* (cEqual [y z]) */ + /* 524 */ {{2,/*7,31 */31751 , cEqual ,PositionalParams,0}, 0, 0x0}, /* (cEqual [y z]) */ + /* 525 */ {{2,/*57,120 */122937 , cNEqual ,PositionalParams,0}, 0, 0x0}, /* (cNEqual [-%@C (cAdd <1>)]) */ + /* 526 */ {{2,/*0,7 */7168 , cLess ,PositionalParams,0}, 0, 0x12}, /* (cLess [x y]) */ + /* 527 */ {{2,/*0,41 */41984 , cLess ,PositionalParams,0}, 0, 0x4}, /* (cLess [x 0]) */ + /* 528 */ {{2,/*0,41 */41984 , cLess ,PositionalParams,0}, 0, 0x0}, /* (cLess [x 0]) */ + /* 529 */ {{2,/*7,0 */7 , cLess ,PositionalParams,0}, 0, 0x0}, /* (cLess [y x]) */ + /* 530 */ {{2,/*0,7 */7168 , cLessOrEq ,PositionalParams,0}, 0, 0x0}, /* (cLessOrEq [x y]) */ + /* 531 */ {{2,/*246,289 */296182 , cLessOrEq ,PositionalParams,0}, 0, 0x0}, /* (cLessOrEq [(cMul <1>) MUL( 0.5 /%@C )@C]) */ + /* 532 */ {{2,/*0,7 */7168 , cGreater ,PositionalParams,0}, 0, 0x12}, /* (cGreater [x y]) */ + /* 533 */ {{2,/*0,41 */41984 , cGreater ,PositionalParams,0}, 0, 0x4}, /* (cGreater [x 0]) */ + /* 534 */ {{2,/*0,41 */41984 , cGreater ,PositionalParams,0}, 0, 0x0}, /* (cGreater [x 0]) */ + /* 535 */ {{2,/*7,0 */7 , cGreater ,PositionalParams,0}, 0, 0x0}, /* (cGreater [y x]) */ + /* 536 */ {{2,/*0,7 */7168 , cGreaterOrEq,PositionalParams,0}, 0, 0x0}, /* (cGreaterOrEq [x y]) */ + /* 537 */ {{2,/*246,289 */296182 , cGreaterOrEq,PositionalParams,0}, 0, 0x0}, /* (cGreaterOrEq [(cMul <1>) MUL( 0.5 /%@C )@C]) */ + /* 538 */ {{1,/*0 */0 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [x]) */ + /* 539 */ {{1,/*245 */245 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [(cMul {x 0.5 /%@C})]) */ + /* 540 */ {{1,/*7 */7 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [y]) */ + /* 541 */ {{1,/*550 */550 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [(cAnd {x y})]) */ + /* 542 */ {{1,/*553 */553 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [(cAnd {z (cIf [x y (cNot [%])])})]) */ + /* 543 */ {{1,/*554 */554 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [(cAnd {z (cIf [x (cNot [%]) y])})]) */ + /* 544 */ {{1,/*556 */556 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [(cOr {x y})]) */ + /* 545 */ {{1,/*31 */31 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [z]) */ + /* 546 */ {{1,/*559 */559 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [(cOr {z (cIf [x y (cNot [%])])})]) */ + /* 547 */ {{1,/*15 */15 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [%]) */ + /* 548 */ {{1,/*560 */560 , cNot ,PositionalParams,0}, 0, 0x0}, /* (cNot [(cOr {z (cIf [x (cNot [%]) y])})]) */ + /* 549 */ {{2,/*538,7 */7706 , cAnd ,SelectedParams ,0}, 0, 0x0}, /* (cAnd {(cNot [x]) y}) */ + /* 550 */ {{2,/*0,7 */7168 , cAnd ,SelectedParams ,0}, 0, 0x0}, /* (cAnd {x y}) */ + /* 551 */ {{2,/*7,35 */35847 , cAnd ,SelectedParams ,0}, 0, 0x0}, /* (cAnd {y a}) */ + /* 552 */ {{2,/*31,30 */30751 , cAnd ,SelectedParams ,0}, 0, 0x0}, /* (cAnd {z b}) */ + /* 553 */ {{2,/*31,453 */463903 , cAnd ,SelectedParams ,0}, 0, 0x0}, /* (cAnd {z (cIf [x y (cNot [%])])}) */ + /* 554 */ {{2,/*31,456 */466975 , cAnd ,SelectedParams ,0}, 0, 0x0}, /* (cAnd {z (cIf [x (cNot [%]) y])}) */ + /* 555 */ {{0,/* */0 , cAnd ,AnyParams ,1}, 0, 0x0}, /* (cAnd <1>) */ + /* 556 */ {{2,/*0,7 */7168 , cOr ,SelectedParams ,0}, 0, 0x0}, /* (cOr {x y}) */ + /* 557 */ {{2,/*538,7 */7706 , cOr ,SelectedParams ,0}, 0, 0x0}, /* (cOr {(cNot [x]) y}) */ + /* 558 */ {{2,/*7,35 */35847 , cOr ,SelectedParams ,0}, 0, 0x0}, /* (cOr {y a}) */ + /* 559 */ {{2,/*31,453 */463903 , cOr ,SelectedParams ,0}, 0, 0x0}, /* (cOr {z (cIf [x y (cNot [%])])}) */ + /* 560 */ {{2,/*31,456 */466975 , cOr ,SelectedParams ,0}, 0, 0x0}, /* (cOr {z (cIf [x (cNot [%]) y])}) */ + /* 561 */ {{2,/*31,30 */30751 , cOr ,SelectedParams ,0}, 0, 0x0}, /* (cOr {z b}) */ + /* 562 */ {{1,/*0 */0 , cNotNot ,PositionalParams,0}, 0, 0x0}, /* (cNotNot [x]) */ + /* 563 */ {{1,/*92 */92 , cNotNot ,PositionalParams,0}, 0, 0x0}, /* (cNotNot [(cAdd {x y})]) */ + /* 564 */ {{1,/*131 */131 , cNotNot ,PositionalParams,0}, 0, 0x0}, /* (cNotNot [(cAdd x <1>)]) */ + /* 565 */ {{1,/*245 */245 , cNotNot ,PositionalParams,0}, 0, 0x0}, /* (cNotNot [(cMul {x 0.5 /%@C})]) */ + /* 566 */ {{1,/*215 */215 , cNotNot ,PositionalParams,0}, 0, 0x0}, /* (cNotNot [(cMul {x (cAnd <1>)})]) */ + /* 567 */ {{1,/*246 */246 , cDeg ,PositionalParams,0}, 0, 0x0}, /* (cDeg [(cMul <1>)]) */ + /* 568 */ {{1,/*246 */246 , cRad ,PositionalParams,0}, 0, 0x0}, /* (cRad [(cMul <1>)]) */ + /* 569 */ {{2,/*0,7 */7168 , cAbsAnd ,SelectedParams ,0}, 0, 0x0}, /* (cAbsAnd {x y}) */ + /* 570 */ {{2,/*0,7 */7168 , cAbsOr ,SelectedParams ,0}, 0, 0x0}, /* (cAbsOr {x y}) */ + /* 571 */ {{1,/*0 */0 , cAbsNot ,PositionalParams,0}, 0, 0x0}, /* (cAbsNot [x]) */ + /* 572 */ {{1,/*0 */0 , cAbsNotNot ,PositionalParams,0}, 0, 0x0}, /* (cAbsNotNot [x]) */ + /* 573 */ {{3,/*0,7,31 */32513024 , cAbsIf ,PositionalParams,0}, 0, 0x0}, /* (cAbsIf [x y z]) */ + }; + +} +namespace FPoptimizer_Grammar +{ + const Rule grammar_rules[262] = + { + /* 0: @R @L (cAbs [x]) + * -> x + */ {ProduceNewTree, 17, 1,/*0 */0 , {1,/*0 */0 , cAbs ,PositionalParams,0}}, + /* 1: @R @F (cAtan [(cMul {x (cPow [y %@N])})]) + * -> (cAtan2 [x (cPow [y -%@C])]) + */ {ProduceNewTree, 18, 1,/*409 */409 , {1,/*146 */146 , cAtan ,PositionalParams,0}}, + /* 2: @R @F (cAtan2 [(cPow [(cAdd {(cMul {(cPow [x 2]) -1}) 1}) 0.5])@D4 x@D4]) + * -> (cAcos [x]) + */ {ProduceNewTree, 18, 1,/*403 */403 , {2,/*300,1 */1324 , cAtan2 ,PositionalParams,0}}, + /* 3: @R @F (cAtan2 [x@D4 (cPow [(cAdd {(cMul {(cPow [x 2]) -1}) 1}) 0.5])@D4]) + * -> (cAsin [x]) + */ {ProduceNewTree, 18, 1,/*405 */405 , {2,/*1,300 */307201 , cAtan2 ,PositionalParams,0}}, + /* 4: @R @F (cAtan2 [(cMul x@P <1>)@D4 (cMul x@P <2>)@D4]) + * : (cMul <1>) (cMul <2>) + */ {ReplaceParams , 18, 2,/*246,247 */253174 , {2,/*248,249 */255224 , cAtan2 ,PositionalParams,0}}, + /* 5: @R @F (cAtan2 [(cMul x@N@V <1>)@D4 (cMul x@N@V <2>)@D4]) + * : (cMul -1 <1>) (cMul -1 <2>) + */ {ReplaceParams , 18, 2,/*252,253 */259324 , {2,/*250,251 */257274 , cAtan2 ,PositionalParams,0}}, + /* 6: @R @F (cCeil [(cMul -1 <1>)]) + * -> (cMul {-1 (cFloor [(cMul <1>)])}) + */ {ProduceNewTree, 18, 1,/*152 */152 , {1,/*252 */252 , cCeil ,PositionalParams,0}}, + /* 7: @F (cCos [(cAdd {1.57079632679 (cMul %@N <1>)})]) + * -> (cSin [(cMul -%@C <1>)]) + */ {ProduceNewTree, 2, 1,/*486 */486 , {1,/*68 */68 , cCos ,PositionalParams,0}}, + /* 8: @F (cCos [(cAdd -1.57079632679 <1>)]) + * -> (cSin [(cAdd <1>)]) + */ {ProduceNewTree, 2, 1,/*482 */482 , {1,/*123 */123 , cCos ,PositionalParams,0}}, + /* 9: @F (cCos [(cAdd 1.57079632679 <1>)]) + * -> (cSin [(cMul {-1 (cAdd <1>)})]) + */ {ProduceNewTree, 2, 1,/*483 */483 , {1,/*125 */125 , cCos ,PositionalParams,0}}, + /* 10: @F (cCos [(cAdd 3.14159265359 <1>)]) + * -> (cMul {-1 (cCos [(cAdd <1>)])}) + */ {ProduceNewTree, 2, 1,/*151 */151 , {1,/*126 */126 , cCos ,PositionalParams,0}}, + /* 11: @F (cCos [(cAdd 0 <1>)]) + * -> (cCos [(cAdd <1>)]) + */ {ProduceNewTree, 2, 1,/*419 */419 , {1,/*124 */124 , cCos ,PositionalParams,0}}, + /* 12: @F (cCos [(cAcos [x])]) + * -> x + */ {ProduceNewTree, 2, 1,/*0 */0 , {1,/*403 */403 , cCos ,PositionalParams,0}}, + /* 13: @F (cCos [(cMul -1 <1>)]) + * : (cMul <1>) + */ {ReplaceParams , 2, 1,/*246 */246 , {1,/*252 */252 , cCos ,PositionalParams,0}}, + /* 14: @R @F (cCos [(cAbs [x])]) + * : x + */ {ReplaceParams , 18, 1,/*0 */0 , {1,/*400 */400 , cCos ,PositionalParams,0}}, + /* 15: @F (cCosh [(cAsinh [x])]) + * -> (cPow [(cAdd {(cPow [x 2]) 1}) 0.5]) + */ {ProduceNewTree, 2, 1,/*301 */301 , {1,/*406 */406 , cCosh ,PositionalParams,0}}, + /* 16: @F (cCosh [(cMul -1 <1>)]) + * : (cMul <1>) + */ {ReplaceParams , 2, 1,/*246 */246 , {1,/*252 */252 , cCosh ,PositionalParams,0}}, + /* 17: @R @F (cCosh [(cAbs [x])]) + * : x + */ {ReplaceParams , 18, 1,/*0 */0 , {1,/*400 */400 , cCosh ,PositionalParams,0}}, + /* 18: @F (cFloor [(cAdd 0.5 <1>)]) + * -> (cInt [(cAdd <1>)]) + */ {ProduceNewTree, 2, 1,/*458 */458 , {1,/*122 */122 , cFloor ,PositionalParams,0}}, + /* 19: @R @F (cFloor [(cMul -1 <1>)]) + * -> (cMul {-1 (cCeil [(cMul <1>)])}) + */ {ProduceNewTree, 18, 1,/*150 */150 , {1,/*252 */252 , cFloor ,PositionalParams,0}}, + /* 20: (cIf [x 0 y]) + * -> (cMul {(cNot [x]) y}) + */ {ProduceNewTree, 0, 1,/*156 */156 , {3,/*0,41,7 */7382016 , cIf ,PositionalParams,0}}, + /* 21: (cIf [x 0 y@L]) + * -> (cAnd {(cNot [x]) y}) + */ {ProduceNewTree, 0, 1,/*549 */549 , {3,/*0,41,8 */8430592 , cIf ,PositionalParams,0}}, + /* 22: (cIf [x 1 y@L]) + * -> (cOr {x y}) + */ {ProduceNewTree, 0, 1,/*556 */556 , {3,/*0,47,8 */8436736 , cIf ,PositionalParams,0}}, + /* 23: (cIf [x y 0]) + * -> (cMul {(cNotNot [x]) y}) + */ {ProduceNewTree, 0, 1,/*157 */157 , {3,/*0,7,41 */42998784 , cIf ,PositionalParams,0}}, + /* 24: (cIf [x y@L 0]) + * -> (cAnd {x y}) + */ {ProduceNewTree, 0, 1,/*550 */550 , {3,/*0,8,41 */42999808 , cIf ,PositionalParams,0}}, + /* 25: (cIf [x 1 0]) + * -> (cNotNot [x]) + */ {ProduceNewTree, 0, 1,/*562 */562 , {3,/*0,47,41 */43039744 , cIf ,PositionalParams,0}}, + /* 26: (cIf [x y@L 1]) + * -> (cOr {(cNot [x]) y}) + */ {ProduceNewTree, 0, 1,/*557 */557 , {3,/*0,8,47 */49291264 , cIf ,PositionalParams,0}}, + /* 27: (cIf [x 0 1]) + * -> (cNot [x]) + */ {ProduceNewTree, 0, 1,/*538 */538 , {3,/*0,41,47 */49325056 , cIf ,PositionalParams,0}}, + /* 28: (cIf [(cLess [x y])@D12 y@D8 x@D4]) + * -> (cMax [x y]) + */ {ProduceNewTree, 0, 1,/*469 */469 , {3,/*526,9,1 */1058318 , cIf ,PositionalParams,0}}, + /* 29: (cIf [(cGreater [x y])@D12 y@D8 x@D4]) + * -> (cMin [x y]) + */ {ProduceNewTree, 0, 1,/*473 */473 , {3,/*532,9,1 */1058324 , cIf ,PositionalParams,0}}, + /* 30: (cIf [(cLess [x y])@D12 x@D4 y@D8]) + * -> (cMin [x y]) + */ {ProduceNewTree, 0, 1,/*473 */473 , {3,/*526,1,9 */9438734 , cIf ,PositionalParams,0}}, + /* 31: (cIf [(cGreater [x y])@D12 x@D4 y@D8]) + * -> (cMax [x y]) + */ {ProduceNewTree, 0, 1,/*469 */469 , {3,/*532,1,9 */9438740 , cIf ,PositionalParams,0}}, + /* 32: (cIf [(cLessOrEq [x y]) z a]) + * : (cLess [y x]) a z + */ {ReplaceParams , 0, 3,/*529,35,31 */32542225 , {3,/*530,31,35 */36732434 , cIf ,PositionalParams,0}}, + /* 33: (cIf [(cGreaterOrEq [x y]) z a]) + * : (cGreater [y x]) a z + */ {ReplaceParams , 0, 3,/*535,35,31 */32542231 , {3,/*536,31,35 */36732440 , cIf ,PositionalParams,0}}, + /* 34: @R (cIf [x@P y z]) + * -> (cAbsIf [x y z]) + */ {ProduceNewTree, 16, 1,/*573 */573 , {3,/*2,7,31 */32513026 , cIf ,PositionalParams,0}}, + /* 35: @R (cIf [(cLess [x 0])@D4 (cCeil [x])@D4 (cFloor [x])@D4]) + * -> (cTrunc [x]) + */ {ProduceNewTree, 16, 1,/*515 */515 , {3,/*527,413,434*/455505423 , cIf ,PositionalParams,0}}, + /* 36: @R (cIf [(cGreater [x 0])@D4 (cFloor [x])@D4 (cCeil [x])@D4]) + * -> (cTrunc [x]) + */ {ProduceNewTree, 16, 1,/*515 */515 , {3,/*533,434,413*/433506837 , cIf ,PositionalParams,0}}, + /* 37: @F (cLog [(cMul %@P <1>)]) + * -> (cAdd {(cLog [(cMul <1>)]) LOG( % )@C}) + */ {ProduceNewTree, 2, 1,/*78 */78 , {1,/*256 */256 , cLog ,PositionalParams,0}}, + /* 38: @F (cLog [(cMul (cPow [% y]) <1>)]) + * -> (cAdd {(cMul {LOG( % )@C y}) (cLog [(cMul <1>)])}) + */ {ProduceNewTree, 2, 1,/*69 */69 , {1,/*258 */258 , cLog ,PositionalParams,0}}, + /* 39: @F (cLog [(cAdd {(cPow [(cAdd {-1 (cPow [x 2])}) 0.5])@D4 x@D4})]) + * -> (cAcosh [x]) + */ {ProduceNewTree, 2, 1,/*404 */404 , {1,/*72 */72 , cLog ,PositionalParams,0}}, + /* 40: @F (cLog [(cMul {(cAdd {1 x})@D4 (cPow [(cAdd {1 (cMul {-1 x})}) -1])@D4})]) + * -> (cMul {(cAtanh [x]) 2}) + */ {ProduceNewTree, 2, 1,/*159 */159 , {1,/*147 */147 , cLog ,PositionalParams,0}}, + /* 41: (cMax x@D4 (cMin x <1>)@D4) + * : x + */ {ReplaceParams , 0, 1,/*0 */0 , {2,/*1,476 */487425 , cMax ,AnyParams ,0}}, + /* 42: @R (cMax (cIf [x y z])@D4 (cIf [x a b])@D4) + * : (cIf [x (cMax [y a]) (cMax [z b])]) + */ {ReplaceParams , 16, 1,/*445 */445 , {2,/*438,440 */450998 , cMax ,AnyParams ,0}}, + /* 43: (cMin x@D4 (cMax x <1>)@D4) + * : x + */ {ReplaceParams , 0, 1,/*0 */0 , {2,/*1,472 */483329 , cMin ,AnyParams ,0}}, + /* 44: @R (cMin (cIf [x y z])@D4 (cIf [x a b])@D4) + * : (cIf [x (cMin [y a]) (cMin [z b])]) + */ {ReplaceParams , 16, 1,/*446 */446 , {2,/*438,440 */450998 , cMin ,AnyParams ,0}}, + /* 45: (cPow [(cMul %@P <1>) &]) + * -> (cMul {POW( % & )@C (cPow [(cMul <1>) &])}) + */ {ProduceNewTree, 0, 1,/*153 */153 , {2,/*256,24 */24832 , cPow ,PositionalParams,0}}, + /* 46: (cPow [(cMul %@N <1>) &@E]) + * -> (cMul {POW( % & )@C (cPow [(cMul <1>) &])}) + */ {ProduceNewTree, 0, 1,/*153 */153 , {2,/*254,25 */25854 , cPow ,PositionalParams,0}}, + /* 47: (cPow [% (cAdd &@M <1>)]) + * -> (cMul {POW( % & )@C (cPow [% (cAdd <1>)])}) + */ {ProduceNewTree, 0, 1,/*154 */154 , {2,/*15,127 */130063 , cPow ,PositionalParams,0}}, + /* 48: (cPow [(cPow [x y@O]) z]) + * : x (cMul {y z}) + */ {ReplaceParams , 0, 2,/*0,162 */165888 , {2,/*311,31 */32055 , cPow ,PositionalParams,0}}, + /* 49: (cPow [(cPow [x y@F]) z]) + * : x (cMul {y z}) + */ {ReplaceParams , 0, 2,/*0,162 */165888 , {2,/*312,31 */32056 , cPow ,PositionalParams,0}}, + /* 50: (cPow [(cPow [x@P y]) z]) + * : x (cMul {y z}) + */ {ReplaceParams , 0, 2,/*0,162 */165888 , {2,/*313,31 */32057 , cPow ,PositionalParams,0}}, + /* 51: (cPow [(cPow [x y])@P z]) + * : (cAbs [x]) (cMul {y z}) + */ {ReplaceParams , 0, 2,/*400,162 */166288 , {2,/*393,31 */32137 , cPow ,PositionalParams,0}}, + /* 52: (cPow [(cPow [x y]) z@I]) + * : x (cMul {y z}) + */ {ReplaceParams , 0, 2,/*0,162 */165888 , {2,/*314,32 */33082 , cPow ,PositionalParams,0}}, + /* 53: (cPow [(cAbs [x]) y@E]) + * : x y + */ {ReplaceParams , 0, 2,/*0,7 */7168 , {2,/*400,12 */12688 , cPow ,PositionalParams,0}}, + /* 54: (cPow [(cMul (cAbs [x]) <1>) y@E]) + * : (cMul x <1>) y + */ {ReplaceParams , 0, 2,/*266,7 */7434 , {2,/*265,12 */12553 , cPow ,PositionalParams,0}}, + /* 55: @F (cPow [(cAdd [(cPow [x %@E]) (cPow [y &@E])]) 0.5]) + * -> (cHypot [(cPow [x MUL( % 0.5 )@C]) (cPow [y MUL( & 0.5 )@C])]) + */ {ProduceNewTree, 2, 1,/*435 */435 , {2,/*66,45 */46146 , cPow ,PositionalParams,0}}, + /* 56: @F (cPow [(cAdd {(cPow [x %@E]) (cMul {z@C (cPow [y &@E])})}) 0.5]) + * -> (cHypot [(cPow [x MUL( % 0.5 )@C]) (cPow [(cMul {y POW( z@C /&@C )@C}) MUL( & 0.5 )@C])]) + */ {ProduceNewTree, 2, 1,/*436 */436 , {2,/*74,45 */46154 , cPow ,PositionalParams,0}}, + /* 57: @F (cPow [(cAdd {(cMul {a@C (cPow [x %@E])}) (cMul {z@C (cPow [y &@E])})}) 0.5]) + * -> (cHypot [(cPow [(cMul {x POW( a@C /%@C )@C}) MUL( % 0.5 )@C]) (cPow [(cMul {y POW( z@C /&@C )@C}) MUL( & 0.5 )@C])]) + */ {ProduceNewTree, 2, 1,/*437 */437 , {2,/*70,45 */46150 , cPow ,PositionalParams,0}}, + /* 58: @F (cPow [% (cAdd {(cLog [x]) &})]) + * -> (cMul {POW( % & )@C (cPow [x LOG( % )@C])}) + */ {ProduceNewTree, 2, 1,/*169 */169 , {2,/*15,82 */83983 , cPow ,PositionalParams,0}}, + /* 59: @F (cPow [z@D16 (cAdd (cMul (cPow [(cLog [z]) -1]) <2>) <1>)@D16]) + * -> (cMul {(cPow [z (cAdd <1>)]) (cPow [2.71828182846 (cMul <2>)])}) + */ {ProduceNewTree, 2, 1,/*168 */168 , {2,/*34,128 */131106 , cPow ,PositionalParams,0}}, + /* 60: @F (cPow [z@D16 (cAdd (cPow [(cLog [z]) -1]) <1>)@D16]) + * -> (cMul {2.71828182846 (cPow [z (cAdd <1>)])}) + */ {ProduceNewTree, 2, 1,/*175 */175 , {2,/*34,130 */133154 , cPow ,PositionalParams,0}}, + /* 61: @F (cPow [% (cLog [x])]) + * : x LOG( % )@C + */ {ReplaceParams , 2, 2,/*0,465 */476160 , {2,/*15,460 */471055 , cPow ,PositionalParams,0}}, + /* 62: @F (cPow [% (cMul (cLog [x]) <1>)]) + * : x (cMul LOG( % )@C <1>) + */ {ReplaceParams , 2, 2,/*0,268 */274432 , {2,/*15,267 */273423 , cPow ,PositionalParams,0}}, + /* 63: @F (cPow [z@D16 (cMul (cPow [(cLog [z]) -1]) (cLog [x]) <1>)@D16]) + * : x (cMul <1>) + */ {ReplaceParams , 2, 2,/*0,246 */251904 , {2,/*34,260 */266274 , cPow ,PositionalParams,0}}, + /* 64: @F (cPow [%@D1 (cMul /LOG( % )@C@C (cLog [x]) <1>)@D1]) + * : x (cMul <1>) + */ {ReplaceParams , 2, 2,/*0,246 */251904 , {2,/*18,257 */263186 , cPow ,PositionalParams,0}}, + /* 65: @F (cSin [(cMul -1 <1>)]) + * -> (cMul {-1 (cSin [(cMul <1>)])}) + */ {ProduceNewTree, 2, 1,/*171 */171 , {1,/*252 */252 , cSin ,PositionalParams,0}}, + /* 66: @F (cSin [(cAdd {1.57079632679 (cMul %@N <1>)})]) + * -> (cCos [(cMul -%@C <1>)]) + */ {ProduceNewTree, 2, 1,/*421 */421 , {1,/*68 */68 , cSin ,PositionalParams,0}}, + /* 67: @F (cSin [(cAdd -1.57079632679 <1>)]) + * -> (cMul {-1 (cCos [(cAdd <1>)])}) + */ {ProduceNewTree, 2, 1,/*151 */151 , {1,/*123 */123 , cSin ,PositionalParams,0}}, + /* 68: @F (cSin [(cAdd 1.57079632679 <1>)]) + * -> (cCos [(cAdd <1>)]) + */ {ProduceNewTree, 2, 1,/*419 */419 , {1,/*125 */125 , cSin ,PositionalParams,0}}, + /* 69: @F (cSin [(cAdd 3.14159265359 <1>)]) + * -> (cMul {-1 (cSin [(cAdd <1>)])}) + */ {ProduceNewTree, 2, 1,/*170 */170 , {1,/*126 */126 , cSin ,PositionalParams,0}}, + /* 70: @F (cSin [(cAdd 0 <1>)]) + * -> (cSin [(cAdd <1>)]) + */ {ProduceNewTree, 2, 1,/*482 */482 , {1,/*124 */124 , cSin ,PositionalParams,0}}, + /* 71: @F (cSin [(cAsin [x])]) + * -> x + */ {ProduceNewTree, 2, 1,/*0 */0 , {1,/*405 */405 , cSin ,PositionalParams,0}}, + /* 72: @F (cSinh [(cMul -1 <1>)]) + * -> (cMul {-1 (cSinh [(cMul <1>)])}) + */ {ProduceNewTree, 2, 1,/*172 */172 , {1,/*252 */252 , cSinh ,PositionalParams,0}}, + /* 73: @F (cSinh [(cAcosh [x])]) + * -> (cPow [(cAdd {(cPow [x 2]) -1}) 0.5]) + */ {ProduceNewTree, 2, 1,/*328 */328 , {1,/*404 */404 , cSinh ,PositionalParams,0}}, + /* 74: @F (cTan [(cMul -1 <1>)]) + * -> (cMul {-1 (cTan [(cMul <1>)])}) + */ {ProduceNewTree, 2, 1,/*173 */173 , {1,/*252 */252 , cTan ,PositionalParams,0}}, + /* 75: @F (cTan [(cAtan [x])]) + * -> x + */ {ProduceNewTree, 2, 1,/*0 */0 , {1,/*408 */408 , cTan ,PositionalParams,0}}, + /* 76: @F (cTan [(cAtan2 [x y])]) + * -> (cMul {x (cPow [y -1])}) + */ {ProduceNewTree, 2, 1,/*176 */176 , {1,/*410 */410 , cTan ,PositionalParams,0}}, + /* 77: @F (cTanh [(cMul -1 <1>)]) + * -> (cMul {-1 (cTanh [(cMul <1>)])}) + */ {ProduceNewTree, 2, 1,/*177 */177 , {1,/*252 */252 , cTanh ,PositionalParams,0}}, + /* 78: (cAdd % (cIf [x & z@C])) + * : (cIf [x ADD( % & )@C ADD( % z@C )@C]) + */ {ReplaceParams , 0, 1,/*442 */442 , {2,/*15,439 */449551 , cAdd ,AnyParams ,0}}, + /* 79: (cAdd (cIf [x y z])@D4 (cIf [x a b])@D4) + * : (cIf [x (cAdd {y a}) (cAdd {z b})]) + */ {ReplaceParams , 0, 1,/*441 */441 , {2,/*438,440 */450998 , cAdd ,AnyParams ,0}}, + /* 80: (cAdd (cMul (cPow [x %@I@P]) <1>)@D4 (cMul (cPow [x &@I]) <2>)@D4) + * : (cMul {(cPow [x MIN( % & )@C]) (cAdd {(cMul (cPow [x (cAdd {% -MIN( % & )@C@C})]) <1>) (cMul (cPow [x (cAdd {& -MIN( % & )@C@C})]) <2>)})}) + */ {ReplaceParams , 0, 1,/*167 */167 , {2,/*261,262 */268549 , cAdd ,AnyParams ,0}}, + /* 81: (cAdd (cMul %@P <1>)@D1 (cMul -%@C <2>)@D1) + * : (cMul {% (cAdd {(cMul <1>) (cMul -1 <2>)})}) + */ {ReplaceParams , 0, 1,/*180 */180 , {2,/*269,270 */276749 , cAdd ,AnyParams ,0}}, + /* 82: (cAdd %@M@D1 (cMul -%@C <2>)@D1) + * : (cMul {% (cAdd {1 (cMul -1 <2>)})}) + */ {ReplaceParams , 0, 1,/*181 */181 , {2,/*20,270 */276500 , cAdd ,AnyParams ,0}}, + /* 83: (cAdd (cMul {%@P (cPow [x 2])})@D4 (cMul {& x y})@D4) + * : (cPow [(cAdd {(cMul {x SQRT( % )@C}) (cMul {y MUL( 0.5 MUL( & /SQRT( % )@C@C )@C )@C})}) 2]) (cMul {(cPow [y 2]) MUL( MUL( -0.25 /%@C )@C POW( & 2 )@C )@C}) + */ {ReplaceParams , 0, 2,/*306,186 */190770 , {2,/*182,185 */189622 , cAdd ,AnyParams ,0}}, + /* 84: (cAdd (cMul {%@P (cAdd {(cPow [x 2]) (cPow [y 2])})})@D12 (cMul {&@P x y})@D12) + * : (cMul {% (cPow [(cAdd {x y}) 2])}) (cMul {ADD( & MUL( -2 % )@C )@C x y}) + */ {ReplaceParams , 0, 2,/*188,190 */194748 , {2,/*187,189 */193723 , cAdd ,AnyParams ,0}}, + /* 85: (cAdd (cMul {%@P (cAdd {(cPow [x 2]) (cPow [y 2])})})@D12 (cMul {&@N x y})@D12) + * : (cMul {% (cPow [(cAdd {x (cMul {-1 y})}) 2])}) (cMul {ADD( & MUL( 2 % )@C )@C x y}) + */ {ReplaceParams , 0, 2,/*191,198 */202943 , {2,/*187,192 */196795 , cAdd ,AnyParams ,0}}, + /* 86: (cAdd (cMul {% (cPow [x y])})@D12 (cPow [x (cMul {2 y})])@D12) + * : (cPow [(cAdd {(cPow [x y]) MUL( % 0.5 )@C}) 2]) -POW( MUL( % 0.5 )@C 2 )@C@C + */ {ReplaceParams , 0, 2,/*307,58 */59699 , {2,/*164,291 */298148 , cAdd ,AnyParams ,0}}, + /* 87: (cAdd (cMul {% (cPow [x (cMul {& y})])})@D14 (cPow [x (cMul {MUL( & 2 )@C y})])@D14) + * : (cPow [(cAdd {(cPow [x (cMul {y &})]) MUL( % 0.5 )@C}) 2]) -POW( MUL( % 0.5 )@C 2 )@C@C + */ {ReplaceParams , 0, 2,/*322,58 */59714 , {2,/*183,318 */325815 , cAdd ,AnyParams ,0}}, + /* 88: (cAdd (cMul {% (cPow [& y])})@D10 (cPow [POW( & 2 )@C y])@D10) + * : (cPow [(cAdd {(cPow [& y]) MUL( % 0.5 )@C}) 2]) -POW( MUL( % 0.5 )@C 2 )@C@C + */ {ReplaceParams , 0, 2,/*332,58 */59724 , {2,/*184,335 */343224 , cAdd ,AnyParams ,0}}, + /* 89: @F (cAdd (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])}) 0.5]) <1>) + * -> (cPow [2.71828182846 (cAsinh [(cAdd <1>)])]) + */ {ProduceNewTree, 2, 1,/*337 */337 , {1,/*333 */333 , cAdd ,AnyParams ,1}}, + /* 90: @F (cAdd (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])}) -0.5]) <1>) + * -> (cPow [0.367879441171 (cAsinh [(cAdd <1>)])]) + */ {ProduceNewTree, 2, 1,/*336 */336 , {1,/*338 */338 , cAdd ,AnyParams ,1}}, + /* 91: @F (cAdd (cPow [(cAdd {1 (cPow [x 2])}) 0.5])@D4 x@D4) + * : (cPow [2.71828182846 (cAsinh [x])]) + */ {ReplaceParams , 2, 1,/*340 */340 , {2,/*339,1 */1363 , cAdd ,AnyParams ,0}}, + /* 92: @F (cAdd (cPow [(cAdd {1 (cPow [x 2])}) -0.5])@D4 x@D4) + * : (cPow [0.367879441171 (cAsinh [x])]) + */ {ReplaceParams , 2, 1,/*342 */342 , {2,/*341,1 */1365 , cAdd ,AnyParams ,0}}, + /* 93: @F (cAdd (cLog [x]) (cLog [y])) + * : (cLog [(cMul {x y})]) + */ {ReplaceParams , 2, 1,/*463 */463 , {2,/*460,461 */472524 , cAdd ,AnyParams ,0}}, + /* 94: @F (cAdd (cPow [(cSin [x]) 2])@D4 (cPow [(cCos [x]) 2])@D4) + * : 1 + */ {ReplaceParams , 2, 1,/*47 */47 , {2,/*359,348 */356711 , cAdd ,AnyParams ,0}}, + /* 95: @F (cAdd 1 (cMul {-1 (cPow [(cSin [x]) 2])})) + * : (cPow [(cCos [x]) 2]) + */ {ReplaceParams , 2, 1,/*349 */349 , {2,/*47,196 */200751 , cAdd ,AnyParams ,0}}, + /* 96: @F (cAdd 1 (cMul {-1 (cPow [(cCos [x]) 2])})) + * : (cPow [(cSin [x]) 2]) + */ {ReplaceParams , 2, 1,/*360 */360 , {2,/*47,195 */199727 , cAdd ,AnyParams ,0}}, + /* 97: @F (cAdd (cMul {(cSin [x]) (cCos [y])})@D12 (cMul {(cCos [x]) (cSin [y])})@D12) + * : (cSin [(cAdd {x y})]) + */ {ReplaceParams , 2, 1,/*480 */480 , {2,/*205,202 */207053 , cAdd ,AnyParams ,0}}, + /* 98: @F (cAdd (cMul {(cSin [x]) (cCos [y])})@D12 (cMul {(cCos [x]) (cSin [y]) -1})@D12) + * : (cSin [(cAdd {x (cMul {-1 y})})]) + */ {ReplaceParams , 2, 1,/*481 */481 , {2,/*205,203 */208077 , cAdd ,AnyParams ,0}}, + /* 99: @F (cAdd (cMul {(cCos [x]) (cCos [y])})@D12 (cMul {(cSin [x]) (cSin [y])})@D12) + * : (cCos [(cAdd {x y})]) + */ {ReplaceParams , 2, 1,/*417 */417 , {2,/*200,206 */211144 , cAdd ,AnyParams ,0}}, + /* 100: @F (cAdd (cMul {(cCos [x]) (cCos [y]) -1})@D12 (cMul {(cSin [x]) (cSin [y])})@D12) + * : (cMul {-1 (cCos [(cAdd {x (cMul {-1 y})})])}) + */ {ReplaceParams , 2, 1,/*209 */209 , {2,/*201,206 */211145 , cAdd ,AnyParams ,0}}, + /* 101: @F (cAdd (cMul {(cCos [x]) (cCos [y])})@D12 (cMul {(cSin [x]) (cSin [y]) -1})@D12) + * : (cCos [(cAdd {x (cMul {-1 y})})]) + */ {ReplaceParams , 2, 1,/*418 */418 , {2,/*200,210 */215240 , cAdd ,AnyParams ,0}}, + /* 102: @F (cAdd (cPow [& x])@D6 (cMul {-1 (cPow [/&@C x])})@D6) + * : (cMul {(cSinh [(cLog [(cPow [& x])])]) 2}) + */ {ReplaceParams , 2, 1,/*212 */212 , {2,/*361,207 */212329 , cAdd ,AnyParams ,0}}, + /* 103: @F (cAdd (cPow [& x])@D6 (cPow [/&@C x])@D6) + * : (cMul {(cCosh [(cLog [(cPow [& x])])]) 2}) + */ {ReplaceParams , 2, 1,/*204 */204 , {2,/*361,364 */373097 , cAdd ,AnyParams ,0}}, + /* 104: @F (cAdd (cMul {-1 (cPow [& x])})@D6 (cPow [/&@C x])@D6) + * : (cMul {(cSinh [(cMul {x LOG( & )@C})]) -2}) + */ {ReplaceParams , 2, 1,/*211 */211 , {2,/*208,364 */372944 , cAdd ,AnyParams ,0}}, + /* 105: @F (cAdd (cMul {% (cPow [& x])})@D7 (cMul {-%@C (cPow [/&@C x])})@D7) + * : (cMul {(cSinh [(cMul {x LOG( & )@C})]) 2 %}) + */ {ReplaceParams , 2, 1,/*217 */217 , {2,/*216,197 */201944 , cAdd ,AnyParams ,0}}, + /* 106: @F (cAdd (cMul {% (cPow [& x])})@D7 (cMul {% (cPow [/&@C x])})@D7) + * : (cMul {(cCosh [(cMul {x LOG( & )@C})]) 2 %}) + */ {ReplaceParams , 2, 1,/*221 */221 , {2,/*216,218 */223448 , cAdd ,AnyParams ,0}}, + /* 107: @F (cAdd (cCosh [x])@D4 (cSinh [x])@D4) + * : (cPow [2.71828182846 x]) + */ {ReplaceParams , 2, 1,/*367 */367 , {2,/*425,496 */508329 , cAdd ,AnyParams ,0}}, + /* 108: @F (cAdd (cMul {(cCosh [x]) -1})@D4 (cSinh [x])@D4) + * : (cMul {(cPow [0.367879441171 x]) -1}) + */ {ReplaceParams , 2, 1,/*219 */219 , {2,/*222,496 */508126 , cAdd ,AnyParams ,0}}, + /* 109: @F (cAdd (cCosh [x])@D4 (cMul {(cPow [2.71828182846 x]) -1})@D4) + * : (cMul {-1 (cSinh [x])}) + */ {ReplaceParams , 2, 1,/*224 */224 , {2,/*425,220 */225705 , cAdd ,AnyParams ,0}}, + /* 110: @F (cAdd (cSinh [x])@D4 (cMul {(cPow [2.71828182846 x]) -1})@D4) + * : (cMul {-1 (cCosh [x])}) + */ {ReplaceParams , 2, 1,/*223 */223 , {2,/*496,220 */225776 , cAdd ,AnyParams ,0}}, + /* 111: @F (cAdd (cCosh [x])@D4 (cMul {(cSinh [x]) -1})@D4) + * : (cPow [0.367879441171 x]) + */ {ReplaceParams , 2, 1,/*365 */365 , {2,/*425,225 */230825 , cAdd ,AnyParams ,0}}, + /* 112: @F (cAdd (cMul {(cSinh [x]) -1})@D4 (cPow [2.71828182846 x])@D4) + * : (cCosh [x]) + */ {ReplaceParams , 2, 1,/*426 */426 , {2,/*225,368 */377057 , cAdd ,AnyParams ,0}}, + /* 113: @F (cAdd (cMul {(cCosh [x]) -1})@D4 (cPow [2.71828182846 x])@D4) + * : (cSinh [x]) + */ {ReplaceParams , 2, 1,/*497 */497 , {2,/*222,368 */377054 , cAdd ,AnyParams ,0}}, + /* 114: @F (cAdd (cCosh [x])@D4 (cMul {(cPow [0.367879441171 x]) -1})@D4) + * : (cSinh [x]) + */ {ReplaceParams , 2, 1,/*497 */497 , {2,/*425,199 */204201 , cAdd ,AnyParams ,0}}, + /* 115: @F (cAdd (cSinh [x])@D4 (cPow [0.367879441171 x])@D4) + * : (cCosh [x]) + */ {ReplaceParams , 2, 1,/*426 */426 , {2,/*496,366 */375280 , cAdd ,AnyParams ,0}}, + /* 116: @F (cAdd (cMul {(cCosh [x]) -1})@D4 (cPow [0.367879441171 x])@D4) + * : (cMul {-1 (cSinh [x])}) + */ {ReplaceParams , 2, 1,/*224 */224 , {2,/*222,366 */375006 , cAdd ,AnyParams ,0}}, + /* 117: @F (cAdd (cMul {-1 (cPow [x 2])})@D4 (cMul {% x})@D4) + * : (cMul {-1 (cPow [(cAdd {x MUL( % -0.5 )@C}) 2])}) POW( MUL( % 0.5 )@C 2 )@C + */ {ReplaceParams , 2, 2,/*229,398 */407781 , {2,/*226,228 */233698 , cAdd ,AnyParams ,0}}, + /* 118: @F (cAdd (cPow [x 2])@D4 (cMul {% x})@D4) + * : (cPow [(cAdd {x MUL( % 0.5 )@C}) 2]) -POW( MUL( % 0.5 )@C 2 )@C@C + */ {ReplaceParams , 2, 2,/*371,58 */59763 , {2,/*370,228 */233842 , cAdd ,AnyParams ,0}}, + /* 119: (cMul (cPow [(cMul x <2>) -1])@D4 x@D4) + * : (cPow [(cMul <2>) -1]) + */ {ReplaceParams , 0, 1,/*372 */372 , {2,/*373,1 */1397 , cMul ,AnyParams ,0}}, + /* 120: (cMul (cAdd (cMul %@M <1>) <2>) &) + * : (cAdd {(cMul % & <1>) (cMul {& (cAdd <2>)})}) + */ {ReplaceParams , 0, 1,/*96 */96 , {2,/*129,24 */24705 , cMul ,AnyParams ,0}}, + /* 121: (cMul (cAdd %@M <1>) &) + * : (cAdd {MUL( % & )@C (cMul {& (cAdd <1>)})}) + */ {ReplaceParams , 0, 1,/*97 */97 , {2,/*132,24 */24708 , cMul ,AnyParams ,0}}, + /* 122: (cMul % (cIf [x & z@C])) + * : (cIf [x MUL( % & )@C MUL( % z@C )@C]) + */ {ReplaceParams , 0, 1,/*444 */444 , {2,/*15,439 */449551 , cMul ,AnyParams ,0}}, + /* 123: (cMul (cIf [x y z])@D4 (cIf [x a b])@D4) + * : (cIf [x (cMul {y a}) (cMul {z b})]) + */ {ReplaceParams , 0, 1,/*443 */443 , {2,/*438,440 */450998 , cMul ,AnyParams ,0}}, + /* 124: (cMul (cPow [x y])@D4 (cAdd {%@1 (cPow [x z])})@D4) + * : (cAdd {(cMul {(cPow [x y]) %}) (cPow [x (cAdd {y z})])}) + */ {ReplaceParams , 0, 1,/*101 */101 , {2,/*374,100 */102774 , cMul ,AnyParams ,0}}, + /* 125: (cMul (cPow [& y]) (cAdd {1 (cPow [x@P z])})) + * : (cAdd {(cPow [& y]) (cPow [& (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})})])}) + */ {ReplaceParams , 0, 1,/*109 */109 , {2,/*325,105 */107845 , cMul ,AnyParams ,0}}, + /* 126: (cMul (cPow [& y]) (cAdd {-1 (cPow [x@P z])})) + * : (cAdd {(cMul {(cPow [& y]) -1}) (cPow [& (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})})])}) + */ {ReplaceParams , 0, 1,/*106 */106 , {2,/*325,102 */104773 , cMul ,AnyParams ,0}}, + /* 127: (cMul (cPow [& y]) (cAdd {(cMul {% (cPow [x@P z])})@D1 %@D1})) + * : % (cAdd {(cPow [& y]) (cPow [& (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})})])}) + */ {ReplaceParams , 0, 2,/*15,109 */111631 , {2,/*325,107 */109893 , cMul ,AnyParams ,0}}, + /* 128: (cMul (cPow [& y]) (cAdd {(cMul {% (cPow [x@P z])})@D1 -%@C@D1})) + * : % (cAdd {(cMul {(cPow [& y]) -1}) (cPow [& (cAdd {y (cMul {z (cLog [x]) /LOG( & )@C@C})})])}) + */ {ReplaceParams , 0, 2,/*15,106 */108559 , {2,/*325,108 */110917 , cMul ,AnyParams ,0}}, + /* 129: @F (cMul {%@D1 (cAdd {1 (cMul {(cLog [x]) /%@C})})@D1}) + * -> (cAdd {(cLog [x]) %}) + */ {ProduceNewTree, 2, 1,/*113 */113 , {2,/*18,110 */112658 , cMul ,SelectedParams ,0}}, + /* 130: @F (cMul 57.2957795131 <1>) + * -> (cDeg [(cMul <1>)]) + */ {ProduceNewTree, 2, 1,/*567 */567 , {1,/*52 */52 , cMul ,AnyParams ,1}}, + /* 131: @F (cMul 0.0174532925199 <1>) + * -> (cRad [(cMul <1>)]) + */ {ProduceNewTree, 2, 1,/*568 */568 , {1,/*42 */42 , cMul ,AnyParams ,1}}, + /* 132: @F (cMul (cLog [x]) 0.434294481903) + * : (cLog10 [x]) + */ {ReplaceParams , 2, 1,/*467 */467 , {2,/*460,44 */45516 , cMul ,AnyParams ,0}}, + /* 133: @F (cMul (cPow [(cLog [x]) -1]) 2.30258509299) + * : (cPow [(cLog10 [x]) -1]) + */ {ReplaceParams , 2, 1,/*356 */356 , {2,/*355,50 */51555 , cMul ,AnyParams ,0}}, + /* 134: @F (cMul (cLog [x]) 1.44269504089) + * : (cLog2 [x]) + */ {ReplaceParams , 2, 1,/*468 */468 , {2,/*460,48 */49612 , cMul ,AnyParams ,0}}, + /* 135: @F (cMul (cPow [(cLog [x]) -1]) 0.69314718056) + * : (cPow [(cLog2 [x]) -1]) + */ {ReplaceParams , 2, 1,/*357 */357 , {2,/*355,46 */47459 , cMul ,AnyParams ,0}}, + /* 136: @F (cMul (cExp [x]) (cExp [y])) + * : (cExp [(cAdd {x y})]) + */ {ReplaceParams , 2, 1,/*429 */429 , {2,/*427,428 */438699 , cMul ,AnyParams ,0}}, + /* 137: @F (cMul (cExp2 [x]) (cExp2 [y])) + * : (cExp2 [(cAdd {x y})]) + */ {ReplaceParams , 2, 1,/*432 */432 , {2,/*430,431 */441774 , cMul ,AnyParams ,0}}, + /* 138: @F (cMul -1 (cSin [(cMul %@N <1>)])) + * : (cSin [(cMul -%@C <1>)]) + */ {ReplaceParams , 2, 1,/*486 */486 , {2,/*38,487 */498726 , cMul ,AnyParams ,0}}, + /* 139: @F (cMul -1 (cSinh [(cMul %@N <1>)])) + * : (cSinh [(cMul -%@C <1>)]) + */ {ReplaceParams , 2, 1,/*494 */494 , {2,/*38,493 */504870 , cMul ,AnyParams ,0}}, + /* 140: @F (cMul (cPow [(cSinh [x]) -1])@D4 (cCosh [x])@D4) + * : (cPow [(cTanh [x]) -1]) + */ {ReplaceParams , 2, 1,/*382 */382 , {2,/*379,425 */435579 , cMul ,AnyParams ,0}}, + /* 141: @F (cMul (cTanh [x])@D4 (cCosh [x])@D4) + * : (cSinh [x]) + */ {ReplaceParams , 2, 1,/*497 */497 , {2,/*509,425 */435709 , cMul ,AnyParams ,0}}, + /* 142: @F (cMul (cPow [(cTanh [x]) -1])@D4 (cSinh [x])@D4) + * : (cCosh [x]) + */ {ReplaceParams , 2, 1,/*426 */426 , {2,/*383,496 */508287 , cMul ,AnyParams ,0}}, + /* 143: @F (cMul (cPow [(cTan [x]) -1])@D4 (cSin [x])@D4) + * : (cCos [x]) + */ {ReplaceParams , 2, 1,/*414 */414 , {2,/*380,488 */500092 , cMul ,AnyParams ,0}}, + /* 144: @F (cMul (cSin [x])@D4 (cPow [(cCos [x]) -1])@D4) + * : (cTan [x]) + */ {ReplaceParams , 2, 1,/*499 */499 , {2,/*488,344 */352744 , cMul ,AnyParams ,0}}, + /* 145: @F (cMul (cTan [x])@D4 (cPow [(cSin [x]) -1])@D4) + * : (cPow [(cCos [x]) -1]) + */ {ReplaceParams , 2, 1,/*345 */345 , {2,/*500,358 */367092 , cMul ,AnyParams ,0}}, + /* 146: @F (cMul (cPow [(cSin [x]) -1])@D4 (cCos [x])@D4) + * : (cPow [(cTan [x]) -1]) + */ {ReplaceParams , 2, 1,/*381 */381 , {2,/*358,415 */425318 , cMul ,AnyParams ,0}}, + /* 147: @F (cMul (cTan [x])@D4 (cCos [x])@D4) + * : (cSin [x]) + */ {ReplaceParams , 2, 1,/*478 */478 , {2,/*500,415 */425460 , cMul ,AnyParams ,0}}, + /* 148: @F (cMul (cTan [(cAdd {1.57079632679 (cMul {-1 x})})])@D4 (cTan [x])@D4) + * : 1 + */ {ReplaceParams , 2, 1,/*47 */47 , {2,/*501,500 */512501 , cMul ,AnyParams ,0}}, + /* 149: @F (cMul (cSin [(cMul % <1>)])@D1 (cPow [(cCos [(cMul -%@C <1>)]) -1])@D1) + * : (cTan [(cMul % <1>)]) + */ {ReplaceParams , 2, 1,/*505 */505 , {2,/*489,347 */355817 , cMul ,AnyParams ,0}}, + /* 150: @F (cMul (cTan [(cAdd {1.57079632679 (cMul -1 <1>)})]) (cTan [(cMul <1>)])) + * : 1 + */ {ReplaceParams , 2, 1,/*47 */47 , {2,/*502,504 */516598 , cMul ,AnyParams ,0}}, + /* 151: @F (cMul -1 (cTan [(cMul %@N <1>)])) + * : (cTan [(cMul -%@C <1>)]) + */ {ReplaceParams , 2, 1,/*507 */507 , {2,/*38,506 */518182 , cMul ,AnyParams ,0}}, + /* 152: @F (cMul (cSinh [x])@D4 (cPow [(cCosh [x]) -1])@D4) + * : (cTanh [x]) + */ {ReplaceParams , 2, 1,/*508 */508 , {2,/*496,350 */358896 , cMul ,AnyParams ,0}}, + /* 153: @F (cMul (cTanh [x])@D4 (cPow [(cSinh [x]) -1])@D4) + * : (cPow [(cCosh [x]) -1]) + */ {ReplaceParams , 2, 1,/*351 */351 , {2,/*509,379 */388605 , cMul ,AnyParams ,0}}, + /* 154: @F (cMul (cSinh [(cMul {% x})])@D5 (cPow [(cCosh [(cMul {-%@C x})]) -1])@D5) + * : (cTanh [(cMul {% x})]) + */ {ReplaceParams , 2, 1,/*511 */511 , {2,/*491,352 */360939 , cMul ,AnyParams ,0}}, + /* 155: @F (cMul (cSin [(cMul {% x})])@D5 (cPow [(cCos [(cMul {-%@C x})]) -1])@D5) + * : (cTan [(cMul {% x})]) + */ {ReplaceParams , 2, 1,/*503 */503 , {2,/*484,346 */354788 , cMul ,AnyParams ,0}}, + /* 156: @F (cMul -1 (cTanh [(cMul %@N <1>)])) + * : (cTanh [(cMul -%@C <1>)]) + */ {ReplaceParams , 2, 1,/*514 */514 , {2,/*38,513 */525350 , cMul ,AnyParams ,0}}, + /* 157: @F (cMul (cAdd {-1 (cPow [% x])})@D5 (cPow [(cAdd {1 (cPow [% x])}) -1])@D5) + * : (cTanh [(cMul {x LOG( % )@C 0.5})]) + */ {ReplaceParams , 2, 1,/*510 */510 , {2,/*103,385 */394343 , cMul ,AnyParams ,0}}, + /* 158: @F (cMul (cAdd {1 (cPow [% x])})@D5 (cPow [(cAdd {-1 (cPow [% x])}) -1])@D5) + * : (cPow [(cTanh [(cMul {x LOG( % )@C 0.5})]) -1]) + */ {ReplaceParams , 2, 1,/*386 */386 , {2,/*115,343 */351347 , cMul ,AnyParams ,0}}, + /* 159: @F (cMul (cSinh [x])@D4 (cPow [(cCosh [x]) %])@D4) + * : (cTanh [x]) (cPow [(cCosh [x]) ADD( % 1 )@C]) + */ {ReplaceParams , 2, 2,/*508,354 */363004 , {2,/*496,353 */361968 , cMul ,AnyParams ,0}}, + /* 160: @R (cMul (cAdd (cIf [(cLess [x 0]) %@D1 -%@C@D1]) <1>)@D4 x@D4) + * : (cAdd {(cMul {(cAbs [x]) -%@C}) (cMul {x (cAdd <1>)})}) + */ {ReplaceParams , 16, 1,/*118 */118 , {2,/*133,1 */1157 , cMul ,AnyParams ,0}}, + /* 161: @R (cMul (cAdd (cIf [(cGreater [x 0]) %@D1 -%@C@D1]) <1>)@D4 x@D4) + * : (cAdd {(cMul {(cAbs [x]) %}) (cMul {x (cAdd <1>)})}) + */ {ReplaceParams , 16, 1,/*119 */119 , {2,/*134,1 */1158 , cMul ,AnyParams ,0}}, + /* 162: @R (cMul (cAbs [x]) (cAbs [y])) + * : (cAbs [(cMul {x y})]) + */ {ReplaceParams , 16, 1,/*402 */402 , {2,/*400,401 */411024 , cMul ,AnyParams ,0}}, + /* 163: @R (cMul (cIf [(cLess [x 0]) %@D1 -%@C@D1])@D4 x@D4) + * : (cAbs [x]) -%@C + */ {ReplaceParams , 16, 2,/*400,57 */58768 , {2,/*448,1 */1472 , cMul ,AnyParams ,0}}, + /* 164: @R (cMul (cIf [(cGreater [x 0]) %@D1 -%@C@D1])@D4 x@D4) + * : (cAbs [x]) % + */ {ReplaceParams , 16, 2,/*400,15 */15760 , {2,/*450,1 */1474 , cMul ,AnyParams ,0}}, + /* 165: @R @L (cMul (cAbs [x])) + * : x + */ {ReplaceParams , 17, 1,/*0 */0 , {1,/*400 */400 , cMul ,AnyParams ,0}}, + /* 166: @R @L (cMul %@N) + * : -%@C + */ {ReplaceParams , 17, 1,/*57 */57 , {1,/*14 */14 , cMul ,AnyParams ,0}}, + /* 167: @I (cEqual [0 x]) + * -> (cNot [x]) + */ {ProduceNewTree, 4, 1,/*538 */538 , {2,/*41,0 */41 , cEqual ,PositionalParams,0}}, + /* 168: @I (cEqual [1 x@L]) + * -> x + */ {ProduceNewTree, 4, 1,/*0 */0 , {2,/*47,5 */5167 , cEqual ,PositionalParams,0}}, + /* 169: @R (cEqual [0 (cAbs [x])]) + * : x 0 + */ {ReplaceParams , 16, 2,/*0,41 */41984 , {2,/*41,400 */409641 , cEqual ,PositionalParams,0}}, + /* 170: @R (cEqual [(cAdd % <1>) &]) + * : (cAdd <1>) SUB( & % )@C + */ {ReplaceParams , 16, 2,/*120,516 */528504 , {2,/*137,24 */24713 , cEqual ,PositionalParams,0}}, + /* 171: @R (cEqual [(cAdd % <1>) (cAdd & <2>)]) + * : (cAdd <1>) (cAdd & -%@C <2>) + */ {ReplaceParams , 16, 2,/*120,139 */142456 , {2,/*137,138 */141449 , cEqual ,PositionalParams,0}}, + /* 172: @R (cEqual [(cAdd x <1>)@D4 (cAdd x <2>)@D4]) + * : (cAdd <1>) (cAdd <2>) + */ {ReplaceParams , 16, 2,/*120,121 */124024 , {2,/*135,136 */139399 , cEqual ,PositionalParams,0}}, + /* 173: @R @F (cEqual [(cMul % <1>) &]) + * : (cMul <1>) DIV( & % )@C + */ {ReplaceParams , 18, 2,/*246,517 */529654 , {2,/*273,24 */24849 , cEqual ,PositionalParams,0}}, + /* 174: @R @F (cEqual [(cPow [x %@P]) &]) + * : (cPow [(cPow [x %]) /%@C]) POW( & /%@C )@C + */ {ReplaceParams , 18, 2,/*388,399 */408964 , {2,/*387,24 */24963 , cEqual ,PositionalParams,0}}, + /* 175: @R @F (cEqual [(cMul % <1>) (cMul & <2>)]) + * : (cMul <1>) (cMul DIV( & % )@C <2>) + */ {ReplaceParams , 18, 2,/*246,276 */282870 , {2,/*273,275 */281873 , cEqual ,PositionalParams,0}}, + /* 176: @R @F (cEqual [(cPow [% x])@D1 (cPow [% y])@D1]) + * : x y + */ {ReplaceParams , 18, 2,/*0,7 */7168 , {2,/*390,392 */401798 , cEqual ,PositionalParams,0}}, + /* 177: @R @F (cEqual [&@P (cPow [%@P x])]) + * : DIV( LOG( & )@C LOG( % )@C )@C x + */ {ReplaceParams , 18, 2,/*518,0 */518 , {2,/*28,391 */400412 , cEqual ,PositionalParams,0}}, + /* 178: @I (cNEqual [0 x]) + * -> (cNotNot [x]) + */ {ProduceNewTree, 4, 1,/*562 */562 , {2,/*41,0 */41 , cNEqual ,PositionalParams,0}}, + /* 179: @I (cNEqual [1 x@L]) + * -> (cNot [x]) + */ {ProduceNewTree, 4, 1,/*538 */538 , {2,/*47,5 */5167 , cNEqual ,PositionalParams,0}}, + /* 180: @R (cNEqual [0 (cAbs [x])]) + * : x 0 + */ {ReplaceParams , 16, 2,/*0,41 */41984 , {2,/*41,400 */409641 , cNEqual ,PositionalParams,0}}, + /* 181: @R (cNEqual [(cAdd % <1>) &]) + * : (cAdd <1>) SUB( & % )@C + */ {ReplaceParams , 16, 2,/*120,516 */528504 , {2,/*137,24 */24713 , cNEqual ,PositionalParams,0}}, + /* 182: @R (cNEqual [(cAdd % <1>) (cAdd & <2>)]) + * : (cAdd <1>) (cAdd & -%@C <2>) + */ {ReplaceParams , 16, 2,/*120,139 */142456 , {2,/*137,138 */141449 , cNEqual ,PositionalParams,0}}, + /* 183: @R (cNEqual [(cAdd x <1>)@D4 (cAdd x <2>)@D4]) + * : (cAdd <1>) (cAdd <2>) + */ {ReplaceParams , 16, 2,/*120,121 */124024 , {2,/*135,136 */139399 , cNEqual ,PositionalParams,0}}, + /* 184: @R @F (cNEqual [(cMul % <1>) &]) + * : (cMul <1>) DIV( & % )@C + */ {ReplaceParams , 18, 2,/*246,517 */529654 , {2,/*273,24 */24849 , cNEqual ,PositionalParams,0}}, + /* 185: @R @F (cNEqual [(cPow [x %@P]) &]) + * : (cPow [(cPow [x %]) /%@C]) POW( & /%@C )@C + */ {ReplaceParams , 18, 2,/*388,399 */408964 , {2,/*387,24 */24963 , cNEqual ,PositionalParams,0}}, + /* 186: @R @F (cNEqual [(cMul % <1>) (cMul & <2>)]) + * : (cMul <1>) (cMul DIV( & % )@C <2>) + */ {ReplaceParams , 18, 2,/*246,276 */282870 , {2,/*273,275 */281873 , cNEqual ,PositionalParams,0}}, + /* 187: @R @F (cNEqual [(cPow [% x])@D1 (cPow [% y])@D1]) + * : x y + */ {ReplaceParams , 18, 2,/*0,7 */7168 , {2,/*390,392 */401798 , cNEqual ,PositionalParams,0}}, + /* 188: @R @F (cNEqual [&@P (cPow [%@P x])]) + * : DIV( LOG( & )@C LOG( % )@C )@C x + */ {ReplaceParams , 18, 2,/*518,0 */518 , {2,/*28,391 */400412 , cNEqual ,PositionalParams,0}}, + /* 189: @R (cLess [(cAdd % <1>) &]) + * : (cAdd <1>) SUB( & % )@C + */ {ReplaceParams , 16, 2,/*120,516 */528504 , {2,/*137,24 */24713 , cLess ,PositionalParams,0}}, + /* 190: @R (cLess [(cAdd % <1>) (cAdd & <2>)]) + * : (cAdd <1>) (cAdd & -%@C <2>) + */ {ReplaceParams , 16, 2,/*120,139 */142456 , {2,/*137,138 */141449 , cLess ,PositionalParams,0}}, + /* 191: @R (cLess [(cAdd x <1>)@D4 (cAdd x <2>)@D4]) + * : (cAdd <1>) (cAdd <2>) + */ {ReplaceParams , 16, 2,/*120,121 */124024 , {2,/*135,136 */139399 , cLess ,PositionalParams,0}}, + /* 192: @R @F (cLess [x 0.5]) + * -> (cAbsNot [x]) + */ {ProduceNewTree, 18, 1,/*571 */571 , {2,/*0,45 */46080 , cLess ,PositionalParams,0}}, + /* 193: @R @F (cLess [(cMul %@P <1>) &]) + * : (cMul <1>) DIV( & % )@C + */ {ReplaceParams , 18, 2,/*246,517 */529654 , {2,/*256,24 */24832 , cLess ,PositionalParams,0}}, + /* 194: @R @F (cLess [(cMul %@N <1>) &]) + * : DIV( & % )@C (cMul <1>) + */ {ReplaceParams , 18, 2,/*517,246 */252421 , {2,/*254,24 */24830 , cLess ,PositionalParams,0}}, + /* 195: @R @F (cLess [(cPow [x %@P]) &]) + * : (cPow [(cPow [x %]) /%@C]) POW( & /%@C )@C + */ {ReplaceParams , 18, 2,/*388,399 */408964 , {2,/*387,24 */24963 , cLess ,PositionalParams,0}}, + /* 196: @R @F (cLess [(cMul %@P <1>) (cMul & <2>)]) + * : (cMul <1>) (cMul DIV( & % )@C <2>) + */ {ReplaceParams , 18, 2,/*246,276 */282870 , {2,/*256,275 */281856 , cLess ,PositionalParams,0}}, + /* 197: @R @F (cLess [(cMul %@N <1>) (cMul & <2>)]) + * : (cMul DIV( & % )@C <2>) (cMul <1>) + */ {ReplaceParams , 18, 2,/*276,246 */252180 , {2,/*254,275 */281854 , cLess ,PositionalParams,0}}, + /* 198: @R @F (cLess [(cPow [% x])@D1 (cPow [% y])@D1]) + * : x y + */ {ReplaceParams , 18, 2,/*0,7 */7168 , {2,/*390,392 */401798 , cLess ,PositionalParams,0}}, + /* 199: @R @F (cLess [&@P (cPow [%@P x])]) + * : DIV( LOG( & )@C LOG( % )@C )@C x + */ {ReplaceParams , 18, 2,/*518,0 */518 , {2,/*28,391 */400412 , cLess ,PositionalParams,0}}, + /* 200: @R @I (cLess [0 (cAbs [x])]) + * -> (cNotNot [x]) + */ {ProduceNewTree, 20, 1,/*562 */562 , {2,/*41,400 */409641 , cLess ,PositionalParams,0}}, + /* 201: @R (cLessOrEq [(cAdd % <1>) &]) + * : (cAdd <1>) SUB( & % )@C + */ {ReplaceParams , 16, 2,/*120,516 */528504 , {2,/*137,24 */24713 , cLessOrEq ,PositionalParams,0}}, + /* 202: @R (cLessOrEq [(cAdd % <1>) (cAdd & <2>)]) + * : (cAdd <1>) (cAdd & -%@C <2>) + */ {ReplaceParams , 16, 2,/*120,139 */142456 , {2,/*137,138 */141449 , cLessOrEq ,PositionalParams,0}}, + /* 203: @R (cLessOrEq [(cAdd x <1>)@D4 (cAdd x <2>)@D4]) + * : (cAdd <1>) (cAdd <2>) + */ {ReplaceParams , 16, 2,/*120,121 */124024 , {2,/*135,136 */139399 , cLessOrEq ,PositionalParams,0}}, + /* 204: @R @F (cLessOrEq [% (cAbs [x])]) + * -> (cNotNot [(cMul {x 0.5 /%@C})]) + */ {ProduceNewTree, 18, 1,/*565 */565 , {2,/*15,400 */409615 , cLessOrEq ,PositionalParams,0}}, + /* 205: @R @F (cLessOrEq [(cMul %@P <1>) &]) + * : (cMul <1>) DIV( & % )@C + */ {ReplaceParams , 18, 2,/*246,517 */529654 , {2,/*256,24 */24832 , cLessOrEq ,PositionalParams,0}}, + /* 206: @R @F (cLessOrEq [(cMul %@N <1>) &]) + * : DIV( & % )@C (cMul <1>) + */ {ReplaceParams , 18, 2,/*517,246 */252421 , {2,/*254,24 */24830 , cLessOrEq ,PositionalParams,0}}, + /* 207: @R @F (cLessOrEq [(cPow [x %@P]) &]) + * : (cPow [(cPow [x %]) /%@C]) POW( & /%@C )@C + */ {ReplaceParams , 18, 2,/*388,399 */408964 , {2,/*387,24 */24963 , cLessOrEq ,PositionalParams,0}}, + /* 208: @R @F (cLessOrEq [(cMul %@P <1>) (cMul & <2>)]) + * : (cMul <1>) (cMul DIV( & % )@C <2>) + */ {ReplaceParams , 18, 2,/*246,276 */282870 , {2,/*256,275 */281856 , cLessOrEq ,PositionalParams,0}}, + /* 209: @R @F (cLessOrEq [(cMul %@N <1>) (cMul & <2>)]) + * : (cMul DIV( & % )@C <2>) (cMul <1>) + */ {ReplaceParams , 18, 2,/*276,246 */252180 , {2,/*254,275 */281854 , cLessOrEq ,PositionalParams,0}}, + /* 210: @R @F (cLessOrEq [(cPow [% x])@D1 (cPow [% y])@D1]) + * : x y + */ {ReplaceParams , 18, 2,/*0,7 */7168 , {2,/*390,392 */401798 , cLessOrEq ,PositionalParams,0}}, + /* 211: @R @F (cLessOrEq [&@P (cPow [%@P x])]) + * : DIV( LOG( & )@C LOG( % )@C )@C x + */ {ReplaceParams , 18, 2,/*518,0 */518 , {2,/*28,391 */400412 , cLessOrEq ,PositionalParams,0}}, + /* 212: @R @I (cLessOrEq [1 (cAbs [x])]) + * -> (cNotNot [x]) + */ {ProduceNewTree, 20, 1,/*562 */562 , {2,/*47,400 */409647 , cLessOrEq ,PositionalParams,0}}, + /* 213: @R (cGreater [(cAdd % <1>) &]) + * : (cAdd <1>) SUB( & % )@C + */ {ReplaceParams , 16, 2,/*120,516 */528504 , {2,/*137,24 */24713 , cGreater ,PositionalParams,0}}, + /* 214: @R (cGreater [(cAdd % <1>) (cAdd & <2>)]) + * : (cAdd <1>) (cAdd & -%@C <2>) + */ {ReplaceParams , 16, 2,/*120,139 */142456 , {2,/*137,138 */141449 , cGreater ,PositionalParams,0}}, + /* 215: @R (cGreater [(cAdd x <1>)@D4 (cAdd x <2>)@D4]) + * : (cAdd <1>) (cAdd <2>) + */ {ReplaceParams , 16, 2,/*120,121 */124024 , {2,/*135,136 */139399 , cGreater ,PositionalParams,0}}, + /* 216: @R @F (cGreater [% (cAbs [x])]) + * -> (cNot [(cMul {x 0.5 /%@C})]) + */ {ProduceNewTree, 18, 1,/*539 */539 , {2,/*15,400 */409615 , cGreater ,PositionalParams,0}}, + /* 217: @R @F (cGreater [(cMul %@P <1>) &]) + * : (cMul <1>) DIV( & % )@C + */ {ReplaceParams , 18, 2,/*246,517 */529654 , {2,/*256,24 */24832 , cGreater ,PositionalParams,0}}, + /* 218: @R @F (cGreater [(cMul %@N <1>) &]) + * : DIV( & % )@C (cMul <1>) + */ {ReplaceParams , 18, 2,/*517,246 */252421 , {2,/*254,24 */24830 , cGreater ,PositionalParams,0}}, + /* 219: @R @F (cGreater [(cPow [x %@P]) &]) + * : (cPow [(cPow [x %]) /%@C]) POW( & /%@C )@C + */ {ReplaceParams , 18, 2,/*388,399 */408964 , {2,/*387,24 */24963 , cGreater ,PositionalParams,0}}, + /* 220: @R @F (cGreater [(cMul %@P <1>) (cMul & <2>)]) + * : (cMul <1>) (cMul DIV( & % )@C <2>) + */ {ReplaceParams , 18, 2,/*246,276 */282870 , {2,/*256,275 */281856 , cGreater ,PositionalParams,0}}, + /* 221: @R @F (cGreater [(cMul %@N <1>) (cMul & <2>)]) + * : (cMul DIV( & % )@C <2>) (cMul <1>) + */ {ReplaceParams , 18, 2,/*276,246 */252180 , {2,/*254,275 */281854 , cGreater ,PositionalParams,0}}, + /* 222: @R @F (cGreater [(cPow [% x])@D1 (cPow [% y])@D1]) + * : x y + */ {ReplaceParams , 18, 2,/*0,7 */7168 , {2,/*390,392 */401798 , cGreater ,PositionalParams,0}}, + /* 223: @R @F (cGreater [&@P (cPow [%@P x])]) + * : DIV( LOG( & )@C LOG( % )@C )@C x + */ {ReplaceParams , 18, 2,/*518,0 */518 , {2,/*28,391 */400412 , cGreater ,PositionalParams,0}}, + /* 224: @R @I (cGreater [1 (cAbs [x])]) + * -> (cNot [x]) + */ {ProduceNewTree, 20, 1,/*538 */538 , {2,/*47,400 */409647 , cGreater ,PositionalParams,0}}, + /* 225: @R (cGreaterOrEq [(cAdd % <1>) &]) + * : (cAdd <1>) SUB( & % )@C + */ {ReplaceParams , 16, 2,/*120,516 */528504 , {2,/*137,24 */24713 , cGreaterOrEq,PositionalParams,0}}, + /* 226: @R (cGreaterOrEq [(cAdd % <1>) (cAdd & <2>)]) + * : (cAdd <1>) (cAdd & -%@C <2>) + */ {ReplaceParams , 16, 2,/*120,139 */142456 , {2,/*137,138 */141449 , cGreaterOrEq,PositionalParams,0}}, + /* 227: @R (cGreaterOrEq [(cAdd x <1>)@D4 (cAdd x <2>)@D4]) + * : (cAdd <1>) (cAdd <2>) + */ {ReplaceParams , 16, 2,/*120,121 */124024 , {2,/*135,136 */139399 , cGreaterOrEq,PositionalParams,0}}, + /* 228: @R @F (cGreaterOrEq [x 0.5]) + * -> (cAbsNotNot [x]) + */ {ProduceNewTree, 18, 1,/*572 */572 , {2,/*0,45 */46080 , cGreaterOrEq,PositionalParams,0}}, + /* 229: @R @F (cGreaterOrEq [(cMul %@P <1>) &]) + * : (cMul <1>) DIV( & % )@C + */ {ReplaceParams , 18, 2,/*246,517 */529654 , {2,/*256,24 */24832 , cGreaterOrEq,PositionalParams,0}}, + /* 230: @R @F (cGreaterOrEq [(cMul %@N <1>) &]) + * : DIV( & % )@C (cMul <1>) + */ {ReplaceParams , 18, 2,/*517,246 */252421 , {2,/*254,24 */24830 , cGreaterOrEq,PositionalParams,0}}, + /* 231: @R @F (cGreaterOrEq [(cPow [x %@P]) &]) + * : (cPow [(cPow [x %]) /%@C]) POW( & /%@C )@C + */ {ReplaceParams , 18, 2,/*388,399 */408964 , {2,/*387,24 */24963 , cGreaterOrEq,PositionalParams,0}}, + /* 232: @R @F (cGreaterOrEq [(cMul %@P <1>) (cMul & <2>)]) + * : (cMul <1>) (cMul DIV( & % )@C <2>) + */ {ReplaceParams , 18, 2,/*246,276 */282870 , {2,/*256,275 */281856 , cGreaterOrEq,PositionalParams,0}}, + /* 233: @R @F (cGreaterOrEq [(cMul %@N <1>) (cMul & <2>)]) + * : (cMul DIV( & % )@C <2>) (cMul <1>) + */ {ReplaceParams , 18, 2,/*276,246 */252180 , {2,/*254,275 */281854 , cGreaterOrEq,PositionalParams,0}}, + /* 234: @R @F (cGreaterOrEq [(cPow [% x])@D1 (cPow [% y])@D1]) + * : x y + */ {ReplaceParams , 18, 2,/*0,7 */7168 , {2,/*390,392 */401798 , cGreaterOrEq,PositionalParams,0}}, + /* 235: @R @F (cGreaterOrEq [&@P (cPow [%@P x])]) + * : DIV( LOG( & )@C LOG( % )@C )@C x + */ {ReplaceParams , 18, 2,/*518,0 */518 , {2,/*28,391 */400412 , cGreaterOrEq,PositionalParams,0}}, + /* 236: @R @I (cGreaterOrEq [0 (cAbs [x])]) + * -> (cNot [x]) + */ {ProduceNewTree, 20, 1,/*538 */538 , {2,/*41,400 */409641 , cGreaterOrEq,PositionalParams,0}}, + /* 237: @I (cNot [(cAdd % <1>)]) + * -> (cEqual [-%@C (cAdd <1>)]) + */ {ProduceNewTree, 4, 1,/*519 */519 , {1,/*137 */137 , cNot ,PositionalParams,0}}, + /* 238: @R (cNot [x@P]) + * -> (cAbsNot [x]) + */ {ProduceNewTree, 16, 1,/*571 */571 , {1,/*2 */2 , cNot ,PositionalParams,0}}, + /* 239: (cAnd (cIf [x y z])@D4 (cIf [x a b])@D4) + * : (cIf [x (cAnd {y a}) (cAnd {z b})]) + */ {ReplaceParams , 0, 1,/*452 */452 , {2,/*438,440 */450998 , cAnd ,AnyParams ,0}}, + /* 240: (cAnd (cEqual [x y])@D12 (cEqual [y z])@D24 (cEqual [x z])@D20) + * : (cEqual [x y]) (cEqual [y z]) + */ {ReplaceParams , 0, 2,/*521,524 */537097 , {3,/*520,523,522*/547892744 , cAnd ,AnyParams ,0}}, + /* 241: @R (cAnd x@L <1>) + * -> (cNotNot [(cMul {x (cAnd <1>)})]) + */ {ProduceNewTree, 16, 1,/*566 */566 , {1,/*5 */5 , cAnd ,AnyParams ,1}}, + /* 242: @R (cAnd x@P y@P) + * : (cAbsAnd {x y}) + */ {ReplaceParams , 16, 1,/*569 */569 , {2,/*2,13 */13314 , cAnd ,AnyParams ,0}}, + /* 243: @R (cAnd (cNot [x]) (cNot [y])) + * : (cNot [(cOr {x y})]) + */ {ReplaceParams , 16, 1,/*544 */544 , {2,/*538,540 */553498 , cAnd ,AnyParams ,0}}, + /* 244: @R (cAnd (cNot [z]) (cIf [x (cNot [y]) %@L])) + * : (cNot [(cOr {z (cIf [x y (cNot [%])])})]) + */ {ReplaceParams , 16, 1,/*546 */546 , {2,/*545,451 */462369 , cAnd ,AnyParams ,0}}, + /* 245: @R (cAnd (cNot [z]) (cIf [x %@L (cNot [y])])) + * : (cNot [(cOr {z (cIf [x (cNot [%]) y])})]) + */ {ReplaceParams , 16, 1,/*548 */548 , {2,/*545,455 */466465 , cAnd ,AnyParams ,0}}, + /* 246: (cOr (cIf [x y z])@D4 (cIf [x a b])@D4) + * : (cIf [x (cOr {y a}) (cOr {z b})]) + */ {ReplaceParams , 0, 1,/*457 */457 , {2,/*438,440 */450998 , cOr ,AnyParams ,0}}, + /* 247: @R (cOr x@P y@P) + * : (cAbsOr {x y}) + */ {ReplaceParams , 16, 1,/*570 */570 , {2,/*2,13 */13314 , cOr ,AnyParams ,0}}, + /* 248: @R (cOr x@L y@L) + * : (cNotNot [(cAdd {x y})]) + */ {ReplaceParams , 16, 1,/*563 */563 , {2,/*5,8 */8197 , cOr ,AnyParams ,0}}, + /* 249: @R (cOr (cNot [x]) (cNot [y])) + * : (cNot [(cAnd {x y})]) + */ {ReplaceParams , 16, 1,/*541 */541 , {2,/*538,540 */553498 , cOr ,AnyParams ,0}}, + /* 250: @R (cOr (cNot [z]) (cIf [x (cNot [y]) %@L])) + * : (cNot [(cAnd {z (cIf [x y (cNot [%])])})]) + */ {ReplaceParams , 16, 1,/*542 */542 , {2,/*545,451 */462369 , cOr ,AnyParams ,0}}, + /* 251: @R (cOr (cNot [z]) (cIf [x %@L (cNot [y])])) + * : (cNot [(cAnd {z (cIf [x (cNot [%]) y])})]) + */ {ReplaceParams , 16, 1,/*543 */543 , {2,/*545,455 */466465 , cOr ,AnyParams ,0}}, + /* 252: @R (cOr x@L (cAdd <1>)@P) + * : (cNotNot [(cAdd x <1>)]) + */ {ReplaceParams , 16, 1,/*564 */564 , {2,/*5,140 */143365 , cOr ,AnyParams ,0}}, + /* 253: @I (cNotNot [(cAdd % <1>)]) + * -> (cNEqual [-%@C (cAdd <1>)]) + */ {ProduceNewTree, 4, 1,/*525 */525 , {1,/*137 */137 , cNotNot ,PositionalParams,0}}, + /* 254: @R (cNotNot [x@P]) + * -> (cAbsNotNot [x]) + */ {ProduceNewTree, 16, 1,/*572 */572 , {1,/*2 */2 , cNotNot ,PositionalParams,0}}, + /* 255: @R @L (cNotNot [x]) + * -> x + */ {ProduceNewTree, 17, 1,/*0 */0 , {1,/*0 */0 , cNotNot ,PositionalParams,0}}, + /* 256: @R @F (cAbsNotNot (cMul %@P <1>)) + * -> (cGreaterOrEq [(cMul <1>) MUL( 0.5 /%@C )@C]) + */ {ProduceNewTree, 18, 1,/*537 */537 , {1,/*256 */256 , cAbsNotNot ,AnyParams ,0}}, + /* 257: @R @F (cAbsNotNot (cMul %@N <1>)) + * -> (cLessOrEq [(cMul <1>) MUL( 0.5 /%@C )@C]) + */ {ProduceNewTree, 18, 1,/*531 */531 , {1,/*254 */254 , cAbsNotNot ,AnyParams ,0}}, + /* 258: (cAbsIf [x 1 0]) + * -> (cAbsNotNot [x]) + */ {ProduceNewTree, 0, 1,/*572 */572 , {3,/*0,47,41 */43039744 , cAbsIf ,PositionalParams,0}}, + /* 259: (cAbsIf [x 0 1]) + * -> (cAbsNot [x]) + */ {ProduceNewTree, 0, 1,/*571 */571 , {3,/*0,41,47 */49325056 , cAbsIf ,PositionalParams,0}}, + /* 260: @R (cAbsIf [(cNotNot [x]) y z]) + * -> (cIf [x y z]) + */ {ProduceNewTree, 16, 1,/*454 */454 , {3,/*562,7,31 */32513586 , cAbsIf ,PositionalParams,0}}, + /* 261: @R (cAbsIf [(cLessOrEq [x y]) z a]) + * : (cLess [y x]) a z + */ {ReplaceParams , 16, 3,/*529,35,31 */32542225 , {3,/*530,31,35 */36732434 , cAbsIf ,PositionalParams,0}}, + }; + + struct grammar_optimize_abslogical_type + { + unsigned c; + unsigned short l[9]; + }; + extern "C" + { + grammar_optimize_abslogical_type grammar_optimize_abslogical = + { + 9, + { 34,192,228,238,242,247,254,260,261 + } }; } + struct grammar_optimize_ignore_if_sideeffects_type + { + unsigned c; + unsigned short l[59]; + }; + extern "C" + { + grammar_optimize_ignore_if_sideeffects_type grammar_optimize_ignore_if_sideeffects = + { + 59, + { 0,20,21,22,23,24,25,26,27,28, + 29,30,31,32,33,35,36,41,42,43, + 44,78,79,122,123,160,161,163,164,165, + 166,167,168,169,178,179,180,200,204,212, + 216,224,236,237,239,240,243,244,245,246, + 249,250,251,253,255,256,257,258,259 + } }; } + struct grammar_optimize_nonshortcut_logical_evaluation_type + { + unsigned c; + unsigned short l[56]; + }; + extern "C" + { + grammar_optimize_nonshortcut_logical_evaluation_type grammar_optimize_nonshortcut_logical_evaluation = + { + 56, + { 0,25,27,28,29,30,31,32,33,35, + 36,41,42,43,44,78,79,122,123,160, + 161,163,164,165,166,167,168,169,178,179, + 180,200,204,212,216,224,236,237,239,240, + 241,243,244,245,246,248,249,250,251,252, + 253,255,256,257,258,259 + } }; } + struct grammar_optimize_recreate_type + { + unsigned c; + unsigned short l[22]; + }; + extern "C" + { + grammar_optimize_recreate_type grammar_optimize_recreate = + { + 22, + { 18,55,56,57,80,81,82,83,84,85, + 117,118,120,121,130,131,132,133,134,135, + 136,137 + } }; } + struct grammar_optimize_round1_type + { + unsigned c; + unsigned short l[125]; + }; + extern "C" + { + grammar_optimize_round1_type grammar_optimize_round1 = + { + 125, + { 0,1,2,3,4,5,6,7,8,9, + 10,11,12,13,14,19,25,27,28,29, + 30,31,32,33,35,36,37,38,41,42, + 43,44,45,46,47,48,49,50,51,52, + 53,54,58,59,60,61,62,63,64,65, + 66,67,68,69,70,71,78,79,80,81, + 82,83,84,85,86,87,88,93,94,95, + 96,97,98,99,100,101,117,118,119,120, + 121,122,123,124,125,126,127,128,129,138, + 160,161,162,163,164,165,166,167,168,169, + 178,179,180,200,204,212,216,224,236,237, + 239,240,243,244,245,246,249,250,251,253, + 255,256,257,258,259 + } }; } + struct grammar_optimize_round2_type + { + unsigned c; + unsigned short l[103]; + }; + extern "C" + { + grammar_optimize_round2_type grammar_optimize_round2 = + { + 103, + { 0,15,16,17,25,27,28,29,30,31, + 32,33,35,36,39,40,41,42,43,44, + 45,46,47,48,49,50,51,52,53,54, + 59,60,72,73,78,79,86,87,88,89, + 90,91,92,102,103,104,105,106,107,108, + 109,110,111,112,113,114,115,116,119,122, + 123,124,125,126,127,128,139,159,160,161, + 162,163,164,165,166,167,168,169,178,179, + 180,200,204,212,216,224,236,237,239,240, + 243,244,245,246,249,250,251,253,255,256, + 257,258,259 + } }; } + struct grammar_optimize_round3_type + { + unsigned c; + unsigned short l[79]; + }; + extern "C" + { + grammar_optimize_round3_type grammar_optimize_round3 = + { + 79, + { 74,75,76,77,140,141,142,143,144,145, + 146,147,148,149,150,151,152,153,154,155, + 156,157,158,170,171,172,173,174,175,176, + 177,181,182,183,184,185,186,187,188,189, + 190,191,193,194,195,196,197,198,199,201, + 202,203,205,206,207,208,209,210,211,213, + 214,215,217,218,219,220,221,222,223,225, + 226,227,229,230,231,232,233,234,235 + } }; } + struct grammar_optimize_round4_type + { + unsigned c; + unsigned short l[12]; + }; + extern "C" + { + grammar_optimize_round4_type grammar_optimize_round4 = + { + 12, + { 18,55,56,57,130,131,132,133,134,135, + 136,137 + } }; } + struct grammar_optimize_shortcut_logical_evaluation_type + { + unsigned c; + unsigned short l[53]; + }; + extern "C" + { + grammar_optimize_shortcut_logical_evaluation_type grammar_optimize_shortcut_logical_evaluation = + { + 53, + { 0,25,27,28,29,30,31,32,33,35, + 36,41,42,43,44,78,79,122,123,160, + 161,163,164,165,166,167,168,169,178,179, + 180,200,204,212,216,224,236,237,239,240, + 243,244,245,246,249,250,251,253,255,256, + 257,258,259 + } }; } +} +namespace FPoptimizer_Grammar +{ + template<typename Value_t> + ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index) + { + index = (paramlist >> (index * 10)) & 1023 /* % (1 << 10) */; + if(index >= 57) + return ParamSpec(SubFunction,(const void*)&plist_s[index-57]); + if(index >= 37) + return ParamSpec(NumConstant,(const void*)&plist_n_container<Value_t>::plist_n[index-37]); + return ParamSpec(ParamHolder,(const void*)&plist_p[index]); + } +} +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_Grammar +{ +#define FP_INSTANTIATE(type) \ + template ParamSpec ParamSpec_Extract<type>(unsigned paramlist, unsigned index); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ diff --git a/fpoptimizer/hash.cc b/fpoptimizer/hash.cc new file mode 100644 index 0000000..05bb6ca --- /dev/null +++ b/fpoptimizer/hash.cc @@ -0,0 +1,254 @@ +#include <list> +#include <algorithm> + +#include "constantfolding.hh" +#include "codetree.hh" +#include "extrasrc/fptypes.hh" +#include "../lib/crc32.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +using namespace FUNCTIONPARSERTYPES; +//using namespace FPoptimizer_Grammar; + +namespace +{ + template<typename Value_t> + bool MarkIncompletes(FPoptimizer_CodeTree::CodeTree<Value_t>& tree) + { + if(tree.Is_Incompletely_Hashed()) + return true; + + bool needs_rehash = false; + for(size_t a=0; a<tree.GetParamCount(); ++a) + needs_rehash |= MarkIncompletes(tree.GetParam(a)); + if(needs_rehash) + tree.Mark_Incompletely_Hashed(); + return needs_rehash; + } + + template<typename Value_t> + void FixIncompletes(FPoptimizer_CodeTree::CodeTree<Value_t>& tree) + { + if(tree.Is_Incompletely_Hashed()) + { + for(size_t a=0; a<tree.GetParamCount(); ++a) + FixIncompletes(tree.GetParam(a)); + tree.Rehash(); + } + } +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + void CodeTree<Value_t>::Sort() + { + data->Sort(); + } + + template<typename Value_t> + void CodeTree<Value_t>::Rehash(bool constantfolding) + { + if(constantfolding) + ConstantFolding(*this); // also runs Sort() + else + Sort(); + + data->Recalculate_Hash_NoRecursion(); + } + + template<typename Value_t> + struct ImmedHashGenerator + { + static void MakeHash( + FUNCTIONPARSERTYPES::fphash_t& NewHash, + const Value_t& Value) + { + /* TODO: For non-POD types, convert the value + * into a base-62 string (or something) and hash that. + */ + NewHash.hash1 = 0; // Try to ensure immeds gets always sorted first + #if 0 + long double value = Value; + fphash_value_t key = crc32::calc((const unsigned char*)&value, sizeof(value)); + key ^= (key << 24); + #elif 0 + union + { + struct + { + unsigned char filler1[16]; + Value_t v; + unsigned char filler2[16]; + } buf2; + struct + { + unsigned char filler3[sizeof(Value_t)+16-sizeof(fphash_value_t)]; + fphash_value_t key; + } buf1; + } data; + memset(&data, 0, sizeof(data)); + data.buf2.v = Value; + fphash_value_t key = data.buf1.key; + #else + int exponent; + Value_t fraction = std::frexp(Value, &exponent); + fphash_value_t key = (unsigned(exponent+0x8000) & 0xFFFF); + if(fraction < 0) + { fraction = -fraction; key = key^0xFFFF; } + else + key += 0x10000; + fraction -= Value_t(0.5); + key <<= 39; // covers bits 39..55 now + key |= fphash_value_t((fraction+fraction) * Value_t(1u<<31)) << 8; + // fraction covers bits 8..39 now + #endif + /* Key = 56-bit unsigned integer value + * that is directly proportional + * to the floating point value. + */ + NewHash.hash1 |= key; + //crc32_t crc = crc32::calc((const unsigned char*)&Value, sizeof(Value)); + fphash_value_t crc = (key >> 10) | (key << (64-10)); + NewHash.hash2 += ((~fphash_value_t(crc)) * 3) ^ 1234567; + } + }; + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename T> + struct ImmedHashGenerator< std::complex<T> > + { + static void MakeHash( + FUNCTIONPARSERTYPES::fphash_t& NewHash, + const std::complex<T>& Value) + { + ImmedHashGenerator<T>::MakeHash(NewHash, Value.real()); + FUNCTIONPARSERTYPES::fphash_t temp; + ImmedHashGenerator<T>::MakeHash(temp, Value.imag()); + NewHash.hash1 ^= temp.hash2; + NewHash.hash2 ^= temp.hash1; + } + }; +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE + template<> + struct ImmedHashGenerator<long> + { + static void MakeHash( + FUNCTIONPARSERTYPES::fphash_t& NewHash, + long Value) + { + fphash_value_t key = Value; + /* Key = 56-bit unsigned integer value + * that is directly proportional + * to the floating point value. + */ + NewHash.hash1 |= key; + //crc32_t crc = crc32::calc((const unsigned char*)&Value, sizeof(Value)); + fphash_value_t crc = (key >> 10) | (key << (64-10)); + NewHash.hash2 += ((~fphash_value_t(crc)) * 3) ^ 1234567; + } + }; +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + struct ImmedHashGenerator<GmpInt> + { + static void MakeHash( + FUNCTIONPARSERTYPES::fphash_t& NewHash, + const GmpInt& Value) + { + fphash_value_t key = Value.toInt(); + /* Key = 56-bit unsigned integer value + * that is directly proportional + * to the floating point value. + */ + NewHash.hash1 |= key; + //crc32_t crc = crc32::calc((const unsigned char*)&Value, sizeof(Value)); + fphash_value_t crc = (key >> 10) | (key << (64-10)); + NewHash.hash2 += ((~fphash_value_t(crc)) * 3) ^ 1234567; + } + }; +#endif + + template<typename Value_t> + void CodeTreeData<Value_t>::Recalculate_Hash_NoRecursion() + { + /* Hash structure: + * hash1: sorting key (8 bytes, 64 bits) + * byte 1: opcode + * hash2: unique value + */ + fphash_t NewHash ( fphash_value_t(Opcode) << 56, + Opcode * FPHASH_CONST(0x1131462E270012B) ); + Depth = 1; + switch(Opcode) + { + case cImmed: // Value + { + ImmedHashGenerator<Value_t>::MakeHash(NewHash, Value); + break; // no params + } + case VarBegin: // Var_or_Funcno + { + NewHash.hash1 |= fphash_value_t(Var_or_Funcno) << 48; + NewHash.hash2 += ((fphash_value_t(Var_or_Funcno)) * 11) + ^ FPHASH_CONST(0x3A83A83A83A83A0); + break; // no params + } + case cFCall: case cPCall: // Var_or_Funcno + { + NewHash.hash1 |= fphash_value_t(Var_or_Funcno) << 48; + NewHash.hash2 += ((~fphash_value_t(Var_or_Funcno)) * 7) ^ 3456789; + /* passthru */ + } + default: + { + size_t MaxChildDepth = 0; + for(size_t a=0; a<Params.size(); ++a) + { + if(Params[a].GetDepth() > MaxChildDepth) + MaxChildDepth = Params[a].GetDepth(); + + NewHash.hash1 += ((Params[a].GetHash().hash1*(a+1)) >> 12); + NewHash.hash2 += Params[a].GetHash().hash1; + NewHash.hash2 += (3)*FPHASH_CONST(0x9ABCD801357); + NewHash.hash2 *= FPHASH_CONST(0xECADB912345); + NewHash.hash2 += (~Params[a].GetHash().hash2) ^ 4567890; + } + Depth += MaxChildDepth; + } + } + if(Hash != NewHash) + { + Hash = NewHash; + OptimizedUsing = 0; + } + } + + template<typename Value_t> + void CodeTree<Value_t>::FixIncompleteHashes() + { + MarkIncompletes(*this); + FixIncompletes(*this); + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template void CodeTree<type>::Sort(); \ + template void CodeTree<type>::Rehash(bool); \ + template void CodeTree<type>::FixIncompleteHashes(); \ + template void CodeTreeData<type>::Recalculate_Hash_NoRecursion(); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/hash.hh b/fpoptimizer/hash.hh new file mode 100644 index 0000000..a0e03cb --- /dev/null +++ b/fpoptimizer/hash.hh @@ -0,0 +1,38 @@ +#ifndef FPoptimizerHashHH +#define FPoptimizerHashHH + +#ifdef _MSC_VER + +typedef unsigned long long fphash_value_t; +#define FPHASH_CONST(x) x##ULL + +#else + +#include <stdint.h> +typedef uint_fast64_t fphash_value_t; +#define FPHASH_CONST(x) x##ULL + +#endif + +namespace FUNCTIONPARSERTYPES +{ + struct fphash_t + { + fphash_value_t hash1, hash2; + + fphash_t() : hash1(0), hash2(0) { } + fphash_t(const fphash_value_t& a, + const fphash_value_t& b) : hash1(a), hash2(b) { } + + bool operator==(const fphash_t& rhs) const + { return hash1 == rhs.hash1 && hash2 == rhs.hash2; } + + bool operator!=(const fphash_t& rhs) const + { return hash1 != rhs.hash1 || hash2 != rhs.hash2; } + + bool operator<(const fphash_t& rhs) const + { return hash1 != rhs.hash1 ? hash1 < rhs.hash1 : hash2 < rhs.hash2; } + }; +} + +#endif diff --git a/fpoptimizer/instantiate.hh b/fpoptimizer/instantiate.hh new file mode 100644 index 0000000..0520de5 --- /dev/null +++ b/fpoptimizer/instantiate.hh @@ -0,0 +1,39 @@ +/* BEGIN_EXPLICIT_INSTANTATION */ + +#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 + +/* Call the given instantiater for each type supported in FPoptimizer */ +#define FPOPTIMIZER_EXPLICITLY_INSTANTIATE(generator) \ + FUNCTIONPARSER_INSTANTIATE_D(generator) \ + FUNCTIONPARSER_INSTANTIATE_F(generator) \ + FUNCTIONPARSER_INSTANTIATE_LD(generator) \ + FUNCTIONPARSER_INSTANTIATE_LI(generator) \ + /*FUNCTIONPARSER_INSTANTIATE_MF(generator)*/ \ + /*FUNCTIONPARSER_INSTANTIATE_GI(generator)*/ \ + /*FUNCTIONPARSER_INSTANTIATE_CD(generator)*/ \ + /*FUNCTIONPARSER_INSTANTIATE_CF(generator)*/ \ + /*FUNCTIONPARSER_INSTANTIATE_CLD(generator)*/ + +/* END_EXPLICIT_INSTANTATION */ diff --git a/fpoptimizer/logic_boolgroups.hh b/fpoptimizer/logic_boolgroups.hh new file mode 100644 index 0000000..a6e284e --- /dev/null +++ b/fpoptimizer/logic_boolgroups.hh @@ -0,0 +1,382 @@ +#include "codetree.hh" + +namespace +{ + using namespace FUNCTIONPARSERTYPES; + using namespace FPoptimizer_CodeTree; + + /***************************/ + /* LOGIC (AND, OR, NOT) */ + /***************************/ + + struct ComparisonSetBase + { + enum { Lt_Mask = 0x1, // 1=less + Eq_Mask = 0x2, // 2=equal + Le_Mask = 0x3, // 1+2 = Less or Equal + Gt_Mask = 0x4, // 4=greater + Ne_Mask = 0x5, // 4+1 = Greater or Less, i.e. Not equal + Ge_Mask = 0x6 }; // 4+2 = Greater or Equal + static int Swap_Mask(int m) { return (m&Eq_Mask) + | ((m&Lt_Mask) ? Gt_Mask : 0) + | ((m&Gt_Mask) ? Lt_Mask : 0); } + enum RelationshipResult + { + Ok, + BecomeZero, + BecomeOne, + Suboptimal + }; + enum ConditionType + { + cond_or, + cond_and, + cond_mul, + cond_add + }; + }; + + template<typename Value_t> + struct ComparisonSet: public ComparisonSetBase /* For optimizing And, Or */ + { + struct Comparison + { + CodeTree<Value_t> a; + CodeTree<Value_t> b; + int relationship; + + Comparison() : a(),b(), relationship() {} + }; + std::vector<Comparison> relationships; + struct Item + { + CodeTree<Value_t> value; + bool negated; + + Item() : value(), negated(false) {} + }; + std::vector<Item> plain_set; + int const_offset; + + ComparisonSet(): + relationships(), + plain_set(), + const_offset(0) + { + } + + RelationshipResult AddItem( + const CodeTree<Value_t>& a, + bool negated, + ConditionType type) + { + for(size_t c=0; c<plain_set.size(); ++c) + if(plain_set[c].value.IsIdenticalTo(a)) + { + if(negated != plain_set[c].negated) + { + switch(type) + { + case cond_or: + return BecomeOne; + case cond_add: + plain_set.erase(plain_set.begin() + c); + const_offset += 1; + return Suboptimal; + case cond_and: + case cond_mul: + return BecomeZero; + } + } + return Suboptimal; + } + Item pole; + pole.value = a; + pole.negated = negated; + plain_set.push_back(pole); + return Ok; + } + + /* Note: Trees are passed by-value so we can use swap() on them safely. */ + RelationshipResult AddRelationship + (CodeTree<Value_t> a, + CodeTree<Value_t> b, + int reltype, + ConditionType type) + { + switch(type) + { + case cond_or: + if(reltype == 7) return BecomeOne; + break; + case cond_add: + if(reltype == 7) { const_offset += 1; return Suboptimal; } + break; + case cond_and: + case cond_mul: + if(reltype == 0) return BecomeZero; + break; + } + + if(!(a.GetHash() < b.GetHash())) + { + a.swap(b); + reltype = Swap_Mask(reltype); + } + + for(size_t c=0; c<relationships.size(); ++c) + { + if(relationships[c].a.IsIdenticalTo(a) + && relationships[c].b.IsIdenticalTo(b)) + { + switch(type) + { + case cond_or: + { + int newrel = relationships[c].relationship | reltype; + if(newrel == 7) return BecomeOne; + relationships[c].relationship = newrel; + break; + } + case cond_and: + case cond_mul: + { + int newrel = relationships[c].relationship & reltype; + if(newrel == 0) return BecomeZero; + relationships[c].relationship = newrel; + break; + } + case cond_add: + { + int newrel_or = relationships[c].relationship | reltype; + int newrel_and = relationships[c].relationship & reltype; + if(newrel_or == 5 // < + > + && newrel_and == 0) + { + // (x<y) + (x>y) = x!=y + relationships[c].relationship = Ne_Mask; + return Suboptimal; + } + if(newrel_or == 7 + && newrel_and == 0) + { + // (x<y) + (x>=y) = 1 + // (x<=y) + (x>y) = 1 + // (x=y) + (x!=y) = 1 + const_offset += 1; + relationships.erase(relationships.begin()+c); + return Suboptimal; + } + if(newrel_or == 7 + && newrel_and == Eq_Mask) + { + // (x<=y) + (x>=y) = 1 + (x=y) + relationships[c].relationship = Eq_Mask; + const_offset += 1; + return Suboptimal; + } + continue; + } + } + return Suboptimal; + } + } + Comparison comp; + comp.a = a; + comp.b = b; + comp.relationship = reltype; + relationships.push_back(comp); + return Ok; + } + }; + + template<typename Value_t, typename CondType> /* ComparisonSet::ConditionType */ + bool ConstantFolding_LogicCommon( + CodeTree<Value_t>& tree, CondType cond_type, bool is_logical) + { + bool should_regenerate = false; + ComparisonSet<Value_t> comp; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + typename ComparisonSetBase::RelationshipResult + change = ComparisonSetBase::Ok; + const CodeTree<Value_t>& atree = tree.GetParam(a); + switch(atree.GetOpcode()) + { + case cEqual: + change = comp.AddRelationship(atree.GetParam(0), atree.GetParam(1), ComparisonSetBase::Eq_Mask, cond_type); + break; + case cNEqual: + change = comp.AddRelationship(atree.GetParam(0), atree.GetParam(1), ComparisonSetBase::Ne_Mask, cond_type); + break; + case cLess: + change = comp.AddRelationship(atree.GetParam(0), atree.GetParam(1), ComparisonSetBase::Lt_Mask, cond_type); + break; + case cLessOrEq: + change = comp.AddRelationship(atree.GetParam(0), atree.GetParam(1), ComparisonSetBase::Le_Mask, cond_type); + break; + case cGreater: + change = comp.AddRelationship(atree.GetParam(0), atree.GetParam(1), ComparisonSetBase::Gt_Mask, cond_type); + break; + case cGreaterOrEq: + change = comp.AddRelationship(atree.GetParam(0), atree.GetParam(1), ComparisonSetBase::Ge_Mask, cond_type); + break; + case cNot: + change = comp.AddItem(atree.GetParam(0), true, cond_type); + break; + case cNotNot: + change = comp.AddItem(atree.GetParam(0), false, cond_type); + break; + default: + if(is_logical || IsLogicalValue(atree)) + change = comp.AddItem(atree, false, cond_type); + } + switch(change) + { + ReplaceTreeWithZero: + tree.ReplaceWithImmed(0); + return true; + ReplaceTreeWithOne: + tree.ReplaceWithImmed(1); + return true; + case ComparisonSetBase::Ok: // ok + break; + case ComparisonSetBase::BecomeZero: // whole set was invalidated + goto ReplaceTreeWithZero; + case ComparisonSetBase::BecomeOne: // whole set was validated + goto ReplaceTreeWithOne; + case ComparisonSetBase::Suboptimal: // something was changed + should_regenerate = true; + break; + } + } + if(should_regenerate) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Before ConstantFolding_LogicCommon: "; DumpTree(tree); + std::cout << "\n"; + #endif + + if(is_logical) + { + tree.DelParams(); // delete all params + } + else + { + // Delete only logical params + for(size_t a=tree.GetParamCount(); a-- > 0; ) + { + const CodeTree<Value_t>& atree = tree.GetParam(a); + if(IsLogicalValue(atree)) + tree.DelParam(a); + } + } + + for(size_t a=0; a<comp.plain_set.size(); ++a) + { + if(comp.plain_set[a].negated) + { + CodeTree<Value_t> r; + r.SetOpcode(cNot); + r.AddParamMove(comp.plain_set[a].value); + r.Rehash(); + tree.AddParamMove(r); + } + else if(!is_logical) + { + CodeTree<Value_t> r; + r.SetOpcode(cNotNot); + r.AddParamMove(comp.plain_set[a].value); + r.Rehash(); + tree.AddParamMove(r); + } + else + tree.AddParamMove(comp.plain_set[a].value); + } + for(size_t a=0; a<comp.relationships.size(); ++a) + { + CodeTree<Value_t> r; + r.SetOpcode(cNop); // dummy + switch(comp.relationships[a].relationship) + { + case ComparisonSetBase::Lt_Mask: r.SetOpcode( cLess ); break; + case ComparisonSetBase::Eq_Mask: r.SetOpcode( cEqual ); break; + case ComparisonSetBase::Gt_Mask: r.SetOpcode( cGreater ); break; + case ComparisonSetBase::Le_Mask: r.SetOpcode( cLessOrEq ); break; + case ComparisonSetBase::Ne_Mask: r.SetOpcode( cNEqual ); break; + case ComparisonSetBase::Ge_Mask: r.SetOpcode( cGreaterOrEq ); break; + } + r.AddParamMove(comp.relationships[a].a); + r.AddParamMove(comp.relationships[a].b); + r.Rehash(); + tree.AddParamMove(r); + } + if(comp.const_offset != 0) + tree.AddParam( CodeTreeImmed( Value_t(comp.const_offset) ) ); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "After ConstantFolding_LogicCommon: "; DumpTree(tree); + std::cout << "\n"; + #endif + return true; + } + /* + Note: One thing this does not yet do, is to detect chains + such as x=y & y=z & x=z, which could be optimized + to x=y & x=z. + */ + return false; + } + + /* ConstantFolding_AndLogic: + * (x > y) & (x >= y) --> (x > y) + * (x <= y) & (x >= y) --> (x = y) + * (x <= y) & (x > y) --> 0 + * !x & !!x --> 0 + * etc. + */ + template<typename Value_t> + bool ConstantFolding_AndLogic(CodeTree<Value_t>& tree) + { + assert(tree.GetOpcode() == cAnd || tree.GetOpcode() == cAbsAnd); + return ConstantFolding_LogicCommon(tree, ComparisonSetBase::cond_and, true ); + } + + /* ConstantFolding_OrLogic: + * (x > y) | (x >= y) --> (x >= y) + * (x <= y) | (x >= y) --> 1 + * (x <= y) | (x > y) --> 1 + * !x | !!x --> 1 + * etc. + */ + template<typename Value_t> + bool ConstantFolding_OrLogic(CodeTree<Value_t>& tree) + { + assert(tree.GetOpcode() == cOr || tree.GetOpcode() == cAbsOr); + return ConstantFolding_LogicCommon(tree, ComparisonSetBase::cond_or, true ); + } + + /* ConstantFolding_AddLogic: + * (x <= y) + (x >= y) --> (x = y) + 1 + * !x + !!x --> 1 + * etc. + */ + template<typename Value_t> + bool ConstantFolding_AddLogicItems(CodeTree<Value_t>& tree) + { + assert(tree.GetOpcode() == cAdd); + return ConstantFolding_LogicCommon(tree, ComparisonSetBase::cond_add, false ); + } + + /* ConstantFolding_MulLogic: + * (x <= y) * (x >= y) --> (x = y) + * (x > y) * (x >= y) --> (x > y) + * !x * !!x --> 0 + * etc. + */ + template<typename Value_t> + bool ConstantFolding_MulLogicItems(CodeTree<Value_t>& tree) + { + assert(tree.GetOpcode() == cMul); + return ConstantFolding_LogicCommon(tree, ComparisonSetBase::cond_mul, false ); + } +} diff --git a/fpoptimizer/logic_collections.hh b/fpoptimizer/logic_collections.hh new file mode 100644 index 0000000..8066d22 --- /dev/null +++ b/fpoptimizer/logic_collections.hh @@ -0,0 +1,712 @@ +#include <vector> +#include <map> +#include <algorithm> + +#include "codetree.hh" +#include "../lib/functional.hh" + +namespace +{ + using namespace FUNCTIONPARSERTYPES; + using namespace FPoptimizer_CodeTree; + + /**************************************/ + /* GROUPING OF COMMON FACTORS / TERMS */ + /**************************************/ + struct CollectionSetBase + { + enum CollectionResult + { + Ok, + Suboptimal + }; + }; + + template<typename Value_t> + struct CollectionSet: public CollectionSetBase /* For optimizing Add, Mul */ + { + struct Collection + { + CodeTree<Value_t> value; + CodeTree<Value_t> factor; + bool factor_needs_rehashing; + + Collection() : value(),factor(), factor_needs_rehashing(false) { } + Collection(const CodeTree<Value_t>& v, + const CodeTree<Value_t>& f) + : value(v), factor(f), factor_needs_rehashing(false) { } + }; + std::multimap<fphash_t, Collection> collections; + + typedef typename + std::multimap<fphash_t, Collection>::iterator + PositionType; + + CollectionSet() : collections() {} + + PositionType FindIdenticalValueTo(const CodeTree<Value_t>& value) + { + fphash_t hash = value.GetHash(); + for(PositionType + i = collections.lower_bound(hash); + i != collections.end() && i->first == hash; + ++i) + { + if(value.IsIdenticalTo(i->second.value)) + return i; + } + return collections.end(); + } + bool Found(const PositionType& b) { return b != collections.end(); } + + CollectionResult AddCollectionTo + (const CodeTree<Value_t>& factor, + const PositionType& into_which) + { + Collection& c = into_which->second; + if(c.factor_needs_rehashing) + c.factor.AddParam(factor); + else + { + CodeTree<Value_t> add; + add.SetOpcode( cAdd ); + add.AddParamMove(c.factor); + add.AddParam(factor); + c.factor.swap(add); + c.factor_needs_rehashing = true; + } + return Suboptimal; + } + + CollectionResult AddCollection + (const CodeTree<Value_t>& value, + const CodeTree<Value_t>& factor) + { + const fphash_t hash = value.GetHash(); + PositionType i = collections.lower_bound(hash); + for(; i != collections.end() && i->first == hash; ++i) + { + if(i->second.value.IsIdenticalTo(value)) + return AddCollectionTo(factor, i); + } + collections.insert( + i, + std::make_pair( hash, Collection(value, factor) ) ); + return Ok; + } + + CollectionResult AddCollection(const CodeTree<Value_t>& a) + { + return AddCollection(a, CodeTreeImmed(Value_t(1)) ); + } + }; + + template<typename Value_t> + struct ConstantExponentCollection + { + typedef std::vector<CodeTree<Value_t> > TreeSet; + typedef std::pair<Value_t, TreeSet> ExponentInfo; + std::vector<ExponentInfo> data; + + ConstantExponentCollection(): data(){} + + void MoveToSet_Unique(const Value_t& exponent, TreeSet& source_set) + { + data.push_back( std::pair<Value_t, TreeSet > + (exponent, TreeSet() ) ); + data.back().second.swap(source_set); + } + void MoveToSet_NonUnique(const Value_t& exponent, TreeSet& source_set) + { + typename std::vector<ExponentInfo>::iterator i + = std::lower_bound(data.begin(), data.end(), exponent, Compare1st()); + if(i != data.end() && i->first == exponent) + { + i->second.insert(i->second.end(), source_set.begin(), source_set.end()); + } + else + { + //MoveToSet_Unique(exponent, source_set); + data.insert(i, std::pair<Value_t, TreeSet > + (exponent, source_set) ); + } + } + + bool Optimize() + { + /* TODO: Group them such that: + * + * x^3 * z^2 becomes (x*z)^2 * x^1 + * x^3 * y^2.5 * z^2 becomes (x*z*y)^2 * y^0.5 * x^1 + * rather than (x*y*z)^2 * (x*y)^0.5 * x^0.5 + * + * x^4.5 * z^2.5 becomes (z * x)^2.5 * x^2 + * becomes (x*z*x)^2 * (z*x)^0.5 + * becomes (z*x*x*z*x)^0.5 * (z*x*x)^1.5 -- buzz, bad. + * + */ + bool changed = false; + std::sort( data.begin(), data.end(), Compare1st() ); + redo: + /* Supposed algorithm: + * For the smallest pair of data[] where the difference + * between the two is a "neat value" (x*16 is positive integer), + * do the combining as indicated above. + */ + /* + * NOTE: Hanged in Testbed test P44, looping the following + * (Var0 ^ 0.75) * ((1.5 * Var0) ^ 1.0) + * = (Var0 ^ 1.75) * (1.5 ^ 1.0) + * Fixed by limiting to cases where (exp_a != 1.0). + * + * NOTE: Converting (x*z)^0.5 * x^16.5 + * into x^17 * z^0.5 + * is handled by code within CollectMulGroup(). + * However, bacause it is prone for infinite looping, + * the use of "IsIdenticalTo(before)" is added at the + * end of ConstantFolding_MulGrouping(). + * + * This algorithm could make it into (x*z*x)^0.5 * x^16, + * but this is wrong, for it falsely includes x^evenint.. twice. + */ + for(size_t a=0; a<data.size(); ++a) + { + Value_t exp_a = data[a].first; + if(fp_equal(exp_a, Value_t(1))) continue; + for(size_t b=a+1; b<data.size(); ++b) + { + Value_t exp_b = data[b].first; + Value_t exp_diff = exp_b - exp_a; + if(exp_diff >= fp_abs(exp_a)) break; + Value_t exp_diff_still_probable_integer = exp_diff * Value_t(16); + if(isInteger(exp_diff_still_probable_integer) + && !(isInteger(exp_b) && !isInteger(exp_diff)) + ) + { + /* When input is x^3 * z^2, + * exp_a = 2 + * a_set = z + * exp_b = 3 + * b_set = x + * exp_diff = 3-2 = 1 + */ + TreeSet& a_set = data[a].second; + TreeSet& b_set = data[b].second; + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Before ConstantExponentCollection iteration:\n"; + Dump(std::cout); + #endif + if(isEvenInteger(exp_b) + //&& !isEvenInteger(exp_diff) + && !isEvenInteger(exp_diff+exp_a)) + { + CodeTree<Value_t> tmp2; + tmp2.SetOpcode( cMul ); + tmp2.SetParamsMove(b_set); + tmp2.Rehash(); + CodeTree<Value_t> tmp; + tmp.SetOpcode( cAbs ); + tmp.AddParamMove(tmp2); + tmp.Rehash(); + b_set.resize(1); + b_set[0].swap(tmp); + } + + a_set.insert(a_set.end(), b_set.begin(), b_set.end()); + + TreeSet b_copy = b_set; + data.erase(data.begin() + b); + MoveToSet_NonUnique(exp_diff, b_copy); + changed = true; + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "After ConstantExponentCollection iteration:\n"; + Dump(std::cout); + #endif + goto redo; + } + } + } + return changed; + } + + #ifdef DEBUG_SUBSTITUTIONS + void Dump(std::ostream& out) + { + for(size_t a=0; a<data.size(); ++a) + { + out.precision(12); + out << data[a].first << ": "; + for(size_t b=0; b<data[a].second.size(); ++b) + { + if(b > 0) out << '*'; + DumpTree(data[a].second[b], out); + } + out << std::endl; + } + } + #endif + }; + + template<typename Value_t> + static CodeTree<Value_t> CollectMulGroup_Item( + CodeTree<Value_t>& value, + bool& has_highlevel_opcodes) + { + switch(value.GetOpcode()) + { + case cPow: + { + CodeTree<Value_t> exponent = value.GetParam(1); + value.Become( value.GetParam(0) ); + return exponent; + } + /* - disabled to avoid clashes with powi + case cCbrt: + value.Become( value.GetParam(0) ); + has_highlevel_opcodes = true; + return CodeTreeImmed( Value_t(1) / Value_t(3) ); + case cSqrt: + value.Become( value.GetParam(0) ); + has_highlevel_opcodes = true; + return CodeTreeImmed( Value_t(0.5) ); + */ + case cRSqrt: + value.Become( value.GetParam(0) ); + has_highlevel_opcodes = true; + return CodeTreeImmed( Value_t(-0.5) ); + case cInv: + value.Become( value.GetParam(0) ); + has_highlevel_opcodes = true; + return CodeTreeImmed( Value_t(-1) ); + default: break; + } + return CodeTreeImmed( Value_t(1) ); + } + + template<typename Value_t> + static void CollectMulGroup( + CollectionSet<Value_t>& mul, + const CodeTree<Value_t>& tree, + const CodeTree<Value_t>& factor, + bool& should_regenerate, + bool& has_highlevel_opcodes + ) + { + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + CodeTree<Value_t> value(tree.GetParam(a)); + + CodeTree<Value_t> exponent ( CollectMulGroup_Item(value, has_highlevel_opcodes) ); + + if(!factor.IsImmed() || factor.GetImmed() != Value_t(1.0)) + { + CodeTree<Value_t> new_exp; + new_exp.SetOpcode(cMul); + new_exp.AddParam( exponent ); + new_exp.AddParam( factor ); + new_exp.Rehash(); + exponent.swap( new_exp ); + } + #if 0 /* FIXME: This does not work */ + if(value.GetOpcode() == cMul) + { + if(1) + { + // Avoid erroneously converting + // (x*z)^0.5 * z^2 + // into x^0.5 * z^2.5 + // It should be x^0.5 * abs(z)^2.5, but this is not a good conversion. + bool exponent_is_even = exponent.IsImmed() && isEvenInteger(exponent.GetImmed()); + + for(size_t b=0; b<value.GetParamCount(); ++b) + { + bool tmp=false; + CodeTree<Value_t> val(value.GetParam(b)); + CodeTree<Value_t> exp(CollectMulGroup_Item(val, tmp)); + if(exponent_is_even + || (exp.IsImmed() && isEvenInteger(exp.GetImmed()))) + { + CodeTree<Value_t> new_exp; + new_exp.SetOpcode(cMul); + new_exp.AddParam(exponent); + new_exp.AddParamMove(exp); + new_exp.ConstantFolding(); + if(!new_exp.IsImmed() || !isEvenInteger(new_exp.GetImmed())) + { + goto cannot_adopt_mul; + } + } + } + } + CollectMulGroup(mul, value, exponent, + should_regenerate, + has_highlevel_opcodes); + } + else cannot_adopt_mul: + #endif + { + if(mul.AddCollection(value, exponent) == CollectionSetBase::Suboptimal) + should_regenerate = true; + } + } + } + + template<typename Value_t> + bool ConstantFolding_MulGrouping(CodeTree<Value_t>& tree) + { + bool has_highlevel_opcodes = false; + bool should_regenerate = false; + CollectionSet<Value_t> mul; + + CollectMulGroup(mul, tree, CodeTreeImmed(Value_t(1)), + should_regenerate, + has_highlevel_opcodes); + + typedef std::pair<CodeTree<Value_t>/*exponent*/, + std::vector<CodeTree<Value_t> >/*base value (mul group)*/ + > exponent_list; + typedef std::multimap<fphash_t,/*exponent hash*/ + exponent_list> exponent_map; + exponent_map by_exponent; + + for(typename CollectionSet<Value_t>::PositionType + j = mul.collections.begin(); + j != mul.collections.end(); + ++j) + { + CodeTree<Value_t>& value = j->second.value; + CodeTree<Value_t>& exponent = j->second.factor; + if(j->second.factor_needs_rehashing) exponent.Rehash(); + const fphash_t exponent_hash = exponent.GetHash(); + + typename exponent_map::iterator i = by_exponent.lower_bound(exponent_hash); + for(; i != by_exponent.end() && i->first == exponent_hash; ++i) + if(i->second.first.IsIdenticalTo(exponent)) + { + if(!exponent.IsImmed() || !fp_equal(exponent.GetImmed(), Value_t(1))) + should_regenerate = true; + i->second.second.push_back(value); + goto skip_b; + } + by_exponent.insert(i, std::make_pair(exponent_hash, + std::make_pair(exponent, + std::vector<CodeTree<Value_t> > (size_t(1), value) + ))); + skip_b:; + } + + #ifdef FP_MUL_COMBINE_EXPONENTS + ConstantExponentCollection<Value_t> by_float_exponent; + for(typename exponent_map::iterator + j,i = by_exponent.begin(); + i != by_exponent.end(); + i=j) + { + j=i; ++j; + exponent_list& list = i->second; + if(list.first.IsImmed()) + { + Value_t exponent = list.first.GetImmed(); + if(!(exponent == Value_t(0))) + by_float_exponent.MoveToSet_Unique(exponent, list.second); + by_exponent.erase(i); + } + } + if(by_float_exponent.Optimize()) + should_regenerate = true; + #endif + + if(should_regenerate) + { + CodeTree<Value_t> before = tree; + before.CopyOnWrite(); + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Before ConstantFolding_MulGrouping: "; DumpTree(before); + std::cout << "\n"; + #endif + tree.DelParams(); + + /* Group by exponents */ + /* First handle non-constant exponents */ + for(typename exponent_map::iterator + i = by_exponent.begin(); + i != by_exponent.end(); + ++i) + { + exponent_list& list = i->second; + #ifndef FP_MUL_COMBINE_EXPONENTS + if(list.first.IsImmed()) + { + Value_t exponent = list.first.GetImmed(); + if(exponent == Value_t(0)) continue; + if(fp_equal(exponent, Value_t(1) )) + { + tree.AddParamsMove(list.second); + continue; + } + } + #endif + CodeTree<Value_t> mul; + mul.SetOpcode(cMul); + mul.SetParamsMove( list.second); + mul.Rehash(); + + if(has_highlevel_opcodes && list.first.IsImmed()) + { + if(list.first.GetImmed() == Value_t(1) / Value_t(3)) + { + CodeTree<Value_t> cbrt; + cbrt.SetOpcode(cCbrt); + cbrt.AddParamMove(mul); + cbrt.Rehash(); + tree.AddParamMove(cbrt); + continue; + } + if(list.first.GetImmed() == Value_t(0.5) ) + { + CodeTree<Value_t> sqrt; + sqrt.SetOpcode(cSqrt); + sqrt.AddParamMove(mul); + sqrt.Rehash(); + tree.AddParamMove(sqrt); + continue; + } + if(list.first.GetImmed() == Value_t(-0.5) ) + { + CodeTree<Value_t> rsqrt; + rsqrt.SetOpcode(cRSqrt); + rsqrt.AddParamMove(mul); + rsqrt.Rehash(); + tree.AddParamMove(rsqrt); + continue; + } + if(list.first.GetImmed() == Value_t(-1)) + { + CodeTree<Value_t> inv; + inv.SetOpcode(cInv); + inv.AddParamMove(mul); + inv.Rehash(); + tree.AddParamMove(inv); + continue; + } + } + CodeTree<Value_t> pow; + pow.SetOpcode(cPow); + pow.AddParamMove(mul); + pow.AddParamMove( list.first ); + pow.Rehash(); + tree.AddParamMove(pow); + } + #ifdef FP_MUL_COMBINE_EXPONENTS + by_exponent.clear(); + /* Then handle constant exponents */ + for(size_t a=0; a<by_float_exponent.data.size(); ++a) + { + Value_t exponent = by_float_exponent.data[a].first; + if(fp_equal(exponent, Value_t(1))) + { + tree.AddParamsMove(by_float_exponent.data[a].second); + continue; + } + CodeTree<Value_t> mul; + mul.SetOpcode(cMul); + mul.SetParamsMove( by_float_exponent.data[a].second ); + mul.Rehash(); + CodeTree<Value_t> pow; + pow.SetOpcode(cPow); + pow.AddParamMove(mul); + pow.AddParam( CodeTreeImmed( exponent ) ); + pow.Rehash(); + tree.AddParamMove(pow); + } + #endif + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "After ConstantFolding_MulGrouping: "; DumpTree(tree); + std::cout << "\n"; + #endif + // return true; + return !tree.IsIdenticalTo(before); // avoids infinite looping + } + return false; + } + + template<typename Value_t> + bool ConstantFolding_AddGrouping(CodeTree<Value_t>& tree) + { + bool should_regenerate = false; + CollectionSet<Value_t> add; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + if(tree.GetParam(a).GetOpcode() == cMul) continue; + if(add.AddCollection(tree.GetParam(a)) == CollectionSetBase::Suboptimal) + should_regenerate = true; + // This catches x + x and x - x + } + std::vector<bool> remaining ( tree.GetParamCount() ); + size_t has_mulgroups_remaining = 0; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + const CodeTree<Value_t>& mulgroup = tree.GetParam(a); + if(mulgroup.GetOpcode() == cMul) + { + // This catches x + y*x*z, producing x*(1 + y*z) + // + // However we avoid changing 7 + 7*x into 7*(x+1), + // because it may lead us into producing code such + // as 20*x + 50*(x+1) + 10, which would be much + // better expressed as 70*x + 60, and converting + // back to that format would be needlessly hairy. + for(size_t b=0; b<mulgroup.GetParamCount(); ++b) + { + if(mulgroup.GetParam(b).IsImmed()) continue; + typename CollectionSet<Value_t>::PositionType c + = add.FindIdenticalValueTo(mulgroup.GetParam(b)); + if(add.Found(c)) + { + CodeTree<Value_t> tmp(mulgroup, typename CodeTree<Value_t>::CloneTag()); + tmp.DelParam(b); + tmp.Rehash(); + add.AddCollectionTo(tmp, c); + should_regenerate = true; + goto done_a; + } + } + remaining[a] = true; + has_mulgroups_remaining += 1; + done_a:; + } + } + + if(has_mulgroups_remaining > 0) + { + if(has_mulgroups_remaining > 1) // is it possible to find a duplicate? + { + std::vector< std::pair<CodeTree<Value_t>, size_t> > occurance_counts; + std::multimap<fphash_t, size_t> occurance_pos; + bool found_dup = false; + for(size_t a=0; a<tree.GetParamCount(); ++a) + if(remaining[a]) + { + // This catches x*a + x*b, producing x*(a+b) + for(size_t b=0; b<tree.GetParam(a).GetParamCount(); ++b) + { + const CodeTree<Value_t>& p = tree.GetParam(a).GetParam(b); + const fphash_t p_hash = p.GetHash(); + for(std::multimap<fphash_t, size_t>::const_iterator + i = occurance_pos.lower_bound(p_hash); + i != occurance_pos.end() && i->first == p_hash; + ++i) + { + if(occurance_counts[i->second].first.IsIdenticalTo(p)) + { + occurance_counts[i->second].second += 1; + found_dup = true; + goto found_mulgroup_item_dup; + } + } + occurance_counts.push_back(std::make_pair(p, size_t(1))); + occurance_pos.insert(std::make_pair(p_hash, occurance_counts.size()-1)); + found_mulgroup_item_dup:; + } + } + if(found_dup) + { + // Find the "x" to group by + CodeTree<Value_t> group_by; { size_t max = 0; + for(size_t p=0; p<occurance_counts.size(); ++p) + if(occurance_counts[p].second <= 1) + occurance_counts[p].second = 0; + else + { + occurance_counts[p].second *= occurance_counts[p].first.GetDepth(); + if(occurance_counts[p].second > max) + { group_by = occurance_counts[p].first; max = occurance_counts[p].second; } + } } + // Collect the items for adding in the group (a+b) + CodeTree<Value_t> group_add; + group_add.SetOpcode(cAdd); + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Duplicate across some trees: "; + DumpTree(group_by); + std::cout << " in "; + DumpTree(tree); + std::cout << "\n"; + #endif + for(size_t a=0; a<tree.GetParamCount(); ++a) + if(remaining[a]) + for(size_t b=0; b<tree.GetParam(a).GetParamCount(); ++b) + if(group_by.IsIdenticalTo(tree.GetParam(a).GetParam(b))) + { + CodeTree<Value_t> tmp(tree.GetParam(a), typename CodeTree<Value_t>::CloneTag()); + tmp.DelParam(b); + tmp.Rehash(); + group_add.AddParamMove(tmp); + remaining[a] = false; + break; + } + group_add.Rehash(); + CodeTree<Value_t> group; + group.SetOpcode(cMul); + group.AddParamMove(group_by); + group.AddParamMove(group_add); + group.Rehash(); + add.AddCollection(group); + should_regenerate = true; + } + } + + // all remaining mul-groups. + for(size_t a=0; a<tree.GetParamCount(); ++a) + if(remaining[a]) + { + if(add.AddCollection(tree.GetParam(a)) == CollectionSetBase::Suboptimal) + should_regenerate = true; + } + } + + if(should_regenerate) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Before ConstantFolding_AddGrouping: "; DumpTree(tree); + std::cout << "\n"; + #endif + tree.DelParams(); + + for(typename CollectionSet<Value_t>::PositionType + j = add.collections.begin(); + j != add.collections.end(); + ++j) + { + CodeTree<Value_t>& value = j->second.value; + CodeTree<Value_t>& coeff = j->second.factor; + if(j->second.factor_needs_rehashing) coeff.Rehash(); + + if(coeff.IsImmed()) + { + if(fp_equal(coeff.GetImmed(), Value_t(0))) + continue; + if(fp_equal(coeff.GetImmed(), Value_t(1))) + { + tree.AddParamMove(value); + continue; + } + } + CodeTree<Value_t> mul; + mul.SetOpcode(cMul); + mul.AddParamMove(value); + mul.AddParamMove(coeff); + mul.Rehash(); + tree.AddParamMove(mul); + } + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "After ConstantFolding_AddGrouping: "; DumpTree(tree); + std::cout << "\n"; + #endif + return true; + } + return false; + } +} diff --git a/fpoptimizer/logic_comparisons.hh b/fpoptimizer/logic_comparisons.hh new file mode 100644 index 0000000..1dc5a1f --- /dev/null +++ b/fpoptimizer/logic_comparisons.hh @@ -0,0 +1,282 @@ +#include "codetree.hh" + +namespace +{ + using namespace FUNCTIONPARSERTYPES; + using namespace FPoptimizer_CodeTree; + + /*****************************************/ + /* RANGE-BASED TREATMENTS TO COMPARISONS */ + /*****************************************/ + + struct RangeComparisonData + { + enum Decision + { + MakeFalse=0, + MakeTrue=1, + MakeNEqual=2, + MakeEqual=3, + MakeNotNotP0=4, + MakeNotNotP1=5, + MakeNotP0=6, + MakeNotP1=7, + Unchanged=8 + }; + enum WhatDoWhenCase + { + Never =0, + Eq0 =1, // val==0 + Eq1 =2, // val==1 + Gt0Le1=3, // val>0 && val<=1 + Ge0Lt1=4 // val>=0 && val<1 + }; + + Decision if_identical; // What to do when operands are identical + Decision if_always[4]; // What to do if Always <, <=, >, >= + struct { Decision what : 4; WhatDoWhenCase when : 4; } + p0_logical_a, p1_logical_a, + p0_logical_b, p1_logical_b; + + template<typename Value_t> + Decision Analyze(const CodeTree<Value_t>& a, const CodeTree<Value_t>& b) const + { + if(a.IsIdenticalTo(b)) + return if_identical; + + range<Value_t> p0 = CalculateResultBoundaries(a); + range<Value_t> p1 = CalculateResultBoundaries(b); + /*printf("Analyze(a: min=%g,known=%s,max=%g,known=%s) (b: min=%g,known=%s,max=%g,known=%s)\n", + (double)p0.min.val,p0.min.known?"true":"false", + (double)p0.max.val,p0.max.known?"true":"false", + (double)p1.min.val,p1.min.known?"true":"false", + (double)p1.max.val,p1.max.known?"true":"false" );*/ + if(p0.max.known && p1.min.known) + { + if(p0.max.val < p1.min.val && if_always[0] != Unchanged) + return if_always[0]; // p0 < p1 + if(p0.max.val <= p1.min.val && if_always[1] != Unchanged) + return if_always[1]; // p0 <= p1 + } + if(p0.min.known && p1.max.known) + { + if(p0.min.val > p1.max.val && if_always[2] != Unchanged) + return if_always[2]; // p0 > p1 + if(p0.min.val >= p1.max.val && if_always[3] != Unchanged) + return if_always[3]; // p0 >= p1 + } + + if(IsLogicalValue(a)) + { + if(p0_logical_a.what != Unchanged) + if(TestCase(p0_logical_a.when, p1)) return p0_logical_a.what; + if(p0_logical_b.what != Unchanged) + if(TestCase(p0_logical_b.when, p1)) return p0_logical_b.what; + } + if(IsLogicalValue(b)) + { + if(p1_logical_a.what != Unchanged) + if(TestCase(p1_logical_a.when, p0)) return p1_logical_a.what; + if(p1_logical_b.what != Unchanged) + if(TestCase(p1_logical_b.when, p0)) return p1_logical_b.what; + } + return Unchanged; + } + + template<typename Value_t> + static bool TestCase(WhatDoWhenCase when, const range<Value_t>& p) + { + if(!p.min.known || !p.max.known) return false; + switch(when) + { + case Eq0: return p.min.val==Value_t(0.0) && p.max.val==p.min.val; + case Eq1: return p.min.val==Value_t(1.0) && p.max.val==p.max.val; + case Gt0Le1: return p.min.val>Value_t(0) && p.max.val<=Value_t(1); + case Ge0Lt1: return p.min.val>=Value_t(0) && p.max.val<Value_t(1); + default:; + } + return false; + } + }; + + namespace RangeComparisonsData + { + static const RangeComparisonData Data[6] = + { + // cEqual: + // Case: p0 == p1 Antonym: p0 != p1 + // Synonym: p1 == p0 Antonym: p1 != p0 + { RangeComparisonData::MakeTrue, // If identical: always true + {RangeComparisonData::MakeFalse, // If Always p0 < p1: always false + RangeComparisonData::Unchanged, + RangeComparisonData::MakeFalse, // If Always p0 > p1: always false + RangeComparisonData::Unchanged}, + // NotNot(p0) if p1==1 NotNot(p1) if p0==1 + // Not(p0) if p1==0 Not(p1) if p0==0 + {RangeComparisonData::MakeNotNotP0, RangeComparisonData::Eq1}, + {RangeComparisonData::MakeNotNotP1, RangeComparisonData::Eq1}, + {RangeComparisonData::MakeNotP0, RangeComparisonData::Eq0}, + {RangeComparisonData::MakeNotP1, RangeComparisonData::Eq0} + }, + // cNEqual: + // Case: p0 != p1 Antonym: p0 == p1 + // Synonym: p1 != p0 Antonym: p1 == p0 + { RangeComparisonData::MakeFalse, // If identical: always false + {RangeComparisonData::MakeTrue, // If Always p0 < p1: always true + RangeComparisonData::Unchanged, + RangeComparisonData::MakeTrue, // If Always p0 > p1: always true + RangeComparisonData::Unchanged}, + // NotNot(p0) if p1==0 NotNot(p1) if p0==0 + // Not(p0) if p1==1 Not(p1) if p0==1 + {RangeComparisonData::MakeNotNotP0, RangeComparisonData::Eq0}, + {RangeComparisonData::MakeNotNotP1, RangeComparisonData::Eq0}, + {RangeComparisonData::MakeNotP0, RangeComparisonData::Eq1}, + {RangeComparisonData::MakeNotP1, RangeComparisonData::Eq1} + }, + // cLess: + // Case: p0 < p1 Antonym: p0 >= p1 + // Synonym: p1 > p0 Antonym: p1 <= p0 + { RangeComparisonData::MakeFalse, // If identical: always false + {RangeComparisonData::MakeTrue, // If Always p0 < p1: always true + RangeComparisonData::MakeNEqual, + RangeComparisonData::MakeFalse, // If Always p0 > p1: always false + RangeComparisonData::MakeFalse},// If Always p0 >= p1: always false + // Not(p0) if p1>0 & p1<=1 -- NotNot(p1) if p0>=0 & p0<1 + {RangeComparisonData::MakeNotP0, RangeComparisonData::Gt0Le1}, + {RangeComparisonData::MakeNotNotP1, RangeComparisonData::Ge0Lt1}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never} + }, + // cLessOrEq: + // Case: p0 <= p1 Antonym: p0 > p1 + // Synonym: p1 >= p0 Antonym: p1 < p0 + { RangeComparisonData::MakeTrue, // If identical: always true + {RangeComparisonData::Unchanged, // If Always p0 < p1: ? + RangeComparisonData::MakeTrue, // If Always p0 <= p1: always true + RangeComparisonData::MakeFalse, // If Always p0 > p1: always false + RangeComparisonData::MakeEqual},// If Never p0 < p1: use cEqual + // Not(p0) if p1>=0 & p1<1 -- NotNot(p1) if p0>0 & p0<=1 + {RangeComparisonData::MakeNotP0, RangeComparisonData::Ge0Lt1}, + {RangeComparisonData::MakeNotNotP1, RangeComparisonData::Gt0Le1}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never} + }, + // cGreater: + // Case: p0 > p1 Antonym: p0 <= p1 + // Synonym: p1 < p0 Antonym: p1 >= p0 + { RangeComparisonData::MakeFalse, // If identical: always false + {RangeComparisonData::MakeFalse, // If Always p0 < p1: always false + RangeComparisonData::MakeFalse, // If Always p0 <= p1: always false + RangeComparisonData::MakeTrue, // If Always p0 > p1: always true + RangeComparisonData::MakeNEqual}, + // NotNot(p0) if p1>=0 & p1<1 -- Not(p1) if p0>0 & p0<=1 + {RangeComparisonData::MakeNotNotP0, RangeComparisonData::Ge0Lt1}, + {RangeComparisonData::MakeNotP1, RangeComparisonData::Gt0Le1}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never} + }, + // cGreaterOrEq: + // Case: p0 >= p1 Antonym: p0 < p1 + // Synonym: p1 <= p0 Antonym: p1 > p0 + { RangeComparisonData::MakeTrue, // If identical: always true + {RangeComparisonData::MakeFalse, // If Always p0 < p1: always false + RangeComparisonData::MakeEqual, // If Always p0 >= p1: always true + RangeComparisonData::Unchanged, // If always p0 > p1: ? + RangeComparisonData::MakeTrue}, // If Never p0 > p1: use cEqual + // NotNot(p0) if p1>0 & p1<=1 -- Not(p1) if p0>=0 & p0<1 + {RangeComparisonData::MakeNotNotP0, RangeComparisonData::Gt0Le1}, + {RangeComparisonData::MakeNotP1, RangeComparisonData::Ge0Lt1}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never}, + {RangeComparisonData::Unchanged, RangeComparisonData::Never} + } + }; + } + + template<typename Value_t> + bool ConstantFolding_Comparison(CodeTree<Value_t>& tree) + { + using namespace RangeComparisonsData; + + assert(tree.GetOpcode() >= cEqual && tree.GetOpcode() <= cGreaterOrEq); + + switch(Data[tree.GetOpcode()-cEqual]. + Analyze(tree.GetParam(0), tree.GetParam(1))) + { + case RangeComparisonData::MakeFalse: + tree.ReplaceWithImmed(0); return true; + case RangeComparisonData::MakeTrue: + tree.ReplaceWithImmed(1); return true; + case RangeComparisonData::MakeEqual: tree.SetOpcode(cEqual); return true; + case RangeComparisonData::MakeNEqual: tree.SetOpcode(cNEqual); return true; + case RangeComparisonData::MakeNotNotP0: tree.SetOpcode(cNotNot); tree.DelParam(1); return true; + case RangeComparisonData::MakeNotNotP1: tree.SetOpcode(cNotNot); tree.DelParam(0); return true; + case RangeComparisonData::MakeNotP0: tree.SetOpcode(cNot); tree.DelParam(1); return true; + case RangeComparisonData::MakeNotP1: tree.SetOpcode(cNot); tree.DelParam(0); return true; + case RangeComparisonData::Unchanged:; + } + + // Any reversible functions: + // sin(x) -> ASIN: Not doable, x can be cyclic + // asin(x) -> SIN: doable. + // Invalid combinations are caught by + // range-estimation. Threshold is at |pi/2|. + // acos(x) -> COS: doable. + // Invalid combinations are caught by + // range-estimation. Note that though + // the range is contiguous, it is direction-flipped. + // log(x) -> EXP: no problem + // exp2, exp10: Converted to cPow, done by grammar. + // atan(x) -> TAN: doable. + // Invalid combinations are caught by + // range-estimation. Threshold is at |pi/2|. + // sinh(x) -> ASINH: no problem + // tanh(x) -> ATANH: no problem, but atanh is limited to -1..1 + // Invalid combinations are caught by + // range-estimation, but the exact value + // of 1.0 still needs checking, because + // it involves infinity. + if(tree.GetParam(1).IsImmed()) + switch(tree.GetParam(0).GetOpcode()) + { + case cAsin: + tree.SetParam(0, tree.GetParam(0).GetParam(0)); + tree.SetParam(1, CodeTreeImmed(fp_sin(tree.GetParam(1).GetImmed()))); + return true; + case cAcos: + // -1..+1 --> pi..0 (polarity-flipping) + tree.SetParam(0, tree.GetParam(0).GetParam(0)); + tree.SetParam(1, CodeTreeImmed(fp_cos(tree.GetParam(1).GetImmed()))); + tree.SetOpcode( tree.GetOpcode()==cLess ? cGreater + : tree.GetOpcode()==cLessOrEq ? cGreaterOrEq + : tree.GetOpcode()==cGreater ? cLess + : tree.GetOpcode()==cGreaterOrEq ? cLessOrEq + : tree.GetOpcode() ); + return true; + case cAtan: + tree.SetParam(0, tree.GetParam(0).GetParam(0)); + tree.SetParam(1, CodeTreeImmed(fp_tan(tree.GetParam(1).GetImmed()))); + return true; + case cLog: + // Different logarithms have a constant-multiplication, + // which is no problem. + tree.SetParam(0, tree.GetParam(0).GetParam(0)); + tree.SetParam(1, CodeTreeImmed(fp_exp(tree.GetParam(1).GetImmed()))); + return true; + case cSinh: + tree.SetParam(0, tree.GetParam(0).GetParam(0)); + tree.SetParam(1, CodeTreeImmed(fp_asinh(tree.GetParam(1).GetImmed()))); + return true; + case cTanh: + if(fp_less(fp_abs(tree.GetParam(1).GetImmed()), Value_t(1))) + { + tree.SetParam(0, tree.GetParam(0).GetParam(0)); + tree.SetParam(1, CodeTreeImmed(fp_atanh(tree.GetParam(1).GetImmed()))); + return true; + } + break; + default: break; + } + + return false; + } +} diff --git a/fpoptimizer/logic_ifoperations.hh b/fpoptimizer/logic_ifoperations.hh new file mode 100644 index 0000000..5fd3ba9 --- /dev/null +++ b/fpoptimizer/logic_ifoperations.hh @@ -0,0 +1,381 @@ +#include "codetree.hh" + +namespace +{ + using namespace FUNCTIONPARSERTYPES; + using namespace FPoptimizer_CodeTree; + + /**************************************/ + /* IF OPERATIONS */ + /**************************************/ + + template<typename Value_t> + bool ConstantFolding_IfOperations(CodeTree<Value_t>& tree) + { + assert(tree.GetOpcode() == cIf || tree.GetOpcode() == cAbsIf); + + // If the If() condition begins with a cNot, + // remove the cNot and swap the branches. + for(;;) + { + if(tree.GetParam(0).GetOpcode() == cNot) // TEST 20/ifnot + { + tree.SetOpcode(cIf); + tree.GetParam(0).Become( tree.GetParam(0).GetParam(0) ); + tree.GetParam(1).swap(tree.GetParam(2)); + } + else if(tree.GetParam(0).GetOpcode() == cAbsNot) // TEST 20/ifabsnot + { + tree.SetOpcode(cAbsIf); + tree.GetParam(0).Become( tree.GetParam(0).GetParam(0) ); + tree.GetParam(1).swap(tree.GetParam(2)); + } + else break; + } + + // If the sub-expression evaluates to approx. zero, yield param3. + // If the sub-expression evaluates to approx. nonzero, yield param2. + switch(GetLogicalValue(tree.GetParam(0), tree.GetOpcode()==cAbsIf)) + { // TEST 20/ifconst + case IsAlways: // true + tree.Become(tree.GetParam(1)); + return true; // rerun optimization (opcode changed) + case IsNever: // false + tree.Become(tree.GetParam(2)); + return true; // rerun optimization (opcode changed) + case Unknown: default: ; + } + + if(tree.GetParam(0).GetOpcode() == cIf + || tree.GetParam(0).GetOpcode() == cAbsIf) + { + // TEST 20/ififconst + // if(if(x, a,b), c,d) + // -> if(x, if(a, c,d), if(b, c,d)) + // when either a or b is constantly true/false + CodeTree<Value_t> cond = tree.GetParam(0); + CodeTree<Value_t> truth_a; + truth_a.SetOpcode(cond.GetOpcode() == cIf ? cNotNot : cAbsNotNot); + truth_a.AddParam(cond.GetParam(1)); + ConstantFolding(truth_a); + CodeTree<Value_t> truth_b; + truth_b.SetOpcode(cond.GetOpcode() == cIf ? cNotNot : cAbsNotNot); + truth_b.AddParam(cond.GetParam(2)); + ConstantFolding(truth_b); + if(truth_a.IsImmed() || truth_b.IsImmed()) + { + CodeTree<Value_t> then_tree; + then_tree.SetOpcode(cond.GetOpcode()); + then_tree.AddParam(cond.GetParam(1)); + then_tree.AddParam(tree.GetParam(1)); + then_tree.AddParam(tree.GetParam(2)); + then_tree.Rehash(); + CodeTree<Value_t> else_tree; + else_tree.SetOpcode(cond.GetOpcode()); + else_tree.AddParam(cond.GetParam(2)); + else_tree.AddParam(tree.GetParam(1)); + else_tree.AddParam(tree.GetParam(2)); + else_tree.Rehash(); + tree.SetOpcode(cond.GetOpcode()); + tree.SetParam(0, cond.GetParam(0)); + tree.SetParamMove(1, then_tree); + tree.SetParamMove(2, else_tree); + return true; // rerun cIf optimization + } + } + if(tree.GetParam(1).GetOpcode() == tree.GetParam(2).GetOpcode() + && (tree.GetParam(1).GetOpcode() == cIf + || tree.GetParam(1).GetOpcode() == cAbsIf)) + { + CodeTree<Value_t>& leaf1 = tree.GetParam(1); + CodeTree<Value_t>& leaf2 = tree.GetParam(2); + if(leaf1.GetParam(0).IsIdenticalTo(leaf2.GetParam(0)) + && (leaf1.GetParam(1).IsIdenticalTo(leaf2.GetParam(1)) + || leaf1.GetParam(2).IsIdenticalTo(leaf2.GetParam(2)))) + { + // TEST 20/ifmerge + // if(x, if(y,a,b), if(y,c,d)) + // -> if(y, if(x,a,c), if(x,b,d)) + // when either a,c are identical or b,d are identical + CodeTree<Value_t> then_tree; + then_tree.SetOpcode(tree.GetOpcode()); + then_tree.AddParam(tree.GetParam(0)); + then_tree.AddParam(leaf1.GetParam(1)); + then_tree.AddParam(leaf2.GetParam(1)); + then_tree.Rehash(); + CodeTree<Value_t> else_tree; + else_tree.SetOpcode(tree.GetOpcode()); + else_tree.AddParam(tree.GetParam(0)); + else_tree.AddParam(leaf1.GetParam(2)); + else_tree.AddParam(leaf2.GetParam(2)); + else_tree.Rehash(); + tree.SetOpcode(leaf1.GetOpcode()); + tree.SetParam(0, leaf1.GetParam(0)); + tree.SetParamMove(1, then_tree); + tree.SetParamMove(2, else_tree); + return true; // rerun cIf optimization + // cIf [x (cIf [y a z]) (cIf [y z b])] : (cXor x y) z (cIf[x a b]) + // ^ if only we had cXor opcode. + } + if(leaf1.GetParam(1).IsIdenticalTo(leaf2.GetParam(1)) + && leaf1.GetParam(2).IsIdenticalTo(leaf2.GetParam(2))) + { + // TEST 20/ifmerge2 + // if(x, if(y,a,b), if(z,a,b)) + // -> if( if(x, y,z), a,b) + CodeTree<Value_t> cond_tree; + cond_tree.SetOpcode(tree.GetOpcode()); + cond_tree.AddParamMove(tree.GetParam(0)); + cond_tree.AddParam(leaf1.GetParam(0)); + cond_tree.AddParam(leaf2.GetParam(0)); + cond_tree.Rehash(); + tree.SetOpcode(leaf1.GetOpcode()); + tree.SetParamMove(0, cond_tree); + tree.SetParam(2, leaf1.GetParam(2)); + tree.SetParam(1, leaf1.GetParam(1)); + return true; // rerun cIf optimization + } + if(leaf1.GetParam(1).IsIdenticalTo(leaf2.GetParam(2)) + && leaf1.GetParam(2).IsIdenticalTo(leaf2.GetParam(1))) + { + // TEST 20/ifmerge2b + // if(x, if(y,a,b), if(z,b,a)) + // -> if( if(x, y,!z), a,b) + CodeTree<Value_t> not_tree; + not_tree.SetOpcode(leaf2.GetOpcode() == cIf ? cNot : cAbsNot); + not_tree.AddParam(leaf2.GetParam(0)); + not_tree.Rehash(); + CodeTree<Value_t> cond_tree; + cond_tree.SetOpcode(tree.GetOpcode()); + cond_tree.AddParamMove(tree.GetParam(0)); + cond_tree.AddParam(leaf1.GetParam(0)); + cond_tree.AddParamMove(not_tree); + cond_tree.Rehash(); + tree.SetOpcode(leaf1.GetOpcode()); + tree.SetParamMove(0, cond_tree); + tree.SetParam(2, leaf1.GetParam(2)); + tree.SetParam(1, leaf1.GetParam(1)); + return true; // rerun cIf optimization + } + } + + CodeTree<Value_t>& branch1 = tree.GetParam(1); + CodeTree<Value_t>& branch2 = tree.GetParam(2); + + if(branch1.IsIdenticalTo(branch2)) + { + // TEST 20/ifnop + // If both branches of an If() are identical, the test becomes unnecessary + // NOTE: Possible side-effect on condition removed + tree.Become(tree.GetParam(1)); + return true; // rerun optimization (opcode changed) + } + + const OPCODE op1 = branch1.GetOpcode(); + const OPCODE op2 = branch2.GetOpcode(); + if(op1 == op2) + { + // TEST 20/if_extract_sin + // TEST 20/if_extract_abs + // If both branches apply the same unary function to different values, + // extract the function. E.g. if(x,sin(a),sin(b)) -> sin(if(x,a,b)) + if(branch1.GetParamCount() == 1) + { + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.AddParamMove(tree.GetParam(0)); + changed_if.AddParam(branch1.GetParam(0)); + changed_if.AddParam(branch2.GetParam(0)); + changed_if.Rehash(); + tree.SetOpcode(op1); + tree.DelParams(); + tree.AddParamMove(changed_if); + return true; // rerun optimization (opcode changed) + } + // TEST 20/if_extract_div + // If both branches apply the same binary function to a set of parameters + // where only one parameter differs, extract the function. + // E.g. if(x, y/2, z/2) --> if(x, y,z)/2 (integer mode) + if(branch1.GetParamCount() == 2 + && branch2.GetParamCount() == 2) + { + if(branch1.GetParam(0).IsIdenticalTo(branch2.GetParam(0))) + { + CodeTree<Value_t> param0 = branch1.GetParam(0); + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.AddParamMove(tree.GetParam(0)); + changed_if.AddParam(branch1.GetParam(1)); + changed_if.AddParam(branch2.GetParam(1)); + changed_if.Rehash(); + tree.SetOpcode(op1); + tree.DelParams(); + tree.AddParamMove(param0); + tree.AddParamMove(changed_if); + return true; // rerun optimization (opcode changed) + } + if(branch1.GetParam(1).IsIdenticalTo(branch2.GetParam(1))) + { + CodeTree<Value_t> param1 = branch1.GetParam(1); + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.AddParamMove(tree.GetParam(0)); + changed_if.AddParam(branch1.GetParam(0)); + changed_if.AddParam(branch2.GetParam(0)); + changed_if.Rehash(); + tree.SetOpcode(op1); + tree.DelParams(); + tree.AddParamMove(changed_if); + tree.AddParamMove(param1); + return true; // rerun optimization (opcode changed) + } + } + // TEST 20/if_extract_add + // TEST 20/if_extract_mul + // TEST 20/if_extract_min + if(op1 == cAdd || op1 == cMul + || op1 == cAnd || op1 == cOr + || op1 == cAbsAnd || op1 == cAbsOr + || op1 == cMin || op1 == cMax) + { + // If the two commutative groups contain one + // or more identical values, extract them. + std::vector<CodeTree<Value_t> > overlap; + for(size_t a=branch1.GetParamCount(); a-- > 0; ) + { + for(size_t b=branch2.GetParamCount(); b-- > 0; ) + { + if(branch1.GetParam(a).IsIdenticalTo(branch2.GetParam(b))) + { + if(overlap.empty()) { branch1.CopyOnWrite(); branch2.CopyOnWrite(); } + overlap.push_back(branch1.GetParam(a)); + branch2.DelParam(b); + branch1.DelParam(a); + break; + } + } + } + if(!overlap.empty()) + { + branch1.Rehash(); + branch2.Rehash(); + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.SetParamsMove(tree.GetParams()); + changed_if.Rehash(); + tree.SetOpcode(op1); + tree.SetParamsMove(overlap); + tree.AddParamMove(changed_if); + return true; // rerun optimization (opcode changed) + } + } + } + // if(x, y+z, y) -> if(x, z,0)+y + if(op1 == cAdd + || op1 == cMul + || (op1 == cAnd && IsLogicalValue(branch2)) + || (op1 == cOr && IsLogicalValue(branch2)) + ) + { + // TEST 20/if_extract_add1 + // TEST 20/if_extract_mul1 + // TEST 20/if_extract_and1_l + // TEST 20/if_extract_and1_nl + // TEST 20/if_extract_or1_l + // TEST 20/if_extract_or1_nl + for(size_t a=branch1.GetParamCount(); a-- > 0; ) + if(branch1.GetParam(a).IsIdenticalTo(branch2)) + { + branch1.CopyOnWrite(); + branch1.DelParam(a); + branch1.Rehash(); + CodeTree<Value_t> branch2_backup = branch2; + branch2 = CodeTreeImmed( Value_t( (op1==cAdd||op1==cOr) ? 0 : 1 ) ); + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.SetParamsMove(tree.GetParams()); + changed_if.Rehash(); + tree.SetOpcode(op1); + tree.AddParamMove(branch2_backup); + tree.AddParamMove(changed_if); + return true; // rerun optimization (opcode changed) + } + } + // if(x, y&z, !!y) -> if(x, z, 1) & y + if((op1 == cAnd || op1 == cOr) && op2 == cNotNot) + { + CodeTree<Value_t>& branch2op = branch2.GetParam(0); + for(size_t a=branch1.GetParamCount(); a-- > 0; ) + if(branch1.GetParam(a).IsIdenticalTo(branch2op)) + { + branch1.CopyOnWrite(); + branch1.DelParam(a); + branch1.Rehash(); + CodeTree<Value_t> branch2_backup = branch2op; + branch2 = CodeTreeImmed( Value_t( (op1==cOr) ? 0 : 1 ) ); + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.SetParamsMove(tree.GetParams()); + changed_if.Rehash(); + tree.SetOpcode(op1); + tree.AddParamMove(branch2_backup); + tree.AddParamMove(changed_if); + return true; // rerun optimization (opcode changed) + } + } + // if(x, y, y+z) -> if(x, 0,z)+y + if(op2 == cAdd + || op2 == cMul + || (op2 == cAnd && IsLogicalValue(branch1)) + || (op2 == cOr && IsLogicalValue(branch1)) + ) + { + // TEST 20/if_extract_add2 + // TEST 20/if_extract_mul2 + // TEST 20/if_extract_and2_l + // TEST 20/if_extract_and2_nl + // TEST 20/if_extract_or2_l + // TEST 20/if_extract_or2_nl + for(size_t a=branch2.GetParamCount(); a-- > 0; ) + if(branch2.GetParam(a).IsIdenticalTo(branch1)) + { + branch2.CopyOnWrite(); + branch2.DelParam(a); + branch2.Rehash(); + CodeTree<Value_t> branch1_backup = branch1; + branch1 = CodeTreeImmed( Value_t( (op2==cAdd||op2==cOr) ? 0 : 1 ) ); + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.SetParamsMove(tree.GetParams()); + changed_if.Rehash(); + tree.SetOpcode(op2); + tree.AddParamMove(branch1_backup); + tree.AddParamMove(changed_if); + return true; // rerun optimization (opcode changed) + } + } + // if(x, !!y, y&z) -> if(x, 1, z) & y + if((op2 == cAnd || op2 == cOr) && op1 == cNotNot) + { + CodeTree<Value_t>& branch1op = branch1.GetParam(0); + for(size_t a=branch2.GetParamCount(); a-- > 0; ) + if(branch2.GetParam(a).IsIdenticalTo(branch1op)) + { + branch2.CopyOnWrite(); + branch2.DelParam(a); + branch2.Rehash(); + CodeTree<Value_t> branch1_backup = branch1op; + branch1 = CodeTreeImmed( Value_t( (op2==cOr) ? 0 : 1 ) ); + CodeTree<Value_t> changed_if; + changed_if.SetOpcode(tree.GetOpcode()); + changed_if.SetParamsMove(tree.GetParams()); + changed_if.Rehash(); + tree.SetOpcode(op2); + tree.AddParamMove(branch1_backup); + tree.AddParamMove(changed_if); + return true; // rerun optimization (opcode changed) + } + } + return false; // No changes + } +} diff --git a/fpoptimizer/logic_powoperations.hh b/fpoptimizer/logic_powoperations.hh new file mode 100644 index 0000000..9b49b16 --- /dev/null +++ b/fpoptimizer/logic_powoperations.hh @@ -0,0 +1,222 @@ +#include "codetree.hh" + +#include <limits> + +/**** +#ifdef _MSC_VER +#include <float.h> +#define isinf(x) (!_finite(x)) +#endif +*/ + +namespace +{ + using namespace FUNCTIONPARSERTYPES; + using namespace FPoptimizer_CodeTree; + + /**************************************/ + /* OPERATIONS DONE TO POW() */ + /**************************************/ + + template<typename Value_t> + int maxFPExponent() + { + return std::numeric_limits<Value_t>::max_exponent; + } + + template<typename Value_t> + bool fpExponentIsTooLarge(Value_t base, Value_t exponent) + { + if(base < Value_t(0)) return true; + if(fp_equal(base, Value_t(0)) || fp_equal(base, Value_t(1))) + return false; + return exponent >= Value_t(maxFPExponent<Value_t>()) / fp_log2(base); + } + + template<typename Value_t> + int fpEstimatePrecision(Value_t val) + { + int ex=0; + Value_t t = std::frexp(val, &ex); + unsigned long value = fp_abs(t) * (1u<<30), v0=value; + unsigned int result = 0; + while(!(value&1)) value >>= 1; + for(; value != 0; value >>= 1) ++result; + //printf("%g: t=%g, ex=%d, value=%ld, result=%d\n", + // (double)val, (double)t, ex, v0, result); + return result; + } + + template<typename Value_t> + bool ConstantFolding_PowOperations(CodeTree<Value_t>& tree) + { + assert(tree.GetOpcode() == cPow); + + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).IsImmed()) + { + Value_t const_value = fp_pow(tree.GetParam(0).GetImmed(), + tree.GetParam(1).GetImmed()); + tree.ReplaceWithImmed(const_value); + return false; + } + if(tree.GetParam(1).IsImmed() + && fp_equal(tree.GetParam(1).GetImmed(), Value_t(1))) + { + // Used to be: float(getimmed()) == 1.0 + // Conversion through a float type value gets rid of + // awkward abs(x)^1 generated from exp(log(x^6)/6), + // without sacrificing as much precision as fp_equal() does. + // x^1 = x + tree.Become(tree.GetParam(0)); + return true; // rerun optimization (opcode changed) + } + if(tree.GetParam(0).IsImmed() + && fp_equal(tree.GetParam(0).GetImmed(), Value_t(1))) + { + // 1^x = 1 + tree.ReplaceWithImmed(1); + return false; + } + + // 5^(20*x) = (5^20)^x + if(tree.GetParam(0).IsImmed() + && tree.GetParam(1).GetOpcode() == cMul) + { + bool changes = false; + Value_t base_immed = tree.GetParam(0).GetImmed(); + CodeTree<Value_t> mulgroup = tree.GetParam(1); + for(size_t a=mulgroup.GetParamCount(); a-->0; ) + if(mulgroup.GetParam(a).IsImmed()) + { + Value_t imm = mulgroup.GetParam(a).GetImmed(); + //if(imm >= 0.0) + { + /**** + Value_t new_base_immed = fp_pow(base_immed, imm); + if(isinf(new_base_immed) + || fp_equal(new_base_immed, Value_t(0))) + { + // It produced an infinity. Do not change. + break; + } + */ + if(fpExponentIsTooLarge(base_immed, imm)) + break; + + Value_t new_base_immed = fp_pow(base_immed, imm); + if(fp_equal(new_base_immed, Value_t(0))) + break; + + if(fpEstimatePrecision(new_base_immed) + < (fpEstimatePrecision(base_immed) + fpEstimatePrecision(imm)) / 4) + { + // Bail out if we got an abrupt loss of precision, + // such as with exp(2e-26 * x) -> pow(1, x). + break; + } + + if(!changes) + { + changes = true; + mulgroup.CopyOnWrite(); + } + base_immed = new_base_immed; + mulgroup.DelParam(a); + break; // + } + } + if(changes) + { + mulgroup.Rehash(); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Before pow-mul change: "; DumpTree(tree); + std::cout << "\n"; + #endif + tree.GetParam(0).Become(CodeTreeImmed<Value_t> (base_immed)); + tree.GetParam(1).Become(mulgroup); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "After pow-mul change: "; DumpTree(tree); + std::cout << "\n"; + #endif + } + } + // (x*20)^2 = x^2 * 20^2 + if(tree.GetParam(1).IsImmed() + && tree.GetParam(0).GetOpcode() == cMul) + { + Value_t exponent_immed = tree.GetParam(1).GetImmed(); + Value_t factor_immed = 1.0; + bool changes = false; + CodeTree<Value_t>& mulgroup = tree.GetParam(0); + for(size_t a=mulgroup.GetParamCount(); a-->0; ) + if(mulgroup.GetParam(a).IsImmed()) + { + Value_t imm = mulgroup.GetParam(a).GetImmed(); + //if(imm >= 0.0) + { + /**** + Value_t new_factor_immed = fp_pow(imm, exponent_immed); + if(isinf(new_factor_immed) + || fp_equal(new_factor_immed, Value_t(0))) + { + // It produced an infinity. Do not change. + break; + } + */ + if(fpExponentIsTooLarge(imm, exponent_immed)) + break; + + Value_t new_factor_immed = fp_pow(imm, exponent_immed); + if(fp_equal(new_factor_immed, Value_t(0))) + break; + + if(!changes) + { + changes = true; + mulgroup.CopyOnWrite(); + } + factor_immed *= new_factor_immed; + mulgroup.DelParam(a); + break; // + } + } + if(changes) + { + mulgroup.Rehash(); + CodeTree<Value_t> newpow; + newpow.SetOpcode(cPow); + newpow.SetParamsMove(tree.GetParams()); + newpow.Rehash(false); + tree.SetOpcode(cMul); + tree.AddParamMove(newpow); + tree.AddParam( CodeTreeImmed<Value_t>(factor_immed) ); + return true; // rerun optimization (opcode changed) + } + } + + // (x^3)^2 = x^6 + // NOTE: If 3 is even and 3*2 is not, x must be changed to abs(x). + if(tree.GetParam(0).GetOpcode() == cPow + && tree.GetParam(1).IsImmed() + && tree.GetParam(0).GetParam(1).IsImmed()) + { + Value_t a = tree.GetParam(0).GetParam(1).GetImmed(); + Value_t b = tree.GetParam(1).GetImmed(); + Value_t c = a * b; // new exponent + if(isEvenInteger(a) // a is an even int? + && !isEvenInteger(c)) // c is not? + { + CodeTree<Value_t> newbase; + newbase.SetOpcode(cAbs); + newbase.AddParam(tree.GetParam(0).GetParam(0)); + newbase.Rehash(); + tree.SetParamMove(0, newbase); + } + else + tree.SetParam(0, tree.GetParam(0).GetParam(0)); + tree.SetParam(1, CodeTreeImmed<Value_t>(c)); + } + return false; // No changes that require a rerun + } +} diff --git a/fpoptimizer/makebytecode.cc b/fpoptimizer/makebytecode.cc new file mode 100644 index 0000000..40e9fe8 --- /dev/null +++ b/fpoptimizer/makebytecode.cc @@ -0,0 +1,484 @@ +#include <cmath> +#include <list> +#include <cassert> + +#include "codetree.hh" +#include "extrasrc/fptypes.hh" +#include "consts.hh" +#include "optimize.hh" +#include "bytecodesynth.hh" + +//#include "grammar.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +using namespace FUNCTIONPARSERTYPES; +//using namespace FPoptimizer_Grammar; + +namespace +{ + using namespace FPoptimizer_CodeTree; + + template<typename Value_t> + bool AssembleSequence( + const CodeTree<Value_t>& tree, long count, + const FPoptimizer_ByteCode::SequenceOpCode<Value_t>& sequencing, + FPoptimizer_ByteCode::ByteCodeSynth<Value_t>& synth, + size_t max_bytecode_grow_length); + + /* + Trigonomic operations are expensive. + If we need to synthesize a tan(x), we could + first check if we can synthesize it by utilizing + some expressions that are already in the stack. + Such as: 1 / cot(x) + sin(x) / cos(x) + sin(x) * sec(x) + (1/csc(x)) / cos(x) + sec(x) / csc(x) + This table lists the instructions for building + each of these functions from components that + might already exist in the stack. + + It is up to CSE to make it possible for this + opportunity to arise as often as possible. + */ + static const struct 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 } }, + // tan(x) = 1/cot(x) + // = sin(x) / cos(x) + // = sin(x) * sec(x) + // = (1/csc(x)) / cos(x) + // = sec(x) / csc(x) + + { cCos, cSec, { cSin,cTan, cCsc,cCot } }, + { cSec, cCos, { cTan,cSin, cCot,cCsc } }, + // cos(x) = 1/sec(x) = sin(x) / tan(x) + + { cSin, cCsc, { cCos,cCot, cSec,cTan } }, + { cCsc, cSin, { cCot,cCos, cTan,cSec } }, + // sin(x) = 1/csc(x) = cos(x)/cot(x) + + { cTanh, cNop, { cSinh,cCosh, cNop,cNop } }, + { cSinh, cNop, { cTanh,cNop, cNop,cCosh } }, + { cCosh, cNop, { cSinh,cTanh, cNop,cNop } }, + { cNop, cTanh, { cCosh,cSinh, cNop,cNop } }, + { cNop, cSinh, { cNop, cTanh, cCosh,cNop } }, + { cNop, cCosh, { cTanh,cSinh, cNop,cNop } } + }; +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + void CodeTree<Value_t>::SynthesizeByteCode( + std::vector<unsigned>& ByteCode, + std::vector<Value_t>& Immed, + size_t& stacktop_max) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Making bytecode for:\n"; + DumpTreeWithIndent(*this); + #endif + while(RecreateInversionsAndNegations()) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "One change issued, produced:\n"; + DumpTreeWithIndent(*this); + #endif + FixIncompleteHashes(); + + using namespace FPoptimizer_Optimize; + using namespace FPoptimizer_Grammar; + const void* g = (const void*)&grammar_optimize_recreate; + while(ApplyGrammar(*(const Grammar*)g, *this)) + { FixIncompleteHashes(); + } + } + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Actually synthesizing, after recreating inv/neg:\n"; + DumpTreeWithIndent(*this); + #endif + + FPoptimizer_ByteCode::ByteCodeSynth<Value_t> synth; + + /* Then synthesize the actual expression */ + SynthesizeByteCode(synth, false); + /* The "false" parameters tells SynthesizeByteCode + * that at the outermost synthesizing level, it does + * not matter if leftover temps are left in the stack. + */ + synth.Pull(ByteCode, Immed, stacktop_max); + } + + template<typename Value_t> + void CodeTree<Value_t>::SynthesizeByteCode( + FPoptimizer_ByteCode::ByteCodeSynth<Value_t>& synth, + bool MustPopTemps) const + { + // If the synth can already locate our operand in the stack, + // never mind synthesizing it again, just dup it. + if(synth.FindAndDup(*this)) + { + return; + } + + for(size_t a=0; a<12; ++a) + { + const SinCosTanDataType& data = SinCosTanData[a]; + if(data.whichopcode != cNop) + { + if(GetOpcode() != data.whichopcode) continue; + + CodeTree invtree; + invtree.SetParams(GetParams()); + invtree.SetOpcode( data.inverse_opcode ); + invtree.Rehash(false); + if(synth.FindAndDup(invtree)) + { + synth.AddOperation(cInv,1,1); + synth.StackTopIs(*this); + return; + } + } + else + { + // cNop indicates that there's no dedicated + // opcode that indicates an inverted function. + // For example, we have inv(cosh(x)). + if(GetOpcode() != cInv) continue; + if(GetParam(0).GetOpcode() != data.inverse_opcode) continue; + if(synth.FindAndDup(GetParam(0))) + { + synth.AddOperation(cInv,1,1); + synth.StackTopIs(*this); + return; + } + } + + // Check which trees we can find + size_t found[4]; + for(size_t b=0; b<4; ++b) + { + CodeTree tree; + if(data.codes[b] == cNop) + { + tree.SetOpcode(cInv); + CodeTree subtree; + subtree.SetParams(GetParams()); + subtree.SetOpcode(data.codes[b ^ 2]); + subtree.Rehash(false); + tree.AddParamMove(subtree); + } + else + { + tree.SetParams(GetParams()); + tree.SetOpcode(data.codes[b]); + } + tree.Rehash(false); + found[b] = synth.FindPos(tree); + } + + if(found[ data.nominator ] != ~size_t(0) + && found[ data.denominator ] != ~size_t(0)) + { + // tan(x) = sin(x) / cos(x) + synth.DoDup( found[data.nominator] ); + synth.DoDup( found[data.denominator] ); + synth.AddOperation(cDiv,2,1); + synth.StackTopIs(*this); + return; + } + + if(found[ data.nominator ] != ~size_t(0) + && found[ data.inverse_denominator ] != ~size_t(0)) + { + // tan(x) = sin(x) * sec(x) + synth.DoDup( found[data.nominator] ); + synth.DoDup( found[data.inverse_denominator] ); + synth.AddOperation(cMul,2,1); + synth.StackTopIs(*this); + return; + } + + if(found[ data.inverse_nominator ] != ~size_t(0) + && found[ data.inverse_denominator ] != ~size_t(0)) + { + // tan(x) = 1 / (csc(x) / sec(x)) = sec(x) / csc(x) + synth.DoDup( found[data.inverse_nominator] ); + synth.DoDup( found[data.inverse_denominator] ); + synth.AddOperation(cRDiv,2,1); + synth.StackTopIs(*this); + return; + } + + if(found[ data.inverse_nominator ] != ~size_t(0) + && found[ data.denominator ] != ~size_t(0)) + { + // tan(x) = 1 / csc(x) / cos(x) = 1 / (csc(x) * cos(x)) + synth.DoDup( found[data.inverse_nominator] ); + synth.DoDup( found[data.denominator] ); + synth.AddOperation(cMul,2,1); + synth.AddOperation(cInv,1,1); + synth.StackTopIs(*this); + return; + } + } + + size_t n_subexpressions_synthesized = SynthCommonSubExpressions(synth); + + switch(GetOpcode()) + { + case VarBegin: + synth.PushVar(GetVar()); + break; + case cImmed: + synth.PushImmed(GetImmed()); + break; + case cAdd: + case cMul: + case cMin: + case cMax: + case cAnd: + case cOr: + case cAbsAnd: + case cAbsOr: + { + if(GetOpcode() == cMul) // Special treatment for cMul sequences + { + // If the paramlist contains an Immed, and that Immed + // fits in a long-integer, try to synthesize it + // as add-sequences instead. + bool did_muli = false; + for(size_t a=0; a<GetParamCount(); ++a) + { + if(GetParam(a).IsImmed() && isLongInteger(GetParam(a).GetImmed())) + { + long value = makeLongInteger(GetParam(a).GetImmed()); + + CodeTree tmp(*this, typename CodeTree::CloneTag()); + tmp.DelParam(a); + tmp.Rehash(); + if(AssembleSequence( + tmp, value, + FPoptimizer_ByteCode::SequenceOpcodes<Value_t>::AddSequence, + synth, + MAX_MULI_BYTECODE_LENGTH)) + { + did_muli = true; + break; + } + } + } + if(did_muli) + break; // done + } + + // If any of the params is currently a copy of + // the stack topmost item, treat it first. + int n_stacked = 0; + std::vector<bool> done( GetParamCount() , false ); + CodeTree synthed_tree; + synthed_tree.SetOpcode(GetOpcode()); + for(;;) + { + bool found = false; + for(size_t a=0; a<GetParamCount(); ++a) + { + if(done[a]) continue; + if(synth.IsStackTop(GetParam(a))) + { + found = true; + done[a] = true; + GetParam(a).SynthesizeByteCode(synth); + synthed_tree.AddParam(GetParam(a)); + if(++n_stacked > 1) + { + // Cumulate at the earliest opportunity. + synth.AddOperation(GetOpcode(), 2); // stack state: -2+1 = -1 + synthed_tree.Rehash(false); + synth.StackTopIs(synthed_tree); + n_stacked = n_stacked - 2 + 1; + } + } + } + if(!found) break; + } + + for(size_t a=0; a<GetParamCount(); ++a) + { + if(done[a]) continue; + GetParam(a).SynthesizeByteCode(synth); + synthed_tree.AddParam(GetParam(a)); + if(++n_stacked > 1) + { + // Cumulate at the earliest opportunity. + synth.AddOperation(GetOpcode(), 2); // stack state: -2+1 = -1 + synthed_tree.Rehash(false); + synth.StackTopIs(synthed_tree); + n_stacked = n_stacked - 2 + 1; + } + } + if(n_stacked == 0) + { + // Uh, we got an empty cAdd/cMul/whatever... + // Synthesize a default value. + // This should never happen. + switch(GetOpcode()) + { + case cAdd: + case cOr: + case cAbsOr: + synth.PushImmed(0); + break; + case cMul: + case cAnd: + case cAbsAnd: + synth.PushImmed(1); + break; + case cMin: + case cMax: + //synth.PushImmed(NaN); + synth.PushImmed(0); + break; + default: + break; + } + ++n_stacked; + } + assert(n_stacked == 1); + break; + } + case cPow: + { + const CodeTree& p0 = GetParam(0); + const CodeTree& p1 = GetParam(1); + + if(!p1.IsImmed() + || !isLongInteger(p1.GetImmed()) + || !AssembleSequence( /* Optimize integer exponents */ + p0, makeLongInteger(p1.GetImmed()), + FPoptimizer_ByteCode::SequenceOpcodes<Value_t>::MulSequence, + synth, + MAX_POWI_BYTECODE_LENGTH) + ) + { + p0.SynthesizeByteCode(synth); + p1.SynthesizeByteCode(synth); + synth.AddOperation(GetOpcode(), 2); // Create a vanilla cPow. + } + break; + } + case cIf: + case cAbsIf: + { + // Assume that the parameter count is 3 as it should. + typename FPoptimizer_ByteCode::ByteCodeSynth<Value_t>::IfData ifdata; + + GetParam(0).SynthesizeByteCode(synth); // expression + + synth.SynthIfStep1(ifdata, GetOpcode()); + + GetParam(1).SynthesizeByteCode(synth); // true branch + + synth.SynthIfStep2(ifdata); + + GetParam(2).SynthesizeByteCode(synth); // false branch + + synth.SynthIfStep3(ifdata); + break; + } + case cFCall: + case cPCall: + { + // Assume that the parameter count is as it should. + for(size_t a=0; a<GetParamCount(); ++a) + GetParam(a).SynthesizeByteCode(synth); + synth.AddOperation(GetOpcode(), (unsigned) GetParamCount()); + synth.AddOperation(0x80000000u | GetFuncNo(), 0, 0); + break; + } + default: + { + // Assume that the parameter count is as it should. + for(size_t a=0; a<GetParamCount(); ++a) + GetParam(a).SynthesizeByteCode(synth); + synth.AddOperation(GetOpcode(), (unsigned) GetParamCount()); + break; + } + } + + // Tell the synthesizer which tree was just produced in the stack + synth.StackTopIs(*this); + + // If we added subexpressions, peel them off the stack now + if(MustPopTemps && n_subexpressions_synthesized > 0) + { + size_t top = synth.GetStackTop(); + synth.DoPopNMov(top-1-n_subexpressions_synthesized, top-1); + } + } +} + +namespace +{ + template<typename Value_t> + bool AssembleSequence( + const CodeTree<Value_t>& tree, long count, + const FPoptimizer_ByteCode::SequenceOpCode<Value_t>& sequencing, + FPoptimizer_ByteCode::ByteCodeSynth<Value_t>& synth, + size_t max_bytecode_grow_length) + { + if(count != 0) + { + FPoptimizer_ByteCode::ByteCodeSynth<Value_t> backup = synth; + + tree.SynthesizeByteCode(synth); + + // Ignore the size generated by subtree + size_t bytecodesize_backup = synth.GetByteCodeSize(); + + FPoptimizer_ByteCode::AssembleSequence(count, sequencing, synth); + + size_t bytecode_grow_amount = synth.GetByteCodeSize() - bytecodesize_backup; + if(bytecode_grow_amount > max_bytecode_grow_length) + { + synth = backup; + return false; + } + return true; + } + else + { + FPoptimizer_ByteCode::AssembleSequence(count, sequencing, synth); + return true; + } + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template void CodeTree<type>::SynthesizeByteCode( \ + std::vector<unsigned>& ByteCode, \ + std::vector<type>& Immed, \ + size_t& stacktop_max); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/opcodename.cc b/fpoptimizer/opcodename.cc new file mode 100644 index 0000000..c02f97b --- /dev/null +++ b/fpoptimizer/opcodename.cc @@ -0,0 +1,143 @@ +#include <string> +#include <sstream> +#include <assert.h> + +#include <iostream> + +#include "fpconfig.hh" +#include "extrasrc/fptypes.hh" + +#include "grammar.hh" +#include "opcodename.hh" + +using namespace FPoptimizer_Grammar; +using namespace FUNCTIONPARSERTYPES; + +const std::string FP_GetOpcodeName(FPoptimizer_Grammar::SpecialOpcode opcode, bool pad) +{ +#if 1 + /* Symbolic meanings for the opcodes? */ + const char* p = 0; + switch( opcode ) + { + case NumConstant: p = "NumConstant"; break; + case ParamHolder: p = "ParamHolder"; break; + case SubFunction: p = "SubFunction"; break; + } + std::ostringstream tmp; + //if(!p) std::cerr << "o=" << opcode << "\n"; + assert(p); + tmp << p; + if(pad) while(tmp.str().size() < 12) tmp << ' '; + return tmp.str(); +#else + /* Just numeric meanings */ + std::ostringstream tmp; + tmp << opcode; + if(pad) while(tmp.str().size() < 5) tmp << ' '; + return tmp.str(); +#endif +} + +const std::string FP_GetOpcodeName(FUNCTIONPARSERTYPES::OPCODE opcode, bool pad) +{ +#if 1 + /* Symbolic meanings for the opcodes? */ + const char* p = 0; + switch(opcode) + { + case cAbs: p = "cAbs"; break; + case cAcos: p = "cAcos"; break; + case cAcosh: p = "cAcosh"; break; + case cArg: p = "cArg"; break; + case cAsin: p = "cAsin"; break; + case cAsinh: p = "cAsinh"; break; + case cAtan: p = "cAtan"; break; + case cAtan2: p = "cAtan2"; break; + case cAtanh: p = "cAtanh"; break; + case cCbrt: p = "cCbrt"; break; + case cCeil: p = "cCeil"; break; + case cConj: p = "cConj"; break; + case cCos: p = "cCos"; break; + case cCosh: p = "cCosh"; break; + case cCot: p = "cCot"; break; + case cCsc: p = "cCsc"; break; + case cExp: p = "cExp"; break; + case cExp2: p = "cExp2"; break; + case cFloor: p = "cFloor"; break; + case cHypot: p = "cHypot"; break; + case cIf: p = "cIf"; break; + case cImag: p = "cImag"; break; + case cInt: p = "cInt"; break; + case cLog: p = "cLog"; break; + case cLog2: p = "cLog2"; break; + case cLog10: p = "cLog10"; break; + case cMax: p = "cMax"; break; + case cMin: p = "cMin"; break; + case cPolar: p = "cPolar"; break; + case cPow: p = "cPow"; break; + case cReal: p = "cReal"; break; + case cSec: p = "cSec"; break; + case cSin: p = "cSin"; break; + case cSinh: p = "cSinh"; break; + case cSqrt: p = "cSqrt"; break; + case cTan: p = "cTan"; break; + case cTanh: p = "cTanh"; break; + case cTrunc: p = "cTrunc"; break; + case cImmed: p = "cImmed"; break; + case cJump: p = "cJump"; break; + case cNeg: p = "cNeg"; break; + case cAdd: p = "cAdd"; break; + case cSub: p = "cSub"; break; + case cMul: p = "cMul"; break; + case cDiv: p = "cDiv"; break; + case cMod: p = "cMod"; break; + case cEqual: p = "cEqual"; break; + case cNEqual: p = "cNEqual"; break; + case cLess: p = "cLess"; break; + case cLessOrEq: p = "cLessOrEq"; break; + case cGreater: p = "cGreater"; break; + case cGreaterOrEq: p = "cGreaterOrEq"; break; + case cNot: p = "cNot"; break; + case cAnd: p = "cAnd"; break; + case cOr: p = "cOr"; break; + case cDeg: p = "cDeg"; break; + case cRad: p = "cRad"; break; + case cFCall: p = "cFCall"; break; + case cPCall: p = "cPCall"; break; +#ifdef FP_SUPPORT_OPTIMIZER + case cFetch: p = "cFetch"; break; + case cPopNMov: p = "cPopNMov"; break; + case cLog2by: p = "cLog2by"; break; + case cNop: p = "cNop"; break; +#endif + case cSinCos: p = "cSinCos"; break; + case cSinhCosh: p = "cSinhCosh"; break; + case cAbsNot: p = "cAbsNot"; break; + case cAbsNotNot: p = "cAbsNotNot"; break; + case cAbsAnd: p = "cAbsAnd"; break; + case cAbsOr: p = "cAbsOr"; break; + case cAbsIf: p = "cAbsIf"; break; + case cDup: p = "cDup"; break; + case cInv: p = "cInv"; break; + case cSqr: p = "cSqr"; break; + case cRDiv: p = "cRDiv"; break; + case cRSub: p = "cRSub"; break; + case cNotNot: p = "cNotNot"; break; + case cRSqrt: p = "cRSqrt"; break; + case VarBegin: p = "VarBegin"; break; + } + std::ostringstream tmp; + //if(!p) std::cerr << "o=" << opcode << "\n"; + assert(p); + tmp << p; + if(pad) while(tmp.str().size() < 12) tmp << ' '; + return tmp.str(); +#else + /* Just numeric meanings */ + std::ostringstream tmp; + tmp << opcode; + if(pad) while(tmp.str().size() < 5) tmp << ' '; + return tmp.str(); +#endif +} diff --git a/fpoptimizer/opcodename.hh b/fpoptimizer/opcodename.hh new file mode 100644 index 0000000..77aaa10 --- /dev/null +++ b/fpoptimizer/opcodename.hh @@ -0,0 +1,5 @@ +#include "grammar.hh" +#include <string> + +const std::string FP_GetOpcodeName(FPoptimizer_Grammar::SpecialOpcode opcode, bool pad=false); +const std::string FP_GetOpcodeName(FUNCTIONPARSERTYPES::OPCODE opcode, bool pad=false); diff --git a/fpoptimizer/optimize.cc b/fpoptimizer/optimize.cc new file mode 100644 index 0000000..40d7e80 --- /dev/null +++ b/fpoptimizer/optimize.cc @@ -0,0 +1,448 @@ +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include "grammar.hh" +#include "consts.hh" +#include "opcodename.hh" +#include "optimize.hh" + +#include <stdio.h> + +#include <algorithm> +#include <map> +#include <sstream> + +using namespace FUNCTIONPARSERTYPES; +using namespace FPoptimizer_Grammar; +using namespace FPoptimizer_CodeTree; +using namespace FPoptimizer_Optimize; + +namespace +{ + /* I have heard that std::equal_range() is practically worthless + * due to the insane limitation that the two parameters for Comp() must + * be of the same type. Hence we must reinvent the wheel and implement + * our own here. This is practically identical to the one from + * GNU libstdc++, except rewritten. -Bisqwit + */ + template<typename It, typename T, typename Comp> + std::pair<It, It> + MyEqualRange(It first, It last, const T& val, Comp comp) + { + /*while(first != last && comp(*first, val)) ++first; + while(first != last) + { + It temp = last; --temp; + if(!comp(val, *temp)) break; + last = temp; + } + return std::pair<It,It>(first,last);*/ + + size_t len = last-first; + while(len > 0) + { + size_t half = len/2; + It middle(first); middle += half; + if(comp(*middle, val)) + { + first = middle; + ++first; + len = len - half - 1; + } + else if(comp(val, *middle)) + { + len = half; + } + else + { + // The following implements this: + // // left = lower_bound(first, middle, val, comp); + It left(first); + {/// + It& first2 = left; + It last2(middle); + size_t len2 = last2-first2; + while(len2 > 0) + { + size_t half2 = len2 / 2; + It middle2(first2); middle2 += half2; + if(comp(*middle2, val)) + { + first2 = middle2; + ++first2; + len2 = len2 - half2 - 1; + } + else + len2 = half2; + } + // left = first2; - not needed, already happens due to reference + }/// + first += len; + // The following implements this: + // // right = upper_bound(++middle, first, val, comp); + It right(++middle); + {/// + It& first2 = right; + It& last2 = first; + size_t len2 = last2-first2; + while(len2 > 0) + { + size_t half2 = len2 / 2; + It middle2(first2); middle2 += half2; + if(comp(val, *middle2)) + len2 = half2; + else + { + first2 = middle2; + ++first2; + len2 = len2 - half2 - 1; + } + } + // right = first2; - not needed, already happens due to reference + }/// + return std::pair<It,It> (left,right); + } + } + return std::pair<It,It> (first,first); + } + + /* A helper for std::equal_range */ + template<typename Value_t> + struct OpcodeRuleCompare + { + bool operator() (const CodeTree<Value_t>& tree, + unsigned rulenumber) const + { + /* If this function returns true, len=half. + */ + const Rule& rule = grammar_rules[rulenumber]; + return tree.GetOpcode() < rule.match_tree.subfunc_opcode; + } + bool operator() (unsigned rulenumber, + const CodeTree<Value_t>& tree) const + { + /* If this function returns true, rule will be excluded from the equal_range + */ + const Rule& rule = grammar_rules[rulenumber]; + return rule.match_tree.subfunc_opcode < tree.GetOpcode(); + } + }; + + /* Test and apply a rule to a given CodeTree */ + template<typename Value_t> + bool TestRuleAndApplyIfMatch( + const Rule& rule, + CodeTree<Value_t>& tree, + bool from_logical_context) + { + MatchInfo<Value_t> info; + + MatchResultType found(false, MatchPositionSpecBaseP()); + + if((rule.situation_flags & LogicalContextOnly) + && !from_logical_context) + { + /* If the rule only applies in logical contexts, + * but we do not have a logical context, fail the rule + */ + goto fail; + } + if(FUNCTIONPARSERTYPES::IsIntType<Value_t>::result) + { + if(rule.situation_flags & NotForIntegers) + goto fail; + } + else + { + if(rule.situation_flags & OnlyForIntegers) + goto fail; + } + if(FUNCTIONPARSERTYPES::IsComplexType<Value_t>::result) + { + if(rule.situation_flags & NotForComplex) + goto fail; + } + else + { + if(rule.situation_flags & OnlyForComplex) + goto fail; + } + + /*std::cout << "TESTING: "; + DumpMatch(rule, *tree, info, false);*/ + + for(;;) + { + #ifdef DEBUG_SUBSTITUTIONS + //DumpMatch(rule, tree, info, "Testing"); + #endif + found = TestParams(rule.match_tree, tree, found.specs, info, true); + if(found.found) break; + if(found.specs.isnull()) + { + fail:; + // Did not match + #ifdef DEBUG_SUBSTITUTIONS + DumpMatch(rule, tree, info, false); + #endif + return false; + } + } + // Matched + #ifdef DEBUG_SUBSTITUTIONS + DumpMatch(rule, tree, info, true); + #endif + SynthesizeRule(rule, tree, info); + return true; + } +} + +namespace FPoptimizer_Optimize +{ + /* Apply the grammar to a given CodeTree */ + template<typename Value_t> + bool ApplyGrammar( + const Grammar& grammar, + CodeTree<Value_t>& tree, + bool from_logical_context) + { + if(tree.GetOptimizedUsing() == &grammar) + { +#ifdef DEBUG_SUBSTITUTIONS + std::cout << "Already optimized: "; + DumpTree(tree); + std::cout << "\n" << std::flush; +#endif + return false; + } + + /* First optimize all children */ + if(true) + { + bool changed = false; + + switch(tree.GetOpcode()) + { + case cNot: + case cNotNot: + case cAnd: + case cOr: + for(size_t a=0; a<tree.GetParamCount(); ++a) + if(ApplyGrammar( grammar, tree.GetParam(a), true)) + changed = true; + break; + case cIf: + case cAbsIf: + if(ApplyGrammar( grammar, tree.GetParam(0), tree.GetOpcode() == cIf)) + changed = true; + for(size_t a=1; a<tree.GetParamCount(); ++a) + if(ApplyGrammar( grammar, tree.GetParam(a), from_logical_context)) + changed = true; + break; + default: + for(size_t a=0; a<tree.GetParamCount(); ++a) + if(ApplyGrammar( grammar, tree.GetParam(a), false)) + changed = true; + } + + if(changed) + { + // Give the parent node a rerun at optimization + tree.Mark_Incompletely_Hashed(); + return true; + } + } + + /* Figure out which rules _may_ match this tree */ + typedef const unsigned short* rulenumit; + + /*std::cout << "---TEST:"; + for(unsigned n=0; n<grammar.rule_count; ++n) + std::cout << ' ' << (unsigned)grammar.rule_list[n]; + std::cout << "\n";*/ + + std::pair<rulenumit, rulenumit> range = + MyEqualRange(grammar.rule_list, + grammar.rule_list + grammar.rule_count, + tree, + OpcodeRuleCompare<Value_t> ()); + + std::vector<unsigned short> rules; + rules.reserve(range.second - range.first); + for(rulenumit r = range.first; r != range.second; ++r) + { + //if(grammar_rules[*r].match_tree.subfunc_opcode != tree.GetOpcode()) continue; + if(IsLogisticallyPlausibleParamsMatch(grammar_rules[*r].match_tree, tree)) + rules.push_back(*r); + } + range.first = !rules.empty() ? &rules[0] : 0; + range.second = !rules.empty() ? &rules[rules.size()-1]+1 : 0; + + if(range.first != range.second) + { +#ifdef DEBUG_SUBSTITUTIONS + if(range.first != range.second) + { + std::cout << "Input (" << FP_GetOpcodeName(tree.GetOpcode()) + << ")[" << tree.GetParamCount() + << "]"; + if(from_logical_context) + std::cout << "(Logical)"; + + unsigned first=~unsigned(0), prev=~unsigned(0); + const char* sep = ", rules "; + for(rulenumit r = range.first; r != range.second; ++r) + { + if(first==~unsigned(0)) first=prev=*r; + else if(*r == prev+1) prev=*r; + else + { + std::cout << sep << first; sep=","; + if(prev != first) std::cout << '-' << prev; + first = prev = *r; + } + } + if(first != ~unsigned(0)) + { + std::cout << sep << first; + if(prev != first) std::cout << '-' << prev; + } + std::cout << ": "; + DumpTree(tree); + std::cout << "\n" << std::flush; + } +#endif + + bool changed = false; + + for(rulenumit r = range.first; r != range.second; ++r) + { + #ifndef DEBUG_SUBSTITUTIONS + if(!IsLogisticallyPlausibleParamsMatch(grammar_rules[*r].match_tree, tree)) + continue; + #endif + if(TestRuleAndApplyIfMatch(grammar_rules[*r], tree, from_logical_context)) + { + changed = true; + break; + } + } + + if(changed) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Changed." << std::endl; + std::cout << "Output: "; + DumpTree(tree); + std::cout << "\n" << std::flush; + #endif + // Give the parent node a rerun at optimization + tree.Mark_Incompletely_Hashed(); + return true; + } + } + + // No changes, consider the tree properly optimized. + tree.SetOptimizedUsing(&grammar); + return false; + } + + // This function (void cast) helps avoid a type punning warning from GCC. + template<typename Value_t> + bool ApplyGrammar(const void* p, FPoptimizer_CodeTree::CodeTree<Value_t>& tree) + { + return ApplyGrammar( *(const Grammar*) p, tree); + } + + template<typename Value_t> + void ApplyGrammars(FPoptimizer_CodeTree::CodeTree<Value_t>& tree) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_round1\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_round1, tree)) + { //std::cout << "Rerunning 1\n"; + tree.FixIncompleteHashes(); + } + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_round2\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_round2, tree)) + { //std::cout << "Rerunning 2\n"; + tree.FixIncompleteHashes(); + } + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_round3\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_round3, tree)) + { //std::cout << "Rerunning 3\n"; + tree.FixIncompleteHashes(); + } + + #ifndef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_nonshortcut_logical_evaluation\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_nonshortcut_logical_evaluation, tree)) + { //std::cout << "Rerunning 3\n"; + tree.FixIncompleteHashes(); + } + #endif + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_round4\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_round4, tree)) + { //std::cout << "Rerunning 4\n"; + tree.FixIncompleteHashes(); + } + + #ifdef FP_ENABLE_SHORTCUT_LOGICAL_EVALUATION + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_shortcut_logical_evaluation\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_shortcut_logical_evaluation, tree)) + { //std::cout << "Rerunning 3\n"; + tree.FixIncompleteHashes(); + } + #endif + + #ifdef FP_ENABLE_IGNORE_IF_SIDEEFFECTS + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_ignore_if_sideeffects\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_ignore_if_sideeffects, tree)) + { //std::cout << "Rerunning 3\n"; + tree.FixIncompleteHashes(); + } + #endif + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Applying grammar_optimize_abslogical\n"; + #endif + while(ApplyGrammar((const void*)&grammar_optimize_abslogical, tree)) + { //std::cout << "Rerunning 3\n"; + tree.FixIncompleteHashes(); + } + + #undef C + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_Optimize +{ +#define FP_INSTANTIATE(type) \ + template void ApplyGrammars(FPoptimizer_CodeTree::CodeTree<type>& tree); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/optimize.hh b/fpoptimizer/optimize.hh new file mode 100644 index 0000000..9d35576 --- /dev/null +++ b/fpoptimizer/optimize.hh @@ -0,0 +1,215 @@ +#include "codetree.hh" +#include "grammar.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include <vector> +#include <utility> +#include <iostream> + +//#define DEBUG_SUBSTITUTIONS + +namespace FPoptimizer_Optimize +{ + using namespace FPoptimizer_Grammar; + using namespace FPoptimizer_CodeTree; + using namespace FUNCTIONPARSERTYPES; + + /* This struct collects information regarding the matching process so far */ + template<typename Value_t> + class MatchInfo + { + public: + std::vector<std::pair<bool,std::vector<CodeTree<Value_t> > + > > restholder_matches; + std::vector<CodeTree<Value_t> > paramholder_matches; + std::vector<unsigned> matched_params; + public: + MatchInfo(): restholder_matches(), paramholder_matches(), matched_params() {} + public: + /* These functions save data from matching */ + bool SaveOrTestRestHolder( + unsigned restholder_index, + const std::vector<CodeTree<Value_t> >& treelist) + { + if(restholder_matches.size() <= restholder_index) + { + restholder_matches.resize(restholder_index+1); + restholder_matches[restholder_index].first = true; + restholder_matches[restholder_index].second = treelist; + return true; + } + if(restholder_matches[restholder_index].first == false) + { + restholder_matches[restholder_index].first = true; + restholder_matches[restholder_index].second = treelist; + return true; + } + const std::vector<CodeTree<Value_t> >& found = + restholder_matches[restholder_index].second; + if(treelist.size() != found.size()) + return false; + for(size_t a=0; a<treelist.size(); ++a) + if(!treelist[a].IsIdenticalTo(found[a])) + return false; + return true; + } + + void SaveRestHolder( + unsigned restholder_index, + std::vector<CodeTree<Value_t> >& treelist) + { + if(restholder_matches.size() <= restholder_index) + restholder_matches.resize(restholder_index+1); + restholder_matches[restholder_index].first = true; + restholder_matches[restholder_index].second.swap(treelist); + } + + bool SaveOrTestParamHolder( + unsigned paramholder_index, + const CodeTree<Value_t>& treeptr) + { + if(paramholder_matches.size() <= paramholder_index) + { + paramholder_matches.reserve(paramholder_index+1); + paramholder_matches.resize(paramholder_index); + paramholder_matches.push_back(treeptr); + return true; + } + if(!paramholder_matches[paramholder_index].IsDefined()) + { + paramholder_matches[paramholder_index] = treeptr; + return true; + } + return treeptr.IsIdenticalTo(paramholder_matches[paramholder_index]); + } + + void SaveMatchedParamIndex(unsigned index) + { + matched_params.push_back(index); + } + + /* These functions retrieve the data from matching + * for use when synthesizing the resulting tree. + */ + const CodeTree<Value_t>& GetParamHolderValueIfFound( unsigned paramholder_index ) const + { + static const CodeTree<Value_t> dummytree; + if(paramholder_matches.size() <= paramholder_index) + return dummytree; + return paramholder_matches[paramholder_index]; + } + + const CodeTree<Value_t>& GetParamHolderValue( unsigned paramholder_index ) const + { return paramholder_matches[paramholder_index]; } + + bool HasRestHolder(unsigned restholder_index) const + { return restholder_matches.size() > restholder_index + && restholder_matches[restholder_index].first == true; } + + const std::vector<CodeTree<Value_t> >& GetRestHolderValues( unsigned restholder_index ) const + { + static const std::vector<CodeTree<Value_t> > empty_result; + if(restholder_matches.size() <= restholder_index) + return empty_result; + return restholder_matches[restholder_index].second; + } + + const std::vector<unsigned>& GetMatchedParamIndexes() const + { return matched_params; } + + /* */ + void swap(MatchInfo<Value_t>& b) + { + restholder_matches.swap(b.restholder_matches); + paramholder_matches.swap(b.paramholder_matches); + matched_params.swap(b.matched_params); + } + MatchInfo<Value_t>& operator=(const MatchInfo<Value_t>& b) + { + restholder_matches = b.restholder_matches; + paramholder_matches = b.paramholder_matches; + matched_params = b.matched_params; + return *this; + } + }; + + class MatchPositionSpecBase; + + // For iterating through match candidates + typedef FPOPT_autoptr<MatchPositionSpecBase> MatchPositionSpecBaseP; + + class MatchPositionSpecBase + { + public: + int RefCount; + public: + MatchPositionSpecBase() : RefCount(0) { } + virtual ~MatchPositionSpecBase() { } + }; + struct MatchResultType + { + bool found; + MatchPositionSpecBaseP specs; + + MatchResultType(bool f) : found(f), specs() { } + MatchResultType(bool f, + const MatchPositionSpecBaseP& s) : found(f), specs(s) { } + }; + + /* Synthesize the given grammatic rule's replacement into the codetree */ + template<typename Value_t> + void SynthesizeRule( + const Rule& rule, + CodeTree<Value_t>& tree, + MatchInfo<Value_t>& info); + + /* Test the given parameter to a given CodeTree */ + template<typename Value_t> + MatchResultType TestParam( + const ParamSpec& parampair, + const CodeTree<Value_t> & tree, + const MatchPositionSpecBaseP& start_at, + MatchInfo<Value_t>& info); + + /* Test the list of parameters to a given CodeTree */ + template<typename Value_t> + MatchResultType TestParams( + const ParamSpec_SubFunctionData& model_tree, + const CodeTree<Value_t> & tree, + const MatchPositionSpecBaseP& start_at, + MatchInfo<Value_t>& info, + bool TopLevel); + + template<typename Value_t> + bool ApplyGrammar(const Grammar& grammar, + FPoptimizer_CodeTree::CodeTree<Value_t> & tree, + bool from_logical_context = false); + + template<typename Value_t> + void ApplyGrammars(FPoptimizer_CodeTree::CodeTree<Value_t>& tree); + + template<typename Value_t> + bool IsLogisticallyPlausibleParamsMatch( + const ParamSpec_SubFunctionData& params, + const CodeTree<Value_t>& tree); +} + +namespace FPoptimizer_Grammar +{ + template<typename Value_t> + void DumpMatch(const Rule& rule, + const FPoptimizer_CodeTree::CodeTree<Value_t> & tree, + const FPoptimizer_Optimize::MatchInfo<Value_t>& info, + bool DidMatch, + std::ostream& o = std::cout); + + template<typename Value_t> + void DumpMatch(const Rule& rule, + const FPoptimizer_CodeTree::CodeTree<Value_t> & tree, + const FPoptimizer_Optimize::MatchInfo<Value_t>& info, + const char* whydump, + std::ostream& o = std::cout); +} + +#endif diff --git a/fpoptimizer/optimize_debug.cc b/fpoptimizer/optimize_debug.cc new file mode 100644 index 0000000..67d7524 --- /dev/null +++ b/fpoptimizer/optimize_debug.cc @@ -0,0 +1,95 @@ +#include "optimize.hh" +#ifdef DEBUG_SUBSTITUTIONS + +#include "grammar.hh" +#include "opcodename.hh" + +#include <sstream> +#include <cstring> + +using namespace FUNCTIONPARSERTYPES; +using namespace FPoptimizer_Grammar; +using namespace FPoptimizer_CodeTree; +using namespace FPoptimizer_Optimize; + +namespace FPoptimizer_Grammar +{ + template<typename Value_t> + void DumpMatch(const Rule& rule, + const CodeTree<Value_t>& tree, + const MatchInfo<Value_t>& info, + bool DidMatch, + std::ostream& o) + { + DumpMatch(rule,tree,info,DidMatch?"Found match":"Found mismatch",o); + } + + template<typename Value_t> + void DumpMatch(const Rule& rule, + const CodeTree<Value_t>& tree, + const MatchInfo<Value_t>& info, + const char* whydump, + std::ostream& o) + { + static const char ParamHolderNames[][2] = {"%","&","x","y","z","a","b","c"}; + + o << whydump + << " (rule " << (&rule - grammar_rules) << ")" + << ":\n" + " Pattern : "; + { ParamSpec tmp; + tmp.first = SubFunction; + ParamSpec_SubFunction tmp2; + tmp2.data = rule.match_tree; + tmp.second = (const void*) &tmp2; + DumpParam<Value_t>(tmp, o); + } + o << "\n" + " Replacement: "; + DumpParams<Value_t>(rule.repl_param_list, rule.repl_param_count, o); + o << "\n"; + + o << + " Tree : "; + DumpTree(tree, o); + o << "\n"; + if(!std::strcmp(whydump,"Found match")) DumpHashes(tree, o); + + for(size_t a=0; a<info.paramholder_matches.size(); ++a) + { + if(!info.paramholder_matches[a].IsDefined()) continue; + o << " " << ParamHolderNames[a] << " = "; + DumpTree(info.paramholder_matches[a], o); + o << "\n"; + } + + for(size_t b=0; b<info.restholder_matches.size(); ++b) + { + if(!info.restholder_matches[b].first) continue; + for(size_t a=0; a<info.restholder_matches[b].second.size(); ++a) + { + o << " <" << b << "> = "; + DumpTree(info.restholder_matches[b].second[a], o); + o << std::endl; + } + } + o << std::flush; + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_Grammar +{ +#define FP_INSTANTIATE(type) \ + template void DumpMatch(const Rule& rule, \ + const CodeTree<type>& tree, \ + const MatchInfo<type>& info, \ + bool DidMatch, \ + std::ostream& o); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/optimize_main.cc b/fpoptimizer/optimize_main.cc new file mode 100644 index 0000000..167fac1 --- /dev/null +++ b/fpoptimizer/optimize_main.cc @@ -0,0 +1,100 @@ +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#include "codetree.hh" +#include "optimize.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +template<typename Value_t> +void FunctionParserBase<Value_t>::Optimize() +{ + using namespace FPoptimizer_CodeTree; + + CopyOnWrite(); + + //PrintByteCode(std::cout); + /*std::fprintf(stderr, + "O:refCount:%u mVarCount:%u mfuncPtrs:%u mFuncParsers:%u mByteCode:%u mImmed:%u\n", + mData->mReferenceCounter, + mData->mVariablesAmount, + (unsigned)mData->mFuncPtrs.size(), + (unsigned)mData->mFuncParsers.size(), + (unsigned)mData->mByteCode.size(), + (unsigned)mData->mImmed.size() + );*/ + + CodeTree<Value_t> tree; + tree.GenerateFrom(*mData); + + FPoptimizer_Optimize::ApplyGrammars(tree); + + std::vector<unsigned> byteCode; + std::vector<Value_t> immed; + size_t stacktop_max = 0; + tree.SynthesizeByteCode(byteCode, immed, stacktop_max); + + /*std::cout << std::flush; + std::cerr << std::flush; + fprintf(stderr, "Estimated stacktop %u\n", (unsigned)stacktop_max); + fflush(stderr);*/ + + if(mData->mStackSize != stacktop_max) + { + mData->mStackSize = unsigned(stacktop_max); // Note: Ignoring GCC warning here. +#if !defined(FP_USE_THREAD_SAFE_EVAL) && \ + !defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) + mData->mStack.resize(stacktop_max); +#endif + } + + mData->mByteCode.swap(byteCode); + mData->mImmed.swap(immed); + + //PrintByteCode(std::cout); +} + +#define FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(type) \ + template<> void FunctionParserBase< type >::Optimize() {} + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(MpfrFloat) +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE +FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(GmpInt) +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(std::complex<double>) +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(std::complex<float>) +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_EMPTY_OPTIMIZE(std::complex<long double>) +#endif + +#define FUNCTIONPARSER_INSTANTIATE_OPTIMIZE(type) \ + template void FunctionParserBase<type>::Optimize(); + +#ifndef FP_DISABLE_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_OPTIMIZE(double) +#endif + +#ifdef FP_SUPPORT_FLOAT_TYPE +FUNCTIONPARSER_INSTANTIATE_OPTIMIZE(float) +#endif + +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE +FUNCTIONPARSER_INSTANTIATE_OPTIMIZE(long double) +#endif + +#ifdef FP_SUPPORT_LONG_INT_TYPE +FUNCTIONPARSER_INSTANTIATE_OPTIMIZE(long) +#endif + +#endif // FP_SUPPORT_OPTIMIZER diff --git a/fpoptimizer/optimize_match.cc b/fpoptimizer/optimize_match.cc new file mode 100644 index 0000000..063713f --- /dev/null +++ b/fpoptimizer/optimize_match.cc @@ -0,0 +1,766 @@ +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include <algorithm> +#include <assert.h> +#include <cstring> +#include <cmath> + +#include <memory> /* for auto_ptr */ + +#include "grammar.hh" +#include "optimize.hh" +#include "rangeestimation.hh" +#include "consts.hh" + +using namespace FUNCTIONPARSERTYPES; +using namespace FPoptimizer_Grammar; +using namespace FPoptimizer_CodeTree; +using namespace FPoptimizer_Optimize; + +namespace +{ + /* Test the given constraints to a given CodeTree */ + template<typename Value_t> + bool TestImmedConstraints(unsigned bitmask, const CodeTree<Value_t>& tree) + { + switch(bitmask & ValueMask) + { + case Value_AnyNum: case ValueMask: break; + case Value_EvenInt: + if(GetEvennessInfo(tree) != IsAlways) + return false; + break; + case Value_OddInt: + if(GetEvennessInfo(tree) != IsNever) + return false; + break; + case Value_IsInteger: + if(GetIntegerInfo(tree) != IsAlways) return false; + break; + case Value_NonInteger: + if(GetIntegerInfo(tree) != IsNever) return false; + break; + case Value_Logical: + if(!IsLogicalValue(tree)) return false; + break; + } + switch(bitmask & SignMask) + { + case Sign_AnySign: /*case SignMask:*/ break; + case Sign_Positive: + if(GetPositivityInfo(tree) != IsAlways) return false; + break; + case Sign_Negative: + if(GetPositivityInfo(tree) != IsNever) return false; + break; + case Sign_NoIdea: + if(GetPositivityInfo(tree) != Unknown) return false; + break; + } + switch(bitmask & OnenessMask) + { + case Oneness_Any: case OnenessMask: break; + case Oneness_One: + if(!tree.IsImmed()) return false; + if(!fp_equal(fp_abs(tree.GetImmed()), Value_t(1))) return false; + break; + case Oneness_NotOne: + if(!tree.IsImmed()) return false; + if(fp_equal(fp_abs(tree.GetImmed()), Value_t(1))) return false; + break; + } + switch(bitmask & ConstnessMask) + { + case Constness_Any: /*case ConstnessMask:*/ break; + case Constness_Const: + if(!tree.IsImmed()) return false; + break; + case Constness_NotConst: + if(tree.IsImmed()) return false; + break; + } + return true; + } + + template<unsigned extent, unsigned nbits, typename item_type=unsigned int> + struct nbitmap + { + private: + static const unsigned bits_in_char = 8; + static const unsigned per_item = (sizeof(item_type)*bits_in_char)/nbits; + item_type data[(extent+per_item-1) / per_item]; + public: + void inc(unsigned index, int by=1) + { + data[pos(index)] += by * item_type(1 << shift(index)); + } + inline void dec(unsigned index) { inc(index, -1); } + int get(unsigned index) const { return (data[pos(index)] >> shift(index)) & mask(); } + + static inline unsigned pos(unsigned index) { return index/per_item; } + static inline unsigned shift(unsigned index) { return nbits * (index%per_item); } + static inline unsigned mask() { return (1 << nbits)-1; } + static inline unsigned mask(unsigned index) { return mask() << shift(index); } + }; + + struct Needs + { + int SubTrees : 8; // This many subtrees + int Others : 8; // This many others (namedholder) + int minimum_need : 8; // At least this many leaves (restholder may require more) + int Immeds : 8; // This many immeds + + nbitmap<VarBegin,2> SubTreesDetail; // This many subtrees of each opcode type + + Needs() + { + std::memset(this, 0, sizeof(*this)); + } + Needs(const Needs& b) + { + std::memcpy(this, &b, sizeof(b)); + } + Needs& operator= (const Needs& b) + { + std::memcpy(this, &b, sizeof(b)); + return *this; + } + }; + + template<typename Value_t> + Needs CreateNeedList_uncached(const ParamSpec_SubFunctionData& params) + { + Needs NeedList; + + // Figure out what we need + for(unsigned a = 0; a < params.param_count; ++a) + { + const ParamSpec& parampair = ParamSpec_Extract<Value_t>(params.param_list, a); + switch(parampair.first) + { + case SubFunction: + { + const ParamSpec_SubFunction& param = *(const ParamSpec_SubFunction*) parampair.second; + if(param.data.match_type == GroupFunction) + ++NeedList.Immeds; + else + { + ++NeedList.SubTrees; + assert( param.data.subfunc_opcode < VarBegin ); + NeedList.SubTreesDetail.inc(param.data.subfunc_opcode); + } + ++NeedList.minimum_need; + break; + } + case NumConstant: + case ParamHolder: + ++NeedList.Others; + ++NeedList.minimum_need; + break; + } + } + + return NeedList; + } + + template<typename Value_t> + Needs& CreateNeedList(const ParamSpec_SubFunctionData& params) + { + typedef std::map<const ParamSpec_SubFunctionData*, Needs> needlist_cached_t; + static needlist_cached_t needlist_cached; + + needlist_cached_t::iterator i = needlist_cached.lower_bound(¶ms); + if(i != needlist_cached.end() && i->first == ¶ms) + return i->second; + + return + needlist_cached.insert(i, + std::make_pair(¶ms, CreateNeedList_uncached<Value_t> (params)) + )->second; + } + /* Construct CodeTree from a GroupFunction, hopefully evaluating to a constant value */ + + template<typename Value_t> + CodeTree<Value_t> CalculateGroupFunction( + const ParamSpec& parampair, + const MatchInfo<Value_t>& info) + { + switch( parampair.first ) + { + case NumConstant: + { + const ParamSpec_NumConstant<Value_t>& param = *(const ParamSpec_NumConstant<Value_t>*) parampair.second; + return CodeTreeImmed( param.constvalue ); // Note: calculates hash too. + } + case ParamHolder: + { + const ParamSpec_ParamHolder& param = *(const ParamSpec_ParamHolder*) parampair.second; + return info.GetParamHolderValueIfFound( param.index ); + // If the ParamHolder is not defined, it will simply + // return an Undefined tree. This is ok. + } + case SubFunction: + { + const ParamSpec_SubFunction& param = *(const ParamSpec_SubFunction*) parampair.second; + /* Synthesize a CodeTree which will take care of + * constant-folding our expression. It will also + * indicate whether the result is, in fact, + * a constant at all. */ + CodeTree<Value_t> result; + result.SetOpcode( param.data.subfunc_opcode ); + result.GetParams().reserve(param.data.param_count); + for(unsigned a=0; a<param.data.param_count; ++a) + { + CodeTree<Value_t> tmp( + CalculateGroupFunction + (ParamSpec_Extract<Value_t> (param.data.param_list, a), info) + ); + result.AddParamMove(tmp); + } + result.Rehash(); // This will also call ConstantFolding(). + return result; + } + } + // Issue an un-calculatable tree. (This should be unreachable) + return CodeTree<Value_t>(); // cNop + } +} + +namespace FPoptimizer_Optimize +{ + /* Test the list of parameters to a given CodeTree */ + /* A helper function which simply checks whether the + * basic shape of the tree matches what we are expecting + * i.e. given number of numeric constants, etc. + */ + template<typename Value_t> + bool IsLogisticallyPlausibleParamsMatch( + const ParamSpec_SubFunctionData& params, + const CodeTree<Value_t>& tree) + { + /* First, check if the tree has any chances of matching... */ + /* Figure out what we need. */ + Needs NeedList ( CreateNeedList<Value_t> (params) ); + + size_t nparams = tree.GetParamCount(); + + if(nparams < size_t(NeedList.minimum_need)) + { + // Impossible to satisfy + return false; + } + + // Figure out what we have (note: we already assume that the opcode of the tree matches!) + for(size_t a=0; a<nparams; ++a) + { + unsigned opcode = tree.GetParam(a).GetOpcode(); + switch(opcode) + { + case cImmed: + if(NeedList.Immeds > 0) --NeedList.Immeds; + else --NeedList.Others; + break; + case VarBegin: + case cFCall: + case cPCall: + --NeedList.Others; + break; + default: + assert( opcode < VarBegin ); + if(NeedList.SubTrees > 0 + && NeedList.SubTreesDetail.get(opcode) > 0) + { + --NeedList.SubTrees; + NeedList.SubTreesDetail.dec(opcode); + } + else --NeedList.Others; + } + } + + // Check whether all needs were satisfied + if(NeedList.Immeds > 0 + || NeedList.SubTrees > 0 + || NeedList.Others > 0) + { + // Something came short, impossible to satisfy. + return false; + } + + if(params.match_type != AnyParams) + { + if(0 + //|| NeedList.Immeds < 0 - already checked + || NeedList.SubTrees < 0 + || NeedList.Others < 0 + //|| params.count != nparams - already checked + ) + { + // Something was too much. + return false; + } + } + return true; + } + + /* Test the given parameter to a given CodeTree */ + template<typename Value_t> + MatchResultType TestParam( + const ParamSpec& parampair, + const CodeTree<Value_t>& tree, + const MatchPositionSpecBaseP& start_at, + MatchInfo<Value_t>& info) + { + /*std::cout << "TestParam("; + DumpParam(parampair); + std::cout << ", "; + DumpTree(tree); + std::cout << ")\n";*/ + + /* What kind of param are we expecting */ + switch( parampair.first ) + { + case NumConstant: /* A particular numeric value */ + { + const ParamSpec_NumConstant<Value_t>& param = *(const ParamSpec_NumConstant<Value_t>*) parampair.second; + if(!tree.IsImmed()) return false; + Value_t imm = tree.GetImmed(); + switch(param.modulo) + { + case Modulo_None: break; + case Modulo_Radians: + imm = fp_mod(imm, fp_const_twopi<Value_t>()); + if(imm < Value_t(0)) + imm += fp_const_twopi<Value_t>(); + if(imm > fp_const_pi<Value_t>()) + imm -= fp_const_twopi<Value_t>(); + break; + } + return fp_equal(imm, param.constvalue); + } + case ParamHolder: /* Any arbitrary node */ + { + const ParamSpec_ParamHolder& param = *(const ParamSpec_ParamHolder*) parampair.second; + if(!TestImmedConstraints(param.constraints, tree)) return false; + return info.SaveOrTestParamHolder(param.index, tree); + } + case SubFunction: + { + const ParamSpec_SubFunction& param = *(const ParamSpec_SubFunction*) parampair.second; + if(param.data.match_type == GroupFunction) + { /* A constant value acquired from this formula */ + if(!TestImmedConstraints(param.constraints, tree)) return false; + /* Construct the formula */ + CodeTree<Value_t> grammar_func = CalculateGroupFunction(parampair, info); + #ifdef DEBUG_SUBSTITUTIONS + DumpHashes(grammar_func); + std::cout << *(const void**)&grammar_func.GetImmed(); + std::cout << "\n"; + std::cout << *(const void**)&tree.GetImmed(); + std::cout << "\n"; + DumpHashes(tree); + std::cout << "Comparing "; + DumpTree(grammar_func); + std::cout << " and "; + DumpTree(tree); + std::cout << ": "; + std::cout << (grammar_func.IsIdenticalTo(tree) ? "true" : "false"); + std::cout << "\n"; + #endif + /* Evaluate it and compare */ + return grammar_func.IsIdenticalTo(tree); + } + else /* A subtree conforming these specs */ + { + if(start_at.isnull()) + { + if(!TestImmedConstraints(param.constraints, tree)) return false; + if(tree.GetOpcode() != param.data.subfunc_opcode) return false; + } + return TestParams(param.data, tree, start_at, info, false); + } + } + } + return false; + } + + template<typename Value_t> + struct PositionalParams_Rec + { + MatchPositionSpecBaseP start_at; /* child's start_at */ + MatchInfo<Value_t> info; /* backup of "info" at start */ + + PositionalParams_Rec(): start_at(), info() { } + }; + + template<typename Value_t> + class MatchPositionSpec_PositionalParams + : public MatchPositionSpecBase, + public std::vector<PositionalParams_Rec<Value_t> > + { + public: + explicit MatchPositionSpec_PositionalParams(size_t n) + : MatchPositionSpecBase(), + std::vector<PositionalParams_Rec<Value_t> > (n) + { } + }; + + struct AnyWhere_Rec + { + MatchPositionSpecBaseP start_at; /* child's start_at */ + AnyWhere_Rec() : start_at() { } + }; + class MatchPositionSpec_AnyWhere + : public MatchPositionSpecBase, + public std::vector<AnyWhere_Rec> + { + public: + unsigned trypos; /* which param index to try next */ + + explicit MatchPositionSpec_AnyWhere(size_t n) + : MatchPositionSpecBase(), + std::vector<AnyWhere_Rec> (n), + trypos(0) + { } + }; + + template<typename Value_t> + MatchResultType TestParam_AnyWhere( + const ParamSpec& parampair, + const CodeTree<Value_t>& tree, + const MatchPositionSpecBaseP& start_at, + MatchInfo<Value_t>& info, + std::vector<bool>& used, + bool TopLevel) + { + FPOPT_autoptr<MatchPositionSpec_AnyWhere> position; + unsigned a; + if(!start_at.isnull()) + { + position = (MatchPositionSpec_AnyWhere*) start_at.get(); + a = position->trypos; + goto retry_anywhere_2; + } + else + { + position = new MatchPositionSpec_AnyWhere(tree.GetParamCount()); + a = 0; + } + for(; a < tree.GetParamCount(); ++a) + { + if(used[a]) continue; + + retry_anywhere: + { MatchResultType r = TestParam( + parampair, + tree.GetParam(a), + (*position)[a].start_at, + info); + + (*position)[a].start_at = r.specs; + if(r.found) + { + used[a] = true; // matched + if(TopLevel) info.SaveMatchedParamIndex(a); + + position->trypos = a; // in case of backtrack, try a again + return MatchResultType(true, position.get()); + } } + retry_anywhere_2: + if((*position)[a].start_at.get()) // is there another try? + { + goto retry_anywhere; + } + // no, move on + } + return false; + } + + template<typename Value_t> + struct AnyParams_Rec + { + MatchPositionSpecBaseP start_at; /* child's start_at */ + MatchInfo<Value_t> info; /* backup of "info" at start */ + std::vector<bool> used; /* which params are remaining */ + + explicit AnyParams_Rec(size_t nparams) + : start_at(), info(), used(nparams) { } + }; + template<typename Value_t> + class MatchPositionSpec_AnyParams + : public MatchPositionSpecBase, + public std::vector<AnyParams_Rec<Value_t> > + { + public: + explicit MatchPositionSpec_AnyParams(size_t n, size_t m) + : MatchPositionSpecBase(), + std::vector<AnyParams_Rec<Value_t> > (n, AnyParams_Rec<Value_t>(m)) + { } + }; + + /* Test the list of parameters to a given CodeTree */ + template<typename Value_t> + MatchResultType TestParams( + const ParamSpec_SubFunctionData& model_tree, + const CodeTree<Value_t>& tree, + const MatchPositionSpecBaseP& start_at, + MatchInfo<Value_t>& info, + bool TopLevel) + { + /* When PositionalParams or SelectedParams, verify that + * the number of parameters is exactly as expected. + */ + if(model_tree.match_type != AnyParams) + { + if(model_tree.param_count != tree.GetParamCount()) + return false; + } + + /* Verify that the tree basically conforms the shape we are expecting */ + /* This test is not necessary; it may just save us some work. */ + if(!IsLogisticallyPlausibleParamsMatch(model_tree, tree)) + { + return false; + } + + /* Verify each parameter that they are found in the tree as expected. */ + switch(model_tree.match_type) + { + case PositionalParams: + { + /* Simple: Test all given parameters in succession. */ + FPOPT_autoptr<MatchPositionSpec_PositionalParams<Value_t> > position; + unsigned a; + if(start_at.get()) + { + position = (MatchPositionSpec_PositionalParams<Value_t> *) start_at.get(); + a = model_tree.param_count - 1; + goto retry_positionalparams_2; + } + else + { + position = new MatchPositionSpec_PositionalParams<Value_t> (model_tree.param_count); + a = 0; + } + + for(; a < model_tree.param_count; ++a) + { + (*position)[a].info = info; + retry_positionalparams: + { MatchResultType r = TestParam( + ParamSpec_Extract<Value_t>(model_tree.param_list, a), + tree.GetParam(a), + (*position)[a].start_at, + info); + + (*position)[a].start_at = r.specs; + if(r.found) + { + continue; + } } + retry_positionalparams_2: + // doesn't match + if((*position)[a].start_at.get()) // is there another try? + { + info = (*position)[a].info; + goto retry_positionalparams; + } + // no, backtrack + if(a > 0) + { + --a; + goto retry_positionalparams_2; + } + // cannot backtrack + info = (*position)[0].info; + return false; + } + if(TopLevel) + for(unsigned a = 0; a < model_tree.param_count; ++a) + info.SaveMatchedParamIndex(a); + return MatchResultType(true, position.get()); + } + case SelectedParams: + // same as AnyParams, except that model_tree.count==tree.GetParamCount() + // and that there are no RestHolders + case AnyParams: + { + /* Ensure that all given parameters are found somewhere, in any order */ + + FPOPT_autoptr<MatchPositionSpec_AnyParams<Value_t> > position; + std::vector<bool> used( tree.GetParamCount() ); + std::vector<unsigned> depcodes( model_tree.param_count ); + std::vector<unsigned> test_order( model_tree.param_count ); + for(unsigned a=0; a<model_tree.param_count; ++a) + { + const ParamSpec parampair = ParamSpec_Extract<Value_t>(model_tree.param_list, a); + depcodes[a] = ParamSpec_GetDepCode(parampair); + } + { unsigned b=0; + for(unsigned a=0; a<model_tree.param_count; ++a) + if(depcodes[a] != 0) + test_order[b++] = a; + for(unsigned a=0; a<model_tree.param_count; ++a) + if(depcodes[a] == 0) + test_order[b++] = a; + } + + unsigned a; + if(start_at.get()) + { + position = (MatchPositionSpec_AnyParams<Value_t>*) start_at.get(); + if(model_tree.param_count == 0) + { + a = 0; + goto retry_anyparams_4; + } + a = model_tree.param_count - 1; + goto retry_anyparams_2; + } + else + { + position = new MatchPositionSpec_AnyParams<Value_t> + (model_tree.param_count, tree.GetParamCount()); + a = 0; + if(model_tree.param_count != 0) + { + (*position)[0].info = info; + (*position)[0].used = used; + } + } + // Match all but restholders + for(; a < model_tree.param_count; ++a) + { + if(a > 0) // this test is not necessary, but it saves from doing + { // duplicate work, because [0] was already saved above. + (*position)[a].info = info; + (*position)[a].used = used; + } + retry_anyparams: + { MatchResultType r = TestParam_AnyWhere<Value_t>( + ParamSpec_Extract<Value_t>(model_tree.param_list, test_order[a]), + tree, + (*position)[a].start_at, + info, + used, + TopLevel); + (*position)[a].start_at = r.specs; + if(r.found) + { + continue; + } } + retry_anyparams_2: + // doesn't match + if((*position)[a].start_at.get()) // is there another try? + { + info = (*position)[a].info; + used = (*position)[a].used; + goto retry_anyparams; + } + // no, backtrack + retry_anyparams_3: + if(a > 0) + { + --a; + goto retry_anyparams_2; + } + // cannot backtrack + info = (*position)[0].info; + return false; + } + retry_anyparams_4: + // Capture anything remaining in the restholder + if(model_tree.restholder_index != 0) + { + //std::vector<bool> used_backup(used); + //MatchInfo info_backup(info); + + if(!TopLevel + || !info.HasRestHolder(model_tree.restholder_index)) + { + std::vector<CodeTree<Value_t> > matches; + matches.reserve(tree.GetParamCount()); + for(unsigned b = 0; b < tree.GetParamCount(); ++b) + { + if(used[b]) continue; // Ignore subtrees that were already used + // Save this tree to this restholder + + matches.push_back(tree.GetParam(b)); + used[b] = true; + if(TopLevel) info.SaveMatchedParamIndex(b); + } + if(!info.SaveOrTestRestHolder(model_tree.restholder_index, matches)) + { + // Failure at restholder matching. Backtrack if possible. + //used.swap(used_backup); + //info.swap(info_backup); + goto retry_anyparams_3; + } + //std::cout << "Saved restholder " << model_tree.restholder_index << "\n"; + } + else + { + const std::vector<CodeTree<Value_t> >& matches + = info.GetRestHolderValues(model_tree.restholder_index); + //std::cout << "Testing restholder " << model_tree.restholder_index << std::flush; + for(size_t a=0; a<matches.size(); ++a) + { + bool found = false; + for(unsigned b = 0; b < tree.GetParamCount(); ++b) + { + if(used[b]) continue; + if(matches[a].IsIdenticalTo(tree.GetParam(b))) + { + used[b] = true; + if(TopLevel) info.SaveMatchedParamIndex(b); + found = true; + break; + } + } + if(!found) + { + //std::cout << " ... failed\n"; + // Failure at restholder matching. Backtrack if possible. + //used.swap(used_backup); + //info.swap(info_backup); + goto retry_anyparams_3; + } + } + //std::cout << " ... ok\n"; + } + } + return MatchResultType(true, model_tree.param_count ? position.get() : 0); + } + case GroupFunction: // never occurs + break; + } + return false; // doesn't match + } +} + + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_Optimize +{ +#define FP_INSTANTIATE(type) \ + template \ + MatchResultType TestParams( \ + const ParamSpec_SubFunctionData& model_tree, \ + const CodeTree<type> & tree, \ + const MatchPositionSpecBaseP& start_at, \ + MatchInfo<type>& info, \ + bool TopLevel); \ + template \ + bool IsLogisticallyPlausibleParamsMatch( \ + const ParamSpec_SubFunctionData& params, \ + const CodeTree<type>& tree); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/optimize_synth.cc b/fpoptimizer/optimize_synth.cc new file mode 100644 index 0000000..bc02244 --- /dev/null +++ b/fpoptimizer/optimize_synth.cc @@ -0,0 +1,139 @@ +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include <algorithm> +#include <assert.h> + +#include "optimize.hh" + +using namespace FPoptimizer_CodeTree; +using namespace FPoptimizer_Optimize; + +namespace +{ + /* Synthesize the given grammatic parameter into the codetree */ + template<typename Value_t> + CodeTree<Value_t> SynthesizeParam( + const ParamSpec& parampair, + MatchInfo<Value_t> & info, + bool inner = true) + { + switch( parampair.first ) + { + case NumConstant: + { const ParamSpec_NumConstant<Value_t>& param = *(const ParamSpec_NumConstant<Value_t>*) parampair.second; + return CodeTreeImmed( param.constvalue ); + } + case ParamHolder: + { const ParamSpec_ParamHolder& param = *(const ParamSpec_ParamHolder*) parampair.second; + return info.GetParamHolderValue( param.index ); + } + case SubFunction: + { const ParamSpec_SubFunction& param = *(const ParamSpec_SubFunction*) parampair.second; + CodeTree<Value_t> tree; + tree.SetOpcode( param.data.subfunc_opcode ); + for(unsigned a=0; a < param.data.param_count; ++a) + { + CodeTree<Value_t> nparam = + SynthesizeParam( ParamSpec_Extract<Value_t>(param.data.param_list, a), + info, true ); + tree.AddParamMove(nparam); + } + if(param.data.restholder_index != 0) + { + std::vector<CodeTree<Value_t> > trees + ( info.GetRestHolderValues( param.data.restholder_index ) ); + tree.AddParamsMove(trees); + // ^note: this fails if the same restholder is synth'd twice + if(tree.GetParamCount() == 1) + { + /* Convert cMul <1> into <1> when <1> only contains one operand. + * This is redundant code; it is also done in ConstantFolding(), + * but it might be better for performance to do it here, too. + */ + assert(tree.GetOpcode() == cAdd || tree.GetOpcode() == cMul + || tree.GetOpcode() == cMin || tree.GetOpcode() == cMax + || tree.GetOpcode() == cAnd || tree.GetOpcode() == cOr + || tree.GetOpcode() == cAbsAnd || tree.GetOpcode() == cAbsOr); + tree.Become(tree.GetParam(0)); + } + else if(tree.GetParamCount() == 0) + { + switch(tree.GetOpcode()) + { + case cAdd: case cOr: + tree = CodeTreeImmed(Value_t(0)); + break; + case cMul: case cAnd: + tree = CodeTreeImmed(Value_t(1)); + default: break; + } + } + } + if(inner) tree.Rehash(); + return tree; + } + } + return CodeTree<Value_t> (); + } +} + +namespace FPoptimizer_Optimize +{ + template<typename Value_t> + void SynthesizeRule( + const Rule& rule, + CodeTree<Value_t>& tree, + MatchInfo<Value_t>& info) + { + switch(rule.ruletype) + { + case ProduceNewTree: + { + tree.Become( + SynthesizeParam( ParamSpec_Extract<Value_t>(rule.repl_param_list, 0), + info, false ) ); + break; + } + case ReplaceParams: + default: + { + /* Delete the matched parameters from the source tree */ + std::vector<unsigned> list = info.GetMatchedParamIndexes(); + std::sort(list.begin(), list.end()); + for(size_t a=list.size(); a-->0; ) + tree.DelParam( list[a] ); + + /* Synthesize the replacement params */ + for(unsigned a=0; a < rule.repl_param_count; ++a) + { + CodeTree<Value_t> nparam + = SynthesizeParam( ParamSpec_Extract<Value_t>(rule.repl_param_list, a), + info, true ); + tree.AddParamMove(nparam); + } + break; + } + } + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_Optimize +{ +#define FP_INSTANTIATE(type) \ + template \ + void SynthesizeRule( \ + const Rule& rule, \ + CodeTree<type>& tree, \ + MatchInfo<type>& info); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/rangeestimation.cc b/fpoptimizer/rangeestimation.cc new file mode 100644 index 0000000..2844496 --- /dev/null +++ b/fpoptimizer/rangeestimation.cc @@ -0,0 +1,956 @@ +#include "rangeestimation.hh" +#include "consts.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +using namespace FUNCTIONPARSERTYPES; +using namespace FPoptimizer_CodeTree; + +//#define DEBUG_SUBSTITUTIONS_extra_verbose + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + range<Value_t> CalculateResultBoundaries(const CodeTree<Value_t>& tree) +#ifdef DEBUG_SUBSTITUTIONS_extra_verbose + { + using namespace FUNCTIONPARSERTYPES; + range<Value_t> tmp = CalculateResultBoundaries_do(tree); + std::cout << "Estimated boundaries: "; + if(tmp.min.known) std::cout << tmp.min.val; else std::cout << "-inf"; + std::cout << " .. "; + if(tmp.max.known) std::cout << tmp.max.val; else std::cout << "+inf"; + std::cout << ": "; + DumpTree(tree); + std::cout << std::endl; + return tmp; + } + template<typename Value_t> + range<Value_t> CodeTree<Value_t>::CalculateResultBoundaries_do(const CodeTree<Value_t>& tree) +#endif + { + static const range<Value_t> pihalf_limits + (-fp_const_pihalf<Value_t>(), + fp_const_pihalf<Value_t>()); + + static const range<Value_t> pi_limits + (-fp_const_pi<Value_t>(), + fp_const_pi<Value_t>()); + + static const range<Value_t> abs_pi_limits + ( Value_t(0), + fp_const_pi<Value_t>()); + + static const range<Value_t> plusminus1_limits + ( Value_t(-1), + Value_t(1) ); + + using namespace std; + switch( tree.GetOpcode() ) + { + case cImmed: + return range<Value_t>(tree.GetImmed(), tree.GetImmed()); // a definite value. + 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: + { + /* These operations always produce truth values (0 or 1) */ + /* Narrowing them down is a matter of performing Constant optimization */ + return range<Value_t>( Value_t(0), Value_t(1) ); + } + case cAbs: + { + /* cAbs always produces a positive value */ + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.set_abs(); + return m; + } + + case cLog: /* Defined for 0.0 < x <= inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.template set_if<cGreater>(Value_t(0), fp_log); // No boundaries + m.max.template set_if<cGreater>(Value_t(0), fp_log); // No boundaries + return m; + } + + case cLog2: /* Defined for 0.0 < x <= inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.template set_if<cGreater>(Value_t(0), fp_log2); // No boundaries + m.max.template set_if<cGreater>(Value_t(0), fp_log2); // No boundaries + return m; + } + + case cLog10: /* Defined for 0.0 < x <= inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.template set_if<cGreater>(Value_t(0), fp_log10); // No boundaries + m.max.template set_if<cGreater>(Value_t(0), fp_log10); // No boundaries + return m; + } + + case cAcosh: /* defined for 1.0 <= x <= inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.template set_if<cGreaterOrEq>(Value_t(1), fp_acosh); // No boundaries + m.max.template set_if<cGreaterOrEq>(Value_t(1), fp_acosh); // No boundaries + return m; + } + case cAsinh: /* defined for all values -inf <= x <= inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_asinh); // No boundaries + m.max.set(fp_asinh); // No boundaries + return m; + } + case cAtanh: /* defined for -1.0 <= x < 1, results within -inf..+inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.template set_if<cGreater> (Value_t(-1), fp_atanh); + m.max.template set_if<cLess> (Value_t( 1), fp_atanh); + return m; + } + case cAcos: /* defined for -1.0 <= x <= 1, results within CONSTANT_PI..0 */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + return range<Value_t>( // Note that the range is flipped! + (m.max.known && (m.max.val) < Value_t(1)) + ? fp_acos(m.max.val) : Value_t(0), + (m.min.known && (m.min.val) >= Value_t(-1)) + ? fp_acos(m.min.val) : fp_const_pi<Value_t>() + ); + } + case cAsin: /* defined for -1.0 <= x < 1, results within -CONSTANT_PIHALF..CONSTANT_PIHALF */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + /* Assuming that x is never outside valid limits */ + m.min.template set_if<cGreater>(Value_t(-1), fp_asin, pihalf_limits.min.val); + m.max.template set_if<cLess >(Value_t( 1), fp_asin, pihalf_limits.max.val); + return m; + } + case cAtan: /* defined for all values -inf <= x <= inf, results within -CONSTANT_PIHALF..CONSTANT_PIHALF */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_atan, pihalf_limits.min.val); + m.max.set(fp_atan, pihalf_limits.max.val); + return m; + } + case cAtan2: /* too complicated to estimate */ + { + //range<Value_t> p0 = CalculateResultBoundaries( tree.GetParam(0) ); + //range<Value_t> p1 = CalculateResultBoundaries( tree.GetParam(1) ); + if(tree.GetParam(0).IsImmed() + && fp_equal(tree.GetParam(0).GetImmed(), Value_t(0))) // y == 0 + { + // Either 0.0 or CONSTANT_PI + return abs_pi_limits; + } + if(tree.GetParam(1).IsImmed() + && fp_equal(tree.GetParam(1).GetImmed(), Value_t(0))) // x == 0 + { + // Either -CONSTANT_PIHALF or +CONSTANT_PIHALF + return pihalf_limits; + } + // Anything else + /* Somewhat complicated to narrow down from this */ + /* TODO: A resourceful programmer may add it later. */ + return pi_limits; + } + + case cSin: + { + /* Quite difficult to estimate due to the cyclic nature of the function. */ + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + bool covers_full_cycle + = !m.min.known || !m.max.known + || (m.max.val - m.min.val) >= (fp_const_twopi<Value_t>()); + if(covers_full_cycle) + return range<Value_t>(Value_t(-1), Value_t(1)); + Value_t min = fp_mod(m.min.val, fp_const_twopi<Value_t>()); if(min<Value_t(0)) min+=fp_const_twopi<Value_t>(); + Value_t max = fp_mod(m.max.val, fp_const_twopi<Value_t>()); if(max<Value_t(0)) max+=fp_const_twopi<Value_t>(); + if(max < min) max += fp_const_twopi<Value_t>(); + bool covers_plus1 = (min <= fp_const_pihalf<Value_t>() && max >= fp_const_pihalf<Value_t>()); + bool covers_minus1 = (min <= Value_t(1.5)*fp_const_pi<Value_t>() && max >= Value_t(1.5)*fp_const_pi<Value_t>()); + if(covers_plus1 && covers_minus1) + return range<Value_t>(Value_t(-1), Value_t(1)); + if(covers_minus1) + return range<Value_t>(Value_t(-1), fp_max(fp_sin(min), fp_sin(max))); + if(covers_plus1) + return range<Value_t>(fp_min(fp_sin(min), fp_sin(max)), Value_t(1)); + return range<Value_t>(fp_min(fp_sin(min), fp_sin(max)), + fp_max(fp_sin(min), fp_sin(max))); + } + case cCos: + { + /* Quite difficult to estimate due to the cyclic nature of the function. */ + /* cos(x) = sin(pi/2 - x) = sin(x + pi/2) */ + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + if(m.min.known) m.min.val += fp_const_pihalf<Value_t>();/*for cCos*/ + if(m.max.known) m.max.val += fp_const_pihalf<Value_t>();/*for cCos*/ + bool covers_full_cycle + = !m.min.known || !m.max.known + || (m.max.val - m.min.val) >= (fp_const_twopi<Value_t>()); + if(covers_full_cycle) + return range<Value_t>(Value_t(-1), Value_t(1)); + Value_t min = fp_mod(m.min.val, fp_const_twopi<Value_t>()); if(min<Value_t(0)) min+=fp_const_twopi<Value_t>(); + Value_t max = fp_mod(m.max.val, fp_const_twopi<Value_t>()); if(max<Value_t(0)) max+=fp_const_twopi<Value_t>(); + if(max < min) max += fp_const_twopi<Value_t>(); + bool covers_plus1 = (min <= fp_const_pihalf<Value_t>() && max >= fp_const_pihalf<Value_t>()); + bool covers_minus1 = (min <= Value_t(1.5)*fp_const_pi<Value_t>() && max >= Value_t(1.5)*fp_const_pi<Value_t>()); + if(covers_plus1 && covers_minus1) + return range<Value_t>(Value_t(-1), Value_t(1)); + if(covers_minus1) + return range<Value_t>(Value_t(-1), fp_max(fp_sin(min), fp_sin(max))); + if(covers_plus1) + return range<Value_t>(fp_min(fp_sin(min), fp_sin(max)), Value_t(1)); + return range<Value_t>(fp_min(fp_sin(min), fp_sin(max)), + fp_max(fp_sin(min), fp_sin(max))); + } + case cTan: + { + /* Could be narrowed down from here, + * but it's too complicated due to + * the cyclic nature of the function */ + /* TODO: A resourceful programmer may add it later. */ + return range<Value_t>(); // (CONSTANT_NEG_INF, CONSTANT_POS_INF); + } + + case cCeil: + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.max.set(fp_ceil); // ceil() may increase the value, may not decrease + return m; + } + case cFloor: + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_floor); // floor() may decrease the value, may not increase + return m; + } + case cTrunc: + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_floor); // trunc() may either increase or decrease the value + m.max.set(fp_ceil); // for safety, we assume both + return m; + } + case cInt: + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_floor); // int() may either increase or decrease the value + m.max.set(fp_ceil); // for safety, we assume both + return m; + } + case cSinh: /* defined for all values -inf <= x <= inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_sinh); // No boundaries + m.max.set(fp_sinh); // No boundaries + return m; + } + case cTanh: /* defined for all values -inf <= x <= inf, results within -1..1 */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_tanh, plusminus1_limits.min); + m.max.set(fp_tanh, plusminus1_limits.max); + return m; + } + case cCosh: /* defined for all values -inf <= x <= inf, results within 1..inf */ + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + if(m.min.known) + { + if(m.max.known) // max, min + { + if(m.min.val >= Value_t(0) && m.max.val >= Value_t(0)) // +x .. +y + { m.min.val = fp_cosh(m.min.val); m.max.val = fp_cosh(m.max.val); } + else if((m.min.val) < Value_t(0) && m.max.val >= Value_t(0)) // -x .. +y + { Value_t tmp = fp_cosh(m.min.val); m.max.val = fp_cosh(m.max.val); + if(tmp > m.max.val) m.max.val = tmp; + m.min.val = Value_t(1); } + else // -x .. -y + { m.min.val = fp_cosh(m.min.val); m.max.val = fp_cosh(m.max.val); + std::swap(m.min.val, m.max.val); } + } + else // min, no max + { + if(m.min.val >= Value_t(0)) // 0..inf -> 1..inf + { m.max.known = false; m.min.val = fp_cosh(m.min.val); } + else + { m.max.known = false; m.min.val = Value_t(1); } // Anything between 1..inf + } + } + else // no min + { + m.min.known = true; m.min.val = Value_t(1); // always a lower boundary + if(m.max.known) // max, no min + { + m.min.val = fp_cosh(m.max.val); // n..inf + m.max.known = false; // No upper boundary + } + else // no max, no min + m.max.known = false; // No upper boundary + } + return m; + } + + case cIf: + case cAbsIf: + { + // No guess which branch is chosen. Produce a spanning min & max. + range<Value_t> res1 = CalculateResultBoundaries( tree.GetParam(1) ); + range<Value_t> res2 = CalculateResultBoundaries( tree.GetParam(2) ); + if(!res2.min.known) res1.min.known = false; else if(res1.min.known && (res2.min.val) < res1.min.val) res1.min.val = res2.min.val; + if(!res2.max.known) res1.max.known = false; else if(res1.max.known && (res2.max.val) > res1.max.val) res1.max.val = res2.max.val; + return res1; + } + + case cMin: + { + bool has_unknown_min = false; + bool has_unknown_max = false; + + range<Value_t> result; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(a) ); + if(!m.min.known) + has_unknown_min = true; + else if(!result.min.known || (m.min.val) < result.min.val) + result.min.val = m.min.val; + + if(!m.max.known) + has_unknown_max = true; + else if(!result.max.known || (m.max.val) < result.max.val) + result.max.val = m.max.val; + } + if(has_unknown_min) result.min.known = false; + if(has_unknown_max) result.max.known = false; + return result; + } + case cMax: + { + bool has_unknown_min = false; + bool has_unknown_max = false; + + range<Value_t> result; + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(a) ); + if(!m.min.known) + has_unknown_min = true; + else if(!result.min.known || m.min.val > result.min.val) + result.min.val = m.min.val; + + if(!m.max.known) + has_unknown_max = true; + else if(!result.max.known || m.max.val > result.max.val) + result.max.val = m.max.val; + } + if(has_unknown_min) result.min.known = false; + if(has_unknown_max) result.max.known = false; + return result; + } + case cAdd: + { + /* It's complicated. Follow the logic below. */ + /* Note: This also deals with the following opcodes: + * cNeg, cSub, cRSub + */ + range<Value_t> result(Value_t(0), Value_t(0)); + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + range<Value_t> item = CalculateResultBoundaries( tree.GetParam(a) ); + + if(item.min.known) result.min.val += item.min.val; + else result.min.known = false; + if(item.max.known) result.max.val += item.max.val; + else result.max.known = false; + + if(!result.min.known && !result.max.known) break; // hopeless + } + if(result.min.known && result.max.known + && result.min.val > result.max.val) std::swap(result.min.val, result.max.val); + return result; + } + case cMul: + { + /* It's very complicated. Follow the logic below. */ + struct Value + { + enum ValueType { Finite, MinusInf, PlusInf }; + ValueType valueType; + Value_t value; + + Value(ValueType t): valueType(t), value(0) {} + Value(Value_t v): valueType(Finite), value(v) {} + + bool isNegative() const + { + return valueType == MinusInf || + (valueType == Finite && value < Value_t(0)); + } + + void operator*=(const Value& rhs) + { + if(valueType == Finite && rhs.valueType == Finite) + value *= rhs.value; + else + valueType = (isNegative() != rhs.isNegative() ? + MinusInf : PlusInf); + } + + bool operator<(const Value& rhs) const + { + return + (valueType == MinusInf && rhs.valueType != MinusInf) || + (valueType == Finite && + (rhs.valueType == PlusInf || + (rhs.valueType == Finite && value < rhs.value))); + } + }; + + struct MultiplicationRange + { + Value minValue, maxValue; + + MultiplicationRange(): + minValue(Value::PlusInf), + maxValue(Value::MinusInf) {} + + void multiply(Value value1, const Value& value2) + { + value1 *= value2; + if(value1 < minValue) minValue = value1; + if(maxValue < value1) maxValue = value1; + } + }; + + range<Value_t> result(Value_t(1), Value_t(1)); + for(size_t a=0; a<tree.GetParamCount(); ++a) + { + range<Value_t> item = CalculateResultBoundaries( tree.GetParam(a) ); + if(!item.min.known && !item.max.known) return range<Value_t>(); // hopeless + + Value minValue0 = result.min.known ? Value(result.min.val) : Value(Value::MinusInf); + Value maxValue0 = result.max.known ? Value(result.max.val) : Value(Value::PlusInf); + Value minValue1 = item.min.known ? Value(item.min.val) : Value(Value::MinusInf); + Value maxValue1 = item.max.known ? Value(item.max.val) : Value(Value::PlusInf); + + MultiplicationRange range; + range.multiply(minValue0, minValue1); + range.multiply(minValue0, maxValue1); + range.multiply(maxValue0, minValue1); + range.multiply(maxValue0, maxValue1); + + if(range.minValue.valueType == Value::Finite) + result.min.val = range.minValue.value; + else result.min.known = false; + + if(range.maxValue.valueType == Value::Finite) + result.max.val = range.maxValue.value; + else result.max.known = false; + + if(!result.min.known && !result.max.known) break; // hopeless + } + if(result.min.known && result.max.known + && result.min.val > result.max.val) std::swap(result.min.val, result.max.val); + return result; + } + case cMod: + { + /* TODO: The boundaries of modulo operator could be estimated better. */ + + range<Value_t> x = CalculateResultBoundaries( tree.GetParam(0) ); + range<Value_t> y = CalculateResultBoundaries( tree.GetParam(1) ); + + if(y.max.known) + { + if(y.max.val >= Value_t(0)) + { + if(!x.min.known || (x.min.val) < Value_t(0)) + return range<Value_t>(-y.max.val, y.max.val); + else + return range<Value_t>(Value_t(0), y.max.val); + } + else + { + if(!x.max.known || (x.max.val) >= Value_t(0)) + return range<Value_t>(y.max.val, -y.max.val); + else + return range<Value_t>(y.max.val, fp_const_negativezero<Value_t>()); + } + } + else + return range<Value_t>(); + } + case cPow: + { + if(tree.GetParam(1).IsImmed() && tree.GetParam(1).GetImmed() == Value_t(0)) + { + // Note: This makes 0^0 evaluate into 1. + return range<Value_t>(Value_t(1), Value_t(1)); // x^0 = 1 + } + if(tree.GetParam(0).IsImmed() && tree.GetParam(0).GetImmed() == Value_t(0)) + { + // Note: This makes 0^0 evaluate into 0. + return range<Value_t>(Value_t(0), Value_t(0)); // 0^x = 0 + } + if(tree.GetParam(0).IsImmed() && fp_equal(tree.GetParam(0).GetImmed(), Value_t(1))) + { + return range<Value_t>(Value_t(1), Value_t(1)); // 1^x = 1 + } + if(tree.GetParam(1).IsImmed() + && tree.GetParam(1).GetImmed() > Value_t(0) + && GetEvennessInfo(tree.GetParam(1)) == IsAlways) + { + // x ^ even_int_const always produces a non-negative value. + Value_t exponent = tree.GetParam(1).GetImmed(); + range<Value_t> tmp = CalculateResultBoundaries( tree.GetParam(0) ); + range<Value_t> result; + result.min.known = true; + result.min.val = 0; + if(tmp.min.known && tmp.min.val >= Value_t(0)) + result.min.val = fp_pow(tmp.min.val, exponent); + else if(tmp.max.known && tmp.max.val <= Value_t(0)) + result.min.val = fp_pow(tmp.max.val, exponent); + + result.max.known = false; + if(tmp.min.known && tmp.max.known) + { + result.max.known = true; + result.max.val = fp_max(fp_abs(tmp.min.val), fp_abs(tmp.max.val)); + result.max.val = fp_pow(result.max.val, exponent); + } + return result; + } + + range<Value_t> p0 = CalculateResultBoundaries( tree.GetParam(0) ); + range<Value_t> p1 = CalculateResultBoundaries( tree.GetParam(1) ); + TriTruthValue p0_positivity = + (p0.min.known && (p0.min.val) >= Value_t(0)) ? IsAlways + : (p0.max.known && (p0.max.val) < Value_t(0) ? IsNever + : Unknown); + TriTruthValue p1_evenness = GetEvennessInfo(tree.GetParam(1)); + + /* If param0 IsAlways, the return value is also IsAlways */ + /* If param1 is even, the return value is IsAlways */ + /* If param1 is odd, the return value is same as param0's */ + /* If param0 is negative and param1 is not integer, + * the return value is imaginary (assumed Unknown) + * + * Illustrated in this truth table: + * P=positive, N=negative + * E=even, O=odd, U=not integer + * *=unknown, X=invalid (unknown), x=maybe invalid (unknown) + * + * param1: PE PO P* NE NO N* PU NU * + * param0: + * PE P P P P P P P P P + * PO P P P P P P P P P + * PU P P P P P P P P P + * P* P P P P P P P P P + * NE P N * P N * X X x + * NO P N * P N * X X x + * NU P N * P N * X X x + * N* P N * P N * X X x + * * P * * P * * x x * + * + * Note: This also deals with the following opcodes: + * cSqrt (param0, PU) (x^0.5) + * cRSqrt (param0, NU) (x^-0.5) + * cExp (PU, param1) (CONSTANT_E^x) + */ + TriTruthValue result_positivity = Unknown; + switch(p0_positivity) + { + case IsAlways: + // e.g. 5^x = positive. + result_positivity = IsAlways; + break; + case IsNever: + { + result_positivity = p1_evenness; + break; + } + default: + switch(p1_evenness) + { + case IsAlways: + // e.g. x^( 4) = positive + // e.g. x^(-4) = positive + result_positivity = IsAlways; + break; + case IsNever: + break; + case Unknown: + { + /* If p1 is const non-integer, + * assume the result is positive + * though it may be NaN instead. + */ + if(tree.GetParam(1).IsImmed() + && !isInteger(tree.GetParam(1).GetImmed()) + && tree.GetParam(1).GetImmed() >= Value_t(0)) + { + result_positivity = IsAlways; + } + break; + } + } + } + switch(result_positivity) + { + case IsAlways: + { + /* The result is always positive. + * Figure out whether we know the minimum value. */ + if((p1.max.known && p1.max.val < 0) + || (p1.min.known && p1.min.val < 0)) + { + // Fix regression 50/10: + // 1/abs(x) must not be estimated to be >=inf + // TODO: Better fix + return range<Value_t>(); + } + Value_t min = Value_t(0); + if(p0.min.known && p1.min.known) + { + min = fp_pow(p0.min.val, p1.min.val); + if(p0.min.val < Value_t(0) && (!p1.max.known || p1.max.val >= Value_t(0)) && min >= Value_t(0)) + min = Value_t(0); + } + if(p0.min.known && p0.min.val >= Value_t(0) && p0.max.known && p1.max.known) + { + Value_t max = fp_pow(p0.max.val, p1.max.val); + if(min > max) std::swap(min, max); + return range<Value_t>(min, max); + } + return range<Value_t>(min, false); + } + case IsNever: + { + /* The result is always negative. + * TODO: Figure out whether we know the maximum value. + */ + return range<Value_t>(false, fp_const_negativezero<Value_t>()); + } + default: + { + /* It can be negative or positive. + * We know nothing about the boundaries. */ + break; + } + } + break; + } + + /* The following opcodes are processed by GenerateFrom() + * within fpoptimizer_bytecode_to_codetree.cc and thus + * they will never occur in the calling context for the + * most of the parsing context. They may however occur + * at the late phase, so we deal with them. + */ + case cNeg: + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.set_neg(); + return m; + } + case cSub: // converted into cAdd(x, cNeg(y)) + { + CodeTree<Value_t> tmp, tmp2; + tmp2.SetOpcode(cNeg); + tmp2.AddParam(tree.GetParam(1)); + tmp.SetOpcode(cAdd); + tmp.AddParam(tree.GetParam(0)); + tmp.AddParamMove(tmp2); + return CalculateResultBoundaries(tmp); + } + case cInv: // converted into cPow x -1 + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cPow); + tmp.AddParam(tree.GetParam(0)); + tmp.AddParam(CodeTreeImmed(Value_t(-1))); + return CalculateResultBoundaries(tmp); + } + case cDiv: // converted into cPow y -1 + { + CodeTree<Value_t> tmp, tmp2; + tmp2.SetOpcode(cInv); + tmp2.AddParam(tree.GetParam(1)); + tmp.SetOpcode(cMul); + tmp.AddParam(tree.GetParam(0)); + tmp.AddParamMove(tmp2); + return CalculateResultBoundaries(tmp); + } + case cRad: // converted into cMul x CONSTANT_RD + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cMul); + tmp.AddParam(tree.GetParam(0)); + tmp.AddParam(CodeTreeImmed(fp_const_rad_to_deg<Value_t>())); + return CalculateResultBoundaries(tmp); + } + case cDeg: // converted into cMul x CONSTANT_DR + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cMul); + tmp.AddParam(tree.GetParam(0)); + tmp.AddParam(CodeTreeImmed(fp_const_deg_to_rad<Value_t>())); + return CalculateResultBoundaries(tmp); + } + case cSqr: // converted into cMul x x or cPow x 2 + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cPow); + tmp.AddParam(tree.GetParam(0)); + tmp.AddParam(CodeTreeImmed(Value_t(2))); + return CalculateResultBoundaries(tmp); + } + case cExp: // converted into cPow CONSTANT_E x + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cPow); + tmp.AddParam(CodeTreeImmed(fp_const_e<Value_t>())); + tmp.AddParam(tree.GetParam(0)); + return CalculateResultBoundaries(tmp); + } + case cExp2: // converted into cPow 2 x + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cPow); + tmp.AddParam(CodeTreeImmed(Value_t(2))); + tmp.AddParam(tree.GetParam(0)); + return CalculateResultBoundaries(tmp); + } + case cCbrt: // converted into cPow x 0.33333333 + { + // However, contrary to x^(1/3), this allows + // negative values for x, and produces those + // as well. + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + m.min.set(fp_cbrt); + m.max.set(fp_cbrt); + return m; + } + case cSqrt: // converted into cPow x 0.5 + { + range<Value_t> m = CalculateResultBoundaries( tree.GetParam(0) ); + if(m.min.known) m.min.val = (m.min.val) < Value_t(0) ? 0 : fp_sqrt(m.min.val); + if(m.max.known) m.max.val = (m.max.val) < Value_t(0) ? 0 : fp_sqrt(m.max.val); + return m; + } + case cRSqrt: // converted into cPow x -0.5 + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cPow); + tmp.AddParam(tree.GetParam(0)); + tmp.AddParam(CodeTreeImmed( Value_t(-0.5) )); + return CalculateResultBoundaries(tmp); + } + case cHypot: // converted into cSqrt(cAdd(cMul(x x), cMul(y y))) + { + CodeTree<Value_t> xsqr, ysqr, add, sqrt; + xsqr.AddParam(tree.GetParam(0)); xsqr.AddParam(CodeTreeImmed( Value_t(2) )); + ysqr.AddParam(tree.GetParam(1)); ysqr.AddParam(CodeTreeImmed( Value_t(2) )); + xsqr.SetOpcode(cPow); ysqr.SetOpcode(cPow); + add.AddParamMove(xsqr); add.AddParamMove(ysqr); + add.SetOpcode(cAdd); sqrt.AddParamMove(add); + sqrt.SetOpcode(cSqrt); + return CalculateResultBoundaries(sqrt); + } + case cLog2by: // converted into cMul y CONSTANT_L2I (cLog x) + { + CodeTree<Value_t> tmp, tmp2; + tmp2.SetOpcode(cLog2); + tmp2.AddParam(tree.GetParam(0)); + tmp.SetOpcode(cMul); + tmp.AddParamMove(tmp2); + tmp.AddParam(tree.GetParam(1)); + return CalculateResultBoundaries(tmp); + } + case cCot: // converted into 1 / cTan + { + CodeTree<Value_t> tmp, tmp2; + tmp2.SetOpcode(cTan); + tmp2.AddParam(tree.GetParam(0)); + tmp.SetOpcode(cInv); + tmp.AddParamMove(tmp2); + return CalculateResultBoundaries(tmp); + } + case cSec: // converted into 1 / cCos + { + CodeTree<Value_t> tmp, tmp2; + tmp2.SetOpcode(cCos); + tmp2.AddParam(tree.GetParam(0)); + tmp.SetOpcode(cInv); + tmp.AddParamMove(tmp2); + return CalculateResultBoundaries(tmp); + } + case cCsc: // converted into 1 / cSin + { + CodeTree<Value_t> tmp, tmp2; + tmp2.SetOpcode(cSin); + tmp2.AddParam(tree.GetParam(0)); + tmp.SetOpcode(cInv); + tmp.AddParamMove(tmp2); + return CalculateResultBoundaries(tmp); + } + /* The following opcodes are processed by GenerateFrom() + * within fpoptimizer_bytecode_to_codetree.cc and thus + * they will never occur in the calling context: + */ + break; /* Should never occur */ + + /* Opcodes that do not occur in the tree for other reasons */ + case cRDiv: // version of cDiv + case cRSub: // version of cSub + case cDup: + case cFetch: + case cPopNMov: + case cSinCos: + case cSinhCosh: + case cNop: + case cJump: + case VarBegin: + break; /* Should never occur */ + + /* Complex functions */ + case cArg: + case cConj: + case cImag: + case cReal: + case cPolar: + break; /* Should never occur */ + + /* Opcodes that are completely unpredictable */ + case cPCall: + break; + case cFCall: + break; // Cannot deduce + } + return range<Value_t>(); /* Cannot deduce */ + } + + template<typename Value_t> + TriTruthValue GetIntegerInfo(const CodeTree<Value_t>& tree) + { + switch(tree.GetOpcode()) + { + case cImmed: + return isInteger(tree.GetImmed()) ? IsAlways : IsNever; + case cFloor: + case cCeil: + case cTrunc: + case cInt: + return IsAlways; + case cAnd: + case cOr: + case cNot: + case cNotNot: + case cEqual: + case cNEqual: + case cLess: + case cLessOrEq: + case cGreater: + case cGreaterOrEq: + /* These operations always produce truth values (0 or 1) */ + return IsAlways; /* 0 and 1 are both integers */ + case cIf: + { + TriTruthValue a = GetIntegerInfo(tree.GetParam(1)); + TriTruthValue b = GetIntegerInfo(tree.GetParam(2)); + if(a == b) return a; + return Unknown; + } + case cAdd: + case cMul: + { + // It's integer if all the components are integer + // Otherwise, unknown whether it's integer + // A confirmed non-integer does not necessarily + // mean the result isn't an integer, because: + // 0.5 + 0.5 = 1.0; sqrt(2) * sqrt(2) = 2.0 + for(size_t a=tree.GetParamCount(); a-- > 0; ) + if(GetIntegerInfo(tree.GetParam(a)) != IsAlways) + return Unknown; + return IsAlways; + } + default: + break; + } + return Unknown; /* Don't know whether it's integer. */ + } + + template<typename Value_t> + bool IsLogicalValue(const CodeTree<Value_t>& tree) + { + switch(tree.GetOpcode()) + { + case cImmed: + return fp_equal(tree.GetImmed(), Value_t(0)) + || fp_equal(tree.GetImmed(), Value_t(1)); + case cAnd: + case cOr: + case cNot: + case cNotNot: + case cAbsAnd: + case cAbsOr: + case cAbsNot: + case cAbsNotNot: + case cEqual: + case cNEqual: + case cLess: + case cLessOrEq: + case cGreater: + case cGreaterOrEq: + /* These operations always produce truth values (0 or 1) */ + return true; + case cMul: + { + for(size_t a=tree.GetParamCount(); a-- > 0; ) + if(!IsLogicalValue(tree.GetParam(a))) + return false; + return true; + } + case cIf: + case cAbsIf: + { + return IsLogicalValue(tree.GetParam(1)) + && IsLogicalValue(tree.GetParam(2)); + } + default: + break; + } + return false; // Not a logical value. + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template range<type> CalculateResultBoundaries(const CodeTree<type> &); \ + template bool IsLogicalValue(const CodeTree<type> &); \ + template TriTruthValue GetIntegerInfo(const CodeTree<type> &); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/rangeestimation.hh b/fpoptimizer/rangeestimation.hh new file mode 100644 index 0000000..fda5162 --- /dev/null +++ b/fpoptimizer/rangeestimation.hh @@ -0,0 +1,53 @@ +#ifndef FPOptimizer_RangeEstimationHH +#define FPOptimizer_RangeEstimationHH + +#include "codetree.hh" +#include "valuerange.hh" + +namespace FPoptimizer_CodeTree +{ + enum TriTruthValue { IsAlways, IsNever, Unknown }; + + /* This function calculates the minimum and maximum values + * of the tree's result. If an estimate cannot be made, + * -inf..+inf is assumed (min.known=max.known=false). + */ + template<typename Value_t> + range<Value_t> CalculateResultBoundaries(const CodeTree<Value_t>& tree); + + template<typename Value_t> + bool IsLogicalValue(const CodeTree<Value_t>& tree); + + template<typename Value_t> + TriTruthValue GetIntegerInfo(const CodeTree<Value_t>& tree); + + template<typename Value_t> + inline TriTruthValue GetEvennessInfo(const CodeTree<Value_t>& tree) + { + if(!tree.IsImmed()) return Unknown; + const Value_t& value = tree.GetImmed(); + if(FUNCTIONPARSERTYPES::isEvenInteger(value)) return IsAlways; + if(FUNCTIONPARSERTYPES::isOddInteger(value)) return IsNever; + return Unknown; + } + + template<typename Value_t> + inline TriTruthValue GetPositivityInfo(const CodeTree<Value_t>& tree) + { + range<Value_t> p = CalculateResultBoundaries(tree); + if(p.min.known && p.min.val >= Value_t()) return IsAlways; + if(p.max.known && p.max.val < Value_t()) return IsNever; + return Unknown; + } + + template<typename Value_t> + inline TriTruthValue GetLogicalValue(const CodeTree<Value_t>& tree, bool abs) + { + range<Value_t> p = CalculateResultBoundaries(tree); + if(IsLogicalTrueValue(p, abs)) return IsAlways; + if(IsLogicalFalseValue(p, abs)) return IsNever; + return Unknown; + } +} + +#endif diff --git a/fpoptimizer/readbytecode.cc b/fpoptimizer/readbytecode.cc new file mode 100644 index 0000000..1b79c1a --- /dev/null +++ b/fpoptimizer/readbytecode.cc @@ -0,0 +1,767 @@ +#include <cmath> +#include <cassert> + +#include "codetree.hh" +#include "optimize.hh" +#include "opcodename.hh" +#include "grammar.hh" +#include "extrasrc/fptypes.hh" + +#include "consts.hh" +#include "fparser.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +using namespace FUNCTIONPARSERTYPES; +//using namespace FPoptimizer_Grammar; + +namespace +{ + using namespace FPoptimizer_CodeTree; + + #define FactorStack std::vector /* typedef*/ + + const struct PowiMuliType + { + unsigned opcode_square; + unsigned opcode_cumulate; + unsigned opcode_invert; + unsigned opcode_half; + unsigned opcode_invhalf; + } iseq_powi = {cSqr,cMul,cInv,cSqrt,cRSqrt}, + iseq_muli = {~unsigned(0), cAdd,cNeg, ~unsigned(0),~unsigned(0) }; + + template<typename Value_t> + Value_t ParsePowiMuli( + const PowiMuliType& opcodes, + const std::vector<unsigned>& ByteCode, size_t& IP, + size_t limit, + size_t factor_stack_base, + FactorStack<Value_t>& stack) + { + Value_t result(1); + while(IP < limit) + { + if(ByteCode[IP] == opcodes.opcode_square) + { + if(!isInteger(result)) break; + result *= 2; + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_invert) + { + result = -result; + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_half) + { + if(result > Value_t(0) && isEvenInteger(result)) + break; + result *= Value_t(0.5); + ++IP; + continue; + } + if(ByteCode[IP] == opcodes.opcode_invhalf) + { + if(result > Value_t(0) && isEvenInteger(result)) + break; + result *= Value_t(-0.5); + ++IP; + continue; + } + + size_t dup_fetch_pos = IP; + Value_t lhs(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); + if(IP >= limit || ByteCode[IP] != opcodes.opcode_cumulate) + { + // It wasn't a powi-dup after all + IP = dup_fetch_pos; + break; + } + ++IP; // skip opcode_cumulate + stack.pop_back(); + result += lhs*subexponent; + continue; + } + break; + } + return result; + } + + template<typename Value_t> + Value_t ParsePowiSequence + (const std::vector<unsigned>& ByteCode, size_t& IP, + size_t limit, size_t factor_stack_base) + { + FactorStack<Value_t> stack; + stack.push_back( Value_t(1) ); + return ParsePowiMuli(iseq_powi, ByteCode, IP, limit, factor_stack_base, stack); + } + + template<typename Value_t> + Value_t ParseMuliSequence + (const std::vector<unsigned>& ByteCode, size_t& IP, + size_t limit, size_t factor_stack_base) + { + FactorStack<Value_t> stack; + stack.push_back( Value_t(1) ); + return ParsePowiMuli(iseq_muli, ByteCode, IP, limit, factor_stack_base, stack); + } + + template<typename Value_t> + class CodeTreeParserData + { + public: + explicit CodeTreeParserData(bool k_powi) + : stack(), clones(), keep_powi(k_powi) { } + + void Eat(size_t nparams, OPCODE opcode) + { + CodeTree<Value_t> newnode; + newnode.SetOpcode(opcode); + + std::vector<CodeTree<Value_t> > params = Pop(nparams); + newnode.SetParamsMove(params); + + if(!keep_powi) + switch(opcode) + { + // asinh: log(x + sqrt(x*x + 1)) + //cAsinh [x] -> cLog (cAdd x (cPow (cAdd (cPow x 2) 1) 0.5)) + // Note: ^ Replacement function refers to x twice + + // acosh: log(x + sqrt(x*x - 1)) + //cAcosh [x] -> cLog (cAdd x (cPow (cAdd (cPow x 2) -1) 0.5)) + + // atanh: log( (1+x) / (1-x)) / 2 + //cAtanh [x] -> cMul (cLog (cMul (cAdd 1 x) (cPow (cAdd 1 (cMul -1 x)) -1))) 0.5 + + // asin: atan2(x, sqrt(1-x*x)) + //cAsin[x] -> cAtan2 [x (cPow [(cAdd 1 (cMul (cPow [x 2] -1)) 0.5])] + + // acos: atan2(sqrt(1-x*x), x) + //cAcos[x] -> cAtan2 [(cPow [(cAdd 1 (cMul (cPow [x 2] -1)) 0.5]) x] + + // The hyperbolic functions themselves are: + // sinh: (exp(x)-exp(-x)) / 2 = exp(-x) * (exp(2*x)-1) / 2 + //cSinh [x] -> cMul 0.5 (cPow [CONSTANT_EI x]) (cAdd [-1 (cPow [CONSTANT_2E x])]) + + // cosh: (exp(x)+exp(-x)) / 2 = exp(-x) * (exp(2*x)+1) / 2 + // cosh(-x) = cosh(x) + //cCosh [x] -> cMul 0.5 (cPow [CONSTANT_EI x]) (cAdd [ 1 (cPow [CONSTANT_2E x])]) + + // tanh: sinh/cosh = (exp(2*x)-1) / (exp(2*x)+1) + //cTanh [x] -> (cMul (cAdd {(cPow [CONSTANT_2E x]) -1}) (cPow [(cAdd {(cPow [CONSTANT_2E x]) 1}) -1])) + case cTanh: + { + CodeTree<Value_t> sinh, cosh; + sinh.SetOpcode(cSinh); sinh.AddParam(newnode.GetParam(0)); sinh.Rehash(); + cosh.SetOpcode(cCosh); cosh.AddParamMove(newnode.GetParam(0)); cosh.Rehash(); + CodeTree<Value_t> pow; + pow.SetOpcode(cPow); + pow.AddParamMove(cosh); + pow.AddParam(CodeTreeImmed(Value_t(-1))); + pow.Rehash(); + newnode.SetOpcode(cMul); + newnode.SetParamMove(0, sinh); + newnode.AddParamMove(pow); + break; + } + + // tan: sin/cos + //cTan [x] -> (cMul (cSin [x]) (cPow [(cCos [x]) -1])) + case cTan: + { + CodeTree<Value_t> sin, cos; + sin.SetOpcode(cSin); sin.AddParam(newnode.GetParam(0)); sin.Rehash(); + cos.SetOpcode(cCos); cos.AddParamMove(newnode.GetParam(0)); cos.Rehash(); + CodeTree<Value_t> pow; + pow.SetOpcode(cPow); + pow.AddParamMove(cos); + pow.AddParam(CodeTreeImmed(Value_t(-1))); + pow.Rehash(); + newnode.SetOpcode(cMul); + newnode.SetParamMove(0, sin); + newnode.AddParamMove(pow); + break; + } + + case cPow: + { + const CodeTree<Value_t>& p0 = newnode.GetParam(0); + const CodeTree<Value_t>& p1 = newnode.GetParam(1); + if(p1.GetOpcode() == cAdd) + { + // convert x^(a + b) into x^a * x^b just so that + // some optimizations can be run on it. + // For instance, exp(log(x)*-61.1 + log(z)*-59.1) + // won't be changed into exp(log(x*z)*-61.1)*z^2 + // unless we do this. + std::vector<CodeTree<Value_t> > mulgroup(p1.GetParamCount()); + for(size_t a=0; a<p1.GetParamCount(); ++a) + { + CodeTree<Value_t> pow; + pow.SetOpcode(cPow); + pow.AddParam(p0); + pow.AddParam(p1.GetParam(a)); + pow.Rehash(); + mulgroup[a].swap(pow); + } + newnode.SetOpcode(cMul); + newnode.SetParamsMove(mulgroup); + } + break; + } + + // Should we change sin(x) into cos(pi/2-x) + // or cos(x) into sin(pi/2-x)? + // note: cos(x-pi/2) = cos(pi/2-x) = sin(x) + // note: sin(x-pi/2) = -sin(pi/2-x) = -cos(x) + default: break; + } + + newnode.Rehash(!keep_powi); + /* + using namespace FPoptimizer_Grammar; + bool recurse = false; + while(ApplyGrammar(pack.glist[0], newnode, recurse)) // intermediate + { //std::cout << "Rerunning 1\n"; + newnode.FixIncompleteHashes(); + recurse = true; + } + */ + FindClone(newnode, false); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "POP " << nparams << ", " << FP_GetOpcodeName(opcode) + << "->" << FP_GetOpcodeName(newnode.GetOpcode()) + << ": PUSH "; + DumpTree(newnode); + std::cout <<std::endl; + DumpHashes(newnode); + #endif + stack.push_back(newnode); + } + + void EatFunc(size_t nparams, OPCODE opcode, unsigned funcno) + { + CodeTree<Value_t> newnode = CodeTreeFuncOp<Value_t> (opcode, funcno); + std::vector<CodeTree<Value_t> > params = Pop(nparams); + newnode.SetParamsMove(params); + newnode.Rehash(false); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "POP " << nparams << ", PUSH "; + DumpTree(newnode); + std::cout << std::endl; + DumpHashes(newnode); + #endif + FindClone(newnode); + stack.push_back(newnode); + } + + void AddConst(const Value_t& value) + { + CodeTree<Value_t> newnode = CodeTreeImmed(value); + FindClone(newnode); + Push(newnode); + } + + void AddVar(unsigned varno) + { + CodeTree<Value_t> newnode = CodeTreeVar<Value_t>(varno); + FindClone(newnode); + Push(newnode); + } + + void SwapLastTwoInStack() + { + stack[stack.size()-1].swap( stack[stack.size()-2] ); + } + + void Dup() + { + Fetch(stack.size()-1); + } + + void Fetch(size_t which) + { + Push(stack[which]); + } + + template<typename T> + void Push(T tree) + { + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "PUSH "; + DumpTree(tree); + std::cout << std::endl; + DumpHashes(tree); + #endif + stack.push_back(tree); + } + + void PopNMov(size_t target, size_t source) + { + stack[target] = stack[source]; + stack.resize(target+1); + } + + CodeTree<Value_t> PullResult() + { + clones.clear(); + CodeTree<Value_t> result(stack.back()); + stack.resize(stack.size()-1); + return result; + } + std::vector<CodeTree<Value_t> > Pop(size_t n_pop) + { + std::vector<CodeTree<Value_t> > result(n_pop); + for(unsigned n=0; n<n_pop; ++n) + result[n].swap(stack[stack.size()-n_pop+n]); + #ifdef DEBUG_SUBSTITUTIONS + for(size_t n=n_pop; n-- > 0; ) + { + std::cout << "POP "; + DumpTree(result[n]); + std::cout << std::endl; + DumpHashes(result[n]); + } + #endif + stack.resize(stack.size()-n_pop); + return result; + } + + size_t GetStackTop() const { return stack.size(); } + private: + void FindClone(CodeTree<Value_t> & /*tree*/, bool /*recurse*/ = true) + { + // Disabled: Causes problems in optimization when + // the same subtree is included in logical and non-logical + // contexts: optimizations applied to the logical one will + // mess up the non-logical one. + return; + /* + std::multimap<fphash_t, CodeTree>::const_iterator + i = clones.lower_bound(tree.GetHash()); + for(; i != clones.end() && i->first == tree.GetHash(); ++i) + { + if(i->second.IsIdenticalTo(tree)) + tree.Become(i->second); + } + if(recurse) + for(size_t a=0; a<tree.GetParamCount(); ++a) + FindClone(tree.GetParam(a)); + clones.insert(std::make_pair(tree.GetHash(), tree)); + */ + } + private: + std::vector<CodeTree<Value_t> > stack; + std::multimap<fphash_t, CodeTree<Value_t> > clones; + + bool keep_powi; + + private: + CodeTreeParserData(const CodeTreeParserData&); + CodeTreeParserData& operator=(const CodeTreeParserData&); + }; + + template<typename Value_t> + struct IfInfo + { + CodeTree<Value_t> condition; + CodeTree<Value_t> thenbranch; + size_t endif_location; + + IfInfo(): condition(), thenbranch(), endif_location() { } + }; +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + void CodeTree<Value_t>::GenerateFrom( + const typename FunctionParserBase<Value_t>::Data& fpdata, + bool keep_powi) + { + std::vector<CodeTree<Value_t> > var_trees; + var_trees.reserve(fpdata.mVariablesAmount); + for(unsigned n=0; n<fpdata.mVariablesAmount; ++n) + { + var_trees.push_back( CodeTreeVar<Value_t> (n+VarBegin) ); + } + GenerateFrom(fpdata,var_trees,keep_powi); + } + + template<typename Value_t> + void CodeTree<Value_t>::GenerateFrom( + const typename FunctionParserBase<Value_t>::Data& fpdata, + const std::vector<CodeTree>& var_trees, + bool keep_powi) + { + const std::vector<unsigned>& ByteCode = fpdata.mByteCode; + const std::vector<Value_t>& Immed = fpdata.mImmed; + + /*for(unsigned i=0; i<ByteCode.size(); ++i) + fprintf(stderr, "by[%u/%u]=%u\n", i, (unsigned)ByteCode.size(), (unsigned) ByteCode[i]);*/ + + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "ENTERS GenerateFrom()\n"; + #endif + CodeTreeParserData<Value_t> sim(keep_powi); + std::vector<IfInfo<Value_t> > if_stack; + + for(size_t IP=0, DP=0; ; ++IP) + { + after_powi: + while(!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.IsDefined()) + )) + { + // The "else" of an "if" ends here + CodeTree elsebranch = sim.PullResult(); + sim.Push(if_stack.back().condition); + sim.Push(if_stack.back().thenbranch); + sim.Push(elsebranch); + sim.Eat(3, cIf); + if_stack.pop_back(); + } + if(IP >= ByteCode.size()) break; + + unsigned opcode = ByteCode[IP]; + if((opcode == cSqr || opcode == cDup + || (opcode == cInv && !IsIntType<Value_t>::result) + || opcode == cNeg + || opcode == cSqrt || opcode == cRSqrt + || opcode == cFetch)) + { + // Parse a powi sequence + size_t was_ip = IP; + Value_t exponent = ParsePowiSequence<Value_t>( + ByteCode, IP, if_stack.empty() ? ByteCode.size() : if_stack.back().endif_location, + sim.GetStackTop()-1); + if(exponent != Value_t(1.0)) + { + //std::cout << "Found exponent at " << was_ip << ": " << exponent << "\n"; + sim.AddConst(exponent); + sim.Eat(2, cPow); + goto after_powi; + } + if(opcode == cDup + || opcode == cFetch + || opcode == cNeg) + { + Value_t factor = ParseMuliSequence<Value_t>( + ByteCode, IP, if_stack.empty() ? ByteCode.size() : if_stack.back().endif_location, + sim.GetStackTop()-1); + if(factor != Value_t(1.0)) + { + //std::cout << "Found factor at " << was_ip << ": " << factor << "\n"; + sim.AddConst(factor); + sim.Eat(2, cMul); + goto after_powi; + } + } + IP = was_ip; + } + if(OPCODE(opcode) >= VarBegin) + { + unsigned index = opcode-VarBegin; + /*std::fprintf(stderr, "IP=%u, opcode=%u, VarBegin=%u, ind=%u\n", + (unsigned)IP,(unsigned)opcode,(unsigned)VarBegin, (unsigned)index);*/ + sim.Push(var_trees[index]); + } + else + { + switch( OPCODE(opcode) ) + { + // Specials + case cIf: + case cAbsIf: + { + if_stack.resize(if_stack.size() + 1); + CodeTree res( sim.PullResult() ); + if_stack.back().condition.swap( res ); + if_stack.back().endif_location = ByteCode.size(); + IP += 2; // dp,sp for elsebranch are irrelevant. + continue; + } + case cJump: + { + CodeTree res( sim.PullResult() ); + if_stack.back().thenbranch.swap( res ); + if_stack.back().endif_location = ByteCode[IP+1]+1; + IP += 2; + continue; + } + case cImmed: + sim.AddConst(Immed[DP++]); + break; + case cDup: + sim.Dup(); + break; + case cNop: + break; + case cFCall: + { + unsigned funcno = ByteCode[++IP]; + assert(funcno < fpdata.mFuncPtrs.size()); + unsigned params = fpdata.mFuncPtrs[funcno].mParams; + sim.EatFunc(params, OPCODE(opcode), funcno); + break; + } + case cPCall: + { + unsigned funcno = ByteCode[++IP]; + assert(funcno < fpdata.mFuncParsers.size()); + const FunctionParserBase<Value_t>& p = + *fpdata.mFuncParsers[funcno].mParserPtr; + unsigned params = fpdata.mFuncParsers[funcno].mParams; + + /* Inline the procedure call */ + /* Works because cPCalls can never recurse */ + std::vector<CodeTree> paramlist = sim.Pop(params); + CodeTree pcall_tree; + pcall_tree.GenerateFrom(*p.mData, paramlist); + sim.Push(pcall_tree); + break; + } + // Unary operators requiring special attention + case cInv: // already handled by powi_opt + //sim.Eat(1, cInv); + //break; + sim.AddConst(1); + sim.SwapLastTwoInStack(); + sim.Eat(2, cDiv); + break; + case cNeg: // already handled by powi_opt + sim.Eat(1, cNeg); + break; + sim.AddConst(0); + sim.SwapLastTwoInStack(); + sim.Eat(2, cSub); + break; + case cSqr: // already handled by powi_opt + //sim.Eat(1, cSqr); + //break; + sim.AddConst(2); + sim.Eat(2, cPow); + break; + // Unary functions requiring special attention + case cSqrt: // already handled by powi_opt + sim.AddConst( Value_t(0.5) ); + sim.Eat(2, cPow); + break; + case cRSqrt: // already handled by powi_opt + sim.AddConst( Value_t(-0.5) ); + sim.Eat(2, cPow); + break; + case cCbrt: + sim.AddConst(Value_t(1) / Value_t(3)); + sim.Eat(2, cPow); + break; + case cDeg: + sim.AddConst(fp_const_rad_to_deg<Value_t>()); + sim.Eat(2, cMul); + break; + case cRad: + sim.AddConst(fp_const_deg_to_rad<Value_t>()); + sim.Eat(2, cMul); + break; + case cExp: + if(keep_powi) goto default_function_handling; + sim.AddConst(fp_const_e<Value_t>()); + sim.SwapLastTwoInStack(); + sim.Eat(2, cPow); + break; + case cExp2: // from fpoptimizer + if(keep_powi) goto default_function_handling; + sim.AddConst(2.0); + sim.SwapLastTwoInStack(); + sim.Eat(2, cPow); + break; + case cCot: + sim.Eat(1, cTan); + if(keep_powi) { sim.Eat(1, cInv); break; } + sim.AddConst(-1); + sim.Eat(2, cPow); + break; + case cCsc: + sim.Eat(1, cSin); + if(keep_powi) { sim.Eat(1, cInv); break; } + sim.AddConst(-1); + sim.Eat(2, cPow); + break; + case cSec: + sim.Eat(1, cCos); + if(keep_powi) { sim.Eat(1, cInv); break; } + sim.AddConst(-1); + sim.Eat(2, cPow); + break; + case cInt: // int(x) = floor(x + 0.5) + #ifndef __x86_64 + if(keep_powi) { sim.Eat(1, cInt); break; } + #endif + sim.AddConst( Value_t(0.5) ); + sim.Eat(2, cAdd); + sim.Eat(1, cFloor); + break; + case cLog10: + sim.Eat(1, cLog); + sim.AddConst(fp_const_log10inv<Value_t>()); + sim.Eat(2, cMul); + break; + case cLog2: + sim.Eat(1, cLog); + sim.AddConst(fp_const_log2inv<Value_t>()); + sim.Eat(2, cMul); + break; + case cLog2by: // x y -> log(x)*CONSTANT_L2I*y + sim.SwapLastTwoInStack(); // y x + sim.Eat(1, cLog); // y log(x) + sim.AddConst(fp_const_log2inv<Value_t>()); // y log(x) CONSTANT_L2I + sim.Eat(3, cMul); // y*log(x)*CONSTANT_L2I + break; + case cHypot: // x y -> sqrt(x*x + y*y) + sim.AddConst(2); + sim.Eat(2, cPow); // x y^2 + sim.SwapLastTwoInStack(); + sim.AddConst(2); + sim.Eat(2, cPow); // y^2 x^2 + sim.Eat(2, cAdd); // y^2 + x^2 + sim.AddConst( Value_t(0.5) ); + sim.Eat(2, cPow); // (y^2 + x^2)^0.5 + break; + case cSinCos: + sim.Dup(); + sim.Eat(1, cSin); + sim.SwapLastTwoInStack(); + sim.Eat(1, cCos); + break; + case cSinhCosh: + sim.Dup(); + sim.Eat(1, cSinh); + sim.SwapLastTwoInStack(); + sim.Eat(1, cCosh); + break; + //case cLog: + // sim.Eat(1, cLog2); + // sim.AddConst(fp_const_log2<Value_t>()); + // sim.Eat(2, cMul); + // break; + // Binary operators requiring special attention + case cRSub: // from fpoptimizer + sim.SwapLastTwoInStack(); + // Passthru to cSub + case cSub: + if(keep_powi) { sim.Eat(2, cSub); break; } + sim.AddConst(-1); + sim.Eat(2, cMul); // -x is x*-1 + sim.Eat(2, cAdd); // Minus is negative adding + break; + case cRDiv: // from fpoptimizer + sim.SwapLastTwoInStack(); + // Passthru to cDiv + case cDiv: + if(keep_powi || IsIntType<Value_t>::result) + { + sim.Eat(2, cDiv); + break; + } + sim.AddConst(-1); + sim.Eat(2, cPow); // 1/x is x^-1 + sim.Eat(2, cMul); // Divide is inverse multiply + break; + // Binary operators not requiring special attention + case cAdd: case cMul: + case cMod: case cPow: + case cEqual: case cLess: case cGreater: + case cNEqual: case cLessOrEq: case cGreaterOrEq: + case cAnd: case cOr: + case cAbsAnd: case cAbsOr: + sim.Eat(2, OPCODE(opcode)); + break; + // Unary operators not requiring special attention + case cNot: + case cNotNot: // from fpoptimizer + case cAbsNot: + case cAbsNotNot: + sim.Eat(1, OPCODE(opcode)); + break; + // Special opcodes generated by fpoptimizer itself + case cFetch: + sim.Fetch(ByteCode[++IP]); + break; + case cPopNMov: + { + unsigned stackOffs_target = ByteCode[++IP]; + unsigned stackOffs_source = ByteCode[++IP]; + sim.PopNMov(stackOffs_target, stackOffs_source); + break; + } + + default: + default_function_handling:; + unsigned funcno = opcode-cAbs; + assert(funcno < FUNC_AMOUNT); + const FuncDefinition& func = Functions[funcno]; + sim.Eat(func.params, OPCODE(opcode)); + break; + } + } + } + Become(sim.PullResult()); + #ifdef DEBUG_SUBSTITUTIONS + std::cout << "Produced tree:\n"; + DumpTreeWithIndent(*this); + #endif + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template \ + void CodeTree<type>::GenerateFrom( \ + const FunctionParserBase<type>::Data& fpdata, \ + bool keep_powi); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/transformations.cc b/fpoptimizer/transformations.cc new file mode 100644 index 0000000..a0340f1 --- /dev/null +++ b/fpoptimizer/transformations.cc @@ -0,0 +1,970 @@ +#include "codetree.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +#include "bytecodesynth.hh" +#include "rangeestimation.hh" +#include "optimize.hh" // For DEBUG_SUBSTITUTIONS + +using namespace FUNCTIONPARSERTYPES; +//using namespace FPoptimizer_Grammar; + +//#define DEBUG_POWI + +#if defined(__x86_64) || !defined(FP_SUPPORT_CPLUSPLUS11_MATH_FUNCS) +# define CBRT_IS_SLOW +#endif + +#if defined(DEBUG_POWI) || defined(DEBUG_SUBSTITUTIONS) +#include <cstdio> +#endif + +namespace FPoptimizer_ByteCode +{ + extern const unsigned char powi_table[256]; +} +namespace +{ + using namespace FPoptimizer_CodeTree; + + template<typename Value_t> + bool IsOptimizableUsingPowi(long immed, long penalty = 0) + { + FPoptimizer_ByteCode::ByteCodeSynth<Value_t> synth; + synth.PushVar(VarBegin); + // Ignore the size generated by subtree + size_t bytecodesize_backup = synth.GetByteCodeSize(); + FPoptimizer_ByteCode::AssembleSequence(immed, + FPoptimizer_ByteCode::SequenceOpcodes<Value_t>::MulSequence, synth); + + size_t bytecode_grow_amount = synth.GetByteCodeSize() - bytecodesize_backup; + + return bytecode_grow_amount < size_t(MAX_POWI_BYTECODE_LENGTH - penalty); + } + + template<typename Value_t> + void ChangeIntoRootChain( + CodeTree<Value_t>& tree, + bool inverted, + long sqrt_count, + long cbrt_count) + { + while(cbrt_count > 0) + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cCbrt); + tmp.AddParamMove(tree); + tmp.Rehash(); + tree.swap(tmp); + --cbrt_count; + } + while(sqrt_count > 0) + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cSqrt); + if(inverted) + { + tmp.SetOpcode(cRSqrt); + inverted = false; + } + tmp.AddParamMove(tree); + tmp.Rehash(); + tree.swap(tmp); + --sqrt_count; + } + if(inverted) + { + CodeTree<Value_t> tmp; + tmp.SetOpcode(cInv); + tmp.AddParamMove(tree); + tree.swap(tmp); + } + } + + template<typename Value_t> + struct RootPowerTable + { + static const Value_t RootPowers[(1+4)*(1+3)]; + }; + template<typename Value_t> + const Value_t RootPowerTable<Value_t>::RootPowers[(1+4)*(1+3)] = + { + // (sqrt^n(x)) + Value_t(1), + Value_t(1) / Value_t(2), + Value_t(1) / Value_t(2*2), + Value_t(1) / Value_t(2*2*2), + Value_t(1) / Value_t(2*2*2*2), + // cbrt^1(sqrt^n(x)) + Value_t(1) / Value_t(3), + Value_t(1) / Value_t(3*2), + Value_t(1) / Value_t(3*2*2), + Value_t(1) / Value_t(3*2*2*2), + Value_t(1) / Value_t(3*2*2*2*2), + // cbrt^2(sqrt^n(x)) + Value_t(1) / Value_t(3*3), + Value_t(1) / Value_t(3*3*2), + Value_t(1) / Value_t(3*3*2*2), + Value_t(1) / Value_t(3*3*2*2*2), + Value_t(1) / Value_t(3*3*2*2*2*2), + // cbrt^3(sqrt^n(x)) + Value_t(1) / Value_t(3*3*3), + Value_t(1) / Value_t(3*3*3*2), + Value_t(1) / Value_t(3*3*3*2*2), + Value_t(1) / Value_t(3*3*3*2*2*2), + Value_t(1) / Value_t(3*3*3*2*2*2*2) + }; + + struct PowiResolver + { + /* Any exponentiation can be turned into one of these: + * + * x^y -> sqrt(x)^(y*2) = x Sqrt y*2 Pow + * x^y -> cbrt(x)^(y*3) = x Cbrt y*3 Pow + * x^y -> rsqrt(x)^(y*-2) = x RSqrt y*-2 Pow + * x^y -> x^(y-1/2) * sqrt(x) = x Sqrt x y-0.5 Pow Mul + * x^y -> x^(y-1/3) * cbrt(x) = x Cbrt x y-0.33 Pow Mul + * x^y -> x^(y+1/2) * rsqrt(x) = x Sqrt x y+0.5 Pow Mul + * x^y -> inv(x)^(-y) = x Inv -y Pow + * + * These rules can be applied recursively. + * The goal is to find the optimal chain of operations + * that results in the least number of sqrt,cbrt operations; + * an integer value of y, and that the integer is as close + * to zero as possible. + */ + static const unsigned MaxSep = 4; + static const int MaxOp = 5; + + typedef int factor_t; + typedef long cost_t; + typedef long int_exponent_t; + + struct PowiResult + { + PowiResult() : + n_int_sqrt(0), + n_int_cbrt(0), + sep_list(), + resulting_exponent(0) { } + + int n_int_sqrt; // totals + int n_int_cbrt; // totals + int sep_list[MaxSep]; // action list. Each element is (n_sqrt + MaxOp * n_cbrt). + int_exponent_t resulting_exponent; + }; + + template<typename Value_t> + static PowiResult CreatePowiResult(Value_t exponent) + { + PowiResult result; + + factor_t best_factor = FindIntegerFactor(exponent); + if(best_factor == 0) + { + #ifdef DEBUG_POWI + printf("no factor found for %Lg\n", (long double)exponent); + #endif + return result; // Unoptimizable + } + + result.resulting_exponent = MultiplyAndMakeLong(exponent, best_factor); + cost_t best_cost = + EvaluateFactorCost(best_factor, 0, 0, 0) + + CalculatePowiFactorCost( result.resulting_exponent ); + int s_count = 0; + int c_count = 0; + int mul_count = 0; + + #ifdef DEBUG_POWI + printf("orig = %Lg\n", (long double) exponent); + printf("plain factor = %d, cost %ld\n", (int) best_factor, (long) best_cost); + #endif + + for(unsigned n_s=0; n_s<MaxSep; ++n_s) + { + int best_selected_sep = 0; + cost_t best_sep_cost = best_cost; + factor_t best_sep_factor = best_factor; + for(int s=1; s<MaxOp*4; ++s) + { +#ifdef CBRT_IS_SLOW + if(s >= MaxOp) break; + // When cbrt is implemented through exp and log, + // there is no advantage over exp(log()), so don't support it. +#endif + int n_sqrt = s%MaxOp; + int n_cbrt = s/MaxOp; + if(n_sqrt + n_cbrt > 4) continue; + + Value_t changed_exponent = exponent; + changed_exponent -= RootPowerTable<Value_t>::RootPowers[s]; + + factor_t factor = FindIntegerFactor(changed_exponent); + if(factor != 0) + { + int_exponent_t int_exponent = MultiplyAndMakeLong(changed_exponent, factor); + cost_t cost = + EvaluateFactorCost(factor, s_count + n_sqrt, c_count + n_cbrt, mul_count + 1) + + CalculatePowiFactorCost(int_exponent); + + #ifdef DEBUG_POWI + printf("Candidate sep %u (%d*sqrt %d*cbrt)factor = %d, cost %ld (for %Lg to %ld)\n", + s, n_sqrt, n_cbrt, factor, + (long) cost, + (long double) changed_exponent, + (long) int_exponent); + #endif + if(cost < best_sep_cost) + { + best_selected_sep = s; + best_sep_factor = factor; + best_sep_cost = cost; + } + } + } + if(!best_selected_sep) break; + + #ifdef DEBUG_POWI + printf("CHOSEN sep %u (%d*sqrt %d*cbrt)factor = %d, cost %ld, exponent %Lg->%Lg\n", + best_selected_sep, + best_selected_sep % MaxOp, + best_selected_sep / MaxOp, + best_sep_factor, best_sep_cost, + (long double)(exponent), + (long double)(exponent-RootPowerTable<Value_t>::RootPowers[best_selected_sep])); + #endif + result.sep_list[n_s] = best_selected_sep; + exponent -= RootPowerTable<Value_t>::RootPowers[best_selected_sep]; + s_count += best_selected_sep % MaxOp; + c_count += best_selected_sep / MaxOp; + best_cost = best_sep_cost; + best_factor = best_sep_factor; + mul_count += 1; + } + + result.resulting_exponent = MultiplyAndMakeLong(exponent, best_factor); + #ifdef DEBUG_POWI + printf("resulting exponent is %ld (from exponent=%Lg, best_factor=%Lg)\n", + result.resulting_exponent, + (long double) exponent, + (long double) best_factor); + #endif + while(best_factor % 2 == 0) + { + ++result.n_int_sqrt; + best_factor /= 2; + } + while(best_factor % 3 == 0) + { + ++result.n_int_cbrt; + best_factor /= 3; + } + return result; + } + + private: + static cost_t CalculatePowiFactorCost(int_exponent_t int_exponent) + { + static std::map<int_exponent_t, cost_t> cache; + if(int_exponent < 0) + { + cost_t cost = 22; // division cost + return cost + CalculatePowiFactorCost(-int_exponent); + } + std::map<int_exponent_t,cost_t>::iterator i = cache.lower_bound(int_exponent); + if(i != cache.end() && i->first == int_exponent) + return i->second; + std::pair<int_exponent_t, cost_t> result(int_exponent, 0.0); + cost_t& cost = result.second; + + while(int_exponent > 1) + { + int factor = 0; + if(int_exponent < 256) + { + factor = FPoptimizer_ByteCode::powi_table[int_exponent]; + if(factor & 128) factor &= 127; else factor = 0; + if(factor & 64) factor = -(factor&63) - 1; + } + if(factor) + { + cost += CalculatePowiFactorCost(factor); + int_exponent /= factor; + continue; + } + if(!(int_exponent & 1)) + { + int_exponent /= 2; + cost += 6; // sqr + } + else + { + cost += 7; // dup+mul + int_exponent -= 1; + } + } + + cache.insert(i, result); + return cost; + } + + template<typename Value_t> + static int_exponent_t MultiplyAndMakeLong(const Value_t& value, factor_t factor) + { + return makeLongInteger( value * Value_t(factor) ); + } + + // Find the integer that "value" must be multiplied + // with to produce an integer... + // Consisting of factors 2 and 3 only. + template<typename Value_t> + static bool MakesInteger(const Value_t& value, factor_t factor) + { + /* Does value, multiplied by factor, result in an integer? */ + Value_t v = value * Value_t(factor); + return isLongInteger(v); + /* + Value_t diff = fp_abs(v - fp_int(v)); + //printf("factor %d: v=%.20f, diff=%.20f\n", factor,v, diff); + return diff < Value_t(1e-9l); + */ + } + + template<typename Value_t> + static factor_t FindIntegerFactor(const Value_t& value) + { + factor_t factor = (2*2*2*2); +#ifdef CBRT_IS_SLOW + // When cbrt is implemented through exp and log, + // there is no advantage over exp(log()), so don't support it. +#else + factor *= (3*3*3); +#endif + factor_t result = 0; + if(MakesInteger(value, factor)) + { + result = factor; + while((factor % 2) == 0 && MakesInteger(value, factor/2)) + result = factor /= 2; + while((factor % 3) == 0 && MakesInteger(value, factor/3)) + result = factor /= 3; + } +#ifdef CBRT_IS_SLOW + if(result == 0) + { + /* Note: Even if we allow one cbrt, + * cbrt(cbrt(x)) still gets turned into + * exp(log(x)*0.111111) + * which gives an error when x < 0... + * should we use a special system here? + * i.e. exp(log(-5)*y) + * = -exp(log(5)*y) + * except when y is an even integer, + * when = exp(log(5)*y) + * We use a custom fp_pow() function + * in order to handle these situations. + */ + if(MakesInteger(value, 3)) return 3; // single cbrt opcode + } +#endif + return result; + } + + static int EvaluateFactorCost(int factor, int s, int c, int nmuls) + { + const int sqrt_cost = 6; +#ifdef CBRT_IS_SLOW + const int cbrt_cost = 25; +#else + const int cbrt_cost = 8; +#endif + int result = s * sqrt_cost + c * cbrt_cost; + while(factor % 2 == 0) { factor /= 2; result += sqrt_cost; } + while(factor % 3 == 0) { factor /= 3; result += cbrt_cost; } + result += nmuls; + return result; + } + }; +} + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + bool CodeTree<Value_t>::RecreateInversionsAndNegations(bool prefer_base2) + { + bool changed = false; + + for(size_t a=0; a<GetParamCount(); ++a) + if(GetParam(a).RecreateInversionsAndNegations(prefer_base2)) + changed = true; + + if(changed) + { + exit_changed: + Mark_Incompletely_Hashed(); + return true; + } + + switch(GetOpcode()) // Recreate inversions and negations + { + case cMul: + { + std::vector<CodeTree<Value_t> > div_params; + CodeTree<Value_t> found_log2, found_log2by; + + if(true) + { + /* This lengthy bit of code + * changes log2(x)^3 * 5 + * to log2by(x, 5^(1/3)) ^ 3 + * which is better for runtime + * than log2by(x,1)^3 * 5 + */ + bool found_log2_on_exponent = false; + Value_t log2_exponent = 0; + for(size_t a = GetParamCount(); a-- > 0; ) + { + const CodeTree<Value_t>& powgroup = GetParam(a); + if(powgroup.GetOpcode() == cPow + && powgroup.GetParam(0).GetOpcode() == cLog2 + && powgroup.GetParam(1).IsImmed()) + { + // Found log2 on exponent + found_log2_on_exponent = true; + log2_exponent = powgroup.GetParam(1).GetImmed(); + break; + } + } + if(found_log2_on_exponent) + { + Value_t immeds = 1.0; + for(size_t a = GetParamCount(); a-- > 0; ) + { + const CodeTree<Value_t>& powgroup = GetParam(a); + if(powgroup.IsImmed()) + { + immeds *= powgroup.GetImmed(); + DelParam(a); + } + } + for(size_t a = GetParamCount(); a-- > 0; ) + { + CodeTree<Value_t>& powgroup = GetParam(a); + if(powgroup.GetOpcode() == cPow + && powgroup.GetParam(0).GetOpcode() == cLog2 + && powgroup.GetParam(1).IsImmed()) + { + CodeTree<Value_t>& log2 = powgroup.GetParam(0); + log2.CopyOnWrite(); + log2.SetOpcode(cLog2by); + log2.AddParam( CodeTreeImmed( + fp_pow(immeds, Value_t(1) / log2_exponent) ) ); + log2.Rehash(); + break; + } + } + } + } + + for(size_t a = GetParamCount(); a-- > 0; ) + { + const CodeTree<Value_t>& powgroup = GetParam(a); + + if(powgroup.GetOpcode() == cPow + && powgroup.GetParam(1).IsImmed()) + { + const CodeTree<Value_t>& exp_param = powgroup.GetParam(1); + Value_t exponent = exp_param.GetImmed(); + if(fp_equal(exponent, Value_t(-1))) + { + CopyOnWrite(); + div_params.push_back(GetParam(a).GetParam(0)); + DelParam(a); // delete the pow group + } + else if(exponent < Value_t(0) && isInteger(exponent)) + { + CodeTree<Value_t> edited_powgroup; + edited_powgroup.SetOpcode(cPow); + edited_powgroup.AddParam(powgroup.GetParam(0)); + edited_powgroup.AddParam(CodeTreeImmed( -exponent )); + edited_powgroup.Rehash(); + div_params.push_back(edited_powgroup); + CopyOnWrite(); + DelParam(a); // delete the pow group + } + } + else if(powgroup.GetOpcode() == cLog2 && !found_log2.IsDefined()) + { + found_log2 = powgroup.GetParam(0); + CopyOnWrite(); + DelParam(a); + } + else if(powgroup.GetOpcode() == cLog2by && !found_log2by.IsDefined()) + { + found_log2by = powgroup; + CopyOnWrite(); + DelParam(a); + } + } + if(!div_params.empty()) + { + changed = true; + + CodeTree<Value_t> divgroup; + divgroup.SetOpcode(cMul); + divgroup.SetParamsMove(div_params); + divgroup.Rehash(); // will reduce to div_params[0] if only one item + CodeTree<Value_t> mulgroup; + mulgroup.SetOpcode(cMul); + mulgroup.SetParamsMove(GetParams()); + mulgroup.Rehash(); // will reduce to 1.0 if none remained in this cMul + if(mulgroup.IsImmed() && fp_equal(mulgroup.GetImmed(), Value_t(1))) + { + SetOpcode(cInv); + AddParamMove(divgroup); + } + /*else if(mulgroup.IsImmed() && fp_equal(mulgroup.GetImmed(), Value_t(-1))) + { + CodeTree<Value_t> invgroup; + invgroup.SetOpcode(cInv); + invgroup.AddParamMove(divgroup); + invgroup.Rehash(); + SetOpcode(cNeg); + AddParamMove(invgroup); + }*/ + else + { + if(mulgroup.GetDepth() >= divgroup.GetDepth()) + { + SetOpcode(cDiv); + AddParamMove(mulgroup); + AddParamMove(divgroup); + } + else + { + SetOpcode(cRDiv); + AddParamMove(divgroup); + AddParamMove(mulgroup); + } + } + } + if(found_log2.IsDefined()) + { + CodeTree<Value_t> mulgroup; + mulgroup.SetOpcode(GetOpcode()); + mulgroup.SetParamsMove(GetParams()); + mulgroup.Rehash(); + while(mulgroup.RecreateInversionsAndNegations(prefer_base2)) + mulgroup.FixIncompleteHashes(); + SetOpcode(cLog2by); + AddParamMove(found_log2); + AddParamMove(mulgroup); + changed = true; + } + if(found_log2by.IsDefined()) + { + CodeTree<Value_t> mulgroup; + mulgroup.SetOpcode(cMul); + mulgroup.AddParamMove(found_log2by.GetParam(1)); + mulgroup.AddParamsMove(GetParams()); + mulgroup.Rehash(); + while(mulgroup.RecreateInversionsAndNegations(prefer_base2)) + mulgroup.FixIncompleteHashes(); + DelParams(); + SetOpcode(cLog2by); + AddParamMove(found_log2by.GetParam(0)); + AddParamMove(mulgroup); + changed = true; + } + break; + } + case cAdd: + { + std::vector<CodeTree<Value_t> > sub_params; + + for(size_t a = GetParamCount(); a-- > 0; ) + if(GetParam(a).GetOpcode() == cMul) + { + bool is_signed = false; // if the mul group has a -1 constant... + + Recheck_RefCount_Mul:; + CodeTree<Value_t>& mulgroup = GetParam(a); + bool needs_cow = GetRefCount() > 1; + + for(size_t b=mulgroup.GetParamCount(); b-- > 0; ) + { + if(mulgroup.GetParam(b).IsImmed()) + { + Value_t factor = mulgroup.GetParam(b).GetImmed(); + if(fp_equal(factor, Value_t(-1))) + { + if(needs_cow) { CopyOnWrite(); goto Recheck_RefCount_Mul; } + mulgroup.CopyOnWrite(); + mulgroup.DelParam(b); + is_signed = !is_signed; + } + else if(fp_equal(factor, Value_t(-2))) + { + if(needs_cow) { CopyOnWrite(); goto Recheck_RefCount_Mul; } + mulgroup.CopyOnWrite(); + mulgroup.DelParam(b); + mulgroup.AddParam( CodeTreeImmed( Value_t(2) ) ); + is_signed = !is_signed; + } + } + } + if(is_signed) + { + mulgroup.Rehash(); + sub_params.push_back(mulgroup); + DelParam(a); + } + } + else if(GetParam(a).GetOpcode() == cDiv && !IsIntType<Value_t>::result) + { + bool is_signed = false; + + Recheck_RefCount_Div:; + CodeTree<Value_t>& divgroup = GetParam(a); + bool needs_cow = GetRefCount() > 1; + + if(divgroup.GetParam(0).IsImmed()) + { + if(fp_equal(divgroup.GetParam(0).GetImmed(), Value_t(-1))) + { + if(needs_cow) { CopyOnWrite(); goto Recheck_RefCount_Div; } + divgroup.CopyOnWrite(); + divgroup.DelParam(0); + divgroup.SetOpcode(cInv); + is_signed = !is_signed; + } + } + if(is_signed) + { + if(needs_cow) { CopyOnWrite(); goto Recheck_RefCount_Div; } + divgroup.Rehash(); + sub_params.push_back(divgroup); + DelParam(a); + } + } + else if(GetParam(a).GetOpcode() == cRDiv && !IsIntType<Value_t>::result) + { + bool is_signed = false; + + Recheck_RefCount_RDiv:; + CodeTree<Value_t>& divgroup = GetParam(a); + bool needs_cow = GetRefCount() > 1; + + if(divgroup.GetParam(1).IsImmed()) + { + if(fp_equal(divgroup.GetParam(1).GetImmed(), Value_t(-1))) + { + if(needs_cow) { CopyOnWrite(); goto Recheck_RefCount_RDiv; } + divgroup.CopyOnWrite(); + divgroup.DelParam(1); + divgroup.SetOpcode(cInv); + is_signed = !is_signed; + } + } + if(is_signed) + { + if(needs_cow) { CopyOnWrite(); goto Recheck_RefCount_RDiv; } + divgroup.Rehash(); + sub_params.push_back(divgroup); + DelParam(a); + } + } + if(!sub_params.empty()) + { + #ifdef DEBUG_SUBSTITUTIONS + printf("Will make a Sub conversion in:\n"); fflush(stdout); + DumpTreeWithIndent(*this); + #endif + CodeTree<Value_t> subgroup; + subgroup.SetOpcode(cAdd); + subgroup.SetParamsMove(sub_params); + subgroup.Rehash(); // will reduce to sub_params[0] if only one item + CodeTree<Value_t> addgroup; + addgroup.SetOpcode(cAdd); + addgroup.SetParamsMove(GetParams()); + addgroup.Rehash(); // will reduce to 0.0 if none remained in this cAdd + if(addgroup.IsImmed() && fp_equal(addgroup.GetImmed(), Value_t(0))) + { + SetOpcode(cNeg); + AddParamMove(subgroup); + } + else + { + if(addgroup.GetDepth() == 1) + { + /* 5 - (x+y+z) is best expressed as rsub(x+y+z, 5); + * this has lowest stack usage. + * This is identified by addgroup having just one member. + */ + SetOpcode(cRSub); + AddParamMove(subgroup); + AddParamMove(addgroup); + } + else if(subgroup.GetOpcode() == cAdd) + { + /* a+b-(x+y+z) is expressed as a+b-x-y-z. + * Making a long chain of cSubs is okay, because the + * cost of cSub is the same as the cost of cAdd. + * Thus we get the lowest stack usage. + * This approach cannot be used for cDiv. + */ + SetOpcode(cSub); + AddParamMove(addgroup); + AddParamMove(subgroup.GetParam(0)); + for(size_t a=1; a<subgroup.GetParamCount(); ++a) + { + CodeTree<Value_t> innersub; + innersub.SetOpcode(cSub); + innersub.SetParamsMove(GetParams()); + innersub.Rehash(false); + //DelParams(); + AddParamMove(innersub); + AddParamMove(subgroup.GetParam(a)); + } + } + else + { + SetOpcode(cSub); + AddParamMove(addgroup); + AddParamMove(subgroup); + } + } + #ifdef DEBUG_SUBSTITUTIONS + printf("After Sub conversion:\n"); fflush(stdout); + DumpTreeWithIndent(*this); + #endif + } + break; + } + case cPow: + { + const CodeTree<Value_t>& p0 = GetParam(0); + const CodeTree<Value_t>& p1 = GetParam(1); + if(p1.IsImmed()) + { + if(p1.GetImmed() != Value_t(0) + && !isInteger(p1.GetImmed())) + { + PowiResolver::PowiResult + r = PowiResolver::CreatePowiResult(fp_abs(p1.GetImmed())); + + if(r.resulting_exponent != 0) + { + bool signed_chain = false; + + if(p1.GetImmed() < Value_t(0) + && r.sep_list[0] == 0 + && r.n_int_sqrt > 0) + { + // If one of the internal sqrts can be changed into rsqrt + signed_chain = true; + } + + #ifdef DEBUG_POWI + printf("Will resolve powi %Lg as powi(chain(%d,%d),%ld)", + (long double) fp_abs(p1.GetImmed()), + r.n_int_sqrt, + r.n_int_cbrt, + r.resulting_exponent); + for(unsigned n=0; n<PowiResolver::MaxSep; ++n) + { + if(r.sep_list[n] == 0) break; + int n_sqrt = r.sep_list[n] % PowiResolver::MaxOp; + int n_cbrt = r.sep_list[n] / PowiResolver::MaxOp; + printf("*chain(%d,%d)", n_sqrt,n_cbrt); + } + printf("\n"); + #endif + + CodeTree<Value_t> source_tree = GetParam(0); + + CodeTree<Value_t> pow_item = source_tree; + pow_item.CopyOnWrite(); + ChangeIntoRootChain(pow_item, + signed_chain, + r.n_int_sqrt, + r.n_int_cbrt); + pow_item.Rehash(); + + CodeTree<Value_t> pow; + if(r.resulting_exponent != 1) + { + pow.SetOpcode(cPow); + pow.AddParamMove(pow_item); + pow.AddParam(CodeTreeImmed( Value_t(r.resulting_exponent) )); + } + else + pow.swap(pow_item); + + CodeTree<Value_t> mul; + mul.SetOpcode(cMul); + mul.AddParamMove(pow); + + for(unsigned n=0; n<PowiResolver::MaxSep; ++n) + { + if(r.sep_list[n] == 0) break; + int n_sqrt = r.sep_list[n] % PowiResolver::MaxOp; + int n_cbrt = r.sep_list[n] / PowiResolver::MaxOp; + + CodeTree<Value_t> mul_item = source_tree; + mul_item.CopyOnWrite(); + ChangeIntoRootChain(mul_item, false, n_sqrt, n_cbrt); + mul_item.Rehash(); + mul.AddParamMove(mul_item); + } + + if(p1.GetImmed() < Value_t(0) && !signed_chain) + { + mul.Rehash(); + SetOpcode(cInv); + SetParamMove(0, mul); + DelParam(1); + } + else + { + SetOpcode(cMul); + SetParamsMove(mul.GetParams()); + } + #ifdef DEBUG_POWI + DumpTreeWithIndent(*this); + #endif + changed = true; + break; + } + } + } + if(GetOpcode() == cPow + && (!p1.IsImmed() + || !isLongInteger(p1.GetImmed()) + || !IsOptimizableUsingPowi<Value_t>( makeLongInteger(p1.GetImmed()) ))) + { + if(p0.IsImmed() && p0.GetImmed() > Value_t(0.0)) + { + // Convert into cExp or Exp2. + // x^y = exp(log(x) * y) = + // Can only be done when x is positive, though. + if(prefer_base2) + { + Value_t mulvalue = fp_log2( p0.GetImmed() ); + if(fp_equal(mulvalue, Value_t(1))) + { + // exp2(1)^x becomes exp2(x) + DelParam(0); + } + else + { + // exp2(4)^x becomes exp2(4*x) + CodeTree<Value_t> exponent; + exponent.SetOpcode(cMul); + exponent.AddParam( CodeTreeImmed<Value_t>( mulvalue ) ); + exponent.AddParam(p1); + exponent.Rehash(); + SetParamMove(0, exponent); + DelParam(1); + } + SetOpcode(cExp2); + changed = true; + } + else + { + Value_t mulvalue = fp_log( p0.GetImmed() ); + if(fp_equal(mulvalue, Value_t(1))) + { + // exp(1)^x becomes exp(x) + DelParam(0); + } + else + { + // exp(4)^x becomes exp(4*x) + CodeTree<Value_t> exponent; + exponent.SetOpcode(cMul); + exponent.AddParam( CodeTreeImmed<Value_t>( mulvalue ) ); + exponent.AddParam(p1); + exponent.Rehash(); + SetParamMove(0, exponent); + DelParam(1); + } + SetOpcode(cExp); + changed = true; + } + } + else if(GetPositivityInfo(p0) == IsAlways) + { + if(prefer_base2) + { + CodeTree<Value_t> log; + log.SetOpcode(cLog2); + log.AddParam(p0); + log.Rehash(); + CodeTree<Value_t> exponent; + exponent.SetOpcode(cMul); + exponent.AddParam(p1); + exponent.AddParamMove(log); + exponent.Rehash(); + SetOpcode(cExp2); + SetParamMove(0, exponent); + DelParam(1); + changed = true; + } + else + { + CodeTree<Value_t> log; + log.SetOpcode(cLog); + log.AddParam(p0); + log.Rehash(); + CodeTree<Value_t> exponent; + exponent.SetOpcode(cMul); + exponent.AddParam(p1); + exponent.AddParamMove(log); + exponent.Rehash(); + SetOpcode(cExp); + SetParamMove(0, exponent); + DelParam(1); + changed = true; + } + } + } + break; + } + case cDiv: + { + // Change 1/x into inv(x) + // Needed in integer mode, no other code does it. + if(GetParam(0).IsImmed() + && fp_equal(GetParam(0).GetImmed(), Value_t(1))) + { + SetOpcode(cInv); + DelParam(0); + } + break; + } + + default: break; + } + + if(changed) + goto exit_changed; + + return changed; + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template \ + bool CodeTree<type>::RecreateInversionsAndNegations(bool prefer_base2); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/treerules.dat b/fpoptimizer/treerules.dat new file mode 100644 index 0000000..cf4693f --- /dev/null +++ b/fpoptimizer/treerules.dat @@ -0,0 +1,1005 @@ +# This datafile documents all the possible optimizations that the optimizer can/should do. +# It is parsed by the parser described in fpoptimizer_grammar_gen.y, which +# is compiled into C++ code in fpoptimizer_grammar_gen.cc. The parser produces +# a C++ file, fpoptimizer_grammar.cc , which lists the grammar rules in tabular +# format. The grammar rules are utilized by fpoptimizer_optimize.cc , which +# matches the function trees into the rules and performing those replacements +# which can be performed. +# +# Copyright 2010 Joel Yliluoma, written specifically +# for Warp's Function Parser (fparser). +# + +# asinh: log(x + sqrt(x*x + 1)) +# acosh: log(x + sqrt(x*x - 1)) +# atanh: log( (1+x) / (1-x)) / 2 +# asin: atan2(x, sqrt(1-x*x)) Complex: -i*log(i*x + sqrt(1 - x*x)) +# acos: atan2(sqrt(1-x*x), x) Complex: -i*log(x + i*sqrt(1 - x*x)) +# atan: Complex: -0.5i * log( (1+i*x) / (1-i*x) ) +# atan2: atan(y/x) +# = 2*atan(y/(sqrt(x^2+y^2) + x)) +# sin: Complex: (exp(i*x) - exp(-i*x)) / (2i) +# cos: Complex: (exp(i*x) + exp(-i*x)) / (2) +# tan: sin/cos Complex: (i-i*exp(2i*x)) / (exp(2i*x)+1) +# sinh: (exp(x)-exp(-x)) / 2 +# = exp(-x) * (exp(2*x)-1) / 2 +# cosh: (exp(x)+exp(-x)) / 2 +# = exp(-x) * (exp(2*x)+1) / 2 +# tanh: sinh/cosh +# = (exp(2*x)-1) / (exp(2*x)+1) +# log10: log/CONSTANT_L10I +# log2: log/CONSTANT_L2I +# sqrt: pow(x, 0.5) +# exp: pow(CONSTANT_E, x) +# int: floor(x + 0.5) + +# Substitution rule syntax: +# +# %token NUMERIC_CONSTANT # literals such as 0, 1, 1.5 or CONSTANT_DR, CONSTANT_L10I +# %token NAMEDHOLDER_TOKEN # placeholders such as x, y, a, b +# %token RESTHOLDER_TOKEN # placeholders such as <1>, <2>, <7> +# %token IMMEDHOLDER_TOKEN # placeholders % and & +# %token BUILTIN_FUNC_NAME # such as COS, CEIL, POW, +, *, MIN, MAX +# %token OPCODE_TOKEN # opcodes such as cCos, cMul +# %token UNARY_TRANSFORMATION # /, -, ! # inverts/negates/inverts the param +# %token PARAM_CONSTRAINT # parameter constraint specifier: +# @E = Even integer only +# @O = Odd integer only +# @I = Integer only +# @F = (Float) non-integer only +# @L = Logical operation (something that only yields 0 or 1) +# @P = Positive only (also zero) +# @N = Negative only +# @Q = Only those where positive/negative not known +# @1 = value evaluating to +1 or -1 only +# @M = (Multiple) value NOT evaluating to +1 or -1 +# @C = Const (x@C is similar to % and &) +# @V = Explicitly non-const +# %token CONST_CONSTRAINT # constraint applicable to a numeric literal: +# @R = Radians: Constant is tested after normalizing to -pi/2..pi/2 range +# # they can be applied to IMMEDHOLDER_TOKENs and NAMEDHOLDER_TOKENs +# %token RULE_CONSTRAINT @L = Logical context only +# i.e. when the result of the tree will only +# only be evaluated using fabs(value) >= 0.5. +# @I = This rule applies for integer types only +# @F = This rule applies for non-integer types only +# @C = This rule applies to complex types only +# @R = This rule applies to real (non-complex) types only +# %token NEWLINE # newline +# +# %% +# grammar: +# grammar substitution +# | grammar rule_constraints substitution +# | grammar NEWLINE +# | /* empty */ +# ; +# +# substitution: +# function '->' param NEWLINE +# /* Entire function is changed into the particular param */ +# +# | function '->' function NEWLINE +# /* Entire function changes, the param_notinv_list is rewritten */ +# /* NOTE: "p x -> o y" is a shortcut for "p x -> (o y)" */ +# +# | function ':' paramlist NEWLINE +# /* The params provided are replaced with the new param_maybeinv_list */ +# ; +# +# function: +# OPCODE_TOKEN '[' paramlist ']' +# /* Match a function with opcode=opcode, +# * and the exact parameter list as specified +# */ +# OPCODE_TOKEN '{' paramlist '}' +# /* Match a function with opcode=opcode, +# * and the exact parameter list in any order +# */ +# | OPCODE_TOKEN paramlist +# /* Match a function with opcode=opcode and the given way of matching params */ +# /* There may be more parameters, don't care about them */ +# ; +# +# paramlist: /* left-recursive list of 0-n params with no delimiter */ +# | paramlist param /* param */ +# | paramlist RESTHOLDER_TOKEN /* a placeholder for all remaining params */ +# | /* empty */ +# ; +# +# param: +# NUMERIC_CONSTANT const_constraints /* particular immed */ +# | IMMEDHOLDER_TOKEN param_constraints /* a placeholder for some immed */ +# | BUILTIN_FUNC_NAME '(' paramlist ')' /* literal logarithm/sin/etc. of the provided immed-type params -- also sum/product/minimum/maximum */ +# | NAMEDHOLDER_TOKEN param_constraints /* any expression, indicated by "x", "a" etc. */ +# | (' function ')' param_constraints /* a subtree */ +# | UNARY_TRANSFORMATION param /* the negated/inverted literal value of the param */ +# ; +# +# param_constraints: /* List of possible constraints to the given param, eg. odd,int,etc */ +# param_constraints PARAM_CONSTRAINT +# | /* empty */ +# ; +# +# rule_constraints: /* List of possible constraints to the given rule */ +# rule_constraints RULE_CONSTRAINT +# | /* empty */ +# ; +# +# const_constraints: /* List of possible constraints to the given numeric value */ +# const_constraints CONST_CONSTRAINT +# | /* empty */ +# ; + +[LOGICAL] + +# Change cLessOrEq into cLess for less rules to check +# This way, the only comparison opcodes appearing in cIf +# are cEqual,cNEqual,cLess. +# cNEqual could be changed to cEqual, but we see no need. +cIf [(cLessOrEq[x y]) z a] : (cLess[y x]) a z +cIf [(cGreaterOrEq[x y]) z a] : (cGreater[y x]) a z +#cIf [(cNEqual[x y]) z a] : (cEqual[y x]) a z + +cIf [(cLess[x y]) x y] -> cMin x y # TEST 20/cmp*_minmax +cIf [(cLess[x y]) y x] -> cMax x y # TEST 20/cmp*_minmax +#cIf [(cLessOrEq[x y]) x y] -> cMin x y # TEST 20/cmp*_minmax +#cIf [(cLessOrEq[x y]) y x] -> cMax x y # TEST 20/cmp*_minmax +cIf [(cGreater[x y]) y x] -> cMin x y # TEST 20/cmp*_minmax +cIf [(cGreater[x y]) x y] -> cMax x y # TEST 20/cmp*_minmax +#cIf [(cGreaterOrEq[x y]) y x] -> cMin x y # TEST 20/cmp*_minmax +#cIf [(cGreaterOrEq[x y]) x y] -> cMax x y # TEST 20/cmp*_minmax + +# abs(x) = (x<0 ? -x : x) +# abs(x) = x * (x<0 ? -1 : 1) +# x * (x<0 ? -5 : 5) = abs(x)*5 +# x * ((x<0 ? -5 : 5) + y) = abs(x)*5 + x*y + +#x<0 ? -x : x POS +#x>0 ? x : -x POS +#x<0 ? x : -x NEG +#x>0 ? -x : x NEG + +@R cMul (cIf [(cLess[x 0]) % -%]) x : (cAbs[x]) -% # TEST 20/ifabs +@R cMul (cIf [(cGreater[x 0]) % -%]) x : (cAbs[x]) % # TEST 20/ifabs + +@R cMul (cAdd (cIf [(cLess[x 0]) % -%]) <1>) x : (cAdd (cMul (cAbs[x]) -%) (cMul x (cAdd <1>))) # TEST 20/ifabs +@R cMul (cAdd (cIf [(cGreater[x 0]) % -%]) <1>) x : (cAdd (cMul (cAbs[x]) %) (cMul x (cAdd <1>))) # TEST 20/ifabs + +cMul % (cIf [x & z@C]) : (cIf [x *(% &) *(% z@C)]) # TEST 20/if_join_mul2, ifabs +cAdd % (cIf [x & z@C]) : (cIf [x +(% &) +(% z@C)]) # TEST 20/if_join_add2 + +@R cIf [(cGreater[x 0]) (cFloor[x]) (cCeil[x])] -> cTrunc x # TEST 20/trunc_from_if +#@R cIf [(cGreaterOrEq[x 0]) (cFloor[x]) (cCeil[x])] -> cTrunc x # TEST 20/trunc_from_if +@R cIf [(cLess[x 0]) (cCeil[x]) (cFloor[x])] -> cTrunc x # TEST 20/trunc_from_if +#@R cIf [(cLessOrEq[x 0]) (cCeil[x]) (cFloor[x])] -> cTrunc x # TEST 20/trunc_from_if + +cAdd (cIf[x y z]) (cIf[x a b]) : (cIf [x (cAdd y a) (cAdd z b)]) # TEST 20/if_join_add +cMul (cIf[x y z]) (cIf[x a b]) : (cIf [x (cMul y a) (cMul z b)]) # TEST 20/if_join_mul +cAnd (cIf[x y z]) (cIf[x a b]) : (cIf [x (cAnd y a) (cAnd z b)]) # TEST 20/if_join_and +cOr (cIf[x y z]) (cIf[x a b]) : (cIf [x (cOr y a) (cOr z b)]) # TEST 20/if_join_or +@R cMin (cIf[x y z]) (cIf[x a b]) : (cIf [x (cMin y a) (cMin z b)]) # TEST 20/if_join_min +@R cMax (cIf[x y z]) (cIf[x a b]) : (cIf [x (cMax y a) (cMax z b)]) # TEST 20/if_join_max + +@R cAnd (cNot[x]) (cNot[y]) : (cNot [(cOr x y)]) # TEST 20/nor2, nor2plus, nor3 +@R cOr (cNot[x]) (cNot[y]) : (cNot [(cAnd x y)]) # TEST 20/nand2, nand2plus, nand3 + +@R cAnd (cNot[z]) (cIf[x (cNot[y]) %@L]) : (cNot [(cOr z (cIf[x y (cNot[%])]))]) +@R cOr (cNot[z]) (cIf[x (cNot[y]) %@L]) : (cNot [(cAnd z (cIf[x y (cNot[%])]))]) + +@R cAnd (cNot[z]) (cIf[x %@L (cNot[y])]) : (cNot [(cOr z (cIf[x (cNot[%]) y]))]) +@R cOr (cNot[z]) (cIf[x %@L (cNot[y])]) : (cNot [(cAnd z (cIf[x (cNot[%]) y]))]) + +# From logic, follows that... +# (a==b) & (b==c) & (a==c) -- one of these is redundant +cAnd (cEqual[x y]) (cEqual[y z]) (cEqual[x z]) : (cEqual[x y]) (cEqual[y z]) +# Note: ^ Replacement function refers to y twice + +# !x = abs(x) < 0.5 +# Thus, !(x*2) = abs(x) < 0.5/2 +# Note: Due to range-based optimizations, % can never be 0 here. These are safe. +@R @F cGreater [% (cAbs[x])] -> cNot[(cMul x 0.5 /%)] # TEST 20/absnzlt +@R @F cLessOrEq [% (cAbs[x])] -> cNotNot[(cMul x 0.5 /%)] # TEST 20/absnzge + +# abs(x) > 0 --> abs(x) != 0 --> x != 0 +@R cEqual [0 (cAbs[x])] : x 0 # TEST 20/abseq0 +@R cNEqual [0 (cAbs[x])] : x 0 # TEST 20/absneq0 + +@I cEqual [0 x] -> cNot [x] # TEST 20/eq0 +@I cNEqual [0 x] -> cNotNot [x] # TEST 20/neq0 +@I cEqual [1 x@L] -> x # TEST 20/eq1 +@I cNEqual [1 x@L] -> cNot [x] # TEST 20/neq1 +@I cNot [(cAdd % <1>)] -> cEqual -% (cAdd <1>) # TEST 20/xaddnot +@I cNotNot [(cAdd % <1>)] -> cNEqual -% (cAdd <1>) # TEST 20/xaddnotnot +@R @I cLess [0 (cAbs[x])] -> cNotNot [x] # TEST 20/gt0_abs +@R @I cLessOrEq [1 (cAbs[x])] -> cNotNot [x] # TEST 20/ge1_abs +@R @I cGreater [1 (cAbs[x])] -> cNot [x] # TEST 20/gt1_abs +@R @I cGreaterOrEq [0 (cAbs[x])] -> cNot [x] # TEST 20/ge0_abs + +cIf [x 1 0] -> cNotNot [x] # TEST 20/if10 (factor 1) +cIf [x 0 1] -> cNot [x] # TEST 20/if10 (factor 10) +cAbsIf [x 1 0] -> cAbsNotNot [x] # TEST 20/if10 (factor 100) +cAbsIf [x 0 1] -> cAbsNot [x] # TEST 20/if10 (factor 1000) + +# In logical contexts: +@R @L cMul %@N : -% # TEST 20/l_mulneg +@R @L cMul (cAbs[x]) : x # TEST 20/l_mulabs +@R @L cNotNot [x] -> x # TEST 20/l_notnot +@R @L cAbs [x] -> x # TEST 20/l_abs + +#@R @F cAnd (cLess[% x]) (cAbsNot[x]) : (cNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5)))) +#@R @F cAnd (cLess[% x]) (cGreater[& x]) : (cNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5)))) +#@R @F cAbsAnd (cLess[% x]) (cGreater[& x]) : (cNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5)))) +#@R @F cAbsAnd (cLess[% x]) (cAbsNot[x]) : (cNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5)))) +#@R @F cOr (cGreaterOrEq[% x]) (cLessOrEq[& x]) : (cNotNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5)))) +#@R @F cOr (cGreaterOrEq[% x]) (cAbsNotNot[x]) : (cNotNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5)))) +#@R @F cAbsOr (cGreaterOrEq[% x]) (cLessOrEq[& x]) : (cNotNot (cMul /+(& -%) (cAdd x *(+(% &) -0.5)))) +#@R @F cAbsOr (cGreaterOrEq[% x]) (cAbsNotNot[x]) : (cNotNot (cMul /+(0.5 -%) (cAdd x *(+(% 0.5) -0.5)))) +# ^ these rules only work if & > %, and currently there's no way to verify it + +#@R cOr (cAbsNot[x]) (cAbsNot[(cMul{x -1})]) : (cNot[x]) +#@R cAbsOr (cAbsNot[x]) (cAbsNot[(cMul{x -1})]) : (cNot[x]) +#@R cOr (cAbsNotNot[x]) (cAbsNotNot[(cMul{x -1})]) : (cNotNot[x]) +#@R cAbsOr (cAbsNotNot[x]) (cAbsNotNot[(cMul{x -1})]) : (cNotNot[x]) + +@R @F cAbsNotNot (cMul %@P <1>) -> (cGreaterOrEq[(cMul <1>) *(0.5 /%)]) +@R @F cAbsNotNot (cMul %@N <1>) -> (cLessOrEq[(cMul <1>) *(0.5 /%)]) + +# min(x, max(x, ...)) = x +# max(x, min(x, ...)) = x +cMin x (cMax x <1>) : x # TEST 20/mixedminmax +cMax x (cMin x <1>) : x # TEST 20/mixedminmax + +[SIMPLIFY_EQUATION] + +@R cLess [(cAdd % <1>) &] : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm +@R cLessOrEq [(cAdd % <1>) &] : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm +@R cGreater [(cAdd % <1>) &] : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm +@R cGreaterOrEq [(cAdd % <1>) &] : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm +@R cEqual [(cAdd % <1>) &] : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm +@R cNEqual [(cAdd % <1>) &] : (cAdd <1>) SUB(& %) # TEST 20/cmp*_add_imm + +@R cLess [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>) (cAdd <2> & -%) # TEST 20/cmp*_add_imm +@R cLessOrEq [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>) (cAdd <2> & -%) # TEST 20/cmp*_add_imm +@R cGreater [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>) (cAdd <2> & -%) # TEST 20/cmp*_add_imm +@R cGreaterOrEq [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>) (cAdd <2> & -%) # TEST 20/cmp*_add_imm +@R cEqual [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>) (cAdd <2> & -%) # TEST 20/cmp*_add_imm +@R cNEqual [(cAdd % <1>) (cAdd & <2>)] : (cAdd <1>) (cAdd <2> & -%) # TEST 20/cmp*_add_imm + +@R cLess [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce +@R cLessOrEq [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce +@R cGreater [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce +@R cGreaterOrEq [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce +@R cEqual [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce +@R cNEqual [(cAdd x <1>) (cAdd x <2>)] : (cAdd <1>) (cAdd <2>) # TEST 20/cmp*_add_reduce + +@R @F cLess [(cMul %@P <1>) &] : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos +@R @F cLessOrEq [(cMul %@P <1>) &] : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos +@R @F cGreater [(cMul %@P <1>) &] : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos +@R @F cGreaterOrEq [(cMul %@P <1>) &] : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos +@R @F cLess [(cMul %@N <1>) &] : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cLessOrEq [(cMul %@N <1>) &] : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cGreater [(cMul %@N <1>) &] : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cGreaterOrEq [(cMul %@N <1>) &] : DIV(& %) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cEqual [(cMul % <1>) &] : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos +@R @F cNEqual [(cMul % <1>) &] : (cMul <1>) DIV(& %) # TEST 20/cmp*_mul_imm_pos + +@R @F cLess [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>) (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos +@R @F cLessOrEq [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>) (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos +@R @F cGreater [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>) (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos +@R @F cGreaterOrEq [(cMul %@P <1>) (cMul & <2>)] : (cMul <1>) (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos +@R @F cLess [(cMul %@N <1>) (cMul & <2>)] : (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cLessOrEq [(cMul %@N <1>) (cMul & <2>)] : (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cGreater [(cMul %@N <1>) (cMul & <2>)] : (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cGreaterOrEq [(cMul %@N <1>) (cMul & <2>)] : (cMul <2> DIV(& %)) (cMul <1>) # TEST 20/cmp*_mul_imm_neg +@R @F cEqual [(cMul % <1>) (cMul & <2>)] : (cMul <1>) (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos +@R @F cNEqual [(cMul % <1>) (cMul & <2>)] : (cMul <1>) (cMul <2> DIV(& %)) # TEST 20/cmp*_mul_imm_pos + +#cLess [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>) +#cLessOrEq [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>) +#cGreater [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>) +#cGreaterOrEq [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>) +#cEqual [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>) +#cNEqual [(cMul x <1>) (cMul x <2>)] : (cMul <1>) (cMul <2>) +# ^ Note: This fails when x=0 + +# Instead of x, generate (x^%)^(1/%) to further +# delegate the possible responsibility of adding an abs() call. +@R @F cLess [(cPow [x %@P]) &] : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_* +@R @F cLessOrEq [(cPow [x %@P]) &] : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_* +@R @F cGreater [(cPow [x %@P]) &] : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_* +@R @F cGreaterOrEq [(cPow [x %@P]) &] : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_* +@R @F cEqual [(cPow [x %@P]) &] : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_* +@R @F cNEqual [(cPow [x %@P]) &] : (cPow [(cPow [x %]) /%]) POW(& /%) # TEST 20/cmp*_pow_imm_* + +#@R @F cLess [(cPow [x %@P]) (cPow [y &@P])] : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos +#@R @F cLessOrEq [(cPow [x %@P]) (cPow [y &@P])] : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos +#@R @F cGreater [(cPow [x %@P]) (cPow [y &@P])] : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos +#@R @F cGreaterOrEq [(cPow [x %@P]) (cPow [y &@P])] : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos +#@R @F cEqual [(cPow [x %@P]) (cPow [y &@P])] : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos +#@R @F cNEqual [(cPow [x %@P]) (cPow [y &@P])] : (cPow [(cPow [x %]) /MIN(% &)]) (cPow [(cPow [y &]) /MIN(% &)]) # TEST 20/cmp*_powpow_imm_pospos +# ^ Note: This fails in "pow(x,2) op pow(y,3)" when x=-5, y=-6" +# TODO: Figure out how to workaround + +@R @F cLess [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base +@R @F cLessOrEq [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base +@R @F cGreater [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base +@R @F cGreaterOrEq [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base +@R @F cEqual [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base +@R @F cNEqual [(cPow [% x]) (cPow [% y])] : x y # TEST 20/cmp*_powpow_imm_base +# ^Note: This fails on exp(x)=exp(y) because of epsilon + +@R @F cLess [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base +@R @F cLessOrEq [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base +@R @F cGreater [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base +@R @F cGreaterOrEq [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base +@R @F cEqual [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base +@R @F cNEqual [&@P (cPow [%@P x])] : DIV(LOG(&) LOG(%)) x # TEST 20/cmp*_pow_imm_pospos_base + +[REMOVE_REDUNDANT] + +@R cMul (cAbs[x]) (cAbs[y]) : (cAbs[(cMul x y)]) # TEST 20/mergemultiabs + +[EXTRACT1] + +# ceil(-x) = -floor(x); floor(-x) = -ceil(x) +@R @F cFloor[(cMul -1 <1>)] -> cMul -1 (cCeil[(cMul <1>)]) # TEST 20/negfloor +@R @F cCeil[(cMul -1 <1>)] -> cMul -1 (cFloor[(cMul <1>)]) # TEST 20/negceil + +[LOGARITHM] + +#### Logarithm optimizations +# log(x^y) = y*log(x) +#@F cLog [(cPow [x y])] -> cMul y (cLog[(cPow [(cPow [x y]) (cPow [y -1])])]) +# ^makes an infinite loop +#@F cLog [(cPow [x@P y])] -> cMul y (cLog[x]) +#@F cLog [(cPow [x y@E])] -> cMul y (cLog [(cAbs [x])]) +# ^ Done in ConstantFolding() + +# CONSTANT_E^log(x) = x +# CONSTANT_E^(log(x)*y) = x^y +# Generalized as: p^ log(x) = x^ log(p) +# p^(log(x)*y) = x^(log(p)*y) +# +# Warning: This loses the information that x > 0, +# that could be utilized in further optimizations. +# +@F cPow [% (cLog[x]) ] : x LOG(%) # TEST 20/powimmlog +@F cPow [% (cMul (cLog[x]) <1>)] : x (cMul LOG(%) <1>) # TEST 20/powimmlog + +# Because log(exp(6)*x) = log(x)+6, we can also do this: +# y^(log(x)+z) +# = y^(log(x*exp(z))) +# = (x*exp(z))^log(y) +# = x^log(y) * y^z +#cPow [y (cAdd {(cLog[x]) &})] -> cMul (cPow [y &]) (cPow [x (cLog [y])]) +# +# Probably beneficial to do it only when y is const, +# though. Otherwise we only trade + for *, which is bad. +# Also z should be const, otherwise we get two pows instead of one. +@F cPow [% (cAdd {(cLog[x]) &})] -> cMul POW(% &) (cPow [x LOG(%)]) # TEST 20/powimmaddimmlog + +# x^(y*z) = (x*y)^z - done by ConstantFolding + +# z^(log(x)/log(z)*y) = x^y +# Note: This rule fails when z=0, because log(0)=-inf and 0^x = 1 +@F cPow [z (cMul (cPow [(cLog[z]) -1]) (cLog[x]) <1>)] : x (cMul <1>) +@F cPow [% (cMul /LOG(%) (cLog[x]) <1>)] : x (cMul <1>) + +# log(x) + log(y) = log(x*y) +@F cAdd (cLog[x]) (cLog[y]) : (cLog (cMul [x y])) # TEST 20/addlog + +# When x is const, the reverse is more beneficial +# i.e. log(2*x) = log(x) + log(2) +@F cLog [(cMul %@P <1>)] -> cAdd (cLog [(cMul <1>)]) LOG(%) # TEST 20/mulimmlog + +# log(x * z^y) = (log(x) / log(z) + y) * log(z) +# = log(x) + log(z)*y +# Only worthwhile when z is an immed, otherwise we trade cPow for cLog +# Note that when z = CONSTANT_E, this reduces rather nicely into log(x) + y +@F cLog [(cMul (cPow [% y]) <1>)] -> cAdd (cMul [LOG(%) y]) (cLog [(cMul <1>)]) + +#cLog [(cMul (cPow [% y]) <1>)] -> cMul LOG(%) (cAdd [y (cMul (cLog [(cMul <1>)]) /LOG(%))]) +# When y=1, the reverse is more useful: +@F cMul {% (cAdd {1 (cMul {(cLog [x]) /%})})} -> cAdd (cLog [x]) % + + +[POW_TRICKS] + +###### Note: Before adding new rules (especially those which handle constant values), +###### verify that it is not already done in ConstantFolding(). + +# (x*5) ^ 2 = x^2 * (5^2) +# (x*5)^-1 = 0.2/x , shrug +cPow [(cMul %@P <1>) &] -> cMul POW(% &) (cPow [(cMul <1>) &]) # TEST 20/powmulimm_* +# ^Limited to positive values so that (-4*x)^3.3 won't be changed into nan*x^3.3 + +cPow [(cMul %@N <1>) &@E] -> cMul POW(% &) (cPow [(cMul <1>) &]) # TEST 20/powmulimm_* +# ^This changes (-5*x)^2 into x^2 * (-5)^2 = x^2 * 25, but only when & is an even integer. + +# z^(x+y/log(z)) = z^x * exp(y) +# Note: This rule fails when z=0, because log(0)=-inf and 0^z = 1 +@F cPow [z (cAdd <1> (cMul <2> (cPow [(cLog [z]) -1])))] -> cMul (cPow [z (cAdd <1>)]) (cPow [CONSTANT_E (cMul <2>)]) +#@F cPow [% (cAdd <1> (cMul <2> /LOG(%)))] -> cMul (cPow [% (cAdd <1>)]) (cPow [CONSTANT_E (cMul <2>)]) +@F cPow [z (cAdd <1> (cPow [(cLog [z]) -1]))] -> cMul CONSTANT_E (cPow [z (cAdd <1>)]) +cPow [% (cAdd <1> &@M)] -> cMul POW(% &) (cPow [% (cAdd <1>)]) + +# x*y / (x*z) = y/z +cMul (cPow [(cMul x <2>) -1]) x : (cPow [(cMul <2>) -1]) + +# (x^y)^z -> x^(y*z) +# safe when y is odd or float, or z is an integer, or x is not negative +cPow [ (cPow[x y@O]) z ] : x (cMul [y z]) +cPow [ (cPow[x y@F]) z ] : x (cMul [y z]) +cPow [ (cPow[x y]) z@I ] : x (cMul [y z]) +cPow [ (cPow[x@P y]) z ] : x (cMul [y z]) + +# (x^y)^z where (y*z) makes an even integer could also be changed safely +#cPow [(cPow [x y@I]) z@E] : x (cMul [y z]) + +# If pow() makes a signless value into a positive value, guard that fact with abs() +cPow [ (cPow[x@Q y])@P z ] : (cAbs [x]) (cMul [y z]) + +# abs(x)^e -> x^e when e=even integer +# This removes the abs() generated by the above rule when needless +cPow [(cAbs[x]) y@E] : x y +cPow [(cMul (cAbs[x]) <1>) y@E] : (cMul x <1>) y +#cPow [(cMul %@N <1>) y@E] : (cMul -% <1>) y +# ^ already done by constantfolding + +# x^y * (n + x^z) = n*x^y + x^(y+z) +cMul (cPow [x y]) (cAdd {%@1 (cPow [x z])}) : (cAdd (cMul (cPow[x y]) %) (cPow[x (cAdd y z)])) +# x^y * (n + a^z) = n*x^y + x^(y+z*log(a)/log(x)) +cMul (cPow [& y]) (cAdd { 1 (cPow [x@P z])}) : (cAdd (cPow[& y]) (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))])) +cMul (cPow [& y]) (cAdd {-1 (cPow [x@P z])}) : (cAdd (cMul (cPow[& y]) -1) (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))])) +# exp(-x)*(exp(2*n)+1)*4 +# becomes +# exp(1) ^ (-x) * (exp(2) ^ n * 4 + 4) +# so we detect that here as well. +cMul (cPow [& y]) (cAdd {(cMul {% (cPow [x@P z])}) %}) : % (cAdd (cPow[& y]) (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))])) +cMul (cPow [& y]) (cAdd {(cMul {% (cPow [x@P z])}) -%}) : % (cAdd (cMul (cPow[& y]) -1) (cPow[& (cAdd y (cMul z (cLog[x]) /LOG(&)))])) + +# exp(2*y) - 2*exp(y) = (exp(x)-1)^2 - 1 +# exp(2*y) - 6*exp(y) = (exp(x)-3)^2 - 9 +# exp(2*y) + 6*exp(y) = (exp(x)+3)^2 - 9 +# note: x^(2*y) = (x^2)^y (especially: exp(2*y) = exp(2)^y) +cAdd (cMul {% (cPow[x y ])}) (cPow[x (cMul { 2 y})]) : (cPow[(cAdd (cPow[x y ]) *(% 0.5)) 2]) -POW(*(% 0.5) 2) +cAdd (cMul {% (cPow[x (cMul {& y})])}) (cPow[x (cMul {*(& 2) y})]) : (cPow[(cAdd (cPow[x (cMul y &)]) *(% 0.5)) 2]) -POW(*(% 0.5) 2) +cAdd (cMul {% (cPow[& y ])}) (cPow[POW(& 2) y ]) : (cPow[(cAdd (cPow[& y ]) *(% 0.5)) 2]) -POW(*(% 0.5) 2) + +[BINOMIAL] + +# Opcodes we will NOT find in the intermediate stage: +# Done by bytecode parser: +# Meta opcodes: cDup, cNop, cFetch, cPopNMov, cJump +# Meta opcodes: cVar, cImmed +# Implemented through cMul: cDiv, cRDiv, cInv, cSqr +# Implemented through cAdd: cSub, cRSub, cNeg +# Implemented through constant-multiplying: cDeg, cRad +# Implemented through cSin, cCos: cCot, cCsc, cSec, cTan +# Implemented through cPow: cSqrt, cExp +# Implemented through cLog: cLog2, cLog10 +# Done by entry rules: +# Extracted: cAsinh, cAcosh, cAtanh +# Extracted: cSinh, cCosh, cTanh + +#### CONTINUED: Flattening the topology of add/mul/min/max/and/or groups + +# a^2 + a*b*X/Z + b^2 = (a+b)^2 + (X/Z-2)*(a*b) +#cAdd (cPow[x 2]) (cPow[y 2]) (cMul x y <1>) : (cPow [(cAdd [x y]) 2]) (cMul [x y (cAdd [(cMul <1>) -2])]) +# For optimizing x^2+2*x*y+y^2: +# With this rule, eval=0.287154 us, optimized = 0.0758879 us +# Without this rule, eval=0.314538 us, optimized = 0.0831386 us +# For optimizing x^2+3*x*y+y^2: +# With this rule, eval=0.295956 us, optimized = 0.0781288 us +# Without this rule, eval=0.300723 us, optimized = 0.075689 us +# The benchmark results seem too varying, so it is hard to tell +# whether this rule had some advantage. It _looks_ like it did +# though, so better keep it, I suppose. -Bisqwit +# +# How about this? +# (a+b+c)^2 = c^2 + 2*b*c + 2*a*c + b^2 + 2*a*b + a^2 +# Seems that it becomes: +# a^2 + b^2 + c^2 + 2*((a+b)*c + a*b) +# Is it worth adding rule for making that into (a+b+c)^2? +# Too specific, I suppose. + +# These are the same as above, but work also if pow() is expanded +# Note: It would work even with y and z instead of % and &, but we +# limit into numeric literals for simplicity. +cAdd (cMul (cPow[x %@P@I]) <1>) (cMul (cPow[x &@I]) <2>) : (cMul (cPow[x MIN(% &)]) (cAdd (cMul <1> (cPow[x (cAdd % -MIN(% &))])) (cMul <2> (cPow[x (cAdd & -MIN(% &))])))) + +# Note: +# x^4*a + b*x^9 -> (x^5 * b + a)*x^4: Eval time goes 0.046 -> 0.056 +# x^5*a + b*x^11 -> (x^6 * b + a)*x^5: Eval time goes 0.060 -> 0.049 +# srsly, what? + +# x^2 + N*y - y^2 = x^2 - (y + N* 0.5)^2 + (N/2)^2 +# x^2 + N*y + y^2 = x^2 + (y + N*-0.5)^2 - (N/2)^2 +@F cAdd (cMul {-1 (cPow[x 2])}) (cMul{% x}) : (cMul {-1 (cPow[(cAdd x *(% -0.5)) 2])}) POW(*(% 0.5) 2) +@F cAdd (cPow[x 2]) (cMul{% x}) : (cPow[(cAdd x *(% 0.5)) 2]) -POW(*(% 0.5) 2) + +#cAdd (cMul (cPow[x %@P@I]) <1>) (cMul x <2>) : (cMul (cPow[x MIN(% 1)]) (cAdd (cMul <1> (cPow[x (cAdd % -MIN(% 1))])) (cMul <2> (cPow[x (cAdd 1 -MIN(% 1))])))) + + +# N*x^2 + M*x^2 = (x*sqrt(N) + y*sqrt(M))^2 - (2*sqrt(N*M))*x*y +# N*x^2 + M*x*y = (x*sqrt(N) + y*0.5*M/sqrt(N))^2 - 0.25*M^2/N*y^2 +cAdd (cMul {%@P (cPow[x 2])}) (cMul {& x y}) : (cPow[(cAdd (cMul x SQRT(%)) (cMul y *(0.5 *(& /SQRT(%)))) ) 2]) (cMul (cPow[y 2]) *(*(-0.25 /%) POW(& 2))) + +# N*(x^2 + y^2) + M*x*y = N*(x+y)^2 + (2*N-M)*x*y +cAdd (cMul {%@P (cAdd {(cPow[x 2]) (cPow[y 2])})}) (cMul {&@P x y}) : (cMul % (cPow[(cAdd x y ) 2])) (cMul +(& *(-2 %)) x y) +cAdd (cMul {%@P (cAdd {(cPow[x 2]) (cPow[y 2])})}) (cMul {&@N x y}) : (cMul % (cPow[(cAdd x (cMul -1 y)) 2])) (cMul +(& *( 2 %)) x y) + +# The replacement expanded below: +# (cMul (cPow[x MIN(% 1)]) +# (cAdd (cMul <1> (cPow[x (cAdd % -MIN(% 1))])) +# (cMul <2> (cPow[x (cAdd 1 -MIN(% 1))])))) +# +# Example: x^2*y + x*z -> x^1 * (y*x^1 + z*x^0) +# Example: x^6*y + x*z -> x^1 * (y*x^5 + z*x^0) +# Example: x^-6*y + x*z -> x^-6 * (y*x^0 + z*x^7) -- not good, so restricted with @P +# +# Example: x*z + 2*x^0.7 -> x^0.7 * (x^0.3 * z+2) -- not good, so also restricted with @I +# + +# Note: These two rules should be done in constantfolding, but it's complicated. +# 5*x - 5*y = 5*(x-y) +cAdd (cMul %@P <1>) (cMul -% <2>) : (cMul % (cAdd (cMul <1>) (cMul -1 <2>))) # TEST 20/addnegmulpos +# 5 - 5*x = -5*(x-1) +#cAdd %@M (cMul -% <2>) : (cMul -% (cAdd (cMul <2>) -1)) +cAdd %@M (cMul -% <2>) : (cMul % (cAdd 1 (cMul <2> -1))) # TEST 20/addnegmulneg + +# (5.1*x + 4.1*y + z+w)*2 +# -> (5.1*2*x + 2*(4.1*y + z+w)) +# -> (5.1*2*x + (4.1*2*y + 2*(z+w))) +cMul (cAdd (cMul %@M <1>) <2>) & : (cAdd (cMul % & <1>) (cMul & (cAdd <2>))) # TEST 20/addmulconstmul + +# (2+x+y)*4 = 2*4 + 4*(x+y) +cMul (cAdd %@M <1>) & : (cAdd *(% &) (cMul & (cAdd <1>))) # TEST 20/addconstmul + + +[TRIGONOMETRIC] + +# sin(-x) = -sin(x) +@F cSin [(cMul -1 <1>)] -> cMul -1 (cSin [(cMul <1>)]) # TEST 20/negsin +# However, -sin(5*x) better expressed as sin(-5*x) +@F cMul -1 (cSin [(cMul %@N <1>)]) : (cSin [(cMul -% <1>)]) +# cos(-x) = cos(x) +@F cCos [(cMul -1 <1>)] : (cMul <1>) # TEST 20/negcos +@R @F cCos [(cAbs [x])] : x # TEST 20/abscos + +# cos(pi/2 - x) = sin(x) +@F cCos [(cAdd {CONSTANT_PIHALF@R (cMul %@N <1>)})] -> cSin[(cMul -% <1>)] # TEST 20/trig_modulo +# sin(pi/2 - x) = cos(x) +@F cSin [(cAdd {CONSTANT_PIHALF@R (cMul %@N <1>)})] -> cCos[(cMul -% <1>)] # TEST 20/trig_modulo +# cos(x - pi/2) = cos(pi/2 - x) = sin(x) +@F cCos [(cAdd -CONSTANT_PIHALF@R <1>)] -> cSin[(cAdd <1>)] # TEST 20/trig_modulo +# sin(x - pi/2) = -sin(pi/2 - x) = -cos(x) +@F cSin [(cAdd -CONSTANT_PIHALF@R <1>)] -> cMul -1 (cCos[(cAdd <1>)]) # TEST 20/trig_modulo +# sin(x + pi/2) = cos(x) +@F cSin [(cAdd CONSTANT_PIHALF@R <1>)] -> cCos[(cAdd <1>)] # TEST 20/trig_modulo +# cos(x + pi/2) = sin(-x) +@F cCos [(cAdd CONSTANT_PIHALF@R <1>)] -> cSin[(cMul -1 (cAdd <1>))] # TEST 20/trig_modulo +# sin(x + pi) = -sin(x) +@F cSin [(cAdd CONSTANT_PI@R <1>)] -> cMul -1 (cSin[(cAdd <1>)]) # TEST 20/trig_modulo +# cos(x + pi) = -cos(x) +@F cCos [(cAdd CONSTANT_PI@R <1>)] -> cMul -1 (cCos[(cAdd <1>)]) # TEST 20/trig_modulo +# +@F cCos [(cAdd 0@R <1>)] -> cCos[(cAdd <1>)] +@F cSin [(cAdd 0@R <1>)] -> cSin[(cAdd <1>)] + + +# sin(x)^2 + cos(x)^2 = 1 +@F cAdd (cPow[ (cSin[x]) 2]) (cPow [(cCos[x]) 2]) : 1 # TEST 20/addsin2cos2 +# y-sin(x)^2 = cos(x)^2+(y-1) +# y-cos(x)^2 = sin(x)^2+(y-1) +@F cAdd 1 (cMul { -1 (cPow[ (cSin[x]) 2]) }) : (cPow [(cCos[x]) 2]) # TEST 20/sub1sin2 +@F cAdd 1 (cMul { -1 (cPow[ (cCos[x]) 2]) }) : (cPow [(cSin[x]) 2]) # TEST 20/sub1cos2 + +# sin(x)*cos(y) + cos(x)*sin(y) = sin(x+y) +# sin(x)*cos(y) - cos(x)*sin(y) = sin(x-y) +# cos(x)*cos(y) + sin(x)*sin(y) = cos(x+y) +# cos(x)*cos(y) - sin(x)*sin(y) = cos(x-y) + +@F cAdd (cMul {(cSin[x]) (cCos[y])}) (cMul {(cCos[x]) (cSin[y]) }) : (cSin [(cAdd[x y] )]) +@F cAdd (cMul {(cSin[x]) (cCos[y])}) (cMul {(cCos[x]) (cSin[y]) -1}) : (cSin [(cAdd[x (cMul [-1 y])])]) +@F cAdd (cMul {(cCos[x]) (cCos[y])}) (cMul {(cSin[x]) (cSin[y]) }) : (cCos [(cAdd[x y] )]) +@F cAdd (cMul {(cCos[x]) (cCos[y])}) (cMul {(cSin[x]) (cSin[y]) -1}) : (cCos [(cAdd[x (cMul [-1 y])])]) + +#@F cAdd (cMul {(cSin[x]) (cCos[y]) -1}) (cMul {(cCos[x]) (cSin[y]) -1}) : (cMul [-1 (cSin [(cAdd[x y] )]) ]) +#@F cAdd (cMul {(cCos[x]) (cCos[y]) -1}) (cMul {(cSin[x]) (cSin[y]) -1}) : (cMul [-1 (cCos [(cAdd[x y] )]) ]) +# ^This one is redundant, subexpression grouping already catches it +@F cAdd (cMul {(cCos[x]) (cCos[y]) -1}) (cMul {(cSin[x]) (cSin[y]) }) : (cMul [-1 (cCos [(cAdd[x (cMul [-1 y])])]) ]) +#@F cAdd (cMul {(cSin[x]) (cCos[y]) -1}) (cMul {(cCos[x]) (cSin[y]) }) : (cMul [-1 (cSin [(cAdd[x (cMul [-1 y])])]) ]) +# ^This one is redudant: It just reaffirms that sin(x) = -sin(-x). + +# sin(asin(x)) = x +@F cSin [(cAsin [x])] -> x # TEST 20/asinsin + +# cos(acos(x)) = x +@F cCos [(cAcos [x])] -> x # TEST 20/acoscos + +# Note: asin(sin(x)) must not be converted, because +# even though asin(sin(1.1)) = 1.1, asin(sin(1500)) != 1500. + +# atan(x/y) = atan2(x,y) -- do this only when we don't know whether y is zero. +# If we know that y is nonzero, ConstantFolding +# will revert this optimization. +@R @F cAtan [(cMul {x (cPow [y@Q %@N])})] -> cAtan2 [x (cPow [y -%])] + +@R @F cAtan2 [(cMul x@P <1>) (cMul x@P <2>)] : (cMul <1>) (cMul <2>) +@R @F cAtan2 [(cMul x@N@V <1>) (cMul x@N@V <2>)] : (cMul -1 <1>) (cMul -1 <2>) + +# asin(x): atan2(x, (1-x*x)^0.5) +# asin(x): atan(x * (1-x*x)^-0.5) - automatically converted to the above. +@R @F cAtan2 [x (cPow [(cAdd {(cMul {(cPow [x 2]) -1}) 1}) 0.5])] -> cAsin[x] + +# acos(x): atan2((1-x*x)^0.5, x) +# acos(x): atan((1-x*x)^0.5 * x^-1) - automatically converted to the above. +@R @F cAtan2 [(cPow [(cAdd {(cMul {(cPow [x 2]) -1}) 1}) 0.5]) x] -> cAcos[x] + + +[REGENERATE_TAN] + +# sin(x)/cos(x) = tan(x) +@F cMul (cSin[x]) (cPow [(cCos[x]) -1]) : (cTan[x]) +@F cMul (cPow [(cSin[x]) -1]) (cCos[x]) : (cPow [(cTan[x]) -1]) +# tan(x)*cos(x) = sin(x) +@F cMul (cTan[x]) (cCos[x]) : (cSin[x]) +# sin(x)/tan(x) = cos(x) +@F cMul (cPow [(cTan[x]) -1]) (cSin[x]) : (cCos[x]) +@F cMul (cTan[x]) (cPow [(cSin[x]) -1]) : (cPow [(cCos[x]) -1]) + +# cos(x)^(-2) * sin(x) = tan(x)/cos(x) +# sin(x)^2 / cos(x) = tan(x)*sin(x) + +# sin(-5*x) / cos(5*x) = tan(-5*x) +@F cMul (cSin [(cMul % <1>)]) (cPow [(cCos [(cMul -% <1>)]) -1]) : (cTan [(cMul % <1>)]) + +# tan(-x) = -tan(x) +@F cTan [(cMul -1 <1>)] -> cMul [-1 (cTan [(cMul <1>)])] + +# However, -tan(5*x) better expressed as tan(-5*x) +@F cMul -1 (cTan [(cMul %@N <1>)]) : (cTan [(cMul -% <1>)]) + +# asin(tan(x)) = x / (1-x^2)^0.5 +#@F cAsin [(cTan [x])] -> cMul x (cPow [(cAdd (cMul (cPow [x 2]) -1) 1) -0.5]) +# +# ^Disabled: Incorrectly produces error when x = 1 + +# acos(tan(x)) = (1-x^2)^0.5 / x +#@F cAcos [(cTan [x])] -> cMul (cPow [x -1]) (cPow [(cAdd (cMul (cPow [x 2]) -1) 1) 0.5]) +# +# ^Disabled: Incorrectly produces error when x = 0 +# Incorrectly produces negative numbers when acos does no such thing + +# cot(pi/2 - x) = 1/tan(pi/2 - x) = tan(x) +# tan(pi/2 - x) = 1/tan(x) +# reverse is probably better +# but cot() isn't exactly bad, so keep it +#cPow [(cTan[x]) -1] -> cTan [(cAdd [CONSTANT_PIHALF@R (cMul [-1 x])])] + +@F cMul (cTan [(cAdd {CONSTANT_PIHALF@R (cMul {-1 x})})]) (cTan [x]) : 1 +@F cMul (cTan [(cAdd {CONSTANT_PIHALF@R (cMul -1 <1>)})]) (cTan [(cMul <1>)]) : 1 + +# tan(atan(x)) = x +@F cTan [(cAtan [x])] -> x + +@F cTan [(cAtan2 [x y])] -> cMul x (cPow [y -1]) + + +[REGENERATE_TANH] + +# sinh(x)/cosh(x) = tanh(x) +@F cMul (cSinh[x]) (cPow [(cCosh[x]) -1]) : (cTanh[x]) +@F cMul (cPow [(cSinh[x]) -1]) (cCosh[x]) : (cPow [(cTanh[x]) -1]) +# tanh(x)*cosh(x) = sinh(x) +@F cMul (cTanh[x]) (cCosh[x]) : (cSinh[x]) +# sinh(x)/tanh(x) = cosh(x) +@F cMul (cPow [(cTanh[x]) -1]) (cSinh[x]) : (cCosh[x]) +@F cMul (cTanh[x]) (cPow [(cSinh[x]) -1]) : (cPow [(cCosh[x]) -1]) + +# sinh(-5*x) / cosh(5*x) = tanh(-5*x) +@F cMul (cSinh [(cMul {% x})]) (cPow [(cCosh [(cMul {-% x})]) -1]) : (cTanh [(cMul % x)]) +@F cMul (cSin [(cMul {% x})]) (cPow [(cCos [(cMul {-% x})]) -1]) : (cTan [(cMul % x)]) +#^ Note: Should use (cMul % <1>) instead of (cMul {% x}), +# but cannot, due to repeated restholders + +# tanh(-x) = -tanh(x) +@F cTanh [(cMul -1 <1>)] -> cMul [-1 (cTanh [(cMul <1>)])] + +# However, -tanh(5*x) better expressed as tanh(-5*x) +@F cMul -1 (cTanh [(cMul %@N <1>)]) : (cTanh [(cMul -% <1>)]) + + +# tanh(x) = (exp(2*x)-1) / (exp(2*x)+1) +# 1/tanh(x) = (exp(2*x)+1) / (exp(2*x)-1) +# exp(2*x) = exp(2)^x +# y^x = exp(log(y)*x) +# tanh(x*log(y)/2) = (y^x-1) / (y^x+1) +@F cMul (cAdd {-1 (cPow [% x])}) (cPow [(cAdd { 1 (cPow [% x])}) -1]) : (cTanh [(cMul x LOG(%) 0.5)]) +@F cMul (cAdd { 1 (cPow [% x])}) (cPow [(cAdd {-1 (cPow [% x])}) -1]) : (cPow [(cTanh [(cMul x LOG(%) 0.5)]) -1]) + + +[SINH_COSH_EXP_TRANSFORMATIONS] + +# sinh(-x) = -sinh(x) +@F cSinh [(cMul -1 <1>)] -> cMul [-1 (cSinh [(cMul <1>)])] # TEST 20/negsinh +# However, -sinh(5*x) better expressed as sinh(-5*x) +@F cMul -1 (cSinh [(cMul %@N <1>)]) : (cSinh [(cMul -% <1>)]) +# cosh(-x) = cosh(x) +@F cCosh [(cMul -1 <1>)] : (cMul <1>) # TEST 20/negcosh +@R @F cCosh [(cAbs [x])] : x # TEST 20/abscosh + +# x - 1/x = sinh(log(x))*2. However, this alone is a pessimal conversion. +#@F cAdd x (cMul {-1 (cPow [ x -1])}) : (cMul (cSinh [(cLog [x])]) 2) +#@F cAdd <1> (cMul {-1 (cPow [(cAdd <1>) -1])}) : (cMul (cSinh [(cLog [(cAdd <1>)])]) 2) +# So we add the requirement of cPow to it. +# cLog(cPow()) reduces into optimal opcodes. +# +# sinh(x)*2 = (exp(x)-exp(-x)) -- note: exp(-x) = 1/exp(x) +# cosh(x)*2 = (exp(x)+exp(-x)) +@F cAdd (cPow [& x]) (cMul { -1 (cPow [/& x]) }) : (cMul (cSinh [(cLog [(cPow [& x])])]) 2) +@F cAdd (cPow [& x]) (cPow [/& x]) : (cMul (cCosh [(cLog [(cPow [& x])])]) 2) +#@F cAdd (cPow [y x]) (cMul { -1 (cPow [y (cMul {x -1})]) }) : (cMul (cSinh [(cLog [(cPow [y x])])]) 2) +#@F cAdd (cPow [y x]) (cPow [y (cMul {x -1})]) : (cMul (cCosh [(cLog [(cPow [y x])])]) 2) +#@F cAdd (cPow [y %]) (cMul { -1 (cPow [y -%]) }) : (cMul (cSinh [(cLog [(cPow [y %])])]) 2) +#@F cAdd (cPow [y %]) (cPow [y -%]) : (cMul (cCosh [(cLog [(cPow [y %])])]) 2) + +# Because sinh(-x) = -sinh(x), +# sinh(x)*-2 = (exp(-x)-exp(x)) +@F cAdd (cMul {-1 (cPow [& x])}) (cPow [/& x]) : (cMul (cSinh [(cMul x LOG(&))]) -2) +@F cAdd (cMul {% (cPow [& x])}) (cMul { -% (cPow [/& x])}) : (cMul (cSinh [(cMul x LOG(&))]) 2 %) +@F cAdd (cMul {% (cPow [& x])}) (cMul { % (cPow [/& x])}) : (cMul (cCosh [(cMul x LOG(&))]) 2 %) + + +# exp(x) = cosh(x)+sinh(x) +@F cAdd (cCosh [x]) (cSinh [x]) : (cPow [CONSTANT_E x]) +# -cosh(x) = sinh(x)-exp(x) +# cosh(x) = exp(x)-sinh(x) +# -sinh(x) = cosh(x)-exp(x) +# sinh(x) = exp(x)-cosh(x) +@F cAdd (cSinh [x]) (cMul {(cPow [CONSTANT_E x]) -1}) : (cMul -1 (cCosh [x])) +@F cAdd (cMul {(cSinh [x]) -1}) (cPow [CONSTANT_E x]) : (cCosh [x]) +@F cAdd (cCosh [x]) (cMul {(cPow [CONSTANT_E x]) -1}) : (cMul -1 (cSinh [x])) +@F cAdd (cMul {(cCosh [x]) -1}) (cPow [CONSTANT_E x]) : (cSinh [x]) +# exp(-x) = cosh(x)-sinh(x) +# -exp(-x) = sinh(x)-cosh(x) +@F cAdd (cCosh [x]) (cMul {(cSinh [x]) -1}) : (cPow [CONSTANT_EI x]) +@F cAdd (cMul {(cCosh [x]) -1}) (cSinh [x]) : (cMul {(cPow [CONSTANT_EI x]) -1}) +# sinh(x) = cosh(x)-exp(-x) +# -sinh(x) = exp(-x)-cosh(x) +# cosh(x) = exp(-x)+sinh(x) +@F cAdd (cCosh [x]) (cMul {(cPow [CONSTANT_EI x]) -1}) : (cSinh [x]) +@F cAdd (cMul {(cCosh [x]) -1}) (cPow [CONSTANT_EI x]) : (cMul -1 (cSinh [x])) +@F cAdd (cSinh [x]) (cPow [CONSTANT_EI x]) : (cCosh [x]) + + +# sinh(x) = ((((E^2) ^ x) + -1) * ((E^-1) ^ x) * 0.5) +# sinh(3*x) = ((((E^6) ^ x) + -1) * ((E^-3) ^ x) * 0.5) + +# sinh(3*x)*2 = (((E^6) ^ x) + -1) * ((E^-3) ^ x) +# sinh(3*x)*2 / (E^-3) ^x = (((E^6) ^ x) + -1) +# sinh(3*x)*2 * (E^ 3) ^x = (((E^6) ^ x) + -1) + +#@F cAdd {-1 (cPow [% x])} : (cMul (cSinh [(cMul x LOG(%) 0.5)]) 2 (cPow [% (cMul x 0.5)])) +#@F cAdd { 1 (cPow [% x])} : (cMul (cCosh [(cMul x LOG(%) 0.5)]) 2 (cPow [% (cMul x 0.5)])) + +#@F cMul (cAdd {-1 (cPow [% x])}) (cPow [POW(% -0.5) x]) : (cSinh [(cMul x LOG(%) 0.5)]) 2 +#@F cMul (cPow [% x]) (cAdd {-1 (cPow [POW(% -2) x])}) : (cSinh [(cMul x LOG(%) 0.5)]) 2 + +# tanh(x) / cosh(x) +# = sinh(x) / cosh(x)^2 +@F cMul (cSinh[x]) (cPow[(cCosh[x]) %]) : (cTanh[x]) (cPow[(cCosh[x]) +(% 1)]) + +# sinh(log(x)) = 0.5*(x - 1/x) (valid only for x>0) +#@F cSinh [(cLog [x])] -> cMul 0.5 (cAdd x (cMul -1 (cPow [x -1]))) + + +[ASINH_ACOSH_ATANH_TRANSFORMATIONS] + +# sinh(acosh(x)) = sqrt(x^2 - 1) (not a typo) +# cosh(asinh(x)) = sqrt(x^2 + 1) (not a typo) +# Not sure whether these are faster. They are more opcodes, but +# simpler. The rationale is in allowing for further optimizations. +@F cSinh [(cAcosh [x])] -> cPow [(cAdd [(cPow [x 2]) -1]) 0.5] # TEST 20/acoshsinh +@F cCosh [(cAsinh [x])] -> cPow [(cAdd [(cPow [x 2]) 1]) 0.5] # TEST 20/asinhcosh + +# asinh: log(x + sqrt(x*x + 1)) +# exp(asinh): x + sqrt(x*x + 1)# +# Disabled: On x86_64, "asinh(x)" is slower than "log(sqrt(x^2+1)+x)" +@F cAdd (cPow [(cAdd {1 (cPow [ x 2])}) 0.5]) x : (cPow [CONSTANT_E (cAsinh [x])]) +@F cAdd (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])}) 0.5]) <1> -> (cPow [CONSTANT_E (cAsinh [(cAdd <1>)])]) +@F cAdd (cPow [(cAdd {1 (cPow [ x 2])}) -0.5]) x : (cPow [CONSTANT_EI (cAsinh [x])]) +@F cAdd (cPow [(cAdd {1 (cPow [(cAdd <1>) 2])}) -0.5]) <1> -> (cPow [CONSTANT_EI (cAsinh [(cAdd <1>)])]) + + +# acosh: log(x + sqrt(x*x - 1)) +# exp(acosh): x + sqrt(x*x - 1) +# Disabled: On x86_64, "acosh(x)" is slower than "log(sqrt(x^2-1)+x)" +@F cLog [(cAdd {(cPow [(cAdd {-1 (cPow [x 2])}) 0.5]) x})] -> cAcosh [x] +#cAdd {(cPow [(cAdd {(cPow [x 2]) -1}) 0.5]) x} -> cPow [CONSTANT_E (cAcosh [x])] + +# atanh(x): log( (1+x) / (1-x)) / 2 +# 2*atanh(x): log( (1+x) / (1-x)) +@F cLog [(cMul {(cAdd {1 x}) (cPow [(cAdd {1 (cMul {-1 x})}) -1])})] -> cMul [(cAtanh [x]) 2] + +# atanh(y*x): log( (1+y*x) / (1+(-1*y*x))) / 2 +# 2*atanh(y*x): log( (1+y*x) / (1+(-1*y*x))) + +# atanh(5*x): log( (1+5*x) / (1+(-5*x))) / 2 +# 2*atanh(5*x): log( (1+5*x) / (1+(-5*x))) + +# atanh(y+x): log( (1+y+x) / (1+(-1*(y+x)))) / 2 +# 2*atanh(y+x): log( (1+y+x) / (1+(-1*(y+x)))) + +#@F cLog [(cMul {(cAdd {1 (cMul {% x})}) (cPow [(cAdd {1 (cMul {-% x})}) -1])})] -> cMul [(cAtanh [(cMul % x)]) 2] + +# atanh(x) = log2( ((x*-2)+1) / ((x*2)-1) ) * log(2)/2 +# atanh(x)*2/log(2) = log2( ((x*-2)+1) / ((x*2)-1) ) +# y^(atanh(x)*2/log(y)) = ((x*-y)+1) / ((x*y)-1) + +#@F cMul (cAdd {1 (cMul {x %})}) (cPow [(cAdd {-1 (cMul {x -%})}) -1]) : (cPow [% (cMul (cAtanh[x]) 2 /LOG(%))]) +#@F cMul (cPow [(cAdd {(cMul {x %}) &}) -1]) (cAdd {(cMul {x -%}) 2 -&}) : (cPow [-% (cMul (cAtanh[(cAdd (cMul -% x) & -1)]) 2 /LOG(-%))]) + + + +[REGENERATE_HIGHLEVEL_OPCODES] + +# x * CONSTANT_RD = cDeg(x) +@F cMul CONSTANT_RD <1> -> cDeg [(cMul <1>)] + +# x * CONSTANT_DR = cRad(x) +@F cMul CONSTANT_DR <1> -> cRad [(cMul <1>)] + +@F cFloor [(cAdd 0.5 <1>)] -> cInt [(cAdd <1>)] + +# log(x) / CONSTANT_L10 = log10(x) +@F cMul (cLog [x]) CONSTANT_L10I : (cLog10 [x]) +@F cMul (cPow [(cLog [x]) -1]) CONSTANT_L10 : (cPow [(cLog10 [x]) -1]) + +# log(x) / CONSTANT_L2 = log2(x) +@F cMul (cLog [x]) CONSTANT_L2I : (cLog2 [x]) +@F cMul (cPow [(cLog [x]) -1]) CONSTANT_L2 : (cPow [(cLog2 [x]) -1]) + +#@F cPow [ (cSin[x]) %@N ] : (cCsc[x]) -% +#@F cPow [ (cCos[x]) %@N ] : (cSec[x]) -% +#@F cPow [ (cTan[x]) %@N ] : (cCot[x]) -% +# ^ DONE BY MAKEBYTECODE + +@F cPow [ (cAdd [( cPow [x %@E] ) ( cPow [y &@E] )] ) 0.5 ] -> (cHypot [(cPow [ x *(% 0.5)]) (cPow [ y *(& 0.5)])]) +@F cPow [ (cAdd {( cPow [x %@E] ) (cMul {z@C (cPow [y &@E])})} ) 0.5 ] -> (cHypot [(cPow [ x *(% 0.5)]) (cPow [(cMul y POW(z@C /&)) *(& 0.5)])]) +@F cPow [ (cAdd {(cMul {a@C (cPow [x %@E])}) (cMul {z@C (cPow [y &@E])})} ) 0.5 ] -> (cHypot [(cPow [(cMul x POW(a@C /%)) *(% 0.5)]) (cPow [(cMul y POW(z@C /&)) *(& 0.5)])]) + +@F cMul (cExp[x]) (cExp[y]) : (cExp[(cAdd x y)]) # TEST 20/expexp_a 20/expexp_b 20/expexp_c +@F cMul (cExp2[x]) (cExp2[y]) : (cExp2[(cAdd x y)]) # TEST 20/expexp_a 20/expexp_b 20/expexp_c + +[ABS_LOGICAL] + +@R cNot [x@P] -> cAbsNot [x] # TEST 20/posnot +@R cNotNot [x@P] -> cAbsNotNot [x] # TEST 20/posnotnot +@R cAnd x@P y@P : (cAbsAnd x y) +@R cOr x@P y@P : (cAbsOr x y) +@R cIf [x@P y z] -> cAbsIf x y z + +#@R @L cAbsNotNot [x] -> x +#@R @L cIf [x (cAbsNotNot[y]) z] : x y z +#@R @L cIf [x y (cAbsNotNot[z])] : x y z +# ^ These are mistakes; (x>=0.5 & y) is not same as (x & y) + +@R cAbsIf [(cLessOrEq[x y]) z a] : (cLess[y x]) a z +@R cAbsIf [(cNotNot[x]) y z] -> cIf x y z + +@R @F cLess [x 0.5] -> cAbsNot[x] # TEST 20/lthalf +@R @F cGreaterOrEq [x 0.5] -> cAbsNotNot[x] # TEST 20/gehalf + +[NON_SHORTCUT_LOGICAL_EVALUATION] + +@R cOr x@L y@L : (cNotNot (cAdd x y)) +@R cOr x@L (cAdd <1>)@P : (cNotNot (cAdd x <1>)) +@R cAnd x@L <1> -> (cNotNot (cMul x (cAnd <1>))) +# ^Conflicts with "cMul x@L y@L" + +[SHORTCUT_LOGICAL_EVALUATION] + +@R cMul x@L y@L : (cAnd x y) # TEST 20/muland2, muland2plus, muland3, mulnor2, mulnor2plus, mulnor3, mulandlt +# ^Conflicts with "cAnd x@L <1>" + +# @L cAdd x@L@M <1> -> cOr x (cAdd <1>) +# cMul x@L <1> -> cAnd x (cMul <1>) + +#cAdd x@L@M <1> -> cAbsIf [x (cAdd <1> 1) (cAdd <1>)] +@R cMul x@L <1> -> cAbsIf [x (cMul <1>) 0] + +cAnd x <1> -> cIf [x (cNotNot[(cAnd <1>)]) 0] +cOr x <1> -> cIf [x 1 (cNotNot[(cOr <1>)]) ] +cAbsAnd x <1> -> cAbsIf [x (cNotNot[(cAbsAnd <1>)]) 0] +cAbsOr x <1> -> cAbsIf [x 1 (cNotNot[(cAbsOr <1>)]) ] + +[IGNORE_IF_SIDEEFFECTS] + +# These rules are the polar opposite of what +# is done in SHORTCUT_LOGICAL_EVALUATION. +# Do not include them in the same optimization set. + +cIf [x y@L 0] -> cAnd x y +cIf [x 0 y@L] -> cAnd (cNot[x]) y +cIf [x y 0] -> cMul (cNotNot[x]) y +cIf [x 0 y] -> cMul (cNot[x]) y + +cIf [x 1 y@L] -> cOr x y +cIf [x y@L 1] -> cOr (cNot[x]) y +cIf [x y 0] -> cMul (cNotNot[x]) y +cIf [x 0 y] -> cMul (cNot[x]) y + +# These cannot be done because y may have side +# effects or just be computation-heavy. + +[BASE2_EXPAND_COMPONENTS] + +#@F cLog [x] -> cMul (cLog2[x]) CONSTANT_L2 +#@F cLog10 [x] -> cMul (cLog2[x]) CONSTANT_L10B +#@F cExp [x] -> cExp2 [(cMul CONSTANT_L2I x)] +#@F cMul (cLog2by [x y]) <1> -> cLog2by [x (cMul y <1>)] +@F cAsin [x] -> cAtan2 x (cSqrt (cSub 1 (cSqr x))) +@F cAcos [x] -> cAtan2 (cSqrt (cSub 1 (cSqr x))) x +@F cSinh [x] -> cMul 0.5 (cSub (cExp[x]) (cInv (cExp[x]))) +@F cCosh [x] -> cMul 0.5 (cSub (cExp[x]) (cInv (cExp[x]))) +@F cTanh [x] -> cDiv (cAdd (cExp [(cMul x 2)]) -1) (cAdd (cExp [(cMul x 2)]) 1) +@F cAtanh [x] -> cMul 0.5 (cLog (cDiv (cAdd 1 x) (cSub 1 x))) +@F cAsinh [x] -> cLog (cAdd x (cSqrt (cAdd 1 (cSqr x)))) +@F cAcosh [x] -> cLog (cAdd x (cSqrt (cAdd -1 (cSqr x)))) + +#@F cLog2 [x] -> cLog2by x 1 +#@F cMul (cPow[(cLog2[x]) %]) & : (cPow[(cLog2by[x POW(& /%)]) %]) +@F cMul (cPow[(cLog2by[x 1]) %]) & : (cPow[(cLog2by[x POW(& /%)]) %]) + +##### Now construct the rounds of optimization: + +$optimize_round1: +LOGICAL +REMOVE_REDUNDANT +LOGARITHM +POW_TRICKS +BINOMIAL +TRIGONOMETRIC +EXTRACT1 + +$optimize_round2: +LOGICAL +REMOVE_REDUNDANT +POW_TRICKS +SINH_COSH_EXP_TRANSFORMATIONS +ASINH_ACOSH_ATANH_TRANSFORMATIONS + +$optimize_round3: +SIMPLIFY_EQUATION +REGENERATE_TAN +REGENERATE_TANH + +$optimize_round4: +REGENERATE_HIGHLEVEL_OPCODES + +$optimize_recreate: +REGENERATE_HIGHLEVEL_OPCODES +BINOMIAL + +$optimize_ignore_if_sideeffects +IGNORE_IF_SIDEEFFECTS +LOGICAL + +$optimize_shortcut_logical_evaluation +#SHORTCUT_LOGICAL_EVALUATION +LOGICAL + +$optimize_nonshortcut_logical_evaluation +NON_SHORTCUT_LOGICAL_EVALUATION +LOGICAL + +$optimize_abslogical +ABS_LOGICAL + +#$optimize_base2_expand +#BASE2_EXPAND_COMPONENTS +#BINOMIAL +#POW_TRICKS diff --git a/fpoptimizer/valuerange.cc b/fpoptimizer/valuerange.cc new file mode 100644 index 0000000..b0a6804 --- /dev/null +++ b/fpoptimizer/valuerange.cc @@ -0,0 +1,94 @@ +#include "valuerange.hh" + +#ifdef FP_SUPPORT_OPTIMIZER + +namespace FPoptimizer_CodeTree +{ + template<typename Value_t> + void range<Value_t>::set_abs() + { + using namespace FUNCTIONPARSERTYPES; + bool has_negative = !min.known || min.val < Value_t(); + bool has_positive = !max.known || max.val > Value_t(); + bool crosses_axis = has_negative && has_positive; + + rangehalf<Value_t> newmax; // ..+inf + if(min.known && max.known) // ..N + newmax.set( fp_max(fp_abs(min.val), fp_abs(max.val)) ); + + if(crosses_axis) + min.set( Value_t() ); // 0.. + else + { + // Does not cross axis, so choose the smallest of known values + // (Either value is known; otherwise it would cross axis) + if(min.known && max.known) // N.. + min.set( fp_min(fp_abs(min.val), fp_abs(max.val)) ); + else if(min.known) + min.set( fp_abs(min.val) ); + else //if(max.known) + min.set( fp_abs(max.val) ); + } + max = newmax; + } + + template<typename Value_t> + void range<Value_t>::set_neg() + { + std::swap(min, max); + min.val = -min.val; + max.val = -max.val; + } + + template<typename Value_t> + bool IsLogicalTrueValue(const range<Value_t>& p, bool abs) + { + if(FUNCTIONPARSERTYPES::IsIntType<Value_t>::result) + { + if(p.min.known && p.min.val >= Value_t(1)) return true; + if(!abs && p.max.known && p.max.val <= Value_t(-1)) return true; + } + else + { + if(p.min.known && p.min.val >= Value_t(0.5)) return true; + if(!abs && p.max.known && p.max.val <= Value_t(-0.5)) return true; + } + return false; + } + + template<typename Value_t> + bool IsLogicalFalseValue(const range<Value_t>& p, bool abs) + { + if(FUNCTIONPARSERTYPES::IsIntType<Value_t>::result) + { + if(abs) + return p.max.known && p.max.val < Value_t(1); + else + return p.min.known && p.max.known + && p.min.val > Value_t(-1) && p.max.val < Value_t(1); + } + else + { + if(abs) + return p.max.known && p.max.val < Value_t(0.5); + else + return p.min.known && p.max.known + && p.min.val > Value_t(-0.5) && p.max.val < Value_t(0.5); + } + } +} + +/* BEGIN_EXPLICIT_INSTANTATION */ +#include "instantiate.hh" +namespace FPoptimizer_CodeTree +{ +#define FP_INSTANTIATE(type) \ + template struct range<type>; \ + template bool IsLogicalTrueValue(const range<type> &, bool); \ + template bool IsLogicalFalseValue(const range<type> &, bool); + FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE) +#undef FP_INSTANTIATE +} +/* END_EXPLICIT_INSTANTATION */ + +#endif diff --git a/fpoptimizer/valuerange.hh b/fpoptimizer/valuerange.hh new file mode 100644 index 0000000..f2d0ab4 --- /dev/null +++ b/fpoptimizer/valuerange.hh @@ -0,0 +1,142 @@ +#ifndef FPOptimizer_ValueRangeHH +#define FPOptimizer_ValueRangeHH + +#include "fparser.hh" +#include "extrasrc/fpaux.hh" + +namespace FPoptimizer_CodeTree +{ + namespace rangeutil + { + template<unsigned Compare> struct Comp { }; + template<>struct Comp<FUNCTIONPARSERTYPES::cLess> { + template<typename Value_t> + inline bool operator() (const Value_t& a, const Value_t& b) { return a<b; } + }; + template<>struct Comp<FUNCTIONPARSERTYPES::cLessOrEq> { + template<typename Value_t> + inline bool operator() (const Value_t& a, const Value_t& b) { return a<=b; } + }; + template<>struct Comp<FUNCTIONPARSERTYPES::cGreater> { + template<typename Value_t> + inline bool operator() (const Value_t& a, const Value_t& b) { return a>b; } + }; + template<>struct Comp<FUNCTIONPARSERTYPES::cGreaterOrEq> { + template<typename Value_t> + inline bool operator() (const Value_t& a, const Value_t& b) { return a>=b; } + }; + template<>struct Comp<FUNCTIONPARSERTYPES::cEqual> { + template<typename Value_t> + inline bool operator() (const Value_t& a, const Value_t& b) { return a==b; } + }; + template<>struct Comp<FUNCTIONPARSERTYPES::cNEqual> { + template<typename Value_t> + inline bool operator() (const Value_t& a, const Value_t& b) { return a!=b; } + }; + } + + template<typename Value_t> + struct rangehalf + { + Value_t val; + bool known; + + rangehalf(): val(), known(false) { } + rangehalf(const Value_t& v) : val(v), known(true) { } + + inline void set(const Value_t& v) { known=true; val=v; } + + ///////// + + /* If value is known, refine it using func. + * Otherwise, use the model. + * + * Call like this: + * range := param + * range.min.set(fp_floor) + * If param is known, sets minimum to floor(param.min) + * Otherwise, sets min to unknown + * Or: + * range := param + * range.min.set(fp_atan, -pihalf) + * If param is known, sets minimum to floor(param.min) + * Otherwise, sets min to -pihalf + */ + void set + (Value_t (*const func)(Value_t), + rangehalf<Value_t> model = rangehalf<Value_t>()) + { + if(known) val = func(val); else *this = model; + } + + void set + (Value_t (*const func)(const Value_t&), + rangehalf<Value_t> model = rangehalf<Value_t>()) + { + if(known) val = func(val); else *this = model; + } + + /* Call like this: + * range := param + * range.min.set_if<cGreater>(-1, fp_asin, -pihalf) + * If param is known AND param.min > -1, sets minimum to asin(param.min) + * Otherwise, sets min to -pihalf + * The purpose of the condition is to ensure that the function + * is not being called with illegal values. + */ + template<unsigned Compare> + void set_if + (Value_t v, + Value_t (*const func)(Value_t), + rangehalf<Value_t> model = rangehalf<Value_t>()) + { + if(known && rangeutil::Comp<Compare>() (val,v)) + val = func(val); + else + *this = model; + } + template<unsigned Compare> + void set_if + (const Value_t& v, + Value_t (*const func)(const Value_t&), + rangehalf<Value_t> model = rangehalf<Value_t>()) + { + if(known && rangeutil::Comp<Compare>() (val,v)) + val = func(val); + else + *this = model; + } + }; + + /* range expresses the range of values that an expression can take. */ + template<typename Value_t> + struct range + { + rangehalf<Value_t> min, max; + + /* Initializations */ + range() : min(),max() { } + range(Value_t mi,Value_t ma): min(mi),max(ma) { } + range(bool,Value_t ma): min(),max(ma) { } + range(Value_t mi,bool): min(mi),max() { } + + /* Apply the abs() function to the range, + * i.e. +3..+5 becomes +3..+5; + * -3..+5 becomes 0..+5; + * -3..-1 becomes 0..+1 + */ + void set_abs(); + + /* Negate the range, i.e. -3..+5 becomes -5..+3 */ + void set_neg(); + }; + + /* Analysis functions for a range */ + template<typename Value_t> + bool IsLogicalTrueValue(const range<Value_t>& p, bool abs); + + template<typename Value_t> + bool IsLogicalFalseValue(const range<Value_t>& p, bool abs); +} + +#endif diff --git a/lib/autoptr.hh b/lib/autoptr.hh new file mode 100644 index 0000000..98004e4 --- /dev/null +++ b/lib/autoptr.hh @@ -0,0 +1,66 @@ +#ifndef FPOptimizerAutoPtrHH +#define FPOptimizerAutoPtrHH + +template<typename Ref> +class FPOPT_autoptr +{ +public: + FPOPT_autoptr() : p(0) { } + FPOPT_autoptr(Ref* b) : p(b) { Birth(); } + FPOPT_autoptr(const FPOPT_autoptr& b) : p(b.p) { Birth(); } + + inline Ref& operator* () const { return *p; } + inline Ref* operator->() const { return p; } + bool isnull() const { return !p; } + Ref* get() const { return p; } + + FPOPT_autoptr& operator= (Ref* b) { Set(b); return *this; } + FPOPT_autoptr& operator= (const FPOPT_autoptr& b) { Set(b.p); return *this; } +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + FPOPT_autoptr(FPOPT_autoptr&& b) : p(b.p) { b.p = 0; } + FPOPT_autoptr& operator= (FPOPT_autoptr&& b) { if(p != b.p) { Forget(); p=b.p; b.p=0; } + return *this; } +#endif + + ~FPOPT_autoptr() { Forget(); } + + void UnsafeSetP(Ref* newp) { p = newp; } + void swap(FPOPT_autoptr<Ref>& b) { Ref* tmp=p; p=b.p; b.p=tmp; } + +private: + inline static void Have(Ref* p2); + inline void Forget(); + inline void Birth(); + inline void Set(Ref* p2); +private: + Ref* p; +}; + +// +template<typename Ref> +inline void FPOPT_autoptr<Ref>::Forget() +{ + if(!p) return; + p->RefCount -= 1; + if(!p->RefCount) delete p; + //assert(p->RefCount >= 0); +} +template<typename Ref> +inline void FPOPT_autoptr<Ref>::Have(Ref* p2) +{ + if(p2) ++(p2->RefCount); +} +template<typename Ref> +inline void FPOPT_autoptr<Ref>::Birth() +{ + Have(p); +} +template<typename Ref> +inline void FPOPT_autoptr<Ref>::Set(Ref* p2) +{ + Have(p2); + Forget(); + p = p2; +} + +#endif diff --git a/lib/crc32.hh b/lib/crc32.hh new file mode 100644 index 0000000..c24c80b --- /dev/null +++ b/lib/crc32.hh @@ -0,0 +1,56 @@ +/* crc32 */ + +#ifdef _MSC_VER + + typedef unsigned int crc32_t; + +#else + + #include <stdint.h> + typedef uint_least32_t crc32_t; + +#endif + +namespace crc32 +{ + enum { startvalue = 0xFFFFFFFFUL, poly = 0xEDB88320UL }; + + /* This code constructs the CRC32 table at compile-time, + * avoiding the need for a huge explicitly written table of magical numbers. */ + template<crc32_t crc> // One byte of a CRC32 (eight bits): + struct b8 + { + enum { b1 = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1), + b2 = (b1 & 1) ? (poly ^ (b1 >> 1)) : (b1 >> 1), + b3 = (b2 & 1) ? (poly ^ (b2 >> 1)) : (b2 >> 1), + b4 = (b3 & 1) ? (poly ^ (b3 >> 1)) : (b3 >> 1), + b5 = (b4 & 1) ? (poly ^ (b4 >> 1)) : (b4 >> 1), + b6 = (b5 & 1) ? (poly ^ (b5 >> 1)) : (b5 >> 1), + b7 = (b6 & 1) ? (poly ^ (b6 >> 1)) : (b6 >> 1), + res= (b7 & 1) ? (poly ^ (b7 >> 1)) : (b7 >> 1) }; + }; + inline crc32_t update(crc32_t crc, unsigned/* char */b) // __attribute__((pure)) + { + // Four values of the table + #define B4(n) b8<n>::res,b8<n+1>::res,b8<n+2>::res,b8<n+3>::res + // Sixteen values of the table + #define R(n) B4(n),B4(n+4),B4(n+8),B4(n+12) + // The whole table, index by steps of 16 + static const crc32_t 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) /* & 0x00FFFFFF*/) ^ table[/*(unsigned char)*/(crc^b)&0xFF]; + } + inline crc32_t calc_upd(crc32_t c, const unsigned char* buf, size_t size) + { + crc32_t value = c; + for(size_t p=0; p<size; ++p) value = update(value, buf[p]); + return value; + } + inline crc32_t calc(const unsigned char* buf, size_t size) + { + return calc_upd(startvalue, buf, size); + } +} diff --git a/lib/functional.hh b/lib/functional.hh new file mode 100644 index 0000000..3f4da4c --- /dev/null +++ b/lib/functional.hh @@ -0,0 +1,32 @@ +#include <utility> + +struct Compare2ndRev +{ + template<typename T> + inline bool operator() (const T& a, const T& b) const + { + return a.second > b.second; + } +}; + +struct Compare1st +{ + template<typename T1, typename T2> + inline bool operator() (const std::pair<T1,T2>& a, + const std::pair<T1,T2>& b) const + { + return a.first < b.first; + } + + template<typename T1, typename T2> + inline bool operator() (const std::pair<T1,T2>& a, T1 b) const + { + return a.first < b; + } + + template<typename T1, typename T2> + inline bool operator() (T1 a, const std::pair<T1,T2>& b) const + { + return a < b.first; + } +}; diff --git a/mpfr/GmpInt.cc b/mpfr/GmpInt.cc new file mode 100644 index 0000000..490add4 --- /dev/null +++ b/mpfr/GmpInt.cc @@ -0,0 +1,710 @@ +#include "GmpInt.hh" +#include <gmp.h> +#include <deque> +#include <vector> +#include <cstring> +#include <cctype> + +//=========================================================================== +// Shared data +//=========================================================================== +namespace +{ + unsigned long gIntDefaultNumberOfBits = 256; + + std::vector<char>& intString() + { + static std::vector<char> str; + return str; + } +} + +//=========================================================================== +// Auxiliary structs +//=========================================================================== +struct GmpInt::GmpIntData +{ + unsigned mRefCount; + GmpIntData* nextFreeNode; + mpz_t mInteger; + + GmpIntData(): mRefCount(1), nextFreeNode(0) {} +}; + +class GmpInt::GmpIntDataContainer +{ + std::deque<GmpInt::GmpIntData> mData; + GmpInt::GmpIntData* mFirstFreeNode; + GmpInt::GmpIntData* mConst_0; + + public: + GmpIntDataContainer(): mFirstFreeNode(0), mConst_0(0) {} + + ~GmpIntDataContainer() + { + for(size_t i = 0; i < mData.size(); ++i) + mpz_clear(mData[i].mInteger); + } + + GmpInt::GmpIntData* allocateGmpIntData(unsigned long numberOfBits, + bool initToZero) + { + if(mFirstFreeNode) + { + GmpInt::GmpIntData* node = mFirstFreeNode; + mFirstFreeNode = node->nextFreeNode; + if(initToZero) mpz_set_si(node->mInteger, 0); + ++(node->mRefCount); + return node; + } + + mData.push_back(GmpInt::GmpIntData()); + if(numberOfBits > 0) + mpz_init2(mData.back().mInteger, numberOfBits); + else + mpz_init(mData.back().mInteger); + return &mData.back(); + } + + void releaseGmpIntData(GmpIntData* data) + { + if(--(data->mRefCount) == 0) + { + data->nextFreeNode = mFirstFreeNode; + mFirstFreeNode = data; + } + } + + GmpInt::GmpIntData* const_0() + { + if(!mConst_0) + mConst_0 = allocateGmpIntData(gIntDefaultNumberOfBits, true); + return mConst_0; + } +}; + + +GmpInt::GmpIntDataContainer& GmpInt::gmpIntDataContainer() +{ + static GmpIntDataContainer container; + return container; +} + +//=========================================================================== +// Auxiliary functions +//=========================================================================== +void GmpInt::setDefaultNumberOfBits(unsigned long value) +{ + gIntDefaultNumberOfBits = value; +} + +unsigned long GmpInt::getDefaultNumberOfBits() +{ + return gIntDefaultNumberOfBits; +} + +inline void GmpInt::copyIfShared() +{ + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + GmpIntData* oldData = mData; + mData = gmpIntDataContainer().allocateGmpIntData(0, false); + mpz_set(mData->mInteger, oldData->mInteger); + } +} + + +//=========================================================================== +// Constructors, destructor, assignment +//=========================================================================== +GmpInt::GmpInt(DummyType): + mData(gmpIntDataContainer().allocateGmpIntData(0, false)) +{} + +GmpInt::GmpInt() +{ + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); +} + +GmpInt::GmpInt(long value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_si(mData->mInteger, value); + } +} + +GmpInt::GmpInt(unsigned long value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_ui(mData->mInteger, value); + } +} + +GmpInt::GmpInt(int value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_si(mData->mInteger, value); + } +} + +GmpInt::GmpInt(double value) +{ + const double absValue = value >= 0.0 ? value : -value; + if(absValue < 1.0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_d(mData->mInteger, value); + } +} + +GmpInt::GmpInt(long double value) +{ + const long double absValue = value >= 0.0L ? value : -value; + if(absValue < 1.0L) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_d(mData->mInteger, double(value)); + } +} + +GmpInt::GmpInt(const GmpInt& rhs): + mData(rhs.mData) +{ + ++(mData->mRefCount); +} + +GmpInt& GmpInt::operator=(const GmpInt& rhs) +{ + if(mData != rhs.mData) + { + gmpIntDataContainer().releaseGmpIntData(mData); + mData = rhs.mData; + ++(mData->mRefCount); + } + return *this; +} + +GmpInt& GmpInt::operator=(signed long value) +{ + if(value == 0) + { + gmpIntDataContainer().releaseGmpIntData(mData); + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + } + mpz_set_si(mData->mInteger, value); + } + return *this; +} + +GmpInt::~GmpInt() +{ + gmpIntDataContainer().releaseGmpIntData(mData); +} + + +//=========================================================================== +// Data getters +//=========================================================================== +template<> +void GmpInt::get_raw_mpfr_data<mpz_t>(mpz_t& dest_mpz_t) +{ + std::memcpy(&dest_mpz_t, mData->mInteger, sizeof(mpz_t)); +} + +const char* GmpInt::getAsString(int base) const +{ + intString().resize(mpz_sizeinbase(mData->mInteger, base) + 2); + return mpz_get_str(&intString()[0], base, mData->mInteger); +} + +long GmpInt::toInt() const +{ + return mpz_get_si(mData->mInteger); +} + + +//=========================================================================== +// Modifying operators +//=========================================================================== +GmpInt& GmpInt::operator+=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_add(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator+=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_add_ui(mData->mInteger, mData->mInteger, value); + else + mpz_sub_ui(mData->mInteger, mData->mInteger, -value); + return *this; +} + +GmpInt& GmpInt::operator-=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_sub(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator-=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_sub_ui(mData->mInteger, mData->mInteger, value); + else + mpz_add_ui(mData->mInteger, mData->mInteger, -value); + return *this; +} + +GmpInt& GmpInt::operator*=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_mul(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator*=(long value) +{ + copyIfShared(); + mpz_mul_si(mData->mInteger, mData->mInteger, value); + return *this; +} + +GmpInt& GmpInt::operator/=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_tdiv_q(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator/=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, value); + else + { + mpz_neg(mData->mInteger, mData->mInteger); + mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, -value); + } + return *this; +} + +GmpInt& GmpInt::operator%=(const GmpInt& rhs) +{ + copyIfShared(); + if(operator<(0)) + { + negate(); + mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + negate(); + } + else + { + mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + } + return *this; +} + +GmpInt& GmpInt::operator%=(long value) +{ + copyIfShared(); + if(value < 0) value = -value; + if(operator<(0)) + { + negate(); + mpz_mod_ui(mData->mInteger, mData->mInteger, value); + negate(); + } + else + { + mpz_mod_ui(mData->mInteger, mData->mInteger, value); + } + return *this; +} + +GmpInt& GmpInt::operator<<=(unsigned long bits) +{ + copyIfShared(); + mpz_mul_2exp(mData->mInteger, mData->mInteger, bits); + return *this; +} + +GmpInt& GmpInt::operator>>=(unsigned long bits) +{ + copyIfShared(); + mpz_tdiv_q_2exp(mData->mInteger, mData->mInteger, bits); + return *this; +} + + +//=========================================================================== +// Modifying functions +//=========================================================================== +void GmpInt::addProduct(const GmpInt& value1, const GmpInt& value2) +{ + copyIfShared(); + mpz_addmul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger); +} + +void GmpInt::addProduct(const GmpInt& value1, unsigned long value2) +{ + copyIfShared(); + mpz_addmul_ui(mData->mInteger, value1.mData->mInteger, value2); +} + +void GmpInt::subProduct(const GmpInt& value1, const GmpInt& value2) +{ + copyIfShared(); + mpz_submul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger); +} + +void GmpInt::subProduct(const GmpInt& value1, unsigned long value2) +{ + copyIfShared(); + mpz_submul_ui(mData->mInteger, value1.mData->mInteger, value2); +} + +void GmpInt::negate() +{ + copyIfShared(); + mpz_neg(mData->mInteger, mData->mInteger); +} + +void GmpInt::abs() +{ + copyIfShared(); + mpz_abs(mData->mInteger, mData->mInteger); +} + +GmpInt GmpInt::abs(const GmpInt& value) +{ + GmpInt retval(kNoInitialization); + mpz_abs(retval.mData->mInteger, value.mData->mInteger); + return retval; +} + + +//=========================================================================== +// Non-modifying operators +//=========================================================================== +GmpInt GmpInt::operator+(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_add(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator+(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_add_ui(retval.mData->mInteger, mData->mInteger, value); + else + mpz_sub_ui(retval.mData->mInteger, mData->mInteger, -value); + return retval; +} + +GmpInt GmpInt::operator-(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_sub(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator-(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_sub_ui(retval.mData->mInteger, mData->mInteger, value); + else + mpz_add_ui(retval.mData->mInteger, mData->mInteger, -value); + return retval; +} + +GmpInt GmpInt::operator*(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_mul(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator*(long value) const +{ + GmpInt retval(kNoInitialization); + mpz_mul_si(retval.mData->mInteger, mData->mInteger, value); + return retval; +} + +GmpInt GmpInt::operator/(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_tdiv_q(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator/(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_tdiv_q_ui(retval.mData->mInteger, mData->mInteger, value); + else + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_tdiv_q_ui(retval.mData->mInteger, retval.mData->mInteger, -value); + } + return retval; +} + +GmpInt GmpInt::operator%(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + if(operator<(0)) + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_mod(retval.mData->mInteger, + retval.mData->mInteger, rhs.mData->mInteger); + retval.negate(); + } + else + { + mpz_mod(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + } + return retval; +} + +GmpInt GmpInt::operator%(long value) const +{ + GmpInt retval(kNoInitialization); + if(value < 0) value = -value; + if(operator<(0)) + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_mod_ui(retval.mData->mInteger, retval.mData->mInteger, value); + retval.negate(); + } + else + { + mpz_mod_ui(retval.mData->mInteger, mData->mInteger, value); + } + return retval; +} + +GmpInt GmpInt::operator-() const +{ + GmpInt retval(kNoInitialization); + mpz_neg(retval.mData->mInteger, mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator<<(unsigned long bits) const +{ + GmpInt retval(kNoInitialization); + mpz_mul_2exp(retval.mData->mInteger, mData->mInteger, bits); + return retval; +} + +GmpInt GmpInt::operator>>(unsigned long bits) const +{ + GmpInt retval(kNoInitialization); + mpz_tdiv_q_2exp(retval.mData->mInteger, mData->mInteger, bits); + return retval; +} + + +//=========================================================================== +// Comparison operators +//=========================================================================== +bool GmpInt::operator<(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) < 0; +} + +bool GmpInt::operator<(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) < 0; +} + +bool GmpInt::operator<=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) <= 0; +} + +bool GmpInt::operator<=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) <= 0; +} + +bool GmpInt::operator>(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) > 0; +} + +bool GmpInt::operator>(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) > 0; +} + +bool GmpInt::operator>=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) >= 0; +} + +bool GmpInt::operator>=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) >= 0; +} + +bool GmpInt::operator==(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) == 0; +} + +bool GmpInt::operator==(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) == 0; +} + +bool GmpInt::operator!=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) != 0; +} + +bool GmpInt::operator!=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) != 0; +} + +void GmpInt::parseValue(const char* value) +{ + mpz_set_str(mData->mInteger, value, 10); +} + +void GmpInt::parseValue(const char* value, char** endptr) +{ + static std::vector<char> str; + + unsigned startIndex = 0; + while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex; + if(!value[startIndex]) { *endptr = const_cast<char*>(value); return; } + + unsigned endIndex = startIndex; + if(value[endIndex] == '-') ++endIndex; + if(!std::isdigit(value[endIndex])) + { *endptr = const_cast<char*>(value); return; } + if(value[endIndex] == '0' && value[endIndex+1] == 'x') + { + endIndex += 1; + while(std::isxdigit(value[++endIndex])) {} + } + else + { + while(std::isdigit(value[++endIndex])) {} + } + + str.reserve(endIndex - startIndex + 1); + str.assign(value + startIndex, value + endIndex); + str.push_back(0); + + mpz_set_str(mData->mInteger, &str[0], 0); + *endptr = const_cast<char*>(value + endIndex); +} + +GmpInt GmpInt::parseString(const char* str, char** endptr) +{ + GmpInt retval(kNoInitialization); + retval.parseValue(str, endptr); + return retval; +} + +//=========================================================================== +// Operator functions +//=========================================================================== +GmpInt operator+(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs); + else + mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + return retval; +} + +GmpInt operator-(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger); + else + { + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + mpz_neg(retval.mData->mInteger, retval.mData->mInteger); + } + return retval; +} + +GmpInt operator*(long lhs, const GmpInt& rhs) +{ + return rhs * lhs; +} + +GmpInt operator/(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) / rhs; +} + +GmpInt operator%(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) % rhs; +} diff --git a/mpfr/GmpInt.hh b/mpfr/GmpInt.hh new file mode 100644 index 0000000..1c1c171 --- /dev/null +++ b/mpfr/GmpInt.hh @@ -0,0 +1,148 @@ +#ifndef ONCE_FP_GMP_INT_HH_ +#define ONCE_FP_GMP_INT_HH_ + +#include <iostream> + +class GmpInt +{ + public: + /* A default of 256 bits will be used for all newly-instantiated GmpInt + objects. This default can be changed with the function below. + */ + static void setDefaultNumberOfBits(unsigned long); + static unsigned long getDefaultNumberOfBits(); + + GmpInt(); + GmpInt(long value); + GmpInt(unsigned long value); + GmpInt(int value); + GmpInt(double value); + GmpInt(long double value); + + GmpInt(const GmpInt&); + GmpInt& operator=(const GmpInt&); + GmpInt& operator=(signed long value); + + ~GmpInt(); + + + /* This function can be used to retrieve the raw mpz_t data structure + used by this object. (The template trick is used to avoid a dependency + of this header file with <gmp.h>.) + In other words, it can be called like: + + mpz_t raw_mpz_data; + intValue.get_raw_mpz_data(raw_mpz_data); + + Note that the returned mpz_t should be considered as read-only and + not be modified from the outside because it may be shared among + several objects. If the calling code needs to modify the data, it + should copy it for itself first with the appropriate GMP library + functions. + */ + template<typename Mpz_t> + void get_raw_mpfr_data(Mpz_t& dest_mpz_t); + + + // Note that the returned char* points to an internal (shared) buffer + // which will be valid until the next time this function is called + // (by any object). + const char* getAsString(int base = 10) const; + long toInt() const; + + GmpInt& operator+=(const GmpInt&); + GmpInt& operator+=(long); + GmpInt& operator-=(const GmpInt&); + GmpInt& operator-=(long); + GmpInt& operator*=(const GmpInt&); + GmpInt& operator*=(long); + GmpInt& operator/=(const GmpInt&); + GmpInt& operator/=(long); + GmpInt& operator%=(const GmpInt&); + GmpInt& operator%=(long); + + GmpInt& operator<<=(unsigned long); + GmpInt& operator>>=(unsigned long); + + // Equivalent to "+= value1 * value2;" + void addProduct(const GmpInt& value1, const GmpInt& value2); + void addProduct(const GmpInt& value1, unsigned long value2); + + // Equivalent to "-= value1 * value2;" + void subProduct(const GmpInt& value1, const GmpInt& value2); + void subProduct(const GmpInt& value1, unsigned long value2); + + void negate(); + void abs(); + static GmpInt abs(const GmpInt&); + + GmpInt operator+(const GmpInt&) const; + GmpInt operator+(long) const; + GmpInt operator-(const GmpInt&) const; + GmpInt operator-(long) const; + GmpInt operator*(const GmpInt&) const; + GmpInt operator*(long) const; + GmpInt operator/(const GmpInt&) const; + GmpInt operator/(long) const; + GmpInt operator%(const GmpInt&) const; + GmpInt operator%(long) const; + + GmpInt operator-() const; + + GmpInt operator<<(unsigned long) const; + GmpInt operator>>(unsigned long) const; + + bool operator<(const GmpInt&) const; + bool operator<(long) const; + bool operator<=(const GmpInt&) const; + bool operator<=(long) const; + bool operator>(const GmpInt&) const; + bool operator>(long) const; + bool operator>=(const GmpInt&) const; + bool operator>=(long) const; + bool operator==(const GmpInt&) const; + bool operator==(long) const; + bool operator!=(const GmpInt&) const; + bool operator!=(long) const; + + void parseValue(const char* value); + void parseValue(const char* value, char** endptr); + static GmpInt parseString(const char* str, char** endptr); + + + private: + struct GmpIntData; + class GmpIntDataContainer; + + GmpIntData* mData; + + enum DummyType { kNoInitialization }; + GmpInt(DummyType); + + void copyIfShared(); + static GmpIntDataContainer& gmpIntDataContainer(); + + friend GmpInt operator+(long lhs, const GmpInt& rhs); + friend GmpInt operator-(long lhs, const GmpInt& rhs); +}; + +GmpInt operator+(long lhs, const GmpInt& rhs); +GmpInt operator-(long lhs, const GmpInt& rhs); +GmpInt operator*(long lhs, const GmpInt& rhs); +GmpInt operator/(long lhs, const GmpInt& rhs); +GmpInt operator%(long lhs, const GmpInt& rhs); + +inline bool operator<(long lhs, const GmpInt& rhs) { return rhs > lhs; } +inline bool operator<=(long lhs, const GmpInt& rhs) { return rhs >= lhs; } +inline bool operator>(long lhs, const GmpInt& rhs) { return rhs < lhs; } +inline bool operator>=(long lhs, const GmpInt& rhs) { return rhs <= lhs; } +inline bool operator==(long lhs, const GmpInt& rhs) { return rhs == lhs; } +inline bool operator!=(long lhs, const GmpInt& rhs) { return rhs != lhs; } + +inline std::ostream& operator<<(std::ostream& os, const GmpInt& value) +{ + os << value.getAsString(); + return os; +} + +#endif diff --git a/mpfr/MpfrFloat.cc b/mpfr/MpfrFloat.cc new file mode 100644 index 0000000..112c684 --- /dev/null +++ b/mpfr/MpfrFloat.cc @@ -0,0 +1,976 @@ +#include "MpfrFloat.hh" +#include <stdio.h> +#include <mpfr.h> +#include <deque> +#include <vector> +#include <cstring> +#include <cassert> + +//=========================================================================== +// Auxiliary structs +//=========================================================================== +struct MpfrFloat::MpfrFloatData +{ + unsigned mRefCount; + MpfrFloatData* nextFreeNode; + mpfr_t mFloat; + + MpfrFloatData(): mRefCount(1), nextFreeNode(0) {} +}; + +class MpfrFloat::MpfrFloatDataContainer +{ + unsigned long mDefaultPrecision; + std::deque<MpfrFloatData> mData; + MpfrFloatData* mFirstFreeNode; + + MpfrFloatData + *mConst_0, *mConst_pi, *mConst_e, *mConst_log2, *mConst_epsilon; + + void recalculateEpsilon() + { + mpfr_set_si(mConst_epsilon->mFloat, 1, GMP_RNDN); + mpfr_div_2ui(mConst_epsilon->mFloat, mConst_epsilon->mFloat, + mDefaultPrecision*7/8 - 1, GMP_RNDN); + } + + public: + MpfrFloatDataContainer(): + mDefaultPrecision(256), mFirstFreeNode(0), mConst_0(0), + mConst_pi(0), mConst_e(0), mConst_log2(0), mConst_epsilon(0) + {} + + ~MpfrFloatDataContainer() + { + for(size_t i = 0; i < mData.size(); ++i) + mpfr_clear(mData[i].mFloat); + } + + MpfrFloatData* allocateMpfrFloatData(bool initToZero) + { + if(mFirstFreeNode) + { + MpfrFloatData* node = mFirstFreeNode; + mFirstFreeNode = node->nextFreeNode; + if(initToZero) mpfr_set_si(node->mFloat, 0, GMP_RNDN); + ++(node->mRefCount); + return node; + } + + mData.push_back(MpfrFloatData()); + mpfr_init2(mData.back().mFloat, mDefaultPrecision); + if(initToZero) mpfr_set_si(mData.back().mFloat, 0, GMP_RNDN); + return &mData.back(); + } + + void releaseMpfrFloatData(MpfrFloatData* data) + { + if(--(data->mRefCount) == 0) + { + data->nextFreeNode = mFirstFreeNode; + mFirstFreeNode = data; + } + } + + void setDefaultPrecision(unsigned long bits) + { + if(bits != mDefaultPrecision) + { + mDefaultPrecision = bits; + for(size_t i = 0; i < mData.size(); ++i) + mpfr_prec_round(mData[i].mFloat, bits, GMP_RNDN); + + if(mConst_pi) mpfr_const_pi(mConst_pi->mFloat, GMP_RNDN); + if(mConst_e) + { + mpfr_set_si(mConst_e->mFloat, 1, GMP_RNDN); + mpfr_exp(mConst_e->mFloat, mConst_e->mFloat, GMP_RNDN); + } + if(mConst_log2) mpfr_const_log2(mConst_log2->mFloat, GMP_RNDN); + if(mConst_epsilon) recalculateEpsilon(); + } + } + + unsigned long getDefaultPrecision() const + { + return mDefaultPrecision; + } + + MpfrFloatData* const_0() + { + if(!mConst_0) mConst_0 = allocateMpfrFloatData(true); + return mConst_0; + } + + MpfrFloat const_pi() + { + if(!mConst_pi) + { + mConst_pi = allocateMpfrFloatData(false); + mpfr_const_pi(mConst_pi->mFloat, GMP_RNDN); + } + return MpfrFloat(mConst_pi); + } + + MpfrFloat const_e() + { + if(!mConst_e) + { + mConst_e = allocateMpfrFloatData(false); + mpfr_set_si(mConst_e->mFloat, 1, GMP_RNDN); + mpfr_exp(mConst_e->mFloat, mConst_e->mFloat, GMP_RNDN); + } + return MpfrFloat(mConst_e); + } + + MpfrFloat const_log2() + { + if(!mConst_log2) + { + mConst_log2 = allocateMpfrFloatData(false); + mpfr_const_log2(mConst_log2->mFloat, GMP_RNDN); + } + return MpfrFloat(mConst_log2); + } + + MpfrFloat const_epsilon() + { + if(!mConst_epsilon) + { + mConst_epsilon = allocateMpfrFloatData(false); + recalculateEpsilon(); + } + return MpfrFloat(mConst_epsilon); + } +}; + + +//=========================================================================== +// Shared data +//=========================================================================== +// This should ensure that the container is not accessed by any MpfrFloat +// instance before it has been constructed or after it has been destroyed +// (which might otherwise happen if MpfrFloat is instantiated globally.) +MpfrFloat::MpfrFloatDataContainer& MpfrFloat::mpfrFloatDataContainer() +{ + static MpfrFloat::MpfrFloatDataContainer container; + return container; +} + + +//=========================================================================== +// Auxiliary functions +//=========================================================================== +void MpfrFloat::setDefaultMantissaBits(unsigned long bits) +{ + mpfrFloatDataContainer().setDefaultPrecision(bits); +} + +unsigned long MpfrFloat::getCurrentDefaultMantissaBits() +{ + return mpfrFloatDataContainer().getDefaultPrecision(); +} + +inline void MpfrFloat::copyIfShared() +{ + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + MpfrFloatData* oldData = mData; + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set(mData->mFloat, oldData->mFloat, GMP_RNDN); + } +} + + +//=========================================================================== +// Constructors, destructor, assignment +//=========================================================================== +MpfrFloat::MpfrFloat(DummyType): + mData(mpfrFloatDataContainer().allocateMpfrFloatData(false)) +{} + +MpfrFloat::MpfrFloat(MpfrFloatData* data): + mData(data) +{ + assert(data != 0); + ++(mData->mRefCount); +} + +MpfrFloat::MpfrFloat(): + mData(mpfrFloatDataContainer().const_0()) +{ + ++(mData->mRefCount); +} + +MpfrFloat::MpfrFloat(double value) +{ + if(value == 0.0) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_d(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(long double value) +{ + if(value == 0.0L) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_ld(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(long value) +{ + if(value == 0) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(int value) +{ + if(value == 0) + { + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } +} + +MpfrFloat::MpfrFloat(const char* value, char** endptr): + mData(mpfrFloatDataContainer().allocateMpfrFloatData(false)) +{ + mpfr_strtofr(mData->mFloat, value, endptr, 0, GMP_RNDN); +} + +MpfrFloat::~MpfrFloat() +{ + mpfrFloatDataContainer().releaseMpfrFloatData(mData); +} + +MpfrFloat::MpfrFloat(const MpfrFloat& rhs): + mData(rhs.mData) +{ + ++(mData->mRefCount); +} + +MpfrFloat& MpfrFloat::operator=(const MpfrFloat& rhs) +{ + if(mData != rhs.mData) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = rhs.mData; + ++(mData->mRefCount); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(double value) +{ + if(value == 0.0) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_d(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(long double value) +{ + if(value == 0.0L) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_ld(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(long value) +{ + if(value == 0) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +MpfrFloat& MpfrFloat::operator=(int value) +{ + if(value == 0) + { + mpfrFloatDataContainer().releaseMpfrFloatData(mData); + mData = mpfrFloatDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + mpfr_set_si(mData->mFloat, value, GMP_RNDN); + } + return *this; +} + +/* +MpfrFloat& MpfrFloat::operator=(const char* value) +{ + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = mpfrFloatDataContainer().allocateMpfrFloatData(false); + } + + mpfr_set_str(mData->mFloat, value, 10, GMP_RNDN); + return *this; +} +*/ + +void MpfrFloat::parseValue(const char* value) +{ + copyIfShared(); + mpfr_set_str(mData->mFloat, value, 10, GMP_RNDN); +} + +void MpfrFloat::parseValue(const char* value, char** endptr) +{ + copyIfShared(); + mpfr_strtofr(mData->mFloat, value, endptr, 0, GMP_RNDN); +} + + +//=========================================================================== +// Data getters +//=========================================================================== +template<> +void MpfrFloat::get_raw_mpfr_data<mpfr_t>(mpfr_t& dest_mpfr_t) +{ + std::memcpy(&dest_mpfr_t, mData->mFloat, sizeof(mpfr_t)); +} + +const char* MpfrFloat::getAsString(unsigned precision) const +{ +#if(MPFR_VERSION_MAJOR < 2 || (MPFR_VERSION_MAJOR == 2 && MPFR_VERSION_MINOR < 4)) + static const char* retval = + "[mpfr_snprintf() is not supported in mpfr versions prior to 2.4]"; + return retval; +#else + static std::vector<char> str; + str.resize(precision+30); + mpfr_snprintf(&(str[0]), precision+30, "%.*RNg", precision, mData->mFloat); + return &(str[0]); +#endif +} + +bool MpfrFloat::isInteger() const +{ + return mpfr_integer_p(mData->mFloat) != 0; +} + +long MpfrFloat::toInt() const +{ + return mpfr_get_si(mData->mFloat, GMP_RNDN); +} + +double MpfrFloat::toDouble() const +{ + return mpfr_get_d(mData->mFloat, GMP_RNDN); +} + + +//=========================================================================== +// Modifying operators +//=========================================================================== +MpfrFloat& MpfrFloat::operator+=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_add(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator+=(double value) +{ + copyIfShared(); + mpfr_add_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator-=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_sub(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator-=(double value) +{ + copyIfShared(); + mpfr_sub_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator*=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_mul(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator*=(double value) +{ + copyIfShared(); + mpfr_mul_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator/=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_div(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator/=(double value) +{ + copyIfShared(); + mpfr_div_d(mData->mFloat, mData->mFloat, value, GMP_RNDN); + return *this; +} + +MpfrFloat& MpfrFloat::operator%=(const MpfrFloat& rhs) +{ + copyIfShared(); + mpfr_fmod(mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return *this; +} + + +//=========================================================================== +// Modifying functions +//=========================================================================== +void MpfrFloat::negate() +{ + copyIfShared(); + mpfr_neg(mData->mFloat, mData->mFloat, GMP_RNDN); +} + +void MpfrFloat::abs() +{ + copyIfShared(); + mpfr_abs(mData->mFloat, mData->mFloat, GMP_RNDN); +} + + +//=========================================================================== +// Non-modifying operators +//=========================================================================== +MpfrFloat MpfrFloat::operator+(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_add(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator+(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_add_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_sub(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_sub_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator*(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_mul(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator*(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_mul_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator/(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_div(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator/(double value) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_div_d(retval.mData->mFloat, mData->mFloat, value, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator%(const MpfrFloat& rhs) const +{ + MpfrFloat retval(kNoInitialization); + mpfr_fmod(retval.mData->mFloat, mData->mFloat, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::operator-() const +{ + MpfrFloat retval(kNoInitialization); + mpfr_neg(retval.mData->mFloat, mData->mFloat, GMP_RNDN); + return retval; +} + + + +//=========================================================================== +// Comparison operators +//=========================================================================== +bool MpfrFloat::operator<(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) < 0; +} + +bool MpfrFloat::operator<(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) < 0; +} + +bool MpfrFloat::operator<=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) <= 0; +} + +bool MpfrFloat::operator<=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) <= 0; +} + +bool MpfrFloat::operator>(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) > 0; +} + +bool MpfrFloat::operator>(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) > 0; +} + +bool MpfrFloat::operator>=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) >= 0; +} + +bool MpfrFloat::operator>=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) >= 0; +} + +bool MpfrFloat::operator==(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) == 0; +} + +bool MpfrFloat::operator==(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) == 0; +} + +bool MpfrFloat::operator!=(const MpfrFloat& rhs) const +{ + return mpfr_cmp(mData->mFloat, rhs.mData->mFloat) != 0; +} + +bool MpfrFloat::operator!=(double value) const +{ + return mpfr_cmp_d(mData->mFloat, value) != 0; +} + + +//=========================================================================== +// Operator functions +//=========================================================================== +MpfrFloat operator+(double lhs, const MpfrFloat& rhs) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_add_d(retval.mData->mFloat, rhs.mData->mFloat, lhs, GMP_RNDN); + return retval; +} + +MpfrFloat operator-(double lhs, const MpfrFloat& rhs) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_d_sub(retval.mData->mFloat, lhs, rhs.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat operator*(double lhs, const MpfrFloat& rhs) +{ + return rhs * lhs; +} + +MpfrFloat operator/(double lhs, const MpfrFloat& rhs) +{ + return MpfrFloat(lhs) / rhs; +} + +MpfrFloat operator%(double lhs, const MpfrFloat& rhs) +{ + return MpfrFloat(lhs) % rhs; +} + +std::ostream& operator<<(std::ostream& os, const MpfrFloat& value) +{ + os << value.getAsString(unsigned(os.precision())); + return os; +} + +//=========================================================================== +// Static functions +//=========================================================================== +MpfrFloat MpfrFloat::log(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::log2(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::log10(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_log10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp2(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp2(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::exp10(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_exp10(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cos(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sin(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::tan(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_tan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sec(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sec(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::csc(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_csc(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cot(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cot(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +void MpfrFloat::sincos(const MpfrFloat& value, + MpfrFloat& sin, + MpfrFloat& cos) +{ + sin.copyIfShared(); + cos.copyIfShared(); + mpfr_sin_cos + (sin.mData->mFloat, cos.mData->mFloat, value.mData->mFloat, GMP_RNDN); +} + +MpfrFloat MpfrFloat::acos(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acos(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asin(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asin(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atan2(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atan2(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::hypot(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_hypot(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::tanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_tanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::acosh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_acosh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::asinh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_asinh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::atanh(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_atanh(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::sqrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_sqrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::cbrt(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_cbrt(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::root(const MpfrFloat& value, unsigned long root) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_root(retval.mData->mFloat, value.mData->mFloat, root, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::pow(const MpfrFloat& value, long exponent) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_pow_si(retval.mData->mFloat, value.mData->mFloat, exponent, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::abs(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_abs(retval.mData->mFloat, value.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::dim(const MpfrFloat& value1, const MpfrFloat& value2) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_dim(retval.mData->mFloat, + value1.mData->mFloat, value2.mData->mFloat, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::round(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_round(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::ceil(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_ceil(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::floor(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_floor(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::trunc(const MpfrFloat& value) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_trunc(retval.mData->mFloat, value.mData->mFloat); + return retval; +} + +MpfrFloat MpfrFloat::parseString(const char* str, char** endptr) +{ + MpfrFloat retval(MpfrFloat::kNoInitialization); + mpfr_strtofr(retval.mData->mFloat, str, endptr, 0, GMP_RNDN); + return retval; +} + +MpfrFloat MpfrFloat::const_pi() +{ + return mpfrFloatDataContainer().const_pi(); +} + +MpfrFloat MpfrFloat::const_e() +{ + return mpfrFloatDataContainer().const_e(); +} + +MpfrFloat MpfrFloat::const_log2() +{ + return mpfrFloatDataContainer().const_log2(); +} + +MpfrFloat MpfrFloat::someEpsilon() +{ + return mpfrFloatDataContainer().const_epsilon(); +} diff --git a/mpfr/MpfrFloat.hh b/mpfr/MpfrFloat.hh new file mode 100644 index 0000000..d455d24 --- /dev/null +++ b/mpfr/MpfrFloat.hh @@ -0,0 +1,206 @@ +#ifndef ONCE_FP_MPFR_FLOAT_ +#define ONCE_FP_MPFR_FLOAT_ + +#include <iostream> + +class MpfrFloat +{ + public: + /* A default of 256 bits will be used unless changed with this function. + Note that all existing and cached GMP objects will be resized to the + specified precision (which can be a somewhat heavy operation). + */ + static void setDefaultMantissaBits(unsigned long bits); + + static unsigned long getCurrentDefaultMantissaBits(); + + /* The default constructor initializes the object to the value 0. + It's efficient to instantiate such zero-initialized objects because + all of them will share the same mpfr data. (Also any object initialized + with or assigned the explicit value of zero will also share that one + mpfr data.) Thus multiple zero-initialized MpfrFloat instances won't + consume significant amounts of memory (until they are modified to + contain some other value, of course). + + Important caveat: + ---------------- + Note that initializing an MpfrFloat object with, for example, 0.1 will + suffer from accuracy problems (at least if the MpfrFloat object has + more mantissa bits than a double). The C++ double value 0.1 has only + 53 mantissa bits, while the MpfrFloat object usually has more. If the + MpfrFloat object is initialized with a double, only that many bits of + accuracy will end up in the value of the MpfrFloat object. This can + create significant rounding/accuracy problems in some cases. + If you need to initialize the MpfrObject with some value (which cannot + be represented accurately by base-2 floating point numbers, eg. 0.1) + at full mantissa precision, you have to use parseValue("0.1") instead, + rather than relying on the constructor taking a double type value. + */ + MpfrFloat(); + MpfrFloat(double value); + MpfrFloat(long double value); + MpfrFloat(long value); + MpfrFloat(int value); + MpfrFloat(const char* value, char** endptr); + + ~MpfrFloat(); + + MpfrFloat(const MpfrFloat&); + + MpfrFloat& operator=(const MpfrFloat&); + MpfrFloat& operator=(double value); + MpfrFloat& operator=(long double value); + MpfrFloat& operator=(long value); + MpfrFloat& operator=(int value); + //MpfrFloat& operator=(const char* value); + + void parseValue(const char* value); + void parseValue(const char* value, char** endptr); + + + /* This function can be used to retrieve the raw mpfr_t data structure + used by this object. (The template trick is used to avoid a dependency + of this header file with <mpfr.h>.) + In other words, it can be called like: + + mpfr_t raw_mpfr_data; + floatValue.get_raw_mpfr_data(raw_mpfr_data); + + Note that the returned mpfr_t should be considered as read-only and + not be modified from the outside because it may be shared among + several objects. If the calling code needs to modify the data, it + should copy it for itself first with the appropriate MPFR library + functions. + */ + template<typename Mpfr_t> + void get_raw_mpfr_data(Mpfr_t& dest_mpfr_t); + + + /* Note that the returned char* points to an internal (shared) buffer + which will be valid until the next time this function is called + (by any object). + */ + const char* getAsString(unsigned precision) const; + + bool isInteger() const; + long toInt() const; + double toDouble() const; + + MpfrFloat& operator+=(const MpfrFloat&); + MpfrFloat& operator+=(double); + MpfrFloat& operator-=(const MpfrFloat&); + MpfrFloat& operator-=(double); + MpfrFloat& operator*=(const MpfrFloat&); + MpfrFloat& operator*=(double); + MpfrFloat& operator/=(const MpfrFloat&); + MpfrFloat& operator/=(double); + MpfrFloat& operator%=(const MpfrFloat&); + + void negate(); + void abs(); + + MpfrFloat operator+(const MpfrFloat&) const; + MpfrFloat operator+(double) const; + MpfrFloat operator-(const MpfrFloat&) const; + MpfrFloat operator-(double) const; + MpfrFloat operator*(const MpfrFloat&) const; + MpfrFloat operator*(double) const; + MpfrFloat operator/(const MpfrFloat&) const; + MpfrFloat operator/(double) const; + MpfrFloat operator%(const MpfrFloat&) const; + + MpfrFloat operator-() const; + + bool operator<(const MpfrFloat&) const; + bool operator<(double) const; + bool operator<=(const MpfrFloat&) const; + bool operator<=(double) const; + bool operator>(const MpfrFloat&) const; + bool operator>(double) const; + bool operator>=(const MpfrFloat&) const; + bool operator>=(double) const; + bool operator==(const MpfrFloat&) const; + bool operator==(double) const; + bool operator!=(const MpfrFloat&) const; + bool operator!=(double) const; + + static MpfrFloat log(const MpfrFloat&); + static MpfrFloat log2(const MpfrFloat&); + static MpfrFloat log10(const MpfrFloat&); + static MpfrFloat exp(const MpfrFloat&); + static MpfrFloat exp2(const MpfrFloat&); + static MpfrFloat exp10(const MpfrFloat&); + static MpfrFloat cos(const MpfrFloat&); + static MpfrFloat sin(const MpfrFloat&); + static MpfrFloat tan(const MpfrFloat&); + static MpfrFloat sec(const MpfrFloat&); + static MpfrFloat csc(const MpfrFloat&); + static MpfrFloat cot(const MpfrFloat&); + static void sincos(const MpfrFloat&, MpfrFloat& sin, MpfrFloat& cos); + static MpfrFloat acos(const MpfrFloat&); + static MpfrFloat asin(const MpfrFloat&); + static MpfrFloat atan(const MpfrFloat&); + static MpfrFloat atan2(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat hypot(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat cosh(const MpfrFloat&); + static MpfrFloat sinh(const MpfrFloat&); + static MpfrFloat tanh(const MpfrFloat&); + static MpfrFloat acosh(const MpfrFloat&); + static MpfrFloat asinh(const MpfrFloat&); + static MpfrFloat atanh(const MpfrFloat&); + static MpfrFloat sqrt(const MpfrFloat&); + static MpfrFloat cbrt(const MpfrFloat&); + static MpfrFloat root(const MpfrFloat&, unsigned long root); + static MpfrFloat pow(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat pow(const MpfrFloat&, long exponent); + static MpfrFloat abs(const MpfrFloat&); + static MpfrFloat dim(const MpfrFloat&, const MpfrFloat&); + static MpfrFloat round(const MpfrFloat&); + static MpfrFloat ceil(const MpfrFloat&); + static MpfrFloat floor(const MpfrFloat&); + static MpfrFloat trunc(const MpfrFloat&); + + static MpfrFloat parseString(const char* str, char** endptr); + + // These values are cached (and recalculated every time the mantissa bits + // change), so it's efficient to call these repeatedly: + static MpfrFloat const_pi(); + static MpfrFloat const_e(); + static MpfrFloat const_log2(); + static MpfrFloat someEpsilon(); + + + private: + struct MpfrFloatData; + class MpfrFloatDataContainer; + + MpfrFloatData* mData; + + enum DummyType { kNoInitialization }; + MpfrFloat(DummyType); + MpfrFloat(MpfrFloatData*); + + void copyIfShared(); + static MpfrFloatDataContainer& mpfrFloatDataContainer(); + + friend MpfrFloat operator+(double lhs, const MpfrFloat& rhs); + friend MpfrFloat operator-(double lhs, const MpfrFloat& rhs); +}; + +MpfrFloat operator+(double lhs, const MpfrFloat& rhs); +MpfrFloat operator-(double lhs, const MpfrFloat& rhs); +MpfrFloat operator*(double lhs, const MpfrFloat& rhs); +MpfrFloat operator/(double lhs, const MpfrFloat& rhs); +MpfrFloat operator%(double lhs, const MpfrFloat& rhs); + +inline bool operator<(double lhs, const MpfrFloat& rhs) { return rhs > lhs; } +inline bool operator<=(double lhs, const MpfrFloat& rhs) { return rhs >= lhs; } +inline bool operator>(double lhs, const MpfrFloat& rhs) { return rhs < lhs; } +inline bool operator>=(double lhs, const MpfrFloat& rhs) { return rhs <= lhs; } +inline bool operator==(double lhs, const MpfrFloat& rhs) { return rhs == lhs; } +inline bool operator!=(double lhs, const MpfrFloat& rhs) { return rhs != lhs; } + +// This function takes into account the value of os.precision() +std::ostream& operator<<(std::ostream& os, const MpfrFloat& value); + +#endif diff --git a/run_full_release_testing.sh b/run_full_release_testing.sh new file mode 100755 index 0000000..372f404 --- /dev/null +++ b/run_full_release_testing.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +runTest() +{ + echo "Building testbed_release with" + echo "FP_FEATURE_FLAGS=$1" + make -s release_clean + FP_FEATURE_FLAGS="$1" make -s testbed_release + if [ "$?" -ne "0" ]; then exit 1; fi + echo "Running: ./testbed_release $2" + ./testbed_release "$2" + if [ "$?" -ne "0" ]; then exit 1; fi +} + +runTest "-D_GLIBCXX_DEBUG" +runTest "-D_GLIBCXX_DEBUG -DFP_NO_SUPPORT_OPTIMIZER" -skipSlowAlgo +runTest "-DFP_USE_THREAD_SAFE_EVAL" -skipSlowAlgo +runTest "-DFP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA" -skipSlowAlgo +runTest "-DFP_NO_SUPPORT_OPTIMIZER -DFP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_FLOAT_TYPE" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_LONG_DOUBLE_TYPE -DFP_USE_STRTOLD" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_LONG_INT_TYPE" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_MPFR_FLOAT_TYPE" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_GMP_INT_TYPE" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_COMPLEX_DOUBLE_TYPE" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_COMPLEX_FLOAT_TYPE" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE -DFP_USE_STRTOLD" -skipSlowAlgo +runTest "-DFP_SUPPORT_LONG_DOUBLE_TYPE -DFP_DISABLE_DOUBLE_TYPE" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_FLOAT_TYPE -DFP_SUPPORT_LONG_DOUBLE_TYPE -DFP_SUPPORT_COMPLEX_DOUBLE_TYPE -DFP_SUPPORT_COMPLEX_FLOAT_TYPE -DFP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE -DFP_SUPPORT_CPLUSPLUS11_MATH_FUNCS" -skipSlowAlgo +runTest "-D_GLIBCXX_DEBUG -DFP_SUPPORT_FLOAT_TYPE -DFP_SUPPORT_LONG_DOUBLE_TYPE -DFP_SUPPORT_LONG_INT_TYPE -DFP_SUPPORT_MPFR_FLOAT_TYPE -DFP_SUPPORT_GMP_INT_TYPE -DFP_SUPPORT_COMPLEX_DOUBLE_TYPE -DFP_SUPPORT_COMPLEX_FLOAT_TYPE -DFP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE" -skipSlowAlgo + +make -s release_clean diff --git a/testbed.cc b/testbed.cc new file mode 100644 index 0000000..7f5762a --- /dev/null +++ b/testbed.cc @@ -0,0 +1,3102 @@ +/*========================================================================== + testbed + --------- + Copyright: Juha Nieminen, Joel Yliluoma + This program (testbed) is distributed under the terms of + the GNU General Public License (GPL) version 3. + See gpl.txt for the license text. +============================================================================*/ + +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + +static const char* const kVersionNumber = "2.3.0.12"; + +#include "fpconfig.hh" +#include "fparser.hh" + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE +#include "fparser_mpfr.hh" +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE +#include "fparser_gmpint.hh" +#endif + +#include "extrasrc/fpaux.hh" + +#include <cmath> +#include <iostream> +#include <iomanip> +#include <cstdio> +#include <sstream> +#include <algorithm> +#include <cstring> +#include <cassert> + +#define CONST 1.5 + +#define StringifyHlp(x) #x +#define Stringify(x) StringifyHlp(x) + +#ifndef FP_DISABLE_DOUBLE_TYPE +typedef FunctionParser DefaultParser; +#elif defined(FP_SUPPORT_LONG_DOUBLE_TYPE) +typedef FunctionParser_ld DefaultParser; +#elif defined(FP_SUPPORT_FLOAT_TYPE) +typedef FunctionParser_f DefaultParser; +#elif defined(FP_SUPPORT_MPFR_FLOAT_TYPE) +typedef FunctionParser_mpfr DefaultParser; +#else +#error "FunctionParserBase<double> was disabled and no viable floating point alternative has been defined" +#endif + +#undef FP_TEST_WANT_FLOAT_TYPE +#ifdef FP_SUPPORT_FLOAT_TYPE + #define FP_TEST_WANT_FLOAT_TYPE +#endif +#undef FP_TEST_WANT_DOUBLE_TYPE +#ifndef FP_DISABLE_DOUBLE_TYPE + #define FP_TEST_WANT_DOUBLE_TYPE +#endif +#undef FP_TEST_WANT_LONG_DOUBLE_TYPE +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + #define FP_TEST_WANT_LONG_DOUBLE_TYPE +#endif +#undef FP_TEST_WANT_MPFR_FLOAT_TYPE +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + #define FP_TEST_WANT_MPFR_FLOAT_TYPE +#endif +#undef FP_TEST_WANT_GMP_INT_TYPE +#ifdef FP_SUPPORT_GMP_INT_TYPE + #define FP_TEST_WANT_GMP_INT_TYPE +#endif +#undef FP_TEST_WANT_LONG_INT_TYPE +#if defined(FP_SUPPORT_LONG_INT_TYPE) || defined(FP_SUPPORT_GMP_INT_TYPE) + #define FP_TEST_WANT_LONG_INT_TYPE +#endif +#undef FP_TEST_WANT_COMPLEX_FLOAT_TYPE +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + #define FP_TEST_WANT_COMPLEX_FLOAT_TYPE +#endif +#undef FP_TEST_WANT_COMPLEX_DOUBLE_TYPE +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + #define FP_TEST_WANT_COMPLEX_DOUBLE_TYPE +#endif +#undef FP_TEST_WANT_COMPLEX_LONG_DOUBLE_TYPE +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + #define FP_TEST_WANT_COMPLEX_LONG_DOUBLE_TYPE +#endif + +typedef DefaultParser::value_type DefaultValue_t; + + +namespace +{ + /* Verbosity level: + 0 = No progress output. Error reporting as in verbosity level 1. + 1 = Very brief progress and error output. + 2 = More verbose progress output, full error reporting. + 3 = Very verbose progress output, full error reporting. + */ + int verbosityLevel = 1; + + + const char* getEvalErrorName(int errorCode) + { + static const char* const evalErrorNames[6] = + { + "no error", "division by zero", "sqrt error", "log error", + "trigonometric error", "max eval recursion level reached" + }; + if(errorCode >= 0 && errorCode < 6) + return evalErrorNames[errorCode]; + return "unknown"; + } + + std::vector<const char*> selectedRegressionTests; + + // Auxiliary functions + // ------------------- + template<typename Value_t> + inline Value_t r2d(Value_t x) + { return x * (Value_t(180) / FUNCTIONPARSERTYPES::fp_const_pi<Value_t>()); } + + template<typename Value_t> + inline Value_t d2r(Value_t x) + { return x * (FUNCTIONPARSERTYPES::fp_const_pi<Value_t>() / Value_t(180)); } + + //inline double log10(double x) { return std::log(x) / std::log(10); } + + template<typename Value_t> + Value_t userDefFuncSqr(const Value_t* p) { return p[0]*p[0]; } + + template<typename Value_t> + Value_t userDefFuncSub(const Value_t* p) { return p[0]-p[1]; } + + template<typename Value_t> + Value_t userDefFuncValue(const Value_t*) { return 10; } + + + template<typename Value_t> + class UserDefFuncWrapper: + public FunctionParserBase<Value_t>::FunctionWrapper + { + Value_t (*mFuncPtr)(const Value_t*); + unsigned mCounter; + + public: + UserDefFuncWrapper(Value_t (*funcPtr)(const Value_t*)) : + mFuncPtr(funcPtr), mCounter(0) + {} + + virtual Value_t callFunction(const Value_t* values) + { + ++mCounter; + return mFuncPtr(values); + } + + unsigned counter() const { return mCounter; } + }; + + + template<typename Value_t> + inline Value_t testbedEpsilon() { return Value_t(1e-9); } + + template<> + inline float testbedEpsilon<float>() { return 1e-3f; } + + template<> + inline long double testbedEpsilon<long double>() { return 1e-10l; } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + inline MpfrFloat testbedEpsilon<MpfrFloat>() + { + static const MpfrFloat eps(2e-20); + return eps; + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + inline std::complex<float> testbedEpsilon<std::complex<float> >() + { return testbedEpsilon<float>(); } +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + inline std::complex<long double> testbedEpsilon<std::complex<long double> >() + { return testbedEpsilon<long double>(); } +#endif + + +#ifndef _MSC_VER + /*void setAnsiColor(unsigned color) + { + static int bold = 0; + std::cout << "\33["; + if(color > 7) + { + if(!bold) { std::cout << "1;"; bold=1; } + color -= 7; + } + else if(bold) { std::cout << "0;"; bold=0; } + std::cout << 30+color << "m"; + }*/ + + void setAnsiBold() { std::cout << "\33[1m"; } + + void resetAnsiColor() { std::cout << "\33[0m"; } +#else + /*void setAnsiColor(unsigned) {}*/ + void setAnsiBold() {} + void resetAnsiColor() {} +#endif +} + + +//========================================================================= +// Copying testing functions +//========================================================================= +bool TestCopyingNoDeepCopy(DefaultParser p) +{ + DefaultValue_t vars[2] = { 3, 5 }; + + if(std::fabs(p.Eval(vars) - 13) > testbedEpsilon<DefaultValue_t>()) + { + if(verbosityLevel >= 2) + { + std::cout + << "\n - Giving as function parameter (no deep copy) failed." + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + p.PrintByteCode(std::cout); +#endif + } + return false; + } + return true; +} + +bool TestCopyingDeepCopy(DefaultParser p) +{ + DefaultValue_t vars[2] = { 3, 5 }; + + p.Parse("x*y-1", "x,y"); + + if(std::fabs(p.Eval(vars) - 14) > testbedEpsilon<DefaultValue_t>()) + { + if(verbosityLevel >= 2) + { + std::cout + << "\n - Giving as function parameter (deep copy) failed." + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + p.PrintByteCode(std::cout); +#endif + } + return false; + } + return true; +} + +int TestCopying() +{ + bool retval = true; + DefaultValue_t vars[2] = { 2, 5 }; + const DefaultValue_t epsilon = testbedEpsilon<DefaultValue_t>(); + + DefaultParser p1, p3; + p1.Parse("x*y-2", "x,y"); + + DefaultParser p2(p1); + if(std::fabs(p2.Eval(vars) - 8) > epsilon) + { + retval = false; + if(verbosityLevel >= 2) + { + std::cout << "\n - Copy constructor with no deep copy failed." + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + p2.PrintByteCode(std::cout); +#endif + } + } + + p2.Parse("x*y-1", "x,y"); + if(std::fabs(p2.Eval(vars) - 9) > epsilon) + { + retval = false; + if(verbosityLevel >= 2) + { + std::cout << "\n - Copy constructor with deep copy failed." + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + p2.PrintByteCode(std::cout); +#endif + } + } + + p3 = p1; + if(std::fabs(p3.Eval(vars) - 8) > epsilon) + { + retval = false; + if(verbosityLevel >= 2) + { + std::cout << "\n - Assignment with no deep copy failed." + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + p3.PrintByteCode(std::cout); +#endif + } + } + + p3.Parse("x*y-1", "x,y"); + if(std::fabs(p3.Eval(vars) - 9) > epsilon) + { + retval = false; + if(verbosityLevel >= 2) + { + std::cout << "\n - Assignment with deep copy failed." + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + p3.PrintByteCode(std::cout); +#endif + } + } + + if(!TestCopyingNoDeepCopy(p1)) + retval = false; + + // Final test to check that p1 still works: + if(std::fabs(p1.Eval(vars) - 8) > epsilon) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Failed: p1 was corrupted." << std::endl; + } + + if(!TestCopyingDeepCopy(p1)) + retval = false; + + // Final test to check that p1 still works: + if(std::fabs(p1.Eval(vars) - 8) > epsilon) + { + retval = false; + if(verbosityLevel >= 2) + { + std::cout << "\n - Failed: p1 was corrupted." << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + p1.PrintByteCode(std::cout); +#endif + } + } + + return retval; +} + + +//========================================================================= +// Test error situations +//========================================================================= +int TestErrorSituations() +{ + bool retval = true; + DefaultParser fp, tmpfp; + fp.AddUnit("unit", 2); + fp.AddFunction("Value", userDefFuncValue<DefaultValue_t>, 0); + fp.AddFunction("Sqr", userDefFuncSqr<DefaultValue_t>, 1); + fp.AddFunctionWrapper("Sub", UserDefFuncWrapper<DefaultValue_t> + (userDefFuncSub<DefaultValue_t>), 2); + tmpfp.Parse("0", "x"); + + static const struct + { + DefaultParser::ParseErrorType expected_error; + int expected_error_position; + const char* function_string; + } invalidFuncs[] = + { + { DefaultParser::MISSING_PARENTH, 5, "sin(x"}, + { DefaultParser::EXPECT_PARENTH_FUNC, 4, "sin x"}, + { DefaultParser::SYNTAX_ERROR, 2, "x+" }, + { DefaultParser::EXPECT_OPERATOR, 2, "x x"}, + { DefaultParser::UNKNOWN_IDENTIFIER, 4, "sin(y)" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 5, "sin(x, 1)" }, + { DefaultParser::EXPECT_OPERATOR, 1, "x, x"}, + { DefaultParser::SYNTAX_ERROR, 2, "x^^2" }, + { DefaultParser::SYNTAX_ERROR, 2, "x**x" }, + { DefaultParser::SYNTAX_ERROR, 2, "x+*x" }, + { DefaultParser::SYNTAX_ERROR, 0, "unit" }, + { DefaultParser::SYNTAX_ERROR, 0, "unit x" }, + { DefaultParser::SYNTAX_ERROR, 2, "x*unit" }, + { DefaultParser::SYNTAX_ERROR, 0, "unit*unit" }, + { DefaultParser::SYNTAX_ERROR, 0, "unit unit" }, + { DefaultParser::EXPECT_OPERATOR, 1, "x(unit)"}, + { DefaultParser::SYNTAX_ERROR, 2, "x+unit" }, + { DefaultParser::SYNTAX_ERROR, 2, "x*unit" }, + { DefaultParser::EMPTY_PARENTH, 1, "()"}, + { DefaultParser::SYNTAX_ERROR, 0, "" }, + { DefaultParser::EXPECT_OPERATOR, 1, "x()"}, + { DefaultParser::EMPTY_PARENTH, 3, "x*()"}, + { DefaultParser::SYNTAX_ERROR, 4, "sin(unit)" }, + { DefaultParser::EXPECT_PARENTH_FUNC, 4, "sin unit"}, + { DefaultParser::EXPECT_OPERATOR, 2, "1..2"}, + { DefaultParser::SYNTAX_ERROR, 1, "(" }, + { DefaultParser::MISM_PARENTH, 0, ")"}, + { DefaultParser::MISSING_PARENTH, 2, "(x"}, + { DefaultParser::EXPECT_OPERATOR, 1, "x)"}, + { DefaultParser::MISM_PARENTH, 0, ")x("}, + { DefaultParser::MISSING_PARENTH, 14,"(((((((x))))))"}, + { DefaultParser::EXPECT_OPERATOR, 15,"(((((((x))))))))"}, + { DefaultParser::EXPECT_OPERATOR, 1, "2x"}, + { DefaultParser::EXPECT_OPERATOR, 3, "(2)x"}, + { DefaultParser::EXPECT_OPERATOR, 3, "(x)2"}, + { DefaultParser::EXPECT_OPERATOR, 1, "2(x)"}, + { DefaultParser::EXPECT_OPERATOR, 1, "x(2)"}, + { DefaultParser::SYNTAX_ERROR, 0, "[x]" }, + { DefaultParser::SYNTAX_ERROR, 0, "@x" }, + { DefaultParser::SYNTAX_ERROR, 0, "$x" }, + { DefaultParser::SYNTAX_ERROR, 0, "{x}" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 5, "max(x)" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 8, "max(x, 1, 2)" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 6, "if(x,2)" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 10,"if(x, 2, 3, 4)" }, + { DefaultParser::MISSING_PARENTH, 6, "Value(x)"}, + { DefaultParser::MISSING_PARENTH, 6, "Value(1+x)"}, + { DefaultParser::MISSING_PARENTH, 6, "Value(1,x)"}, + // Note: ^should these three not return ILL_PARAMS_AMOUNT instead? + { DefaultParser::ILL_PARAMS_AMOUNT, 4, "Sqr()"}, + { DefaultParser::ILL_PARAMS_AMOUNT, 5, "Sqr(x,1)" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 5, "Sqr(1,2,x)" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 4, "Sub()" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 5, "Sub(x)" }, + { DefaultParser::ILL_PARAMS_AMOUNT, 7, "Sub(x,1,2)" }, + { DefaultParser::UNKNOWN_IDENTIFIER, 2, "x+Sin(1)" }, + { DefaultParser::UNKNOWN_IDENTIFIER, 0, "sub(1,2)" }, + { DefaultParser::UNKNOWN_IDENTIFIER, 0, "sinx(1)" }, + { DefaultParser::UNKNOWN_IDENTIFIER, 2, "1+X" }, + { DefaultParser::UNKNOWN_IDENTIFIER, 0, "eval(x)" } + }; + const unsigned amnt = sizeof(invalidFuncs)/sizeof(invalidFuncs[0]); + for(unsigned i = 0; i < amnt; ++i) + { + int parse_result = fp.Parse(invalidFuncs[i].function_string, "x"); + if(parse_result < 0) + { + retval = false; + if(verbosityLevel >= 2) + { + std::cout << "\n - Parsing the invalid function \"" + << invalidFuncs[i].function_string + << "\" didn't fail\n"; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + fp.PrintByteCode(std::cout); +#endif + } + } + else if(fp.GetParseErrorType() != invalidFuncs[i].expected_error + || parse_result != invalidFuncs[i].expected_error_position) + { + retval = false; + if(verbosityLevel >= 2) + { + std::cout << "\n - Parsing the invalid function \"" + << invalidFuncs[i].function_string + << "\" produced "; + if(fp.GetParseErrorType() != invalidFuncs[i].expected_error) + std::cout << "wrong error code (" << fp.ErrorMsg() << ")"; + if(parse_result != invalidFuncs[i].expected_error_position) + std::cout << "wrong pointer (expected " + << invalidFuncs[i].expected_error_position + << ", got " << parse_result << ")"; + std::cout << "\n"; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + fp.PrintByteCode(std::cout); +#endif + } + } + } + + static const char* const invalidNames[] = + { "s2%", "sin", "(x)", "5x", "2", "\302\240"/*nbsp*/ }; + const unsigned namesAmnt = sizeof(invalidNames)/sizeof(invalidNames[0]); + + for(unsigned i = 0; i < namesAmnt; ++i) + { + const char* const n = invalidNames[i]; + if(fp.AddConstant(n, 1)) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Adding an invalid name (\"" << n + << "\") as constant didn't fail" << std::endl; + } + if(fp.AddFunction(n, userDefFuncSqr<DefaultValue_t>, 1)) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Adding an invalid name (\"" << n + << "\") as funcptr didn't fail" << std::endl; + } + if(fp.AddFunction(n, tmpfp)) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Adding an invalid name (\"" << n + << "\") as funcparser didn't fail" << std::endl; + } + if(fp.Parse("0", n) < 0) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Using an invalid name (\"" << n + << "\") as variable name didn't fail" << std::endl; + } + } + + fp.AddConstant("CONST", 1); + fp.AddFunction("PTR", userDefFuncSqr<DefaultValue_t>, 1); + fp.AddFunction("PARSER", tmpfp); + + if(fp.AddConstant("PTR", 1)) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Adding a userdef function (\"PTR\") as " + << "constant didn't fail" << std::endl; + } + if(fp.AddFunction("CONST", userDefFuncSqr<DefaultValue_t>, 1)) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Adding a userdef constant (\"CONST\") as " + << "funcptr didn't fail" << std::endl; + } + if(fp.AddFunction("CONST", tmpfp)) + { + retval = false; + if(verbosityLevel >= 2) + std::cout << "\n - Adding a userdef constant (\"CONST\") as " + << "funcparser didn't fail" << std::endl; + } + + return retval; +} + + +//========================================================================= +// Thoroughly test whitespaces +//========================================================================= +DefaultValue_t wsFunc(DefaultValue_t x) +{ + return + x + std::sin((x*-1.5)-(.5*2.0)*(((-x)*1.5+(2-(x)*2.0)*2.0)+(3.0*2.0))+ + (1.5*2.0))+(cos(x)*2.0); +} + +bool testWsFunc(DefaultParser& fp, const std::string& function) +{ + int res = fp.Parse(function, "x"); + if(res > -1) + { + if(verbosityLevel >= 2) + std::cout << "\n - Parsing function:\n\"" << function + << "\"\nfailed at char " << res + << ": " << fp.ErrorMsg() << std::endl; + return false; + } + + DefaultValue_t vars[1]; + for(vars[0] = -2.0; vars[0] <= 2.0; vars[0] += .1) + if(std::fabs(fp.Eval(vars) - wsFunc(vars[0])) > + testbedEpsilon<DefaultValue_t>()) + { + return false; + } + return true; +} + +int WhiteSpaceTest() +{ + DefaultParser fp; + fp.AddConstant("const", 1.5); + fp.AddUnit("unit", 2.0); + std::string function(" x + sin ( ( x * - 1.5 ) - .5 unit * ( ( ( - x ) * " + "const + ( 2 - ( x ) unit ) unit ) + 3 unit ) + " + "( const ) unit ) + cos ( x ) unit "); + + if(!testWsFunc(fp, function)) return false; + + static const unsigned char WhiteSpaceTables[][4] = + { + { 1, 0x09, 0,0 }, // tab + { 1, 0x0A, 0,0 }, // linefeed + { 1, 0x0B, 0,0 }, // vertical tab + { 1, 0x0D, 0,0 }, // carriage return + { 1, 0x20, 0,0 }, // space + { 2, 0xC2,0xA0, 0 }, // U+00A0 (nbsp) + { 3, 0xE2,0x80,0x80 }, { 3, 0xE2,0x80,0x81 }, // U+2000 to... + { 3, 0xE2,0x80,0x82 }, { 3, 0xE2,0x80,0x83 }, { 3, 0xE2,0x80,0x84 }, + { 3, 0xE2,0x80,0x85 }, { 3, 0xE2,0x80,0x86 }, { 3, 0xE2,0x80,0x87 }, + { 3, 0xE2,0x80,0x88 }, { 3, 0xE2,0x80,0x89 }, + { 3, 0xE2,0x80,0x8A }, { 3, 0xE2,0x80,0x8B }, // ... U+200B + { 3, 0xE2,0x80,0xAF }, { 3, 0xE2,0x81,0x9F }, // U+202F and U+205F + { 3, 0xE3,0x80,0x80 } // U+3000 + }; + const unsigned n_whitespaces = + sizeof(WhiteSpaceTables)/sizeof(*WhiteSpaceTables); + + for(unsigned i = 0; i < function.size(); ++i) + { + if(function[i] == ' ') + { + function.erase(i, 1); + for(std::size_t a = 0; a < n_whitespaces; ++a) + { + if(!testWsFunc(fp, function)) return false; + int length = (int)WhiteSpaceTables[a][0]; + const char* sequence = (const char*)&WhiteSpaceTables[a][1]; + function.insert(i, sequence, length); + if(!testWsFunc(fp, function)) return false; + function.erase(i, length); + } + } + } + return true; +} + + +//========================================================================= +// Test integer powers +//========================================================================= +bool compareExpValues(DefaultValue_t value, + const std::string& funcStr, + DefaultValue_t v1, + DefaultValue_t v2, + bool isOptimized) +{ + const DefaultValue_t epsilon = testbedEpsilon<DefaultValue_t>(); + const DefaultValue_t diff = + std::fabs(v1) < epsilon ? + (std::fabs(v2) < epsilon ? std::fabs(v1 - v2) : + std::fabs((v1 - v2) / v2)) : + std::fabs((v1 - v2) / v1); + if(diff > epsilon) + { + if(verbosityLevel >= 2) + { + std::cout << "\n - For \"" << funcStr << "\" with x=" << value + << " the library ("; + if(!isOptimized) std::cout << "not "; + std::cout << "optimized) returned\n" + << std::setprecision(18) << v2 + << " instead of " << v1 << std::endl; + } + return false; + } + return true; +} + +bool runIntPowTest(DefaultParser& fp, const std::string& funcStr, + int exponent, bool isOptimized) +{ + const int absExponent = exponent < 0 ? -exponent : exponent; + + for(int valueOffset = 0; valueOffset <= 5; ++valueOffset) + { + const DefaultValue_t value = + (exponent >= 0 && valueOffset == 0) ? 0.0 : + 1.0+(valueOffset-1)/100.0; + DefaultValue_t v1 = exponent == 0 ? 1 : value; + for(int i = 2; i <= absExponent; ++i) + v1 *= value; + if(exponent < 0) v1 = 1.0/v1; + + const DefaultValue_t v2 = fp.Eval(&value); + + if(!compareExpValues(value, funcStr, v1, v2, isOptimized)) + return false; + } + + return true; +} + +bool runFractionalPowTest(const std::string& funcStr, double exponent) +{ + DefaultParser fp; + if(fp.Parse(funcStr, "x") != -1) + { + if(verbosityLevel >= 2) + std::cout << "\n - Parsing \"" << funcStr <<"\" failed: " + << fp.ErrorMsg() << "\n"; + return false; + } + + for(int i = 0; i < 3; ++i) + { + for(int valueOffset = 0; valueOffset <= 10; ++valueOffset) + { + const DefaultValue_t value = + (exponent >= 0 && valueOffset == 0) ? 0.0 : + 1.0+(valueOffset-1)/2.0; + const DefaultValue_t v1 = std::pow(value, exponent); + const DefaultValue_t v2 = fp.Eval(&value); + + if(!compareExpValues(value, funcStr, v1, v2, i > 0)) + return false; + } + fp.Optimize(); + } + + return true; +} + +int TestIntPow() +{ + DefaultParser fp; + + for(int exponent = -1300; exponent <= 1300; ++exponent) + { + std::ostringstream os; + os << "x^" << exponent; + const std::string func = os.str(); + if(fp.Parse(func, "x") != -1) + { + if(verbosityLevel >= 2) + std::cout << "\n - Parsing \"" << func <<"\" failed: " + << fp.ErrorMsg() << "\n"; + return false; + } + + if(!runIntPowTest(fp, func, exponent, false)) return false; + fp.Optimize(); + if(!runIntPowTest(fp, func, exponent, true)) return false; + } + + for(int m = -27; m <= 27; ++m) + { + for(int n_sqrt=0; n_sqrt<=4; ++n_sqrt) + for(int n_cbrt=0; n_cbrt<=4; ++n_cbrt) + { + if(n_sqrt+n_cbrt == 0) continue; + + std::ostringstream os; + os << "x^(" << m << "/(1"; + for(int n=0; n<n_sqrt; ++n) os << "*2"; + for(int n=0; n<n_cbrt; ++n) os << "*3"; + os << "))"; + DefaultValue_t exponent = DefaultValue_t(m); + if(n_sqrt > 0) exponent /= std::pow(2.0, n_sqrt); + if(n_cbrt > 0) exponent /= std::pow(3.0, n_cbrt); + if(!runFractionalPowTest(os.str(), exponent)) return false; + } + } + + return true; +} + + +//========================================================================= +// Test UTF-8 parsing +//========================================================================= +namespace +{ + typedef unsigned char UChar; + struct CharValueRange { const UChar first, last; }; + + const CharValueRange validValueRanges[][4] = + { + { { 0x30, 0x39 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // digits + { { 0x41, 0x5A }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // uppercase ascii + { { 0x5F, 0x5F }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // underscore + { { 0x61, 0x7A }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, // lowercase ascii + // U+0080 through U+009F + { { 0xC2, 0xC2 }, { 0x80, 0x9F }, { 0, 0 }, { 0, 0 } }, + // U+00A1 through U+00BF + { { 0xC2, 0xC2 }, { 0xA1, 0xBF }, { 0, 0 }, { 0, 0 } }, + // U+00C0 through U+07FF + { { 0xC3, 0xDF }, { 0x80, 0xBF }, { 0, 0 }, { 0, 0 } }, + // U+0800 through U+1FFF (skip U+2000..U+200bB, which are whitespaces) + { { 0xE0, 0xE0 }, { 0xA0, 0xBF }, { 0x80, 0xBF }, { 0, 0 } }, + { { 0xE1, 0xE1 }, { 0x80, 0xBF }, { 0x80, 0xBF }, { 0, 0 } }, + // U+200C through U+202E (skip U+202F, which is a whitespace) + { { 0xE2, 0xE2 }, { 0x80, 0x80 }, { 0x8C, 0xAE }, { 0, 0 } }, + // U+2030 through U+205E (skip U+205F, which is a whitespace) + { { 0xE2, 0xE2 }, { 0x80, 0x80 }, { 0xB0, 0xBF }, { 0, 0 } }, + { { 0xE2, 0xE2 }, { 0x81, 0x81 }, { 0x80, 0x9E }, { 0, 0 } }, + // U+2060 through U+20FF (skip U+3000, which is a whitespace) + { { 0xE2, 0xE2 }, { 0x81, 0x81 }, { 0xA0, 0xBF }, { 0, 0 } }, + { { 0xE2, 0xE2 }, { 0x82, 0xBF }, { 0x80, 0xBF }, { 0, 0 } }, + // U+3001 through U+CFFF + { { 0xE3, 0xE3 }, { 0x80, 0x80 }, { 0x81, 0xBF }, { 0, 0 } }, + { { 0xE3, 0xE3 }, { 0x81, 0xBF }, { 0x80, 0xBF }, { 0, 0 } }, + { { 0xE4, 0xEC }, { 0x80, 0xBF }, { 0x80, 0xBF }, { 0, 0 } }, + // U+E000 through U+FFFF + { { 0xEE, 0xEF }, { 0x80, 0xBF }, { 0x80, 0xBF }, { 0, 0 } }, + // U+10000 through U+FFFFF + { { 0xF0, 0xF0 }, { 0x90, 0xBF }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + { { 0xF1, 0xF3 }, { 0x80, 0xBF }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + // U+100000 through U+10FFFF + { { 0xF4, 0xF4 }, { 0x80, 0x8F }, { 0x80, 0xBF }, { 0x80, 0xBF } } + }; + const unsigned validValueRangesAmount = + sizeof(validValueRanges)/sizeof(validValueRanges[0]); + + const CharValueRange invalidValueRanges[][4] = + { + // spaces: + { { 0x09, 0x09 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x0A, 0x0A }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x0B, 0x0B }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x0D, 0x0D }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x20, 0x20 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0xC2, 0xC2 }, { 0xA0, 0xA0 }, { 0, 0 }, { 0, 0 } }, + { { 0xE2, 0xE2 }, { 0x80, 0x80 }, { 0x80, 0x8B }, { 0, 0 } }, + { { 0xE2, 0xE2 }, { 0x80, 0x80 }, { 0xAF, 0xAF }, { 0, 0 } }, + { { 0xE2, 0xE2 }, { 0x81, 0x81 }, { 0x9F, 0x9F }, { 0, 0 } }, + { { 0xE3, 0xE3 }, { 0x80, 0x80 }, { 0x80, 0x80 }, { 0, 0 } }, + // others: + { { 0xC0, 0xC1 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0xED, 0xED }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0xF5, 0xFF }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x21, 0x2F }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x3A, 0x40 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x5B, 0x5E }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x60, 0x60 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x7B, 0x7F }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0x80, 0xFF }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, + { { 0xE0, 0xEF }, { 0x80, 0xFF }, { 0, 0 }, { 0, 0 } }, + { { 0xF0, 0xF4 }, { 0x80, 0xFF }, { 0x80, 0xFF }, { 0, 0 } }, + + { { 0xC2, 0xDF }, { 0x00, 0x7F }, { 0, 0 }, { 0, 0 } }, + { { 0xC2, 0xDF }, { 0xC0, 0xFF }, { 0, 0 }, { 0, 0 } }, + + { { 0xE0, 0xE0 }, { 0x00, 0x9F }, { 0x80, 0xBF }, { 0, 0 } }, + { { 0xE0, 0xE0 }, { 0xA0, 0xBF }, { 0x00, 0x7F }, { 0, 0 } }, + { { 0xE0, 0xE0 }, { 0xA0, 0xBF }, { 0xC0, 0xFF }, { 0, 0 } }, + + { { 0xE1, 0xEC }, { 0x00, 0x7F }, { 0x80, 0xBF }, { 0, 0 } }, + { { 0xE1, 0xEC }, { 0xC0, 0xFF }, { 0x80, 0xBF }, { 0, 0 } }, + { { 0xE1, 0xEC }, { 0x80, 0xBF }, { 0x00, 0x7F }, { 0, 0 } }, + { { 0xE1, 0xEC }, { 0x80, 0xBF }, { 0xC0, 0xFF }, { 0, 0 } }, + + { { 0xEE, 0xEF }, { 0x00, 0x7F }, { 0x80, 0xBF }, { 0, 0 } }, + { { 0xEE, 0xEF }, { 0xC0, 0xFF }, { 0x80, 0xBF }, { 0, 0 } }, + { { 0xEE, 0xEF }, { 0x80, 0xBF }, { 0x00, 0x7F }, { 0, 0 } }, + { { 0xEE, 0xEF }, { 0x80, 0xBF }, { 0xC0, 0xFF }, { 0, 0 } }, + + { { 0xF0, 0xF0 }, { 0x00, 0x8F }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + { { 0xF0, 0xF0 }, { 0xC0, 0xFF }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + { { 0xF0, 0xF0 }, { 0x90, 0xBF }, { 0x00, 0x7F }, { 0x80, 0xBF } }, + { { 0xF0, 0xF0 }, { 0x90, 0xBF }, { 0xC0, 0xFF }, { 0x80, 0xBF } }, + { { 0xF0, 0xF0 }, { 0x90, 0xBF }, { 0x80, 0xBF }, { 0x00, 0x7F } }, + { { 0xF0, 0xF0 }, { 0x90, 0xBF }, { 0x80, 0xBF }, { 0xC0, 0xFF } }, + + { { 0xF1, 0xF3 }, { 0x00, 0x7F }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + { { 0xF1, 0xF3 }, { 0xC0, 0xFF }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + { { 0xF1, 0xF3 }, { 0x80, 0xBF }, { 0x00, 0x7F }, { 0x80, 0xBF } }, + { { 0xF1, 0xF3 }, { 0x80, 0xBF }, { 0xC0, 0xFF }, { 0x80, 0xBF } }, + { { 0xF1, 0xF3 }, { 0x80, 0xBF }, { 0x80, 0xBF }, { 0x00, 0x7F } }, + { { 0xF1, 0xF3 }, { 0x80, 0xBF }, { 0x80, 0xBF }, { 0xC0, 0xFF } }, + + { { 0xF4, 0xF4 }, { 0x00, 0x7F }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + { { 0xF4, 0xF4 }, { 0x90, 0xFF }, { 0x80, 0xBF }, { 0x80, 0xBF } }, + { { 0xF4, 0xF4 }, { 0x80, 0x8F }, { 0x00, 0x7F }, { 0x80, 0xBF } }, + { { 0xF4, 0xF4 }, { 0x80, 0x8F }, { 0xC0, 0xFF }, { 0x80, 0xBF } }, + { { 0xF4, 0xF4 }, { 0x80, 0x8F }, { 0x80, 0xBF }, { 0x00, 0x7F } }, + { { 0xF4, 0xF4 }, { 0x80, 0x8F }, { 0x80, 0xBF }, { 0xC0, 0xFF } } + }; + const unsigned invalidValueRangesAmount = + sizeof(invalidValueRanges)/sizeof(invalidValueRanges[0]); + + class CharIter + { + const CharValueRange (*valueRanges)[4]; + const unsigned valueRangesAmount; + UChar charValues[4]; + unsigned rangeIndex, firstRangeIndex, skipIndex; + + void initCharValues() + { + for(unsigned i = 0; i < 4; ++i) + charValues[i] = valueRanges[rangeIndex][i].first; + } + + public: + CharIter(bool skipDigits, bool skipLowerCaseAscii): + valueRanges(validValueRanges), + valueRangesAmount(validValueRangesAmount), + rangeIndex(skipDigits ? 1 : 0), + firstRangeIndex(skipDigits ? 1 : 0), + skipIndex(skipLowerCaseAscii ? 3 : ~0U) + { + initCharValues(); + } + + CharIter(): + valueRanges(invalidValueRanges), + valueRangesAmount(invalidValueRangesAmount), + rangeIndex(0), firstRangeIndex(0), skipIndex(~0U) + { + initCharValues(); + } + + void appendChar(std::string& dest) const + { + for(unsigned i = 0; i < 4; ++i) + { + if(charValues[i] == 0) break; + dest += char(charValues[i]); + } + } + + bool next() + { + for(unsigned i = 0; i < 4; ++i) + { + if(charValues[i] < valueRanges[rangeIndex][i].last) + { + ++charValues[i]; + return true; + } + } + if(++rangeIndex == skipIndex) ++rangeIndex; + if(rangeIndex < valueRangesAmount) + { + initCharValues(); + return true; + } + rangeIndex = firstRangeIndex; + initCharValues(); + return false; + } + + void print() const + { + std::printf("{"); + for(unsigned i = 0; i < 4; ++i) + { + if(charValues[i] == 0) break; + if(i > 0) std::printf(","); + std::printf("%02X", unsigned(charValues[i])); + } + std::printf("}"); + } + }; + + bool printUTF8TestError(const char* testType, + const CharIter* iters, unsigned length, + const std::string& identifier) + { + if(verbosityLevel >= 2) + { + std::printf("\n - %s failed with identifier ", testType); + for(unsigned i = 0; i < length; ++i) + iters[i].print(); + std::printf(": \"%s\"\n", identifier.c_str()); + } + return false; + } + + bool printUTF8TestError2(const CharIter* iters, unsigned length) + { + if(verbosityLevel >= 2) + { + std::printf("\n - Parsing didn't fail with invalid identifier "); + for(unsigned i = 0; i < length; ++i) + iters[(length-1)-i].print(); + std::printf("\n"); + } + return false; + } +} + +int UTF8Test() +{ + typedef DefaultParser::value_type Value_t; + + CharIter iters[4] = + { CharIter(true, false), + CharIter(false, true), + CharIter(false, false), + CharIter(false, false) }; + std::string identifier; + DefaultParser fp; + const Value_t value = 0.0; + + for(unsigned length = 1; length <= 4; ++length) + { + if(verbosityLevel >= 1) + std::cout << " " << length << std::flush; + bool cont = true; + while(cont) + { + identifier.clear(); + for(unsigned i = 0; i < length; ++i) + iters[i].appendChar(identifier); + + if(fp.Parse(identifier, identifier) >= 0) + return printUTF8TestError("Parsing", iters, length, identifier); + + if(fp.Eval(&value) != 0.0) + return printUTF8TestError("Evaluation", iters, length, + identifier); + + cont = false; + const unsigned step = (length == 1) ? 1 : length-1; + for(unsigned i = 0; i < length; i += step) + if(iters[i].next()) + { + cont = true; + break; + } + } + } + + CharIter invalidIters[3] = + { CharIter(), CharIter(true, false), CharIter() }; + // test 5: inv + // test 6: inv + normal + // test 7: normal + inv + + for(unsigned length = 1; length <= 3; ++length) + { + if(verbosityLevel >= 1) + std::cout << " " << 4+length << std::flush; + unsigned numchars = length < 3 ? length : 2; + unsigned firstchar = length < 3 ? 0 : 1; + bool cont = true; + while(cont) + { + identifier.clear(); + identifier += 'a'; + for(unsigned i = 0; i < numchars; ++i) + invalidIters[firstchar+i].appendChar(identifier); + identifier += 'a'; + + if(fp.Parse(identifier, identifier) < 0) + return printUTF8TestError2(invalidIters, length); + + cont = false; + for(unsigned i = 0; i < numchars; ++i) + if(invalidIters[firstchar+i].next()) + { + cont = true; + break; + } + } + } + + return true; +} + + +//========================================================================= +// Test identifier adding and removal +//========================================================================= +bool AddIdentifier(DefaultParser& fp, const std::string& name, int type) +{ + static DefaultParser anotherParser; + static bool anotherParserInitialized = false; + if(!anotherParserInitialized) + { + anotherParser.Parse("x", "x"); + anotherParserInitialized = true; + } + + switch(type) + { + case 0: return fp.AddConstant(name, 123); + case 1: return fp.AddUnit(name, 456); + case 2: return fp.AddFunction(name, userDefFuncSqr<DefaultValue_t>, 1); + case 3: return fp.AddFunction(name, anotherParser); + } + return false; +} + +int TestIdentifiers() +{ + DefaultParser fParser; + std::vector<std::string> identifierNames(26*26, std::string("AA")); + + unsigned nameInd = 0; + for(int i1 = 0; i1 < 26; ++i1) + { + for(int i2 = 0; i2 < 26; ++i2) + { + identifierNames.at(nameInd)[0] = char('A' + i1); + identifierNames[nameInd][1] = char('A' + i2); + + if(!AddIdentifier(fParser, identifierNames[nameInd], (i1+26*i2)%3)) + { + if(verbosityLevel >= 2) + std::cout << "\n - Failed to add identifier '" + << identifierNames[nameInd] << "'\n"; + return false; + } + + ++nameInd; + } + } + + std::random_shuffle(identifierNames.begin(), identifierNames.end()); + + for(unsigned nameInd = 0; nameInd <= identifierNames.size(); ++nameInd) + { + for(unsigned removedInd = 0; removedInd < nameInd; ++removedInd) + { + if(!AddIdentifier(fParser, identifierNames[removedInd], 3)) + { + if(verbosityLevel >= 2) + std::cout + << "\n - Failure: Identifier '" + << identifierNames[removedInd] + << "' was still reserved even after removing it.\n"; + return false; + } + if(!fParser.RemoveIdentifier(identifierNames[removedInd])) + { + if(verbosityLevel >= 2) + std::cout << "\n - Failure: Removing the identifier '" + << identifierNames[removedInd] + << "' after adding it again failed.\n"; + return false; + } + } + + for(unsigned existingInd = nameInd; + existingInd < identifierNames.size(); ++existingInd) + { + if(AddIdentifier(fParser, identifierNames[existingInd], 3)) + { + if(verbosityLevel >= 2) + std::cout << "\n - Failure: Trying to add identifier '" + << identifierNames[existingInd] + << "' for a second time didn't fail.\n"; + return false; + } + } + + if(nameInd < identifierNames.size()) + { + if(!fParser.RemoveIdentifier(identifierNames[nameInd])) + { + if(verbosityLevel >= 2) + std::cout << "\n - Failure: Trying to remove identifier '" + << identifierNames[nameInd] << "' failed.\n"; + return false; + } + if(fParser.RemoveIdentifier(identifierNames[nameInd])) + { + if(verbosityLevel >= 2) + std::cout << "\n - Failure: Trying to remove identifier '" + << identifierNames[nameInd] + << "' for a second time didn't fail.\n"; + return false; + } + } + } + + return true; +} + + +//========================================================================= +// Test user-defined functions +//========================================================================= +namespace +{ + template<int VarsAmount> + DefaultValue_t userFunction(const DefaultValue_t* p) + { + DefaultValue_t result = 1.0; + for(int i = 0; i < VarsAmount; ++i) + result += (VarsAmount+i/10.0) * p[i]; + return result; + } + + DefaultValue_t(*userFunctions[])(const DefaultValue_t*) = + { + userFunction<0>, userFunction<1>, userFunction<2>, userFunction<3>, + userFunction<4>, userFunction<5>, userFunction<6>, userFunction<7>, + userFunction<8>, userFunction<9>, userFunction<10>, userFunction<11> + }; + const unsigned userFunctionsAmount = + sizeof(userFunctions) / sizeof(userFunctions[0]); + + DefaultValue_t nestedFunc1(const DefaultValue_t* p) + { + return p[0] + 2.0*p[1] + 3.0*p[2]; + } + + DefaultValue_t nestedFunc2(const DefaultValue_t* p) + { + const DefaultValue_t params[3] = { -5.0*p[0], -10.0*p[1], -p[0] }; + return p[0] + 4.0*nestedFunc1(params); + } + + DefaultValue_t nestedFunc3(const DefaultValue_t* p) + { + const DefaultValue_t params1[3] = { 2.5*p[0]+2.0, p[2], p[1]/2.5 }; + const DefaultValue_t params2[2] = { p[1] / 1.5 - 1.0, p[0] - 2.5 }; + return nestedFunc1(params1) + nestedFunc2(params2); + } +} + +int testUserDefinedFunctions() +{ + const DefaultValue_t epsilon = testbedEpsilon<DefaultValue_t>(); + + DefaultParser nestedParser1, nestedParser2, nestedParser3; + nestedParser1.Parse("x + 2.0*y + 3.0*z", "x, y, z"); + nestedParser2.AddFunction("nestedFunc1", nestedParser1); + nestedParser2.Parse("x + 4.0*nestedFunc1(-5.0*x, -10.0*y, -x)", "x,y"); + nestedParser3.AddFunction("nestedFunc1", nestedParser1); + nestedParser3.AddFunction("nestedFunc2", nestedParser2); + nestedParser3.Parse("nestedFunc1(2.5*x+2.0, z, y/2.5) + " + "nestedFunc2(y/1.5 - 1.0, x - 2.5)", "x,y,z"); + + for(int iteration = 0; iteration < 2; ++iteration) + { + DefaultValue_t nestedFuncParams[3]; + for(int i = 0; i < 100; ++i) + { + nestedFuncParams[0] = -10.0 + 20.0*i/100.0; + for(int j = 0; j < 100; ++j) + { + nestedFuncParams[1] = -10.0 + 20.0*j/100.0; + for(int k = 0; k < 100; ++k) + { + nestedFuncParams[2] = -10.0 + 20.0*k/100.0; + + const DefaultValue_t v1 = + nestedParser3.Eval(nestedFuncParams); + const DefaultValue_t v2 = + nestedFunc3(nestedFuncParams); + if(std::fabs(v1-v2) > epsilon) + { + if(verbosityLevel >= 2) + std::cout + << "\n - Nested function test failed with " + << "parameter values (" + << nestedFuncParams[0] << "," + << nestedFuncParams[1] + << ").\nThe library " + << (iteration > 0 ? "(optimized) " : "") + << "returned " << v1 + << " instead of " << v2 << "." << std::endl; + return false; + } + } + } + } + nestedParser3.Optimize(); + } + + std::string funcNames[userFunctionsAmount]; + std::string userFunctionParserFunctions[userFunctionsAmount]; + std::string userFunctionParserParameters[userFunctionsAmount]; + DefaultParser userFunctionParsers[userFunctionsAmount]; + DefaultValue_t funcParams[userFunctionsAmount]; + DefaultParser parser1, parser2; + + for(unsigned funcInd = 0; funcInd < userFunctionsAmount; ++funcInd) + { + std::ostringstream functionString, paramString; + + functionString << '1'; + for(unsigned paramInd = 0; paramInd < funcInd; ++paramInd) + { + functionString << "+" << funcInd+paramInd/10.0 + << "*p" << paramInd; + + if(paramInd > 0) paramString << ','; + paramString << "p" << paramInd; + } + + userFunctionParserFunctions[funcInd] = functionString.str(); + userFunctionParserParameters[funcInd] = paramString.str(); + + if(userFunctionParsers[funcInd].Parse + (userFunctionParserFunctions[funcInd], + userFunctionParserParameters[funcInd]) >= 0) + { + if(verbosityLevel >= 2) + std::cout << "\n - Failed to parse function\n\"" + << functionString.str() << "\"\nwith parameters: \"" + << paramString.str() << "\":\n" + << userFunctionParsers[funcInd].ErrorMsg() << "\n"; + return false; + } + + for(unsigned testInd = 0; testInd < 10; ++testInd) + { + for(unsigned paramInd = 0; paramInd < testInd; ++paramInd) + funcParams[paramInd] = testInd+paramInd; + const DefaultValue_t result = userFunctions[funcInd](funcParams); + const DefaultValue_t parserResult = + userFunctionParsers[funcInd].Eval(funcParams); + if(std::fabs(result - parserResult) > epsilon) + { + if(verbosityLevel >= 2) + { + std::cout << "\n - Function\n\"" << functionString.str() + << "\"\nwith parameters ("; + for(unsigned paramInd = 0; paramInd < testInd; ++paramInd) + { + if(paramInd > 0) std::cout << ','; + std::cout << funcParams[paramInd]; + } + std::cout << ")\nreturned " << parserResult + << " instead of " << result << "\n"; + } + return false; + } + } + } + + for(unsigned funcInd = 0; funcInd < userFunctionsAmount; ++funcInd) + { + funcNames[funcInd] = "func00"; + funcNames[funcInd][4] = char('0' + funcInd/10); + funcNames[funcInd][5] = char('0' + funcInd%10); + + if(!parser1.AddFunction(funcNames[funcInd], userFunctions[funcInd], + funcInd)) + { + if(verbosityLevel >= 2) + std::cout << "\n - Failed to add user-defined function \"" + << funcNames[funcInd] << "\".\n"; + return false; + } + if(!parser2.AddFunction(funcNames[funcInd], + userFunctionParsers[funcInd])) + { + if(verbosityLevel >= 2) + std::cout + << "\n - Failed to add user-defined function parser \"" + << funcNames[funcInd] << "\".\n"; + return false; + } + + std::ostringstream functionString; + for(unsigned factorInd = 0; factorInd <= funcInd; ++factorInd) + { + if(factorInd > 0) functionString << '+'; + functionString << factorInd+1 << "*" + << funcNames[factorInd] << '('; + for(unsigned paramInd = 0; paramInd < factorInd; ++paramInd) + { + if(paramInd > 0) functionString << ','; + const unsigned value = factorInd*funcInd + paramInd; + functionString << value << "+x"; + } + functionString << ')'; + } + + if(parser1.Parse(functionString.str(), "x") >= 0) + { + if(verbosityLevel >= 2) + std::cout << "\n - parser1 failed to parse function\n\"" + << functionString.str() << "\":\n" + << parser1.ErrorMsg() << "\n"; + return false; + } + if(parser2.Parse(functionString.str(), "x") >= 0) + { + if(verbosityLevel >= 2) + std::cout << "\n - parser2 failed to parse function\n\"" + << functionString.str() << "\":\n" + << parser2.ErrorMsg() << "\n"; + return false; + } + + for(unsigned optimizeInd = 0; optimizeInd < 4; ++optimizeInd) + { + for(unsigned testInd = 0; testInd < 100; ++testInd) + { + const DefaultValue_t x = testInd/10.0; + DefaultValue_t result = 0.0; + for(unsigned factorInd = 0; factorInd <= funcInd; ++factorInd) + { + for(unsigned paramInd = 0; paramInd < factorInd; ++paramInd) + { + const unsigned value = factorInd*funcInd + paramInd; + funcParams[paramInd] = value+x; + } + result += + (factorInd+1) * userFunctions[factorInd](funcParams); + } + + const DefaultValue_t parser1Result = parser1.Eval(&x); + const DefaultValue_t parser2Result = parser2.Eval(&x); + const bool parser1Failed = + std::fabs(result - parser1Result) > epsilon; + const bool parser2Failed = + std::fabs(result - parser2Result) > epsilon; + + if(parser1Failed || parser2Failed) + { + if(verbosityLevel >= 2) + { + std::cout << "\n - For function:\n\"" + << functionString.str() << "\""; + if(optimizeInd > 0) + std::cout << "\n(Optimized " << optimizeInd + << (optimizeInd > 1 ? + " times)" : " time)"); + std::cout << "\nwith x=" << x + << " parser"; + if(parser1Failed) + std::cout << "1 returned " << parser1Result; + else + std::cout << "2 returned " << parser2Result; + std::cout << " instead of " << result << ".\n"; + + if(parser2Failed) + { + std::cout << "The user-defined functions are:\n"; + for(unsigned i = 0; i <= funcInd; ++i) + std::cout << funcNames[i] << "=\"" + << userFunctionParserFunctions[i] + << "\"\n"; + } + } + + return false; + } + } + + parser1.Optimize(); + } + } + + return true; +} + + +//========================================================================= +// Multithreaded test +//========================================================================= +#if defined(FP_USE_THREAD_SAFE_EVAL) || \ + defined(FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA) +#include <boost/thread.hpp> + +class TestingThread +{ + int mThreadNumber; + DefaultParser* mFp; + volatile static bool mOk; + + static DefaultValue_t function(const DefaultValue_t* vars) + { + const DefaultValue_t x = vars[0], y = vars[1]; + return sin(sqrt(x*x+y*y)) + 2*cos(2*sqrt(2*x*x+2*y*y)); + } + + public: + TestingThread(int n, DefaultParser* fp): + mThreadNumber(n), mFp(fp) + {} + + static bool ok() { return mOk; } + + void operator()() + { + const DefaultValue_t epsilon = testbedEpsilon<DefaultValue_t>(); + DefaultValue_t vars[2]; + for(vars[0] = -10.0; vars[0] <= 10.0; vars[0] += 0.02) + { + for(vars[1] = -10.0; vars[1] <= 10.0; vars[1] += 0.02) + { + if(!mOk) return; + + const DefaultValue_t v1 = function(vars); + const DefaultValue_t v2 = mFp->Eval(vars); + /* + const double scale = pow(10.0, floor(log10(fabs(v1)))); + const double sv1 = fabs(v1) < testbedEpsilon<double>() ? 0 : v1/scale; + const double sv2 = fabs(v2) < testbedEpsilon<double>() ? 0 : v2/scale; + const double diff = fabs(sv2-sv1); + */ + const DefaultValue_t diff = + std::fabs(v1) < epsilon ? + (std::fabs(v2) < epsilon ? + std::fabs(v1 - v2) : + std::fabs((v1 - v2) / v2)) : + std::fabs((v1 - v2) / v1); + + if(std::fabs(diff) > epsilon) + { + mOk = false; + if(verbosityLevel >= 2) + std::cout << "\n - Thread " << mThreadNumber + << " failed ([" << vars[0] << "," << vars[1] + << "] -> " << v2 << " vs. " << v1 << ")" + << std::endl; + return; + } + } + } + } +}; + +volatile bool TestingThread::mOk = true; + +int testMultithreadedEvaluation() +{ + DefaultParser fp; + fp.Parse("sin(sqrt(x*x+y*y)) + 2*cos(2*sqrt(2*x*x+2*y*y))", "x,y"); + + if(verbosityLevel >= 1) + std::cout << " 1" << std::flush; + boost::thread t1(TestingThread(1, &fp)), t2(TestingThread(2, &fp)); + t1.join(); + t2.join(); + if(!TestingThread::ok()) return false; + + if(verbosityLevel >= 1) + std::cout << " 2" << std::flush; + boost::thread + t3(TestingThread(3, &fp)), t4(TestingThread(4, &fp)), + t5(TestingThread(5, &fp)), t6(TestingThread(6, &fp)); + t3.join(); + t4.join(); + t5.join(); + t6.join(); + if(!TestingThread::ok()) return false; + + if(verbosityLevel >= 1) + std::cout << " 3" << std::flush; + fp.Optimize(); + boost::thread + t7(TestingThread(7, &fp)), t8(TestingThread(8, &fp)), + t9(TestingThread(9, &fp)); + t7.join(); + t8.join(); + t9.join(); + if(!TestingThread::ok()) return false; + + return true; +} + +#else + +int testMultithreadedEvaluation() +{ + return -1; +} + +#endif + +//========================================================================= +// Test variable deduction +//========================================================================= +template<typename Value_t> +struct TestType +{ + unsigned paramAmount; + Value_t paramMin, paramMax, paramStep; + bool useDegrees; + + Value_t (*funcPtr)(const Value_t*); +#ifdef FP_TEST_WANT_DOUBLE_TYPE + double (*doubleFuncPtr)(const double*); +#endif +#ifdef FP_TEST_WANT_LONG_INT_TYPE + long (*longFuncPtr)(const long*); +#endif + + const char* paramString; + const char* testName; + const char* funcString; +}; + + +template<typename Value_t> +bool checkVarString(const char* idString, + FunctionParserBase<Value_t> & fp, + const TestType<Value_t>& testData, + int errorIndex, + int variablesAmount, const std::string& variablesString, + std::ostream& briefErrorMessages) +{ + const bool stringsMatch = + (variablesString == testData.paramString); + if(errorIndex >= 0 || + variablesAmount != int(testData.paramAmount) || + !stringsMatch) + { + if(verbosityLevel >= 2) + { + std::cout << "\n" << idString + << " ParseAndDeduceVariables() failed with function:\n\"" + << testData.funcString << "\"\n"; + if(errorIndex >= 0) + std::cout << "Error index: " << errorIndex + << ": " << fp.ErrorMsg() << std::endl; + else if(!stringsMatch) + std::cout << "Deduced var string was \"" << variablesString + << "\" instead of \"" + << testData.paramString + << "\"." << std::endl; + else + std::cout << "Deduced variables amount was " + << variablesAmount << " instead of " + << testData.paramAmount << "." + << std::endl; + } + else + { + briefErrorMessages << "- " << testData.testName + << ": Failed ParseAndDeduceVariables().\n"; + } + return false; + } + return true; +} + +template<typename Value_t> +bool testVariableDeduction(FunctionParserBase<Value_t>& fp, + const TestType<Value_t>& testData, + std::ostream& briefErrorMessages) +{ + static std::string variablesString; + static std::vector<std::string> variables; + + if(verbosityLevel >= 3) + std::cout << "(Variable deduction)" << std::flush; + + int variablesAmount = -1; + int retval = fp.ParseAndDeduceVariables + (testData.funcString, + &variablesAmount, testData.useDegrees); + if(retval >= 0 || variablesAmount != + int(testData.paramAmount)) + { + if(verbosityLevel >= 2) + { + std::cout << + "\nFirst ParseAndDeduceVariables() failed with function:\n\"" + << testData.funcString << "\"\n"; + if(retval >= 0) + std::cout << "Error index: " << retval + << ": " << fp.ErrorMsg() << std::endl; + else + std::cout << "Deduced variables amount was " + << variablesAmount << " instead of " + << testData.paramAmount << "." + << std::endl; + } + else + { + briefErrorMessages << "- " << testData.testName + << ": Failed ParseAndDeduceVariables().\n"; + } + return false; + } + + variablesAmount = -1; + retval = fp.ParseAndDeduceVariables + (testData.funcString, + variablesString, + &variablesAmount, + testData.useDegrees); + if(!checkVarString("Second", fp, testData, retval, variablesAmount, + variablesString, briefErrorMessages)) + return false; + + retval = fp.ParseAndDeduceVariables(testData.funcString, + variables, + testData.useDegrees); + variablesAmount = int(variables.size()); + variablesString.clear(); + for(unsigned i = 0; i < variables.size(); ++i) + { + if(i > 0) variablesString += ','; + variablesString += variables[i]; + } + return checkVarString("Third", fp, testData, retval, variablesAmount, + variablesString, briefErrorMessages); +} + + +//========================================================================= +// Main test function +//========================================================================= +namespace +{ + template<typename Value_t> + struct RegressionTests + { + static const TestType<Value_t> Tests[]; + }; + template<typename Value_t> + const TestType<Value_t> RegressionTests<Value_t>::Tests[] = { TestType<Value_t>() }; + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + inline MpfrFloat makeMF(const char* str) + { + MpfrFloat f; + f.parseValue(str); + return f; + } +#endif + + /* These functions in fparser produce bool values. However, + * the testing functions require that they produce Value_t's. */ + #define BoolProxy(Fname) \ + template<typename Value_t> \ + Value_t tb_##Fname(const Value_t& a, const Value_t& b) \ + { return Value_t(FUNCTIONPARSERTYPES::Fname(a,b)); } + + BoolProxy(fp_less) + BoolProxy(fp_lessOrEq) + BoolProxy(fp_greater) + BoolProxy(fp_greaterOrEq) + BoolProxy(fp_equal) + BoolProxy(fp_nequal) + + template<typename Value_t> + Value_t fp_truth(const Value_t& a) + { return Value_t(FUNCTIONPARSERTYPES::fp_truth(a)); } + +// Maybe these should be used in the test files instead... +#define fp_less tb_fp_less +#define fp_lessOrEq tb_fp_lessOrEq +#define fp_greater tb_fp_greater +#define fp_greaterOrEq tb_fp_greaterOrEq +#define fp_equal tb_fp_equal +#define fp_nequal tb_fp_nequal + +#include "testbed_tests.inc" + +#undef fp_less +#undef fp_lessOrEq +#undef fp_greater +#undef fp_greaterOrEq +#undef fp_equal +#undef fp_nequal +} + +namespace +{ + template<typename Value_t> + void testAgainstDouble(Value_t*, Value_t, const TestType<Value_t>&, + std::ostream&) {} + +#if defined(FP_TEST_WANT_MPFR_FLOAT_TYPE) && defined(FP_TEST_WANT_DOUBLE_TYPE) + void testAgainstDouble(MpfrFloat* vars, MpfrFloat parserValue, + const TestType<MpfrFloat>& testData, + std::ostream& error) + { + if(!testData.doubleFuncPtr) return; + + double doubleVars[10]; + for(unsigned i = 0; i < 10; ++i) doubleVars[i] = vars[i].toDouble(); + + const double Eps = testbedEpsilon<double>(); + + const double v1 = testData.doubleFuncPtr(doubleVars); + const double v2 = parserValue.toDouble(); + + /* + using namespace FUNCTIONPARSERTYPES; + const double scale = fp_pow(10.0, fp_floor(fp_log10(fp_abs(v1)))); + const double sv1 = fp_abs(v1) < Eps ? 0 : v1/scale; + const double sv2 = fp_abs(v2) < Eps ? 0 : v2/scale; + const double diff = fp_abs(sv2-sv1); + */ + const double diff = + std::fabs(v1) < Eps ? + (std::fabs(v2) < Eps ? std::fabs(v1 - v2) : + std::fabs((v1 - v2) / v2)) : + std::fabs((v1 - v2) / v1); + + if(diff > Eps) + { + using namespace FUNCTIONPARSERTYPES; + if(verbosityLevel >= 2) + error << std::setprecision(16) << v2 << " instead of " + << std::setprecision(16) << v1 + << "\n(Difference: " + << std::setprecision(16) << v2-v1 + << ", epsilon: " + << std::setprecision(16) << Eps + << "; scaled diff " + << std::setprecision(16) << diff + << ")\nwhen tested against the double function."; + else + error << std::setprecision(16) << v2 << " vs " + << std::setprecision(16) << v1 + << " (diff: " + << std::setprecision(16) << v2-v1 + << ", sdiff " + << std::setprecision(16) << diff + << ") against double."; + } + } +#endif + + template<typename Value_t> + void testAgainstLongInt(Value_t*, Value_t, const TestType<Value_t>&, + std::ostream&) {} + +#if defined(FP_TEST_WANT_GMP_INT_TYPE) && defined(FP_TEST_WANT_LONG_INT_TYPE) + void testAgainstLongInt(GmpInt* vars, GmpInt parserValue, + const TestType<GmpInt>& testData, + std::ostream& error) + { + if(!testData.longFuncPtr) return; + + long longVars[10]; + for(unsigned i = 0; i < 10; ++i) longVars[i] = vars[i].toInt(); + + const long longValue = testData.longFuncPtr(longVars); + if(longValue != parserValue) + { + if(verbosityLevel >= 2) + error << parserValue << " instead of " << longValue + << "\nwhen tested against the long int function."; + else + error << parserValue << " vs " << longValue + << " against long."; + } + } +#endif +} + +template<typename Value_t> +bool runRegressionTest(FunctionParserBase<Value_t>& fp, + const TestType<Value_t>& testData, + const std::string& valueType, + const Value_t Eps, + std::ostream& briefErrorMessages) +{ + Value_t vars[10]; + Value_t fp_vars[10]; + + for(unsigned i = 0; i < testData.paramAmount; ++i) + vars[i] = testData.paramMin; + + while(true) + { + unsigned paramInd = 0; + while(paramInd < testData.paramAmount) + { + using namespace FUNCTIONPARSERTYPES; + /* ^ Import a possible <= operator from that + * namespace for this particular comparison only */ + vars[paramInd] += testData.paramStep; + if(vars[paramInd] <= testData.paramMax) break; + vars[paramInd++] = testData.paramMin; + } + + if(paramInd == testData.paramAmount) break; + + for(unsigned i = 0; i < testData.paramAmount; ++i) + fp_vars[i] = vars[i]; + + if(verbosityLevel >= 4) + { + std::cout << "Trying ("; + for(unsigned ind = 0; ind < testData.paramAmount; ++ind) + std::cout << (ind>0 ? ", " : "") << vars[ind]; + std::cout << ")\n" << std::flush; + } + const Value_t v1 = testData.funcPtr(vars); + if(true) /*test Eval() */ + { + const Value_t v2 = fp.Eval(fp_vars); + + std::ostringstream error; + + if(fp.EvalError() > 0) + { + error << "EvalError " << fp.EvalError() << " (" + << getEvalErrorName(fp.EvalError()) << ")"; + } + else if(FUNCTIONPARSERTYPES::IsIntType<Value_t>::result) + { + if(v1 != v2) + { + using namespace FUNCTIONPARSERTYPES; + if(verbosityLevel >= 2) + error << v2 << " instead of " << v1; + else + error << v2 << " vs " << v1; + } + else + testAgainstLongInt(vars, v2, testData, error); + } + else + { + using namespace FUNCTIONPARSERTYPES; + /* + const Value_t scale = + fp_pow(Value_t(10.0), fp_floor(fp_log10(fp_abs(v1)))); + const Value_t sv1 = fp_abs(v1) < Eps ? 0 : v1/scale; + const Value_t sv2 = fp_abs(v2) < Eps ? 0 : v2/scale; + const Value_t diff = fp_abs(sv2-sv1); + */ + const Value_t diff = + fp_abs(v1) < Eps ? + (fp_abs(v2) < Eps ? fp_abs(v1 - v2) : + fp_abs((v1 - v2) / v2)) : + fp_abs((v1 - v2) / v1); + /* + const Value_t diff = + v1 == Value_t(0) ? + (v2 == Value_t(0) ? Value_t(0) : + fp_abs((v1 - v2) / v2)) : + fp_abs((v1 - v2) / v1); + */ + + if(diff > Eps) + { + using namespace FUNCTIONPARSERTYPES; + if(verbosityLevel >= 2) + error << std::setprecision(28) << v2 << " instead of " + << std::setprecision(28) << v1 + << "\n(Difference: " + << std::setprecision(28) << v2-v1 + << ", epsilon: " + << std::setprecision(28) << Eps + << "; scaled diff " + << std::setprecision(28) << diff + << ")"; + else + error << std::setprecision(16) << v2 << " vs " + << std::setprecision(16) << v1 + << " (diff: " + << std::setprecision(16) << v2-v1 + << ", sdiff " + << std::setprecision(16) << diff + << ")"; + } + else + testAgainstDouble(vars, v2, testData, error); + } + + if(!error.str().empty()) + { + if(verbosityLevel == 2) + std::cout << "\n****************************\nTest " + << testData.testName + << ", function:\n\"" << testData.funcString + << "\"\n(" << valueType << ")"; + + if(verbosityLevel >= 2) + { + using namespace FUNCTIONPARSERTYPES; + // ^ For output of complex numbers according to fparser practice + + std::cout << std::endl << "Error: For (" << std::setprecision(20); + for(unsigned ind = 0; ind < testData.paramAmount; ++ind) + std::cout << (ind>0 ? ", " : "") << vars[ind]; + std::cout << ")\nthe library returned " << error.str() + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + fp.PrintByteCode(std::cout); +#endif + } + else + { + using namespace FUNCTIONPARSERTYPES; + + briefErrorMessages << "- " << testData.testName << " ("; + for(unsigned ind = 0; ind < testData.paramAmount; ++ind) + briefErrorMessages << (ind>0 ? "," : "") << vars[ind]; + briefErrorMessages << "): " << error.str() << "\n"; + } + return false; + } + } /* test Eval() */ + } + return true; +} + +static bool WildMatch(const char *pattern, const char *what) +{ + for(; *what || *pattern; ++what, ++pattern) + if(*pattern == '*') + { + while(*++pattern == '*') {} + for(; *what; ++what) + if(WildMatch(pattern, what)) + return true; + return !*pattern; + } + else if(*pattern != '?' && *pattern != *what) + return false; + return true; +} +static bool WildMatch_Dirmask(const char *pattern, const char *what) +{ + std::string testmask = pattern; + if(testmask.find('/') == testmask.npos) testmask = "*/" + testmask; + return WildMatch(testmask.c_str(), what); +} +bool IsSelectedTest(const char* testName) +{ + for(std::size_t a=0; a<selectedRegressionTests.size(); ++a) + if(WildMatch_Dirmask(selectedRegressionTests[a], testName)) + return true; + return false; +} +/* Asciibetical comparator, with in-string integer values sorted naturally */ +bool natcomp(const std::string& a, const std::string& b) +{ + std::size_t ap=0, bp=0; + while(ap < a.size() && bp < b.size()) + { + if(a[ap] >= '0' && a[ap] <= '9' + && b[bp] >= '0' && b[bp] <= '9') + { + unsigned long aval = (a[ap++] - '0'); + unsigned long bval = (b[bp++] - '0'); + while(ap < a.size() && a[ap] >= '0' && a[ap] <= '9') + aval = aval*10ul + (a[ap++] - '0'); + while(bp < b.size() && b[bp] >= '0' && b[bp] <= '9') + bval = bval*10ul + (b[bp++] - '0'); + if(aval != bval) + return aval < bval; + } + else + { + if(a[ap] != b[ap]) return a[ap] < b[ap]; + ++ap; ++bp; + } + } + return (bp < b.size() && ap >= a.size()); +} + + +template<typename Value_t> +bool runRegressionTests(const std::string& valueType) +{ + // Setup the function parser for testing + // ------------------------------------- + FunctionParserBase<Value_t> fp; + + if(verbosityLevel >= 1) + { + setAnsiBold(); + std::cout << "==================== Parser type \"" << valueType + << "\" ====================" << std::endl; + resetAnsiColor(); + } + + bool ret = fp.AddConstant("pi", + FUNCTIONPARSERTYPES::fp_const_pi<Value_t>()); + ret = ret && fp.AddConstant("naturalnumber", + FUNCTIONPARSERTYPES::fp_const_e<Value_t>()); + ret = ret && fp.AddConstant("logtwo", + FUNCTIONPARSERTYPES::fp_const_log2<Value_t>()); + ret = ret && fp.AddConstant("logten", + FUNCTIONPARSERTYPES::fp_const_log10<Value_t>()); + ret = ret && fp.AddConstant("CONST", Value_t(CONST)); + if(!ret) + { + std::cout << "Ooops! AddConstant() didn't work" << std::endl; + return false; + } + + ret = fp.AddUnit("doubled", 2); + ret = ret && fp.AddUnit("tripled", 3); + if(!ret) + { + std::cout << "Ooops! AddUnit() didn't work" << std::endl; + return false; + } + + ret = fp.AddFunctionWrapper + ("sub", UserDefFuncWrapper<Value_t>(userDefFuncSub<Value_t>), 2); + ret = ret && fp.AddFunction("sqr", userDefFuncSqr<Value_t>, 1); + ret = ret && fp.AddFunction("value", userDefFuncValue<Value_t>, 0); + if(!ret) + { + std::cout << "Ooops! AddFunction(ptr) didn't work" << std::endl; + return false; + } + + UserDefFuncWrapper<Value_t>* wrapper = + dynamic_cast<UserDefFuncWrapper<Value_t>*> + (fp.GetFunctionWrapper("sub")); + if(!wrapper || wrapper->counter() != 0) + { + std::cout << "Ooops! AddFunctionWrapper() didn't work" << std::endl; + return false; + } + + FunctionParserBase<Value_t> SqrFun, SubFun, ValueFun; + if(verbosityLevel >= 3) std::cout << "Parsing SqrFun... "; + SqrFun.Parse("x*x", "x"); + if(verbosityLevel >= 3) std::cout << "\nParsing SubFun... "; + SubFun.Parse("x-y", "x,y"); + if(verbosityLevel >= 3) std::cout << "\nParsing ValueFun... "; + ValueFun.Parse("5", ""); + if(verbosityLevel >= 3) std::cout << std::endl; + + ret = fp.AddFunction("psqr", SqrFun); + ret = ret && fp.AddFunction("psub", SubFun); + ret = ret && fp.AddFunction("pvalue", ValueFun); + if(!ret) + { + std::cout << "Ooops! AddFunction(parser) didn't work" << std::endl; + return false; + } + + // Test repeated constant addition + // ------------------------------- + {using namespace FUNCTIONPARSERTYPES; // For a possible custom < operator + for(Value_t value = 0; value < Value_t(20); value += 1) + { + if(!fp.AddConstant("TestConstant", value)) + { + std::cout << "Ooops2! AddConstant() didn't work" << std::endl; + return false; + } + + fp.Parse("TestConstant", ""); + if(fp.Eval(0) != value) + { + if(value == Value_t(0)) std::cout << "Usage of 'TestConstant' failed\n"; + else std::cout << "Changing the value of 'TestConstant' failed\n"; + return false; + } + }} + + bool allRegressionTestsOk = true; + std::ostringstream briefErrorMessages; + + std::string prev_test_prefix; + const unsigned maxtests = ~0U; // unknown + /* sizeof(RegressionTests<Value_t>::Tests) + / sizeof(RegressionTests<Value_t>::Tests[0]); */ + for(unsigned i = 0; i < maxtests; ++i) + { + const TestType<Value_t>& testData = RegressionTests<Value_t>::Tests[i]; + if(!testData.testName) break; + + if(!IsSelectedTest(testData.testName)) continue; + + const int retval = + fp.Parse(testData.funcString, testData.paramString, + testData.useDegrees); + if(retval >= 0) + { + std::cout << + "With FunctionParserBase<" << valueType << ">" + "\nin \"" << testData.funcString << + "\" (\"" << testData.paramString << + "\"), col " << retval << + ":\n" << fp.ErrorMsg() << std::endl; + return false; + } + + //fp.PrintByteCode(std::cout); + if(verbosityLevel >= 3) + { + std::cout + << /*std::right <<*/ std::setw(2) + << testData.testName << ": \"" + << testData.funcString << "\" (" + << FUNCTIONPARSERTYPES::fp_pow + ((testData.paramMax - testData.paramMin) / + testData.paramStep, + Value_t( (int) testData.paramAmount)) + << " param. combinations): " << std::flush; + } + else if(verbosityLevel == 2) + { + const char* tn = testData.testName; + const char* p = std::strrchr(tn, '/'); + if(!p) + { prev_test_prefix = ""; std::cout << tn; } + else + { + std::string path_prefix(tn, p-tn); + if(path_prefix == prev_test_prefix) + std::cout << (p+1); + else + { if(!prev_test_prefix.empty()) std::cout << std::endl; + std::cout << tn; + prev_test_prefix = path_prefix; } + } + std::cout << std::flush << " "; + } + + bool thisTestOk = + runRegressionTest(fp, testData, valueType + ", not optimized", + testbedEpsilon<Value_t>(), briefErrorMessages); + + if(thisTestOk) + { + if(verbosityLevel >= 3) std::cout << "Ok." << std::endl; + + fp.Optimize(); + //fp.PrintByteCode(std::cout); + + if(verbosityLevel >= 3) + std::cout << " Optimized: " << std::flush; + + thisTestOk = + runRegressionTest(fp, testData, + valueType + ", after optimization", + testbedEpsilon<Value_t>(), briefErrorMessages); + if(thisTestOk) + { + if(verbosityLevel >= 3) + std::cout << "(Calling Optimize() several times) " + << std::flush; + + for(int j = 0; j < 20; ++j) + fp.Optimize(); + + /* Sometimes literals drift when the optimizer is run many + times, which can become significant with floats. The only + purpose to test running the optimizer several times is just + to see that it doesn't break. It's not intended to be called + several times normally. Hence just skip testing with floats, + because the drift just causes differences larger than + epsilon... + */ + if(valueType != "float") + { + thisTestOk = + runRegressionTest + (fp, testData, + valueType + ", after several optimization runs", + testbedEpsilon<Value_t>(), briefErrorMessages); + } + + if(thisTestOk) + { + thisTestOk = + testVariableDeduction(fp, testData, briefErrorMessages); + + if(thisTestOk && verbosityLevel >= 3) + std::cout << "Ok." << std::endl; + } + } + } // if(thisTestOk) + + if(!thisTestOk) allRegressionTestsOk = false; + + if(verbosityLevel == 1) + std::cout << (thisTestOk ? "." : "!") << std::flush; + } // for(unsigned i = 0; i < maxtests; ++i) + + if(allRegressionTestsOk) + { + if(verbosityLevel == 1 || verbosityLevel == 2) + std::cout << std::endl; + } + else if(verbosityLevel <= 1) + { + if(verbosityLevel == 1) std::cout << "\n"; + std::cout << briefErrorMessages.str() << std::flush; + } + + if(verbosityLevel >= 2) + std::cout << "User-defined function \"sub\" was called " + << (dynamic_cast<UserDefFuncWrapper<Value_t>*> + (fp.GetFunctionWrapper("sub"))->counter()) + << " times." << std::endl; + + return allRegressionTestsOk; +} + +//========================================================================= +// Optimizer tests +//========================================================================= +namespace OptimizerTests +{ + // -------------------------------------------------------------------- + // Optimizer test 1 + // -------------------------------------------------------------------- + /* Tests functions of the form "A(x^B)^C op D(x^E)^F", where: + - A,D = {sin,cos,tan,sinh,cosh,tanh,exp} + - B,E = {1,2} + - C,F = {-2,-1,0,1,2} + - op = +, * + */ + struct MathFuncData + { + DefaultValue_t (*mathFunc)(DefaultValue_t d); + const char* funcName; + }; + + const MathFuncData mathFuncs[] = + { + { &std::sin, "sin" }, { &std::cos, "cos" }, { &std::tan, "tan" }, + { &std::sinh, "sinh" }, { &std::cosh, "cosh" }, { &std::tanh, "tanh" }, + { &std::exp, "exp" } + }; + const unsigned mathFuncsAmount = sizeof(mathFuncs) / sizeof(mathFuncs[0]); + + unsigned mathFuncIndexA, mathFuncIndexD; + int exponent_B, exponent_E; + int exponent_C, exponent_F; + unsigned operatorIndex; + + DefaultValue_t evaluateFunction(const DefaultValue_t* params) + { + const DefaultValue_t x = params[0]; + const MathFuncData& data1 = mathFuncs[mathFuncIndexA]; + const MathFuncData& data2 = mathFuncs[mathFuncIndexD]; + + const DefaultValue_t angle1 = + (exponent_B == 1 ? x : std::pow(x, exponent_B)); + const DefaultValue_t angle2 = + (exponent_E == 1 ? x : std::pow(x, exponent_E)); + const DefaultValue_t part1 = + std::pow(data1.mathFunc(angle1), exponent_C); + const DefaultValue_t part2 = + std::pow(data2.mathFunc(angle2), exponent_F); + + if(operatorIndex == 0) return part1 + part2; + return part1 * part2; + } + + bool runCurrentTrigCombinationTest() + { + const MathFuncData& data1 = mathFuncs[mathFuncIndexA]; + const MathFuncData& data2 = mathFuncs[mathFuncIndexD]; + + std::ostringstream os; + os << data1.funcName << "(x^" << exponent_B << ")^" << exponent_C; + if(operatorIndex == 0) os << "+"; + else os << "*"; + os << data2.funcName << "(x^" << exponent_E << ")^" << exponent_F; + const std::string funcString = os.str(); + + const TestType<DefaultValue_t> testData = + { + 1, -4.0, 4.0, 0.49, false, &evaluateFunction, DBL_ONLY(0)LNG_ONLY(0) + "x", "'trig. combo optimizer test'", funcString.c_str() + }; + + DefaultParser parser; + if(parser.Parse(funcString, "x") >= 0) + { + std::cout << "Oops: Function \"" << funcString + << "\" was malformed." << std::endl; + return false; + } + + std::ostringstream briefErrorMessages; + + if(!runRegressionTest(parser, testData, "DefaultValue_t", + testbedEpsilon<DefaultValue_t>(), briefErrorMessages)) + { + if(verbosityLevel == 1) + std::cout << "\n - " << briefErrorMessages.str() << std::flush; + return false; + } + return true; + } + + bool runTrigCombinationTests() + { + unsigned testCounter = 0; + + for(mathFuncIndexA = 0; + mathFuncIndexA < mathFuncsAmount; + ++mathFuncIndexA) + { + for(mathFuncIndexD = 0; + mathFuncIndexD < mathFuncsAmount; + ++mathFuncIndexD) + { + for(exponent_B = 1; exponent_B <= 2; ++exponent_B) + { + for(exponent_E = 1; exponent_E <= 2; ++exponent_E) + { + for(exponent_C = -2; exponent_C <= 2; ++exponent_C) + { + for(exponent_F = -2; exponent_F <= 2; ++exponent_F) + { + for(operatorIndex = 0; + operatorIndex < 2; + ++operatorIndex) + { + ++testCounter; + if(!runCurrentTrigCombinationTest()) + return false; + } + } + } + } + } + } + } + + if(verbosityLevel >= 1) + std::cout << " (" << testCounter << ")" << std::flush; + return true; + } + + + // -------------------------------------------------------------------- + // Optimizer test 2 + // -------------------------------------------------------------------- + /* Tests functions of the form "A op B [op C]", where + A, B, C = { var, !var, !!var, var comp value } + var = A -> x, B -> y, C -> z + comp = { <, <=, =, !=, >, >= } + value = { -1, -.5, 0, .5, 1 } + op = { and, or, not and, not or } + */ + // opIndex = 0-32 for doubles, 0-20 for ints + const char* getOperandString(char varName, unsigned opIndex) + { + if(opIndex <= 2) + { + static char operand[] = "!!x"; + operand[2] = varName; + return operand + (2 - opIndex); + } + + opIndex -= 3; + const unsigned compIndex = opIndex % 6, valueIndex = opIndex / 6; + assert(valueIndex <= 4); + + static const char* const comp[] = + { "< ", "<=", "= ", "!=", "> ", ">=" }; + static const char* const value[] = + { "-1 ", "0 ", "1 ", ".5 ", "-.5" }; + static char expression[] = "(x<=-.5)"; + + expression[1] = varName; + expression[2] = comp[compIndex][0]; + expression[3] = comp[compIndex][1]; + expression[4] = value[valueIndex][0]; + expression[5] = value[valueIndex][1]; + expression[6] = value[valueIndex][2]; + return expression; + } + + template<typename Value_t> + Value_t getOperandValue(Value_t varValue, unsigned opIndex) + { + using namespace FUNCTIONPARSERTYPES; + + switch(opIndex) + { + case 0: return varValue; + case 1: return fp_not(varValue); + case 2: return fp_notNot(varValue); + } + + opIndex -= 3; + const unsigned compIndex = opIndex % 6, valueIndex = opIndex / 6; + + static const Value_t value[] = + { -1, 0, 1, Value_t(.5), Value_t(-.5) }; + + switch(compIndex) + { + case 0: return fp_less(varValue, value[valueIndex]); + case 1: return fp_lessOrEq(varValue, value[valueIndex]); + case 2: return fp_equal(varValue, value[valueIndex]); + case 3: return fp_nequal(varValue, value[valueIndex]); + case 4: return fp_greater(varValue, value[valueIndex]); + case 5: return fp_greaterOrEq(varValue, value[valueIndex]); + } + assert(false); + return 0; + } + + // exprIndex = 0-3 + std::string getBooleanExpression(const std::string& operand1, + const std::string& operand2, + unsigned exprIndex) + { + switch(exprIndex) + { + case 0: return operand1 + "&" + operand2; + case 1: return operand1 + "|" + operand2; + case 2: return "!(" + operand1 + "&" + operand2 + ")"; + case 3: return "!(" + operand1 + "|" + operand2 + ")"; + } + assert(false); + return ""; + } + + template<typename Value_t> + Value_t getBooleanValue(Value_t operand1Value, Value_t operand2Value, + unsigned exprIndex) + { + using namespace FUNCTIONPARSERTYPES; + switch(exprIndex) + { + case 0: return fp_and(operand1Value, operand2Value); + case 1: return fp_or(operand1Value, operand2Value); + case 2: return fp_not(fp_and(operand1Value, operand2Value)); + case 3: return fp_not(fp_or(operand1Value, operand2Value)); + } + assert(false); + return 0; + } + + bool updateIndices(unsigned* operandIndices, unsigned* exprIndices, + unsigned operands, const unsigned maxOperandIndex) + { + for(unsigned oi = 0; oi < operands; ++oi) + { + if(++operandIndices[oi] <= maxOperandIndex) + return true; + operandIndices[oi] = 0; + } + for(unsigned ei = 0; ei < operands-1; ++ei) + { + if(++exprIndices[ei] <= 3) return true; + exprIndices[ei] = 0; + } + return false; + } + + template<typename Value_t, unsigned varsAmount> + bool runBooleanComparisonEvaluation(const unsigned* operandIndices, + const unsigned* exprIndices, + const unsigned operands, + FunctionParserBase<Value_t>& fparser, + const std::string& functionString, + bool optimized) + { + const bool isIntegral = FUNCTIONPARSERTYPES::IsIntType<Value_t>::result; + const unsigned varValuesToTest = isIntegral ? 3 : 4; + + static const Value_t values[] = + { -1, 0, 1, Value_t(0.5), Value_t(-0.5) }; + static unsigned valueIndices[varsAmount]; + static Value_t variableValues[varsAmount]; + + for(unsigned i = 0; i < operands; ++i) valueIndices[i] = 0; + + bool stop = false; + while(!stop) + { + for(unsigned i = 0; i < operands; ++i) + variableValues[i] = values[valueIndices[i]]; + + const Value_t parserValue = fparser.Eval(variableValues); + + Value_t correctValue = getOperandValue(variableValues[0], + operandIndices[0]); + + for(unsigned i = 1; i < operands; ++i) + correctValue = + getBooleanValue(correctValue, + getOperandValue(variableValues[i], + operandIndices[i]), + exprIndices[i-1]); + + if(FUNCTIONPARSERTYPES::fp_nequal(parserValue, correctValue)) + { + const bool isIntegral = + FUNCTIONPARSERTYPES::IsIntType<Value_t>::result; + if(verbosityLevel >= 2) + { + using namespace FUNCTIONPARSERTYPES; + std::cout + << "\nFor function \"" << functionString + << "\" ("; + for(unsigned i = 0; i < operands; ++i) + std::cout << (i>0 ? "," : "") + << variableValues[i]; + std::cout + << "): Parser<" + << (isIntegral ? "long" : "double") + << ">" + << (optimized ? " (optimized)" : "") + << "\nreturned " << parserValue + << " instead of " << correctValue + << std::endl; +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + fparser.PrintByteCode(std::cout); +#endif + } + else if(verbosityLevel >= 1) + { + using namespace FUNCTIONPARSERTYPES; + std::cout << "<" << (isIntegral ? "long" : "double"); + std::cout << (optimized ? ",optimized" : ""); + std::cout << ">\"" << functionString + << "\"("; + for(unsigned i = 0; i < operands; ++i) + std::cout << (i>0 ? "," : "") + << variableValues[i]; + std::cout << "): "; + std::cout << parserValue << " vs " << correctValue; + std::cout << "\n"; + } + return false; + } + + stop = true; + for(unsigned i = 0; i < operands; ++i) + { + if(++valueIndices[i] < varValuesToTest) + { stop = false; break; } + valueIndices[i] = 0; + } + } + + return true; + } + + template<typename Value_t> + bool runBooleanComparisonTestsForType() + { + const bool isIntegral = FUNCTIONPARSERTYPES::IsIntType<Value_t>::result; + const unsigned maxOperandIndex = isIntegral ? 20 : 32; + + const char varNames[] = { 'x', 'y', 'z' }; + const char* const varString = "x,y,z"; + const unsigned varsAmount = sizeof(varNames) / sizeof(varNames[0]); + + unsigned operandIndices[varsAmount]; + unsigned exprIndices[varsAmount - 1]; + + unsigned testCounter = 0; + FunctionParserBase<Value_t> fparser; + + bool errors = false; + + for(unsigned operands = 2; operands <= varsAmount; ++operands) + { + for(unsigned i = 0; i < operands; ++i) operandIndices[i] = 0; + for(unsigned i = 0; i < operands-1; ++i) exprIndices[i] = 0; + + do + { + // Generate function string: + std::string functionString = + getOperandString(varNames[0], operandIndices[0]); + + for(unsigned i = 1; i < operands; ++i) + functionString = + getBooleanExpression + (i == 1 ? functionString : "(" + functionString + ")", + getOperandString(varNames[i], operandIndices[i]), + exprIndices[i-1]); + + //std::cout << '"' << functionString << "\"\n"; + + // Parse function string: + int errorIndex = fparser.Parse(functionString, varString); + if(errorIndex >= 0) + { + std::cout << "\nOops! Function \"" << functionString + << "\" was malformed.\n"; + return false; + } + + // Evaluate function and test for correctness: + if(!runBooleanComparisonEvaluation<Value_t, varsAmount> + (operandIndices, exprIndices, operands, + fparser, functionString, false)) + { + if (verbosityLevel < 1) return false; + errors = true; + } + + fparser.Optimize(); + + if(!runBooleanComparisonEvaluation<Value_t, varsAmount> + (operandIndices, exprIndices, operands, + fparser, functionString, true)) + { + if (verbosityLevel < 1) return false; + errors = true; + } + + ++testCounter; + } + while(updateIndices(operandIndices, exprIndices, + operands, maxOperandIndex)); + } + if(errors) return false; + + if(verbosityLevel >= 1) + std::cout << " (" << testCounter << ")" << std::flush; + + return true; + } +} + +int testOptimizer1() +{ + return OptimizerTests::runTrigCombinationTests(); +} + +int testOptimizer2() +{ + return OptimizerTests::runBooleanComparisonTestsForType<DefaultValue_t>(); +} + +int testOptimizer3() +{ +#ifdef FP_SUPPORT_LONG_INT_TYPE + return OptimizerTests::runBooleanComparisonTestsForType<long>(); +#else + return -1; +#endif +} + + +//========================================================================= +// Help output +//========================================================================= +void printAvailableTests(std::vector<std::string>& tests) +{ + std::cout << "Available tests:\n"; + std::size_t column=0; + std::string prev_test_prefix; + + bool counting_tests = false; + long last_count = 0, count_length = 0; + + for(std::size_t a=0; a<tests.size(); ++a) + { + std::string tn = tests[a]; + std::size_t p = tn.rfind('/'); + if(p == tn.npos) + prev_test_prefix = ""; + else + { + { + std::string path_prefix(tn, 0, p); + if(path_prefix != prev_test_prefix) + { + if(counting_tests && count_length > 1) + { + std::ostringstream tmp; tmp << "-" << last_count; + std::cout << tmp.str(); column += tmp.str().size(); + } + counting_tests = false; + if(column) { std::cout << std::endl; column=0; } + prev_test_prefix = path_prefix; + std::cout << " " << path_prefix << "/\n"; + } + } + tn.erase(0, p+1); + } + if(column+tn.size() >= 76) { column=0; std::cout << "\n"; } + if(column==0) { std::cout << " "; column+=8; } + else { std::cout << " "; column+=1; } + + /* TODO: Rewrite this such that backspaces are not needed, + * because they don't work with util-linux's "more" + */ + char* endptr = 0; + long val = strtol(tn.c_str(), &endptr, 10); + if(!*endptr) + { + if(!counting_tests) + { + counting_tests = true; count_length = 1; last_count = val; + } + else if(val == last_count+1) + { + ++count_length; + last_count = val; std::cout << "\b"; --column; continue; + } + else if(count_length > 1) + { + std::ostringstream tmp; tmp << "\b-" << last_count << " "; + std::cout << tmp.str(); column += tmp.str().size(); + counting_tests = false; + } + else counting_tests = false; + } + else if(counting_tests && count_length > 1) + { + std::ostringstream tmp; tmp << "\b-" << last_count << " "; + std::cout << tmp.str(); column += tmp.str().size(); + counting_tests = false; + } + else counting_tests = false; + + std::cout << tn; + column += tn.size(); + } + if(column) std::cout << std::endl; +} + +//========================================================================= +// Main +//========================================================================= +int main(int argc, char* argv[]) +{ + const char* const optionsHelpText = + " -q Quiet (no progress, brief error reports)\n" + " -v Verbose (progress, full error reports)\n" + " -vv Very verbose\n" + " -tests <tests> Select tests to perform, wildcards ok (implies -noalgo)\n" + " Example: -tests 'cmp*'\n" + " -tests help List available tests\n" + " -d Test double datatype\n" + " -f Test float datatype\n" + " -ld Test long double datatype\n" + " -li Test long int datatype\n" + " -mf, -mpfr Test MpfrFloat datatype\n" + " -gi, -gmpint Test GmpInt datatype\n" + " -cd Test std::complex<double> datatype\n" + " -cf Test std::complex<float> datatype\n" + " -cld Test std::complex<long double> datatype\n" + " -algo <n> Run only algorithmic test <n>\n" + " -noalgo Skip all algorithmic tests\n" + " -skipSlowAlgo Skip slow algorithmic tests\n" + " -h, --help This help\n"; + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + MpfrFloat::setDefaultMantissaBits(80); +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE + GmpInt::setDefaultNumberOfBits(80); +#endif + + bool skipSlowAlgo = false; + bool runAllTypes = true; + bool runAlgoTests = true; + bool run_d = false, run_f = false, run_ld = false; + bool run_li = false, run_mf = false, run_gi = false; + bool run_cd = false, run_cf = false, run_cld = false; + unsigned runAlgoTest = 0; + + for(int i = 1; i < argc; ++i) + { + if(std::strcmp(argv[i], "-q") == 0) verbosityLevel = 0; + else if(std::strcmp(argv[i], "-v") == 0) verbosityLevel = 2; + else if(std::strcmp(argv[i], "-vv") == 0) verbosityLevel = 3; + else if(std::strcmp(argv[i], "-vvv") == 0) verbosityLevel = 4; + else if(std::strcmp(argv[i], "-noalgo") == 0) runAlgoTests = false; + else if(std::strcmp(argv[i], "-skipSlowAlgo") == 0) skipSlowAlgo = true; + else if(std::strcmp(argv[i], "-algo") == 0) + { + if(i+1 < argc) runAlgoTest = std::atoi(argv[++i]); + runAlgoTests = true; + } + else if(std::strcmp(argv[i], "-tests") == 0) + { + runAlgoTests = false; + + std::vector<std::string> tests; +#ifndef FP_DISABLE_DOUBLE_TYPE + for(unsigned a=0; RegressionTests<double>::Tests[a].testName; ++a) + tests.push_back(RegressionTests<double>::Tests[a].testName); +#endif +#ifdef FP_SUPPORT_FLOAT_TYPE + for(unsigned a=0; RegressionTests<float>::Tests[a].testName; ++a) + tests.push_back(RegressionTests<float>::Tests[a].testName); +#endif +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + for(unsigned a=0; RegressionTests<long double>::Tests[a].testName; ++a) + tests.push_back(RegressionTests<long double>::Tests[a].testName); +#endif +#ifdef FP_SUPPORT_LONG_INT_TYPE + for(unsigned a=0; RegressionTests<long>::Tests[a].testName; ++a) + tests.push_back(RegressionTests<long>::Tests[a].testName); +#endif +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + for(unsigned a=0; RegressionTests<MpfrFloat>::Tests[a].testName; ++a) + tests.push_back(RegressionTests<MpfrFloat>::Tests[a].testName); +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE + for(unsigned a=0; RegressionTests<GmpInt>::Tests[a].testName; ++a) + tests.push_back(RegressionTests<GmpInt>::Tests[a].testName); +#endif + std::sort(tests.begin(), tests.end(), natcomp); + tests.erase(std::unique(tests.begin(), tests.end()), tests.end()); + + if(std::strcmp(argv[i+1], "help") == 0) + { + printAvailableTests(tests); + return 0; + } + while(i+1 < argc && argv[i+1][0] != '-') + { + const char* t = argv[++i]; + bool ok = false; + for(std::size_t a=0; a<tests.size(); ++a) + if(WildMatch_Dirmask(t, tests[a].c_str())) + { ok=true; break; } + if(!ok) + { + std::cout << "No such test: " << t + << "\n\"testbed -tests help\" to list " + << "available tests.\n"; + return -1; + } + selectedRegressionTests.push_back(t); + } + } + else if(std::strcmp(argv[i], "-d") == 0 + || std::strcmp(argv[i], "-double") == 0) + runAllTypes = false, run_d = true; + else if(std::strcmp(argv[i], "-f") == 0 + || std::strcmp(argv[i], "-float") == 0) + runAllTypes = false, run_f = true; + else if(std::strcmp(argv[i], "-ld") == 0 + || std::strcmp(argv[i], "-longdouble") == 0) + runAllTypes = false, run_ld = true; + else if(std::strcmp(argv[i], "-li") == 0 + || std::strcmp(argv[i], "-longint") == 0) + runAllTypes = false, run_li = true; + else if(std::strcmp(argv[i], "-mf") == 0 + || std::strcmp(argv[i], "-mpfr") == 0) + runAllTypes = false, run_mf = true; + else if(std::strcmp(argv[i], "-gi") == 0 + || std::strcmp(argv[i], "-gmpint") == 0) + runAllTypes = false, run_gi = true; + else if(std::strcmp(argv[i], "-cd") == 0) + runAllTypes = false, run_cd = true; + else if(std::strcmp(argv[i], "-cf") == 0) + runAllTypes = false, run_cf = true; + else if(std::strcmp(argv[i], "-cld") == 0) + runAllTypes = false, run_cld = true; + + else if(std::strcmp(argv[i], "--help") == 0 + || std::strcmp(argv[i], "-help") == 0 + || std::strcmp(argv[i], "-h") == 0 + || std::strcmp(argv[i], "/?") == 0) + { + std::cout << + "FunctionParser testbed " << kVersionNumber << + "\n\nUsage: " << argv[0] << " [<option> ...]\n" + "\n" << optionsHelpText; + return 0; + } + else if(std::strlen(argv[i]) > 0) + { + std::cout << "Unknown option: '" << argv[i] << "'\n"; + return 1; + } + } + + if(selectedRegressionTests.empty()) + selectedRegressionTests.push_back("*"); + + DefaultParser fp0; + + // Test that the parser doesn't crash if Eval() is called before Parse(): + fp0.Eval(0); + + const char* const delimiterTestFunction = "x+y } "; + fp0.setDelimiterChar('}'); + int res = fp0.Parse(delimiterTestFunction, "x,y"); + if(fp0.GetParseErrorType() != fp0.FP_NO_ERROR || res != 4) + { + std::cout << "Delimiter test \"" << delimiterTestFunction + << "\" failed at " << res << ": " << fp0.ErrorMsg() + << std::endl; + return 1; + } + fp0.Parse("x+}y", "x,y"); + if(fp0.GetParseErrorType() == fp0.FP_NO_ERROR) + { + std::cout << "Erroneous function with delimiter didn't fail" + << std::endl; + return 1; + } + + bool allTestsOk = true; + + if(!runAllTypes || runAlgoTest == 0) + { +#ifndef FP_DISABLE_DOUBLE_TYPE + if(runAllTypes || run_d) + if(!runRegressionTests<double>("double")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_FLOAT_TYPE + if(runAllTypes || run_f) + if(!runRegressionTests<float>("float")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + if(runAllTypes || run_ld) + if(!runRegressionTests<long double>("long double")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_LONG_INT_TYPE + if(runAllTypes || run_li) + if(!runRegressionTests<long>("long int")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + if(runAllTypes || run_mf) + if(!runRegressionTests<MpfrFloat>("MpfrFloat")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_GMP_INT_TYPE + if(runAllTypes || run_gi) + if(!runRegressionTests<GmpInt>("GmpInt")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + if(runAllTypes || run_cd) + if(!runRegressionTests<std::complex<double> >("std::complex<double>")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + if(runAllTypes || run_cf) + if(!runRegressionTests<std::complex<float> >("std::complex<float>")) + allTestsOk = false; +#endif +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + if(runAllTypes || run_cld) + if(!runRegressionTests<std::complex<long double> >("std::complex<long double>")) + allTestsOk = false; +#endif + } + +//////////////////////////// +//////////////////////////// +//////////////////////////// +//////////////////////////// + + // Misc. tests + // ----------- + const struct + { + const char* const testName; + int(*testFunction)(); + } + algorithmicTests[] = + { + { "Copy constructor and assignment", &TestCopying }, + { "Error situations", &TestErrorSituations }, + { "Whitespaces", &WhiteSpaceTest }, + { "Optimizer test 1 (trig. combinations)", &testOptimizer1 }, + { "Optimizer test 2 (bool combinations, double)", + (skipSlowAlgo || (!runAllTypes && !run_d)) ? 0 : &testOptimizer2 }, + { "Optimizer test 3 (bool combinations, long)", + (!runAllTypes && !run_li) ? 0 : &testOptimizer3 }, + { "Integral powers", &TestIntPow }, + { "UTF8 test", skipSlowAlgo ? 0 : &UTF8Test }, + { "Identifier test", &TestIdentifiers }, + { "Used-defined functions", &testUserDefinedFunctions }, + { "Multithreading", &testMultithreadedEvaluation } + }; + + const unsigned algorithmicTestsAmount = + sizeof(algorithmicTests) / sizeof(algorithmicTests[0]); + + if(runAlgoTests) + { + for(unsigned i = 0; i < algorithmicTestsAmount; ++i) + { + if(runAlgoTest >= 1 && runAlgoTest <= algorithmicTestsAmount && + runAlgoTest != i+1) + continue; + + if(verbosityLevel >= 1) + std::cout << "Algo test " << i+1 << ": " + << algorithmicTests[i].testName << std::flush; + + if(!algorithmicTests[i].testFunction) + { + if(verbosityLevel >= 1) + std::cout << ": Skipped." << std::endl; + continue; + } + + int result = algorithmicTests[i].testFunction(); + + if(result == 0) + { + allTestsOk = false; + if(verbosityLevel == 0) + std::cout << "Algo test " << i+1 << ": " + << algorithmicTests[i].testName; + if(verbosityLevel <= 1) + std::cout << ": FAILED." << std::endl; + } + else if(verbosityLevel >= 1) + { + if(result < 0 ) + std::cout << ": (No support)" << std::endl; + else + std::cout << ": Ok." << std::endl; + } + } + } + + if(!allTestsOk) + { + std::cout << "Some tests failed." << std::endl; + return 1; + } + if(verbosityLevel == 1) + std::cout << "================= All tests OK =================\n"; + else if(verbosityLevel >= 2) + std::cout << "================================================\n" + << "================= All tests OK =================\n" + << "================================================\n"; + return 0; +} diff --git a/testbed_tests.inc b/testbed_tests.inc new file mode 100644 index 0000000..02c364b --- /dev/null +++ b/testbed_tests.inc @@ -0,0 +1,11667 @@ +#define w23 "<" gX3 +#define w13 "<=" gX3 +#define w03 )/a;}q3 +#define oZ3 ),gP gE +#define oY3 q0(1))+ +#define oX3 *fp_or( +#define oW3 qK exp( +#define oV3 " < " +#define oU3 " " qD3 +#define oT3 " <= " +#define oS3 +q0(gO( +#define oR3 -a);}q3 +#define oQ3 gZ1 dK1 +#define oP3 gZ1 dJ1 +#define oO3 dN 1,hI +#define oN3 Sqrneq0 +#define oM3 Gt1_abs +#define oL3 Gt0_abs +#define oK3 Ge1_abs +#define oJ3 Ge0_abs +#define oI3 Cmp_sqr +#define oH3 Cmp_neg +#define oG3 Cmp_add +#define oF3 Absneq0 +#define oE3 2 dN hS +#define oD3 "-125)" +#define oC3 ,y);}q3 +#define oB3 2,-3,3, +#define oA3 Ifmerge +#define o93 Xaddnot +#define o83 Sqr_yxx +#define o73 Sqr_xnx +#define o63 Sqr_nxx +#define o53 Absnzlt +#define o43 Absnzge +#define o33 " +" o13" " +#define o23 o13" " +#define o13 " " +#define o03 qO2" " +#define dZ3 o1", " +#define dY3 h42" " +#define dX3 h12" " +#define dW3 "x*0+ " +#define dV3 40000.0 +#define dU3 )*wE*x*x +#define dT3 gZ1 0l)) +#define dS3 qV qP-g2 +#define dR3 q0(0l qQ +#define dQ3 hN1") " +#define dP3 Multodiv +#define dO3 "if" oU2 +#define dN3 Nor2plus +#define dM3 Lt_or_ne +#define dL3 Lt_or_le +#define dK3 Lt_or_gt +#define dJ3 Lt_or_ge +#define dI3 Lt_or_eq +#define dH3 Le_or_ne +#define dG3 Le_or_eq +#define dF3 L_notnot +#define dE3 L_mulneg +#define dD3 L_mulabs +#define dC3 Ifmerge2 +#define dB3 Gt_or_ne +#define dA3 Gt_or_le +#define d93 Gt_or_ge +#define d83 Gt_or_eq +#define d73 Ge_or_ne +#define d63 Ge_or_le +#define d53 Ge_or_eq +#define d43 "y,x,y)" +#define d33 g11" " +#define d23 wO"4) " +#define d13 Xxsqrdup +#define d03 Sqr_yxnx +#define hZ3 Sqr_ynxx +#define hY3 "abs(x)" +#define hX3 (x mP +#define hW3 aG1"1 > " +#define hV3 qR2"1 < " +#define hU3 aF1"0 > " +#define hT3 qQ2"0 < " +#define hS3 "!x * !y" +#define hR3 hC2" !!y" +#define hQ3 "0.0625)" +#define hP3 "!x & !y" +#define hO3 Nand2plus +#define hN3 "!x | !y" +#define hM3 a3" | " +#define hL3 Lt_and_ne +#define hK3 Lt_and_le +#define hJ3 Lt_and_gt +#define hI3 Lt_and_ge +#define hH3 Lt_and_eq +#define hG3 Le_and_ne +#define hF3 Le_and_eq +#define hE3 Ifmerge2b +#define hD3 Gt_and_ne +#define hC3 Gt_and_le +#define hB3 Gt_and_ge +#define hA3 Gt_and_eq +#define h93 Ge_and_ne +#define h83 Ge_and_le +#define h73 Ge_and_eq +#define h63 Notnotnot +#define h53 Dupminmax +#define h43 w61"1 >= " +#define h33 aE1"1 <= " +#define h23 w41"0 >= " +#define h13 aD1"0 <= " +#define h03 a1 o13 +#define gZ3 " != " +#define gY3 dW o13 +#define gX3 " " hX +#define gW3 Cmp_mulpos +#define gV3 Cmp_mulneg +#define gU3 wE1 o22" " +#define gT3 Xaddnotnot +#define gS3 Notnotnot2 +#define gR3 Dupxmuladd +#define gQ3 Dupminmax3 +#define gP3 Dupminmax2 +#define gO3 Dupaddmul7 +#define gN3 "abs" hF1 +#define gM3 "abs" h71 +#define gL3 o42 o13" " +#define gK3 "y,y,x)" +#define gJ3 Cmp_sqr_neg +#define gI3 "floor" qK2 +#define gH3 Mixedminmax +#define gG3 Mergemulabs +#define gF3 Addconstmul +#define gE3 "acos" hF1 +#define gD3 "ceil" qL2 +#define gC3 "-0.015625)" +#define gB3 If_join_mul2 +#define gA3 If_join_add2 +#define g93 Cmpzz_minmax +#define g83 Cmpne_minmax +#define g73 Cmplt_minmax +#define g63 Cmple_minmax +#define g53 Cmpgt_minmax +#define g43 Cmpge_minmax +#define g33 "y," h22 +#define g23 Cmpeq_minmax +#define g13 Addnegmulpos +#define g03 Addnegmulneg +#define qZ3 Absnotnotnot +#define qY3 Cmpzz_add_imm +#define qX3 Cmpne_add_imm +#define qW3 Cmplt_add_imm +#define qV3 Cmple_add_imm +#define qU3 Cmpgt_add_imm +#define qT3 Cmpge_add_imm +#define qS3 Cmpeq_add_imm +#define qR3 "sin(x))"}, +#define qQ3 "25" gO2 +#define qP3 h72 aM2" " +#define qO3 If_extract_mul +#define qN3 If_extract_min +#define qM3 If_extract_add +#define qL3 If_extract_abs +#define qK3 Addmulconstmul +#define qJ3 gM3" " +#define qI3 "acos" w7 o7 +#define qH3 If_extract_mul2 +#define qG3 If_extract_mul1 +#define qF3 If_extract_add2 +#define qE3 If_extract_add1 +#define qD3 "(5.0625 " +#define qC3 If_extract_or2_l +#define qB3 If_extract_or1_l +#define qA3 Cmpzz_minmax_rev +#define q93 Cmpzz_addadd_imm +#define q83 Cmpzz_add_reduce +#define q73 Cmpne_minmax_rev +#define q63 Cmpne_addadd_imm +#define q53 Cmpne_add_reduce +#define q43 Cmplt_minmax_rev +#define q33 Cmplt_addadd_imm +#define q23 Cmplt_add_reduce +#define q13 Cmple_minmax_rev +#define q03 Cmple_addadd_imm +#define mZ2 Cmple_add_reduce +#define mY2 Cmpgt_minmax_rev +#define mX2 Cmpgt_addadd_imm +#define mW2 Cmpgt_add_reduce +#define mV2 Cmpge_minmax_rev +#define mU2 Cmpge_addadd_imm +#define mT2 Cmpge_add_reduce +#define mS2 "y,y," aN1 +#define mR2 Cmpeq_minmax_rev +#define mQ2 Cmpeq_addadd_imm +#define mP2 Cmpeq_add_reduce +#define mO2 If_extract_or2_nl +#define mN2 If_extract_or1_nl +#define mM2 If_extract_and2_l +#define mL2 If_extract_and1_l +#define mK2 Cmpzz_mul_imm_pos +#define mJ2 Cmpzz_mul_imm_neg +#define mI2 Cmpne_mul_imm_pos +#define mH2 Cmpne_mul_imm_neg +#define mG2 Cmplt_mul_imm_pos +#define mF2 Cmplt_mul_imm_neg +#define mE2 Cmple_mul_imm_pos +#define mD2 Cmple_mul_imm_neg +#define mC2 Cmpgt_mul_imm_pos +#define mB2 Cmpgt_mul_imm_neg +#define mA2 Cmpge_mul_imm_pos +#define m92 Cmpge_mul_imm_neg +#define m82 Cmpeq_mul_imm_pos +#define m72 Cmpeq_mul_imm_neg +#define m62 d4"5.0625 " +#define m52 "-125" gO2 +#define m42 If_extract_and2_nl +#define m32 If_extract_and1_nl +#define m22 "y, 0,1" gO2 +#define m12 Cmpzz_mulmul_imm_pos +#define m02 Cmpzz_mulmul_imm_neg +#define aZ2 Cmpne_mulmul_imm_pos +#define aY2 Cmpne_mulmul_imm_neg +#define aX2 Cmplt_mulmul_imm_pos +#define aW2 Cmplt_mulmul_imm_neg +#define aV2 Cmple_mulmul_imm_pos +#define aU2 Cmple_mulmul_imm_neg +#define aT2 Cmpgt_mulmul_imm_pos +#define aS2 Cmpgt_mulmul_imm_neg +#define aR2 Cmpge_mulmul_imm_pos +#define aQ2 Cmpge_mulmul_imm_neg +#define aP2 Cmpeq_mulmul_imm_pos +#define aO2 Cmpeq_mulmul_imm_neg +#define aN2 "0.0625" gO2 +#define aM2 o13 o13 +#define aL2 cpp_03unit_constants:: +#define aK2 "-0.015625" gO2 +#define aJ2 cpp_02unit_functions:: +#define aI2 hA LNG_ONLY +#define aH2 cpp_99misc:: +#define aG2 cpp_50regressions:: +#define aF2 cpp_01unit_operators:: +#define aE2 cpp_10optimizer_bytecode:: +#define aD2 cpp_11optimizer_constaddmul:: +#define aC2 DBL_ONLY +#define aB2 cpp_20optimizer_optimizations:: +#define aA2 q0(0 mY +#define a92 "a" gK2 +#define a82 qP gM2 +#define a72 (qK qP +#define a62 {1 oG +#define a52 {1,0,dD +#define a42 fp_pow( +#define a32 {2,hE1 +#define a22 fp_less( +#define a12 -400 mR +#define a02 o13" 4" +#define wZ2 " " qB1 +#define wY2 fp_and( +#define wX2 (fp_acos( +#define wW2 q0(dJ)) +#define wV2 -6,6,1 qL +#define wU2 {1,-10,10, +#define wT2 {2,N(.1), +#define wS2 (qK tanf +#define wR2 fp_ceil( +#define wQ2 "a",qE +#define wP2 *q0(0)+q0( +#define wO2 (aD y),qK1 +#define wN2 qA mV1 +#define wM2 "<4)" aV +#define wL2 "*(" w0 +#define wK2 N(0.5,0.0), +#define wJ2 {1,-1000,1000, +#define wI2 TestType<q0> +#define wH2 {using namespace FUNCTIONPARSERTYPES;q0 +#define wG2 4.0l hU +#define wF2 "(" h02 +#define wE2 "x",oK +#define wD2 "(1,0,1" +#define wC2 (1.1f +#define wB2 4.0f hU +#define wA2 q42 x*x +#define w92 "(" dQ1 +#define w82 "(" w5 +#define w72 "(" aZ1 +#define w62 aT1/gE+ +#define w52 (qH oL +#define w42 fp_max( +#define w32 aD x-gF +#define w22 *q0 dV2+ +#define w12 *wW1 wT1 +#define w02 ,w42 +#define oZ2 ,fp_min( +#define oY2 0l);}q3 +#define oX2 wH h0(x +#define oW2 wH gZ x +#define oV2 ")" gJ2 +#define oU2 "(x" dU +#define oT2 1.1)h81 +#define oS2 "y" gO2 +#define oR2 "abs(a" +#define oQ2 ")/a"}, +#define oP2 ")*0"}, +#define oO2 "*" hT2 +#define oN2 ")*" gV2 +#define oM2 ")*a"}, +#define oL2 wQ1" +" +#define oK2 o13" 2" +#define oJ2 N(.5)h8 +#define oI2 "5" o42 +#define oH2 *wE mU*x +#define oG2 (qK x* +#define oF2 qA,oZ +#define oE2 N(.2)h8 +#define oD2 "expex" +#define oC2 "p" hF1 +#define oB2 "acosh" +#define oA2 (qH q0 +#define o92 q0(1.1l))+ +#define o82 q0(5l) +#define o72 ")" mS1 +#define o62 mflit0_25 +#define o52 *-q0 h6 +#define o42 ") +" +#define o32 "*z" o42 +#define o22 "<=y &" +#define o12 mB" | " +#define o02 mB" & " +#define dZ2 g01 hD1 +#define dY2 o6")" +#define dX2 "x))"}, +#define dW2 -x),wG +#define dV2 (6l)/gE +#define dU2 hQ gE) +#define dT2 hQ x), +#define dS2 hQ hQ1 +#define dR2 oC gE) +#define dQ2 oB gE) +#define dP2 "(" a0 +#define dO2 ")+(x" +#define dN2 +q0(gH( +#define dM2 +q0(gW( +#define dL2 +q0 h6 +#define dK2 (qK aD x)+ +#define dJ2 "exp(" +#define dI2 dH2"/" +#define dH2 qA g5 +#define dG2 gZ3 +#define dF2 " >= " +#define dE2 "m_deg", +#define dD2 mflit2_5 +#define dC2 mflit7_1 +#define dB2 d2r(wZ +#define dA2 5),q0(4) +#define d92 qK oQ1 +#define d82 hA qA oJ +#define d72 logf(x +#define d62 true q4 +#define d52 q0(3l)) +#define d42 q0(2.0l) +#define d32 0.0l))+ +#define d22 aS1;}q3 +#define d12 fp_not(z +#define d02 mV);}q3 +#define hZ2 fp_cosh( +#define hY2 qK-x;}q3 +#define hX2 qH x+oV1 +#define hW2 " " dC1 +#define hV2 o1 dE" " +#define hU2 "a,b",oK +#define hT2 "atan2" +#define hS2 hN1"))" +#define hR2 gC1")" +#define hQ2 gC1"))" +#define hP2 "abs(b" +#define hO2 ")" wI1 +#define hN2 oA"-5)" +#define hM2 oA"5)" +#define hL2 wL" 32" +#define hK2 wL d21 +#define hJ2 N(-6.0,0.0),wS +#define hI2 wL d31 +#define hH2 q91"))*" +#define hG2 N(.15)h8 +#define hF2 "x+-x+-" +#define hE2 N(.1)h8 +#define hD2 "7/2" o42 +#define hC2 "!!x *" +#define hB2 "180/pi" +#define hA2 10,10,h7 +#define h92 mG1 1,hI +#define h82 ",-" w01 +#define h72 "," w01 +#define h62 "*" g11 +#define h52 " " qX1 +#define h42 "x" hA1 +#define h32 {1,q2 +#define h22 "x,y" gO2 +#define h12 "x",o1 +#define h02 "1,4,0" +#define gZ2 "x,y,z", +#define gY2 fp_exp2( +#define gX2 fp_cos( +#define gW2 gX2 y +#define gV2 "5"}, +#define gU2 "hm_deg", +#define gT2 ",y" gO2{ +#define gS2 (qH gG1 +#define gR2 ")" mO"+" +#define gQ2 qR dE1 +#define gP2 qA dF1 +#define gO2 ")"}, +#define gN2 gK;}q0 +#define gM2 gY;}q0 +#define gL2 gJ;}q0 +#define gK2 "sinh" +#define gJ2 ",if(" +#define gI2 fp_exp(-x) +#define gH2 fp_exp(x) +#define gG2 mflit1_5* +#define gF2 (oY3 +#define gE2 q0(2)+q0( +#define gD2 atan2l( +#define gC2 sqrtl(x*x +#define gB2 atan2f( +#define gA2 "^1506"}, +#define g92 +x+x+x+x +#define g82 +aD x+gF* +#define g72 (qH a6*y, +#define g62 +a22 +#define g52 (qH x>=oV1 +#define g42 0x0010l)* +#define g32 fp_nequal +#define g22 (hE(o82 +#define g12 qK a42 +#define g02 o82* +#define qZ2 fp_tan( +#define qY2 qP-hZ)) +#define qX2 gC),-wG +#define qW2 )wV1 dX,y), +#define qV2 oE-hR)) +#define qU2 gB-gE +#define qT2 "(x*" q12 +#define qS2 "(x) +" +#define qR2 " > 1" o9 +#define qQ2 " > 0" o9 +#define qP2 ")+x+(" +#define qO2 "xp" wL +#define qN2 "(log(x+" +#define qM2 o13"if(x" +#define qL2 "(x)" g71 +#define qK2 "(x)" o31 +#define qJ2 -3,3,1,q7 +#define qI2 "(x^2" gO2 +#define qH2 "pow(x" +#define qG2 qA",y,z", +#define qF2 "x!=y" o42 +#define qE2 a3" & " +#define qD2 4 dN 1,q7 +#define qC2 " > 6" gO2 +#define qB2 qK fp_not( +#define qA2 ") > " g01 aC +#define q92 ") <= " g01 aG +#define q82 "*(" wU +#define q72 "*(" aS +#define q62 ") < " g01 aE +#define q52 " = 6" gO2 +#define q42 sqrtf( +#define q32 =vars[1] +#define q22 fp_sqrt( +#define q12 "5" gO2 +#define q02 "cmp_ex" +#define mZ1 ")/log(" +#define mY1 "(1.0" +#define mX1 {1 dN hS +#define mW1 "pi/180" +#define mV1 ",y,z",oZ +#define mU1 "x" mV1 +#define mT1 {2,3,5,hS +#define mS1 " + (x*" +#define mR1 ,N(0.25) +#define mQ1 1 mR1, +#define mP1 ,0,1,1,q7 +#define mO1 {3 mP1 +#define mN1 "x" dH +#define mM1 gA1" | " +#define mL1 gA1" & " +#define mK1 qZ1"*y)" +#define mJ1 qY1"*y)" +#define mI1 1,-5,5,1 +#define mH1 N(2.0,0.0) +#define mG1 ,-2,2, +#define mF1 2 mG1 1,qM +#define mE1 ];return +#define mD1 qZ2 y)+ +#define mC1 q0(10l) +#define mB1 y),w8,y mY +#define mA1 ,"abs(" +#define m91 a42 x*z+q0(17l), +#define m81 a42 fp_exp(m6 +#define m71 w42 q0( +#define m61 fp_min(q0( +#define m51 +fp_min(x, +#define m41 ,q0(25l mY +#define m31 wH dN2 x +#define m21 (oY 1l);}q3 +#define m11 wH dM2 x +#define m01 wH oS3 x +#define aZ1 "0.7" gG +#define aY1 qK r2d( +#define aX1 ,dZ3"y" +#define aW1 qH q0(hF( +#define aV1 dA x:y)+q0( +#define aU1 dA y:m1 +#define aT1 q0(7l) +#define aS1 q0(0l) +#define aR1 (qK fp_exp( +#define aQ1 qT aS1, +#define aP1 qK log(1.1) +#define aO1 qX aS1, +#define aN1 "x)"}, +#define aM1 gW2*q0(1.5l)) +#define aL1 q0(1l) +#define aK1 (qK aL1/ +#define aJ1 mY dF 0l), +#define aI1 N(4.0,0.0) +#define aH1 "log(x)"}, +#define aG1 " < 1" g81 +#define aF1 " < 0" g81 +#define aE1 " >= 1" o9 +#define aD1 " >= 0" o9 +#define aC1 ")" oS1 +#define aB1 "(x*z+17)" +#define aA1 "sub(sub(" +#define a91 10,10,1,hI +#define a81 " >= 6" wI +#define a71 " > 6)" aC +#define a61 " < 6)" +#define a51 " <= 6" gO2 +#define a41 " >= 6" gO2 +#define a31 wO"-4)" +#define a21 mflit0_5 +#define a11 ,qG"/sin" +#define a01 q0(0.5l) +#define wZ1 ")" d7 gL +#define wY1 (qH wY2 x +#define wX1 userDefFuncSqr<q0>(( +#define wW1 q0(2l) +#define wV1 *wY2 +#define wU1 fp_atan2( +#define wT1 /d52+ +#define wS1 fp_or(q0( +#define wR1 aL1)) +#define wQ1 "sin(x)" +#define wP1 {3 dN hS +#define wO1 w02 x w02 +#define wN1 h2"x)" +#define wM1 "(-" aN1 +#define wL1 ">-4)" mD +#define wK1 "<-4)" aV +#define wJ1 "=-4)" aU +#define wI1 " " wH1 +#define wH1 "+ 32" +#define wG1 "=-2" o9 +#define wF1 "(x>4" gO2 +#define wE1 "*(x" +#define wD1 2 dN 1 qL +#define wC1 ))+mflit1_2* +#define wB1 ))+mflit1_1* +#define wA1 q0(5 mY 1)/ +#define w91 mflit0_7 hU +#define w81 q22 q0( +#define w71 " cos(x)"}, +#define w61 " <= 1" g81 +#define w51 ,"(sin(x)" +#define w41 " <= 0" g81 +#define w31 ",max(x,ma" +#define w21 o13"10*" o1 +#define w11 qA q8"/pow" +#define w01 "x)) +" +#define oZ1 " <= 6)" aG +#define oY1 "dupminmax" +#define oX1 (oL,q0(4l)qQ +#define oW1 dG2 g01 d7 +#define oV1 y;}q3 +#define oU1 qK g32( +#define oT1 (qK a22 +#define oS1 "^(1/" +#define oR1 q0(fp_abs(x) +#define oQ1 r2d(q0:: +#define oP1 gW2)+ +#define oO1 N(1e-6)mR dP +#define oN1 "(acos(x)" +#define oM1 (qK logf wC2 +#define oL1 "(abs(x)" +#define oK1 d2r(x)mP +#define oJ1 1 dN N(0.01) +#define oI1 =vars[0],& +#define oH1 fp_or(y,z) +#define oG1 x*-q0(dZ+q0( +#define oF1 ),hQ x+q0(6l)) +#define oE1 q0(0.5l qQ +#define oD1 wY2 q0( +#define oC1 d2r(x qQ +#define oB1 )-fp_int( +#define oA1 {1 dN 1,q7 +#define o91 h3")" +#define o81 oS"pow" +#define o71 "<=-4)" aW +#define o61 "*((-x)" +#define o51 ">4)" mD +#define o41 "=4)" aU +#define o31 ",ceil(x))+" +#define o21 g11 dU"))"}, +#define o11 "cmpeq_" +#define o01 gR"cmpne_" +#define dZ1 gR"cmplt_" +#define dY1 gR"cmpge_" +#define dX1 "cbrt(x^6" +#define dW1 ")), int(" +#define dV1 gZ3"6)" +#define dU1 wO"4*y)" +#define dT1 q5"/" +#define dS1 40,40,3,qM +#define dR1 fp_lessOrEq( +#define dQ1 "y" o42" x/" +#define dP1 qK q0(hF( +#define dO1 fp_abs(a) +#define dN1 ,-q0(16l) +#define dM1 "sin(" a0 +#define dL1 4000,N(0.1)dP +#define dK1 1l))qT aL1, +#define dJ1 1l))qX aL1, +#define dI1 1l mY dF 1l), +#define dH1 dN 2 q6 +#define dG1 3,3,N(0.41)qL +#define dF1 ",y",oZ +#define dE1 "if_ex" +#define dD1 wY2 y,z) +#define dC1 "+ " hH1"*" +#define dB1 {2,q2 +#define dA1 +o82;}q3 +#define d91 "!=4" gO2 +#define d81 " " gL",2)" +#define d71 " " gL",3)" +#define d61 "x" dF1 +#define d51 oB3 2,q7 +#define d41 2,-4,4,1,q7 +#define d31 o13" 8" +#define d21 o13" 16" +#define d11 "(2))"}, +#define d01 oO"(" hG1 +#define hZ1 oO"(x)" +#define hY1 "(x" gZ3"y" gO2 +#define hX1 "(x = y" gO2 +#define hW1 aD x)+mflit1_2 +#define hV1 hE((aL1/mL) +#define hU1 oD qN-hR)) +#define hT1 -q0(2l qQ +#define hS1 {1,-36,36,1 qL +#define hR1 wU2 1 qL +#define hQ1 x),-gE +#define hP1 gR"cmple_" +#define hO1 gR"cmpgt_" +#define hN1 "1,1,1" +#define hM1 "1.1^x*4.1" gO2 +#define hL1 "<=4)" aW +#define hK1 "!=-2" gO2 +#define hJ1 wL a02 +#define hI1 wL oK2 +#define hH1 "sin(x+pi" +#define hG1 "abs(x))" +#define hF1 "(x))"}, +#define hE1 -3,3,2 qL +#define hD1 g1"0010 *" +#define hC1 wO"-4*y)" +#define hB1 " & (y+2" gO2 +#define hA1 "_rev",o1 +#define h91 wW1 qQ +#define h81 +x;}q3 +#define h71 w7"*(abs(x)" +#define h61 " + sin(x-pi*" +#define h51 ,"((-5.1)*x*y)" +#define h41 {1,-4,4,1 qL +#define h31 oS"powx" +#define h21 " " gL",-2)" +#define h11 " " gL",-3)" +#define h01 q0(5l mY 1l)/ +#define gZ1 x),q0( +#define gY1 dA y:x)+q0( +#define gX1 (x mS y,q0(6l mY +#define gW1 (qK dR1 +#define gV1 fp_not(-fp_not( +#define gU1 "*(" aR +#define gT1 {1,0,4,N(0.1)qL +#define gS1 d2r wC2)hU +#define gR1 fp_notNot(x +#define gQ1 fp_abs(dT3 +#define gP1 fp_abs(x qQ +#define gO1 g0 o3"+y+z" +#define gN1 "x" q8"/" +#define gM1 },{2,-4,4,N(0.05) +#define gL1 true qI +#define gK1 ,q0(25l qQ +#define gJ1 fp_int(q0( +#define gI1 "x" g5"/" +#define gH1 "x" qW1 +#define gG1 fp_equal(x +#define gF1 (qK fp_equal +#define gE1 5l),d52+x +#define gD1 ")) " aY"if(" +#define gC1 "1,0,0" +#define gB1 {2,-460,100,8,qM +#define gA1 ,"(x > y)" +#define g91 {1 mP1 +#define g81 ") " aY +#define g71 ",floor(x))+" +#define g61 ",y" q8"/pow" +#define g51 "(x <= y)" +#define g41 " + cos(x-pi*" +#define g31 fp_abs(x)>=a21 +#define g21 1,N(-5.0,0.0),N(5.0,0.0),mH1,q7 +#define g11 " if(x" +#define g01 "(y+6))" +#define qZ1 " " wO"4" +#define qY1 " " wO"-4" +#define qX1 o6"+y)" +#define qW1 ",y",g7 +#define qV1 hC-1,1,N(0.01) +#define qU1 log(x+sqrt(x*x +#define qT1 " +" oK2"*(if(" +#define qS1 "pow(-4,y))" +#define qR1 (aD x)+gW2))* +#define qQ1 10,10,N(0.8)qL +#define qP1 -6,6,N(0.5),qM +#define qO1 "*(5+" o1 +#define qN1 3 dN 1,q7 +#define qM1 gW2*mflit1_5) +#define qL1 d2r(1.1l)hU +#define qK1 gW2)): +#define qJ1 gH2, +#define qI1 hM x+y+x+x-z h81 +#define qH1 qK q0(0x0001)*a22 +#define qG1 ,"((1/" o13"abs(b))*" +#define qF1 "*(sinh(x)" +#define qE1 {1,N(0.5)o8 +#define qD1 "*(atan(x)" +#define qC1 "(x*if(1,-1,0))"}, +#define qB1 "(pow(2,x)" +#define qA1 a22 y,q0(1l +#define q91 "(sin(x)+cos(y" +#define q81 o42" cos(x+pi*" +#define q71 fp_not(x)*fp_not(y) +#define q61 -3,3,N(0.1)qL +#define q51 q0(4l qQ +#define q41 fp_tanh(x),gE +#define q31 x*gZ1 16l)) +#define q21 fp_asin(x),gE +#define q11 fp_acos(x),gE +#define q01 gR"cmpzz_pow" +#define mZ dA x:y);}q3 +#define mY ))+q0( +#define mX qK fp_greater( +#define mW "pow(1.5,x))" +#define mV *q0(5l +#define mU *x*x*x*x +#define mT x*x,-q0(125l qQ +#define mS +q0(4l)+ +#define mR ,400,N(0.1) +#define mQ )*(o82+( +#define mP );}q0 +#define mO o23 +#define mN +q0(0x0020)*fp_equal( +#define mM ,aS1)gM x:-x mY +#define mL fp_abs(b) +#define mK {2,qD +#define mJ qK logl( +#define mI gX2 x +#define mH {1,-15,15,2 q6 +#define mG {1,-3 o8 +#define mF log(1.1+sqrt(1.1* +#define mE ">=4" hO2 +#define mD " +" wV +#define mC dN N(0.5)qL +#define mB "(x >= y)" +#define mA +q0(0x0010)*g32( +#define m9 qN 1.1l),x)*q0(4.1l qQ +#define m8 +q0(0x0008)*fp_greaterOrEq( +#define m7 +q0(0x0004)*fp_greater( +#define m6 q0(1.0l) +#define m5 (1.1l hU +#define m4 40000,40000,5 +#define m3 *x*x,-q0(125l)) +#define m2 a22 x +#define m1 x);}q3 +#define m0 q0(4l)*d5 +#define aZ /d52) +#define aY "+ 8*(" +#define aX ">=-2" o42" 32" +#define aW " +" o13"8" +#define aV " +" o13"4" +#define aU " +" o13"2" +#define aT "<-2" o42 a02 +#define aS "exp2(x)" +#define aR "exp(x)" +#define aQ "*((1-x+x+5)" +#define aP "x,y,z" q8"/" +#define aO "(1.1" gG qL +#define aN +q0(0x0002)*dR1 +#define aM fp_or(fp_not(x),fp_not(y +#define aL (fp_truth( +#define aK ,qG"/" +#define aJ qA",y,z" q8"/" +#define aI qA",y" q8"/" +#define aH N(-1.25),N(1.25)mR1 +#define aG g1"0004 *" +#define aF ,aS1)gM-x:x mY +#define aE g1"0002 *" +#define aD fp_sin( +#define aC g1"0008 * " +#define aB wY2 fp_not(x),fp_not(y +#define aA gR1)*fp_notNot(y) +#define a9 ">-2" o42 d21 +#define a8 "<=-2" o42 d31 +#define a7 qS1}, +#define a6 a42(q0(-5.1l))*x +#define a5 qH a42(mflitm5_1)*x*y, +#define a4 N(-7.25),N(7.25),N(0.5),qM +#define a3 ,"(x < y)" +#define a2 LNG_ONLY(0)q5"/x" +#define a1 "^6.1)) +" +#define a0 "0.75)) +" +#define wZ mflit1_1)hU +#define wY A_very_long_variable_name_1 +#define wX N(-1.0,0.0)qJ N(1.0,0.0),q7 +#define wW "*((x*x)" +#define wV o13"16" +#define wU "log2(x)" +#define wT mW}, +#define wS N(6.0,0.0),wK2 qM +#define wR {1 dN N(0.25)qL +#define wQ qA qW1 +#define wP 2 mG1 1,q7 +#define wO "((x*" +#define wN qP-gE,q0(0.0625l)) +#define wM qK fp_greaterOrEq( +#define wL "(2)) +" +#define wK N(-.1),N(.1),N(0.01)qL +#define wJ qA,"03unit_constants/" +#define wI ")" hD1 +#define wH (4l),y+q0(6l)) +#define wG q0(4l)) +#define wF ,q0(1)/q0( +#define wE a42 x*x +#define wD +q0(4l)*a22 +#define wC 2,N(-3.0,0.0),N(3.0,0.0)qJ q7 +#define wB {3,N(0.0,0.0)qJ N(1.0,0.0),q7 +#define wA "*(log2(" hG1 +#define w9 ,aL1/q0( +#define w8 g32(x +#define w7 "(x))" o33"4" +#define w6 LNG_ONLY(0)q5"/pow" +#define w5 "1.1)+x"}, +#define w4 const q0*vars){const q0& +#define w3 gY2 x),-q0(4l +#define w2 "sin(x))" o33"4*(sin(x)" +#define w1 h2"(x/3))" +#define w0 "log10(x)" +#define oZ "99misc/" +#define oY qH x*aS1+y*aS1+q0( +#define oX qN 2l),x),qN-4l),y)) +#define oW qJ1 fp_exp(gE) +#define oV qH m2,wG gM +#define oU "(1.061^(x/3)))" +#define oT "((-1.061)^x))" +#define oS qZ"cmp_" +#define oR qK qW +#define oQ hA wJ +#define oP "*(tanh(x)" +#define oO "*(log" +#define oN "*(a" wQ1 +#define oM 5.0625l),qN 1.5l),x)) +#define oL fp_greater(x +#define oK "50regressions/" +#define oJ ",y","02unit_functions" +#define oI qP-gE,q0(0.0625l qQ +#define oH "1.1" gG,d62 +#define oG ,0,1,1 qL +#define oF fp_sinh(x),fp_sinh( +#define oE gC/d52,qN +#define oD qN-gC), +#define oC gY2 x),gY2 +#define oB fp_atan(x),fp_atan( +#define oA "*((x/2*x*" +#define o9 o42 oK2"*(" +#define o8 ,3,N(0.5)qL +#define o7 "*(acos(x)" +#define o6 "((x+4" +#define o5 ),q0(1l mY 2l)*dR1 aL1, +#define o4 N(-2.0,0.0),mH1,wK2 q7 +#define o3 "+y+z+y+z+y+z" +#define o2 x dO g92 g3 g3+y+z) +#define o1 "if(x" +#define o0 fp_truth(x)gM +#define dZ 4l)*y,q0(6l)) +#define dY (gW2+aL1),aD y+aL1 qQ +#define dX dR1 x +#define dW "(x^-6.1)) +" +#define dV gZ1 0l mY 2l)*dR1 aS1, +#define dU "<4, cos(y),sin(y+1" +#define dT ,"0x0001 *" +#define dS "((((x*5/2)+x*x-2))" +#define dR 2,N(-4.0,0.0),aI1 qJ q7 +#define dQ {2 mP1 +#define dP ,false qI +#define dO g92+x+x +#define dN ,-1,1, +#define dM 1 dN 1 qL +#define dL N(-7.25,0.0),N(7.25,0.0),wK2 qM +#define dK qN 2l),x),qN-4l),y qQ +#define dJ 1l)-x+x+o82),q0(4l +#define dI "*(log10(" hG1 +#define dH ",y,z" q8"/" dE1 +#define dG 5.0625l),qN 1.5l),x qQ +#define dF 8l)*fp_greaterOrEq(q0( +#define dE "<4, sin(y),cos(y+1))" +#define dD 1,1,false,aL2 +#define dC {1,-5,5,2,q7 +#define dB {1,wX +#define dA ,y)!=aS1)? +#define d9 /wW1*x*-o82),q0(4l +#define d8 /wW1*x mV)),q0(4l +#define d7 " + 0x0020 * " +#define d6 qP-d52,-q0(0.015625l +#define d5 y,q0(6l qQ +#define d4 "pow_imm_pospos_base","(" +#define d3 "pow_imm_pospos",gL",2)" +#define d2 "pow_imm_posneg",gL",3)" +#define d1 fp_greaterOrEq(x +#define d0 g2 qP q0(6.1l))) +#define hZ g2 qP-q0(6.1l) +#define hY "pow_imm_negpos",gL",-2)" +#define hX g01}, +#define hW 1,-6,6,1,q7 +#define hV "pow_imm_negneg",gL",-3)" +#define hU )+x;}q0 +#define hT 2,N(-3.0,0.0),N(3.0,0.0),mH1,q7 +#define hS N(0.5),q7 +#define hR 1.061l),x +#define hQ fp_log( +#define hP LNG_ONLY(0)q5"/sin" +#define hO fp_tanh(x),fp_tanh(q0(0.75l) +#define hN ,N(-1.0,0.0)qJ wK2 q7 +#define hM (qC,&y q32,&z=vars[2 mE1 +#define hL fp_asin(x),fp_asin(q0(0.75l) +#define hK fp_acos(x),fp_acos(q0(0.75l) +#define hJ {mQ1 3 mR1 qL +#define hI false,aG2 +#define hH "powpow_imm_base",qB1 +#define hG ,&x=vars[2],&y=vars[3 mE1(o0 aL y)gM +#define hF 0x0001l)*fp_less +#define hE const q9 +#define hD "a,b",qE +#define hC "(x)"},{1, +#define hB fp_log2( +#define hA aC2(0) +#define h9 {2,N(-1.75),N(1.75)mR1,qM +#define h8 ,false,aH2 +#define h7 1 h8 +#define h6 (4l),y+q0(6l qQ +#define h5 N(3.0,0.0),N(5.0,0.0),wK2 q7 +#define h4 "*((x^5.1)" +#define h3 "*((x^-5.1" +#define h2 "*((2.051^" +#define h1 wO"5/2)+abs(x)))" +#define h0 +q0(0x0020l)*fp_equal +#define gZ +q0(g42 g32( +#define gY -q0(2)),mflit0_0625) +#define gX N(-1.0,0.0)qJ mH1 q6 +#define gW 0x0004l)*fp_greater +#define gV N(1e-6,0.0),N(4000.0,0.0),N(0.1,0.0)dP +#define gU {3,wX +#define gT {2,N(-2.0,0.0),mH1 qJ q7 +#define gS 2,N(0.0,0.0)qJ N(1.0,0.0),q7 +#define gR qA q8"/" +#define gQ mflit1_1 hU +#define gP fp_log10( +#define gO 0x0002l)*fp_lessOrEq +#define gN N(-6.0,-3.0),N(6.0,+3.0),N(0.5,+0.25),qM +#define gM !=aS1? +#define gL "(pow(x" +#define gK mflit5_0625,a42 mflit1_5,x)) +#define gJ qP-q0(3)),-mflit0_015625) +#define gI N(-1.75,0.0),N(1.75,0.0),N(0.25,0.0),qM +#define gH 0x0008l)*fp_greaterOrEq +#define gG ")+x"},{1,0,1,1 +#define gF fp_const_pi<q0>() +#define gE wW1) +#define gD {1,N(-0.7),N(0.7),N(0.28)qL +#define gC 2.051l),x +#define gB fp_abs(x)), +#define gA (((x mV)/gE+x*x-gE,((x mV)/gE+fp_abs(x) +#define g9 {2,-6,6,1,q7 +#define g8 (w4 a=vars[0 mE1 +#define g7 "01unit_operators/" +#define g6 {2,-15,15,2 q6 +#define g5 ",y","10optimizer_bytecode" +#define g4 "*(((-2.051)^x)" +#define g3 +y+z+y+z+y+z+y+z +#define g2 q0(5.1l)), +#define g1 o33"0x" +#define g0 "y+z" o3"+y+z" +#define qZ LNG_ONLY(0)dT1 +#define qY qC,&y q32,&z=vars[2 mE1 o0 +#define qX +wW1*a22 +#define qW aL1*fp_equal( +#define qV +q0(32l)*g32( +#define qU +q0(16l)*fp_greaterOrEq( +#define qT +q0(8l)*fp_greater( +#define qS +q0(4l)*dR1 +#define qR "x,y" q8"/" +#define qQ ));}q3 +#define qP a42 x, +#define qO qA,"02unit_functions" +#define qN a42 q0( +#define qM false,aF2 +#define qL ,false q4 +#define qK qC;return +#define qJ ,N(1.0,0.0), +#define qI ,aJ2 +#define qH qC,&y=vars[1 mE1 +#define qG aI2(0)q5 +#define qF ,hA qO +#define qE "11optimizer_constaddmul/" +#define qD N(-15.0,0.0),N(15.0,0.0),mH1 q6 +#define qC const q0 q1 +#define qB qK q0:: +#define qA LNG_ONLY(0)"x" +#define q9 q0*vars){const q0&a oI1 b=vars[1 mE1 +#define q8 ,"20optimizer_optimizations" +#define q7 false,aB2 +#define q6 ,false,aD2 +#define q5 "x","10optimizer_bytecode" +#define q4 ,aE2 +#define q3 template<typename q0>static q0 +#define q2 N(-6.0,0.0),N(6.0,0.0)qJ q7 +#define q1 *vars){const q0&x=vars[0] +#define q0 Value_t +#ifdef FP_TEST_WANT_DOUBLE_TYPE +#define DBL_ONLY(p) p, +#else +#define DBL_ONLY(p) +#endif +#ifdef FP_TEST_WANT_LONG_INT_TYPE +#define LNG_ONLY(p) p, +#else +#define LNG_ONLY(p) +#endif +#define APP(x,y) x##y +#define S {2,-dS1 Add_i,aI2(aF2 Add_i)gH1"add_i","x+y"}, +#define T {3,-dS1 Addsub_i,aI2(aF2 Addsub_i)gZ2 g7"addsub_i","x+y+x+x-z+x"}, +#define U {mF1 And_i,aI2(aF2 And_i)gH1"and_i","x&y"}, +#define W {mF1 Cmpeq_i,aI2(aF2 Cmpeq_i)gH1"cmpeq_i","x=y"}, +#define Y {mF1 Cmpge_i,aI2(aF2 Cmpge_i)gH1"cmpge_i","x>=y"}, +#define S1 {mF1 Cmpgt_i,aI2(aF2 Cmpgt_i)gH1"cmpgt_i","x>y"}, +#define T1 {mF1 Cmple_i,aI2(aF2 Cmple_i)gH1"cmple_i","x<=y"}, +#define U1 {mF1 Cmplt_i,aI2(aF2 Cmplt_i)gH1"cmplt_i","x<y"}, +#define W1 {mF1 Cmpne_i,aI2(aF2 Cmpne_i)gH1"cmpne_i","x!=y"}, +#define Y1 gB1 Div_i,aI2(aF2 Div_i)gH1"div_i","x/(y+3" gO2 +#define S2 {3,-46,40,2,qM Divmul_i,aI2(aF2 Divmul_i)gZ2 g7"divmul_i","x*y*x*x/(z+3)*(x+4" gO2 +#define T2 {1,-41,40,3,qM Inv_i,aI2(aF2 Inv_i)"x",g7"inv_i","1/x"}, +#define U2 gB1 Mod_i,aI2(aF2 Mod_i)"x,z",g7"mod_i","x%(z+3" gO2 +#define W2 gB1 Mul_i,aI2(aF2 Mul_i)gH1"mul_i","x*(y+4" gO2 +#define Y2 {1,-dS1 Neg_i,aI2(aF2 Neg_i)"x",g7"neg_i","-x"}, +#define S3 {1 mG1 1,qM Not_i,aI2(aF2 Not_i)"x",g7"not_i","!x"}, +#define T3 {1 mG1 1,qM Notnot_i,aI2(aF2 Notnot_i)"x",g7"notnot_i","!!x"}, +#define U3 {mF1 Or_i,aI2(aF2 Or_i)gH1"or_i","x|y"}, +#define W3 {2,-dS1 Sub_i,aI2(aF2 Sub_i)gH1"sub_i","x-y"}, +#define Y3 {1,-40000,40000,1 dP Abs_i,aI2(aJ2 Abs_i)"x","02unit_functions/abs_i",hY3}, +#define S4 {3 mG1 1 dP If_i,aI2(aJ2 If_i)gZ2"02unit_functions/if_i",o1",y,z" gO2 +#define T4 {2,-4,4,1 dP Max,aC2(aJ2 Max)LNG_ONLY(aJ2 Max)"x" oJ"/max","max(x,y" gO2 +#define U4 {2,-4,4,1 dP Min,aC2(aJ2 Min)LNG_ONLY(aJ2 Min)"x" oJ"/min","min(x,y" gO2 +#define W4 a62 Abs,aC2(aE2 Abs)LNG_ONLY(aE2 Abs)dT1"abs","(abs(-3))+x"}, +#define Y4 {dM Absnot,aC2(aE2 Absnot)LNG_ONLY(aE2 Absnot)dT1"absnot","!(abs" hF1 +#define S5 {dM qZ3,aC2(aE2 qZ3)LNG_ONLY(aE2 qZ3)dT1"absnotnotnot","!(!!((x*x)))"}, +#define T5 {mI1 qL o43,aC2(aE2 o43)LNG_ONLY(aE2 o43)dT1"absnzge","sub" oL1" >= 4, " hY3" >= 0" gO2 +#define U5 {mI1 qL o53,aC2(aE2 o53)LNG_ONLY(aE2 o53)dT1"absnzlt","sub" oL1" < 4, " hY3" < 0" gO2 +#define W5 {dM Abssqr,aC2(aE2 Abssqr)LNG_ONLY(aE2 Abssqr)dT1"abssqr","abs(x)*abs(x)"}, +#define Y5 {1,-3,3,1 qL gO3,aC2(aE2 gO3)LNG_ONLY(aE2 gO3)dT1"dupaddmul7","(x+x)*7"}, +#define S6 hR1 h53,aC2(aE2 h53)LNG_ONLY(aE2 h53)dT1 oY1,"sub(min(x,x), max(x," dX2 +#define T6 hR1 gP3,aC2(aE2 gP3)LNG_ONLY(aE2 gP3)dT1 oY1"2","sub(x+min(x,x), x+max(x," dX2 +#define U6 {2 mG1 1 qL gQ3,aC2(aE2 gQ3)LNG_ONLY(aE2 gQ3)gI1 oY1"3","sub(min(min(y,x),x), max(max(y,x)," dX2 +#define W6 hR1 gR3,aC2(aE2 gR3)LNG_ONLY(aE2 gR3)dT1"dupxmuladd","x+(x*4" gO2 +#define Y6 a32 Invmul,aC2(aE2 Invmul)LNG_ONLY(aE2 Invmul)gI1"invmul","y*(1/x)"}, +#define S7 a62 Max,aC2(aE2 Max)LNG_ONLY(aE2 Max)dT1"max","max(5,4)+x"}, +#define T7 a62 Min,aC2(aE2 Min)LNG_ONLY(aE2 Min)dT1"min","min(4,5)+x"}, +#define U7 a62 Mul2,aC2(aE2 Mul2)LNG_ONLY(aE2 Mul2)dT1"mul2","x*2"}, +#define W7 {oB3 1 qL Mul4,aC2(aE2 Mul4)LNG_ONLY(aE2 Mul4)gI1"mul4","y*(x*2)*2 + (y*2)*2"}, +#define Y7 {dM Negabs,aC2(aE2 Negabs)LNG_ONLY(aE2 Negabs)dT1"negabs","abs" wM1 +#define S8 {dM Negdiv,aC2(aE2 Negdiv)LNG_ONLY(aE2 Negdiv)dT1"negdiv","(-x)/" gV2 +#define T8 {1,hE1 Negneg,aC2(aE2 Negneg)LNG_ONLY(aE2 Negneg)dT1"negneg","-(-(-(-(-(-(x))))))"}, +#define U8 {dM Negnot,aC2(aE2 Negnot)LNG_ONLY(aE2 Negnot)dT1"negnot","!" wM1 +#define W8 {dM Negsqr,aC2(aE2 Negsqr)LNG_ONLY(aE2 Negsqr)dT1"negsqr","(-x)*(-" aN1 +#define Y8 {2 oG Not_eq,aC2(aE2 Not_eq)LNG_ONLY(aE2 Not_eq)gI1"not_eq","!" hX1 +#define S9 {2 oG Not_ge,aC2(aE2 Not_ge)LNG_ONLY(aE2 Not_ge)gI1"not_ge","!" mB}, +#define T9 {2 oG Not_gt,aC2(aE2 Not_gt)LNG_ONLY(aE2 Not_gt)gI1"not_gt","!(x > y" gO2 +#define U9 {2 oG Not_le,aC2(aE2 Not_le)LNG_ONLY(aE2 Not_le)gI1"not_le","!" g51}, +#define W9 {2 oG Not_lt,aC2(aE2 Not_lt)LNG_ONLY(aE2 Not_lt)gI1"not_lt","!(x < y" gO2 +#define Y9 {2 oG Not_ne,aC2(aE2 Not_ne)LNG_ONLY(aE2 Not_ne)gI1"not_ne","!" hY1 +#define SA {dM Notnot,aC2(aE2 Notnot)LNG_ONLY(aE2 Notnot)dT1"notnot","!!(x)"}, +#define TA {dM h63,aC2(aE2 h63)LNG_ONLY(aE2 h63)dT1"notnotnot","!!!(x)"}, +#define UA {dM gS3,aC2(aE2 gS3)LNG_ONLY(aE2 gS3)dT1"notnotnot2","!x&!x"}, +#define WA {dM o63,aC2(aE2 o63)LNG_ONLY(aE2 o63)dT1"sqr_nxx","(-x)*x"}, +#define YA {dM o73,aC2(aE2 o73)LNG_ONLY(aE2 o73)dT1"sqr_xnx","x*(-" aN1 +#define SB {dM Sqr_xx,aC2(aE2 Sqr_xx)LNG_ONLY(aE2 Sqr_xx)dT1"sqr_xx","x*x"}, +#define TB {wD1 hZ3,aC2(aE2 hZ3)LNG_ONLY(aE2 hZ3)gI1"sqr_ynxx","y*-x*x"}, +#define UB {wD1 d03,aC2(aE2 d03)LNG_ONLY(aE2 d03)gI1"sqr_yxnx","y*x*-x"}, +#define WB {wD1 o83,aC2(aE2 o83)LNG_ONLY(aE2 o83)gI1"sqr_yxx","y*x*x"}, +#define YB {mI1 qL o93,aC2(aE2 o93)LNG_ONLY(aE2 o93)q5"/xaddnot","!(x+4" gO2 +#define SC {mI1 qL gT3,aC2(aE2 gT3)LNG_ONLY(aE2 gT3)q5"/xaddnotnot","!!(x+4" gO2 +#define TC {dM Xxdup,aC2(aE2 Xxdup)LNG_ONLY(aE2 Xxdup)q5"/xxdup","sub(x," aN1 +#define UC {wD1 d13,aC2(aE2 d13)LNG_ONLY(aE2 d13)"x" g5"/xxsqrdup","y*abs(x)*abs(x)"}, +#define WC {mI1,q7 o43,aC2(aB2 o43)LNG_ONLY(aB2 o43)gN1"absnzge","sub" oL1" >= if" wF2"), " hY3 dF2"(if(1,1,0)-1))"}, +#define YC {mI1,q7 o53,aC2(aB2 o53)LNG_ONLY(aB2 o53)gN1"absnzlt","sub" oL1" < if" wF2"), " hY3" < (if(1,1,0)-1))"}, +#define SD {d51 gF3,aC2(aB2 gF3)LNG_ONLY(aB2 gF3)qR"addconstmul","5*(if" wF2")+x+" oS2 +#define TD {d51 qK3,aC2(aB2 qK3)LNG_ONLY(aB2 qK3)qR"addmulconstmul","5*(if" wF2")*y+x)"}, +#define UD {d51 g03,aC2(aB2 g03)LNG_ONLY(aB2 g03)qR"addnegmulneg","-5 + (if(1,5,0)*x*" oS2 +#define WD {d51 g13,aC2(aB2 g13)LNG_ONLY(aB2 g13)qR"addnegmulpos","(if(1,-5,0)*y" o42" (if(1,5,0)*x)"}, +#define YD g9 qS3,aC2(aB2 qS3)LNG_ONLY(aB2 qS3)qR"cmpeq_add_imm",qX1 q52 +#define SE {hW mP2,aC2(aB2 mP2)LNG_ONLY(aB2 mP2)gN1"cmpeq_add_reduce",dS" = " h1}, +#define TE g9 mQ2,aC2(aB2 mQ2)LNG_ONLY(aB2 mQ2)qR"cmpeq_addadd_imm",dY2" =" gX3 +#define UE dQ g23,aC2(aB2 g23)LNG_ONLY(aB2 g23)qR"cmpeq_minma" dX3"= " g33 +#define WE dQ mR2,aC2(aB2 mR2)LNG_ONLY(aB2 mR2)qR"cmpeq_minma" dY3"= " mS2 +#define YE g9 m72,aC2(aB2 m72)LNG_ONLY(aB2 m72)qR"cmpeq_mul_imm_neg",hC1 q52 +#define SF g9 m82,aC2(aB2 m82)LNG_ONLY(aB2 m82)qR"cmpeq_mul_imm_pos",dU1 q52 +#define TF g9 aO2,aC2(aB2 aO2)LNG_ONLY(aB2 aO2)qR"cmpeq_mulmul_imm_neg",a31" =" gX3 +#define UF g9 aP2,aC2(aB2 aP2)LNG_ONLY(aB2 aP2)qR"cmpeq_mulmul_imm_pos",d23"=" gX3 +#define WF g9 qT3,aC2(aB2 qT3)LNG_ONLY(aB2 qT3)qR"cmpge_add_imm",qX1 a41 +#define YF {hW mT2,aC2(aB2 mT2)LNG_ONLY(aB2 mT2)gN1"cmpge_add_reduce",dS dF2 h1}, +#define SG g9 mU2,aC2(aB2 mU2)LNG_ONLY(aB2 mU2)qR"cmpge_addadd_imm",dY2 dF2 hX +#define TG dQ g43,aC2(aB2 g43)LNG_ONLY(aB2 g43)qR"cmpge_minma" dX3">= " g33 +#define UG dQ mV2,aC2(aB2 mV2)LNG_ONLY(aB2 mV2)qR"cmpge_minma" dY3">= " mS2 +#define WG g9 m92,aC2(aB2 m92)LNG_ONLY(aB2 m92)qR"cmpge_mul_imm_neg",hC1 a41 +#define YG g9 mA2,aC2(aB2 mA2)LNG_ONLY(aB2 mA2)qR"cmpge_mul_imm_pos",dU1 a41 +#define SH g9 aQ2,aC2(aB2 aQ2)LNG_ONLY(aB2 aQ2)qR"cmpge_mulmul_imm_neg",a31 dF2 hX +#define TH g9 aR2,aC2(aB2 aR2)LNG_ONLY(aB2 aR2)qR"cmpge_mulmul_imm_pos",wO"4)" dF2 hX +#define UH g9 qU3,aC2(aB2 qU3)LNG_ONLY(aB2 qU3)qR"cmpgt_add_imm",qX1 qC2 +#define WH {hW mW2,aC2(aB2 mW2)LNG_ONLY(aB2 mW2)gN1"cmpgt_add_reduce",dS" > " h1}, +#define YH g9 mX2,aC2(aB2 mX2)LNG_ONLY(aB2 mX2)qR"cmpgt_addadd_imm",dY2" >" gX3 +#define SI dQ g53,aC2(aB2 g53)LNG_ONLY(aB2 g53)qR"cmpgt_minma" dX3"> " g33 +#define TI dQ mY2,aC2(aB2 mY2)LNG_ONLY(aB2 mY2)qR"cmpgt_minma" dY3"> " mS2 +#define UI g9 mB2,aC2(aB2 mB2)LNG_ONLY(aB2 mB2)qR"cmpgt_mul_imm_neg",hC1 qC2 +#define WI g9 mC2,aC2(aB2 mC2)LNG_ONLY(aB2 mC2)qR"cmpgt_mul_imm_pos",dU1 qC2 +#define YI g9 aS2,aC2(aB2 aS2)LNG_ONLY(aB2 aS2)qR"cmpgt_mulmul_imm_neg",a31" >" gX3 +#define SJ g9 aT2,aC2(aB2 aT2)LNG_ONLY(aB2 aT2)qR"cmpgt_mulmul_imm_pos",d23">" gX3 +#define TJ g9 qV3,aC2(aB2 qV3)LNG_ONLY(aB2 qV3)qR"cmple_add_imm",qX1 a51 +#define UJ {hW mZ2,aC2(aB2 mZ2)LNG_ONLY(aB2 mZ2)gN1"cmple_add_reduce",dS oT3 h1}, +#define WJ g9 q03,aC2(aB2 q03)LNG_ONLY(aB2 q03)qR"cmple_addadd_imm",dY2" " w13 +#define YJ dQ g63,aC2(aB2 g63)LNG_ONLY(aB2 g63)qR"cmple_minma" dX3"<= " g33 +#define SK dQ q13,aC2(aB2 q13)LNG_ONLY(aB2 q13)qR"cmple_minma" dY3"<= " mS2 +#define TK g9 mD2,aC2(aB2 mD2)LNG_ONLY(aB2 mD2)qR"cmple_mul_imm_neg",hC1 a51 +#define UK g9 mE2,aC2(aB2 mE2)LNG_ONLY(aB2 mE2)qR"cmple_mul_imm_pos",dU1 a51 +#define WK g9 aU2,aC2(aB2 aU2)LNG_ONLY(aB2 aU2)qR"cmple_mulmul_imm_neg",a31" " w13 +#define YK g9 aV2,aC2(aB2 aV2)LNG_ONLY(aB2 aV2)qR"cmple_mulmul_imm_pos",d23 w13 +#define SL g9 qW3,aC2(aB2 qW3)LNG_ONLY(aB2 qW3)qR"cmplt_add_imm",qX1 a61}, +#define TL {hW q23,aC2(aB2 q23)LNG_ONLY(aB2 q23)gN1"cmplt_add_reduce",dS oV3 h1}, +#define UL g9 q33,aC2(aB2 q33)LNG_ONLY(aB2 q33)qR"cmplt_addadd_imm",dY2" " w23 +#define WL dQ g73,aC2(aB2 g73)LNG_ONLY(aB2 g73)qR"cmplt_minma" dX3"< " g33 +#define YL dQ q43,aC2(aB2 q43)LNG_ONLY(aB2 q43)qR"cmplt_minma" dY3"< " mS2 +#define SM g9 mF2,aC2(aB2 mF2)LNG_ONLY(aB2 mF2)qR"cmplt_mul_imm_neg",hC1 a61}, +#define TM g9 mG2,aC2(aB2 mG2)LNG_ONLY(aB2 mG2)qR"cmplt_mul_imm_pos",dU1 a61}, +#define UM g9 aW2,aC2(aB2 aW2)LNG_ONLY(aB2 aW2)qR"cmplt_mulmul_imm_neg",a31" " w23 +#define WM g9 aX2,aC2(aB2 aX2)LNG_ONLY(aB2 aX2)qR"cmplt_mulmul_imm_pos",d23 w23 +#define YM g9 qX3,aC2(aB2 qX3)LNG_ONLY(aB2 qX3)qR"cmpne_add_imm",qX1 dV1}, +#define SN {hW q53,aC2(aB2 q53)LNG_ONLY(aB2 q53)gN1"cmpne_add_reduce",dS dG2 h1}, +#define TN g9 q63,aC2(aB2 q63)LNG_ONLY(aB2 q63)qR"cmpne_addadd_imm",dY2 dG2 hX +#define UN dQ g83,aC2(aB2 g83)LNG_ONLY(aB2 g83)qR"cmpne_minma" h12 gZ3 g33 +#define WN dQ q73,aC2(aB2 q73)LNG_ONLY(aB2 q73)qR"cmpne_minma" h42 gZ3 mS2 +#define YN g9 mH2,aC2(aB2 mH2)LNG_ONLY(aB2 mH2)qR"cmpne_mul_imm_neg",hC1 dV1}, +#define SO g9 mI2,aC2(aB2 mI2)LNG_ONLY(aB2 mI2)qR"cmpne_mul_imm_pos",dU1 dV1}, +#define TO g9 aY2,aC2(aB2 aY2)LNG_ONLY(aB2 aY2)qR"cmpne_mulmul_imm_neg",a31 dG2 hX +#define UO g9 aZ2,aC2(aB2 aZ2)LNG_ONLY(aB2 aZ2)qR"cmpne_mulmul_imm_pos",wO"4)" dG2 hX +#define WO g9 qY3,aC2(aB2 qY3)LNG_ONLY(aB2 qY3)qR"cmpzz_add_imm" dT h52 a61 aE h52 oZ1 h52 a71 qX1 a81 h52 dV1 d7 qX1 q52 +#define YO {hW q83,aC2(aB2 q83)LNG_ONLY(aB2 q83)gN1"cmpzz_add_reduce" dT" " dS oV3 h1 aE" " dS oT3 h1 aG" " dS" > " h1 aC dS dF2 h1 hD1" " dS dG2 h1 d7 dS" = " h1}, +#define SP g9 q93,aC2(aB2 q93)LNG_ONLY(aB2 q93)qR"cmpzz_addadd_imm" dT" " o6 q62" " o6 q92" " o6 qA2 dY2 dF2 dZ2" " dY2 oW1 dY2" =" gX3 +#define TP dQ g93,aC2(aB2 g93)LNG_ONLY(aB2 g93)qR"cmpzz_minmax" dT d33"< " d43 aE d33"<= " d43 aG d33"> " d43 g1"0008 " h62" >= y,x,y" wI g11 gZ3"y,x,y" o42" 0x0020 " h62" = " g33 +#define UP dQ qA3,aC2(aB2 qA3)LNG_ONLY(aB2 qA3)qR"cmpzz_minmax_rev" dT d33"< " gK3 aE d33"<= " gK3 aG d33"> " gK3 g1"0008 " h62" >= " gK3 hD1 g11 gZ3 gK3" + 0x0020 " h62" = " mS2 +#define WP g9 mJ2,aC2(aB2 mJ2)LNG_ONLY(aB2 mJ2)qR"cmpzz_mul_imm_neg" dT mJ1 a61 aE mJ1 oZ1 mJ1 a71 hC1 a81 mJ1 dV1 d7 hC1 q52 +#define YP g9 mK2,aC2(aB2 mK2)LNG_ONLY(aB2 mK2)qR"cmpzz_mul_imm_pos" dT mK1 a61 aE mK1 oZ1 mK1 a71 dU1 a81 mK1 dV1 d7 dU1 q52 +#define SQ g9 m02,aC2(aB2 m02)LNG_ONLY(aB2 m02)qR"cmpzz_mulmul_imm_neg" dT qY1 q62 qY1 q92 qY1 qA2 a31 dF2 dZ2 qY1")" oW1 a31" =" gX3 +#define TQ g9 m12,aC2(aB2 m12)LNG_ONLY(aB2 m12)qR"cmpzz_mulmul_imm_pos" dT qZ1 q62 qZ1 q92 qZ1 qA2 wO"4)" dF2 dZ2 qZ1")" oW1 d23"=" gX3 +#define UQ dQ h73,aC2(aB2 h73)LNG_ONLY(aB2 h73)qR"ge_and_eq",o02 hX1 +#define WQ dQ h83,aC2(aB2 h83)LNG_ONLY(aB2 h83)qR"ge_and_le",o02 g51}, +#define YQ dQ h93,aC2(aB2 h93)LNG_ONLY(aB2 h93)qR"ge_and_ne",o02 hY1 +#define SR dQ d53,aC2(aB2 d53)LNG_ONLY(aB2 d53)qR"ge_or_eq",o12 hX1 +#define TR dQ d63,aC2(aB2 d63)LNG_ONLY(aB2 d63)qR"ge_or_le",o12 g51}, +#define UR dQ d73,aC2(aB2 d73)LNG_ONLY(aB2 d73)qR"ge_or_ne",o12 hY1 +#define WR dQ hA3,aC2(aB2 hA3)LNG_ONLY(aB2 hA3)qR"gt_and_eq" mL1 hX1 +#define YR dQ hB3,aC2(aB2 hB3)LNG_ONLY(aB2 hB3)qR"gt_and_ge" mL1 mB}, +#define SS dQ hC3,aC2(aB2 hC3)LNG_ONLY(aB2 hC3)qR"gt_and_le" mL1 g51}, +#define TS dQ hD3,aC2(aB2 hD3)LNG_ONLY(aB2 hD3)qR"gt_and_ne" mL1 hY1 +#define US dQ d83,aC2(aB2 d83)LNG_ONLY(aB2 d83)qR"gt_or_eq" mM1 hX1 +#define WS dQ d93,aC2(aB2 d93)LNG_ONLY(aB2 d93)qR"gt_or_ge" mM1 mB}, +#define YS dQ dA3,aC2(aB2 dA3)LNG_ONLY(aB2 dA3)qR"gt_or_le" mM1 g51}, +#define ST dQ dB3,aC2(aB2 dB3)LNG_ONLY(aB2 dB3)qR"gt_or_ne" mM1 hY1 +#define TT g91 If10,aC2(aB2 If10)LNG_ONLY(aB2 If10)gN1"if10",o1",1,0" o42" 10*" o1",0,1)" o13" + 100*" o1">0,1,0" o42" 1000*" o1">0,0,1" gO2 +#define UT {wP qL3,aC2(aB2 qL3)LNG_ONLY(aB2 qL3)gQ2"tract_abs",dZ3"abs(x+2), abs(y+5))"}, +#define WT {wP qM3,aC2(aB2 qM3)LNG_ONLY(aB2 qM3)gQ2"tract_add" aX1"+2, y+" q12 +#define YT {wP qE3,aC2(aB2 qE3)LNG_ONLY(aB2 qE3)gQ2"tract_add1" aX1"+2, y" gO2 +#define SU {wP qF3,aC2(aB2 qF3)LNG_ONLY(aB2 qF3)gQ2"tract_add2",dZ3"y, y+2" gO2 +#define TU {qN1 mL2,aC2(aB2 mL2)LNG_ONLY(aB2 mL2)mN1"tract_and1_l" aX1"&z, y<1" gO2 +#define UU {qN1 m32,aC2(aB2 m32)LNG_ONLY(aB2 m32)mN1"tract_and1_nl" aX1"&z, z" gO2 +#define WU {qN1 mM2,aC2(aB2 mM2)LNG_ONLY(aB2 mM2)mN1"tract_and2_l",dZ3"y<1, y&z" gO2 +#define YU {qN1 m42,aC2(aB2 m42)LNG_ONLY(aB2 m42)mN1"tract_and2_nl",dZ3"z, y&z" gO2 +#define SV {wP If_extract_div,aI2(aB2 If_extract_div)gQ2"tract_div" aX1"/x, y/2" gO2 +#define TV {wP qN3,aC2(aB2 qN3)LNG_ONLY(aB2 qN3)gQ2"tract_min",dZ3"min(y,2), min(y,5))"}, +#define UV {wP qO3,aC2(aB2 qO3)LNG_ONLY(aB2 qO3)gQ2"tract_mul" aX1"*2, y*" q12 +#define WV {wP qG3,aC2(aB2 qG3)LNG_ONLY(aB2 qG3)gQ2"tract_mul1" aX1"*2, y" gO2 +#define YV {wP qH3,aC2(aB2 qH3)LNG_ONLY(aB2 qH3)gQ2"tract_mul2",dZ3"y, y*2" gO2 +#define SW {qN1 qB3,aC2(aB2 qB3)LNG_ONLY(aB2 qB3)mN1"tract_or1_l",dZ3"y|z, y<1" gO2 +#define TW {qN1 mN2,aC2(aB2 mN2)LNG_ONLY(aB2 mN2)mN1"tract_or1_nl",dZ3"y|z, z" gO2 +#define UW {qN1 qC3,aC2(aB2 qC3)LNG_ONLY(aB2 qC3)mN1"tract_or2_l",dZ3"y<1, y|z" gO2 +#define WW {qN1 mO2,aC2(aB2 mO2)LNG_ONLY(aB2 mO2)mN1"tract_or2_nl",dZ3"z, y|z" gO2 +#define YW {1,3,5,1,q7 gA3,aC2(aB2 gA3)LNG_ONLY(aB2 gA3)gN1"if_join_add2","x + 10 +" g11"<4, 3,4" gO2 +#define SX {1,3,5,1,q7 gB3,aC2(aB2 gB3)LNG_ONLY(aB2 gB3)gN1"if_join_mul2","x * 10 " h62"<4, 3,4" gO2 +#define TX oA1 Ifabs,aC2(aB2 Ifabs)LNG_ONLY(aB2 Ifabs)gN1"ifabs","1" qO1"< 0,-x" qP3 o13"10" qO1"<=0,-x" qP3" 100" qO1"> 0,-x" qP3" 1000" qO1">=0,-x" qP3"10000" qO1"< 0,x" h82 aM2" 100000" qO1"<=0,x" h82 aM2"1000000" qO1"> 0,x" h82" 10000000" qO1">=0,x,-" dX2 +#define UX {qD2 oA3,aC2(aB2 oA3)LNG_ONLY(aB2 oA3)"b,d," qR"ifmerge",o1 gJ2"y,x,b" oV2"y,x,d)) + if(b,if(d,y,x)" gJ2"d,b," dX2 +#define WX {qD2 dC3,aC2(aB2 dC3)LNG_ONLY(aB2 dC3)"a,b," qR"ifmerge2",o1 gJ2"y,a,b" oV2"b,a,b))"}, +#define YX {qD2 hE3,aC2(aB2 hE3)LNG_ONLY(aB2 hE3)"a,b," qR"ifmerge2b",o1 gJ2"y,a,b" oV2"b,b,a))"}, +#define SY dQ Ifnop,aC2(aB2 Ifnop)LNG_ONLY(aB2 Ifnop)qR"ifnop",o1",y,y" gO2 +#define TY {d41 L_abs,aC2(aB2 L_abs)LNG_ONLY(aB2 L_abs)qR"l_abs","(x+2) & " hY3 hB1 +#define UY {d41 dD3,aC2(aB2 dD3)LNG_ONLY(aB2 dD3)qR"l_mulabs","(x*abs(y))" hB1 +#define WY {d41 dE3,aC2(aB2 dE3)LNG_ONLY(aB2 dE3)qR"l_mulneg","(x*y*-5)" hB1 +#define YY {d41 dF3,aC2(aB2 dF3)LNG_ONLY(aB2 dF3)qR"l_notnot","(x+2) & !!x" hB1 +#define SZ dQ hF3,aC2(aB2 hF3)LNG_ONLY(aB2 hF3)qR"le_and_eq",g51" & " hX1 +#define TZ dQ hG3,aC2(aB2 hG3)LNG_ONLY(aB2 hG3)qR"le_and_ne",g51" & " hY1 +#define UZ dQ dG3,aC2(aB2 dG3)LNG_ONLY(aB2 dG3)qR"le_or_eq",g51" | " hX1 +#define WZ dQ dH3,aC2(aB2 dH3)LNG_ONLY(aB2 dH3)qR"le_or_ne",g51" | " hY1 +#define YZ dQ hH3,aC2(aB2 hH3)LNG_ONLY(aB2 hH3)qR"lt_and_eq" qE2 hX1 +#define Sa dQ hI3,aC2(aB2 hI3)LNG_ONLY(aB2 hI3)qR"lt_and_ge" qE2 mB}, +#define Ta dQ hJ3,aC2(aB2 hJ3)LNG_ONLY(aB2 hJ3)qR"lt_and_gt" qE2"(x > y" gO2 +#define Ua dQ hK3,aC2(aB2 hK3)LNG_ONLY(aB2 hK3)qR"lt_and_le" qE2 g51}, +#define Wa dQ hL3,aC2(aB2 hL3)LNG_ONLY(aB2 hL3)qR"lt_and_ne" qE2 hY1 +#define Ya dQ dI3,aC2(aB2 dI3)LNG_ONLY(aB2 dI3)qR"lt_or_eq" hM3 hX1 +#define Sb dQ dJ3,aC2(aB2 dJ3)LNG_ONLY(aB2 dJ3)qR"lt_or_ge" hM3 mB}, +#define Tb dQ dK3,aC2(aB2 dK3)LNG_ONLY(aB2 dK3)qR"lt_or_gt" hM3"(x > y" gO2 +#define Ub dQ dL3,aC2(aB2 dL3)LNG_ONLY(aB2 dL3)qR"lt_or_le" hM3 g51}, +#define Wb dQ dM3,aC2(aB2 dM3)LNG_ONLY(aB2 dM3)qR"lt_or_ne" hM3 hY1 +#define Yb {qN1 gG3,aC2(aB2 gG3)LNG_ONLY(aB2 gG3)aP"mergemulabs","abs(x)*abs(y)*z"}, +#define Sc {3,0,4,1,q7 gH3,aC2(aB2 gH3)LNG_ONLY(aB2 gH3)aP"mixedminmax","max(z,min(x,max(max(z,y),x)))" o33"10*min(z,max(x,min(y,x)))" o33"100*min(max(x,y),min(y,z)) + 1000*max(min(x,y),max(y,z))"}, +#define Tc dQ Nand2,aC2(aB2 Nand2)LNG_ONLY(aB2 Nand2)qR"nand2",hN3}, +#define Uc mO1 hO3,aC2(aB2 hO3)LNG_ONLY(aB2 hO3)aP"nand2plus",hN3" | z"}, +#define Wc mO1 Nand3,aC2(aB2 Nand3)LNG_ONLY(aB2 Nand3)aP"nand3",hN3" | !z"}, +#define Yc dQ Nor2,aC2(aB2 Nor2)LNG_ONLY(aB2 Nor2)qR"nor2",hP3}, +#define Sd mO1 dN3,aC2(aB2 dN3)LNG_ONLY(aB2 dN3)aP"nor2plus",hP3" & z"}, +#define Td mO1 Nor3,aC2(aB2 Nor3)LNG_ONLY(aB2 Nor3)aP"nor3",hP3" & !z"}, +#define Ud dQ Not_eq,aC2(aB2 Not_eq)LNG_ONLY(aB2 Not_eq)qR"not_eq",o1" = " m22 +#define Wd dQ Not_ge,aC2(aB2 Not_ge)LNG_ONLY(aB2 Not_ge)qR"not_ge",o1" >= " m22 +#define Yd dQ Not_gt,aC2(aB2 Not_gt)LNG_ONLY(aB2 Not_gt)qR"not_gt",o1" > " m22 +#define Se dQ Not_le,aC2(aB2 Not_le)LNG_ONLY(aB2 Not_le)qR"not_le",o1 oT3 m22 +#define Te dQ Not_lt,aC2(aB2 Not_lt)LNG_ONLY(aB2 Not_lt)qR"not_lt",o1 oV3 m22 +#define Ue dQ Not_ne,aC2(aB2 Not_ne)LNG_ONLY(aB2 Not_ne)qR"not_ne",o1 gZ3 m22 +#define We {wP Notnot,aC2(aB2 Notnot)LNG_ONLY(aB2 Notnot)qR"notnot","!!x + if(y, 1,0" gO2 +#define Ye {mI1,q7 o93,aC2(aB2 o93)LNG_ONLY(aB2 o93)"x" q8"/xaddnot","!(x+if(1,4,4))"}, +#define Sf {mI1,q7 gT3,aC2(aB2 gT3)LNG_ONLY(aB2 gT3)"x" q8"/xaddnotnot","!!(x+if(1,4,4))"}, +#define Tf {1,-a91 t1,aC2(aG2 t1)LNG_ONLY(aG2 t1)wE2"1","x+max(0, min(-2,0))"}, +#define Uf {1,-a91 t2,aC2(aG2 t2)LNG_ONLY(aG2 t2)wE2"2","min(x,min(1," dX2 +#define Wf {1 h92 t3,aC2(aG2 t3)LNG_ONLY(aG2 t3)wE2"3","sub( (!x & !!x) , (!x | !!x) " gO2 +#define Yf {2 h92 t4,aC2(aG2 t4)LNG_ONLY(aG2 t4)"x,y",oK"4","sub(!(x-y), !!(x-y))"}, +#define Sg {mI1,hI t6,aC2(aG2 t6)LNG_ONLY(aG2 t6)wE2"6","sub(!(x+4), !!(x+3))"}, +#define Tg {1,-a91 t36,aC2(aG2 t36)LNG_ONLY(aG2 t36)wE2"36","-if(x<0, x, -x) + -if(x<5, 2, 3" gO2 +#define Ug {2 h92 t60,aC2(aG2 t60)LNG_ONLY(aG2 t60)"x,y",oK"60","sqr(x) | sub(x,y) | value()"}, +#define Wg {2,-20,20,h7 t16,aC2(aH2 t16)LNG_ONLY(aH2 t16)d61"16",o1"<0, if(y<0, x+y, x-y), if(y>0, x*y, x+2*y))"}, +#define Yg {2,-20,20,h7 t17,aC2(aH2 t17)LNG_ONLY(aH2 t17)d61"17","sqr(x)+sub(x,y)+psqr(y)+psub(y+1,x-2)-1"}, +#define Sh {2,-100,100,h7 t19,aC2(aH2 t19)LNG_ONLY(aH2 t19)d61"19","(x<y)+10" wE1"<=y)+100" wE1">y)+1000" wE1">=y)+10000" wE1"=y)+100000" wE1"!=y)+ (x&y)*2+(x|y)*20+(!x)*200+(!!x)*2000+4*!((x<y)&(x<3))+40*!!(!(x>y)|(x>3))"}, +#define Th {2,-100,100,h7 t20,aC2(aH2 t20)LNG_ONLY(aH2 t20)d61"20","(!(x" gZ3"y) & !x) + !(!(!(!y)))"}, +#define Uh {1,-hA2 t21,aC2(aH2 t21)LNG_ONLY(aH2 t21)"x",oZ"21","sqr(x)+value()-pvalue ( " gO2 +#define Wh wJ2 h7 t24,aC2(aH2 t24)LNG_ONLY(aH2 t24)"x",oZ"24","(min(x, min(1," w01" min(x, 1))/2 + min(x, 1)*3 + max(0, min(-2,0))"}, +#define Yh {2,-5,5,h7 t29,aC2(aH2 t29)LNG_ONLY(aH2 t29)d61"29","x-y*1"}, +#define Si {4,-5,5,h7 t34,aC2(aH2 t34)LNG_ONLY(aH2 t34)"t,ã†,ãŠ,æ—©",oZ"34","ãŠ+æ—©*ã†-t"}, +#define Ti {3,-hA2 t35,aC2(aH2 t35)LNG_ONLY(aH2 t35)"A_very_long_variable_name_1,A_very_long_variable_name_2,Yet_a_third_very_long_variable_name",oZ"35","A_very_long_variable_name_1-A_very_long_variable_name_2+ Yet_a_third_very_long_variable_name*A_very_long_variable_name_1"}, +#define Ui {2,-hA2 t50,aC2(aH2 t50)LNG_ONLY(aH2 t50)d61"50","(x<y | y<x) +" o23"2" wE1"<y & y<x) +" o23"4" gU3"y<=x) +" o23"8" wE1"<y & " qF2 o23"16" wE1"<y | " qF2 o23"32" gU3"x>=y" gL3" 64" wE1"<=y | x>=y" gL3" 128" wE1"!=y & x=y" gL3" 256" wE1"!=y & " qF2" 512" gU3"x=y" gO2 +#define Wi {2,-11,11,h7 t58,aC2(aH2 t58)LNG_ONLY(aH2 t58)d61"58","(-x < 3" o72"-1 > 5" o72"-3 < 10" o72"-3 < y*7" o42" (x*4 < y*7" o72"6 < y*-3" o42" (-x < 11" o42" (5 < -y" gO2 +#define Yi {3,-8,7,h7 I1,aI2(aH2 I1)mU1"i1","1+2+3-4*5*6/3+10/2-9%2 + (x+y - 11*x + z/10 + x/(z+31))"}, +#define Sj {3,-7,7,h7 I2,aI2(aH2 I2)mU1"i2","if(abs(x*y) < 20 | x+y > 30 & z > 5, min(x,2*y), max(y,z*2))"}, +#define Tj {3,1,7,h7 I3,aI2(aH2 I3)mU1"i3","(x+y" o42" 2" wE1"-z" o42" 3*(x*y" o42" 4*(y/z" o42" 5" wE1"%z" gL3"6" wE1"<y" o42" 7" wE1"<=z" o42" 8" wE1">2" o32" 9*(y>=3" o32" 10*(x+y!=z" o42" 11*(100+x) + 12*(101-y" o42" 13*(102" o32" 14*(103/x)"}, +#define Uj {2,qP1 Add_d,aC2(aF2 Add_d)wQ"add_d","x+y"}, +#define Wj {3,qP1 Addsub_d,aC2(aF2 Addsub_d)qG2 g7"addsub_d","x+y+x+x-z+x"}, +#define Yj h9 And_d,aC2(aF2 And_d)wQ"and_d","x&y"}, +#define Sk h9 Cmpeq_d,aC2(aF2 Cmpeq_d)wQ"cmpeq_d","x=y"}, +#define Tk h9 Cmpge_d,aC2(aF2 Cmpge_d)wQ"cmpge_d","x>=y"}, +#define Uk h9 Cmpgt_d,aC2(aF2 Cmpgt_d)wQ"cmpgt_d","x>y"}, +#define Wk h9 Cmple_d,aC2(aF2 Cmple_d)wQ"cmple_d","x<=y"}, +#define Yk h9 Cmplt_d,aC2(aF2 Cmplt_d)wQ"cmplt_d","x<y"}, +#define Sl h9 Cmpne_d,aC2(aF2 Cmpne_d)wQ"cmpne_d","x!=y"}, +#define Tl {2,a4 Div_d,aC2(aF2 Div_d)wQ"div_d","(x-0.25)/y"}, +#define Ul {3,a4 Divmul_d,aC2(aF2 Divmul_d)qG2 g7"divmul_d","x*y*x*x/z" wE1"-0.25" gO2 +#define Wl {1,-7,6,N(0.6),qM Inv_d,aC2(aF2 Inv_d)qA,g7"inv_d","1/x"}, +#define Yl {2,a4 Mul_d,aC2(aF2 Mul_d)wQ"mul_d","x*y"}, +#define Sm {1,qP1 Neg_d,aC2(aF2 Neg_d)qA,g7"neg_d","-x"}, +#define Tm {1,aH,qM Not_d,aC2(aF2 Not_d)qA,g7"not_d","!x"}, +#define Um {1,aH,qM Notnot_d,aC2(aF2 Notnot_d)qA,g7"notnot_d","!!x"}, +#define Wm h9 Or_d,aC2(aF2 Or_d)wQ"or_d","x|y"}, +#define Ym {2,qP1 Sub_d,aC2(aF2 Sub_d)wQ"sub_d","x-y"}, +#define Sn {1,-400,400,N(0.5)dP Abs_d,aC2(aJ2 Abs_d)qO"/abs_d",hY3}, +#define Tn {3,aH dP If_d,aC2(aJ2 If_d)qG2"02unit_functions/if_d",o1",y,z" gO2 +#define Un {1,-4000,dL1 Int,aC2(aJ2 Int)qO"/int","int(x)"}, +#define Wn wR Absneverneg,aC2(aE2 Absneverneg)qZ"absneverneg" mA1 gE3 +#define Yn wR Absnot2,aC2(aE2 Absnot2)qZ"absnot2","!acos(x)"}, +#define So {2 dN N(0.25)qL Absnot3,aC2(aE2 Absnot3)dI2"absnot3","!(!(x&y))"}, +#define To wR Absnot4,aC2(aE2 Absnot4)qZ"absnot4","!(!acos" hF1 +#define Uo {1,1,3,N(0.1)qL Acoshcosh,aC2(aE2 Acoshcosh)qZ"acoshcosh","cosh(" oB2 hF1 +#define Wo {1,N(1.7),N(3.7),N(0.28)qL Acoshsinh,aC2(aE2 Acoshsinh)qZ oB2 gK2,gK2"(" oB2 hF1 +#define Yo {1,-3,-3,N(0.7)qL Addexp,aC2(aE2 Addexp)qZ"addexp","exp(x+4" gO2 +#define Sp {1,-3,-3,N(0.7)qL Addexp2,aC2(aE2 Addexp2)qZ"addexp2","exp2(x+4" gO2 +#define Tp gD Asinhcosh,aC2(aE2 Asinhcosh)qZ"asinhcosh","cosh(a" gK2 hF1 +#define Up {1,q61 Asinhsinh,aC2(aE2 Asinhsinh)qZ a92 gK2,gK2"(a" gK2 hF1 +#define Wp {oB3 N(0.11)qL Atan2tan,aC2(aE2 Atan2tan)dI2"atan2tan","tan(" hT2"(x,y))"}, +#define Yp {1 mC Ceilneg,aC2(aE2 Ceilneg)qZ"ceilneg","ceil" wM1 +#define Sq {2,-qQ1 Deg,aC2(aE2 Deg)dI2"deg","(" hB2")*y + x*(" hB2 o42" (y*(" hB2"))*4"}, +#define Tq {1 dN N(0.5),d62 Degxmul,aC2(aE2 Degxmul)qZ"degxmul","acos(x)*2"}, +#define Uq {1,-3,3,1 qL Dupaddmulh,aC2(aE2 Dupaddmulh)qZ"dupaddmulh","(x+x)*0.5"}, +#define Wq {oB3 1 qL Dupaddmulmul7,aC2(aE2 Dupaddmulmul7)dI2"dupaddmulmul7","y*(x+x)*7"}, +#define Yq {oB3 1 qL Dupaddmulmulh,aC2(aE2 Dupaddmulmulh)dI2"dupaddmulmulh","y*(x+x)*0.5"}, +#define Sr hR1 Dupxpowmul,aC2(aE2 Dupxpowmul)qZ"dupxpowmul","x*(x^3" gO2 +#define Tr a32 Exp2div,aC2(aE2 Exp2div)dI2"exp2div","x/exp2(" oS2 +#define Ur {1,q61 Exp2log2,aC2(aE2 Exp2log2)qZ"exp2log2","log2(exp2" hF1 +#define Wr a32 Expdiv,aC2(aE2 Expdiv)dI2"expdiv","x/" dJ2 oS2 +#define Yr {1,q61 Explog,aC2(aE2 Explog)qZ"explog","log(ex" oC2 +#define Ss {1,q61 Explog2,aC2(aE2 Explog2)qZ"explog2","log2(ex" oC2 +#define Ts {1,q61 Explog10,aC2(aE2 Explog10)qZ"explog10","log10(ex" oC2 +#define Us {1 mC Floorneg,aC2(aE2 Floorneg)qZ"floorneg","floor" wM1 +#define Ws {1,N(-1.5),N(1.5)mR1 qL Int,aC2(aE2 Int)qZ"int","x+" aA1 aA1"sub(int(1.1), int(1.6" dW1"1.5" dW1"-1.1" dW1"-1.6" dW1"-1.5))"}, +#define Ys {1 mC Intceil,aC2(aE2 Intceil)qZ"intceil","ceil" wF1 +#define St {1 mC Intfloor,aC2(aE2 Intfloor)qZ"intfloor","floor" wF1 +#define Tt {1 mC Intint,aC2(aE2 Intint)qZ"intint","int" wF1 +#define Ut {1 mC Inttrunc,aC2(aE2 Inttrunc)qZ"inttrunc","trunc" wF1 +#define Wt a32 Invdiv,aC2(aE2 Invdiv)dI2"invdiv","y/(1/x)"}, +#define Yt {1,hE1 Invinv,aC2(aE2 Invinv)qZ"invinv","1/(1/x)"}, +#define Su {1 mC Negceil,aC2(aE2 Negceil)qZ"negceil","-ceil(x)"}, +#define Tu {1 mC Negfloor,aC2(aE2 Negfloor)qZ"negfloor","-floor(x)"}, +#define Uu a32 Powdiv,aC2(aE2 Powdiv)dH2"/powdiv","x/pow(x,y" gO2 +#define Wu gT1 Powhalf,aC2(aE2 Powhalf)w6"half",qH2",0.5" gO2 +#define Yu a32 Powinv,aC2(aE2 Powinv)dH2"/powinv","1/pow(x,y" gO2 +#define Sv gT1 Powminushalf,aC2(aE2 Powminushalf)w6"minushalf",qH2",-0.5" gO2 +#define Tv {1,1,5,1 qL Powminusone,aC2(aE2 Powminusone)w6"minusone",qH2",-1.0" gO2 +#define Uv gT1 Powminusthird,aC2(aE2 Powminusthird)w6"minusthird",qH2",(-1.0/3.0))"}, +#define Wv gT1 Powthird,aC2(aE2 Powthird)w6"third",qH2"," mY1"/3.0))"}, +#define Yv {2,-qQ1 Rad,aC2(aE2 Rad)dI2"rad","(" mW1")*y + x*(" mW1 o42" (x*(" mW1"))*4"}, +#define Sw {1 mG1 N(0.8)qL Radxmul,aC2(aE2 Radxmul)qZ"radxmul","cos" wO mW1")*4" gO2 +#define Tw {1,-qQ1 Sqrlog,aC2(aE2 Sqrlog)qZ"sqrlog","log" qI2 +#define Uw {1,-qQ1 Sqrlog2,aC2(aE2 Sqrlog2)qZ"sqrlog2","log2" qI2 +#define Ww {1,-qQ1 Sqrlog10,aC2(aE2 Sqrlog10)qZ"sqrlog10","log10" qI2 +#define Yw {1 mG1 N(0.8),d62 Xmulrad,aC2(aE2 Xmulrad)a2"mulrad","cos" qT2 +#define Sx {dM Xxfdup,aC2(aE2 Xxfdup)LNG_ONLY(0)q5"/xxfdup","sub(sin(x),sin(x))"}, +#define Tx oA1 Abscos,aC2(aB2 Abscos)gR"abscos","cos(sqrt(" dX1"))) + sqrt(" dX1"))"}, +#define Ux oA1 Abscosh,aC2(aB2 Abscosh)gR"abscosh","cosh(sqrt(" dX1"))) + sqrt(" dX1"))"}, +#define Wx {1 dN N(0.1),q7 Acoscos,aC2(aB2 Acoscos)gR"acoscos","cos(acos" hF1 +#define Yx {1,N(1.7),N(3.7),N(0.28),q7 Acoshsinh,aC2(aB2 Acoshsinh)gR oB2 gK2,gK2"(if(1,acosh(x),0))"}, +#define Sy {2 mR1,mQ1 q7 Addlog,aC2(aB2 Addlog)aI"addlog","log(x)+log(" oS2 +#define Ty mX1 Addsin2cos2,aC2(aB2 Addsin2cos2)gR"addsin2cos2",wQ1"^2 + cos(x)^2"}, +#define Uy {1,N(-0.7),N(0.7),N(0.28),q7 Asinhcosh,aC2(aB2 Asinhcosh)gR"asinhcosh","cosh(if(1,a" gK2"(x),0))"}, +#define Wy {1 dN N(0.1),q7 Asinsin,aC2(aB2 Asinsin)gR"asinsin","sin(asin(x))"}, +#define Yy dC Cmpeq_pow_imm_negneg,aC2(aB2 Cmpeq_pow_imm_negneg)gR o11 hV" = " aK2 +#define Sz dC Cmpeq_pow_imm_negpos,aC2(aB2 Cmpeq_pow_imm_negpos)gR o11 hY" = " aN2 +#define Tz {hW Cmpeq_pow_imm_posneg,aC2(aB2 Cmpeq_pow_imm_posneg)gR o11 d2" = " m52 +#define Uz {hW Cmpeq_pow_imm_pospos,aC2(aB2 Cmpeq_pow_imm_pospos)gR o11 d3" = " qQ3 +#define Wz {hW Cmpeq_pow_imm_pospos_base,aC2(aB2 Cmpeq_pow_imm_pospos_base)gR o11 m62"= " wT +#define Yz g9 Cmpeq_powpow_imm_base,aC2(aB2 Cmpeq_powpow_imm_base)aI o11 hH" = " a7 +#define S_ dC Cmpge_pow_imm_negneg,aC2(aB2 Cmpge_pow_imm_negneg)dY1 hV" >= " aK2 +#define T_ dC Cmpge_pow_imm_negpos,aC2(aB2 Cmpge_pow_imm_negpos)dY1 hY" >= " aN2 +#define U_ {hW Cmpge_pow_imm_posneg,aC2(aB2 Cmpge_pow_imm_posneg)dY1 d2" >= " m52 +#define W_ {hW Cmpge_pow_imm_pospos,aC2(aB2 Cmpge_pow_imm_pospos)dY1 d3" >= " qQ3 +#define Y_ {hW Cmpge_pow_imm_pospos_base,aC2(aB2 Cmpge_pow_imm_pospos_base)dY1 m62">= " wT +#define S01 g9 Cmpge_powpow_imm_base,aC2(aB2 Cmpge_powpow_imm_base)aI"cmpge_" hH dF2 a7 +#define T01 dC Cmpgt_pow_imm_negneg,aC2(aB2 Cmpgt_pow_imm_negneg)hO1 hV" > " aK2 +#define U01 dC Cmpgt_pow_imm_negpos,aC2(aB2 Cmpgt_pow_imm_negpos)hO1 hY" > " aN2 +#define W01 {hW Cmpgt_pow_imm_posneg,aC2(aB2 Cmpgt_pow_imm_posneg)hO1 d2" > " m52 +#define Y01 {hW Cmpgt_pow_imm_pospos,aC2(aB2 Cmpgt_pow_imm_pospos)hO1 d3" > " qQ3 +#define S11 {hW Cmpgt_pow_imm_pospos_base,aC2(aB2 Cmpgt_pow_imm_pospos_base)hO1 m62"> " wT +#define T11 g9 Cmpgt_powpow_imm_base,aC2(aB2 Cmpgt_powpow_imm_base)aI"cmpgt_" hH" > " a7 +#define U11 dC Cmple_pow_imm_negneg,aC2(aB2 Cmple_pow_imm_negneg)hP1 hV oT3 aK2 +#define W11 dC Cmple_pow_imm_negpos,aC2(aB2 Cmple_pow_imm_negpos)hP1 hY oT3 aN2 +#define Y11 {hW Cmple_pow_imm_posneg,aC2(aB2 Cmple_pow_imm_posneg)hP1 d2 oT3 m52 +#define S21 {hW Cmple_pow_imm_pospos,aC2(aB2 Cmple_pow_imm_pospos)hP1 d3 oT3 qQ3 +#define T21 {hW Cmple_pow_imm_pospos_base,aC2(aB2 Cmple_pow_imm_pospos_base)hP1 m62"<= " wT +#define U21 g9 Cmple_powpow_imm_base,aC2(aB2 Cmple_powpow_imm_base)aI"cmple_" hH oT3 a7 +#define W21 dC Cmplt_pow_imm_negneg,aC2(aB2 Cmplt_pow_imm_negneg)dZ1 hV oV3 aK2 +#define Y21 dC Cmplt_pow_imm_negpos,aC2(aB2 Cmplt_pow_imm_negpos)dZ1 hY oV3 aN2 +#define S31 {hW Cmplt_pow_imm_posneg,aC2(aB2 Cmplt_pow_imm_posneg)dZ1 d2 oV3 m52 +#define T31 {hW Cmplt_pow_imm_pospos,aC2(aB2 Cmplt_pow_imm_pospos)dZ1 d3 oV3 qQ3 +#define U31 {hW Cmplt_pow_imm_pospos_base,aC2(aB2 Cmplt_pow_imm_pospos_base)dZ1 m62"< " wT +#define W31 g9 Cmplt_powpow_imm_base,aC2(aB2 Cmplt_powpow_imm_base)aI"cmplt_" hH oV3 a7 +#define Y31 dC Cmpne_pow_imm_negneg,aC2(aB2 Cmpne_pow_imm_negneg)o01 hV gZ3 aK2 +#define S41 dC Cmpne_pow_imm_negpos,aC2(aB2 Cmpne_pow_imm_negpos)o01 hY gZ3 aN2 +#define T41 {hW Cmpne_pow_imm_posneg,aC2(aB2 Cmpne_pow_imm_posneg)o01 d2 gZ3 m52 +#define U41 {hW Cmpne_pow_imm_pospos,aC2(aB2 Cmpne_pow_imm_pospos)o01 d3 gZ3 qQ3 +#define W41 {hW Cmpne_pow_imm_pospos_base,aC2(aB2 Cmpne_pow_imm_pospos_base)o01 m62"!= " wT +#define Y41 g9 Cmpne_powpow_imm_base,aC2(aB2 Cmpne_powpow_imm_base)aI"cmpne_" hH dG2 a7 +#define S51 dC Cmpzz_pow_imm_negneg,aC2(aB2 Cmpzz_pow_imm_negneg)q01"_imm_negneg" dT h11 oV3 gC3 aE h11 oT3 gC3 aG h11" > " gC3 aC gL",-3) >= -0.015625" wI h11 gZ3"-0.015625" wZ1",-3) = " aK2 +#define T51 dC Cmpzz_pow_imm_negpos,aC2(aB2 Cmpzz_pow_imm_negpos)q01"_imm_negpos" dT h21 oV3 hQ3 aE h21 oT3 hQ3 aG h21" > " hQ3 aC gL",-2) >= 0.0625" wI h21 gZ3"0.0625" wZ1",-2) = " aN2 +#define U51 {hW Cmpzz_pow_imm_posneg,aC2(aB2 Cmpzz_pow_imm_posneg)q01"_imm_posneg" dT d71 oV3 oD3 aE d71 oT3 oD3 aG d71" > " oD3 aC gL",3) >= -125" wI d71 gZ3"-125" wZ1",3) = " m52 +#define W51 {hW Cmpzz_pow_imm_pospos,aC2(aB2 Cmpzz_pow_imm_pospos)q01"_imm_pospos" dT d81" < 25)" aE d81" <= 25)" aG d81" > 25)" aC gL",2) >= 25" wI d81 gZ3"25" wZ1",2) = " qQ3 +#define Y51 {hW Cmpzz_pow_imm_pospos_base,aC2(aB2 Cmpzz_pow_imm_pospos_base)q01"_imm_pospos_base" dT oU3"< " mW aE oU3"<= " mW aG oU3"> " mW aC qD3">= " mW hD1 oU3"!= " mW d7 qD3"= " wT +#define S61 g9 Cmpzz_powpow_imm_base,aC2(aB2 Cmpzz_powpow_imm_base)aI"cmpzz_powpow_imm_base" dT wZ2 oV3 qS1 aE wZ2 oT3 qS1 aG wZ2" > " qS1 aC qB1 dF2 qS1 hD1 wZ2 dG2 qS1 d7 qB1" = " a7 +#define T61 {2 mG1 hS Expexp_a,aC2(aB2 Expexp_a)aI oD2"p_a","exp(x*2 + y*3" gO2 +#define U61 {3 mG1 hS Expexp_b,aC2(aB2 Expexp_b)aJ oD2"p_b",aR" * exp(y+z" gO2 +#define W61 {3 mG1 hS Expexp_c,aC2(aB2 Expexp_c)aJ oD2"p_c","exp(x + y*z" gO2 +#define Y61 {2,-4,4,hS If_extract_sin,aC2(aB2 If_extract_sin)aI dE1"tract_sin",dZ3"sin(y), " qR3 +#define S71 mT1 If_join_add,aC2(aB2 If_join_add)aI"if_join_add",hV2"+" o21 +#define T71 mT1 If_join_and,aC2(aB2 If_join_and)aI"if_join_and",hV2"&" o21 +#define U71 mT1 If_join_max,aC2(aB2 If_join_max)aI"if_join_max","max(" o1 dE", " dO3")))"}, +#define W71 mT1 If_join_min,aC2(aB2 If_join_min)aI"if_join_min","min(" o1 dE", " dO3")))"}, +#define Y71 mT1 If_join_mul,aC2(aB2 If_join_mul)aI"if_join_mul",hV2"*" o21 +#define S81 mT1 If_join_or,aC2(aB2 If_join_or)aI"if_join_or",o1 dE" | " dO3"))"}, +#define T81 wP1 Ifabsnot,aC2(aB2 Ifabsnot)aJ"ifabsnot","if(!(sin(x)+1.2), y,z" gO2 +#define U81 wP1 Ifconst,aC2(aB2 Ifconst)aJ"ifconst","if(1, x,y" o42" if(0,z,y" gO2 +#define W81 {4 mP1 Ififconst,aC2(aB2 Ififconst)LNG_ONLY(0)"w," aP"ififconst","if(" o1",1,y),z,w" o42" if(if(w,z,0)," h22 +#define Y81 mO1 Ifnot,aC2(aB2 Ifnot)aJ"ifnot","if(!x, y,z" gO2 +#define S91 {oE3 Muland2,aC2(aB2 Muland2)aI"muland2",hR3}, +#define T91 wP1 Muland2plus,aC2(aB2 Muland2plus)aJ"muland2plus",hR3" * z"}, +#define U91 wP1 Muland3,aC2(aB2 Muland3)aJ"muland3",hR3" * !!z"}, +#define W91 {oE3 Mulandlt,aC2(aB2 Mulandlt)aI"mulandlt",hC2" (y<0" gO2 +#define Y91 {2 mR1,mQ1 q7 Mulimmlog,aC2(aB2 Mulimmlog)aI"mulimmlog","log(if(1,5,0)*x*" oS2 +#define SA1 {oE3 Mulnor2,aC2(aB2 Mulnor2)aI"mulnor2",hS3}, +#define TA1 wP1 Mulnor2plus,aC2(aB2 Mulnor2plus)aJ"mulnor2plus",hS3" * z"}, +#define UA1 wP1 Mulnor3,aC2(aB2 Mulnor3)aJ"mulnor3",hS3" * !z"}, +#define WA1 oA1 Negceil,aC2(aB2 Negceil)gR"negceil","ceil(x*(abs(x)-abs(x)-1))"}, +#define YA1 oA1 Negcos,aC2(aB2 Negcos)gR"negcos","cos" qC1 +#define SB1 oA1 Negcosh,aC2(aB2 Negcosh)gR"negcosh","cosh" qC1 +#define TB1 oA1 Negfloor,aC2(aB2 Negfloor)gR"negfloor","floor(x*(abs(x)-abs(x)-1))"}, +#define UB1 oA1 Negsin,aC2(aB2 Negsin)gR"negsin","sin(x*if(1,-1,0))"}, +#define WB1 oA1 Negsinh,aC2(aB2 Negsinh)gR"neg" gK2,gK2 qC1 +#define YB1 mX1 Posnot,aC2(aB2 Posnot)gR"posnot","!(sin(x) + 1.2" gO2 +#define SC1 mX1 Posnotnot,aC2(aB2 Posnotnot)gR"posnotnot","!!(sin(x) + 1.2" gO2 +#define TC1 {mQ1 mQ1 q7 Powimmaddimmlog,aC2(aB2 Powimmaddimmlog)w11"immaddimmlog","pow(5, log(x)+1" gO2 +#define UC1 {mQ1 2 mR1,q7 Powimmlog,aC2(aB2 Powimmlog)w11"immlog","pow(3, log(x)) + pow(5, log(x)*sin(x))"}, +#define WC1 {d51 Powmulimm_fnen,aC2(aB2 Powmulimm_fnen)qA g61"mulimm_fnen" h51"^(-8" gO2 +#define YC1 {2,qJ2 Powmulimm_fnep,aC2(aB2 Powmulimm_fnep)qA g61"mulimm_fnep" h51"^(4" gO2 +#define SD1 {1,-3,-1,hS Powmulimm_fnfn,aC2(aB2 Powmulimm_fnfn)w11"mulimm_fnfn","((-5.1)*x)^(-7.1" gO2 +#define TD1 {2,qJ2 Powmulimm_fnfp,aC2(aB2 Powmulimm_fnfp)qA g61"mulimm_fnfp" h51"^7.1"}, +#define UD1 {2,qJ2 Powmulimm_fpfp,aC2(aB2 Powmulimm_fpfp)qA g61"mulimm_fpfp","(5.1*x*y)^7.1"}, +#define WD1 mX1 Sub1cos2,aC2(aB2 Sub1cos2)gR"sub1cos2","1-cos(x)^2"}, +#define YD1 mX1 Sub1sin2,aC2(aB2 Sub1sin2)gR"sub1sin2","1-" wQ1"^2"}, +#define SE1 {1,N(-9.42477796076937971538793014983850865259),N(9.42477796076937971538793014983850865259),N(0.785398163397448309615660845819875721049292349),q7 Trig_modulo,aC2(aB2 Trig_modulo)gR"trig_modulo","cos(x+pi" q81"2/3" q81"5/2" q81"6/2" q81 hD2 o13" " hH1")" hW2"2/3)" hW2"5/2)" hW2"6/2)" hW2 hD2 o13" cos(x-pi)" g41"2/3)" g41"5/2)" g41"6/2)" g41 hD2" sin(x-pi)" h61"2/3)" h61"5/2)" h61"6/2)" h61"7/2" gO2 +#define TE1 {1,-3,3 mR1,q7 Trunc_from_if,aC2(aB2 Trunc_from_if)gR"trunc_from_if",o1">0, " gI3 qM2">=0, " gI3 qM2"<0, " gD3 qM2"<=0, " gD3 w21">0, " gD3 w21">=0, " gD3 w21"<0, " gI3" 10*" o1"<=0, floor(x),ceil" hF1 +#define UE1 {1,N(-0.7),N(0.7),N(0.28),hI t5,aC2(aG2 t5)qA,oK"5","sub(sin(x)+csc(x),cos" hF1 +#define WE1 {oB3 N(.25),hI t42,aC2(aG2 t42)qA",y",oK"42","sqrt(x*x) + 1.5*((y*y)^.25" o42" hypot(x,y" gO2 +#define YE1 {1,-100,-1,N(.5),hI t51,aC2(aG2 t51)qA,oK"51","log" wM1 +#define SF1 {1,N(.05),1,N(.01),hI t57,aC2(aG2 t57)qA,oK"57","cosh(a" gK2 hF1 +#define TF1 {2 mG1 N(1.2),hI t59,aC2(aG2 t59)qA",y",oK"59","cosh(x^2" o42" tanh(y^2" gO2 +#define UF1 wJ2 N(.25)h8 t1,aC2(aH2 t1)oF2"1","x*4/2 + (1+(2+3)) + x*x+x+1+2+3*4+5*6*\n7-8*9"}, +#define WF1 wJ2 hE2 t2,aC2(aH2 t2)oF2"2","2 * x+ sin ( x ) / .5 + 2-sin(x)*sin(x)"}, +#define YF1 {3,-7,7,oJ2 t3,aC2(aH2 t3)wN2"3","(x=y & y=x)+ 1+2-3.1*4e2/.5 + x*x+y*y+z*z + (x&x) + (y|y" gO2 +#define SG1 {2,-10,10,oJ2 t4,aC2(aH2 t4)gP2"4","( ((( ( x-y) -( ((y) *2) -3)) )* 4))+sin(x)*cos(y)-cos(x)*sin(" oS2 +#define TG1 wT2 8,hG2 t5,aC2(aH2 t5)LNG_ONLY(0)"__A5_x08,o__5_0AB_",oZ"5","__A5_x08^o__5_0AB_"}, +#define UG1 wU2 N(.01)h8 t7,aC2(aH2 t7)oF2"7","cos(x)*sin(1-x)*(1-cos(x/2)*sin(x*5))"}, +#define WG1 {2,-8,8,oE2 t8,aC2(aH2 t8)gP2"8",hT2"(x,y)+max(x,y" gO2 +#define YG1 {3,1,15,N(.7)h8 t9,aC2(aH2 t9)wN2"9","1.5+x*y-2+4/8+z+z+z+z+x/(y*z" gO2 +#define SH1 {3,1,4,N(.3)h8 t10,aC2(aH2 t10)wN2"10","1+sin(cos(max(1+2+3+4+5, x+y+z)))+2"}, +#define TH1 {3,1,19,N(.8)h8 t11,aC2(aH2 t11)wN2"11","-(-(-(-(-x))-x))+y*1+log(1.1^z" gO2 +#define UH1 {1,1,2000,oJ2 t12,aC2(aH2 t12)oF2"12","1/log(10^((3-2)/log(x)))"}, +#define WH1 {2,-30,30,oJ2 t13,aC2(aH2 t13)gP2"13","x^3 * x^4 + y^3 * y^5"}, +#define YH1 {1,-50,50,hE2 t14,aC2(aH2 t14)oF2"14","x*pi + sin(2*pi" o42" CONST"}, +#define SI1 {2,N(1.1),6,N(.07)h8 t15,aC2(aH2 t15)gP2"15","x^y/log(y" o42" log(x)/log(y" o42" log(x^y" gO2 +#define TI1 {2,1,17,oE2 t18,aC2(aH2 t18)gP2"18","- ( - ( - ( - 5 ) ) ) * -x^ -y^-2"}, +#define UI1 {2,-4,4,hE2 t22,aC2(aH2 t22)gP2"22","3.5doubled + 10*x tripled - sin(y)doubled" o33"100" wE1" doubled-y tripled)doubled + 5/2doubled + 1.1^x doubled + 1.1doubled^x doubled"}, +#define WI1 wJ2 hE2 t23,aC2(aH2 t23)oF2"23","(x/(2*acos(0)))*180"}, +#define YI1 {3,1,3,oE2 t25,aC2(aH2 t25)LNG_ONLY(0)"a,b,c",oZ"25","a^b^c + a^-2 * (-b^2" o42" (-b^-c" gO2 +#define SJ1 {1,-100,100,N(.1),true,aH2 t26_deg,aC2(aH2 t26_deg)oF2"26_deg",oL2" cos(x*1.5" o42" asin(x/110" o42" acos(x/120" gO2 +#define TJ1 wT2 N(.9),N(.025)h8 t27,aC2(aH2 t27)gP2"27","abs(x)+acos(x)+asin(x)+atan(x)+" hT2"(x,y)+ceil(x)+cos(x)+cosh(x)+cot(x)+csc" qS2" " qH2",y" gO2 +#define UJ1 wT2 N(.9),N(.025)h8 t28,aC2(aH2 t28)gP2"28","exp(x)+floor(x)+int(x)+log(x)+log10(x)+max(x,y)+min(x,y)+sec(x)+sin(x)+sinh(x)+sqrt(x)+tan(x)+tanh(x)+ceil(y)+trunc(" oS2 +#define WJ1 {2,3,10,h7 t30,aC2(aH2 t30)gP2"30","x - y*1 + (x%y" o42" x / (y^1.1" o42" 2^3 + 5%3 + x^(y^0" o42" x^0.5"}, +#define YJ1 {3,N(.1),4,N(.35)h8 t31,aC2(aH2 t31)wN2"31","x - (y*(y*(y*-1))*1" o42" log(x*exp" mY1")^y) - log(x^y" gL3"exp" mY1")^log(x+6" o42" 10^" qN2"6" mZ1"y+6)*log(z+6" mZ1"10)) -" o13" exp" mY1")^" qN2"6)*y) - 5^" qN2"7" mZ1"5)) + " aB1"^3 * " aB1"^2 / " aB1"^4"}, +#define SK1 {3,1,2,N(.05)h8 t32,aC2(aH2 t32)wN2"32","x" mO"+y/y-min(3,4)-x-max(4,3)+max(3,4)-min(4,3)+0+(z*1)" mO"+(x-2+2)+(x*0.5*2)+y*0" o23"+min(min(min(4.0,x),1.0),min(x,min(min(y,4.0),z)))" mO"+max(max(max(4.0,x),1.0)" w31"x(max(y,4.0),z)))" mO"+(abs(1)+acos" mY1")+asin(1.0)+atan" mY1")+ceil(1.1)+cos(0.0)" aM2"+cosh(0.0)+floor(1.1)+log" mY1")+sin(0.0)+sinh(0.0)+tan" mY1")" aM2"+tanh" mY1")+" hT2"(1.0,1.0))" mO"+(x-(y-z))" mO"+(x+y" o72"y" gR2"max(x" w31"x(x,max(x,x))))*-1.0" o23"+(z-z" gR2"1/sin(x/" oI2" 1/cos(y/" oI2" 1/tan(z/5" gR2"log10(cot(z/" oI2" csc(y/" oI2" sec(x/5))" mO"+log(30+x)*log(40+y" mZ1"50+z)" mO"+sin(x/57.295779513082320877" gR2"asin(x/10)*57.295779513082320877" o23"+floor(-x) + 1/ceil(x)" mO"+sqrt(5 * 0.2) +(-" hF2 hF2"x+-" aN1 +#define TK1 {2 mG1 hE2 t33,aC2(aH2 t33)gP2"33","sin(sqrt(10-x*x+y*y))+cos(sqrt(15-x*x-y*y))+sin(x*x+y*" oS2 +#define UK1 wU2 hE2 t37,aC2(aH2 t37)oF2"37","5 + 7.5*8 / 3 - 2^4*2 + 7%2+4 + x"}, +#define WK1 {3,N(-.9),N(.9),hE2 t38,aC2(aH2 t38)wN2"38",a92 qS2" 1.5*" oB2"(y+3" o42" 2.5*atanh(z" gO2 +#define YK1 {3,N(-1.3),N(1.3),hG2 t39,aC2(aH2 t39)wN2"39","sin(x+cos(y*1.5))-cos(x+sin(y*1.5))+z*z*z*sin(z*z*z-x*x-y*y)-" o13" cos(y*1.5)*sin(x+cos(y*1.5))+x*y*z+x*y*2.5+x*y*z*cos(x)+x*y*cos(x)+x*z*cos(x)+ y*z*2.5+(x*y*z*cos(x)-x*y*z-y*cos(x)-x*z*y+x*y+x*z-cos(x)*x)"}, +#define SL1 {3,N(-1.3),N(1.3),N(.075)h8 t40,aC2(aH2 t40)wN2"40","(x+x+x+x+x+x+x+x+x+x+x+" gO1")*" o13" (x+x+x+x+x+x+x+x+x+x+x+" gO1")+" oK2"*(x+x+x+x+x+x+x+x+x+x+x+" gO1")-" o13" x*y*(x+x+x+x+x+x+x+x+x+x+x+" gO1")+ x*(x+x+x+x+x+x+x+x+x+x+x+" gO1 gO2 +#define TL1 {3 mG1 hG2 t41,aC2(aH2 t41)wN2"41","x*3+x*y+x*z+x*sin(y*z) -" o13" " hH2"4" o33 q91"))*x" o33 hH2"y + " hH2"z"}, +#define UL1 {1,-100,100,N(.03)h8 t43,aC2(aH2 t43)oF2"43","log(x*x)+abs(" dJ2"abs(x)+1))"}, +#define WL1 {1,0,100,N(.125)h8 t44,aC2(aH2 t44)oF2"44","(x^2" aC1"8" gL3"1.1" wE1"^3" aC1"7" gL3"1.2" wE1"^4" aC1"6" gL3"1.3" wE1"^5" aC1 oI2 o13" 1.4" wE1"^6" aC1"6" gL3"1.5" wE1"^7" aC1"4" gL3"1.6" wE1"^8" aC1"3" gL3"1.7" wE1"^9" aC1"2" o42" 1.8*(sqrt(abs(-sqrt(x))^3))"}, +#define YL1 wU2 N(.025)h8 t45,aC2(aH2 t45)oF2"45","(x^2" aC1"7" o42" 1.1" wE1"^4" aC1 oI2" 1.2" wE1"^6" aC1"3" gO2 +#define SM1 {2,N(-.9),N(.9),hG2 t46,aC2(aH2 t46)gP2"46" mA1"floor(acos(x)+4)) + 1.1*abs(floor(acos(y)+1.5)) + " oN1" < (acos(y)-10)) + 1.2*max(-4, acos(x)) + 1.3*min(9, acos(x)-9" gO2 +#define TM1 {oB3 hE2 t47,aC2(aH2 t47)gP2"47","1.25*(exp(x)+" dJ2"-" w01" 1.5*(" dJ2"y)-exp(-y)) + 1.75*((" dJ2"-x)+exp(x))/2" o42" 2.0*((" dJ2"-x)-exp(x))/2" o42" 2.25*(cosh(y)+sinh(y))"}, +#define UM1 {1,2,N(1e9),N(1.2e7)h8 t48,aC2(aH2 t48)oF2"48",gK2"((log(x)/5+1)*" oI2" 1.2*cosh((log(x)/log(2)+1)*log" wL" !(x | !(x/4))"}, +#define WM1 {1,-100,100,N(.05)h8 t49,aC2(aH2 t49)oF2"49",hT2"(0, x) + (-4" wE1"-100))^3.3"}, +#define YM1 wU2 oJ2 t52,aC2(aH2 t52)oF2"52","x + " mY1"+2.0+3.0+4.0-5.0-6.0-7.0-8.0)/3.0" o33"4.0*(1.0+sin(2.0)+cos(4.0*5.0+6.0)/2.0" o42" cos(0.5)*tan(0.6+0.2) - 1.1/log(2.1)*sqrt(3.3" o42" 2^3"}, +#define SN1 {2,0,10,N(0.5)h8 t53,aC2(aH2 t53)gP2"53","(x&y" o42" 4*(int(x/10)|int(y/10)) + 8*((-!-!-x)+(!-!-!y)) + 16*(-------x + !!!!!!!y" gO2 +#define TN1 {2,-10,100,oJ2 t54,aC2(aH2 t54)gP2"54","(x<y" dO2"<=y" dO2">y" dO2">=y)+" o13" (x=y" dO2"!=y)+(x&y" dO2"|y)+" o13" (!x)+(!!x)+" o13" !((x<y)&(x<3))+ !!(!(x>y)|(x>3))"}, +#define UN1 {2,1,100,oJ2 t55,aC2(aH2 t55)gP2"55","(x^1.2 < 0" o42" (y^2.5 < 0" o42" 2*(x*x<0" o42" 3*(y^3<0" o42" 4" wE1"^4<0" gO2 +#define WN1 {1,N(.25),100,N(.25)h8 t56,aC2(aH2 t56)oF2"56","1.75e21%x"}, +#define YN1 {1,-3,3,N(0.2)h8 t59,aC2(aH2 t59)oF2"59","(cos(x) < sin(x))" o33"(cos(x)-sin(x))" o33"sub(sinh(x)-cosh(x), " gK2"(x)/cosh(x)) + sqrt(cos(x)^2+sin(x)^2" gO2 +#define SO1 {1,N(1e-6),dL1 Log,aC2(aJ2 Log)qO"/log",aH1 +#define TO1 gD Abscos,aC2(aE2 Abscos)qZ"abscos","cos(abs" hF1 +#define UO1 gD Abscosh,aC2(aE2 Abscosh)qZ"abscosh","cosh(abs" hF1 +#define WO1 a62 Abseq0,aC2(aE2 Abseq0)LNG_ONLY(aE2 Abseq0)dT1"abseq0",oL1"=0" o42" (0=abs" hF1 +#define YO1 {1,N(0.001),N(0.9),N(0.01)qL Absevenconstpow,aC2(aE2 Absevenconstpow)qZ"absevenconstpow",hY3" ^ 1506"}, +#define SP1 {2,N(0.001),N(0.9),N(0.01)qL Absmulevenconstpow,aC2(aE2 Absmulevenconstpow)dI2"absmulevenconstpow","(abs(x)*y) ^ 1506"}, +#define TP1 a62 oF3,aC2(aE2 oF3)LNG_ONLY(aE2 oF3)dT1"absneq0",oL1"=0" o42" (0=abs" hF1 +#define UP1 a62 Add,aC2(aE2 Add)LNG_ONLY(aE2 Add)dT1"add","5+3+x"}, +#define WP1 a62 Add0,aC2(aE2 Add0)LNG_ONLY(aE2 Add0)dT1"add0","x+0+x"}, +#define YP1 a62 And,aC2(aE2 And)LNG_ONLY(aE2 And)dT1"and","(5&3" qP2"5&0)+(0&5)+(0&0" gO2 +#define SQ1 wR Cmp_acos,aC2(aE2 Cmp_acos)qZ"cmp_acos","1" o7"=acos" dP2 oK2 o7"<acos" dP2 a02 o7"<=acos" dP2 d31 o7">acos" dP2 d21 o7">=acos" dP2" 32" o7"!=acos(0.75))"}, +#define TQ1 wR Cmp_acos_outrange,aC2(aE2 Cmp_acos_outrange)qZ"cmp_acos_outrange","1" o7"=2" o42 oK2 o7"<2" o42 a02 o7"<=2" o42 d31 o7">2" o42 d21 o7">=2" o42" 32" o7"!=2" gO2 +#define UQ1 hR1 oG3,aC2(aE2 oG3)LNG_ONLY(aE2 oG3)dT1"cmp_add","1" aQ o41 aQ wM2 aQ hL1 aQ o51 aQ mE aQ d91 +#define WQ1 wR Cmp_asin,aC2(aE2 Cmp_asin)qZ"cmp_asin","1" oN"=a" dM1 oK2 oN"<a" dM1 a02 oN"<=a" dM1 d31 oN">a" dM1 d21 oN">=a" dM1" 32" oN"!=asin(0.75))"}, +#define YQ1 wR Cmp_asin_outrange,aC2(aE2 Cmp_asin_outrange)qZ"cmp_asin_outrange","1" oN"=2" o9"a" wQ1"<2" o42 a02 oN"<=2" o42 d31 oN">2" o42 d21 oN">=2" o42" 32" oN"!=2" gO2 +#define SR1 mG Cmp_atan,aC2(aE2 Cmp_atan)qZ"cmp_atan","1" qD1"=atan" hI1 qD1"<atan" hJ1 qD1"<=atan" hI2 qD1">atan" hK2 qD1">=atan" hL2 qD1"!=atan" d11 +#define TR1 mG Cmp_exp,aC2(aE2 Cmp_exp)qZ q02"p","1" gU1"=e" o03"2" gU1"<e" o03"4" gU1"<=e" o03" 8" gU1">e" o03"16" gU1">=e" o03"32" gU1"!=exp" d11 +#define UR1 mG Cmp_exp2,aC2(aE2 Cmp_exp2)qZ q02"p2","1" q72"=exp2" wL" 2" q72"<exp2" wL" 4" q72"<=exp2" wL" 8" q72">exp2" wL" 16" q72">=exp2" wL" 32" q72"!=exp2" d11 +#define WR1 mG Cmp_exp2_neg,aC2(aE2 Cmp_exp2_neg)qZ q02"p2_neg","1" q72"=-4" o42" 2" q72"<-4" o42" 4" q72"<=-4" g81 aS">-4" o42" 16" q72">=-4" hO2 q72"!=-4" gO2 +#define YR1 mG Cmp_exp_neg,aC2(aE2 Cmp_exp_neg)qZ q02"p_neg","1" gU1"=-4" o42" 2" gU1"<-4" o42" 4" gU1"<=-4" g81 aR">-4" o42" 16" gU1">=-4" hO2 gU1"!=-4" gO2 +#define SS1 qE1 Cmp_log2_nn,aC2(aE2 Cmp_log2_nn)qZ"cmp_log2_nn","1" q82 wG1 wU aT q82 a8 q82 a9 q82 aX q82 hK1 +#define TS1 qE1 Cmp_log2_np,aC2(aE2 Cmp_log2_np)qZ"cmp_log2_np","1" q82"=log2" hI1 q82"<log2" hJ1 q82"<=log2" hI2 q82">log2" hK2 q82">=log2" hL2 q82"!=log2" d11 +#define US1 mG Cmp_log2_pn,aC2(aE2 Cmp_log2_pn)qZ"cmp_log2_pn","1" wA wG1"log2(" hG1 aT wA a8 wA a9 wA aX wA hK1 +#define WS1 mG Cmp_log2_pp,aC2(aE2 Cmp_log2_pp)qZ"cmp_log2_pp","1" wA"=log2" hI1 wA"<log2" hJ1 wA"<=log2" hI2 wA">log2" hK2 wA">=log2" hL2 wA"!=log2" d11 +#define YS1 qE1 Cmp_log10_nn,aC2(aE2 Cmp_log10_nn)qZ"cmp_log10_nn","1*(" w0 wG1 w0 aT wL2 a8 wL2 a9 wL2 aX wL2 hK1 +#define ST1 qE1 Cmp_log10_np,aC2(aE2 Cmp_log10_np)qZ"cmp_log10_np","1*(" w0"=log10" hI1 wL2"<log10" hJ1 wL2"<=log10" hI2 wL2">log10" hK2 wL2">=log10" hL2 wL2"!=log10" d11 +#define TT1 mG Cmp_log10_pn,aC2(aE2 Cmp_log10_pn)qZ"cmp_log10_pn","1" dI"=-2" o42 oK2 dI aT dI a8 dI a9 dI aX dI hK1 +#define UT1 mG Cmp_log10_pp,aC2(aE2 Cmp_log10_pp)qZ"cmp_log10_pp","1" dI"=log10(1)) +" oK2 dI"<log10(1))" o33"4" dI"<=log10(1)) +" d31 dI">log10(1)) +" d21 dI">=log10(1)) + 32" dI"!=log10(1))"}, +#define WT1 qE1 Cmp_log_nn,aC2(aE2 Cmp_log_nn)qZ"cmp_log_nn","1" hZ1 wG1"log(x)" aT hZ1 a8 hZ1 a9 hZ1 aX hZ1 hK1 +#define YT1 qE1 Cmp_log_np,aC2(aE2 Cmp_log_np)qZ"cmp_log_np","1" hZ1"=log" hI1 hZ1"<log" hJ1 hZ1"<=log" hI2 hZ1">log" hK2 hZ1">=log" hL2 hZ1"!=log" d11 +#define SU1 mG Cmp_log_pn,aC2(aE2 Cmp_log_pn)qZ"cmp_log_pn","1" d01 wG1"log(" hG1 aT d01 a8 d01 a9 d01 aX d01 hK1 +#define TU1 mG Cmp_log_pp,aC2(aE2 Cmp_log_pp)qZ"cmp_log_pp","1" d01"=log" hI1 d01"<log" hJ1 d01"<=log" hI2 d01">log" hK2 d01">=log" hL2 d01"!=log" d11 +#define UU1 hR1 gV3,aC2(aE2 gV3)LNG_ONLY(aE2 gV3)dT1"cmp_mulneg","1" hM2 o41 hM2 wM2 hM2 hL1 hM2 o51 hM2 mE hM2 d91 +#define WU1 hR1 gW3,aC2(aE2 gW3)LNG_ONLY(aE2 gW3)dT1"cmp_mulpos","1" hN2 o41 hN2 wM2 hN2 hL1 hN2 o51 hN2 mE hN2 d91 +#define YU1 hR1 oH3,aC2(aE2 oH3)LNG_ONLY(aE2 oH3)dT1"cmp_neg","1" o61"=4" o42" 2" o61"<4" o42" 4" o61"<=4" o42" 8" o61">4" o42" 16" o61 mE o61 d91 +#define SV1 hS1 Cmp_powx_n_n,aC2(aE2 Cmp_powx_n_n)h31"_n_n","1" g4"=" oT aU g4"<" oT aV g4"<=" oT aW g4">" oT mD g4">=" oT wI1 g4"!=" oT}, +#define TV1 hS1 Cmp_powx_n_p,aC2(aE2 Cmp_powx_n_p)h31"_n_p","1" g4"=" oU aU g4"<" oU aV g4"<=" oU aW g4">" oU mD g4">=" oU wI1 g4"!=" oU}, +#define UV1 h41 Cmp_powx_nn,aC2(aE2 Cmp_powx_nn)h31"_nn","1" g4 wJ1 g4 wK1 g4 o71 g4 wL1 g4">=-4" hO2 g4"!=-4" gO2 +#define WV1 h41 Cmp_powx_np,aC2(aE2 Cmp_powx_np)h31"_np","1" g4 o41 g4 wM2 g4 hL1 g4 o51 g4 mE g4 d91 +#define YV1 hS1 Cmp_powx_p_n,aC2(aE2 Cmp_powx_p_n)h31"_p_n","1" w1"=" oT aU w1"<" oT aV w1"<=" oT aW w1">" oT mD w1">=" oT wI1 w1"!=" oT}, +#define SW1 hS1 Cmp_powx_p_p,aC2(aE2 Cmp_powx_p_p)h31"_p_p","1" w1"=" oU aU w1"<" oU aV w1"<=" oU aW w1">" oU mD w1">=" oU wI1 w1"!=" oU}, +#define TW1 h41 Cmp_powx_pn,aC2(aE2 Cmp_powx_pn)h31"_pn","1" wN1 wJ1 wN1 wK1 wN1 o71 wN1 wL1 wN1">=-4" hO2 wN1"!=-4" gO2 +#define UW1 h41 Cmp_powx_pp,aC2(aE2 Cmp_powx_pp)h31"_pp","1" wN1 o41 wN1 wM2 wN1 hL1 wN1 o51 wN1 mE wN1 d91 +#define WW1 hJ Cmp_powy_n_n,aC2(aE2 Cmp_powy_n_n)o81"y_n_n","1" o91"=" gY3"2" o91"<" gY3"4" o91"<=" gY3"8" o91">" dW wV o91">=" dW" 32" o91"!=(x^-6.1))"}, +#define YW1 hJ Cmp_powy_n_p,aC2(aE2 Cmp_powy_n_p)o81"y_n_p","1" o91"=(x" h03"2" o91"<(x" h03"4" o91"<=(x" h03"8" o91">(x" a1 wV o91">=(x" a1" 32" o91"!=(x^6.1))"}, +#define SX1 hJ Cmp_powy_nn,aC2(aE2 Cmp_powy_nn)o81"y_nn","1" o91 wJ1 o91 wK1 o91 o71 o91 wL1 o91">=-4" hO2 o91"!=-4" gO2 +#define TX1 hJ Cmp_powy_np,aC2(aE2 Cmp_powy_np)o81"y_np","1" o91 o41 o91 wM2 o91 hL1 o91 o51 o91 mE o91 d91 +#define UX1 hJ Cmp_powy_p_n,aC2(aE2 Cmp_powy_p_n)o81"y_p_n","1" h4"=" gY3"2" h4"<" gY3"4" h4"<=" gY3"8" h4">" dW wV h4">=" dW" 32" h4"!=(x^-6.1))"}, +#define WX1 hJ Cmp_powy_p_p,aC2(aE2 Cmp_powy_p_p)o81"y_p_p","1" h4"=(x" h03"2" h4"<(x" h03"4" h4"<=(x" h03"8" h4">(x" a1 wV h4">=(x" a1" 32" h4"!=(x^6.1))"}, +#define YX1 hJ Cmp_powy_pn,aC2(aE2 Cmp_powy_pn)o81"y_pn","1" h4 wJ1 h4 wK1 h4 o71 h4 wL1 h4">=-4" hO2 h4"!=-4" gO2 +#define SY1 hJ Cmp_powy_pp,aC2(aE2 Cmp_powy_pp)o81"y_pp","1" h4 o41 h4 wM2 h4 hL1 h4 o51 h4 mE h4 d91 +#define TY1 mG Cmp_sinh,aC2(aE2 Cmp_sinh)oS gK2,"1" qF1"=" gK2 hI1 qF1"<" gK2 hJ1 qF1"<=" gK2 hI2 qF1">" gK2 hK2 qF1">=" gK2 hL2 qF1"!=" gK2 d11 +#define UY1 hR1 oI3,aC2(aE2 oI3)LNG_ONLY(aE2 oI3)dT1"cmp_sqr","1" wW"=16" o42" 2" wW"<16" o42" 4" wW"<=16" o42" 8" wW">16" o42" 16" wW">=16" hO2 wW"!=16" gO2 +#define WY1 hR1 gJ3,aC2(aE2 gJ3)LNG_ONLY(aE2 gJ3)dT1"cmp_sqr_neg","1" wW"=-16" o42" 2" wW"<-16" o42" 4" wW"<=-16" o42" 8" wW">-16" o42" -16" wW">=-16" hO2 wW"!=-16" gO2 +#define YY1 {1,-4,4 mR1 qL Cmp_tanh,aC2(aE2 Cmp_tanh)qZ"cmp_tanh","1" oP"=tanh" dP2 oK2 oP"<tanh" dP2 a02 oP"<=tanh" dP2 d31 oP">tanh" dP2 d21 oP">=tanh" dP2" 32" oP"!=tanh(0.75))"}, +#define SZ1 {1,-4,4 mR1 qL Cmp_tanh_outrange,aC2(aE2 Cmp_tanh_outrange)qZ"cmp_tanh_outrange","1" oP"=2" o9"tanh(x)<2" o42 a02 oP"<=2" o42 d31 oP">2" o42 d21 oP">=2" o42" 32" oP"!=2" gO2 +#define TZ1 a62 Cmpeq,aC2(aE2 Cmpeq)LNG_ONLY(aE2 Cmpeq)dT1"cmpeq","(5=3" qP2"4=4" gO2 +#define UZ1 a62 Cmpge,aC2(aE2 Cmpge)LNG_ONLY(aE2 Cmpge)dT1"cmpge","(5>=3" qP2"4>=8" gO2 +#define WZ1 a62 Cmpgt,aC2(aE2 Cmpgt)LNG_ONLY(aE2 Cmpgt)dT1"cmpgt","(5>3" qP2"4>8" gO2 +#define YZ1 a62 Cmple,aC2(aE2 Cmple)LNG_ONLY(aE2 Cmple)dT1"cmple","(5<3" qP2"4<8" gO2 +#define Sa1 a62 Cmplt,aC2(aE2 Cmplt)LNG_ONLY(aE2 Cmplt)dT1"cmplt","(5<3)+x"}, +#define Ta1 a62 Cmpne,aC2(aE2 Cmpne)LNG_ONLY(aE2 Cmpne)dT1"cmpne","(5!=3" qP2"4!=4" gO2 +#define Ua1 a62 Div,aC2(aE2 Div)LNG_ONLY(aE2 Div)dT1"div","(5/4)+x"}, +#define Wa1 a62 Div1,aC2(aE2 Div1)LNG_ONLY(aE2 Div1)dT1"div1","x/1+x"}, +#define Ya1 a62 Divxx,aC2(aE2 Divxx)LNG_ONLY(aE2 Divxx)dT1"divxx","x+x/x+x"}, +#define Sb1 a62 Eq0,aC2(aE2 Eq0)LNG_ONLY(aE2 Eq0)dT1"eq0","(x=0" o42" (0=" aN1 +#define Tb1 a62 Eq1,aC2(aE2 Eq1)LNG_ONLY(aE2 Eq1)dT1"eq1","(!x=1" gO2 +#define Ub1 {dM oJ3,aC2(aE2 oJ3)LNG_ONLY(aE2 oJ3)dT1"ge0_abs",oL1 h13 gM3 h23 gN3 +#define Wb1 wR Ge0_neg,aC2(aE2 Ge0_neg)qZ"ge0_neg" w51 h13 w2 h23 qR3 +#define Yb1 wR Ge0_pos,aC2(aE2 Ge0_pos)qZ"ge0_pos",oN1 h13 qI3 h23 gE3 +#define Sc1 {dM oK3,aC2(aE2 oK3)LNG_ONLY(aE2 oK3)dT1"ge1_abs",oL1 h33 gM3 h43 gN3 +#define Tc1 wR Ge1_neg,aC2(aE2 Ge1_neg)qZ"ge1_neg" w51 h33 w2 h43 qR3 +#define Uc1 wR Ge1_pos,aC2(aE2 Ge1_pos)qZ"ge1_pos",oN1 h33 qI3 h43 gE3 +#define Wc1 wR Gehalf,aC2(aE2 Gehalf)qZ"gehalf","x>=0.5"}, +#define Yc1 {dM oL3,aC2(aE2 oL3)LNG_ONLY(aE2 oL3)dT1"gt0_abs",oL1 hT3 gM3 hU3 gN3 +#define Sd1 wR Gt0_neg,aC2(aE2 Gt0_neg)qZ"gt0_neg" w51 hT3 w2 hU3 qR3 +#define Td1 wR Gt0_pos,aC2(aE2 Gt0_pos)qZ"gt0_pos",oN1 hT3 qI3 hU3 gE3 +#define Ud1 {dM oM3,aC2(aE2 oM3)LNG_ONLY(aE2 oM3)dT1"gt1_abs",oL1 hV3 gM3 hW3 gN3 +#define Wd1 wR Gt1_neg,aC2(aE2 Gt1_neg)qZ"gt1_neg" w51 hV3 w2 hW3 qR3 +#define Yd1 wR Gt1_pos,aC2(aE2 Gt1_pos)qZ"gt1_pos",oN1 hV3 qI3 hW3 gE3 +#define Se1 wR Gtminushalf,aC2(aE2 Gtminushalf)qZ"gtminushalf","x>-0.5"}, +#define Te1 {1,wV2 Immsub,aC2(aE2 Immsub)LNG_ONLY(aE2 Immsub)dT1"immsub","x-5"}, +#define Ue1 wR Leminushalf,aC2(aE2 Leminushalf)qZ"leminushalf","x<=-0.5"}, +#define We1 {1,0 o8 Log2exp1,aC2(aE2 Log2exp1)qZ"log2exp1",dJ2"log2" hF1 +#define Ye1 {1,-1,N(0.75)mR1 qL Log2exp2,aC2(aE2 Log2exp2)qZ"log2exp2","exp2(log2(acos(x)))"}, +#define Sf1 {1,0 o8 Logexp1,aC2(aE2 Logexp1)qZ"logexp1",dJ2"log" hF1 +#define Tf1 {1,-1,N(0.75)mR1 qL Logexp2,aC2(aE2 Logexp2)qZ"logexp2",dJ2"log(acos(x)))"}, +#define Uf1 {1,-dG1 Logmul,aC2(aE2 Logmul)qZ"logmul","log(" hM1 +#define Wf1 {1,-dG1 Logmul2,aC2(aE2 Logmul2)qZ"logmul2","log2(" hM1 +#define Yf1 {1,-dG1 Logmul10,aC2(aE2 Logmul10)qZ"logmul10","log10(" hM1 +#define Sg1 {dM Lt0,aC2(aE2 Lt0)LNG_ONLY(aE2 Lt0)dT1"lt0","sub" oL1"<0, x<0" gO2 +#define Tg1 wR Lthalf,aC2(aE2 Lthalf)qZ"lthalf","x<0.5"}, +#define Ug1 a62 Mod,aC2(aE2 Mod)LNG_ONLY(aE2 Mod)dT1"mod","(5%4)+x"}, +#define Wg1 a62 Mul,aC2(aE2 Mul)LNG_ONLY(aE2 Mul)dT1"mul","(5*4)+x"}, +#define Yg1 a62 Mul1,aC2(aE2 Mul1)LNG_ONLY(aE2 Mul1)dT1"mul1","x*1+x"}, +#define Sh1 a62 Mul1b,aC2(aE2 Mul1b)qZ"mul1b",wO"0.2)*5)+x"}, +#define Th1 {2,N(0.1),10,N(0.1)qL Mul_zero,aC2(aE2 Mul_zero)dI2"mul_zero","(x*y+1)+(sin(x)+sin(y))*log(x)*y*x*0"}, +#define Uh1 a62 Mulneg,aC2(aE2 Mulneg)LNG_ONLY(aE2 Mulneg)dT1"mulneg","-" qT2 +#define Wh1 a62 dP3,aC2(aE2 dP3)LNG_ONLY(aE2 dP3)dT1"multodiv","x/4+x"}, +#define Yh1 {2,wV2 Negadd,aC2(aE2 Negadd)LNG_ONLY(aE2 Negadd)gI1"negadd","x+(-y" gO2 +#define Si1 gD Negcos,aC2(aE2 Negcos)qZ"negcos","cos" wM1 +#define Ti1 gD Negcosh,aC2(aE2 Negcosh)qZ"negcosh","cosh" wM1 +#define Ui1 a62 Negmul,aC2(aE2 Negmul)LNG_ONLY(aE2 Negmul)dT1"negmul","(-x)*" gV2 +#define Wi1 gD Negsin,aC2(aE2 Negsin)qZ"negsin","sin(-" aN1 +#define Yi1 gD Negsinh,aC2(aE2 Negsinh)qZ"neg" gK2,gK2 wM1 +#define Sj1 {2,wV2 Negsub,aC2(aE2 Negsub)LNG_ONLY(aE2 Negsub)gI1"negsub","x-(-y" gO2 +#define Tj1 gD Negtan,aC2(aE2 Negtan)qZ"negtan","tan" wM1 +#define Uj1 gD Negtanh,aC2(aE2 Negtanh)qZ"negtanh","tanh" wM1 +#define Wj1 a62 Neq0,aC2(aE2 Neq0)LNG_ONLY(aE2 Neq0)dT1"neq0","(x!=0" o42" (0!=" aN1 +#define Yj1 a62 Neq1,aC2(aE2 Neq1)LNG_ONLY(aE2 Neq1)dT1"neq1","(!x!=1" gO2 +#define Sk1 a62 Not,aC2(aE2 Not)LNG_ONLY(aE2 Not)dT1"not","(!(3))+x"}, +#define Tk1 a62 Or,aC2(aE2 Or)LNG_ONLY(aE2 Or)dT1"or","(5|3" qP2"5|0)+(0|5)+(0|0" gO2 +#define Uk1 gD Sincos_cci,aC2(aE2 Sincos_cci)hP"cos_cci","cos" qS2" sec(x)"}, +#define Wk1 gD Sincos_cic,aC2(aE2 Sincos_cic)hP"cos_cic","sec" qS2 w71 +#define Yk1 gD Sincos_sc,aC2(aE2 Sincos_sc)hP"cos_sc",oL2 w71 +#define Sl1 gD Sincos_sci,aC2(aE2 Sincos_sci)hP"cos_sci",oL2" sec(x)"}, +#define Tl1 gD Sincos_sis,aC2(aE2 Sincos_sis)hP"cos_sis","csc" qS2" " wQ1}, +#define Ul1 gD Sincos_ssi,aC2(aE2 Sincos_ssi)hP"cos_ssi",oL2" csc(x)"}, +#define Wl1 gD Sincos_tan,aC2(aE2 Sincos_tan)hP"cos_tan",wQ1" /" w71 +#define Yl1 gD Sincos_tit,aC2(aE2 Sincos_tit)hP"cos_tit","cot" qS2" tan(x)"}, +#define Sm1 gD Sincos_tti,aC2(aE2 Sincos_tti)hP"cos_tti","tan" qS2" cot(x)"}, +#define Tm1 a62 Sqreq0,aC2(aE2 Sqreq0)LNG_ONLY(aE2 Sqreq0)dT1"sqreq0","(x*x=0" o42" (0=x*x)"}, +#define Um1 a62 oN3,aC2(aE2 oN3)LNG_ONLY(aE2 oN3)dT1"sqrneq0","(x*x=0" o42" (0=x*x)"}, +#define Wm1 {1,0 o8 Sqrtsqr1,aC2(aE2 Sqrtsqr1)qZ"sqrtsqr1","sqrt(x)^2"}, +#define Ym1 {1 mC Sqrtsqr2,aC2(aE2 Sqrtsqr2)qZ"sqrtsqr2","sqrt(acos(x))^2"}, +#define Sn1 a62 Sub,aC2(aE2 Sub)LNG_ONLY(aE2 Sub)dT1"sub","5-3+x"}, +#define Tn1 a62 Sub0,aC2(aE2 Sub0)LNG_ONLY(aE2 Sub0)dT1"sub0","x-0+x"}, +#define Un1 {1,-3,3,1 qL Subxx,aC2(aE2 Subxx)LNG_ONLY(aE2 Subxx)dT1"subxx","x+(x-x)+x+(1-x+x)"}, +#define Wn1 gD Xmulsinhneg,aC2(aE2 Xmulsinhneg)a2"mulsinhneg","-" gK2 qT2 +#define Yn1 gD Xmulsinneg,aC2(aE2 Xmulsinneg)a2"mulsinneg","-sin(x*" q12 +#define So1 gD Xmultanhneg,aC2(aE2 Xmultanhneg)a2"multanhneg","-tanh" qT2 +#define To1 gD Xmultanneg,aC2(aE2 Xmultanneg)a2"multanneg","-tan" qT2 +#define Uo1 {1,N(0.5),3,N(0.7)qL Xsqryfsqrhypot,aC2(aE2 Xsqryfsqrhypot)a2"sqryfsqrhypot","sqrt(log(x)^2+" wU"^2" gO2 +#define Wo1 {2,N(0.5),3,N(0.7)qL Xsqrysqrhypot,aC2(aE2 Xsqrysqrhypot)dH2"/xsqrysqrhypot","sqrt(log(x)^2+y*" oS2 +#define Yo1 {1 dH1 t1,aC2(aD2 t1)LNG_ONLY(aD2 t1)wQ2"1","(1/a" oN2 +#define Sp1 {1 dH1 t2,aC2(aD2 t2)LNG_ONLY(aD2 t2)wQ2"2","5*a"}, +#define Tp1 {1 dH1 t3,aC2(aD2 t3)LNG_ONLY(aD2 t3)wQ2"3","5/a"}, +#define Up1 {2 dH1 t4,aC2(aD2 t4)LNG_ONLY(aD2 t4)hD"4","(a*5)*b"}, +#define Wp1 {2 dH1 t5,aC2(aD2 t5)LNG_ONLY(aD2 t5)hD"5","(a*5)/b"}, +#define Yp1 {2 dH1 t6,aC2(aD2 t6)LNG_ONLY(aD2 t6)hD"6","(1/a)*b"}, +#define Sq1 {2 dH1 t7,aC2(aD2 t7)LNG_ONLY(aD2 t7)hD"7","(1/a)/b"}, +#define Tq1 {2 dH1 t8,aC2(aD2 t8)LNG_ONLY(aD2 t8)hD"8" mA1"a)*(" hP2")*" q12 +#define Uq1 {2 dH1 t9,aC2(aD2 t9)LNG_ONLY(aD2 t9)hD"9" mA1"a)/(" hP2")*" q12 +#define Wq1 g6 t10,aC2(aD2 t10)LNG_ONLY(aD2 t10)hD"10" mA1"b)*(5/a" gO2 +#define Yq1 g6 t11,aC2(aD2 t11)LNG_ONLY(aD2 t11)hD"11" mA1"b)/(50/a" gO2 +#define Sr1 mH t12,aC2(aD2 t12)LNG_ONLY(aD2 t12)wQ2"12","(-a)+" gV2 +#define Tr1 g6 t13,aC2(aD2 t13)LNG_ONLY(aD2 t13)hD"13","5+(a*b" gO2 +#define Ur1 g6 t14,aC2(aD2 t14)LNG_ONLY(aD2 t14)hD"14","5-(a*b" gO2 +#define Wr1 g6 t15,aC2(aD2 t15)LNG_ONLY(aD2 t15)hD"15","(a+5)+" hP2 gO2 +#define Yr1 g6 t16,aC2(aD2 t16)LNG_ONLY(aD2 t16)hD"16","(a+5)-abs(b" gO2 +#define Ss1 g6 t17,aC2(aD2 t17)LNG_ONLY(aD2 t17)hD"17","(-a)+" hP2 gO2 +#define Ts1 g6 t18,aC2(aD2 t18)LNG_ONLY(aD2 t18)hD"18","(-a)-abs(b" gO2 +#define Us1 g6 t19,aC2(aD2 t19)LNG_ONLY(aD2 t19)hD"19","b+(" oR2")+" q12 +#define Ws1 g6 t20,aC2(aD2 t20)LNG_ONLY(aD2 t20)hD"20","b-(" oR2")+" q12 +#define Ys1 g6 t21,aC2(aD2 t21)LNG_ONLY(aD2 t21)hD"21" mA1"b)+(5-a" gO2 +#define St1 g6 t22,aC2(aD2 t22)LNG_ONLY(aD2 t22)hD"22" mA1"b)-(5-a" gO2 +#define Tt1 g6 t23,aC2(aD2 t23)LNG_ONLY(aD2 t23)hD"23" qG1"b" oQ2 +#define Ut1 g6 t24,aC2(aD2 t24)LNG_ONLY(aD2 t24)hD"24" qG1"5" oQ2 +#define Wt1 g6 t25,aC2(aD2 t25)LNG_ONLY(aD2 t25)hD"25" qG1"5" oM2 +#define Yt1 g6 t26,aC2(aD2 t26)LNG_ONLY(aD2 t26)hD"26","(" o13"abs(a)/b" oQ2 +#define Su1 g6 t27,aC2(aD2 t27)LNG_ONLY(aD2 t27)hD"27","(" o13"abs(a)/b" oM2 +#define Tu1 g6 t28,aC2(aD2 t28)LNG_ONLY(aD2 t28)hD"28","((-a)/b" oN2 +#define Uu1 g6 t29,aC2(aD2 t29)LNG_ONLY(aD2 t29)hD"29","(5/b" oM2 +#define Wu1 mH t30,aC2(aD2 t30)LNG_ONLY(aD2 t30)"b",qE"30","(7/b" oN2 +#define Yu1 g6 t31,aC2(aD2 t31)LNG_ONLY(aD2 t31)hD"31","b*(7/-a" gO2 +#define Sv1 g6 t32,aC2(aD2 t32)LNG_ONLY(aD2 t32)hD"32","(5-b)-a"}, +#define Tv1 g6 t33,aC2(aD2 t33)LNG_ONLY(aD2 t33)hD"33","(5-b)+a"}, +#define Uv1 g6 t34,aC2(aD2 t34)LNG_ONLY(aD2 t34)hD"34","((a+7)-b)+" gV2 +#define Wv1 g6 t35,aC2(aD2 t35)LNG_ONLY(aD2 t35)hD"35","((-a)-b)+" gV2 +#define Yv1 mH t36,aC2(aD2 t36)LNG_ONLY(aD2 t36)wQ2"36","(7-abs(a))+" gV2 +#define Sw1 g6 t37,aC2(aD2 t37)LNG_ONLY(aD2 t37)hD"37","((7-b)+a)+" gV2 +#define Tw1 g6 t38,aC2(aD2 t38)LNG_ONLY(aD2 t38)hD"38","((5*b+" oR2"))<0)*1 + ((" hP2"))<0)*2"}, +#define Uw1 mH t39,aC2(aD2 t39)LNG_ONLY(aD2 t39)wQ2"39","(a+7" oN2 +#define Ww1 g6 t40,aC2(aD2 t40)LNG_ONLY(aD2 t40)hD"40","(b+(a*7))*" gV2 +#define Yw1 g6 t41,aC2(aD2 t41)LNG_ONLY(aD2 t41)hD"41","(b-(a*7))*" gV2 +#define Sx1 mH t42,aC2(aD2 t42)LNG_ONLY(aD2 t42)wQ2"42","(a+7)+" gV2 +#define Tx1 mH t43,aC2(aD2 t43)LNG_ONLY(aD2 t43)wQ2"43","(a*7" oN2 +#define Ux1 g91 Abseq0,aC2(aB2 Abseq0)LNG_ONLY(aB2 Abseq0)gN1"abseq0",oL1"=if" wD2")) + (if" wD2")=abs" hF1 +#define Wx1 g91 oF3,aC2(aB2 oF3)LNG_ONLY(aB2 oF3)gN1"absneq0",oL1"=if" wD2")) + (if" wD2")=abs" hF1 +#define Yx1 g91 Eq0,aC2(aB2 Eq0)LNG_ONLY(aB2 Eq0)gN1"eq0","(x=if(" hQ2" + (if(" hR2"=" aN1 +#define Sy1 g91 Eq1,aC2(aB2 Eq1)LNG_ONLY(aB2 Eq1)gN1"eq1","(!x=if(" hS2}, +#define Ty1 oA1 oJ3,aC2(aB2 oJ3)LNG_ONLY(aB2 oJ3)gN1"ge0_abs",oL1" >= if(" hQ2 qT1 hR2 oT3 qJ3"<= if(" gC1 gD1 hR2" >= " gN3 +#define Uy1 oA1 oK3,aC2(aB2 oK3)LNG_ONLY(aB2 oK3)gN1"ge1_abs",oL1" >= if(" hS2 qT1 dQ3"<= " qJ3"<= if(" hN1 gD1 dQ3">= " gN3 +#define Wy1 {1 dN N(0.25),q7 Gehalf,aC2(aB2 Gehalf)gR"gehalf","x>=if(1,0.5,0" gO2 +#define Yy1 oA1 oL3,aC2(aB2 oL3)LNG_ONLY(aB2 oL3)gN1"gt0_abs",oL1" > if(" hQ2 qT1 hR2 oV3 qJ3"< if(" gC1 gD1 hR2" > " gN3 +#define Sz1 oA1 oM3,aC2(aB2 oM3)LNG_ONLY(aB2 oM3)gN1"gt1_abs",oL1" > if(" hS2 qT1 dQ3"< " qJ3"< if(" hN1 gD1 dQ3"> " gN3 +#define Tz1 {1 dN N(0.25),q7 Lthalf,aC2(aB2 Lthalf)gR"lthalf","x<if(1,0.5,0" gO2 +#define Uz1 g91 Neq0,aC2(aB2 Neq0)LNG_ONLY(aB2 Neq0)gN1"neq0","(x!=if(" hQ2" + (if(" hR2"!=" aN1 +#define Wz1 g91 Neq1,aC2(aB2 Neq1)LNG_ONLY(aB2 Neq1)gN1"neq1","(!x!=if(" hS2}, +#define Yz1 {1,-9,9,1,hI t7,aC2(aG2 t7)LNG_ONLY(aG2 t7)wE2"7","x>7 & x<2"}, +#define S_1 {2,-9,9,1,hI t8,aC2(aG2 t8)qA",y",oK"8",hT2"(-x,-y" o42" 10" oO2"(-x,y" o42" 20" oO2"(x,-y" o42" 30" oO2"(x,y" gO2 +#define T_1 {1 oO3 t9a,aC2(aG2 t9a)LNG_ONLY(aG2 t9a)wE2"9a","a:=x;a*0"}, +#define U_1 {2 oO3 t9b,aC2(aG2 t9b)LNG_ONLY(aG2 t9b)hU2"9b","sub(a,b" oP2 +#define W_1 {2 oO3 t9c,aC2(aG2 t9c)LNG_ONLY(aG2 t9c)hU2"9c","psub(a,b" oP2 +#define Y_1 {2 oO3 t9d,aC2(aG2 t9d)LNG_ONLY(aG2 t9d)hU2"9d","if(a,b*0,a*0" oP2 +#define S02 {1,1,10,1,hI t10,aC2(aG2 t10)qA,oK"10","1/abs(x)<1"}, +#define T02 {1,N(1e25),N(10e25),N(1e25),hI t11,aC2(aG2 t11)qA,oK"11","exp(x/5e+25" gO2 +#define U02 {3,-3,3,2,hI t61,aC2(aG2 t61)LNG_ONLY(aG2 t61)gZ2 oK"61","5*x*y + -5*z"}, +#define W02 {2,gN Add_cd,hA wQ"add_cd","x+y"}, +#define Y02 {2,hJ2 Add_d,aC2(aF2 Add_d)wQ"add_d","x+y"}, +#define S12 {3,gN Addsub_cd,hA qG2 g7"addsub_cd","x+y+x+x-z+x"}, +#define T12 {3,hJ2 Addsub_d,aC2(aF2 Addsub_d)qG2 g7"addsub_d","x+y+x+x-z+x"}, +#define U12 {2,gI And_d,aC2(aF2 And_d)wQ"and_d","x&y"}, +#define W12 {2,gN Cmpeq_cd,hA wQ"cmpeq_cd","x=y"}, +#define Y12 {2,gI Cmpeq_d,aC2(aF2 Cmpeq_d)wQ"cmpeq_d","x=y"}, +#define S22 {2,gI Cmpge_d,aC2(aF2 Cmpge_d)wQ"cmpge_d","x>=y"}, +#define T22 {2,gI Cmpgt_d,aC2(aF2 Cmpgt_d)wQ"cmpgt_d","x>y"}, +#define U22 {2,gI Cmple_d,aC2(aF2 Cmple_d)wQ"cmple_d","x<=y"}, +#define W22 {2,gI Cmplt_d,aC2(aF2 Cmplt_d)wQ"cmplt_d","x<y"}, +#define Y22 {2,gN Cmpne_cd,hA wQ"cmpne_cd","x!=y"}, +#define S32 {2,gI Cmpne_d,aC2(aF2 Cmpne_d)wQ"cmpne_d","x!=y"}, +#define T32 {2,dL Div_d,aC2(aF2 Div_d)wQ"div_d","(x-0.25)/y"}, +#define U32 {3,dL Divmul_d,aC2(aF2 Divmul_d)qG2 g7"divmul_d","x*y*x*x/z" wE1"-0.25" gO2 +#define W32 {1,N(-7.0,0.0),N(6.0,0.0),N(0.6,0.0),qM Inv_d,aC2(aF2 Inv_d)qA,g7"inv_d","1/x"}, +#define Y32 {2,N(-7.25,+3.625),N(7.25,-3.625),N(0.5,-0.25),qM Mul_cd,hA wQ"mul_cd","x*y"}, +#define S42 {2,dL Mul_d,aC2(aF2 Mul_d)wQ"mul_d","x*y"}, +#define T42 {1,gN Neg_cd,hA qA,g7"neg_cd","-x"}, +#define U42 {1,hJ2 Neg_d,aC2(aF2 Neg_d)qA,g7"neg_d","-x"}, +#define W42 {1,N(-1.25,0.0),N(1.25,0.0),N(0.25,0.0),qM Not_d,aC2(aF2 Not_d)qA,g7"not_d","!x"}, +#define Y42 {1,N(-1.25,0.0),N(1.25,0.0),N(0.25,0.0),qM Notnot_d,aC2(aF2 Notnot_d)qA,g7"notnot_d","!!x"}, +#define S52 {2,gI Or_d,aC2(aF2 Or_d)wQ"or_d","x|y"}, +#define T52 {2,gN Sub_cd,hA wQ"sub_cd","x-y"}, +#define U52 {2,hJ2 Sub_d,aC2(aF2 Sub_d)wQ"sub_d","x-y"}, +#define W52 {1,N(-400.0,+200.0),N(400.0,-200.0),N(0.5,-0.25)dP Abs_cd qF"/abs_cd",hY3}, +#define Y52 {1,gV Arg qF"/arg",aH1 +#define S62 {1,gV Conj qF"/conj","conj(x)"}, +#define T62 {1,gV Imag qF"/imag","imag(x)"}, +#define U62 {1,gV Log,aC2(aJ2 Log)qO"/log",aH1 +#define W62 {1,N(-4000.0,-0.5),N(4000.0,+0.5),N(0.3,+3.75e-05)dP Log_cd qF"/log_cd",aH1 +#define Y62 {2,N(-4.0,0.0),aI1 qJ false qI Max,aC2(aJ2 Max)LNG_ONLY(aJ2 Max)"x" oJ"/max","max(x,y" gO2 +#define S72 {2,N(-4.0,0.0),aI1 qJ false qI Min,aC2(aJ2 Min)LNG_ONLY(aJ2 Min)"x" oJ"/min","min(x,y" gO2 +#define T72 {2,N(0.01,0.0),aI1,N(0.05,0.0)dP Polar,d82"/polar","polar(x,y" gO2 +#define U72 {1,gV Real qF"/real","real(x)"}, +#define W72 {1,N(-100000.0,0.0),N(100000.0,0.0),N(1000.0,0.0)dP Sqrt_cd qF"/sqrt_cd","sqrt(x)"}, +#define Y72 {1,gX t1,aC2(aD2 t1)LNG_ONLY(aD2 t1)wQ2"1","(1/a" oN2 +#define S82 {1,gX t2,aC2(aD2 t2)LNG_ONLY(aD2 t2)wQ2"2","5*a"}, +#define T82 {1,gX t3,aC2(aD2 t3)LNG_ONLY(aD2 t3)wQ2"3","5/a"}, +#define U82 {2,gX t4,aC2(aD2 t4)LNG_ONLY(aD2 t4)hD"4","(a*5)*b"}, +#define W82 {2,gX t5,aC2(aD2 t5)LNG_ONLY(aD2 t5)hD"5","(a*5)/b"}, +#define Y82 {2,gX t6,aC2(aD2 t6)LNG_ONLY(aD2 t6)hD"6","(1/a)*b"}, +#define S92 {2,gX t7,aC2(aD2 t7)LNG_ONLY(aD2 t7)hD"7","(1/a)/b"}, +#define T92 {2,gX t8,aC2(aD2 t8)LNG_ONLY(aD2 t8)hD"8" mA1"a)*(" hP2")*" q12 +#define U92 {2,gX t9,aC2(aD2 t9)LNG_ONLY(aD2 t9)hD"9" mA1"a)/(" hP2")*" q12 +#define W92 mK t10,aC2(aD2 t10)LNG_ONLY(aD2 t10)hD"10" mA1"b)*(5/a" gO2 +#define Y92 mK t11,aC2(aD2 t11)LNG_ONLY(aD2 t11)hD"11" mA1"b)/(50/a" gO2 +#define SA2 {1,qD t12,aC2(aD2 t12)LNG_ONLY(aD2 t12)wQ2"12","(-a)+" gV2 +#define TA2 mK t13,aC2(aD2 t13)LNG_ONLY(aD2 t13)hD"13","5+(a*b" gO2 +#define UA2 mK t14,aC2(aD2 t14)LNG_ONLY(aD2 t14)hD"14","5-(a*b" gO2 +#define WA2 mK t15,aC2(aD2 t15)LNG_ONLY(aD2 t15)hD"15","(a+5)+" hP2 gO2 +#define YA2 mK t16,aC2(aD2 t16)LNG_ONLY(aD2 t16)hD"16","(a+5)-abs(b" gO2 +#define SB2 mK t17,aC2(aD2 t17)LNG_ONLY(aD2 t17)hD"17","(-a)+" hP2 gO2 +#define TB2 mK t18,aC2(aD2 t18)LNG_ONLY(aD2 t18)hD"18","(-a)-abs(b" gO2 +#define UB2 mK t19,aC2(aD2 t19)LNG_ONLY(aD2 t19)hD"19","b+(" oR2")+" q12 +#define WB2 mK t20,aC2(aD2 t20)LNG_ONLY(aD2 t20)hD"20","b-(" oR2")+" q12 +#define YB2 mK t21,aC2(aD2 t21)LNG_ONLY(aD2 t21)hD"21" mA1"b)+(5-a" gO2 +#define SC2 mK t22,aC2(aD2 t22)LNG_ONLY(aD2 t22)hD"22" mA1"b)-(5-a" gO2 +#define TC2 mK t23,aC2(aD2 t23)LNG_ONLY(aD2 t23)hD"23" qG1"b" oQ2 +#define UC2 mK t24,aC2(aD2 t24)LNG_ONLY(aD2 t24)hD"24" qG1"5" oQ2 +#define WC2 mK t25,aC2(aD2 t25)LNG_ONLY(aD2 t25)hD"25" qG1"5" oM2 +#define YC2 mK t26,aC2(aD2 t26)LNG_ONLY(aD2 t26)hD"26","(" o13"abs(a)/b" oQ2 +#define SD2 mK t27,aC2(aD2 t27)LNG_ONLY(aD2 t27)hD"27","(" o13"abs(a)/b" oM2 +#define TD2 mK t28,aC2(aD2 t28)LNG_ONLY(aD2 t28)hD"28","((-a)/b" oN2 +#define UD2 mK t29,aC2(aD2 t29)LNG_ONLY(aD2 t29)hD"29","(5/b" oM2 +#define WD2 {1,qD t30,aC2(aD2 t30)LNG_ONLY(aD2 t30)"b",qE"30","(7/b" oN2 +#define YD2 mK t31,aC2(aD2 t31)LNG_ONLY(aD2 t31)hD"31","b*(7/-a" gO2 +#define SE2 mK t32,aC2(aD2 t32)LNG_ONLY(aD2 t32)hD"32","(5-b)-a"}, +#define TE2 mK t33,aC2(aD2 t33)LNG_ONLY(aD2 t33)hD"33","(5-b)+a"}, +#define UE2 mK t34,aC2(aD2 t34)LNG_ONLY(aD2 t34)hD"34","((a+7)-b)+" gV2 +#define WE2 mK t35,aC2(aD2 t35)LNG_ONLY(aD2 t35)hD"35","((-a)-b)+" gV2 +#define YE2 {1,qD t36,aC2(aD2 t36)LNG_ONLY(aD2 t36)wQ2"36","(7-abs(a))+" gV2 +#define SF2 mK t37,aC2(aD2 t37)LNG_ONLY(aD2 t37)hD"37","((7-b)+a)+" gV2 +#define TF2 mK t38,aC2(aD2 t38)LNG_ONLY(aD2 t38)hD"38","((5*b+" oR2"))<0)*1 + ((" hP2"))<0)*2"}, +#define UF2 {1,qD t39,aC2(aD2 t39)LNG_ONLY(aD2 t39)wQ2"39","(a+7" oN2 +#define WF2 mK t40,aC2(aD2 t40)LNG_ONLY(aD2 t40)hD"40","(b+(a*7))*" gV2 +#define YF2 mK t41,aC2(aD2 t41)LNG_ONLY(aD2 t41)hD"41","(b-(a*7))*" gV2 +#define SG2 {1,qD t42,aC2(aD2 t42)LNG_ONLY(aD2 t42)wQ2"42","(a+7)+" gV2 +#define TG2 {1,qD t43,aC2(aD2 t43)LNG_ONLY(aD2 t43)wQ2"43","(a*7" oN2 +#define UG2 dB Abscos,aC2(aB2 Abscos)gR"abscos","cos(sqrt(" dX1"))) + sqrt(" dX1"))"}, +#define WG2 dB Abscosh,aC2(aB2 Abscosh)gR"abscosh","cosh(sqrt(" dX1"))) + sqrt(" dX1"))"}, +#define YG2 {1,N(0.0,0.0)qJ N(1.0,0.0),q7 Abseq0,aC2(aB2 Abseq0)LNG_ONLY(aB2 Abseq0)gN1"abseq0",oL1"=if" wD2")) + (if" wD2")=abs" hF1 +#define SH2 {1,N(0.0,0.0)qJ N(1.0,0.0),q7 oF3,aC2(aB2 oF3)LNG_ONLY(aB2 oF3)gN1"absneq0",oL1"=if" wD2")) + (if" wD2")=abs" hF1 +#define TH2 {1,N(-5.0,0.0),N(5.0,0.0)qJ q7 o43,aC2(aB2 o43)LNG_ONLY(aB2 o43)gN1"absnzge","sub" oL1" >= if" wF2"), " hY3 dF2"(if(1,1,0)-1))"}, +#define UH2 {1,N(-5.0,0.0),N(5.0,0.0)qJ q7 o53,aC2(aB2 o53)LNG_ONLY(aB2 o53)gN1"absnzlt","sub" oL1" < if" wF2"), " hY3" < (if(1,1,0)-1))"}, +#define WH2 {1,N(-1.0,0.0)qJ N(0.1,0.0),q7 Acoscos,aC2(aB2 Acoscos)gR"acoscos","cos(acos" hF1 +#define YH2 {1,N(1.7,0.0),N(3.7,0.0),N(0.28,0.0),q7 Acoshsinh,aC2(aB2 Acoshsinh)gR oB2 gK2,gK2"(if(1,acosh(x),0))"}, +#define SI2 {hT gF3,aC2(aB2 gF3)LNG_ONLY(aB2 gF3)qR"addconstmul","5*(if" wF2")+x+" oS2 +#define TI2 {2,N(0.25,0.0)qJ N(0.25,0.0),q7 Addlog,aC2(aB2 Addlog)aI"addlog","log(x)+log(" oS2 +#define UI2 {hT qK3,aC2(aB2 qK3)LNG_ONLY(aB2 qK3)qR"addmulconstmul","5*(if" wF2")*y+x)"}, +#define WI2 {hT g03,aC2(aB2 g03)LNG_ONLY(aB2 g03)qR"addnegmulneg","-5 + (if(1,5,0)*x*" oS2 +#define YI2 {hT g13,aC2(aB2 g13)LNG_ONLY(aB2 g13)qR"addnegmulpos","(if(1,-5,0)*y" o42" (if(1,5,0)*x)"}, +#define SJ2 {1 hN Addsin2cos2,aC2(aB2 Addsin2cos2)gR"addsin2cos2",wQ1"^2 + cos(x)^2"}, +#define TJ2 {1,N(-0.7,0.0),N(0.7,0.0),N(0.28,0.0),q7 Asinhcosh,aC2(aB2 Asinhcosh)gR"asinhcosh","cosh(if(1,a" gK2"(x),0))"}, +#define UJ2 {1,N(-1.0,0.0)qJ N(0.1,0.0),q7 Asinsin,aC2(aB2 Asinsin)gR"asinsin","sin(asin(x))"}, +#define WJ2 dB1 qS3,aC2(aB2 qS3)LNG_ONLY(aB2 qS3)qR"cmpeq_add_imm",qX1 q52 +#define YJ2 h32 mP2,aC2(aB2 mP2)LNG_ONLY(aB2 mP2)gN1"cmpeq_add_reduce",dS" = " h1}, +#define SK2 dB1 mQ2,aC2(aB2 mQ2)LNG_ONLY(aB2 mQ2)qR"cmpeq_addadd_imm",dY2" =" gX3 +#define TK2 {gS g23,aC2(aB2 g23)LNG_ONLY(aB2 g23)qR"cmpeq_minma" dX3"= " g33 +#define UK2 {gS mR2,aC2(aB2 mR2)LNG_ONLY(aB2 mR2)qR"cmpeq_minma" dY3"= " mS2 +#define WK2 dB1 m72,aC2(aB2 m72)LNG_ONLY(aB2 m72)qR"cmpeq_mul_imm_neg",hC1 q52 +#define YK2 dB1 m82,aC2(aB2 m82)LNG_ONLY(aB2 m82)qR"cmpeq_mul_imm_pos",dU1 q52 +#define SL2 dB1 aO2,aC2(aB2 aO2)LNG_ONLY(aB2 aO2)qR"cmpeq_mulmul_imm_neg",a31" =" gX3 +#define TL2 dB1 aP2,aC2(aB2 aP2)LNG_ONLY(aB2 aP2)qR"cmpeq_mulmul_imm_pos",d23"=" gX3 +#define UL2 {g21 Cmpeq_pow_imm_negneg,aC2(aB2 Cmpeq_pow_imm_negneg)gR o11 hV" = " aK2 +#define WL2 {g21 Cmpeq_pow_imm_negpos,aC2(aB2 Cmpeq_pow_imm_negpos)gR o11 hY" = " aN2 +#define YL2 h32 Cmpeq_pow_imm_posneg,aC2(aB2 Cmpeq_pow_imm_posneg)gR o11 d2" = " m52 +#define SM2 h32 Cmpeq_pow_imm_pospos,aC2(aB2 Cmpeq_pow_imm_pospos)gR o11 d3" = " qQ3 +#define TM2 h32 Cmpeq_pow_imm_pospos_base,aC2(aB2 Cmpeq_pow_imm_pospos_base)gR o11 m62"= " wT +#define UM2 dB1 Cmpeq_powpow_imm_base,aC2(aB2 Cmpeq_powpow_imm_base)aI o11 hH" = " a7 +#define WM2 dB1 qT3,aC2(aB2 qT3)LNG_ONLY(aB2 qT3)qR"cmpge_add_imm",qX1 a41 +#define YM2 h32 mT2,aC2(aB2 mT2)LNG_ONLY(aB2 mT2)gN1"cmpge_add_reduce",dS dF2 h1}, +#define SN2 dB1 mU2,aC2(aB2 mU2)LNG_ONLY(aB2 mU2)qR"cmpge_addadd_imm",dY2 dF2 hX +#define TN2 {gS g43,aC2(aB2 g43)LNG_ONLY(aB2 g43)qR"cmpge_minma" dX3">= " g33 +#define UN2 {gS mV2,aC2(aB2 mV2)LNG_ONLY(aB2 mV2)qR"cmpge_minma" dY3">= " mS2 +#define WN2 dB1 m92,aC2(aB2 m92)LNG_ONLY(aB2 m92)qR"cmpge_mul_imm_neg",hC1 a41 +#define YN2 dB1 mA2,aC2(aB2 mA2)LNG_ONLY(aB2 mA2)qR"cmpge_mul_imm_pos",dU1 a41 +#define SO2 dB1 aQ2,aC2(aB2 aQ2)LNG_ONLY(aB2 aQ2)qR"cmpge_mulmul_imm_neg",a31 dF2 hX +#define TO2 dB1 aR2,aC2(aB2 aR2)LNG_ONLY(aB2 aR2)qR"cmpge_mulmul_imm_pos",wO"4)" dF2 hX +#define UO2 {g21 Cmpge_pow_imm_negneg,aC2(aB2 Cmpge_pow_imm_negneg)dY1 hV" >= " aK2 +#define WO2 {g21 Cmpge_pow_imm_negpos,aC2(aB2 Cmpge_pow_imm_negpos)dY1 hY" >= " aN2 +#define YO2 h32 Cmpge_pow_imm_posneg,aC2(aB2 Cmpge_pow_imm_posneg)dY1 d2" >= " m52 +#define SP2 h32 Cmpge_pow_imm_pospos,aC2(aB2 Cmpge_pow_imm_pospos)dY1 d3" >= " qQ3 +#define TP2 h32 Cmpge_pow_imm_pospos_base,aC2(aB2 Cmpge_pow_imm_pospos_base)dY1 m62">= " wT +#define UP2 dB1 Cmpge_powpow_imm_base,aC2(aB2 Cmpge_powpow_imm_base)aI"cmpge_" hH dF2 a7 +#define WP2 dB1 qU3,aC2(aB2 qU3)LNG_ONLY(aB2 qU3)qR"cmpgt_add_imm",qX1 qC2 +#define YP2 h32 mW2,aC2(aB2 mW2)LNG_ONLY(aB2 mW2)gN1"cmpgt_add_reduce",dS" > " h1}, +#define SQ2 dB1 mX2,aC2(aB2 mX2)LNG_ONLY(aB2 mX2)qR"cmpgt_addadd_imm",dY2" >" gX3 +#define TQ2 {gS g53,aC2(aB2 g53)LNG_ONLY(aB2 g53)qR"cmpgt_minma" dX3"> " g33 +#define UQ2 {gS mY2,aC2(aB2 mY2)LNG_ONLY(aB2 mY2)qR"cmpgt_minma" dY3"> " mS2 +#define WQ2 dB1 mB2,aC2(aB2 mB2)LNG_ONLY(aB2 mB2)qR"cmpgt_mul_imm_neg",hC1 qC2 +#define YQ2 dB1 mC2,aC2(aB2 mC2)LNG_ONLY(aB2 mC2)qR"cmpgt_mul_imm_pos",dU1 qC2 +#define SR2 dB1 aS2,aC2(aB2 aS2)LNG_ONLY(aB2 aS2)qR"cmpgt_mulmul_imm_neg",a31" >" gX3 +#define TR2 dB1 aT2,aC2(aB2 aT2)LNG_ONLY(aB2 aT2)qR"cmpgt_mulmul_imm_pos",d23">" gX3 +#define UR2 {g21 Cmpgt_pow_imm_negneg,aC2(aB2 Cmpgt_pow_imm_negneg)hO1 hV" > " aK2 +#define WR2 {g21 Cmpgt_pow_imm_negpos,aC2(aB2 Cmpgt_pow_imm_negpos)hO1 hY" > " aN2 +#define YR2 h32 Cmpgt_pow_imm_posneg,aC2(aB2 Cmpgt_pow_imm_posneg)hO1 d2" > " m52 +#define SS2 h32 Cmpgt_pow_imm_pospos,aC2(aB2 Cmpgt_pow_imm_pospos)hO1 d3" > " qQ3 +#define TS2 h32 Cmpgt_pow_imm_pospos_base,aC2(aB2 Cmpgt_pow_imm_pospos_base)hO1 m62"> " wT +#define US2 dB1 Cmpgt_powpow_imm_base,aC2(aB2 Cmpgt_powpow_imm_base)aI"cmpgt_" hH" > " a7 +#define WS2 dB1 qV3,aC2(aB2 qV3)LNG_ONLY(aB2 qV3)qR"cmple_add_imm",qX1 a51 +#define YS2 h32 mZ2,aC2(aB2 mZ2)LNG_ONLY(aB2 mZ2)gN1"cmple_add_reduce",dS oT3 h1}, +#define ST2 dB1 q03,aC2(aB2 q03)LNG_ONLY(aB2 q03)qR"cmple_addadd_imm",dY2" " w13 +#define TT2 {gS g63,aC2(aB2 g63)LNG_ONLY(aB2 g63)qR"cmple_minma" dX3"<= " g33 +#define UT2 {gS q13,aC2(aB2 q13)LNG_ONLY(aB2 q13)qR"cmple_minma" dY3"<= " mS2 +#define WT2 dB1 mD2,aC2(aB2 mD2)LNG_ONLY(aB2 mD2)qR"cmple_mul_imm_neg",hC1 a51 +#define YT2 dB1 mE2,aC2(aB2 mE2)LNG_ONLY(aB2 mE2)qR"cmple_mul_imm_pos",dU1 a51 +#define SU2 dB1 aU2,aC2(aB2 aU2)LNG_ONLY(aB2 aU2)qR"cmple_mulmul_imm_neg",a31" " w13 +#define TU2 dB1 aV2,aC2(aB2 aV2)LNG_ONLY(aB2 aV2)qR"cmple_mulmul_imm_pos",d23 w13 +#define UU2 {g21 Cmple_pow_imm_negneg,aC2(aB2 Cmple_pow_imm_negneg)hP1 hV oT3 aK2 +#define WU2 {g21 Cmple_pow_imm_negpos,aC2(aB2 Cmple_pow_imm_negpos)hP1 hY oT3 aN2 +#define YU2 h32 Cmple_pow_imm_posneg,aC2(aB2 Cmple_pow_imm_posneg)hP1 d2 oT3 m52 +#define SV2 h32 Cmple_pow_imm_pospos,aC2(aB2 Cmple_pow_imm_pospos)hP1 d3 oT3 qQ3 +#define TV2 h32 Cmple_pow_imm_pospos_base,aC2(aB2 Cmple_pow_imm_pospos_base)hP1 m62"<= " wT +#define UV2 dB1 Cmple_powpow_imm_base,aC2(aB2 Cmple_powpow_imm_base)aI"cmple_" hH oT3 a7 +#define WV2 dB1 qW3,aC2(aB2 qW3)LNG_ONLY(aB2 qW3)qR"cmplt_add_imm",qX1 a61}, +#define YV2 h32 q23,aC2(aB2 q23)LNG_ONLY(aB2 q23)gN1"cmplt_add_reduce",dS oV3 h1}, +#define SW2 dB1 q33,aC2(aB2 q33)LNG_ONLY(aB2 q33)qR"cmplt_addadd_imm",dY2" " w23 +#define TW2 {gS g73,aC2(aB2 g73)LNG_ONLY(aB2 g73)qR"cmplt_minma" dX3"< " g33 +#define UW2 {gS q43,aC2(aB2 q43)LNG_ONLY(aB2 q43)qR"cmplt_minma" dY3"< " mS2 +#define WW2 dB1 mF2,aC2(aB2 mF2)LNG_ONLY(aB2 mF2)qR"cmplt_mul_imm_neg",hC1 a61}, +#define YW2 dB1 mG2,aC2(aB2 mG2)LNG_ONLY(aB2 mG2)qR"cmplt_mul_imm_pos",dU1 a61}, +#define SX2 dB1 aW2,aC2(aB2 aW2)LNG_ONLY(aB2 aW2)qR"cmplt_mulmul_imm_neg",a31" " w23 +#define TX2 dB1 aX2,aC2(aB2 aX2)LNG_ONLY(aB2 aX2)qR"cmplt_mulmul_imm_pos",d23 w23 +#define UX2 {g21 Cmplt_pow_imm_negneg,aC2(aB2 Cmplt_pow_imm_negneg)dZ1 hV oV3 aK2 +#define WX2 {g21 Cmplt_pow_imm_negpos,aC2(aB2 Cmplt_pow_imm_negpos)dZ1 hY oV3 aN2 +#define YX2 h32 Cmplt_pow_imm_posneg,aC2(aB2 Cmplt_pow_imm_posneg)dZ1 d2 oV3 m52 +#define SY2 h32 Cmplt_pow_imm_pospos,aC2(aB2 Cmplt_pow_imm_pospos)dZ1 d3 oV3 qQ3 +#define TY2 h32 Cmplt_pow_imm_pospos_base,aC2(aB2 Cmplt_pow_imm_pospos_base)dZ1 m62"< " wT +#define UY2 dB1 Cmplt_powpow_imm_base,aC2(aB2 Cmplt_powpow_imm_base)aI"cmplt_" hH oV3 a7 +#define WY2 dB1 qX3,aC2(aB2 qX3)LNG_ONLY(aB2 qX3)qR"cmpne_add_imm",qX1 dV1}, +#define YY2 h32 q53,aC2(aB2 q53)LNG_ONLY(aB2 q53)gN1"cmpne_add_reduce",dS dG2 h1}, +#define SZ2 dB1 q63,aC2(aB2 q63)LNG_ONLY(aB2 q63)qR"cmpne_addadd_imm",dY2 dG2 hX +#define TZ2 {gS g83,aC2(aB2 g83)LNG_ONLY(aB2 g83)qR"cmpne_minma" h12 gZ3 g33 +#define UZ2 {gS q73,aC2(aB2 q73)LNG_ONLY(aB2 q73)qR"cmpne_minma" h42 gZ3 mS2 +#define WZ2 dB1 mH2,aC2(aB2 mH2)LNG_ONLY(aB2 mH2)qR"cmpne_mul_imm_neg",hC1 dV1}, +#define YZ2 dB1 mI2,aC2(aB2 mI2)LNG_ONLY(aB2 mI2)qR"cmpne_mul_imm_pos",dU1 dV1}, +#define Sa2 dB1 aY2,aC2(aB2 aY2)LNG_ONLY(aB2 aY2)qR"cmpne_mulmul_imm_neg",a31 dG2 hX +#define Ta2 dB1 aZ2,aC2(aB2 aZ2)LNG_ONLY(aB2 aZ2)qR"cmpne_mulmul_imm_pos",wO"4)" dG2 hX +#define Ua2 {g21 Cmpne_pow_imm_negneg,aC2(aB2 Cmpne_pow_imm_negneg)o01 hV gZ3 aK2 +#define Wa2 {g21 Cmpne_pow_imm_negpos,aC2(aB2 Cmpne_pow_imm_negpos)o01 hY gZ3 aN2 +#define Ya2 h32 Cmpne_pow_imm_posneg,aC2(aB2 Cmpne_pow_imm_posneg)o01 d2 gZ3 m52 +#define Sb2 h32 Cmpne_pow_imm_pospos,aC2(aB2 Cmpne_pow_imm_pospos)o01 d3 gZ3 qQ3 +#define Tb2 h32 Cmpne_pow_imm_pospos_base,aC2(aB2 Cmpne_pow_imm_pospos_base)o01 m62"!= " wT +#define Ub2 dB1 Cmpne_powpow_imm_base,aC2(aB2 Cmpne_powpow_imm_base)aI"cmpne_" hH dG2 a7 +#define Wb2 dB1 qY3,aC2(aB2 qY3)LNG_ONLY(aB2 qY3)qR"cmpzz_add_imm" dT h52 a61 aE h52 oZ1 h52 a71 qX1 a81 h52 dV1 d7 qX1 q52 +#define Yb2 h32 q83,aC2(aB2 q83)LNG_ONLY(aB2 q83)gN1"cmpzz_add_reduce" dT" " dS oV3 h1 aE" " dS oT3 h1 aG" " dS" > " h1 aC dS dF2 h1 hD1" " dS dG2 h1 d7 dS" = " h1}, +#define Sc2 dB1 q93,aC2(aB2 q93)LNG_ONLY(aB2 q93)qR"cmpzz_addadd_imm" dT" " o6 q62" " o6 q92" " o6 qA2 dY2 dF2 dZ2" " dY2 oW1 dY2" =" gX3 +#define Tc2 {gS g93,aC2(aB2 g93)LNG_ONLY(aB2 g93)qR"cmpzz_minmax" dT d33"< " d43 aE d33"<= " d43 aG d33"> " d43 g1"0008 " h62" >= y,x,y" wI g11 gZ3"y,x,y" o42" 0x0020 " h62" = " g33 +#define Uc2 {gS qA3,aC2(aB2 qA3)LNG_ONLY(aB2 qA3)qR"cmpzz_minmax_rev" dT d33"< " gK3 aE d33"<= " gK3 aG d33"> " gK3 g1"0008 " h62" >= " gK3 hD1 g11 gZ3 gK3" + 0x0020 " h62" = " mS2 +#define Wc2 dB1 mJ2,aC2(aB2 mJ2)LNG_ONLY(aB2 mJ2)qR"cmpzz_mul_imm_neg" dT mJ1 a61 aE mJ1 oZ1 mJ1 a71 hC1 a81 mJ1 dV1 d7 hC1 q52 +#define Yc2 dB1 mK2,aC2(aB2 mK2)LNG_ONLY(aB2 mK2)qR"cmpzz_mul_imm_pos" dT mK1 a61 aE mK1 oZ1 mK1 a71 dU1 a81 mK1 dV1 d7 dU1 q52 +#define Sd2 dB1 m02,aC2(aB2 m02)LNG_ONLY(aB2 m02)qR"cmpzz_mulmul_imm_neg" dT qY1 q62 qY1 q92 qY1 qA2 a31 dF2 dZ2 qY1")" oW1 a31" =" gX3 +#define Td2 dB1 m12,aC2(aB2 m12)LNG_ONLY(aB2 m12)qR"cmpzz_mulmul_imm_pos" dT qZ1 q62 qZ1 q92 qZ1 qA2 wO"4)" dF2 dZ2 qZ1")" oW1 d23"=" gX3 +#define Ud2 {g21 Cmpzz_pow_imm_negneg,aC2(aB2 Cmpzz_pow_imm_negneg)q01"_imm_negneg" dT h11 oV3 gC3 aE h11 oT3 gC3 aG h11" > " gC3 aC gL",-3) >= -0.015625" wI h11 gZ3"-0.015625" wZ1",-3) = " aK2 +#define Wd2 {g21 Cmpzz_pow_imm_negpos,aC2(aB2 Cmpzz_pow_imm_negpos)q01"_imm_negpos" dT h21 oV3 hQ3 aE h21 oT3 hQ3 aG h21" > " hQ3 aC gL",-2) >= 0.0625" wI h21 gZ3"0.0625" wZ1",-2) = " aN2 +#define Yd2 h32 Cmpzz_pow_imm_posneg,aC2(aB2 Cmpzz_pow_imm_posneg)q01"_imm_posneg" dT d71 oV3 oD3 aE d71 oT3 oD3 aG d71" > " oD3 aC gL",3) >= -125" wI d71 gZ3"-125" wZ1",3) = " m52 +#define Se2 h32 Cmpzz_pow_imm_pospos,aC2(aB2 Cmpzz_pow_imm_pospos)q01"_imm_pospos" dT d81" < 25)" aE d81" <= 25)" aG d81" > 25)" aC gL",2) >= 25" wI d81 gZ3"25" wZ1",2) = " qQ3 +#define Te2 h32 Cmpzz_pow_imm_pospos_base,aC2(aB2 Cmpzz_pow_imm_pospos_base)q01"_imm_pospos_base" dT oU3"< " mW aE oU3"<= " mW aG oU3"> " mW aC qD3">= " mW hD1 oU3"!= " mW d7 qD3"= " wT +#define Ue2 dB1 Cmpzz_powpow_imm_base,aC2(aB2 Cmpzz_powpow_imm_base)aI"cmpzz_powpow_imm_base" dT wZ2 oV3 qS1 aE wZ2 oT3 qS1 aG wZ2" > " qS1 aC qB1 dF2 qS1 hD1 wZ2 dG2 qS1 d7 qB1" = " a7 +#define We2 {1,N(0.0,0.0)qJ N(1.0,0.0),q7 Eq0,aC2(aB2 Eq0)LNG_ONLY(aB2 Eq0)gN1"eq0","(x=if(" hQ2" + (if(" hR2"=" aN1 +#define Ye2 {1,N(0.0,0.0)qJ N(1.0,0.0),q7 Eq1,aC2(aB2 Eq1)LNG_ONLY(aB2 Eq1)gN1"eq1","(!x=if(" hS2}, +#define Sf2 {2,o4 Expexp_a,aC2(aB2 Expexp_a)aI oD2"p_a","exp(x*2 + y*3" gO2 +#define Tf2 {3,o4 Expexp_b,aC2(aB2 Expexp_b)aJ oD2"p_b",aR" * exp(y+z" gO2 +#define Uf2 {3,o4 Expexp_c,aC2(aB2 Expexp_c)aJ oD2"p_c","exp(x + y*z" gO2 +#define Wf2 dB oJ3,aC2(aB2 oJ3)LNG_ONLY(aB2 oJ3)gN1"ge0_abs",oL1" >= if(" hQ2 qT1 hR2 oT3 qJ3"<= if(" gC1 gD1 hR2" >= " gN3 +#define Yf2 dB oK3,aC2(aB2 oK3)LNG_ONLY(aB2 oK3)gN1"ge1_abs",oL1" >= if(" hS2 qT1 dQ3"<= " qJ3"<= if(" hN1 gD1 dQ3">= " gN3 +#define Sg2 {gS h73,aC2(aB2 h73)LNG_ONLY(aB2 h73)qR"ge_and_eq",o02 hX1 +#define Tg2 {gS h83,aC2(aB2 h83)LNG_ONLY(aB2 h83)qR"ge_and_le",o02 g51}, +#define Ug2 {gS h93,aC2(aB2 h93)LNG_ONLY(aB2 h93)qR"ge_and_ne",o02 hY1 +#define Wg2 {gS d53,aC2(aB2 d53)LNG_ONLY(aB2 d53)qR"ge_or_eq",o12 hX1 +#define Yg2 {gS d63,aC2(aB2 d63)LNG_ONLY(aB2 d63)qR"ge_or_le",o12 g51}, +#define Sh2 {gS d73,aC2(aB2 d73)LNG_ONLY(aB2 d73)qR"ge_or_ne",o12 hY1 +#define Th2 {1,N(-1.0,0.0)qJ N(0.25,0.0),q7 Gehalf,aC2(aB2 Gehalf)gR"gehalf","x>=if(1,0.5,0" gO2 +#define Uh2 dB oL3,aC2(aB2 oL3)LNG_ONLY(aB2 oL3)gN1"gt0_abs",oL1" > if(" hQ2 qT1 hR2 oV3 qJ3"< if(" gC1 gD1 hR2" > " gN3 +#define Wh2 dB oM3,aC2(aB2 oM3)LNG_ONLY(aB2 oM3)gN1"gt1_abs",oL1" > if(" hS2 qT1 dQ3"< " qJ3"< if(" hN1 gD1 dQ3"> " gN3 +#define Yh2 {gS hA3,aC2(aB2 hA3)LNG_ONLY(aB2 hA3)qR"gt_and_eq" mL1 hX1 +#define Si2 {gS hB3,aC2(aB2 hB3)LNG_ONLY(aB2 hB3)qR"gt_and_ge" mL1 mB}, +#define Ti2 {gS hC3,aC2(aB2 hC3)LNG_ONLY(aB2 hC3)qR"gt_and_le" mL1 g51}, +#define Ui2 {gS hD3,aC2(aB2 hD3)LNG_ONLY(aB2 hD3)qR"gt_and_ne" mL1 hY1 +#define Wi2 {gS d83,aC2(aB2 d83)LNG_ONLY(aB2 d83)qR"gt_or_eq" mM1 hX1 +#define Yi2 {gS d93,aC2(aB2 d93)LNG_ONLY(aB2 d93)qR"gt_or_ge" mM1 mB}, +#define Sj2 {gS dA3,aC2(aB2 dA3)LNG_ONLY(aB2 dA3)qR"gt_or_le" mM1 g51}, +#define Tj2 {gS dB3,aC2(aB2 dB3)LNG_ONLY(aB2 dB3)qR"gt_or_ne" mM1 hY1 +#define Uj2 {1,N(0.0,0.0)qJ N(1.0,0.0),q7 If10,aC2(aB2 If10)LNG_ONLY(aB2 If10)gN1"if10",o1",1,0" o42" 10*" o1",0,1)" o13" + 100*" o1">0,1,0" o42" 1000*" o1">0,0,1" gO2 +#define Wj2 gT qL3,aC2(aB2 qL3)LNG_ONLY(aB2 qL3)gQ2"tract_abs",dZ3"abs(x+2), abs(y+5))"}, +#define Yj2 gT qM3,aC2(aB2 qM3)LNG_ONLY(aB2 qM3)gQ2"tract_add" aX1"+2, y+" q12 +#define Sk2 gT qE3,aC2(aB2 qE3)LNG_ONLY(aB2 qE3)gQ2"tract_add1" aX1"+2, y" gO2 +#define Tk2 gT qF3,aC2(aB2 qF3)LNG_ONLY(aB2 qF3)gQ2"tract_add2",dZ3"y, y+2" gO2 +#define Uk2 gU mL2,aC2(aB2 mL2)LNG_ONLY(aB2 mL2)mN1"tract_and1_l" aX1"&z, y<1" gO2 +#define Wk2 gU m32,aC2(aB2 m32)LNG_ONLY(aB2 m32)mN1"tract_and1_nl" aX1"&z, z" gO2 +#define Yk2 gU mM2,aC2(aB2 mM2)LNG_ONLY(aB2 mM2)mN1"tract_and2_l",dZ3"y<1, y&z" gO2 +#define Sl2 gU m42,aC2(aB2 m42)LNG_ONLY(aB2 m42)mN1"tract_and2_nl",dZ3"z, y&z" gO2 +#define Tl2 gT qN3,aC2(aB2 qN3)LNG_ONLY(aB2 qN3)gQ2"tract_min",dZ3"min(y,2), min(y,5))"}, +#define Ul2 gT qO3,aC2(aB2 qO3)LNG_ONLY(aB2 qO3)gQ2"tract_mul" aX1"*2, y*" q12 +#define Wl2 gT qG3,aC2(aB2 qG3)LNG_ONLY(aB2 qG3)gQ2"tract_mul1" aX1"*2, y" gO2 +#define Yl2 gT qH3,aC2(aB2 qH3)LNG_ONLY(aB2 qH3)gQ2"tract_mul2",dZ3"y, y*2" gO2 +#define Sm2 gU qB3,aC2(aB2 qB3)LNG_ONLY(aB2 qB3)mN1"tract_or1_l",dZ3"y|z, y<1" gO2 +#define Tm2 gU mN2,aC2(aB2 mN2)LNG_ONLY(aB2 mN2)mN1"tract_or1_nl",dZ3"y|z, z" gO2 +#define Um2 gU qC3,aC2(aB2 qC3)LNG_ONLY(aB2 qC3)mN1"tract_or2_l",dZ3"y<1, y|z" gO2 +#define Wm2 gU mO2,aC2(aB2 mO2)LNG_ONLY(aB2 mO2)mN1"tract_or2_nl",dZ3"z, y|z" gO2 +#define Ym2 {2,N(-4.0,0.0),aI1,wK2 q7 If_extract_sin,aC2(aB2 If_extract_sin)aI dE1"tract_sin",dZ3"sin(y), " qR3 +#define Sn2 {2,h5 If_join_add,aC2(aB2 If_join_add)aI"if_join_add",hV2"+" o21 +#define Tn2 {1,N(3.0,0.0),N(5.0,0.0)qJ q7 gA3,aC2(aB2 gA3)LNG_ONLY(aB2 gA3)gN1"if_join_add2","x + 10 +" g11"<4, 3,4" gO2 +#define Un2 {2,h5 If_join_and,aC2(aB2 If_join_and)aI"if_join_and",hV2"&" o21 +#define Wn2 {2,h5 If_join_max,aC2(aB2 If_join_max)aI"if_join_max","max(" o1 dE", " dO3")))"}, +#define Yn2 {2,h5 If_join_min,aC2(aB2 If_join_min)aI"if_join_min","min(" o1 dE", " dO3")))"}, +#define So2 {2,h5 If_join_mul,aC2(aB2 If_join_mul)aI"if_join_mul",hV2"*" o21 +#define To2 {1,N(3.0,0.0),N(5.0,0.0)qJ q7 gB3,aC2(aB2 gB3)LNG_ONLY(aB2 gB3)gN1"if_join_mul2","x * 10 " h62"<4, 3,4" gO2 +#define Uo2 {2,h5 If_join_or,aC2(aB2 If_join_or)aI"if_join_or",o1 dE" | " dO3"))"}, +#define Wo2 dB Ifabs,aC2(aB2 Ifabs)LNG_ONLY(aB2 Ifabs)gN1"ifabs","1" qO1"< 0,-x" qP3 o13"10" qO1"<=0,-x" qP3" 100" qO1"> 0,-x" qP3" 1000" qO1">=0,-x" qP3"10000" qO1"< 0,x" h82 aM2" 100000" qO1"<=0,x" h82 aM2"1000000" qO1"> 0,x" h82" 10000000" qO1">=0,x,-" dX2 +#define Yo2 {3 hN Ifabsnot,aC2(aB2 Ifabsnot)aJ"ifabsnot","if(!(sin(x)+1.2), y,z" gO2 +#define Sp2 {3 hN Ifconst,aC2(aB2 Ifconst)aJ"ifconst","if(1, x,y" o42" if(0,z,y" gO2 +#define Tp2 {4,N(0.0,0.0)qJ N(1.0,0.0),q7 Ififconst,aC2(aB2 Ififconst)LNG_ONLY(0)"w," aP"ififconst","if(" o1",1,y),z,w" o42" if(if(w,z,0)," h22 +#define Up2 {4,wX oA3,aC2(aB2 oA3)LNG_ONLY(aB2 oA3)"b,d," qR"ifmerge",o1 gJ2"y,x,b" oV2"y,x,d)) + if(b,if(d,y,x)" gJ2"d,b," dX2 +#define Wp2 {4,wX dC3,aC2(aB2 dC3)LNG_ONLY(aB2 dC3)"a,b," qR"ifmerge2",o1 gJ2"y,a,b" oV2"b,a,b))"}, +#define Yp2 {4,wX hE3,aC2(aB2 hE3)LNG_ONLY(aB2 hE3)"a,b," qR"ifmerge2b",o1 gJ2"y,a,b" oV2"b,b,a))"}, +#define Sq2 {gS Ifnop,aC2(aB2 Ifnop)LNG_ONLY(aB2 Ifnop)qR"ifnop",o1",y,y" gO2 +#define Tq2 wB Ifnot,aC2(aB2 Ifnot)aJ"ifnot","if(!x, y,z" gO2 +#define Uq2 {dR L_abs,aC2(aB2 L_abs)LNG_ONLY(aB2 L_abs)qR"l_abs","(x+2) & " hY3 hB1 +#define Wq2 {dR dD3,aC2(aB2 dD3)LNG_ONLY(aB2 dD3)qR"l_mulabs","(x*abs(y))" hB1 +#define Yq2 {dR dE3,aC2(aB2 dE3)LNG_ONLY(aB2 dE3)qR"l_mulneg","(x*y*-5)" hB1 +#define Sr2 {dR dF3,aC2(aB2 dF3)LNG_ONLY(aB2 dF3)qR"l_notnot","(x+2) & !!x" hB1 +#define Tr2 {gS hF3,aC2(aB2 hF3)LNG_ONLY(aB2 hF3)qR"le_and_eq",g51" & " hX1 +#define Ur2 {gS hG3,aC2(aB2 hG3)LNG_ONLY(aB2 hG3)qR"le_and_ne",g51" & " hY1 +#define Wr2 {gS dG3,aC2(aB2 dG3)LNG_ONLY(aB2 dG3)qR"le_or_eq",g51" | " hX1 +#define Yr2 {gS dH3,aC2(aB2 dH3)LNG_ONLY(aB2 dH3)qR"le_or_ne",g51" | " hY1 +#define Ss2 {gS hH3,aC2(aB2 hH3)LNG_ONLY(aB2 hH3)qR"lt_and_eq" qE2 hX1 +#define Ts2 {gS hI3,aC2(aB2 hI3)LNG_ONLY(aB2 hI3)qR"lt_and_ge" qE2 mB}, +#define Us2 {gS hJ3,aC2(aB2 hJ3)LNG_ONLY(aB2 hJ3)qR"lt_and_gt" qE2"(x > y" gO2 +#define Ws2 {gS hK3,aC2(aB2 hK3)LNG_ONLY(aB2 hK3)qR"lt_and_le" qE2 g51}, +#define Ys2 {gS hL3,aC2(aB2 hL3)LNG_ONLY(aB2 hL3)qR"lt_and_ne" qE2 hY1 +#define St2 {gS dI3,aC2(aB2 dI3)LNG_ONLY(aB2 dI3)qR"lt_or_eq" hM3 hX1 +#define Tt2 {gS dJ3,aC2(aB2 dJ3)LNG_ONLY(aB2 dJ3)qR"lt_or_ge" hM3 mB}, +#define Ut2 {gS dK3,aC2(aB2 dK3)LNG_ONLY(aB2 dK3)qR"lt_or_gt" hM3"(x > y" gO2 +#define Wt2 {gS dL3,aC2(aB2 dL3)LNG_ONLY(aB2 dL3)qR"lt_or_le" hM3 g51}, +#define Yt2 {gS dM3,aC2(aB2 dM3)LNG_ONLY(aB2 dM3)qR"lt_or_ne" hM3 hY1 +#define Su2 {1,N(-1.0,0.0)qJ N(0.25,0.0),q7 Lthalf,aC2(aB2 Lthalf)gR"lthalf","x<if(1,0.5,0" gO2 +#define Tu2 gU gG3,aC2(aB2 gG3)LNG_ONLY(aB2 gG3)aP"mergemulabs","abs(x)*abs(y)*z"}, +#define Uu2 {3,N(0.0,0.0),aI1 qJ q7 gH3,aC2(aB2 gH3)LNG_ONLY(aB2 gH3)aP"mixedminmax","max(z,min(x,max(max(z,y),x)))" o33"10*min(z,max(x,min(y,x)))" o33"100*min(max(x,y),min(y,z)) + 1000*max(min(x,y),max(y,z))"}, +#define Wu2 {2 hN Muland2,aC2(aB2 Muland2)aI"muland2",hR3}, +#define Yu2 {3 hN Muland2plus,aC2(aB2 Muland2plus)aJ"muland2plus",hR3" * z"}, +#define Sv2 {3 hN Muland3,aC2(aB2 Muland3)aJ"muland3",hR3" * !!z"}, +#define Tv2 {2 hN Mulandlt,aC2(aB2 Mulandlt)aI"mulandlt",hC2" (y<0" gO2 +#define Uv2 {2,N(0.25,0.0)qJ N(0.25,0.0),q7 Mulimmlog,aC2(aB2 Mulimmlog)aI"mulimmlog","log(if(1,5,0)*x*" oS2 +#define Wv2 {2 hN Mulnor2,aC2(aB2 Mulnor2)aI"mulnor2",hS3}, +#define Yv2 {3 hN Mulnor2plus,aC2(aB2 Mulnor2plus)aJ"mulnor2plus",hS3" * z"}, +#define Sw2 {3 hN Mulnor3,aC2(aB2 Mulnor3)aJ"mulnor3",hS3" * !z"}, +#define Tw2 {gS Nand2,aC2(aB2 Nand2)LNG_ONLY(aB2 Nand2)qR"nand2",hN3}, +#define Uw2 wB hO3,aC2(aB2 hO3)LNG_ONLY(aB2 hO3)aP"nand2plus",hN3" | z"}, +#define Ww2 wB Nand3,aC2(aB2 Nand3)LNG_ONLY(aB2 Nand3)aP"nand3",hN3" | !z"}, +#define Yw2 dB Negceil,aC2(aB2 Negceil)gR"negceil","ceil(x*(abs(x)-abs(x)-1))"}, +#define Sx2 dB Negcos,aC2(aB2 Negcos)gR"negcos","cos" qC1 +#define Tx2 dB Negcosh,aC2(aB2 Negcosh)gR"negcosh","cosh" qC1 +#define Ux2 dB Negfloor,aC2(aB2 Negfloor)gR"negfloor","floor(x*(abs(x)-abs(x)-1))"}, +#define Wx2 dB Negsin,aC2(aB2 Negsin)gR"negsin","sin(x*if(1,-1,0))"}, +#define Yx2 dB Negsinh,aC2(aB2 Negsinh)gR"neg" gK2,gK2 qC1 +#define Sy2 {1,N(0.0,0.0)qJ N(1.0,0.0),q7 Neq0,aC2(aB2 Neq0)LNG_ONLY(aB2 Neq0)gN1"neq0","(x!=if(" hQ2" + (if(" hR2"!=" aN1 +#define Ty2 {1,N(0.0,0.0)qJ N(1.0,0.0),q7 Neq1,aC2(aB2 Neq1)LNG_ONLY(aB2 Neq1)gN1"neq1","(!x!=if(" hS2}, +#define Uy2 {gS Nor2,aC2(aB2 Nor2)LNG_ONLY(aB2 Nor2)qR"nor2",hP3}, +#define Wy2 wB dN3,aC2(aB2 dN3)LNG_ONLY(aB2 dN3)aP"nor2plus",hP3" & z"}, +#define Yy2 wB Nor3,aC2(aB2 Nor3)LNG_ONLY(aB2 Nor3)aP"nor3",hP3" & !z"}, +#define Sz2 {gS Not_eq,aC2(aB2 Not_eq)LNG_ONLY(aB2 Not_eq)qR"not_eq",o1" = " m22 +#define Tz2 {gS Not_ge,aC2(aB2 Not_ge)LNG_ONLY(aB2 Not_ge)qR"not_ge",o1" >= " m22 +#define Uz2 {gS Not_gt,aC2(aB2 Not_gt)LNG_ONLY(aB2 Not_gt)qR"not_gt",o1" > " m22 +#define Wz2 {gS Not_le,aC2(aB2 Not_le)LNG_ONLY(aB2 Not_le)qR"not_le",o1 oT3 m22 +#define Yz2 {gS Not_lt,aC2(aB2 Not_lt)LNG_ONLY(aB2 Not_lt)qR"not_lt",o1 oV3 m22 +#define S_2 {gS Not_ne,aC2(aB2 Not_ne)LNG_ONLY(aB2 Not_ne)qR"not_ne",o1 gZ3 m22 +#define T_2 gT Notnot,aC2(aB2 Notnot)LNG_ONLY(aB2 Notnot)qR"notnot","!!x + if(y, 1,0" gO2 +#define U_2 {1 hN Posnot,aC2(aB2 Posnot)gR"posnot","!(sin(x) + 1.2" gO2 +#define W_2 {1 hN Posnotnot,aC2(aB2 Posnotnot)gR"posnotnot","!!(sin(x) + 1.2" gO2 +#define Y_2 {1,N(0.25,0.0)qJ N(0.25,0.0),q7 Powimmaddimmlog,aC2(aB2 Powimmaddimmlog)w11"immaddimmlog","pow(5, log(x)+1" gO2 +#define S03 {1,N(0.25,0.0),mH1,N(0.25,0.0),q7 Powimmlog,aC2(aB2 Powimmlog)w11"immlog","pow(3, log(x)) + pow(5, log(x)*sin(x))"}, +#define T03 {hT Powmulimm_fnen,aC2(aB2 Powmulimm_fnen)qA g61"mulimm_fnen" h51"^(-8" gO2 +#define U03 {wC Powmulimm_fnep,aC2(aB2 Powmulimm_fnep)qA g61"mulimm_fnep" h51"^(4" gO2 +#define W03 {1,N(-3.0,0.0),N(-1.0,0.0),wK2 q7 Powmulimm_fnfn,aC2(aB2 Powmulimm_fnfn)w11"mulimm_fnfn","((-5.1)*x)^(-7.1" gO2 +#define Y03 {wC Powmulimm_fnfp,aC2(aB2 Powmulimm_fnfp)qA g61"mulimm_fnfp" h51"^7.1"}, +#define S13 {wC Powmulimm_fpfp,aC2(aB2 Powmulimm_fpfp)qA g61"mulimm_fpfp","(5.1*x*y)^7.1"}, +#define T13 {1 hN Sub1cos2,aC2(aB2 Sub1cos2)gR"sub1cos2","1-cos(x)^2"}, +#define U13 {1 hN Sub1sin2,aC2(aB2 Sub1sin2)gR"sub1sin2","1-" wQ1"^2"}, +#define W13 {1,N(-9.42477796076937971538793014983850865259,0.0),N(9.42477796076937971538793014983850865259,0.0),N(0.785398163397448309615660845819875721049292349,0.0),q7 Trig_modulo,aC2(aB2 Trig_modulo)gR"trig_modulo","cos(x+pi" q81"2/3" q81"5/2" q81"6/2" q81 hD2 o13" " hH1")" hW2"2/3)" hW2"5/2)" hW2"6/2)" hW2 hD2 o13" cos(x-pi)" g41"2/3)" g41"5/2)" g41"6/2)" g41 hD2" sin(x-pi)" h61"2/3)" h61"5/2)" h61"6/2)" h61"7/2" gO2 +#define Y13 {1,N(-3.0,0.0),N(3.0,0.0),N(0.25,0.0),q7 Trunc_from_if,aC2(aB2 Trunc_from_if)gR"trunc_from_if",o1">0, " gI3 qM2">=0, " gI3 qM2"<0, " gD3 qM2"<=0, " gD3 w21">0, " gD3 w21">=0, " gD3 w21"<0, " gI3" 10*" o1"<=0, floor(x),ceil" hF1 +#define S23 {1,N(-5.0,0.0),N(5.0,0.0)qJ q7 o93,aC2(aB2 o93)LNG_ONLY(aB2 o93)"x" q8"/xaddnot","!(x+if(1,4,4))"}, +#define T23 {1,N(-5.0,0.0),N(5.0,0.0)qJ q7 gT3,aC2(aB2 gT3)LNG_ONLY(aB2 gT3)"x" q8"/xaddnotnot","!!(x+if(1,4,4))"}, +#define N(x) (x) +#define P(x) N(x##.0) +namespace +cpp_01unit_operators{using +namespace +FUNCTIONPARSERTYPES;q3 +Add_cd(hX2 +Add_d(hX2 +Add_i(hX2 +Addsub_cd +qI1 +Addsub_d +qI1 +Addsub_i +qI1 +And_d(qH +oR1>=a01?fp_abs(y)>=a01:dR3 +And_i(qH +x +gM +y!=aS1:d22 +Cmpeq_cd(qH +x==oV1 +Cmpeq_d(qH +x==oV1 +Cmpeq_i(qH +x==oV1 +Cmpge_d +g52 +Cmpge_i +g52 +Cmpgt_d(qH +x>oV1 +Cmpgt_i(qH +x>oV1 +Cmple_d(qH +x<=oV1 +Cmple_i(qH +x<=oV1 +Cmplt_d(qH +x<oV1 +Cmplt_i(qH +x<oV1 +Cmpne_cd(qH +x!=oV1 +Cmpne_d(qH +x!=oV1 +Cmpne_i(qH +x!=oV1 +Div_d(qH(x-q0(0.25l))/oV1 +Div_i(qH +x/(y+q0(3l +qQ +Divmul_d +hM +x*y*x*x/z*(x-q0(0.25l +qQ +Divmul_i +hM +x*y*x*x/(z+d52*(x+q51 +Inv_d +aK1 +x;} +q3 +Inv_i +aK1 +x;} +q3 +Mod(qC,&z=vars[1 +mE1 +fmod(x,z);} +q3 +Mod_i(qC,&z=vars[1 +mE1 +x%(z+q0(3l +qQ +Mul_cd(qH +x*oV1 +Mul_d(qH +x*oV1 +Mul_i(qH +x*(y+q51 +Neg_cd(hY2 +Neg_d(hY2 +Neg_i(hY2 +Not_d(qK +oR1<oE1 +Not_i(qK +q0(x==dR3 +Notnot_d(qK +oR1>=oE1 +Notnot_i(qK +q0(x!=dR3 +Or_d(qH +oR1<a01?fp_abs(y)>=a01:q0(1l +qQ +Or_i(qH +x==aS1?y!=aS1:aL1;} +q3 +Sub_cd(qH +x-oV1 +Sub_d(qH +x-oV1 +Sub_i(qH +x-y;} +} +namespace +cpp_02unit_functions{using +namespace +FUNCTIONPARSERTYPES;q3 +Abs_cd(qK +std::abs(m1 +Abs_d(qK +x<aS1?-x:x;} +q3 +Abs_i(qK +x<aS1?-x:x;} +q3 +Acos(qK +acos(m1 +Acos_deg(aY1 +acos(x +qQ +Acosh(qK +qU1-1.0 +qQ +Acosh_deg(aY1 +qU1-1.0)qQ +Arg(qK +hQ +m1 +Asin(qK +asin(m1 +Asin_deg(aY1 +asin(x +qQ +Asinh(qK +qU1+1.0 +qQ +Asinh_deg(aY1 +qU1+1.0)qQ +Atan(qK +atan(m1 +Atan2(qH +atan2(x +oC3 +Atan2_deg(qH +r2d(atan2(x,y +qQ +Atan_deg(aY1 +atan(x +qQ +Atanh(qK +log((1.0+x)/(1.0-x))*0.5;} +q3 +Cbrt(qK +x<0.0?-exp(log(-x)/3.0):(x>0.0?exp(log(x)/3.0):0.0);} +q3 +Ceil(qK +ceil(m1 +Conj(qK +fp_conj(m1 +Cos(qK +cos(m1 +Cos_deg(qK +cos(oC1 +Cosh(qK +cosh(m1 +Cosh_deg(qK +cosh(oC1 +Exp(oW3 +m1 +Exp2(oW3 +x*fp_const_log2<q0>(qQ +Floor(qK +floor(m1 +Hypot(qH +sqrt(x*x+y*y);} +q3 +If_d +hM +fp_abs(x)>=a01?y:z;} +q3 +If_i +hM(x!=aS1)?y:z;} +q3 +Imag(qK +fp_imag(m1 +Int(qK +fp_floor(x+oE1 +Log(qK +log(m1 +Log2(qK +log(x)*1.4426950408889634073599246810018921374266;} +q3 +Log10(qK +log(x)*0.43429448190325182765112891891660508229;} +q3 +Log_cd(qK +std::log(m1 +Max(qH +x>y?x:oV1 +Min(qH +x<y?x:oV1 +Polar(qH +fp_polar(x +oC3 +Pow_neg(qH +pow(-x*0.25 +oC3 +Pow_pos(qH +pow(x +oC3 +Real(qK +fp_real(m1 +Sin(qK +sin(m1 +Sin_deg(qK +sin(oC1 +Sinh(qK +sinh(m1 +Sinh_deg(qK +sinh(oC1 +Sqrt(qK +sqrt(m1 +Sqrt_cd(qK +std::sqrt(m1 +Tan(qK +tan(m1 +Tan_deg(qK +tan(oC1 +Tanh(qK +tanh(m1 +Tanh_deg(qK +tanh(oC1 +Trunc(qK +x<0.0?ceil(x):floor(x);} +} +namespace +cpp_03unit_constants{using +namespace +FUNCTIONPARSERTYPES;q3 +E_d(oW3 +x*0.0+1.0);} +q3 +L2_d(qK +log(x*0.0+2.0);} +q3 +L10_d(qK +log(x*0.0+10.0);} +q3 +Pi_d(qK +atan2(x*0.0,-1.0);} +} +namespace +cpp_10optimizer_bytecode{using +namespace +FUNCTIONPARSERTYPES;q3 +Abs(qK(d52 +h81 +Abscos(qK +gX2 +gP1 +Abscosh(qK +hZ2 +gP1 +Abseq0 +gF1(gQ1+fp_equal(aS1,gP1 +Absevenconstpow(g12 +fp_abs(gZ1 +1506l +qQ +Absmulevenconstpow(qH +a42 +fp_abs(x)*y,q0(1506l +qQ +oF3 +gF1(gQ1+fp_equal(aS1,gP1 +Absneverneg(qK +fp_acos(m1 +Absnot(qB2 +gP1 +Absnot2(qB2 +fp_acos(x +qQ +Absnot3(qH +fp_not(fp_not(wY2 +x,y)qQ +Absnot4(qB2 +fp_not +wX2 +x)qQ +qZ3(qB2 +fp_notNot((x*x)qQ +o43(qC;q0 +b0[2 +mE1 +userDefFuncSub<q0>((b0[0]=(fp_greaterOrEq(fp_abs(x),wG),b0[1]=(fp_greaterOrEq(gQ1),b0 +qQ +o53(qC;q0 +b1[2 +mE1 +userDefFuncSub<q0>((b1[0]=(a22 +fp_abs(x),wG),b1[1]=(a22 +gQ1),b1 +qQ +Abssqr +oG2 +x;} +q3 +Absyxpow_neg(g12 +qP-4.0),1.5);} +q3 +Absyxpow_pos(g12 +qP +4.0),1.5);} +q3 +Acos(qK +acos(0.7)h81 +Acos_deg(aY1 +acos(0.7))h81 +Acosh(qK +mF +1.1-1.0))h81 +Acosh_deg(aY1 +mF +1.1-1.0)))h81 +Acoshcosh(qK +hZ2 +fp_acosh(x +qQ +Acoshsinh(qK +fp_sinh(fp_acosh(x +qQ +Add(qK +o82+q0(3l)h81 +Add0(qK +x+aS1 +h81 +Addexp +aR1 +x+q51 +Addexp2(qK +gY2 +x+q51 +And(qK +oD1 +gE1+oD1 +5l),aS1)+oD1 +0l),o82)+oD1 +0l),dR3 +Asin(qK +asin(0.7)h81 +Asin_deg(aY1 +asin(0.7))h81 +Asinh(qK +mF +1.1+1.0))h81 +Asinh_deg(aY1 +mF +1.1+1.0)))h81 +Asinhcosh(qK +hZ2 +fp_asinh(x +qQ +Asinhsinh(qK +fp_sinh(fp_asinh(x +qQ +Atan(qK +atan(oT2 +Atan2(qK +atan2(5.0,4.0)h81 +Atan2_deg(aY1 +atan2(5.0,4.0))h81 +Atan2tan(qH +qZ2 +wU1 +x,y +qQ +Atan_deg(aY1 +atan(1.1))h81 +Atanh(qK +log((1.0+0.7)/(1.0-0.7))*0.5+x;} +q3 +Cbrt(oW3 +log(1.1)/3.0)h81 +Ceil(qK +ceil(oT2 +Ceilneg(qK +wR2-m1 +Cmp_acos(oR +hK))qX +hK))qS +hK))qT +hK))qU +hK))qV +hK +qQ +Cmp_acos_outrange(oR +q11 +qX +q11 +qS +q11 +qT +q11 +qU +q11 +qV +fp_acos(gZ1 +2l +qQ +oG3(oR(wW2 +qX(wW2 +qS(wW2 +qT(wW2 +qU(wW2 +qV(q0(dJ +qQ +Cmp_asin(oR +hL))qX +hL))qS +hL))qT +hL))qU +hL))qV +hL +qQ +Cmp_asin_outrange(oR +q21 +qX +q21 +qS +q21 +qT +q21 +qU +q21 +qV +fp_asin(gZ1 +2l +qQ +Cmp_atan(oR +dQ2 +qX +dQ2 +qS +dQ2 +qT +dQ2 +qU +dQ2 +qV +oB +h91 +Cmp_exp(oR +oW +qX +oW +qS +oW +qT +oW +qU +oW +qV +qJ1 +fp_exp(h91 +Cmp_exp2(oR +dR2 +qX +dR2 +qS +dR2 +qT +dR2 +qU +dR2 +qV +oC +h91 +Cmp_exp2_neg(oR +w3))qX +w3))qS +w3))qT +w3))qU +w3))qV +w3 +qQ +Cmp_exp_neg(oR +qJ1-wG +qX +qJ1-wG +qS +qJ1-wG +qT +qJ1-wG +qU +qJ1-wG +qV +qJ1-q51 +Cmp_log2_nn(oR +hB +hQ1 +qX +hB +hQ1 +qS +hB +hQ1 +qT +hB +hQ1 +qU +hB +hQ1 +qV +hB +x),hT1 +Cmp_log2_np(oR +hB +x),hB +gE)qX +hB +x),hB +gE)qS +hB +x),hB +gE)qT +hB +x),hB +gE)qU +hB +x),hB +gE)qV +hB +x),hB +h91 +Cmp_log2_pn(oR +hB +qU2 +qX +hB +qU2 +qS +hB +qU2 +qT +hB +qU2 +qU +hB +qU2 +qV +hB +gB +hT1 +Cmp_log2_pp(oR +hB +gB +hB +gE)qX +hB +gB +hB +gE)qS +hB +gB +hB +gE)qT +hB +gB +hB +gE)qU +hB +gB +hB +gE)qV +hB +gB +hB +h91 +Cmp_log10_nn(oR +gP +hQ1 +qX +gP +hQ1 +qS +gP +hQ1 +qT +gP +hQ1 +qU +gP +hQ1 +qV +gP +x),hT1 +Cmp_log10_np(oR +gP +x +oZ3)qX +gP +x +oZ3)qS +gP +x +oZ3)qT +gP +x +oZ3)qU +gP +x +oZ3)qV +gP +x),gP +h91 +Cmp_log10_pn(oR +gP +qU2 +qX +gP +qU2 +qS +gP +qU2 +qT +gP +qU2 +qU +gP +qU2 +qV +gP +gB +hT1 +Cmp_log10_pp(oR +gP +gB +gP +wR1 +qX +gP +gB +gP +wR1 +qS +gP +gB +gP +wR1 +qT +gP +gB +gP +wR1 +qU +gP +gB +gP +wR1 +qV +gP +gB +gP +aL1 +qQ +Cmp_log_nn(oR +dS2 +qX +dS2 +qS +dS2 +qT +dS2 +qU +dS2 +qV +dT2 +hT1 +Cmp_log_np(oR +dT2 +dU2 +qX +dT2 +dU2 +qS +dT2 +dU2 +qT +dT2 +dU2 +qU +dT2 +dU2 +qV +dT2 +hQ +h91 +Cmp_log_pn(oR +hQ +qU2 +qX +hQ +qU2 +qS +hQ +qU2 +qT +hQ +qU2 +qU +hQ +qU2 +qV +hQ +gB +hT1 +Cmp_log_pp(oR +hQ +gB +dU2 +qX +hQ +gB +dU2 +qS +hQ +gB +dU2 +qT +hQ +gB +dU2 +qU +hQ +gB +dU2 +qV +hQ +gB +hQ +h91 +gV3(oR(x +d8))qX(x +d8))qS(x +d8))qT(x +d8))qU(x +d8))qV(x +d8 +qQ +gW3(oR(x +d9))qX(x +d9))qS(x +d9))qT(x +d9))qU(x +d9))qV(x +d9 +qQ +oH3(oR(dW2 +qX(dW2 +qS(dW2 +qT(dW2 +qU(dW2 +qV(-x),q51 +Cmp_powx_n_n(oR +hU1 +qX +hU1 +qS +hU1 +qT +hU1 +qU +hU1 +qV +oD +qN-hR +qQ +Cmp_powx_n_p(oR +oD +qN +hR +aZ +qX +oD +qN +hR +aZ +qS +oD +qN +hR +aZ +qT +oD +qN +hR +aZ +qU +oD +qN +hR +aZ +qV +oD +qN +hR/q0(3l)qQ +Cmp_powx_nn(oR +oD-wG +qX +oD-wG +qS +oD-wG +qT +oD-wG +qU +oD-wG +qV +oD-q51 +Cmp_powx_np(oR +oD +wG +qX +oD +wG +qS +oD +wG +qT +oD +wG +qU +oD +wG +qV +oD +q51 +Cmp_powx_p_n(oR +qN +qV2 +qX +qN +qV2 +qS +qN +qV2 +qT +qN +qV2 +qU +qN +qV2 +qV +qN +oE-hR +qQ +Cmp_powx_p_p(oR +qN +oE +hR +aZ +qX +qN +oE +hR +aZ +qS +qN +oE +hR +aZ +qT +qN +oE +hR +aZ +qU +qN +oE +hR +aZ +qV +qN +oE +hR/q0(3l)qQ +Cmp_powx_pn(oR +qN +qX2 +qX +qN +qX2 +qS +qN +qX2 +qT +qN +qX2 +qU +qN +qX2 +qV +qN +gC),-q51 +Cmp_powx_pp(oR +qN +gC),wG +qX +qN +gC),wG +qS +qN +gC),wG +qT +qN +gC),wG +qU +qN +gC),wG +qV +qN +gC),q51 +Cmp_powy_n_n(oR +qY2 +qX +qY2 +qS +qY2 +qT +qY2 +qU +qY2 +qV +qP-hZ +qQ +Cmp_powy_n_p(oR +qP-d0 +qX +qP-d0 +qS +qP-d0 +qT +qP-d0 +qU +qP-d0 +dS3 +qP +q0(6.1l)qQ +Cmp_powy_nn(oR +qP-g2-wG +qX +qP-g2-wG +qS +qP-g2-wG +qT +qP-g2-wG +qU +qP-g2-wG +dS3-q51 +Cmp_powy_np(oR +qP-g2 +wG +qX +qP-g2 +wG +qS +qP-g2 +wG +qT +qP-g2 +wG +qU +qP-g2 +wG +dS3 +q51 +Cmp_powy_p_n(oR +qP +hZ))qX +qP +hZ))qS +qP +hZ))qT +qP +hZ))qU +qP +hZ))qV +qP +hZ +qQ +Cmp_powy_p_p(oR +qP +d0 +qX +qP +d0 +qS +qP +d0 +qT +qP +d0 +qU +qP +d0 +qV +qP +g2 +qP +q0(6.1l)qQ +Cmp_powy_pn(oR +qP +g2-wG +qX +qP +g2-wG +qS +qP +g2-wG +qT +qP +g2-wG +qU +qP +g2-wG +qV +qP +g2-q51 +Cmp_powy_pp(oR +qP +g2 +wG +qX +qP +g2 +wG +qS +qP +g2 +wG +qT +qP +g2 +wG +qU +qP +g2 +wG +qV +qP +g2 +q51 +Cmp_sinh(oR +oF +gE)qX +oF +gE)qS +oF +gE)qT +oF +gE)qU +oF +gE)qV +oF +h91 +oI3(oR(q31 +qX(q31 +qS(q31 +qT(q31 +qU(q31 +qV(x*gZ1 +16l +qQ +gJ3(oR(x*x)dN1)qX(x*x)dN1)qS(x*x)dN1)qT(x*x)dN1)+-q0(16l)*fp_greaterOrEq((x*x)dN1)qV(x*x),-q0(16l +qQ +Cmp_tanh(oR +hO))qX +hO))qS +hO))qT +hO))qU +hO))qV +hO +qQ +Cmp_tanh_outrange(oR +q41 +qX +q41 +qS +q41 +qT +q41 +qU +q41 +qV +fp_tanh(gZ1 +2l +qQ +Cmpeq +gF1(q0(gE1+fp_equal(q0(4l),q51 +Cmpge +gW1 +q0(3l),o82)+x+dR1 +q0(8l),q51 +Cmpgt +oT1 +q0(3l),o82)+x +g62 +q0(8l),q51 +Cmple +gW1 +q0(gE1+dR1 +q0(4l),q0(8l +qQ +Cmplt +oT1 +q0(gE1;} +q3 +Cmpne(oU1 +q0(gE1+g32(q0(4l),q51 +Cos(qK +cos(oT2 +Cos_deg(qK +cos(d2r(1.1))h81 +Cosh(qK +cosh(oT2 +Cosh_deg(qK +cosh(d2r(1.1))h81 +Deg(qH +r2d(y)+r2d(x)+r2d(y)*q0(4l);} +q3 +Degxmul(aY1 +fp_acos(x))*wW1;} +q3 +Div(qK(o82/wG +h81 +Div1(qK +x/aL1 +h81 +Divxx(qK +x+x/x +h81 +gO3 +oG2 +q0(14l);} +q3 +Dupaddmulh(qK +x;} +q3 +Dupaddmulmul7(qH +y*x*q0(14l);} +q3 +Dupaddmulmulh(qH +y*x;} +q3 +h53(qC;q0 +b2[2 +mE1 +userDefFuncSub<q0>((b2[0]=(fp_min(x,x)),b2[1]=(w42 +x,x)),b2 +qQ +gP3(qC;q0 +b3[2 +mE1 +userDefFuncSub<q0>((b3[0]=(x +m51 +x)),b3[1]=(x+w42 +x,x)),b3 +qQ +gQ3(qC,&y +q32;q0 +b4[2 +mE1 +userDefFuncSub<q0>((b4[0]=(fp_min(y,x)),b4[1]=(w42 +y,x)),b4 +qQ +gR3(qK +x +d02 +Dupxpowmul +a72 +q51 +Eq0 +gF1(x,aS1)+fp_equal(aS1,m1 +Eq1 +gF1(fp_not(gZ1 +1l +qQ +Exp(oW3 +oT2 +Exp2(oW3 +1.1*0.693147180559945309417232121458176568075500134)h81 +Exp2div(qH +x/gY2 +y);} +q3 +Exp2log2(qK +hB +gY2 +x +qQ +Exp2xpow(g12 +gY2 +x),1506.0);} +q3 +Expdiv(qH +x/fp_exp(y);} +q3 +Explog(qK +hQ +fp_exp(x +qQ +Explog2(qK +x/fp_const_log2<q0>();} +q3 +Explog10(qK +x/fp_const_log10<q0>();} +q3 +Expxpow(g12 +qJ1 +1506.0);} +q3 +Floor(qK +floor(oT2 +Floorneg(qK +fp_floor(-m1 +oJ3(wM +fp_abs(dV +fp_abs(x))qS +fp_abs(gZ1 +0l +aJ1 +gP1 +Ge0_neg(wM +aD +dV +aD +x))qS +aD +gZ1 +0l +aJ1 +aD +x +qQ +Ge0_pos(wM +fp_acos(dV +fp_acos(x))qS +fp_acos(gZ1 +0l +aJ1 +fp_acos(x +qQ +oK3(wM +fp_abs(x +o5 +fp_abs(x))qS +fp_abs(gZ1 +dI1 +gP1 +Ge1_neg(wM +aD +x +o5 +aD +x))qS +aD +gZ1 +dI1 +aD +x +qQ +Ge1_pos(wM +fp_acos(x +o5 +fp_acos(x))qS +fp_acos(gZ1 +dI1 +fp_acos(x +qQ +Gehalf(qK +d1,oE1 +oL3(mX +gQ1 +aO1 +fp_abs(x))wD +gQ1 +aQ1 +gP1 +Gt0_neg(mX +aD +dT3 +aO1 +aD +x))wD +aD +dT3 +aQ1 +aD +x +qQ +Gt0_pos(mX +fp_acos(dT3 +aO1 +fp_acos(x))wD +fp_acos(dT3 +aQ1 +fp_acos(x +qQ +oM3(mX +fp_abs(oP3 +fp_abs(x))wD +fp_abs(oQ3 +gP1 +Gt1_neg(mX +aD +oP3 +aD +x))wD +aD +oQ3 +aD +x +qQ +Gt1_pos(mX +fp_acos(oP3 +fp_acos(x))wD +fp_acos(oQ3 +fp_acos(x +qQ +Gtminushalf(qK +oL,-oE1 +Hypot(qK +sqrt(5.0*5.0+4.0*4.0)h81 +Immsub(qK +x-o82;} +q3 +Int(qK +x+(((((gJ1 +1.1l))-gJ1 +1.6l)))-gJ1 +1.5l)))-gJ1-1.1l)))-gJ1-1.6l)))-gJ1-1.5l)qQ +Intceil(qK +fp_ceil +oX1 +Intfloor(qK +fp_floor +oX1 +Intint(qK +fp_int +oX1 +Inttrunc(qK +fp_trunc +oX1 +Invdiv(qH +y/(aL1/m1 +Invinv +aK1(aL1/m1 +Invmul(qH +y*(aL1/m1 +Leminushalf(qK +dX,-oE1 +Log(aP1 +h81 +Log2(aP1*1.4426950408889634073599246810018921374266+x;} +q3 +Log2exp1 +aR1 +hB +x +qQ +Log2exp2(qK +gY2 +hB +fp_acos(x)qQ +Log10(aP1*0.43429448190325182765112891891660508229+x;} +q3 +Logexp1 +aR1 +hQ +x +qQ +Logexp2 +aR1 +hQ +fp_acos(x)qQ +Logmul(qK +hQ +m9 +Logmul2(qK +hB +m9 +Logmul10(qK +gP +m9 +Lt0 +oT1 +fp_abs(x),x-x)-m2,x-m1 +Lthalf(qK +m2,oE1 +Max(qK +o82 +h81 +Min(qK +q0(4l)h81 +Mod(qK +fp_mod(o82,wG +h81 +Mul(qK(g02 +wG +h81 +Mul1 +oG2 +aL1 +h81 +Mul1b(qK((x*q0(0.2l))mV))h81 +Mul2(qK +x +h81 +Mul4(qH +y*(x*gE*wW1+(y*gE*wW1;} +q3 +Mul_zero(qH(x*y+aL1)+(aD +x)+aD +y))*hQ +x)*y*x*d22 +Mulminus1 +oG2-1.0;} +q3 +Mulneg(qK-(x +mV +qQ +dP3(qK +x/q0(4l)h81 +Neg(qK((-((5.0))))h81 +Negabs(qK +fp_abs(-m1 +Negadd(qH +x+(-y);} +q3 +Negceil(qK-wR2 +m1 +Negcos(qK +gX2-m1 +Negcosh(qK +hZ2-m1 +Negdiv(qK(-x)/o82;} +q3 +Negfloor(qK-fp_floor(m1 +Negmul(qK(-x)d02 +Negneg(qK-(-(-(-(-(-(x))))qQ +Negnot(qB2-m1 +Negsin(qK +aD-m1 +Negsinh(qK +fp_sinh(-m1 +Negsqr +oG2 +x;} +q3 +Negsub(qH +x-(-y);} +q3 +Negtan(qK +qZ2-m1 +Negtanh(qK +fp_tanh(-m1 +Neq0(qK(w8,aS1))+(g32(aS1,x +qQ +Neq1(oU1 +fp_not(gZ1 +1l +qQ +Not(qB2 +d52 +h81 +Not_eq(qH +x!=oV1 +Not_ge(qH +x<oV1 +Not_gt(qH +x<=oV1 +Not_le(qH +x>oV1 +Not_lt +g52 +Not_ne(qH +x==oV1 +Notnot(qK +fp_notNot(m1 +h63(qB2 +m1 +gS3(qB2 +m1 +Or(qK +wS1 +gE1+wS1 +5l),aS1)+wS1 +0l),o82)+wS1 +0l),dR3 +Pow_neg(qK +pow(-0.25,4.0)h81 +Pow_pos(qK +pow(1.1,7.1)h81 +Powdiv(qH +x/qP +y);} +q3 +Powhalf +a72 +oE1 +Powinv(qH +aL1/qP +y);} +q3 +Powminushalf +a72-oE1 +Powminusone +a72-q0(1.0l +qQ +Powminusthird +a72(q0(-1.0l)/q0(3.0l)qQ +Powthird +a72(m6/q0(3.0l)qQ +Powxpow(g12 +qP +1.7),1506.0);} +q3 +Rad(qH +d2r(y)+d2r(x)+d2r(x)*q0(4l);} +q3 +Radxmul(qK +gX2 +d2r(x+x+x+x +qQ +Rsqrt(qK +1.0/q22 +m1 +Sin(qK +sin(oT2 +Sin_deg(qK +sin(d2r(1.1))h81 +Sincos_cci(qK +mI)+aL1/gX2 +m1 +Sincos_cic +aK1 +mI)+gX2 +m1 +Sincos_sc +dK2 +gX2 +m1 +Sincos_sci +dK2 +aL1/gX2 +m1 +Sincos_sis +aK1 +aD +x)+aD +m1 +Sincos_ssi +dK2 +aL1/aD +m1 +Sincos_tan(qK +qZ2 +m1 +Sincos_tit +aK1 +qZ2 +x)+qZ2 +m1 +Sincos_tti(qK +qZ2 +x)+aL1/qZ2 +m1 +Sinh(qK +sinh(oT2 +Sinh_deg(qK +sinh(d2r(1.1))h81 +o63(qK(-x)*x;} +q3 +o73 +oG2(-m1 +Sqr_xx +oG2 +x;} +q3 +hZ3(qH +y*-x*x;} +q3 +d03(qH +y*x*-x;} +q3 +o83(qH +y*x*x;} +q3 +Sqreq0 +gF1(x*x,aS1)+fp_equal(aS1,x*m1 +Sqrlog(qK +hQ +x*m1 +Sqrlog2(qK +hB +x*m1 +Sqrlog10(qK +gP +x*m1 +oN3 +gF1(x*x,aS1)+fp_equal(aS1,x*m1 +Sqrsqrt(qK +q22 +x*m1 +Sqrt(qK +sqrt(oT2 +Sqrtsqr1(g12 +q22 +gZ1 +2l +qQ +Sqrtsqr2(g12 +q22 +fp_acos(x)),q0(2l +qQ +Sqrxpow(qK +wE,2402.0);} +q3 +Sqrxpow_nonint(qK +wE,3.5);} +q3 +Sub(qK +o82-q0(3l)h81 +Sub0(qK +x-aS1 +h81 +Subxx(qK +x+(x-x)+x+(aL1-x+m1 +Tan(qK +tan(oT2 +Tan_deg(qK +tan(d2r(1.1))h81 +Tanh(qK +tanh(oT2 +Tanh_deg(qK +tanh(d2r(1.1))h81 +Trunc(qK +1.0+x;} +q3 +o93(qB2 +x+q51 +gT3(qK +gR1+q51 +Xmulrad(qK +gX2 +d2r(x +g92 +qQ +Xmulsinhneg(qK-fp_sinh(x +mV +qQ +Xmulsinneg(qK-aD +x +mV +qQ +Xmultanhneg(qK-fp_tanh(x +mV +qQ +Xmultanneg(qK-qZ2 +x +mV +qQ +Xsqryfsqrhypot(qK +fp_hypot(dT2 +hB +x +qQ +Xsqrysqrhypot(qH +fp_hypot(dT2 +y);} +q3 +Xxdup(qK +x-x;} +q3 +Xxfdup(qK +x-x;} +q3 +d13(qH +y*fp_abs(x)*fp_abs(m1 +Ypowxpow(g12 +qP +38.5),5.0);} +} +namespace +cpp_11optimizer_constaddmul{using +namespace +FUNCTIONPARSERTYPES;q3 +t1 +g8(aL1/a)d02 +t2 +g8 +g02 +a;} +q3 +t3 +g8 +o82/a;} +q3 +t4(hE(a +mV))*b;} +q3 +t5(hE(a +mV))/b;} +q3 +t6(hE(aL1/a)*b;} +q3 +t7(hE(aL1/a)/b;} +q3 +t8(hE +dO1*(mL +mV +qQ +t9(hE +dO1/(mL +mV +qQ +t10(hE +mL*(o82/a);} +q3 +t11(hE +mL/(q0(50l)/a);} +q3 +t12 +g8(-a)dA1 +t13(hE +o82+(a*b);} +q3 +t14(hE +o82-(a*b);} +q3 +t15(hE(a+o82)+mL;} +q3 +t16(hE(a+o82)-mL;} +q3 +t17(hE(-a)+mL;} +q3 +t18(hE(-a)-mL;} +q3 +t19(hE +b+(dO1+q0(5l +qQ +t20(hE +b-(dO1+q0(5l +qQ +t21(hE +mL+(o82 +oR3 +t22(hE +mL-(o82 +oR3 +t23(hV1*b +w03 +t24(hV1 +mV)w03 +t25(hV1 +mV))*a;} +q3 +t26(hE(dO1/b +w03 +t27(hE(dO1/b)*a;} +q3 +t28(hE((-a)/b)d02 +t29 +g22/b)*a;} +q3 +t30(w4 +b=vars[0 +mE1(aT1/b)d02 +t31(hE +b*(aT1/oR3 +t32 +g22-b)-a;} +q3 +t33 +g22-b)+a;} +q3 +t34(hE((a+aT1)-b)dA1 +t35(hE((-a)-b)dA1 +t36 +g8(aT1-fp_abs(a +mY +5l);} +q3 +t37(hE((aT1-b)+a)dA1 +t38(hE +a22(g02 +b+dO1),aS1)*aL1 +g62(mL),aS1)*wW1;} +q3 +t39 +g8(a+aT1)d02 +t40(hE(b+(a*aT1))d02 +t41(hE(b-(a*aT1))d02 +t42 +g8(a+q0(7l +mY +5l);} +q3 +t43 +g8(a*aT1)mV);} +} +namespace +cpp_20optimizer_optimizations{using +namespace +FUNCTIONPARSERTYPES;q3 +Abscos(qK +gX2 +fp_abs(x))+fp_abs(m1 +Abscosh(qK +hZ2 +fp_abs(x))+fp_abs(m1 +Abseq0 +gF1(gQ1+fp_equal(aS1,gP1 +oF3 +gF1(gQ1+fp_equal(aS1,gP1 +o43(qC;q0 +b5[2 +mE1 +userDefFuncSub<q0>((b5[0]=(fp_greaterOrEq(fp_abs(x),wG),b5[1]=(fp_greaterOrEq(gQ1),b5 +qQ +o53(qC;q0 +b6[2 +mE1 +userDefFuncSub<q0>((b6[0]=(a22 +fp_abs(x),wG),b6[1]=(a22 +gQ1),b6 +qQ +Acoscos(qK +gX2 +fp_acos(x +qQ +Acoshsinh(qK +fp_sinh(fp_acosh(x +qQ +gF3(qH +g02(q0(4l)+x+y);} +q3 +Addlog(qH +hQ +x)+hQ +y);} +q3 +qK3(qH +g02(q0(4l)*y+m1 +g03(qH-o82+(g02 +x*y);} +q3 +g13(qH-g02 +y+(g02 +m1 +Addsin2cos2(g12 +aD +x),gE+a42 +mI),q0(2l +qQ +Asinhcosh(qK +hZ2 +fp_asinh(x +qQ +Asinsin(qK +aD +fp_asin(x +qQ +qS3 +gS2 +mS +d5 +mP2 +gF1 +gA +qQ +mQ2 +gS2 +dL2 +g23(qH((gG1 +mZ +mR2(qH((gG1 +aU1 +m72 +gS2*-m0 +m82 +gS2*m0 +aO2 +gS2 +o52 +aP2 +gS2*q0 +h6 +Cmpeq_pow_imm_negneg +gF1(d6 +qQ +Cmpeq_pow_imm_negpos +gF1(oI +Cmpeq_pow_imm_posneg +gF1(x*mT +Cmpeq_pow_imm_pospos +gF1(x*x +gK1 +Cmpeq_pow_imm_pospos_base +gF1(q0(dG +Cmpeq_powpow_imm_base(qH +fp_equal(dK +qT3(qH +d1 +mS +d5 +mT2(qK +fp_greaterOrEq +gA +qQ +mU2(qH +d1 +dL2 +g43(qH((d1 +mZ +mV2(qH((d1 +aU1 +m92(qH +d1*-m0 +mA2(qH +d1*m0 +aQ2(qH +d1 +o52 +aR2(qH +d1*q0 +h6 +Cmpge_pow_imm_negneg(wM +d6 +qQ +Cmpge_pow_imm_negpos(wM +oI +Cmpge_pow_imm_posneg(qK +d1*mT +Cmpge_pow_imm_pospos(qK +d1*x +gK1 +Cmpge_pow_imm_pospos_base(wM +q0(dG +Cmpge_powpow_imm_base(qH +fp_greaterOrEq(dK +qU3 +w52 +mS +d5 +mW2(qK +fp_greater +gA +qQ +mX2 +w52 +dL2 +g53(qH((oL +mZ +mY2(qH((oL +aU1 +mB2 +w52*-m0 +mC2 +w52*m0 +aS2 +w52 +o52 +aT2 +w52*q0 +h6 +Cmpgt_pow_imm_negneg(mX +d6 +qQ +Cmpgt_pow_imm_negpos(mX +oI +Cmpgt_pow_imm_posneg(qK +oL*mT +Cmpgt_pow_imm_pospos(qK +oL*x +gK1 +Cmpgt_pow_imm_pospos_base(mX +q0(dG +Cmpgt_powpow_imm_base(qH +fp_greater(dK +qV3(qH +dX +mS +d5 +mZ2(qK +fp_lessOrEq +gA +qQ +q03(qH +dX +dL2 +g63(qH((dX +mZ +q13(qH((dX +aU1 +mD2(qH +dX*-m0 +mE2(qH +dX*m0 +aU2(qH +dX +o52 +aV2(qH +dX*q0 +h6 +Cmple_pow_imm_negneg +gW1 +d6 +qQ +Cmple_pow_imm_negpos +gW1 +oI +Cmple_pow_imm_posneg(qK +dX*mT +Cmple_pow_imm_pospos(qK +dX*x +gK1 +Cmple_pow_imm_pospos_base +gW1 +q0(dG +Cmple_powpow_imm_base(qH +dR1 +dK +qW3(qH +m2 +mS +d5 +q23(qK +fp_less +gA +qQ +q33(qH +m2 +dL2 +g73(qH((m2 +mZ +q43(qH((m2 +aU1 +mF2(qH +m2*-m0 +mG2(qH +m2*m0 +aW2(qH +m2 +o52 +aX2(qH +m2*q0 +h6 +Cmplt_pow_imm_negneg +oT1 +d6 +qQ +Cmplt_pow_imm_negpos +oT1 +oI +Cmplt_pow_imm_posneg(qK +m2*mT +Cmplt_pow_imm_pospos(qK +m2*x +gK1 +Cmplt_pow_imm_pospos_base +oT1 +q0(dG +Cmplt_powpow_imm_base(qH +a22 +dK +qX3(qH +w8 +mS +d5 +q53(qK +g32 +gA +qQ +q63(qH +w8 +dL2 +g83(qH((w8 +mZ +q73(qH((w8 +aU1 +mH2(qH +w8*-m0 +mI2(qH +w8*m0 +aY2(qH +w8 +o52 +aZ2(qH +w8*q0 +h6 +Cmpne_pow_imm_negneg(oU1 +d6 +qQ +Cmpne_pow_imm_negpos(oU1 +oI +Cmpne_pow_imm_posneg(qK +w8*mT +Cmpne_pow_imm_pospos(qK +w8*x +gK1 +Cmpne_pow_imm_pospos_base(oU1 +q0(dG +Cmpne_powpow_imm_base(qH +g32(dK +qY3 +oA2(hF +gX1 +gO +gX1 +gW +gX1 +gH(x +mS +y,q0(6l))gZ +x +mS +y,q0(6l))h0(x +mS +d5 +q83(qK +q0(hF +gA +mY +gO +gA +mY +gW +gA +mY +gH +gA +mY +g42 +g32 +gA))h0 +gA +qQ +q93(aW1 +x+q0 +m01+q0 +m11+q0 +m31+q0 +oW2+q0 +oX2 +dL2 +g93 +oA2(0x0001l)*((m2 +aV1 +0x0002l)*((dX +aV1 +0x0004l)*((oL +aV1 +0x0008l)*((d1 +aV1 +g42((w8 +aV1 +0x0020l)*((gG1 +mZ +qA3 +oA2(0x0001l)*((m2 +gY1 +0x0002l)*((dX +gY1 +0x0004l)*((oL +gY1 +0x0008l)*((d1 +gY1 +g42((w8 +gY1 +0x0020l)*((gG1 +aU1 +mJ2(aW1 +oG1 +gO(oG1 +gW(oG1 +gH(x*-q0(dZ +gZ +x*-q0(dZ +h0(x*-m0 +mK2(aW1 +x*q0(dZ +oS3 +x*q0(dZ +dM2 +x*q0(dZ +dN2 +x*q0(dZ +gZ +x*q0(dZ +h0(x*m0 +m02(aW1 +x*-q0 +m01*-q0 +m11*-q0 +m31*-q0 +oW2*-q0 +oX2 +o52 +m12(aW1 +x*q0 +m01*q0 +m11*q0 +m31*q0 +oW2*q0 +oX2*q0 +h6 +Cmpzz_pow_imm_negneg(dP1 +d6 +mY +gO(d6 +mY +gW(d6 +mY +gH(d6))gZ +d6))h0(d6 +qQ +Cmpzz_pow_imm_negpos(dP1 +wN +oS3 +wN +dM2 +wN +dN2 +wN +gZ +wN +h0(oI +Cmpzz_pow_imm_posneg(dP1 +x +m3 +oS3 +x +m3 +dM2 +x +m3 +dN2 +x +m3 +gZ +x +m3 +h0(x*mT +Cmpzz_pow_imm_pospos(dP1 +x*x +m41 +gO(x*x +m41 +gW(x*x +m41 +gH(x*x,q0(25l))gZ +x*x,q0(25l))h0(x*x +gK1 +Cmpzz_pow_imm_pospos_base(dP1 +q0(oM +oS3 +q0(oM +dM2 +q0(oM +dN2 +q0(oM +gZ +q0(oM +h0(q0(dG +Cmpzz_powpow_imm_base(aW1 +oX +oS3 +oX +dM2 +oX +dN2 +oX +gZ +oX +h0(dK +Eq0 +gF1(x,aS1)+fp_equal(aS1,m1 +Eq1 +gF1(fp_not(gZ1 +1l +qQ +Expexp_a(qH +fp_exp(x*wW1+y*q0(3l +qQ +Expexp_b +hM +gH2*fp_exp(y+z);} +q3 +Expexp_c +hM +fp_exp(x+y*z);} +q3 +oJ3(wM +fp_abs(dV +fp_abs(x))qS +fp_abs(gZ1 +0l +aJ1 +gP1 +oK3(wM +fp_abs(x +o5 +fp_abs(x))qS +fp_abs(gZ1 +dI1 +gP1 +h73(qH +x==oV1 +h83(qH +x==oV1 +h93(qH +x>oV1 +d53 +g52 +d63 +m21 +d73 +m21 +Gehalf(qK +d1,oE1 +oL3(mX +gQ1 +aO1 +fp_abs(x))wD +gQ1 +aQ1 +gP1 +oM3(mX +fp_abs(oP3 +fp_abs(x))wD +fp_abs(oQ3 +gP1 +hA3(oY +oY2 +hB3(qH +x>oV1 +hC3(oY +oY2 +hD3(qH +x>oV1 +d83 +g52 +d93 +g52 +dA3 +m21 +dB3(qH +x!=oV1 +If10(qK +gR1)+mC1*fp_not(x)+q0(100l)*oL,q0(0l +mY +1000l)*dX,dR3 +qL3(qH +fp_abs(o0(x+gE:(y+o82 +qQ +qM3(qH +y+(o0 +wW1:q0(5l +qQ +qE3(qH +o0(y+gE:oV1 +qF3(qH +o0 +y:(y+q0(2l +qQ +mL2(qY +dD1:qA1 +qQ +m32(qY +dD1:z;} +q3 +mM2(qY +qA1)):dD1;} +q3 +m42(qY +z:dD1;} +q3 +If_extract_div(qH +y/(o0 +x:q0(2l +qQ +qN3(qH +fp_min(y,(o0 +wW1:o82 +qQ +qO3(qH +y*(o0 +wW1:q0(5l +qQ +qG3(qH +o0(y*gE:oV1 +qH3(qH +o0 +y:(y*q0(2l +qQ +qB3(qY +oH1:qA1 +qQ +mN2(qY +oH1:z;} +q3 +qC3(qY +qA1)):oH1;} +q3 +mO2(qY +z:oH1;} +q3 +If_extract_sin(qH +aD +o0 +y:m1 +If_join_add(oV(aD +y)+qK1(gW2+aL1)+aD +y+aL1 +qQ +gA3(qK +x+(m2,wG +gM +q0(13l):q0(14l +qQ +If_join_and(oV +fp_and +wO2 +fp_and +dY +If_join_max(oV +w42 +aD +y),qK1 +fp_max +dY +If_join_min(oV +fp_min +wO2 +fp_min +dY +If_join_mul(oV(aD +y)*qK1(gW2+aL1)*aD +y+aL1 +qQ +gB3 +oG2(m2,wG +gM +q0(30l):q0(40l +qQ +If_join_or(oV +fp_or +wO2 +fp_or +dY +Ifabs(qK +q0(1l +mQ +m2 +aF +10l +mQ +dX +aF +100l +mQ +oL +aF +1000l +mQ +d1 +aF +10000l +mQ +m2 +mM +100000l +mQ +dX +mM +1000000l +mQ +oL +mM +10000000l +mQ +d1,aS1)gM +x:-x +qQ +Ifabsnot +hM +fp_truth(aD +x)+q0(1.2l))gM +z:oV1 +Ifconst +hM +x+y+z*d22 +Ififconst(w4 +w +oI1 +x +q32,&y=vars[2],&z=vars[3 +mE1 +aL +o0 +aL1:y)gM +z:w)+aL +fp_truth(w)gM +z:aS1)gM +x:y);} +q3 +oA3(w4 +b +oI1 +d +q32 +hG +x:b):aL +y)gM +x:d))+aL +b)gM +aL +d)gM +y:x):aL +d)gM +b:x +qQ +dC3(w4 +a +oI1 +b +q32 +hG +a:b):aL +b)gM +a:b +qQ +hE3(w4 +a +oI1 +b +q32 +hG +a:b):aL +b)gM +b:a +qQ +Ifnop(qH +x*aS1+oV1 +Ifnot(qY +z:oV1 +L_abs +wY1+wW1,wY2 +fp_abs(x),y+h91 +dD3 +wY1*y*fp_abs(y),y+q0(2l +qQ +dE3 +wY1*y*-o82,y+q0(2l +qQ +dF3 +wY1+wW1,wY2 +gR1),y+h91 +hF3(qH +x==oV1 +hG3(qH +x<oV1 +dG3(qH +x<=oV1 +dH3 +m21 +hH3(oY +oY2 +hI3(oY +oY2 +hJ3(oY +oY2 +hK3(qH +x<oV1 +hL3(qH +x<oV1 +dI3(qH +x<=oV1 +dJ3 +m21 +dK3(qH +x!=oV1 +dL3(qH +x<=oV1 +dM3(qH +x!=oV1 +Lthalf(qK +m2,oE1 +gG3 +hM +fp_abs(x)*fp_abs(y)*z;} +q3 +gH3 +hM +w42 +z +oZ2 +x +w02 +w42 +z,y),x)mY +10l)*fp_min(z +w02 +x +oZ2 +y,x)mY +100l)*fp_min(w42 +x,y)oZ2 +y,z +mY +1000l)*w42 +fp_min(x,y)w02 +y,z +qQ +Muland2(qH +aA;} +q3 +Muland2plus +hM +aA*z;} +q3 +Muland3 +hM +aA*fp_notNot(z);} +q3 +Mulandlt(qH +gR1)*q0(a22 +y,aS1 +qQ +Mulimmlog(qH +hQ +g02 +x*y);} +q3 +Mulnor2(qH +q71;} +q3 +Mulnor2plus +hM +q71*z;} +q3 +Mulnor3 +hM +q71*d12);} +q3 +Nand2(qH +aM +qQ +hO3 +hM +fp_or(aM)),z);} +q3 +Nand3 +hM +fp_or(aM)),d12 +qQ +Negceil(qK +wR2-m1 +Negcos(qK +gX2-m1 +Negcosh(qK +hZ2-m1 +Negfloor(qK +fp_floor(-m1 +Negsin(qK +aD-m1 +Negsinh(qK +fp_sinh(-m1 +Neq0(qK(w8,aS1))+(g32(aS1,x +qQ +Neq1(oU1 +fp_not(gZ1 +1l +qQ +Nor2(qH +aB +qQ +dN3 +hM +wY2 +aB)),z);} +q3 +Nor3 +hM +wY2 +aB)),d12 +qQ +Not_eq(qH +x!=oV1 +Not_ge(qH +x<oV1 +Not_gt(qH +x<=oV1 +Not_le(qH +x>oV1 +Not_lt +g52 +Not_ne(qH +x==oV1 +Notnot(qH +fp_truth(x)+fp_truth(y);} +q3 +Posnot(qB2 +aD +x)+q0(1.2l +qQ +Posnotnot(qK +fp_notNot(aD +x)+q0(1.2l +qQ +Powimmaddimmlog(qK +qN +5l),hQ +x)+q0(1l +qQ +Powimmlog(qK +qN +3l),hQ +x))+qN +5l),hQ +x)*aD +x +qQ +Powmulimm_fnen +g72(q0(-8l)qQ +Powmulimm_fnep +g72(q0(4l)qQ +Powmulimm_fnfn(qK +a6,(q0(-7.1l)qQ +Powmulimm_fnfp +g72 +q0(7.1l +qQ +Powmulimm_fpfp(qH +qN +5.1l)*x*y,q0(7.1l +qQ +Sub1cos2(qK +aL1-a42 +mI),q0(2l +qQ +Sub1sin2(qK +aL1-a42 +aD +gZ1 +2l +qQ +Trig_modulo(qK +mI+gF)+mI+gF +w12 +mI+gF +mV)/gE+mI+gF +w22 +mI+gF*w62 +aD +x+gF)g82 +wW1 +wT1 +aD +x+gF +mV)/gE +g82 +q0 +dV2 +g82 +w62 +mI-gF)+mI-gF +w12 +mI-gF +mV)/gE+mI-gF +w22 +mI-gF*w62 +w32)+w32 +w12 +w32 +mV)/gE+w32 +w22 +w32*aT1/q0(2l +qQ +Trunc_from_if(qK +fp_trunc(x)*q0(4l)+q0(40l)*(x>aS1?wR2 +x):fp_floor(x +qQ +o93(qB2 +x+q51 +gT3(qK +gR1+wG;} +} +namespace +cpp_50regressions{using +namespace +FUNCTIONPARSERTYPES;q3 +t1(qK +x+w42 +aS1,m61-2l),aS1 +qQ +t2(qK +fp_min(x +oZ2 +aL1,x +qQ +t3(qC;q0 +b7[2 +mE1 +userDefFuncSub<q0>((b7[0]=(wY2 +fp_not(x),gR1))),b7[1]=(fp_or(fp_not(x),gR1))),b7 +qQ +t4(qC,&y +q32;q0 +b9[2 +mE1 +userDefFuncSub<q0>((b9[0]=(fp_not(x-y)),b9[1]=(gR1-y)),b9 +qQ +t5(qC;q0 +b11[2 +mE1 +userDefFuncSub<q0>((b11[0]=(aD +x)+aL1/aD +x)),b11[1]=(mI)),b11 +qQ +t6(qC;q0 +b13[2 +mE1 +userDefFuncSub<q0>((b13[0]=(fp_not(x+wG),b13[1]=(gR1+d52),b13 +qQ +t7(qK +x-x;} +q3 +t8(qH +wU1-x,-y)+mC1*wU1-x,y)+q0(20l)*wU1 +x,-y)+q0(30l)*wU1 +x +oC3 +t9a +oG2 +d22 +t9b(hE(a-b)*d22 +t9c(hE(a-b)*d22 +t9d(hE +a*b*d22 +t10 +aK1 +fp_abs(x)<aL1;} +q3 +t11 +aR1 +x/q0(5e+25l +qQ +t36(qK-(x<aS1?x:-x)+-(x<o82?wW1:q0(3l +qQ +t42(qH +q22 +x*x)+q0(1.5l)*(a42 +y*y,q0(0.25l)))+fp_hypot(x +oC3 +t51(qK +hQ-m1 +t57(qK +hZ2 +fp_asinh(x +qQ +t59(qH +hZ2 +x*x)+fp_tanh(y*y);} +q3 +t60(qC,&y +q32;q0 +b14[1];q0 +b15[2 +mE1 +fp_or(fp_or(wX1 +b14[0]=(x),b14)),userDefFuncSub<q0>((b15[0]=(x),b15[1]=(y),b15))),userDefFuncValue<q0>((0)qQ +t61 +hM +g02 +x*y+-g02 +z;} +} +namespace +cpp_99misc{using +namespace +FUNCTIONPARSERTYPES;q3 +t1 +oG2 +q0(4l)/wW1+(aL1+(wW1+d52)+x*x+x+(m6+d42+q0(3.0l)*q0(4.0l)+q0(5.0l)*q0(6.0l)*q0(7.0l)-q0(8.0l)*q0(9.0l +qQ +t2(qK +wW1*x+aD +x)/q0(.5l)+wW1-aD +x)*aD +m1 +t3 +hM +wY2 +gG1,y),fp_equal(y,x))+m6+d42-q0(3.1l)*q0(4e2l)/q0(.5l)+x*x+y*y+z*z+wY2 +x,x)+fp_or(y +oC3 +t4(qH(((((x-y)-(((y)*gE-d52))*wG)+aD +x)*gW2)-mI)*aD +y);} +q3 +t5(w4 +__A5_x08 +oI1 +o__5_0AB_=vars[1 +mE1 +a42 +__A5_x08,o__5_0AB_);} +q3 +t7(qK +mI)*aD +aL1-x)*(aL1-mI/gE*aD +x +mV)qQ +t8(qH +wU1 +x,y)+(x>y?x:y);} +q3 +t9 +hM +q0(1.5l)+x*y-d42+q0(4.0l)/q0(8.0l)+z+z+z+z+x/(y*z);} +q3 +t10 +hM +aL1+aD +gX2 +w42 +aL1+wW1+q0(3l)mS +o82,x+y+z)mY +2l);} +q3 +t11 +hM(-x-x)+y+hQ +qN +1.1l),z +qQ +t12(qK +m6/hQ +qN +10.0l),m6/hQ +x)qQ +t13(qH +qP +d52*qP +wG+a42 +y,d52*a42 +y,q0(5l +qQ +t14 +oG2 +gF+aD +wW1*gF)+q0(CONST);} +q3 +t15(qH +qP +y)/hQ +y)+hQ +x)/hQ +y)+hQ +qP +y +qQ +t16(qH +x<aS1?(y<aS1?x+y:x-y):(y>aS1?x*y:x+wW1*y);} +q3 +t17(qC,&y +q32;q0 +b18[1];q0 +b19[2];q0 +b20[1];q0 +b21[2 +mE1 +wX1 +b18[0]=(x),b18))+userDefFuncSub<q0>((b19[0]=(x),b19[1]=(y),b19))+wX1 +b20[0]=(y),b20))+userDefFuncSub<q0>((b21[0]=(y+aL1),b21[1]=(x-gE,b21))-aL1;} +q3 +t18(qH-(-(-(-o82)))*-qP-a42 +y,-h91 +t19(qH +m2,y)+mC1*dX,y)+q0(100l)*oL,y)+q0(1000l)*d1,y)+q0(10000l)*gG1,y)+q0(100000l)*w8,y)+wY2 +x,y)*wW1+fp_or(x,y)*q0(20l)+fp_not(x)*q0(200l)+fp_truth(x)*q0(2000l)+q0(4l)*fp_not(wY2 +m2,y),m2,d52 +mY +40l)oX3 +fp_not(oL,y)),oL,q0(3l)qQ +t20(qH +wY2 +fp_not<q0>(x!=y),fp_not(x))+fp_truth(y);} +q3 +t21(qC;q0 +b26[1 +mE1 +wX1 +b26[0]=(x),b26))+userDefFuncValue<q0>((0))-o82;} +q3 +t22(qH(q0(3.5l)*gE+mC1*(x*d52-(aD +y)*gE+q0(100l)*((x*gE-(y*d52)*wW1+q0(5.0l)/(wW1*gE+qN +1.1l),x*gE+qN +1.1l)*wW1,x*q0(2l +qQ +t23(qK(x/(wW1*fp_acos(q0(0.0l))))*q0(180l);} +q3 +t24(qK(fp_min(x +oZ2 +aL1,x))m51 +wR1/wW1 +m51 +aL1)*q0(3l)+w42 +aS1,m61-2l),aS1 +qQ +t25(w4 +a +oI1 +b +q32,&c=vars[2 +mE1 +a42 +a,a42 +b,c))+a42 +a,-gE*(-a42 +b,gE)+(-a42 +b,-c +qQ +t26_deg(qK +aD +d2r(x))+gX2 +d2r(x*q0(1.5l)))+r2d(fp_asin(x/q0(110.0l)))+r2d +wX2 +x/q0(120.0l)qQ +t27(qH +fp_abs(x)+fp_acos(x)+fp_asin(x)+fp_atan(x)+wU1 +x,y)+wR2 +x)+mI)+hZ2 +x)+m6/qZ2 +x)+m6/aD +x)+qP +y);} +q3 +t28(qH +gH2+fp_floor(x)+fp_int(x)+hQ +x)+gP +x)+w42 +x,y)m51 +y)+aL1/mI)+aD +x)+fp_sinh(x)+q22 +x)+qZ2 +x)+fp_tanh(x)+wR2 +y)+fp_trunc(y);} +q3 +t29(qH +x-y*aL1;} +q3 +t30(qH +x-y*aL1+fp_mod(x,y)+x/a42 +y,o92 +qN +2l),d52+fp_mod(o82,d52+qP +a42 +y,aS1))+qP +oE1 +t31 +hM +x-(y*(y*(y*-wR1*aL1)+hQ +x*m81),y))-hQ +qP +y))+m81 +oF1)+qN +10.0l +oF1/hQ +y+q0(6l))*hQ +z+q0(6l))/hQ +q0(10.0l)))-m81 +oF1*y)-qN +5.0l),hQ +x+aT1)/hQ +q0(5.0l)))+m91 +d52*m91 +gE/m91 +q51 +t32 +hM +x+y/y-m61 +3l),wG-x-m71 +4l),d52+m71 +3l),wG-m61 +4l),q0(3l +mY +0l)+(z*aL1)+(x-wW1+gE+(x*a01*gE+y*aS1+fp_min(fp_min(m61 +4.0l),x),m6)oZ2 +x +oZ2 +fp_min(y,q0(4.0l)),z)))+w42 +w42 +m71 +4.0l),x),m6)wO1 +w42 +y,q0(4.0l)),z)))+(fp_abs(aL1)+fp_acos(m6)+fp_asin(m6)+fp_atan(m6)+wR2 +o92 +gX2 +q0(d32 +hZ2 +q0(d32 +fp_floor(o92 +hQ +m6)+aD +q0(d32 +fp_sinh(q0(d32 +qZ2 +m6)+fp_tanh(m6)+wU1 +m6,m6))+(x-(y-z))+(x+y)+(x*y)+w42 +x +wO1 +x +w02 +x,x))))*-m6+(z-z)+aL1/aD +x/h01 +gW2/h01 +qZ2 +z/o82)+gP +aL1/qZ2 +z/h01 +aD +y/h01 +mI/o82))+hQ +q0(30l)+x)*hQ +q0(40l)+y)/hQ +q0(50l)+z)+aD +x/q0(57.295779513082320877l))+fp_asin(x/mC1)*q0(57.295779513082320877l)+fp_floor(-x)+aL1/wR2 +x)+w81 +5l)*q0(0.2l))+(-x+-x+-x+-x+-x+-m1 +t33(qH +aD +w81 +10l)-x*x+y*y))+gX2 +w81 +15l)-x*x-y*y))+aD +x*x+y*y);} +q3 +t34(w4 +t +oI1 +rvar0 +q32,&rvar1=vars[2],&rvar2=vars[3 +mE1 +rvar1+rvar2*rvar0-t;} +q3 +t35(w4 +wY +oI1 +A_very_long_variable_name_2 +q32,&Yet_a_third_very_long_variable_name=vars[2 +mE1 +wY-A_very_long_variable_name_2+Yet_a_third_very_long_variable_name*wY;} +q3 +t37(qK +o82+q0(7.5l)*q0(8l)/q0(3l)-qN +2l),wG*wW1+fp_mod(aT1,gE +mS +x;} +q3 +t38 +hM +fp_asinh(x)+q0(1.5l)*fp_acosh(y+q0(3l +mY +2.5l)*fp_atanh(z);} +q3 +t39 +hM +aD +x+aM1)-mI+aD +y*q0(1.5l)))+z*z*z*aD +z*z*z-x*x-y*y)-aM1*aD +x+aM1)+x*y*z+x*y*q0(2.5l)+x*y*z*mI)+x*y*mI)+x*z*mI)+y*z*q0(2.5l)+(x*y*z*mI)-x*y*z-y*mI)-x*z*y+x*y+x*z-mI)*m1 +t40 +hM(o2*(o2+wW1*(o2-x*y*(o2+x*(o2;} +q3 +t41 +hM +x*q0(3l)+x*y+x*z+x*aD +y*z)-qR1 +q0(4l)+qR1 +x+qR1 +y+qR1 +z;} +q3 +t43(qK +hQ +x*x)+fp_abs(fp_exp(fp_abs(x)+aL1 +qQ +t44(qK +wE +w9 +8l +mY +1.1l)*wE*x +w9 +7l +mY +1.2l +dU3 +w9 +6l +mY +1.3l +dU3*x +w9 +5l +mY +1.4l)*wE +mU +w9 +6l +mY +1.5l)oH2 +w9 +4l +mY +1.6l)oH2*x +w9 +3l +mY +1.7l)oH2*x*x,aL1/gE+q0(1.8l)*(q22 +a42 +fp_abs(-q22 +x)),d52 +qQ +t45(qK +wE +w9 +7l +mY +1.1l +dU3 +w9 +5l +mY +1.2l)*wE +mU +w9 +3l +qQ +t46(qH +fp_abs(fp_floor +wX2 +x)+wG)+q0(1.1l)*fp_abs(fp_floor +wX2 +y)+q0(1.5l)))g62 +fp_acos(x),wX2 +y)-mC1 +mY +1.2l)*m71-4l),fp_acos(x +mY +1.3l)*m61 +9l),fp_acos(x)-q0(9l +qQ +t47 +oA2(1.25l)*(gH2+fp_exp(-x +mY +1.5l)*(fp_exp(y)-fp_exp(-y +mY +1.75l)*((gI2+gH2)/gE+d42*((gI2-gH2)/gE+q0(2.25l)*(hZ2 +y)+fp_sinh(y +qQ +t48(qK +fp_sinh((hQ +x)/o82+aL1)mV +mY +1.2l)*hZ2(hQ +x)/hQ +gE+aL1)*dU2+fp_not(fp_or +aL +x),fp_not(x/wG +qQ +t49(qK +wU1 +aS1,x)+qN-4l)*(x-q0(100l)),q0(3.3l +qQ +t50(qH +fp_or(m2,y),a22 +y,x +mY +2l)wV1 +m2,y),a22 +y,x +mY +4l +qW2 +dR1 +y,x +mY +8l)wV1 +m2,mB1 +16l)oX3 +m2,mB1 +32l +qW2 +d1,y +mY +64l)oX3 +dX,y),d1,y +mY +128l)wV1 +w8,y),gG1,y +mY +256l)wV1 +w8,mB1 +512l +qW2 +gG1,y +qQ +t52(qK +x+(m6+d42+q0(3.0l)+q0(4.0l)-q0(5.0l)-q0(6.0l)-q0(7.0l)-q0(8.0l))/q0(3.0l)+q0(4.0l)*(m6+aD +d42)+gX2 +q0(4.0l)*q0(5.0l)+q0(6.0l))/d42)+gX2 +a01)*qZ2 +q0(0.6l)+q0(0.2l))-q0(1.1l)/hQ +q0(2.1l))*w81 +3.3l))+qN +2l),q0(3l +qQ +t53 +wY1,y)+q0(4l)oX3 +fp_int(x/mC1),fp_int(y/mC1 +mY +8l)*((-gV1-x)))+(gV1-fp_not(y)))mY +16l)*(-x+fp_not(y +qQ +t54(qH +m2,y)+dX,y)+oL,y)+d1,y)+gG1,y)+w8,y)+wY2 +x,y)+fp_or(x,y)+fp_not(x)+fp_truth(x)+fp_not(wY2 +m2,y),m2,d52))+fp_or(fp_not(oL,y)),oL,q0(3l)qQ +t55(qH +a22 +qP +q0(1.2l)),aS1)g62 +a42 +y,q0(2.5l)),aS1)qX +x*x,q0(0l +mY +3l)*a22 +a42 +y,d52,aS1)wD +qP +wG,dR3 +t56(qK +fp_mod(q0(1.75e21l),m1 +t58(qH +a22-x,d52+oL*-aL1,o82)+m2*-q0(3l),mC1)+m2*-q0(3l),y*aT1)+m2*q0(4l),y*aT1)+m2*q0(6l),y*-d52 +g62-x,q0(11l))g62 +o82,-y);} +q3 +t59 +oT1 +mI),aD +x))+(mI)-aD +x))+((fp_sinh(x)-hZ2 +x))-(fp_sinh(x)/hZ2 +x)mY +q0(1l +qQ +I1 +hM +aL1+wW1+q0(3l)-q0(4l)mV)*q0(6l)/q0(3l)+mC1/wW1-q0(9l)%wW1+(x+y-q0(11l)*x+z/mC1+x/(z+q0(31l)qQ +I2 +hM((fp_abs(x*y)<q0(20l))||(((x+y)>q0(30l))&&(z>o82)))?fp_min(x,wW1*y):w42 +y,z*q0(2l +qQ +I3 +hM(x+y)+wW1*(x-z)+q0(3l)*(x*y)+q0(4l)*(y/z)+g02 +fp_mod(x,z)+q0(6l)*(x<y)+aT1*(x<=z)+q0(8l)*(x>wW1*z)+q0(9l)*(y>=q0(3l)*z)+mC1*(x+y!=z)+q0(11l)*(q0(100l)+x)+q0(12l)*(q0(101l)-y)+q0(13l)*(q0(102l)*z)+q0(14l)*(q0(103l)/x);} +} +#define Value_t double +#undef Value_t +#undef N +#undef P +#ifdef FP_TEST_WANT_COMPLEX_DOUBLE_TYPE +#define N(x,y) (q0(x,y)) +#define Value_t std::complex<double> +namespace +cpp_02unit_functions +wH2 +Cos_cd(qK +cos +hX3 +Sin_cd(qK +sin(x);} +} +template<>const +wI2 +RegressionTests<q0>::Tests[]={W02 +Y02 +S12 +T12 +U12 +W12 +Y12 +S22 +T22 +U22 +W22 +Y22 +S32 +T32 +U32 +W32 +Y32 +S42 +T42 +U42 +W42 +Y42 +S52 +T52 +U52 +W52 +Y52 +S62{1,N(-dV3,+200.0),N(dV3,-200.0),N(5.0,-0.025)dP +Cos_cd +qF"/cos_cd" +,"cos(x)" +} +,T62 +U62 +W62 +Y62 +S72 +T72 +U72{1,N(-dV3,+200.0),N(dV3,-200.0),N(5.0,-0.025)dP +Sin_cd +qF"/sin_cd" +,wQ1} +,W72 +Y72 +S82 +T82 +U82 +W82 +Y82 +S92 +T92 +U92 +W92 +Y92 +SA2 +TA2 +UA2 +WA2 +YA2 +SB2 +TB2 +UB2 +WB2 +YB2 +SC2 +TC2 +UC2 +WC2 +YC2 +SD2 +TD2 +UD2 +WD2 +YD2 +SE2 +TE2 +UE2 +WE2 +YE2 +SF2 +TF2 +UF2 +WF2 +YF2 +SG2 +TG2 +UG2 +WG2 +YG2 +SH2 +TH2 +UH2 +WH2 +YH2 +SI2 +TI2 +UI2 +WI2 +YI2 +SJ2 +TJ2 +UJ2 +WJ2 +YJ2 +SK2 +TK2 +UK2 +WK2 +YK2 +SL2 +TL2 +UL2 +WL2 +YL2 +SM2 +TM2 +UM2 +WM2 +YM2 +SN2 +TN2 +UN2 +WN2 +YN2 +SO2 +TO2 +UO2 +WO2 +YO2 +SP2 +TP2 +UP2 +WP2 +YP2 +SQ2 +TQ2 +UQ2 +WQ2 +YQ2 +SR2 +TR2 +UR2 +WR2 +YR2 +SS2 +TS2 +US2 +WS2 +YS2 +ST2 +TT2 +UT2 +WT2 +YT2 +SU2 +TU2 +UU2 +WU2 +YU2 +SV2 +TV2 +UV2 +WV2 +YV2 +SW2 +TW2 +UW2 +WW2 +YW2 +SX2 +TX2 +UX2 +WX2 +YX2 +SY2 +TY2 +UY2 +WY2 +YY2 +SZ2 +TZ2 +UZ2 +WZ2 +YZ2 +Sa2 +Ta2 +Ua2 +Wa2 +Ya2 +Sb2 +Tb2 +Ub2 +Wb2 +Yb2 +Sc2 +Tc2 +Uc2 +Wc2 +Yc2 +Sd2 +Td2 +Ud2 +Wd2 +Yd2 +Se2 +Te2 +Ue2 +We2 +Ye2 +Sf2 +Tf2 +Uf2 +Wf2 +Yf2 +Sg2 +Tg2 +Ug2 +Wg2 +Yg2 +Sh2 +Th2 +Uh2 +Wh2 +Yh2 +Si2 +Ti2 +Ui2 +Wi2 +Yi2 +Sj2 +Tj2 +Uj2 +Wj2 +Yj2 +Sk2 +Tk2 +Uk2 +Wk2 +Yk2 +Sl2 +Tl2 +Ul2 +Wl2 +Yl2 +Sm2 +Tm2 +Um2 +Wm2 +Ym2 +Sn2 +Tn2 +Un2 +Wn2 +Yn2 +So2 +To2 +Uo2 +Wo2 +Yo2 +Sp2 +Tp2 +Up2 +Wp2 +Yp2 +Sq2 +Tq2 +Uq2 +Wq2 +Yq2 +Sr2 +Tr2 +Ur2 +Wr2 +Yr2 +Ss2 +Ts2 +Us2 +Ws2 +Ys2 +St2 +Tt2 +Ut2 +Wt2 +Yt2 +Su2 +Tu2 +Uu2 +Wu2 +Yu2 +Sv2 +Tv2 +Uv2 +Wv2 +Yv2 +Sw2 +Tw2 +Uw2 +Ww2 +Yw2 +Sx2 +Tx2 +Ux2 +Wx2 +Yx2 +Sy2 +Ty2 +Uy2 +Wy2 +Yy2 +Sz2 +Tz2 +Uz2 +Wz2 +Yz2 +S_2 +T_2 +U_2 +W_2 +Y_2 +S03 +T03 +U03 +W03 +Y03 +S13 +T13 +U13 +W13 +Y13 +S23 +T23 +wI2()} +; +#undef Value_t +#undef N +#endif /*FP_TEST_WANT_COMPLEX_DOUBLE_TYPE */ +#ifdef FP_TEST_WANT_COMPLEX_FLOAT_TYPE +#define N(x,y) (q0(APP(x,f),APP(y,f))) +#define Value_t std::complex<float> +namespace +cpp_02unit_functions +wH2 +Cos_cf(qK +cos +hX3 +Sin_cf(qK +sin(x);} +} +template<>const +wI2 +RegressionTests<q0>::Tests[]={W02 +Y02 +S12 +T12 +U12 +W12 +Y12 +S22 +T22 +U22 +W22 +Y22 +S32 +T32 +U32 +W32 +Y32 +S42 +T42 +U42 +W42 +Y42 +S52 +T52 +U52 +W52 +Y52 +S62{1,N(-40.0,+0.5),N(40.0,-0.5),N(0.1,-0.00125)dP +Cos_cf +qF"/cos_cf" +,"cos(x)" +} +,T62 +W62 +Y62 +S72 +T72 +U72{1,N(-40.0,+0.5),N(40.0,-0.5),N(0.1,-0.00125)dP +Sin_cf +qF"/sin_cf" +,wQ1} +,W72 +UG2 +WG2 +WH2 +YH2 +SI2 +TI2 +UI2 +WI2 +YI2 +SJ2 +TJ2 +UJ2 +WJ2 +YJ2 +SK2 +TK2 +UK2 +WK2 +YK2 +SL2 +TL2 +UL2 +WL2 +YL2 +SM2 +TM2 +UM2 +WM2 +YM2 +SN2 +TN2 +UN2 +WN2 +YN2 +SO2 +TO2 +UO2 +WO2 +YO2 +SP2 +TP2 +UP2 +WP2 +YP2 +SQ2 +TQ2 +UQ2 +WQ2 +YQ2 +SR2 +TR2 +UR2 +WR2 +YR2 +SS2 +TS2 +US2 +WS2 +YS2 +ST2 +TT2 +UT2 +WT2 +YT2 +SU2 +TU2 +UU2 +WU2 +YU2 +SV2 +TV2 +UV2 +WV2 +YV2 +SW2 +TW2 +UW2 +WW2 +YW2 +SX2 +TX2 +UX2 +WX2 +YX2 +SY2 +TY2 +UY2 +WY2 +YY2 +SZ2 +TZ2 +UZ2 +WZ2 +YZ2 +Sa2 +Ta2 +Ua2 +Wa2 +Ya2 +Sb2 +Tb2 +Ub2 +Wb2 +Yb2 +Sc2 +Tc2 +Uc2 +Wc2 +Yc2 +Sd2 +Td2 +Ud2 +Wd2 +Yd2 +Se2 +Te2 +Ue2 +We2 +Ye2 +Sf2 +Tf2 +Uf2 +Wf2 +Yf2 +Sg2 +Tg2 +Ug2 +Wg2 +Yg2 +Sh2 +Th2 +Uh2 +Wh2 +Yh2 +Si2 +Ti2 +Ui2 +Wi2 +Yi2 +Sj2 +Tj2 +Uj2 +Wj2 +Yj2 +Sk2 +Tk2 +Uk2 +Wk2 +Yk2 +Sl2 +Tl2 +Ul2 +Wl2 +Yl2 +Sm2 +Tm2 +Um2 +Wm2 +Ym2 +Sn2 +Tn2 +Un2 +Wn2 +Yn2 +So2 +To2 +Uo2 +Wo2 +Yo2 +Sp2 +Tp2 +Up2 +Wp2 +Yp2 +Sq2 +Tq2 +Uq2 +Wq2 +Yq2 +Sr2 +Tr2 +Ur2 +Wr2 +Yr2 +Ss2 +Ts2 +Us2 +Ws2 +Ys2 +St2 +Tt2 +Ut2 +Wt2 +Yt2 +Su2 +Tu2 +Uu2 +Wu2 +Yu2 +Sv2 +Tv2 +Uv2 +Wv2 +Yv2 +Sw2 +Tw2 +Uw2 +Ww2 +Yw2 +Sx2 +Tx2 +Ux2 +Wx2 +Yx2 +Sy2 +Ty2 +Uy2 +Wy2 +Yy2 +Sz2 +Tz2 +Uz2 +Wz2 +Yz2 +S_2 +T_2 +U_2 +W_2 +Y_2 +S03 +T03 +U03 +W03 +Y03 +S13 +T13 +U13 +W13 +Y13 +S23 +T23 +wI2()} +; +#undef Value_t +#undef N +#endif /*FP_TEST_WANT_COMPLEX_FLOAT_TYPE */ +#ifdef FP_TEST_WANT_COMPLEX_LONG_DOUBLE_TYPE +#define N(x,y) (q0(APP(x,l),APP(y,l))) +#define Value_t std::complex<long double> +template<>const +wI2 +RegressionTests<q0>::Tests[]={Y02 +T12 +U12 +Y12 +S22 +T22 +U22 +W22 +S32 +T32 +U32 +W32 +S42 +U42 +W42 +Y42 +S52 +U52 +Y52 +S62 +T62 +Y62 +S72 +T72 +U72 +UG2 +WG2 +WH2 +YH2 +SI2 +TI2 +UI2 +WI2 +YI2 +SJ2 +TJ2 +UJ2 +WJ2 +YJ2 +SK2 +TK2 +UK2 +WK2 +YK2 +SL2 +TL2 +UL2 +WL2 +YL2 +SM2 +TM2 +UM2 +WM2 +YM2 +SN2 +TN2 +UN2 +WN2 +YN2 +SO2 +TO2 +UO2 +WO2 +YO2 +SP2 +TP2 +UP2 +WP2 +YP2 +SQ2 +TQ2 +UQ2 +WQ2 +YQ2 +SR2 +TR2 +UR2 +WR2 +YR2 +SS2 +TS2 +US2 +WS2 +YS2 +ST2 +TT2 +UT2 +WT2 +YT2 +SU2 +TU2 +UU2 +WU2 +YU2 +SV2 +TV2 +UV2 +WV2 +YV2 +SW2 +TW2 +UW2 +WW2 +YW2 +SX2 +TX2 +UX2 +WX2 +YX2 +SY2 +TY2 +UY2 +WY2 +YY2 +SZ2 +TZ2 +UZ2 +WZ2 +YZ2 +Sa2 +Ta2 +Ua2 +Wa2 +Ya2 +Sb2 +Tb2 +Ub2 +Wb2 +Yb2 +Sc2 +Tc2 +Uc2 +Wc2 +Yc2 +Sd2 +Td2 +Ud2 +Wd2 +Yd2 +Se2 +Te2 +Ue2 +We2 +Ye2 +Sf2 +Tf2 +Uf2 +Wf2 +Yf2 +Sg2 +Tg2 +Ug2 +Wg2 +Yg2 +Sh2 +Uh2 +Wh2 +Yh2 +Si2 +Ti2 +Ui2 +Wi2 +Yi2 +Sj2 +Tj2 +Uj2 +Wj2 +Yj2 +Sk2 +Tk2 +Uk2 +Wk2 +Yk2 +Sl2 +Tl2 +Ul2 +Wl2 +Yl2 +Sm2 +Tm2 +Um2 +Wm2 +Ym2 +Sn2 +Tn2 +Un2 +Wn2 +Yn2 +So2 +To2 +Uo2 +Wo2 +Yo2 +Sp2 +Tp2 +Up2 +Wp2 +Yp2 +Sq2 +Tq2 +Uq2 +Wq2 +Yq2 +Sr2 +Tr2 +Ur2 +Wr2 +Yr2 +Ss2 +Ts2 +Us2 +Ws2 +Ys2 +St2 +Tt2 +Ut2 +Wt2 +Yt2 +Tu2 +Uu2 +Wu2 +Yu2 +Sv2 +Tv2 +Uv2 +Wv2 +Yv2 +Sw2 +Tw2 +Uw2 +Ww2 +Yw2 +Sx2 +Tx2 +Ux2 +Wx2 +Yx2 +Sy2 +Ty2 +Uy2 +Wy2 +Yy2 +Sz2 +Tz2 +Uz2 +Wz2 +Yz2 +S_2 +T_2 +U_2 +W_2 +Y_2 +S03 +T03 +U03 +W03 +Y03 +S13 +T13 +U13 +W13 +Y13 +S23 +T23 +wI2()} +; +#undef Value_t +#undef N +#endif /*FP_TEST_WANT_COMPLEX_LONG_DOUBLE_TYPE */ +#ifdef FP_TEST_WANT_DOUBLE_TYPE +#define N(x) (x) +#define P(x) N(x##.0) +#define Value_t double +template<>const +wI2 +RegressionTests<q0>::Tests[]={Uj +Wj +Yj +Sk +Tk +Uk +Wk +Yk +Sl +Tl +Ul +Wl{2,-11,11,N(0.3),qM +Mod,aC2(aF2 +Mod)qA",z" +,g7"mod" +,"x%z" +} +,Yl +Sm +Tm +Um +Wm +Ym +Sn{oJ1 +dP +Acos,aC2(aJ2 +Acos)qO"/acos" +,"acos" +qV1,gL1 +Acos_deg,aC2(aJ2 +Acos_deg)qO"/acos_deg" +,"acos" +hC +1 +mR +dP +Acosh,aC2(aJ2 +Acosh)qO"/" +oB2,oB2 +hC +1 +mR,gL1 +Acosh_deg,aC2(aJ2 +Acosh_deg)qO"/acosh_deg" +,oB2 +qV1 +dP +Asin,aC2(aJ2 +Asin)qO"/asin" +,"a" +wQ1} +,{oJ1,gL1 +Asin_deg,aC2(aJ2 +Asin_deg)qO"/asin_deg" +,"a" +wQ1} +,{oJ1 +dP +Asinh,aC2(aJ2 +Asinh)qO"/a" +gK2,a92 +qV1,gL1 +Asinh_deg,aC2(aJ2 +Asinh_deg)qO"/asinh_deg" +,a92 +hC +a12 +dP +Atan,aC2(aJ2 +Atan)qO"/atan" +,"atan(x)" +gM1 +dP +Atan2,aC2(aJ2 +Atan2)qA +oJ"/" +hT2,hT2"(x,y)" +gM1,gL1 +Atan2_deg,aC2(aJ2 +Atan2_deg)qA +oJ"/atan2_deg" +,hT2"(x" +gT2 +1,a12,gL1 +Atan_deg,aC2(aJ2 +Atan_deg)qO"/atan_deg" +,"atan" +qV1 +dP +Atanh,aC2(aJ2 +Atanh)qO"/atanh" +,"atanh" +hC-50000,50000,1000 +dP +Cbrt,aC2(aJ2 +Cbrt)qO"/cbrt" +,"cbrt" +hC-10,10 +mR1 +dP +Ceil,aC2(aJ2 +Ceil)qO"/ceil" +,"ceil" +hC-m4 +dP +Cos,aC2(aJ2 +Cos)qO"/cos" +,"cos" +hC-m4,gL1 +Cos_deg,aC2(aJ2 +Cos_deg)qO"/cos_deg" +,"cos" +hC-140,140,N(0.1)dP +Cosh,aC2(aJ2 +Cosh)qO"/cosh" +,"cosh" +hC-140,140,N(0.1),gL1 +Cosh_deg,aC2(aJ2 +Cosh_deg)qO"/cosh_deg" +,"cosh" +hC-90,90,N(0.01)dP +Exp,aC2(aJ2 +Exp)qO"/exp" +,"exp" +hC-90,90,N(0.01)dP +Exp2,aC2(aJ2 +Exp2)qO"/exp2" +,"exp2" +hC-10,10 +mR1 +dP +Floor,aC2(aJ2 +Floor)qO"/floor" +,"floor(x)" +gM1 +dP +Hypot,aC2(aJ2 +Hypot)qA +oJ"/hypot" +,"hypot(x,y" +gO2 +Tn +Un +SO1{1,N(1e-6),dL1 +Log2,aC2(aJ2 +Log2)qO"/log2" +,"log2" +hC +N(1e-6),dL1 +Log10,aC2(aJ2 +Log10)qO"/log10" +,w0} +,T4 +U4{2,1,20,1 +dP +Pow_neg,aC2(aJ2 +Pow_neg)qA +oJ"/pow_neg" +,"pow(-x*0.25,y" +gO2{2,N(0.01),4,N(0.05)dP +Pow_pos,aC2(aJ2 +Pow_pos)qA +oJ"/pow_pos" +,qH2 +gT2 +1,-m4 +dP +Sin,aC2(aJ2 +Sin)qO"/sin" +,wQ1} +,{1,-m4,gL1 +Sin_deg,aC2(aJ2 +Sin_deg)qO"/sin_deg" +,wQ1} +,{1,a12 +dP +Sinh,aC2(aJ2 +Sinh)qO"/sinh" +,gK2 +hC +a12,gL1 +Sinh_deg,aC2(aJ2 +Sinh_deg)qO"/sinh_deg" +,gK2 +hC +0,100000,1000 +dP +Sqrt,aC2(aJ2 +Sqrt)qO"/sqrt" +,"sqrt" +hC +N(-1.3),N(1.3),N(0.05)dP +Tan,aC2(aJ2 +Tan)qO"/tan" +,"tan" +hC-89,89 +mR1,gL1 +Tan_deg,aC2(aJ2 +Tan_deg)qO"/tan_deg" +,"tan" +hC-m4 +dP +Tanh,aC2(aJ2 +Tanh)qO"/tanh" +,"tanh" +hC-m4,gL1 +Tanh_deg,aC2(aJ2 +Tanh_deg)qO"/tanh_deg" +,"tanh" +hC-4000,dL1 +Trunc,aC2(aJ2 +Trunc)qO"/trunc" +,"trunc" +hC +0,dD +E_d,aC2(aL2 +E_d)wJ"e_d" +,dW3"naturalnumber" +} +,a52 +L2_d,aC2(aL2 +L2_d)wJ"l2_d" +,dW3"logtwo" +} +,a52 +L10_d,aC2(aL2 +L10_d)wJ"l10_d" +,dW3"logten" +} +,a52 +Pi_d,aC2(aL2 +Pi_d)wJ"pi_d" +,dW3"pi" +} +,W4 +TO1 +UO1 +WO1 +YO1 +SP1 +TP1 +Wn +Y4 +Yn +So +To +S5 +T5 +U5 +W5 +wU2 +N(0.1)qL +Absyxpow_neg,aC2(aE2 +Absyxpow_neg)qZ"absyxpow_neg" +,"(x^-4)^1.5" +} +,wU2 +N(0.1)qL +Absyxpow_pos,aC2(aE2 +Absyxpow_pos)qZ"absyxpow_pos" +,"(x^4)^1.5" +} +,a62 +Acos,aC2(aE2 +Acos)qZ"acos" +,"acos" +w72,d62 +Acos_deg,aC2(aE2 +Acos_deg)qZ"acos_deg" +,"acos" +w72 +qL +Acosh,aC2(aE2 +Acosh)qZ +oB2,oB2"(" +oH +Acosh_deg,aC2(aE2 +Acosh_deg)qZ"acosh_deg" +,oB2 +w82 +Uo +Wo +UP1 +WP1 +Yo +Sp +YP1 +a62 +Asin,aC2(aE2 +Asin)qZ"asin" +,"asin(" +aZ1,d62 +Asin_deg,aC2(aE2 +Asin_deg)qZ"asin_deg" +,"asin(" +aZ1 +qL +Asinh,aC2(aE2 +Asinh)qZ +a92,a92"(" +oH +Asinh_deg,aC2(aE2 +Asinh_deg)qZ"asinh_deg" +,a92 +w82 +Tp +Up +a62 +Atan,aC2(aE2 +Atan)qZ"atan" +,"atan" +aO +Atan2,aC2(aE2 +Atan2)qZ +hT2,hT2"(5,4" +gG,d62 +Atan2_deg,aC2(aE2 +Atan2_deg)qZ"atan2_deg" +,hT2"(5,4)+x" +} +,Wp{1,0,1,1,d62 +Atan_deg,aC2(aE2 +Atan_deg)qZ"atan_deg" +,"atan" +aO +Atanh,aC2(aE2 +Atanh)qZ"atanh" +,"atanh" +w72 +qL +Cbrt,aC2(aE2 +Cbrt)qZ"cbrt" +,"cbrt" +aO +Ceil,aC2(aE2 +Ceil)qZ"ceil" +,"ceil" +w82 +Yp +SQ1 +TQ1 +UQ1 +WQ1 +YQ1 +SR1 +TR1 +UR1 +WR1 +YR1 +SS1 +TS1 +US1 +WS1 +YS1 +ST1 +TT1 +UT1 +WT1 +YT1 +SU1 +TU1 +UU1 +WU1 +YU1 +SV1 +TV1 +UV1 +WV1 +YV1 +SW1 +TW1 +UW1 +WW1 +YW1 +SX1 +TX1 +UX1 +WX1 +YX1 +SY1 +TY1 +UY1 +WY1 +YY1 +SZ1 +TZ1 +UZ1 +WZ1 +YZ1 +Sa1 +Ta1 +a62 +Cos,aC2(aE2 +Cos)qZ"cos" +,"cos(" +oH +Cos_deg,aC2(aE2 +Cos_deg)qZ"cos_deg" +,"cos" +aO +Cosh,aC2(aE2 +Cosh)qZ"cosh" +,"cosh(" +oH +Cosh_deg,aC2(aE2 +Cosh_deg)qZ"cosh_deg" +,"cosh" +w82 +Sq +Tq +Ua1 +Wa1 +Ya1 +Y5 +Uq +Wq +Yq +S6 +T6 +U6 +W6 +Sr +Sb1 +Tb1 +a62 +Exp,aC2(aE2 +Exp)qZ"exp" +,"exp" +aO +Exp2,aC2(aE2 +Exp2)qZ"exp2" +,"exp2" +w82 +Tr +Ur{1,wK +Exp2xpow,aC2(aE2 +Exp2xpow)qZ"exp2xpow" +,aS +gA2 +Wr +Yr +Ss +Ts{1,wK +Expxpow,aC2(aE2 +Expxpow)qZ"expxpow" +,aR +gA2 +a62 +Floor,aC2(aE2 +Floor)qZ"floor" +,"floor" +w82 +Us +Ub1 +Wb1 +Yb1 +Sc1 +Tc1 +Uc1 +Wc1 +Yc1 +Sd1 +Td1 +Ud1 +Wd1 +Yd1 +Se1 +a62 +Hypot,aC2(aE2 +Hypot)qZ"hypot" +,"hypot(5,4)+x" +} +,Te1 +Ws +Ys +St +Tt +Ut +Wt +Yt +Y6 +Ue1 +a62 +Log,aC2(aE2 +Log)qZ"log" +,"log" +aO +Log2,aC2(aE2 +Log2)qZ"log2" +,"log2" +w82 +We1 +Ye1 +a62 +Log10,aC2(aE2 +Log10)qZ"log10" +,"log10" +w82 +Sf1 +Tf1 +Uf1 +Wf1 +Yf1 +Sg1 +Tg1 +S7 +T7 +Ug1 +Wg1 +Yg1 +Sh1 +U7 +W7 +Th1 +a62 +Mulminus1,aC2(aE2 +Mulminus1)qZ"mulminus1" +,"x*-1" +} +,Uh1 +Wh1 +a62 +Neg,aC2(aE2 +Neg)qZ"neg" +,"((-((5))))+x" +} +,Y7 +Yh1 +Su +Si1 +Ti1 +S8 +Tu +Ui1 +T8 +U8 +Wi1 +Yi1 +W8 +Sj1 +Tj1 +Uj1 +Wj1 +Yj1 +Sk1 +Y8 +S9 +T9 +U9 +W9 +Y9 +SA +TA +UA +Tk1 +a62 +Pow_neg,aC2(aE2 +Pow_neg)w6"_neg" +,"pow(-0.25,4" +gG +qL +Pow_pos,aC2(aE2 +Pow_pos)w6"_pos" +,"pow(1.1, 7.1)+x" +} +,Uu +Wu +Yu +Sv +Tv +Uv +Wv{1,wK +Powxpow,aC2(aE2 +Powxpow)LNG_ONLY(0)q5"/powxpow" +,"(x^1.7)" +gA2 +Yv +Sw{1,N(0.01),10,N(0.05)qL +Rsqrt,aC2(aE2 +Rsqrt)qZ"rsqrt" +,"1/sqrt" +hC +0,1,1 +qL +Sin,aC2(aE2 +Sin)hP,"sin(" +oH +Sin_deg,aC2(aE2 +Sin_deg)hP"_deg" +,"sin(" +w5 +Uk1 +Wk1 +Yk1 +Sl1 +Tl1 +Ul1 +Wl1 +Yl1 +Sm1 +a62 +Sinh,aC2(aE2 +Sinh)hP"h" +,gK2"(" +oH +Sinh_deg,aC2(aE2 +Sinh_deg)hP"h_deg" +,gK2 +w82 +WA +YA +SB +TB +UB +WB +Tm1 +Tw +Uw +Ww +Um1 +wU2 +N(0.1)qL +Sqrsqrt,aC2(aE2 +Sqrsqrt)qZ"sqrsqrt" +,"sqrt" +qI2 +a62 +Sqrt,aC2(aE2 +Sqrt)qZ"sqrt" +,"sqrt" +w82 +Wm1 +Ym1{1,wK +Sqrxpow,aC2(aE2 +Sqrxpow)qZ"sqrxpow" +,"(x^2)^2402" +} +,wU2 +N(0.1)qL +Sqrxpow_nonint,aC2(aE2 +Sqrxpow_nonint)qZ"sqrxpow_nonint" +,"(x^2)^3.5" +} +,Sn1 +Tn1 +Un1 +a62 +Tan,aC2(aE2 +Tan)qZ"tan" +,"tan(" +oH +Tan_deg,aC2(aE2 +Tan_deg)qZ"tan_deg" +,"tan" +aO +Tanh,aC2(aE2 +Tanh)qZ"tanh" +,"tanh(" +oH +Tanh_deg,aC2(aE2 +Tanh_deg)qZ"tanh_deg" +,"tanh" +aO +Trunc,aC2(aE2 +Trunc)qZ"trunc" +,"trunc" +w82 +YB +SC +Yw +Wn1 +Yn1 +So1 +To1 +Uo1 +Wo1 +TC +Sx +UC{1,0,10,N(0.01)qL +Ypowxpow,aC2(aE2 +Ypowxpow)qZ"ypowxpow" +,"(x^38.5)^5" +} +,Yo1 +Sp1 +Tp1 +Up1 +Wp1 +Yp1 +Sq1 +Tq1 +Uq1 +Wq1 +Yq1 +Sr1 +Tr1 +Ur1 +Wr1 +Yr1 +Ss1 +Ts1 +Us1 +Ws1 +Ys1 +St1 +Tt1 +Ut1 +Wt1 +Yt1 +Su1 +Tu1 +Uu1 +Wu1 +Yu1 +Sv1 +Tv1 +Uv1 +Wv1 +Yv1 +Sw1 +Tw1 +Uw1 +Ww1 +Yw1 +Sx1 +Tx1 +Tx +Ux +Ux1 +Wx1 +WC +YC +Wx +Yx +SD +Sy +TD +UD +WD +Ty +Uy +Wy +YD +SE +TE +UE +WE +YE +SF +TF +UF +Yy +Sz +Tz +Uz +Wz +Yz +WF +YF +SG +TG +UG +WG +YG +SH +TH +S_ +T_ +U_ +W_ +Y_ +S01 +UH +WH +YH +SI +TI +UI +WI +YI +SJ +T01 +U01 +W01 +Y01 +S11 +T11 +TJ +UJ +WJ +YJ +SK +TK +UK +WK +YK +U11 +W11 +Y11 +S21 +T21 +U21 +SL +TL +UL +WL +YL +SM +TM +UM +WM +W21 +Y21 +S31 +T31 +U31 +W31 +YM +SN +TN +UN +WN +YN +SO +TO +UO +Y31 +S41 +T41 +U41 +W41 +Y41 +WO +YO +SP +TP +UP +WP +YP +SQ +TQ +S51 +T51 +U51 +W51 +Y51 +S61 +Yx1 +Sy1 +T61 +U61 +W61 +Ty1 +Uy1 +UQ +WQ +YQ +SR +TR +UR +Wy1 +Yy1 +Sz1 +WR +YR +SS +TS +US +WS +YS +ST +TT +UT +WT +YT +SU +TU +UU +WU +YU +TV +UV +WV +YV +SW +TW +UW +WW +Y61 +S71 +YW +T71 +U71 +W71 +Y71 +SX +S81 +TX +T81 +U81 +W81 +UX +WX +YX +SY +Y81 +TY +UY +WY +YY +SZ +TZ +UZ +WZ +YZ +Sa +Ta +Ua +Wa +Ya +Sb +Tb +Ub +Wb +Tz1 +Yb +Sc +S91 +T91 +U91 +W91 +Y91 +SA1 +TA1 +UA1 +Tc +Uc +Wc +WA1 +YA1 +SB1 +TB1 +UB1 +WB1 +Uz1 +Wz1 +Yc +Sd +Td +Ud +Wd +Yd +Se +Te +Ue +We +YB1 +SC1 +TC1 +UC1 +WC1 +YC1 +SD1 +TD1 +UD1 +WD1 +YD1 +SE1 +TE1 +Ye +Sf +Tf +Uf +Wf +Yf +UE1 +Sg +Yz1 +S_1 +T_1 +U_1 +W_1 +Y_1 +S02 +T02 +Tg +WE1 +YE1 +SF1 +TF1 +Ug +U02 +UF1 +WF1 +YF1 +SG1 +TG1 +UG1 +WG1 +YG1 +SH1 +TH1 +UH1 +WH1 +YH1 +SI1 +Wg +Yg +TI1 +Sh +Th +Uh +UI1 +WI1 +Wh +YI1 +SJ1 +TJ1 +UJ1 +Yh +WJ1 +YJ1 +SK1 +TK1 +Si +Ti +UK1 +WK1 +YK1 +SL1 +TL1 +UL1 +WL1 +YL1 +SM1 +TM1 +UM1 +WM1 +Ui +YM1 +SN1 +TN1 +UN1 +WN1 +Wi +YN1 +wI2()} +; +#undef Value_t +#undef N +#undef P +#endif /*FP_TEST_WANT_DOUBLE_TYPE */ +#ifdef FP_TEST_WANT_FLOAT_TYPE +#define N(x) (APP(x,f)) +#define P(x) N(x##.0) +#define Value_t float +namespace +cpp_01unit_operators +wH2 +Modf(qC,&z=vars[1 +mE1 +fmodf(x,z);} +} +namespace +cpp_02unit_functions +wH2 +Acosf(qK +acosf +hX3 +Acosf_deg(aY1 +acosf(x)mP +Acoshf(qK +d72+wA2-1.0f)mP +Acoshf_deg(aY1 +fp_acosh(x)mP +Asinf(qK +asinf +hX3 +Asinf_deg(aY1 +asinf(x)mP +Asinhf(qK +d72+wA2+1.0f)mP +Asinhf_deg(aY1 +fp_asinh(x)mP +Atan2f(qH +gB2 +x,y +mP +Atan2f_deg(qH +r2d(gB2 +x,y)mP +Atanf(qK +atanf +hX3 +Atanf_deg(aY1 +atanf(x)mP +Atanhf(qK +logf((1.0f+x)/(1.0f-x))*0.5f;} +q0 +Cbrtf(qK +fp_cbrt +hX3 +Ceilf(qK +ceilf +hX3 +Cosf(qK +cosf +hX3 +Cosf_deg(qK +cosf(oK1 +Coshf(qK +coshf +hX3 +Coshf_deg(qK +coshf(oK1 +Exp2f(qK +expf(x*fp_const_log2<q0>()mP +Expf(qK +expf +hX3 +Floorf(qK +floorf +hX3 +Hypotf(qH +wA2+y*y +mP +Log2f(qK +d72)*1.4426950408889634073599246810018921374266f;} +q0 +Log10f(qK +log10f +hX3 +Logf(qK +d72 +mP +Pow_negf(qH +powf(-x*0.25f,y +mP +Pow_posf(qH +powf(x,y +mP +Sinf(qK +sinf +hX3 +Sinf_deg(qK +sinf(oK1 +Sinhf(qK +sinhf +hX3 +Sinhf_deg(qK +sinhf(oK1 +Sqrtf(qK +q42 +x +mP +Tanf +wS2 +hX3 +Tanf_deg +wS2(oK1 +Tanhf(qK +tanhf +hX3 +Tanhf_deg(qK +tanhf(oK1 +Truncf(qK +fp_trunc(x);} +} +namespace +cpp_03unit_constants +wH2 +E_f(qK +expf(x*0.0f+1.0f +mP +L2_f(qK +d72*0.0f+2.0f +mP +L10_f(qK +d72*0.0f+10.0f +mP +Pi_f(qK +gB2 +x*0.0f,-1.0f);} +} +namespace +cpp_10optimizer_bytecode +wH2 +Acosf(qK +acosf(0.7f +hU +Acosf_deg(aY1 +acosf(0.7f)hU +Acoshf +oM1+q42 +1.1f*1.1f-1.0f)hU +Acoshf_deg(aY1 +fp_acosh +wC2)hU +Asinf(qK +asinf(0.7f +hU +Asinf_deg(aY1 +asinf(0.7f)hU +Asinhf +oM1+q42 +1.1f*1.1f+1.0f)hU +Asinhf_deg(aY1 +fp_asinh +wC2)hU +Atan2f(qK +gB2 +5.0f,wB2 +Atan2f_deg(aY1 +gB2 +5.0f,4.0f)hU +Atanf(qK +atanf +wC2 +hU +Atanf_deg(aY1 +atanf +wC2)hU +Atanhf(qK +logf((1.0f+0.7f)/(1.0f-0.7f))*0.5f+x;} +q0 +Cbrtf(qK +fp_cbrt +wC2 +hU +Ceilf(qK +ceilf +wC2 +hU +Cosf(qK +cosf +wC2 +hU +Cosf_deg(qK +cosf(gS1 +Coshf(qK +coshf +wC2 +hU +Coshf_deg(qK +coshf(gS1 +Exp2f(qK +expf +wC2*0.693147180559945309417232121458176568075500134f +hU +Expf(qK +expf +wC2 +hU +Floorf(qK +floorf +wC2 +hU +Hypotf(qK +q42 +5.0f*5.0f+4.0f*wB2 +Log2f +oM1)*1.4426950408889634073599246810018921374266f+x;} +q0 +Log10f(qK +log10f +wC2 +hU +Logf +oM1 +hU +Pow_negf(qK +powf(-0.25f,wB2 +Pow_posf(qK +powf +wC2,7.1f +hU +Sinf(qK +sinf +wC2 +hU +Sinf_deg(qK +sinf(gS1 +Sinhf(qK +sinhf +wC2 +hU +Sinhf_deg(qK +sinhf(gS1 +Sqrtf(qK +q42 +1.1f +hU +Tanf +wS2 +wC2 +hU +Tanf_deg +wS2(gS1 +Tanhf(qK +tanhf +wC2 +hU +Tanhf_deg(qK +tanhf(gS1 +Truncf(qK +1.0f+x;} +} +template<>const +wI2 +RegressionTests<q0>::Tests[]={Uj +Wj +Yj +Sk +Tk +Uk +Wk +Yk +Sl +Tl +Ul +Wl{2,-11,11,N(0.3),qM +Modf,hA +qA",z" +,g7"modf" +,"x%z" +} +,Yl +Sm +Tm +Um +Wm +Ym +Sn{oJ1 +dP +Acosf +qF"/acosf" +,"acos" +qV1,gL1 +Acosf_deg +qF"/acosf_deg" +,"acos" +hC +1 +mR +dP +Acoshf +qF"/acoshf" +,oB2 +hC +1 +mR,gL1 +Acoshf_deg +qF"/acoshf_deg" +,oB2 +qV1 +dP +Asinf +qF"/asinf" +,"a" +wQ1} +,{oJ1,gL1 +Asinf_deg +qF"/asinf_deg" +,"a" +wQ1} +,{oJ1 +dP +Asinhf +qF"/asinhf" +,a92 +qV1,gL1 +Asinhf_deg +qF"/asinhf_deg" +,a92"(x)" +gM1 +dP +Atan2f,d82"/atan2f" +,hT2"(x,y)" +gM1,gL1 +Atan2f_deg,d82"/atan2f_deg" +,hT2"(x" +gT2 +1,a12 +dP +Atanf +qF"/atanf" +,"atan" +hC +a12,gL1 +Atanf_deg +qF"/atanf_deg" +,"atan" +qV1 +dP +Atanhf +qF"/atanhf" +,"atanh" +hC-50000,50000,1000 +dP +Cbrtf +qF"/cbrtf" +,"cbrt" +hC-10,10 +mR1 +dP +Ceilf +qF"/ceilf" +,"ceil" +hC-m4 +dP +Cosf +qF"/cosf" +,"cos" +hC-400,400,5,gL1 +Cosf_deg +qF"/cosf_deg" +,"cos" +hC-40,40,N(0.025)dP +Coshf +qF"/coshf" +,"cosh" +hC-40,40,N(0.1),gL1 +Coshf_deg +qF"/coshf_deg" +,"cosh" +hC-90,90,N(0.01)dP +Exp2f +qF"/exp2f" +,"exp2" +hC-20,20,N(0.01)dP +Expf +qF"/expf" +,"exp" +hC-10,10 +mR1 +dP +Floorf +qF"/floorf" +,"floor(x)" +gM1 +dP +Hypotf,d82"/hypotf" +,"hypot(x,y" +gO2 +Tn +Un{1,oO1 +Log2f +qF"/log2f" +,"log2" +hC +oO1 +Log10f +qF"/log10f" +,"log10" +hC +oO1 +Logf +qF"/logf" +,aH1 +T4 +U4{2,1,20,1 +dP +Pow_negf,d82"/pow_negf" +,"pow(-x*0.25,y" +gO2{2,N(0.01),4,N(0.05)dP +Pow_posf,d82"/pow_posf" +,qH2 +gT2 +1,-m4 +dP +Sinf +qF"/sinf" +,wQ1} +,{1,-400,400,5,gL1 +Sinf_deg +qF"/sinf_deg" +,wQ1} +,{1,-40,40,N(0.1)dP +Sinhf +qF"/sinhf" +,gK2 +hC +a12,gL1 +Sinhf_deg +qF"/sinhf_deg" +,gK2 +hC +0,100000,1000 +dP +Sqrtf +qF"/sqrtf" +,"sqrt" +hC +N(-1.3),N(1.3),N(0.05)dP +Tanf +qF"/tanf" +,"tan" +hC-89,89 +mR1,gL1 +Tanf_deg +qF"/tanf_deg" +,"tan" +hC-m4 +dP +Tanhf +qF"/tanhf" +,"tanh" +hC-m4,gL1 +Tanhf_deg +qF"/tanhf_deg" +,"tanh" +hC +a12 +dP +Truncf +qF"/truncf" +,"trunc" +hC +0,dD +E_f,oQ"e_f" +,dW3"naturalnumber" +} +,a52 +L2_f,oQ"l2_f" +,dW3"logtwo" +} +,a52 +L10_f,oQ"l10_f" +,dW3"logten" +} +,a52 +Pi_f,oQ"pi_f" +,dW3"pi" +} +,W4 +TO1 +UO1 +YO1 +SP1 +Wn +Y4 +Yn +So +To +S5 +W5 +a62 +Acosf +aK"acosf" +,"acos" +w72,d62 +Acosf_deg +aK"acosf_deg" +,"acos(0.7)+x" +} +,Uo +a62 +Acoshf +aK"acoshf" +,oB2"(" +oH +Acoshf_deg +aK"acoshf_deg" +,oB2 +w82 +Wo +Yo +Sp +a62 +Asinf +aK"asinf" +,"asin(" +aZ1,d62 +Asinf_deg +aK"asinf_deg" +,"asin(0.7)+x" +} +,Tp +a62 +Asinhf +aK"asinhf" +,a92"(" +oH +Asinhf_deg +aK"asinhf_deg" +,a92 +w82 +Up +a62 +Atan2f +aK"atan2f" +,hT2"(5,4" +gG,d62 +Atan2f_deg +aK"atan2f_deg" +,hT2"(5,4)+x" +} +,Wp +a62 +Atanf +aK"atanf" +,"atan(" +oH +Atanf_deg +aK"atanf_deg" +,"atan" +aO +Atanhf +aK"atanhf" +,"atanh" +w72 +qL +Cbrtf +aK"cbrtf" +,"cbrt" +aO +Ceilf +aK"ceilf" +,"ceil" +w82 +Yp +SQ1 +TQ1 +UQ1 +WQ1 +YQ1 +SR1 +TR1 +UR1 +WR1 +YR1 +SS1 +TS1 +US1 +WS1 +YS1 +ST1 +TT1 +UT1 +WT1 +YT1 +SU1 +TU1 +UU1 +WU1 +YU1 +SV1 +TV1 +UV1 +WV1 +YV1 +SW1 +TW1 +UW1 +WW1 +YW1 +SX1 +TX1 +UX1 +WX1 +YX1 +SY1 +TY1 +UY1 +WY1 +YY1 +SZ1 +a62 +Cosf +aK"cosf" +,"cos(" +oH +Cosf_deg +aK"cosf_deg" +,"cos" +aO +Coshf +aK"coshf" +,"cosh(" +oH +Coshf_deg +aK"coshf_deg" +,"cosh" +w82 +Sq +Tq +Y5 +Uq +Wq +Yq +S6 +T6 +U6 +W6 +Sr +Sb1 +Tb1 +Tr +a62 +Exp2f +aK"exp2f" +,"exp2" +w82 +Ur +Wr +a62 +Expf +aK"expf" +,dJ2 +w5 +Yr +Ss +Ts +a62 +Floorf +aK"floorf" +,"floor" +w82 +Us +Ub1 +Wb1 +Yb1 +Sc1 +Tc1 +Uc1 +Wc1 +Yc1 +Sd1 +Td1 +Ud1 +Wd1 +Yd1 +Se1 +a62 +Hypotf +aK"hypotf" +,"hypot(5,4)+x" +} +,Ws +Ys +St +Tt +Ut +Wt +Yt +Y6 +Ue1 +We1 +Ye1 +a62 +Log2f +aK"log2f" +,"log2" +aO +Log10f +aK"log10f" +,"log10" +w82 +Sf1 +Tf1 +a62 +Logf +aK"logf" +,"log" +w82 +Uf1 +Wf1 +Yf1 +Sg1 +Tg1 +S7 +T7 +Sh1 +U7 +W7 +Th1 +Y7 +Su +Si1 +Ti1 +S8 +Tu +T8 +U8 +Wi1 +Yi1 +W8 +Tj1 +Uj1 +Wj1 +Yj1 +Y8 +S9 +T9 +U9 +W9 +Y9 +SA +TA +UA +a62 +Pow_negf,qG"/pow_negf" +,"pow(-0.25,4" +gG +qL +Pow_posf,qG"/pow_posf" +,"pow(1.1, 7.1)+x" +} +,Uu +Wu +Yu +Sv +Tv +Uv +Wv +Yv +Sw +Uk1 +Wk1 +Yk1 +Sl1 +Tl1 +Ul1 +Wl1 +Yl1 +Sm1 +a62 +Sinf +a11"f" +,"sin(" +oH +Sinf_deg +a11"f_deg" +,"sin(1.1" +gG +qL +Sinhf +a11"hf" +,gK2"(" +oH +Sinhf_deg +a11"hf_deg" +,gK2 +w82 +WA +YA +SB +TB +UB +WB +Tw +Uw +Ww +a62 +Sqrtf +aK"sqrtf" +,"sqrt" +w82 +Wm1 +Ym1 +Un1 +a62 +Tanf +aK"tanf" +,"tan(" +oH +Tanf_deg +aK"tanf_deg" +,"tan" +aO +Tanhf +aK"tanhf" +,"tanh(" +oH +Tanhf_deg +aK"tanhf_deg" +,"tanh" +aO +Truncf +aK"truncf" +,"trunc" +w82 +YB +SC +Yw +Wn1 +Yn1 +So1 +To1 +Uo1 +Wo1 +TC +Sx +UC +Tx +Ux +Wx +Yx +SD +Sy +TD +UD +WD +Ty +Uy +Wy +YD +SE +TE +UE +WE +YE +SF +TF +UF +Yy +Sz +Tz +Uz +Wz +Yz +WF +YF +SG +TG +UG +WG +YG +SH +TH +S_ +T_ +U_ +W_ +Y_ +S01 +UH +WH +YH +SI +TI +UI +WI +YI +SJ +T01 +U01 +W01 +Y01 +S11 +T11 +TJ +UJ +WJ +YJ +SK +TK +UK +WK +YK +U11 +W11 +Y11 +S21 +T21 +U21 +SL +TL +UL +WL +YL +SM +TM +UM +WM +W21 +Y21 +S31 +T31 +U31 +W31 +YM +SN +TN +UN +WN +YN +SO +TO +UO +Y31 +S41 +T41 +U41 +W41 +Y41 +WO +YO +SP +TP +UP +WP +YP +SQ +TQ +S51 +T51 +U51 +W51 +Y51 +S61 +Yx1 +Sy1 +T61 +U61 +W61 +Ty1 +Uy1 +UQ +WQ +YQ +SR +TR +UR +Wy1 +Yy1 +Sz1 +WR +YR +SS +TS +US +WS +YS +ST +TT +UT +WT +YT +SU +TU +UU +WU +YU +TV +UV +WV +YV +SW +TW +UW +WW +Y61 +S71 +YW +T71 +U71 +W71 +Y71 +SX +S81 +TX +T81 +U81 +W81 +UX +WX +YX +SY +Y81 +TY +UY +WY +YY +SZ +TZ +UZ +WZ +YZ +Sa +Ta +Ua +Wa +Ya +Sb +Tb +Ub +Wb +Tz1 +Yb +Sc +S91 +T91 +U91 +W91 +Y91 +SA1 +TA1 +UA1 +Tc +Uc +Wc +WA1 +YA1 +SB1 +TB1 +UB1 +WB1 +Uz1 +Wz1 +Yc +Sd +Td +Ud +Wd +Yd +Se +Te +Ue +We +YB1 +SC1 +TC1 +UC1 +WC1 +YC1 +SD1 +TD1 +UD1 +WD1 +YD1 +SE1 +TE1 +Ye +Sf +Tf +Uf +Wf +Yf +UE1 +S_1 +S02 +T02 +Tg +WE1 +YE1 +SF1 +TF1 +Ug +U02 +UF1 +WF1 +YF1 +SG1 +TG1 +UG1 +WG1 +YG1 +SH1 +TH1 +UH1 +WH1 +YH1 +SI1 +Wg +Yg +TI1 +Sh +Th +Uh +WI1 +Wh +YI1 +SJ1 +TJ1 +UJ1 +Yh +WJ1 +SK1 +Si +Ti +UK1 +WL1 +YL1 +SM1 +TM1 +UM1 +WM1 +Ui +YM1 +SN1 +TN1 +UN1 +WN1 +Wi +YN1 +wI2()} +; +#undef Value_t +#undef N +#undef P +#endif /*FP_TEST_WANT_FLOAT_TYPE */ +#ifdef FP_TEST_WANT_GMP_INT_TYPE +#define P(x) (APP(x,l)) +#define Value_t GmpInt +template<>const +wI2 +RegressionTests<q0>::Tests[]={S +T +U +W +Y +S1 +T1 +U1 +W1 +Y1 +S2 +T2 +U2 +W2 +Y2 +S3 +T3 +U3 +W3 +Y3 +S4 +T4 +U4 +W4 +Y4 +S5 +T5 +U5 +W5 +Y5 +S6 +T6 +U6 +W6 +Y6 +S7 +T7 +U7 +W7 +Y7 +S8 +T8 +U8 +W8 +Y8 +S9 +T9 +U9 +W9 +Y9 +SA +TA +UA +WA +YA +SB +TB +UB +WB +YB +SC +TC +UC +WC +YC +SD +TD +UD +WD +YD +SE +TE +UE +WE +YE +SF +TF +UF +WF +YF +SG +TG +UG +WG +YG +SH +TH +UH +WH +YH +SI +TI +UI +WI +YI +SJ +TJ +UJ +WJ +YJ +SK +TK +UK +WK +YK +SL +TL +UL +WL +YL +SM +TM +UM +WM +YM +SN +TN +UN +WN +YN +SO +TO +UO +WO +YO +SP +TP +UP +WP +YP +SQ +TQ +UQ +WQ +YQ +SR +TR +UR +WR +YR +SS +TS +US +WS +YS +ST +TT +UT +WT +YT +SU +TU +UU +WU +YU +SV +TV +UV +WV +YV +SW +TW +UW +WW +YW +SX +TX +UX +WX +YX +SY +TY +UY +WY +YY +SZ +TZ +UZ +WZ +YZ +Sa +Ta +Ua +Wa +Ya +Sb +Tb +Ub +Wb +Yb +Sc +Tc +Uc +Wc +Yc +Sd +Td +Ud +Wd +Yd +Se +Te +Ue +We +Ye +Sf +Tf +Uf +Wf +Yf +Sg +Tg +Ug +Wg +Yg +Sh +Th +Uh +Wh +Yh +Si +Ti +Ui +Wi +Yi +Sj +Tj +wI2()} +; +#undef Value_t +#undef P +#endif /*FP_TEST_WANT_GMP_INT_TYPE */ +#ifdef FP_TEST_WANT_LONG_DOUBLE_TYPE +#define N(x) (APP(x,l)) +#define P(x) N(x##.0) +#define Value_t long double +namespace +cpp_01unit_operators +wH2 +Modl(qC,&z=vars[1 +mE1 +fmodl(x,z);} +} +namespace +cpp_02unit_functions +wH2 +Acoshl(mJ +x+gC2-1.0l)mP +Acoshl_deg(aY1 +fp_acosh(x)mP +Acosl(qK +acosl +hX3 +Acosl_deg(aY1 +acosl(x)mP +Asinhl(mJ +x+gC2+1.0l)mP +Asinhl_deg(aY1 +fp_asinh(x)mP +Asinl(qK +asinl +hX3 +Asinl_deg(aY1 +asinl(x)mP +Atan2l(qH +gD2 +x,y +mP +Atan2l_deg(qH +r2d(gD2 +x,y)mP +Atanhl(mJ(1.0l+x)/(1.0l-x))*0.5l;} +q0 +Atanl(qK +atanl +hX3 +Atanl_deg(aY1 +atanl(x)mP +Cbrtl(qK +fp_cbrt +hX3 +Ceill(qK +ceill +hX3 +Coshl(qK +coshl +hX3 +Coshl_deg(qK +coshl(oK1 +Cosl(qK +cosl +hX3 +Cosl_deg(qK +cosl(oK1 +Exp2l(qK +expl(x*fp_const_log2<q0>()mP +Expl(qK +expl +hX3 +Floorl(qK +floorl +hX3 +Hypotl(qH +gC2+y*y +mP +Log2l(mJ +x)*1.4426950408889634073599246810018921374266l;} +q0 +Log10l(qK +log10l +hX3 +Logl(mJ +x +mP +Pow_negl(qH +powl(-x*0.25l,y +mP +Pow_posl(qH +powl(x,y +mP +Sinhl(qK +sinhl +hX3 +Sinhl_deg(qK +sinhl(oK1 +Sinl(qK +sinl +hX3 +Sinl_deg(qK +sinl(oK1 +Sqrtl(qK +sqrtl +hX3 +Tanhl(qK +tanhl +hX3 +Tanhl_deg(qK +tanhl(oK1 +Tanl(qK +tanl +hX3 +Tanl_deg(qK +tanl(oK1 +Truncl(qK +fp_trunc(x);} +} +namespace +cpp_03unit_constants +wH2 +E_ld(qK +expl(x*0.0l+1.0l +mP +L2_ld(mJ +x*0.0l+2.0l +mP +L10_ld(mJ +x*0.0l+10.0l +mP +Pi_ld(qK +gD2 +x*0.0l,-1.0l);} +} +namespace +cpp_10optimizer_bytecode +wH2 +Acoshl(mJ +1.1l+sqrtl(1.1l*1.1l-1.0l)hU +Acoshl_deg(aY1 +fp_acosh(1.1l)hU +Acosl(qK +acosl(0.7l +hU +Acosl_deg(aY1 +acosl(0.7l)hU +Asinhl(mJ +1.1l+sqrtl(1.1l*1.1l+1.0l)hU +Asinhl_deg(aY1 +fp_asinh(1.1l)hU +Asinl(qK +asinl(0.7l +hU +Asinl_deg(aY1 +asinl(0.7l)hU +Atan2l(qK +gD2 +5.0l,wG2 +Atan2l_deg(aY1 +gD2 +5.0l,4.0l)hU +Atanhl(mJ(1.0l+0.7l)/(1.0l-0.7l))*0.5l+x;} +q0 +Atanl(qK +atanl +m5 +Atanl_deg(aY1 +atanl(1.1l)hU +Cbrtl(qK +fp_cbrt +m5 +Ceill(qK +ceill +m5 +Coshl(qK +coshl +m5 +Coshl_deg(qK +coshl(qL1 +Cosl(qK +cosl +m5 +Cosl_deg(qK +cosl(qL1 +Exp2l(qK +expl(1.1l*0.693147180559945309417232121458176568075500134l +hU +Expl(qK +expl +m5 +Floorl(qK +floorl +m5 +Hypotl(qK +sqrtl(5.0l*5.0l+4.0l*wG2 +Invsincostan(qH +x/aD +y)+x/oP1 +x/mD1 +x*aD +y)+x*oP1 +x*mD1 +1.0l/aD +y)+1.0l/oP1 +1.0l/mD1 +1.0l*aD +y)+1.0l*oP1 +1.0l*qZ2 +y +mP +Log2l(mJ +1.1l)*1.4426950408889634073599246810018921374266l+x;} +q0 +Log10l(qK +log10l +m5 +Logl(qK +logl +m5 +Pow_negl(qK +powl(-0.25l,wG2 +Pow_posl(qK +powl(1.1l,7.1l +hU +Sinhl(qK +sinhl +m5 +Sinhl_deg(qK +sinhl(qL1 +Sinl(qK +sinl +m5 +Sinl_deg(qK +sinl(qL1 +Sqrtl(qK +sqrtl +m5 +Tanhl(qK +tanhl +m5 +Tanhl_deg(qK +tanhl(qL1 +Tanl(qK +tanl +m5 +Tanl_deg(qK +tanl(qL1 +Truncl(qK +1.0l+x;} +} +template<>const +wI2 +RegressionTests<q0>::Tests[]={Uj +Wj +Yj +Sk +Tk +Uk +Wk +Yk +Sl +Tl +Ul +Wl{2,-11,11,N(0.3),qM +Modl,hA +qA",z" +,g7"modl" +,"x%z" +} +,Yl +Sm +Tm +Um +Wm +Ym +Sn{1,1 +mR +dP +Acoshl +qF"/acoshl" +,oB2 +hC +1 +mR,gL1 +Acoshl_deg +qF"/acoshl_deg" +,oB2 +qV1 +dP +Acosl +qF"/acosl" +,"acos" +qV1,gL1 +Acosl_deg +qF"/acosl_deg" +,"acos" +qV1 +dP +Asinhl +qF"/asinhl" +,a92 +qV1,gL1 +Asinhl_deg +qF"/asinhl_deg" +,a92 +qV1 +dP +Asinl +qF"/asinl" +,"a" +wQ1} +,{oJ1,gL1 +Asinl_deg +qF"/asinl_deg" +,"a" +wQ1 +gM1 +dP +Atan2l,d82"/atan2l" +,hT2"(x,y)" +gM1,gL1 +Atan2l_deg,d82"/atan2l_deg" +,hT2"(x" +gT2 +oJ1 +dP +Atanhl +qF"/atanhl" +,"atanh" +hC +a12 +dP +Atanl +qF"/atanl" +,"atan" +hC +a12,gL1 +Atanl_deg +qF"/atanl_deg" +,"atan" +hC-50000,50000,1000 +dP +Cbrtl +qF"/cbrtl" +,"cbrt" +hC-10,10 +mR1 +dP +Ceill +qF"/ceill" +,"ceil" +hC-140,140,N(0.1)dP +Coshl +qF"/coshl" +,"cosh" +hC-140,140,N(0.1),gL1 +Coshl_deg +qF"/coshl_deg" +,"cosh" +hC-m4 +dP +Cosl +qF"/cosl" +,"cos" +hC-m4,gL1 +Cosl_deg +qF"/cosl_deg" +,"cos" +hC-90,90,N(0.01)dP +Exp2l +qF"/exp2l" +,"exp2" +hC-90,90,N(0.01)dP +Expl +qF"/expl" +,"exp" +hC-10,10 +mR1 +dP +Floorl +qF"/floorl" +,"floor(x)" +gM1 +dP +Hypotl,d82"/hypotl" +,"hypot(x,y" +gO2 +Tn +Un{1,oO1 +Log2l +qF"/log2l" +,"log2" +hC +oO1 +Log10l +qF"/log10l" +,"log10" +hC +oO1 +Logl +qF"/logl" +,aH1 +T4 +U4{2,1,20,1 +dP +Pow_negl,d82"/pow_negl" +,"pow(-x*0.25,y" +gO2{2,N(0.01),4,N(0.05)dP +Pow_posl,d82"/pow_posl" +,qH2 +gT2 +1,a12 +dP +Sinhl +qF"/sinhl" +,gK2 +hC +a12,gL1 +Sinhl_deg +qF"/sinhl_deg" +,gK2 +hC-m4 +dP +Sinl +qF"/sinl" +,wQ1} +,{1,-m4,gL1 +Sinl_deg +qF"/sinl_deg" +,wQ1} +,{1,0,100000,1000 +dP +Sqrtl +qF"/sqrtl" +,"sqrt" +hC-m4 +dP +Tanhl +qF"/tanhl" +,"tanh" +hC-m4,gL1 +Tanhl_deg +qF"/tanhl_deg" +,"tanh" +hC +N(-1.3),N(1.3),N(0.05)dP +Tanl +qF"/tanl" +,"tan" +hC-89,89 +mR1,gL1 +Tanl_deg +qF"/tanl_deg" +,"tan" +hC +a12 +dP +Truncl +qF"/truncl" +,"trunc" +hC +0,dD +E_ld,oQ"e_ld" +,dW3"naturalnumber" +} +,a52 +L2_ld,oQ"l2_ld" +,dW3"logtwo" +} +,a52 +L10_ld,oQ"l10_ld" +,dW3"logten" +} +,a52 +Pi_ld,oQ"pi_ld" +,dW3"pi" +} +,W4 +YO1 +SP1 +Wn +Y4 +Yn +So +To +S5 +W5 +Uo +a62 +Acoshl +aK"acoshl" +,oB2"(" +oH +Acoshl_deg +aK"acoshl_deg" +,oB2 +w82 +Wo +a62 +Acosl +aK"acosl" +,"acos" +w72,d62 +Acosl_deg +aK"acosl_deg" +,"acos(0.7)+x" +} +,Yo +Sp +Tp +a62 +Asinhl +aK"asinhl" +,a92"(" +oH +Asinhl_deg +aK"asinhl_deg" +,a92 +w82 +Up +a62 +Asinl +aK"asinl" +,"asin(" +aZ1,d62 +Asinl_deg +aK"asinl_deg" +,"asin(" +aZ1 +qL +Atan2l +aK"atan2l" +,hT2"(5,4" +gG,d62 +Atan2l_deg +aK"atan2l_deg" +,hT2"(5,4)+x" +} +,Wp +a62 +Atanhl +aK"atanhl" +,"atanh" +w72 +qL +Atanl +aK"atanl" +,"atan(" +oH +Atanl_deg +aK"atanl_deg" +,"atan" +aO +Cbrtl +aK"cbrtl" +,"cbrt" +aO +Ceill +aK"ceill" +,"ceil" +w82 +Yp +SQ1 +TQ1 +UQ1 +WQ1 +YQ1 +SR1 +TR1 +UR1 +WR1 +YR1 +SS1 +TS1 +US1 +WS1 +YS1 +ST1 +TT1 +UT1 +WT1 +YT1 +SU1 +TU1 +UU1 +WU1 +YU1 +SV1 +TV1 +UV1 +WV1 +YV1 +SW1 +TW1 +UW1 +WW1 +YW1 +SX1 +TX1 +UX1 +WX1 +YX1 +SY1 +TY1 +UY1 +WY1 +YY1 +SZ1 +a62 +Coshl +aK"coshl" +,"cosh(" +oH +Coshl_deg +aK"coshl_deg" +,"cosh" +aO +Cosl +aK"cosl" +,"cos(" +oH +Cosl_deg +aK"cosl_deg" +,"cos" +w82 +Sq +Tq +Y5 +Uq +Wq +Yq +S6 +T6 +U6 +W6 +Sr +Sb1 +Tb1 +Tr +a62 +Exp2l +aK"exp2l" +,"exp2" +w82 +Ur +Wr +a62 +Expl +aK"expl" +,dJ2 +w5 +Yr +Ss +Ts +a62 +Floorl +aK"floorl" +,"floor" +w82 +Us +Ub1 +Wb1 +Yb1 +Sc1 +Tc1 +Uc1 +Yc1 +Sd1 +Td1 +Ud1 +Wd1 +Yd1 +a62 +Hypotl +aK"hypotl" +,"hypot(5,4)+x" +} +,Ws +Ys +St +Tt +Ut +Wt +Yt +Y6{2,N(-0.7),N(0.7),N(0.28)qL +Invsincostan,hA +dI2"invsincostan" +,"x/sin(" +dQ1"cos" +w92"tan" +w92"csc" +w92"sec" +w92"cot(y" +o42" 1/sin(y" +o42" 1/cos(y" +o42" 1/tan(y" +o42" 1/csc(y" +o42" 1/sec(y" +o42" 1/cot(" +oS2 +a62 +Log2l +aK"log2l" +,"log2" +aO +Log10l +aK"log10l" +,"log10" +aO +Logl +aK"logl" +,"log" +w82 +Uf1 +Wf1 +Yf1 +S7 +T7 +U7 +W7 +Y7 +Su +S8 +Tu +T8 +U8 +W8 +Wj1 +Yj1 +Y8 +S9 +T9 +U9 +W9 +Y9 +SA +TA +UA +a62 +Pow_negl,qG"/pow_negl" +,"pow(-0.25,4" +gG +qL +Pow_posl,qG"/pow_posl" +,"pow(1.1, 7.1)+x" +} +,Uu +Wu +Yu +Sv +Tv +Uv +Wv +Yv +Sw +Uk1 +Wk1 +Yk1 +Sl1 +Tl1 +Ul1 +Wl1 +Yl1 +Sm1 +a62 +Sinhl +a11"hl" +,gK2"(" +oH +Sinhl_deg +a11"hl_deg" +,gK2 +aO +Sinl +a11"l" +,"sin(" +oH +Sinl_deg +a11"l_deg" +,"sin(" +w5 +WA +YA +SB +TB +UB +WB +Tw +Uw +Ww +a62 +Sqrtl +aK"sqrtl" +,"sqrt" +w82 +Un1 +a62 +Tanhl +aK"tanhl" +,"tanh(" +oH +Tanhl_deg +aK"tanhl_deg" +,"tanh" +aO +Tanl +aK"tanl" +,"tan(" +oH +Tanl_deg +aK"tanl_deg" +,"tan" +aO +Truncl +aK"truncl" +,"trunc" +w82 +YB +SC +Yw +Uo1 +Wo1 +TC +Sx +UC +Tx +Ux +Wx +Yx +SD +Sy +TD +UD +WD +Ty +Uy +Wy +YD +SE +TE +UE +WE +YE +SF +TF +UF +Yy +Sz +Tz +Uz +Wz +Yz +WF +YF +SG +TG +UG +WG +YG +SH +TH +S_ +T_ +U_ +W_ +Y_ +S01 +UH +WH +YH +SI +TI +UI +WI +YI +SJ +T01 +U01 +W01 +Y01 +S11 +T11 +TJ +UJ +WJ +YJ +SK +TK +UK +WK +YK +U11 +W11 +Y11 +S21 +T21 +U21 +SL +TL +UL +WL +YL +SM +TM +UM +WM +W21 +Y21 +S31 +T31 +U31 +W31 +YM +SN +TN +UN +WN +YN +SO +TO +UO +Y31 +S41 +T41 +U41 +W41 +Y41 +WO +YO +SP +TP +UP +WP +YP +SQ +TQ +S51 +T51 +U51 +W51 +Y51 +S61 +Yx1 +Sy1 +T61 +U61 +W61 +Ty1 +Uy1 +UQ +WQ +YQ +SR +TR +UR +Yy1 +Sz1 +WR +YR +SS +TS +US +WS +YS +ST +TT +UT +WT +YT +SU +TU +UU +WU +YU +TV +UV +WV +YV +SW +TW +UW +WW +Y61 +S71 +YW +T71 +U71 +W71 +Y71 +SX +S81 +TX +T81 +U81 +W81 +UX +WX +YX +SY +Y81 +TY +UY +WY +YY +SZ +TZ +UZ +WZ +YZ +Sa +Ta +Ua +Wa +Ya +Sb +Tb +Ub +Wb +Yb +Sc +S91 +T91 +U91 +W91 +Y91 +SA1 +TA1 +UA1 +Tc +Uc +Wc +WA1 +YA1 +SB1 +TB1 +UB1 +WB1 +Uz1 +Wz1 +Yc +Sd +Td +Ud +Wd +Yd +Se +Te +Ue +We +YB1 +SC1 +TC1 +UC1 +WC1 +YC1 +SD1 +TD1 +UD1 +WD1 +YD1 +SE1 +TE1 +Ye +Sf +Tf +Uf +Wf +Yf +UE1 +S02 +T02 +Tg +WE1 +YE1 +SF1 +TF1 +Ug +UF1 +WF1 +YF1 +SG1 +TG1 +UG1 +WG1 +YG1 +SH1 +TH1 +UH1 +WH1 +YH1 +SI1 +Wg +Yg +TI1 +Sh +Th +Uh +UI1 +WI1 +Wh +YI1 +SJ1 +TJ1 +UJ1 +Yh +WJ1 +YJ1 +SK1 +TK1 +Si +Ti +UK1 +WK1 +YK1 +SL1 +TL1 +UL1 +WL1 +YL1 +SM1 +TM1 +UM1 +WM1 +Ui +YM1 +SN1 +TN1 +UN1 +WN1 +Wi +YN1 +wI2()} +; +#undef Value_t +#undef N +#undef P +#endif /*FP_TEST_WANT_LONG_DOUBLE_TYPE */ +#ifdef FP_TEST_WANT_LONG_INT_TYPE +#define P(x) (APP(x,l)) +#define Value_t long +template<>const +wI2 +RegressionTests<q0>::Tests[]={S +T +U +W +Y +S1 +T1 +U1 +W1 +Y1 +S2 +T2 +U2 +W2 +Y2 +S3 +T3 +U3 +W3 +Y3 +S4 +T4 +U4 +W4 +WO1 +TP1 +Y4 +S5 +T5 +U5 +W5 +UP1 +WP1 +YP1 +UQ1 +UU1 +WU1 +YU1 +UY1 +WY1 +TZ1 +UZ1 +WZ1 +YZ1 +Sa1 +Ta1 +Ua1 +Wa1 +Ya1 +Y5 +S6 +T6 +U6 +W6 +Sb1 +Tb1 +Ub1 +Sc1 +Yc1 +Ud1 +Te1 +Y6 +Sg1 +S7 +T7 +Ug1 +Wg1 +Yg1 +U7 +W7 +Uh1 +Wh1 +Y7 +Yh1 +S8 +Ui1 +T8 +U8 +W8 +Sj1 +Wj1 +Yj1 +Sk1 +Y8 +S9 +T9 +U9 +W9 +Y9 +SA +TA +UA +Tk1 +WA +YA +SB +TB +UB +WB +Tm1 +Um1 +Sn1 +Tn1 +Un1 +YB +SC +TC +UC +Yo1 +Sp1 +Tp1 +Up1 +Wp1 +Yp1 +Sq1 +Tq1 +Uq1 +Wq1 +Yq1 +Sr1 +Tr1 +Ur1 +Wr1 +Yr1 +Ss1 +Ts1 +Us1 +Ws1 +Ys1 +St1 +Tt1 +Ut1 +Wt1 +Yt1 +Su1 +Tu1 +Uu1 +Wu1 +Yu1 +Sv1 +Tv1 +Uv1 +Wv1 +Yv1 +Sw1 +Tw1 +Uw1 +Ww1 +Yw1 +Sx1 +Tx1 +Ux1 +Wx1 +WC +YC +SD +TD +UD +WD +YD +SE +TE +UE +WE +YE +SF +TF +UF +WF +YF +SG +TG +UG +WG +YG +SH +TH +UH +WH +YH +SI +TI +UI +WI +YI +SJ +TJ +UJ +WJ +YJ +SK +TK +UK +WK +YK +SL +TL +UL +WL +YL +SM +TM +UM +WM +YM +SN +TN +UN +WN +YN +SO +TO +UO +WO +YO +SP +TP +UP +WP +YP +SQ +TQ +Yx1 +Sy1 +Ty1 +Uy1 +UQ +WQ +YQ +SR +TR +UR +Yy1 +Sz1 +WR +YR +SS +TS +US +WS +YS +ST +TT +UT +WT +YT +SU +TU +UU +WU +YU +SV +TV +UV +WV +YV +SW +TW +UW +WW +YW +SX +TX +UX +WX +YX +SY +TY +UY +WY +YY +SZ +TZ +UZ +WZ +YZ +Sa +Ta +Ua +Wa +Ya +Sb +Tb +Ub +Wb +Yb +Sc +Tc +Uc +Wc +Uz1 +Wz1 +Yc +Sd +Td +Ud +Wd +Yd +Se +Te +Ue +We +Ye +Sf +Tf +Uf +Wf +Yf +Sg +Yz1 +T_1 +U_1 +W_1 +Y_1 +Tg +Ug +U02 +Wg +Yg +Sh +Th +Uh +Wh +Yh +Si +Ti +Ui +Wi +Yi +Sj +Tj +wI2()} +; +#undef Value_t +#undef P +#endif /*FP_TEST_WANT_LONG_INT_TYPE */ +#ifdef FP_TEST_WANT_MPFR_FLOAT_TYPE +#define N(x) (q0(#x,0)) +#define P(x) N(x) +#define Value_t MpfrFloat +static +const +q0 +a21("0.5" +,0),o62("0.25" +,0),mflit1_1("1.1" +,0),mflit0_7("0.7" +,0),mflit1_6("1.6" +,0),mflit1_5("1.5" +,0),mflitm1_1("-1.1" +,0),mflitm1_6("-1.6" +,0),mflitm1_5("-1.5" +,0),mflitm0_25("-0.25" +,0),dC2("7.1" +,0),mflit0_015625("0.015625" +,0),mflit0_0625("0.0625" +,0),mflit5_0625("5.0625" +,0),mflit1_2("1.2" +,0),mflitm5_1("-5.1" +,0),mflitm7_1("-7.1" +,0),mflit5_1("5.1" +,0),mflit_5(".5" +,0),mflit3_1("3.1" +,0),mflit4e2("4e2" +,0),mflit3_5("3.5" +,0),mflit57_295779513082320877("57.295779513082320877" +,0),mflit0_2("0.2" +,0),mflit7_5("7.5" +,0),dD2("2.5" +,0),mflit1_3("1.3" +,0),mflit1_4("1.4" +,0),mflit1_7("1.7" +,0),mflit1_8("1.8" +,0),mflit1_25("1.25" +,0),mflit1_75("1.75" +,0),mflit2_25("2.25" +,0),mflit3_3("3.3" +,0),mflit0_6("0.6" +,0),mflit2_1("2.1" +,0),mflit1_75e21("1.75e21" +,0);namespace +cpp_01unit_operators +wH2 +And_d +oA2(g31?fp_abs(y)>=a21:q0(0)mP +Div_d(qH(x-o62)/y;} +q0 +Divmul_d +hM +x*y*x*x/z*(x-o62 +mP +Modm(qC,&z=vars[1 +mE1 +x%z;} +q0 +Not_d(qK +oR1<a21 +mP +Notnot_d(qK +q0(g31 +mP +Or_d(qH +oR1<a21?fp_abs(y)>=a21:q0(1));} +} +namespace +cpp_02unit_functions +wH2 +Acoshm(qB +acosh +hX3 +Acoshm_deg(d92 +acosh(x)mP +Acosm(qB +acos +hX3 +Acosm_deg(d92 +acos(x)mP +Asinhm(qB +asinh +hX3 +Asinhm_deg(d92 +asinh(x)mP +Asinm(qB +asin +hX3 +Asinm_deg(d92 +asin(x)mP +Atan2m +oA2::atan2(x,y +mP +Atan2m_deg(qH +oQ1 +atan2(x,y)mP +Atanhm(qB +atanh +hX3 +Atanm(qB +atan +hX3 +Atanm_deg(d92 +atan(x)mP +Cbrtm(qB +cbrt +hX3 +Ceilm(qB +ceil +hX3 +Coshm(qB +cosh +hX3 +Coshm_deg(qB +cosh(oK1 +Cosm(qB +cos +hX3 +Cosm_deg(qB +cos(oK1 +Exp2m(qB +exp2 +hX3 +Expm(qB +exp +hX3 +Floorm(qB +floor +hX3 +Hypotm +oA2::hypot(x,y +mP +If_d +hM +g31?y:z;} +q0 +Int(qK +fp_floor(x+a21 +mP +Log2m(qB +log2 +hX3 +Log10m(qB +log10 +hX3 +Logm(qB +log +hX3 +Pow_negm +oA2::pow(-x*o62,y +mP +Pow_posm +oA2::pow(x,y +mP +Sinhm(qB +sinh +hX3 +Sinhm_deg(qB +sinh(oK1 +Sinm(qB +sin +hX3 +Sinm_deg(qB +sin(oK1 +Sqrtm(qB +sqrt +hX3 +Tanhm(qB +tanh +hX3 +Tanhm_deg(qB +tanh(oK1 +Tanm(qB +tan +hX3 +Tanm_deg(qB +tan(oK1 +Truncm(qB +trunc(x);} +} +namespace +cpp_03unit_constants +wH2 +E_mpfr(qB +exp(x +wP2 +1)mP +L2_mpfr(qB +log(x +wP2 +2)mP +L10_mpfr(qB +log(x +wP2 +10)mP +Pi_mpfr(qB +atan2(x*q0(0),-q0(1));} +} +namespace +cpp_10optimizer_bytecode +wH2 +Acoshm(qB +acosh(gQ +Acoshm_deg(d92 +acosh(wZ +Acosm(qB +acos(w91 +Acosm_deg(d92 +acos(mflit0_7)hU +Asinhm(qB +asinh(gQ +Asinhm_deg(d92 +asinh(wZ +Asinm(qB +asin(w91 +Asinm_deg(d92 +asin(mflit0_7)hU +Atan2m(qB +atan2(q0(dA2 +hU +Atan2m_deg(d92 +atan2(q0(dA2)hU +Atanhm(qB +atanh(w91 +Atanm(qB +atan(gQ +Atanm_deg(d92 +atan(wZ +Cbrtm(qB +cbrt(gQ +Ceilm(qB +ceil(gQ +Coshm(qB +cosh(gQ +Coshm_deg(qB +cosh(dB2 +Cosm(qB +cos(gQ +Cosm_deg(qB +cos(dB2 +Exp2m(qB +exp2(gQ +Expm(qB +exp(gQ +Floorm(qB +floor(gQ +Hypotm(qB +hypot(q0(dA2 +hU +Int(qK +x+(((((fp_int(mflit1_1 +oB1 +mflit1_6)oB1 +mflit1_5)oB1 +mflitm1_1)oB1 +mflitm1_6)oB1 +mflitm1_5)mP +Log2m(qB +log2(gQ +Log10m(qB +log10(gQ +Logm(qB +log(gQ +Pow_negm(qB +pow(mflitm0_25,q0(4)hU +Pow_posm(qB +pow(mflit1_1,dC2 +hU +Powhalf +a72 +a21 +mP +Powminushalf +a72-a21 +mP +Sinhm(qB +sinh(gQ +Sinhm_deg(qB +sinh(dB2 +Sinm(qB +sin(gQ +Sinm_deg(qB +sin(dB2 +Sqrtm(qB +sqrt(gQ +Tanhm(qB +tanh(gQ +Tanhm_deg(qB +tanh(dB2 +Tanm(qB +tan(gQ +Tanm_deg(qB +tan(dB2 +Truncm(qK +q0(1)+x;} +} +namespace +cpp_20optimizer_optimizations +wH2 +Cmpeq_pow_imm_negneg +gF1(gL2 +Cmpeq_pow_imm_negpos +gF1(a82 +Cmpeq_pow_imm_pospos_base +gF1(gN2 +Cmpge_pow_imm_negneg(wM +gL2 +Cmpge_pow_imm_negpos(wM +a82 +Cmpge_pow_imm_pospos_base(wM +gN2 +Cmpgt_pow_imm_negneg(mX +gL2 +Cmpgt_pow_imm_negpos(mX +a82 +Cmpgt_pow_imm_pospos_base(mX +gN2 +Cmple_pow_imm_negneg +gW1 +gL2 +Cmple_pow_imm_negpos +gW1 +a82 +Cmple_pow_imm_pospos_base +gW1 +gN2 +Cmplt_pow_imm_negneg +oT1 +gL2 +Cmplt_pow_imm_negpos +oT1 +a82 +Cmplt_pow_imm_pospos_base +oT1 +gN2 +Cmpne_pow_imm_negneg(oU1 +gL2 +Cmpne_pow_imm_negpos(oU1 +a82 +Cmpne_pow_imm_pospos_base(oU1 +gN2 +Cmpzz_pow_imm_negneg(qH1 +gJ +aN +gJ +m7 +gJ +m8 +gJ +mA +gJ +mN +gL2 +Cmpzz_pow_imm_negpos(qH1 +qP +gY +aN +qP +gY +m7 +qP +gY +m8 +qP +gY +mA +qP +gY +mN +a82 +Cmpzz_pow_imm_pospos_base(qH1 +gK +aN +gK +m7 +gK +m8 +gK +mA +gK +mN +gN2 +Ifabsnot +hM +fp_truth(hW1)!=q0(0)?z:y;} +q0 +Posnot(qB2 +hW1 +mP +Posnotnot(qK +fp_notNot(hW1 +mP +Powmulimm_fnen(a5(q0(-8))mP +Powmulimm_fnep(a5(q0(4))mP +Powmulimm_fnfn(g12(mflitm5_1)*x,(mflitm7_1)mP +Powmulimm_fnfp(a5 +dC2 +mP +Powmulimm_fpfp(qH +a42 +mflit5_1*x*y,dC2);} +} +namespace +cpp_50regressions +wH2 +t42(qH +q22 +x*x)+gG2(a42 +y*y,o62))+fp_hypot(x,y);} +} +namespace +cpp_99misc +wH2 +t2(qK +q0(2)*x+aD +x)/mflit_5+q0(2)-aD +x)*aD +x +mP +t3 +hM +wY2 +gG1,y),fp_equal(y,x +mY +1)+q0(2)-mflit3_1*mflit4e2/mflit_5+x*x+y*y+z*z+wY2 +x,x)+fp_or(y,y +mP +t9 +hM +mflit1_5+x*y-gE2 +4)/q0(8)+z+z+z+z+x/(y*z +mP +t11 +hM(-x-x)+y+hQ +a42 +mflit1_1,z)mP +t22(qH(mflit3_5*q0(2 +mY +10)*(x*q0(3))-(aD +y)*q0(2 +mY +100)*((x*q0(2))-(y*q0(3)))*gE2 +5)/(q0(2)*q0(2))+a42 +mflit1_1,x*q0(2))+a42 +mflit1_1*q0(2),x*q0(2)mP +t26_deg(qK +aD +d2r(x))+gX2 +d2r(x*mflit1_5))+r2d(fp_asin(x/q0(110)))+r2d +wX2 +x/q0(120))mP +t30(qH +x-y*q0(1)+fp_mod(x,y)+x/a42 +y,mflit1_1)+qN +2),q0(3))+fp_mod(q0(5),q0(3))+qP +a42 +y,q0(0)))+qP +a21 +mP +t32 +hM +x+y/y-m61 +3),q0(4))-x-m71 +4),q0(3))+m71 +3),q0(4))-m61 +4),q0(3 +mY +0)+(z*oY3(x-gE2 +2))+(x*a21*q0(2))+y*q0(0)+fp_min(fp_min(m61 +4),gZ1 +1))oZ2 +x +oZ2 +fp_min(y,q0(4)),z)))+w42 +w42 +m71 +4),gZ1 +1))wO1 +w42 +y,q0(4)),z)))+(fp_abs +gF2 +fp_acos +gF2 +fp_asin +gF2 +fp_atan +gF2 +wR2 +mflit1_1)+gX2 +q0(0))+hZ2 +q0(0))+fp_floor(mflit1_1)+hQ +oY3 +aD +q0(0))+fp_sinh(q0(0))+qZ2 +oY3 +fp_tanh +gF2 +wU1 +q0(1),q0(1)))+(x-(y-z))+(x+y)+(x*y)+w42 +x +wO1 +x +w02 +x,x))))*-q0(1)+(z-z)+q0(1)/aD +x/wA1 +gW2/wA1 +qZ2 +z/q0(5))+gP +q0(1)/qZ2 +z/wA1 +aD +y/wA1 +mI/q0(5)))+hQ +q0(30)+x)*hQ +q0(40)+y)/hQ +q0(50)+z)+aD +x/mflit57_295779513082320877)+fp_asin(x/q0(10))*mflit57_295779513082320877+fp_floor(-x)+q0(1)/wR2 +x)+w81 +5)*mflit0_2)+(-x+-x+-x+-x+-x+-x +mP +t37(qK +q0(5)+mflit7_5*q0(8)/q0(3)-qN +2),q0(4))*q0(2)+fp_mod(q0(7),q0(2 +mY +4 +hU +t38 +hM +fp_asinh(x)+gG2 +fp_acosh(y+q0(3))+dD2*fp_atanh(z +mP +t39 +hM +aD +x+qM1)-mI+aD +y*mflit1_5))+z*z*z*aD +z*z*z-x*x-y*y)-qM1*aD +x+qM1)+x*y*z+x*y*dD2+x*y*z*mI)+x*y*mI)+x*z*mI)+y*z*dD2+(x*y*z*mI)-x*y*z-y*mI)-x*z*y+x*y+x*z-mI)*x +mP +t44(qK +wE +wF +8 +wB1 +wE*x +wF +7 +wC1 +wE*x*x +wF +6))+mflit1_3*wE*x*x*x +wF +5))+mflit1_4*wE +mU +wF +6))+gG2 +wE +mU*x +wF +4))+mflit1_6 +oH2*x +wF +3))+mflit1_7 +oH2*x*x +wF +2))+mflit1_8*(q22 +a42 +fp_abs(-q22 +x)),q0(3)))mP +t45(qK +wE +wF +7 +wB1 +wE*x*x +wF +5 +wC1 +wE +mU +wF +3)mP +t46(qH +fp_abs(fp_floor +wX2 +x)+q0(4)wB1 +fp_abs(fp_floor +wX2 +y)+mflit1_5))g62 +fp_acos(x),wX2 +y)-q0(10)wC1 +m71-4),fp_acos(x))+mflit1_3*m61 +9),fp_acos(x)-q0(9)mP +t47(qH +mflit1_25*(gH2+gI2)+gG2(fp_exp(y)-fp_exp(-y))+mflit1_75*((gI2+gH2)/q0(2 +mY +2)*((gI2-gH2)/q0(2))+mflit2_25*(hZ2 +y)+fp_sinh(y)mP +t48(qK +fp_sinh((hQ +x)/q0(5)+q0(1))*q0(5 +wC1 +hZ2(hQ +x)/hQ +q0(2 +mY +1))*hQ +q0(2)))+fp_not(fp_or +aL +x),fp_not(x/q0(4)))mP +t49(qK +wU1 +q0(0),x)+qN-4)*(x-q0(100)),mflit3_3 +mP +t52(qK +x+(q0(1)+gE2 +3)+q0(4)-q0(5)-q0(6)-q0(7)-q0(8))/q0(3)+q0(4)*(q0(1)+aD +q0(2))+gX2 +q0(4)*q0(5)+q0(6))/q0(2))+gX2 +a21)*qZ2 +mflit0_6+mflit0_2)-mflit1_1/hQ +mflit2_1)*q22 +mflit3_3)+qN +2),q0(3)mP +t55(qH +a22 +qP +mflit1_2),q0(0))g62 +a42 +y,dD2),aA2 +2)*m2*x,aA2 +3)*a22 +a42 +y,q0(3)),aA2 +4)*a22 +qP +q0(4)),q0(0)mP +t56(qK +fp_mod(mflit1_75e21,x);} +} +template<>const +wI2 +RegressionTests<q0>::Tests[]={Uj +Wj +Yj +Sk +Tk +Uk +Wk +Yk +Sl +Tl +Ul +Wl{2,-11,11,N(0.3),qM +Modm,hA +qA",z" +,g7"modm" +,"x%z" +} +,Yl +Sm +Tm +Um +Wm +Ym +Sn{1,1 +mR +dP +Acoshm +qF"/acoshm" +,oB2 +hC +1 +mR,gL1 +Acoshm_deg +qF"/acoshm_deg" +,oB2 +qV1 +dP +Acosm +qF"/acosm" +,"acos" +qV1,gL1 +Acosm_deg +qF"/acosm_deg" +,"acos" +qV1 +dP +Asinhm +qF"/asinhm" +,a92 +qV1,gL1 +Asinhm_deg +qF"/asin" +gU2 +a92 +qV1 +dP +Asinm +qF"/asinm" +,"a" +wQ1} +,{oJ1,gL1 +Asinm_deg +qF"/asin" +dE2"a" +wQ1} +,{2,-4,4,N(0.15)dP +Atan2m,d82"/atan2m" +,hT2"(x" +gT2 +2,-4,4,N(0.15),gL1 +Atan2m_deg,d82"/atan2m_deg" +,hT2"(x" +gT2 +oJ1 +dP +Atanhm +qF"/atanhm" +,"atanh" +hC +a12 +dP +Atanm +qF"/atanm" +,"atan" +hC +a12,gL1 +Atanm_deg +qF"/atanm_deg" +,"atan" +hC-50000,50000,1000 +dP +Cbrtm +qF"/cbrtm" +,"cbrt" +hC-10,10 +mR1 +dP +Ceilm +qF"/ceilm" +,"ceil" +hC-140,140,N(0.1)dP +Coshm +qF"/coshm" +,"cosh" +hC-140,140,N(0.1),gL1 +Coshm_deg +qF"/coshm_deg" +,"cosh" +hC-m4 +dP +Cosm +qF"/cosm" +,"cos" +hC-m4,gL1 +Cosm_deg +qF"/cosm_deg" +,"cos" +hC-90,90,N(0.02)dP +Exp2m +qF"/exp2m" +,"exp2" +hC-90,90,N(0.02)dP +Expm +qF"/expm" +,"exp" +hC-10,10 +mR1 +dP +Floorm +qF"/floorm" +,"floor(x)" +gM1 +dP +Hypotm,d82"/hypotm" +,"hypot(x,y" +gO2 +Tn +Un{1,oO1 +Log2m +qF"/log2m" +,"log2" +hC +oO1 +Log10m +qF"/log10m" +,"log10" +hC +oO1 +Logm +qF"/logm" +,aH1 +T4 +U4{2,1,20,1 +dP +Pow_negm,d82"/pow_negm" +,"pow(-x*0.25,y" +gO2{2,N(0.01),4,N(0.05)dP +Pow_posm,d82"/pow_posm" +,qH2 +gT2 +1,a12 +dP +Sinhm +qF"/sinhm" +,gK2 +hC +a12,gL1 +Sinhm_deg +qF"/sin" +gU2 +gK2 +hC-m4 +dP +Sinm +qF"/sinm" +,wQ1} +,{1,-m4,gL1 +Sinm_deg +qF"/sin" +dE2 +wQ1} +,{1,0,100000,1000 +dP +Sqrtm +qF"/sqrtm" +,"sqrt" +hC-m4 +dP +Tanhm +qF"/tanhm" +,"tanh" +hC-m4,gL1 +Tanhm_deg +qF"/tanhm_deg" +,"tanh" +hC +N(-1.3),N(1.3),N(0.05)dP +Tanm +qF"/tanm" +,"tan" +hC-89,89 +mR1,gL1 +Tanm_deg +qF"/tanm_deg" +,"tan" +hC +a12 +dP +Truncm +qF"/truncm" +,"trunc" +hC +0,dD +E_mpfr,oQ"e_mpfr" +,dW3"naturalnumber" +} +,a52 +L2_mpfr,oQ"l2_mpfr" +,dW3"logtwo" +} +,a52 +L10_mpfr,oQ"l10_mpfr" +,dW3"logten" +} +,a52 +Pi_mpfr,oQ"pi_mpfr" +,dW3"pi" +} +,W4 +Wn +Y4 +Yn +So +To +S5 +W5 +Uo +a62 +Acoshm +aK"acoshm" +,oB2"(" +oH +Acoshm_deg +aK"acoshm_deg" +,oB2 +w82 +Wo +a62 +Acosm +aK"acosm" +,"acos" +w72,d62 +Acosm_deg +aK"acosm_deg" +,"acos(0.7)+x" +} +,Yo +Sp +Tp +a62 +Asinhm +aK"asinhm" +,a92"(" +oH +Asinhm_deg +aK"asin" +gU2 +a92 +w82 +Up +a62 +Asinm +aK"asinm" +,"asin(" +aZ1,d62 +Asinm_deg +aK"asin" +dE2"asin(" +aZ1 +qL +Atan2m +aK"atan2m" +,hT2"(5,4" +gG,d62 +Atan2m_deg +aK"atan2m_deg" +,hT2"(5,4)+x" +} +,Wp +a62 +Atanhm +aK"atanhm" +,"atanh" +w72 +qL +Atanm +aK"atanm" +,"atan(" +oH +Atanm_deg +aK"atanm_deg" +,"atan" +aO +Cbrtm +aK"cbrtm" +,"cbrt" +aO +Ceilm +aK"ceilm" +,"ceil" +w82 +Yp +a62 +Coshm +aK"coshm" +,"cosh(" +oH +Coshm_deg +aK"coshm_deg" +,"cosh" +aO +Cosm +aK"cosm" +,"cos(" +oH +Cosm_deg +aK"cosm_deg" +,"cos" +w82 +Sq +Tq +Y5 +Uq +Wq +Yq +W6 +Sr +Tr +Ur +a62 +Exp2m +aK"exp2m" +,"exp2" +w82 +Wr +Yr +Ss +Ts +a62 +Expm +aK"expm" +,"exp" +aO +Floorm +aK"floorm" +,"floor" +w82 +Us +a62 +Hypotm +aK"hypotm" +,"hypot(5,4)+x" +} +,Ws +Ys +St +Tt +Ut +Wt +Yt +Y6 +a62 +Log2m +aK"log2m" +,"log2" +aO +Log10m +aK"log10m" +,"log10" +aO +Logm +aK"logm" +,"log" +w82 +S7 +T7 +U7 +W7 +Y7 +Su +S8 +Tu +T8 +U8 +W8 +Y8 +S9 +T9 +U9 +W9 +Y9 +SA +TA +UA +a62 +Pow_negm,qG"/pow_negm" +,"pow(-0.25,4" +gG +qL +Pow_posm,qG"/pow_posm" +,"pow(1.1, 7.1)+x" +} +,Uu +Wu +Yu +Sv +Tv +Uv +Wv +Yv +Sw +a62 +Sinhm +a11"hm" +,gK2"(" +oH +Sinhm_deg +a11 +gU2 +gK2 +aO +Sinm +a11"m" +,"sin(" +oH +Sinm_deg +a11 +dE2"sin(" +w5 +WA +YA +SB +TB +UB +WB +Tw +Uw +Ww +a62 +Sqrtm +aK"sqrtm" +,"sqrt" +aO +Tanhm +aK"tanhm" +,"tanh(" +oH +Tanhm_deg +aK"tanhm_deg" +,"tanh" +aO +Tanm +aK"tanm" +,"tan(" +oH +Tanm_deg +aK"tanm_deg" +,"tan" +aO +Truncm +aK"truncm" +,"trunc" +w82 +Yw +TC +Sx +UC +Tx +Ux +Wx +Yx +SD +Sy +TD +UD +WD +Ty +Uy +Wy +YD +SE +TE +UE +WE +YE +SF +TF +UF +Yy +Sz +Tz +Uz +Wz +Yz +WF +YF +SG +TG +UG +WG +YG +SH +TH +S_ +T_ +U_ +W_ +Y_ +S01 +UH +WH +YH +SI +TI +UI +WI +YI +SJ +T01 +U01 +W01 +Y01 +S11 +T11 +TJ +UJ +WJ +YJ +SK +TK +UK +WK +YK +U11 +W11 +Y11 +S21 +T21 +U21 +SL +TL +UL +WL +YL +SM +TM +UM +WM +W21 +Y21 +S31 +T31 +U31 +W31 +YM +SN +TN +UN +WN +YN +SO +TO +UO +Y31 +S41 +T41 +U41 +W41 +Y41 +WO +YO +SP +TP +UP +WP +YP +SQ +TQ +S51 +T51 +U51 +W51 +Y51 +S61 +T61 +U61 +W61 +UQ +WQ +YQ +SR +TR +UR +WR +YR +SS +TS +US +WS +YS +ST +TT +UT +WT +YT +SU +TU +UU +WU +YU +TV +UV +WV +YV +SW +TW +UW +WW +Y61 +S71 +YW +T71 +U71 +W71 +Y71 +SX +S81 +TX +T81 +U81 +W81 +UX +WX +YX +SY +Y81 +TY +UY +WY +YY +SZ +TZ +UZ +WZ +YZ +Sa +Ta +Ua +Wa +Ya +Sb +Tb +Ub +Wb +Yb +Sc +S91 +T91 +U91 +W91 +Y91 +SA1 +TA1 +UA1 +Tc +Uc +Wc +WA1 +YA1 +SB1 +TB1 +UB1 +WB1 +Yc +Sd +Td +Ud +Wd +Yd +Se +Te +Ue +We +YB1 +SC1 +TC1 +UC1 +WC1 +YC1 +SD1 +TD1 +UD1 +WD1 +YD1 +SE1 +TE1 +Tf +Uf +Wf +Yf +UE1 +Tg +WE1 +YE1 +SF1 +TF1 +Ug +UF1 +WF1 +YF1 +SG1 +TG1 +UG1 +WG1 +YG1 +SH1 +TH1 +UH1 +WH1 +YH1 +SI1 +Wg +Yg +TI1 +Sh +Th +Uh +UI1 +WI1 +Wh +YI1 +SJ1 +TJ1 +UJ1 +Yh +WJ1 +YJ1 +SK1 +TK1 +Si +Ti +UK1 +WK1 +YK1 +SL1 +TL1 +UL1 +WL1 +YL1 +SM1 +TM1 +UM1 +WM1 +Ui +YM1 +SN1 +TN1 +UN1 +WN1 +Wi +YN1 +wI2()} +; +#undef Value_t +#undef N +#undef P +#endif /*FP_TEST_WANT_MPFR_FLOAT_TYPE */ diff --git a/tests/01unit_operators/add_cd b/tests/01unit_operators/add_cd new file mode 100644 index 0000000..c5342ce --- /dev/null +++ b/tests/01unit_operators/add_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x,y +R=-6-3i, 6+3i, 0.5+0.25i +F=x+y +C=x+y diff --git a/tests/01unit_operators/add_d b/tests/01unit_operators/add_d new file mode 100644 index 0000000..9d31c21 --- /dev/null +++ b/tests/01unit_operators/add_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-6, 6, 0.5 +F=x+y +C=x+y diff --git a/tests/01unit_operators/add_i b/tests/01unit_operators/add_i new file mode 100644 index 0000000..ce48bcf --- /dev/null +++ b/tests/01unit_operators/add_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-40, 40, 3 +F=x+y +C=x+y diff --git a/tests/01unit_operators/addsub_cd b/tests/01unit_operators/addsub_cd new file mode 100644 index 0000000..bc5a53e --- /dev/null +++ b/tests/01unit_operators/addsub_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x,y,z +R=-6-3i, 6+3i, 0.5+0.25i +F=x+y+x+x-z+x +C=x+y+x+x-z+x diff --git a/tests/01unit_operators/addsub_d b/tests/01unit_operators/addsub_d new file mode 100644 index 0000000..4e856a1 --- /dev/null +++ b/tests/01unit_operators/addsub_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y,z +R=-6, 6, 0.5 +F=x+y+x+x-z+x +C=x+y+x+x-z+x diff --git a/tests/01unit_operators/addsub_i b/tests/01unit_operators/addsub_i new file mode 100644 index 0000000..44db2e9 --- /dev/null +++ b/tests/01unit_operators/addsub_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y,z +R=-40, 40, 3 +F=x+y+x+x-z+x +C=x+y+x+x-z+x diff --git a/tests/01unit_operators/and_d b/tests/01unit_operators/and_d new file mode 100644 index 0000000..5f07962 --- /dev/null +++ b/tests/01unit_operators/and_d @@ -0,0 +1,6 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x&y +C=Value_t( fp_abs(x) >= 0.5 ? fp_abs(y) >= 0.5 : 0 ) + diff --git a/tests/01unit_operators/and_i b/tests/01unit_operators/and_i new file mode 100644 index 0000000..bd8d7c9 --- /dev/null +++ b/tests/01unit_operators/and_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x&y +C=x != 0 ? y != 0 : 0 diff --git a/tests/01unit_operators/cmpeq_cd b/tests/01unit_operators/cmpeq_cd new file mode 100644 index 0000000..946e1cb --- /dev/null +++ b/tests/01unit_operators/cmpeq_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x,y +R=-6-3i, 6+3i, 0.5+0.25i +F=x=y +C=x==y diff --git a/tests/01unit_operators/cmpeq_d b/tests/01unit_operators/cmpeq_d new file mode 100644 index 0000000..e1722ef --- /dev/null +++ b/tests/01unit_operators/cmpeq_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x=y +C=x==y diff --git a/tests/01unit_operators/cmpeq_i b/tests/01unit_operators/cmpeq_i new file mode 100644 index 0000000..ae181a7 --- /dev/null +++ b/tests/01unit_operators/cmpeq_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x=y +C=x==y diff --git a/tests/01unit_operators/cmpge_d b/tests/01unit_operators/cmpge_d new file mode 100644 index 0000000..3d7cf62 --- /dev/null +++ b/tests/01unit_operators/cmpge_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x>=y +C=x>=y diff --git a/tests/01unit_operators/cmpge_i b/tests/01unit_operators/cmpge_i new file mode 100644 index 0000000..d79cb57 --- /dev/null +++ b/tests/01unit_operators/cmpge_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x>=y +C=x>=y diff --git a/tests/01unit_operators/cmpgt_d b/tests/01unit_operators/cmpgt_d new file mode 100644 index 0000000..5ce4a00 --- /dev/null +++ b/tests/01unit_operators/cmpgt_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x>y +C=x>y diff --git a/tests/01unit_operators/cmpgt_i b/tests/01unit_operators/cmpgt_i new file mode 100644 index 0000000..0b57ade --- /dev/null +++ b/tests/01unit_operators/cmpgt_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x>y +C=x>y diff --git a/tests/01unit_operators/cmple_d b/tests/01unit_operators/cmple_d new file mode 100644 index 0000000..5f346c4 --- /dev/null +++ b/tests/01unit_operators/cmple_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x<=y +C=x<=y diff --git a/tests/01unit_operators/cmple_i b/tests/01unit_operators/cmple_i new file mode 100644 index 0000000..7d3070a --- /dev/null +++ b/tests/01unit_operators/cmple_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x<=y +C=x<=y diff --git a/tests/01unit_operators/cmplt_d b/tests/01unit_operators/cmplt_d new file mode 100644 index 0000000..64a08ee --- /dev/null +++ b/tests/01unit_operators/cmplt_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x<y +C=x<y diff --git a/tests/01unit_operators/cmplt_i b/tests/01unit_operators/cmplt_i new file mode 100644 index 0000000..e57d186 --- /dev/null +++ b/tests/01unit_operators/cmplt_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x<y +C=x<y diff --git a/tests/01unit_operators/cmpne_cd b/tests/01unit_operators/cmpne_cd new file mode 100644 index 0000000..5c7a6ed --- /dev/null +++ b/tests/01unit_operators/cmpne_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x,y +R=-6-3i, 6+3i, 0.5+0.25i +F=x!=y +C=x!=y diff --git a/tests/01unit_operators/cmpne_d b/tests/01unit_operators/cmpne_d new file mode 100644 index 0000000..1f82c5b --- /dev/null +++ b/tests/01unit_operators/cmpne_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x!=y +C=x!=y diff --git a/tests/01unit_operators/cmpne_i b/tests/01unit_operators/cmpne_i new file mode 100644 index 0000000..ae7c783 --- /dev/null +++ b/tests/01unit_operators/cmpne_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x!=y +C=x!=y diff --git a/tests/01unit_operators/div_d b/tests/01unit_operators/div_d new file mode 100644 index 0000000..b227862 --- /dev/null +++ b/tests/01unit_operators/div_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-7.25, 7.25, 0.5 +F=(x-0.25)/y +C=(x-0.25)/y diff --git a/tests/01unit_operators/div_i b/tests/01unit_operators/div_i new file mode 100644 index 0000000..8684f03 --- /dev/null +++ b/tests/01unit_operators/div_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-460, 100, 8 +F=x/(y+3) +C=x/(y+3) diff --git a/tests/01unit_operators/divmul_d b/tests/01unit_operators/divmul_d new file mode 100644 index 0000000..b04fc46 --- /dev/null +++ b/tests/01unit_operators/divmul_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y,z +R=-7.25, 7.25, 0.5 +F=x*y*x*x/z*(x-0.25) +C=x*y*x*x/z*(x-0.25) diff --git a/tests/01unit_operators/divmul_i b/tests/01unit_operators/divmul_i new file mode 100644 index 0000000..fd6c686 --- /dev/null +++ b/tests/01unit_operators/divmul_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y,z +R=-46, 40, 2 +F=x*y*x*x/(z+3)*(x+4) +C=x*y*x*x/(z+3)*(x+4) diff --git a/tests/01unit_operators/inv_d b/tests/01unit_operators/inv_d new file mode 100644 index 0000000..f5bb031 --- /dev/null +++ b/tests/01unit_operators/inv_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=-7, 6, 0.6 +F=1/x +C=1/x diff --git a/tests/01unit_operators/inv_i b/tests/01unit_operators/inv_i new file mode 100644 index 0000000..8fbd87a --- /dev/null +++ b/tests/01unit_operators/inv_i @@ -0,0 +1,5 @@ +T=li gi +V=x +R=-41, 40, 3 +F=1/x +C=1/x diff --git a/tests/01unit_operators/mod b/tests/01unit_operators/mod new file mode 100644 index 0000000..6da51d4 --- /dev/null +++ b/tests/01unit_operators/mod @@ -0,0 +1,5 @@ +T=d +V=x,z +R=-11, 11, 0.3 +F=x%z +C=fmod(x,z) diff --git a/tests/01unit_operators/mod_i b/tests/01unit_operators/mod_i new file mode 100644 index 0000000..2ee0e66 --- /dev/null +++ b/tests/01unit_operators/mod_i @@ -0,0 +1,5 @@ +T=li gi +V=x,z +R=-460, 100, 8 +F=x%(z+3) +C=x%(z+3) diff --git a/tests/01unit_operators/modf b/tests/01unit_operators/modf new file mode 100644 index 0000000..9055088 --- /dev/null +++ b/tests/01unit_operators/modf @@ -0,0 +1,5 @@ +T=f +V=x,z +R=-11, 11, 0.3 +F=x%z +C=fmodf(x,z) diff --git a/tests/01unit_operators/modl b/tests/01unit_operators/modl new file mode 100644 index 0000000..ba12da3 --- /dev/null +++ b/tests/01unit_operators/modl @@ -0,0 +1,5 @@ +T=ld +V=x,z +R=-11, 11, 0.3 +F=x%z +C=fmodl(x,z) diff --git a/tests/01unit_operators/modm b/tests/01unit_operators/modm new file mode 100644 index 0000000..c1d553f --- /dev/null +++ b/tests/01unit_operators/modm @@ -0,0 +1,5 @@ +T=mf +V=x,z +R=-11, 11, 0.3 +F=x%z +C=x%z diff --git a/tests/01unit_operators/mul_cd b/tests/01unit_operators/mul_cd new file mode 100644 index 0000000..efe8f72 --- /dev/null +++ b/tests/01unit_operators/mul_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x,y +R=-7.25+3.625i, 7.25-3.625i, 0.5-0.25i +F=x*y +C=x*y diff --git a/tests/01unit_operators/mul_d b/tests/01unit_operators/mul_d new file mode 100644 index 0000000..70a2544 --- /dev/null +++ b/tests/01unit_operators/mul_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-7.25, 7.25, 0.5 +F=x*y +C=x*y diff --git a/tests/01unit_operators/mul_i b/tests/01unit_operators/mul_i new file mode 100644 index 0000000..895699b --- /dev/null +++ b/tests/01unit_operators/mul_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-460, 100, 8 +F=x*(y+4) +C=x*(y+4) diff --git a/tests/01unit_operators/neg_cd b/tests/01unit_operators/neg_cd new file mode 100644 index 0000000..cc25876 --- /dev/null +++ b/tests/01unit_operators/neg_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x +R=-6-3i, 6+3i, 0.5+0.25i +F=-x +C=-x diff --git a/tests/01unit_operators/neg_d b/tests/01unit_operators/neg_d new file mode 100644 index 0000000..dc8ceb4 --- /dev/null +++ b/tests/01unit_operators/neg_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=-6, 6, 0.5 +F=-x +C=-x diff --git a/tests/01unit_operators/neg_i b/tests/01unit_operators/neg_i new file mode 100644 index 0000000..767059b --- /dev/null +++ b/tests/01unit_operators/neg_i @@ -0,0 +1,5 @@ +T=li gi +V=x +R=-40, 40, 3 +F=-x +C=-x diff --git a/tests/01unit_operators/not_d b/tests/01unit_operators/not_d new file mode 100644 index 0000000..cd79c7a --- /dev/null +++ b/tests/01unit_operators/not_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=-1.25,1.25,0.25 +F=!x +C=Value_t( fp_abs(x) < 0.5 ) diff --git a/tests/01unit_operators/not_i b/tests/01unit_operators/not_i new file mode 100644 index 0000000..a600fa1 --- /dev/null +++ b/tests/01unit_operators/not_i @@ -0,0 +1,5 @@ +T=li gi +V=x +R=-2, 2, 1 +F=!x +C=Value_t(x==0) diff --git a/tests/01unit_operators/notnot_d b/tests/01unit_operators/notnot_d new file mode 100644 index 0000000..9ad785a --- /dev/null +++ b/tests/01unit_operators/notnot_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=-1.25,1.25,0.25 +F=!!x +C=Value_t( fp_abs(x) >= 0.5 ) diff --git a/tests/01unit_operators/notnot_i b/tests/01unit_operators/notnot_i new file mode 100644 index 0000000..c676920 --- /dev/null +++ b/tests/01unit_operators/notnot_i @@ -0,0 +1,5 @@ +T=li gi +V=x +R=-2, 2, 1 +F=!!x +C=Value_t(x!=0) diff --git a/tests/01unit_operators/or_d b/tests/01unit_operators/or_d new file mode 100644 index 0000000..810af55 --- /dev/null +++ b/tests/01unit_operators/or_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-1.75, 1.75, 0.25 +F=x|y +C=Value_t( fp_abs(x) < 0.5 ? fp_abs(y) >= 0.5 : 1 ) diff --git a/tests/01unit_operators/or_i b/tests/01unit_operators/or_i new file mode 100644 index 0000000..70e75e6 --- /dev/null +++ b/tests/01unit_operators/or_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2, 2, 1 +F=x|y +C=x == 0 ? y != 0 : 1 diff --git a/tests/01unit_operators/sub_cd b/tests/01unit_operators/sub_cd new file mode 100644 index 0000000..0c962a6 --- /dev/null +++ b/tests/01unit_operators/sub_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x,y +R=-6-3i, 6+3i, 0.5+0.25i +F=x-y +C=x-y diff --git a/tests/01unit_operators/sub_d b/tests/01unit_operators/sub_d new file mode 100644 index 0000000..5ad65f7 --- /dev/null +++ b/tests/01unit_operators/sub_d @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-6, 6, 0.5 +F=x-y +C=x-y diff --git a/tests/01unit_operators/sub_i b/tests/01unit_operators/sub_i new file mode 100644 index 0000000..139c24f --- /dev/null +++ b/tests/01unit_operators/sub_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-40, 40, 3 +F=x-y +C=x-y diff --git a/tests/02unit_functions/abs_cd b/tests/02unit_functions/abs_cd new file mode 100644 index 0000000..a705302 --- /dev/null +++ b/tests/02unit_functions/abs_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x +R=-400+200i, 400-200i, 0.5-0.25i +F=abs(x) +C=std::abs(x) diff --git a/tests/02unit_functions/abs_d b/tests/02unit_functions/abs_d new file mode 100644 index 0000000..7f653d2 --- /dev/null +++ b/tests/02unit_functions/abs_d @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-400, 400, 0.5 +F=abs(x) +C=x<0 ? -x : x diff --git a/tests/02unit_functions/abs_i b/tests/02unit_functions/abs_i new file mode 100644 index 0000000..7100bec --- /dev/null +++ b/tests/02unit_functions/abs_i @@ -0,0 +1,5 @@ +T=li gi +V=x +R=-40000,40000,1 +F=abs(x) +C=x<0 ? -x : x diff --git a/tests/02unit_functions/acos b/tests/02unit_functions/acos new file mode 100644 index 0000000..5d1f912 --- /dev/null +++ b/tests/02unit_functions/acos @@ -0,0 +1,5 @@ +T=d +V=x +R=-1, 1, 0.01 +F=acos(x) +C=acos(x) diff --git a/tests/02unit_functions/acos_deg b/tests/02unit_functions/acos_deg new file mode 100644 index 0000000..dd38ae4 --- /dev/null +++ b/tests/02unit_functions/acos_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-1, 1, 0.01 +F=acos(x) +C=r2d(acos(x)) diff --git a/tests/02unit_functions/acosf b/tests/02unit_functions/acosf new file mode 100644 index 0000000..0693cde --- /dev/null +++ b/tests/02unit_functions/acosf @@ -0,0 +1,5 @@ +T=f +V=x +R=-1, 1, 0.01 +F=acos(x) +C=acosf(x) diff --git a/tests/02unit_functions/acosf_deg b/tests/02unit_functions/acosf_deg new file mode 100644 index 0000000..e222c95 --- /dev/null +++ b/tests/02unit_functions/acosf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-1, 1, 0.01 +F=acos(x) +C=r2d(acosf(x)) diff --git a/tests/02unit_functions/acosh b/tests/02unit_functions/acosh new file mode 100644 index 0000000..57c84ae --- /dev/null +++ b/tests/02unit_functions/acosh @@ -0,0 +1,5 @@ +T=d +V=x +R=1, 400, 0.1 +F=acosh(x) +C=log(x + sqrt(x*x - 1)) diff --git a/tests/02unit_functions/acosh_deg b/tests/02unit_functions/acosh_deg new file mode 100644 index 0000000..312417d --- /dev/null +++ b/tests/02unit_functions/acosh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=1, 400, 0.1 +F=acosh(x) +C=r2d(log(x + sqrt(x*x - 1))) diff --git a/tests/02unit_functions/acoshf b/tests/02unit_functions/acoshf new file mode 100644 index 0000000..889be64 --- /dev/null +++ b/tests/02unit_functions/acoshf @@ -0,0 +1,5 @@ +T=f +V=x +R=1, 400, 0.1 +F=acosh(x) +C=logf(x + sqrtf(x*x - 1)) diff --git a/tests/02unit_functions/acoshf_deg b/tests/02unit_functions/acoshf_deg new file mode 100644 index 0000000..b5003bc --- /dev/null +++ b/tests/02unit_functions/acoshf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=1, 400, 0.1 +F=acosh(x) +C=r2d(fp_acosh(x)) diff --git a/tests/02unit_functions/acoshl b/tests/02unit_functions/acoshl new file mode 100644 index 0000000..bbcc872 --- /dev/null +++ b/tests/02unit_functions/acoshl @@ -0,0 +1,5 @@ +T=ld +V=x +R=1, 400, 0.1 +F=acosh(x) +C=logl(x + sqrtl(x*x - 1)) diff --git a/tests/02unit_functions/acoshl_deg b/tests/02unit_functions/acoshl_deg new file mode 100644 index 0000000..d212abb --- /dev/null +++ b/tests/02unit_functions/acoshl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=1, 400, 0.1 +F=acosh(x) +C=r2d(fp_acosh(x)) diff --git a/tests/02unit_functions/acoshm b/tests/02unit_functions/acoshm new file mode 100644 index 0000000..3165083 --- /dev/null +++ b/tests/02unit_functions/acoshm @@ -0,0 +1,5 @@ +T=mf +V=x +R=1, 400, 0.1 +F=acosh(x) +C=MpfrFloat::acosh(x) diff --git a/tests/02unit_functions/acoshm_deg b/tests/02unit_functions/acoshm_deg new file mode 100644 index 0000000..ba99452 --- /dev/null +++ b/tests/02unit_functions/acoshm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=1, 400, 0.1 +F=acosh(x) +C=r2d(MpfrFloat::acosh(x)) diff --git a/tests/02unit_functions/acosl b/tests/02unit_functions/acosl new file mode 100644 index 0000000..a604ad7 --- /dev/null +++ b/tests/02unit_functions/acosl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-1, 1, 0.01 +F=acos(x) +C=acosl(x) diff --git a/tests/02unit_functions/acosl_deg b/tests/02unit_functions/acosl_deg new file mode 100644 index 0000000..1913d2a --- /dev/null +++ b/tests/02unit_functions/acosl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-1, 1, 0.01 +F=acos(x) +C=r2d(acosl(x)) diff --git a/tests/02unit_functions/acosm b/tests/02unit_functions/acosm new file mode 100644 index 0000000..0119115 --- /dev/null +++ b/tests/02unit_functions/acosm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-1, 1, 0.01 +F=acos(x) +C=MpfrFloat::acos(x) diff --git a/tests/02unit_functions/acosm_deg b/tests/02unit_functions/acosm_deg new file mode 100644 index 0000000..859794c --- /dev/null +++ b/tests/02unit_functions/acosm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-1, 1, 0.01 +F=acos(x) +C=r2d(MpfrFloat::acos(x)) diff --git a/tests/02unit_functions/arg b/tests/02unit_functions/arg new file mode 100644 index 0000000..acfdce2 --- /dev/null +++ b/tests/02unit_functions/arg @@ -0,0 +1,5 @@ +T=cd cf cld +V=x +R=1e-6, 4000, 0.1 +F=log(x) +C=fp_log(x) diff --git a/tests/02unit_functions/asin b/tests/02unit_functions/asin new file mode 100644 index 0000000..e5b729b --- /dev/null +++ b/tests/02unit_functions/asin @@ -0,0 +1,5 @@ +T=d +V=x +R=-1, 1, 0.01 +F=asin(x) +C=asin(x) diff --git a/tests/02unit_functions/asin_deg b/tests/02unit_functions/asin_deg new file mode 100644 index 0000000..f07b959 --- /dev/null +++ b/tests/02unit_functions/asin_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-1, 1, 0.01 +F=asin(x) +C=r2d(asin(x)) diff --git a/tests/02unit_functions/asinf b/tests/02unit_functions/asinf new file mode 100644 index 0000000..7225246 --- /dev/null +++ b/tests/02unit_functions/asinf @@ -0,0 +1,5 @@ +T=f +V=x +R=-1, 1, 0.01 +F=asin(x) +C=asinf(x) diff --git a/tests/02unit_functions/asinf_deg b/tests/02unit_functions/asinf_deg new file mode 100644 index 0000000..2e92b2b --- /dev/null +++ b/tests/02unit_functions/asinf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-1, 1, 0.01 +F=asin(x) +C=r2d(asinf(x)) diff --git a/tests/02unit_functions/asinh b/tests/02unit_functions/asinh new file mode 100644 index 0000000..8e8d6e7 --- /dev/null +++ b/tests/02unit_functions/asinh @@ -0,0 +1,5 @@ +T=d +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=log(x + sqrt(x*x+1)) diff --git a/tests/02unit_functions/asinh_deg b/tests/02unit_functions/asinh_deg new file mode 100644 index 0000000..070f196 --- /dev/null +++ b/tests/02unit_functions/asinh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=r2d(log(x + sqrt(x*x+1))) diff --git a/tests/02unit_functions/asinhf b/tests/02unit_functions/asinhf new file mode 100644 index 0000000..2c2d9ad --- /dev/null +++ b/tests/02unit_functions/asinhf @@ -0,0 +1,5 @@ +T=f +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=logf(x + sqrtf(x*x+1)) diff --git a/tests/02unit_functions/asinhf_deg b/tests/02unit_functions/asinhf_deg new file mode 100644 index 0000000..48bb0f9 --- /dev/null +++ b/tests/02unit_functions/asinhf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=r2d(fp_asinh(x)) diff --git a/tests/02unit_functions/asinhl b/tests/02unit_functions/asinhl new file mode 100644 index 0000000..16ff3ee --- /dev/null +++ b/tests/02unit_functions/asinhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=logl(x + sqrtl(x*x+1)) diff --git a/tests/02unit_functions/asinhl_deg b/tests/02unit_functions/asinhl_deg new file mode 100644 index 0000000..cb85f2a --- /dev/null +++ b/tests/02unit_functions/asinhl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=r2d(fp_asinh(x)) diff --git a/tests/02unit_functions/asinhm b/tests/02unit_functions/asinhm new file mode 100644 index 0000000..687dbe8 --- /dev/null +++ b/tests/02unit_functions/asinhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=MpfrFloat::asinh(x) diff --git a/tests/02unit_functions/asinhm_deg b/tests/02unit_functions/asinhm_deg new file mode 100644 index 0000000..751258b --- /dev/null +++ b/tests/02unit_functions/asinhm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-1, 1, 0.01 +F=asinh(x) +C=r2d(MpfrFloat::asinh(x)) diff --git a/tests/02unit_functions/asinl b/tests/02unit_functions/asinl new file mode 100644 index 0000000..afa8830 --- /dev/null +++ b/tests/02unit_functions/asinl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-1, 1, 0.01 +F=asin(x) +C=asinl(x) diff --git a/tests/02unit_functions/asinl_deg b/tests/02unit_functions/asinl_deg new file mode 100644 index 0000000..41ef020 --- /dev/null +++ b/tests/02unit_functions/asinl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-1, 1, 0.01 +F=asin(x) +C=r2d(asinl(x)) diff --git a/tests/02unit_functions/asinm b/tests/02unit_functions/asinm new file mode 100644 index 0000000..eaa7f21 --- /dev/null +++ b/tests/02unit_functions/asinm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-1, 1, 0.01 +F=asin(x) +C=MpfrFloat::asin(x) diff --git a/tests/02unit_functions/asinm_deg b/tests/02unit_functions/asinm_deg new file mode 100644 index 0000000..31c1ba9 --- /dev/null +++ b/tests/02unit_functions/asinm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-1, 1, 0.01 +F=asin(x) +C=r2d(MpfrFloat::asin(x)) diff --git a/tests/02unit_functions/atan b/tests/02unit_functions/atan new file mode 100644 index 0000000..c83857e --- /dev/null +++ b/tests/02unit_functions/atan @@ -0,0 +1,5 @@ +T=d +V=x +R=-400, 400, 0.1 +F=atan(x) +C=atan(x) diff --git a/tests/02unit_functions/atan2 b/tests/02unit_functions/atan2 new file mode 100644 index 0000000..6918cdf --- /dev/null +++ b/tests/02unit_functions/atan2 @@ -0,0 +1,5 @@ +T=d +V=x,y +R=-4, 4, 0.05 +F=atan2(x,y) +C=atan2(x,y) diff --git a/tests/02unit_functions/atan2_deg b/tests/02unit_functions/atan2_deg new file mode 100644 index 0000000..b5e5596 --- /dev/null +++ b/tests/02unit_functions/atan2_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x,y +R=-4, 4, 0.05 +F=atan2(x,y) +C=r2d(atan2(x,y)) diff --git a/tests/02unit_functions/atan2f b/tests/02unit_functions/atan2f new file mode 100644 index 0000000..b702b24 --- /dev/null +++ b/tests/02unit_functions/atan2f @@ -0,0 +1,5 @@ +T=f +V=x,y +R=-4, 4, 0.05 +F=atan2(x,y) +C=atan2f(x,y) diff --git a/tests/02unit_functions/atan2f_deg b/tests/02unit_functions/atan2f_deg new file mode 100644 index 0000000..f644ec1 --- /dev/null +++ b/tests/02unit_functions/atan2f_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x,y +R=-4, 4, 0.05 +F=atan2(x,y) +C=r2d(atan2f(x,y)) diff --git a/tests/02unit_functions/atan2l b/tests/02unit_functions/atan2l new file mode 100644 index 0000000..0c8c5d4 --- /dev/null +++ b/tests/02unit_functions/atan2l @@ -0,0 +1,5 @@ +T=ld +V=x,y +R=-4, 4, 0.05 +F=atan2(x,y) +C=atan2l(x,y) diff --git a/tests/02unit_functions/atan2l_deg b/tests/02unit_functions/atan2l_deg new file mode 100644 index 0000000..40959dd --- /dev/null +++ b/tests/02unit_functions/atan2l_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x,y +R=-4, 4, 0.05 +F=atan2(x,y) +C=r2d(atan2l(x,y)) diff --git a/tests/02unit_functions/atan2m b/tests/02unit_functions/atan2m new file mode 100644 index 0000000..0b0e43f --- /dev/null +++ b/tests/02unit_functions/atan2m @@ -0,0 +1,5 @@ +T=mf +V=x,y +R=-4, 4, 0.15 +F=atan2(x,y) +C=MpfrFloat::atan2(x,y) diff --git a/tests/02unit_functions/atan2m_deg b/tests/02unit_functions/atan2m_deg new file mode 100644 index 0000000..693c47f --- /dev/null +++ b/tests/02unit_functions/atan2m_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x,y +R=-4, 4, 0.15 +F=atan2(x,y) +C=r2d(MpfrFloat::atan2(x,y)) diff --git a/tests/02unit_functions/atan_deg b/tests/02unit_functions/atan_deg new file mode 100644 index 0000000..231132a --- /dev/null +++ b/tests/02unit_functions/atan_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-400, 400, 0.1 +F=atan(x) +C=r2d(atan(x)) diff --git a/tests/02unit_functions/atanf b/tests/02unit_functions/atanf new file mode 100644 index 0000000..0e32636 --- /dev/null +++ b/tests/02unit_functions/atanf @@ -0,0 +1,5 @@ +T=f +V=x +R=-400, 400, 0.1 +F=atan(x) +C=atanf(x) diff --git a/tests/02unit_functions/atanf_deg b/tests/02unit_functions/atanf_deg new file mode 100644 index 0000000..0dd400e --- /dev/null +++ b/tests/02unit_functions/atanf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-400, 400, 0.1 +F=atan(x) +C=r2d(atanf(x)) diff --git a/tests/02unit_functions/atanh b/tests/02unit_functions/atanh new file mode 100644 index 0000000..f384ac0 --- /dev/null +++ b/tests/02unit_functions/atanh @@ -0,0 +1,5 @@ +T=d +V=x +R=-1, 1, 0.01 +F=atanh(x) +C=log( (1+x) / (1-x) ) * 0.5 diff --git a/tests/02unit_functions/atanhf b/tests/02unit_functions/atanhf new file mode 100644 index 0000000..9dec86e --- /dev/null +++ b/tests/02unit_functions/atanhf @@ -0,0 +1,5 @@ +T=f +V=x +R=-1, 1, 0.01 +F=atanh(x) +C=logf( (1+x) / (1-x) ) * 0.5 diff --git a/tests/02unit_functions/atanhl b/tests/02unit_functions/atanhl new file mode 100644 index 0000000..ed6f206 --- /dev/null +++ b/tests/02unit_functions/atanhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-1, 1, 0.01 +F=atanh(x) +C=logl( (1+x) / (1-x) ) * 0.5 diff --git a/tests/02unit_functions/atanhm b/tests/02unit_functions/atanhm new file mode 100644 index 0000000..d895a60 --- /dev/null +++ b/tests/02unit_functions/atanhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-1, 1, 0.01 +F=atanh(x) +C=MpfrFloat::atanh(x) diff --git a/tests/02unit_functions/atanl b/tests/02unit_functions/atanl new file mode 100644 index 0000000..1866866 --- /dev/null +++ b/tests/02unit_functions/atanl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-400, 400, 0.1 +F=atan(x) +C=atanl(x) diff --git a/tests/02unit_functions/atanl_deg b/tests/02unit_functions/atanl_deg new file mode 100644 index 0000000..f1a541e --- /dev/null +++ b/tests/02unit_functions/atanl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-400, 400, 0.1 +F=atan(x) +C=r2d(atanl(x)) diff --git a/tests/02unit_functions/atanm b/tests/02unit_functions/atanm new file mode 100644 index 0000000..721981a --- /dev/null +++ b/tests/02unit_functions/atanm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-400, 400, 0.1 +F=atan(x) +C=MpfrFloat::atan(x) diff --git a/tests/02unit_functions/atanm_deg b/tests/02unit_functions/atanm_deg new file mode 100644 index 0000000..54a5b6f --- /dev/null +++ b/tests/02unit_functions/atanm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-400, 400, 0.1 +F=atan(x) +C=r2d(MpfrFloat::atan(x)) diff --git a/tests/02unit_functions/cbrt b/tests/02unit_functions/cbrt new file mode 100644 index 0000000..1d498c8 --- /dev/null +++ b/tests/02unit_functions/cbrt @@ -0,0 +1,5 @@ +T=d +V=x +R=-50000, 50000, 1000 +F=cbrt(x) +C=x<0 ? -exp(log(-x) / 3) : (x>0 ? exp(log(x) / 3) : 0) diff --git a/tests/02unit_functions/cbrtf b/tests/02unit_functions/cbrtf new file mode 100644 index 0000000..d1528d3 --- /dev/null +++ b/tests/02unit_functions/cbrtf @@ -0,0 +1,5 @@ +T=f +V=x +R=-50000, 50000, 1000 +F=cbrt(x) +C=fp_cbrt(x) diff --git a/tests/02unit_functions/cbrtl b/tests/02unit_functions/cbrtl new file mode 100644 index 0000000..f866be4 --- /dev/null +++ b/tests/02unit_functions/cbrtl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-50000, 50000, 1000 +F=cbrt(x) +C=fp_cbrt(x) diff --git a/tests/02unit_functions/cbrtm b/tests/02unit_functions/cbrtm new file mode 100644 index 0000000..6c7a52a --- /dev/null +++ b/tests/02unit_functions/cbrtm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-50000, 50000, 1000 +F=cbrt(x) +C=MpfrFloat::cbrt(x) diff --git a/tests/02unit_functions/ceil b/tests/02unit_functions/ceil new file mode 100644 index 0000000..8b61894 --- /dev/null +++ b/tests/02unit_functions/ceil @@ -0,0 +1,5 @@ +T=d +V=x +R=-10, 10, 0.25 +F=ceil(x) +C=ceil(x) diff --git a/tests/02unit_functions/ceilf b/tests/02unit_functions/ceilf new file mode 100644 index 0000000..90c4ef9 --- /dev/null +++ b/tests/02unit_functions/ceilf @@ -0,0 +1,5 @@ +T=f +V=x +R=-10, 10, 0.25 +F=ceil(x) +C=ceilf(x) diff --git a/tests/02unit_functions/ceill b/tests/02unit_functions/ceill new file mode 100644 index 0000000..e6843da --- /dev/null +++ b/tests/02unit_functions/ceill @@ -0,0 +1,5 @@ +T=ld +V=x +R=-10, 10, 0.25 +F=ceil(x) +C=ceill(x) diff --git a/tests/02unit_functions/ceilm b/tests/02unit_functions/ceilm new file mode 100644 index 0000000..8fe2570 --- /dev/null +++ b/tests/02unit_functions/ceilm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-10, 10, 0.25 +F=ceil(x) +C=MpfrFloat::ceil(x) diff --git a/tests/02unit_functions/conj b/tests/02unit_functions/conj new file mode 100644 index 0000000..8cd6dd0 --- /dev/null +++ b/tests/02unit_functions/conj @@ -0,0 +1,5 @@ +T=cd cf cld +V=x +R=1e-6, 4000, 0.1 +F=conj(x) +C=fp_conj(x) diff --git a/tests/02unit_functions/cos b/tests/02unit_functions/cos new file mode 100644 index 0000000..c19805b --- /dev/null +++ b/tests/02unit_functions/cos @@ -0,0 +1,5 @@ +T=d +V=x +R=-40000, 40000, 5 +F=cos(x) +C=cos(x) diff --git a/tests/02unit_functions/cos_cd b/tests/02unit_functions/cos_cd new file mode 100644 index 0000000..14999d2 --- /dev/null +++ b/tests/02unit_functions/cos_cd @@ -0,0 +1,5 @@ +T=cd +V=x +R=-40000+200i, 40000-200i, 5-0.025i +F=cos(x) +C=cos(x) diff --git a/tests/02unit_functions/cos_cf b/tests/02unit_functions/cos_cf new file mode 100644 index 0000000..26f8251 --- /dev/null +++ b/tests/02unit_functions/cos_cf @@ -0,0 +1,5 @@ +T=cf +V=x +R=-40+0.5i, 40-0.5i, 0.1-0.00125i +F=cos(x) +C=cos(x) diff --git a/tests/02unit_functions/cos_deg b/tests/02unit_functions/cos_deg new file mode 100644 index 0000000..cb5fe5d --- /dev/null +++ b/tests/02unit_functions/cos_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-40000, 40000, 5 +F=cos(x) +C=cos(d2r(x)) diff --git a/tests/02unit_functions/cosf b/tests/02unit_functions/cosf new file mode 100644 index 0000000..6aa61fb --- /dev/null +++ b/tests/02unit_functions/cosf @@ -0,0 +1,5 @@ +T=f +V=x +R=-40000, 40000, 5 +F=cos(x) +C=cosf(x) diff --git a/tests/02unit_functions/cosf_deg b/tests/02unit_functions/cosf_deg new file mode 100644 index 0000000..d6cf602 --- /dev/null +++ b/tests/02unit_functions/cosf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-400, 400, 5 +F=cos(x) +C=cosf(d2r(x)) diff --git a/tests/02unit_functions/cosh b/tests/02unit_functions/cosh new file mode 100644 index 0000000..c6e2d38 --- /dev/null +++ b/tests/02unit_functions/cosh @@ -0,0 +1,5 @@ +T=d +V=x +R=-140, 140, 0.1 +F=cosh(x) +C=cosh(x) diff --git a/tests/02unit_functions/cosh_deg b/tests/02unit_functions/cosh_deg new file mode 100644 index 0000000..661f901 --- /dev/null +++ b/tests/02unit_functions/cosh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-140, 140, 0.1 +F=cosh(x) +C=cosh(d2r(x)) diff --git a/tests/02unit_functions/coshf b/tests/02unit_functions/coshf new file mode 100644 index 0000000..7cfa833 --- /dev/null +++ b/tests/02unit_functions/coshf @@ -0,0 +1,5 @@ +T=f +V=x +R=-40, 40, 0.025 +F=cosh(x) +C=coshf(x) diff --git a/tests/02unit_functions/coshf_deg b/tests/02unit_functions/coshf_deg new file mode 100644 index 0000000..1d80afd --- /dev/null +++ b/tests/02unit_functions/coshf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-40, 40, 0.1 +F=cosh(x) +C=coshf(d2r(x)) diff --git a/tests/02unit_functions/coshl b/tests/02unit_functions/coshl new file mode 100644 index 0000000..82b1e8f --- /dev/null +++ b/tests/02unit_functions/coshl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-140, 140, 0.1 +F=cosh(x) +C=coshl(x) diff --git a/tests/02unit_functions/coshl_deg b/tests/02unit_functions/coshl_deg new file mode 100644 index 0000000..9a73466 --- /dev/null +++ b/tests/02unit_functions/coshl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-140, 140, 0.1 +F=cosh(x) +C=coshl(d2r(x)) diff --git a/tests/02unit_functions/coshm b/tests/02unit_functions/coshm new file mode 100644 index 0000000..99cd539 --- /dev/null +++ b/tests/02unit_functions/coshm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-140, 140, 0.1 +F=cosh(x) +C=MpfrFloat::cosh(x) diff --git a/tests/02unit_functions/coshm_deg b/tests/02unit_functions/coshm_deg new file mode 100644 index 0000000..104ad77 --- /dev/null +++ b/tests/02unit_functions/coshm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-140, 140, 0.1 +F=cosh(x) +C=MpfrFloat::cosh(d2r(x)) diff --git a/tests/02unit_functions/cosl b/tests/02unit_functions/cosl new file mode 100644 index 0000000..d1854dc --- /dev/null +++ b/tests/02unit_functions/cosl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-40000, 40000, 5 +F=cos(x) +C=cosl(x) diff --git a/tests/02unit_functions/cosl_deg b/tests/02unit_functions/cosl_deg new file mode 100644 index 0000000..92e70bd --- /dev/null +++ b/tests/02unit_functions/cosl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-40000, 40000, 5 +F=cos(x) +C=cosl(d2r(x)) diff --git a/tests/02unit_functions/cosm b/tests/02unit_functions/cosm new file mode 100644 index 0000000..1f0dae2 --- /dev/null +++ b/tests/02unit_functions/cosm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-40000, 40000, 5 +F=cos(x) +C=MpfrFloat::cos(x) diff --git a/tests/02unit_functions/cosm_deg b/tests/02unit_functions/cosm_deg new file mode 100644 index 0000000..bae1a86 --- /dev/null +++ b/tests/02unit_functions/cosm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-40000, 40000, 5 +F=cos(x) +C=MpfrFloat::cos(d2r(x)) diff --git a/tests/02unit_functions/exp b/tests/02unit_functions/exp new file mode 100644 index 0000000..d05c279 --- /dev/null +++ b/tests/02unit_functions/exp @@ -0,0 +1,5 @@ +T=d +V=x +R=-90, 90, 0.01 +F=exp(x) +C=exp(x) diff --git a/tests/02unit_functions/exp2 b/tests/02unit_functions/exp2 new file mode 100644 index 0000000..8649683 --- /dev/null +++ b/tests/02unit_functions/exp2 @@ -0,0 +1,5 @@ +T=d +V=x +R=-90, 90, 0.01 +F=exp2(x) +C=exp(x*fp_const_log2<Value_t>()) diff --git a/tests/02unit_functions/exp2f b/tests/02unit_functions/exp2f new file mode 100644 index 0000000..ad7a0b0 --- /dev/null +++ b/tests/02unit_functions/exp2f @@ -0,0 +1,5 @@ +T=f +V=x +R=-90, 90, 0.01 +F=exp2(x) +C=expf(x*fp_const_log2<Value_t>()) diff --git a/tests/02unit_functions/exp2l b/tests/02unit_functions/exp2l new file mode 100644 index 0000000..d365a8d --- /dev/null +++ b/tests/02unit_functions/exp2l @@ -0,0 +1,5 @@ +T=ld +V=x +R=-90, 90, 0.01 +F=exp2(x) +C=expl(x*fp_const_log2<Value_t>()) diff --git a/tests/02unit_functions/exp2m b/tests/02unit_functions/exp2m new file mode 100644 index 0000000..1c93425 --- /dev/null +++ b/tests/02unit_functions/exp2m @@ -0,0 +1,5 @@ +T=mf +V=x +R=-90, 90, 0.02 +F=exp2(x) +C=MpfrFloat::exp2(x) diff --git a/tests/02unit_functions/expf b/tests/02unit_functions/expf new file mode 100644 index 0000000..5c88609 --- /dev/null +++ b/tests/02unit_functions/expf @@ -0,0 +1,5 @@ +T=f +V=x +R=-20, 20, 0.01 +F=exp(x) +C=expf(x) diff --git a/tests/02unit_functions/expl b/tests/02unit_functions/expl new file mode 100644 index 0000000..7e86303 --- /dev/null +++ b/tests/02unit_functions/expl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-90, 90, 0.01 +F=exp(x) +C=expl(x) diff --git a/tests/02unit_functions/expm b/tests/02unit_functions/expm new file mode 100644 index 0000000..c3f5310 --- /dev/null +++ b/tests/02unit_functions/expm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-90, 90, 0.02 +F=exp(x) +C=MpfrFloat::exp(x) diff --git a/tests/02unit_functions/floor b/tests/02unit_functions/floor new file mode 100644 index 0000000..230d4cf --- /dev/null +++ b/tests/02unit_functions/floor @@ -0,0 +1,5 @@ +T=d +V=x +R=-10, 10, 0.25 +F=floor(x) +C=floor(x) diff --git a/tests/02unit_functions/floorf b/tests/02unit_functions/floorf new file mode 100644 index 0000000..b87db8f --- /dev/null +++ b/tests/02unit_functions/floorf @@ -0,0 +1,5 @@ +T=f +V=x +R=-10, 10, 0.25 +F=floor(x) +C=floorf(x) diff --git a/tests/02unit_functions/floorl b/tests/02unit_functions/floorl new file mode 100644 index 0000000..e31112b --- /dev/null +++ b/tests/02unit_functions/floorl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-10, 10, 0.25 +F=floor(x) +C=floorl(x) diff --git a/tests/02unit_functions/floorm b/tests/02unit_functions/floorm new file mode 100644 index 0000000..cd3648c --- /dev/null +++ b/tests/02unit_functions/floorm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-10, 10, 0.25 +F=floor(x) +C=MpfrFloat::floor(x) diff --git a/tests/02unit_functions/hypot b/tests/02unit_functions/hypot new file mode 100644 index 0000000..a6c0a1b --- /dev/null +++ b/tests/02unit_functions/hypot @@ -0,0 +1,5 @@ +T=d +V=x,y +R=-4, 4, 0.05 +F=hypot(x,y) +C=sqrt(x*x + y*y) diff --git a/tests/02unit_functions/hypotf b/tests/02unit_functions/hypotf new file mode 100644 index 0000000..68862cd --- /dev/null +++ b/tests/02unit_functions/hypotf @@ -0,0 +1,5 @@ +T=f +V=x,y +R=-4, 4, 0.05 +F=hypot(x,y) +C=sqrtf(x*x + y*y) diff --git a/tests/02unit_functions/hypotl b/tests/02unit_functions/hypotl new file mode 100644 index 0000000..6417228 --- /dev/null +++ b/tests/02unit_functions/hypotl @@ -0,0 +1,5 @@ +T=ld +V=x,y +R=-4, 4, 0.05 +F=hypot(x,y) +C=sqrtl(x*x + y*y) diff --git a/tests/02unit_functions/hypotm b/tests/02unit_functions/hypotm new file mode 100644 index 0000000..58bb300 --- /dev/null +++ b/tests/02unit_functions/hypotm @@ -0,0 +1,5 @@ +T=mf +V=x,y +R=-4, 4, 0.05 +F=hypot(x,y) +C=MpfrFloat::hypot(x,y) diff --git a/tests/02unit_functions/if_d b/tests/02unit_functions/if_d new file mode 100644 index 0000000..04d3479 --- /dev/null +++ b/tests/02unit_functions/if_d @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y,z +R=-1.25,1.25,0.25 +F=if(x,y,z) +C=fp_abs(x) >= 0.5 ? y : z diff --git a/tests/02unit_functions/if_i b/tests/02unit_functions/if_i new file mode 100644 index 0000000..5d394ed --- /dev/null +++ b/tests/02unit_functions/if_i @@ -0,0 +1,5 @@ +T=li gi +V=x,y,z +R=-2,2,1 +F=if(x,y,z) +C=(x!=0) ? y : z diff --git a/tests/02unit_functions/imag b/tests/02unit_functions/imag new file mode 100644 index 0000000..6468817 --- /dev/null +++ b/tests/02unit_functions/imag @@ -0,0 +1,5 @@ +T=cd cf cld +V=x +R=1e-6, 4000, 0.1 +F=imag(x) +C=fp_imag(x) diff --git a/tests/02unit_functions/int b/tests/02unit_functions/int new file mode 100644 index 0000000..937f132 --- /dev/null +++ b/tests/02unit_functions/int @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-4000, 4000, 0.1 +F=int(x) +C=fp_floor(x+0.5) diff --git a/tests/02unit_functions/log b/tests/02unit_functions/log new file mode 100644 index 0000000..13fb797 --- /dev/null +++ b/tests/02unit_functions/log @@ -0,0 +1,5 @@ +T=d cd +V=x +R=1e-6, 4000, 0.1 +F=log(x) +C=log(x) diff --git a/tests/02unit_functions/log10 b/tests/02unit_functions/log10 new file mode 100644 index 0000000..fb595b5 --- /dev/null +++ b/tests/02unit_functions/log10 @@ -0,0 +1,5 @@ +T=d +V=x +R=1e-6, 4000, 0.1 +F=log10(x) +C=log(x)*0.43429448190325182765112891891660508229 diff --git a/tests/02unit_functions/log10f b/tests/02unit_functions/log10f new file mode 100644 index 0000000..1448fed --- /dev/null +++ b/tests/02unit_functions/log10f @@ -0,0 +1,5 @@ +T=f +V=x +R=1e-6, 400, 0.1 +F=log10(x) +C=log10f(x) diff --git a/tests/02unit_functions/log10l b/tests/02unit_functions/log10l new file mode 100644 index 0000000..61aafd7 --- /dev/null +++ b/tests/02unit_functions/log10l @@ -0,0 +1,5 @@ +T=ld +V=x +R=1e-6, 400, 0.1 +F=log10(x) +C=log10l(x) diff --git a/tests/02unit_functions/log10m b/tests/02unit_functions/log10m new file mode 100644 index 0000000..453f90a --- /dev/null +++ b/tests/02unit_functions/log10m @@ -0,0 +1,5 @@ +T=mf +V=x +R=1e-6, 400, 0.1 +F=log10(x) +C=MpfrFloat::log10(x) diff --git a/tests/02unit_functions/log2 b/tests/02unit_functions/log2 new file mode 100644 index 0000000..0ce4db6 --- /dev/null +++ b/tests/02unit_functions/log2 @@ -0,0 +1,5 @@ +T=d +V=x +R=1e-6, 4000, 0.1 +F=log2(x) +C=log(x)*1.4426950408889634073599246810018921374266 diff --git a/tests/02unit_functions/log2f b/tests/02unit_functions/log2f new file mode 100644 index 0000000..6835620 --- /dev/null +++ b/tests/02unit_functions/log2f @@ -0,0 +1,5 @@ +T=f +V=x +R=1e-6, 400, 0.1 +F=log2(x) +C=logf(x)*1.4426950408889634073599246810018921374266 diff --git a/tests/02unit_functions/log2l b/tests/02unit_functions/log2l new file mode 100644 index 0000000..420e719 --- /dev/null +++ b/tests/02unit_functions/log2l @@ -0,0 +1,5 @@ +T=ld +V=x +R=1e-6, 400, 0.1 +F=log2(x) +C=logl(x)*1.4426950408889634073599246810018921374266 diff --git a/tests/02unit_functions/log2m b/tests/02unit_functions/log2m new file mode 100644 index 0000000..16f0d8d --- /dev/null +++ b/tests/02unit_functions/log2m @@ -0,0 +1,5 @@ +T=mf +V=x +R=1e-6, 400, 0.1 +F=log2(x) +C=MpfrFloat::log2(x) diff --git a/tests/02unit_functions/log_cd b/tests/02unit_functions/log_cd new file mode 100644 index 0000000..77c63a9 --- /dev/null +++ b/tests/02unit_functions/log_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x +R=-4000-0.5i, 4000+0.5i, 0.3+3.75e-05i +F=log(x) +C=std::log(x) diff --git a/tests/02unit_functions/logf b/tests/02unit_functions/logf new file mode 100644 index 0000000..66171a1 --- /dev/null +++ b/tests/02unit_functions/logf @@ -0,0 +1,5 @@ +T=f +V=x +R=1e-6, 400, 0.1 +F=log(x) +C=logf(x) diff --git a/tests/02unit_functions/logl b/tests/02unit_functions/logl new file mode 100644 index 0000000..7e271b8 --- /dev/null +++ b/tests/02unit_functions/logl @@ -0,0 +1,5 @@ +T=ld +V=x +R=1e-6, 400, 0.1 +F=log(x) +C=logl(x) diff --git a/tests/02unit_functions/logm b/tests/02unit_functions/logm new file mode 100644 index 0000000..31796de --- /dev/null +++ b/tests/02unit_functions/logm @@ -0,0 +1,5 @@ +T=mf +V=x +R=1e-6, 400, 0.1 +F=log(x) +C=MpfrFloat::log(x) diff --git a/tests/02unit_functions/max b/tests/02unit_functions/max new file mode 100644 index 0000000..628f649 --- /dev/null +++ b/tests/02unit_functions/max @@ -0,0 +1,5 @@ +T=d f ld mf li gi cd cf cld +V=x,y +R=-4, 4, 1 +F=max(x,y) +C=x>y ? x : y diff --git a/tests/02unit_functions/min b/tests/02unit_functions/min new file mode 100644 index 0000000..bd1d2a6 --- /dev/null +++ b/tests/02unit_functions/min @@ -0,0 +1,5 @@ +T=d f ld mf li gi cd cf cld +V=x,y +R=-4, 4, 1 +F=min(x,y) +C=x<y ? x : y diff --git a/tests/02unit_functions/polar b/tests/02unit_functions/polar new file mode 100644 index 0000000..75de241 --- /dev/null +++ b/tests/02unit_functions/polar @@ -0,0 +1,5 @@ +T=cd cf cld +V=x,y +R=0.01, 4, 0.05 +F=polar(x,y) +C=fp_polar(x,y) diff --git a/tests/02unit_functions/pow_neg b/tests/02unit_functions/pow_neg new file mode 100644 index 0000000..ce23e35 --- /dev/null +++ b/tests/02unit_functions/pow_neg @@ -0,0 +1,5 @@ +T=d +V=x,y +R=1,20,1 +F=pow(-x*0.25,y) +C=pow(-x*0.25,y) diff --git a/tests/02unit_functions/pow_negf b/tests/02unit_functions/pow_negf new file mode 100644 index 0000000..91b1bcf --- /dev/null +++ b/tests/02unit_functions/pow_negf @@ -0,0 +1,5 @@ +T=f +V=x,y +R=1,20,1 +F=pow(-x*0.25,y) +C=powf(-x*0.25,y) diff --git a/tests/02unit_functions/pow_negl b/tests/02unit_functions/pow_negl new file mode 100644 index 0000000..0c635c5 --- /dev/null +++ b/tests/02unit_functions/pow_negl @@ -0,0 +1,5 @@ +T=ld +V=x,y +R=1,20,1 +F=pow(-x*0.25,y) +C=powl(-x*0.25,y) diff --git a/tests/02unit_functions/pow_negm b/tests/02unit_functions/pow_negm new file mode 100644 index 0000000..47fa878 --- /dev/null +++ b/tests/02unit_functions/pow_negm @@ -0,0 +1,5 @@ +T=mf +V=x,y +R=1,20,1 +F=pow(-x*0.25,y) +C=MpfrFloat::pow(-x*0.25,y) diff --git a/tests/02unit_functions/pow_pos b/tests/02unit_functions/pow_pos new file mode 100644 index 0000000..c7cc75c --- /dev/null +++ b/tests/02unit_functions/pow_pos @@ -0,0 +1,5 @@ +T=d +V=x,y +R=0.01, 4, 0.05 +F=pow(x,y) +C=pow(x,y) diff --git a/tests/02unit_functions/pow_posf b/tests/02unit_functions/pow_posf new file mode 100644 index 0000000..003ae1e --- /dev/null +++ b/tests/02unit_functions/pow_posf @@ -0,0 +1,5 @@ +T=f +V=x,y +R=0.01, 4, 0.05 +F=pow(x,y) +C=powf(x,y) diff --git a/tests/02unit_functions/pow_posl b/tests/02unit_functions/pow_posl new file mode 100644 index 0000000..ecb2c67 --- /dev/null +++ b/tests/02unit_functions/pow_posl @@ -0,0 +1,5 @@ +T=ld +V=x,y +R=0.01, 4, 0.05 +F=pow(x,y) +C=powl(x,y) diff --git a/tests/02unit_functions/pow_posm b/tests/02unit_functions/pow_posm new file mode 100644 index 0000000..779cdb6 --- /dev/null +++ b/tests/02unit_functions/pow_posm @@ -0,0 +1,5 @@ +T=mf +V=x,y +R=0.01, 4, 0.05 +F=pow(x,y) +C=MpfrFloat::pow(x,y) diff --git a/tests/02unit_functions/real b/tests/02unit_functions/real new file mode 100644 index 0000000..9b4de48 --- /dev/null +++ b/tests/02unit_functions/real @@ -0,0 +1,5 @@ +T=cd cf cld +V=x +R=1e-6, 4000, 0.1 +F=real(x) +C=fp_real(x) diff --git a/tests/02unit_functions/sin b/tests/02unit_functions/sin new file mode 100644 index 0000000..15381bb --- /dev/null +++ b/tests/02unit_functions/sin @@ -0,0 +1,5 @@ +T=d +V=x +R=-40000, 40000, 5 +F=sin(x) +C=sin(x) diff --git a/tests/02unit_functions/sin_cd b/tests/02unit_functions/sin_cd new file mode 100644 index 0000000..078286f --- /dev/null +++ b/tests/02unit_functions/sin_cd @@ -0,0 +1,5 @@ +T=cd +V=x +R=-40000+200i, 40000-200i, 5-0.025i +F=sin(x) +C=sin(x) diff --git a/tests/02unit_functions/sin_cf b/tests/02unit_functions/sin_cf new file mode 100644 index 0000000..7a7f405 --- /dev/null +++ b/tests/02unit_functions/sin_cf @@ -0,0 +1,5 @@ +T=cf +V=x +R=-40+0.5i, 40-0.5i, 0.1-0.00125i +F=sin(x) +C=sin(x) diff --git a/tests/02unit_functions/sin_deg b/tests/02unit_functions/sin_deg new file mode 100644 index 0000000..bb4d998 --- /dev/null +++ b/tests/02unit_functions/sin_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-40000, 40000, 5 +F=sin(x) +C=sin(d2r(x)) diff --git a/tests/02unit_functions/sinf b/tests/02unit_functions/sinf new file mode 100644 index 0000000..0561a8d --- /dev/null +++ b/tests/02unit_functions/sinf @@ -0,0 +1,5 @@ +T=f +V=x +R=-40000, 40000, 5 +F=sin(x) +C=sinf(x) diff --git a/tests/02unit_functions/sinf_deg b/tests/02unit_functions/sinf_deg new file mode 100644 index 0000000..39335fb --- /dev/null +++ b/tests/02unit_functions/sinf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-400, 400, 5 +F=sin(x) +C=sinf(d2r(x)) diff --git a/tests/02unit_functions/sinh b/tests/02unit_functions/sinh new file mode 100644 index 0000000..cae9a88 --- /dev/null +++ b/tests/02unit_functions/sinh @@ -0,0 +1,5 @@ +T=d +V=x +R=-400, 400, 0.1 +F=sinh(x) +C=sinh(x) diff --git a/tests/02unit_functions/sinh_deg b/tests/02unit_functions/sinh_deg new file mode 100644 index 0000000..13aef19 --- /dev/null +++ b/tests/02unit_functions/sinh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-400, 400, 0.1 +F=sinh(x) +C=sinh(d2r(x)) diff --git a/tests/02unit_functions/sinhf b/tests/02unit_functions/sinhf new file mode 100644 index 0000000..30e1271 --- /dev/null +++ b/tests/02unit_functions/sinhf @@ -0,0 +1,5 @@ +T=f +V=x +R=-40, 40, 0.1 +F=sinh(x) +C=sinhf(x) diff --git a/tests/02unit_functions/sinhf_deg b/tests/02unit_functions/sinhf_deg new file mode 100644 index 0000000..f6f0583 --- /dev/null +++ b/tests/02unit_functions/sinhf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-400, 400, 0.1 +F=sinh(x) +C=sinhf(d2r(x)) diff --git a/tests/02unit_functions/sinhl b/tests/02unit_functions/sinhl new file mode 100644 index 0000000..335c698 --- /dev/null +++ b/tests/02unit_functions/sinhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-400, 400, 0.1 +F=sinh(x) +C=sinhl(x) diff --git a/tests/02unit_functions/sinhl_deg b/tests/02unit_functions/sinhl_deg new file mode 100644 index 0000000..61ad0d7 --- /dev/null +++ b/tests/02unit_functions/sinhl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-400, 400, 0.1 +F=sinh(x) +C=sinhl(d2r(x)) diff --git a/tests/02unit_functions/sinhm b/tests/02unit_functions/sinhm new file mode 100644 index 0000000..c29f910 --- /dev/null +++ b/tests/02unit_functions/sinhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-400, 400, 0.1 +F=sinh(x) +C=MpfrFloat::sinh(x) diff --git a/tests/02unit_functions/sinhm_deg b/tests/02unit_functions/sinhm_deg new file mode 100644 index 0000000..fc5e1d6 --- /dev/null +++ b/tests/02unit_functions/sinhm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-400, 400, 0.1 +F=sinh(x) +C=MpfrFloat::sinh(d2r(x)) diff --git a/tests/02unit_functions/sinl b/tests/02unit_functions/sinl new file mode 100644 index 0000000..0506893 --- /dev/null +++ b/tests/02unit_functions/sinl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-40000, 40000, 5 +F=sin(x) +C=sinl(x) diff --git a/tests/02unit_functions/sinl_deg b/tests/02unit_functions/sinl_deg new file mode 100644 index 0000000..1549d2a --- /dev/null +++ b/tests/02unit_functions/sinl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-40000, 40000, 5 +F=sin(x) +C=sinl(d2r(x)) diff --git a/tests/02unit_functions/sinm b/tests/02unit_functions/sinm new file mode 100644 index 0000000..9eb826f --- /dev/null +++ b/tests/02unit_functions/sinm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-40000, 40000, 5 +F=sin(x) +C=MpfrFloat::sin(x) diff --git a/tests/02unit_functions/sinm_deg b/tests/02unit_functions/sinm_deg new file mode 100644 index 0000000..a6c6a9e --- /dev/null +++ b/tests/02unit_functions/sinm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-40000, 40000, 5 +F=sin(x) +C=MpfrFloat::sin(d2r(x)) diff --git a/tests/02unit_functions/sqrt b/tests/02unit_functions/sqrt new file mode 100644 index 0000000..2d1e4a3 --- /dev/null +++ b/tests/02unit_functions/sqrt @@ -0,0 +1,5 @@ +T=d +V=x +R=0, 100000, 1000 +F=sqrt(x) +C=sqrt(x) diff --git a/tests/02unit_functions/sqrt_cd b/tests/02unit_functions/sqrt_cd new file mode 100644 index 0000000..5630710 --- /dev/null +++ b/tests/02unit_functions/sqrt_cd @@ -0,0 +1,5 @@ +T=cd cf +V=x +R=-100000, 100000, 1000 +F=sqrt(x) +C=std::sqrt(x) diff --git a/tests/02unit_functions/sqrtf b/tests/02unit_functions/sqrtf new file mode 100644 index 0000000..a7f596d --- /dev/null +++ b/tests/02unit_functions/sqrtf @@ -0,0 +1,5 @@ +T=f +V=x +R=0, 100000, 1000 +F=sqrt(x) +C=sqrtf(x) diff --git a/tests/02unit_functions/sqrtl b/tests/02unit_functions/sqrtl new file mode 100644 index 0000000..c3e40d1 --- /dev/null +++ b/tests/02unit_functions/sqrtl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0, 100000, 1000 +F=sqrt(x) +C=sqrtl(x) diff --git a/tests/02unit_functions/sqrtm b/tests/02unit_functions/sqrtm new file mode 100644 index 0000000..1b83272 --- /dev/null +++ b/tests/02unit_functions/sqrtm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0, 100000, 1000 +F=sqrt(x) +C=MpfrFloat::sqrt(x) diff --git a/tests/02unit_functions/tan b/tests/02unit_functions/tan new file mode 100644 index 0000000..13ae12f --- /dev/null +++ b/tests/02unit_functions/tan @@ -0,0 +1,5 @@ +T=d +V=x +R=-1.3, 1.3, 0.05 +F=tan(x) +C=tan(x) diff --git a/tests/02unit_functions/tan_deg b/tests/02unit_functions/tan_deg new file mode 100644 index 0000000..11e372a --- /dev/null +++ b/tests/02unit_functions/tan_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-89, 89, 0.25 +F=tan(x) +C=tan(d2r(x)) diff --git a/tests/02unit_functions/tanf b/tests/02unit_functions/tanf new file mode 100644 index 0000000..0ec3988 --- /dev/null +++ b/tests/02unit_functions/tanf @@ -0,0 +1,5 @@ +T=f +V=x +R=-1.3, 1.3, 0.05 +F=tan(x) +C=tanf(x) diff --git a/tests/02unit_functions/tanf_deg b/tests/02unit_functions/tanf_deg new file mode 100644 index 0000000..16de0db --- /dev/null +++ b/tests/02unit_functions/tanf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-89, 89, 0.25 +F=tan(x) +C=tanf(d2r(x)) diff --git a/tests/02unit_functions/tanh b/tests/02unit_functions/tanh new file mode 100644 index 0000000..dd033c4 --- /dev/null +++ b/tests/02unit_functions/tanh @@ -0,0 +1,5 @@ +T=d +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=tanh(x) diff --git a/tests/02unit_functions/tanh_deg b/tests/02unit_functions/tanh_deg new file mode 100644 index 0000000..b0d251d --- /dev/null +++ b/tests/02unit_functions/tanh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=tanh(d2r(x)) diff --git a/tests/02unit_functions/tanhf b/tests/02unit_functions/tanhf new file mode 100644 index 0000000..d0b930b --- /dev/null +++ b/tests/02unit_functions/tanhf @@ -0,0 +1,5 @@ +T=f +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=tanhf(x) diff --git a/tests/02unit_functions/tanhf_deg b/tests/02unit_functions/tanhf_deg new file mode 100644 index 0000000..7c8d276 --- /dev/null +++ b/tests/02unit_functions/tanhf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=tanhf(d2r(x)) diff --git a/tests/02unit_functions/tanhl b/tests/02unit_functions/tanhl new file mode 100644 index 0000000..d615f1f --- /dev/null +++ b/tests/02unit_functions/tanhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=tanhl(x) diff --git a/tests/02unit_functions/tanhl_deg b/tests/02unit_functions/tanhl_deg new file mode 100644 index 0000000..05e23e7 --- /dev/null +++ b/tests/02unit_functions/tanhl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=tanhl(d2r(x)) diff --git a/tests/02unit_functions/tanhm b/tests/02unit_functions/tanhm new file mode 100644 index 0000000..93c7f7d --- /dev/null +++ b/tests/02unit_functions/tanhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=MpfrFloat::tanh(x) diff --git a/tests/02unit_functions/tanhm_deg b/tests/02unit_functions/tanhm_deg new file mode 100644 index 0000000..c2fc737 --- /dev/null +++ b/tests/02unit_functions/tanhm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-40000, 40000, 5 +F=tanh(x) +C=MpfrFloat::tanh(d2r(x)) diff --git a/tests/02unit_functions/tanl b/tests/02unit_functions/tanl new file mode 100644 index 0000000..a5e8778 --- /dev/null +++ b/tests/02unit_functions/tanl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-1.3, 1.3, 0.05 +F=tan(x) +C=tanl(x) diff --git a/tests/02unit_functions/tanl_deg b/tests/02unit_functions/tanl_deg new file mode 100644 index 0000000..e1ffba5 --- /dev/null +++ b/tests/02unit_functions/tanl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=-89, 89, 0.25 +F=tan(x) +C=tanl(d2r(x)) diff --git a/tests/02unit_functions/tanm b/tests/02unit_functions/tanm new file mode 100644 index 0000000..90d96d2 --- /dev/null +++ b/tests/02unit_functions/tanm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-1.3, 1.3, 0.05 +F=tan(x) +C=MpfrFloat::tan(x) diff --git a/tests/02unit_functions/tanm_deg b/tests/02unit_functions/tanm_deg new file mode 100644 index 0000000..447e3f3 --- /dev/null +++ b/tests/02unit_functions/tanm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=-89, 89, 0.25 +F=tan(x) +C=MpfrFloat::tan(d2r(x)) diff --git a/tests/02unit_functions/trunc b/tests/02unit_functions/trunc new file mode 100644 index 0000000..749cbb8 --- /dev/null +++ b/tests/02unit_functions/trunc @@ -0,0 +1,5 @@ +T=d +V=x +R=-4000, 4000, 0.1 +F=trunc(x) +C=x<0 ? ceil(x) : floor(x) diff --git a/tests/02unit_functions/truncf b/tests/02unit_functions/truncf new file mode 100644 index 0000000..eb9435f --- /dev/null +++ b/tests/02unit_functions/truncf @@ -0,0 +1,5 @@ +T=f +V=x +R=-400, 400, 0.1 +F=trunc(x) +C=fp_trunc(x) diff --git a/tests/02unit_functions/truncl b/tests/02unit_functions/truncl new file mode 100644 index 0000000..4bb3bec --- /dev/null +++ b/tests/02unit_functions/truncl @@ -0,0 +1,5 @@ +T=ld +V=x +R=-400, 400, 0.1 +F=trunc(x) +C=fp_trunc(x) diff --git a/tests/02unit_functions/truncm b/tests/02unit_functions/truncm new file mode 100644 index 0000000..2d539cc --- /dev/null +++ b/tests/02unit_functions/truncm @@ -0,0 +1,5 @@ +T=mf +V=x +R=-400, 400, 0.1 +F=trunc(x) +C=MpfrFloat::trunc(x) diff --git a/tests/03unit_constants/e_d b/tests/03unit_constants/e_d new file mode 100644 index 0000000..fc7f398 --- /dev/null +++ b/tests/03unit_constants/e_d @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=x*0+ naturalnumber +C=exp(x*0+1) diff --git a/tests/03unit_constants/e_f b/tests/03unit_constants/e_f new file mode 100644 index 0000000..af152cb --- /dev/null +++ b/tests/03unit_constants/e_f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=x*0+ naturalnumber +C=expf(x*0+1) diff --git a/tests/03unit_constants/e_ld b/tests/03unit_constants/e_ld new file mode 100644 index 0000000..6547d34 --- /dev/null +++ b/tests/03unit_constants/e_ld @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=x*0+ naturalnumber +C=expl(x*0+1) diff --git a/tests/03unit_constants/e_mpfr b/tests/03unit_constants/e_mpfr new file mode 100644 index 0000000..9c51f2f --- /dev/null +++ b/tests/03unit_constants/e_mpfr @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=x*0+ naturalnumber +C=MpfrFloat::exp(x*0+1) diff --git a/tests/03unit_constants/l10_d b/tests/03unit_constants/l10_d new file mode 100644 index 0000000..d709e72 --- /dev/null +++ b/tests/03unit_constants/l10_d @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=x*0+ logten +C=log(x*0+10) diff --git a/tests/03unit_constants/l10_f b/tests/03unit_constants/l10_f new file mode 100644 index 0000000..b970ee5 --- /dev/null +++ b/tests/03unit_constants/l10_f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=x*0+ logten +C=logf(x*0+10) diff --git a/tests/03unit_constants/l10_ld b/tests/03unit_constants/l10_ld new file mode 100644 index 0000000..fb18983 --- /dev/null +++ b/tests/03unit_constants/l10_ld @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=x*0+ logten +C=logl(x*0+10) diff --git a/tests/03unit_constants/l10_mpfr b/tests/03unit_constants/l10_mpfr new file mode 100644 index 0000000..b4cb87d --- /dev/null +++ b/tests/03unit_constants/l10_mpfr @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=x*0+ logten +C=MpfrFloat::log(x*0+10) diff --git a/tests/03unit_constants/l2_d b/tests/03unit_constants/l2_d new file mode 100644 index 0000000..5a36bd7 --- /dev/null +++ b/tests/03unit_constants/l2_d @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=x*0+ logtwo +C=log(x*0+2) diff --git a/tests/03unit_constants/l2_f b/tests/03unit_constants/l2_f new file mode 100644 index 0000000..8039ce0 --- /dev/null +++ b/tests/03unit_constants/l2_f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=x*0+ logtwo +C=logf(x*0+2) diff --git a/tests/03unit_constants/l2_ld b/tests/03unit_constants/l2_ld new file mode 100644 index 0000000..b208600 --- /dev/null +++ b/tests/03unit_constants/l2_ld @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=x*0+ logtwo +C=logl(x*0+2) diff --git a/tests/03unit_constants/l2_mpfr b/tests/03unit_constants/l2_mpfr new file mode 100644 index 0000000..e07c4a6 --- /dev/null +++ b/tests/03unit_constants/l2_mpfr @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=x*0+ logtwo +C=MpfrFloat::log(x*0+2) diff --git a/tests/03unit_constants/pi_d b/tests/03unit_constants/pi_d new file mode 100644 index 0000000..a2f442d --- /dev/null +++ b/tests/03unit_constants/pi_d @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=x*0+ pi +C=atan2(x*0,-1) diff --git a/tests/03unit_constants/pi_f b/tests/03unit_constants/pi_f new file mode 100644 index 0000000..d790d10 --- /dev/null +++ b/tests/03unit_constants/pi_f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=x*0+ pi +C=atan2f(x*0,-1) diff --git a/tests/03unit_constants/pi_ld b/tests/03unit_constants/pi_ld new file mode 100644 index 0000000..a0506a7 --- /dev/null +++ b/tests/03unit_constants/pi_ld @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=x*0+ pi +C=atan2l(x*0,-1) diff --git a/tests/03unit_constants/pi_mpfr b/tests/03unit_constants/pi_mpfr new file mode 100644 index 0000000..7e6c103 --- /dev/null +++ b/tests/03unit_constants/pi_mpfr @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=x*0+ pi +C=MpfrFloat::atan2(x*0,-1) diff --git a/tests/10optimizer_bytecode/abs b/tests/10optimizer_bytecode/abs new file mode 100644 index 0000000..a1b4f15 --- /dev/null +++ b/tests/10optimizer_bytecode/abs @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x +R=0,1,1 +F=(abs(-3))+x +C=(3)+x diff --git a/tests/10optimizer_bytecode/abscos b/tests/10optimizer_bytecode/abscos new file mode 100644 index 0000000..b80367a --- /dev/null +++ b/tests/10optimizer_bytecode/abscos @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=cos(abs(x)) +C=fp_cos(fp_abs(x)) diff --git a/tests/10optimizer_bytecode/abscosh b/tests/10optimizer_bytecode/abscosh new file mode 100644 index 0000000..7a9a36d --- /dev/null +++ b/tests/10optimizer_bytecode/abscosh @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=cosh(abs(x)) +C=fp_cosh(fp_abs(x)) diff --git a/tests/10optimizer_bytecode/abseq0 b/tests/10optimizer_bytecode/abseq0 new file mode 100644 index 0000000..b0caf58 --- /dev/null +++ b/tests/10optimizer_bytecode/abseq0 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(abs(x)=0) + (0=abs(x)) +C=fp_equal(fp_abs(x),0) + fp_equal(0,fp_abs(x)) diff --git a/tests/10optimizer_bytecode/absevenconstpow b/tests/10optimizer_bytecode/absevenconstpow new file mode 100644 index 0000000..c1798d8 --- /dev/null +++ b/tests/10optimizer_bytecode/absevenconstpow @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=0.001, 0.9, 0.01 +F=abs(x) ^ 1506 +C=fp_pow(fp_abs(x), 1506) diff --git a/tests/10optimizer_bytecode/absmulevenconstpow b/tests/10optimizer_bytecode/absmulevenconstpow new file mode 100644 index 0000000..af7d799 --- /dev/null +++ b/tests/10optimizer_bytecode/absmulevenconstpow @@ -0,0 +1,5 @@ +T=d f ld +V=x,y +R=0.001, 0.9, 0.01 +F=(abs(x)*y) ^ 1506 +C=fp_pow(fp_abs(x)*y, 1506) diff --git a/tests/10optimizer_bytecode/absneq0 b/tests/10optimizer_bytecode/absneq0 new file mode 100644 index 0000000..b0caf58 --- /dev/null +++ b/tests/10optimizer_bytecode/absneq0 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(abs(x)=0) + (0=abs(x)) +C=fp_equal(fp_abs(x),0) + fp_equal(0,fp_abs(x)) diff --git a/tests/10optimizer_bytecode/absneverneg b/tests/10optimizer_bytecode/absneverneg new file mode 100644 index 0000000..2469efe --- /dev/null +++ b/tests/10optimizer_bytecode/absneverneg @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.25 +F=abs(acos(x)) +C=fp_acos(x) diff --git a/tests/10optimizer_bytecode/absnot b/tests/10optimizer_bytecode/absnot new file mode 100644 index 0000000..e52a7dd --- /dev/null +++ b/tests/10optimizer_bytecode/absnot @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=!(abs(x)) +C=fp_not(fp_abs(x)) diff --git a/tests/10optimizer_bytecode/absnot2 b/tests/10optimizer_bytecode/absnot2 new file mode 100644 index 0000000..6a8c53a --- /dev/null +++ b/tests/10optimizer_bytecode/absnot2 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.25 +F=!acos(x) +C=fp_not(fp_acos(x)) diff --git a/tests/10optimizer_bytecode/absnot3 b/tests/10optimizer_bytecode/absnot3 new file mode 100644 index 0000000..8e1ce3c --- /dev/null +++ b/tests/10optimizer_bytecode/absnot3 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-1,1,0.25 +F=!(!(x&y)) +C=fp_not(fp_not(fp_and(x,y))) diff --git a/tests/10optimizer_bytecode/absnot4 b/tests/10optimizer_bytecode/absnot4 new file mode 100644 index 0000000..729e7e4 --- /dev/null +++ b/tests/10optimizer_bytecode/absnot4 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.25 +F=!(!acos(x)) +C=fp_not(fp_not(fp_acos(x))) diff --git a/tests/10optimizer_bytecode/absnotnotnot b/tests/10optimizer_bytecode/absnotnotnot new file mode 100644 index 0000000..eb45d70 --- /dev/null +++ b/tests/10optimizer_bytecode/absnotnotnot @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=!(!!((x*x))) +C=fp_not(fp_notNot((x*x))) diff --git a/tests/10optimizer_bytecode/absnzge b/tests/10optimizer_bytecode/absnzge new file mode 100644 index 0000000..9c8d288 --- /dev/null +++ b/tests/10optimizer_bytecode/absnzge @@ -0,0 +1,5 @@ +T=d li gi +V=x +R=-5,5,1 +F=sub(abs(x) >= 4, abs(x) >= 0) +C=userDefFuncSub({fp_greaterOrEq(fp_abs(x),4), fp_greaterOrEq(fp_abs(x),0)}) diff --git a/tests/10optimizer_bytecode/absnzlt b/tests/10optimizer_bytecode/absnzlt new file mode 100644 index 0000000..2618341 --- /dev/null +++ b/tests/10optimizer_bytecode/absnzlt @@ -0,0 +1,5 @@ +T=d li gi +V=x +R=-5,5,1 +F=sub(abs(x) < 4, abs(x) < 0) +C=userDefFuncSub({fp_less(fp_abs(x),4), fp_less(fp_abs(x),0)}) diff --git a/tests/10optimizer_bytecode/abssqr b/tests/10optimizer_bytecode/abssqr new file mode 100644 index 0000000..5265f05 --- /dev/null +++ b/tests/10optimizer_bytecode/abssqr @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=abs(x)*abs(x) +C=x*x diff --git a/tests/10optimizer_bytecode/absyxpow_neg b/tests/10optimizer_bytecode/absyxpow_neg new file mode 100644 index 0000000..c6fb507 --- /dev/null +++ b/tests/10optimizer_bytecode/absyxpow_neg @@ -0,0 +1,6 @@ +# y [isEvenInteger(y)&&!isEvenInteger(x*y)] cPow x cPow +T=d +V=x +R=-10,10,0.1 +F=(x^-4)^1.5 +C=fp_pow(fp_pow(x,-4),1.5) diff --git a/tests/10optimizer_bytecode/absyxpow_pos b/tests/10optimizer_bytecode/absyxpow_pos new file mode 100644 index 0000000..7547b25 --- /dev/null +++ b/tests/10optimizer_bytecode/absyxpow_pos @@ -0,0 +1,6 @@ +# y [isEvenInteger(y)&&!isEvenInteger(x*y)] cPow x cPow +T=d +V=x +R=-10,10,0.1 +F=(x^4)^1.5 +C=fp_pow(fp_pow(x,4),1.5) diff --git a/tests/10optimizer_bytecode/acos b/tests/10optimizer_bytecode/acos new file mode 100644 index 0000000..59ed768 --- /dev/null +++ b/tests/10optimizer_bytecode/acos @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=acos(0.7)+x +C=acos(0.7)+x diff --git a/tests/10optimizer_bytecode/acos_deg b/tests/10optimizer_bytecode/acos_deg new file mode 100644 index 0000000..f90ad1c --- /dev/null +++ b/tests/10optimizer_bytecode/acos_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=acos(0.7)+x +C=r2d(acos(0.7))+x diff --git a/tests/10optimizer_bytecode/acosf b/tests/10optimizer_bytecode/acosf new file mode 100644 index 0000000..6688f9e --- /dev/null +++ b/tests/10optimizer_bytecode/acosf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=acos(0.7)+x +C=acosf(0.7)+x diff --git a/tests/10optimizer_bytecode/acosf_deg b/tests/10optimizer_bytecode/acosf_deg new file mode 100644 index 0000000..04d94ae --- /dev/null +++ b/tests/10optimizer_bytecode/acosf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=acos(0.7)+x +C=r2d(acosf(0.7))+x diff --git a/tests/10optimizer_bytecode/acosh b/tests/10optimizer_bytecode/acosh new file mode 100644 index 0000000..73fa76b --- /dev/null +++ b/tests/10optimizer_bytecode/acosh @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=acosh(1.1)+x +C=log(1.1 + sqrt(1.1*1.1 - 1))+x diff --git a/tests/10optimizer_bytecode/acosh_deg b/tests/10optimizer_bytecode/acosh_deg new file mode 100644 index 0000000..58631ba --- /dev/null +++ b/tests/10optimizer_bytecode/acosh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=acosh(1.1)+x +C=r2d(log(1.1 + sqrt(1.1*1.1 - 1)))+x diff --git a/tests/10optimizer_bytecode/acoshcosh b/tests/10optimizer_bytecode/acoshcosh new file mode 100644 index 0000000..6ffcc99 --- /dev/null +++ b/tests/10optimizer_bytecode/acoshcosh @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=1,3,0.1 +F=cosh(acosh(x)) +C=fp_cosh(fp_acosh(x)) diff --git a/tests/10optimizer_bytecode/acoshf b/tests/10optimizer_bytecode/acoshf new file mode 100644 index 0000000..b15b9f2 --- /dev/null +++ b/tests/10optimizer_bytecode/acoshf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=acosh(1.1)+x +C=logf(1.1 + sqrtf(1.1*1.1 - 1))+x diff --git a/tests/10optimizer_bytecode/acoshf_deg b/tests/10optimizer_bytecode/acoshf_deg new file mode 100644 index 0000000..973eaeb --- /dev/null +++ b/tests/10optimizer_bytecode/acoshf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=acosh(1.1)+x +C=r2d(fp_acosh(1.1))+x diff --git a/tests/10optimizer_bytecode/acoshl b/tests/10optimizer_bytecode/acoshl new file mode 100644 index 0000000..6ebbaf4 --- /dev/null +++ b/tests/10optimizer_bytecode/acoshl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=acosh(1.1)+x +C=logl(1.1 + sqrtl(1.1*1.1 - 1))+x diff --git a/tests/10optimizer_bytecode/acoshl_deg b/tests/10optimizer_bytecode/acoshl_deg new file mode 100644 index 0000000..f5f494f --- /dev/null +++ b/tests/10optimizer_bytecode/acoshl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=acosh(1.1)+x +C=r2d(fp_acosh(1.1))+x diff --git a/tests/10optimizer_bytecode/acoshm b/tests/10optimizer_bytecode/acoshm new file mode 100644 index 0000000..b75b254 --- /dev/null +++ b/tests/10optimizer_bytecode/acoshm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=acosh(1.1)+x +C=MpfrFloat::acosh(1.1)+x diff --git a/tests/10optimizer_bytecode/acoshm_deg b/tests/10optimizer_bytecode/acoshm_deg new file mode 100644 index 0000000..09a7aaf --- /dev/null +++ b/tests/10optimizer_bytecode/acoshm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=acosh(1.1)+x +C=r2d(MpfrFloat::acosh(1.1))+x diff --git a/tests/10optimizer_bytecode/acoshsinh b/tests/10optimizer_bytecode/acoshsinh new file mode 100644 index 0000000..eb9fa21 --- /dev/null +++ b/tests/10optimizer_bytecode/acoshsinh @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=1.7, 3.7, 0.28 +F=sinh(acosh(x)) +C=fp_sinh(fp_acosh(x)) diff --git a/tests/10optimizer_bytecode/acosl b/tests/10optimizer_bytecode/acosl new file mode 100644 index 0000000..8d30758 --- /dev/null +++ b/tests/10optimizer_bytecode/acosl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=acos(0.7)+x +C=acosl(0.7)+x diff --git a/tests/10optimizer_bytecode/acosl_deg b/tests/10optimizer_bytecode/acosl_deg new file mode 100644 index 0000000..0e9c458 --- /dev/null +++ b/tests/10optimizer_bytecode/acosl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=acos(0.7)+x +C=r2d(acosl(0.7))+x diff --git a/tests/10optimizer_bytecode/acosm b/tests/10optimizer_bytecode/acosm new file mode 100644 index 0000000..fef677e --- /dev/null +++ b/tests/10optimizer_bytecode/acosm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=acos(0.7)+x +C=MpfrFloat::acos(0.7)+x diff --git a/tests/10optimizer_bytecode/acosm_deg b/tests/10optimizer_bytecode/acosm_deg new file mode 100644 index 0000000..ec5b146 --- /dev/null +++ b/tests/10optimizer_bytecode/acosm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=acos(0.7)+x +C=r2d(MpfrFloat::acos(0.7))+x diff --git a/tests/10optimizer_bytecode/add b/tests/10optimizer_bytecode/add new file mode 100644 index 0000000..7f7753b --- /dev/null +++ b/tests/10optimizer_bytecode/add @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=5+3+x +C=5+3+x diff --git a/tests/10optimizer_bytecode/add0 b/tests/10optimizer_bytecode/add0 new file mode 100644 index 0000000..66d1e9c --- /dev/null +++ b/tests/10optimizer_bytecode/add0 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=x+0+x +C=x+0+x diff --git a/tests/10optimizer_bytecode/addexp b/tests/10optimizer_bytecode/addexp new file mode 100644 index 0000000..b245a1c --- /dev/null +++ b/tests/10optimizer_bytecode/addexp @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-3,-3,0.7 +F=exp(x+4) +C=fp_exp(x+4) diff --git a/tests/10optimizer_bytecode/addexp2 b/tests/10optimizer_bytecode/addexp2 new file mode 100644 index 0000000..8a6174c --- /dev/null +++ b/tests/10optimizer_bytecode/addexp2 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-3,-3,0.7 +F=exp2(x+4) +C=fp_exp2(x+4) diff --git a/tests/10optimizer_bytecode/and b/tests/10optimizer_bytecode/and new file mode 100644 index 0000000..908d1df --- /dev/null +++ b/tests/10optimizer_bytecode/and @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5&3)+x+(5&0)+(0&5)+(0&0) +C=fp_and(5,3)+x+fp_and(5,0)+fp_and(0,5)+fp_and(0,0) diff --git a/tests/10optimizer_bytecode/asin b/tests/10optimizer_bytecode/asin new file mode 100644 index 0000000..4a1c56c --- /dev/null +++ b/tests/10optimizer_bytecode/asin @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=asin(0.7)+x +C=asin(0.7)+x diff --git a/tests/10optimizer_bytecode/asin_deg b/tests/10optimizer_bytecode/asin_deg new file mode 100644 index 0000000..4dc059c --- /dev/null +++ b/tests/10optimizer_bytecode/asin_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=asin(0.7)+x +C=r2d(asin(0.7))+x diff --git a/tests/10optimizer_bytecode/asinf b/tests/10optimizer_bytecode/asinf new file mode 100644 index 0000000..093d5e2 --- /dev/null +++ b/tests/10optimizer_bytecode/asinf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=asin(0.7)+x +C=asinf(0.7)+x diff --git a/tests/10optimizer_bytecode/asinf_deg b/tests/10optimizer_bytecode/asinf_deg new file mode 100644 index 0000000..5488122 --- /dev/null +++ b/tests/10optimizer_bytecode/asinf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=asin(0.7)+x +C=r2d(asinf(0.7))+x diff --git a/tests/10optimizer_bytecode/asinh b/tests/10optimizer_bytecode/asinh new file mode 100644 index 0000000..e4eb54f --- /dev/null +++ b/tests/10optimizer_bytecode/asinh @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=asinh(1.1)+x +C=log(1.1 + sqrt(1.1*1.1+1))+x diff --git a/tests/10optimizer_bytecode/asinh_deg b/tests/10optimizer_bytecode/asinh_deg new file mode 100644 index 0000000..e01a3a6 --- /dev/null +++ b/tests/10optimizer_bytecode/asinh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=asinh(1.1)+x +C=r2d(log(1.1 + sqrt(1.1*1.1+1)))+x diff --git a/tests/10optimizer_bytecode/asinhcosh b/tests/10optimizer_bytecode/asinhcosh new file mode 100644 index 0000000..a828791 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhcosh @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-0.7, 0.7, 0.28 +F=cosh(asinh(x)) +C=fp_cosh(fp_asinh(x)) diff --git a/tests/10optimizer_bytecode/asinhf b/tests/10optimizer_bytecode/asinhf new file mode 100644 index 0000000..deaad73 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=asinh(1.1)+x +C=logf(1.1 + sqrtf(1.1*1.1+1))+x diff --git a/tests/10optimizer_bytecode/asinhf_deg b/tests/10optimizer_bytecode/asinhf_deg new file mode 100644 index 0000000..da25424 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=asinh(1.1)+x +C=r2d(fp_asinh(1.1))+x diff --git a/tests/10optimizer_bytecode/asinhl b/tests/10optimizer_bytecode/asinhl new file mode 100644 index 0000000..3d5c661 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=asinh(1.1)+x +C=logl(1.1 + sqrtl(1.1*1.1+1))+x diff --git a/tests/10optimizer_bytecode/asinhl_deg b/tests/10optimizer_bytecode/asinhl_deg new file mode 100644 index 0000000..66a60a8 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=asinh(1.1)+x +C=r2d(fp_asinh(1.1))+x diff --git a/tests/10optimizer_bytecode/asinhm b/tests/10optimizer_bytecode/asinhm new file mode 100644 index 0000000..b7a9e27 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=asinh(1.1)+x +C=MpfrFloat::asinh(1.1)+x diff --git a/tests/10optimizer_bytecode/asinhm_deg b/tests/10optimizer_bytecode/asinhm_deg new file mode 100644 index 0000000..efef4f8 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=asinh(1.1)+x +C=r2d(MpfrFloat::asinh(1.1))+x diff --git a/tests/10optimizer_bytecode/asinhsinh b/tests/10optimizer_bytecode/asinhsinh new file mode 100644 index 0000000..84b37c9 --- /dev/null +++ b/tests/10optimizer_bytecode/asinhsinh @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-3,3,0.1 +F=sinh(asinh(x)) +C=fp_sinh(fp_asinh(x)) diff --git a/tests/10optimizer_bytecode/asinl b/tests/10optimizer_bytecode/asinl new file mode 100644 index 0000000..699680b --- /dev/null +++ b/tests/10optimizer_bytecode/asinl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=asin(0.7)+x +C=asinl(0.7)+x diff --git a/tests/10optimizer_bytecode/asinl_deg b/tests/10optimizer_bytecode/asinl_deg new file mode 100644 index 0000000..d37bf7f --- /dev/null +++ b/tests/10optimizer_bytecode/asinl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=asin(0.7)+x +C=r2d(asinl(0.7))+x diff --git a/tests/10optimizer_bytecode/asinm b/tests/10optimizer_bytecode/asinm new file mode 100644 index 0000000..81a8401 --- /dev/null +++ b/tests/10optimizer_bytecode/asinm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=asin(0.7)+x +C=MpfrFloat::asin(0.7)+x diff --git a/tests/10optimizer_bytecode/asinm_deg b/tests/10optimizer_bytecode/asinm_deg new file mode 100644 index 0000000..889adf0 --- /dev/null +++ b/tests/10optimizer_bytecode/asinm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=asin(0.7)+x +C=r2d(MpfrFloat::asin(0.7))+x diff --git a/tests/10optimizer_bytecode/atan b/tests/10optimizer_bytecode/atan new file mode 100644 index 0000000..6922e58 --- /dev/null +++ b/tests/10optimizer_bytecode/atan @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=atan(1.1)+x +C=atan(1.1)+x diff --git a/tests/10optimizer_bytecode/atan2 b/tests/10optimizer_bytecode/atan2 new file mode 100644 index 0000000..f0515b9 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2 @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=atan2(5,4)+x +C=atan2(5,4)+x diff --git a/tests/10optimizer_bytecode/atan2_deg b/tests/10optimizer_bytecode/atan2_deg new file mode 100644 index 0000000..a4a13e9 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=atan2(5,4)+x +C=r2d(atan2(5,4))+x diff --git a/tests/10optimizer_bytecode/atan2f b/tests/10optimizer_bytecode/atan2f new file mode 100644 index 0000000..515a460 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=atan2(5,4)+x +C=atan2f(5,4)+x diff --git a/tests/10optimizer_bytecode/atan2f_deg b/tests/10optimizer_bytecode/atan2f_deg new file mode 100644 index 0000000..f8c40e7 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2f_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=atan2(5,4)+x +C=r2d(atan2f(5,4))+x diff --git a/tests/10optimizer_bytecode/atan2l b/tests/10optimizer_bytecode/atan2l new file mode 100644 index 0000000..012e131 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2l @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=atan2(5,4)+x +C=atan2l(5,4)+x diff --git a/tests/10optimizer_bytecode/atan2l_deg b/tests/10optimizer_bytecode/atan2l_deg new file mode 100644 index 0000000..d2a8554 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2l_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=atan2(5,4)+x +C=r2d(atan2l(5,4))+x diff --git a/tests/10optimizer_bytecode/atan2m b/tests/10optimizer_bytecode/atan2m new file mode 100644 index 0000000..acfbec0 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2m @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=atan2(5,4)+x +C=MpfrFloat::atan2(5,4)+x diff --git a/tests/10optimizer_bytecode/atan2m_deg b/tests/10optimizer_bytecode/atan2m_deg new file mode 100644 index 0000000..6a6a886 --- /dev/null +++ b/tests/10optimizer_bytecode/atan2m_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=atan2(5,4)+x +C=r2d(MpfrFloat::atan2(5,4))+x diff --git a/tests/10optimizer_bytecode/atan2tan b/tests/10optimizer_bytecode/atan2tan new file mode 100644 index 0000000..ef464de --- /dev/null +++ b/tests/10optimizer_bytecode/atan2tan @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-3,3,0.11 +F=tan(atan2(x,y)) +C=fp_tan(fp_atan2(x,y)) diff --git a/tests/10optimizer_bytecode/atan_deg b/tests/10optimizer_bytecode/atan_deg new file mode 100644 index 0000000..99544ed --- /dev/null +++ b/tests/10optimizer_bytecode/atan_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=atan(1.1)+x +C=r2d(atan(1.1))+x diff --git a/tests/10optimizer_bytecode/atanf b/tests/10optimizer_bytecode/atanf new file mode 100644 index 0000000..2b51d89 --- /dev/null +++ b/tests/10optimizer_bytecode/atanf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=atan(1.1)+x +C=atanf(1.1)+x diff --git a/tests/10optimizer_bytecode/atanf_deg b/tests/10optimizer_bytecode/atanf_deg new file mode 100644 index 0000000..bfdb513 --- /dev/null +++ b/tests/10optimizer_bytecode/atanf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=atan(1.1)+x +C=r2d(atanf(1.1))+x diff --git a/tests/10optimizer_bytecode/atanh b/tests/10optimizer_bytecode/atanh new file mode 100644 index 0000000..3e8b320 --- /dev/null +++ b/tests/10optimizer_bytecode/atanh @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=atanh(0.7)+x +C=log( (1+0.7) / (1-0.7) ) * 0.5+x diff --git a/tests/10optimizer_bytecode/atanhf b/tests/10optimizer_bytecode/atanhf new file mode 100644 index 0000000..e6666fd --- /dev/null +++ b/tests/10optimizer_bytecode/atanhf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=atanh(0.7)+x +C=logf( (1+0.7) / (1-0.7) ) * 0.5+x diff --git a/tests/10optimizer_bytecode/atanhl b/tests/10optimizer_bytecode/atanhl new file mode 100644 index 0000000..5f0943a --- /dev/null +++ b/tests/10optimizer_bytecode/atanhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=atanh(0.7)+x +C=logl( (1+0.7) / (1-0.7) ) * 0.5+x diff --git a/tests/10optimizer_bytecode/atanhm b/tests/10optimizer_bytecode/atanhm new file mode 100644 index 0000000..d8b8ea3 --- /dev/null +++ b/tests/10optimizer_bytecode/atanhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=atanh(0.7)+x +C=MpfrFloat::atanh(0.7)+x diff --git a/tests/10optimizer_bytecode/atanl b/tests/10optimizer_bytecode/atanl new file mode 100644 index 0000000..a173b22 --- /dev/null +++ b/tests/10optimizer_bytecode/atanl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=atan(1.1)+x +C=atanl(1.1)+x diff --git a/tests/10optimizer_bytecode/atanl_deg b/tests/10optimizer_bytecode/atanl_deg new file mode 100644 index 0000000..f1e8793 --- /dev/null +++ b/tests/10optimizer_bytecode/atanl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=atan(1.1)+x +C=r2d(atanl(1.1))+x diff --git a/tests/10optimizer_bytecode/atanm b/tests/10optimizer_bytecode/atanm new file mode 100644 index 0000000..8c9c031 --- /dev/null +++ b/tests/10optimizer_bytecode/atanm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=atan(1.1)+x +C=MpfrFloat::atan(1.1)+x diff --git a/tests/10optimizer_bytecode/atanm_deg b/tests/10optimizer_bytecode/atanm_deg new file mode 100644 index 0000000..1a80979 --- /dev/null +++ b/tests/10optimizer_bytecode/atanm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=atan(1.1)+x +C=r2d(MpfrFloat::atan(1.1))+x diff --git a/tests/10optimizer_bytecode/cbrt b/tests/10optimizer_bytecode/cbrt new file mode 100644 index 0000000..723b4ac --- /dev/null +++ b/tests/10optimizer_bytecode/cbrt @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=cbrt(1.1)+x +C=exp(log(1.1) / 3)+x diff --git a/tests/10optimizer_bytecode/cbrtf b/tests/10optimizer_bytecode/cbrtf new file mode 100644 index 0000000..1c36d2e --- /dev/null +++ b/tests/10optimizer_bytecode/cbrtf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=cbrt(1.1)+x +C=fp_cbrt(1.1)+x diff --git a/tests/10optimizer_bytecode/cbrtl b/tests/10optimizer_bytecode/cbrtl new file mode 100644 index 0000000..0bf390b --- /dev/null +++ b/tests/10optimizer_bytecode/cbrtl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=cbrt(1.1)+x +C=fp_cbrt(1.1)+x diff --git a/tests/10optimizer_bytecode/cbrtm b/tests/10optimizer_bytecode/cbrtm new file mode 100644 index 0000000..81197c7 --- /dev/null +++ b/tests/10optimizer_bytecode/cbrtm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=cbrt(1.1)+x +C=MpfrFloat::cbrt(1.1)+x diff --git a/tests/10optimizer_bytecode/ceil b/tests/10optimizer_bytecode/ceil new file mode 100644 index 0000000..9728f55 --- /dev/null +++ b/tests/10optimizer_bytecode/ceil @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=ceil(1.1)+x +C=ceil(1.1)+x diff --git a/tests/10optimizer_bytecode/ceilf b/tests/10optimizer_bytecode/ceilf new file mode 100644 index 0000000..7279a80 --- /dev/null +++ b/tests/10optimizer_bytecode/ceilf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=ceil(1.1)+x +C=ceilf(1.1)+x diff --git a/tests/10optimizer_bytecode/ceill b/tests/10optimizer_bytecode/ceill new file mode 100644 index 0000000..c409c7e --- /dev/null +++ b/tests/10optimizer_bytecode/ceill @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=ceil(1.1)+x +C=ceill(1.1)+x diff --git a/tests/10optimizer_bytecode/ceilm b/tests/10optimizer_bytecode/ceilm new file mode 100644 index 0000000..de13d1d --- /dev/null +++ b/tests/10optimizer_bytecode/ceilm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=ceil(1.1)+x +C=MpfrFloat::ceil(1.1)+x diff --git a/tests/10optimizer_bytecode/ceilneg b/tests/10optimizer_bytecode/ceilneg new file mode 100644 index 0000000..bb932ff --- /dev/null +++ b/tests/10optimizer_bytecode/ceilneg @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=ceil(-x) +C=fp_ceil(-x) diff --git a/tests/10optimizer_bytecode/cmp_acos b/tests/10optimizer_bytecode/cmp_acos new file mode 100644 index 0000000..a6990e9 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_acos @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=1*(acos(x)=acos(0.75)) + \ + 2*(acos(x)<acos(0.75)) + \ + 4*(acos(x)<=acos(0.75)) + \ + 8*(acos(x)>acos(0.75)) + \ + 16*(acos(x)>=acos(0.75)) + \ + 32*(acos(x)!=acos(0.75)) +C=1*fp_equal(fp_acos(x),fp_acos(0.75)) + \ + 2*fp_less(fp_acos(x),fp_acos(0.75)) + \ + 4*fp_lessOrEq(fp_acos(x),fp_acos(0.75)) + \ + 8*fp_greater(fp_acos(x),fp_acos(0.75)) + \ + 16*fp_greaterOrEq(fp_acos(x),fp_acos(0.75)) + \ + 32*fp_nequal(fp_acos(x),fp_acos(0.75)) diff --git a/tests/10optimizer_bytecode/cmp_acos_outrange b/tests/10optimizer_bytecode/cmp_acos_outrange new file mode 100644 index 0000000..5e7cbe8 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_acos_outrange @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=1*(acos(x)=2) + \ + 2*(acos(x)<2) + \ + 4*(acos(x)<=2) + \ + 8*(acos(x)>2) + \ + 16*(acos(x)>=2) + \ + 32*(acos(x)!=2) +C=1*fp_equal(fp_acos(x),2) + \ + 2*fp_less(fp_acos(x),2) + \ + 4*fp_lessOrEq(fp_acos(x),2) + \ + 8*fp_greater(fp_acos(x),2) + \ + 16*fp_greaterOrEq(fp_acos(x),2) + \ + 32*fp_nequal(fp_acos(x),2) diff --git a/tests/10optimizer_bytecode/cmp_add b/tests/10optimizer_bytecode/cmp_add new file mode 100644 index 0000000..a6c1b1c --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_add @@ -0,0 +1,15 @@ +T=d f ld li +V=x +R=-10,10,1 +F=1*((1-x+x+5)=4) +\ + 2*((1-x+x+5)<4) +\ + 4*((1-x+x+5)<=4) +\ + 8*((1-x+x+5)>4) +\ + 16*((1-x+x+5)>=4) +\ + 32*((1-x+x+5)!=4) +C=1*fp_equal((1-x+x+5),4) +\ + 2*fp_less((1-x+x+5),4) +\ + 4*fp_lessOrEq((1-x+x+5),4) +\ + 8*fp_greater((1-x+x+5),4) +\ + 16*fp_greaterOrEq((1-x+x+5),4) +\ + 32*fp_nequal((1-x+x+5),4) diff --git a/tests/10optimizer_bytecode/cmp_asin b/tests/10optimizer_bytecode/cmp_asin new file mode 100644 index 0000000..7f7e99b --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_asin @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=1*(asin(x)=asin(0.75)) + \ + 2*(asin(x)<asin(0.75)) + \ + 4*(asin(x)<=asin(0.75)) + \ + 8*(asin(x)>asin(0.75)) + \ + 16*(asin(x)>=asin(0.75)) + \ + 32*(asin(x)!=asin(0.75)) +C=1*fp_equal(fp_asin(x),fp_asin(0.75)) + \ + 2*fp_less(fp_asin(x),fp_asin(0.75)) + \ + 4*fp_lessOrEq(fp_asin(x),fp_asin(0.75)) + \ + 8*fp_greater(fp_asin(x),fp_asin(0.75)) + \ + 16*fp_greaterOrEq(fp_asin(x),fp_asin(0.75)) + \ + 32*fp_nequal(fp_asin(x),fp_asin(0.75)) diff --git a/tests/10optimizer_bytecode/cmp_asin_outrange b/tests/10optimizer_bytecode/cmp_asin_outrange new file mode 100644 index 0000000..576de83 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_asin_outrange @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=1*(asin(x)=2) + \ + 2*(asin(x)<2) + \ + 4*(asin(x)<=2) + \ + 8*(asin(x)>2) + \ + 16*(asin(x)>=2) + \ + 32*(asin(x)!=2) +C=1*fp_equal(fp_asin(x),2) + \ + 2*fp_less(fp_asin(x),2) + \ + 4*fp_lessOrEq(fp_asin(x),2) + \ + 8*fp_greater(fp_asin(x),2) + \ + 16*fp_greaterOrEq(fp_asin(x),2) + \ + 32*fp_nequal(fp_asin(x),2) diff --git a/tests/10optimizer_bytecode/cmp_atan b/tests/10optimizer_bytecode/cmp_atan new file mode 100644 index 0000000..4353b03 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_atan @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(atan(x)=atan(2)) + \ + 2*(atan(x)<atan(2)) + \ + 4*(atan(x)<=atan(2)) + \ + 8*(atan(x)>atan(2)) + \ + 16*(atan(x)>=atan(2)) + \ + 32*(atan(x)!=atan(2)) +C=1*fp_equal(fp_atan(x),fp_atan(2)) + \ + 2*fp_less(fp_atan(x),fp_atan(2)) + \ + 4*fp_lessOrEq(fp_atan(x),fp_atan(2)) + \ + 8*fp_greater(fp_atan(x),fp_atan(2)) + \ + 16*fp_greaterOrEq(fp_atan(x),fp_atan(2)) + \ + 32*fp_nequal(fp_atan(x),fp_atan(2)) diff --git a/tests/10optimizer_bytecode/cmp_exp b/tests/10optimizer_bytecode/cmp_exp new file mode 100644 index 0000000..1c18b6d --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_exp @@ -0,0 +1,7 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(exp(x)=exp(2)) + 2*(exp(x)<exp(2)) + 4*(exp(x)<=exp(2)) + \ + 8*(exp(x)>exp(2)) + 16*(exp(x)>=exp(2)) + 32*(exp(x)!=exp(2)) +C=1*fp_equal(fp_exp(x),fp_exp(2)) + 2*fp_less(fp_exp(x),fp_exp(2)) + 4*fp_lessOrEq(fp_exp(x),fp_exp(2)) + \ + 8*fp_greater(fp_exp(x),fp_exp(2)) + 16*fp_greaterOrEq(fp_exp(x),fp_exp(2)) + 32*fp_nequal(fp_exp(x),fp_exp(2)) diff --git a/tests/10optimizer_bytecode/cmp_exp2 b/tests/10optimizer_bytecode/cmp_exp2 new file mode 100644 index 0000000..7ddae26 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_exp2 @@ -0,0 +1,7 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(exp2(x)=exp2(2)) + 2*(exp2(x)<exp2(2)) + 4*(exp2(x)<=exp2(2)) + \ + 8*(exp2(x)>exp2(2)) + 16*(exp2(x)>=exp2(2)) + 32*(exp2(x)!=exp2(2)) +C=1*fp_equal(fp_exp2(x),fp_exp2(2)) + 2*fp_less(fp_exp2(x),fp_exp2(2)) + 4*fp_lessOrEq(fp_exp2(x),fp_exp2(2)) + \ + 8*fp_greater(fp_exp2(x),fp_exp2(2)) + 16*fp_greaterOrEq(fp_exp2(x),fp_exp2(2)) + 32*fp_nequal(fp_exp2(x),fp_exp2(2)) diff --git a/tests/10optimizer_bytecode/cmp_exp2_neg b/tests/10optimizer_bytecode/cmp_exp2_neg new file mode 100644 index 0000000..4a70b71 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_exp2_neg @@ -0,0 +1,7 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(exp2(x)=-4) + 2*(exp2(x)<-4) + 4*(exp2(x)<=-4) + \ + 8*(exp2(x)>-4) + 16*(exp2(x)>=-4) + 32*(exp2(x)!=-4) +C=1*fp_equal(fp_exp2(x),-4) + 2*fp_less(fp_exp2(x),-4) + 4*fp_lessOrEq(fp_exp2(x),-4) + \ + 8*fp_greater(fp_exp2(x),-4) + 16*fp_greaterOrEq(fp_exp2(x),-4) + 32*fp_nequal(fp_exp2(x),-4) diff --git a/tests/10optimizer_bytecode/cmp_exp_neg b/tests/10optimizer_bytecode/cmp_exp_neg new file mode 100644 index 0000000..0c90dc4 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_exp_neg @@ -0,0 +1,7 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(exp(x)=-4) + 2*(exp(x)<-4) + 4*(exp(x)<=-4) + \ + 8*(exp(x)>-4) + 16*(exp(x)>=-4) + 32*(exp(x)!=-4) +C=1*fp_equal(fp_exp(x),-4) + 2*fp_less(fp_exp(x),-4) + 4*fp_lessOrEq(fp_exp(x),-4) + \ + 8*fp_greater(fp_exp(x),-4) + 16*fp_greaterOrEq(fp_exp(x),-4) + 32*fp_nequal(fp_exp(x),-4) diff --git a/tests/10optimizer_bytecode/cmp_log10_nn b/tests/10optimizer_bytecode/cmp_log10_nn new file mode 100644 index 0000000..c3d8edd --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log10_nn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.5,3,0.5 +F=1*(log10(x)=-2) + \ + 2*(log10(x)<-2) + \ + 4*(log10(x)<=-2) + \ + 8*(log10(x)>-2) + \ + 16*(log10(x)>=-2) + \ + 32*(log10(x)!=-2) +C=1*fp_equal(fp_log10(x),-2) + \ + 2*fp_less(fp_log10(x),-2) + \ + 4*fp_lessOrEq(fp_log10(x),-2) + \ + 8*fp_greater(fp_log10(x),-2) + \ + 16*fp_greaterOrEq(fp_log10(x),-2) + \ + 32*fp_nequal(fp_log10(x),-2) diff --git a/tests/10optimizer_bytecode/cmp_log10_np b/tests/10optimizer_bytecode/cmp_log10_np new file mode 100644 index 0000000..bec5116 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log10_np @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.5,3,0.5 +F=1*(log10(x)=log10(2)) + \ + 2*(log10(x)<log10(2)) + \ + 4*(log10(x)<=log10(2)) + \ + 8*(log10(x)>log10(2)) + \ + 16*(log10(x)>=log10(2)) + \ + 32*(log10(x)!=log10(2)) +C=1*fp_equal(fp_log10(x),fp_log10(2)) + \ + 2*fp_less(fp_log10(x),fp_log10(2)) + \ + 4*fp_lessOrEq(fp_log10(x),fp_log10(2)) + \ + 8*fp_greater(fp_log10(x),fp_log10(2)) + \ + 16*fp_greaterOrEq(fp_log10(x),fp_log10(2)) + \ + 32*fp_nequal(fp_log10(x),fp_log10(2)) diff --git a/tests/10optimizer_bytecode/cmp_log10_pn b/tests/10optimizer_bytecode/cmp_log10_pn new file mode 100644 index 0000000..533d10d --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log10_pn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(log10(abs(x))=-2) + \ + 2*(log10(abs(x))<-2) + \ + 4*(log10(abs(x))<=-2) + \ + 8*(log10(abs(x))>-2) + \ + 16*(log10(abs(x))>=-2) + \ + 32*(log10(abs(x))!=-2) +C=1*fp_equal(fp_log10(fp_abs(x)),-2) + \ + 2*fp_less(fp_log10(fp_abs(x)),-2) + \ + 4*fp_lessOrEq(fp_log10(fp_abs(x)),-2) + \ + 8*fp_greater(fp_log10(fp_abs(x)),-2) + \ + 16*fp_greaterOrEq(fp_log10(fp_abs(x)),-2) + \ + 32*fp_nequal(fp_log10(fp_abs(x)),-2) diff --git a/tests/10optimizer_bytecode/cmp_log10_pp b/tests/10optimizer_bytecode/cmp_log10_pp new file mode 100644 index 0000000..821b15b --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log10_pp @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(log10(abs(x))=log10(1)) + \ + 2*(log10(abs(x))<log10(1)) + \ + 4*(log10(abs(x))<=log10(1)) + \ + 8*(log10(abs(x))>log10(1)) + \ + 16*(log10(abs(x))>=log10(1)) + \ + 32*(log10(abs(x))!=log10(1)) +C=1*fp_equal(fp_log10(fp_abs(x)),fp_log10(1)) + \ + 2*fp_less(fp_log10(fp_abs(x)),fp_log10(1)) + \ + 4*fp_lessOrEq(fp_log10(fp_abs(x)),fp_log10(1)) + \ + 8*fp_greater(fp_log10(fp_abs(x)),fp_log10(1)) + \ + 16*fp_greaterOrEq(fp_log10(fp_abs(x)),fp_log10(1)) + \ + 32*fp_nequal(fp_log10(fp_abs(x)),fp_log10(1)) diff --git a/tests/10optimizer_bytecode/cmp_log2_nn b/tests/10optimizer_bytecode/cmp_log2_nn new file mode 100644 index 0000000..34a6bae --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log2_nn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.5,3,0.5 +F=1*(log2(x)=-2) + \ + 2*(log2(x)<-2) + \ + 4*(log2(x)<=-2) + \ + 8*(log2(x)>-2) + \ + 16*(log2(x)>=-2) + \ + 32*(log2(x)!=-2) +C=1*fp_equal(fp_log2(x),-2) + \ + 2*fp_less(fp_log2(x),-2) + \ + 4*fp_lessOrEq(fp_log2(x),-2) + \ + 8*fp_greater(fp_log2(x),-2) + \ + 16*fp_greaterOrEq(fp_log2(x),-2) + \ + 32*fp_nequal(fp_log2(x),-2) diff --git a/tests/10optimizer_bytecode/cmp_log2_np b/tests/10optimizer_bytecode/cmp_log2_np new file mode 100644 index 0000000..f1156b8 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log2_np @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.5,3,0.5 +F=1*(log2(x)=log2(2)) + \ + 2*(log2(x)<log2(2)) + \ + 4*(log2(x)<=log2(2)) + \ + 8*(log2(x)>log2(2)) + \ + 16*(log2(x)>=log2(2)) + \ + 32*(log2(x)!=log2(2)) +C=1*fp_equal(fp_log2(x),fp_log2(2)) + \ + 2*fp_less(fp_log2(x),fp_log2(2)) + \ + 4*fp_lessOrEq(fp_log2(x),fp_log2(2)) + \ + 8*fp_greater(fp_log2(x),fp_log2(2)) + \ + 16*fp_greaterOrEq(fp_log2(x),fp_log2(2)) + \ + 32*fp_nequal(fp_log2(x),fp_log2(2)) diff --git a/tests/10optimizer_bytecode/cmp_log2_pn b/tests/10optimizer_bytecode/cmp_log2_pn new file mode 100644 index 0000000..a09600e --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log2_pn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(log2(abs(x))=-2) + \ + 2*(log2(abs(x))<-2) + \ + 4*(log2(abs(x))<=-2) + \ + 8*(log2(abs(x))>-2) + \ + 16*(log2(abs(x))>=-2) + \ + 32*(log2(abs(x))!=-2) +C=1*fp_equal(fp_log2(fp_abs(x)),-2) + \ + 2*fp_less(fp_log2(fp_abs(x)),-2) + \ + 4*fp_lessOrEq(fp_log2(fp_abs(x)),-2) + \ + 8*fp_greater(fp_log2(fp_abs(x)),-2) + \ + 16*fp_greaterOrEq(fp_log2(fp_abs(x)),-2) + \ + 32*fp_nequal(fp_log2(fp_abs(x)),-2) diff --git a/tests/10optimizer_bytecode/cmp_log2_pp b/tests/10optimizer_bytecode/cmp_log2_pp new file mode 100644 index 0000000..643dde7 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log2_pp @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(log2(abs(x))=log2(2)) + \ + 2*(log2(abs(x))<log2(2)) + \ + 4*(log2(abs(x))<=log2(2)) + \ + 8*(log2(abs(x))>log2(2)) + \ + 16*(log2(abs(x))>=log2(2)) + \ + 32*(log2(abs(x))!=log2(2)) +C=1*fp_equal(fp_log2(fp_abs(x)),fp_log2(2)) + \ + 2*fp_less(fp_log2(fp_abs(x)),fp_log2(2)) + \ + 4*fp_lessOrEq(fp_log2(fp_abs(x)),fp_log2(2)) + \ + 8*fp_greater(fp_log2(fp_abs(x)),fp_log2(2)) + \ + 16*fp_greaterOrEq(fp_log2(fp_abs(x)),fp_log2(2)) + \ + 32*fp_nequal(fp_log2(fp_abs(x)),fp_log2(2)) diff --git a/tests/10optimizer_bytecode/cmp_log_nn b/tests/10optimizer_bytecode/cmp_log_nn new file mode 100644 index 0000000..9263137 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log_nn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.5,3,0.5 +F=1*(log(x)=-2) + \ + 2*(log(x)<-2) + \ + 4*(log(x)<=-2) + \ + 8*(log(x)>-2) + \ + 16*(log(x)>=-2) + \ + 32*(log(x)!=-2) +C=1*fp_equal(fp_log(x),-2) + \ + 2*fp_less(fp_log(x),-2) + \ + 4*fp_lessOrEq(fp_log(x),-2) + \ + 8*fp_greater(fp_log(x),-2) + \ + 16*fp_greaterOrEq(fp_log(x),-2) + \ + 32*fp_nequal(fp_log(x),-2) diff --git a/tests/10optimizer_bytecode/cmp_log_np b/tests/10optimizer_bytecode/cmp_log_np new file mode 100644 index 0000000..1a83b4c --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log_np @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.5,3,0.5 +F=1*(log(x)=log(2)) + \ + 2*(log(x)<log(2)) + \ + 4*(log(x)<=log(2)) + \ + 8*(log(x)>log(2)) + \ + 16*(log(x)>=log(2)) + \ + 32*(log(x)!=log(2)) +C=1*fp_equal(fp_log(x),fp_log(2)) + \ + 2*fp_less(fp_log(x),fp_log(2)) + \ + 4*fp_lessOrEq(fp_log(x),fp_log(2)) + \ + 8*fp_greater(fp_log(x),fp_log(2)) + \ + 16*fp_greaterOrEq(fp_log(x),fp_log(2)) + \ + 32*fp_nequal(fp_log(x),fp_log(2)) diff --git a/tests/10optimizer_bytecode/cmp_log_pn b/tests/10optimizer_bytecode/cmp_log_pn new file mode 100644 index 0000000..9fb3ce0 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log_pn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(log(abs(x))=-2) + \ + 2*(log(abs(x))<-2) + \ + 4*(log(abs(x))<=-2) + \ + 8*(log(abs(x))>-2) + \ + 16*(log(abs(x))>=-2) + \ + 32*(log(abs(x))!=-2) +C=1*fp_equal(fp_log(fp_abs(x)),-2) + \ + 2*fp_less(fp_log(fp_abs(x)),-2) + \ + 4*fp_lessOrEq(fp_log(fp_abs(x)),-2) + \ + 8*fp_greater(fp_log(fp_abs(x)),-2) + \ + 16*fp_greaterOrEq(fp_log(fp_abs(x)),-2) + \ + 32*fp_nequal(fp_log(fp_abs(x)),-2) diff --git a/tests/10optimizer_bytecode/cmp_log_pp b/tests/10optimizer_bytecode/cmp_log_pp new file mode 100644 index 0000000..08d88bd --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_log_pp @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(log(abs(x))=log(2)) + \ + 2*(log(abs(x))<log(2)) + \ + 4*(log(abs(x))<=log(2)) + \ + 8*(log(abs(x))>log(2)) + \ + 16*(log(abs(x))>=log(2)) + \ + 32*(log(abs(x))!=log(2)) +C=1*fp_equal(fp_log(fp_abs(x)),fp_log(2)) + \ + 2*fp_less(fp_log(fp_abs(x)),fp_log(2)) + \ + 4*fp_lessOrEq(fp_log(fp_abs(x)),fp_log(2)) + \ + 8*fp_greater(fp_log(fp_abs(x)),fp_log(2)) + \ + 16*fp_greaterOrEq(fp_log(fp_abs(x)),fp_log(2)) + \ + 32*fp_nequal(fp_log(fp_abs(x)),fp_log(2)) diff --git a/tests/10optimizer_bytecode/cmp_mulneg b/tests/10optimizer_bytecode/cmp_mulneg new file mode 100644 index 0000000..72e2adb --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_mulneg @@ -0,0 +1,15 @@ +T=d f ld li +V=x +R=-10,10,1 +F=1*((x/2*x*5)=4) +\ + 2*((x/2*x*5)<4) +\ + 4*((x/2*x*5)<=4) +\ + 8*((x/2*x*5)>4) +\ + 16*((x/2*x*5)>=4) +\ + 32*((x/2*x*5)!=4) +C=1*fp_equal((x/2*x*5),4) +\ + 2*fp_less((x/2*x*5),4) +\ + 4*fp_lessOrEq((x/2*x*5),4) +\ + 8*fp_greater((x/2*x*5),4) +\ + 16*fp_greaterOrEq((x/2*x*5),4) +\ + 32*fp_nequal((x/2*x*5),4) diff --git a/tests/10optimizer_bytecode/cmp_mulpos b/tests/10optimizer_bytecode/cmp_mulpos new file mode 100644 index 0000000..c525153 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_mulpos @@ -0,0 +1,15 @@ +T=d f ld li +V=x +R=-10,10,1 +F=1*((x/2*x*-5)=4) +\ + 2*((x/2*x*-5)<4) +\ + 4*((x/2*x*-5)<=4) +\ + 8*((x/2*x*-5)>4) +\ + 16*((x/2*x*-5)>=4) +\ + 32*((x/2*x*-5)!=4) +C=1*fp_equal((x/2*x*-5),4) +\ + 2*fp_less((x/2*x*-5),4) +\ + 4*fp_lessOrEq((x/2*x*-5),4) +\ + 8*fp_greater((x/2*x*-5),4) +\ + 16*fp_greaterOrEq((x/2*x*-5),4) +\ + 32*fp_nequal((x/2*x*-5),4) diff --git a/tests/10optimizer_bytecode/cmp_neg b/tests/10optimizer_bytecode/cmp_neg new file mode 100644 index 0000000..790934a --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_neg @@ -0,0 +1,7 @@ +T=d f ld li +V=x +R=-10,10,1 +F=1*((-x)=4) + 2*((-x)<4) + 4*((-x)<=4) + \ + 8*((-x)>4) + 16*((-x)>=4) + 32*((-x)!=4) +C=1*fp_equal((-x),4) + 2*fp_less((-x),4) + 4*fp_lessOrEq((-x),4) + \ + 8*fp_greater((-x),4) + 16*fp_greaterOrEq((-x),4) + 32*fp_nequal((-x),4) diff --git a/tests/10optimizer_bytecode/cmp_powx_n_n b/tests/10optimizer_bytecode/cmp_powx_n_n new file mode 100644 index 0000000..369ce55 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_n_n @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-36,36,1 +F=1*(((-2.051)^x)=((-1.061)^x)) +\ + 2*(((-2.051)^x)<((-1.061)^x)) +\ + 4*(((-2.051)^x)<=((-1.061)^x)) +\ + 8*(((-2.051)^x)>((-1.061)^x)) +\ + 16*(((-2.051)^x)>=((-1.061)^x)) +\ + 32*(((-2.051)^x)!=((-1.061)^x)) +C=1*fp_equal(fp_pow(-2.051,x),fp_pow(-1.061,x)) +\ + 2*fp_less(fp_pow(-2.051,x),fp_pow(-1.061,x)) +\ + 4*fp_lessOrEq(fp_pow(-2.051,x),fp_pow(-1.061,x)) +\ + 8*fp_greater(fp_pow(-2.051,x),fp_pow(-1.061,x)) +\ + 16*fp_greaterOrEq(fp_pow(-2.051,x),fp_pow(-1.061,x)) +\ + 32*fp_nequal(fp_pow(-2.051,x),fp_pow(-1.061,x)) diff --git a/tests/10optimizer_bytecode/cmp_powx_n_p b/tests/10optimizer_bytecode/cmp_powx_n_p new file mode 100644 index 0000000..e2aaf76 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_n_p @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-36,36,1 +F=1*(((-2.051)^x)=(1.061^(x/3))) +\ + 2*(((-2.051)^x)<(1.061^(x/3))) +\ + 4*(((-2.051)^x)<=(1.061^(x/3))) +\ + 8*(((-2.051)^x)>(1.061^(x/3))) +\ + 16*(((-2.051)^x)>=(1.061^(x/3))) +\ + 32*(((-2.051)^x)!=(1.061^(x/3))) +C=1*fp_equal(fp_pow(-2.051,x),fp_pow(1.061,x/3)) +\ + 2*fp_less(fp_pow(-2.051,x),fp_pow(1.061,x/3)) +\ + 4*fp_lessOrEq(fp_pow(-2.051,x),fp_pow(1.061,x/3)) +\ + 8*fp_greater(fp_pow(-2.051,x),fp_pow(1.061,x/3)) +\ + 16*fp_greaterOrEq(fp_pow(-2.051,x),fp_pow(1.061,x/3)) +\ + 32*fp_nequal(fp_pow(-2.051,x),fp_pow(1.061,x/3)) diff --git a/tests/10optimizer_bytecode/cmp_powx_nn b/tests/10optimizer_bytecode/cmp_powx_nn new file mode 100644 index 0000000..8e6d091 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_nn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-4,4,1 +F=1*(((-2.051)^x)=-4) +\ + 2*(((-2.051)^x)<-4) +\ + 4*(((-2.051)^x)<=-4) +\ + 8*(((-2.051)^x)>-4) +\ + 16*(((-2.051)^x)>=-4) +\ + 32*(((-2.051)^x)!=-4) +C=1*fp_equal(fp_pow(-2.051,x),-4) +\ + 2*fp_less(fp_pow(-2.051,x),-4) +\ + 4*fp_lessOrEq(fp_pow(-2.051,x),-4) +\ + 8*fp_greater(fp_pow(-2.051,x),-4) +\ + 16*fp_greaterOrEq(fp_pow(-2.051,x),-4) +\ + 32*fp_nequal(fp_pow(-2.051,x),-4) diff --git a/tests/10optimizer_bytecode/cmp_powx_np b/tests/10optimizer_bytecode/cmp_powx_np new file mode 100644 index 0000000..381ef38 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_np @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-4,4,1 +F=1*(((-2.051)^x)=4) +\ + 2*(((-2.051)^x)<4) +\ + 4*(((-2.051)^x)<=4) +\ + 8*(((-2.051)^x)>4) +\ + 16*(((-2.051)^x)>=4) +\ + 32*(((-2.051)^x)!=4) +C=1*fp_equal(fp_pow(-2.051,x),4) +\ + 2*fp_less(fp_pow(-2.051,x),4) +\ + 4*fp_lessOrEq(fp_pow(-2.051,x),4) +\ + 8*fp_greater(fp_pow(-2.051,x),4) +\ + 16*fp_greaterOrEq(fp_pow(-2.051,x),4) +\ + 32*fp_nequal(fp_pow(-2.051,x),4) diff --git a/tests/10optimizer_bytecode/cmp_powx_p_n b/tests/10optimizer_bytecode/cmp_powx_p_n new file mode 100644 index 0000000..9a2662f --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_p_n @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-36,36,1 +F=1*((2.051^(x/3))=((-1.061)^x)) +\ + 2*((2.051^(x/3))<((-1.061)^x)) +\ + 4*((2.051^(x/3))<=((-1.061)^x)) +\ + 8*((2.051^(x/3))>((-1.061)^x)) +\ + 16*((2.051^(x/3))>=((-1.061)^x)) +\ + 32*((2.051^(x/3))!=((-1.061)^x)) +C=1*fp_equal(fp_pow(2.051,x/3),fp_pow(-1.061,x)) +\ + 2*fp_less(fp_pow(2.051,x/3),fp_pow(-1.061,x)) +\ + 4*fp_lessOrEq(fp_pow(2.051,x/3),fp_pow(-1.061,x)) +\ + 8*fp_greater(fp_pow(2.051,x/3),fp_pow(-1.061,x)) +\ + 16*fp_greaterOrEq(fp_pow(2.051,x/3),fp_pow(-1.061,x)) +\ + 32*fp_nequal(fp_pow(2.051,x/3),fp_pow(-1.061,x)) diff --git a/tests/10optimizer_bytecode/cmp_powx_p_p b/tests/10optimizer_bytecode/cmp_powx_p_p new file mode 100644 index 0000000..5a83a0b --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_p_p @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-36,36,1 +F=1*((2.051^(x/3))=(1.061^(x/3))) +\ + 2*((2.051^(x/3))<(1.061^(x/3))) +\ + 4*((2.051^(x/3))<=(1.061^(x/3))) +\ + 8*((2.051^(x/3))>(1.061^(x/3))) +\ + 16*((2.051^(x/3))>=(1.061^(x/3))) +\ + 32*((2.051^(x/3))!=(1.061^(x/3))) +C=1*fp_equal(fp_pow(2.051,x/3),fp_pow(1.061,x/3)) +\ + 2*fp_less(fp_pow(2.051,x/3),fp_pow(1.061,x/3)) +\ + 4*fp_lessOrEq(fp_pow(2.051,x/3),fp_pow(1.061,x/3)) +\ + 8*fp_greater(fp_pow(2.051,x/3),fp_pow(1.061,x/3)) +\ + 16*fp_greaterOrEq(fp_pow(2.051,x/3),fp_pow(1.061,x/3)) +\ + 32*fp_nequal(fp_pow(2.051,x/3),fp_pow(1.061,x/3)) diff --git a/tests/10optimizer_bytecode/cmp_powx_pn b/tests/10optimizer_bytecode/cmp_powx_pn new file mode 100644 index 0000000..1c08906 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_pn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-4,4,1 +F=1*((2.051^x)=-4) +\ + 2*((2.051^x)<-4) +\ + 4*((2.051^x)<=-4) +\ + 8*((2.051^x)>-4) +\ + 16*((2.051^x)>=-4) +\ + 32*((2.051^x)!=-4) +C=1*fp_equal(fp_pow(2.051,x),-4) +\ + 2*fp_less(fp_pow(2.051,x),-4) +\ + 4*fp_lessOrEq(fp_pow(2.051,x),-4) +\ + 8*fp_greater(fp_pow(2.051,x),-4) +\ + 16*fp_greaterOrEq(fp_pow(2.051,x),-4) +\ + 32*fp_nequal(fp_pow(2.051,x),-4) diff --git a/tests/10optimizer_bytecode/cmp_powx_pp b/tests/10optimizer_bytecode/cmp_powx_pp new file mode 100644 index 0000000..b191607 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powx_pp @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-4,4,1 +F=1*((2.051^x)=4) +\ + 2*((2.051^x)<4) +\ + 4*((2.051^x)<=4) +\ + 8*((2.051^x)>4) +\ + 16*((2.051^x)>=4) +\ + 32*((2.051^x)!=4) +C=1*fp_equal(fp_pow(2.051,x),4) +\ + 2*fp_less(fp_pow(2.051,x),4) +\ + 4*fp_lessOrEq(fp_pow(2.051,x),4) +\ + 8*fp_greater(fp_pow(2.051,x),4) +\ + 16*fp_greaterOrEq(fp_pow(2.051,x),4) +\ + 32*fp_nequal(fp_pow(2.051,x),4) diff --git a/tests/10optimizer_bytecode/cmp_powy_n_n b/tests/10optimizer_bytecode/cmp_powy_n_n new file mode 100644 index 0000000..35077a3 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_n_n @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^-5.1)=(x^-6.1)) +\ + 2*((x^-5.1)<(x^-6.1)) +\ + 4*((x^-5.1)<=(x^-6.1)) +\ + 8*((x^-5.1)>(x^-6.1)) +\ + 16*((x^-5.1)>=(x^-6.1)) +\ + 32*((x^-5.1)!=(x^-6.1)) +C=1*fp_equal(fp_pow(x,-5.1),fp_pow(x,-6.1)) +\ + 2*fp_less(fp_pow(x,-5.1),fp_pow(x,-6.1)) +\ + 4*fp_lessOrEq(fp_pow(x,-5.1),fp_pow(x,-6.1)) +\ + 8*fp_greater(fp_pow(x,-5.1),fp_pow(x,-6.1)) +\ + 16*fp_greaterOrEq(fp_pow(x,-5.1),fp_pow(x,-6.1)) +\ + 32*fp_nequal(fp_pow(x,-5.1),fp_pow(x,-6.1)) diff --git a/tests/10optimizer_bytecode/cmp_powy_n_p b/tests/10optimizer_bytecode/cmp_powy_n_p new file mode 100644 index 0000000..de1f946 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_n_p @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^-5.1)=(x^6.1)) +\ + 2*((x^-5.1)<(x^6.1)) +\ + 4*((x^-5.1)<=(x^6.1)) +\ + 8*((x^-5.1)>(x^6.1)) +\ + 16*((x^-5.1)>=(x^6.1)) +\ + 32*((x^-5.1)!=(x^6.1)) +C=1*fp_equal(fp_pow(x,-5.1),fp_pow(x,6.1)) +\ + 2*fp_less(fp_pow(x,-5.1),fp_pow(x,6.1)) +\ + 4*fp_lessOrEq(fp_pow(x,-5.1),fp_pow(x,6.1)) +\ + 8*fp_greater(fp_pow(x,-5.1),fp_pow(x,6.1)) +\ + 16*fp_greaterOrEq(fp_pow(x,-5.1),fp_pow(x,6.1)) +\ + 32*fp_nequal(fp_pow(x,-5.1),fp_pow(x,6.1)) diff --git a/tests/10optimizer_bytecode/cmp_powy_nn b/tests/10optimizer_bytecode/cmp_powy_nn new file mode 100644 index 0000000..9496964 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_nn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^-5.1)=-4) +\ + 2*((x^-5.1)<-4) +\ + 4*((x^-5.1)<=-4) +\ + 8*((x^-5.1)>-4) +\ + 16*((x^-5.1)>=-4) +\ + 32*((x^-5.1)!=-4) +C=1*fp_equal(fp_pow(x,-5.1),-4) +\ + 2*fp_less(fp_pow(x,-5.1),-4) +\ + 4*fp_lessOrEq(fp_pow(x,-5.1),-4) +\ + 8*fp_greater(fp_pow(x,-5.1),-4) +\ + 16*fp_greaterOrEq(fp_pow(x,-5.1),-4) +\ + 32*fp_nequal(fp_pow(x,-5.1),-4) diff --git a/tests/10optimizer_bytecode/cmp_powy_np b/tests/10optimizer_bytecode/cmp_powy_np new file mode 100644 index 0000000..3228697 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_np @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^-5.1)=4) +\ + 2*((x^-5.1)<4) +\ + 4*((x^-5.1)<=4) +\ + 8*((x^-5.1)>4) +\ + 16*((x^-5.1)>=4) +\ + 32*((x^-5.1)!=4) +C=1*fp_equal(fp_pow(x,-5.1),4) +\ + 2*fp_less(fp_pow(x,-5.1),4) +\ + 4*fp_lessOrEq(fp_pow(x,-5.1),4) +\ + 8*fp_greater(fp_pow(x,-5.1),4) +\ + 16*fp_greaterOrEq(fp_pow(x,-5.1),4) +\ + 32*fp_nequal(fp_pow(x,-5.1),4) diff --git a/tests/10optimizer_bytecode/cmp_powy_p_n b/tests/10optimizer_bytecode/cmp_powy_p_n new file mode 100644 index 0000000..0a26e8f --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_p_n @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^5.1)=(x^-6.1)) +\ + 2*((x^5.1)<(x^-6.1)) +\ + 4*((x^5.1)<=(x^-6.1)) +\ + 8*((x^5.1)>(x^-6.1)) +\ + 16*((x^5.1)>=(x^-6.1)) +\ + 32*((x^5.1)!=(x^-6.1)) +C=1*fp_equal(fp_pow(x,5.1),fp_pow(x,-6.1)) +\ + 2*fp_less(fp_pow(x,5.1),fp_pow(x,-6.1)) +\ + 4*fp_lessOrEq(fp_pow(x,5.1),fp_pow(x,-6.1)) +\ + 8*fp_greater(fp_pow(x,5.1),fp_pow(x,-6.1)) +\ + 16*fp_greaterOrEq(fp_pow(x,5.1),fp_pow(x,-6.1)) +\ + 32*fp_nequal(fp_pow(x,5.1),fp_pow(x,-6.1)) diff --git a/tests/10optimizer_bytecode/cmp_powy_p_p b/tests/10optimizer_bytecode/cmp_powy_p_p new file mode 100644 index 0000000..3ff2fe6 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_p_p @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^5.1)=(x^6.1)) +\ + 2*((x^5.1)<(x^6.1)) +\ + 4*((x^5.1)<=(x^6.1)) +\ + 8*((x^5.1)>(x^6.1)) +\ + 16*((x^5.1)>=(x^6.1)) +\ + 32*((x^5.1)!=(x^6.1)) +C=1*fp_equal(fp_pow(x,5.1),fp_pow(x,6.1)) +\ + 2*fp_less(fp_pow(x,5.1),fp_pow(x,6.1)) +\ + 4*fp_lessOrEq(fp_pow(x,5.1),fp_pow(x,6.1)) +\ + 8*fp_greater(fp_pow(x,5.1),fp_pow(x,6.1)) +\ + 16*fp_greaterOrEq(fp_pow(x,5.1),fp_pow(x,6.1)) +\ + 32*fp_nequal(fp_pow(x,5.1),fp_pow(x,6.1)) diff --git a/tests/10optimizer_bytecode/cmp_powy_pn b/tests/10optimizer_bytecode/cmp_powy_pn new file mode 100644 index 0000000..1c6e4db --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_pn @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^5.1)=-4) +\ + 2*((x^5.1)<-4) +\ + 4*((x^5.1)<=-4) +\ + 8*((x^5.1)>-4) +\ + 16*((x^5.1)>=-4) +\ + 32*((x^5.1)!=-4) +C=1*fp_equal(fp_pow(x,5.1),-4) +\ + 2*fp_less(fp_pow(x,5.1),-4) +\ + 4*fp_lessOrEq(fp_pow(x,5.1),-4) +\ + 8*fp_greater(fp_pow(x,5.1),-4) +\ + 16*fp_greaterOrEq(fp_pow(x,5.1),-4) +\ + 32*fp_nequal(fp_pow(x,5.1),-4) diff --git a/tests/10optimizer_bytecode/cmp_powy_pp b/tests/10optimizer_bytecode/cmp_powy_pp new file mode 100644 index 0000000..7d809da --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_powy_pp @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=0.25,3,0.25 +F=1*((x^5.1)=4) +\ + 2*((x^5.1)<4) +\ + 4*((x^5.1)<=4) +\ + 8*((x^5.1)>4) +\ + 16*((x^5.1)>=4) +\ + 32*((x^5.1)!=4) +C=1*fp_equal(fp_pow(x,5.1),4) +\ + 2*fp_less(fp_pow(x,5.1),4) +\ + 4*fp_lessOrEq(fp_pow(x,5.1),4) +\ + 8*fp_greater(fp_pow(x,5.1),4) +\ + 16*fp_greaterOrEq(fp_pow(x,5.1),4) +\ + 32*fp_nequal(fp_pow(x,5.1),4) diff --git a/tests/10optimizer_bytecode/cmp_sinh b/tests/10optimizer_bytecode/cmp_sinh new file mode 100644 index 0000000..16531b3 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_sinh @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-3,3,0.5 +F=1*(sinh(x)=sinh(2)) + \ + 2*(sinh(x)<sinh(2)) + \ + 4*(sinh(x)<=sinh(2)) + \ + 8*(sinh(x)>sinh(2)) + \ + 16*(sinh(x)>=sinh(2)) + \ + 32*(sinh(x)!=sinh(2)) +C=1*fp_equal(fp_sinh(x),fp_sinh(2)) + \ + 2*fp_less(fp_sinh(x),fp_sinh(2)) + \ + 4*fp_lessOrEq(fp_sinh(x),fp_sinh(2)) + \ + 8*fp_greater(fp_sinh(x),fp_sinh(2)) + \ + 16*fp_greaterOrEq(fp_sinh(x),fp_sinh(2)) + \ + 32*fp_nequal(fp_sinh(x),fp_sinh(2)) diff --git a/tests/10optimizer_bytecode/cmp_sqr b/tests/10optimizer_bytecode/cmp_sqr new file mode 100644 index 0000000..91cf41c --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_sqr @@ -0,0 +1,7 @@ +T=d f ld li +V=x +R=-10,10,1 +F=1*((x*x)=16) + 2*((x*x)<16) + 4*((x*x)<=16) + \ + 8*((x*x)>16) + 16*((x*x)>=16) + 32*((x*x)!=16) +C=1*fp_equal((x*x),16) + 2*fp_less((x*x),16) + 4*fp_lessOrEq((x*x),16) + \ + 8*fp_greater((x*x),16) + 16*fp_greaterOrEq((x*x),16) + 32*fp_nequal((x*x),16) diff --git a/tests/10optimizer_bytecode/cmp_sqr_neg b/tests/10optimizer_bytecode/cmp_sqr_neg new file mode 100644 index 0000000..680b0ac --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_sqr_neg @@ -0,0 +1,7 @@ +T=d f ld li +V=x +R=-10,10,1 +F=1*((x*x)=-16) + 2*((x*x)<-16) + 4*((x*x)<=-16) + \ + 8*((x*x)>-16) + -16*((x*x)>=-16) + 32*((x*x)!=-16) +C=1*fp_equal((x*x),-16) + 2*fp_less((x*x),-16) + 4*fp_lessOrEq((x*x),-16) + \ + 8*fp_greater((x*x),-16) + -16*fp_greaterOrEq((x*x),-16) + 32*fp_nequal((x*x),-16) diff --git a/tests/10optimizer_bytecode/cmp_tanh b/tests/10optimizer_bytecode/cmp_tanh new file mode 100644 index 0000000..6a6fcac --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_tanh @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-4,4,0.25 +F=1*(tanh(x)=tanh(0.75)) + \ + 2*(tanh(x)<tanh(0.75)) + \ + 4*(tanh(x)<=tanh(0.75)) + \ + 8*(tanh(x)>tanh(0.75)) + \ + 16*(tanh(x)>=tanh(0.75)) + \ + 32*(tanh(x)!=tanh(0.75)) +C=1*fp_equal(fp_tanh(x),fp_tanh(0.75)) + \ + 2*fp_less(fp_tanh(x),fp_tanh(0.75)) + \ + 4*fp_lessOrEq(fp_tanh(x),fp_tanh(0.75)) + \ + 8*fp_greater(fp_tanh(x),fp_tanh(0.75)) + \ + 16*fp_greaterOrEq(fp_tanh(x),fp_tanh(0.75)) + \ + 32*fp_nequal(fp_tanh(x),fp_tanh(0.75)) diff --git a/tests/10optimizer_bytecode/cmp_tanh_outrange b/tests/10optimizer_bytecode/cmp_tanh_outrange new file mode 100644 index 0000000..08061e1 --- /dev/null +++ b/tests/10optimizer_bytecode/cmp_tanh_outrange @@ -0,0 +1,15 @@ +T=d f ld +V=x +R=-4,4,0.25 +F=1*(tanh(x)=2) + \ + 2*(tanh(x)<2) + \ + 4*(tanh(x)<=2) + \ + 8*(tanh(x)>2) + \ + 16*(tanh(x)>=2) + \ + 32*(tanh(x)!=2) +C=1*fp_equal(fp_tanh(x),2) + \ + 2*fp_less(fp_tanh(x),2) + \ + 4*fp_lessOrEq(fp_tanh(x),2) + \ + 8*fp_greater(fp_tanh(x),2) + \ + 16*fp_greaterOrEq(fp_tanh(x),2) + \ + 32*fp_nequal(fp_tanh(x),2) diff --git a/tests/10optimizer_bytecode/cmpeq b/tests/10optimizer_bytecode/cmpeq new file mode 100644 index 0000000..c2f5a88 --- /dev/null +++ b/tests/10optimizer_bytecode/cmpeq @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5=3)+x+(4=4) +C=fp_equal(5,3)+x+fp_equal(4,4) diff --git a/tests/10optimizer_bytecode/cmpge b/tests/10optimizer_bytecode/cmpge new file mode 100644 index 0000000..d8c021e --- /dev/null +++ b/tests/10optimizer_bytecode/cmpge @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5>=3)+x+(4>=8) +C=fp_lessOrEq(3,5)+x+fp_lessOrEq(8,4) diff --git a/tests/10optimizer_bytecode/cmpgt b/tests/10optimizer_bytecode/cmpgt new file mode 100644 index 0000000..73fbb0f --- /dev/null +++ b/tests/10optimizer_bytecode/cmpgt @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5>3)+x+(4>8) +C=fp_less(3,5)+x+fp_less(8,4) diff --git a/tests/10optimizer_bytecode/cmple b/tests/10optimizer_bytecode/cmple new file mode 100644 index 0000000..17fb34b --- /dev/null +++ b/tests/10optimizer_bytecode/cmple @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5<3)+x+(4<8) +C=fp_lessOrEq(5,3)+x+fp_lessOrEq(4,8) diff --git a/tests/10optimizer_bytecode/cmplt b/tests/10optimizer_bytecode/cmplt new file mode 100644 index 0000000..5257c84 --- /dev/null +++ b/tests/10optimizer_bytecode/cmplt @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5<3)+x +C=fp_less(5,3)+x diff --git a/tests/10optimizer_bytecode/cmpne b/tests/10optimizer_bytecode/cmpne new file mode 100644 index 0000000..9c3d907 --- /dev/null +++ b/tests/10optimizer_bytecode/cmpne @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5!=3)+x+(4!=4) +C=fp_nequal(5,3)+x+fp_nequal(4,4) diff --git a/tests/10optimizer_bytecode/cos b/tests/10optimizer_bytecode/cos new file mode 100644 index 0000000..97ad037 --- /dev/null +++ b/tests/10optimizer_bytecode/cos @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=cos(1.1)+x +C=cos(1.1)+x diff --git a/tests/10optimizer_bytecode/cos_deg b/tests/10optimizer_bytecode/cos_deg new file mode 100644 index 0000000..833a6db --- /dev/null +++ b/tests/10optimizer_bytecode/cos_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=cos(1.1)+x +C=cos(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/cosf b/tests/10optimizer_bytecode/cosf new file mode 100644 index 0000000..7f6b743 --- /dev/null +++ b/tests/10optimizer_bytecode/cosf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=cos(1.1)+x +C=cosf(1.1)+x diff --git a/tests/10optimizer_bytecode/cosf_deg b/tests/10optimizer_bytecode/cosf_deg new file mode 100644 index 0000000..c9d2241 --- /dev/null +++ b/tests/10optimizer_bytecode/cosf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=cos(1.1)+x +C=cosf(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/cosh b/tests/10optimizer_bytecode/cosh new file mode 100644 index 0000000..5c83211 --- /dev/null +++ b/tests/10optimizer_bytecode/cosh @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=cosh(1.1)+x +C=cosh(1.1)+x diff --git a/tests/10optimizer_bytecode/cosh_deg b/tests/10optimizer_bytecode/cosh_deg new file mode 100644 index 0000000..57b8f27 --- /dev/null +++ b/tests/10optimizer_bytecode/cosh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=cosh(1.1)+x +C=cosh(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/coshf b/tests/10optimizer_bytecode/coshf new file mode 100644 index 0000000..41789ae --- /dev/null +++ b/tests/10optimizer_bytecode/coshf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=cosh(1.1)+x +C=coshf(1.1)+x diff --git a/tests/10optimizer_bytecode/coshf_deg b/tests/10optimizer_bytecode/coshf_deg new file mode 100644 index 0000000..83dfc89 --- /dev/null +++ b/tests/10optimizer_bytecode/coshf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=cosh(1.1)+x +C=coshf(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/coshl b/tests/10optimizer_bytecode/coshl new file mode 100644 index 0000000..23f3f8d --- /dev/null +++ b/tests/10optimizer_bytecode/coshl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=cosh(1.1)+x +C=coshl(1.1)+x diff --git a/tests/10optimizer_bytecode/coshl_deg b/tests/10optimizer_bytecode/coshl_deg new file mode 100644 index 0000000..e4fb524 --- /dev/null +++ b/tests/10optimizer_bytecode/coshl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=cosh(1.1)+x +C=coshl(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/coshm b/tests/10optimizer_bytecode/coshm new file mode 100644 index 0000000..0c301c6 --- /dev/null +++ b/tests/10optimizer_bytecode/coshm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=cosh(1.1)+x +C=MpfrFloat::cosh(1.1)+x diff --git a/tests/10optimizer_bytecode/coshm_deg b/tests/10optimizer_bytecode/coshm_deg new file mode 100644 index 0000000..0da634f --- /dev/null +++ b/tests/10optimizer_bytecode/coshm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=cosh(1.1)+x +C=MpfrFloat::cosh(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/cosl b/tests/10optimizer_bytecode/cosl new file mode 100644 index 0000000..6ded7de --- /dev/null +++ b/tests/10optimizer_bytecode/cosl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=cos(1.1)+x +C=cosl(1.1)+x diff --git a/tests/10optimizer_bytecode/cosl_deg b/tests/10optimizer_bytecode/cosl_deg new file mode 100644 index 0000000..8ea0d3b --- /dev/null +++ b/tests/10optimizer_bytecode/cosl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=cos(1.1)+x +C=cosl(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/cosm b/tests/10optimizer_bytecode/cosm new file mode 100644 index 0000000..909c221 --- /dev/null +++ b/tests/10optimizer_bytecode/cosm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=cos(1.1)+x +C=MpfrFloat::cos(1.1)+x diff --git a/tests/10optimizer_bytecode/cosm_deg b/tests/10optimizer_bytecode/cosm_deg new file mode 100644 index 0000000..fb3490f --- /dev/null +++ b/tests/10optimizer_bytecode/cosm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=cos(1.1)+x +C=MpfrFloat::cos(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/deg b/tests/10optimizer_bytecode/deg new file mode 100644 index 0000000..66b2867 --- /dev/null +++ b/tests/10optimizer_bytecode/deg @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-10,10,0.8 +F=(180/pi)*y + x*(180/pi) + (y*(180/pi))*4 +C=r2d(y) + r2d(x) + r2d(y)*4 diff --git a/tests/10optimizer_bytecode/degxmul b/tests/10optimizer_bytecode/degxmul new file mode 100644 index 0000000..1e10622 --- /dev/null +++ b/tests/10optimizer_bytecode/degxmul @@ -0,0 +1,6 @@ +DEG=1 +T=d f ld mf +V=x +R=-1,1,0.5 +F=acos(x)*2 +C=r2d(fp_acos(x))*2 diff --git a/tests/10optimizer_bytecode/div b/tests/10optimizer_bytecode/div new file mode 100644 index 0000000..f4c9df0 --- /dev/null +++ b/tests/10optimizer_bytecode/div @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5/4)+x +C=(5/4)+x diff --git a/tests/10optimizer_bytecode/div1 b/tests/10optimizer_bytecode/div1 new file mode 100644 index 0000000..fe1e402 --- /dev/null +++ b/tests/10optimizer_bytecode/div1 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=x/1+x +C=x/1+x diff --git a/tests/10optimizer_bytecode/divxx b/tests/10optimizer_bytecode/divxx new file mode 100644 index 0000000..56f9350 --- /dev/null +++ b/tests/10optimizer_bytecode/divxx @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=x+x/x+x +C=x+x/x+x diff --git a/tests/10optimizer_bytecode/dupaddmul7 b/tests/10optimizer_bytecode/dupaddmul7 new file mode 100644 index 0000000..eaa6892 --- /dev/null +++ b/tests/10optimizer_bytecode/dupaddmul7 @@ -0,0 +1,7 @@ +# cDup cAdd x cMul + +T=d f ld mf li gi +V=x +R=-3,3,1 +F=(x+x)*7 +C=x*14 diff --git a/tests/10optimizer_bytecode/dupaddmulh b/tests/10optimizer_bytecode/dupaddmulh new file mode 100644 index 0000000..3198446 --- /dev/null +++ b/tests/10optimizer_bytecode/dupaddmulh @@ -0,0 +1,7 @@ +# cDup [x+x==Value_t(1)] cAdd x cMul + +T=d f ld mf +V=x +R=-3,3,1 +F=(x+x)*0.5 +C=x diff --git a/tests/10optimizer_bytecode/dupaddmulmul7 b/tests/10optimizer_bytecode/dupaddmulmul7 new file mode 100644 index 0000000..5eb9f3b --- /dev/null +++ b/tests/10optimizer_bytecode/dupaddmulmul7 @@ -0,0 +1,7 @@ +# cDup cAdd cMul x cMul + +T=d f ld mf +V=x,y +R=-3,3,1 +F=y*(x+x)*7 +C=y*x*14 diff --git a/tests/10optimizer_bytecode/dupaddmulmulh b/tests/10optimizer_bytecode/dupaddmulmulh new file mode 100644 index 0000000..8cfefbd --- /dev/null +++ b/tests/10optimizer_bytecode/dupaddmulmulh @@ -0,0 +1,7 @@ +# cDup [x+x==Value_t(1)] cAdd cMul x cMul + +T=d f ld mf +V=x,y +R=-3,3,1 +F=y*(x+x)*0.5 +C=y*x diff --git a/tests/10optimizer_bytecode/dupminmax b/tests/10optimizer_bytecode/dupminmax new file mode 100644 index 0000000..809be8a --- /dev/null +++ b/tests/10optimizer_bytecode/dupminmax @@ -0,0 +1,7 @@ +# cDup cMin -> +# cDup cMax -> +T=d f ld li gi +V=x +R=-10,10,1 +F=sub(min(x,x), max(x,x)) +C=userDefFuncSub({fp_min(x,x), fp_max(x,x)}) diff --git a/tests/10optimizer_bytecode/dupminmax2 b/tests/10optimizer_bytecode/dupminmax2 new file mode 100644 index 0000000..d18ae47 --- /dev/null +++ b/tests/10optimizer_bytecode/dupminmax2 @@ -0,0 +1,7 @@ +# x cDup x cMin -> x cDup +# x cDup x cMax -> x cDup +T=d f ld li gi +V=x +R=-10,10,1 +F=sub(x+min(x,x), x+max(x,x)) +C=userDefFuncSub({x+fp_min(x,x), x+fp_max(x,x)}) diff --git a/tests/10optimizer_bytecode/dupminmax3 b/tests/10optimizer_bytecode/dupminmax3 new file mode 100644 index 0000000..013780b --- /dev/null +++ b/tests/10optimizer_bytecode/dupminmax3 @@ -0,0 +1,6 @@ +# x cMin x cMin -> x cMin +T=d f ld li gi +V=x,y +R=-2,2,1 +F=sub(min(min(y,x),x), max(max(y,x),x)) +C=userDefFuncSub({fp_min(y,x), fp_max(y,x)}) diff --git a/tests/10optimizer_bytecode/dupxmuladd b/tests/10optimizer_bytecode/dupxmuladd new file mode 100644 index 0000000..ca88d7f --- /dev/null +++ b/tests/10optimizer_bytecode/dupxmuladd @@ -0,0 +1,5 @@ +T=d f ld li gi mf +V=x +R=-10,10,1 +F=x+(x*4) +C=x*5 diff --git a/tests/10optimizer_bytecode/dupxpowmul b/tests/10optimizer_bytecode/dupxpowmul new file mode 100644 index 0000000..ba8bf8c --- /dev/null +++ b/tests/10optimizer_bytecode/dupxpowmul @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-10,10,1 +F=x*(x^3) +C=fp_pow(x,4) diff --git a/tests/10optimizer_bytecode/eq0 b/tests/10optimizer_bytecode/eq0 new file mode 100644 index 0000000..943fb87 --- /dev/null +++ b/tests/10optimizer_bytecode/eq0 @@ -0,0 +1,6 @@ +T=d f ld li +V=x +R=0,1,1 +F=(x=0) + (0=x) +C=fp_equal(x,0) + fp_equal(0,x) + diff --git a/tests/10optimizer_bytecode/eq1 b/tests/10optimizer_bytecode/eq1 new file mode 100644 index 0000000..035d5a0 --- /dev/null +++ b/tests/10optimizer_bytecode/eq1 @@ -0,0 +1,6 @@ +T=d f ld li +V=x +R=0,1,1 +F=(!x=1) +C=fp_equal(fp_not(x),1) + diff --git a/tests/10optimizer_bytecode/exp b/tests/10optimizer_bytecode/exp new file mode 100644 index 0000000..11dd5ea --- /dev/null +++ b/tests/10optimizer_bytecode/exp @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=exp(1.1)+x +C=exp(1.1)+x diff --git a/tests/10optimizer_bytecode/exp2 b/tests/10optimizer_bytecode/exp2 new file mode 100644 index 0000000..c5af366 --- /dev/null +++ b/tests/10optimizer_bytecode/exp2 @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=exp2(1.1)+x +C=exp(1.1*0.693147180559945309417232121458176568075500134)+x diff --git a/tests/10optimizer_bytecode/exp2div b/tests/10optimizer_bytecode/exp2div new file mode 100644 index 0000000..0ec271c --- /dev/null +++ b/tests/10optimizer_bytecode/exp2div @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-3,3,2 +F=x/exp2(y) +C=x/fp_exp2(y) diff --git a/tests/10optimizer_bytecode/exp2f b/tests/10optimizer_bytecode/exp2f new file mode 100644 index 0000000..64520e8 --- /dev/null +++ b/tests/10optimizer_bytecode/exp2f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=exp2(1.1)+x +C=expf(1.1*0.693147180559945309417232121458176568075500134)+x diff --git a/tests/10optimizer_bytecode/exp2l b/tests/10optimizer_bytecode/exp2l new file mode 100644 index 0000000..d474447 --- /dev/null +++ b/tests/10optimizer_bytecode/exp2l @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=exp2(1.1)+x +C=expl(1.1*0.693147180559945309417232121458176568075500134)+x diff --git a/tests/10optimizer_bytecode/exp2log2 b/tests/10optimizer_bytecode/exp2log2 new file mode 100644 index 0000000..235cab8 --- /dev/null +++ b/tests/10optimizer_bytecode/exp2log2 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-3,3,0.1 +F=log2(exp2(x)) +C=fp_log2(fp_exp2(x)) diff --git a/tests/10optimizer_bytecode/exp2m b/tests/10optimizer_bytecode/exp2m new file mode 100644 index 0000000..9a6e382 --- /dev/null +++ b/tests/10optimizer_bytecode/exp2m @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=exp2(1.1)+x +C=MpfrFloat::exp2(1.1)+x diff --git a/tests/10optimizer_bytecode/exp2xpow b/tests/10optimizer_bytecode/exp2xpow new file mode 100644 index 0000000..eaa05f6 --- /dev/null +++ b/tests/10optimizer_bytecode/exp2xpow @@ -0,0 +1,6 @@ +# cExp2 x [IsIntegerConst(x)] cPow -> [x] cMul cExp +T=d +V=x +R=-.1,.1,0.01 +F=exp2(x)^1506 +C=fp_pow(fp_exp2(x),1506) diff --git a/tests/10optimizer_bytecode/expdiv b/tests/10optimizer_bytecode/expdiv new file mode 100644 index 0000000..82cc12b --- /dev/null +++ b/tests/10optimizer_bytecode/expdiv @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-3,3,2 +F=x/exp(y) +C=x/fp_exp(y) diff --git a/tests/10optimizer_bytecode/expf b/tests/10optimizer_bytecode/expf new file mode 100644 index 0000000..b2a81ce --- /dev/null +++ b/tests/10optimizer_bytecode/expf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=exp(1.1)+x +C=expf(1.1)+x diff --git a/tests/10optimizer_bytecode/expl b/tests/10optimizer_bytecode/expl new file mode 100644 index 0000000..1d465e9 --- /dev/null +++ b/tests/10optimizer_bytecode/expl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=exp(1.1)+x +C=expl(1.1)+x diff --git a/tests/10optimizer_bytecode/explog b/tests/10optimizer_bytecode/explog new file mode 100644 index 0000000..a32cc71 --- /dev/null +++ b/tests/10optimizer_bytecode/explog @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-3,3,0.1 +F=log(exp(x)) +C=fp_log(fp_exp(x)) diff --git a/tests/10optimizer_bytecode/explog10 b/tests/10optimizer_bytecode/explog10 new file mode 100644 index 0000000..4f2522d --- /dev/null +++ b/tests/10optimizer_bytecode/explog10 @@ -0,0 +1,7 @@ +# log10(exp(x)) = log(exp(x)) / log(10) = x / log(10) + +T=d f ld mf +V=x +R=-3,3,0.1 +F=log10(exp(x)) +C=x/fp_const_log10<Value_t>() diff --git a/tests/10optimizer_bytecode/explog2 b/tests/10optimizer_bytecode/explog2 new file mode 100644 index 0000000..8f25bda --- /dev/null +++ b/tests/10optimizer_bytecode/explog2 @@ -0,0 +1,7 @@ +# log2(exp(x)) = log(exp(x)) / log(2) = x / log(2) + +T=d f ld mf +V=x +R=-3,3,0.1 +F=log2(exp(x)) +C=x/fp_const_log2<Value_t>() diff --git a/tests/10optimizer_bytecode/expm b/tests/10optimizer_bytecode/expm new file mode 100644 index 0000000..8d96fb7 --- /dev/null +++ b/tests/10optimizer_bytecode/expm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=exp(1.1)+x +C=MpfrFloat::exp(1.1)+x diff --git a/tests/10optimizer_bytecode/expxpow b/tests/10optimizer_bytecode/expxpow new file mode 100644 index 0000000..53855cc --- /dev/null +++ b/tests/10optimizer_bytecode/expxpow @@ -0,0 +1,6 @@ +# cExp x [IsIntegerConst(x)] cPow -> [x] cMul cExp +T=d +V=x +R=-.1,.1,0.01 +F=exp(x)^1506 +C=fp_pow(fp_exp(x),1506) diff --git a/tests/10optimizer_bytecode/floor b/tests/10optimizer_bytecode/floor new file mode 100644 index 0000000..6c82a18 --- /dev/null +++ b/tests/10optimizer_bytecode/floor @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=floor(1.1)+x +C=floor(1.1)+x diff --git a/tests/10optimizer_bytecode/floorf b/tests/10optimizer_bytecode/floorf new file mode 100644 index 0000000..d93a997 --- /dev/null +++ b/tests/10optimizer_bytecode/floorf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=floor(1.1)+x +C=floorf(1.1)+x diff --git a/tests/10optimizer_bytecode/floorl b/tests/10optimizer_bytecode/floorl new file mode 100644 index 0000000..1c5f978 --- /dev/null +++ b/tests/10optimizer_bytecode/floorl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=floor(1.1)+x +C=floorl(1.1)+x diff --git a/tests/10optimizer_bytecode/floorm b/tests/10optimizer_bytecode/floorm new file mode 100644 index 0000000..534e9c8 --- /dev/null +++ b/tests/10optimizer_bytecode/floorm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=floor(1.1)+x +C=MpfrFloat::floor(1.1)+x diff --git a/tests/10optimizer_bytecode/floorneg b/tests/10optimizer_bytecode/floorneg new file mode 100644 index 0000000..8f99333 --- /dev/null +++ b/tests/10optimizer_bytecode/floorneg @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=floor(-x) +C=fp_floor(-x) diff --git a/tests/10optimizer_bytecode/ge0_abs b/tests/10optimizer_bytecode/ge0_abs new file mode 100644 index 0000000..8ff0618 --- /dev/null +++ b/tests/10optimizer_bytecode/ge0_abs @@ -0,0 +1,11 @@ +T=d f ld li +V=x +R=-1,1,1 +F=(abs(x) >= 0) + \ + 2*(0 <= abs(x)) + \ + 4*(abs(x) <= 0) + \ + 8*(0 >= abs(x)) +C=fp_greaterOrEq(fp_abs(x), 0) + \ + 2*fp_lessOrEq(0, fp_abs(x)) + \ + 4*fp_lessOrEq(fp_abs(x), 0) + \ + 8*fp_greaterOrEq(0, fp_abs(x)) diff --git a/tests/10optimizer_bytecode/ge0_neg b/tests/10optimizer_bytecode/ge0_neg new file mode 100644 index 0000000..6bb1644 --- /dev/null +++ b/tests/10optimizer_bytecode/ge0_neg @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(sin(x) >= 0) + \ + 2*(0 <= sin(x)) + \ + 4*(sin(x) <= 0) + \ + 8*(0 >= sin(x)) +C=fp_greaterOrEq(fp_sin(x), 0) + \ + 2*fp_lessOrEq(0, fp_sin(x)) + \ + 4*fp_lessOrEq(fp_sin(x), 0) + \ + 8*fp_greaterOrEq(0, fp_sin(x)) diff --git a/tests/10optimizer_bytecode/ge0_pos b/tests/10optimizer_bytecode/ge0_pos new file mode 100644 index 0000000..f24679b --- /dev/null +++ b/tests/10optimizer_bytecode/ge0_pos @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(acos(x) >= 0) + \ + 2*(0 <= acos(x)) + \ + 4*(acos(x) <= 0) + \ + 8*(0 >= acos(x)) +C=fp_greaterOrEq(fp_acos(x), 0) + \ + 2*fp_lessOrEq(0, fp_acos(x)) + \ + 4*fp_lessOrEq(fp_acos(x), 0) + \ + 8*fp_greaterOrEq(0, fp_acos(x)) diff --git a/tests/10optimizer_bytecode/ge1_abs b/tests/10optimizer_bytecode/ge1_abs new file mode 100644 index 0000000..be20358 --- /dev/null +++ b/tests/10optimizer_bytecode/ge1_abs @@ -0,0 +1,11 @@ +T=d f ld li +V=x +R=-1,1,1 +F=(abs(x) >= 1) + \ + 2*(1 <= abs(x)) + \ + 4*(abs(x) <= 1) + \ + 8*(1 >= abs(x)) +C=fp_greaterOrEq(fp_abs(x), 1) + \ + 2*fp_lessOrEq(1, fp_abs(x)) + \ + 4*fp_lessOrEq(fp_abs(x), 1) + \ + 8*fp_greaterOrEq(1, fp_abs(x)) diff --git a/tests/10optimizer_bytecode/ge1_neg b/tests/10optimizer_bytecode/ge1_neg new file mode 100644 index 0000000..0cef2d4 --- /dev/null +++ b/tests/10optimizer_bytecode/ge1_neg @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(sin(x) >= 1) + \ + 2*(1 <= sin(x)) + \ + 4*(sin(x) <= 1) + \ + 8*(1 >= sin(x)) +C=fp_greaterOrEq(fp_sin(x), 1) + \ + 2*fp_lessOrEq(1, fp_sin(x)) + \ + 4*fp_lessOrEq(fp_sin(x), 1) + \ + 8*fp_greaterOrEq(1, fp_sin(x)) diff --git a/tests/10optimizer_bytecode/ge1_pos b/tests/10optimizer_bytecode/ge1_pos new file mode 100644 index 0000000..7e8b32b --- /dev/null +++ b/tests/10optimizer_bytecode/ge1_pos @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(acos(x) >= 1) + \ + 2*(1 <= acos(x)) + \ + 4*(acos(x) <= 1) + \ + 8*(1 >= acos(x)) +C=fp_greaterOrEq(fp_acos(x), 1) + \ + 2*fp_lessOrEq(1, fp_acos(x)) + \ + 4*fp_lessOrEq(fp_acos(x), 1) + \ + 8*fp_greaterOrEq(1, fp_acos(x)) diff --git a/tests/10optimizer_bytecode/gehalf b/tests/10optimizer_bytecode/gehalf new file mode 100644 index 0000000..45177a5 --- /dev/null +++ b/tests/10optimizer_bytecode/gehalf @@ -0,0 +1,5 @@ +T=d f +V=x +R=-1,1,0.25 +F=x>=0.5 +C=fp_greaterOrEq(x, 0.5) diff --git a/tests/10optimizer_bytecode/gt0_abs b/tests/10optimizer_bytecode/gt0_abs new file mode 100644 index 0000000..dccab23 --- /dev/null +++ b/tests/10optimizer_bytecode/gt0_abs @@ -0,0 +1,11 @@ +T=d f ld li +V=x +R=-1,1,1 +F=(abs(x) > 0) + \ + 2*(0 < abs(x)) + \ + 4*(abs(x) < 0) + \ + 8*(0 > abs(x)) +C=fp_greater(fp_abs(x), 0) + \ + 2*fp_less(0, fp_abs(x)) + \ + 4*fp_less(fp_abs(x), 0) + \ + 8*fp_greater(0, fp_abs(x)) diff --git a/tests/10optimizer_bytecode/gt0_neg b/tests/10optimizer_bytecode/gt0_neg new file mode 100644 index 0000000..9ea34e3 --- /dev/null +++ b/tests/10optimizer_bytecode/gt0_neg @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(sin(x) > 0) + \ + 2*(0 < sin(x)) + \ + 4*(sin(x) < 0) + \ + 8*(0 > sin(x)) +C=fp_greater(fp_sin(x), 0) + \ + 2*fp_less(0, fp_sin(x)) + \ + 4*fp_less(fp_sin(x), 0) + \ + 8*fp_greater(0, fp_sin(x)) diff --git a/tests/10optimizer_bytecode/gt0_pos b/tests/10optimizer_bytecode/gt0_pos new file mode 100644 index 0000000..b2c2423 --- /dev/null +++ b/tests/10optimizer_bytecode/gt0_pos @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(acos(x) > 0) + \ + 2*(0 < acos(x)) + \ + 4*(acos(x) < 0) + \ + 8*(0 > acos(x)) +C=fp_greater(fp_acos(x), 0) + \ + 2*fp_less(0, fp_acos(x)) + \ + 4*fp_less(fp_acos(x), 0) + \ + 8*fp_greater(0, fp_acos(x)) diff --git a/tests/10optimizer_bytecode/gt1_abs b/tests/10optimizer_bytecode/gt1_abs new file mode 100644 index 0000000..f412eab --- /dev/null +++ b/tests/10optimizer_bytecode/gt1_abs @@ -0,0 +1,11 @@ +T=d f ld li +V=x +R=-1,1,1 +F=(abs(x) > 1) + \ + 2*(1 < abs(x)) + \ + 4*(abs(x) < 1) + \ + 8*(1 > abs(x)) +C=fp_greater(fp_abs(x), 1) + \ + 2*fp_less(1, fp_abs(x)) + \ + 4*fp_less(fp_abs(x), 1) + \ + 8*fp_greater(1, fp_abs(x)) diff --git a/tests/10optimizer_bytecode/gt1_neg b/tests/10optimizer_bytecode/gt1_neg new file mode 100644 index 0000000..70f9a76 --- /dev/null +++ b/tests/10optimizer_bytecode/gt1_neg @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(sin(x) > 1) + \ + 2*(1 < sin(x)) + \ + 4*(sin(x) < 1) + \ + 8*(1 > sin(x)) +C=fp_greater(fp_sin(x), 1) + \ + 2*fp_less(1, fp_sin(x)) + \ + 4*fp_less(fp_sin(x), 1) + \ + 8*fp_greater(1, fp_sin(x)) diff --git a/tests/10optimizer_bytecode/gt1_pos b/tests/10optimizer_bytecode/gt1_pos new file mode 100644 index 0000000..bcf95cf --- /dev/null +++ b/tests/10optimizer_bytecode/gt1_pos @@ -0,0 +1,11 @@ +T=d f ld +V=x +R=-1,1,0.25 +F=(acos(x) > 1) + \ + 2*(1 < acos(x)) + \ + 4*(acos(x) < 1) + \ + 8*(1 > acos(x)) +C=fp_greater(fp_acos(x), 1) + \ + 2*fp_less(1, fp_acos(x)) + \ + 4*fp_less(fp_acos(x), 1) + \ + 8*fp_greater(1, fp_acos(x)) diff --git a/tests/10optimizer_bytecode/gtminushalf b/tests/10optimizer_bytecode/gtminushalf new file mode 100644 index 0000000..64a7611 --- /dev/null +++ b/tests/10optimizer_bytecode/gtminushalf @@ -0,0 +1,5 @@ +T=d f +V=x +R=-1,1,0.25 +F=x>-0.5 +C=fp_greater(x, -0.5) diff --git a/tests/10optimizer_bytecode/hypot b/tests/10optimizer_bytecode/hypot new file mode 100644 index 0000000..801ecf9 --- /dev/null +++ b/tests/10optimizer_bytecode/hypot @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=hypot(5,4)+x +C=sqrt(5*5+4*4)+x diff --git a/tests/10optimizer_bytecode/hypotf b/tests/10optimizer_bytecode/hypotf new file mode 100644 index 0000000..0e55778 --- /dev/null +++ b/tests/10optimizer_bytecode/hypotf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=hypot(5,4)+x +C=sqrtf(5*5+4*4)+x diff --git a/tests/10optimizer_bytecode/hypotl b/tests/10optimizer_bytecode/hypotl new file mode 100644 index 0000000..5d32b9a --- /dev/null +++ b/tests/10optimizer_bytecode/hypotl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=hypot(5,4)+x +C=sqrtl(5*5+4*4)+x diff --git a/tests/10optimizer_bytecode/hypotm b/tests/10optimizer_bytecode/hypotm new file mode 100644 index 0000000..73c7434 --- /dev/null +++ b/tests/10optimizer_bytecode/hypotm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=hypot(5,4)+x +C=MpfrFloat::hypot(5,4)+x diff --git a/tests/10optimizer_bytecode/immsub b/tests/10optimizer_bytecode/immsub new file mode 100644 index 0000000..2024891 --- /dev/null +++ b/tests/10optimizer_bytecode/immsub @@ -0,0 +1,5 @@ +T=d li +V=x +R=-6, 6, 1 +F=x-5 +C=x-5 diff --git a/tests/10optimizer_bytecode/int b/tests/10optimizer_bytecode/int new file mode 100644 index 0000000..407c7db --- /dev/null +++ b/tests/10optimizer_bytecode/int @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1.5, 1.5, 0.25 +F=x+sub(sub(sub(sub(sub(int(1.1), int(1.6)), int(1.5)), int(-1.1)), int(-1.6)), int(-1.5)) +C=x + (((((fp_int(1.1) - fp_int(1.6)) - fp_int(1.5)) - fp_int(-1.1)) - fp_int(-1.6)) - fp_int(-1.5)) diff --git a/tests/10optimizer_bytecode/intceil b/tests/10optimizer_bytecode/intceil new file mode 100644 index 0000000..a26dc85 --- /dev/null +++ b/tests/10optimizer_bytecode/intceil @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=ceil(x>4) +C=fp_ceil(fp_greater(x,4)) diff --git a/tests/10optimizer_bytecode/intfloor b/tests/10optimizer_bytecode/intfloor new file mode 100644 index 0000000..b7323e9 --- /dev/null +++ b/tests/10optimizer_bytecode/intfloor @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=floor(x>4) +C=fp_floor(fp_greater(x,4)) diff --git a/tests/10optimizer_bytecode/intint b/tests/10optimizer_bytecode/intint new file mode 100644 index 0000000..e1bafec --- /dev/null +++ b/tests/10optimizer_bytecode/intint @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=int(x>4) +C=fp_int(fp_greater(x,4)) diff --git a/tests/10optimizer_bytecode/inttrunc b/tests/10optimizer_bytecode/inttrunc new file mode 100644 index 0000000..f887a50 --- /dev/null +++ b/tests/10optimizer_bytecode/inttrunc @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=trunc(x>4) +C=fp_trunc(fp_greater(x,4)) diff --git a/tests/10optimizer_bytecode/invdiv b/tests/10optimizer_bytecode/invdiv new file mode 100644 index 0000000..b42971b --- /dev/null +++ b/tests/10optimizer_bytecode/invdiv @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-3,3,2 +F=y/(1/x) +C=y/(1/x) diff --git a/tests/10optimizer_bytecode/invinv b/tests/10optimizer_bytecode/invinv new file mode 100644 index 0000000..36ce291 --- /dev/null +++ b/tests/10optimizer_bytecode/invinv @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-3,3,2 +F=1/(1/x) +C=1/(1/x) diff --git a/tests/10optimizer_bytecode/invmul b/tests/10optimizer_bytecode/invmul new file mode 100644 index 0000000..acbd1dd --- /dev/null +++ b/tests/10optimizer_bytecode/invmul @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x,y +R=-3,3,2 +F=y*(1/x) +C=y*(1/x) diff --git a/tests/10optimizer_bytecode/invsincostan b/tests/10optimizer_bytecode/invsincostan new file mode 100644 index 0000000..343be9a --- /dev/null +++ b/tests/10optimizer_bytecode/invsincostan @@ -0,0 +1,62 @@ +T=ld +V=x,y +R=-0.7, 0.7, 0.28 +F=x/sin(y) + x/cos(y) + x/tan(y) + x/csc(y) + x/sec(y) + x/cot(y) + \ + 1/sin(y) + 1/cos(y) + 1/tan(y) + 1/csc(y) + 1/sec(y) + 1/cot(y) + +# Expected outcome after bytecode optimization: +# x*csc(y) + x*sec(y) + x*cot(y) +# + x*sin(y) + x*cos(y) + x*tan(y) +# + csc(y) + sec(y) + cot(y) +# + sin(y) + cos(y) + tan(y) + +# Expected intermediate form in tree optimization: +# x*sin(y)^-1 + x*cos(y)^-1 + x*cos(y)*sin(y)^-1 +# + x*sin(y) + x*cos(y) + x*sin(y)*cos(y)^-1 +# + sin(y)^-1 + cos(y)^-1 + cos(y)*sin(y)^-1 +# + sin(y) + cos(y) + sin(y)*cos(y)^-1 + +# One of possible outcomes after tree optimization: +# (x+1) * ( (sin(y)+cos(y)+tan(y)) + 1/(sin(y)+cos(y)+tan(y)) ) + +# One of possible outcomes after tree optimization: +# (x+1) * (sin(y) * (1 + cos(y)^-1) +# + cos(y) * (1 + sin(y)^-1) +# + sin(y)^-1 +# + cos(y)^-1) +# Note: sin(y) and cos(y) are subject to CSE and use of sincos(). +# which would optimally result in the following bytecode: +# 00 push y [0=y] +# 01 sincos [0=sin,1=cos] +# 02 dup [2=cos] +# 03 inv [2=cos^-1] +# 04 fetch 0 [3=sin] +# 06 inv [3=sin^-1] +# 07 push x [4=x] +# 08 push 1 [5=1] +# 09 add [4=x+1] +# 0A fetch 0 [5=sin] +# 0C push 1 [6=1] +# 0D fetch 2 [7=cos^-1] +# 0F add [6=1+cos^-1] +# 10 mul [5=sin * (1+cos^-1)] +# 11 fetch 1 [6=sin] +# 13 push 1 [7=1] +# 14 fetch 3 [8=sin^-1] +# 16 add [7=1+sin^-1] +# 17 mul [6=cos * (1+cos^-1)] +# 18 add [5=sin * (1+cos^-1) + cos * (1+cos^-1)] +# 19 fetch 3 [6=sin^-1] +# 1B add [5=sin * (1+cos^-1) + cos * (1+cos^-1) + sin^-1] +# 1C fetch 2 [6=cos^-1] +# 1E add [5=sin * (1+cos^-1) + cos * (1+cos^-1) + sin^-1 + cos^-1] +# 1F mul [4=result] +# 20 <end> + +# Unfortunately, the optimizer generates tan(), sec() and so on +# before it realizes the opportunities for sincos() use. + +C= x/fp_sin(y) + x/fp_cos(y) + x/fp_tan(y) \ + + x*fp_sin(y) + x*fp_cos(y) + x*fp_tan(y) \ + + 1/fp_sin(y) + 1/fp_cos(y) + 1/fp_tan(y) \ + + 1*fp_sin(y) + 1*fp_cos(y) + 1*fp_tan(y) diff --git a/tests/10optimizer_bytecode/leminushalf b/tests/10optimizer_bytecode/leminushalf new file mode 100644 index 0000000..f186f79 --- /dev/null +++ b/tests/10optimizer_bytecode/leminushalf @@ -0,0 +1,5 @@ +T=d f +V=x +R=-1,1,0.25 +F=x<=-0.5 +C=fp_lessOrEq(x, -0.5) diff --git a/tests/10optimizer_bytecode/log b/tests/10optimizer_bytecode/log new file mode 100644 index 0000000..42efe6c --- /dev/null +++ b/tests/10optimizer_bytecode/log @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=log(1.1)+x +C=log(1.1)+x diff --git a/tests/10optimizer_bytecode/log10 b/tests/10optimizer_bytecode/log10 new file mode 100644 index 0000000..40d09cf --- /dev/null +++ b/tests/10optimizer_bytecode/log10 @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=log10(1.1)+x +C=log(1.1)*0.43429448190325182765112891891660508229+x diff --git a/tests/10optimizer_bytecode/log10f b/tests/10optimizer_bytecode/log10f new file mode 100644 index 0000000..0892b30 --- /dev/null +++ b/tests/10optimizer_bytecode/log10f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=log10(1.1)+x +C=log10f(1.1)+x diff --git a/tests/10optimizer_bytecode/log10l b/tests/10optimizer_bytecode/log10l new file mode 100644 index 0000000..39895aa --- /dev/null +++ b/tests/10optimizer_bytecode/log10l @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=log10(1.1)+x +C=log10l(1.1)+x diff --git a/tests/10optimizer_bytecode/log10m b/tests/10optimizer_bytecode/log10m new file mode 100644 index 0000000..1a8215d --- /dev/null +++ b/tests/10optimizer_bytecode/log10m @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=log10(1.1)+x +C=MpfrFloat::log10(1.1)+x diff --git a/tests/10optimizer_bytecode/log2 b/tests/10optimizer_bytecode/log2 new file mode 100644 index 0000000..e2da926 --- /dev/null +++ b/tests/10optimizer_bytecode/log2 @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=log2(1.1)+x +C=log(1.1)*1.4426950408889634073599246810018921374266+x diff --git a/tests/10optimizer_bytecode/log2exp1 b/tests/10optimizer_bytecode/log2exp1 new file mode 100644 index 0000000..08f9031 --- /dev/null +++ b/tests/10optimizer_bytecode/log2exp1 @@ -0,0 +1,7 @@ +# x cLog2 cExp -> x (when not known whether x may be negative) + +T=d f +V=x +R=0, 3, 0.5 +F=exp(log2(x)) +C=fp_exp(fp_log2(x)) diff --git a/tests/10optimizer_bytecode/log2exp2 b/tests/10optimizer_bytecode/log2exp2 new file mode 100644 index 0000000..5fd5280 --- /dev/null +++ b/tests/10optimizer_bytecode/log2exp2 @@ -0,0 +1,7 @@ +# x cLog2 cExp2 -> x (when x is never negative) + +T=d f +V=x +R=-1,0.75,0.25 +F=exp2(log2(acos(x))) +C=fp_exp2(fp_log2(fp_acos(x))) diff --git a/tests/10optimizer_bytecode/log2f b/tests/10optimizer_bytecode/log2f new file mode 100644 index 0000000..23ad34e --- /dev/null +++ b/tests/10optimizer_bytecode/log2f @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=log2(1.1)+x +C=logf(1.1)*1.4426950408889634073599246810018921374266+x diff --git a/tests/10optimizer_bytecode/log2l b/tests/10optimizer_bytecode/log2l new file mode 100644 index 0000000..f8d0a50 --- /dev/null +++ b/tests/10optimizer_bytecode/log2l @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=log2(1.1)+x +C=logl(1.1)*1.4426950408889634073599246810018921374266+x diff --git a/tests/10optimizer_bytecode/log2m b/tests/10optimizer_bytecode/log2m new file mode 100644 index 0000000..b5fa3e4 --- /dev/null +++ b/tests/10optimizer_bytecode/log2m @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=log2(1.1)+x +C=MpfrFloat::log2(1.1)+x diff --git a/tests/10optimizer_bytecode/logexp1 b/tests/10optimizer_bytecode/logexp1 new file mode 100644 index 0000000..d9a44c4 --- /dev/null +++ b/tests/10optimizer_bytecode/logexp1 @@ -0,0 +1,7 @@ +# x cLog cExp -> x (when not known whether x may be negative) + +T=d f +V=x +R=0, 3, 0.5 +F=exp(log(x)) +C=fp_exp(fp_log(x)) diff --git a/tests/10optimizer_bytecode/logexp2 b/tests/10optimizer_bytecode/logexp2 new file mode 100644 index 0000000..29cac82 --- /dev/null +++ b/tests/10optimizer_bytecode/logexp2 @@ -0,0 +1,7 @@ +# x cLog cExp -> x (when x is never negative) + +T=d f +V=x +R=-1,0.75,0.25 +F=exp(log(acos(x))) +C=fp_exp(fp_log(fp_acos(x))) diff --git a/tests/10optimizer_bytecode/logf b/tests/10optimizer_bytecode/logf new file mode 100644 index 0000000..15f40c9 --- /dev/null +++ b/tests/10optimizer_bytecode/logf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=log(1.1)+x +C=logf(1.1)+x diff --git a/tests/10optimizer_bytecode/logl b/tests/10optimizer_bytecode/logl new file mode 100644 index 0000000..641bd6e --- /dev/null +++ b/tests/10optimizer_bytecode/logl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=log(1.1)+x +C=logl(1.1)+x diff --git a/tests/10optimizer_bytecode/logm b/tests/10optimizer_bytecode/logm new file mode 100644 index 0000000..dbcb808 --- /dev/null +++ b/tests/10optimizer_bytecode/logm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=log(1.1)+x +C=MpfrFloat::log(1.1)+x diff --git a/tests/10optimizer_bytecode/logmul b/tests/10optimizer_bytecode/logmul new file mode 100644 index 0000000..df4fae3 --- /dev/null +++ b/tests/10optimizer_bytecode/logmul @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-3,3,0.41 +F=log(1.1^x*4.1) +C=fp_log(fp_pow(1.1, x) * 4.1) diff --git a/tests/10optimizer_bytecode/logmul10 b/tests/10optimizer_bytecode/logmul10 new file mode 100644 index 0000000..7503240 --- /dev/null +++ b/tests/10optimizer_bytecode/logmul10 @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-3,3,0.41 +F=log10(1.1^x*4.1) +C=fp_log10(fp_pow(1.1, x) * 4.1) diff --git a/tests/10optimizer_bytecode/logmul2 b/tests/10optimizer_bytecode/logmul2 new file mode 100644 index 0000000..33c3c95 --- /dev/null +++ b/tests/10optimizer_bytecode/logmul2 @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-3,3,0.41 +F=log2(1.1^x*4.1) +C=fp_log2(fp_pow(1.1, x) * 4.1) diff --git a/tests/10optimizer_bytecode/lt0 b/tests/10optimizer_bytecode/lt0 new file mode 100644 index 0000000..10768cc --- /dev/null +++ b/tests/10optimizer_bytecode/lt0 @@ -0,0 +1,5 @@ +T=d f li +V=x +R=-1,1,1 +F=sub(abs(x)<0, x<0) +C=fp_less(fp_abs(x),x-x) - fp_less(x,x-x) diff --git a/tests/10optimizer_bytecode/lthalf b/tests/10optimizer_bytecode/lthalf new file mode 100644 index 0000000..2d08079 --- /dev/null +++ b/tests/10optimizer_bytecode/lthalf @@ -0,0 +1,5 @@ +T=d f +V=x +R=-1,1,0.25 +F=x<0.5 +C=fp_less(x, 0.5) diff --git a/tests/10optimizer_bytecode/max b/tests/10optimizer_bytecode/max new file mode 100644 index 0000000..3168206 --- /dev/null +++ b/tests/10optimizer_bytecode/max @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x +R=0,1,1 +F=max(5,4)+x +C=5+x diff --git a/tests/10optimizer_bytecode/min b/tests/10optimizer_bytecode/min new file mode 100644 index 0000000..fdd22b1 --- /dev/null +++ b/tests/10optimizer_bytecode/min @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x +R=0,1,1 +F=min(4,5)+x +C=4+x diff --git a/tests/10optimizer_bytecode/mod b/tests/10optimizer_bytecode/mod new file mode 100644 index 0000000..3e33397 --- /dev/null +++ b/tests/10optimizer_bytecode/mod @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5%4)+x +C=fp_mod(5,4)+x diff --git a/tests/10optimizer_bytecode/mul b/tests/10optimizer_bytecode/mul new file mode 100644 index 0000000..a99b63b --- /dev/null +++ b/tests/10optimizer_bytecode/mul @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(5*4)+x +C=(5*4)+x diff --git a/tests/10optimizer_bytecode/mul1 b/tests/10optimizer_bytecode/mul1 new file mode 100644 index 0000000..00e9739 --- /dev/null +++ b/tests/10optimizer_bytecode/mul1 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=x*1+x +C=x*1+x diff --git a/tests/10optimizer_bytecode/mul1b b/tests/10optimizer_bytecode/mul1b new file mode 100644 index 0000000..d8a4f8d --- /dev/null +++ b/tests/10optimizer_bytecode/mul1b @@ -0,0 +1,5 @@ +T=d f +V=x +R=0,1,1 +F=((x*0.2)*5)+x +C=((x*0.2)*5)+x diff --git a/tests/10optimizer_bytecode/mul2 b/tests/10optimizer_bytecode/mul2 new file mode 100644 index 0000000..e0f05df --- /dev/null +++ b/tests/10optimizer_bytecode/mul2 @@ -0,0 +1,5 @@ +T=d f ld li mf gi +V=x +R=0,1,1 +F=x*2 +C=x+x diff --git a/tests/10optimizer_bytecode/mul4 b/tests/10optimizer_bytecode/mul4 new file mode 100644 index 0000000..37f0716 --- /dev/null +++ b/tests/10optimizer_bytecode/mul4 @@ -0,0 +1,5 @@ +T=d f ld li mf gi +V=x,y +R=-3,3,1 +F=y*(x*2)*2 + (y*2)*2 +C=y*(x*2)*2 + (y*2)*2 diff --git a/tests/10optimizer_bytecode/mul_zero b/tests/10optimizer_bytecode/mul_zero new file mode 100644 index 0000000..7c354df --- /dev/null +++ b/tests/10optimizer_bytecode/mul_zero @@ -0,0 +1,6 @@ +# multiplications by zero +T=d f +V=x,y +R=0.1,10,0.1 +F=(x*y+1)+(sin(x)+sin(y))*log(x)*y*x*0 +C=(x*y+1)+(fp_sin(x)+fp_sin(y))*fp_log(x)*y*x*0 diff --git a/tests/10optimizer_bytecode/mulminus1 b/tests/10optimizer_bytecode/mulminus1 new file mode 100644 index 0000000..d5b0ddb --- /dev/null +++ b/tests/10optimizer_bytecode/mulminus1 @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=x*-1 +C=x*-1 diff --git a/tests/10optimizer_bytecode/mulneg b/tests/10optimizer_bytecode/mulneg new file mode 100644 index 0000000..cdd9b11 --- /dev/null +++ b/tests/10optimizer_bytecode/mulneg @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=-(x*5) +C=-(x*5) diff --git a/tests/10optimizer_bytecode/multodiv b/tests/10optimizer_bytecode/multodiv new file mode 100644 index 0000000..344ebff --- /dev/null +++ b/tests/10optimizer_bytecode/multodiv @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=x/4+x +C=x/4+x diff --git a/tests/10optimizer_bytecode/neg b/tests/10optimizer_bytecode/neg new file mode 100644 index 0000000..0e6c4c8 --- /dev/null +++ b/tests/10optimizer_bytecode/neg @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=((-((5))))+x +C=((-((5))))+x diff --git a/tests/10optimizer_bytecode/negabs b/tests/10optimizer_bytecode/negabs new file mode 100644 index 0000000..42b20fc --- /dev/null +++ b/tests/10optimizer_bytecode/negabs @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=abs(-x) +C=fp_abs(-x) diff --git a/tests/10optimizer_bytecode/negadd b/tests/10optimizer_bytecode/negadd new file mode 100644 index 0000000..7744f10 --- /dev/null +++ b/tests/10optimizer_bytecode/negadd @@ -0,0 +1,5 @@ +T=d li +V=x,y +R=-6, 6, 1 +F=x+(-y) +C=x+(-y) diff --git a/tests/10optimizer_bytecode/negceil b/tests/10optimizer_bytecode/negceil new file mode 100644 index 0000000..b40b89f --- /dev/null +++ b/tests/10optimizer_bytecode/negceil @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=-ceil(x) +C=-fp_ceil(x) diff --git a/tests/10optimizer_bytecode/negcos b/tests/10optimizer_bytecode/negcos new file mode 100644 index 0000000..7e36ff0 --- /dev/null +++ b/tests/10optimizer_bytecode/negcos @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=cos(-x) +C=fp_cos(-x) diff --git a/tests/10optimizer_bytecode/negcosh b/tests/10optimizer_bytecode/negcosh new file mode 100644 index 0000000..47e4f01 --- /dev/null +++ b/tests/10optimizer_bytecode/negcosh @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=cosh(-x) +C=fp_cosh(-x) diff --git a/tests/10optimizer_bytecode/negdiv b/tests/10optimizer_bytecode/negdiv new file mode 100644 index 0000000..1fa42bf --- /dev/null +++ b/tests/10optimizer_bytecode/negdiv @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=(-x)/5 +C=(-x)/5 diff --git a/tests/10optimizer_bytecode/negfloor b/tests/10optimizer_bytecode/negfloor new file mode 100644 index 0000000..e07604b --- /dev/null +++ b/tests/10optimizer_bytecode/negfloor @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,0.5 +F=-floor(x) +C=-fp_floor(x) diff --git a/tests/10optimizer_bytecode/negmul b/tests/10optimizer_bytecode/negmul new file mode 100644 index 0000000..ec79086 --- /dev/null +++ b/tests/10optimizer_bytecode/negmul @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(-x)*5 +C=(-x)*5 diff --git a/tests/10optimizer_bytecode/negneg b/tests/10optimizer_bytecode/negneg new file mode 100644 index 0000000..5c5a63b --- /dev/null +++ b/tests/10optimizer_bytecode/negneg @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-3,3,2 +F=-(-(-(-(-(-(x)))))) +C=-(-(-(-(-(-(x)))))) diff --git a/tests/10optimizer_bytecode/negnot b/tests/10optimizer_bytecode/negnot new file mode 100644 index 0000000..fa8e6fc --- /dev/null +++ b/tests/10optimizer_bytecode/negnot @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=!(-x) +C=fp_not(-x) diff --git a/tests/10optimizer_bytecode/negsin b/tests/10optimizer_bytecode/negsin new file mode 100644 index 0000000..e935649 --- /dev/null +++ b/tests/10optimizer_bytecode/negsin @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=sin(-x) +C=fp_sin(-x) diff --git a/tests/10optimizer_bytecode/negsinh b/tests/10optimizer_bytecode/negsinh new file mode 100644 index 0000000..a1f7791 --- /dev/null +++ b/tests/10optimizer_bytecode/negsinh @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=sinh(-x) +C=fp_sinh(-x) diff --git a/tests/10optimizer_bytecode/negsqr b/tests/10optimizer_bytecode/negsqr new file mode 100644 index 0000000..8efc4e9 --- /dev/null +++ b/tests/10optimizer_bytecode/negsqr @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=(-x)*(-x) +C=x*x diff --git a/tests/10optimizer_bytecode/negsub b/tests/10optimizer_bytecode/negsub new file mode 100644 index 0000000..3bae30b --- /dev/null +++ b/tests/10optimizer_bytecode/negsub @@ -0,0 +1,5 @@ +T=d li +V=x,y +R=-6, 6, 1 +F=x-(-y) +C=x-(-y) diff --git a/tests/10optimizer_bytecode/negtan b/tests/10optimizer_bytecode/negtan new file mode 100644 index 0000000..0eb5c84 --- /dev/null +++ b/tests/10optimizer_bytecode/negtan @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=tan(-x) +C=fp_tan(-x) diff --git a/tests/10optimizer_bytecode/negtanh b/tests/10optimizer_bytecode/negtanh new file mode 100644 index 0000000..e207cf6 --- /dev/null +++ b/tests/10optimizer_bytecode/negtanh @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=tanh(-x) +C=fp_tanh(-x) diff --git a/tests/10optimizer_bytecode/neq0 b/tests/10optimizer_bytecode/neq0 new file mode 100644 index 0000000..9517d3c --- /dev/null +++ b/tests/10optimizer_bytecode/neq0 @@ -0,0 +1,5 @@ +T=d f ld li +V=x +R=0,1,1 +F=(x!=0) + (0!=x) +C=(fp_nequal(x,0)) + (fp_nequal(0,x)) diff --git a/tests/10optimizer_bytecode/neq1 b/tests/10optimizer_bytecode/neq1 new file mode 100644 index 0000000..d968fab --- /dev/null +++ b/tests/10optimizer_bytecode/neq1 @@ -0,0 +1,6 @@ +T=d f ld li +V=x +R=0,1,1 +F=(!x!=1) +C=fp_nequal(fp_not(x),1) + diff --git a/tests/10optimizer_bytecode/not b/tests/10optimizer_bytecode/not new file mode 100644 index 0000000..3263631 --- /dev/null +++ b/tests/10optimizer_bytecode/not @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(!(3))+x +C=fp_not(3)+x diff --git a/tests/10optimizer_bytecode/not_eq b/tests/10optimizer_bytecode/not_eq new file mode 100644 index 0000000..d617d2b --- /dev/null +++ b/tests/10optimizer_bytecode/not_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi +V=x,y +R=0,1,1 +F= !(x = y) +C= x != y diff --git a/tests/10optimizer_bytecode/not_ge b/tests/10optimizer_bytecode/not_ge new file mode 100644 index 0000000..d54dda2 --- /dev/null +++ b/tests/10optimizer_bytecode/not_ge @@ -0,0 +1,5 @@ +T=d ld li f mf gi +V=x,y +R=0,1,1 +F= !(x >= y) +C= x < y diff --git a/tests/10optimizer_bytecode/not_gt b/tests/10optimizer_bytecode/not_gt new file mode 100644 index 0000000..5efebcb --- /dev/null +++ b/tests/10optimizer_bytecode/not_gt @@ -0,0 +1,5 @@ +T=d ld li f mf gi +V=x,y +R=0,1,1 +F= !(x > y) +C= x <= y diff --git a/tests/10optimizer_bytecode/not_le b/tests/10optimizer_bytecode/not_le new file mode 100644 index 0000000..48f712b --- /dev/null +++ b/tests/10optimizer_bytecode/not_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi +V=x,y +R=0,1,1 +F= !(x <= y) +C= x > y diff --git a/tests/10optimizer_bytecode/not_lt b/tests/10optimizer_bytecode/not_lt new file mode 100644 index 0000000..c8d5d92 --- /dev/null +++ b/tests/10optimizer_bytecode/not_lt @@ -0,0 +1,5 @@ +T=d ld li f mf gi +V=x,y +R=0,1,1 +F= !(x < y) +C= x >= y diff --git a/tests/10optimizer_bytecode/not_ne b/tests/10optimizer_bytecode/not_ne new file mode 100644 index 0000000..c45ce99 --- /dev/null +++ b/tests/10optimizer_bytecode/not_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi +V=x,y +R=0,1,1 +F= !(x != y) +C= x == y diff --git a/tests/10optimizer_bytecode/notnot b/tests/10optimizer_bytecode/notnot new file mode 100644 index 0000000..e2936b8 --- /dev/null +++ b/tests/10optimizer_bytecode/notnot @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=!!(x) +C=fp_notNot(x) diff --git a/tests/10optimizer_bytecode/notnotnot b/tests/10optimizer_bytecode/notnotnot new file mode 100644 index 0000000..cf98dfd --- /dev/null +++ b/tests/10optimizer_bytecode/notnotnot @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=!!!(x) +C=fp_not(x) diff --git a/tests/10optimizer_bytecode/notnotnot2 b/tests/10optimizer_bytecode/notnotnot2 new file mode 100644 index 0000000..88594e4 --- /dev/null +++ b/tests/10optimizer_bytecode/notnotnot2 @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=!x&!x +C=fp_not(x) diff --git a/tests/10optimizer_bytecode/or b/tests/10optimizer_bytecode/or new file mode 100644 index 0000000..284963d --- /dev/null +++ b/tests/10optimizer_bytecode/or @@ -0,0 +1,6 @@ +T=d li +V=x +R=0,1,1 +F=(5|3)+x+(5|0)+(0|5)+(0|0) +C=fp_or(5,3)+x+fp_or(5,0)+fp_or(0,5)+fp_or(0,0) + diff --git a/tests/10optimizer_bytecode/pow_neg b/tests/10optimizer_bytecode/pow_neg new file mode 100644 index 0000000..9062019 --- /dev/null +++ b/tests/10optimizer_bytecode/pow_neg @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=pow(-0.25,4)+x +C=pow(-0.25,4)+x diff --git a/tests/10optimizer_bytecode/pow_negf b/tests/10optimizer_bytecode/pow_negf new file mode 100644 index 0000000..9ac6d39 --- /dev/null +++ b/tests/10optimizer_bytecode/pow_negf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=pow(-0.25,4)+x +C=powf(-0.25,4)+x diff --git a/tests/10optimizer_bytecode/pow_negl b/tests/10optimizer_bytecode/pow_negl new file mode 100644 index 0000000..a615f13 --- /dev/null +++ b/tests/10optimizer_bytecode/pow_negl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=pow(-0.25,4)+x +C=powl(-0.25,4)+x diff --git a/tests/10optimizer_bytecode/pow_negm b/tests/10optimizer_bytecode/pow_negm new file mode 100644 index 0000000..2d8653a --- /dev/null +++ b/tests/10optimizer_bytecode/pow_negm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=pow(-0.25,4)+x +C=MpfrFloat::pow(-0.25,4)+x diff --git a/tests/10optimizer_bytecode/pow_pos b/tests/10optimizer_bytecode/pow_pos new file mode 100644 index 0000000..fce90c4 --- /dev/null +++ b/tests/10optimizer_bytecode/pow_pos @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=pow(1.1, 7.1)+x +C=pow(1.1, 7.1)+x diff --git a/tests/10optimizer_bytecode/pow_posf b/tests/10optimizer_bytecode/pow_posf new file mode 100644 index 0000000..d979261 --- /dev/null +++ b/tests/10optimizer_bytecode/pow_posf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=pow(1.1, 7.1)+x +C=powf(1.1, 7.1)+x diff --git a/tests/10optimizer_bytecode/pow_posl b/tests/10optimizer_bytecode/pow_posl new file mode 100644 index 0000000..a8aec3a --- /dev/null +++ b/tests/10optimizer_bytecode/pow_posl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=pow(1.1, 7.1)+x +C=powl(1.1, 7.1)+x diff --git a/tests/10optimizer_bytecode/pow_posm b/tests/10optimizer_bytecode/pow_posm new file mode 100644 index 0000000..52ec25b --- /dev/null +++ b/tests/10optimizer_bytecode/pow_posm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=pow(1.1, 7.1)+x +C=MpfrFloat::pow(1.1, 7.1)+x diff --git a/tests/10optimizer_bytecode/powdiv b/tests/10optimizer_bytecode/powdiv new file mode 100644 index 0000000..d89d134 --- /dev/null +++ b/tests/10optimizer_bytecode/powdiv @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-3,3,2 +F=x/pow(x,y) +C=x/fp_pow(x,y) diff --git a/tests/10optimizer_bytecode/powhalf b/tests/10optimizer_bytecode/powhalf new file mode 100644 index 0000000..95aec78 --- /dev/null +++ b/tests/10optimizer_bytecode/powhalf @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=0,4,0.1 +F=pow(x,0.5) +C=fp_pow(x,0.5) diff --git a/tests/10optimizer_bytecode/powinv b/tests/10optimizer_bytecode/powinv new file mode 100644 index 0000000..1626da8 --- /dev/null +++ b/tests/10optimizer_bytecode/powinv @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-3,3,2 +F=1/pow(x,y) +C=1/fp_pow(x,y) diff --git a/tests/10optimizer_bytecode/powminushalf b/tests/10optimizer_bytecode/powminushalf new file mode 100644 index 0000000..81366a6 --- /dev/null +++ b/tests/10optimizer_bytecode/powminushalf @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=0,4,0.1 +F=pow(x,-0.5) +C=fp_pow(x,-0.5) diff --git a/tests/10optimizer_bytecode/powminusone b/tests/10optimizer_bytecode/powminusone new file mode 100644 index 0000000..2efcedf --- /dev/null +++ b/tests/10optimizer_bytecode/powminusone @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=1,5,1 +F=pow(x,-1.0) +C=fp_pow(x,-1.0) diff --git a/tests/10optimizer_bytecode/powminusthird b/tests/10optimizer_bytecode/powminusthird new file mode 100644 index 0000000..6b4fb97 --- /dev/null +++ b/tests/10optimizer_bytecode/powminusthird @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=0,4,0.1 +F=pow(x,(-1.0/3.0)) +C=fp_pow(x,(-1.0/3.0)) diff --git a/tests/10optimizer_bytecode/powthird b/tests/10optimizer_bytecode/powthird new file mode 100644 index 0000000..9a05e2e --- /dev/null +++ b/tests/10optimizer_bytecode/powthird @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=0,4,0.1 +F=pow(x,(1.0/3.0)) +C=fp_pow(x,(1.0/3.0)) diff --git a/tests/10optimizer_bytecode/powxpow b/tests/10optimizer_bytecode/powxpow new file mode 100644 index 0000000..c3ea5c5 --- /dev/null +++ b/tests/10optimizer_bytecode/powxpow @@ -0,0 +1,6 @@ +# cPow x [IsIntegerConst(x)] cPow -> [x] cMul cPow +T=d +V=x +R=-.1,.1,0.01 +F=(x^1.7)^1506 +C=fp_pow(fp_pow(x,1.7),1506) diff --git a/tests/10optimizer_bytecode/rad b/tests/10optimizer_bytecode/rad new file mode 100644 index 0000000..a43f035 --- /dev/null +++ b/tests/10optimizer_bytecode/rad @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-10,10,0.8 +F=(pi/180)*y + x*(pi/180) + (x*(pi/180))*4 +C=d2r(y) + d2r(x) + d2r(x)*4 diff --git a/tests/10optimizer_bytecode/radxmul b/tests/10optimizer_bytecode/radxmul new file mode 100644 index 0000000..21482b4 --- /dev/null +++ b/tests/10optimizer_bytecode/radxmul @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-2,2,0.8 +F=cos((x*pi/180)*4) +C=fp_cos(d2r(x+x+x+x)) diff --git a/tests/10optimizer_bytecode/rsqrt b/tests/10optimizer_bytecode/rsqrt new file mode 100644 index 0000000..452038f --- /dev/null +++ b/tests/10optimizer_bytecode/rsqrt @@ -0,0 +1,6 @@ +# cSqrt cInv -> cRSqrt +T=d +V=x +R=0.01,10,0.05 +F=1/sqrt(x) +C=1/fp_sqrt(x) diff --git a/tests/10optimizer_bytecode/sin b/tests/10optimizer_bytecode/sin new file mode 100644 index 0000000..6b2ad23 --- /dev/null +++ b/tests/10optimizer_bytecode/sin @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=sin(1.1)+x +C=sin(1.1)+x diff --git a/tests/10optimizer_bytecode/sin_deg b/tests/10optimizer_bytecode/sin_deg new file mode 100644 index 0000000..393bfbf --- /dev/null +++ b/tests/10optimizer_bytecode/sin_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=sin(1.1)+x +C=sin(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sincos_cci b/tests/10optimizer_bytecode/sincos_cci new file mode 100644 index 0000000..8c4b368 --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_cci @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=cos(x) + sec(x) +C=fp_cos(x) + 1/fp_cos(x) diff --git a/tests/10optimizer_bytecode/sincos_cic b/tests/10optimizer_bytecode/sincos_cic new file mode 100644 index 0000000..ddc9343 --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_cic @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=sec(x) + cos(x) +C=1/fp_cos(x) + fp_cos(x) diff --git a/tests/10optimizer_bytecode/sincos_sc b/tests/10optimizer_bytecode/sincos_sc new file mode 100644 index 0000000..b93045b --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_sc @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=sin(x) + cos(x) +C=fp_sin(x) + fp_cos(x) diff --git a/tests/10optimizer_bytecode/sincos_sci b/tests/10optimizer_bytecode/sincos_sci new file mode 100644 index 0000000..d20756f --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_sci @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=sin(x) + sec(x) +C=fp_sin(x) + 1/fp_cos(x) diff --git a/tests/10optimizer_bytecode/sincos_sis b/tests/10optimizer_bytecode/sincos_sis new file mode 100644 index 0000000..ebdd783 --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_sis @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=csc(x) + sin(x) +C=1/fp_sin(x) + fp_sin(x) diff --git a/tests/10optimizer_bytecode/sincos_ssi b/tests/10optimizer_bytecode/sincos_ssi new file mode 100644 index 0000000..f1d1dfb --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_ssi @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=sin(x) + csc(x) +C=fp_sin(x) + 1/fp_sin(x) diff --git a/tests/10optimizer_bytecode/sincos_tan b/tests/10optimizer_bytecode/sincos_tan new file mode 100644 index 0000000..2a155e6 --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_tan @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=sin(x) / cos(x) +C=fp_tan(x) diff --git a/tests/10optimizer_bytecode/sincos_tit b/tests/10optimizer_bytecode/sincos_tit new file mode 100644 index 0000000..e68d427 --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_tit @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=cot(x) + tan(x) +C=1/fp_tan(x) + fp_tan(x) diff --git a/tests/10optimizer_bytecode/sincos_tti b/tests/10optimizer_bytecode/sincos_tti new file mode 100644 index 0000000..e85652e --- /dev/null +++ b/tests/10optimizer_bytecode/sincos_tti @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=-0.7, 0.7, 0.28 +F=tan(x) + cot(x) +C=fp_tan(x) + 1/fp_tan(x) diff --git a/tests/10optimizer_bytecode/sinf b/tests/10optimizer_bytecode/sinf new file mode 100644 index 0000000..aaccd87 --- /dev/null +++ b/tests/10optimizer_bytecode/sinf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=sin(1.1)+x +C=sinf(1.1)+x diff --git a/tests/10optimizer_bytecode/sinf_deg b/tests/10optimizer_bytecode/sinf_deg new file mode 100644 index 0000000..965c3a0 --- /dev/null +++ b/tests/10optimizer_bytecode/sinf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=sin(1.1)+x +C=sinf(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sinh b/tests/10optimizer_bytecode/sinh new file mode 100644 index 0000000..bc63a6a --- /dev/null +++ b/tests/10optimizer_bytecode/sinh @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=sinh(1.1)+x +C=sinh(1.1)+x diff --git a/tests/10optimizer_bytecode/sinh_deg b/tests/10optimizer_bytecode/sinh_deg new file mode 100644 index 0000000..f8ab21c --- /dev/null +++ b/tests/10optimizer_bytecode/sinh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=sinh(1.1)+x +C=sinh(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sinhf b/tests/10optimizer_bytecode/sinhf new file mode 100644 index 0000000..24d8512 --- /dev/null +++ b/tests/10optimizer_bytecode/sinhf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=sinh(1.1)+x +C=sinhf(1.1)+x diff --git a/tests/10optimizer_bytecode/sinhf_deg b/tests/10optimizer_bytecode/sinhf_deg new file mode 100644 index 0000000..53d555e --- /dev/null +++ b/tests/10optimizer_bytecode/sinhf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=sinh(1.1)+x +C=sinhf(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sinhl b/tests/10optimizer_bytecode/sinhl new file mode 100644 index 0000000..b922810 --- /dev/null +++ b/tests/10optimizer_bytecode/sinhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=sinh(1.1)+x +C=sinhl(1.1)+x diff --git a/tests/10optimizer_bytecode/sinhl_deg b/tests/10optimizer_bytecode/sinhl_deg new file mode 100644 index 0000000..527dc9b --- /dev/null +++ b/tests/10optimizer_bytecode/sinhl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=sinh(1.1)+x +C=sinhl(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sinhm b/tests/10optimizer_bytecode/sinhm new file mode 100644 index 0000000..f8f7cbf --- /dev/null +++ b/tests/10optimizer_bytecode/sinhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=sinh(1.1)+x +C=MpfrFloat::sinh(1.1)+x diff --git a/tests/10optimizer_bytecode/sinhm_deg b/tests/10optimizer_bytecode/sinhm_deg new file mode 100644 index 0000000..0386b19 --- /dev/null +++ b/tests/10optimizer_bytecode/sinhm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=sinh(1.1)+x +C=MpfrFloat::sinh(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sinl b/tests/10optimizer_bytecode/sinl new file mode 100644 index 0000000..a03b4e3 --- /dev/null +++ b/tests/10optimizer_bytecode/sinl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=sin(1.1)+x +C=sinl(1.1)+x diff --git a/tests/10optimizer_bytecode/sinl_deg b/tests/10optimizer_bytecode/sinl_deg new file mode 100644 index 0000000..d9b41ce --- /dev/null +++ b/tests/10optimizer_bytecode/sinl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=sin(1.1)+x +C=sinl(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sinm b/tests/10optimizer_bytecode/sinm new file mode 100644 index 0000000..8ec385d --- /dev/null +++ b/tests/10optimizer_bytecode/sinm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=sin(1.1)+x +C=MpfrFloat::sin(1.1)+x diff --git a/tests/10optimizer_bytecode/sinm_deg b/tests/10optimizer_bytecode/sinm_deg new file mode 100644 index 0000000..46ca1e9 --- /dev/null +++ b/tests/10optimizer_bytecode/sinm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=sin(1.1)+x +C=MpfrFloat::sin(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/sqr_nxx b/tests/10optimizer_bytecode/sqr_nxx new file mode 100644 index 0000000..33d6949 --- /dev/null +++ b/tests/10optimizer_bytecode/sqr_nxx @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=(-x)*x +C=(-x)*x diff --git a/tests/10optimizer_bytecode/sqr_xnx b/tests/10optimizer_bytecode/sqr_xnx new file mode 100644 index 0000000..fcabb3b --- /dev/null +++ b/tests/10optimizer_bytecode/sqr_xnx @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=x*(-x) +C=x*(-x) diff --git a/tests/10optimizer_bytecode/sqr_xx b/tests/10optimizer_bytecode/sqr_xx new file mode 100644 index 0000000..3bdb82e --- /dev/null +++ b/tests/10optimizer_bytecode/sqr_xx @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=x*x +C=x*x diff --git a/tests/10optimizer_bytecode/sqr_ynxx b/tests/10optimizer_bytecode/sqr_ynxx new file mode 100644 index 0000000..f467eed --- /dev/null +++ b/tests/10optimizer_bytecode/sqr_ynxx @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x,y +R=-1,1,1 +F=y*-x*x +C=y*-x*x diff --git a/tests/10optimizer_bytecode/sqr_yxnx b/tests/10optimizer_bytecode/sqr_yxnx new file mode 100644 index 0000000..0917446 --- /dev/null +++ b/tests/10optimizer_bytecode/sqr_yxnx @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x,y +R=-1,1,1 +F=y*x*-x +C=y*x*-x diff --git a/tests/10optimizer_bytecode/sqr_yxx b/tests/10optimizer_bytecode/sqr_yxx new file mode 100644 index 0000000..fd9470f --- /dev/null +++ b/tests/10optimizer_bytecode/sqr_yxx @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x,y +R=-1,1,1 +F=y*x*x +C=y*x*x diff --git a/tests/10optimizer_bytecode/sqreq0 b/tests/10optimizer_bytecode/sqreq0 new file mode 100644 index 0000000..07ad468 --- /dev/null +++ b/tests/10optimizer_bytecode/sqreq0 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(x*x=0) + (0=x*x) +C=fp_equal(x*x,0) + fp_equal(0,x*x) diff --git a/tests/10optimizer_bytecode/sqrlog b/tests/10optimizer_bytecode/sqrlog new file mode 100644 index 0000000..927cc3c --- /dev/null +++ b/tests/10optimizer_bytecode/sqrlog @@ -0,0 +1,6 @@ +# cSqr cLog -> cAbs cLog cDup cAdd +T=d f ld mf +V=x +R=-10,10,0.8 +F=log(x^2) +C=fp_log(x*x) diff --git a/tests/10optimizer_bytecode/sqrlog10 b/tests/10optimizer_bytecode/sqrlog10 new file mode 100644 index 0000000..fca65e3 --- /dev/null +++ b/tests/10optimizer_bytecode/sqrlog10 @@ -0,0 +1,6 @@ +# cSqr cLog -> cAbs cLog cDup cAdd +T=d f ld mf +V=x +R=-10,10,0.8 +F=log10(x^2) +C=fp_log10(x*x) diff --git a/tests/10optimizer_bytecode/sqrlog2 b/tests/10optimizer_bytecode/sqrlog2 new file mode 100644 index 0000000..9acddf2 --- /dev/null +++ b/tests/10optimizer_bytecode/sqrlog2 @@ -0,0 +1,6 @@ +# cSqr cLog -> cAbs cLog cDup cAdd +T=d f ld mf +V=x +R=-10,10,0.8 +F=log2(x^2) +C=fp_log2(x*x) diff --git a/tests/10optimizer_bytecode/sqrneq0 b/tests/10optimizer_bytecode/sqrneq0 new file mode 100644 index 0000000..07ad468 --- /dev/null +++ b/tests/10optimizer_bytecode/sqrneq0 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=(x*x=0) + (0=x*x) +C=fp_equal(x*x,0) + fp_equal(0,x*x) diff --git a/tests/10optimizer_bytecode/sqrsqrt b/tests/10optimizer_bytecode/sqrsqrt new file mode 100644 index 0000000..83c9711 --- /dev/null +++ b/tests/10optimizer_bytecode/sqrsqrt @@ -0,0 +1,6 @@ +# cSqr cSqrt +T=d +V=x +R=-10,10,0.1 +F=sqrt(x^2) +C=fp_sqrt(x*x) diff --git a/tests/10optimizer_bytecode/sqrt b/tests/10optimizer_bytecode/sqrt new file mode 100644 index 0000000..a1165ec --- /dev/null +++ b/tests/10optimizer_bytecode/sqrt @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=sqrt(1.1)+x +C=sqrt(1.1)+x diff --git a/tests/10optimizer_bytecode/sqrtf b/tests/10optimizer_bytecode/sqrtf new file mode 100644 index 0000000..b8c7603 --- /dev/null +++ b/tests/10optimizer_bytecode/sqrtf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=sqrt(1.1)+x +C=sqrtf(1.1)+x diff --git a/tests/10optimizer_bytecode/sqrtl b/tests/10optimizer_bytecode/sqrtl new file mode 100644 index 0000000..018c8ef --- /dev/null +++ b/tests/10optimizer_bytecode/sqrtl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=sqrt(1.1)+x +C=sqrtl(1.1)+x diff --git a/tests/10optimizer_bytecode/sqrtm b/tests/10optimizer_bytecode/sqrtm new file mode 100644 index 0000000..cc71883 --- /dev/null +++ b/tests/10optimizer_bytecode/sqrtm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=sqrt(1.1)+x +C=MpfrFloat::sqrt(1.1)+x diff --git a/tests/10optimizer_bytecode/sqrtsqr1 b/tests/10optimizer_bytecode/sqrtsqr1 new file mode 100644 index 0000000..eaf5a2d --- /dev/null +++ b/tests/10optimizer_bytecode/sqrtsqr1 @@ -0,0 +1,7 @@ +# x cSqrt cSqr -> x (when not known whether x may be negative) + +T=d f +V=x +R=0, 3, 0.5 +F=sqrt(x)^2 +C=fp_pow(fp_sqrt(x), 2) diff --git a/tests/10optimizer_bytecode/sqrtsqr2 b/tests/10optimizer_bytecode/sqrtsqr2 new file mode 100644 index 0000000..ff0673a --- /dev/null +++ b/tests/10optimizer_bytecode/sqrtsqr2 @@ -0,0 +1,7 @@ +# x cSqrt cSqr -> x (when x is never negative) + +T=d f +V=x +R=-1,1,0.5 +F=sqrt(acos(x))^2 +C=fp_pow(fp_sqrt(fp_acos(x)), 2) diff --git a/tests/10optimizer_bytecode/sqrxpow b/tests/10optimizer_bytecode/sqrxpow new file mode 100644 index 0000000..5de6cb0 --- /dev/null +++ b/tests/10optimizer_bytecode/sqrxpow @@ -0,0 +1,6 @@ +# cSqr x cPow -> [x+x] cPow +T=d +V=x +R=-.1,.1,0.01 +F=(x^2)^2402 +C=fp_pow(x*x, 2402) diff --git a/tests/10optimizer_bytecode/sqrxpow_nonint b/tests/10optimizer_bytecode/sqrxpow_nonint new file mode 100644 index 0000000..bb505df --- /dev/null +++ b/tests/10optimizer_bytecode/sqrxpow_nonint @@ -0,0 +1,6 @@ +# cSqr x [!isEvenInteger(x+x)] cPow -> cAbs [x+x] cPow +T=d +V=x +R=-10,10,0.1 +F=(x^2)^3.5 +C=fp_pow(x*x, 3.5) diff --git a/tests/10optimizer_bytecode/sub b/tests/10optimizer_bytecode/sub new file mode 100644 index 0000000..4b4b764 --- /dev/null +++ b/tests/10optimizer_bytecode/sub @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=5-3+x +C=5-3+x diff --git a/tests/10optimizer_bytecode/sub0 b/tests/10optimizer_bytecode/sub0 new file mode 100644 index 0000000..57f4912 --- /dev/null +++ b/tests/10optimizer_bytecode/sub0 @@ -0,0 +1,5 @@ +T=d li +V=x +R=0,1,1 +F=x-0+x +C=x-0+x diff --git a/tests/10optimizer_bytecode/subxx b/tests/10optimizer_bytecode/subxx new file mode 100644 index 0000000..5845010 --- /dev/null +++ b/tests/10optimizer_bytecode/subxx @@ -0,0 +1,5 @@ +T=d li f ld +V=x +R=-3,3,1 +F=x+(x-x)+x+(1-x+x) +C=x+(x-x)+x+(1-x+x) diff --git a/tests/10optimizer_bytecode/tan b/tests/10optimizer_bytecode/tan new file mode 100644 index 0000000..1c95ffb --- /dev/null +++ b/tests/10optimizer_bytecode/tan @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=tan(1.1)+x +C=tan(1.1)+x diff --git a/tests/10optimizer_bytecode/tan_deg b/tests/10optimizer_bytecode/tan_deg new file mode 100644 index 0000000..9875a86 --- /dev/null +++ b/tests/10optimizer_bytecode/tan_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=tan(1.1)+x +C=tan(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/tanf b/tests/10optimizer_bytecode/tanf new file mode 100644 index 0000000..1fa4e1f --- /dev/null +++ b/tests/10optimizer_bytecode/tanf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=tan(1.1)+x +C=tanf(1.1)+x diff --git a/tests/10optimizer_bytecode/tanf_deg b/tests/10optimizer_bytecode/tanf_deg new file mode 100644 index 0000000..79286d7 --- /dev/null +++ b/tests/10optimizer_bytecode/tanf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=tan(1.1)+x +C=tanf(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/tanh b/tests/10optimizer_bytecode/tanh new file mode 100644 index 0000000..6de5606 --- /dev/null +++ b/tests/10optimizer_bytecode/tanh @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=tanh(1.1)+x +C=tanh(1.1)+x diff --git a/tests/10optimizer_bytecode/tanh_deg b/tests/10optimizer_bytecode/tanh_deg new file mode 100644 index 0000000..5eef89f --- /dev/null +++ b/tests/10optimizer_bytecode/tanh_deg @@ -0,0 +1,6 @@ +DEG=true +T=d +V=x +R=0,1,1 +F=tanh(1.1)+x +C=tanh(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/tanhf b/tests/10optimizer_bytecode/tanhf new file mode 100644 index 0000000..56a3b55 --- /dev/null +++ b/tests/10optimizer_bytecode/tanhf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=tanh(1.1)+x +C=tanhf(1.1)+x diff --git a/tests/10optimizer_bytecode/tanhf_deg b/tests/10optimizer_bytecode/tanhf_deg new file mode 100644 index 0000000..411b05e --- /dev/null +++ b/tests/10optimizer_bytecode/tanhf_deg @@ -0,0 +1,6 @@ +DEG=true +T=f +V=x +R=0,1,1 +F=tanh(1.1)+x +C=tanhf(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/tanhl b/tests/10optimizer_bytecode/tanhl new file mode 100644 index 0000000..b610c1b --- /dev/null +++ b/tests/10optimizer_bytecode/tanhl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=tanh(1.1)+x +C=tanhl(1.1)+x diff --git a/tests/10optimizer_bytecode/tanhl_deg b/tests/10optimizer_bytecode/tanhl_deg new file mode 100644 index 0000000..c3eda10 --- /dev/null +++ b/tests/10optimizer_bytecode/tanhl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=tanh(1.1)+x +C=tanhl(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/tanhm b/tests/10optimizer_bytecode/tanhm new file mode 100644 index 0000000..29ce495 --- /dev/null +++ b/tests/10optimizer_bytecode/tanhm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=tanh(1.1)+x +C=MpfrFloat::tanh(1.1)+x diff --git a/tests/10optimizer_bytecode/tanhm_deg b/tests/10optimizer_bytecode/tanhm_deg new file mode 100644 index 0000000..7629e56 --- /dev/null +++ b/tests/10optimizer_bytecode/tanhm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=tanh(1.1)+x +C=MpfrFloat::tanh(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/tanl b/tests/10optimizer_bytecode/tanl new file mode 100644 index 0000000..3535d9c --- /dev/null +++ b/tests/10optimizer_bytecode/tanl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=tan(1.1)+x +C=tanl(1.1)+x diff --git a/tests/10optimizer_bytecode/tanl_deg b/tests/10optimizer_bytecode/tanl_deg new file mode 100644 index 0000000..efcff18 --- /dev/null +++ b/tests/10optimizer_bytecode/tanl_deg @@ -0,0 +1,6 @@ +DEG=true +T=ld +V=x +R=0,1,1 +F=tan(1.1)+x +C=tanl(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/tanm b/tests/10optimizer_bytecode/tanm new file mode 100644 index 0000000..27664e9 --- /dev/null +++ b/tests/10optimizer_bytecode/tanm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=tan(1.1)+x +C=MpfrFloat::tan(1.1)+x diff --git a/tests/10optimizer_bytecode/tanm_deg b/tests/10optimizer_bytecode/tanm_deg new file mode 100644 index 0000000..acdb8fe --- /dev/null +++ b/tests/10optimizer_bytecode/tanm_deg @@ -0,0 +1,6 @@ +DEG=true +T=mf +V=x +R=0,1,1 +F=tan(1.1)+x +C=MpfrFloat::tan(d2r(1.1))+x diff --git a/tests/10optimizer_bytecode/trunc b/tests/10optimizer_bytecode/trunc new file mode 100644 index 0000000..34a27fc --- /dev/null +++ b/tests/10optimizer_bytecode/trunc @@ -0,0 +1,5 @@ +T=d +V=x +R=0,1,1 +F=trunc(1.1)+x +C=1+x diff --git a/tests/10optimizer_bytecode/truncf b/tests/10optimizer_bytecode/truncf new file mode 100644 index 0000000..4e5b281 --- /dev/null +++ b/tests/10optimizer_bytecode/truncf @@ -0,0 +1,5 @@ +T=f +V=x +R=0,1,1 +F=trunc(1.1)+x +C=1+x diff --git a/tests/10optimizer_bytecode/truncl b/tests/10optimizer_bytecode/truncl new file mode 100644 index 0000000..aa508f2 --- /dev/null +++ b/tests/10optimizer_bytecode/truncl @@ -0,0 +1,5 @@ +T=ld +V=x +R=0,1,1 +F=trunc(1.1)+x +C=1+x diff --git a/tests/10optimizer_bytecode/truncm b/tests/10optimizer_bytecode/truncm new file mode 100644 index 0000000..8cbe493 --- /dev/null +++ b/tests/10optimizer_bytecode/truncm @@ -0,0 +1,5 @@ +T=mf +V=x +R=0,1,1 +F=trunc(1.1)+x +C=1+x diff --git a/tests/10optimizer_bytecode/xaddnot b/tests/10optimizer_bytecode/xaddnot new file mode 100644 index 0000000..07315cd --- /dev/null +++ b/tests/10optimizer_bytecode/xaddnot @@ -0,0 +1,5 @@ +T=d f ld li gi +V=x +R=-5,5,1 +F=!(x+4) +C=fp_not(x+4) diff --git a/tests/10optimizer_bytecode/xaddnotnot b/tests/10optimizer_bytecode/xaddnotnot new file mode 100644 index 0000000..d1aafa7 --- /dev/null +++ b/tests/10optimizer_bytecode/xaddnotnot @@ -0,0 +1,5 @@ +T=d f ld li gi +V=x +R=-5,5,1 +F=!!(x+4) +C=fp_notNot(x+4) diff --git a/tests/10optimizer_bytecode/xmulrad b/tests/10optimizer_bytecode/xmulrad new file mode 100644 index 0000000..2096c03 --- /dev/null +++ b/tests/10optimizer_bytecode/xmulrad @@ -0,0 +1,6 @@ +DEG=1 +T=d f ld mf +V=x +R=-2,2,0.8 +F=cos(x*5) +C=fp_cos(d2r(x+x+x+x+x)) diff --git a/tests/10optimizer_bytecode/xmulsinhneg b/tests/10optimizer_bytecode/xmulsinhneg new file mode 100644 index 0000000..b773ee3 --- /dev/null +++ b/tests/10optimizer_bytecode/xmulsinhneg @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=-sinh(x*5) +C=-fp_sinh(x*5) diff --git a/tests/10optimizer_bytecode/xmulsinneg b/tests/10optimizer_bytecode/xmulsinneg new file mode 100644 index 0000000..eb0c4a3 --- /dev/null +++ b/tests/10optimizer_bytecode/xmulsinneg @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=-sin(x*5) +C=-fp_sin(x*5) diff --git a/tests/10optimizer_bytecode/xmultanhneg b/tests/10optimizer_bytecode/xmultanhneg new file mode 100644 index 0000000..ae89862 --- /dev/null +++ b/tests/10optimizer_bytecode/xmultanhneg @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=-tanh(x*5) +C=-fp_tanh(x*5) diff --git a/tests/10optimizer_bytecode/xmultanneg b/tests/10optimizer_bytecode/xmultanneg new file mode 100644 index 0000000..2c6ff53 --- /dev/null +++ b/tests/10optimizer_bytecode/xmultanneg @@ -0,0 +1,5 @@ +T=d f +V=x +R=-0.7, 0.7, 0.28 +F=-tan(x*5) +C=-fp_tan(x*5) diff --git a/tests/10optimizer_bytecode/xsqryfsqrhypot b/tests/10optimizer_bytecode/xsqryfsqrhypot new file mode 100644 index 0000000..147be24 --- /dev/null +++ b/tests/10optimizer_bytecode/xsqryfsqrhypot @@ -0,0 +1,5 @@ +T=d f ld +V=x +R=0.5,3,0.7 +F=sqrt(log(x)^2+log2(x)^2) +C=fp_hypot(fp_log(x),fp_log2(x)) diff --git a/tests/10optimizer_bytecode/xsqrysqrhypot b/tests/10optimizer_bytecode/xsqrysqrhypot new file mode 100644 index 0000000..1c29296 --- /dev/null +++ b/tests/10optimizer_bytecode/xsqrysqrhypot @@ -0,0 +1,5 @@ +T=d f ld +V=x,y +R=0.5,3,0.7 +F=sqrt(log(x)^2+y*y) +C=fp_hypot(fp_log(x),y) diff --git a/tests/10optimizer_bytecode/xxdup b/tests/10optimizer_bytecode/xxdup new file mode 100644 index 0000000..d8bc9a8 --- /dev/null +++ b/tests/10optimizer_bytecode/xxdup @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x +R=-1,1,1 +F=sub(x,x) +C=x-x diff --git a/tests/10optimizer_bytecode/xxfdup b/tests/10optimizer_bytecode/xxfdup new file mode 100644 index 0000000..ea61c34 --- /dev/null +++ b/tests/10optimizer_bytecode/xxfdup @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1,1,1 +F=sub(sin(x),sin(x)) +C=x-x diff --git a/tests/10optimizer_bytecode/xxsqrdup b/tests/10optimizer_bytecode/xxsqrdup new file mode 100644 index 0000000..52b6f10 --- /dev/null +++ b/tests/10optimizer_bytecode/xxsqrdup @@ -0,0 +1,5 @@ +T=d f li ld mf gi +V=x,y +R=-1,1,1 +F=y*abs(x)*abs(x) +C=y*fp_abs(x)*fp_abs(x) diff --git a/tests/10optimizer_bytecode/ypowxpow b/tests/10optimizer_bytecode/ypowxpow new file mode 100644 index 0000000..58dced8 --- /dev/null +++ b/tests/10optimizer_bytecode/ypowxpow @@ -0,0 +1,6 @@ +# y [!IsIntegerConst(y)] cPow x [IsIntegerConst(x)] cPow +T=d +V=x +R=0,10,0.01 +F=(x^38.5)^5 +C=fp_pow(fp_pow(x,38.5),5) diff --git a/tests/11optimizer_constaddmul/1 b/tests/11optimizer_constaddmul/1 new file mode 100644 index 0000000..db0fbc1 --- /dev/null +++ b/tests/11optimizer_constaddmul/1 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-1,1,2 +F=(1/a)*5 +C=(1/a)*5 diff --git a/tests/11optimizer_constaddmul/10 b/tests/11optimizer_constaddmul/10 new file mode 100644 index 0000000..46bbc16 --- /dev/null +++ b/tests/11optimizer_constaddmul/10 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=abs(b)*(5/a) +C=fp_abs(b)*(5/a) diff --git a/tests/11optimizer_constaddmul/11 b/tests/11optimizer_constaddmul/11 new file mode 100644 index 0000000..f823c36 --- /dev/null +++ b/tests/11optimizer_constaddmul/11 @@ -0,0 +1,6 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=abs(b)/(50/a) +C=fp_abs(b)/(50/a) +# Note: Using 50 instead of 5 to prevent division-by-zero in integer test diff --git a/tests/11optimizer_constaddmul/12 b/tests/11optimizer_constaddmul/12 new file mode 100644 index 0000000..0dbd6c6 --- /dev/null +++ b/tests/11optimizer_constaddmul/12 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-15,15,2 +F=(-a)+5 +C=(-a)+5 diff --git a/tests/11optimizer_constaddmul/13 b/tests/11optimizer_constaddmul/13 new file mode 100644 index 0000000..6c5447a --- /dev/null +++ b/tests/11optimizer_constaddmul/13 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=5+(a*b) +C=5+(a*b) diff --git a/tests/11optimizer_constaddmul/14 b/tests/11optimizer_constaddmul/14 new file mode 100644 index 0000000..9a26fdb --- /dev/null +++ b/tests/11optimizer_constaddmul/14 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=5-(a*b) +C=5-(a*b) diff --git a/tests/11optimizer_constaddmul/15 b/tests/11optimizer_constaddmul/15 new file mode 100644 index 0000000..23f5d90 --- /dev/null +++ b/tests/11optimizer_constaddmul/15 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(a+5)+abs(b) +C=(a+5)+fp_abs(b) diff --git a/tests/11optimizer_constaddmul/16 b/tests/11optimizer_constaddmul/16 new file mode 100644 index 0000000..a60c1df --- /dev/null +++ b/tests/11optimizer_constaddmul/16 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(a+5)-abs(b) +C=(a+5)-fp_abs(b) diff --git a/tests/11optimizer_constaddmul/17 b/tests/11optimizer_constaddmul/17 new file mode 100644 index 0000000..8e8a303 --- /dev/null +++ b/tests/11optimizer_constaddmul/17 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(-a)+abs(b) +C=(-a)+fp_abs(b) diff --git a/tests/11optimizer_constaddmul/18 b/tests/11optimizer_constaddmul/18 new file mode 100644 index 0000000..99b6ab5 --- /dev/null +++ b/tests/11optimizer_constaddmul/18 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(-a)-abs(b) +C=(-a)-fp_abs(b) diff --git a/tests/11optimizer_constaddmul/19 b/tests/11optimizer_constaddmul/19 new file mode 100644 index 0000000..d8db0a6 --- /dev/null +++ b/tests/11optimizer_constaddmul/19 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=b+(abs(a)+5) +C=b+(fp_abs(a)+5) diff --git a/tests/11optimizer_constaddmul/2 b/tests/11optimizer_constaddmul/2 new file mode 100644 index 0000000..8538f51 --- /dev/null +++ b/tests/11optimizer_constaddmul/2 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-1,1,2 +F=5*a +C=5*a diff --git a/tests/11optimizer_constaddmul/20 b/tests/11optimizer_constaddmul/20 new file mode 100644 index 0000000..f5cfb11 --- /dev/null +++ b/tests/11optimizer_constaddmul/20 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=b-(abs(a)+5) +C=b-(fp_abs(a)+5) diff --git a/tests/11optimizer_constaddmul/21 b/tests/11optimizer_constaddmul/21 new file mode 100644 index 0000000..c577909 --- /dev/null +++ b/tests/11optimizer_constaddmul/21 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=abs(b)+(5-a) +C=fp_abs(b)+(5-a) diff --git a/tests/11optimizer_constaddmul/22 b/tests/11optimizer_constaddmul/22 new file mode 100644 index 0000000..9517e8d --- /dev/null +++ b/tests/11optimizer_constaddmul/22 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=abs(b)-(5-a) +C=fp_abs(b)-(5-a) diff --git a/tests/11optimizer_constaddmul/23 b/tests/11optimizer_constaddmul/23 new file mode 100644 index 0000000..e113663 --- /dev/null +++ b/tests/11optimizer_constaddmul/23 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((1/ abs(b))*b)/a +C=((1/fp_abs(b))*b)/a diff --git a/tests/11optimizer_constaddmul/24 b/tests/11optimizer_constaddmul/24 new file mode 100644 index 0000000..7ba8424 --- /dev/null +++ b/tests/11optimizer_constaddmul/24 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((1/ abs(b))*5)/a +C=((1/fp_abs(b))*5)/a diff --git a/tests/11optimizer_constaddmul/25 b/tests/11optimizer_constaddmul/25 new file mode 100644 index 0000000..e9d2e79 --- /dev/null +++ b/tests/11optimizer_constaddmul/25 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((1/ abs(b))*5)*a +C=((1/fp_abs(b))*5)*a diff --git a/tests/11optimizer_constaddmul/26 b/tests/11optimizer_constaddmul/26 new file mode 100644 index 0000000..148590f --- /dev/null +++ b/tests/11optimizer_constaddmul/26 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=( abs(a)/b)/a +C=(fp_abs(a)/b)/a diff --git a/tests/11optimizer_constaddmul/27 b/tests/11optimizer_constaddmul/27 new file mode 100644 index 0000000..16cb5cb --- /dev/null +++ b/tests/11optimizer_constaddmul/27 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=( abs(a)/b)*a +C=(fp_abs(a)/b)*a diff --git a/tests/11optimizer_constaddmul/28 b/tests/11optimizer_constaddmul/28 new file mode 100644 index 0000000..753291b --- /dev/null +++ b/tests/11optimizer_constaddmul/28 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((-a)/b)*5 +C=((-a)/b)*5 diff --git a/tests/11optimizer_constaddmul/29 b/tests/11optimizer_constaddmul/29 new file mode 100644 index 0000000..e1e1b4c --- /dev/null +++ b/tests/11optimizer_constaddmul/29 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(5/b)*a +C=(5/b)*a diff --git a/tests/11optimizer_constaddmul/3 b/tests/11optimizer_constaddmul/3 new file mode 100644 index 0000000..46bb26c --- /dev/null +++ b/tests/11optimizer_constaddmul/3 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-1,1,2 +F=5/a +C=5/a diff --git a/tests/11optimizer_constaddmul/30 b/tests/11optimizer_constaddmul/30 new file mode 100644 index 0000000..dcd2efd --- /dev/null +++ b/tests/11optimizer_constaddmul/30 @@ -0,0 +1,5 @@ +T=d li cd +V=b +R=-15,15,2 +F=(7/b)*5 +C=(7/b)*5 diff --git a/tests/11optimizer_constaddmul/31 b/tests/11optimizer_constaddmul/31 new file mode 100644 index 0000000..d7d42eb --- /dev/null +++ b/tests/11optimizer_constaddmul/31 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=b*(7/-a) +C=b*(7/-a) diff --git a/tests/11optimizer_constaddmul/32 b/tests/11optimizer_constaddmul/32 new file mode 100644 index 0000000..8cf5042 --- /dev/null +++ b/tests/11optimizer_constaddmul/32 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(5-b)-a +C=(5-b)-a diff --git a/tests/11optimizer_constaddmul/33 b/tests/11optimizer_constaddmul/33 new file mode 100644 index 0000000..ffc2afd --- /dev/null +++ b/tests/11optimizer_constaddmul/33 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(5-b)+a +C=(5-b)+a diff --git a/tests/11optimizer_constaddmul/34 b/tests/11optimizer_constaddmul/34 new file mode 100644 index 0000000..5f07066 --- /dev/null +++ b/tests/11optimizer_constaddmul/34 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((a+7)-b)+5 +C=((a+7)-b)+5 diff --git a/tests/11optimizer_constaddmul/35 b/tests/11optimizer_constaddmul/35 new file mode 100644 index 0000000..11e2dc1 --- /dev/null +++ b/tests/11optimizer_constaddmul/35 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((-a)-b)+5 +C=((-a)-b)+5 diff --git a/tests/11optimizer_constaddmul/36 b/tests/11optimizer_constaddmul/36 new file mode 100644 index 0000000..29c8dcd --- /dev/null +++ b/tests/11optimizer_constaddmul/36 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-15,15,2 +F=(7-abs(a))+5 +C=(7-fp_abs(a))+5 diff --git a/tests/11optimizer_constaddmul/37 b/tests/11optimizer_constaddmul/37 new file mode 100644 index 0000000..647049b --- /dev/null +++ b/tests/11optimizer_constaddmul/37 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((7-b)+a)+5 +C=((7-b)+a)+5 diff --git a/tests/11optimizer_constaddmul/38 b/tests/11optimizer_constaddmul/38 new file mode 100644 index 0000000..d32d2b7 --- /dev/null +++ b/tests/11optimizer_constaddmul/38 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=((5*b+abs(a))<0)*1 + ((abs(b))<0)*2 +C=fp_less((5*b+fp_abs(a)),0)*1 + fp_less((fp_abs(b)),0)*2 diff --git a/tests/11optimizer_constaddmul/39 b/tests/11optimizer_constaddmul/39 new file mode 100644 index 0000000..2a98e56 --- /dev/null +++ b/tests/11optimizer_constaddmul/39 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-15,15,2 +F=(a+7)*5 +C=(a+7)*5 diff --git a/tests/11optimizer_constaddmul/4 b/tests/11optimizer_constaddmul/4 new file mode 100644 index 0000000..2ce93a1 --- /dev/null +++ b/tests/11optimizer_constaddmul/4 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-1,1,2 +F=(a*5)*b +C=(a*5)*b diff --git a/tests/11optimizer_constaddmul/40 b/tests/11optimizer_constaddmul/40 new file mode 100644 index 0000000..1fd4411 --- /dev/null +++ b/tests/11optimizer_constaddmul/40 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(b+(a*7))*5 +C=(b+(a*7))*5 diff --git a/tests/11optimizer_constaddmul/41 b/tests/11optimizer_constaddmul/41 new file mode 100644 index 0000000..7c5efd0 --- /dev/null +++ b/tests/11optimizer_constaddmul/41 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-15,15,2 +F=(b-(a*7))*5 +C=(b-(a*7))*5 diff --git a/tests/11optimizer_constaddmul/42 b/tests/11optimizer_constaddmul/42 new file mode 100644 index 0000000..6d226b6 --- /dev/null +++ b/tests/11optimizer_constaddmul/42 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-15,15,2 +F=(a+7)+5 +C=(a+7)+5 diff --git a/tests/11optimizer_constaddmul/43 b/tests/11optimizer_constaddmul/43 new file mode 100644 index 0000000..8a1e85f --- /dev/null +++ b/tests/11optimizer_constaddmul/43 @@ -0,0 +1,5 @@ +T=d li cd +V=a +R=-15,15,2 +F=(a*7)*5 +C=(a*7)*5 diff --git a/tests/11optimizer_constaddmul/5 b/tests/11optimizer_constaddmul/5 new file mode 100644 index 0000000..0c9506c --- /dev/null +++ b/tests/11optimizer_constaddmul/5 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-1,1,2 +F=(a*5)/b +C=(a*5)/b diff --git a/tests/11optimizer_constaddmul/6 b/tests/11optimizer_constaddmul/6 new file mode 100644 index 0000000..a9597cc --- /dev/null +++ b/tests/11optimizer_constaddmul/6 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-1,1,2 +F=(1/a)*b +C=(1/a)*b diff --git a/tests/11optimizer_constaddmul/7 b/tests/11optimizer_constaddmul/7 new file mode 100644 index 0000000..27aa0bd --- /dev/null +++ b/tests/11optimizer_constaddmul/7 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-1,1,2 +F=(1/a)/b +C=(1/a)/b diff --git a/tests/11optimizer_constaddmul/8 b/tests/11optimizer_constaddmul/8 new file mode 100644 index 0000000..4c666b5 --- /dev/null +++ b/tests/11optimizer_constaddmul/8 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-1,1,2 +F=abs(a)*(abs(b)*5) +C=fp_abs(a)*(fp_abs(b)*5) diff --git a/tests/11optimizer_constaddmul/9 b/tests/11optimizer_constaddmul/9 new file mode 100644 index 0000000..1b7172f --- /dev/null +++ b/tests/11optimizer_constaddmul/9 @@ -0,0 +1,5 @@ +T=d li cd +V=a,b +R=-1,1,2 +F=abs(a)/(abs(b)*5) +C=fp_abs(a)/(fp_abs(b)*5) diff --git a/tests/11optimizer_constaddmul/README b/tests/11optimizer_constaddmul/README new file mode 100644 index 0000000..33accf3 --- /dev/null +++ b/tests/11optimizer_constaddmul/README @@ -0,0 +1,69 @@ +# Test topics: +# +# fparser.cc, CompileMul: +# +# ... cInv 5 cMul --> ... 5 cRDiv TEST 1 +# 5 ... cMul --> ... 5 cMul TEST 2 +# 5 ... cDiv --> cInv ... 5 cMul TEST 3 +# ::: 5 cMul ... cMul --> ::: ... cMul 5 cMul TEST 4 +# ::: 5 cMul ... cDiv --> ::: ... cDiv 5 cMul TEST 5 +# ::: cInv ... cMul --> ::: ... cRDiv TEST 6 +# ::: cInv ... cDiv --> ::: ... cMul cInv TEST 7 +# ::: ... 5 cMul cMul --> ::: ... cMul 5 cMul TEST 8 +# ::: ... 5 cMul cDiv --> ::: ... cDiv .2 cMul TEST 9 +# ::: ... 5 cRDiv cMul --> ::: ... cDiv 5 cMul TEST 10 +# ::: ... 5 cRDiv cDiv --> ::: ... cDiv .2 cMul TEST 11 +# +# fparser.cc, CompileAdd: +# +# ... cNeg 5 cAdd --> ... 5 cRSub TEST 12 +# 5 ... cAdd --> ... 5 cAdd TEST 13 +# 5 ... cSub --> ... cNeg 5 cAdd TEST 14 +# ::: 5 cAdd ... cAdd --> ::: ... cAdd 5 cAdd TEST 15 +# ::: 5 cAdd ... cSub --> ::: ... cSub 5 cAdd TEST 16 +# ::: cNeg ... cAdd --> ::: ... cRSub TEST 17 +# ::: cNeg ... cSub --> ::: ... cAdd cNeg TEST 18 +# ::: ... 5 cAdd cAdd --> ::: ... cAdd 5 cAdd TEST 19 +# ::: ... 5 cAdd cSub --> ::: ... cSub -5 cAdd TEST 20 +# ::: ... 5 cRSub cAdd --> ::: ... cSub 5 cAdd TEST 21 +# ::: ... 5 cRSub cSub --> ::: ... cAdd -5 cAdd TEST 22 +# +# bytecoderules (a,b = variables, P=non-negative opcode): +# +# b cRDiv a cDiv --> a cMul b cRDiv TEST 23 +# 5 cRDiv a cDiv --> a cMul 5 cRDiv TEST 24 +# 5 cRDiv a cMul --> a 5 cMul cRDiv TEST 25 +# b cDiv a cDiv --> b a cMul cDiv TEST 26 +# b cDiv a cMul --> a cMul b cDiv TEST 27 +# 7 b cDiv 5 cMul --> 35 b cDiv Cannot achieve test case +# 7 cMul b cDiv 5 cMul --> 35 cMul b cDiv Cannot achieve test case +# cNeg b cDiv 5 cMul --> -5 cMul b cDiv TEST 28 +# cRDiv a cMul --> a cMul cRDiv TEST 29 (possibly duplicate of 25) +# 7 cRDiv 5 cMul --> 35 cRDiv TEST 30 +# 7 cMul cRDiv 5 cMul --> 35 cMul cRDiv Cannot achieve test case +# cNeg cRDiv 5 cMul --> -5 cMul cRDiv TEST 31 +# +# 5 cRSub a cSub --> a cAdd 5 cRSub TEST 32 +# 5 cRSub a cAdd --> a 5 cAdd cRSub TEST 33 +# 7 b cSub 5 cAdd --> 12 b cSub Cannot achieve test case +# 7 cAdd b cSub 5 cAdd --> 12 cAdd b cSub TEST 34 +# cNeg b cSub 5 cAdd --> -5 cAdd b csub TEST 35 +# cRSub a cAdd --> a cAdd cRSub TEST 32 (duplicate) +# cRSub a cSub --> a cSub cRSub TEST 33 (duplicate) +# 7 cRSub 5 cAdd --> 12 cRSub TEST 36 +# 7 cAdd cRSub 5 cAdd --> 12 cAdd cRSub TEST 37 +# cNeg cRSub 5 cAdd --> -5 cAdd cRSub Cannot achieve test case +# P 0 cLess --> P 0 cMul TEST 38 +# +# 7 cAdd 5 cMul --> 5 cMul 35 cAdd TEST 39 +# a 7 cMul cAdd 5 cMul --> 5 cMul a 35 cMul cAdd TEST 40 +# a 7 cMul cSub 5 cMul --> 5 cMul a 35 cMul cSub TEST 41 +# +# 7 cAdd 5 cAdd --> 12 cAdd TEST 42 +# 7 cMul 5 cMul --> 35 cMul TEST 43 +# +# Tests are done for a floating point type (double) +# and an integer type (long int). +# Some of these optimizations are not done for integers, and +# testing will verify that int mathematics is not broken. +# diff --git a/tests/20optimizer_optimizations/abscos b/tests/20optimizer_optimizations/abscos new file mode 100644 index 0000000..f02ef5e --- /dev/null +++ b/tests/20optimizer_optimizations/abscos @@ -0,0 +1,9 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=cos(sqrt(cbrt(x^6))) + sqrt(cbrt(x^6)) +C=fp_cos(fp_abs(x)) + fp_abs(x) + +# sqrt(cbrt(x^6)) produces abs(x) through fpoptimizer. +# We cannot use abs(x) directly, because +# then bytecode optimizer would take it. diff --git a/tests/20optimizer_optimizations/abscosh b/tests/20optimizer_optimizations/abscosh new file mode 100644 index 0000000..6cf480b --- /dev/null +++ b/tests/20optimizer_optimizations/abscosh @@ -0,0 +1,9 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=cosh(sqrt(cbrt(x^6))) + sqrt(cbrt(x^6)) +C=fp_cosh(fp_abs(x)) + fp_abs(x) + +# sqrt(cbrt(x^6)) produces abs(x) through fpoptimizer. +# We cannot use abs(x) directly, because +# then bytecode optimizer would take it. diff --git a/tests/20optimizer_optimizations/abseq0 b/tests/20optimizer_optimizations/abseq0 new file mode 100644 index 0000000..bec8155 --- /dev/null +++ b/tests/20optimizer_optimizations/abseq0 @@ -0,0 +1,5 @@ +T=d li cd +V=x +R=0,1,1 +F=(abs(x)=if(1,0,1)) + (if(1,0,1)=abs(x)) +C=fp_equal(fp_abs(x),0) + fp_equal(0,fp_abs(x)) diff --git a/tests/20optimizer_optimizations/absneq0 b/tests/20optimizer_optimizations/absneq0 new file mode 100644 index 0000000..bec8155 --- /dev/null +++ b/tests/20optimizer_optimizations/absneq0 @@ -0,0 +1,5 @@ +T=d li cd +V=x +R=0,1,1 +F=(abs(x)=if(1,0,1)) + (if(1,0,1)=abs(x)) +C=fp_equal(fp_abs(x),0) + fp_equal(0,fp_abs(x)) diff --git a/tests/20optimizer_optimizations/absnzge b/tests/20optimizer_optimizations/absnzge new file mode 100644 index 0000000..39b377f --- /dev/null +++ b/tests/20optimizer_optimizations/absnzge @@ -0,0 +1,5 @@ +T=d li gi cd +V=x +R=-5,5,1 +F=sub(abs(x) >= if(1,4,0), abs(x) >= (if(1,1,0)-1)) +C=userDefFuncSub({fp_greaterOrEq(fp_abs(x),4), fp_greaterOrEq(fp_abs(x),0)}) diff --git a/tests/20optimizer_optimizations/absnzlt b/tests/20optimizer_optimizations/absnzlt new file mode 100644 index 0000000..f7e32e5 --- /dev/null +++ b/tests/20optimizer_optimizations/absnzlt @@ -0,0 +1,5 @@ +T=d li gi cd +V=x +R=-5,5,1 +F=sub(abs(x) < if(1,4,0), abs(x) < (if(1,1,0)-1)) +C=userDefFuncSub({fp_less(fp_abs(x),4), fp_less(fp_abs(x),0)}) diff --git a/tests/20optimizer_optimizations/acoscos b/tests/20optimizer_optimizations/acoscos new file mode 100644 index 0000000..cf499d7 --- /dev/null +++ b/tests/20optimizer_optimizations/acoscos @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=-1,1,0.1 +F=cos(acos(x)) +C=fp_cos(fp_acos(x)) diff --git a/tests/20optimizer_optimizations/acoshsinh b/tests/20optimizer_optimizations/acoshsinh new file mode 100644 index 0000000..0258ae4 --- /dev/null +++ b/tests/20optimizer_optimizations/acoshsinh @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=1.7, 3.7, 0.28 +F=sinh(if(1,acosh(x),0)) +C=fp_sinh(fp_acosh(x)) diff --git a/tests/20optimizer_optimizations/addconstmul b/tests/20optimizer_optimizations/addconstmul new file mode 100644 index 0000000..a9932f3 --- /dev/null +++ b/tests/20optimizer_optimizations/addconstmul @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=x,y +R=-3,3,2 +F=5*(if(1,4,0)+x+y) +C=5*(4+x+y) diff --git a/tests/20optimizer_optimizations/addlog b/tests/20optimizer_optimizations/addlog new file mode 100644 index 0000000..86eb0b6 --- /dev/null +++ b/tests/20optimizer_optimizations/addlog @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x,y +R=0.25, 1, 0.25 +F=log(x)+log(y) +C=fp_log(x)+fp_log(y) + +# Expected result: log(x*y) diff --git a/tests/20optimizer_optimizations/addmulconstmul b/tests/20optimizer_optimizations/addmulconstmul new file mode 100644 index 0000000..299c000 --- /dev/null +++ b/tests/20optimizer_optimizations/addmulconstmul @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=x,y +R=-3,3,2 +F=5*(if(1,4,0)*y+x) +C=5*(4*y+x) diff --git a/tests/20optimizer_optimizations/addnegmulneg b/tests/20optimizer_optimizations/addnegmulneg new file mode 100644 index 0000000..18f8885 --- /dev/null +++ b/tests/20optimizer_optimizations/addnegmulneg @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y +R=-3,3,2 +F=-5 + (if(1,5,0)*x*y) +C=-5 + (5*x*y) + +# Expected result: (1 - x*y) * -5 diff --git a/tests/20optimizer_optimizations/addnegmulpos b/tests/20optimizer_optimizations/addnegmulpos new file mode 100644 index 0000000..0336867 --- /dev/null +++ b/tests/20optimizer_optimizations/addnegmulpos @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y +R=-3,3,2 +F=(if(1,-5,0)*y) + (if(1,5,0)*x) +C=-5*y + (5*x) + +# Expected result: (x-y) * 5 diff --git a/tests/20optimizer_optimizations/addsin2cos2 b/tests/20optimizer_optimizations/addsin2cos2 new file mode 100644 index 0000000..1fc07fb --- /dev/null +++ b/tests/20optimizer_optimizations/addsin2cos2 @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,0.5 +F=sin(x)^2 + cos(x)^2 +C=fp_pow(fp_sin(x),2) + fp_pow(fp_cos(x),2) + +# Expected optimization: 1 diff --git a/tests/20optimizer_optimizations/asinhcosh b/tests/20optimizer_optimizations/asinhcosh new file mode 100644 index 0000000..f2506d0 --- /dev/null +++ b/tests/20optimizer_optimizations/asinhcosh @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=-0.7, 0.7, 0.28 +F=cosh(if(1,asinh(x),0)) +C=fp_cosh(fp_asinh(x)) diff --git a/tests/20optimizer_optimizations/asinsin b/tests/20optimizer_optimizations/asinsin new file mode 100644 index 0000000..9b13485 --- /dev/null +++ b/tests/20optimizer_optimizations/asinsin @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x +R=-1,1,0.1 +F=sin(asin(x)) +C=fp_sin(fp_asin(x)) diff --git a/tests/20optimizer_optimizations/cmpeq_add_imm b/tests/20optimizer_optimizations/cmpeq_add_imm new file mode 100644 index 0000000..6d4f9cd --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_add_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4+y) = 6) +C=fp_equal(x+4+y, 6) diff --git a/tests/20optimizer_optimizations/cmpeq_add_reduce b/tests/20optimizer_optimizations/cmpeq_add_reduce new file mode 100644 index 0000000..ae303d5 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_add_reduce @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-6,6,1 +F=((((x*5/2)+x*x-2)) = ((x*5/2)+abs(x))) +C=fp_equal(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) diff --git a/tests/20optimizer_optimizations/cmpeq_addadd_imm b/tests/20optimizer_optimizations/cmpeq_addadd_imm new file mode 100644 index 0000000..6f20972 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_addadd_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4) = (y+6)) +C=fp_equal(x+4, y+6) diff --git a/tests/20optimizer_optimizations/cmpeq_minmax b/tests/20optimizer_optimizations/cmpeq_minmax new file mode 100644 index 0000000..88a8342 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_minmax @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x = y,x,y) +C=((fp_equal(x,y)!=0)?x:y) diff --git a/tests/20optimizer_optimizations/cmpeq_minmax_rev b/tests/20optimizer_optimizations/cmpeq_minmax_rev new file mode 100644 index 0000000..45c8b0a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_minmax_rev @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x = y,y,x) +C=((fp_equal(x,y)!=0)?y:x) diff --git a/tests/20optimizer_optimizations/cmpeq_mul_imm_neg b/tests/20optimizer_optimizations/cmpeq_mul_imm_neg new file mode 100644 index 0000000..0018f50 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_mul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4*y) = 6) +C=fp_equal(x*-4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpeq_mul_imm_pos b/tests/20optimizer_optimizations/cmpeq_mul_imm_pos new file mode 100644 index 0000000..b311d85 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_mul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4*y) = 6) +C=fp_equal(x*4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpeq_mulmul_imm_neg b/tests/20optimizer_optimizations/cmpeq_mulmul_imm_neg new file mode 100644 index 0000000..db91e01 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_mulmul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4) = (y+6)) +C=fp_equal(x*-4, y+6) diff --git a/tests/20optimizer_optimizations/cmpeq_mulmul_imm_pos b/tests/20optimizer_optimizations/cmpeq_mulmul_imm_pos new file mode 100644 index 0000000..699672a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_mulmul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4) = (y+6)) +C=fp_equal(x*4, y+6) diff --git a/tests/20optimizer_optimizations/cmpeq_pow_imm_negneg b/tests/20optimizer_optimizations/cmpeq_pow_imm_negneg new file mode 100644 index 0000000..0645414 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_pow_imm_negneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-3) = -0.015625) +C=fp_equal(fp_pow(x,-3), -0.015625) diff --git a/tests/20optimizer_optimizations/cmpeq_pow_imm_negpos b/tests/20optimizer_optimizations/cmpeq_pow_imm_negpos new file mode 100644 index 0000000..a35e0b0 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_pow_imm_negpos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-2) = 0.0625) +C=fp_equal(fp_pow(x,-2), 0.0625) diff --git a/tests/20optimizer_optimizations/cmpeq_pow_imm_posneg b/tests/20optimizer_optimizations/cmpeq_pow_imm_posneg new file mode 100644 index 0000000..deeeb15 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_pow_imm_posneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,3) = -125) +C=fp_equal(x*x*x, -125) diff --git a/tests/20optimizer_optimizations/cmpeq_pow_imm_pospos b/tests/20optimizer_optimizations/cmpeq_pow_imm_pospos new file mode 100644 index 0000000..2273cf1 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_pow_imm_pospos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,2) = 25) +C=fp_equal(x*x, 25) diff --git a/tests/20optimizer_optimizations/cmpeq_pow_imm_pospos_base b/tests/20optimizer_optimizations/cmpeq_pow_imm_pospos_base new file mode 100644 index 0000000..ab80ac4 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_pow_imm_pospos_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(5.0625 = pow(1.5,x)) +C=fp_equal(5.0625, fp_pow(1.5,x)) diff --git a/tests/20optimizer_optimizations/cmpeq_powpow_imm_base b/tests/20optimizer_optimizations/cmpeq_powpow_imm_base new file mode 100644 index 0000000..e95a996 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpeq_powpow_imm_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-6,6,1 +F=(pow(2,x) = pow(-4,y)) +C=fp_equal(fp_pow(2,x), fp_pow(-4,y)) diff --git a/tests/20optimizer_optimizations/cmpge_add_imm b/tests/20optimizer_optimizations/cmpge_add_imm new file mode 100644 index 0000000..bc4852a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_add_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4+y) >= 6) +C=fp_greaterOrEq(x+4+y, 6) diff --git a/tests/20optimizer_optimizations/cmpge_add_reduce b/tests/20optimizer_optimizations/cmpge_add_reduce new file mode 100644 index 0000000..87f392a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_add_reduce @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-6,6,1 +F=((((x*5/2)+x*x-2)) >= ((x*5/2)+abs(x))) +C=fp_greaterOrEq(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) diff --git a/tests/20optimizer_optimizations/cmpge_addadd_imm b/tests/20optimizer_optimizations/cmpge_addadd_imm new file mode 100644 index 0000000..409960f --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_addadd_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4) >= (y+6)) +C=fp_greaterOrEq(x+4, y+6) diff --git a/tests/20optimizer_optimizations/cmpge_minmax b/tests/20optimizer_optimizations/cmpge_minmax new file mode 100644 index 0000000..31fca73 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_minmax @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x >= y,x,y) +C=((fp_greaterOrEq(x,y)!=0)?x:y) diff --git a/tests/20optimizer_optimizations/cmpge_minmax_rev b/tests/20optimizer_optimizations/cmpge_minmax_rev new file mode 100644 index 0000000..525ad01 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_minmax_rev @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x >= y,y,x) +C=((fp_greaterOrEq(x,y)!=0)?y:x) diff --git a/tests/20optimizer_optimizations/cmpge_mul_imm_neg b/tests/20optimizer_optimizations/cmpge_mul_imm_neg new file mode 100644 index 0000000..8cb340b --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_mul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4*y) >= 6) +C=fp_greaterOrEq(x*-4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpge_mul_imm_pos b/tests/20optimizer_optimizations/cmpge_mul_imm_pos new file mode 100644 index 0000000..46877c5 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_mul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4*y) >= 6) +C=fp_greaterOrEq(x*4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpge_mulmul_imm_neg b/tests/20optimizer_optimizations/cmpge_mulmul_imm_neg new file mode 100644 index 0000000..df087ac --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_mulmul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4) >= (y+6)) +C=fp_greaterOrEq(x*-4, y+6) diff --git a/tests/20optimizer_optimizations/cmpge_mulmul_imm_pos b/tests/20optimizer_optimizations/cmpge_mulmul_imm_pos new file mode 100644 index 0000000..5dff6aa --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_mulmul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4) >= (y+6)) +C=fp_greaterOrEq(x*4, y+6) diff --git a/tests/20optimizer_optimizations/cmpge_pow_imm_negneg b/tests/20optimizer_optimizations/cmpge_pow_imm_negneg new file mode 100644 index 0000000..44e384a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_pow_imm_negneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-3) >= -0.015625) +C=fp_greaterOrEq(fp_pow(x,-3), -0.015625) diff --git a/tests/20optimizer_optimizations/cmpge_pow_imm_negpos b/tests/20optimizer_optimizations/cmpge_pow_imm_negpos new file mode 100644 index 0000000..3e89c60 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_pow_imm_negpos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-2) >= 0.0625) +C=fp_greaterOrEq(fp_pow(x,-2), 0.0625) diff --git a/tests/20optimizer_optimizations/cmpge_pow_imm_posneg b/tests/20optimizer_optimizations/cmpge_pow_imm_posneg new file mode 100644 index 0000000..f30858f --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_pow_imm_posneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,3) >= -125) +C=fp_greaterOrEq(x*x*x, -125) diff --git a/tests/20optimizer_optimizations/cmpge_pow_imm_pospos b/tests/20optimizer_optimizations/cmpge_pow_imm_pospos new file mode 100644 index 0000000..dae851e --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_pow_imm_pospos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,2) >= 25) +C=fp_greaterOrEq(x*x, 25) diff --git a/tests/20optimizer_optimizations/cmpge_pow_imm_pospos_base b/tests/20optimizer_optimizations/cmpge_pow_imm_pospos_base new file mode 100644 index 0000000..2031751 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_pow_imm_pospos_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(5.0625 >= pow(1.5,x)) +C=fp_greaterOrEq(5.0625, fp_pow(1.5,x)) diff --git a/tests/20optimizer_optimizations/cmpge_powpow_imm_base b/tests/20optimizer_optimizations/cmpge_powpow_imm_base new file mode 100644 index 0000000..58b62bb --- /dev/null +++ b/tests/20optimizer_optimizations/cmpge_powpow_imm_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-6,6,1 +F=(pow(2,x) >= pow(-4,y)) +C=fp_greaterOrEq(fp_pow(2,x), fp_pow(-4,y)) diff --git a/tests/20optimizer_optimizations/cmpgt_add_imm b/tests/20optimizer_optimizations/cmpgt_add_imm new file mode 100644 index 0000000..86aa195 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_add_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4+y) > 6) +C=fp_greater(x+4+y, 6) diff --git a/tests/20optimizer_optimizations/cmpgt_add_reduce b/tests/20optimizer_optimizations/cmpgt_add_reduce new file mode 100644 index 0000000..370d9e3 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_add_reduce @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-6,6,1 +F=((((x*5/2)+x*x-2)) > ((x*5/2)+abs(x))) +C=fp_greater(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) diff --git a/tests/20optimizer_optimizations/cmpgt_addadd_imm b/tests/20optimizer_optimizations/cmpgt_addadd_imm new file mode 100644 index 0000000..83c40c8 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_addadd_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4) > (y+6)) +C=fp_greater(x+4, y+6) diff --git a/tests/20optimizer_optimizations/cmpgt_minmax b/tests/20optimizer_optimizations/cmpgt_minmax new file mode 100644 index 0000000..4f4b23b --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_minmax @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x > y,x,y) +C=((fp_greater(x,y)!=0)?x:y) diff --git a/tests/20optimizer_optimizations/cmpgt_minmax_rev b/tests/20optimizer_optimizations/cmpgt_minmax_rev new file mode 100644 index 0000000..7a06d99 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_minmax_rev @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x > y,y,x) +C=((fp_greater(x,y)!=0)?y:x) diff --git a/tests/20optimizer_optimizations/cmpgt_mul_imm_neg b/tests/20optimizer_optimizations/cmpgt_mul_imm_neg new file mode 100644 index 0000000..454d135 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_mul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4*y) > 6) +C=fp_greater(x*-4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpgt_mul_imm_pos b/tests/20optimizer_optimizations/cmpgt_mul_imm_pos new file mode 100644 index 0000000..ca4de8c --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_mul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4*y) > 6) +C=fp_greater(x*4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpgt_mulmul_imm_neg b/tests/20optimizer_optimizations/cmpgt_mulmul_imm_neg new file mode 100644 index 0000000..222274a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_mulmul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4) > (y+6)) +C=fp_greater(x*-4, y+6) diff --git a/tests/20optimizer_optimizations/cmpgt_mulmul_imm_pos b/tests/20optimizer_optimizations/cmpgt_mulmul_imm_pos new file mode 100644 index 0000000..01df9b4 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_mulmul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4) > (y+6)) +C=fp_greater(x*4, y+6) diff --git a/tests/20optimizer_optimizations/cmpgt_pow_imm_negneg b/tests/20optimizer_optimizations/cmpgt_pow_imm_negneg new file mode 100644 index 0000000..1d56fc0 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_pow_imm_negneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-3) > -0.015625) +C=fp_greater(fp_pow(x,-3), -0.015625) diff --git a/tests/20optimizer_optimizations/cmpgt_pow_imm_negpos b/tests/20optimizer_optimizations/cmpgt_pow_imm_negpos new file mode 100644 index 0000000..2fd0f5e --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_pow_imm_negpos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-2) > 0.0625) +C=fp_greater(fp_pow(x,-2), 0.0625) diff --git a/tests/20optimizer_optimizations/cmpgt_pow_imm_posneg b/tests/20optimizer_optimizations/cmpgt_pow_imm_posneg new file mode 100644 index 0000000..c6be28a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_pow_imm_posneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,3) > -125) +C=fp_greater(x*x*x, -125) diff --git a/tests/20optimizer_optimizations/cmpgt_pow_imm_pospos b/tests/20optimizer_optimizations/cmpgt_pow_imm_pospos new file mode 100644 index 0000000..c9668c3 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_pow_imm_pospos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,2) > 25) +C=fp_greater(x*x, 25) diff --git a/tests/20optimizer_optimizations/cmpgt_pow_imm_pospos_base b/tests/20optimizer_optimizations/cmpgt_pow_imm_pospos_base new file mode 100644 index 0000000..9bb28a8 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_pow_imm_pospos_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(5.0625 > pow(1.5,x)) +C=fp_greater(5.0625, fp_pow(1.5,x)) diff --git a/tests/20optimizer_optimizations/cmpgt_powpow_imm_base b/tests/20optimizer_optimizations/cmpgt_powpow_imm_base new file mode 100644 index 0000000..338dd62 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpgt_powpow_imm_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-6,6,1 +F=(pow(2,x) > pow(-4,y)) +C=fp_greater(fp_pow(2,x), fp_pow(-4,y)) diff --git a/tests/20optimizer_optimizations/cmple_add_imm b/tests/20optimizer_optimizations/cmple_add_imm new file mode 100644 index 0000000..4a6746e --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_add_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4+y) <= 6) +C=fp_lessOrEq(x+4+y, 6) diff --git a/tests/20optimizer_optimizations/cmple_add_reduce b/tests/20optimizer_optimizations/cmple_add_reduce new file mode 100644 index 0000000..afbb756 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_add_reduce @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-6,6,1 +F=((((x*5/2)+x*x-2)) <= ((x*5/2)+abs(x))) +C=fp_lessOrEq(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) diff --git a/tests/20optimizer_optimizations/cmple_addadd_imm b/tests/20optimizer_optimizations/cmple_addadd_imm new file mode 100644 index 0000000..90d76b1 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_addadd_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4) <= (y+6)) +C=fp_lessOrEq(x+4, y+6) diff --git a/tests/20optimizer_optimizations/cmple_minmax b/tests/20optimizer_optimizations/cmple_minmax new file mode 100644 index 0000000..96f5736 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_minmax @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x <= y,x,y) +C=((fp_lessOrEq(x,y)!=0)?x:y) diff --git a/tests/20optimizer_optimizations/cmple_minmax_rev b/tests/20optimizer_optimizations/cmple_minmax_rev new file mode 100644 index 0000000..4083728 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_minmax_rev @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x <= y,y,x) +C=((fp_lessOrEq(x,y)!=0)?y:x) diff --git a/tests/20optimizer_optimizations/cmple_mul_imm_neg b/tests/20optimizer_optimizations/cmple_mul_imm_neg new file mode 100644 index 0000000..48dcac1 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_mul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4*y) <= 6) +C=fp_lessOrEq(x*-4*y, 6) diff --git a/tests/20optimizer_optimizations/cmple_mul_imm_pos b/tests/20optimizer_optimizations/cmple_mul_imm_pos new file mode 100644 index 0000000..4e99912 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_mul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4*y) <= 6) +C=fp_lessOrEq(x*4*y, 6) diff --git a/tests/20optimizer_optimizations/cmple_mulmul_imm_neg b/tests/20optimizer_optimizations/cmple_mulmul_imm_neg new file mode 100644 index 0000000..78cf6f1 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_mulmul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4) <= (y+6)) +C=fp_lessOrEq(x*-4, y+6) diff --git a/tests/20optimizer_optimizations/cmple_mulmul_imm_pos b/tests/20optimizer_optimizations/cmple_mulmul_imm_pos new file mode 100644 index 0000000..35e0efd --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_mulmul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4) <= (y+6)) +C=fp_lessOrEq(x*4, y+6) diff --git a/tests/20optimizer_optimizations/cmple_pow_imm_negneg b/tests/20optimizer_optimizations/cmple_pow_imm_negneg new file mode 100644 index 0000000..60f2617 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_pow_imm_negneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-3) <= -0.015625) +C=fp_lessOrEq(fp_pow(x,-3), -0.015625) diff --git a/tests/20optimizer_optimizations/cmple_pow_imm_negpos b/tests/20optimizer_optimizations/cmple_pow_imm_negpos new file mode 100644 index 0000000..9e90c41 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_pow_imm_negpos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-2) <= 0.0625) +C=fp_lessOrEq(fp_pow(x,-2), 0.0625) diff --git a/tests/20optimizer_optimizations/cmple_pow_imm_posneg b/tests/20optimizer_optimizations/cmple_pow_imm_posneg new file mode 100644 index 0000000..941e86f --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_pow_imm_posneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,3) <= -125) +C=fp_lessOrEq(x*x*x, -125) diff --git a/tests/20optimizer_optimizations/cmple_pow_imm_pospos b/tests/20optimizer_optimizations/cmple_pow_imm_pospos new file mode 100644 index 0000000..6d87b0f --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_pow_imm_pospos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,2) <= 25) +C=fp_lessOrEq(x*x, 25) diff --git a/tests/20optimizer_optimizations/cmple_pow_imm_pospos_base b/tests/20optimizer_optimizations/cmple_pow_imm_pospos_base new file mode 100644 index 0000000..410c308 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_pow_imm_pospos_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(5.0625 <= pow(1.5,x)) +C=fp_lessOrEq(5.0625, fp_pow(1.5,x)) diff --git a/tests/20optimizer_optimizations/cmple_powpow_imm_base b/tests/20optimizer_optimizations/cmple_powpow_imm_base new file mode 100644 index 0000000..0a3f620 --- /dev/null +++ b/tests/20optimizer_optimizations/cmple_powpow_imm_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-6,6,1 +F=(pow(2,x) <= pow(-4,y)) +C=fp_lessOrEq(fp_pow(2,x), fp_pow(-4,y)) diff --git a/tests/20optimizer_optimizations/cmplt_add_imm b/tests/20optimizer_optimizations/cmplt_add_imm new file mode 100644 index 0000000..cebf959 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_add_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4+y) < 6) +C=fp_less(x+4+y, 6) diff --git a/tests/20optimizer_optimizations/cmplt_add_reduce b/tests/20optimizer_optimizations/cmplt_add_reduce new file mode 100644 index 0000000..ad4096f --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_add_reduce @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-6,6,1 +F=((((x*5/2)+x*x-2)) < ((x*5/2)+abs(x))) +C=fp_less(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) diff --git a/tests/20optimizer_optimizations/cmplt_addadd_imm b/tests/20optimizer_optimizations/cmplt_addadd_imm new file mode 100644 index 0000000..979a3ba --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_addadd_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4) < (y+6)) +C=fp_less(x+4, y+6) diff --git a/tests/20optimizer_optimizations/cmplt_minmax b/tests/20optimizer_optimizations/cmplt_minmax new file mode 100644 index 0000000..7128ed6 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_minmax @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x < y,x,y) +C=((fp_less(x,y)!=0)?x:y) diff --git a/tests/20optimizer_optimizations/cmplt_minmax_rev b/tests/20optimizer_optimizations/cmplt_minmax_rev new file mode 100644 index 0000000..3f12856 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_minmax_rev @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x < y,y,x) +C=((fp_less(x,y)!=0)?y:x) diff --git a/tests/20optimizer_optimizations/cmplt_mul_imm_neg b/tests/20optimizer_optimizations/cmplt_mul_imm_neg new file mode 100644 index 0000000..f2d6494 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_mul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4*y) < 6) +C=fp_less(x*-4*y, 6) diff --git a/tests/20optimizer_optimizations/cmplt_mul_imm_pos b/tests/20optimizer_optimizations/cmplt_mul_imm_pos new file mode 100644 index 0000000..429ab08 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_mul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4*y) < 6) +C=fp_less(x*4*y, 6) diff --git a/tests/20optimizer_optimizations/cmplt_mulmul_imm_neg b/tests/20optimizer_optimizations/cmplt_mulmul_imm_neg new file mode 100644 index 0000000..6b05e06 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_mulmul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4) < (y+6)) +C=fp_less(x*-4, y+6) diff --git a/tests/20optimizer_optimizations/cmplt_mulmul_imm_pos b/tests/20optimizer_optimizations/cmplt_mulmul_imm_pos new file mode 100644 index 0000000..e3d10dd --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_mulmul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4) < (y+6)) +C=fp_less(x*4, y+6) diff --git a/tests/20optimizer_optimizations/cmplt_pow_imm_negneg b/tests/20optimizer_optimizations/cmplt_pow_imm_negneg new file mode 100644 index 0000000..ab817fb --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_pow_imm_negneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-3) < -0.015625) +C=fp_less(fp_pow(x,-3), -0.015625) diff --git a/tests/20optimizer_optimizations/cmplt_pow_imm_negpos b/tests/20optimizer_optimizations/cmplt_pow_imm_negpos new file mode 100644 index 0000000..d211b51 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_pow_imm_negpos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-2) < 0.0625) +C=fp_less(fp_pow(x,-2), 0.0625) diff --git a/tests/20optimizer_optimizations/cmplt_pow_imm_posneg b/tests/20optimizer_optimizations/cmplt_pow_imm_posneg new file mode 100644 index 0000000..dc8394f --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_pow_imm_posneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,3) < -125) +C=fp_less(x*x*x, -125) diff --git a/tests/20optimizer_optimizations/cmplt_pow_imm_pospos b/tests/20optimizer_optimizations/cmplt_pow_imm_pospos new file mode 100644 index 0000000..405b191 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_pow_imm_pospos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,2) < 25) +C=fp_less(x*x, 25) diff --git a/tests/20optimizer_optimizations/cmplt_pow_imm_pospos_base b/tests/20optimizer_optimizations/cmplt_pow_imm_pospos_base new file mode 100644 index 0000000..bf691d4 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_pow_imm_pospos_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(5.0625 < pow(1.5,x)) +C=fp_less(5.0625, fp_pow(1.5,x)) diff --git a/tests/20optimizer_optimizations/cmplt_powpow_imm_base b/tests/20optimizer_optimizations/cmplt_powpow_imm_base new file mode 100644 index 0000000..e24a292 --- /dev/null +++ b/tests/20optimizer_optimizations/cmplt_powpow_imm_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-6,6,1 +F=(pow(2,x) < pow(-4,y)) +C=fp_less(fp_pow(2,x), fp_pow(-4,y)) diff --git a/tests/20optimizer_optimizations/cmpne_add_imm b/tests/20optimizer_optimizations/cmpne_add_imm new file mode 100644 index 0000000..a0ae9bc --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_add_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4+y) != 6) +C=fp_nequal(x+4+y, 6) diff --git a/tests/20optimizer_optimizations/cmpne_add_reduce b/tests/20optimizer_optimizations/cmpne_add_reduce new file mode 100644 index 0000000..b2bf6ee --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_add_reduce @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-6,6,1 +F=((((x*5/2)+x*x-2)) != ((x*5/2)+abs(x))) +C=fp_nequal(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) diff --git a/tests/20optimizer_optimizations/cmpne_addadd_imm b/tests/20optimizer_optimizations/cmpne_addadd_imm new file mode 100644 index 0000000..8aac2ac --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_addadd_imm @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x+4) != (y+6)) +C=fp_nequal(x+4, y+6) diff --git a/tests/20optimizer_optimizations/cmpne_minmax b/tests/20optimizer_optimizations/cmpne_minmax new file mode 100644 index 0000000..46dc0a9 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_minmax @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x != y,x,y) +C=((fp_nequal(x,y)!=0)?x:y) diff --git a/tests/20optimizer_optimizations/cmpne_minmax_rev b/tests/20optimizer_optimizations/cmpne_minmax_rev new file mode 100644 index 0000000..797329d --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_minmax_rev @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F=if(x != y,y,x) +C=((fp_nequal(x,y)!=0)?y:x) diff --git a/tests/20optimizer_optimizations/cmpne_mul_imm_neg b/tests/20optimizer_optimizations/cmpne_mul_imm_neg new file mode 100644 index 0000000..5a851b6 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_mul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4*y) != 6) +C=fp_nequal(x*-4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpne_mul_imm_pos b/tests/20optimizer_optimizations/cmpne_mul_imm_pos new file mode 100644 index 0000000..e96f727 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_mul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4*y) != 6) +C=fp_nequal(x*4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpne_mulmul_imm_neg b/tests/20optimizer_optimizations/cmpne_mulmul_imm_neg new file mode 100644 index 0000000..8ed54a4 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_mulmul_imm_neg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*-4) != (y+6)) +C=fp_nequal(x*-4, y+6) diff --git a/tests/20optimizer_optimizations/cmpne_mulmul_imm_pos b/tests/20optimizer_optimizations/cmpne_mulmul_imm_pos new file mode 100644 index 0000000..4cf78e9 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_mulmul_imm_pos @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 +F=((x*4) != (y+6)) +C=fp_nequal(x*4, y+6) diff --git a/tests/20optimizer_optimizations/cmpne_pow_imm_negneg b/tests/20optimizer_optimizations/cmpne_pow_imm_negneg new file mode 100644 index 0000000..a7e48cb --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_pow_imm_negneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-3) != -0.015625) +C=fp_nequal(fp_pow(x,-3), -0.015625) diff --git a/tests/20optimizer_optimizations/cmpne_pow_imm_negpos b/tests/20optimizer_optimizations/cmpne_pow_imm_negpos new file mode 100644 index 0000000..b796076 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_pow_imm_negpos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 +F=(pow(x,-2) != 0.0625) +C=fp_nequal(fp_pow(x,-2), 0.0625) diff --git a/tests/20optimizer_optimizations/cmpne_pow_imm_posneg b/tests/20optimizer_optimizations/cmpne_pow_imm_posneg new file mode 100644 index 0000000..d6922d2 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_pow_imm_posneg @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,3) != -125) +C=fp_nequal(x*x*x, -125) diff --git a/tests/20optimizer_optimizations/cmpne_pow_imm_pospos b/tests/20optimizer_optimizations/cmpne_pow_imm_pospos new file mode 100644 index 0000000..3e72cc8 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_pow_imm_pospos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(pow(x,2) != 25) +C=fp_nequal(x*x, 25) diff --git a/tests/20optimizer_optimizations/cmpne_pow_imm_pospos_base b/tests/20optimizer_optimizations/cmpne_pow_imm_pospos_base new file mode 100644 index 0000000..a83614a --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_pow_imm_pospos_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 +F=(5.0625 != pow(1.5,x)) +C=fp_nequal(5.0625, fp_pow(1.5,x)) diff --git a/tests/20optimizer_optimizations/cmpne_powpow_imm_base b/tests/20optimizer_optimizations/cmpne_powpow_imm_base new file mode 100644 index 0000000..ce9c41d --- /dev/null +++ b/tests/20optimizer_optimizations/cmpne_powpow_imm_base @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-6,6,1 +F=(pow(2,x) != pow(-4,y)) +C=fp_nequal(fp_pow(2,x), fp_pow(-4,y)) diff --git a/tests/20optimizer_optimizations/cmpzz_add_imm b/tests/20optimizer_optimizations/cmpzz_add_imm new file mode 100644 index 0000000..e1dcb55 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_add_imm @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 + +# Combine tests: +# cmplt_add_imm +# cmple_add_imm +# cmpgt_add_imm +# cmpge_add_imm +# cmpne_add_imm +# cmpeq_add_imm + +F=0x0001 * ((x+4+y) < 6) + \ + 0x0002 * ((x+4+y) <= 6) + \ + 0x0004 * ((x+4+y) > 6) + \ + 0x0008 * ((x+4+y) >= 6) + \ + 0x0010 * ((x+4+y) != 6) + \ + 0x0020 * ((x+4+y) = 6) +C=0x0001 * fp_less(x+4+y, 6) + \ + 0x0002 * fp_lessOrEq(x+4+y, 6) + \ + 0x0004 * fp_greater(x+4+y, 6) + \ + 0x0008 * fp_greaterOrEq(x+4+y, 6) + \ + 0x0010 * fp_nequal(x+4+y, 6) + \ + 0x0020 * fp_equal(x+4+y, 6) diff --git a/tests/20optimizer_optimizations/cmpzz_add_reduce b/tests/20optimizer_optimizations/cmpzz_add_reduce new file mode 100644 index 0000000..837c52f --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_add_reduce @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-6,6,1 + +# Combine tests: +# cmplt_add_reduce +# cmple_add_reduce +# cmpgt_add_reduce +# cmpge_add_reduce +# cmpne_add_reduce +# cmpeq_add_reduce + +F=0x0001 * ((((x*5/2)+x*x-2)) < ((x*5/2)+abs(x))) + \ + 0x0002 * ((((x*5/2)+x*x-2)) <= ((x*5/2)+abs(x))) + \ + 0x0004 * ((((x*5/2)+x*x-2)) > ((x*5/2)+abs(x))) + \ + 0x0008 * ((((x*5/2)+x*x-2)) >= ((x*5/2)+abs(x))) + \ + 0x0010 * ((((x*5/2)+x*x-2)) != ((x*5/2)+abs(x))) + \ + 0x0020 * ((((x*5/2)+x*x-2)) = ((x*5/2)+abs(x))) +C=0x0001 * fp_less(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) + \ + 0x0002 * fp_lessOrEq(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) + \ + 0x0004 * fp_greater(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) + \ + 0x0008 * fp_greaterOrEq(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) + \ + 0x0010 * fp_nequal(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) + \ + 0x0020 * fp_equal(((x*5/2)+x*x-2), ((x*5/2)+fp_abs(x))) diff --git a/tests/20optimizer_optimizations/cmpzz_addadd_imm b/tests/20optimizer_optimizations/cmpzz_addadd_imm new file mode 100644 index 0000000..000f93d --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_addadd_imm @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 + +# Combine tests: +# cmplt_addadd_imm +# cmple_addadd_imm +# cmpgt_addadd_imm +# cmpge_addadd_imm +# cmpne_addadd_imm +# cmpeq_addadd_imm + +F=0x0001 * ((x+4) < (y+6)) + \ + 0x0002 * ((x+4) <= (y+6)) + \ + 0x0004 * ((x+4) > (y+6)) + \ + 0x0008 * ((x+4) >= (y+6)) + \ + 0x0010 * ((x+4) != (y+6)) + \ + 0x0020 * ((x+4) = (y+6)) +C=0x0001 * fp_less(x+4, y+6) + \ + 0x0002 * fp_lessOrEq(x+4, y+6) + \ + 0x0004 * fp_greater(x+4, y+6) + \ + 0x0008 * fp_greaterOrEq(x+4, y+6) + \ + 0x0010 * fp_nequal(x+4, y+6) + \ + 0x0020 * fp_equal(x+4, y+6) diff --git a/tests/20optimizer_optimizations/cmpzz_minmax b/tests/20optimizer_optimizations/cmpzz_minmax new file mode 100644 index 0000000..0e24260 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_minmax @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 + +# Combine tests: +# cmplt_minmax +# cmple_minmax +# cmpgt_minmax +# cmpge_minmax +# cmpne_minmax +# cmpeq_minmax + +F=0x0001 * if(x < y,x,y) + \ + 0x0002 * if(x <= y,x,y) + \ + 0x0004 * if(x > y,x,y) + \ + 0x0008 * if(x >= y,x,y) + \ + 0x0010 * if(x != y,x,y) + \ + 0x0020 * if(x = y,x,y) +C=0x0001 * ((fp_less(x,y)!=0)?x:y) + \ + 0x0002 * ((fp_lessOrEq(x,y)!=0)?x:y) + \ + 0x0004 * ((fp_greater(x,y)!=0)?x:y) + \ + 0x0008 * ((fp_greaterOrEq(x,y)!=0)?x:y) + \ + 0x0010 * ((fp_nequal(x,y)!=0)?x:y) + \ + 0x0020 * ((fp_equal(x,y)!=0)?x:y) diff --git a/tests/20optimizer_optimizations/cmpzz_minmax_rev b/tests/20optimizer_optimizations/cmpzz_minmax_rev new file mode 100644 index 0000000..5795b8c --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_minmax_rev @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 + +# Combine tests: +# cmplt_minmax_rev +# cmple_minmax_rev +# cmpgt_minmax_rev +# cmpge_minmax_rev +# cmpne_minmax_rev +# cmpeq_minmax_rev + +F=0x0001 * if(x < y,y,x) + \ + 0x0002 * if(x <= y,y,x) + \ + 0x0004 * if(x > y,y,x) + \ + 0x0008 * if(x >= y,y,x) + \ + 0x0010 * if(x != y,y,x) + \ + 0x0020 * if(x = y,y,x) +C=0x0001 * ((fp_less(x,y)!=0)?y:x) + \ + 0x0002 * ((fp_lessOrEq(x,y)!=0)?y:x) + \ + 0x0004 * ((fp_greater(x,y)!=0)?y:x) + \ + 0x0008 * ((fp_greaterOrEq(x,y)!=0)?y:x) + \ + 0x0010 * ((fp_nequal(x,y)!=0)?y:x) + \ + 0x0020 * ((fp_equal(x,y)!=0)?y:x) diff --git a/tests/20optimizer_optimizations/cmpzz_mul_imm_neg b/tests/20optimizer_optimizations/cmpzz_mul_imm_neg new file mode 100644 index 0000000..5e09b2f --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_mul_imm_neg @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 + +# Combine tests: +# cmplt_mul_imm_neg +# cmple_mul_imm_neg +# cmpgt_mul_imm_neg +# cmpge_mul_imm_neg +# cmpne_mul_imm_neg +# cmpeq_mul_imm_neg + +F=0x0001 * ((x*-4*y) < 6) + \ + 0x0002 * ((x*-4*y) <= 6) + \ + 0x0004 * ((x*-4*y) > 6) + \ + 0x0008 * ((x*-4*y) >= 6) + \ + 0x0010 * ((x*-4*y) != 6) + \ + 0x0020 * ((x*-4*y) = 6) +C=0x0001 * fp_less(x*-4*y, 6) + \ + 0x0002 * fp_lessOrEq(x*-4*y, 6) + \ + 0x0004 * fp_greater(x*-4*y, 6) + \ + 0x0008 * fp_greaterOrEq(x*-4*y, 6) + \ + 0x0010 * fp_nequal(x*-4*y, 6) + \ + 0x0020 * fp_equal(x*-4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpzz_mul_imm_pos b/tests/20optimizer_optimizations/cmpzz_mul_imm_pos new file mode 100644 index 0000000..d15af75 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_mul_imm_pos @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 + +# Combine tests: +# cmplt_mul_imm_pos +# cmple_mul_imm_pos +# cmpgt_mul_imm_pos +# cmpge_mul_imm_pos +# cmpne_mul_imm_pos +# cmpeq_mul_imm_pos + +F=0x0001 * ((x*4*y) < 6) + \ + 0x0002 * ((x*4*y) <= 6) + \ + 0x0004 * ((x*4*y) > 6) + \ + 0x0008 * ((x*4*y) >= 6) + \ + 0x0010 * ((x*4*y) != 6) + \ + 0x0020 * ((x*4*y) = 6) +C=0x0001 * fp_less(x*4*y, 6) + \ + 0x0002 * fp_lessOrEq(x*4*y, 6) + \ + 0x0004 * fp_greater(x*4*y, 6) + \ + 0x0008 * fp_greaterOrEq(x*4*y, 6) + \ + 0x0010 * fp_nequal(x*4*y, 6) + \ + 0x0020 * fp_equal(x*4*y, 6) diff --git a/tests/20optimizer_optimizations/cmpzz_mulmul_imm_neg b/tests/20optimizer_optimizations/cmpzz_mulmul_imm_neg new file mode 100644 index 0000000..14dab04 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_mulmul_imm_neg @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 + +# Combine tests: +# cmplt_mulmul_imm_neg +# cmple_mulmul_imm_neg +# cmpgt_mulmul_imm_neg +# cmpge_mulmul_imm_neg +# cmpne_mulmul_imm_neg +# cmpeq_mulmul_imm_neg + +F=0x0001 * ((x*-4) < (y+6)) + \ + 0x0002 * ((x*-4) <= (y+6)) + \ + 0x0004 * ((x*-4) > (y+6)) + \ + 0x0008 * ((x*-4) >= (y+6)) + \ + 0x0010 * ((x*-4) != (y+6)) + \ + 0x0020 * ((x*-4) = (y+6)) +C=0x0001 * fp_less(x*-4, y+6) + \ + 0x0002 * fp_lessOrEq(x*-4, y+6) + \ + 0x0004 * fp_greater(x*-4, y+6) + \ + 0x0008 * fp_greaterOrEq(x*-4, y+6) + \ + 0x0010 * fp_nequal(x*-4, y+6) + \ + 0x0020 * fp_equal(x*-4, y+6) diff --git a/tests/20optimizer_optimizations/cmpzz_mulmul_imm_pos b/tests/20optimizer_optimizations/cmpzz_mulmul_imm_pos new file mode 100644 index 0000000..ba0df17 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_mulmul_imm_pos @@ -0,0 +1,24 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-6,6,1 + +# Combine tests: +# cmplt_mulmul_imm_pos +# cmple_mulmul_imm_pos +# cmpgt_mulmul_imm_pos +# cmpge_mulmul_imm_pos +# cmpne_mulmul_imm_pos +# cmpeq_mulmul_imm_pos + +F=0x0001 * ((x*4) < (y+6)) + \ + 0x0002 * ((x*4) <= (y+6)) + \ + 0x0004 * ((x*4) > (y+6)) + \ + 0x0008 * ((x*4) >= (y+6)) + \ + 0x0010 * ((x*4) != (y+6)) + \ + 0x0020 * ((x*4) = (y+6)) +C=0x0001 * fp_less(x*4, y+6) + \ + 0x0002 * fp_lessOrEq(x*4, y+6) + \ + 0x0004 * fp_greater(x*4, y+6) + \ + 0x0008 * fp_greaterOrEq(x*4, y+6) + \ + 0x0010 * fp_nequal(x*4, y+6) + \ + 0x0020 * fp_equal(x*4, y+6) diff --git a/tests/20optimizer_optimizations/cmpzz_pow_imm_negneg b/tests/20optimizer_optimizations/cmpzz_pow_imm_negneg new file mode 100644 index 0000000..07de6da --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_pow_imm_negneg @@ -0,0 +1,24 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 + +# Combine tests: +# cmplt_pow_imm_negneg +# cmple_pow_imm_negneg +# cmpgt_pow_imm_negneg +# cmpge_pow_imm_negneg +# cmpne_pow_imm_negneg +# cmpeq_pow_imm_negneg + +F=0x0001 * (pow(x,-3) < -0.015625) + \ + 0x0002 * (pow(x,-3) <= -0.015625) + \ + 0x0004 * (pow(x,-3) > -0.015625) + \ + 0x0008 * (pow(x,-3) >= -0.015625) + \ + 0x0010 * (pow(x,-3) != -0.015625) + \ + 0x0020 * (pow(x,-3) = -0.015625) +C=0x0001 * fp_less(fp_pow(x,-3), -0.015625) + \ + 0x0002 * fp_lessOrEq(fp_pow(x,-3), -0.015625) + \ + 0x0004 * fp_greater(fp_pow(x,-3), -0.015625) + \ + 0x0008 * fp_greaterOrEq(fp_pow(x,-3), -0.015625) + \ + 0x0010 * fp_nequal(fp_pow(x,-3), -0.015625) + \ + 0x0020 * fp_equal(fp_pow(x,-3), -0.015625) diff --git a/tests/20optimizer_optimizations/cmpzz_pow_imm_negpos b/tests/20optimizer_optimizations/cmpzz_pow_imm_negpos new file mode 100644 index 0000000..e2a9c29 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_pow_imm_negpos @@ -0,0 +1,24 @@ +T=d ld f mf cd cf cld +V=x +R=-5,5,2 + +# Combine tests: +# cmplt_pow_imm_negpos +# cmple_pow_imm_negpos +# cmpgt_pow_imm_negpos +# cmpge_pow_imm_negpos +# cmpne_pow_imm_negpos +# cmpeq_pow_imm_negpos + +F=0x0001 * (pow(x,-2) < 0.0625) + \ + 0x0002 * (pow(x,-2) <= 0.0625) + \ + 0x0004 * (pow(x,-2) > 0.0625) + \ + 0x0008 * (pow(x,-2) >= 0.0625) + \ + 0x0010 * (pow(x,-2) != 0.0625) + \ + 0x0020 * (pow(x,-2) = 0.0625) +C=0x0001 * fp_less(fp_pow(x,-2), 0.0625) + \ + 0x0002 * fp_lessOrEq(fp_pow(x,-2), 0.0625) + \ + 0x0004 * fp_greater(fp_pow(x,-2), 0.0625) + \ + 0x0008 * fp_greaterOrEq(fp_pow(x,-2), 0.0625) + \ + 0x0010 * fp_nequal(fp_pow(x,-2), 0.0625) + \ + 0x0020 * fp_equal(fp_pow(x,-2), 0.0625) diff --git a/tests/20optimizer_optimizations/cmpzz_pow_imm_posneg b/tests/20optimizer_optimizations/cmpzz_pow_imm_posneg new file mode 100644 index 0000000..de4afe3 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_pow_imm_posneg @@ -0,0 +1,24 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 + +# Combine tests: +# cmplt_pow_imm_posneg +# cmple_pow_imm_posneg +# cmpgt_pow_imm_posneg +# cmpge_pow_imm_posneg +# cmpne_pow_imm_posneg +# cmpeq_pow_imm_posneg + +F=0x0001 * (pow(x,3) < -125) + \ + 0x0002 * (pow(x,3) <= -125) + \ + 0x0004 * (pow(x,3) > -125) + \ + 0x0008 * (pow(x,3) >= -125) + \ + 0x0010 * (pow(x,3) != -125) + \ + 0x0020 * (pow(x,3) = -125) +C=0x0001 * fp_less(x*x*x, -125) + \ + 0x0002 * fp_lessOrEq(x*x*x, -125) + \ + 0x0004 * fp_greater(x*x*x, -125) + \ + 0x0008 * fp_greaterOrEq(x*x*x, -125) + \ + 0x0010 * fp_nequal(x*x*x, -125) + \ + 0x0020 * fp_equal(x*x*x, -125) diff --git a/tests/20optimizer_optimizations/cmpzz_pow_imm_pospos b/tests/20optimizer_optimizations/cmpzz_pow_imm_pospos new file mode 100644 index 0000000..56ce5cc --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_pow_imm_pospos @@ -0,0 +1,24 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 + +# Combine tests: +# cmplt_pow_imm_pospos +# cmple_pow_imm_pospos +# cmpgt_pow_imm_pospos +# cmpge_pow_imm_pospos +# cmpne_pow_imm_pospos +# cmpeq_pow_imm_pospos + +F=0x0001 * (pow(x,2) < 25) + \ + 0x0002 * (pow(x,2) <= 25) + \ + 0x0004 * (pow(x,2) > 25) + \ + 0x0008 * (pow(x,2) >= 25) + \ + 0x0010 * (pow(x,2) != 25) + \ + 0x0020 * (pow(x,2) = 25) +C=0x0001 * fp_less(x*x, 25) + \ + 0x0002 * fp_lessOrEq(x*x, 25) + \ + 0x0004 * fp_greater(x*x, 25) + \ + 0x0008 * fp_greaterOrEq(x*x, 25) + \ + 0x0010 * fp_nequal(x*x, 25) + \ + 0x0020 * fp_equal(x*x, 25) diff --git a/tests/20optimizer_optimizations/cmpzz_pow_imm_pospos_base b/tests/20optimizer_optimizations/cmpzz_pow_imm_pospos_base new file mode 100644 index 0000000..34f5918 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_pow_imm_pospos_base @@ -0,0 +1,24 @@ +T=d ld f mf cd cf cld +V=x +R=-6,6,1 + +# Combine tests: +# cmplt_pow_imm_pospos_base +# cmple_pow_imm_pospos_base +# cmpgt_pow_imm_pospos_base +# cmpge_pow_imm_pospos_base +# cmpne_pow_imm_pospos_base +# cmpeq_pow_imm_pospos_base + +F=0x0001 * (5.0625 < pow(1.5,x)) + \ + 0x0002 * (5.0625 <= pow(1.5,x)) + \ + 0x0004 * (5.0625 > pow(1.5,x)) + \ + 0x0008 * (5.0625 >= pow(1.5,x)) + \ + 0x0010 * (5.0625 != pow(1.5,x)) + \ + 0x0020 * (5.0625 = pow(1.5,x)) +C=0x0001 * fp_less(5.0625, fp_pow(1.5,x)) + \ + 0x0002 * fp_lessOrEq(5.0625, fp_pow(1.5,x)) + \ + 0x0004 * fp_greater(5.0625, fp_pow(1.5,x)) + \ + 0x0008 * fp_greaterOrEq(5.0625, fp_pow(1.5,x)) + \ + 0x0010 * fp_nequal(5.0625, fp_pow(1.5,x)) + \ + 0x0020 * fp_equal(5.0625, fp_pow(1.5,x)) diff --git a/tests/20optimizer_optimizations/cmpzz_powpow_imm_base b/tests/20optimizer_optimizations/cmpzz_powpow_imm_base new file mode 100644 index 0000000..f5d59c8 --- /dev/null +++ b/tests/20optimizer_optimizations/cmpzz_powpow_imm_base @@ -0,0 +1,24 @@ +T=d ld f mf cd cf cld +V=x,y +R=-6,6,1 + +# Combine tests: +# cmplt_powpow_imm_base +# cmple_powpow_imm_base +# cmpgt_powpow_imm_base +# cmpge_powpow_imm_base +# cmpne_powpow_imm_base +# cmpeq_powpow_imm_base + +F=0x0001 * (pow(2,x) < pow(-4,y)) + \ + 0x0002 * (pow(2,x) <= pow(-4,y)) + \ + 0x0004 * (pow(2,x) > pow(-4,y)) + \ + 0x0008 * (pow(2,x) >= pow(-4,y)) + \ + 0x0010 * (pow(2,x) != pow(-4,y)) + \ + 0x0020 * (pow(2,x) = pow(-4,y)) +C=0x0001 * fp_less(fp_pow(2,x), fp_pow(-4,y)) + \ + 0x0002 * fp_lessOrEq(fp_pow(2,x), fp_pow(-4,y)) + \ + 0x0004 * fp_greater(fp_pow(2,x), fp_pow(-4,y)) + \ + 0x0008 * fp_greaterOrEq(fp_pow(2,x), fp_pow(-4,y)) + \ + 0x0010 * fp_nequal(fp_pow(2,x), fp_pow(-4,y)) + \ + 0x0020 * fp_equal(fp_pow(2,x), fp_pow(-4,y)) diff --git a/tests/20optimizer_optimizations/eq0 b/tests/20optimizer_optimizations/eq0 new file mode 100644 index 0000000..387a914 --- /dev/null +++ b/tests/20optimizer_optimizations/eq0 @@ -0,0 +1,6 @@ +T=d f ld li cd cf cld +V=x +R=0,1,1 +F=(x=if(1,0,0)) + (if(1,0,0)=x) +C=fp_equal(x,0) + fp_equal(0,x) + diff --git a/tests/20optimizer_optimizations/eq1 b/tests/20optimizer_optimizations/eq1 new file mode 100644 index 0000000..cd2e6a9 --- /dev/null +++ b/tests/20optimizer_optimizations/eq1 @@ -0,0 +1,6 @@ +T=d f ld li cd cf cld +V=x +R=0,1,1 +F=(!x=if(1,1,1)) +C=fp_equal(fp_not(x),1) + diff --git a/tests/20optimizer_optimizations/expexp_a b/tests/20optimizer_optimizations/expexp_a new file mode 100644 index 0000000..85deaad --- /dev/null +++ b/tests/20optimizer_optimizations/expexp_a @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y +R=-2,2,0.5 +F=exp(x*2 + y*3) +C=fp_exp(x*2 + y*3) diff --git a/tests/20optimizer_optimizations/expexp_b b/tests/20optimizer_optimizations/expexp_b new file mode 100644 index 0000000..8b2b589 --- /dev/null +++ b/tests/20optimizer_optimizations/expexp_b @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y,z +R=-2,2,0.5 +F=exp(x) * exp(y+z) +C=fp_exp(x) * fp_exp(y+z) diff --git a/tests/20optimizer_optimizations/expexp_c b/tests/20optimizer_optimizations/expexp_c new file mode 100644 index 0000000..c0c2ed3 --- /dev/null +++ b/tests/20optimizer_optimizations/expexp_c @@ -0,0 +1,5 @@ +T=d f ld mf cd cf cld +V=x,y,z +R=-2,2,0.5 +F=exp(x + y*z) +C=fp_exp(x + y*z) diff --git a/tests/20optimizer_optimizations/ge0_abs b/tests/20optimizer_optimizations/ge0_abs new file mode 100644 index 0000000..fb944cb --- /dev/null +++ b/tests/20optimizer_optimizations/ge0_abs @@ -0,0 +1,11 @@ +T=d f ld li cd cf cld +V=x +R=-1,1,1 +F=(abs(x) >= if(1,0,0)) + \ + 2*(if(1,0,0) <= abs(x)) + \ + 4*(abs(x) <= if(1,0,0)) + \ + 8*(if(1,0,0) >= abs(x)) +C=fp_greaterOrEq(fp_abs(x), 0) + \ + 2*fp_lessOrEq(0, fp_abs(x)) + \ + 4*fp_lessOrEq(fp_abs(x), 0) + \ + 8*fp_greaterOrEq(0, fp_abs(x)) diff --git a/tests/20optimizer_optimizations/ge1_abs b/tests/20optimizer_optimizations/ge1_abs new file mode 100644 index 0000000..829851c --- /dev/null +++ b/tests/20optimizer_optimizations/ge1_abs @@ -0,0 +1,11 @@ +T=d f ld li cd cf cld +V=x +R=-1,1,1 +F=(abs(x) >= if(1,1,1)) + \ + 2*(if(1,1,1) <= abs(x)) + \ + 4*(abs(x) <= if(1,1,1)) + \ + 8*(if(1,1,1) >= abs(x)) +C=fp_greaterOrEq(fp_abs(x), 1) + \ + 2*fp_lessOrEq(1, fp_abs(x)) + \ + 4*fp_lessOrEq(fp_abs(x), 1) + \ + 8*fp_greaterOrEq(1, fp_abs(x)) diff --git a/tests/20optimizer_optimizations/ge_and_eq b/tests/20optimizer_optimizations/ge_and_eq new file mode 100644 index 0000000..bd7dde6 --- /dev/null +++ b/tests/20optimizer_optimizations/ge_and_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x >= y) & (x = y) +C= x == y diff --git a/tests/20optimizer_optimizations/ge_and_le b/tests/20optimizer_optimizations/ge_and_le new file mode 100644 index 0000000..5987471 --- /dev/null +++ b/tests/20optimizer_optimizations/ge_and_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x >= y) & (x <= y) +C= x == y diff --git a/tests/20optimizer_optimizations/ge_and_ne b/tests/20optimizer_optimizations/ge_and_ne new file mode 100644 index 0000000..60c3649 --- /dev/null +++ b/tests/20optimizer_optimizations/ge_and_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x >= y) & (x != y) +C= x > y diff --git a/tests/20optimizer_optimizations/ge_or_eq b/tests/20optimizer_optimizations/ge_or_eq new file mode 100644 index 0000000..b47128a --- /dev/null +++ b/tests/20optimizer_optimizations/ge_or_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x >= y) | (x = y) +C= x >= y diff --git a/tests/20optimizer_optimizations/ge_or_le b/tests/20optimizer_optimizations/ge_or_le new file mode 100644 index 0000000..8dbe3cb --- /dev/null +++ b/tests/20optimizer_optimizations/ge_or_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x >= y) | (x <= y) +C= x*0+y*0+ 1 diff --git a/tests/20optimizer_optimizations/ge_or_ne b/tests/20optimizer_optimizations/ge_or_ne new file mode 100644 index 0000000..e1fe3d0 --- /dev/null +++ b/tests/20optimizer_optimizations/ge_or_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x >= y) | (x != y) +C= x*0+y*0+ 1 diff --git a/tests/20optimizer_optimizations/gehalf b/tests/20optimizer_optimizations/gehalf new file mode 100644 index 0000000..43c533b --- /dev/null +++ b/tests/20optimizer_optimizations/gehalf @@ -0,0 +1,5 @@ +T=d f cd cf +V=x +R=-1,1,0.25 +F=x>=if(1,0.5,0) +C=fp_greaterOrEq(x, 0.5) diff --git a/tests/20optimizer_optimizations/gt0_abs b/tests/20optimizer_optimizations/gt0_abs new file mode 100644 index 0000000..8e4d4dc --- /dev/null +++ b/tests/20optimizer_optimizations/gt0_abs @@ -0,0 +1,11 @@ +T=d f ld li cd cf cld +V=x +R=-1,1,1 +F=(abs(x) > if(1,0,0)) + \ + 2*(if(1,0,0) < abs(x)) + \ + 4*(abs(x) < if(1,0,0)) + \ + 8*(if(1,0,0) > abs(x)) +C=fp_greater(fp_abs(x), 0) + \ + 2*fp_less(0, fp_abs(x)) + \ + 4*fp_less(fp_abs(x), 0) + \ + 8*fp_greater(0, fp_abs(x)) diff --git a/tests/20optimizer_optimizations/gt1_abs b/tests/20optimizer_optimizations/gt1_abs new file mode 100644 index 0000000..63bc1e3 --- /dev/null +++ b/tests/20optimizer_optimizations/gt1_abs @@ -0,0 +1,11 @@ +T=d f ld li cd cf cld +V=x +R=-1,1,1 +F=(abs(x) > if(1,1,1)) + \ + 2*(if(1,1,1) < abs(x)) + \ + 4*(abs(x) < if(1,1,1)) + \ + 8*(if(1,1,1) > abs(x)) +C=fp_greater(fp_abs(x), 1) + \ + 2*fp_less(1, fp_abs(x)) + \ + 4*fp_less(fp_abs(x), 1) + \ + 8*fp_greater(1, fp_abs(x)) diff --git a/tests/20optimizer_optimizations/gt_and_eq b/tests/20optimizer_optimizations/gt_and_eq new file mode 100644 index 0000000..d6681dc --- /dev/null +++ b/tests/20optimizer_optimizations/gt_and_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) & (x = y) +C= x*0+y*0+ 0 diff --git a/tests/20optimizer_optimizations/gt_and_ge b/tests/20optimizer_optimizations/gt_and_ge new file mode 100644 index 0000000..f93a6ea --- /dev/null +++ b/tests/20optimizer_optimizations/gt_and_ge @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) & (x >= y) +C= x > y diff --git a/tests/20optimizer_optimizations/gt_and_le b/tests/20optimizer_optimizations/gt_and_le new file mode 100644 index 0000000..d47b61e --- /dev/null +++ b/tests/20optimizer_optimizations/gt_and_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) & (x <= y) +C= x*0+y*0+ 0 diff --git a/tests/20optimizer_optimizations/gt_and_ne b/tests/20optimizer_optimizations/gt_and_ne new file mode 100644 index 0000000..3dcbe48 --- /dev/null +++ b/tests/20optimizer_optimizations/gt_and_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) & (x != y) +C= x > y diff --git a/tests/20optimizer_optimizations/gt_or_eq b/tests/20optimizer_optimizations/gt_or_eq new file mode 100644 index 0000000..92ae8c3 --- /dev/null +++ b/tests/20optimizer_optimizations/gt_or_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) | (x = y) +C= x >= y diff --git a/tests/20optimizer_optimizations/gt_or_ge b/tests/20optimizer_optimizations/gt_or_ge new file mode 100644 index 0000000..2b0f179 --- /dev/null +++ b/tests/20optimizer_optimizations/gt_or_ge @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) | (x >= y) +C= x >= y diff --git a/tests/20optimizer_optimizations/gt_or_le b/tests/20optimizer_optimizations/gt_or_le new file mode 100644 index 0000000..a7fb818 --- /dev/null +++ b/tests/20optimizer_optimizations/gt_or_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) | (x <= y) +C= x*0+y*0+ 1 diff --git a/tests/20optimizer_optimizations/gt_or_ne b/tests/20optimizer_optimizations/gt_or_ne new file mode 100644 index 0000000..8c146f4 --- /dev/null +++ b/tests/20optimizer_optimizations/gt_or_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x > y) | (x != y) +C= x != y diff --git a/tests/20optimizer_optimizations/if10 b/tests/20optimizer_optimizations/if10 new file mode 100644 index 0000000..7e997fa --- /dev/null +++ b/tests/20optimizer_optimizations/if10 @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x +R=0,1,1 +F=if(x,1,0) + 10*if(x,0,1) + 100*if(x>0,1,0) + 1000*if(x>0,0,1) +C=fp_notNot(x) + 10*fp_not(x) + 100*fp_greater(x,0) + 1000*fp_lessOrEq(x,0) diff --git a/tests/20optimizer_optimizations/if_extract_abs b/tests/20optimizer_optimizations/if_extract_abs new file mode 100644 index 0000000..bd8fffc --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_abs @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, abs(x+2), abs(y+5)) +C=fp_abs(fp_truth(x)!=0 ? (x+2) : (y+5)) diff --git a/tests/20optimizer_optimizations/if_extract_add b/tests/20optimizer_optimizations/if_extract_add new file mode 100644 index 0000000..8a6a356 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_add @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, y+2, y+5) +C=y + (fp_truth(x)!=0 ? 2 : 5) diff --git a/tests/20optimizer_optimizations/if_extract_add1 b/tests/20optimizer_optimizations/if_extract_add1 new file mode 100644 index 0000000..f9e5f64 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_add1 @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, y+2, y) +C=fp_truth(x)!=0 ? (y+2) : y diff --git a/tests/20optimizer_optimizations/if_extract_add2 b/tests/20optimizer_optimizations/if_extract_add2 new file mode 100644 index 0000000..117d839 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_add2 @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, y, y+2) +C=fp_truth(x)!=0 ? y : (y+2) diff --git a/tests/20optimizer_optimizations/if_extract_and1_l b/tests/20optimizer_optimizations/if_extract_and1_l new file mode 100644 index 0000000..c4fe4ee --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_and1_l @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, y&z, y<1) +C=fp_truth(x)!=0 ? fp_and(y,z) : fp_less(y,1) diff --git a/tests/20optimizer_optimizations/if_extract_and1_nl b/tests/20optimizer_optimizations/if_extract_and1_nl new file mode 100644 index 0000000..6b6429c --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_and1_nl @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, y&z, z) +C=fp_truth(x)!=0 ? fp_and(y,z) : z diff --git a/tests/20optimizer_optimizations/if_extract_and2_l b/tests/20optimizer_optimizations/if_extract_and2_l new file mode 100644 index 0000000..19944c1 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_and2_l @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, y<1, y&z) +C=fp_truth(x)!=0 ? fp_less(y,1) : fp_and(y,z) diff --git a/tests/20optimizer_optimizations/if_extract_and2_nl b/tests/20optimizer_optimizations/if_extract_and2_nl new file mode 100644 index 0000000..b4540d6 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_and2_nl @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, z, y&z) +C=fp_truth(x)!=0 ? z : fp_and(y,z) diff --git a/tests/20optimizer_optimizations/if_extract_div b/tests/20optimizer_optimizations/if_extract_div new file mode 100644 index 0000000..08b42ac --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_div @@ -0,0 +1,5 @@ +T=li gi +V=x,y +R=-2,2,1 +F=if(x, y/x, y/2) +C=y / (fp_truth(x)!=0 ? x : 2) diff --git a/tests/20optimizer_optimizations/if_extract_min b/tests/20optimizer_optimizations/if_extract_min new file mode 100644 index 0000000..5a7e9fa --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_min @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, min(y,2), min(y,5)) +C=fp_min(y, (fp_truth(x)!=0 ? 2 : 5)) diff --git a/tests/20optimizer_optimizations/if_extract_mul b/tests/20optimizer_optimizations/if_extract_mul new file mode 100644 index 0000000..5b46336 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_mul @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, y*2, y*5) +C=y * (fp_truth(x)!=0 ? 2 : 5) diff --git a/tests/20optimizer_optimizations/if_extract_mul1 b/tests/20optimizer_optimizations/if_extract_mul1 new file mode 100644 index 0000000..34b2f22 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_mul1 @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, y*2, y) +C=fp_truth(x)!=0 ? (y*2) : y diff --git a/tests/20optimizer_optimizations/if_extract_mul2 b/tests/20optimizer_optimizations/if_extract_mul2 new file mode 100644 index 0000000..b943e7b --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_mul2 @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=if(x, y, y*2) +C=fp_truth(x)!=0 ? y : (y*2) diff --git a/tests/20optimizer_optimizations/if_extract_or1_l b/tests/20optimizer_optimizations/if_extract_or1_l new file mode 100644 index 0000000..f26e021 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_or1_l @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, y|z, y<1) +C=fp_truth(x)!=0 ? fp_or(y,z) : fp_less(y,1) diff --git a/tests/20optimizer_optimizations/if_extract_or1_nl b/tests/20optimizer_optimizations/if_extract_or1_nl new file mode 100644 index 0000000..98f73a9 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_or1_nl @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, y|z, z) +C=fp_truth(x)!=0 ? fp_or(y,z) : z diff --git a/tests/20optimizer_optimizations/if_extract_or2_l b/tests/20optimizer_optimizations/if_extract_or2_l new file mode 100644 index 0000000..bbfbf47 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_or2_l @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, y<1, y|z) +C=fp_truth(x)!=0 ? fp_less(y,1) : fp_or(y,z) diff --git a/tests/20optimizer_optimizations/if_extract_or2_nl b/tests/20optimizer_optimizations/if_extract_or2_nl new file mode 100644 index 0000000..28fe68a --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_or2_nl @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=-1,1,1 +F=if(x, z, y|z) +C=fp_truth(x)!=0 ? z : fp_or(y,z) diff --git a/tests/20optimizer_optimizations/if_extract_sin b/tests/20optimizer_optimizations/if_extract_sin new file mode 100644 index 0000000..2b4f511 --- /dev/null +++ b/tests/20optimizer_optimizations/if_extract_sin @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-4,4,0.5 +F=if(x, sin(y), sin(x)) +C=fp_sin(fp_truth(x)!=0 ? y : x) diff --git a/tests/20optimizer_optimizations/if_join_add b/tests/20optimizer_optimizations/if_join_add new file mode 100644 index 0000000..94e213d --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_add @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=3,5,0.5 +F=if(x<4, sin(y),cos(y+1)) + if(x<4, cos(y),sin(y+1)) +C=fp_less(x,4)!=0 ? (fp_sin(y)+fp_cos(y)) : (fp_cos(y+1)+fp_sin(y+1)) diff --git a/tests/20optimizer_optimizations/if_join_add2 b/tests/20optimizer_optimizations/if_join_add2 new file mode 100644 index 0000000..fc02b59 --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_add2 @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=x +R=3,5,1 +F=x + 10 + if(x<4, 3,4) +C=x + (fp_less(x,4)!=0 ? 13 : 14) diff --git a/tests/20optimizer_optimizations/if_join_and b/tests/20optimizer_optimizations/if_join_and new file mode 100644 index 0000000..494d961 --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_and @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=3,5,0.5 +F=if(x<4, sin(y),cos(y+1)) & if(x<4, cos(y),sin(y+1)) +C=fp_less(x,4)!=0 ? fp_and(fp_sin(y),fp_cos(y)) : fp_and(fp_cos(y+1),fp_sin(y+1)) diff --git a/tests/20optimizer_optimizations/if_join_max b/tests/20optimizer_optimizations/if_join_max new file mode 100644 index 0000000..ce27bed --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_max @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=3,5,0.5 +F=max(if(x<4, sin(y),cos(y+1)), if(x<4, cos(y),sin(y+1))) +C=fp_less(x,4)!=0 ? fp_max(fp_sin(y),fp_cos(y)) : fp_max(fp_cos(y+1),fp_sin(y+1)) diff --git a/tests/20optimizer_optimizations/if_join_min b/tests/20optimizer_optimizations/if_join_min new file mode 100644 index 0000000..e00c0a5 --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_min @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=3,5,0.5 +F=min(if(x<4, sin(y),cos(y+1)), if(x<4, cos(y),sin(y+1))) +C=fp_less(x,4)!=0 ? fp_min(fp_sin(y),fp_cos(y)) : fp_min(fp_cos(y+1),fp_sin(y+1)) diff --git a/tests/20optimizer_optimizations/if_join_mul b/tests/20optimizer_optimizations/if_join_mul new file mode 100644 index 0000000..bf780ae --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_mul @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=3,5,0.5 +F=if(x<4, sin(y),cos(y+1)) * if(x<4, cos(y),sin(y+1)) +C=fp_less(x,4)!=0 ? (fp_sin(y)*fp_cos(y)) : (fp_cos(y+1)*fp_sin(y+1)) diff --git a/tests/20optimizer_optimizations/if_join_mul2 b/tests/20optimizer_optimizations/if_join_mul2 new file mode 100644 index 0000000..056a18f --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_mul2 @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=x +R=3,5,1 +F=x * 10 * if(x<4, 3,4) +C=x * (fp_less(x,4)!=0 ? 30 : 40) diff --git a/tests/20optimizer_optimizations/if_join_or b/tests/20optimizer_optimizations/if_join_or new file mode 100644 index 0000000..68ed720 --- /dev/null +++ b/tests/20optimizer_optimizations/if_join_or @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=3,5,0.5 +F=if(x<4, sin(y),cos(y+1)) | if(x<4, cos(y),sin(y+1)) +C=fp_less(x,4)!=0 ? fp_or(fp_sin(y),fp_cos(y)) : fp_or(fp_cos(y+1),fp_sin(y+1)) diff --git a/tests/20optimizer_optimizations/ifabs b/tests/20optimizer_optimizations/ifabs new file mode 100644 index 0000000..a0c78db --- /dev/null +++ b/tests/20optimizer_optimizations/ifabs @@ -0,0 +1,21 @@ +T=d ld li f mf gi cd cf cld +V=x +R=-1,1,1 +F= 1*(5+if(x< 0,-x,x)) + \ + 10*(5+if(x<=0,-x,x)) + \ + 100*(5+if(x> 0,-x,x)) + \ + 1000*(5+if(x>=0,-x,x)) + \ + 10000*(5+if(x< 0,x,-x)) + \ + 100000*(5+if(x<=0,x,-x)) + \ + 1000000*(5+if(x> 0,x,-x)) + \ + 10000000*(5+if(x>=0,x,-x)) +C= 1*(5+(fp_less(x, 0)!=0?-x:x)) + \ + 10*(5+(fp_lessOrEq(x, 0)!=0?-x:x)) + \ + 100*(5+(fp_greater(x, 0)!=0?-x:x)) + \ + 1000*(5+(fp_greaterOrEq(x,0)!=0?-x:x)) + \ + 10000*(5+(fp_less(x, 0)!=0?x:-x)) + \ + 100000*(5+(fp_lessOrEq(x, 0)!=0?x:-x)) + \ + 1000000*(5+(fp_greater(x, 0)!=0?x:-x)) + \ + 10000000*(5+(fp_greaterOrEq(x,0)!=0?x:-x)) + +# Expected result: 55555555+10888911*abs(x) diff --git a/tests/20optimizer_optimizations/ifabsnot b/tests/20optimizer_optimizations/ifabsnot new file mode 100644 index 0000000..599e620 --- /dev/null +++ b/tests/20optimizer_optimizations/ifabsnot @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y,z +R=-1,1,0.5 +F=if(!(sin(x)+1.2), y,z) +C=fp_truth(fp_sin(x)+1.2)!=0 ? z:y diff --git a/tests/20optimizer_optimizations/ifconst b/tests/20optimizer_optimizations/ifconst new file mode 100644 index 0000000..19c4577 --- /dev/null +++ b/tests/20optimizer_optimizations/ifconst @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y,z +R=-1,1,0.5 +F=if(1, x,y) + if(0,z,y) +C=x+y+z*0 diff --git a/tests/20optimizer_optimizations/ififconst b/tests/20optimizer_optimizations/ififconst new file mode 100644 index 0000000..4187213 --- /dev/null +++ b/tests/20optimizer_optimizations/ififconst @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=w,x,y,z +R=0,1,1 +F=if(if(x,1,y),z,w) + if(if(w,z,0),x,y) +C=(fp_truth(fp_truth(x)!=0 ? 1 : y)!=0 ? z : w) + (fp_truth(fp_truth(w)!=0 ? z : 0)!=0 ? x : y) diff --git a/tests/20optimizer_optimizations/ifmerge b/tests/20optimizer_optimizations/ifmerge new file mode 100644 index 0000000..9bacd1c --- /dev/null +++ b/tests/20optimizer_optimizations/ifmerge @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=b,d,x,y +R=-1,1,1 +F=if(x,if(y,x,b),if(y,x,d)) + \ + if(b,if(d,y,x),if(d,b,x)) +C=(fp_truth(x)!=0 ? (fp_truth(y)!=0?x:b) : (fp_truth(y)!=0?x:d)) + \ + (fp_truth(b)!=0 ? (fp_truth(d)!=0?y:x) : (fp_truth(d)!=0?b:x)) diff --git a/tests/20optimizer_optimizations/ifmerge2 b/tests/20optimizer_optimizations/ifmerge2 new file mode 100644 index 0000000..37de7f5 --- /dev/null +++ b/tests/20optimizer_optimizations/ifmerge2 @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=a,b,x,y +R=-1,1,1 +F=if(x,if(y,a,b),if(b,a,b)) +C=(fp_truth(x)!=0 ? (fp_truth(y)!=0?a:b) : (fp_truth(b)!=0?a:b)) diff --git a/tests/20optimizer_optimizations/ifmerge2b b/tests/20optimizer_optimizations/ifmerge2b new file mode 100644 index 0000000..d54d357 --- /dev/null +++ b/tests/20optimizer_optimizations/ifmerge2b @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=a,b,x,y +R=-1,1,1 +F=if(x,if(y,a,b),if(b,b,a)) +C=(fp_truth(x)!=0 ? (fp_truth(y)!=0?a:b) : (fp_truth(b)!=0?b:a)) diff --git a/tests/20optimizer_optimizations/ifnop b/tests/20optimizer_optimizations/ifnop new file mode 100644 index 0000000..586f6ac --- /dev/null +++ b/tests/20optimizer_optimizations/ifnop @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=x,y +R=0,1,1 +F=if(x,y,y) +C=x*0+y diff --git a/tests/20optimizer_optimizations/ifnot b/tests/20optimizer_optimizations/ifnot new file mode 100644 index 0000000..a3aa4d6 --- /dev/null +++ b/tests/20optimizer_optimizations/ifnot @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y,z +R=0,1,1 +F=if(!x, y,z) +C=fp_truth(x)!=0 ? z : y diff --git a/tests/20optimizer_optimizations/l_abs b/tests/20optimizer_optimizations/l_abs new file mode 100644 index 0000000..fef54b4 --- /dev/null +++ b/tests/20optimizer_optimizations/l_abs @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-4,4,1 +F=(x+2) & abs(x) & (y+2) +C=fp_and(x+2, fp_and(fp_abs(x), y+2)) diff --git a/tests/20optimizer_optimizations/l_mulabs b/tests/20optimizer_optimizations/l_mulabs new file mode 100644 index 0000000..465fbd7 --- /dev/null +++ b/tests/20optimizer_optimizations/l_mulabs @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-4,4,1 +F=(x*abs(y)) & (y+2) +C=fp_and(x*y*fp_abs(y), y+2) diff --git a/tests/20optimizer_optimizations/l_mulneg b/tests/20optimizer_optimizations/l_mulneg new file mode 100644 index 0000000..5e55817 --- /dev/null +++ b/tests/20optimizer_optimizations/l_mulneg @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-4,4,1 +F=(x*y*-5) & (y+2) +C=fp_and(x*y*-5, y+2) diff --git a/tests/20optimizer_optimizations/l_notnot b/tests/20optimizer_optimizations/l_notnot new file mode 100644 index 0000000..abec0b3 --- /dev/null +++ b/tests/20optimizer_optimizations/l_notnot @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-4,4,1 +F=(x+2) & !!x & (y+2) +C=fp_and(x+2, fp_and(fp_notNot(x), y+2)) diff --git a/tests/20optimizer_optimizations/le_and_eq b/tests/20optimizer_optimizations/le_and_eq new file mode 100644 index 0000000..b13ffe8 --- /dev/null +++ b/tests/20optimizer_optimizations/le_and_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x <= y) & (x = y) +C= x == y diff --git a/tests/20optimizer_optimizations/le_and_ne b/tests/20optimizer_optimizations/le_and_ne new file mode 100644 index 0000000..029cba0 --- /dev/null +++ b/tests/20optimizer_optimizations/le_and_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x <= y) & (x != y) +C= x < y diff --git a/tests/20optimizer_optimizations/le_or_eq b/tests/20optimizer_optimizations/le_or_eq new file mode 100644 index 0000000..41e9649 --- /dev/null +++ b/tests/20optimizer_optimizations/le_or_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x <= y) | (x = y) +C= x <= y diff --git a/tests/20optimizer_optimizations/le_or_ne b/tests/20optimizer_optimizations/le_or_ne new file mode 100644 index 0000000..5d673ec --- /dev/null +++ b/tests/20optimizer_optimizations/le_or_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x <= y) | (x != y) +C= x*0+y*0+ 1 diff --git a/tests/20optimizer_optimizations/lt_and_eq b/tests/20optimizer_optimizations/lt_and_eq new file mode 100644 index 0000000..601c72a --- /dev/null +++ b/tests/20optimizer_optimizations/lt_and_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) & (x = y) +C= x*0+y*0+ 0 diff --git a/tests/20optimizer_optimizations/lt_and_ge b/tests/20optimizer_optimizations/lt_and_ge new file mode 100644 index 0000000..6afe346 --- /dev/null +++ b/tests/20optimizer_optimizations/lt_and_ge @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) & (x >= y) +C= x*0+y*0+ 0 diff --git a/tests/20optimizer_optimizations/lt_and_gt b/tests/20optimizer_optimizations/lt_and_gt new file mode 100644 index 0000000..bc33ed0 --- /dev/null +++ b/tests/20optimizer_optimizations/lt_and_gt @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) & (x > y) +C= x*0+y*0+ 0 diff --git a/tests/20optimizer_optimizations/lt_and_le b/tests/20optimizer_optimizations/lt_and_le new file mode 100644 index 0000000..9d9dc03 --- /dev/null +++ b/tests/20optimizer_optimizations/lt_and_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) & (x <= y) +C= x < y diff --git a/tests/20optimizer_optimizations/lt_and_ne b/tests/20optimizer_optimizations/lt_and_ne new file mode 100644 index 0000000..42574d3 --- /dev/null +++ b/tests/20optimizer_optimizations/lt_and_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) & (x != y) +C= x < y diff --git a/tests/20optimizer_optimizations/lt_or_eq b/tests/20optimizer_optimizations/lt_or_eq new file mode 100644 index 0000000..82e1f7a --- /dev/null +++ b/tests/20optimizer_optimizations/lt_or_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) | (x = y) +C= x <= y diff --git a/tests/20optimizer_optimizations/lt_or_ge b/tests/20optimizer_optimizations/lt_or_ge new file mode 100644 index 0000000..1aaa9c2 --- /dev/null +++ b/tests/20optimizer_optimizations/lt_or_ge @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) | (x >= y) +C= x*0+y*0+ 1 diff --git a/tests/20optimizer_optimizations/lt_or_gt b/tests/20optimizer_optimizations/lt_or_gt new file mode 100644 index 0000000..bed9d85 --- /dev/null +++ b/tests/20optimizer_optimizations/lt_or_gt @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) | (x > y) +C= x != y diff --git a/tests/20optimizer_optimizations/lt_or_le b/tests/20optimizer_optimizations/lt_or_le new file mode 100644 index 0000000..6a413b0 --- /dev/null +++ b/tests/20optimizer_optimizations/lt_or_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) | (x <= y) +C= x <= y diff --git a/tests/20optimizer_optimizations/lt_or_ne b/tests/20optimizer_optimizations/lt_or_ne new file mode 100644 index 0000000..47be08d --- /dev/null +++ b/tests/20optimizer_optimizations/lt_or_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= (x < y) | (x != y) +C= x != y diff --git a/tests/20optimizer_optimizations/lthalf b/tests/20optimizer_optimizations/lthalf new file mode 100644 index 0000000..7d5c494 --- /dev/null +++ b/tests/20optimizer_optimizations/lthalf @@ -0,0 +1,5 @@ +T=d f cd cf +V=x +R=-1,1,0.25 +F=x<if(1,0.5,0) +C=fp_less(x, 0.5) diff --git a/tests/20optimizer_optimizations/mergemulabs b/tests/20optimizer_optimizations/mergemulabs new file mode 100644 index 0000000..4fb6cae --- /dev/null +++ b/tests/20optimizer_optimizations/mergemulabs @@ -0,0 +1,5 @@ +T=d ld f mf li gi cd cf cld +V=x,y,z +R=-1,1,1 +F=abs(x)*abs(y)*z +C=fp_abs(x)*fp_abs(y)*z diff --git a/tests/20optimizer_optimizations/mixedminmax b/tests/20optimizer_optimizations/mixedminmax new file mode 100644 index 0000000..107ba60 --- /dev/null +++ b/tests/20optimizer_optimizations/mixedminmax @@ -0,0 +1,13 @@ +T=d ld li f mf gi cd cf cld +V=x,y,z +R=0,4,1 +F=max(z,min(x,max(max(z,y),x))) + \ + 10*min(z,max(x,min(y,x))) + \ + 100*min(max(x,y),min(y,z)) + \ + 1000*max(min(x,y),max(y,z)) +C=fp_max(z,fp_min(x,fp_max(fp_max(z,y),x))) + \ + 10*fp_min(z,fp_max(x,fp_min(y,x))) + \ + 100*fp_min(fp_max(x,y),fp_min(y,z)) + \ + 1000*fp_max(fp_min(x,y),fp_max(y,z)) + +# Expected optimization: max(x,z) + min(x,z)*10 + min(y,z)*100 + max(y,z)*1000 diff --git a/tests/20optimizer_optimizations/muland2 b/tests/20optimizer_optimizations/muland2 new file mode 100644 index 0000000..be619d5 --- /dev/null +++ b/tests/20optimizer_optimizations/muland2 @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-1,1,0.5 +F=!!x * !!y +C=fp_notNot(x) * fp_notNot(y) diff --git a/tests/20optimizer_optimizations/muland2plus b/tests/20optimizer_optimizations/muland2plus new file mode 100644 index 0000000..0593d8d --- /dev/null +++ b/tests/20optimizer_optimizations/muland2plus @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y,z +R=-1,1,0.5 +F=!!x * !!y * z +C=fp_notNot(x) * fp_notNot(y) * z diff --git a/tests/20optimizer_optimizations/muland3 b/tests/20optimizer_optimizations/muland3 new file mode 100644 index 0000000..52fbe19 --- /dev/null +++ b/tests/20optimizer_optimizations/muland3 @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y,z +R=-1,1,0.5 +F=!!x * !!y * !!z +C=fp_notNot(x) * fp_notNot(y) * fp_notNot(z) diff --git a/tests/20optimizer_optimizations/mulandlt b/tests/20optimizer_optimizations/mulandlt new file mode 100644 index 0000000..d65b0de --- /dev/null +++ b/tests/20optimizer_optimizations/mulandlt @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-1,1,0.5 +F=!!x * (y<0) +C=fp_notNot(x) * Value_t(fp_less(y,0)) diff --git a/tests/20optimizer_optimizations/mulimmlog b/tests/20optimizer_optimizations/mulimmlog new file mode 100644 index 0000000..8dbbfbe --- /dev/null +++ b/tests/20optimizer_optimizations/mulimmlog @@ -0,0 +1,11 @@ +T=d ld f mf cd cf cld +V=x,y +R=0.25, 1, 0.25 +F=log(if(1,5,0)*x*y) +C=fp_log(5*x*y) + +# Expected result: log(x*y) + log(5) + +# Using if(1,5,0) to prevent bytecode optimizer +# from doing this optimization. +# The test subject is fpoptimizer. diff --git a/tests/20optimizer_optimizations/mulnor2 b/tests/20optimizer_optimizations/mulnor2 new file mode 100644 index 0000000..7870f8d --- /dev/null +++ b/tests/20optimizer_optimizations/mulnor2 @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x,y +R=-1,1,0.5 +F=!x * !y +C=fp_not(x) * fp_not(y) + +# Expected result: !(x | y) hence NOR diff --git a/tests/20optimizer_optimizations/mulnor2plus b/tests/20optimizer_optimizations/mulnor2plus new file mode 100644 index 0000000..f4ee408 --- /dev/null +++ b/tests/20optimizer_optimizations/mulnor2plus @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x,y,z +R=-1,1,0.5 +F=!x * !y * z +C=fp_not(x) * fp_not(y) * z + +# Expected result: z * !(x | y) hence NOR diff --git a/tests/20optimizer_optimizations/mulnor3 b/tests/20optimizer_optimizations/mulnor3 new file mode 100644 index 0000000..ef7c83d --- /dev/null +++ b/tests/20optimizer_optimizations/mulnor3 @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x,y,z +R=-1,1,0.5 +F=!x * !y * !z +C=fp_not(x) * fp_not(y) * fp_not(z) + +# Expected result: !(x | y | z) hence NOR diff --git a/tests/20optimizer_optimizations/nand2 b/tests/20optimizer_optimizations/nand2 new file mode 100644 index 0000000..1346b09 --- /dev/null +++ b/tests/20optimizer_optimizations/nand2 @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y +R=0,1,1 +F=!x | !y +C=fp_or(fp_not(x),fp_not(y)) + +# Expected result: !(x & y) hence NAND diff --git a/tests/20optimizer_optimizations/nand2plus b/tests/20optimizer_optimizations/nand2plus new file mode 100644 index 0000000..60ad3eb --- /dev/null +++ b/tests/20optimizer_optimizations/nand2plus @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y,z +R=0,1,1 +F=!x | !y | z +C=fp_or(fp_or(fp_not(x),fp_not(y)),z) + +# Expected result: z | !(x & y) hence NAND diff --git a/tests/20optimizer_optimizations/nand3 b/tests/20optimizer_optimizations/nand3 new file mode 100644 index 0000000..8c7880f --- /dev/null +++ b/tests/20optimizer_optimizations/nand3 @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y,z +R=0,1,1 +F=!x | !y | !z +C=fp_or(fp_or(fp_not(x),fp_not(y)), fp_not(z)) + +# Expected result: !(x & y & z) hence NAND diff --git a/tests/20optimizer_optimizations/negceil b/tests/20optimizer_optimizations/negceil new file mode 100644 index 0000000..50ef9f7 --- /dev/null +++ b/tests/20optimizer_optimizations/negceil @@ -0,0 +1,9 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=ceil(x*(abs(x)-abs(x)-1)) +C=fp_ceil(-x) + + +# abs(x)-abs(x)-1 is used to produce a -1 without +# the bytecode optimizer taking a bite of it diff --git a/tests/20optimizer_optimizations/negcos b/tests/20optimizer_optimizations/negcos new file mode 100644 index 0000000..d5b825e --- /dev/null +++ b/tests/20optimizer_optimizations/negcos @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=cos(x*if(1,-1,0)) +C=fp_cos(-x) diff --git a/tests/20optimizer_optimizations/negcosh b/tests/20optimizer_optimizations/negcosh new file mode 100644 index 0000000..7a44ffb --- /dev/null +++ b/tests/20optimizer_optimizations/negcosh @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=cosh(x*if(1,-1,0)) +C=fp_cosh(-x) diff --git a/tests/20optimizer_optimizations/negfloor b/tests/20optimizer_optimizations/negfloor new file mode 100644 index 0000000..930c95a --- /dev/null +++ b/tests/20optimizer_optimizations/negfloor @@ -0,0 +1,9 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=floor(x*(abs(x)-abs(x)-1)) +C=fp_floor(-x) + + +# abs(x)-abs(x)-1 is used to produce a -1 without +# the bytecode optimizer taking a bite of it diff --git a/tests/20optimizer_optimizations/negsin b/tests/20optimizer_optimizations/negsin new file mode 100644 index 0000000..90b3137 --- /dev/null +++ b/tests/20optimizer_optimizations/negsin @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=sin(x*if(1,-1,0)) +C=fp_sin(-x) diff --git a/tests/20optimizer_optimizations/negsinh b/tests/20optimizer_optimizations/negsinh new file mode 100644 index 0000000..5ec6493 --- /dev/null +++ b/tests/20optimizer_optimizations/negsinh @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,1 +F=sinh(x*if(1,-1,0)) +C=fp_sinh(-x) diff --git a/tests/20optimizer_optimizations/neq0 b/tests/20optimizer_optimizations/neq0 new file mode 100644 index 0000000..2812a0f --- /dev/null +++ b/tests/20optimizer_optimizations/neq0 @@ -0,0 +1,5 @@ +T=d f ld li cd cf cld +V=x +R=0,1,1 +F=(x!=if(1,0,0)) + (if(1,0,0)!=x) +C=(fp_nequal(x,0)) + (fp_nequal(0,x)) diff --git a/tests/20optimizer_optimizations/neq1 b/tests/20optimizer_optimizations/neq1 new file mode 100644 index 0000000..3d551ae --- /dev/null +++ b/tests/20optimizer_optimizations/neq1 @@ -0,0 +1,6 @@ +T=d f ld li cd cf cld +V=x +R=0,1,1 +F=(!x!=if(1,1,1)) +C=fp_nequal(fp_not(x),1) + diff --git a/tests/20optimizer_optimizations/nor2 b/tests/20optimizer_optimizations/nor2 new file mode 100644 index 0000000..1610185 --- /dev/null +++ b/tests/20optimizer_optimizations/nor2 @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y +R=0,1,1 +F=!x & !y +C=fp_and(fp_not(x),fp_not(y)) + +# Expected result: !(x | y) hence NOR diff --git a/tests/20optimizer_optimizations/nor2plus b/tests/20optimizer_optimizations/nor2plus new file mode 100644 index 0000000..76f8f97 --- /dev/null +++ b/tests/20optimizer_optimizations/nor2plus @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y,z +R=0,1,1 +F=!x & !y & z +C=fp_and(fp_and(fp_not(x),fp_not(y)),z) + +# Expected result: z & !(x | y) hence NOR diff --git a/tests/20optimizer_optimizations/nor3 b/tests/20optimizer_optimizations/nor3 new file mode 100644 index 0000000..fdce04e --- /dev/null +++ b/tests/20optimizer_optimizations/nor3 @@ -0,0 +1,7 @@ +T=d ld f mf li gi cd cf cld +V=x,y,z +R=0,1,1 +F=!x & !y & !z +C=fp_and(fp_and(fp_not(x),fp_not(y)), fp_not(z)) + +# Expected result: !(x | y | z) hence NOR diff --git a/tests/20optimizer_optimizations/not_eq b/tests/20optimizer_optimizations/not_eq new file mode 100644 index 0000000..5f47e96 --- /dev/null +++ b/tests/20optimizer_optimizations/not_eq @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= if(x = y, 0,1) +C= x != y diff --git a/tests/20optimizer_optimizations/not_ge b/tests/20optimizer_optimizations/not_ge new file mode 100644 index 0000000..f6ef4d6 --- /dev/null +++ b/tests/20optimizer_optimizations/not_ge @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= if(x >= y, 0,1) +C= x < y diff --git a/tests/20optimizer_optimizations/not_gt b/tests/20optimizer_optimizations/not_gt new file mode 100644 index 0000000..beeeffa --- /dev/null +++ b/tests/20optimizer_optimizations/not_gt @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= if(x > y, 0,1) +C= x <= y diff --git a/tests/20optimizer_optimizations/not_le b/tests/20optimizer_optimizations/not_le new file mode 100644 index 0000000..7d5b689 --- /dev/null +++ b/tests/20optimizer_optimizations/not_le @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= if(x <= y, 0,1) +C= x > y diff --git a/tests/20optimizer_optimizations/not_lt b/tests/20optimizer_optimizations/not_lt new file mode 100644 index 0000000..6955276 --- /dev/null +++ b/tests/20optimizer_optimizations/not_lt @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= if(x < y, 0,1) +C= x >= y diff --git a/tests/20optimizer_optimizations/not_ne b/tests/20optimizer_optimizations/not_ne new file mode 100644 index 0000000..ceb2ca6 --- /dev/null +++ b/tests/20optimizer_optimizations/not_ne @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=0,1,1 +F= if(x != y, 0,1) +C= x == y diff --git a/tests/20optimizer_optimizations/notnot b/tests/20optimizer_optimizations/notnot new file mode 100644 index 0000000..ce4f5d7 --- /dev/null +++ b/tests/20optimizer_optimizations/notnot @@ -0,0 +1,5 @@ +T=d ld li f mf gi cd cf cld +V=x,y +R=-2,2,1 +F=!!x + if(y, 1,0) +C=fp_truth(x) + fp_truth(y) diff --git a/tests/20optimizer_optimizations/posnot b/tests/20optimizer_optimizations/posnot new file mode 100644 index 0000000..b6db77e --- /dev/null +++ b/tests/20optimizer_optimizations/posnot @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,0.5 +F=!(sin(x) + 1.2) +C=fp_not(fp_sin(x) + 1.2) + +# Expected optimization: produce cAbsNot diff --git a/tests/20optimizer_optimizations/posnotnot b/tests/20optimizer_optimizations/posnotnot new file mode 100644 index 0000000..737e583 --- /dev/null +++ b/tests/20optimizer_optimizations/posnotnot @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,0.5 +F=!!(sin(x) + 1.2) +C=fp_notNot(fp_sin(x) + 1.2) + +# Expected optimization: produce cAbsNotNot diff --git a/tests/20optimizer_optimizations/powimmaddimmlog b/tests/20optimizer_optimizations/powimmaddimmlog new file mode 100644 index 0000000..f51b94b --- /dev/null +++ b/tests/20optimizer_optimizations/powimmaddimmlog @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x +R=0.25, 1, 0.25 +F=pow(5, log(x)+1) +C=fp_pow(5, fp_log(x)+1) + +# Expected result: 5^1 * x^log(5) diff --git a/tests/20optimizer_optimizations/powimmlog b/tests/20optimizer_optimizations/powimmlog new file mode 100644 index 0000000..40def8e --- /dev/null +++ b/tests/20optimizer_optimizations/powimmlog @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x +R=0.25, 2, 0.25 +F=pow(3, log(x)) + pow(5, log(x)*sin(x)) +C=fp_pow(3, fp_log(x)) + fp_pow(5, fp_log(x)*fp_sin(x)) + +# Expected result: pow(x, log(3)) + pow(x, log(3)*sin(x)) diff --git a/tests/20optimizer_optimizations/powmulimm_fnen b/tests/20optimizer_optimizations/powmulimm_fnen new file mode 100644 index 0000000..3f6c6db --- /dev/null +++ b/tests/20optimizer_optimizations/powmulimm_fnen @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-3,3,2 +F=((-5.1)*x*y)^(-8) +C=fp_pow((-5.1)*x*y, (-8)) diff --git a/tests/20optimizer_optimizations/powmulimm_fnep b/tests/20optimizer_optimizations/powmulimm_fnep new file mode 100644 index 0000000..39f70f7 --- /dev/null +++ b/tests/20optimizer_optimizations/powmulimm_fnep @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-3,3,1 +F=((-5.1)*x*y)^(4) +C=fp_pow((-5.1)*x*y, (4)) diff --git a/tests/20optimizer_optimizations/powmulimm_fnfn b/tests/20optimizer_optimizations/powmulimm_fnfn new file mode 100644 index 0000000..2ab6361 --- /dev/null +++ b/tests/20optimizer_optimizations/powmulimm_fnfn @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x +R=-3,-1,0.5 +F=((-5.1)*x)^(-7.1) +C=fp_pow((-5.1)*x, (-7.1)) diff --git a/tests/20optimizer_optimizations/powmulimm_fnfp b/tests/20optimizer_optimizations/powmulimm_fnfp new file mode 100644 index 0000000..35d1b5f --- /dev/null +++ b/tests/20optimizer_optimizations/powmulimm_fnfp @@ -0,0 +1,5 @@ +T=d ld f mf cd cf cld +V=x,y +R=-3,3,1 +F=((-5.1)*x*y)^7.1 +C=fp_pow((-5.1)*x*y, 7.1) diff --git a/tests/20optimizer_optimizations/powmulimm_fpfp b/tests/20optimizer_optimizations/powmulimm_fpfp new file mode 100644 index 0000000..c1eedb3 --- /dev/null +++ b/tests/20optimizer_optimizations/powmulimm_fpfp @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x,y +R=-3,3,1 +F=(5.1*x*y)^7.1 +C=fp_pow(5.1*x*y, 7.1) + +# Expected result: 5.1^7.1 * (x*y)^7.1 diff --git a/tests/20optimizer_optimizations/sub1cos2 b/tests/20optimizer_optimizations/sub1cos2 new file mode 100644 index 0000000..096ac09 --- /dev/null +++ b/tests/20optimizer_optimizations/sub1cos2 @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,0.5 +F=1-cos(x)^2 +C=1 - fp_pow(fp_cos(x),2) + +# Expected optimization: sin(x)^2 diff --git a/tests/20optimizer_optimizations/sub1sin2 b/tests/20optimizer_optimizations/sub1sin2 new file mode 100644 index 0000000..fa48e2b --- /dev/null +++ b/tests/20optimizer_optimizations/sub1sin2 @@ -0,0 +1,7 @@ +T=d ld f mf cd cf cld +V=x +R=-1,1,0.5 +F=1-sin(x)^2 +C=1 - fp_pow(fp_sin(x),2) + +# Expected optimization: cos(x)^2 diff --git a/tests/20optimizer_optimizations/trig_modulo b/tests/20optimizer_optimizations/trig_modulo new file mode 100644 index 0000000..468421a --- /dev/null +++ b/tests/20optimizer_optimizations/trig_modulo @@ -0,0 +1,35 @@ +T=d ld f mf cd cf cld +V=x +R=-9.42477796076937971538793014983850865259,9.42477796076937971538793014983850865259,0.785398163397448309615660845819875721049292349 +F=cos(x+pi) + cos(x+pi*2/3) + cos(x+pi*5/2) + cos(x+pi*6/2) + cos(x+pi*7/2) + \ + sin(x+pi) + sin(x+pi*2/3) + sin(x+pi*5/2) + sin(x+pi*6/2) + sin(x+pi*7/2) + \ + cos(x-pi) + cos(x-pi*2/3) + cos(x-pi*5/2) + cos(x-pi*6/2) + cos(x-pi*7/2) + \ + sin(x-pi) + sin(x-pi*2/3) + sin(x-pi*5/2) + sin(x-pi*6/2) + sin(x-pi*7/2) +C=fp_cos(x+fp_const_pi<Value_t>()) + \ + fp_cos(x+fp_const_pi<Value_t>()*2/3) + \ + fp_cos(x+fp_const_pi<Value_t>()*5/2) + \ + fp_cos(x+fp_const_pi<Value_t>()*6/2) + \ + fp_cos(x+fp_const_pi<Value_t>()*7/2) + \ + fp_sin(x+fp_const_pi<Value_t>()) + \ + fp_sin(x+fp_const_pi<Value_t>()*2/3) + \ + fp_sin(x+fp_const_pi<Value_t>()*5/2) + \ + fp_sin(x+fp_const_pi<Value_t>()*6/2) + \ + fp_sin(x+fp_const_pi<Value_t>()*7/2) + \ + fp_cos(x-fp_const_pi<Value_t>()) + \ + fp_cos(x-fp_const_pi<Value_t>()*2/3) + \ + fp_cos(x-fp_const_pi<Value_t>()*5/2) + \ + fp_cos(x-fp_const_pi<Value_t>()*6/2) + \ + fp_cos(x-fp_const_pi<Value_t>()*7/2) + \ + fp_sin(x-fp_const_pi<Value_t>()) + \ + fp_sin(x-fp_const_pi<Value_t>()*2/3) + \ + fp_sin(x-fp_const_pi<Value_t>()*5/2) + \ + fp_sin(x-fp_const_pi<Value_t>()*6/2) + \ + fp_sin(x-fp_const_pi<Value_t>()*7/2) + +# Expected optimization: +# cos(x + pi*2/3) +# + cos(x - pi*2/3) +# + sin(x - pi*2/3) +# + sin(x + pi*2/3) +# - 4*sin(x) +# - 4*cos(x) diff --git a/tests/20optimizer_optimizations/trunc_from_if b/tests/20optimizer_optimizations/trunc_from_if new file mode 100644 index 0000000..68bff0d --- /dev/null +++ b/tests/20optimizer_optimizations/trunc_from_if @@ -0,0 +1,12 @@ +T=d ld f mf cd cf cld +V=x +R=-3,3,0.25 +F=if(x>0, floor(x),ceil(x))+\ + if(x>=0, floor(x),ceil(x))+\ + if(x<0, ceil(x),floor(x))+\ + if(x<=0, ceil(x),floor(x))+\ + 10*if(x>0, ceil(x),floor(x))+\ + 10*if(x>=0, ceil(x),floor(x))+\ + 10*if(x<0, floor(x),ceil(x))+\ + 10*if(x<=0, floor(x),ceil(x)) +C=fp_trunc(x)*4 + 40*(x>0?fp_ceil(x):fp_floor(x)) diff --git a/tests/20optimizer_optimizations/xaddnot b/tests/20optimizer_optimizations/xaddnot new file mode 100644 index 0000000..9ab0426 --- /dev/null +++ b/tests/20optimizer_optimizations/xaddnot @@ -0,0 +1,5 @@ +T=d f ld li gi cd cf cld +V=x +R=-5,5,1 +F=!(x+if(1,4,4)) +C=fp_not(x+4) diff --git a/tests/20optimizer_optimizations/xaddnotnot b/tests/20optimizer_optimizations/xaddnotnot new file mode 100644 index 0000000..cf096ec --- /dev/null +++ b/tests/20optimizer_optimizations/xaddnotnot @@ -0,0 +1,5 @@ +T=d f ld li gi cd cf cld +V=x +R=-5,5,1 +F=!!(x+if(1,4,4)) +C=fp_notNot(x+4) diff --git a/tests/21optimizer_trigcombinations/README b/tests/21optimizer_trigcombinations/README new file mode 100644 index 0000000..e44c9ce --- /dev/null +++ b/tests/21optimizer_trigcombinations/README @@ -0,0 +1 @@ +Moved into testbed code. diff --git a/tests/21optimizer_trigcombinations/make.php b/tests/21optimizer_trigcombinations/make.php new file mode 100644 index 0000000..c4239b1 --- /dev/null +++ b/tests/21optimizer_trigcombinations/make.php @@ -0,0 +1,80 @@ +<?php + +function CreateTest($f, $file) +{ + $F = $f; + $C = preg_replace('/(sinh?|cosh?|tanh?|pow|exp)/', 'fp_$1', $f); + + $vars = Array('x'); + #if(strpos($f, '(x)') !== false) $vars[] = 'x'; + #if(strpos($f, '(y)') !== false) $vars[] = 'y'; + + print "$F\n"; + +/* file_put_contents($file, + "T=d\n". + "V=".join(',', $vars)."\n". + "R=-4,4,0.5\n". + "F= $F\n". + "C= $C\n");*/ +} + +$functions = Array('sin','cos','tan','sinh','cosh','tanh','exp'); + +for($operator=0; $operator<2; ++$operator) +for($a=0; $a<7; ++$a) + for($b=$a+1; $b<7; ++$b) + { + $f1 = $functions[$a]; + $f2 = $functions[$b]; + + for($ae=-2; $ae<=2; ++$ae) + for($be=-2; $be<=2; ++$be) + { + if($be == 0 && $ae == 1) continue; // testing the function alone is not very cool + if($ae == 0 && $be == 1) continue; // testing the function alone is not very cool + + if($a < 3 && $f2=='exp') continue; // don't bother mixing exp with sin/cos/tan + if($b < 3 && $f1=='exp') continue; // don't bother mixing exp with sin/cos/tan + + if(!$ae && !$be) continue; + + $afunc = "$f1(x)"; + if($ae == 0) $afunc = "1"; + elseif($ae != 1) $afunc = "pow($afunc,{$ae}.0)"; + + $func = $afunc; + + if($be < 0 && $operator==0) + { + $func .= " / "; + + $bfunc = "$f2(x)"; + if($be == -1) {} + else $bfunc = "pow($bfunc,".(-$be).".0)"; + $func .= $bfunc; + } + else if($be != 0) + { + $func .= ($operator==0 ? " * " : " + "); + + $bfunc = "$f2(x)"; + if($be == 1) {} + else $bfunc = "pow($bfunc,{$be}.0)"; + $func .= $bfunc; + } + + static $counter = 0; + ++$counter; + $name = $counter; + #$op = $operator?'add':'mul'; + #$name = sprintf('%s_%sp%d_%sp%d', $op,$f1,$ae,$f2,$be); + + CreateTest($func, $name); + if(preg_match('/h\(/', $func)) + { + CreateTest(str_replace('(x)', '(x*x)', $func), + ++$counter); + } + } + } diff --git a/tests/50regressions/1 b/tests/50regressions/1 new file mode 100644 index 0000000..217457e --- /dev/null +++ b/tests/50regressions/1 @@ -0,0 +1,7 @@ +# Bug fixed in release version 2.84 + +T=d f ld mf li gi +V=x +R=-10,10,1 +F=x+max(0, min(-2,0)) +C=x+fp_max(0, fp_min(-2,0)) diff --git a/tests/50regressions/10 b/tests/50regressions/10 new file mode 100644 index 0000000..13eac2b --- /dev/null +++ b/tests/50regressions/10 @@ -0,0 +1,6 @@ +# Fixed in commit faae669a9ff6e5557437ab0cd9ce108e27ca5763 +T=d f ld +V=x +R=1,10,1 +F=1/abs(x)<1 +C=1/fp_abs(x)<1 diff --git a/tests/50regressions/11 b/tests/50regressions/11 new file mode 100644 index 0000000..df9aa25 --- /dev/null +++ b/tests/50regressions/11 @@ -0,0 +1,6 @@ +# Fixed in commit 055f1dda1331e8c17829f9651d6052eddc1f61ba +T=d f ld +V=x +R=1e25,10e25,1e25 +F=exp(x/5e+25) +C=fp_exp(x/5e+25) diff --git a/tests/50regressions/2 b/tests/50regressions/2 new file mode 100644 index 0000000..4c6795e --- /dev/null +++ b/tests/50regressions/2 @@ -0,0 +1,7 @@ +# Bug fixed in commit 933cb4b9499535eb2718193897326811e62829a6 + +T=d f ld mf li gi +V=x +R=-10,10,1 +F=min(x,min(1,x)) +C=fp_min(x,fp_min(1,x)) diff --git a/tests/50regressions/3 b/tests/50regressions/3 new file mode 100644 index 0000000..6a7b330 --- /dev/null +++ b/tests/50regressions/3 @@ -0,0 +1,9 @@ +# Bug fixed in commit 6a5cf0e5cbdf96464b17b9784c2b2fd9ff2bd3b9 +# !x & !!x should be 0, became !!x + +T=d f ld mf li gi +V=x +R=-2, 2, 1 +F=sub( (!x & !!x) , (!x | !!x) ) +#C=-1 +C=userDefFuncSub({ fp_and(fp_not(x), fp_notNot(x)), fp_or(fp_not(x), fp_notNot(x)) }) diff --git a/tests/50regressions/36 b/tests/50regressions/36 new file mode 100644 index 0000000..9ba8c4d --- /dev/null +++ b/tests/50regressions/36 @@ -0,0 +1,7 @@ +# See "What's new in v3.0.3" for this regression + +T=d f ld mf li gi +V=x +R=-10,10,1 +F=-if(x<0, x, -x) + -if(x<5, 2, 3) +C=-(x<0 ? x : -x) + -(x<5 ? 2 : 3) diff --git a/tests/50regressions/4 b/tests/50regressions/4 new file mode 100644 index 0000000..8a6196d --- /dev/null +++ b/tests/50regressions/4 @@ -0,0 +1,9 @@ +# Bug fixed in commit d0c31571026723d9c5852a4de33bc7a616a4943e +# sub(!(x-y), !!(x-y)) bugs when double-optimized +# due to buggy CopyOnWrite calling in cSub/cRSub reconstruction + +T=d f ld mf li gi +V=x,y +R=-2, 2, 1 +F=sub(!(x-y), !!(x-y)) +C=userDefFuncSub({ fp_not(x-y), fp_notNot(x-y) }) diff --git a/tests/50regressions/42 b/tests/50regressions/42 new file mode 100644 index 0000000..17e284e --- /dev/null +++ b/tests/50regressions/42 @@ -0,0 +1,7 @@ +# See "What's new in v3.2" for this regression. hypot() is unrelated. + +T=d f ld mf +V=x,y +R=-3,3,.25 +F=sqrt(x*x) + 1.5*((y*y)^.25) + hypot(x,y) +C=fp_sqrt(x*x) + 1.5*(fp_pow(y*y, 0.25)) + fp_hypot(x,y) diff --git a/tests/50regressions/5 b/tests/50regressions/5 new file mode 100644 index 0000000..4e09739 --- /dev/null +++ b/tests/50regressions/5 @@ -0,0 +1,9 @@ +# sin/cos/tan/csc/sec/cot CSE bugs +# Introduced in commit 62b869dd21c1c7fe7ec4fcd846c9e9c12a27a34a +# Fixed in commit b887b5a13b0ca689c208fb01072ac353a048797c + +T=d f ld mf +V=x +R=-0.7, 0.7, 0.28 +F=sub(sin(x)+csc(x),cos(x)) +C=userDefFuncSub({fp_sin(x)+1/fp_sin(x),fp_cos(x)}) diff --git a/tests/50regressions/51 b/tests/50regressions/51 new file mode 100644 index 0000000..a4e9fd2 --- /dev/null +++ b/tests/50regressions/51 @@ -0,0 +1,7 @@ +# See "What's new in v3.2.1" for this regression. + +T=d f ld mf +V=x +R=-100, -1, .5 +F=log(-x) +C=fp_log(-x) diff --git a/tests/50regressions/57 b/tests/50regressions/57 new file mode 100644 index 0000000..bc6bb8c --- /dev/null +++ b/tests/50regressions/57 @@ -0,0 +1,7 @@ +# See "What's new in v4.0.2" for this regression. + +T=d f ld mf +V=x +R=.05, 1.0, .01 +F=cosh(asinh(x)) +C=fp_cosh(fp_asinh(x)) diff --git a/tests/50regressions/59 b/tests/50regressions/59 new file mode 100644 index 0000000..c500899 --- /dev/null +++ b/tests/50regressions/59 @@ -0,0 +1,7 @@ +# See "What's new in v4.0.3" for this regression. + +T=d f ld mf +V=x,y +R=-2, 2, 1.2 +F=cosh(x^2) + tanh(y^2) +C=fp_cosh(x*x) + fp_tanh(y*y) diff --git a/tests/50regressions/6 b/tests/50regressions/6 new file mode 100644 index 0000000..5a9ca87 --- /dev/null +++ b/tests/50regressions/6 @@ -0,0 +1,8 @@ +# Bug: !(x+4) fails on integer types +# Introduced in commit ________ +# Fixed in commit 6461cac2dab474ea091befd3782717ccd573b385 +T=d li gi +V=x +R=-5,5,1 +F=sub(!(x+4), !!(x+3)) +C=userDefFuncSub({fp_not(x+4), fp_notNot(x+3)}) diff --git a/tests/50regressions/60 b/tests/50regressions/60 new file mode 100644 index 0000000..d8244bd --- /dev/null +++ b/tests/50regressions/60 @@ -0,0 +1,7 @@ +# Bug fixed in release version 4.0.4 + +T=d f ld mf li gi +V=x,y +R=-2, 2, 1 +F=sqr(x) | sub(x,y) | value() +C=fp_or(fp_or(userDefFuncSqr({x}), userDefFuncSub({x,y})), userDefFuncValue({})) diff --git a/tests/50regressions/61 b/tests/50regressions/61 new file mode 100644 index 0000000..cf5b4c7 --- /dev/null +++ b/tests/50regressions/61 @@ -0,0 +1,11 @@ +# Bug: positiveinteger*terms1 + -sameinteger*terms2 incorrectly ungroups the terms in terms1 +# Fixed in commit 11d99dabc69750b8ac232570b3e523b026c51a2a + +T=f d li +V=x,y,z +R=-3,3,2 +F=5*x*y + -5*z +C=5*x*y + -5*z + +# Expected result: (x*y-z)*5 +# Erroneous result: ((x+y)-z)*5 diff --git a/tests/50regressions/7 b/tests/50regressions/7 new file mode 100644 index 0000000..b5b5776 --- /dev/null +++ b/tests/50regressions/7 @@ -0,0 +1,9 @@ +# Bug: x>7 & x<2 (which should produce 0) was wrongly optimized +# with the same rule that works for e.g. x>7 & x<13 +# Introduced in commit ________ +# Fixed in commit e42268a289f256104c01c15873f2d63eac3a95b2 +T=d li +V=x +R=-9,9,1 +F=x>7 & x<2 +C=x-x diff --git a/tests/50regressions/8 b/tests/50regressions/8 new file mode 100644 index 0000000..4b41b45 --- /dev/null +++ b/tests/50regressions/8 @@ -0,0 +1,8 @@ +# Bug: atan2(-x,-y) wrongly optimized to atan2(x,y) +# Introduced in commit ff12195f506cb3138067ee0e467ead97cdaca322 +# Fixed in commit 907b889a93e4b93b0dc501fb904f471744c779e4 +T=d f +V=x,y +R=-9,9,1 +F=atan2(-x,-y) + 10*atan2(-x,y) + 20*atan2(x,-y) + 30*atan2(x,y) +C=fp_atan2(-x,-y) + 10*fp_atan2(-x,y) + 20*fp_atan2(x,-y) + 30*fp_atan2(x,y) diff --git a/tests/50regressions/9a b/tests/50regressions/9a new file mode 100644 index 0000000..9ddf3d4 --- /dev/null +++ b/tests/50regressions/9a @@ -0,0 +1,8 @@ +# Bug: a:=x;a*0 begets a half cFetch opcode +# Introduced in commit 547195b5f155cf7a706e3a5cca796e9cb7d33c38 +# Fixed in commit 7146fbe79611e0a6bb77ff983448fa23909336c6 +T=d li +V=x +R=-1,1,1 +F=a:=x;a*0 +C=x*0 diff --git a/tests/50regressions/9b b/tests/50regressions/9b new file mode 100644 index 0000000..58b34e7 --- /dev/null +++ b/tests/50regressions/9b @@ -0,0 +1,8 @@ +# Bug: fCall + multiplication by zero begets a broken opcode +# Introduced in commit 547195b5f155cf7a706e3a5cca796e9cb7d33c38 +# Fixed in commit 7146fbe79611e0a6bb77ff983448fa23909336c6 +T=d li +V=a,b +R=-1,1,1 +F=sub(a,b)*0 +C=(a-b)*0 diff --git a/tests/50regressions/9c b/tests/50regressions/9c new file mode 100644 index 0000000..e47c648 --- /dev/null +++ b/tests/50regressions/9c @@ -0,0 +1,8 @@ +# Bug: pCall + multiplication by zero begets a broken opcode +# Introduced in commit 547195b5f155cf7a706e3a5cca796e9cb7d33c38 +# Fixed in commit 7146fbe79611e0a6bb77ff983448fa23909336c6 +T=d li +V=a,b +R=-1,1,1 +F=psub(a,b)*0 +C=(a-b)*0 diff --git a/tests/50regressions/9d b/tests/50regressions/9d new file mode 100644 index 0000000..6468041 --- /dev/null +++ b/tests/50regressions/9d @@ -0,0 +1,8 @@ +# Bug: pIf + multiplication by zero begets a broken opcode +# Introduced in commit 547195b5f155cf7a706e3a5cca796e9cb7d33c38 +# Fixed in commit 7146fbe79611e0a6bb77ff983448fa23909336c6 +T=d li +V=a,b +R=-1,1,1 +F=if(a,b*0,a*0)*0 +C=a*b*0 diff --git a/tests/99misc/1 b/tests/99misc/1 new file mode 100644 index 0000000..27eb69b --- /dev/null +++ b/tests/99misc/1 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1000,1000,.25 +F=x*4/2 + (1+(2+3)) + x*x+x+1+2+3*4+5*6*\n7-8*9 +C=x*4/2 + (1+(2+3)) + x*x+x+(1.0+2.0+3.0*4.0+5.0*6.0*7.0-8.0*9.0) diff --git a/tests/99misc/10 b/tests/99misc/10 new file mode 100644 index 0000000..24ebd0a --- /dev/null +++ b/tests/99misc/10 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y,z +R=1,4,.3 +F=1+sin(cos(max(1+2+3+4+5, x+y+z)))+2 +C=1+fp_sin(fp_cos( fp_max(1+2+3+4+5, x+y+z)))+2 diff --git a/tests/99misc/11 b/tests/99misc/11 new file mode 100644 index 0000000..c34f0a8 --- /dev/null +++ b/tests/99misc/11 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y,z +R=1,19,.8 +F=-(-(-(-(-x))-x))+y*1+log(1.1^z) +C=(-x-x)+y+fp_log(fp_pow(1.1, z)) diff --git a/tests/99misc/12 b/tests/99misc/12 new file mode 100644 index 0000000..15942f0 --- /dev/null +++ b/tests/99misc/12 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=1,2000,.5 +F=1/log(10^((3-2)/log(x))) +C=1.0/fp_log(fp_pow(10.0, 1.0/fp_log(x))) diff --git a/tests/99misc/13 b/tests/99misc/13 new file mode 100644 index 0000000..08540a8 --- /dev/null +++ b/tests/99misc/13 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-30,30,.5 +F=x^3 * x^4 + y^3 * y^5 +C=fp_pow(x,3) * fp_pow(x,4) + fp_pow(y,3) * fp_pow(y,5) diff --git a/tests/99misc/14 b/tests/99misc/14 new file mode 100644 index 0000000..83f6ce0 --- /dev/null +++ b/tests/99misc/14 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-50,50,.1 +F=x*pi + sin(2*pi) + CONST +C=x*fp_const_pi<Value_t>() + fp_sin(2*fp_const_pi<Value_t>()) + Value_t(CONST) diff --git a/tests/99misc/15 b/tests/99misc/15 new file mode 100644 index 0000000..b24072f --- /dev/null +++ b/tests/99misc/15 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=1.1, 6, .07 +F=x^y/log(y) + log(x)/log(y) + log(x^y) +C=fp_pow(x,y)/fp_log(y) + fp_log(x)/fp_log(y) + fp_log(fp_pow(x,y)) diff --git a/tests/99misc/16 b/tests/99misc/16 new file mode 100644 index 0000000..02736f4 --- /dev/null +++ b/tests/99misc/16 @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x,y +R=-20, 20, 1 +F=if(x<0, if(y<0, x+y, x-y), if(y>0, x*y, x+2*y)) +C=x<0 ? (y<0 ? x+y : x-y) : (y>0 ? x*y : x+2*y) diff --git a/tests/99misc/17 b/tests/99misc/17 new file mode 100644 index 0000000..88c3de7 --- /dev/null +++ b/tests/99misc/17 @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x,y +R=-20, 20, 1 +F=sqr(x)+sub(x,y)+psqr(y)+psub(y+1,x-2)-1 +C=userDefFuncSqr({x})+userDefFuncSub({x,y})+userDefFuncSqr({y})+userDefFuncSub({y+1,x-2})-1 diff --git a/tests/99misc/18 b/tests/99misc/18 new file mode 100644 index 0000000..dfb776f --- /dev/null +++ b/tests/99misc/18 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=1,17,.2 +F= - ( - ( - ( - 5 ) ) ) * -x^ -y^-2 +C=- ( - ( - ( - 5 ) ) ) * -fp_pow(x, -fp_pow(y, -2)) diff --git a/tests/99misc/19 b/tests/99misc/19 new file mode 100644 index 0000000..fbabe3e --- /dev/null +++ b/tests/99misc/19 @@ -0,0 +1,17 @@ +T=d f ld mf li gi +V=x,y +R=-100,100,1 +F=(x<y)+10*(x<=y)+100*(x>y)+1000*(x>=y)+10000*(x=y)+100000*(x!=y)+ \ + (x&y)*2+(x|y)*20+(!x)*200+(!!x)*2000+4*!((x<y)&(x<3))+40*!!(!(x>y)|(x>3)) +C= fp_less(x,y)+\ + 10*fp_lessOrEq(x,y)+\ + 100*fp_greater(x,y)+\ + 1000*fp_greaterOrEq(x,y)+\ + 10000*fp_equal(x,y)+\ + 100000*fp_nequal(x,y) \ + +fp_and(x,y)*2 \ + +fp_or(x,y)*20 \ + +fp_not(x)*200 \ + +fp_truth(x)*2000 \ + +4*fp_not(fp_and(fp_less(x,y), fp_less(x,3))) \ + +40*fp_or(fp_not(fp_greater(x,y)), fp_greater(x,3)) diff --git a/tests/99misc/2 b/tests/99misc/2 new file mode 100644 index 0000000..1f029bb --- /dev/null +++ b/tests/99misc/2 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1000,1000,.1 +F= 2 * x+ sin ( x ) / .5 + 2-sin(x)*sin(x) +C=2 * x + fp_sin(x)/.5 + 2-fp_sin(x)*fp_sin(x) diff --git a/tests/99misc/20 b/tests/99misc/20 new file mode 100644 index 0000000..ff89452 --- /dev/null +++ b/tests/99misc/20 @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x,y +R=-100,100,1 +F=(!(x != y) & !x) + !(!(!(!y))) +C=fp_and(fp_not<Value_t>(x != y), fp_not(x)) + fp_truth(y) diff --git a/tests/99misc/21 b/tests/99misc/21 new file mode 100644 index 0000000..faa73fa --- /dev/null +++ b/tests/99misc/21 @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x +R=-10,10,1 +F=sqr(x)+value()-pvalue ( ) +C=userDefFuncSqr({x})+userDefFuncValue({})-5 diff --git a/tests/99misc/22 b/tests/99misc/22 new file mode 100644 index 0000000..2d38405 --- /dev/null +++ b/tests/99misc/22 @@ -0,0 +1,11 @@ +T=d ld mf +V=x,y +R=-4,4,.1 + +# This function is too complex for "float" accuracy + +F=3.5doubled + 10*x tripled - sin(y)doubled + \ + 100*(x doubled-y tripled)doubled + 5/2doubled + 1.1^x doubled + \ + 1.1doubled^x doubled +C=(3.5*2) + 10*(x*3) - (fp_sin(y)*2) + 100*((x*2)-(y*3))*2 + 5.0/(2*2) + \ + fp_pow(1.1, x*2) + fp_pow(1.1*2, x*2) diff --git a/tests/99misc/23 b/tests/99misc/23 new file mode 100644 index 0000000..eb87ad5 --- /dev/null +++ b/tests/99misc/23 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-1000,1000,.1 +F=(x/(2*acos(0)))*180 +C=(x/(2*fp_acos(0.0)))*180 diff --git a/tests/99misc/24 b/tests/99misc/24 new file mode 100644 index 0000000..a8bba35 --- /dev/null +++ b/tests/99misc/24 @@ -0,0 +1,7 @@ +# Note: Contains a duplicate of regressions 1 and 2 + +T=d f ld mf li gi +V=x +R=-1000,1000,1 +F=(min(x, min(1,x)) + min(x, 1))/2 + min(x, 1)*3 + max(0, min(-2,0)) +C=(fp_min(x, fp_min(1,x)) + fp_min(x, 1))/2 + fp_min(x, 1)*3 + fp_max(0, fp_min(-2,0)) diff --git a/tests/99misc/25 b/tests/99misc/25 new file mode 100644 index 0000000..8c9a122 --- /dev/null +++ b/tests/99misc/25 @@ -0,0 +1,5 @@ +T=d f ld mf +V=a,b,c +R=1,3,.2 +F=a^b^c + a^-2 * (-b^2) + (-b^-c) +C=fp_pow(a, fp_pow(b, c)) + fp_pow(a, -2) * (-fp_pow(b, 2)) + (-fp_pow(b, -c)) diff --git a/tests/99misc/26_deg b/tests/99misc/26_deg new file mode 100644 index 0000000..c2945a3 --- /dev/null +++ b/tests/99misc/26_deg @@ -0,0 +1,6 @@ +T=d f ld mf +DEG=1 +V=x +R=-100,100,.1 +F=sin(x) + cos(x*1.5) + asin(x/110) + acos(x/120) +C=fp_sin(d2r(x)) + fp_cos(d2r(x*1.5)) + r2d(fp_asin(x/110.0)) + r2d(fp_acos(x/120.0)) diff --git a/tests/99misc/27 b/tests/99misc/27 new file mode 100644 index 0000000..276b2bb --- /dev/null +++ b/tests/99misc/27 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=.1, .9, .025 +F=abs(x)+acos(x)+asin(x)+atan(x)+atan2(x,y)+ceil(x)+cos(x)+cosh(x)+cot(x)+csc(x) + pow(x,y) +C=fp_abs(x)+fp_acos(x)+fp_asin(x)+fp_atan(x)+fp_atan2(x,y)+fp_ceil(x)+fp_cos(x)+fp_cosh(x)+1.0/fp_tan(x)+1.0/fp_sin(x) +fp_pow(x,y) diff --git a/tests/99misc/28 b/tests/99misc/28 new file mode 100644 index 0000000..5492253 --- /dev/null +++ b/tests/99misc/28 @@ -0,0 +1,6 @@ +T=d f ld mf +V=x,y +R=.1, .9, .025 +F=exp(x)+floor(x)+int(x)+log(x)+log10(x)+max(x,y)+min(x,y)+sec(x)+sin(x)+sinh(x)+sqrt(x)+tan(x)+tanh(x)+ceil(y)+trunc(y) +C=fp_exp(x)+fp_floor(x)+fp_int(x)+fp_log(x)+fp_log10(x)+fp_max(x,y)+fp_min(x,y)+ \ + 1/fp_cos(x)+fp_sin(x)+fp_sinh(x)+fp_sqrt(x)+fp_tan(x)+fp_tanh(x)+fp_ceil(y)+fp_trunc(y) diff --git a/tests/99misc/29 b/tests/99misc/29 new file mode 100644 index 0000000..dc3cda6 --- /dev/null +++ b/tests/99misc/29 @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=x,y +R=-5,5,1 +F=x-y*1 +C=x-y*1 diff --git a/tests/99misc/3 b/tests/99misc/3 new file mode 100644 index 0000000..b34dee5 --- /dev/null +++ b/tests/99misc/3 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y,z +R=-7,7,.5 +F=(x=y & y=x)+ 1+2-3.1*4e2/.5 + x*x+y*y+z*z + (x&x) + (y|y) +C=fp_and(fp_equal(x,y), fp_equal(y,x))+ 1.0+2.0-3.1*4e2/.5 + x*x+y*y+z*z + fp_and(x,x) + fp_or(y,y) diff --git a/tests/99misc/30 b/tests/99misc/30 new file mode 100644 index 0000000..21f0c99 --- /dev/null +++ b/tests/99misc/30 @@ -0,0 +1,6 @@ +T=d f ld mf +V=x,y +R=3,10,1 +F=x - y*1 + (x%y) + x / (y^1.1) + 2^3 + 5%3 + x^(y^0) + x^0.5 +C=x - y*1 + fp_mod(x,y) + x / fp_pow(y,1.1) + fp_pow(2,3) + \ + fp_mod(5,3) + fp_pow(x,fp_pow(y,0)) + fp_pow(x,0.5) diff --git a/tests/99misc/31 b/tests/99misc/31 new file mode 100644 index 0000000..784e1c9 --- /dev/null +++ b/tests/99misc/31 @@ -0,0 +1,15 @@ +T=d ld mf +V=x,y,z +R=.1,4,.35 + +# This function is too complex for "float" accuracy + +F=x - (y*(y*(y*-1))*1) + log(x*exp(1.0)^y) - log(x^y) + \ + exp(1.0)^log(x+6) + 10^(log(x+6)/log(y+6)*log(z+6)/log(10)) - \ + exp(1.0)^(log(x+6)*y) - 5^(log(x+7)/log(5)) + (x*z+17)^3 * (x*z+17)^2 / \ + (x*z+17)^4 +C=x - (y*(y*(y*-1))*1) + fp_log(x*fp_pow(fp_exp(1.0),y)) - fp_log(fp_pow(x,y)) + \ + fp_pow(fp_exp(1.0),fp_log(x+6)) + \ + fp_pow(10.0,fp_log(x+6)/fp_log(y+6)*fp_log(z+6)/fp_log(10.0)) - \ + fp_pow(fp_exp(1.0), fp_log(x+6)*y) - fp_pow(5.0,fp_log(x+7)/fp_log(5.0)) + \ + fp_pow(x*z+17,3) * fp_pow(x*z+17,2) / fp_pow(x*z+17,4) diff --git a/tests/99misc/32 b/tests/99misc/32 new file mode 100644 index 0000000..d49dcaf --- /dev/null +++ b/tests/99misc/32 @@ -0,0 +1,43 @@ +T=d f ld mf +V=x,y,z +R=1,2,.05 +F=x\ + +y/y-min(3,4)-x-max(4,3)+max(3,4)-min(4,3)+0+(z*1)\ + +(x-2+2)+(x*0.5*2)+y*0\ + +min(min(min(4.0,x),1.0),min(x,min(min(y,4.0),z)))\ + +max(max(max(4.0,x),1.0),max(x,max(max(y,4.0),z)))\ + +(abs(1)+acos(1.0)+asin(1.0)+atan(1.0)+ceil(1.1)+cos(0.0)\ + +cosh(0.0)+floor(1.1)+log(1.0)+sin(0.0)+sinh(0.0)+tan(1.0)\ + +tanh(1.0)+atan2(1.0,1.0))\ + +(x-(y-z))\ + +(x+y) + (x*y)\ + +max(x,max(x,max(x,max(x,x))))*-1.0\ + +(z-z)\ + +1/sin(x/5) + 1/cos(y/5) + 1/tan(z/5)\ + +log10(cot(z/5) + csc(y/5) + sec(x/5))\ + +log(30+x)*log(40+y)/log(50+z)\ + +sin(x/57.295779513082320877)\ + +asin(x/10)*57.295779513082320877\ + +floor(-x) + 1/ceil(x)\ + +sqrt(5 * 0.2)\ + +(-x+-x+-x+-x+-x+-x) +C=x\ + +y/y-fp_min(3,4)-x-fp_max(4,3)+fp_max(3,4)-fp_min(4,3)+0+(z*1)\ + +(x-2+2)+(x*0.5*2)+y*0\ + +fp_min(fp_min(fp_min(4.0,x),1.0),fp_min(x,fp_min(fp_min(y,4.0),z)))\ + +fp_max(fp_max(fp_max(4.0,x),1.0),fp_max(x,fp_max(fp_max(y,4.0),z)))\ + +(fp_abs(1)+fp_acos(1.0)+fp_asin(1.0)+fp_atan(1.0)+fp_ceil(1.1)+fp_cos(0.0)\ + +fp_cosh(0.0)+fp_floor(1.1)+fp_log(1.0)+fp_sin(0.0)+fp_sinh(0.0)+fp_tan(1.0)\ + +fp_tanh(1.0)+fp_atan2(1.0,1.0))\ + +(x-(y-z))\ + +(x+y) + (x*y)\ + +fp_max(x,fp_max(x,fp_max(x,fp_max(x,x))))*-1.0\ + +(z-z)\ + +1/fp_sin(x/5) + 1/fp_cos(y/5) + 1/fp_tan(z/5)\ + +fp_log10(1/fp_tan(z/5) + 1/fp_sin(y/5) + 1/fp_cos(x/5))\ + +fp_log(30+x)*fp_log(40+y)/fp_log(50+z)\ + +fp_sin(x/57.295779513082320877)\ + +fp_asin(x/10)*57.295779513082320877\ + +fp_floor(-x) + 1/fp_ceil(x)\ + +fp_sqrt(5 * 0.2)\ + +(-x+-x+-x+-x+-x+-x) diff --git a/tests/99misc/33 b/tests/99misc/33 new file mode 100644 index 0000000..9e4ce2b --- /dev/null +++ b/tests/99misc/33 @@ -0,0 +1,8 @@ +T=d ld mf +V=x,y +R=-2,2,.1 + +# float accuracy just fails here. + +F=sin(sqrt(10-x*x+y*y))+cos(sqrt(15-x*x-y*y))+sin(x*x+y*y) +C=fp_sin(fp_sqrt(10-x*x+y*y))+fp_cos(fp_sqrt(15-x*x-y*y))+fp_sin(x*x+y*y) diff --git a/tests/99misc/34 b/tests/99misc/34 new file mode 100644 index 0000000..cad1a74 --- /dev/null +++ b/tests/99misc/34 @@ -0,0 +1,5 @@ +T=d f ld mf li gi +V=t,ã†,ãŠ,æ—© +R=-5,5,1 +F=ãŠ+æ—©*ã†-t +C=ãŠ+æ—©*ã†-t diff --git a/tests/99misc/35 b/tests/99misc/35 new file mode 100644 index 0000000..487691e --- /dev/null +++ b/tests/99misc/35 @@ -0,0 +1,7 @@ +T=d f ld mf li gi +V=A_very_long_variable_name_1,A_very_long_variable_name_2,Yet_a_third_very_long_variable_name +R=-10,10,1 +F=A_very_long_variable_name_1-A_very_long_variable_name_2+ \ + Yet_a_third_very_long_variable_name*A_very_long_variable_name_1 +C=A_very_long_variable_name_1-A_very_long_variable_name_2+ \ + Yet_a_third_very_long_variable_name*A_very_long_variable_name_1 diff --git a/tests/99misc/37 b/tests/99misc/37 new file mode 100644 index 0000000..4bf1ae6 --- /dev/null +++ b/tests/99misc/37 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-10,10,.1 +F=5 + 7.5*8 / 3 - 2^4*2 + 7%2+4 + x +C=5 + 7.5*8 / 3 - fp_pow(2,4)*2 + fp_mod(7,2)+4 + x diff --git a/tests/99misc/38 b/tests/99misc/38 new file mode 100644 index 0000000..c6a0b5f --- /dev/null +++ b/tests/99misc/38 @@ -0,0 +1,5 @@ +T=d ld mf +V=x,y,z +R=-.9, .9, .1 +F=asinh(x) + 1.5*acosh(y+3) + 2.5*atanh(z) +C=fp_asinh(x) + 1.5*fp_acosh(y+3) + 2.5*fp_atanh(z) diff --git a/tests/99misc/39 b/tests/99misc/39 new file mode 100644 index 0000000..44f8894 --- /dev/null +++ b/tests/99misc/39 @@ -0,0 +1,12 @@ +T=d ld mf +V=x,y,z +R=-1.3, 1.3, .15 + +# This function is too hard for 'float' accuracy + +F=sin(x+cos(y*1.5))-cos(x+sin(y*1.5))+z*z*z*sin(z*z*z-x*x-y*y)- \ + cos(y*1.5)*sin(x+cos(y*1.5))+x*y*z+x*y*2.5+x*y*z*cos(x)+x*y*cos(x)+x*z*cos(x)+ \ + y*z*2.5+(x*y*z*cos(x)-x*y*z-y*cos(x)-x*z*y+x*y+x*z-cos(x)*x) +C=fp_sin(x+fp_cos(y*1.5))-fp_cos(x+fp_sin(y*1.5))+z*z*z*fp_sin(z*z*z-x*x-y*y)- \ + fp_cos(y*1.5)*fp_sin(x+fp_cos(y*1.5))+x*y*z+x*y*2.5+x*y*z*fp_cos(x)+x*y*fp_cos(x)+x*z*fp_cos(x)+ \ + y*z*2.5+(x*y*z*fp_cos(x)-x*y*z-y*fp_cos(x)-x*z*y+x*y+x*z-fp_cos(x)*x) diff --git a/tests/99misc/4 b/tests/99misc/4 new file mode 100644 index 0000000..5a87782 --- /dev/null +++ b/tests/99misc/4 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-10,10,.5 +F= ( ((( ( x-y) -( ((y) *2) -3)) )* 4))+sin(x)*cos(y)-cos(x)*sin(y) +C=( ((( ( x-y) -( ((y) *2) -3)) )* 4))+fp_sin(x)*fp_cos(y)-fp_cos(x)*fp_sin(y) diff --git a/tests/99misc/40 b/tests/99misc/40 new file mode 100644 index 0000000..3dcb6ea --- /dev/null +++ b/tests/99misc/40 @@ -0,0 +1,16 @@ +T=d ld mf +V=x,y,z +R=-1.3,1.3,.075 + +# This function is too hard for 'float' accuracy + +F=(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)* \ + (x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)+ \ + 2*(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)- \ + x*y*(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)+ \ + x*(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z) +C=(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)* \ + (x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)+ \ + 2*(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)- \ + x*y*(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z)+ \ + x*(x+x+x+x+x+x+x+x+x+x+x+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z+y+z) diff --git a/tests/99misc/41 b/tests/99misc/41 new file mode 100644 index 0000000..16e06c8 --- /dev/null +++ b/tests/99misc/41 @@ -0,0 +1,16 @@ +T=d ld mf +V=x,y,z +R=-2, 2, .15 + +# This function is too complex for "float" accuracy + +F=x*3+x*y+x*z+x*sin(y*z) - \ + (sin(x)+cos(y))*4 + \ + (sin(x)+cos(y))*x + \ + (sin(x)+cos(y))*y + \ + (sin(x)+cos(y))*z +C=x*3+x*y+x*z+x*fp_sin(y*z) - \ + (fp_sin(x)+fp_cos(y))*4 + \ + (fp_sin(x)+fp_cos(y))*x + \ + (fp_sin(x)+fp_cos(y))*y + \ + (fp_sin(x)+fp_cos(y))*z diff --git a/tests/99misc/43 b/tests/99misc/43 new file mode 100644 index 0000000..321c2c2 --- /dev/null +++ b/tests/99misc/43 @@ -0,0 +1,8 @@ +T=d ld mf +V=x +R=-100,100,.03 + +# This function is too complex for "float" accuracy + +F=log(x*x)+abs(exp(abs(x)+1)) +C=fp_log(x*x)+fp_abs(fp_exp(fp_abs(x)+1)) diff --git a/tests/99misc/44 b/tests/99misc/44 new file mode 100644 index 0000000..74c774b --- /dev/null +++ b/tests/99misc/44 @@ -0,0 +1,21 @@ +T=d f ld mf +V=x +R=0,100,.125 +F=(x^2)^(1/8) + \ + 1.1*(x^3)^(1/7) + \ + 1.2*(x^4)^(1/6) + \ + 1.3*(x^5)^(1/5) + \ + 1.4*(x^6)^(1/6) + \ + 1.5*(x^7)^(1/4) + \ + 1.6*(x^8)^(1/3) + \ + 1.7*(x^9)^(1/2) + \ + 1.8*(sqrt(abs(-sqrt(x))^3)) +C=fp_pow(x*x, 1/8) + \ + 1.1*fp_pow(x*x*x, 1/7) + \ + 1.2*fp_pow(x*x*x*x, 1/6) + \ + 1.3*fp_pow(x*x*x*x*x, 1/5) + \ + 1.4*fp_pow(x*x*x*x*x*x, 1/6) + \ + 1.5*fp_pow(x*x*x*x*x*x*x, 1/4) + \ + 1.6*fp_pow(x*x*x*x*x*x*x*x, 1/3) + \ + 1.7*fp_pow(x*x*x*x*x*x*x*x*x, 1/2) + \ + 1.8*(fp_sqrt(fp_pow(fp_abs(-fp_sqrt(x)), 3))) diff --git a/tests/99misc/45 b/tests/99misc/45 new file mode 100644 index 0000000..8e15094 --- /dev/null +++ b/tests/99misc/45 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-10,10,.025 +F=(x^2)^(1/7) + 1.1*(x^4)^(1/5) + 1.2*(x^6)^(1/3) +C=fp_pow(x*x, 1/7) + 1.1*fp_pow(x*x*x*x, 1/5) + 1.2*fp_pow(x*x*x*x*x*x, 1/3) diff --git a/tests/99misc/46 b/tests/99misc/46 new file mode 100644 index 0000000..467e50a --- /dev/null +++ b/tests/99misc/46 @@ -0,0 +1,10 @@ +T=d f ld mf +V=x,y +R=-.9, .9, .15 +F=abs(floor(acos(x)+4)) + 1.1*abs(floor(acos(y)+1.5)) + \ + (acos(x) < (acos(y)-10)) + 1.2*max(-4, acos(x)) + 1.3*min(9, acos(x)-9) +C=fp_abs(fp_floor(fp_acos(x)+4)) + \ + 1.1*fp_abs(fp_floor(fp_acos(y)+1.5)) + \ + fp_less(fp_acos(x), (fp_acos(y)-10)) + \ + 1.2*fp_max(-4, fp_acos(x)) + \ + 1.3*fp_min(9, fp_acos(x)-9) diff --git a/tests/99misc/47 b/tests/99misc/47 new file mode 100644 index 0000000..7d7124a --- /dev/null +++ b/tests/99misc/47 @@ -0,0 +1,7 @@ +T=d f ld mf +V=x,y +R=-3, 3, .1 +F=1.25*(exp(x)+exp(-x)) + 1.5*(exp(y)-exp(-y)) + \ + 1.75*((exp(-x)+exp(x))/2) + 2.0*((exp(-x)-exp(x))/2) + 2.25*(cosh(y)+sinh(y)) +C=1.25*(fp_exp(x)+fp_exp(-x)) + 1.5*(fp_exp(y)-fp_exp(-y)) + \ + 1.75*((fp_exp(-x)+fp_exp(x))/2) + 2.0*((fp_exp(-x)-fp_exp(x))/2) + 2.25*(fp_cosh(y)+fp_sinh(y)) diff --git a/tests/99misc/48 b/tests/99misc/48 new file mode 100644 index 0000000..a283522 --- /dev/null +++ b/tests/99misc/48 @@ -0,0 +1,6 @@ +T=d f ld mf +V=x +R=2, 1e9, 1.2e7 +F=sinh((log(x)/5+1)*5) + 1.2*cosh((log(x)/log(2)+1)*log(2)) + !(x | !(x/4)) +C=fp_sinh((fp_log(x)/5+1)*5) + 1.2*fp_cosh((fp_log(x)/fp_log(2)+1)*fp_log(2)) + \ + fp_not(fp_or(fp_truth(x), fp_not(x/4))) diff --git a/tests/99misc/49 b/tests/99misc/49 new file mode 100644 index 0000000..a2dfcb1 --- /dev/null +++ b/tests/99misc/49 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-100, 100, .05 +F=atan2(0, x) + (-4*(x-100))^3.3 +C=fp_atan2(0, x) + fp_pow(-4*(x-100), 3.3) diff --git a/tests/99misc/5 b/tests/99misc/5 new file mode 100644 index 0000000..30deb42 --- /dev/null +++ b/tests/99misc/5 @@ -0,0 +1,5 @@ +T=d f ld mf +V=__A5_x08,o__5_0AB_ +R=.1,8,.15 +F=__A5_x08^o__5_0AB_ +C=fp_pow(__A5_x08, o__5_0AB_) diff --git a/tests/99misc/50 b/tests/99misc/50 new file mode 100644 index 0000000..ebe6d9c --- /dev/null +++ b/tests/99misc/50 @@ -0,0 +1,23 @@ +T=d f ld mf li gi +V=x,y +R=-10, 10, 1 +F=(x<y | y<x) + \ + 2*(x<y & y<x) + \ + 4*(x<=y & y<=x) + \ + 8*(x<y & x!=y) + \ + 16*(x<y | x!=y) + \ + 32*(x<=y & x>=y) + \ + 64*(x<=y | x>=y) + \ + 128*(x!=y & x=y) + \ + 256*(x!=y & x!=y) + \ + 512*(x<=y & x=y) +C=fp_or(fp_less(x,y), fp_less(y,x)) + \ + 2*fp_and(fp_less(x,y), fp_less(y,x)) + \ + 4*fp_and(fp_lessOrEq(x,y), fp_lessOrEq(y,x)) + \ + 8*fp_and(fp_less(x,y), fp_nequal(x,y)) + \ + 16*fp_or(fp_less(x,y), fp_nequal(x,y)) + \ + 32*fp_and(fp_lessOrEq(x,y), fp_greaterOrEq(x,y)) + \ + 64*fp_or(fp_lessOrEq(x,y), fp_greaterOrEq(x,y)) + \ + 128*fp_and(fp_nequal(x,y), fp_equal(x,y)) + \ + 256*fp_and(fp_nequal(x,y), fp_nequal(x,y)) + \ + 512*fp_and(fp_lessOrEq(x,y), fp_equal(x,y)) diff --git a/tests/99misc/52 b/tests/99misc/52 new file mode 100644 index 0000000..16cc375 --- /dev/null +++ b/tests/99misc/52 @@ -0,0 +1,9 @@ +T=d f ld mf +V=x +R=-10, 10, .5 +F=x + (1.0+2.0+3.0+4.0-5.0-6.0-7.0-8.0)/3.0 + \ + 4.0*(1.0+sin(2.0)+cos(4.0*5.0+6.0)/2.0) + cos(0.5)*tan(0.6+0.2) - \ + 1.1/log(2.1)*sqrt(3.3) + 2^3 +C=x + (1.0+2.0+3.0+4.0-5.0-6.0-7.0-8.0)/3.0 + \ + 4.0*(1.0+fp_sin(2.0)+fp_cos(4.0*5.0+6.0)/2.0) + fp_cos(0.5)*fp_tan(0.6+0.2) - \ + 1.1/fp_log(2.1)*fp_sqrt(3.3) + fp_pow(2,3) diff --git a/tests/99misc/53 b/tests/99misc/53 new file mode 100644 index 0000000..b7d7a6f --- /dev/null +++ b/tests/99misc/53 @@ -0,0 +1,8 @@ +T=d f ld mf +V=x,y +R=0, 10, 0.5 +F=(x&y) + 4*(int(x/10)|int(y/10)) + 8*((-!-!-x)+(!-!-!y)) + 16*(-------x + !!!!!!!y) +C=fp_and(x,y) + 4*fp_or(fp_int(x/10), fp_int(y/10)) + \ + 8*((-fp_not(-fp_not(-x)))+ \ + (fp_not(-fp_not(-fp_not(y))))) \ + + 16*(-x + fp_not(y)) diff --git a/tests/99misc/54 b/tests/99misc/54 new file mode 100644 index 0000000..588856e --- /dev/null +++ b/tests/99misc/54 @@ -0,0 +1,20 @@ +T=d f ld mf +V=x,y +R=-10, 100, .5 +F=(x<y)+(x<=y)+(x>y)+(x>=y)+ \ + (x=y)+(x!=y)+(x&y)+(x|y)+ \ + (!x)+(!!x)+ \ + !((x<y)&(x<3))+ \ + !!(!(x>y)|(x>3)) +C=fp_less(x,y)+\ + fp_lessOrEq(x,y)+\ + fp_greater(x,y)+\ + fp_greaterOrEq(x,y)+ \ + fp_equal(x,y)+\ + fp_nequal(x,y)+\ + fp_and(x,y)+\ + fp_or(x,y)+ \ + fp_not(x)+\ + fp_truth(x)+ \ + fp_not(fp_and(fp_less(x,y),fp_less(x,3)))+ \ + fp_or( fp_not(fp_greater(x,y)), fp_greater(x,3)) diff --git a/tests/99misc/55 b/tests/99misc/55 new file mode 100644 index 0000000..21f04f5 --- /dev/null +++ b/tests/99misc/55 @@ -0,0 +1,9 @@ +T=d f ld mf +V=x,y +R=1,100, .5 +F=(x^1.2 < 0) + (y^2.5 < 0) + 2*(x*x<0) + 3*(y^3<0) + 4*(x^4<0) +C=fp_less(fp_pow(x,1.2), 0) + \ + fp_less(fp_pow(y,2.5), 0) + \ + 2*fp_less(x*x, 0) + \ + 3*fp_less(fp_pow(y,3), 0) + \ + 4*fp_less(fp_pow(x,4), 0) diff --git a/tests/99misc/56 b/tests/99misc/56 new file mode 100644 index 0000000..e953ab6 --- /dev/null +++ b/tests/99misc/56 @@ -0,0 +1,10 @@ +T=d f ld mf +V=x +R=.25, 100, .25 + +# 1.75e21 is an arbitrary value larger than 2^64, which +# is the limit where repeated runs of the fprem opcode +# on 387 is required. + +F=1.75e21%x +C=fp_mod(1.75e21, x) diff --git a/tests/99misc/58 b/tests/99misc/58 new file mode 100644 index 0000000..e8f8b64 --- /dev/null +++ b/tests/99misc/58 @@ -0,0 +1,15 @@ +# Also test number i4 + +T=d f ld mf li gi +V=x,y +R=-11, 11, 1 +F=(-x < 3) + (x*-1 > 5) + (x*-3 < 10) + (x*-3 < y*7) + \ + (x*4 < y*7) + (x*6 < y*-3) + (-x < 11) + (5 < -y) +C=fp_less(-x, 3) + \ + fp_greater(x*-1, 5) + \ + fp_less(x*-3, 10) + \ + fp_less(x*-3, y*7) + \ + fp_less(x*4, y*7) + \ + fp_less(x*6, y*-3) + \ + fp_less(-x, 11) + \ + fp_less(5, -y) diff --git a/tests/99misc/59 b/tests/99misc/59 new file mode 100644 index 0000000..f1009f5 --- /dev/null +++ b/tests/99misc/59 @@ -0,0 +1,11 @@ +T=d f ld mf +V=x +R=-3, 3, 0.2 +F=(cos(x) < sin(x)) + \ + (cos(x)-sin(x)) + \ + sub(sinh(x)-cosh(x), sinh(x)/cosh(x)) + \ + sqrt(cos(x)^2+sin(x)^2) +C=fp_less(fp_cos(x), fp_sin(x)) + \ + (fp_cos(x) - fp_sin(x)) + \ + ((fp_sinh(x)-fp_cosh(x)) - (fp_sinh(x)/fp_cosh(x))) + \ + Value_t(1) diff --git a/tests/99misc/7 b/tests/99misc/7 new file mode 100644 index 0000000..4a94ab0 --- /dev/null +++ b/tests/99misc/7 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x +R=-10,10,.01 +F=cos(x)*sin(1-x)*(1-cos(x/2)*sin(x*5)) +C=fp_cos(x)*fp_sin(1-x)*(1-fp_cos(x/2)*fp_sin(x*5)) diff --git a/tests/99misc/8 b/tests/99misc/8 new file mode 100644 index 0000000..cce4111 --- /dev/null +++ b/tests/99misc/8 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y +R=-8,8,.2 +F=atan2(x,y)+max(x,y) +C=fp_atan2(x,y) + (x>y ? x : y) diff --git a/tests/99misc/9 b/tests/99misc/9 new file mode 100644 index 0000000..221b9b5 --- /dev/null +++ b/tests/99misc/9 @@ -0,0 +1,5 @@ +T=d f ld mf +V=x,y,z +R=1,15,.7 +F=1.5+x*y-2+4/8+z+z+z+z+x/(y*z) +C=1.5+x*y-2.0+4.0/8.0+z+z+z+z+x/(y*z) diff --git a/tests/99misc/i1 b/tests/99misc/i1 new file mode 100644 index 0000000..68113db --- /dev/null +++ b/tests/99misc/i1 @@ -0,0 +1,5 @@ +T=li gi +V=x,y,z +R=-8,7,1 +F=1+2+3-4*5*6/3+10/2-9%2 + (x+y - 11*x + z/10 + x/(z+31)) +C=1+2+3-4*5*6/3+10/2-9%2 + (x+y - 11*x + z/10 + x/(z+31)) diff --git a/tests/99misc/i2 b/tests/99misc/i2 new file mode 100644 index 0000000..faa97a7 --- /dev/null +++ b/tests/99misc/i2 @@ -0,0 +1,7 @@ +T=li gi +V=x,y,z +R=-7,7,1 +F=if(abs(x*y) < 20 | x+y > 30 & z > 5, min(x,2*y), max(y,z*2)) +C=((fp_abs(x*y) < 20) \ + || (((x+y) > 30) \ + && (z > 5))) ? fp_min(x,2*y) : fp_max(y,z*2) diff --git a/tests/99misc/i3 b/tests/99misc/i3 new file mode 100644 index 0000000..4893187 --- /dev/null +++ b/tests/99misc/i3 @@ -0,0 +1,9 @@ +T=li gi +V=x,y,z +R=1,7,1 +F=(x+y) + 2*(x-z) + 3*(x*y) + 4*(y/z) + 5*(x%z) + \ + 6*(x<y) + 7*(x<=z) + 8*(x>2*z) + 9*(y>=3*z) + 10*(x+y!=z) + \ + 11*(100+x) + 12*(101-y) + 13*(102*z) + 14*(103/x) +C=(x+y) + 2*(x-z) + 3*(x*y) + 4*(y/z) + 5*fp_mod(x,z) + \ + 6*(x<y) + 7*(x<=z) + 8*(x>2*z) + 9*(y>=3*z) + 10*(x+y!=z) + \ + 11*(100+x) + 12*(101-y) + 13*(102*z) + 14*(103/x) diff --git a/tests/make_tests.cc b/tests/make_tests.cc new file mode 100644 index 0000000..2ed6c79 --- /dev/null +++ b/tests/make_tests.cc @@ -0,0 +1,1099 @@ +#include <vector> +#include <map> +#include <set> +#include <string> +#include <sstream> +#include <cstdio> +#include <cctype> +#include <iostream> +#include <fstream> +#include <cstring> +#include <cstdlib> +#include <algorithm> + +namespace +{ + std::string GetDefinesFor(const std::string& type) + { + if(type == "float") return "FP_TEST_WANT_FLOAT_TYPE"; + if(type == "long double") return "FP_TEST_WANT_LONG_DOUBLE_TYPE"; + if(type == "long") return "FP_TEST_WANT_LONG_INT_TYPE"; + if(type == "double") return "FP_TEST_WANT_DOUBLE_TYPE"; + if(type == "MpfrFloat") return "FP_TEST_WANT_MPFR_FLOAT_TYPE"; + if(type == "GmpInt") return "FP_TEST_WANT_GMP_INT_TYPE"; + if(type == "std::complex<double>") return "FP_TEST_WANT_COMPLEX_DOUBLE_TYPE"; + if(type == "std::complex<float>") return "FP_TEST_WANT_COMPLEX_FLOAT_TYPE"; + if(type == "std::complex<long double>") return "FP_TEST_WANT_COMPLEX_LONG_DOUBLE_TYPE"; + return std::string(); + } + std::string GetTypeForDefine(const std::string& def) + { + if(def == "FP_TEST_WANT_FLOAT_TYPE") return "float"; + if(def == "FP_TEST_WANT_LONG_DOUBLE_TYPE") return "long double"; + if(def == "FP_TEST_WANT_LONG_INT_TYPE") return "long"; + if(def == "FP_TEST_WANT_DOUBLE_TYPE") return "double"; + if(def == "FP_TEST_WANT_MPFR_FLOAT_TYPE") return "MpfrFloat"; + if(def == "FP_TEST_WANT_GMP_INT_TYPE") return "GmpInt"; + if(def == "FP_TEST_WANT_COMPLEX_DOUBLE_TYPE") return "std::complex<double>"; + if(def == "FP_TEST_WANT_COMPLEX_FLOAT_TYPE") return "std::complex<float>"; + if(def == "FP_TEST_WANT_COMPLEX_LONG_DOUBLE_TYPE") return "std::complex<long double>"; + return "double"; + } + std::string NumConst(const std::string& type, const std::string& value, bool direct_cast = false) + { + if(direct_cast) + { + if(type == "long") return value + "l"; + + std::string fltvalue = value; + + char* endptr = 0; + strtol(value.c_str(), &endptr, 10); + if(endptr && !*endptr) + fltvalue += ".0"; + + if(type == "float" + || type == "std::complex<float>") return fltvalue + "f"; + if(type == "long double" + || type == "std::complex<long double>") return fltvalue + "l"; + if(type == "double") return fltvalue; + return value; + } + else + { + size_t n_trailing_zeros = 0; + while(n_trailing_zeros < value.size() + && value[value.size()-1-n_trailing_zeros] == '0') + ++n_trailing_zeros; + if(n_trailing_zeros < value.size() + && value[value.size()-1-n_trailing_zeros] == '.') + { + return NumConst(type, value.substr(0, value.size()-1-n_trailing_zeros)); + } + + if(type == "std::complex<double>" + || type == "std::complex<float>" + || type == "std::complex<long double>") + { + /* N() and P() require two parameters: a real part and an imaginary part. + * Make those two parts. + */ + const char* first_part = value.c_str(); + const char* second_part_begin = first_part; + + if(*first_part == '+' || *first_part == '-') + ++second_part_begin; + while(*second_part_begin != '\0' + && !( (*second_part_begin == '-' + || *second_part_begin == '+') + && second_part_begin[-1] != 'e' + && second_part_begin[-1] != 'E')) ++second_part_begin; + std::string first_part_str(first_part, second_part_begin - first_part); + std::string second_part_str(second_part_begin); + if(second_part_str.empty()) + { + second_part_str = "0"; + if(value[value.size()-1] == 'i' + || value[value.size()-1] == 'I') + first_part_str.erase(first_part_str.size()-1); + } + else + { + if(value[value.size()-1] == 'i' + || value[value.size()-1] == 'I') + { + second_part_str.erase(second_part_str.size()-1); + } + } + if(first_part_str.find('.') == std::string::npos + && first_part_str.find('e') == std::string::npos + ) first_part_str += ".0"; + if(second_part_str.find('.') == std::string::npos + && second_part_str.find('e') == std::string::npos + ) second_part_str += ".0"; + return "N(" + first_part_str + "," + second_part_str + ")"; + } + char* endptr = 0; + long longval = strtol(value.c_str(), &endptr, 10); + if(endptr && !*endptr) + { + if(longval == (long)(float)(longval)) return value; + //if(longval >= -32768 && longval < 32767) return value; + return "P(" + value + ")"; + } + return "N(" + value + ")"; + } + } + std::string NumConstDefines(const std::string& type) + { + if(type == "std::complex<double>") + return "#define N(x,y) (Value_t(x,y))\n"; + if(type == "std::complex<float>") + return "#define N(x,y) (Value_t(APP(x,f),APP(y,f)))\n"; + if(type == "std::complex<long double>") + return "#define N(x,y) (Value_t(APP(x,l),APP(y,l)))\n"; + if(type == "MpfrFloat") + return "#define N(x) (Value_t(#x,0))\n" + "#define P(x) N(x)\n"; + if(type == "long" || type == "GmpInt") + return "#define P(x) (APP(x,l))\n"; + std::string result = "(x)"; + if(type == "float") result = "(APP(x,f))"; + if(type == "long double") result = "(APP(x,l))"; + return "#define N(x) " + result + "\n" + "#define P(x) N(x##.0)\n"; + } + std::string NumConstUndefines(const std::string& type) + { + if(type == "std::complex<double>" + || type == "std::complex<float>" + || type == "std::complex<long double>") return "#undef N\n"; + if(type == "long" || type == "GmpInt") return "#undef P\n"; + return "#undef N\n" + "#undef P\n"; + } + std::string GetTypeFor(const std::string& typecode) + { + if(typecode == "d") + return ("double"); + else if(typecode == "f") + return ("float"); + else if(typecode == "ld") + return ("long double"); + else if(typecode == "li") + return ("long"); + else if(typecode == "mf") + return ("MpfrFloat"); + else if(typecode == "gi") + return ("GmpInt"); + else if(typecode == "cd") + return ("std::complex<double>"); + else if(typecode == "cf") + return ("std::complex<float>"); + else if(typecode == "cld") + return ("std::complex<long double>"); + return typecode; + } + std::string test_declaration(const std::string& name) + { + return "template<typename Value_t> static Value_t "+name+"(const Value_t* vars)"; + } + /*std::string test_specialization(const std::string& name, const std::string& type) + { + return "template<> Value_t "+name+"<Value_t> (const Value_t* vars) /""* " + type + " *""/"; + }*/ + std::string test_specialized_declaration(const std::string& name, const std::string& type) + { + return "Value_t "+name+"(const Value_t* vars) /""* " + type + " *""/"; + } +} + + +struct TestData +{ + std::string IfDef; + + std::string FuncString, ParamString; + unsigned ParamAmount; + std::string ParamValueRanges; + bool UseDegrees; + std::string TestFuncName, TestName; + std::set<std::string> DataTypes; + + TestData(): + FuncString(), ParamString(), + ParamAmount(0), + ParamValueRanges(), + UseDegrees(false), + TestFuncName(), TestName() + { + } +}; + +typedef std::vector<TestData> TestCollection; + +std::map<std::string/*datatype*/, + TestCollection> tests; + +std::set<std::string> mpfrconst_set; + +struct section_data +{ + std::string test_list; + std::string definitions; + std::map<std::string, std::string> namespace_functions; +}; +std::map<std::string, section_data> define_sections; + +std::string default_function_section; +std::map<std::string, std::pair<std::string, std::string> > class_declarations; + +std::string TranslateString(const std::string& str); + +static const char cbuf[] = +"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; + +template<typename CharT> +void +str_replace_inplace(std::basic_string<CharT>& where, + const std::basic_string<CharT>& search, + const std::basic_string<CharT>& with) +{ + for(typename std::basic_string<CharT>::size_type a = where.size(); + (a = where.rfind(search, a)) != where.npos; + ) + { + where.replace(a, search.size(), with); + if(a--==0) break; + } +} + + +void ListTests(std::ostream& outStream) +{ + unsigned DefineCounter=0; + std::map<std::string, std::string> TestDefines; + + for(std::map<std::string, TestCollection>::const_iterator + i = tests.begin(); + i != tests.end(); + ++i) + { + std::ostringstream listbuffer; + + const std::string& type = i->first; + std::string defines = GetDefinesFor(type); + size_t n_tests = i->second.size(); + + listbuffer << "\n"; + + //listbuffer << "#define Value_t " << type << "\n"; + listbuffer << + "template<>\n" + "const TestType<Value_t>\n" + " RegressionTests<Value_t>::Tests[]"; + if(n_tests == 0) + { + listbuffer << + " = { TestType<Value_t>() };\n"; + } + else + { + listbuffer << " =\n{\n"; + for(size_t a=0; a<n_tests; ++a) + { + const TestData& testdata = i->second[a]; + + std::ostringstream linebuf; + + std::ostringstream ranges; + const char* rangesdata = testdata.ParamValueRanges.c_str(); + while(*rangesdata) + { + char* endptr = 0; + std::strtod(rangesdata, &endptr); + if(endptr && endptr != rangesdata) + { + /* Complex number support: */ + if(*endptr == 'i' || *endptr == 'I') + ++endptr; + else if(*endptr == '+' || *endptr == '-') + { + std::strtod(endptr, &endptr); + if(*endptr == 'i' || *endptr == 'I') ++endptr; + } + ranges << NumConst(type, std::string(rangesdata,endptr-rangesdata)); + rangesdata = endptr; + } + else + ranges << *rangesdata++; + } + + int n_duplicates = (int)testdata.DataTypes.size(); + + linebuf + << " { " << testdata.ParamAmount + << ", " << ranges.str() + << ", " << (testdata.UseDegrees ? "true" : "false") + << ", " << testdata.TestFuncName + << ","; + + if(/*type == "MpfrFloat" + &&*/ testdata.DataTypes.find("double") + != testdata.DataTypes.end()) + { + // If the same test is defined for both "double" and + // "MpfrFloat", include an extra pointer to the "double" + // test in the "MpfrFloat" test. + linebuf << "DBL_ONLY(" << testdata.TestFuncName << ")"; + //n_duplicates = 1; + } + else + linebuf << "DBL_ONLY(0)"; + + if(/*type == "GmpInt" + &&*/ testdata.DataTypes.find("long") + != testdata.DataTypes.end()) + { + // If the same test is defined for both "long" and + // "GmpInt", include an extra pointer to the "long" + // test in the "GmpInt" test. + linebuf << "LNG_ONLY(" << testdata.TestFuncName << ")"; + //n_duplicates = 1; + } + else + linebuf << "LNG_ONLY(0)"; + + linebuf + << "\n " << TranslateString(testdata.ParamString) + << ", " << TranslateString(testdata.TestName) + << ", " << TranslateString(testdata.FuncString) + << " },\n"; + + /*if(testdata.DataTypes.find("double") + != testdata.DataTypes.end() + && testdata.DataTypes.find("MpfrFloat") + != testdata.DataTypes.end()) + { + --n_duplicates; + } + if(testdata.DataTypes.find("long") + != testdata.DataTypes.end() + && testdata.DataTypes.find("GmpInt") + != testdata.DataTypes.end()) + { + --n_duplicates; + }*/ + + if(!testdata.IfDef.empty()) + listbuffer << "#if " << testdata.IfDef << "\n"; + + if(n_duplicates > 1) + { + std::string teststr(linebuf.str()); + std::map<std::string, std::string>::iterator + i = TestDefines.lower_bound(teststr); + if(i == TestDefines.end() || i->first != teststr) + { + char MacroName[32], *m = MacroName; + unsigned p = DefineCounter++; + *m++ = "STUWY"[p%5]; p/=5; + for(; p != 0; p /= 63) + *m++ = cbuf[p % 63]; + *m++ = '\0'; + TestDefines.insert(i, std::pair<std::string,std::string> + (teststr, MacroName)); + + str_replace_inplace(teststr, + std::string("\n"), std::string(" ")); + /*while(!teststr.empty() && (teststr[teststr.size()-1]==' ' + || teststr[teststr.size()-1]==',')) + teststr.erase(teststr.size()-1); + */ + outStream << "#define " << MacroName << " " << teststr << "\n"; + listbuffer << MacroName << "\n"; + } + else + listbuffer << i->second << "\n"; + } + else + { + listbuffer << linebuf.str(); + } + + if(!testdata.IfDef.empty()) + listbuffer << "#endif /*" << testdata.IfDef << " */\n"; + } + listbuffer << " TestType<Value_t>()\n};\n"; + } + + //listbuffer << "#undef Value_t\n"; + define_sections[defines].test_list += listbuffer.str(); + } +} + +void CompileFunction(const char*& funcstr, const std::string& eval_name, + std::ostream& declbuf, + std::ostream& codebuf, + const std::string& limited_to_datatype) +{ + static unsigned BufCounter = 0; + + unsigned depth = 0; + + while(*funcstr && *funcstr != '}' && (*funcstr != ',' || depth>0)) + { + if(strncmp(funcstr, "EVAL", 4) == 0) + { + codebuf << eval_name; + funcstr += 4; + continue; + } + if(funcstr[0] == '(' && funcstr[1] == '{') + { + codebuf << "<Value_t>("; + funcstr += 2; + unsigned NParams = 0; + std::string BufName; + + codebuf << "("; + for(;;) + { + while(std::isspace(*funcstr)) ++funcstr; + if(!*funcstr) break; + if(*funcstr == '}') { ++funcstr; break; } + + ++NParams; + if(NParams == 1) + { + std::ostringstream BufNameBuf; + BufNameBuf << "b" << BufCounter++; + BufName = BufNameBuf.str(); + } + + codebuf << BufName << "[" << (NParams-1) << "]=("; + + CompileFunction(funcstr, eval_name, + declbuf, codebuf, limited_to_datatype); + + codebuf << "), "; + if(*funcstr == ',') ++funcstr; + } + + if(NParams) + { + declbuf << " Value_t " << BufName << "[" << NParams << "];\n"; + codebuf << BufName; + } + else + { + codebuf << "0"; + } + codebuf << "))"; + while(std::isspace(*funcstr)) ++funcstr; + if(*funcstr == ')') ++funcstr; + } + else + { + if(*funcstr == '(') ++depth; + if(*funcstr == ')') --depth; + + char* endptr = 0; + if((*funcstr >= '0' && *funcstr <= '9') + || *funcstr == '.' + || (*funcstr == '-' && funcstr[-1] == '(') + ) + std::strtod(funcstr, &endptr); + if(endptr && endptr != funcstr) + { + if(limited_to_datatype == "MpfrFloat") + { + std::string num(funcstr, endptr-funcstr); + char* endptr2 = 0; + strtol(funcstr, &endptr2, 0); + //fprintf(stderr, "<%s>:<%s>\n", funcstr, endptr2); + if(endptr2==endptr-2 && std::strncmp(endptr2, ".0", 2) == 0) + { + num.erase(num.size()-2, 2); // made-int + codebuf << "Value_t(" << num << ")"; + } + else if(endptr2 && endptr2 == endptr) // an int or long + { + codebuf << "Value_t(" << num << ")"; + } + else + { + std::string mpfrconst_name = "mflit" + num; + str_replace_inplace(mpfrconst_name, std::string("."), std::string("_")); + str_replace_inplace(mpfrconst_name, std::string("+"), std::string("p")); + str_replace_inplace(mpfrconst_name, std::string("-"), std::string("m")); + + if(mpfrconst_set.insert(mpfrconst_name).second) + { + std::string& defs = define_sections["FP_TEST_WANT_MPFR_FLOAT_TYPE"].definitions; + if(defs.empty()) + defs += "static const Value_t "; + else + { + defs.erase(defs.size()-2, 2); /* Remove ";\n" */ + defs += ",\n "; + } + defs += mpfrconst_name + "(\"" + num + "\", 0);\n"; + } + codebuf << mpfrconst_name; + } + //if(*endptr == 'f' || *endptr == 'l') ++endptr; + } + else + { + std::string num(funcstr, endptr-funcstr); + if(limited_to_datatype.empty()) + codebuf << "Value_t(" << num << "l)"; + else + codebuf << NumConst(limited_to_datatype, num, true); + /* + if(*endptr == 'f' || *endptr == 'l') + num += *endptr++; + else + num += 'l'; + codebuf << "Value_t(" << num << ")"; + */ + } + funcstr = endptr; + } + else if((*funcstr >= 'A' && *funcstr <= 'Z') + || (*funcstr >= 'a' && *funcstr <= 'z') + || *funcstr == '_') + { + do { + codebuf << *funcstr++; + } while((*funcstr >= 'A' && *funcstr <= 'Z') + || (*funcstr >= 'a' && *funcstr <= 'z') + || (*funcstr >= '0' && *funcstr <= '9') + || *funcstr == '_'); + } + else + codebuf << *funcstr++; + } + } +} + +std::string ReplaceVars(const char* function, + const std::map<std::string, std::string>& var_trans) +{ + std::string result = function; + + for(std::map<std::string, std::string>::const_iterator + i = var_trans.begin(); + i != var_trans.end(); + ++i) + { + str_replace_inplace(result, i->first, i->second); + } + + return result; +} + +//std::string StringBuffer; +std::string TranslateString(const std::string& str) +{ + std::string val = str; + str_replace_inplace(val, std::string("/"), std::string("\"\"/\"\"")); + str_replace_inplace(val, std::string("+"), std::string("\"\"+\"\"")); + str_replace_inplace(val, std::string("*"), std::string("\"\"*\"\"")); + str_replace_inplace(val, std::string("x"), std::string("\"\"x\"\"")); + str_replace_inplace(val, std::string("&"), std::string("\"\"&\"\"")); + str_replace_inplace(val, std::string("("), std::string("\"\"(\"\"")); + str_replace_inplace(val, std::string(")"), std::string("\"\")\"\"")); + str_replace_inplace(val, std::string("pow"), std::string("\"\"pow\"\"")); + str_replace_inplace(val, std::string("sin"), std::string("\"\"sin\"\"")); + if(val[0] == '"') val.erase(0,1); else val.insert(val.begin(), '"'); + if(val[val.size()-1] == '"') val.erase(val.size()-1, 1); else val += '"'; + str_replace_inplace(val, std::string("\"\"\"\""), std::string("")); + return val; + /* + if(str.size() <= 6) + { + return '"' + str + '"'; + } + std::string keyword = str; + keyword += '\0'; + size_t p = StringBuffer.find(keyword); + if(p == StringBuffer.npos) + { + p = StringBuffer.size(); + StringBuffer += keyword; + } + char Buf[128]; + std::sprintf(Buf, "ts+%u", (unsigned)p); + return Buf; + */ +} +/* +void MakeStringBuffer(std::ostream& out) +{ + size_t pos = 26; bool quote = false; + out << "const char ts[" << StringBuffer.size() << "] = "; + for(size_t a=0; a < StringBuffer.size(); ++a) + { + //if(pos >= 70) { if(quote) { quote=false; out << '"'; } out << "\n"; pos = 0; } + if(!quote) { quote=true; out << '"'; ++pos; } + if(StringBuffer[a] == '\0') + { out << "\\0"; pos += 2; + if(a+1 < StringBuffer.size() + && std::isdigit(StringBuffer[a+1])) + { out << '"'; quote=false; ++pos; } + } + else + { out << StringBuffer[a]; pos += 1; + if(StringBuffer[a] == '/') + { out << '"'; quote=false; ++pos; } + } + } + if(quote) out << '"'; + out << ";\n"; +}*/ + +std::pair<std::string, std::string> + MakeFuncName(const std::string& testname) +{ +#if 0 + static unsigned counter = 0; + std::string result = "qZ"; + for(unsigned p = counter++; p != 0; p /= 63) + result += cbuf[p % 63]; + return result; +#else + std::string base = "cpp/" + testname; + + size_t p = base.rfind('/'); + std::string classname = base.substr(0, p); + std::string methodname = base.substr(p+1); + str_replace_inplace(classname, std::string("/"), std::string("_")); + str_replace_inplace(methodname, std::string("/"), std::string("_")); + // Change the method name to prevent clashes with + // with reserved words or the any namespace + if(isdigit(methodname[0])) + methodname.insert(0, "t"); + else + methodname[0] = (char)std::toupper(methodname[0]); + return std::make_pair(classname, methodname); +#endif +} + +void CompileTest(const std::string& testname, FILE* fp) +{ + char Buf[4096]={0}; + std::string linebuf; + + TestData test; + std::set<std::string> DataTypes; + + test.TestName = testname; + str_replace_inplace(test.TestName, std::string("tests/"), std::string("")); + + std::ostringstream declbuf; + + std::map<std::string, std::string> var_trans; + + std::string limited_to_datatype; + + unsigned linenumber = 0; + while(fgets(Buf,sizeof(Buf)-1,fp)) + { + ++linenumber; + const char* line = Buf; + while(*line == ' ' || *line == '\t') ++line; + std::strtok(Buf, "\r"); + std::strtok(Buf, "\n"); + + const char* backslash = std::strchr(line, '\\'); + if(backslash && backslash[1] == '\0') + { + linebuf = ""; + for(;;) + { + // Append the line, sans backslash + linebuf.append(line, backslash-line); + linebuf += ' '; + + if(!fgets(Buf,sizeof(Buf)-1,fp)) break; + ++linenumber; + const char* line = Buf; + while(*line == ' ' || *line == '\t') ++line; + std::strtok(Buf, "\r"); + std::strtok(Buf, "\n"); + backslash = std::strchr(line, '\\'); + + if(backslash && backslash[1] == '\0') + continue; + + // add the final, backslash-less line + linebuf += line; + break; + } + line = linebuf.c_str(); + } + else + { + // no backslash on the line + linebuf = Buf; + } + + const char* valuepos = std::strchr(line, '='); + if(valuepos) + { + ++valuepos; + while(*valuepos == ' ' || *valuepos == '\t') ++valuepos; + } + + switch(line[0]) + { + case '#': + continue; // comment line + case '\0': + continue; // blank line + case 'D': // test define condition + if(line[1] == 'E') + test.UseDegrees = true; + else if(valuepos) + test.IfDef = valuepos; + break; + case 'T': // list of applicable types + if(valuepos) + { + for(;;) + { + while(*valuepos == ' ') ++valuepos; + if(!*valuepos) break; + + const char* space = std::strchr(valuepos, ' '); + if(!space) space = std::strrchr(valuepos, '\0'); + std::string type(valuepos, space); + + DataTypes.insert(GetTypeFor(type)); + + valuepos = space; + } + + if(DataTypes.size() == 1) + limited_to_datatype = *DataTypes.begin(); + + test.DataTypes = DataTypes; + } + break; + case 'V': // variable list + if(valuepos) + { + test.ParamString = valuepos; + test.ParamAmount = test.ParamString.empty() ? 0 : 1; + + const char* begin = valuepos; + + std::vector<std::string> vars; + + for(; *valuepos; ++valuepos) + if(*valuepos == ',') + { + vars.push_back( std::string(begin,valuepos-begin) ); + begin = valuepos+1; + ++test.ParamAmount; + } + + if(begin != valuepos) + vars.push_back(begin); + + bool outputted_line_stmt = false; + + for(size_t a=0; a<vars.size(); ++a) + { + std::string oldvarname = vars[a]; + std::string newvarname = vars[a]; + bool needs_replacement = false; + for(size_t b=0; b<oldvarname.size(); ++b) + { + char c = oldvarname[b]; + if((c >= '0' && c <= '9') + || c == '_' + || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z')) continue; + needs_replacement = true; break; + } + if(needs_replacement) + { + static unsigned var_counter = 0; + std::ostringstream varnamebuf; + varnamebuf << "rvar" << var_counter++; + newvarname = varnamebuf.str(); + var_trans[oldvarname] = newvarname; + } + + if(!outputted_line_stmt) + { + outputted_line_stmt = true; + //declbuf << "#line " << linenumber << " \"" << testname << "\"\n"; + declbuf << " const Value_t"; + } + else + declbuf << ","; + declbuf << " &" << newvarname + << " = vars[" << a << "]"; + } + if(outputted_line_stmt) + declbuf << ";\n"; + } + break; + case 'R': // parameter value ranges + if(valuepos) + test.ParamValueRanges = valuepos; + break; + case 'F': // the function string + if(valuepos) + test.FuncString = valuepos; + break; + case 'C': // the C++ template function + if(valuepos) + { + std::string Replaced; + if(!var_trans.empty()) + { + Replaced = ReplaceVars(valuepos, var_trans); + valuepos = Replaced.c_str(); + } + + std::pair<std::string,std::string> + funcname = MakeFuncName(test.TestName); + test.TestFuncName = funcname.first+"::"+funcname.second; + + bool includes_mpfr = DataTypes.find("MpfrFloat") != DataTypes.end(); + bool unitype = DataTypes.size() == 1; + + //bool has_generic = false; + + if(!unitype || !includes_mpfr) + { + std::ostringstream declbuf1, codebuf1; + declbuf1 << declbuf.str(); + //declbuf1 << "#line " << linenumber << " \"" << testname << "\"\n"; + + const char* valuepos_1 = valuepos; + CompileFunction(valuepos_1, funcname.second, declbuf1, codebuf1, + limited_to_datatype); + + std::string code = codebuf1.str(); + std::string bodystr = + "{\n" + + declbuf1.str() + + " return " + code + ";\n" + "}\n"; + + if(limited_to_datatype.empty() || limited_to_datatype == "double") + { + define_sections[""] + .namespace_functions[funcname.first] + += test_declaration(funcname.second) + "\n" + bodystr; + //has_generic = true; + } + else + { + define_sections[GetDefinesFor(limited_to_datatype)] + .namespace_functions[funcname.first] += + test_specialized_declaration(funcname.second, limited_to_datatype) + + "\n" + bodystr; + } + } + else + { + // When it's mpfr-only + //class_declarations[funcname.first].first += + // test_declaration(funcname.second) + ";\n"; + } + + if(includes_mpfr) + { + std::ostringstream declbuf2, codebuf2; + declbuf2 << declbuf.str(); + //declbuf2 << "#line " << linenumber << " \"" << testname << "\"\n"; + + CompileFunction(valuepos, funcname.second, + declbuf2, codebuf2, "MpfrFloat"); + + if(codebuf2.str().find("mflit") != codebuf2.str().npos + || unitype) + { + std::string code = codebuf2.str(); + str_replace_inplace(code, std::string("MpfrFloat"), std::string("Value_t")); + + std::string bodystr2 = + "{\n" + + declbuf2.str() + + " return " + code + ";\n" + "}\n"; + + std::ostringstream out2; + + if(!test.IfDef.empty()) + out2 << "#if " << test.IfDef << "\n"; + + /*if(has_generic) + out2 << test_specialization(funcname.second, "MpfrFloat") << "\n"; + else*/ + out2 << test_specialized_declaration(funcname.second, "MpfrFloat") << "\n"; + out2 << bodystr2; + + if(!test.IfDef.empty()) + out2 << "#endif /* " << test.IfDef << " */\n"; + + define_sections["FP_TEST_WANT_MPFR_FLOAT_TYPE"] + .namespace_functions[funcname.first] += out2.str(); + } + } + } + break; + } + } + + for(std::set<std::string>::const_iterator + i = DataTypes.begin(); + i != DataTypes.end(); + ++i) + { + tests[*i].push_back(test); + } +} + +/* Asciibetical comparator, with in-string integer values sorted naturally */ +bool natcomp(const std::string& a, const std::string& b) +{ + size_t ap=0, bp=0; + while(ap < a.size() && bp < b.size()) + { + if(a[ap] >= '0' && a[ap] <= '9' + && b[bp] >= '0' && b[bp] <= '9') + { + unsigned long aval = (a[ap++] - '0'); + unsigned long bval = (b[bp++] - '0'); + while(ap < a.size() && a[ap] >= '0' && a[ap] <= '9') + aval = aval*10ul + (a[ap++] - '0'); + while(bp < b.size() && b[bp] >= '0' && b[bp] <= '9') + bval = bval*10ul + (b[bp++] - '0'); + if(aval != bval) + return aval < bval; + } + else + { + if(a[ap] != b[ap]) return a[ap] < b[ap]; + ++ap; ++bp; + } + } + return (bp < b.size() && ap >= a.size()); +} + +#include "../util/cpp_compress.hh" + +int main(int argc, char* argv[]) +{ + const char* outputFileName = 0; + std::ofstream outputFileStream; + + std::ostringstream out; + + std::vector<std::string> files; + + for(int a=1; a<argc; ++a) + { + if(std::strcmp(argv[a], "-o") == 0) + { + if(++a == argc) + { + std::cerr << "Expecting output file name after -o\n"; + return 1; + } + outputFileName = argv[a]; + outputFileStream.open(argv[a]); + if(!outputFileStream) + { + std::cerr << "Could not write to " << argv[a] << "\n"; + return 1; + } + continue; + } + + std::string fn ( argv[a] ); + if(fn.empty()) continue; + + if(fn[fn.size()-1] == '~') continue; // ignore backup files + if(fn[0] == '.') continue; // ignore special files + + files.push_back(fn); + } + + std::ostream& outStream = outputFileName ? outputFileStream : std::cout; + //const char* outStreamName = outputFileName ? outputFileName : "<stdout>"; + + std::sort(files.begin(), files.end(), natcomp); + + for(size_t a=0; a<files.size(); ++a) + { + FILE* fp = std::fopen(files[a].c_str(), "rt"); + if(!fp) + { + std::perror(files[a].c_str()); + continue; + } + CompileTest(files[a], fp); + fclose(fp); + } + + out << + "#ifdef FP_TEST_WANT_DOUBLE_TYPE\n" + " #define DBL_ONLY(p) p,\n" + "#else\n" + " #define DBL_ONLY(p)\n" + "#endif\n" + "\n" + "#ifdef FP_TEST_WANT_LONG_INT_TYPE\n" + " #define LNG_ONLY(p) p,\n" + "#else\n" + " #define LNG_ONLY(p)\n" + "#endif\n" + "\n" + "#define APP(x,y) x##y\n"; + for(std::map<std::string, std::pair<std::string,std::string> >::const_iterator + i = class_declarations.begin(); + i != class_declarations.end(); + ++i) + { + std::string decls = i->second.first + i->second.second; + define_sections[""].namespace_functions[i->first].insert(0, decls); + } + + ListTests(out); + + for(std::map<std::string, section_data>::const_iterator + i = define_sections.begin(); i != define_sections.end(); ++i) + { + const std::string type = GetTypeForDefine(i->first); + if(!i->first.empty()) + out << "\n#ifdef " << i->first << "\n"; + + out << NumConstDefines(type) << "\n"; + + if(i->first != "") out << "#define Value_t " + type + "\n"; + + out << i->second.definitions; + + for(std::map<std::string, std::string>::const_iterator + j = i->second.namespace_functions.begin(); + j != i->second.namespace_functions.end(); + ++j) + { + std::string nscontent = j->second; + str_replace_inplace(nscontent, std::string("\n"), std::string("\n ")); + + out << "namespace " << j->first << "\n" + "{\n" + " using namespace FUNCTIONPARSERTYPES;\n " + << nscontent << "\n}\n"; + } + + if(i->first == "") out << "#define Value_t " + type + "\n"; + + out << i->second.test_list; + out << "#undef Value_t\n"; + out << NumConstUndefines(type); + + if(!i->first.empty()) + out << "#endif /*" << i->first << " */\n"; + } + + //MakeStringBuffer(out); + //outStream << "extern const char ts[" << StringBuffer.size() << "];\n"; + + CPPcompressor Compressor; + + //outStream << out.str(); + outStream << Compressor.Compress(out.str()); + + return 0; +} diff --git a/tests/test_file_syntax.txt b/tests/test_file_syntax.txt new file mode 100644 index 0000000..f5aaa6a --- /dev/null +++ b/tests/test_file_syntax.txt @@ -0,0 +1,176 @@ +Each file documents a distinct function to test, and the conditions for testing. + +------------------------- +D=defined(CONSTANT1) && !defined(CONSTANT2) +------------------------- + +Optional. +This line can be used to specify compile-time conditions which +determine whether this rule should be tested at all. +If your line is "D=xxx", the rule will be handled +as if enclosed in "#if xxx" ... "#endif". + +This line, if used, must be indicated before the C line. + +------------------------- +T=d f ld mf li gi +------------------------- + +Mandatory! +A line beginning with "T=" describes which datatypes this rule applies to. + d=double + f=float + ld=long double + mf=mpfr float + li=long int + gi=gmp int + +------------------------- +DEG=true +------------------------- + +Optional. +This line, when exists, specifies that degrees conversion is to be +requested from fparser. In the C++ function you must do your own +degrees conversions. + + +------------------------- +V=x,y,z +------------------------- + +Mandatory! +This lists the parameters (variables) for the function. +The number of parameters is automatically deduced from this. +The variable names are to be written in a format accepted by fparser. +If they are not valid C++ variable names, make_tests will rename them +transparently. + +This line, must be indicated before the C line. + + +------------------------- +R=-100, 100, 0.5 +------------------------- + +Mandatory! +This specifies the minimum, the maximum, and the step value +that are used for iterating through the function parameters +in the testing procedure. + + +------------------------- +F=x+y+z +------------------------- + +Mandatory! +This specifies the fparser function to test. + +You can use \ to continue the function to the next line. + + +------------------------- +C=x+y+z +------------------------- + +Mandatory! +This specifies the C++ function expression that corresponds +the fparser function. You do not need to typecast your numeric +constants; casts will be automatically added by make_tests. + +You can use \ to continue the function to the next line. + +The expression must not be a full statement; make_tests will +automatically prefix it with "return " and add a ";" at the +end of it. + +------------------------ +Calling PCall functions in the C++ code +----------------------- +In order to call PCall functions in the C++ code, +use this syntax: + + userDefFuncSub({x+1, y-1}) + +This is equivalent to the fparser function Sub(x+1, y-1). + +make_tests will automatically translate this to code that +sets up an array for the function parameters, and will place +the expressions in that array, and pass the array pointer +to the function as a parameter. + + + +------------------------ +Using recursion in the C++ code +----------------------- +In order to recurse in the C++ code, +use this syntax: + + Eval({x+1, y-1}) + +This is equivalent to the fparser function eval(x+1, y-1). + +make_tests will automatically translate this to code that +sets up an array for the function parameters, and will place +the expressions in that array, and pass the array pointer +to the same function as a parameter. + + +------------------------ +Which tests go where +------------------------ + +01unit_operators: + These tests test each basic operator in the most + simple manner possible. The C++ functions used + to verify the operators should not use code that + depends on portions of fparser being implemented + correctly. + +02unit_functions: + These tests test each built-in function in the + most simple manner possble. The C++ functions used + to verify the operators should not use code that + depends on portions of fparser being implemented + correctly, aside from basic operators. + I.e. to test sin(), don't use fp_sin() to verify + it; verify it against math library's sin(), sinf(), + etc. directly. + +03unit_constants: + These tests verify that the fp_const_* functions + produce mathematically correct values. + +10optimizer_bytecode: + Unit tests for each bytecode optimization done + by the parser itself. + +11optimizer_constaddmul: + Unit tests for those bytecode optimizations done + by the parser itself, which pertain to the grouping + of numeric literal values. + +20optimizer_optimizations: + Testcases for categorigally each fpoptimizer optimization. + (Incomplete) + +21optimizer_trigcombinations: + This is a machine generated list of tests that stress + all combinations of sin/cos/tan/sinh/cos/tanh/exp + with exponents -2..+2 in multiplications and additions, + to catch any misoperations thereof. It is easy to + get them wrong, so an exhaustive testing is justified. + +50regressions: + Tests in this directory target specific bugs which + have been discovered. The test should contain nothing + but the minimal code to trigger the bug. + The test file should document the bug. + +99misc: + Put here tests which don't belong in other categories. + In the C++ functions, use the type-agnostic fp_* functions + to reduce the need to implement different versions for + each type. The validity of each fp_* function is expected + to have been verified in the unit tests. diff --git a/util/bytecoderules.dat b/util/bytecoderules.dat new file mode 100644 index 0000000..6584c54 --- /dev/null +++ b/util/bytecoderules.dat @@ -0,0 +1,513 @@ +# This documents all the optimizations that are done to bytecode +# by fparser.cc directly while parsing the input function +# (excluding powi). + +# identifiers: lowercase=cImmeds, uppercase=opcodes +# [bracketed expression in condition]: constraints to input immeds or opcodes +# [bracketed expression in replacement]: function that produces an immed +# {braceted expression in replacement}: function that produces an opcode + +# +# The comment tag "#TEST pathlet" indicates the test(s) that apply +# to this particular rule. Note that the tests only test that this +# rule does not _break_ anything (they try to invoke the rule), +# but they don't test whether the rule is actually applied +# and that the rule has the intended effect. +# + +#y [isEvenInteger(y)&&!isEvenInteger(x*y)] cExp x cPow -> cAbs [y*x] cExp +#y [isEvenInteger(y)&&!isEvenInteger(x*y)] cExp2 x cPow -> cAbs [y*x] cExp2 +# ^ y cExp never occurs (already optimized to literal) +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [isEvenInteger(y)&&!isEvenInteger(x*y)] cPow x cPow -> cAbs [y*x] cPow #TEST 10/absyxpow_neg, 10/absyxpow_pos +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr x [!isEvenInteger(x+x)] cPow -> cAbs [x+x] cPow +IF(FP_FLOAT_VERSION) cSqr cSqrt -> cAbs # TEST 10/sqrsqrt +#IF(FP_FLOAT_VERSION) cSqr cRSqrt -> cAbs cInv + + # (x^y)^1.5 is unacceptable, + # for y might be 2, resulting in x^3 + # f(-2) = 8 + # f'(-2) = -8 + # (x^y)^5 is okay + # for y might be 1.2, resulting in x^6 + # f(-2) = nan + # f'(-2) = 64 + # (x^y)^2 is okay, + # for y might be 1.5, resulting in x^3 + # f(-2) = nan <- ok because of this + # f'(-2) = -8 + # +#y [!isInteger(y)] cExp x [isInteger(x)] cPow -> [y*x] cExp +#y [!isInteger(y)] cExp2 x [isInteger(x)] cPow -> [y*x] cExp2 +# ^ y cExp never occurs (already optimized to literal) +IF(FP_FLOAT_VERSION) y [!isInteger(y)] cPow x [isInteger(x)] cPow -> [y*x] cPow # TEST 10/ypowxpow +IF(FP_FLOAT_VERSION) cExp x [isInteger(x)] cPow -> [x] cMul cExp # TEST 10/expxpow +IF(FP_FLOAT_VERSION) cExp2 x [isInteger(x)] cPow -> [x] cMul cExp2 # TEST 10/exp2xpow +IF(FP_FLOAT_VERSION) cPow x [isInteger(x)] cPow -> [x] cMul cPow # TEST 10/powxpow +IF(FP_FLOAT_VERSION) cSqr x cPow -> [x+x] cPow #TEST 10/sqrxpow, 10/sqrxpow_nonint + +# This rule does not speed up evaluation at all, but +# it greatly simplifies the optimization rule set, when +# we don't need to check for sequences of an immed and cSub. +x cSub -> [-x] cAdd # TEST 10/immsub + +###### REMOVING IDLE OPERATIONS : + +x [x==Value_t(1)] cMul -> # TEST 10/mul1 +x [x==Value_t(1)] cDiv -> # TEST 10/div1 +x [x==Value_t()] cAdd -> # TEST 10/add0 +x [x==Value_t()] cSub -> # TEST 10/sub0 +cDup cMin -> # TEST 10/dupminmax +cDup cMax -> # TEST 10/dupminmax +cNeg cNeg -> # TEST 10/negneg +IF(FP_FLOAT_VERSION) cInv cInv -> # TEST 10/invinv +IF(FP_COMPLEX_VERSION) cConj cConj -> + +B [B==A] cDup A [IsVarOpcode(A)] cMin -> B cDup # TEST 10/dupminmax2 +B [B==A] cDup A [IsVarOpcode(A)] cMax -> B cDup # TEST 10/dupminmax2 +B [B==A] cMin A [IsVarOpcode(A)] cMin -> B cMin # TEST 10/dupminmax3 +B [B==A] cMax A [IsVarOpcode(A)] cMax -> B cMax # TEST 10/dupminmax3 + +y [y*x==Value_t(1)] cMul x cMul -> # TEST 10/mul1b + +###### OPERATIONS WHICH PRODUCE A CONSTANT VALUE: +###### An expression is turned into a constant value +###### by multiplying it with zero and adding the constant. + +cDup cSub -> [Value_t()] cMul # TEST 10/subxx +cDup cRSub -> [Value_t()] cMul # TEST 10/subxx +cDup cDiv -> [Value_t()] cMul [Value_t(1)] cAdd # TEST 10/divxx + +IF(FP_COMPLEX_VERSION) cReal cImag -> [Value_t()] cMul +IF(FP_COMPLEX_VERSION) cAbs cImag -> [Value_t()] cMul + +IF(FP_FLOAT_VERSION) x [x==Value_t()] cPow -> [Value_t()] cMul [Value_t(1)] cAdd +IF(FP_FLOAT_VERSION) cSinCos cHypot -> [Value_t()] cMul [Value_t(1)] cAdd # TEST 99/59 + +# Multiplications by zero: Undo as many operands as possible by peeling. +# Some of these optimimizations can be disabled due to law of diminishing returns. +A [IsVarOpcode(A)] x [x==Value_t()] cMul -> [x] # TEST 10/mul_zero VERIFY + A [IsUnaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> [x] cMul # TEST 10/mul_zero VERIFY +B [IsVarOpcode(B)] A [IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> [x] cMul # TEST 10/mul_zero VERIFY +B [IsUnaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A [IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> A [x] cMul # TEST 10/mul_zero VERIFY +y A [IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> [x] cMul # TEST 10/mul_zero VERIFY +A [IsVarOpcode(A)] cMul x [x==Value_t()] cMul -> [x] cMul # TEST 10/mul_zero VERIFY +C [IsVarOpcode(C)] B [IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> A [x] cMul # TEST 10/mul_zero VERIFY +C [IsUnaryOpcode(C)&&!HasInvalidRangesOpcode(C)] B [IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> B A [x] cMul # TEST 10/mul_zero VERIFY +y B [IsBinaryOpcode(B)&&!HasInvalidRangesOpcode(B)] A[IsBinaryOpcode(A)&&!HasInvalidRangesOpcode(A)] x [x==Value_t()] cMul -> A [x] cMul # TEST 10/mul_zero VERIFY + +###### INLINE EXPANSION OF BASIC OPERATORS : + +x cNeg -> [-x] # TEST 10/neg +x [x!=Value_t()] cInv -> [Value_t(1)/x] +y x cMul -> [y*x] # TEST 10/mul +y x [x!=Value_t()] cDiv -> [y/x] # TEST 10/div +y x [x!=Value_t()] cMod -> [fp_mod(y,x)] # TEST 10/mod +y x cAdd -> [y+x] # TEST 10/add +y x cSub -> [y-x] # TEST 10/sub +x cNot -> [fp_not(x)] # TEST 10/not +#y [y!=Value_t()] x cRDiv -> [x/y] +#y x cRSub -> [x-y] + +y x cLess -> [fp_less(y,x)] # TEST 10/cmplt +y x cLessOrEq -> [fp_lessOrEq(y,x)] # TEST 10/cmple +y x cGreater -> [fp_less(x,y)] # TEST 10/cmpgt +y x cGreaterOrEq -> [fp_lessOrEq(x,y)] # TEST 10/cmpge +y x cEqual -> [fp_equal(y,x)] # TEST 10/cmpeq +y x cNEqual -> [fp_nequal(y,x)] # TEST 10/cmpne +y x cAnd -> [fp_and(x,y)] # TEST 10/and +y x cOr -> [fp_or(x,y)] # TEST 10/or +#y x cAbsAnd -> [fp_absAnd(x,y)] +#y x cAbsOr -> [fp_absOr(x,y)] + +cNeg x cMul -> [-x] cMul # TEST 10/negmul +x cMul cNeg -> [-x] cMul # TEST 10/mulneg +x [x==Value_t(-1)] cMul -> cNeg # TEST 10/mulminus1 +cNeg x [x!=Value_t()] cDiv -> [-x] cDiv # TEST 10/negdiv + +y cAdd x cAdd -> [y+x] cAdd # TEST 11/42 +y cMul x cMul -> [y*x] cMul # TEST 11/43 + +###### INLINE EXPANSION OF BASIC FUNCTIONS : + +x cAbs -> [fp_abs(x)] # TEST 10/abs +IF(FP_FLOAT_VERSION) x cDeg -> [RadiansToDegrees(x)] # TEST 10/deg +IF(FP_FLOAT_VERSION) x cRad -> [DegreesToRadians(x)] # TEST 10/rad +IF(FP_FLOAT_VERSION) x cCeil -> [fp_ceil(x)] # TEST 10/ceil* +IF(FP_FLOAT_VERSION) x cFloor -> [fp_floor(x)] # TEST 10/floor* +IF(FP_FLOAT_VERSION) x cInt -> [fp_int(x)] # TEST 10/int +IF(FP_FLOAT_VERSION) x cTrunc -> [fp_trunc(x)] # TEST 10/runc* +IF(FP_FLOAT_VERSION) y x cAtan2 -> [fp_atan2(y,x)] # TEST 10/atan2* +y x cMin -> [fp_min(x,y)] # TEST 10/min +y x cMax -> [fp_max(x,y)] # TEST 10/max + +##### REAL VERSIONS: + +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x>=Value_t(1)] cAcosh -> [fp_acosh(x)] # TEST 10/acosh* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAsinh -> [fp_asinh(x)] # TEST 10/asinh* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [fp_abs(x)< Value_t(1)] cAtanh -> [fp_atanh(x)] # TEST 10/atanh* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [fp_abs(x)<=Value_t(1)] cAcos -> [fp_acos(x)] # TEST 10/acos* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [fp_abs(x)<=Value_t(1)] cAsin -> [fp_asin(x)] # TEST 10/asin* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAtan -> [fp_atan(x)] # TEST 10/atan* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCbrt -> [fp_cbrt(x)] # TEST 10/cbrt* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCos -> [fp_cos(x)] # TEST 10/cos* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCosh -> [fp_cosh(x)] # TEST 10/cosh* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp -> [fp_exp(x)] # TEST 10/exp* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp2 -> [fp_exp2(x)] # TEST 10/exp2* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x> Value_t(0)] cLog -> [fp_log(x)] # TEST 10/log* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x> Value_t(0)] cLog10 -> [fp_log10(x)] # TEST 10/log10* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x> Value_t(0)] cLog2 -> [fp_log2(x)] # TEST 10/log2* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSin -> [fp_sin(x)] # TEST 10/sin* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSinh -> [fp_sinh(x)] # TEST 10/sinh* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x>=Value_t(0)] cSqrt -> [fp_sqrt(x)] # TEST 10/sqr* +#IF(FP_FLOAT_VERSION) x [x> Value_t()] cRSqrt -> [Value_t(1)/fp_sqrt(x)] +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTan -> [fp_tan(x)] # TEST 10/tan* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTanh -> [fp_tanh(x)] # TEST 10/tanh* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [ y!=Value_t(0) || x>=Value_t(0)] x cPow -> [fp_pow(y,x)] # TEST 10/pow* + +##### COMPLEX VERSIONS: + +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAcosh -> [fp_acosh(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAsinh -> [fp_asinh(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [Value_t(fp_abs(x.real()),x.imag())!=Value_t(1,0)] cAtanh -> [fp_atanh(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAcos -> [fp_acos(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cAsin -> [fp_asin(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [Value_t(x.real(),fp_abs(x.imag()))!=Value_t(0,1)] cAtan -> [fp_atan(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCbrt -> [fp_cbrt(x)] # TEST 10/cbrt* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCos -> [fp_cos(x)] # TEST 10/cos* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cCosh -> [fp_cosh(x)] # TEST 10/cosh* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp -> [fp_exp(x)] # TEST 10/exp* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cExp2 -> [fp_exp2(x)] # TEST 10/exp2* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x!=Value_t(0)] cLog -> [fp_log(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x!=Value_t(0)] cLog10 -> [fp_log10(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x!=Value_t(0)] cLog2 -> [fp_log2(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSin -> [fp_sin(x)] # TEST 10/sin* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSinh -> [fp_sinh(x)] # TEST 10/sinh* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cSqrt -> [fp_sqrt(x)] +#IF(FP_FLOAT_VERSION) x [x> Value_t(0)] cRSqrt -> [Value_t(1)/fp_sqrt(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTan -> [fp_tan(x)] # TEST 10/tan* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cTanh -> [fp_tanh(x)] # TEST 10/tanh* +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y x cPow -> [fp_pow(y,x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x cArg -> [fp_arg(x)] +IF(FP_COMPLEX_VERSION) x cReal -> [fp_real(x)] +IF(FP_COMPLEX_VERSION) x cImag -> [fp_imag(x)] +IF(FP_COMPLEX_VERSION) x cConj -> [fp_conj(x)] +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x y cPolar -> [fp_polar(x,y)] + +###### SIMPLIFYING SOME OPCODE SEQUENCES : + +x [x==Value_t(2)] cMul -> cDup cAdd # TEST 10/mul2 +cNeg cAdd -> cSub # TEST 10/negadd +cNeg cSub -> cAdd # TEST 10/negsub +cNeg cAbs -> cAbs # TEST 10/negabs +cDup cMul -> cSqr # TEST 10/sqr_xx +cNeg cSqr -> cSqr # TEST 10/negsqr +cAbs cSqr -> cSqr # TEST 10/abssqr + +IF(FP_FLOAT_VERSION) cSqrt cInv -> cRSqrt # TEST 10/rsqrt +IF(FP_FLOAT_VERSION) x [x==fp_const_rad_to_deg<Value_t>()] cMul -> cDeg #TEST 10/deg +IF(FP_FLOAT_VERSION) x [x==fp_const_deg_to_rad<Value_t>()] cMul -> cRad #TEST 10/rad +IF(FP_FLOAT_VERSION) cDeg x cMul -> [RadiansToDegrees(x)] cMul # TEST 10/degxmul +IF(FP_FLOAT_VERSION) cRad x cMul -> [DegreesToRadians(x)] cMul # TEST 10/radxmul VERIFY +IF(FP_FLOAT_VERSION) x cMul cRad -> [DegreesToRadians(x)] cMul # TEST 10/xmulrad + +IF(FP_FLOAT_VERSION) cInv cDiv -> cMul # TEST 10/invdiv +IF(FP_FLOAT_VERSION) cInv cMul -> cDiv # TEST 10/invmul (float-only, because: y*(1/x) vs y/x) + +cLess cNot -> cGreaterOrEq # TEST 10/not_lt +cLessOrEq cNot -> cGreater # TEST 10/not_le +cGreater cNot -> cLessOrEq # TEST 10/not_gt +cGreaterOrEq cNot -> cLess # TEST 10/not_ge +cEqual cNot -> cNEqual # TEST 10/not_eq +cNEqual cNot -> cEqual # TEST 10/not_ne + +cDup cOr -> cNotNot # TEST 99/3 +cDup cAnd -> cNotNot # TEST 99/3 + +IF(!FP_COMPLEX_VERSION) cNeg cNot -> cNot # TEST 10/negnot +IF(!FP_COMPLEX_VERSION) cAbs cNot -> cNot # TEST 10/absnot + +cNot cNot -> cNotNot # TEST 10/notnot +cNotNot cNot -> cNot # TEST 10/notnotnot +cAbsNotNot cNot -> cAbsNot # TEST 10/absnotnotnot +cNot cNotNot -> cNot # TEST 10/notnotnot2 +# ^ Impossible as it seems, it is triggered by (!x & !x) -> !!(!x) + +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs cCos -> cCos # TEST 10/abscos +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs cCosh -> cCosh # TEST 10/abscosh + +IF(FP_FLOAT_VERSION) cNeg cCos -> cCos # TEST 10/negcos +IF(FP_FLOAT_VERSION) cNeg cCosh -> cCosh # TEST 10/negcosh +IF(FP_FLOAT_VERSION) cNeg cSin -> cSin cNeg # TEST 10/negsin +IF(FP_FLOAT_VERSION) cNeg cSinh -> cSinh cNeg # TEST 10/negsinh +IF(FP_FLOAT_VERSION) cNeg cTan -> cTan cNeg # TEST 10/negtan +IF(FP_FLOAT_VERSION) cNeg cTanh -> cTanh cNeg # TEST 10/negtanh +IF(FP_FLOAT_VERSION) x cMul cSin cNeg -> [-x] cMul cSin # TEST 10/xmulsinneg +IF(FP_FLOAT_VERSION) x cMul cSinh cNeg -> [-x] cMul cSinh # TEST 10/xmulsinhneg +IF(FP_FLOAT_VERSION) x cMul cTan cNeg -> [-x] cMul cTan # TEST 10/xmultanneg +IF(FP_FLOAT_VERSION) x cMul cTanh cNeg -> [-x] cMul cTanh # TEST 10/xmultanhneg + +IF(FP_FLOAT_VERSION) cSin cDiv -> cCsc cMul # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cCos cDiv -> cSec cMul # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cTan cDiv -> cCot cMul # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cCsc cDiv -> cSin cMul # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cSec cDiv -> cCos cMul # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cCot cDiv -> cTan cMul # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cSin cInv -> cCsc # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cCos cInv -> cSec # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cTan cInv -> cCot # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cCsc cInv -> cSin # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cSec cInv -> cCos # TEST 10/invsincostan +IF(FP_FLOAT_VERSION) cCot cInv -> cTan # TEST 10/invsincostan + +################### + +# rdiv(x,y)/z --> rdiv(x*z,y) (y/x/z = y/(x*z)) +IF(FP_FLOAT_VERSION) B [IsVarOpcode(B)] cRDiv A [IsVarOpcode(A)] cDiv -> A cMul B cRDiv #TEST 11/23 +IF(FP_FLOAT_VERSION) x cRDiv A [IsVarOpcode(A)] cDiv -> A cMul [x] cRDiv #TEST 11/24 +IF(FP_FLOAT_VERSION) x cRDiv A [IsVarOpcode(A)] cMul -> [DO_STACKPLUS1] A [x] cMul cRDiv #TEST 11/25 +x [x==Value_t(1)] cRDiv -> cInv + +# a/b/c = a/(b*c) +IF(FP_FLOAT_VERSION) B [IsVarOpcode(B)] cDiv A [IsVarOpcode(A)] cDiv -> [DO_STACKPLUS1] B A cMul cDiv #TEST 11/26 + +# a/b*c = a*b/c (increases chances of doing the div grouping if more divs come later) +IF(FP_FLOAT_VERSION) B [IsVarOpcode(B)] cDiv A [IsVarOpcode(A)] cMul -> [DO_STACKPLUS1] A cMul B cDiv #TEST 11/27 +# The three rules below: same as above, but with immed instead of var A +# (do only when there is an explicit optimization; otherwise we get an infinite loop) +IF(FP_FLOAT_VERSION) y B [IsVarOpcode(B)] cDiv x cMul -> [y*x] B cDiv +IF(FP_FLOAT_VERSION) y cMul B [IsVarOpcode(B)] cDiv x cMul -> [y*x] cMul B cDiv +IF(FP_FLOAT_VERSION) cNeg B [IsVarOpcode(B)] cDiv x cMul -> [-x] cMul B cDiv #TEST 11/28 + +IF(FP_FLOAT_VERSION) cRDiv A [IsVarOpcode(A)] cMul -> [DO_STACKPLUS1] A cMul cRDiv #TEST 11/29 +# The three rules below: same as above, but with immed instead of var A +# (do only when there is an explicit optimization; otherwise we get an infinite loop) +IF(FP_FLOAT_VERSION) y cRDiv x cMul -> [y*x] cRDiv #TEST 11/30 +IF(FP_FLOAT_VERSION) y cMul cRDiv x cMul -> [y*x] cMul cRDiv +IF(FP_FLOAT_VERSION) cNeg cRDiv x cMul -> [-x] cMul cRDiv #TEST 11/31 + +# These below are just Add/Sub analogies of the above rules. +x cRSub A [IsVarOpcode(A)] cSub -> A cAdd [x] cRSub #TEST 11/32 +x cRSub A [IsVarOpcode(A)] cAdd -> [DO_STACKPLUS1] A [x] cAdd cRSub #TEST 11/33 +y B [IsVarOpcode(B)] cSub x cAdd -> [ y+x] B cSub +y cAdd B [IsVarOpcode(B)] cSub x cAdd -> [ y+x] cAdd B cSub #TEST 11/34 +cNeg B [IsVarOpcode(B)] cSub x cAdd -> [-x] cAdd B cSub #TEST 11/35 + +cRSub A [IsVarOpcode(A)] cAdd -> [DO_STACKPLUS1] A cAdd cRSub #TEST 11/32 (DUP) +cRSub A [IsVarOpcode(A)] cSub -> [DO_STACKPLUS1] A cSub cRSub #TEST 11/33 (DUP) +y cRSub x cAdd -> [ y+x] cRSub #TEST 11/36 +y cAdd cRSub x cAdd -> [ y+x] cAdd cRSub #TEST 11/37 +cNeg cRSub x cAdd -> [-x] cAdd cRSub + +A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(0)] cLess -> A [x] cMul # TEST 10/lt0 + +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr cLog -> cAbs cLog cDup cAdd # TEST 10/sqrlog +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr cLog2 -> cAbs cLog2 cDup cAdd # TEST 10/sqrlog2 +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr cLog10 -> cAbs cLog10 cDup cAdd # TEST 10/sqrlog10 + +IF(FP_FLOAT_VERSION) y [(y*x)==fp_const_rad_to_deg<Value_t>()] cMul x cMul -> cDeg +IF(FP_FLOAT_VERSION) y [(y*x)==fp_const_deg_to_rad<Value_t>()] cMul x cMul -> cRad + +cDup cAdd cDup cAdd -> [Value_t(4)] cMul # TEST 10/mul4 +cDup cAdd cMul cDup cAdd -> cMul [Value_t(4)] cMul # TEST 10/mul4 + +cDup x cMul cAdd -> [x+Value_t(1)] cMul # TEST 10/dupxmuladd +cDup x cPow cMul -> [x+Value_t(1)] cPow # TEST 10/dupxpowmul + +IF(FP_FLOAT_VERSION) cDup [x+x==Value_t(1)] cAdd x cMul -> # TEST 10/dupaddmulh + cDup cAdd x cMul -> [x+x] cMul # TEST 10/dupaddmul7 +IF(FP_FLOAT_VERSION) cDup [x+x==Value_t(1)] cAdd cMul x cMul -> cMul # TEST 10/dupaddmulmulh + cDup cAdd cMul x cMul -> cMul [x+x] cMul # TEST 10/dupaddmulmul7 + +IF(FP_FLOAT_VERSION) y [(y/x)==fp_const_rad_to_deg<Value_t>()] cMul x [x!=Value_t(0)] cDiv -> cDeg +IF(FP_FLOAT_VERSION) y [(y/x)==fp_const_deg_to_rad<Value_t>()] cMul x [x!=Value_t(0)] cDiv -> cRad +IF(FP_FLOAT_VERSION) y cMul x [x!=Value_t(0)] cDiv -> [y/x] cMul + +IF(FP_FLOAT_VERSION) x [x!=Value_t(0)] cDiv -> [Value_t(1)/x] cMul # TEST 10/multodiv + +#IF(FP_FLOAT_VERSION) y cExp x cPow -> [y*x] cExp +#IF(FP_FLOAT_VERSION) y cExp2 x cPow -> [y*x] cExp2 +# ^ y cExp never occurs (already optimized to literal) +IF(FP_FLOAT_VERSION) y cPow x cPow -> [y*x] cPow # TEST 10/ypowxpow (maybe?) + +IF(FP_FLOAT_VERSION) x [x==Value_t(0.5)] cPow -> cSqrt # TEST 10/powhalf +IF(FP_FLOAT_VERSION) x [x==Value_t(1)/Value_t(3)] cPow -> cCbrt # TEST 10/powthird +IF(FP_FLOAT_VERSION) x [x==Value_t(1)/Value_t(-3)] cPow -> cCbrt cInv # TEST 10/powminusthird +IF(FP_FLOAT_VERSION) x [x==Value_t(-0.5)] cPow -> cRSqrt # TEST 10/powminushalf +IF(FP_FLOAT_VERSION) x [x==Value_t(-1)] cPow -> cInv # TEST 10/powminusone + +IF(FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] cSqrt cSqr -> A # TEST 10/sqrtsqr1, 10/sqrtsqr2 +# ^ Doable only if lhs > 0. +IF(FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] cLog cExp -> A # TEST 10/logexp1, 10/logexp2 +IF(FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] cLog2 cExp2 -> A # TEST 10/log2exp1, 10/log2exp2 +# ^ Doable only if lhs > 0. +IF(FP_FLOAT_VERSION) cExp cLog -> # TEST 10/explog +IF(FP_FLOAT_VERSION) cExp2 cLog2 -> # TEST 12/exp2log2 +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAsin cSin -> +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAcos cCos -> +# ^ For real values, doable only if abs(x) <= 1 +#IF(FP_FLOAT_VERSION) cAtan cTan -> +IF(FP_FLOAT_VERSION) cAsinh cSinh -> # TEST 10/asinhsinh +#IF(FP_FLOAT_VERSION) cAcosh cCosh -> # TEST 10/acoshcosh +# ^ Doable only if x >= 1 +IF(FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAtanh cTanh -> +# ^ For real values, doable only if abs(x) < 1 +IF(FP_FLOAT_VERSION) cAtan2 cTan -> cDiv # TEST 10/atan2tan +IF(FP_FLOAT_VERSION) cPow cInv -> cNeg cPow # TEST 10/powinv + +#IF(FP_FLOAT_VERSION) x [x<0] cPow cMul -> [-x] cPow cDiv + +cAbs x [x==Value_t(0)] cEqual -> [x] cEqual # TEST 10/abseq0 +cAbs x [x==Value_t(0)] cNEqual -> [x] cNEqual # TEST 10/absneq0 +cSqr x [x==Value_t(0)] cEqual -> [x] cEqual # TEST 10/sqreq0 +cSqr x [x==Value_t(0)] cNEqual -> [x] cNEqual # TEST 10/sqrneq0 + +IF(!FP_COMPLEX_VERSION) y cAdd x A [IsComparisonOpcode(A)] -> [x-y] A # TEST 10/cmp_add +IF(!FP_COMPLEX_VERSION) cNeg x A [IsComparisonOpcode(A)] -> [-x] {OppositeComparisonOpcode(A)} # TEST 10/cmp_neg +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [y>Value_t(0)] cMul x A [IsComparisonOpcode(A)] -> [x/y] A # TEST 10/cmp_mulpos +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [y<Value_t(0)] cMul x A [IsComparisonOpcode(A)] -> [x/y] {OppositeComparisonOpcode(A)} # TEST 10/cmp_mulneg +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) y [y>Value_t(0)] cPow [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> [fp_pow(x,Value_t(1)/y)] A # TEST 10/cmp_powy_* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSqr [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> cAbs [fp_sqrt(x)] A # TEST 10/cmp_sqr, 10/cmp_sqr_neg +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cExp [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> [fp_log(x)] A # TEST 10/cmp_exp, 10/cmp_exp_neg +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cExp2 [x>Value_t(0)] x A [IsComparisonOpcode(A)] -> [fp_log2(x)] A # TEST 10/cmp_exp2, 10/cmp_exp2_neg +# ^ Always doable +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) B [IsNeverNegativeValueOpcode(B)] cLog x A [IsComparisonOpcode(A)] -> B [fp_exp(x)] A # TEST 10/cmp_log_* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) B [IsNeverNegativeValueOpcode(B)] cLog2 x A [IsComparisonOpcode(A)] -> B [fp_exp2(x)] A # TEST 10/cmp_log2_* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) B [IsNeverNegativeValueOpcode(B)] cLog10 x A [IsComparisonOpcode(A)] -> B [fp_pow(Value_t(10),x)] A # TEST 10/cmp_log10_* +# ^ Doable only if lhs > 0. +#IF(FP_FLOAT_VERSION) cAsin [fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)] x A [IsComparisonOpcode(A)] -> [fp_sin(x)] A # TEST 10/cmp_asin* +#IF(FP_FLOAT_VERSION) cAcos [x>=Value_t(0)&&fp_abs(x)<fp_const_pi<Value_t>()] x A [IsComparisonOpcode(A)] -> [fp_cos(x)] {OppositeComparisonOpcode(A)} # TEST 10/cmp_acos* +# ^ Doable only if abs(x) <= 1 +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAtan [fp_abs(x)<fp_const_pi<Value_t>()*Value_t(0.5)] x A [IsComparisonOpcode(A)] -> [fp_tan(x)] A # TEST 10/cmp_atan* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cSinh x A [IsComparisonOpcode(A)] -> [fp_asinh(x)] A # TEST 10/cmp_sinh* +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cTanh [fp_abs(x)<Value_t(1)] x A [IsComparisonOpcode(A)] -> [fp_atanh(x)] A # TEST 10/cmp_tanh* + +# (x+3)*4 -> x*4 + 12 + y cAdd x cMul -> [x] cMul [y*x] cAdd #TEST 11/39 +A [IsVarOpcode(A)] y cMul cAdd x cMul -> [x] cMul A [y*x] cMul cAdd #TEST 11/40 +A [IsVarOpcode(A)] y cMul cSub x cMul -> [x] cMul A [y*x] cMul cSub #TEST 11/41 + +IF(!FP_COMPLEX_VERSION) A [IsLogicalOpcode(A)] cAbsNot cNot -> A # TEST 10/absnot3 +IF(!FP_COMPLEX_VERSION) A [A!=cImmed] cAbsNot cNot -> A cAbsNotNot # TEST 10/absnot4 +IF(!FP_COMPLEX_VERSION) A [IsNeverNegativeValueOpcode(A)] cNot -> A cAbsNot # TEST 10/absnot2 + +IF(!FP_COMPLEX_VERSION) A [IsNeverNegativeValueOpcode(A)] cAbs -> A # TEST 10/absneverneg +IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)] cTrunc-> A # TEST 10/inttrunc +IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)] cFloor-> A # TEST 10/intfloor +IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)] cCeil -> A # TEST 10/intceil +IF(FP_FLOAT_VERSION) A [IsAlwaysIntegerOpcode(A)] cInt -> A # TEST 10/intint + +#IF(FP_FLOAT_VERSION) x cMul cFloor cNeg -> [-x] cMul cCeil +#IF(FP_FLOAT_VERSION) x cMul cCeil cNeg -> [-x] cMul cFloor +IF(FP_FLOAT_VERSION) cNeg cFloor -> cCeil cNeg # TEST 10/negfloor, 10/floorneg +IF(FP_FLOAT_VERSION) cNeg cCeil -> cFloor cNeg # TEST 10/negceil, 10/ceilneg + +IF(FP_FLOAT_VERSION) x cAdd cExp -> cExp [fp_exp(x)] cMul # TEST 10/addexp +IF(FP_FLOAT_VERSION) x cAdd cExp2 -> cExp2 [fp_exp2(x)] cMul # TEST 10/addexp2 + +IF(FP_FLOAT_VERSION) cPow cDiv -> cNeg cPow cMul # TEST 10/powdiv +IF(FP_FLOAT_VERSION) cExp cDiv -> cNeg cExp cMul # TEST 10/expdiv +IF(FP_FLOAT_VERSION) cExp2 cDiv -> cNeg cExp2 cMul # TEST 10/exp2div + +IF(!FP_FLOAT_VERSION) x [x==Value_t(0)] cEqual -> cNot # TEST 10/eq0 +IF(!FP_FLOAT_VERSION) x [x==Value_t(0)] cNEqual -> cNotNot # TEST 10/neq0 +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(0)] cGreater -> cNotNot # TEST 10/gt0_abs +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(1)] cGreaterOrEq -> cNotNot # TEST 10/ge1_abs +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(1)] cLess -> cNot # TEST 10/gt1_abs +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) cAbs x [x==Value_t(0)] cLessOrEq -> cNot # TEST 10/ge0_abs +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(0)] cGreater -> A cNotNot # TEST 10/gt0_pos, 10/gt0_neg +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(1)] cGreaterOrEq -> A cNotNot # TEST 10/ge1_pos, 10/ge1_neg +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(1)] cLess -> A cNot # TEST 10/gt1_pos, 10/gt1_neg +IF(!FP_COMPLEX_VERSION && !FP_FLOAT_VERSION) A [IsNeverNegativeValueOpcode(A)] x [x==Value_t(0)] cLessOrEq -> A cNot # TEST 10/ge0_pos, 10/ge0_neg +IF(!FP_FLOAT_VERSION) A [IsLogicalOpcode(A)] x [x==Value_t(1)] cEqual -> A # TEST 10/eq1 +IF(!FP_FLOAT_VERSION) A [IsLogicalOpcode(A)] x [x==Value_t(1)] cNEqual -> A cNot # TEST 10/neq1 +IF(!FP_FLOAT_VERSION) x cAdd cNotNot -> [-x] cNEqual # TEST 10/xaddnotnot +IF(!FP_FLOAT_VERSION) x cAdd cNot -> [-x] cEqual # TEST 10/xaddnot + +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs x [x!=Value_t(0)] cLess -> [Value_t(0.5)/x] cMul cNot # TEST 10/absnzlt +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs x [x!=Value_t(0)] cGreaterOrEq -> [Value_t(0.5)/x] cMul cNotNot # TEST 10/absnzge + +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(0.5)] cLess -> cAbsNot # TEST 10/lthalf +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(0.5)] cGreaterOrEq -> cAbsNotNot # TEST 10/gehalf +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(-0.5)] cGreater -> cNeg cAbsNot # TEST 10/gtminushalf +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) x [x==Value_t(-0.5)] cLessOrEq -> cNeg cAbsNotNot # TEST 10/leminushalf + +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs x [isEvenInteger(x)] cPow -> [x] cPow # TEST 10/absevenconstpow +IF(!FP_COMPLEX_VERSION && FP_FLOAT_VERSION) cAbs cMul x [isEvenInteger(x)] cPow -> cMul [x] cPow # TEST 10/absmulevenconstpow + +IF(FP_FLOAT_VERSION) cAcosh cSinh -> [DO_STACKPLUS1] cSqr [Value_t(-1)] cAdd cSqrt # TEST 10/acoshsinh +# sinh(x) = 0.5 * (exp(x) - exp(-x)) +# acosh(x) = log(x + sqrt(x*x - 1)) +# Thus, +# sinh(acosh(x)) = 0.5 * (exp(log(x + sqrt(x*x - 1))) - exp(-log(x + sqrt(x*x - 1)))) +# sinh(acosh(x)) = 0.5 * ( ( (x + sqrt(x*x - 1))) - 1 / (x + sqrt(x*x - 1)) ) +# sinh(acosh(x)) = 0.5 * (x + sqrt(x*x - 1) - 1 / (x + sqrt(x*x - 1))) +# sinh(acosh(x)) = 0.5*x + 0.5*sqrt(x*x - 1) - 0.5/(x + sqrt(x*x - 1)) +# Maxima gets a step further and says that: +# sinh(acosh(x)) = sqrt(x-1)*sqrt(x+1) +# Furthermore, Wikipedia gives us this: +# sinh(acosh(x)) = sqrt(x*x-1) IF abs(x) > 1 or complex version + +IF(FP_FLOAT_VERSION) cAsinh cCosh -> [DO_STACKPLUS1] cSqr [Value_t(1)] cAdd cSqrt # TEST 10/asinhcosh +# cosh(asinh(x)) = sqrt(x^2+1) + +# Hardcoded optimizations that are too complex or +# impossible to convey using this rule file: +IF(FP_FLOAT_VERSION) x cPow -> [DO_POWI] + +# x*x = x^2 +B [B==A] A [IsVarOpcode(A)] cMul -> B cSqr # TEST 10/sqr_xx + +# ...*x*x = ...*x^2 +B [B==A] cMul A [IsVarOpcode(A)] cMul -> B cSqr cMul # TEST 10/sqr_yxx + +# -x*x = -(x^2) +B [B==A] cNeg A [IsVarOpcode(A)] cMul -> B cSqr cNeg # TEST 10/sqr_nxx + +# x*-x = -(x^2) +cDup cNeg cMul -> cSqr cNeg # TEST 10/sqr_xnx + +# ...*-x*x = ...*-(x^2) +B [B==A] cNeg cMul A [IsVarOpcode(A)] cMul -> B cSqr cMul cNeg # TEST 10/sqr_ynxx + +# ...*x*-x = ...*-(x^2) +B [B==A] cMul A [IsVarOpcode(A)] cNeg cMul -> B cSqr cMul cNeg # TEST 10/sqr_yxnx + +B [B==A] A [IsVarOpcode(A) && mData->mByteCode.size() > 0] -> B cDup # TEST 10/xxdup +D [D==B] C [C==A] B [IsVarOpcode(B) && mData->mByteCode.size() > 1] A [IsUnaryOpcode(A)] -> D C cDup # TEST 10/xxfdup +D [D==B] C [C==A] cMul B [IsVarOpcode(B) && mData->mByteCode.size() > 1] A [IsUnaryOpcode(A)] cMul -> D C cSqr cMul # TEST 10/xxsqrdup + +IF(FP_FLOAT_VERSION) cExp2 -> [DO_STACKPLUS1] [fp_log(Value_t(2))] cMul cExp # TEST 02/exp2 +IF(FP_FLOAT_VERSION) cExp cLog2 -> [DO_STACKPLUS1] [fp_log2(fp_const_e<Value_t>())] cMul # TEST 10/explog2 +IF(FP_FLOAT_VERSION) cExp cLog10 -> [DO_STACKPLUS1] [fp_log10(fp_const_e<Value_t>())] cMul # TEST 10/explog10 + +# expr0 expr1 cExp cMul cLog +# -> expr0 cLog expr1 cAdd +# could be done if expr1 is a var. Too special case. Not doing... +# expr0 cLog expr1 cLog +# -> expr0 expr1 cMul cLog +# similar. + +IF(FP_FLOAT_VERSION) x [x>Value_t(0)] cMul cLog2 -> cLog2 [fp_log2(x)] cAdd # TEST 10/logmul2 +IF(FP_FLOAT_VERSION) x [x>Value_t(0)] cMul cLog -> cLog [fp_log(x)] cAdd # TEST 10/logmul +IF(FP_FLOAT_VERSION) x [x>Value_t(0)] cMul cLog10 -> cLog10 [fp_log10(x)] cAdd # TEST 10/logmul10 + +IF(FP_FLOAT_VERSION) B [B==A] cSin A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCos -> B cSinCos # TEST 10/sincos_sc +IF(FP_FLOAT_VERSION) B [B==A] cSin A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cSec -> B cSinCos cInv # TEST 10/sincos_sci +IF(FP_FLOAT_VERSION) B [B==A] cSin A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCsc -> B cSin cDup cInv # TEST 10/sincos_ssi +IF(FP_FLOAT_VERSION) B [B==A] cCos A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cSec -> B cCos cDup cInv # TEST 10/sincos_cci +IF(FP_FLOAT_VERSION) B [B==A] cTan A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCot -> B cTan cDup cInv # TEST 10/sincos_tti +IF(FP_FLOAT_VERSION) B [B==A] cCsc A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cSin -> B cCsc cDup cInv # TEST 10/sincos_sis +IF(FP_FLOAT_VERSION) B [B==A] cSec A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCos -> B cSec cDup cInv # TEST 10/sincos_cic +IF(FP_FLOAT_VERSION) B [B==A] cCot A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cTan -> B cCot cDup cInv # TEST 10/sincos_tit +IF(FP_FLOAT_VERSION) cSinCos cDiv -> cTan # TEST 10/sincos_tan +IF(FP_FLOAT_VERSION) cSinCos cRDiv -> cCot + +IF(FP_FLOAT_VERSION) B [B==A] cCos A [IsVarOpcode(A) && mData->mByteCode.size() > 3] cSin C [IsCommutativeOrParamSwappableBinaryOpcode(C)] -> B cSinCos {GetParamSwappedBinaryOpcode(C)} # TEST 99/59 +IF(FP_FLOAT_VERSION) B [B==A] cCosh A [IsVarOpcode(A) && mData->mByteCode.size() > 3] cSinh C [IsCommutativeOrParamSwappableBinaryOpcode(C)] -> B cSinhCosh {GetParamSwappedBinaryOpcode(C)} # TEST 99/59 +IF(FP_FLOAT_VERSION) B [B==A] cSinh A [IsVarOpcode(A) && mData->mByteCode.size() > 2] cCosh -> B cSinhCosh +IF(FP_FLOAT_VERSION) B [B==A] cCos A [IsVarOpcode(A) && mData->mByteCode.size() > 3] cCsc cMul -> B cCot +IF(FP_FLOAT_VERSION) cSinhCosh cDiv -> cTanh +IF(FP_FLOAT_VERSION) cSinhCosh cRDiv -> cTanh cInv + +IF(FP_FLOAT_VERSION) cSqr A [IsVarOpcode(A)] cSqr cAdd cSqrt -> A cHypot # TEST 10/xsqrysqrhypot +IF(FP_FLOAT_VERSION) cSqr A [IsVarOpcode(A)] B [IsUnaryOpcode(B)] cSqr cAdd cSqrt -> A B cHypot # TEST 10/xsqryfsqrhypot diff --git a/util/bytecoderules_header.txt b/util/bytecoderules_header.txt new file mode 100644 index 0000000..103d206 --- /dev/null +++ b/util/bytecoderules_header.txt @@ -0,0 +1,27 @@ +/* Function Parser for C++ v4.5.2 + + NOTE: + Do not include this file in your project. The fparser.cc file #includes +this file internally and thus you don't need to do anything (other than keep +this file in the same directory as fparser.cc). + + This file contains generated code and is thus not intended to be to +be modified by hand. It was generated by util/bytecoderules_parser, which +is available in the development package. +*/ +#define HasInvalidRangesOpcode HasInvalidRangesOpcode<IsComplexType<Value_t>::result> +#define FP_TRACE_BYTECODE_OPTIMIZATION(srcline,from,to,with) \ + /*std::cout << "Changing \"" from "\"\t(line " #srcline ")\n" \ + " into \"" to "\"\n" with << std::flush*/ +#define FP_TRACE_OPCODENAME(op) \ + (op < VarBegin \ + ? FP_GetOpcodeName(OPCODE(op)) \ + : findName(mData->mNamePtrs,op,NameData<Value_t>::VARIABLE)) +#define FP_TRACE_BYTECODE_ADD(opcode) \ + /*std::cout << "Adding opcode: " << FP_TRACE_OPCODENAME(opcode) \ + << ", bytecode length " << data->ByteCode.size() \ + << ", pointer is " << (void*)ByteCodePtr \ + << ", code is " << (data->ByteCode.empty() \ + ? (void*)0 \ + : (void*)&data->ByteCode[0]) \ + << std::endl*/ diff --git a/util/bytecoderules_parser.cc b/util/bytecoderules_parser.cc new file mode 100644 index 0000000..2f0dd6d --- /dev/null +++ b/util/bytecoderules_parser.cc @@ -0,0 +1,1480 @@ +static const char* const kVersionNumber = "1.0.0.0"; + +#include <ctype.h> +#include <cstdio> +#include <cstdlib> +#include <vector> +#include <string> +#include <iostream> +#include <sstream> +#include <vector> +#include <assert.h> +#include <map> +#include <set> + +#include "../lib/crc32.hh" + +//#define USE_CONTINUATIONS + +namespace +{ + std::string trim(const std::string& s); + + const unsigned ShortLabelLength = 3u; + + struct Operation + { + enum { Opcode, ImmedFunc, OpcodeFunc } type; + std::string result; + }; + struct Match + { + enum { FixedOpcode, Immed, AnyOpcode } type; + std::string name; // opcode name such as cInt, or holder name such as x or X + std::string condition; // condition that applies when Immed or AnyOpcode + + bool operator==(const Match& b) const + { + return type==b.type + && name==b.name + && condition==b.condition; + } + + std::vector<Operation> operations; + bool has_operations; + unsigned defined_on_line; + }; + struct Node + { + Match opcode; + std::vector<Node*> predecessors; + }; + + Node global_head; + std::set<std::string> PossiblyUnusedLabelList; + unsigned DefaultLabelCounter; + + std::string trim(const std::string& s) + { + size_t rm_begin = 0; + while(rm_begin < s.size() && s[rm_begin] == ' ') ++rm_begin; + size_t rm_end = 0; + while(rm_end < s.size()-rm_begin && s[s.size()-1-rm_end] == ' ') ++rm_end; + std::string result (s, rm_begin, s.size()-rm_end-rm_begin ); + do { + std::string::size_type spos = result.find(' '); + if(spos == result.npos) break; + result.erase(spos, 1); + } while(true); + return result; + } + + std::string Indent(size_t ntabs, size_t nspaces=0) + { + return std::string(ntabs, '\t') + std::string(nspaces, ' '); + } + + std::string Bexpr(size_t pos) + { + if(pos == 0) return "opcode"; + std::ostringstream tmp; + tmp << "ByteCodePtr[" << -int(pos-1) << "]"; + return tmp.str(); + } + + std::string Iexpr(size_t pos) + { + std::ostringstream tmp; + tmp << "ImmedPtr[" << -int(pos) << "]"; + return tmp.str(); + } + + std::string BexprName(size_t pos) + { + if(pos == 0) return "opcode"; + std::ostringstream tmp; + tmp << "op_" << pos; + return tmp.str(); + } + + bool HasHandlingFor(const std::string& opcode) + { + if(!(opcode[0] == 'c' && isupper(opcode[1]))) + return true; + + if(opcode == "cImmed" || opcode == "cDup") return false; + + for(size_t b=0; b<global_head.predecessors.size(); ++b) + if(global_head.predecessors[b]->opcode.type == Match::FixedOpcode + && global_head.predecessors[b]->opcode.name == opcode) + return true; + + for(size_t b=0; b<global_head.predecessors.size(); ++b) + if(global_head.predecessors[b]->opcode.type == Match::AnyOpcode) + return true; + return false; + } + bool HasTailCallFor(const std::string& opcode) + { + for(size_t b=0; b<global_head.predecessors.size(); ++b) + if(global_head.predecessors[b]->opcode.type == Match::FixedOpcode + && global_head.predecessors[b]->opcode.name == opcode) + return true; + return false; + } + + struct LineSeqs + { + void OutChain(std::ostream& out, + const std::vector<std::string>& chain, + size_t indent) + { + std::string codehash, prevlabel; + for(size_t a=chain.size(); a-- > 0; ) + { + codehash += chain[a]; + std::string label = GenLabel(codehash); + Chains::iterator i = code.lower_bound(label); + if(i != code.end() && i->first == label) + { + std::string got_chain; + for(Chains::iterator j = i; j != code.end(); ) + { + got_chain.insert(0, j->second.code); + if(j->second.nextlabel.empty()) break; + j = code.find(j->second.nextlabel); + } + /* + std::cerr << "expected: <" << codehash << ">\n" + "got: <" << got_chain << ">\n", + */ + assert(got_chain == codehash); + + // nothing to do + i->second.n_uses += 1; + if(!prevlabel.empty()) + code.find(prevlabel)->second.n_uses -= 1; + } + else + { + ChainItem item; + item.code = chain[a]; + item.nextlabel = prevlabel; + item.n_uses = 1; + code.insert(i, std::make_pair(label, item)); + } + prevlabel = label; + } + if(!prevlabel.empty()) + { + heads.push_back(prevlabel); + out << Indent(indent) << "goto " << ChangeLabel(prevlabel) << ";\n"; + } + } + void Flush(std::ostream& out) + { + std::set<std::string> done; + std::vector<std::string> remain; + + for(size_t a=0; a<heads.size(); ++a) + { + if(done.find(heads[a]) != done.end()) + continue; + + size_t mini = 0; + remain.push_back(heads[a]); + while(!remain.empty()) + { + Chains::const_iterator i = code.find(remain.back()); + remain.pop_back(); + + const ChainItem& item = i->second; + done.insert(i->first); + + if(item.n_uses > mini) + { + std::string l = ChangeLabel(i->first); + out << l << ": "; + } + else + out << std::string(ShortLabelLength+2, ' '); + //out << " /*" << item.n_uses << "*/ "; + out << item.code; + if(!item.nextlabel.empty()) + { + if(done.find(item.nextlabel) != done.end()) + { + std::string l = ChangeLabel(item.nextlabel); + out << " goto " << l << ';'; + } + else + remain.push_back(item.nextlabel); + } + else if(item.code.compare(0,5,"goto ") != false) + out << " return;"; + out << "\n"; + + mini = 1; + } + } + } + void clear() + { + heads.clear(); + label_trans.clear(); + code.clear(); + } + private: + std::string GenLabel(unsigned crc, unsigned len) + { + /* If you get duplicate label errors from the resulting code + * and the only thing you have done is add more optimization + * rules, just uncomment one of these characters to enable + * its use in the label name. If they are all already in use, + * you will need to increase the ShortLabellength setting by one. + */ + static const char table[] = + /*"0123456789"*/ + /*"ABCDEFGHIJKLMNOPQRSTUVWXYZ"*/ + "abcdefghijklmnopq" + /*"rstuvwxyz_"*/; + char result[16] = {0}; + int o=15; + while(true) + { + result[--o] = table[crc % (sizeof(table)-1)]; + crc /= (sizeof(table)-1); + if(crc == 0 && (16-o) > 2) break; + } + result[--o] = 'L'; + std::string result2(result+o); + result2.resize(len,' '); + return result2; + } + std::string GenLabel(const std::string& code) + { + return GenLabel(crc32::calc((const unsigned char*)&code[0], code.size()), 20); + } + std::string ChangeLabel(const std::string& orig) + { + std::map<std::string, unsigned>::iterator + j = label_trans.lower_bound(orig); + if(j != label_trans.end() && j->first == orig) + return GenLabel(j->second, ShortLabelLength); + size_t lno = label_trans.size(); + label_trans.insert(j, std::make_pair(orig, lno)); + return GenLabel(unsigned(lno), ShortLabelLength); + } + private: + struct ChainItem + { + std::string code; + std::string nextlabel; + unsigned n_uses; + }; + typedef std::map<std::string/*label*/, ChainItem> Chains; + std::vector<std::string> heads; + std::map<std::string, unsigned> label_trans; + Chains code; + } CodeSeq; + + struct OutCode; + struct OutLine + { + OutLine(OutCode& o) : out(o) { } + template<typename T> + OutLine& operator<< (const T& b) { buf << b; return *this; } + ~OutLine(); + private: + OutCode& out; + std::ostringstream buf; + }; + struct OutCode + { + OutCode(std::ostream& o, size_t i) + : out(o), + indent(i) { } + ~OutCode() + { + for(size_t a=0; a<seq.size(); ) + { + if((seq[a][0] == '/' && seq[a][1] == '*') + || (seq[a][0] == 'n' && seq[a][1] == '_') + || (seq[a][0] == 'r' && seq[a][1] == 'e' && seq[a][2] == 'p') + || (seq[a][0] == 'o' && seq[a][1] == 'p' && seq[a][2] == '_') + ) + { + out << Indent(indent) << seq[a] << "\n"; + seq.erase(seq.begin()+a); + } + else ++a; + } + #ifdef USE_CONTINUATIONS + if(!seq.empty() && seq.back().compare(0,9,"goto Tail")==false) + { + size_t skip = 0; + for(size_t a=0; a<seq.size(); ++a) + { + if(seq[a].compare(0,8,"opcode =") == false) + { + std::string opcode_assign = seq[a]; + seq.erase(seq.begin()+a); + seq.insert(seq.begin(), opcode_assign); + skip = 1; + break; + } + } + if(seq.size() > skip+1) + { + //const std::string tail_label = seq.back().substr(5); + //const std::string tail_opcode = tail_label.substr(9, tail_label.size()-10); + //CodeSeq.AddContinuation(tail_label, tail_opcode); + //std::string continuation_line = + // "/""* Will tailcall " + tail_opcode + " *""/"; + //seq.insert(seq.begin()+skip, continuation_line); + seq.back() = "goto PickContinuation;"; + } + } + #endif + CodeSeq.OutChain(out, seq, indent); + if(seq.empty()) + out << Indent(indent) << "return;\n"; + } + void Flush() + { + for(size_t a=0; a<seq.size(); ++a) + out << Indent(indent) << seq[a] << "\n"; + seq.clear(); + } + bool HasOperations() const { return !seq.empty(); } + private: + friend struct OutLine; + void DidLine(const std::string& line) { seq.push_back(line); } + std::ostream& out; + std::vector<std::string> seq; + size_t indent; + }; + OutLine::~OutLine() + { + out.DidLine(buf.str()); + } + + struct Synther + { + Synther(OutCode& o, size_t i) + : Out(o), + know_bytecode_offset(true), + know_immed_offset(true), + indent(i) + { + } + + /* Reset is called before an operation that requires + * that the vector's size() reflects the state shown + * in the Ptr variable. + * It is assumed that what follows is an instruction + * that may reallocate the vector and invalidate pointers. + */ + + void ResetImmed(int offset = 0) + { + #if 0 + if(know_immed_offset) + { + OutLine(Out) << "mData->mImmed.resize( " << (1-offset) << " + ImmedPtr - &mData->mImmed[0] );"; + } + know_immed_offset = false; + #else + know_immed_offset = false; + PopImmedBy(offset); + #endif + } + + void ResetByteCode(int offset = 0) + { + #if 0 + if(know_bytecode_offset) + { + OutLine(Out) << "mData->mByteCode.resize( " << (1-offset) << " + ByteCodePtr - &mData->mByteCode[0] );"; + } + know_bytecode_offset = false; + #else + know_bytecode_offset = false; + PopByteCodeBy(offset); + #endif + } + + void ResetBoth(int b_offset, int i_offset) + { + ResetImmed(i_offset); + ResetByteCode(b_offset); + } + + void PopByteCodeBy(int n) + { + #if 0 + if(know_bytecode_offset) + OutLine(Out) << "ByteCodePtr -= " << n << ";"; + else + for(; n > 0; --n) + OutLine(Out) << "mData->mByteCode.pop_back();"; + #else + #if 0 + for(; n > 0; --n) + OutLine(Out) << "mData->mByteCode.pop_back();"; + #else + if(n == 1) + OutLine(Out) << "mData->mByteCode.pop_back();"; + else if(n > 0) + { + OutLine(Out) << "for(unsigned tmp=" << n << "; tmp-->0; ) mData->mByteCode.pop_back();"; + } + #endif + if(know_bytecode_offset) + { + //OutLine(Out) << "if(mData->mByteCode.empty()) ByteCodePtr = 0; else ByteCodePtr -= " << n << ";"; + OutLine(Out) << "ByteCodePtr -= " << n << ";"; + } + #endif + } + + void PopImmedBy(int n) + { + #if 0 + if(know_immed_offset) + OutLine(Out) << "ImmedPtr -= " << n << ";"; + else + for(; n > 0; --n) + OutLine(Out) << "mData->mImmed.pop_back();"; + #else + if(know_immed_offset) + OutLine(Out) << "ImmedPtr -= " << n << ";"; + #if 0 + for(; n > 0; --n) + OutLine(Out) << "mData->mImmed.pop_back();"; + #else + if(n == 1) + OutLine(Out) << "mData->mImmed.pop_back();"; + else if(n > 0) + { + OutLine(Out) << "for(unsigned tmp=" << n << "; tmp-->0; ) mData->mImmed.pop_back();"; + } + #endif + #endif + } + + bool KnowOffsets() const + { + return know_bytecode_offset && know_immed_offset; + } + + private: + OutCode& Out; + bool know_bytecode_offset, know_immed_offset; + size_t indent; + }; + + bool SynthOperations( + size_t indent, std::ostream& outstream, + const std::vector<Match>& so_far, + const Match& src_node, + size_t b_used, + size_t i_used) + { + std::vector<Operation> operations ( src_node.operations ); + + outstream + << Indent(indent) + << "FP_TRACE_BYTECODE_OPTIMIZATION(" << src_node.defined_on_line << ','; + + unsigned n_with_lines = 0; + std::ostringstream trace_with; + for(size_t a=0; a<so_far.size(); ++a) + { + if(so_far[a].type != Match::Immed + && so_far[a].type != Match::AnyOpcode) continue; + if(n_with_lines == 0) + trace_with << ",\n" << Indent(indent+1) << "\" with "; + else + trace_with << "\n" << Indent(indent+1,4) << "<< \", "; + trace_with << so_far[a].name << " = \" << "; + if(so_far[a].type == Match::Immed) + trace_with << so_far[a].name; + else + trace_with << "FP_TRACE_OPCODENAME(" << so_far[a].name << ")"; + ++n_with_lines; + } + if(n_with_lines > 0) + outstream << "\n" << Indent(indent+1); + + outstream << '"'; + for(size_t a=so_far.size(); a-- > 0; ) + { + if(a+1 != so_far.size()) outstream << " "; + outstream << so_far[a].name; + if(!so_far[a].condition.empty()) + outstream << "[" << so_far[a].condition << "]"; + } + if(n_with_lines > 0) + outstream << "\",\n" << Indent(indent+1) << "\""; + else + outstream << "\", \""; + for(size_t a=0; a<operations.size(); ++a) + { + if(a > 0) outstream << ' '; + switch(operations[a].type) + { + case Operation::ImmedFunc: + outstream << '[' << operations[a].result << ']'; + break; + case Operation::OpcodeFunc: + outstream << '{' << operations[a].result << '}'; + break; + case Operation::Opcode: + outstream << operations[a].result; + } + } + outstream << "\""; + if(n_with_lines == 0) + outstream << ", \"\""; + else if(n_with_lines == 1) + trace_with << " << \"\\n\""; + else + trace_with << "\n" << Indent(indent+1,4) << "<< \"\\n\""; + outstream << trace_with.str(); + outstream << ");\n"; + + if(!operations.empty() && operations[0].result == "DO_POWI") + { + outstream + << Indent(indent) << "if(TryCompilePowi(" << so_far.back().name << "))\n" + << Indent(indent) << " return;\n"; + return false; + } + + OutCode Out(outstream, indent); + + int n_b_exist = (int)(b_used-1); + int n_i_exist = (int)(i_used ); + + int b_offset = n_b_exist; + int i_offset = n_i_exist; + + Synther offset_synth(Out, indent); + + bool rep_v_used = false; + bool op_v_used = false; + + bool changed = false; + for(size_t a=0; a<operations.size(); ++a) + { + std::string opcode = trim(operations[a].result); + if(opcode == "DO_STACKPLUS1") + { + outstream + << Indent(indent) << "incStackPtr();\n" + << Indent(indent) << "--mStackPtr;\n"; + continue; + } + + if(operations[a].type == Operation::ImmedFunc) + { + //bool requires_var = false; + //for(size_t a=0; a<opcode.size(); ++a) + // if(isalpha(opcode[a])) + // requires_var = true; + + if(i_offset > 0) + { + bool i_redundant = false; + const Match& m = so_far[i_offset]; + if(m.type == Match::Immed && opcode == m.name) + i_redundant = true; + if(i_redundant) + { + //requires_var = false; + OutLine(Out) + << "/* " << Iexpr(i_offset-1) << " = " << opcode << "; */" + << " // redundant, matches " << so_far[i_offset].name + << " @ " << (i_offset); + } + else + { + if(rep_v_used || true) + OutLine(Out) << Iexpr(i_offset-1) << " = " << opcode << ";"; + else + { + OutLine(Out) << "rep_v = " << opcode << ";"; + OutLine(Out) << Iexpr(i_offset-1) << " = rep_v;"; + rep_v_used = true; + } + changed = true; + } + } + else + { + offset_synth.ResetImmed(); + if(rep_v_used || true) + OutLine(Out) << "mData->mImmed.push_back(" << opcode << ");"; + else + { + OutLine(Out) << "rep_v = " << opcode << ";"; + OutLine(Out) << "mData->mImmed.push_back(rep_v);"; + rep_v_used = true; + } + changed = true; + } + //if(requires_var) { Out.Flush(); requires_var = false; } + --i_offset; + opcode = "cImmed"; + } + + bool redundant = false; + if(b_offset > 0 && (!changed || !HasHandlingFor(opcode))) + { + const Match& m = so_far[b_offset]; + if(opcode == (m.type == Match::Immed ? "cImmed" : m.name)) + { + redundant = true; + } + } + + bool requires_var = !(opcode[0] == 'c' && isupper(opcode[1])); + + if(!redundant && HasHandlingFor(opcode)) + { + if(a+1 == operations.size() + && opcode[0] == 'c' && isupper(opcode[1]) + && HasTailCallFor(opcode)) + { + if(b_offset > 0 && i_offset > 0) + offset_synth.ResetBoth(b_offset, i_offset); + else + { + if(b_offset > 0) offset_synth.PopByteCodeBy(b_offset); + if(i_offset > 0) offset_synth.PopImmedBy(i_offset); + } + if(so_far[0].type == Match::FixedOpcode + && so_far[0].name == operations.back().result) + { + OutLine(Out) + << "/* opcode = " << operations.back().result << "; */" + << " // redundant, matches " << so_far[0].name << " @ 0"; + } + else + { + #if 0 + OutLine(Out) + << "/* opcode = " << operations.back().result << "; */" + << " // redundant, not really needed with tailcalls"; + #else + OutLine(Out) << "opcode = " << operations.back().result << ";"; + #endif + } + + if(!offset_synth.KnowOffsets()) + OutLine(Out) << "FP_ReDefinePointers();"; + OutLine(Out) << "FP_TRACE_BYTECODE_ADD(" << opcode << ");"; + OutLine(Out) << "goto TailCall_" << opcode << ";"; + PossiblyUnusedLabelList.erase("TailCall_" + opcode); + return true; + } + else + { + offset_synth.ResetBoth(b_offset>0 ? b_offset : 0, + i_offset>0 ? i_offset : 0); + if(op_v_used || true || opcode[0]!='c' || opcode=="cImmed") + OutLine(Out) << "AddFunctionOpcode(" << opcode << ");"; + else + { + OutLine(Out) << "op_v = " << opcode << ";"; + OutLine(Out) << "AddFunctionOpcode(op_v);"; + op_v_used = true; + } + //if(requires_var) { Out.Flush(); requires_var = false; } + i_offset = b_offset = 0; + changed = true; + } + } + else + { + if(b_offset > 0) + { + if(redundant) + { + requires_var = false; + OutLine(Out) + << "/* " << Bexpr(b_offset) << " = " << opcode << "; */" + << " // redundant, matches " << so_far[b_offset].name + << " @ " << (b_offset); + } + else + { + OutLine(Out) << Bexpr(b_offset) << " = " << opcode << ";"; + changed = true; + } + } + else + { + offset_synth.ResetByteCode(); + if(op_v_used || true || opcode[0]!='c' || opcode=="cImmed") + OutLine(Out) << "mData->mByteCode.push_back(" << opcode << ");"; + else + { + OutLine(Out) << "op_v = " << opcode << ";"; + OutLine(Out) << "mData->mByteCode.push_back(op_v);"; + op_v_used = true; + } + changed = true; + } + if(requires_var) { Out.Flush(); requires_var = false; } + --b_offset; + } + } + offset_synth.ResetBoth(b_offset,i_offset); + + if(!Out.HasOperations()) + outstream << "return;\n"; + return true; + } + + std::set<std::string> declared; + + enum { mode_children = 1, mode_operations = 2 }; + bool Generate( + const Node& head, + const std::vector<Match>& so_far, + size_t indent, + std::ostream& declarations, + std::ostream& code, + size_t b_used, + size_t i_used, + int mode = mode_children+mode_operations) + { + if(!head.predecessors.empty() && (mode & mode_children)) + { + std::string last_op_name = BexprName(b_used); + std::string default_label_name; + /* + if(last_op_name != "opcode") + code << Indent(indent) << "const unsigned " << last_op_name << " = " << Bexpr(b_used) << ";\n"; + code << Indent(indent) << "switch(" << last_op_name << ")\n"; + */ + #ifdef USE_CONTINUATIONS + if(b_used == 0) + { + code << Indent(indent-1,2) << "PickContinuation:\n"; + } + #endif + bool needs_default_case = false; + bool needs_immed_case = false; + std::set<std::string> other_cases; + for(size_t b=0; b<head.predecessors.size(); ++b) + { + const Node& n = *head.predecessors[b]; + if(n.opcode.type == Match::AnyOpcode) + needs_default_case = true; + else if(n.opcode.type == Match::Immed) + needs_immed_case = true; + else + other_cases.insert(n.opcode.name); + } + bool needs_switchcase = + (needs_immed_case+needs_default_case+other_cases.size()) > 1; + + if(needs_switchcase) + { + code << Indent(indent) << "switch(" << Bexpr(b_used) << ")\n"; + code << Indent(indent) << "{\n"; + } + + if(!other_cases.empty()) + { + unsigned other_indent = needs_switchcase ? 1 : 1; + + for(std::set<std::string>::const_iterator + i = other_cases.begin(); + i != other_cases.end(); + ++i) + { + const std::string& op = *i; + + #ifndef USE_CONTINUATIONS + if(b_used == 0) + { + code << Indent(indent) << "TailCall_" << op << ":\n"; + PossiblyUnusedLabelList.insert("TailCall_" + op); + + /* If ByteCodePtr is null, just add the opcode. */ + code << Indent(indent) << "if(!ByteCodePtr)\n"; + code << Indent(indent) << "{\n"; + { OutCode Out(code, indent+other_indent); + Synther(Out, indent+other_indent).ResetBoth(0,0); + OutLine(Out) << "mData->mByteCode.push_back(opcode);"; + } + code << Indent(indent) << "}\n"; + } + #endif + if(needs_switchcase) + { + code << Indent(indent) << "case " << op << ":\n"; + } + else + { + code << Indent(indent) << "if(" << Bexpr(b_used) << " == " << op << ")\n" + << Indent(indent) << "{\n"; + } + + bool returned = false; + + for(int round=0; round<4; ++round) + for(size_t a=0; a<head.predecessors.size(); ++a) + { + const Node& n = *head.predecessors[a]; + if(round < 2 && n.opcode.has_operations) continue; + if(round >= 2 && !n.opcode.has_operations) continue; + if((round & 1) != !!n.opcode.condition.empty()) continue; + + if(n.opcode.type == Match::FixedOpcode + && n.opcode.name == op) + { + //code << Indent(indent) << " {\n"; + std::vector<Match> ref(so_far); + ref.push_back(n.opcode); + + if(n.opcode.condition.empty()) + { + returned |= + Generate(n, ref, indent+other_indent, declarations,code, b_used+1, i_used, mode_children|(round>=2?mode_operations:0)); + } + else + { + code << Indent(indent+other_indent) << "if(" << n.opcode.condition << ")\n"; + code << Indent(indent+other_indent) << "{\n"; + Generate(n, ref, indent+other_indent+1, declarations,code, b_used+1, i_used, mode_children|(round>=2?mode_operations:0)); + code << Indent(indent+other_indent) << "}\n"; + } + } + } + if(!returned) + { + if(needs_default_case) + { + if(default_label_name.empty()) + { + std::ostringstream tmp; + tmp << "Default" << DefaultLabelCounter++; + default_label_name = tmp.str(); + } + code << Indent(indent+other_indent) << "goto " << default_label_name << ";\n"; + } + else if(needs_switchcase) + { + code << Indent(indent+other_indent) << "break;\n"; + } + } + if(!needs_switchcase) + code << Indent(indent) << "}\n"; + } + } + + std::set<std::string> immed_labels; + bool immed_returned = false; + /* + Round 0: no-code, has condition, mode_children + Round 1: no-code, no condition, mode_children + Round 2: code, has condition, mode_children | mode_operations + Round 3: code, no condition, mode_children | mode_operations + */ + if(needs_immed_case) + { + if(needs_switchcase) + { + code << Indent(indent) << "case cImmed:\n"; + } + else + { + code << Indent(indent) << "if(" << Bexpr(b_used) << " == cImmed)\n" + << Indent(indent) << "{\n"; + } + unsigned imm_indent = needs_switchcase ? 1 : 1; + + for(int round=0; round<4; ++round) + for(size_t a=0; a<head.predecessors.size(); ++a) + { + const Node& n = *head.predecessors[a]; + if(n.opcode.type == Match::Immed) + { + if(round < 2 && n.opcode.has_operations) continue; + if(round >= 2 && !n.opcode.has_operations) continue; + if((round & 1) != !!n.opcode.condition.empty()) continue; + + //code << Indent(indent) << " /* round " << round << " a = " << a << " */\n"; + std::set<std::string>::iterator i = immed_labels.lower_bound(n.opcode.name); + if(i == immed_labels.end() || *i != n.opcode.name) + { + if(declared.find(n.opcode.name) == declared.end()) + { + declared.insert(n.opcode.name); + declarations << Indent(1) << "Value_t " << n.opcode.name << ";\n"; + } + + code << Indent(indent+imm_indent) << n.opcode.name << " = " << Iexpr(i_used) << ";\n"; + immed_labels.insert(i, n.opcode.name); + } + std::vector<Match> ref(so_far); + ref.push_back(n.opcode); + if(n.opcode.condition.empty()) + immed_returned = + Generate(n, ref, indent+imm_indent, declarations,code, b_used+1, i_used+1, mode_children|(round>=2?mode_operations:0)); + else + { + code << Indent(indent+imm_indent) << "if(" << n.opcode.condition << ")\n"; + code << Indent(indent+imm_indent) << "{\n"; + Generate(n, ref, indent+imm_indent+1, declarations,code, b_used+1, i_used+1, mode_children|(round>=2?mode_operations:0)); + code << Indent(indent+imm_indent) << "}\n"; + } + } + } + + if(needs_switchcase) + { + if(!immed_returned) + code << Indent(indent+imm_indent) << "break;\n"; + } + else + { + code << Indent(indent) << "}\n"; + } + } + + std::set<std::string> opcode_labels; + + if(needs_default_case) + { + if(needs_switchcase) + { + code << Indent(indent) << "default:"; + if(!default_label_name.empty()) + code << " " << default_label_name << ":;"; + code << "\n"; + } + unsigned default_indent = needs_switchcase ? 1 : 0; + + for(int round=0; round<4; ++round) + for(size_t a=0; a<head.predecessors.size(); ++a) + { + const Node& n = *head.predecessors[a]; + if(n.opcode.type == Match::AnyOpcode) + { + if(round < 2 && n.opcode.has_operations) continue; + if(round >= 2 && !n.opcode.has_operations) continue; + if((round & 1) != !!n.opcode.condition.empty()) continue; + //code << Indent(indent) << " /* round " << round << " a = " << a << " */\n"; + std::set<std::string>::iterator i = opcode_labels.lower_bound(n.opcode.name); + if(i == opcode_labels.end() || *i != n.opcode.name) + { + if(declared.find(n.opcode.name) == declared.end()) + { + declared.insert(n.opcode.name); + declarations << Indent(1) << "unsigned " << n.opcode.name << ";\n"; + } + code << Indent(indent+default_indent) << n.opcode.name << " = " << Bexpr(b_used) << ";\n"; + opcode_labels.insert(i, n.opcode.name); + } + std::vector<Match> ref(so_far); + ref.push_back(n.opcode); + if(n.opcode.condition.empty()) + Generate(n, ref, indent+default_indent, declarations,code, b_used+1, i_used, mode_children|(round>=2?mode_operations:0)); + else + { + code << Indent(indent+default_indent) << "if(" << n.opcode.condition << ")\n"; + code << Indent(indent+default_indent) << "{\n"; + Generate(n, ref, indent+default_indent+1, declarations,code, b_used+1, i_used, mode_children|(round>=2?mode_operations:0)); + code << Indent(indent+default_indent) << "}\n"; + } + } + } + } + + if(needs_switchcase) + { + code << Indent(indent) << "}\n"; + } + } + if(head.opcode.has_operations && (mode & mode_operations)) + { + /*if(!head.predecessors.empty()) + std::cout << Indent(indent) << "/""* NOTE: POSSIBLY AMBIGIOUS *""/\n";*/ + if(SynthOperations(indent,code, so_far, head.opcode, b_used, i_used)) + { + //out << Indent(indent) << "return;\n"; + // ^ now redundant, as it is done by SynthOperations() + return true; + } + } + return false; + } + + void Generate(std::ostream& out) + { + std::ostringstream code; + std::ostream& declarations = out; + Generate(global_head, std::vector<Match>(), 1, declarations,code, 0,0); + out << code.str(); + + { OutCode Out(out, 1); + Synther(Out, 1).ResetBoth(0,0); + OutLine(Out) << "mData->mByteCode.push_back(opcode);"; + } + CodeSeq.Flush(out); + + out << "return;\n"; + out << "// This list of dummy gotos is here to inhibit\n" + "// compiler warnings on unused labels\n"; + unsigned a=0; + for(std::set<std::string>::const_iterator + i = PossiblyUnusedLabelList.begin(); + i != PossiblyUnusedLabelList.end(); + ++i) + { + out << "goto " << *i << ";"; + if(a+1 == PossiblyUnusedLabelList.size() + || a%3 == 2) out << "\n"; + ++a; + } + } + + bool isnamech(char c) + { + return c=='_' || (c>='a' && c<='z') || (c>='A' && c<='Z'); + } + + void VerifyExpressions( + const std::set<std::string>& expressions, + const std::set<std::string>& identifiers, + unsigned lineno) + { + for(std::set<std::string>::const_iterator + i = expressions.begin(); + i != expressions.end(); + ++i) + { + const std::string& e = *i; + for(size_t a=0; a<e.size(); ++a) + { + if( isnamech(e[a]) + && !isnamech(e[a+1]) + && (a==0 || (!isnamech(e[a-1]) + && !std::isdigit(e[a-1])) + )) + { + std::string id(e, a, 1); + if(identifiers.find(id) == identifiers.end()) + { + std::cerr + << "WARNING: Identifier '" << id + << "' used on line " << lineno + << " is undefined\n"; + } + } + } + } + } + + template<typename T> + bool SplitConditionString(const std::string& s, T& set, T& unset) + { + size_t a=0, b=s.size(); + bool glue_necessary = false; + while(a < b) + { + if(s[a] == ' ') { ++a; continue; } + if(s[a] == '(' || s[a] == ')') return false; // Cannot evaluate + bool positive = true; + if(glue_necessary) + { + if(s[a] != '&' || s[a+1] != '&') return false; + a += 2; + if(a >= b) return false; + } + while(a < b && s[a] == ' ') ++a; + if(s[a] == '!') { ++a; positive = false; if(a >= b) return false; } + while(a < b && s[a] == ' ') ++a; + if(a >= b) return false; + if((s[a] >= 'A' && s[a] <= 'Z') + || (s[a] >= 'a' && s[a] <= 'z') + || s[a]=='_') + { + size_t begin = a; + while(++a < b && ((s[a] >= 'A' && s[a] <= 'Z') + || (s[a] >= 'a' && s[a] <= 'z') + || (s[a] >= '0' && s[a] <= '9') + || s[a]=='_')) + { } + (positive ? set : unset).insert( s.substr(begin, a-begin) ); + glue_necessary = true; + continue; + } + else + break; + } + return true; + } + + struct ParsingMode + { + std::set<std::string> different_preconditions; + bool collect_preconditions; + std::set<std::string> allowed_preconditions; + }; + void Parse(ParsingMode& mode) + { + unsigned lineno = 0; + while(true) + { + char Buf[2048]; + if(!std::fgets(Buf, sizeof(Buf), stdin)) break; + ++lineno; + char* bufptr = Buf; + while(*bufptr == ' ' || *bufptr == '\t') ++bufptr; + if(*bufptr == '#' || *bufptr == '\r' || *bufptr == '\n') continue; + + std::string Precondition; + + if(*bufptr == 'I' && bufptr[1] == 'F' && bufptr[2] == '(') + { + bufptr += 3; + size_t balance = 0; + while(*bufptr != ')' || balance != 0) + { + if(*bufptr == '\r' || *bufptr == '\n') break; + if(*bufptr == '(') ++balance; + if(*bufptr == ')') --balance; + Precondition += *bufptr++; + } + if(*bufptr == ')') ++bufptr; + while(*bufptr == ' ' || *bufptr == '\t') ++bufptr; + } + + if(mode.collect_preconditions) + { + std::set<std::string> en, dis; + if(SplitConditionString(Precondition, en, dis)) + { + mode.different_preconditions.insert(en.begin(), en.end()); + mode.different_preconditions.insert(dis.begin(), dis.end()); + } + else + { + while(!Precondition.empty() + && Precondition[0] == '!') Precondition.erase(Precondition.begin()); + if(!Precondition.empty()) + mode.different_preconditions.insert(Precondition); + } + continue; + } + + if(!Precondition.empty()) + { + std::set<std::string> en, dis; + /*fprintf(stderr, "Rule %u, Condition %s, allowed:", + lineno, Precondition.c_str()); + for(std::set<std::string>::const_iterator + i = mode.allowed_preconditions.begin(); + i != mode.allowed_preconditions.end(); + ++i) + fprintf(stderr, " %s", i->c_str());*/ + + if(SplitConditionString(Precondition, en, dis)) + { + bool ok = true; + for(std::set<std::string>::const_iterator + i = en.begin(); i != en.end(); ++i) + { + /*fprintf(stderr, "[en:%s]", i->c_str());*/ + if(mode.allowed_preconditions.find(*i) + == mode.allowed_preconditions.end()) + { ok = false; break; } + } + for(std::set<std::string>::const_iterator + i = dis.begin(); i != dis.end(); ++i) + { + /*fprintf(stderr, "[dis:%s]", i->c_str());*/ + if(mode.allowed_preconditions.find(*i) + != mode.allowed_preconditions.end()) + { ok = false; break; } + } + /*fprintf(stderr, " - decision: %s\n", ok?"OK":" Not ok"); + fflush(stderr);*/ + if(!ok) continue; + } + else + { + std::string cond = Precondition; + bool inverse = false; + while(cond[0] == '!') + { inverse = !inverse; cond.erase(cond.begin()); } + if((mode.allowed_preconditions.find(cond) + == mode.allowed_preconditions.end()) != inverse) + { + continue; + } + } + } + + std::set<std::string> identifiers_defined_here; + std::set<std::string> expressions_used_here; + + std::vector<Match> sequence; + while(true) + { + Match m; + m.has_operations = false; + while(*bufptr == ' ' || *bufptr == '\t') ++bufptr; + if(*bufptr == '-' && bufptr[1] == '>') break; + while(isalnum(*bufptr)) m.name += *bufptr++; + m.name = trim(m.name); + while(*bufptr == ' ' || *bufptr == '\t') ++bufptr; + if(*bufptr == '#') break; + if(*bufptr == '[') + { + size_t balance = 0; ++bufptr; + while(*bufptr != ']' || balance != 0) + { + if(*bufptr == '\r' || *bufptr == '\n') break; + if(*bufptr == '[') ++balance; + if(*bufptr == ']') --balance; + m.condition += *bufptr++; + } + if(*bufptr == ']') ++bufptr; + m.condition = trim(m.condition); + expressions_used_here.insert(m.condition); + } + if(m.name[0] == 'c' && m.name.size() > 1) + m.type = Match::FixedOpcode; + else if(isupper(m.name[0])) + { + m.type = Match::AnyOpcode; + identifiers_defined_here.insert(m.name); + } + else + { + m.type = Match::Immed; + identifiers_defined_here.insert(m.name); + } + + sequence.push_back(m); + } + + Node* head = &global_head; + for(size_t b=sequence.size(); b-->0; ) + { + const Match& m = sequence[b]; + bool dup = false; + for(size_t a=0; a< head->predecessors.size(); ++a) + { + if(m == head->predecessors[a]->opcode) + { + head = head->predecessors[a]; + dup = true; + break; + } + } + if(!dup) + { + Node* newhead = new Node; + newhead->opcode = m; + head->predecessors.push_back(newhead); + head = newhead; + } + } + + if(*bufptr == '-' && bufptr[1] == '>') + { + if(head->opcode.has_operations) + { + std::cerr << "WARNING: Duplicate definition on line " << lineno + << ", previously defined on line " << head->opcode.defined_on_line + << std::endl; + } + head->opcode.has_operations = true; + head->opcode.defined_on_line = lineno; + bufptr += 2; + + while(true) + { + while(*bufptr == ' ' || *bufptr == '\t') ++bufptr; + if(*bufptr == '#' || *bufptr == '\r' || *bufptr == '\n') break; + Operation op; + if(*bufptr == '[') + { + size_t balance = 0; ++bufptr; + while(*bufptr != ']' || balance != 0) + { + if(*bufptr == '\r' || *bufptr == '\n') break; + if(*bufptr == '[') ++balance; + if(*bufptr == ']') --balance; + op.result += *bufptr++; + } + if(*bufptr == ']') ++bufptr; + op.type = Operation::ImmedFunc; + expressions_used_here.insert(op.result); + } + else if(*bufptr == '{') + { + size_t balance = 0; ++bufptr; + while(*bufptr != '}' || balance != 0) + { + if(*bufptr == '\r' || *bufptr == '\n') break; + if(*bufptr == '{') ++balance; + if(*bufptr == '}') --balance; + op.result += *bufptr++; + } + if(*bufptr == '}') ++bufptr; + op.type = Operation::OpcodeFunc; + expressions_used_here.insert(op.result); + } + else + { + while(isalnum(*bufptr)) + op.result += *bufptr++; + op.type = Operation::Opcode; + } + head->opcode.operations.push_back(op); + } + } + + VerifyExpressions(expressions_used_here, + identifiers_defined_here, + lineno); + } + } + + std::string GetPreconditionMaskName( + const std::vector<std::string>& cond, + size_t bitmask) + { + std::set<std::string> enabled; + std::set<std::string> disabled; + + for(size_t b=0; b<cond.size(); ++b) + { + if(bitmask & (1 << b)) + { + std::string c = cond[b]; + /*std::set<std::string> e, d; + if(!SplitConditionString(c, e, d))*/ + enabled.insert(c); + /*else + { + enabled.insert(e.begin(), e.end()); + disabled.insert(d.begin(), d.end()); + }*/ + } + else + { + disabled.insert(cond[b]); + // No splitting of conditions here, + // because !(a && b) yields !a || !b, not !a && !b + } + } + + std::string result; + bool first=true; + for(std::set<std::string>::const_iterator + i = enabled.begin(); i != enabled.end(); ++i) + { + if(disabled.find(*i) != disabled.end()) + return std::string(); // conflicting conditions + if(first) first=false; else result += " && "; + result += "(" + *i + ")"; + } + for(std::set<std::string>::const_iterator + i = disabled.begin(); i != disabled.end(); ++i) + { + if(first) first=false; else result += " && "; + result += "!(" + *i + ")"; + } + return result; + } +} + +int main() +{ + ParsingMode mode; + mode.collect_preconditions = true; + Parse(mode); + + std::vector<std::string> different_preconditions( + mode.different_preconditions.begin(), + mode.different_preconditions.end() ); + + size_t n_different_parsers = 1 << different_preconditions.size(); + + std::ostream& out = std::cout; + + out << + // "template<typename Value_t>\n" + // "inline void FunctionParserBase<Value_t>::AddFunctionOpcode(unsigned opcode)\n" + // "{\n" + " unsigned* ByteCodePtr;\n" + " Value_t* ImmedPtr;\n" + //" unsigned n_b, n_i, op_v;\n" + //" Value_t rep_v;\n" + "\n" + " #define FP_ReDefinePointers() \\\n" + " ByteCodePtr = !mData->mByteCode.empty() ? &mData->mByteCode[0] + mData->mByteCode.size() - 1 : 0; \\\n" + " ImmedPtr = !mData->mImmed.empty() ? &mData->mImmed[0] + mData->mImmed.size() - 1 : 0;\n" + " FP_ReDefinePointers();\n"; + + out << " FP_TRACE_BYTECODE_ADD(opcode);\n"; + + for(size_t n=0; n<n_different_parsers; ++n) + { + mode.collect_preconditions = false; + mode.allowed_preconditions.clear(); + for(size_t b=0; b<different_preconditions.size(); ++b) + { + if(n & (1 << b)) + mode.allowed_preconditions.insert(different_preconditions[b]); + } + if(std::fseek(stdin, 0, SEEK_SET) < 0) + { + std::perror("fseek"); + return -1; + } + + global_head = Node(); + PossiblyUnusedLabelList.clear(); + DefaultLabelCounter=0; + CodeSeq.clear(); + declared.clear(); + + Parse(mode); + + out << "\n"; + + if(n_different_parsers == 1) + Generate(out); + else + { + std::string mask = GetPreconditionMaskName(different_preconditions, n); + if(!mask.empty()) + { + out << "#if(" << mask << ")\n" << std::flush; + Generate(out); + out << "#endif\n"; + } + } + } + + out << + "\n" + "#undef FP_ReDefinePointers\n" + // "}\n" + "#undef FP_TRACE_BYTECODE_OPTIMIZATION\n" + "#undef FP_TRACE_OPCODENAME\n"; + + return 0; +} diff --git a/util/cpp_compress.cc b/util/cpp_compress.cc new file mode 100644 index 0000000..cdc73df --- /dev/null +++ b/util/cpp_compress.cc @@ -0,0 +1,832 @@ +#include "cpp_compress.hh" + +#include <vector> +#include <map> +#include <set> +#include <iostream> + +#include <stdio.h> + +namespace +{ + std::string macro_prefix_chars = "qghdowam"; + bool verbose = false; + + /* ^List of characters that are _least_ likely to form + * a legitimate identifier name in the input code when + * a [0-9A-Z] (case sensitive) is appended to it. + */ + + std::set<std::string> parametric_macro_list; + + void reset_parametric_macro_list() + { + static const char* const list[] = + { + /* IMPORTANT NOTE: HARDCODED LIST OF ALL PREPROCESSOR + * MACROS THAT TAKE PARAMETERS. ANY EXTERNAL MACROS + * NOT LISTED HERE WILL BE BROKEN AFTER COMPRESSION. + * MACROS DEFINED WITHIN THE PROCESSED INPUT ARE FINE. + */ + "assert", "getc", "putc", + "FP_TRACE_OPCODENAME", + "FP_TRACE_BYTECODE_OPTIMIZATION", + "FP_TRACE_BYTECODE_ADD", + "N","P", "DBL_ONLY", "LNG_ONLY", + "incStackPtr", "TryCompilePowi","findName" + }; + parametric_macro_list.clear(); + for(unsigned p=0; p<sizeof(list)/sizeof(*list); ++p) + parametric_macro_list.insert(list[p]); + } + + struct length_rec + { + unsigned begin_index; + unsigned num_tokens; + unsigned num_occurrences; + }; + + inline bool isnamechar(char c) + { + switch(c) + { + case '0':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case '1':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l': + case '2':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r': + case '3':case 's':case 't':case 'u':case 'v':case 'w':case 'x': + case '4':case 'y':case 'z':case '_': + case '5':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + case '6':case 'G':case 'H':case 'I':case 'J':case 'K':case 'L': + case '7':case 'M':case 'N':case 'O':case 'P':case 'Q':case 'R': + case '8':case 'S':case 'T':case 'U':case 'V':case 'W':case 'X': + case '9':case 'Y':case 'Z': return true; + } + return false; + } + + class StringSeq: private std::string + { + private: + std::vector<bool> sticky; + public: + StringSeq() + : std::string(), sticky() { } + + StringSeq(const std::string& s) + : std::string(s), sticky() { } + + const std::string& GetString() const { return *this; } + + template<typename T> + void operator += (const T& k) + { + std::string::operator+=(k); + } + char operator[] (size_t pos) const + { + return std::string::operator[] (pos); + } + + void SetSticky(size_t n_last_chars) + { + if(sticky.size() < size()) sticky.resize(size()); + for(size_t p = size() - n_last_chars; p < size(); ++p) + sticky[p] = true; + } + bool IsSticky(size_t index) const + { + return index < sticky.size() && sticky[index]; + } + bool HasSticky() const { return !sticky.empty(); } + + StringSeq substr(size_t begin, size_t count = std::string::npos) const + { + StringSeq result; + result.std::string::assign(*this, begin,count); + result.sticky.assign( + begin < sticky.size() + ? sticky.begin() + begin + : sticky.end(), + (count != std::string::npos && begin+count < sticky.size()) + ? sticky.begin() + begin + count + : sticky.end()); + while(!result.sticky.empty() && !result.sticky.back()) + result.sticky.pop_back(); + return result; + } + + using std::string::empty; + using std::string::size; + using std::string::append; + }; + + struct token + { + std::string value; + struct token_meta + { + unsigned hash; + int balance; + unsigned comma; + bool preproc; + } meta; + + token(const std::string& v) : value(v) + { + Rehash(); + } + + token(const StringSeq& v) : value(v.GetString()) + { + Rehash(); + if(v.HasSticky()) + meta.preproc = true; + } + + void operator=(const std::string& v) { value=v; Rehash(); } + + bool operator==(const token& b) const + { + return meta.hash == b.meta.hash + && value == b.value + && meta.preproc == b.meta.preproc; + } + + bool operator!=(const token& b) const + { return !operator==(b); } + + void Rehash() + { + const char* v = value.data(); + meta.preproc = (v[0] == '#' || v[0] == '\n'); + meta.balance = 0; + meta.comma = 0; + meta.hash = 0; + for(size_t a=0; a<value.size(); ++a) + { + //meta.hash = meta.hash*0x8088405u + v[a]; + meta.hash = ((meta.hash << (1)) | (meta.hash >> (32-1))) - v[a]; + switch(v[a]) + { + case '(': ++meta.balance; break; + case ')': --meta.balance; break; + case ',': ++meta.comma; break; + } + } + } + void swap(token& b) + { + value.swap(b.value); + std::swap(meta, b.meta); + } + }; + bool Debug = false; + StringSeq GetSeq(std::vector<token>::const_iterator begin, + size_t n, bool NewLines) + { + bool InDefineMode = false; + + /* Resequence the input */ + StringSeq result; + int quotemode = 0; + while(n-- > 0) + { + const token& tok = *begin; + const std::string& value = tok.value; ++begin; + + if(Debug) + result += tok.meta.preproc + ? (InDefineMode ? "\xBF" : "\xA1") // upside-down ? and ! + : (InDefineMode ? "\x3F" : "\x21"); // ?, ! + else if (!result.empty() && result[result.size()-1] != '\n') + { + if (!InDefineMode && NewLines && value[0] == '#') result += '\n'; + else if (isnamechar(value[0]) + && (isnamechar(result[result.size()-1]) + || result[result.size()-1] == '"' + || result[result.size()-1] == '\'' + // || result[result.size()-1]==')' + /* An identifier preceded by an identifier character + * requires a separator. Also, an identifier + * preceded by a macro that expands to something + * that ends in an identifier character requires a + * separator when using Microsoft C++, thus you may + * need to include the ")" check above sometimes. + * Also, in C++11 you can't tack an identifier right + * after a string or character constant or there will + * be an error. + */ + )) + { + if (!NewLines || InDefineMode) + result += ' '; + else + result += '\n'; + } + } + if (value[0] == '#') + { + if (value.substr(0,7) == "#define") InDefineMode = true; + if (value.substr(0,8) == "#include") InDefineMode = true; + } + if (value == "\n") + { + if (InDefineMode) { result += "\n"; InDefineMode = false; } + continue; + } + + switch(quotemode) + { + case 0: // prev wasn't a quote, or this is not a quote + if (value[0] == '"' + && (n>0 && begin->value[0] == '"')) // this and next are quotes + { quotemode = 1; + result.append(value, 0, value.size()-1); + //result += value.substr(0, value.size()-1); + continue; + } + else + { + result += value; + if(tok.meta.preproc || (value[0] == '(' && value.size() > 1)) + { + /* A macro parameter list is an undivisible entity */ + result.SetSticky(value.size()); + } + } + break; + case 1: // prev was a quote, skip this quote + if (n>0 && begin->value[0] == '"') + { //result += value.substr(1, value.size()-2); + result.append(value, 1, value.size()-2); + continue; + } + else + { quotemode = 0; + //result += value.substr(1); + result.append(value, 1, value.size()-1); + } + break; + } + if (!Debug) + { + if (NewLines && !InDefineMode) + { + if (value[0] == '#' + || value[0] == '}' + || value[0] == '"' + ) + { + result += '\n'; + } + } + if (n > 0 && (value.size() == 1 && + (value[0] == '<' // < < is not << + || value[0] == '>' // > > is not >> + || value[0] == '+' // + + is not ++ + || value[0] == '-' // - - is not -- + || value[0] == '&') // & & is not && + ) && value == begin->value) + { + result += ' '; + } + } + } + return result; + } + + struct DefineParsingMode + { + bool Active; + std::set<std::string> ParamList; + + DefineParsingMode() : Active(false), ParamList() { } + + void Activate() { Active=true; } + void Deactivate() { Active=false; ParamList.clear(); } + }; + + std::vector<token>* + Tokenize(const StringSeq& input, + DefineParsingMode& defmode, + bool SplitMacros, + bool SplitStrings) + { + std::vector<token>* result = new std::vector<token>; + size_t a=0, b=input.size(); + while(a < b) + { + /*if(input.IsSticky(a)) + { + size_t eat = 1; + while(input.IsSticky(a+eat)) ++eat; + result->push_back( input.substr(a, eat) ); + a += eat; + continue; + }*/ + if (defmode.Active && input[a]=='\\' && input[a+1] == '\n') + { + a += 2; + continue; + } + if (defmode.Active && input[a]=='\n') + { + defmode.Deactivate(); + result->push_back( token("\n") ); + ++a; + continue; + } + if (input[a]==' ' || input[a]=='\t' + || input[a]=='\n' || input[a]=='\r') { ++a; continue; } + + if (input[a]=='/' && input[a+1]=='*') + { + a += 2; + while(a < b && (input[a-2]!='*' || input[a-1]!='/')) ++a; + continue; + } + if (input[a]=='/' && input[a+1]=='/') + { + while(a < b && input[a]!='\n') ++a; + continue; + } + if (input[a]=='_' || (input[a]>='a' && input[a]<='z') + || (input[a]>='A' && input[a]<='Z')) + { + size_t name_begin = a; + while(++a < b) + { + if (isnamechar(input[a])) continue; + break; + } + + // name + result->push_back( std::string(input.GetString(), name_begin, a-name_begin) ); + + if (defmode.Active && defmode.ParamList.find(result->back().value) + != defmode.ParamList.end()) + { + // Define params are immutable. + result->back().meta.preproc = true; + } + + if (input[a] == '(' + && parametric_macro_list.find(result->back().value) + != parametric_macro_list.end()) + { + // This function is recursion-heavy, so we use "new". + std::vector<token>* remains = + Tokenize(input.substr(a), defmode, SplitMacros, SplitStrings); + int balance = 1; + size_t eat = 1; + for(; eat < remains->size() && balance != 0; ++eat) + balance += (*remains)[eat].meta.balance; + if(SplitMacros) + { + for(size_t c=0; c<eat; ++c) + if((*remains)[c].meta.balance != 0 + || (*remains)[c].meta.comma != 0) + (*remains)[c].meta.preproc = true; + result->insert(result->end(), remains->begin(), remains->end()); + } + else + { + //result->push_back( GetSeq(remains->begin(), eat, false) ); + StringSeq tmp = GetSeq(remains->begin(), eat, false); + result->back() = result->back().value + tmp.GetString(); + result->insert(result->end(), remains->begin()+eat, remains->end()); + } + delete remains; + a = b; // done + } + continue; + } + if (std::isdigit(input[a]) || + (input[a] == '.' && std::isdigit(input[a+1]))) + { + size_t value_begin = a; + while(++a < b) + { + if ((input[a]>='0' && input[a]<='9') + || input[a]=='.' || input[a]=='+' || input[a]=='-' + || input[a]=='x' || (input[a]>='a' && input[a]<='f') + || input[a]=='p' || (input[a]>='A' && input[a]<='F') + || input[a]=='u' || input[a]=='U' + || input[a]=='l' || input[a]=='f' + || input[a]=='L' || input[a]=='F') continue; + break; + } + StringSeq s = input.substr(value_begin, a-value_begin ); + /* TODO: Convert hex to decimal */ + result->push_back( s ); + continue; + } + if (a+1 < b && input[a] == '>' && input[a+1] == '>') + { int n = (a+2 < b && input[a+2] == '=') ? 3 : 2; + result->push_back(input.substr(a, n)); a += n; continue; } + if (a+1 < b && input[a] == '<' && input[a+1] == '<') + { int n = (a+2 < b && input[a+2] == '=') ? 3 : 2; + result->push_back(input.substr(a, n)); a += n; continue; } + if (a+1 < b && input[a] == '+' && input[a+1] == '+') + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (a+1 < b && input[a] == '-' && input[a+1] == '-') + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (a+1 < b && input[a] == '-' && input[a+1] == '>') + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (a+1 < b && input[a] == '#' && input[a+1] == '#') + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (a+1 < b && input[a] == '&' && input[a+1] == '&') + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (a+1 < b && input[a] == '|' && input[a+1] == '|') + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (a+1 < b && (input[a] == '>' || input[a] == '<' + || input[a] == '!' || input[a] == '=' + || input[a] == '+' || input[a] == '-' + || input[a] == '*' || input[a] == '/' + || input[a] == '&' || input[a] == '|')) + if (input[a+1] == '=') + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (a+1 < b && (input[a] == ':' && input[a+1] == ':')) + { result->push_back(input.substr(a, 2)); a += 2; continue; } + if (!defmode.Active && input[a] == '#') + { + if (input.substr(a,8).GetString() == "#include") + { + size_t p = a; + while(p < b && input[p] != '\n') ++p; + result->push_back( input.substr(a, p-a) ); + result->back().meta.preproc = true; + result->push_back( token("\n") ); + a = p; + continue; + } + if (input.substr(a,7).GetString() == "#define") + { + size_t p = a+7; + while(p < b && std::isspace(input[p])) ++p; // skip blank + size_t term_begin = p; + while(p < b && isnamechar(input[p])) ++p; // skip term + if (input[p] != '(') + { + defmode.Activate(); + std::string def = input.substr(a, p-a).GetString(); + if(input[p] != '\n') def += ' '; + result->push_back(def); /* #define, term name and a space */ + a = p; + continue; + } + else + { + std::string macro(input.GetString(), term_begin, p-term_begin); + if(parametric_macro_list.find(macro) + == parametric_macro_list.end()) + { + if(verbose) std::cerr << "Detected parametric macro: " << macro << " (ok)\n"; + parametric_macro_list.insert(macro); + } + + size_t /*param_list_begin = p,*/ param_begin = p+1; + int balance = 1; + for (++p; true; ++p) + { + if(input[p]=='(') ++balance; + if(input[p]==',' || input[p]==')') + { + std::string paramname = input.substr(param_begin,p-param_begin).GetString(); + //std::cerr << "Param name<" << paramname << ">\n"; + defmode.ParamList.insert(paramname); + param_begin = p+1; + } + if(input[p]==')') { if(--balance == 0) { ++p; break; } } + } + size_t param_list_end = p; + while(input[p] != '\n' && std::isspace(input[p])) ++p; + + defmode.Activate(); + std::string def = input.substr(a, param_list_end-a).GetString(); + if(input[p] != '\n') def += ' '; + result->push_back(def); /* #define, term name, params and a space */ + a = p; + continue; + } + } + size_t preproc_begin = a; + bool in_quotes = false; + while(++a < b) + { + if (!in_quotes && input[a]=='"') + { in_quotes=true; continue; } + if (in_quotes && input[a]=='"' && input[a-1]!='\\') + { in_quotes=false; continue; } + if (input[a]=='\\' && input[a+1]=='\n') { ++a; continue; } + if (input[a]=='\n') break; + } + std::string stmt(input.GetString(), preproc_begin, a-preproc_begin); + if (stmt.substr(0,5) != "#line") + result->push_back(stmt); + result->push_back( token("\n") ); + continue; + } + if (input[a] == '"') + { + size_t string_begin = a; + while(++a < b) + if (input[a]=='"' && + (input[a-1] != '\\' + || input[a-2]=='\\')) { ++a; break; } + if(input.GetString() == "\"\"") continue; // Don't add an empty string token + + std::string stringconst(input.GetString(), string_begin+1, a-string_begin-2); + if (SplitMacros) + while (true) + { + size_t p = stringconst.find_first_of(" ,+-", 0, 1); + if(p == stringconst.npos) break; + if(p > 0) + result->push_back( "\""+std::string(stringconst,0,p)+"\"" ); + result->push_back( "\""+std::string(stringconst,p,1)+"\"" ); + stringconst.erase(0, p+1); + } + if(!stringconst.empty()) result->push_back("\""+stringconst+"\""); + continue; + } + if (input[a] == '\'') + { + size_t char_begin = a; a += 3; + if (input[a-2] == '\\') ++a; + result->push_back( std::string(input.GetString(), char_begin, a-char_begin) ); + continue; + } + + result->push_back( input.substr(a++, 1) ); + } + return result; + } + + static const char cbuf[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; + + unsigned macro_counter = 0; + + std::string GenerateMacroName() + { + std::string result; + unsigned p = macro_counter++; + result += macro_prefix_chars[(p/36)%macro_prefix_chars.size()]; + result += cbuf[p%36]; + p /= unsigned(macro_prefix_chars.size()*36); // 0-9A-Z + for(; p != 0; p /= 63) + result += cbuf[p%63]; + return result; + } + + bool CompressWithNonparametricMacros + (std::vector<token>& tokens, + const std::string& seq_name_buf) + { + size_t seq_name_length = seq_name_buf.size(); + + /* Find a sub-sequence of tokens for which + * the occurrence-count times total length is + * largest and the balance of parentheses is even. + */ + std::map<unsigned, length_rec> hash_results; + long best_score=0; + //size_t best_score_length=0; + unsigned best_hash=0; + + if(verbose) std::cerr << tokens.size() << " tokens\n"; + + std::vector<bool> donttest(tokens.size(), false); + + const size_t lookahead_depth = (140*100000) / tokens.size(); + // ^Lookahead limit. The value chosen is an arbitrary value + // to shield against exponential runtime. A larger value + // yields better compression, but is slower. + + for(size_t a=0; a<tokens.size(); ++a) + { + if (donttest[a]) continue; + + //std::cerr << a << '\t' << best_score << '\t' << best_score_length << '\r' << std::flush; + size_t cap = a+lookahead_depth; + for(size_t b=a+1; b<tokens.size() && b<cap; ++b) + { + size_t max_match_len = std::min(tokens.size()-b, b-a); + size_t match_len = 0; + unsigned hash = 0; + //int balance = 0; + + while(match_len < max_match_len + && tokens[a+match_len] == tokens[b+match_len] + && tokens[a+match_len].meta.preproc == false) + { + const token& word = tokens[a+match_len]; + + //balance += word.meta.balance; + //if (preserve_params + // && (balance < 0 || (word.meta.comma && balance==0))) break; + + ++match_len; + hash = ((hash << (1+0*(match_len&31))) + ^ (hash >> (31-0*(match_len&31)))) + ^ word.meta.hash; + //hash = ~hash*0x8088405u + word.meta.hash; + + donttest[b] = true; + + //if (!balance == 0) + { + std::map<unsigned, length_rec>::iterator i + = hash_results.lower_bound(hash); + if (i == hash_results.end() || i->first != hash) + { + length_rec rec; + rec.begin_index = (unsigned)a; + rec.num_tokens = (unsigned)match_len; + rec.num_occurrences = 1; + hash_results.insert(i, std::make_pair(hash,rec)); + cap = std::max(cap, b+match_len+lookahead_depth); + } + else if (i->second.begin_index == (unsigned)a) + { + if (std::equal( + tokens.begin()+a, tokens.begin()+a+match_len, + tokens.begin() + i->second.begin_index)) + { + long string_len = GetSeq(tokens.begin()+a, match_len, false).size(); + long n = (i->second.num_occurrences += 1); + long define_length = seq_name_length + 9 - long(string_len); + long replace_length = long(string_len) - (long(seq_name_length)+1); + long score = replace_length * n - define_length; + if (score > best_score) + { + best_score = score; + //best_score_length = string_len; + best_hash = hash; + } + } + cap = std::max(cap, b+match_len+lookahead_depth); + } + } + } + } + } + if (best_score > 0) + { + const length_rec& rec = hash_results[best_hash]; + if (rec.num_occurrences > 0) + { + /* Found a practical saving */ + std::vector<token> sequence + (tokens.begin()+rec.begin_index, + tokens.begin()+rec.begin_index+rec.num_tokens); + if(verbose) std::cerr << "#define " << seq_name_buf << " " << + GetSeq(sequence.begin(), sequence.size(), false).GetString() + //<< " /* " << rec.num_occurrences + //<< " occurrences */" + << std::endl; + + /* Replace all occurrences of the sequence with the sequence name */ + std::vector<bool> deletemap(tokens.size(), false); + for(size_t a=0;//rec.begin_index+rec.num_tokens; + a+rec.num_tokens<=tokens.size(); + ++a) + { + if (std::equal(sequence.begin(), + sequence.end(), + tokens.begin()+a)) + { + tokens[a] = seq_name_buf; + for(size_t b=1; b<rec.num_tokens; ++b) + deletemap[++a] = true; + } + } + size_t tgt=0, src=0; + for(; src < tokens.size(); ++src) + if (!deletemap[src]) + tokens[tgt++].swap(tokens[src]); + tokens.erase(tokens.begin()+tgt, tokens.end()); + + sequence.insert(sequence.begin(), + token("#define " + seq_name_buf + " ")); + sequence.push_back( token("\n") ); + + tokens.insert(tokens.begin(), + sequence.begin(), sequence.end()); + + /* Find more repetitions */ + return true; + } + } + return false; + } + + bool CompressWithParametricMacros( + std::vector<token>& /*tokens*/, + const std::string& /*seq_name_buf*/) + { + /* TODO: Someone invent an algorithm for this? + * + * Find e.g. + * + * Cmpeq_i qI x == y ; } q1 + * Cmpge_d qI x >= y ; } q1 + * Cmpge_i qI x >= y ; } q1 + * Cmpgt_d qI x > y ; } q1 + * Cmpgt_i qI x > y ; } q1 + * Cmple_d qI x <= y ; } q1 + * Cmple_i qI x <= y ; } q1 + * Cmplt_d qI x < y ; } q1 + * Cmplt_i qI x < y ; } q1 + * Cmpne_d qI x != y ; } q1 + * Cmpne_i qI x != y ; } q1 + * + * Substitute with: + * + * #define Zzz(A,B) A qI x B y ; } q1 + * Zzz(Cmpeq_i,==) + * Zzz(Cmpge_d,>=) + * Zzz(Cmpge_i,>=) + * Zzz(Cmpgt_d,>) + * Zzz(Cmpgt_i,>) + * Zzz(Cmple_d,<=) + * Zzz(Cmple_i,<=) + * Zzz(Cmplt_d,<) + * Zzz(Cmplt_i,<) + * Zzz(Cmpne_d,!=) + * Zzz(Cmpne_i,!=) + * + * Which can be further turned into (well, theoretically): + * + * #define Zzz(A,B) A qI x B y ; } q1 + * #define Zxy(A,B) Zzz(Cmp##A##_d,B) Zzz(Cmp##A##_i,B) + * Zzz(Cmpeq_i,==) + * Zxy(ge,>=) + * Zxy(gt,>) + * Zxy(le,<=) + * Zxy(lt,<) + * Zxy(ne,!=) + */ + return false; + } +} + +std::string CPPcompressor::Compress(const std::string& input) +{ + FILE* fp = fopen("cpp_compress_disable", "r"); + if(fp) { fclose(fp); return input; } + + reset_parametric_macro_list(); + macro_counter = 0; + + DefineParsingMode defmode; + std::vector<token>* tokens = Tokenize(input, defmode, false, false); + + int tried_retoken_rounds = 0; + std::string seq_name_buf = GenerateMacroName(); + + //bool preserve_parens = false; + + StringSeq result; + while (true) + { + if (CompressWithNonparametricMacros(*tokens, seq_name_buf)) + { + tried_retoken_rounds = 0; + seq_name_buf = GenerateMacroName(); + } + else if (CompressWithParametricMacros(*tokens, seq_name_buf)) + { + tried_retoken_rounds = 0; + seq_name_buf = GenerateMacroName(); + } + else + { + if (tried_retoken_rounds >= 4) break; + //preserve_parens = true; + + if(verbose) std::cerr << "Retokenizing\n"; + //static int counter=0; ++counter; + //if(counter>=1) {Debug=true;} + result = GetSeq(tokens->begin(), tokens->size(), true); + //if(counter>=1) break; + + DefineParsingMode defmode; + delete tokens; + tokens = Tokenize(result, defmode, tried_retoken_rounds&1, tried_retoken_rounds&2); + ++tried_retoken_rounds; + } + } + delete tokens; + return result.GetString(); +} + +std::string CPPcompressor::Compress + (const std::string& input, + const std::string& m) +{ + if(!m.empty()) macro_prefix_chars = m; + return Compress(input); +} diff --git a/util/cpp_compress.hh b/util/cpp_compress.hh new file mode 100644 index 0000000..62bcfda --- /dev/null +++ b/util/cpp_compress.hh @@ -0,0 +1,10 @@ +#include <string> + +class CPPcompressor +{ +public: + /* Compress the given C++ source code. Warning: Function not re-entrant. */ + std::string Compress(const std::string& input); + std::string Compress(const std::string& input, + const std::string& macro_prefix_chars); +}; diff --git a/util/cpp_compress_main.cc b/util/cpp_compress_main.cc new file mode 100644 index 0000000..f4b4937 --- /dev/null +++ b/util/cpp_compress_main.cc @@ -0,0 +1,20 @@ +#include <cstdio> +#include <iostream> +#include "cpp_compress.hh" + +int main(int argc, char* argv[]) +{ + std::string out; + for(;;) + { + char Buf[32768]; + if(!std::fgets(Buf, sizeof(Buf), stdin)) break; + Buf[(sizeof Buf)-1] = '\0'; + out += Buf; + } + CPPcompressor Compressor; + + std::string prefix; + if(argc == 2 && argv[1][0] != '-') prefix = argv[1]; + std::cout << Compressor.Compress(out, prefix); +} diff --git a/util/create_testrules_for_optimization_rules.cc b/util/create_testrules_for_optimization_rules.cc new file mode 100644 index 0000000..91b397c --- /dev/null +++ b/util/create_testrules_for_optimization_rules.cc @@ -0,0 +1,358 @@ +#include "fpoptimizer/grammar.hh" +#include <algorithm> +#include <sstream> +#include <cmath> +#include <set> + +using namespace FPoptimizer_Grammar; +using namespace FUNCTIONPARSERTYPES; + +namespace +{ + class TestFunction + { + public: + std::string fparser_test; + std::string cpp_test; + public: + TestFunction() + : fparser_test(), + cpp_test() + { + } + + TestFunction(const std::string& s) + : fparser_test(s), + cpp_test(s) + { + } + + TestFunction(const std::string& fp, const std::string& cp) + : fparser_test(fp), + cpp_test(cp) + { + } + + struct TestInfo + { + const char* fp_pref, *cp_pref; + const char* fp_sep, *cp_sep; + const char* fp_suff, *cp_suff; + + explicit TestInfo(OPCODE opcode) + { + fp_pref = cp_pref = "(("; + fp_sep = cp_sep = ","; + fp_suff = cp_suff = "))"; + switch(opcode) + { + case cMul: fp_sep = cp_sep = ")*("; return; + case cAdd: fp_sep = cp_sep = ")+("; return; + case cSub: fp_sep = cp_sep = ")-("; return; + case cDiv: fp_sep = cp_sep = ")/("; return; + case cAnd: fp_sep = cp_sep = ")&("; return; + case cOr: fp_sep = cp_sep = ")|("; return; + case cEqual: fp_sep = ")=("; cp_sep = ")==("; return; + case cNEqual: fp_sep = cp_sep = ")!=("; return; + case cLess: fp_sep = cp_sep = ")<("; return; + case cLessOrEq: fp_sep = cp_sep = ")<=("; return; + case cGreater: fp_sep = cp_sep = ")>("; return; + case cGreaterOrEq: fp_sep = cp_sep = ")>=("; return; + case cMod: fp_sep = ")%("; cp_pref = "(fmod("; cp_sep = ","; return; + case cPow: fp_sep = ")^("; cp_pref = "(pow("; cp_sep = ","; return; + case cNeg: fp_pref = cp_pref = "(-("; return; + case cNot: fp_pref = cp_pref = "(!("; return; + case cNotNot: fp_pref = cp_pref = "(!!("; return; + case cInv: fp_pref = cp_pref = "(1/("; return; + case cCot: fp_pref = "cot"; cp_pref = "(1/tan("; return; + case cCsc: fp_pref = "csc"; cp_pref = "(1/sin("; return; + case cSec: fp_pref = "sec"; cp_pref = "(1/cos("; return; + case cInt: fp_pref = "int"; cp_pref = "(floor(0.5+("; return; + #define op(opcode, fpcode, cpcode) \ + case opcode: \ + fp_pref = #fpcode "("; \ + cp_pref = #cpcode "("; \ + fp_suff = cp_suff = ")"; return + op(cAbs,abs,abs); + op(cAcos,acos,acos); + op(cAcosh,acosh,fp_acosh); + op(cAsin,asin,asin); + op(cAsinh,asinh,fp_asinh); + op(cAtan,atan,atan); + op(cAtan2,atan2,atan2); + op(cAtanh,atanh,fp_atanh); + op(cCeil,ceil,ceil); + op(cCos,cos,cos); + op(cCosh,cosh,cosh); + case cIf: + fp_pref = "if(("; + return; + op(cExp,exp,exp); + op(cExp2,exp2,exp2); + op(cFloor,floor,floor); + op(cLog,log,log); + op(cLog10,log10,log10); + op(cLog2,log2,log2); + op(cMax,max,max); + op(cMin,min,min); + op(cSin,sin,sin); + op(cSinh,sinh,sinh); + op(cSqrt,sqrt,sqrt); + op(cTan,tan,tan); + op(cTanh,tanh,tanh); + op(cTrunc,trunc,trunc); + #undef op + case cImmed: return; // does not occur + case cJump: return; // does not occur + case cDup: return; // does not occur + case cFetch: return; // does not occur + case cPopNMov: return; // does not occur + case cSqr: return; // does not occur + case cRDiv: return; // does not occur + case cRSub: return; // does not occur + case cRSqrt: return; // does not occur (?) + case cNop: return; // does not occur + case VarBegin: return; // does not occur + } + } + }; + }; + + class TestGenerator + { + std::map<unsigned, std::string> holders; + public: + TestFunction CreateTest(const ParamSpec_ParamHolder& holder) + { + std::map<unsigned, std::string>::const_iterator i = holders.find(holder.index); + if(i != holders.end()) return TestFunction( i->second ); + std::string result; + if(holder.constraints & Constness_Const) + { + get_const_instead:; + double value = 4.91; + switch(ImmedConstraint_Value( holder.constraints & ValueMask) ) + { + case Value_IsInteger: case Value_EvenInt: + value = std::floor(value); + break; + case Value_OddInt: + value = 3.0; + break; + case Value_Logical: + value = 1.0; + default: break; + } + if(holder.constraints & Oneness_One) + value = 1.0; + if(holder.constraints & Sign_Negative) + value = -value; + std::ostringstream r; + r.precision(15); + r << value; + result = r.str(); + } + else + { + if(holder.constraints & OnenessMask) goto get_const_instead; + static const char* const predefined[] = + { "x", "y", "z", "sinh(x)" }; + result = predefined[(holder.index+4-2) % 4]; + // any expression evaluating to the given constraints + switch(ImmedConstraint_Value( holder.constraints & ValueMask) ) + { + case Value_IsInteger: + result = "floor(" + result + ")"; + break; + case Value_OddInt: + case Value_EvenInt: + case Value_NonInteger: + goto get_const_instead; + case Value_Logical: + result = "(" + result + " < 3)"; + break; + } + switch(ImmedConstraint_Sign( holder.constraints & SignMask) ) + { + case Sign_Positive: + result = "abs(" + result + ")"; + break; + case Sign_Negative: + result = "(-cosh(" + result + "))"; + break; + } + } + return TestFunction( holders[holder.index] = result ); + } + + TestFunction CreateTest(const ParamSpec_NumConstant& n) + { + std::ostringstream s; + s.precision(15); + s << n.constvalue; + return TestFunction( s.str() ); + } + + TestFunction CreateTest(const ParamSpec_SubFunctionData& tree, unsigned constraints) + { + TestFunction::TestInfo info ( tree.subfunc_opcode ); + std::vector<ParamSpec> params; + for(unsigned p=0; p<tree.param_count; ++p) + params.push_back( ParamSpec_Extract(tree.param_list, p) ); + + std::vector<TestFunction> result_params; + for(unsigned p=0; p<tree.param_count; ++p) + { + const ParamSpec& param = params[p]; + switch(param.first) + { + case NumConstant: + { + const ParamSpec_NumConstant& n = *(const ParamSpec_NumConstant*)param.second; + result_params.push_back( CreateTest( n ) ); + break; + } + case ParamHolder: + { + const ParamSpec_ParamHolder& n = *(const ParamSpec_ParamHolder*)param.second; + result_params.push_back( CreateTest( n ) ); + break; + } + case SubFunction: + { + const ParamSpec_SubFunction& n = *(const ParamSpec_SubFunction*)param.second; + result_params.push_back( CreateTest( n.data, n.constraints ) ); + break; + } + } + } + if(tree.restholder_index != 0) + { + // add two random params + if(constraints & Sign_Positive) + result_params.push_back( TestFunction( "abs(q)" ) ); + else + { + result_params.push_back( TestFunction( "q" ) ); + result_params.push_back( TestFunction( "w" ) ); + } + } + + if(tree.match_type != PositionalParams) + std::random_shuffle( result_params.begin(), result_params.end() ); + TestFunction result; + result.fparser_test += info.fp_pref; + result.cpp_test += info.cp_pref; + for(unsigned p=0; p<result_params.size(); ++p) + { + if(tree.subfunc_opcode == cIf) + { + static const char* const fp_list[3] = { "", "),(", "),(" }; + static const char* const cp_list[3] = { "", ")?(", "):(" }; + info.fp_sep = fp_list[p]; + info.cp_sep = cp_list[p]; + } + if(p > 0) + { + result.fparser_test += info.fp_sep; + result.cpp_test += info.cp_sep; + } + result.fparser_test += result_params[p].fparser_test; + result.cpp_test += result_params[p].cpp_test; + } + result.fparser_test += info.fp_suff; + result.cpp_test += info.cp_suff; + return result; + } + }; +} + +static std::set<const Rule*> Rules; + +static void FindRules(const Grammar& g) +{ + for(unsigned a=0; a<g.rule_count; ++a) + Rules.insert(&grammar_rules[g.rule_list[a]]); +} + +int main() +{ + FindRules(grammar_optimize_round1); + FindRules(grammar_optimize_round2); + FindRules(grammar_optimize_round3); + + for(std::set<const Rule*>::const_iterator + i = Rules.begin(); + i != Rules.end(); + ++i) + { + const Rule& r = **i; + + if(r.logical_context) + { + // Skipping logical context rule + // FIXME: Instead, devise a test that utilizes logical context + continue; + } + + ParamSpec_SubFunctionData in_func = r.match_tree; + if(r.ruletype == ReplaceParams + && (in_func.subfunc_opcode == cAdd + || in_func.subfunc_opcode == cMul + || in_func.subfunc_opcode == cAnd + || in_func.subfunc_opcode == cOr)) + { + in_func.restholder_index = 7; + } + TestGenerator gen; + TestFunction test = gen.CreateTest(in_func, 0); + + TestFunction repl; + if(r.ruletype == ReplaceParams) + { + ParamSpec_SubFunctionData repl_func = + { r.repl_param_count, r.repl_param_list, + r.match_tree.subfunc_opcode, + PositionalParams, in_func.restholder_index }; + repl = gen.CreateTest(repl_func, 0); + } + else + { + ParamSpec p = ParamSpec_Extract(r.repl_param_list, 0); + if(p.first == SubFunction) + repl = gen.CreateTest(*(const ParamSpec_SubFunctionData*)p.second, 0); + else if(p.first == ParamHolder) + repl = gen.CreateTest(*(const ParamSpec_ParamHolder*)p.second); + else + repl = gen.CreateTest(*(const ParamSpec_NumConstant*)p.second); + } + ParamSpec_SubFunction tmp = {r.match_tree,0,0}; + + std::cout << "echo '---------NEW TEST-----------'\n"; + std::cout << "echo 'Rule: "; + FPoptimizer_Grammar::DumpParam( ParamSpec(SubFunction, (const void*) &tmp) ); + std::cout << "'\n"; + if(r.ruletype == ProduceNewTree) + { + std::cout << "echo ' -> "; + FPoptimizer_Grammar::DumpParam( + ParamSpec_Extract(r.repl_param_list, 0) ); + std::cout << "'\n"; + } + else + { + std::cout << "echo ' : "; + FPoptimizer_Grammar::DumpParams( + r.repl_param_list, r.repl_param_count ); + std::cout << "'\n"; + } + + std::cout << "./functioninfo '" << test.fparser_test + << "' '" << repl.fparser_test << "'\n"; + /* + std::cout << test.fparser_test << + "\n" << test.cpp_test << + "\n\n"; + */ + } +} diff --git a/util/ftest.cc b/util/ftest.cc new file mode 100644 index 0000000..b3e8ef6 --- /dev/null +++ b/util/ftest.cc @@ -0,0 +1,213 @@ +#include "fparser.hh" + +#include <iostream> +#include <iomanip> +#include <cstdio> +#include <string> +#include <sstream> +#include <cmath> + +struct Counts { unsigned opcodes, muls; }; + +namespace +{ + static int Log2up(unsigned long value) + { + unsigned long res = 0; + while(value > (1LU << res)) ++res; + return res; + } + static int PopCount(unsigned long value) // population count + { + static const int counts[16] = { 0,1,1,2, 1,2,2,3, 1,2,2,3, 2,3,3,4 }; + int result = 0; + while(value > 0) { result += counts[value & 15]; value >>= 4; } + return result; + } +} + +Counts generateOpcodesForExp(unsigned n, bool print, double& value) +{ + Counts retval = { 0, 0 }; + if(n > 1) + { + if(n % 2 == 1) + { + if(true) // USE_DIVISIONS_AS_WELL + { + int next_power_of_2 = Log2up(n); + int popcount = PopCount(n); + //fprintf(stderr, "Considering %u... %u/%u\n", n, popcount,next_power_of_2); + //fflush(stderr); + if(n != 3 && popcount >= next_power_of_2 ) + { + int morepower = 1 << next_power_of_2; + int lesspower = -(n - morepower); + const double valueCopy = value; + if(print) std::cout << "dup "; + retval = generateOpcodesForExp(morepower, print, value); + if(print) std::cout << "fetch "; + const double high = value; + value = valueCopy; + Counts r2 = generateOpcodesForExp(lesspower, print, value); + if(print) std::cout << "rdiv "; + retval.opcodes += r2.opcodes; + retval.muls += r2.muls; + retval.muls += 1; + retval.opcodes += 3; + value = high / value; + return retval; + } + } + if(print) std::cout << "dup "; + const double valueCopy = value; + retval = generateOpcodesForExp(n-1, print, value); + retval.opcodes += 2; + ++retval.muls; + if(print) std::cout << "mul "; + value *= valueCopy; + } + else + { + retval = generateOpcodesForExp(n/2, print, value); + ++retval.opcodes; + ++retval.muls; + if(print) std::cout << "sqr "; + value *= value; + } + } + return retval; +} + +Counts getParserOpcodesAmount(const std::string& func, double& value) +{ + FunctionParser fp; + std::string line; + + fp.Parse(func, "x"); + fp.Optimize(); + std::ostringstream buf; + fp.PrintByteCode(buf); + std::istringstream lines(buf.str()); + + Counts counts = { 0, 0 }; + while(std::getline(lines, line).good()) + { + ++counts.opcodes; + const std::string end = line.substr(line.size()-3); + if(end == "mul" + || end == "div" + || end == "rdi" + || end == "sqr") ++counts.muls; + } + --counts.opcodes; + + value = fp.Eval(&value); + + return counts; +} + +bool compare(double v1, double v2) +{ + const double Epsilon = .000001; + const double scale = pow(10.0, floor(log10(fabs(v1)))); + double sv1 = fabs(v1) < Epsilon ? 0 : v1/scale; + double sv2 = fabs(v2) < Epsilon ? 0 : v2/scale; + double diff = sv2-sv1; + return std::fabs(diff) < Epsilon; +} + +int main() +{ + std::printf + ("Number of opcodes generated:\n" + "Func Naive Bisq Func Naive Bisq Func Naive Bisq Func Naive Bisq\n" + "---- ----- ---- ---- ----- ---- ---- ----- ---- ---- ----- ----\n"); + + const Counts minimum = { 0, 0 }; + + for(unsigned i = 0; i < 100; ++i) + { + for(unsigned col = 0; col < 4; ++col) + { + const unsigned exponent = i + 100*col; + + const double value = 1.02; + double result = exponent == 0 ? 1 : value; + for(unsigned i = 2; i <= exponent; ++i) + result *= value; + + std::ostringstream funcStream; + if(exponent < 10) funcStream << " "; + funcStream << "x^" << exponent; + const std::string func = funcStream.str(); + + double naiveValue = exponent == 0 ? 1 : value; + Counts naiveOpcodes = exponent < 2 ? minimum : + generateOpcodesForExp(exponent, false, naiveValue); + ++naiveOpcodes.opcodes; + + double bisqValue = value; + const Counts bisqOpcodes = getParserOpcodesAmount(func, bisqValue); + + if(!compare(naiveValue, result)) + { + std::cerr << "\nFor exponent " << exponent + << " naive algorithm returned \n" + << std::setprecision(18) + << naiveValue << " instead of " << result << "\n"; + return 1; + } + if(!compare(bisqValue, result)) + { + std::cerr << "\nFor exponent " << exponent + << " Bisq algorithm returned \n" + << bisqValue << " instead of " << result << "\n"; + return 1; + } + + //fflush(stderr); + std::printf("%s: %3u (%2u) %3u (%2u) ", func.c_str(), + naiveOpcodes.opcodes, naiveOpcodes.muls, + bisqOpcodes.opcodes, bisqOpcodes.muls); + //fflush(stdout); + } + std::printf("\n"); + } + return 0; + + /* + for(unsigned i = 2; i < 20; ++i) + { + std::cout << "x^" << i << ": "; + unsigned amount = generateOpcodesForExp(i, true).opcodes; + std::cout << ": " << amount << "\n"; + } + return 0; + + + + + std::string function; + FunctionParser fparser; + + while(true) + { + std::cout << "f(x) = "; + std::getline(std::cin, function); + int res = fparser.Parse(function, "x"); + + if(res >= 0) + std::cout << std::string(res+7, ' ') << "^\n" + << fparser.ErrorMsg() << "\n\n"; + else + { + std::cout << "------- Normal: -------\n"; + fparser.PrintByteCode(std::cout); + std::cout << "------- Optimized: -------\n"; + fparser.Optimize(); + fparser.PrintByteCode(std::cout); + } + } + */ +} diff --git a/util/functioninfo.cc b/util/functioninfo.cc new file mode 100644 index 0000000..c778aa4 --- /dev/null +++ b/util/functioninfo.cc @@ -0,0 +1,1422 @@ +/*========================================================================== + functioninfo + ------------ + Copyright: Juha Nieminen, Joel Yliluoma + This program (functioninfo) is distributed under the terms of the + GNU General Public License (GPL) version 3. + See gpl.txt for the license text. +============================================================================*/ + +static const char* const kVersionNumber = "1.2.0.4"; + +#include "fparser.hh" +#include "fparser_mpfr.hh" +#include "fparser_gmpint.hh" +#include "extrasrc/fpaux.hh" +#include <iostream> +#include <iomanip> +#include <vector> +#include <set> +#include <string> +#include <cstring> +#include <cstdio> +#include <cstdlib> +#include <ctime> +#include <cmath> +#include <sstream> +#include <cassert> +#include <algorithm> +#include <cctype> + +#define SEPARATOR \ +"----------------------------------------------------------------------------" + +namespace +{ + template<typename Value_t> + struct TimingConst + { + static const unsigned kParseLoopsPerUnit = 100000; + static const unsigned kEvalLoopsPerUnit = 300000; + static const unsigned kOptimizeLoopsPerUnit = 1000; + }; + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + struct TimingConst<MpfrFloat> + { + static const unsigned kParseLoopsPerUnit = 100000; + static const unsigned kEvalLoopsPerUnit = 10000; + static const unsigned kOptimizeLoopsPerUnit = 500; + }; +#endif + + const unsigned kTestTime = 250; // In milliseconds + const bool kPrintTimingProgress = false; + + const unsigned kMaxVarValueSetsAmount = 10000; + const double kVarValuesUpperLimit = 100000.0; + const double kVarValuesInitialDelta = 0.1; + const double kVarValuesDeltaFactor1 = 1.25; + const double kVarValuesDeltaFactor2 = 10.0; + const double kVarValuesDeltaFactor2Threshold = 10.0; + + bool gPrintByteCodeExpressions = true; + + template<typename Value_t> Value_t epsilon() { return Value_t(1e-9); } + template<> inline float epsilon<float>() { return 1e-5F; } + //template<> inline long epsilon<long>() { return 0; } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> inline MpfrFloat epsilon<MpfrFloat>() + { return MpfrFloat::someEpsilon(); } +#endif + +//#ifdef FP_SUPPORT_GMP_INT_TYPE + //template<> inline GmpInt epsilon<GmpInt>() { return 0; } +//#endif + + template<typename Value_t> + Value_t Sqr(const Value_t* p) + { + return p[0]*p[0]; + } + + template<typename Value_t> + Value_t Sub(const Value_t* p) + { + return p[0]-p[1]; + } + + template<typename Value_t> + Value_t Value(const Value_t*) + { + return Value_t(10); + } + + template<typename Value_t> + class InitializableParser: public FunctionParserBase<Value_t> + { + public: + InitializableParser(const char* function, const char* vars) + { + assert(FunctionParserBase<Value_t>::Parse(function, vars) < 0); + } + }; + + + template<typename Value_t> + class ParserWithConsts: public FunctionParserBase<Value_t> + { + public: + ParserWithConsts() + { + typedef FunctionParserBase<Value_t> b; + b::AddConstant("pi", Value_t(3.14159265358979323846)); + b::AddConstant("e", Value_t(2.71828182845904523536)); + b::AddUnit("k", Value_t(1000)); + b::AddUnit("M", Value_t(1000000)); + b::AddUnit("dozen", Value_t(12)); + b::AddUnit("dozens", Value_t(12)); + + b::AddFunction("sqr", Sqr<Value_t>, 1); + b::AddFunction("sub", Sub<Value_t>, 2); + b::AddFunction("value", Value<Value_t>, 0); + + static InitializableParser<Value_t> SqrFun("x*x", "x"); + static InitializableParser<Value_t> SubFun("x-y", "x,y"); + static InitializableParser<Value_t> ValueFun("5", ""); + + b::AddFunction("psqr", SqrFun); + b::AddFunction("psub", SubFun); + b::AddFunction("pvalue", ValueFun); + } + + // Publicize fparser's parsing functions + using FunctionParserBase<Value_t>::ParseLiteral; + using FunctionParserBase<Value_t>::ParseIdentifier; + }; + + struct TimingInfo + { + double mMicroSeconds; + unsigned mLoopsPerSecond; + }; + + template<typename Value_t> + struct FunctionInfo + { + std::string mFunctionString; + ParserWithConsts<Value_t> mParser; + std::vector<Value_t> mValidVarValues; + + TimingInfo mParseTiming; + TimingInfo mEvalTiming; + TimingInfo mOptimizeTiming; + TimingInfo mDoubleOptimizeTiming; + TimingInfo mOptimizedEvalTiming; + TimingInfo mDoubleOptimizedEvalTiming; + }; + + + template<typename Value_t> + struct ParserData + { + static ParserWithConsts<Value_t> gParser, gAuxParser; + static std::vector<std::vector<Value_t> > gVarValues; + static const Value_t* gEvalParameters; + }; + + template<typename Value_t> + ParserWithConsts<Value_t> ParserData<Value_t>::gParser; + + template<typename Value_t> + ParserWithConsts<Value_t> ParserData<Value_t>::gAuxParser; + + template<typename Value_t> + std::vector<std::vector<Value_t> > ParserData<Value_t>::gVarValues; + + template<typename Value_t> + const Value_t* ParserData<Value_t>::gEvalParameters = 0; + + + std::string gFunctionString, gVarString; + bool gUseDegrees = false; + + template<typename Value_t> + inline void doParse() + { + ParserData<Value_t>::gParser.Parse + (gFunctionString, gVarString, gUseDegrees); + } + + template<typename Value_t> + inline void doEval() + { + ParserData<Value_t>::gParser.Eval + (ParserData<Value_t>::gEvalParameters); + } + + template<typename Value_t> + inline void doOptimize() + { + ParserData<Value_t>::gAuxParser = ParserData<Value_t>::gParser; + ParserData<Value_t>::gAuxParser.Optimize(); + } + + template<void(*Function)(), unsigned loopsPerUnit> + TimingInfo getTimingInfo() + { + unsigned loopUnitsPerformed = 0; + unsigned totalMilliseconds; + std::clock_t iClock = std::clock(); + do + { + for(unsigned i = 0; i < loopsPerUnit; ++i) + Function(); + ++loopUnitsPerformed; + totalMilliseconds = unsigned( + (std::clock() - iClock) * 1000 / CLOCKS_PER_SEC ); + } + while(totalMilliseconds < kTestTime); + //std::cout << loopUnitsPerformed << "\n"; + + const double totalSeconds = totalMilliseconds / 1000.0; + const double totalLoops = + double(loopUnitsPerformed) * double(loopsPerUnit); + + TimingInfo info; + info.mMicroSeconds = totalSeconds * 1e6 / totalLoops; + info.mLoopsPerSecond = unsigned(totalLoops / totalSeconds + 0.5); + + return info; + } + + unsigned gTimingCounter = 0; + std::size_t gTimingTotalCount; + + void printTimingInfo() + { + if(!kPrintTimingProgress) return; + std::cout << "Timing " << gTimingCounter * 100 / gTimingTotalCount + << "%\r" << std::flush; + ++gTimingCounter; + } + + template<typename Value_t> + void getTimingInfo(FunctionInfo<Value_t>& info) + { + gFunctionString = info.mFunctionString; + ParserData<Value_t>::gEvalParameters = &info.mValidVarValues[0]; + + printTimingInfo(); + info.mParseTiming = + getTimingInfo + <doParse<Value_t>, TimingConst<Value_t>::kParseLoopsPerUnit>(); + + printTimingInfo(); + info.mEvalTiming = + getTimingInfo + <doEval<Value_t>, TimingConst<Value_t>::kEvalLoopsPerUnit>(); + + printTimingInfo(); + info.mOptimizeTiming = // optimizing a non-optimized func + getTimingInfo + <doOptimize<Value_t>, + TimingConst<Value_t>::kOptimizeLoopsPerUnit>(); + + printTimingInfo(); + ParserData<Value_t>::gParser.Optimize(); + info.mDoubleOptimizeTiming = // optimizing an already-optimized func + getTimingInfo<doOptimize<Value_t>, + TimingConst<Value_t>::kOptimizeLoopsPerUnit>(); + + printTimingInfo(); + info.mOptimizedEvalTiming = // evaluating an optimized func + getTimingInfo + <doEval<Value_t>, TimingConst<Value_t>::kEvalLoopsPerUnit>(); + + printTimingInfo(); + ParserData<Value_t>::gParser.Optimize(); + info.mDoubleOptimizedEvalTiming = // evaluating a twice-optimized func + getTimingInfo + <doEval<Value_t>, TimingConst<Value_t>::kEvalLoopsPerUnit>(); + } + + template<typename Value_t> + inline bool valueIsOk(Value_t value) + { + return !(value < -1e14 || value > 1e14); + } + + template<> + inline bool valueIsOk<long>(long) { return true; } + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool valueIsOk<GmpInt>(GmpInt) { return true; } +#endif + +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + template<> + inline bool valueIsOk<std::complex<double> > (std::complex<double>) + { + return true; + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + template<> + inline bool valueIsOk<std::complex<float> > (std::complex<float>) + { + return true; + } +#endif + +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + template<> + inline bool valueIsOk<std::complex<long double> > (std::complex<long double>) + { + return true; + } +#endif + + template<typename Value_t> + std::vector<Value_t> findImmeds(const std::vector<FunctionInfo<Value_t> >& functions) + { + std::vector<Value_t> result; + + for(std::size_t a=0; a<functions.size(); ++a) + { + const std::string& functionString = functions[a].mFunctionString; + const ParserWithConsts<Value_t>& parser = functions[a].mParser; + const char* function = functionString.c_str(); + std::size_t len = functionString.size(); + + for(std::size_t pos=0; pos<len; ) + { + std::pair<const char*, Value_t> + literal = parser.ParseLiteral(function+pos); + if(literal.first != (function+pos)) + { + result.push_back(literal.second); + result.push_back(-literal.second); + pos = literal.first - function; + continue; + } + unsigned identifier = parser.ParseIdentifier(function); + + unsigned skip_length = identifier & 0xFFFF; + if(skip_length == 0) skip_length = 1; + pos += skip_length; + } + } + + std::sort(result.begin(), result.end(), FUNCTIONPARSERTYPES::fp_less<Value_t> ); + result.erase(std::unique(result.begin(), result.end()), result.end()); + return result; + } + + template<typename Value_t> + double makeDoubleFrom(const Value_t& v) + { + /* FIXME: Why is this function needed? + * Why does findValidVarValues() use "double" datatype? + */ + return double(v); + } + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + double makeDoubleFrom(const GmpInt& v) + { + return v.toInt(); + } +#endif + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + double makeDoubleFrom(const MpfrFloat& v) + { + return v.toDouble(); + } +#endif + + template<typename Value_t> + std::vector<Value_t> parseUserGivenVarValues(const std::string& str) + { + std::vector<Value_t> values; + std::istringstream is(str); + Value_t value; + while(is >> value) values.push_back(value); + return values; + } + + template<typename Value_t> + std::vector<Value_t> parseUserGivenVarValuesFromSpecialClass + (const std::string& str) + { + std::vector<Value_t> values; + const char* ptr = str.c_str(); + char* endptr = 0; + while(true) + { + Value_t value = Value_t::parseString(ptr, &endptr); + if(endptr == ptr) break; + values.push_back(value); + ptr += endptr - ptr; + } + return values; + } + +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + template<> + std::vector<MpfrFloat> parseUserGivenVarValues<MpfrFloat> + (const std::string& str) + { + return parseUserGivenVarValuesFromSpecialClass<MpfrFloat>(str); + } +#endif + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + std::vector<GmpInt> parseUserGivenVarValues<GmpInt> + (const std::string& str) + { + return parseUserGivenVarValuesFromSpecialClass<GmpInt>(str); + } +#endif + + template<typename Value_t +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + , bool IsComplexType=FUNCTIONPARSERTYPES::IsComplexType<Value_t>::result +#endif + > + struct findValidVarValuesAux + { + static bool find(std::vector<FunctionInfo<Value_t> >& functions, + const std::string& userGivenVarValuesString) + { + unsigned varsAmount = 1; + for(std::size_t i = 0; i < gVarString.length(); ++i) + if(gVarString[i] == ',') + ++varsAmount; + + std::vector<Value_t> userGivenVarValues; + if(!userGivenVarValuesString.empty()) + { + userGivenVarValues = + parseUserGivenVarValues<Value_t>(userGivenVarValuesString); + if(userGivenVarValues.size() != varsAmount) + { + std::cout << "Warning: Wrong amount of values specified with " + "-varValues. Ignoring." << std::endl; + userGivenVarValues.clear(); + } + } + + std::vector<Value_t> varValues(varsAmount, Value_t()); + std::vector<double> doubleValues(varsAmount, 0); + std::vector<double> deltas(varsAmount, kVarValuesInitialDelta); + + std::vector<Value_t> immedList = findImmeds(functions); + + if(userGivenVarValues.empty()) + { + for(std::size_t i = 0; i < functions.size(); ++i) + functions[i].mValidVarValues = varValues; + } + else + { + for(std::size_t i = 0; i < functions.size(); ++i) + functions[i].mValidVarValues = userGivenVarValues; + ParserData<Value_t>::gVarValues.push_back(userGivenVarValues); + } + + std::vector<std::size_t> immedCounter(varsAmount, 0); + + while(true) + { + for(unsigned i = 0; i < varsAmount; ++i) + varValues[i] = Value_t(doubleValues[i]); + + bool wasOk = false; + for(std::size_t i = 0; i < functions.size(); ++i) + { + Value_t value = functions[i].mParser.Eval(&varValues[0]); + if(functions[i].mParser.EvalError() == 0 && valueIsOk(value)) + { + if(userGivenVarValues.empty()) + functions[i].mValidVarValues = varValues; + wasOk = true; + } + } + + if(wasOk) + { + ParserData<Value_t>::gVarValues.push_back(varValues); + if(ParserData<Value_t>::gVarValues.size() >= + kMaxVarValueSetsAmount) + return true; + } + + std::size_t varIndex = 0; + while(true) + { + if(immedCounter[varIndex] == 0) + { + doubleValues[varIndex] = -doubleValues[varIndex]; + if(doubleValues[varIndex] < 0.0) + break; + + doubleValues[varIndex] += deltas[varIndex]; + if(deltas[varIndex] < kVarValuesDeltaFactor2Threshold) + deltas[varIndex] *= kVarValuesDeltaFactor1; + else + deltas[varIndex] *= kVarValuesDeltaFactor2; + + if(doubleValues[varIndex] <= kVarValuesUpperLimit) + break; + } + + if(immedCounter[varIndex] < immedList.size()) + { + std::size_t& i = immedCounter[varIndex]; + doubleValues[varIndex] = + makeDoubleFrom (immedList[i] ); + i += 1; + break; + } + + immedCounter[varIndex] = 0; + doubleValues[varIndex] = 0.0; + deltas[varIndex] = kVarValuesInitialDelta; + if(++varIndex == doubleValues.size()) + { + if(ParserData<Value_t>::gVarValues.empty()) + { + ParserData<Value_t>::gVarValues.push_back + (std::vector<Value_t>(varsAmount, Value_t())); + return false; + } + return true; + } + } + } + } + }; + +#ifdef FP_SUPPORT_COMPLEX_NUMBERS + template<typename Value_t> + struct findValidVarValuesAux<Value_t, true> + { + /* Same as above, but for complex numbers */ + + static double makeDouble1From(const Value_t& v) + { + return makeDoubleFrom(v.real()); + } + static double makeDouble2From(const Value_t& v) + { + return makeDoubleFrom(v.imag()); + } + + static bool find(std::vector<FunctionInfo<Value_t> >& functions, + const std::string& userGivenVarValuesString) + { + unsigned varsAmount = 1; + for(std::size_t i = 0; i < gVarString.length(); ++i) + if(gVarString[i] == ',') + ++varsAmount; + + std::vector<Value_t> userGivenVarValues; + if(!userGivenVarValuesString.empty()) + { + userGivenVarValues = + parseUserGivenVarValues<Value_t>(userGivenVarValuesString); + if(userGivenVarValues.size() != varsAmount) + { + std::cout << "Warning: Wrong amount of values specified with " + "-varValues. Ignoring." << std::endl; + userGivenVarValues.clear(); + } + } + + const unsigned valuesAmount = varsAmount*2; + + std::vector<Value_t> varValues(varsAmount, 0); + std::vector<double> doubleValues(valuesAmount, 0); + std::vector<double> deltas(valuesAmount, kVarValuesInitialDelta); + + std::vector<Value_t> immedList = findImmeds(functions); + + if(userGivenVarValues.empty()) + { + for(std::size_t i = 0; i < functions.size(); ++i) + functions[i].mValidVarValues = varValues; + } + else + { + for(std::size_t i = 0; i < functions.size(); ++i) + functions[i].mValidVarValues = userGivenVarValues; + ParserData<Value_t>::gVarValues.push_back(userGivenVarValues); + } + + std::vector<std::size_t> immedCounter(valuesAmount, 0); + + while(true) + { + for(unsigned i = 0; i < varsAmount; ++i) + varValues[i] = Value_t( + doubleValues[i*2+0], + doubleValues[i*2+1] + ); + + bool wasOk = false; + for(std::size_t i = 0; i < functions.size(); ++i) + { + Value_t value = functions[i].mParser.Eval(&varValues[0]); + if(functions[i].mParser.EvalError() == 0 && valueIsOk(value)) + { + if(userGivenVarValues.empty()) + functions[i].mValidVarValues = varValues; + wasOk = true; + } + } + + if(wasOk) + { + ParserData<Value_t>::gVarValues.push_back(varValues); + if(ParserData<Value_t>::gVarValues.size() >= + kMaxVarValueSetsAmount) + return true; + } + + std::size_t valueIndex = 0; + while(true) + { + if(immedCounter[valueIndex] == 0) + { + doubleValues[valueIndex] = -doubleValues[valueIndex]; + if(doubleValues[valueIndex] < 0.0) + break; + + doubleValues[valueIndex] += deltas[valueIndex]; + if(deltas[valueIndex] < kVarValuesDeltaFactor2Threshold) + deltas[valueIndex] *= kVarValuesDeltaFactor1; + else + deltas[valueIndex] *= kVarValuesDeltaFactor2; + + if(doubleValues[valueIndex] <= kVarValuesUpperLimit) + break; + } + + if(immedCounter[valueIndex] < immedList.size()) + { + std::size_t& i = immedCounter[valueIndex]; + doubleValues[valueIndex] = + (valueIndex & 1) + ? makeDouble2From( immedList[i] ) + : makeDouble1From( immedList[i] ); + i += 1; + break; + } + + immedCounter[valueIndex] = 0; + doubleValues[valueIndex] = 0.0; + deltas[valueIndex] = kVarValuesInitialDelta; + if(++valueIndex == doubleValues.size()) + { + if(ParserData<Value_t>::gVarValues.empty()) + { + ParserData<Value_t>::gVarValues.push_back + (std::vector<Value_t>(varsAmount, Value_t())); + return false; + } + return true; + } + } + } + } + }; +#endif + + template<typename Value_t> + bool findValidVarValues(std::vector<FunctionInfo<Value_t> >& functions, + const std::string& userGivenVarValuesString) + { + return findValidVarValuesAux<Value_t> + ::find(functions, userGivenVarValuesString); + } + + template<typename Value_t> + inline Value_t scaledDiff(Value_t v1, Value_t v2) + { + using namespace FUNCTIONPARSERTYPES; + const Value_t scale = + fp_pow(Value_t(10), fp_floor(fp_log10(fp_abs(v1)))); + const Value_t sv1 = + fp_abs(v1) < epsilon<Value_t>() ? 0 : v1/scale; + const Value_t sv2 = + fp_abs(v2) < epsilon<Value_t>() ? 0 : v2/scale; + return sv2 - sv1; + } + + template<> + inline long scaledDiff<long>(long v1, long v2) + { + return v2 - v1; + } + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline GmpInt scaledDiff<GmpInt>(GmpInt v1, GmpInt v2) + { + return v2 - v1; + } +#endif + + template<typename Value_t> + inline bool notEqual(Value_t v1, Value_t v2) + { + using namespace FUNCTIONPARSERTYPES; + return fp_abs(scaledDiff(v1, v2)) > epsilon<Value_t>(); + } + + template<> + inline bool notEqual<long>(long v1, long v2) + { + return v1 != v2; + } + +#ifdef FP_SUPPORT_GMP_INT_TYPE + template<> + inline bool notEqual<GmpInt>(GmpInt v1, GmpInt v2) + { + return v1 != v2; + } +#endif + + template<typename Value_t> + bool compareFunctions(std::size_t function1Index, + std::size_t function2Index, + ParserWithConsts<Value_t>& parser1, + const char* parser1Type, + ParserWithConsts<Value_t>& parser2, + const char* parser2Type) + { + const std::size_t varsAmount = + ParserData<Value_t>::gVarValues[0].size(); + for(std::size_t varSetInd = 0; + varSetInd < ParserData<Value_t>::gVarValues.size(); + ++varSetInd) + { + const Value_t* values = + &ParserData<Value_t>::gVarValues[varSetInd][0]; + const Value_t v1 = parser1.Eval(values); + const Value_t v2 = parser2.Eval(values); + + if(notEqual(v1, v2)) + { + if(parser1.EvalError() && parser1Type[0] == 'n') + { + // If the source expression returns an error, + // ignore this "failure" + continue; + } + + using namespace FUNCTIONPARSERTYPES; + std::cout << SEPARATOR << "\n******* For variable values ("; + for(std::size_t i = 0; i < varsAmount; ++i) + { + if(i > 0) std::cout << ","; + std::cout << values[i]; + } + std::cout << ")\n"; + std::cout << "******* function " << function1Index+1 + << " (" << parser1Type << ") returned "; + if(parser1.EvalError()) + std::cout << "error " << parser1.EvalError(); + else + std::cout << std::setprecision(18) << v1; + std::cout << "\n"; + std::cout << "******* function " << function2Index+1 + << " (" << parser2Type << ") returned "; + if(parser2.EvalError()) + std::cout << "error " << parser2.EvalError(); + else + std::cout << std::setprecision(18) << v2; + std::cout << "\n******* (Difference: " << (v2-v1) + << ", scaled diff: " + << std::setprecision(18) << scaledDiff(v1, v2) + << ")" << std::endl; + return false; + } + } + return true; + } + + bool had_double_optimization_problems = false; + + template<typename Value_t> + bool checkEquality(const std::vector<FunctionInfo<Value_t> >& functions) + { + static const char not_optimized[] = "not optimized"; + static const char optimized[] = "optimized"; + static const char optimized2[] = "double-optimized"; + static const char* const optimize_labels[3] = + { not_optimized, optimized, optimized2 }; + + ParserWithConsts<Value_t> parser1, parser2, parser3; + + bool errors = false; + for(std::size_t ind1 = 0; ind1 < functions.size(); ++ind1) + { + parser1.Parse + (functions[ind1].mFunctionString, gVarString, gUseDegrees); + parser2.Parse + (functions[ind1].mFunctionString, gVarString, gUseDegrees); + // parser 1 is not optimized + + // Printing the bytecode right _here_ is useful + // for debugging situations where fparser crashes + // before printByteCodes() is reached, such as + // within Optimize() or Eval(). + + ////std::cout << "Not optimized:\n"; parser2.PrintByteCode(std::cout); + parser2.Optimize(); // parser 2 is optimized once + + ////std::cout << "Is optimized:\n"; parser2.PrintByteCode(std::cout); + + if(!compareFunctions(ind1, ind1, parser1, not_optimized, + parser2, optimized)) + errors = true; + + parser2.Optimize(); // parser 2 is optimized twice + ////std::cout << "Twice optimized:\n"; parser2.PrintByteCode(std::cout); + + if(!compareFunctions(ind1, ind1, parser1, not_optimized, + parser2, optimized2)) + errors = had_double_optimization_problems = true; + + parser1.Optimize(); // parser 1 is optimized once + if(!compareFunctions(ind1, ind1, parser1, optimized, + parser2, optimized2)) + errors = had_double_optimization_problems = true; + + for(std::size_t ind2 = ind1+1; ind2 < functions.size(); ++ind2) + { + parser1.Parse(functions[ind1].mFunctionString, gVarString, + gUseDegrees); + for(int n_optimizes1 = 0; n_optimizes1 <= 2; ++n_optimizes1) + { + if(errors) break; + if(n_optimizes1 > 0) parser1.Optimize(); + + parser2.Parse(functions[ind2].mFunctionString, gVarString, + gUseDegrees); + + for(int n_optimizes2 = 0; n_optimizes2 <= 2; ++n_optimizes2) + { + if(n_optimizes2 > 0) parser2.Optimize(); + bool ok = compareFunctions(ind1, ind2, + parser1, optimize_labels[n_optimizes1], + parser2, optimize_labels[n_optimizes2]); + if(!ok) + { + errors = true; + if(n_optimizes1 > 1 || n_optimizes2 > 1) + had_double_optimization_problems = true; + break; + } + } + } + } + } + return !errors; + } + + void wrapLine(std::string& line, std::size_t cutter, std::string& wrap_buf, + bool always_cut = false) + { + if(line.size() <= cutter) + line.resize(cutter, ' '); + else + { + if(!always_cut) + { + for(std::size_t wrap_at = cutter; wrap_at > 0; --wrap_at) + { + char c = line[wrap_at-1]; + if(c == '*' || c == '+' || c == '/' || c == '(' + || c == ')' || c == '^' || c == ',' || c == '&' + || c == '|' || c == '-') + { + wrap_buf = std::string(20, ' '); + wrap_buf += line.substr(wrap_at); + line.erase(line.begin()+wrap_at, line.end()); + line.resize(cutter, ' '); + return; + } + } + } + + line.resize(cutter, ' '); + line[cutter-1] = '~'; + } + } + + enum PrintMode { print_wrap, print_cut, print_no_cut_or_wrap }; + + template<typename Value_t> + void printByteCodes(const std::vector<FunctionInfo<Value_t> >& functions, + PrintMode mode = print_no_cut_or_wrap) + { +#ifdef FUNCTIONPARSER_SUPPORT_DEBUGGING + ParserWithConsts<Value_t> parser; + const char* const wall = + (mode == print_no_cut_or_wrap) + ? "\33[0m| " + : "| "; + const char* const newline = + (mode == print_no_cut_or_wrap) + ? "\33[0m\n" + : "\n"; + const char* colors[3] = { "\33[37m", "\33[36m", "\33[32m" }; + if(mode != print_no_cut_or_wrap) + colors[0] = colors[1] = colors[2] = ""; + + for(std::size_t i = 0; i < functions.size(); ++i) + { + std::cout << SEPARATOR << std::endl; + + std::stringstream streams[3]; + + parser.Parse(functions[i].mFunctionString, gVarString, gUseDegrees); + + std::size_t one_column = 38; + std::size_t two_columns = one_column * 2 + 2; + + streams[0] << + "Function " << i+1 << " original\n" + "-------------------\n"; + parser.PrintByteCode(streams[0], gPrintByteCodeExpressions); + + streams[1] << + "Optimized\n" + "---------\n"; + parser.Optimize(); + { + std::ostringstream streams2_bytecodeonly; + parser.PrintByteCode(streams2_bytecodeonly, + gPrintByteCodeExpressions); + streams[1] << streams2_bytecodeonly.str(); + + parser.Optimize(); + { + std::ostringstream streams3_bytecodeonly; + parser.PrintByteCode(streams3_bytecodeonly, + gPrintByteCodeExpressions); + + if(had_double_optimization_problems || + streams2_bytecodeonly.str() != + streams3_bytecodeonly.str()) + { + streams[2] << + "Double-optimized\n" + "----------------\n"; + streams[2] << streams3_bytecodeonly.str(); + //one_column = 24; + //two_columns = one_column * 2 + 2; + } + } + } + + #if 0 + std::cout << "Code 0\n" << streams[0].str() << std::endl; + std::cout << "Code 1\n" << streams[1].str() << std::endl; + std::cout << "Code 2\n" << streams[2].str() << std::endl; + #else + std::string streams_wrap_buf[3]; + std::string lines[3]; + while(true) + { + bool all_empty = true; + for(int p=0; p<3; ++p) + { + if(!streams_wrap_buf[p].empty()) + { + lines[p].clear(); + lines[p].swap( streams_wrap_buf[p] ); + } + else if(streams[p]) + std::getline(streams[p], lines[p]); + else + lines[p].clear(); + if(!lines[p].empty()) all_empty = false; + } + if(all_empty) break; + + if(mode != print_no_cut_or_wrap) + { + if(!lines[1].empty()) + wrapLine(lines[0], one_column, streams_wrap_buf[0], + mode == print_cut); + else if(!lines[2].empty()) + wrapLine(lines[0], two_columns, streams_wrap_buf[0], + mode == print_cut); + if(!lines[2].empty() && !lines[1].empty()) + wrapLine(lines[1], one_column, streams_wrap_buf[1], + mode == print_cut); + } + else + { + bool wrap0 = false; + if(!lines[1].empty()) + { + if(lines[0].size() >= one_column) wrap0 = true; + else lines[0].resize(one_column, ' '); + } + else if(!lines[2].empty()) + { + if(lines[0].size() >= two_columns) wrap0 = true; + else lines[0].resize(two_columns, ' '); + } + + if(wrap0) + { + lines[1].swap(streams_wrap_buf[1]); + if(!lines[2].empty() && lines[0].size() >= two_columns) + lines[2].swap(streams_wrap_buf[2]); + else if(lines[0].size() < two_columns) + lines[0].resize(two_columns, ' '); + } + + bool wrap1 = false; + if(!lines[2].empty() && !lines[1].empty()) + { + if(lines[1].size() >= one_column) wrap1 = true; + else lines[1].resize(one_column, ' '); + } + + if(wrap1 && !lines[2].empty()) + { + lines[2].swap(streams_wrap_buf[2]); + } + } + + std::cout << colors[0] << lines[0]; + if(!lines[1].empty()) + std::cout << wall << colors[1] << lines[1]; + if(!lines[2].empty()) + std::cout << wall << colors[2] << lines[2]; + std::cout << newline; + } + #endif + } +#endif + } + + template<typename Value_t> + void printFunctionTimings(std::vector<FunctionInfo<Value_t> >& functions) + { + std::printf + (" ,------------------------------------------------------------------------,\n" + " | Parse | Eval | Eval (O) | Eval (O2) | Optimize | Repeat O.|\n" + ",---+------------+-----------+-----------+-----------+-----------+-----------+\n"); + for(std::size_t i = 0; i < functions.size(); ++i) + { + getTimingInfo(functions[i]); + std::printf + ("|%2u | %10.3f |%10.3f |%10.3f |%10.3f |%10.1f |%10.1f |\n", + unsigned(i+1), + functions[i].mParseTiming.mMicroSeconds, + functions[i].mEvalTiming.mMicroSeconds, + functions[i].mOptimizedEvalTiming.mMicroSeconds, + functions[i].mDoubleOptimizedEvalTiming.mMicroSeconds, + functions[i].mOptimizeTiming.mMicroSeconds, + functions[i].mDoubleOptimizeTiming.mMicroSeconds + ); + } + std::printf + ("'----------------------------------------------------------------------------'\n"); + } + + template<typename Value_t> + bool checkFunctionValidity(FunctionInfo<Value_t>& info) + { + int result = info.mParser.Parse(info.mFunctionString, gVarString, + gUseDegrees); + if(result >= 0) + { + std::cerr << "\"" << info.mFunctionString << "\"\n" + << std::string(result+1, ' ') + << "^ " << info.mParser.ErrorMsg() << std::endl; + if(info.mParser.GetParseErrorType() == + FunctionParserBase<Value_t>::INVALID_VARS) + std::cerr << "Vars: \"" << gVarString << "\"" << std::endl; + return false; + } + return true; + } + + template<typename Value_t> + void deduceVariables(const std::vector<FunctionInfo<Value_t> >& functions) + { + typedef std::set<std::string> StrSet; + StrSet varNames; + ParserWithConsts<Value_t> parser; + + for(std::size_t funcInd = 0; funcInd < functions.size(); ++funcInd) + { + const std::string funcStr = functions[funcInd].mFunctionString; + int oldIndex = -1; + + while(true) + { + gVarString.clear(); + for(StrSet::iterator iter = varNames.begin(); + iter != varNames.end(); + ++iter) + { + if(iter != varNames.begin()) gVarString += ","; + gVarString += *iter; + } + + int index = parser.Parse(funcStr, gVarString, gUseDegrees); + if(index < 0) break; + if(index == oldIndex) return; + + int index2 = index; + if(index2 < int(funcStr.length()) && + (std::isalpha(funcStr[index2]) || funcStr[index2] == '_')) + { + while(index2 < int(funcStr.length()) && + (std::isalnum(funcStr[index2]) || + funcStr[index2] == '_')) + ++index2; + } + + if(index2 == index) + return; + + varNames.insert(funcStr.substr(index, index2-index)); + oldIndex = index; + } + } + } + + int printHelp(const char* programName) + { + std::cerr << + "FunctionParser functioninfo utility " << kVersionNumber << + "\n\nUsage: " << programName << + " [<options] <function1> [<function2> ...]\n\n" + "Options:\n" + " -f : Use FunctionParser_f.\n" + " -ld : Use FunctionParser_ld.\n" + " -mpfr : Use FunctionParser_mpfr.\n" + " -mpfr_bits <bits> : MpfrFloat mantissa bits (default 80).\n" + " -li : Use FunctionParser_li.\n" + " -gi : Use FunctionParser_gmpint.\n" + " -cd : Use FunctionParser_cd.\n" + " -cf : Use FunctionParser_cf.\n" + " -cld : Use FunctionParser_cld.\n" + " -vars <string> : Specify a var string.\n" + " -nt : No timing measurements.\n" + " -ntd : No timing if functions differ.\n" + " -deg : Use degrees for trigonometry.\n" + " -noexpr : Don't print byte code expressions.\n" + " -varValues <values> : Space-separated variable values to use.\n"; + return 1; + } +} + +template<typename Value_t> +int functionInfo(const char* const parserTypeString, + const std::vector<std::string>& functionStrings, + bool measureTimings, bool noTimingIfEqualityErrors, + const std::string& userGivenVarValues) +{ + std::vector<FunctionInfo<Value_t> > functions(functionStrings.size()); + for(std::size_t i = 0; i < functions.size(); ++i) + functions[i].mFunctionString = functionStrings[i]; + + if(gVarString.empty()) + deduceVariables(functions); + + for(std::size_t i = 0; i < functions.size(); ++i) + { + if(!checkFunctionValidity(functions[i])) + return 1; + } + + const bool validVarValuesFound = + findValidVarValues(functions, userGivenVarValues); + + std::cout << SEPARATOR << std::endl + << "Parser type: " << parserTypeString << std::endl; + for(std::size_t i = 0; i < functions.size(); ++i) + std::cout << "- Function " << i+1 << ": \"" + << functions[i].mFunctionString << "\"\n"; + const std::size_t varsAmount = ParserData<Value_t>::gVarValues[0].size(); + const std::size_t varValueSetsAmount = ParserData<Value_t>::gVarValues.size(); + std::cout << "- Var string: \"" << gVarString << "\" (" + << ParserData<Value_t>::gVarValues[0].size() + << (varsAmount == 1 ? " var" : " vars") + << ") (using " << varValueSetsAmount << " set" + << (varValueSetsAmount == 1 ? ")\n" : "s)\n"); + +#if 0 + std::cout << SEPARATOR << "\nTesting with variable values:\n"; + for(std::size_t i = 0; i < ParserData<Value_t>::gVarValues.size(); ++i) + { + if(i > 0) std::cout << (i%5==0 ? "\n" : " "); + std::cout << "("; + for(std::size_t j = 0; j < ParserData<Value_t>::gVarValues[i].size(); ++j) + { + if(j > 0) std::cout << ","; + using namespace FUNCTIONPARSERTYPES; + std::cout << ParserData<Value_t>::gVarValues[i][j]; + } + std::cout << ")"; + } + if(!validVarValuesFound) + std::cout << " [no valid variable values were found...]"; + std::cout << "\n" << SEPARATOR << std::endl; +#else + if(!validVarValuesFound) + std::cout << SEPARATOR + << "\nWarning: No valid variable values were found." + << " Using (0,0)." << std::endl; +#endif + + const bool equalityErrors = checkEquality(functions) == false; + + printByteCodes(functions); + + if(noTimingIfEqualityErrors && equalityErrors) + measureTimings = false; + + if(measureTimings) + { + gTimingTotalCount = functions.size() * 4; + printFunctionTimings(functions); + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + if(argc < 2) return printHelp(argv[0]); + + enum ParserType { FP_D, FP_F, FP_LD, FP_MPFR, FP_LI, FP_GI, FP_CD, FP_CF, FP_CLD }; + + std::vector<std::string> functionStrings; + bool measureTimings = true, noTimingIfEqualityErrors = false; + ParserType parserType = FP_D; + unsigned long mantissaBits = 80; + std::string userGivenVarValues; + + for(int i = 1; i < argc; ++i) + { + if(std::strcmp(argv[i], "-f") == 0) parserType = FP_F; + else if(std::strcmp(argv[i], "-ld") == 0) parserType = FP_LD; + else if(std::strcmp(argv[i], "-mpfr") == 0) parserType = FP_MPFR; + else if(std::strcmp(argv[i], "-li") == 0) parserType = FP_LI; + else if(std::strcmp(argv[i], "-gi") == 0) parserType = FP_GI; + else if(std::strcmp(argv[i], "-cd") == 0) parserType = FP_CD; + else if(std::strcmp(argv[i], "-cf") == 0) parserType = FP_CF; + else if(std::strcmp(argv[i], "-cld") == 0) parserType = FP_CLD; + else if(std::strcmp(argv[i], "-vars") == 0) + { + if(++i == argc) return printHelp(argv[0]); + gVarString = argv[i]; + } + else if(std::strcmp(argv[i], "-nt") == 0) + measureTimings = false; + else if(std::strcmp(argv[i], "-ntd") == 0) + noTimingIfEqualityErrors = true; + else if(std::strcmp(argv[i], "-deg") == 0) + gUseDegrees = true; + else if(std::strcmp(argv[i], "-mpfr_bits") == 0) + { + if(++i == argc) return printHelp(argv[0]); + mantissaBits = std::atol(argv[i]); + } + else if(std::strcmp(argv[i], "-noexpr") == 0) + gPrintByteCodeExpressions = false; + else if(std::strcmp(argv[i], "-varValues") == 0) + { + if(++i == argc) return printHelp(argv[0]); + userGivenVarValues = argv[i]; + } + else if(std::strcmp(argv[i], "--help") == 0 + || std::strcmp(argv[i], "-help") == 0 + || std::strcmp(argv[i], "-h") == 0 + || std::strcmp(argv[i], "/?") == 0) + printHelp(argv[0]); + else + functionStrings.push_back(argv[i]); + } + + if(functionStrings.empty()) return printHelp(argv[0]); + + const char* notCompiledParserType = 0; + + switch(parserType) + { + case FP_D: +#ifndef FP_DISABLE_DOUBLE_TYPE + return functionInfo<double> + ("double", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "double"; + break; +#endif + + case FP_F: +#ifdef FP_SUPPORT_FLOAT_TYPE + return functionInfo<float> + ("float", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "float"; + break; +#endif + + case FP_LD: +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + return functionInfo<long double> + ("long double", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "long double"; + break; +#endif + + case FP_MPFR: +#ifdef FP_SUPPORT_MPFR_FLOAT_TYPE + { + MpfrFloat::setDefaultMantissaBits(mantissaBits); + std::ostringstream typeName; + typeName << "MpfrFloat(" << mantissaBits << ")"; + return functionInfo<MpfrFloat> + (typeName.str().c_str(), functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); + } +#else + notCompiledParserType = "MpfrFloat"; + break; +#endif + + case FP_LI: +#ifdef FP_SUPPORT_LONG_INT_TYPE + return functionInfo<long int> + ("long int", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "long int"; + break; +#endif + + case FP_GI: +#ifdef FP_SUPPORT_GMP_INT_TYPE + return functionInfo<GmpInt> + ("GmpInt", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "GmpInt"; + break; +#endif + + case FP_CD: +#ifdef FP_SUPPORT_COMPLEX_DOUBLE_TYPE + return functionInfo<std::complex<double> > + ("std::complex<double>", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "std::complex<double>"; + break; +#endif + + case FP_CF: +#ifdef FP_SUPPORT_COMPLEX_FLOAT_TYPE + return functionInfo<std::complex<float> > + ("std::complex<float>", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "std::complex<float>"; + break; +#endif + + case FP_CLD: +#ifdef FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE + return functionInfo<std::complex<long double> > + ("std::complex<long double>", functionStrings, + measureTimings, noTimingIfEqualityErrors, + userGivenVarValues); +#else + notCompiledParserType = "std::complex<long double>"; + break; +#endif + } + + if(notCompiledParserType) + { + std::cout << "Error: Support for type " << notCompiledParserType + << " was not compiled in." << std::endl; + return 1; + } + return 0; +} diff --git a/util/make_function_name_parser.cc b/util/make_function_name_parser.cc new file mode 100644 index 0000000..12820f7 --- /dev/null +++ b/util/make_function_name_parser.cc @@ -0,0 +1,177 @@ +/*========================================================================== + make_function_name_parser + ------------------------- + Copyright: Joel Yliluoma + This program (make_function_name_parser) is distributed under the terms of + the GNU General Public License (GPL) version 3. + See gpl.txt for the license text. +============================================================================*/ + +#define FUNCTIONPARSER_SUPPORT_DEBUGGING + +#include <set> +#include <iostream> +#include <sstream> +#include <string.h> + +#include "fparser.hh" +#include "fpconfig.hh" +#include "extrasrc/fptypes.hh" + +#include "../fpoptimizer/opcodename.cc" +#include "../util/cpp_compress.hh" + +using namespace FUNCTIONPARSERTYPES; + +static void Compile(std::ostream& outStream, const std::string& prefix, size_t length) +{ + // if the prefix matches, check what we've got + outStream << "/* prefix " << prefix << " */"; + + for(size_t a=0; a<FUNC_AMOUNT; ++a) + if(prefix == Functions[a].name + && length == strlen(Functions[a].name)) + { + std::string o = FP_GetOpcodeName(OPCODE(a)); + outStream << "return (" << o << "<<16) | 0x"; + outStream << std::hex << (0x80000000U | length); + outStream << std::dec << "U;"; + outStream << "\n "; + return; + } + + size_t n_possible_children = 0; + for(size_t a=0; a<FUNC_AMOUNT; ++a) + { + if(strlen(Functions[a].name) != length) continue; + if(strlen(Functions[a].name) < prefix.size()) continue; + if(prefix == std::string(Functions[a].name, prefix.size())) + ++n_possible_children; + } + + if(n_possible_children == 1) + { + for(size_t a=0; a<FUNC_AMOUNT; ++a) + { + if(strlen(Functions[a].name) != length) continue; + if(strlen(Functions[a].name) < prefix.size()) continue; + if(prefix == std::string(Functions[a].name, prefix.size())) + { + if(prefix != Functions[a].name) + { + size_t tmpbytes = length - prefix.size(); + if(tmpbytes > 2) + { + outStream << "{"; + outStream << "static const char tmp[" << tmpbytes << "] = {"; + for(size_t b=prefix.size(); b<length; ++b) + { + if(b > prefix.size()) outStream << ','; + outStream << "'" << Functions[a].name[b] << "'"; + } + outStream << "};\n "; + } + + if(tmpbytes > 2) + outStream << "if(std::memcmp(uptr+" << prefix.size() << ", tmp, " << tmpbytes << ") == 0) "; + else + { + outStream << "if("; + for(size_t b=prefix.size(); b<length; ++b) + { + if(b != prefix.size()) outStream << "\n && "; + outStream << "'" << Functions[a].name[b] << "' == uptr[" << b << "]"; + } + outStream << ") "; + } + + std::string o = FP_GetOpcodeName(OPCODE(a)); + outStream << "return (" << o << "<<16) | 0x"; + outStream << std::hex << (0x80000000U | length); + outStream << std::dec << "U;"; + outStream << "\n return " << length << ";"; + if(tmpbytes > 2) outStream << " }"; + outStream << "\n "; + } + } + } + return; + } + + std::set<char> possible_children; + for(size_t a=0; a<FUNC_AMOUNT; ++a) + { + if(strlen(Functions[a].name) != length) continue; + if(strlen(Functions[a].name) <= prefix.size()) continue; + if(prefix == std::string(Functions[a].name, prefix.size())) + { + char c = Functions[a].name[prefix.size()]; + possible_children.insert(c); + } + } + + if(possible_children.empty()) + { + outStream << "return " << length << ";\n "; + } + else + { + if(possible_children.size() == 1) + { + for(std::set<char>::const_iterator + i = possible_children.begin(); + i != possible_children.end(); + ++i) + { + outStream << "if('" << *i << "' == uptr[" << prefix.size() << "]) {\n "; + std::string tmp(prefix); + tmp += *i; + Compile(outStream, tmp, length); + outStream << "}"; + } + outStream << "return " << length << ";"; + } + else + { + outStream << "switch(uptr[" << prefix.size() << "]) {\n "; + for(std::set<char>::const_iterator + i = possible_children.begin(); + i != possible_children.end(); + ++i) + { + outStream << "case '" << *i << "':\n "; + std::string tmp(prefix); + tmp += *i; + Compile(outStream, tmp, length); + } + outStream << "default: return " << length << "; }\n "; + } + } +} + +int main() +{ + std::ostringstream outStream; + + outStream << +" switch(nameLength)\n" +" {\n "; + std::set<unsigned> lengthSet; + for(size_t a=0; a<FUNC_AMOUNT; ++a) + lengthSet.insert(strlen(Functions[a].name)); + for(std::set<unsigned>::iterator + i = lengthSet.begin(); i != lengthSet.end(); ++i) + { + outStream << " case " << *i << ":\n "; + Compile(outStream, "", *i); + outStream << "\n "; + } + outStream << +" default: break;\n" +" }\n" +" return nameLength;\n"; + + CPPcompressor Compressor; + //std::cout << outStream.str(); + std::cout << Compressor.Compress(outStream.str(), "l"); +} diff --git a/util/powi_opt.cc b/util/powi_opt.cc new file mode 100644 index 0000000..832aec9 --- /dev/null +++ b/util/powi_opt.cc @@ -0,0 +1,208 @@ +#include <iostream> + +#define FP_GENERATING_POWI_TABLE +#include "../fpoptimizer/bytecodesynth.cc" +#include "../fpoptimizer/codetree.hh" +#include "extrasrc/fptypes.hh" + +using namespace FUNCTIONPARSERTYPES; +using namespace FPoptimizer_CodeTree; +using namespace FPoptimizer_ByteCode; + +#include <iomanip> +namespace +{ + inline void printHex(std::ostream& dest, unsigned n) + { + dest.width(8); dest.fill('0'); std::hex(dest); //uppercase(dest); + dest << n; + } +} + +static +void PrintByteCode(const std::vector<unsigned>& ByteCode, + const std::vector<double>& Immed, + std::ostream& dest) +{ + for(unsigned IP = 0, DP = 0; IP < ByteCode.size(); ++IP) + { + printHex(dest, IP); + dest << ": "; + + unsigned opcode = ByteCode[IP]; + + switch(opcode) + { + case cIf: + dest << "jz\t"; + printHex(dest, ByteCode[IP+1]+1); + dest << std::endl; + IP += 2; + break; + + case cJump: + dest << "jump\t"; + printHex(dest, ByteCode[IP+1]+1); + dest << std::endl; + IP += 2; + break; + case cImmed: + dest.precision(10); + dest << "push\t" << Immed[DP++] << std::endl; + break; + + default: + if(OPCODE(opcode) < VarBegin) + { + std::string n; + unsigned params = 1; + switch(opcode) + { + case cNeg: n = "neg"; break; + case cAdd: n = "add"; break; + case cSub: n = "sub"; break; + case cMul: n = "mul"; break; + case cDiv: n = "div"; break; + case cMod: n = "mod"; break; + case cPow: n = "pow"; break; + case cEqual: n = "eq"; break; + case cNEqual: n = "neq"; break; + case cLess: n = "lt"; break; + case cLessOrEq: n = "le"; break; + case cGreater: n = "gt"; break; + case cGreaterOrEq: n = "ge"; break; + case cAnd: n = "and"; break; + case cOr: n = "or"; break; + case cNot: n = "not"; break; + case cDeg: n = "deg"; break; + case cRad: n = "rad"; break; + +#ifdef FP_SUPPORT_OPTIMIZER + case cDup: n = "dup"; break; + case cInv: n = "inv"; break; + case cSqr: n = "sqr"; break; + case cFetch: + dest << "cFetch(" << ByteCode[++IP] << ")"; + break; + case cPopNMov: + { + size_t a = ByteCode[++IP]; + size_t b = ByteCode[++IP]; + dest << "cPopNMov(" << a << ", " << b << ")"; + break; + } +#endif + + default: + n = Functions[opcode-cAbs].name; + params = Functions[opcode-cAbs].params; + } + dest << n; + if(params != 1) dest << " (" << params << ")"; + dest << std::endl; + } + else + { + dest << "push\tVar" << opcode-VarBegin << std::endl; + } + } + } +} + +static long min(long a,long b) { return a<b?a:b;} + +int main() +{ + for(long exponent = 2; exponent < 256; ++exponent) + { + CodeTree ct; + + double bestres = 0; + long bestp = -1; + + /* x^40 / x^5 (rdiv) cannot be used when x=0 */ + for(long p=1; p<256; ++p) + { + long factor = p&127; + if(factor & 64) + { + factor = -(factor&63) - 1; + continue; + } + if(p & 128) + { + if(factor == 0) continue; + if(factor==1 || exponent % factor != 0) continue; + if(factor >= exponent) continue; + } + else + { + if(factor >= exponent) continue; + if(factor < 0 + && (( (-factor&(-factor-1))) + || -factor <= exponent) + ) continue; + } + + //if(p != powi_table[exponent]) continue; + + powi_table[exponent] = p; + + fprintf(stderr, "For %ld, trying %ld (%ld%s)... ", + exponent, + p, factor, + (p&128) ? ", factor": ""); + + ByteCodeSynth synth; + synth.PushVar(VarBegin); + AssembleSequence(exponent, MulSequence, synth); + + std::vector<unsigned> byteCode; + std::vector<double> immed; + size_t stacktop_max=1; + synth.Pull(byteCode, immed, stacktop_max); + + double res = 0; + for(size_t a=0; a<byteCode.size(); ++a) + { + if(byteCode[a] == cMul) + res += 7; + else if(byteCode[a] == cDiv || byteCode[a] == cRDiv) + res += 11; + else if(byteCode[a] == cSqr) + res += 6.5; + else if(byteCode[a] == cDup) + res += 1; + else if(byteCode[a] == cPopNMov) + { res += 5; a += 2; } + else if(byteCode[a] == cFetch) + { res += 3.5; a += 1; } + } + + res += stacktop_max*0.3; + + fprintf(stderr, "gets %g, stackmax %u", res, (unsigned)stacktop_max); + if(res < bestres + || bestp == -1 + ) + { + fprintf(stderr, " -- beats %g (%ld)\n", bestres, bestp); + bestp = p; + bestres = res; + } + else + fprintf(stderr, "\n"); + fflush(stderr); + + PrintByteCode(byteCode, immed, std::cerr); + std::cerr << std::endl; + } + powi_table[exponent] = bestp; + } + for(unsigned n=0; n<256; ++n) + { + if(n%8 == 0) printf(" "); + printf("%4d,", powi_table[n]); + if(n%8 == 7) printf(" /*%4d -%4d */\n", n&~7, (n&~7)|7); + } +} diff --git a/util/powi_speedtest.cc b/util/powi_speedtest.cc new file mode 100644 index 0000000..68414e1 --- /dev/null +++ b/util/powi_speedtest.cc @@ -0,0 +1,63 @@ +#include "fparser.hh" +#include <cstdio> +#include <sstream> +#include <string> +#include <ctime> +#include <cmath> + +std::string getFunction(int exponent) +{ + std::ostringstream os; + os << "x^" << exponent; + std::string func = os.str(); + while(func.length() < 6) func = " " + func; + return func; +} + +unsigned getEvalsPerMS(FunctionParser& fp) +{ + const unsigned loops = 3000000; + + std::clock_t iTime = std::clock(); + const double value = 1.02; + + for(unsigned i = 0; i < loops; ++i) + fp.Eval(&value); + + std::clock_t t = std::clock() - iTime; + return unsigned(std::floor(double(loops)*CLOCKS_PER_SEC/1000.0/t + .5)); +} + +int main() +{ + FunctionParser fp; + + std::printf + ("Evaluations per microsecond:\n" + " Func Normal Optim Func Normal Optim Func Normal Optim Func Normal Optim\n" + " ---- ------ ----- ---- ------ ----- ---- ------ ----- ---- ------ -----\n"); + + for(int row = 0; row < 100; ++row) + { + for(int sign = 1; sign >= -1; sign -= 2) + { + for(int column = 0; column < 4; ++column) + { + const int exponent = (row + column*100) * sign; + { + const std::string func = getFunction(exponent); + fp.Parse(func, "x"); + + const unsigned epms1 = (getEvalsPerMS(fp)+50)/100; + fp.Optimize(); + const unsigned epms2 = (getEvalsPerMS(fp)+50)/100; + + std::printf("%s %4u.%1u %4u.%1u ", func.c_str(), + epms1/10, epms1%10, epms2/10, epms2%10); + std::fflush(stdout); + } + } + std::printf("\n"); + } + } +} diff --git a/util/speedtest.cc b/util/speedtest.cc new file mode 100644 index 0000000..758a1c9 --- /dev/null +++ b/util/speedtest.cc @@ -0,0 +1,344 @@ +/*========================================================================== + speedtest + --------- + Copyright: Juha Nieminen, Joel Yliluoma + This program (speedtest) is distributed under the terms of + the GNU General Public License (GPL) version 3. + See gpl.txt for the license text. +============================================================================*/ + +static const char* const kVersionNumber = "1.0.0.0"; + +//#define TEST_JIT +//#define MEASURE_PARSING_SPEED_ONLY + +#include "fparser.hh" +#include <ctime> +#include <string> +#include <iostream> +#include <cmath> +#include <sstream> +#include <cstring> + +#include <sys/time.h> + +//#define FUNC0 x+y+(sin(x)*cos(x)*log(x)*(-x-y+log(y)-sin(x))) +//#define FUNC0 pow(x,14)+pow(y,8)+pow(x,2)+2*x*y+pow(y,2) +#define FUNC0 pow(x,14) + pow(y,8) +#define FUNC0P x^14 + y^8 + +#define FUNC1 ((3*pow(x,4)-7*pow(x,3)+2*x*x-4*x+10) - (4*pow(y,3)+2*y*y-10*y+2))*10 +#define FUNC1P ((3*x^4-7*x^3+2*x^2-4*x+10) - (4*y^3+2*y^2-10*y+2))*10 + +#define FUNC2 ((3*(x+(5*(y+2)-7*x)*3-y)+4*5+3)-7+(8*x+5*y+(7-x))*4)-10*3+4 +#define FUNC2P FUNC2 + +#define FUNC3 pow((tan(x)*cos(x)), 2) - 1.2*log(atan2(sqrt((-pow(y,2))+1), y) * pow(4.91, y)) + pow(cos(-x), 2) +#define FUNC3P (tan(x)*cos(x))^2 - 1.2*log(atan2(sqrt((-y^2)+1), y) * 4.91^y) + cos(-x)^2 + +#define FUNC4 exp((-x*x-y*y)/100)*sin(sqrt(x*x+y*y))/(10*2) + sin(pow(x,4)-4*pow(x,3)+3*x*x-2*x+2*5-3) - cos(-2*pow(y,4)+5*pow(y,3)-14*x*x+8*x-120/2+4) +#define FUNC4P FUNC4 + +#define StringifyHlp(x) #x +#define Stringify(x) StringifyHlp(x) + +#define CreateFunction(funcName, Value_t, funcBody) \ +Value_t funcName(const Value_t* vars) \ +{ \ + const Value_t x = vars[0], y = vars[1]; \ + return funcBody; \ +} + +namespace +{ + bool gPrintHTML = false; + + struct FuncData + { + const char* const funcStr; + const std::string paramStr; + double (*const function_d)(const double*); + float (*const function_f)(const float*); + long double (*const function_ld)(const long double*); + }; + + CreateFunction(func0_d, double, FUNC0) + CreateFunction(func1_d, double, FUNC1) + CreateFunction(func2_d, double, FUNC2) + CreateFunction(func3_d, double, FUNC3) + CreateFunction(func4_d, double, FUNC4) + +#define exp expf +#define pow powf +#define sin sinf +#define cos cosf +#define sqrt sqrtf + CreateFunction(func0_f, float, FUNC0) + CreateFunction(func1_f, float, FUNC1) + CreateFunction(func2_f, float, FUNC2) + CreateFunction(func3_f, float, FUNC3) + CreateFunction(func4_f, float, FUNC4) +#undef exp +#undef pow +#undef sin +#undef cos +#undef sqrt + +#define exp expl +#define pow powl +#define sin sinl +#define cos cosl +#define sqrt sqrtl + CreateFunction(func0_ld, long double, FUNC0) + CreateFunction(func1_ld, long double, FUNC1) + CreateFunction(func2_ld, long double, FUNC2) + CreateFunction(func3_ld, long double, FUNC3) + CreateFunction(func4_ld, long double, FUNC4) +#undef exp +#undef pow +#undef sin +#undef cos +#undef sqrt + + const FuncData funcData[] = + { + { Stringify(FUNC0P), "x,y", func0_d, func0_f, func0_ld }, + { Stringify(FUNC1P), "x,y", func1_d, func1_f, func1_ld }, + { Stringify(FUNC2P), "x,y", func2_d, func2_f, func2_ld }, + { Stringify(FUNC3P), "x,y", func3_d, func3_f, func3_ld }, + { Stringify(FUNC4P), "x,y", func4_d, func4_f, func4_ld } + }; + + const unsigned FunctionsAmount = sizeof(funcData)/sizeof(funcData[0]); + + inline double callFunc(const FuncData& data, const double* values) + { + return data.function_d(values); + } + + inline float callFunc(const FuncData& data, const float* values) + { + return data.function_f(values); + } + + inline long double callFunc(const FuncData& data, const long double* values) + { + return data.function_ld(values); + } + + std::string beautify(int value) + { + std::ostringstream os; + os << value; + std::string result = os.str(); + for(std::size_t i = result.size(); i > 3;) + result.insert(i -= 3, gPrintHTML ? " " : " "); + return result; + } +} + +class Test +{ +public: + void Start(unsigned nloops) + { + this->nloops = nloops; + this->iter = 0; + this->result = 0; + this->reset_threshold = nloops / 10; + this->nloops = this->reset_threshold * 10; + gettimeofday(&this->begin, 0); + } + bool Loop() + { + if(this->iter >= this->nloops) return false; + + this->iter += 1; + if(!(this->iter % this->reset_threshold)) + { + TakeResult(); + } + return true; + } + void Report(const char* title, const char* unit, + bool printTimeAsInt = false) + { + if(gPrintHTML) + { + std::cout.precision(2); + std::cout << " <li>" << std::fixed; + } + std::cout << title << ": "; + if(printTimeAsInt) std::cout << int(result); + else std::cout << result; + std::cout << (gPrintHTML ? " µs. (" : " us. (") + << beautify(int(1e6/result)) << " " << unit << "/s)\n"; + } + void TakeResult() + { + struct timeval end; + gettimeofday(&end, 0); + double begin_d = begin.tv_sec * 1e6 + begin.tv_usec; + double end_d = end.tv_sec * 1e6 + end.tv_usec; + double diff_d = (end_d - begin_d) / this->reset_threshold; + if(iter == this->reset_threshold + || diff_d < result) + { + result = diff_d; + } + begin = end; + } +private: + unsigned nloops; + unsigned iter; + unsigned reset_threshold; + struct timeval begin; + double result; +}; + +template<typename Parser_t> +int run() +{ + Parser_t fp, fp2; + typename Parser_t::value_type values[3] = { .25, .5, .75 }; + + for(unsigned i = 0; i < FunctionsAmount; ++i) + { + // Parse function + // -------------- + if(gPrintHTML) + std::cout << "\n<hr>\n<p>Function:\n<code>\"" + << funcData[i].funcStr << "\"</code>" << std::endl; + else + std::cout << "\n--- Function:\n\"" << funcData[i].funcStr + << "\"" << std::endl; + + int res = fp.Parse(funcData[i].funcStr, funcData[i].paramStr); + if(res >= 0) + { + std::cout << "Col " << res << ": " << fp.ErrorMsg() << std::endl; + return 1; + } + + const unsigned ParseLoops = 2000000; + const unsigned EvalLoops = 20000000; + const unsigned OptimizationLoops = 20000; + const unsigned FuncLoops = 50000000; + + Test tester; + + if(gPrintHTML) std::cout << "<ul>\n"; + + // Measure parsing speed + // --------------------- + tester.Start(ParseLoops); + while(tester.Loop()) + fp.Parse(funcData[i].funcStr, funcData[i].paramStr); + tester.Report("Parse time", "parses"); + +#ifndef MEASURE_PARSING_SPEED_ONLY +// fp.PrintByteCode(std::cout); + + // Measure evaluation speed + // ------------------------ + tester.Start(EvalLoops); + while(tester.Loop()) + fp.Eval(values); + tester.Report("Eval time", "evals"); + + // Measure evaluation speed, optimized + // ----------------------------------- + fp2 = fp; + fp2.Optimize(); + +// fp2.PrintByteCode(std::cout); + + tester.Start(EvalLoops); + while(tester.Loop()) + fp2.Eval(values); + tester.Report("Optimized", "evals"); + + +#ifdef TEST_JIT + // Measure evaluation speed, jit-compiled + // -------------------------------------- + const unsigned JitLoops = 50000000; + fp2.CreateJIT(); + + tester.Start(JitLoops); + while(tester.Loop()) + fp2.Eval(values); + tester.Report("JIT-compiled", "evals"); +#endif + + + // Measure optimization speed + // -------------------------- + tester.Start(OptimizationLoops); + while(tester.Loop()) + { + fp2 = fp; + fp2.Optimize(); + } + tester.Report("Optimization time", "optimizes", gPrintHTML); + + + // Measure C++ function speed + // -------------------------- + if(!gPrintHTML) + { + tester.Start(FuncLoops); + while(tester.Loop()) + callFunc(funcData[i], values); + + tester.Report("C++ function time", "evals"); + } +#endif + + if(gPrintHTML) std::cout << "</ul>\n"; + } + + return 0; +} + +int main(int argc, char* argv[]) +{ + enum ParserType { FP_D, FP_F, FP_LD }; + ParserType parserType = FP_D; + + for(int i = 1; i < argc; ++i) + { + if(std::strcmp(argv[1], "-html") == 0) gPrintHTML = true; + else if(std::strcmp(argv[1], "-f") == 0) parserType = FP_F; + else if(std::strcmp(argv[1], "-ld") == 0) parserType = FP_LD; + else if(std::strcmp(argv[i], "--help") == 0 + || std::strcmp(argv[i], "-help") == 0 + || std::strcmp(argv[i], "-h") == 0 + || std::strcmp(argv[i], "/?") == 0) + { + std::cout << + "FunctionParser speedtest " << kVersionNumber << + "\n\nUsage: " << argv[0] << " [<option> ...]\n" + "\n" + " -f Test float datatype\n" + " -ld Test long double datatype\n" + " -html Print output in html format\n" + " -h, --help This help\n" + "\n"; + return 0; + } + } + + switch(parserType) + { + case FP_D: return run<FunctionParser>(); +#ifdef FP_SUPPORT_FLOAT_TYPE + case FP_F: return run<FunctionParser_f>(); +#endif +#ifdef FP_SUPPORT_LONG_DOUBLE_TYPE + case FP_LD: return run<FunctionParser_ld>(); +#endif + } + + return 0; +} diff --git a/util/tree_grammar_parser.cc b/util/tree_grammar_parser.cc new file mode 100644 index 0000000..bb0bf2b --- /dev/null +++ b/util/tree_grammar_parser.cc @@ -0,0 +1,3621 @@ +/* A Bison parser, made by GNU Bison 2.7. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.7" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* Copy the first part of user declarations. */ +/* Line 371 of yacc.c */ +#line 1 "util/tree_grammar_parser.y" + +#define YYDEBUG 1 +#define YYERROR_VERBOSE 1 +#include <string.h> // for error reporting + +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#include "../fpoptimizer/grammar.hh" +#include "../fpoptimizer/consts.hh" + +#include "../fpoptimizer/grammar.cc" +/* ^Note: including .cc file here in order to be able + * to instantiate DumpParam and DumpParams for complex types. + */ + +#include <cstdio> +#include <cctype> +#include <cstdlib> +#include <iostream> +#include <sstream> +#include <complex> +#include <map> +#include <set> +#include <algorithm> +#include <assert.h> + +#include "../lib/crc32.hh" + +#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 + +static const unsigned PARAM_INDEX_BITS = 10; + +/*********/ +using namespace FPoptimizer_Grammar; + +class GrammarDumper; + +static void yyerror(const char* msg); +static int yylex(union YYSTYPE* lval); + +namespace +{ + /* This function generated with make_identifier_parser.cc */ + unsigned readOpcode(const char* input) + { + using namespace FUNCTIONPARSERTYPES; +#include "extrasrc/fp_identifier_parser.inc" + return 0; + } +} + +//namespace +//{ + struct mycomplex + { + double real, imag; + }; + mycomplex operator -(const mycomplex& v) + { mycomplex res = {-v.real, -v.imag }; return res; } + + typedef std::complex<double> stdcomplex; +//} + +namespace GrammarData +{ + class ParamSpec; + + class MatchedParams + { + public: + ParamMatchingType Type; + std::vector<ParamSpec*> Params; + unsigned RestHolderIndex; + + public: + MatchedParams() : Type(PositionalParams), Params(), RestHolderIndex(0) { } + MatchedParams(ParamMatchingType t) : Type(t), Params(), RestHolderIndex(0) { } + MatchedParams(ParamSpec* p) : Type(PositionalParams), Params(), RestHolderIndex(0) { Params.push_back(p); } + + MatchedParams* SetType(ParamMatchingType t) { Type=t; return this; } + MatchedParams* AddParam(ParamSpec* p) { Params.push_back(p); return this; } + + const std::vector<ParamSpec*>& GetParams() const { return Params; } + + void RecursivelySetDefaultParamMatchingType(); + bool EnsureNoRepeatedNamedHolders(std::set<unsigned>& used) const; + bool EnsureNoRepeatedNamedHolders() const; + bool EnsureNoVariableCoverageParams_InPositionalParamLists(); + + unsigned CalcRequiredParamsCount() const; + + unsigned BuildDepMask(); + void BuildFinalDepMask(); + }; + + class FunctionType + { + public: + FUNCTIONPARSERTYPES::OPCODE Opcode; + MatchedParams Params; + public: + FunctionType(FUNCTIONPARSERTYPES::OPCODE o, const MatchedParams& p) + : Opcode(o), Params(p) { } + + void RecursivelySetDefaultParamMatchingType() + { + using namespace FUNCTIONPARSERTYPES; + Params.RecursivelySetDefaultParamMatchingType(); + if((Opcode == cAdd || Opcode == cMul + || Opcode == cAnd || Opcode == cOr + || Opcode == cAbsAnd || Opcode == cAbsOr) + && Params.Type == PositionalParams) + Params.Type = SelectedParams; + } + + bool EnsureNoRepeatedNamedHolders() const + { return Params.EnsureNoRepeatedNamedHolders(); } + }; + + class ParamSpec + { + public: + unsigned DepMask; + + SpecialOpcode Opcode; // specifies the type of the function + union + { + mycomplex ConstantValue;// for NumConstant + unsigned Index; // for ParamHolder + FunctionType* Func; // for SubFunction + }; + unsigned ImmedConstraint; + bool IsConst; // when SubFunction + + public: + struct ParamHolderTag{}; + + ParamSpec(FunctionType* f) + : DepMask(), + Opcode(SubFunction), + Func(f), + ImmedConstraint(0), + IsConst(false) + { + } + + ParamSpec(mycomplex d, unsigned constraints) + : DepMask(), + Opcode(NumConstant), + ConstantValue(d), + ImmedConstraint(constraints), + IsConst(true) + { + } + + ParamSpec(FUNCTIONPARSERTYPES::OPCODE o, const std::vector<ParamSpec*>& p) + : DepMask(), + Opcode(SubFunction), + Func(new FunctionType(o, MatchedParams(PositionalParams))), + ImmedConstraint(0), + IsConst(true) + { + if(o == FUNCTIONPARSERTYPES::cNeg && p[0]->Opcode == NumConstant) + { + delete Func; + Opcode = NumConstant; + ConstantValue = -p[0]->ConstantValue; + ImmedConstraint = p[0]->ImmedConstraint; + } + else + { + Func->Params.Params = p; + /* + if(o == cAdd && p[1]->Opcode == SubFunction + && p[1]->Func->Opcode == cNeg + && p.size() == 2) + { + Func->Opcode = cSub; + Func->Params.Params[1] = p[1]->Func->Params.Params[0]; + } -- not done because ConstantFolding() cannot handle cSub + */ + } + } + + ParamSpec(unsigned i, ParamHolderTag) + : DepMask(), + Opcode(ParamHolder), Index(i), + ImmedConstraint(0), + IsConst(true) + { + } + +/* + // Order: + // NumConstant { ConstantValue } + // ParamHolder { Index } + // SubFunction { Opcode, IsConst } + bool operator< (const ParamSpec& b) const + { + if(Opcode == NumConstant) + return (b.Opcode == NumConstant) + ? ConstantValue < b.ConstantValue + : true; + if(Opcode == ParamHolder) + return (b.Opcode == ParamHolder) + ? Index < b.Index + : (b.Opcode == SubFunction) + ? true + : false; + if(Opcode == SubFunction) + return (b.Opcode == SubFunction) + ? (Func->Opcode != b.Func->Opcode + ? Func->Opcode < b.Func->Opcode + : IsConst < b.IsConst + ) + : false; + return false; + } + bool operator!= (const ParamSpec& b) const { return !operator==(b); } + bool operator== (const ParamSpec& b) const + { + switch(Opcode) + { + case NumConstant: + return b.Opcode == Opcode && fp_equal(ConstantValue, b.ConstantValue); + case ParamHolder: + return b.Opcode == Opcode && ImmedConstraint == b.ImmedConstraint + && b.DepMask == DepMask && Index == b.Index; + case SubFunction: + if(b.Opcode != SubFunction) return false; + if(Func->Opcode != b.Func->Opcode) return false; + if(ImmedConstraint != b.ImmedConstraint) return false; + if(DepMask != b.DepMask) return false; + if(IsConst != b.IsConst) return false; + if(Func->Params.Type != b.Func->Params.Type + || Func->Params.RestHolderIndex != b.Func->Params.RestHolderIndex + || Func->Params.Params.size() != b.Func->Params.Params.size()) + return false; + for(size_t a=0; a<Func->Params.Params.size(); ++a) + if(*Func->Params.Params[a] != *b.Func->Params.Params[a]) + return false; + } + return true; + } +*/ + ParamSpec* SetConstraint(unsigned mask) + { ImmedConstraint |= mask; return this; } + + unsigned BuildDepMask(); + + void RecursivelySetDefaultParamMatchingType() + { + if(Opcode == SubFunction) + Func->RecursivelySetDefaultParamMatchingType(); + } + bool VerifyIsConstant() + { + switch(Opcode) + { + case NumConstant: return true; + case ParamHolder: return + (ImmedConstraint & ConstnessMask) == Constness_Const; + case SubFunction: + if(!IsConst) return false; // subfunctions are not constant + } + // For const-subfunctions, all params must be const. + for(size_t a=0; a<Func->Params.Params.size(); ++a) + if(!Func->Params.Params[a]->VerifyIsConstant()) return false; + return true; + } + + bool EnsureNoRepeatedNamedHolders() const + { + if(Opcode != SubFunction) return true; + MatchedParams tmp; + tmp.Params = Func->Params.Params; + return tmp.EnsureNoRepeatedNamedHolders(); + } + + private: + ParamSpec(const ParamSpec&); + ParamSpec& operator= (const ParamSpec&); + }; + + class Rule + { + public: + friend class GrammarDumper; + RuleType Type; + + FunctionType Input; + MatchedParams Replacement; // length should be 1 if ProduceNewTree is used + unsigned SituationFlags; + public: + Rule(RuleType t, const FunctionType& f, const MatchedParams& r) + : Type(t), Input(f), Replacement(r), SituationFlags(0) + { } + + Rule(RuleType t, const FunctionType& f, ParamSpec* p) + : Type(t), Input(f), Replacement(), SituationFlags(0) + { Replacement.AddParam(p); } + + void BuildFinalDepMask() + { + Input.Params.BuildFinalDepMask(); + //Replacement.BuildFinalDepMask(); -- not needed, though not wrong either. + } + void SetSituationFlags(unsigned flags) + { + SituationFlags = flags; + } + }; + + class Grammar + { + public: + std::vector<Rule> rules; + public: + Grammar(): rules() { } + + void AddRule(const Rule& r) { rules.push_back(r); } + void BuildFinalDepMask() + { + for(size_t a=0; a<rules.size(); ++a) + rules[a].BuildFinalDepMask(); + } + }; + + //////////////////// + + void MatchedParams::RecursivelySetDefaultParamMatchingType() + { + Type = PositionalParams; + if(RestHolderIndex != 0) + Type = AnyParams; + + for(size_t a=0; a<Params.size(); ++a) + Params[a]->RecursivelySetDefaultParamMatchingType(); + } + + bool MatchedParams::EnsureNoRepeatedNamedHolders(std::set<unsigned>& used) const + { + for(size_t a=0; a<Params.size(); ++a) + { + if(Params[a]->Opcode == ParamHolder) + { + unsigned index = Params[a]->Index; + std::set<unsigned>::iterator i = used.lower_bound(index); + if(i != used.end() && *i == index) + return false; + used.insert(i, index); + } + if(Params[a]->Opcode == SubFunction) + if(!Params[a]->Func->Params.EnsureNoRepeatedNamedHolders(used)) + return false; + } + return true; + } + + bool MatchedParams::EnsureNoRepeatedNamedHolders() const + { + std::set<unsigned> used; + return EnsureNoRepeatedNamedHolders(used); + } + + bool MatchedParams::EnsureNoVariableCoverageParams_InPositionalParamLists() + { + if(Type != PositionalParams + && Type != SelectedParams) return true; + + if(RestHolderIndex != 0) return false; + + for(size_t a=0; a<Params.size(); ++a) + { + if(Params[a]->Opcode == SubFunction) + if(!Params[a]->Func->Params.EnsureNoVariableCoverageParams_InPositionalParamLists()) + return false; + } + return true; + } + unsigned MatchedParams::CalcRequiredParamsCount() const + { + return (unsigned)Params.size(); + } + + unsigned MatchedParams::BuildDepMask() + { + unsigned result = 0; + for(size_t a=0; a<Params.size(); ++a) + result |= Params[a]->BuildDepMask(); + return result; + } + + void MatchedParams::BuildFinalDepMask() + { + unsigned all_bits = BuildDepMask(); + + // For each bit that is set in all_bits, unset + // all of them that are only set in one of the parameters. + for(unsigned bit=1; all_bits >= bit; bit <<= 1) + if(all_bits & bit) + { + unsigned count_found = 0; + for(size_t a=0; a<Params.size(); ++a) + { + unsigned param_bitmask = Params[a]->DepMask; + if(param_bitmask & bit) ++count_found; + } + if(count_found <= 1) + { + for(size_t a=0; a<Params.size(); ++a) + Params[a]->DepMask &= ~bit; + } + } + + // Recurse + for(size_t a=0; a<Params.size(); ++a) + if(Params[a]->Opcode == SubFunction) + Params[a]->Func->Params.BuildFinalDepMask(); + } +} + +namespace FPoptimizer_Grammar +{ + template<typename Value_t> // Used only by tree_grammar_parser.y + bool ParamSpec_Compare(const void* aa, const void* bb, SpecialOpcode type) + { + switch(type) + { + case ParamHolder: + { + ParamSpec_ParamHolder& a = *(ParamSpec_ParamHolder*) aa; + ParamSpec_ParamHolder& b = *(ParamSpec_ParamHolder*) bb; + return a.constraints == b.constraints + && a.index == b.index + && a.depcode == b.depcode; + } + case NumConstant: + { + ParamSpec_NumConstant<Value_t>& a = *(ParamSpec_NumConstant<Value_t>*) aa; + ParamSpec_NumConstant<Value_t>& b = *(ParamSpec_NumConstant<Value_t>*) bb; + return a.constvalue == b.constvalue + && a.modulo == b.modulo; + } + case SubFunction: + { + ParamSpec_SubFunction& a = *(ParamSpec_SubFunction*) aa; + ParamSpec_SubFunction& b = *(ParamSpec_SubFunction*) bb; + return a.constraints == b.constraints + && a.data.subfunc_opcode == b.data.subfunc_opcode + && a.data.match_type == b.data.match_type + && a.data.param_count == b.data.param_count + && a.data.param_list == b.data.param_list + && a.data.restholder_index == b.data.restholder_index + && a.depcode == b.depcode; + } + } + return true; + } +} + +GrammarData::Grammar grammar; +std::vector<ParamSpec> plist; +std::vector<Rule> rlist; + +struct RuleComparer +{ + bool operator() (const Rule& a, const Rule& b) const + { + if(a.match_tree.subfunc_opcode != b.match_tree.subfunc_opcode) + return a.match_tree.subfunc_opcode < b.match_tree.subfunc_opcode; + + // Other rules to break ties + if(a.situation_flags != b.situation_flags) + return a.situation_flags < b.situation_flags; + + if(a.ruletype != b.ruletype) + return a.ruletype < b.ruletype; + + if(a.match_tree.match_type != b.match_tree.match_type) + return a.match_tree.match_type < b.match_tree.match_type; + + if(a.match_tree.param_count != b.match_tree.param_count) + return a.match_tree.param_count < b.match_tree.param_count; + + if(a.repl_param_count != b.repl_param_count) + return a.repl_param_count < b.repl_param_count; + + if(a.match_tree.param_list != b.match_tree.param_list) + return a.match_tree.param_list < b.match_tree.param_list; + + if(a.repl_param_list != b.repl_param_list) + return a.repl_param_list < b.repl_param_list; + + return false; + } + + bool operator() (unsigned a, unsigned b) const + { + return this->operator() ( rlist[a], rlist[b] ); + } +}; + +class GrammarDumper +{ +private: + std::string GenName(const char* prefix) + { + static unsigned counter = 0; + std::ostringstream tmp; + tmp << prefix << ++counter; + return tmp.str(); + } +private: + std::map<std::string, size_t> n_index; + + std::vector<std::string> nlist; + std::map<std::string, Grammar> glist; +public: + GrammarDumper(): + n_index(), + nlist(),glist() + { + plist.reserve(16384); + nlist.reserve(16); + rlist.reserve(16384); + } + + unsigned ConvertNamedHolderNameIntoIndex(const std::string& n) + { + std::map<std::string, size_t>::const_iterator i = n_index.find(n); + if(i != n_index.end()) return i->second; + nlist.push_back(n); + return n_index[n] = (unsigned)(nlist.size()-1); + } + size_t GetNumNamedHolderNames() const { return nlist.size(); } + + void DumpParamList(const std::vector<GrammarData::ParamSpec*>& Params, + unsigned& param_count, + unsigned& param_list) + { + param_count = (unsigned)Params.size(); + param_list = 0; + for(unsigned a=0; a<param_count; ++a) + { + ParamSpec p = CreateParam(*Params[a]); + + unsigned paramno = (unsigned)plist.size(); + + for(size_t b = 0; b < plist.size(); ++b) + if(plist[b].first == p.first + && ParamSpec_Compare<stdcomplex>(plist[b].second, p.second, p.first)) + { + paramno = (unsigned)b; + break; + } + + if(paramno == plist.size()) plist.push_back(p); + + param_list |= paramno << (a * PARAM_INDEX_BITS); + } + } + + ParamSpec CreateParam(const GrammarData::ParamSpec& p) + { + unsigned pcount; + unsigned plist; + switch(p.Opcode) + { + case SubFunction: + { + ParamSpec_SubFunction* result = new ParamSpec_SubFunction; + result->constraints = p.ImmedConstraint; + result->data.subfunc_opcode = p.Func->Opcode; + result->data.match_type = p.Func->Params.Type; + DumpParamList(p.Func->Params.Params, pcount, plist); + result->data.param_count = pcount; + result->data.param_list = plist; + result->depcode = p.DepMask; + result->data.restholder_index = p.Func->Params.RestHolderIndex; + if(p.IsConst) + { + result->data.match_type = GroupFunction; + result->constraints |= Constness_Const; + } + return std::make_pair(SubFunction, (void*)result); + } + case NumConstant: + { + typedef stdcomplex v; + ParamSpec_NumConstant<v>* result = new ParamSpec_NumConstant<v>; + result->constvalue = v(p.ConstantValue.real, p.ConstantValue.imag); + result->modulo = p.ImmedConstraint; + return std::make_pair(NumConstant, (void*)result); + } + case ParamHolder: + { + ParamSpec_ParamHolder* result = new ParamSpec_ParamHolder; + result->constraints = p.ImmedConstraint; + result->index = p.Index; + result->depcode = p.DepMask; + return std::make_pair(ParamHolder, (void*)result); + } + } + std::cout << "???\n"; + return std::make_pair(SubFunction, (void*) 0); + } + + Rule CreateRule(const GrammarData::Rule& r) + { + //unsigned min_params = r.Input.Params.CalcRequiredParamsCount(); + + Rule ritem; + memset(&ritem, 0, sizeof(ritem)); + //ritem.n_minimum_params = min_params; + ritem.ruletype = r.Type; + ritem.situation_flags = r.SituationFlags; + ritem.match_tree.subfunc_opcode = r.Input.Opcode; + ritem.match_tree.match_type = r.Input.Params.Type; + ritem.match_tree.restholder_index = r.Input.Params.RestHolderIndex; + unsigned pcount; + unsigned plist; + DumpParamList(r.Input.Params.Params, pcount, plist); + ritem.match_tree.param_count = pcount; + ritem.match_tree.param_list = plist; + + DumpParamList(r.Replacement.Params, pcount, plist); + ritem.repl_param_count = pcount; + ritem.repl_param_list = plist; + return ritem; + } + + void RegisterGrammar(const std::vector<GrammarData::Grammar>& gset) + { + using namespace FUNCTIONPARSERTYPES; + std::vector<Rule> this_rules; + + for(size_t a=0; a<gset.size(); ++a) + { + const GrammarData::Grammar& g = gset[a]; + + for(size_t a=0; a<g.rules.size(); ++a) + { + if(g.rules[a].Input.Opcode == cNop) continue; + this_rules.push_back( CreateRule(g.rules[a]) ); + } + } + + std::sort(this_rules.begin(), this_rules.end(), + RuleComparer()); + + for(size_t a=0; a<this_rules.size(); ++a) + { + const Rule& r = this_rules[a]; + + // Add to global rule list, unless it's already there + bool dup=false; + for(size_t c=0; c<rlist.size(); ++c) + if(memcmp(&r, &rlist[c], sizeof(r)) == 0) + { + // Already in global rule list... + dup = true; + break; + } + if(!dup) + rlist.push_back(r); + } + } + + void DumpGrammar(const std::string& grammarname, + const std::vector<GrammarData::Grammar>& gset) + { + using namespace FUNCTIONPARSERTYPES; + std::vector<unsigned> rule_list; + + std::vector<Rule> this_rules; + + for(size_t a=0; a<gset.size(); ++a) + { + const GrammarData::Grammar& g = gset[a]; + + for(size_t a=0; a<g.rules.size(); ++a) + { + if(g.rules[a].Input.Opcode == cNop) continue; + this_rules.push_back( CreateRule(g.rules[a]) ); + } + } + + std::sort(this_rules.begin(), this_rules.end(), + RuleComparer()); + + for(size_t a=0; a<this_rules.size(); ++a) + { + const Rule& r = this_rules[a]; + + // Add to global rule list, unless it's already there + bool dup=false; + for(size_t c=0; c<rlist.size(); ++c) + if(memcmp(&r, &rlist[c], sizeof(r)) == 0) + { + // Already in global rule list... + // Add to grammar's rule list unless it's already there + dup = false; + for(size_t b=0; b<rule_list.size(); ++b) + if(c == rule_list[b]) + { + dup = true; + break; + } + if(!dup) + { + // Global duplicate, but not yet in grammar. + rule_list.push_back(c); + } + dup = true; + break; + } + if(!dup) + { + // Not in global rule list. Add there and in grammar. + rule_list.push_back( (unsigned) rlist.size() ); + rlist.push_back(r); + } + } + + Grammar& gitem = glist[grammarname]; + + gitem.rule_count = (unsigned) rule_list.size(); + + std::sort(rule_list.begin(), rule_list.end(), + RuleComparer()); + + for(size_t a=0; a<rule_list.size(); ++a) + gitem.rule_list[a] = rule_list[a]; + } + + static std::string ConstraintsToString(unsigned constraints) + { + std::ostringstream result; + const char* sep = ""; + static const char s[] = " | "; + switch( ImmedConstraint_Value( constraints & ValueMask ) ) + { + case ValueMask: case Value_AnyNum: break; + case Value_EvenInt: result << sep << "Value_EvenInt"; sep=s; break; + case Value_OddInt: result << sep << "Value_OddInt"; sep=s; break; + case Value_IsInteger: result << sep << "Value_IsInteger"; sep=s; break; + case Value_NonInteger: result << sep << "Value_NonInteger"; sep=s; break; + case Value_Logical: result << sep << "Value_Logical"; sep=s; break; + } + switch( ImmedConstraint_Sign( constraints & SignMask ) ) + { + /*case SignMask:*/ case Sign_AnySign: break; + case Sign_Positive: result << sep << "Sign_Positive"; sep=s; break; + case Sign_Negative: result << sep << "Sign_Negative"; sep=s; break; + case Sign_NoIdea: result << sep << "Sign_NoIdea"; sep=s; break; + } + switch( ImmedConstraint_Oneness( constraints & OnenessMask ) ) + { + case OnenessMask: case Oneness_Any: break; + case Oneness_One: result << sep << "Oneness_One"; sep=s; break; + case Oneness_NotOne: result << sep << "Oneness_NotOne"; sep=s; break; + } + switch( ImmedConstraint_Constness( constraints & ConstnessMask ) ) + { + case ConstnessMask: case Oneness_Any: break; + case Constness_Const: result << sep << "Constness_Const"; sep=s; break; + case Constness_NotConst: result << sep << "Constness_NotConst"; sep=s; break; + } + if(!*sep) result << "0"; + return result.str(); + } + static std::string ModuloToString(unsigned constraints) + { + std::ostringstream result; + const char* sep = ""; + static const char s[] = " | "; + switch( Modulo_Mode(constraints) ) + { + case Modulo_None: break; + case Modulo_Radians: result << sep << "Modulo_Radians"; sep=s; break; + } + if(!*sep) result << "0"; + return result.str(); + } + + static std::string ConstValueToString(const stdcomplex& value) + { + using namespace FUNCTIONPARSERTYPES; + std::ostringstream result; + result.precision(50); + double dvalue = value.real(); + if(value.imag() != 0.0) goto NotAnyKnownConstant; + #define Value_t double + #define if_const(n) \ + if((dvalue)==(n)) result << #n; \ + else if((dvalue)==(-n)) result << "-" #n; + if_const(fp_const_e<Value_t>()) + else if_const(fp_const_einv<Value_t>()) + else if_const(fp_const_twoe<Value_t>()) + else if_const(fp_const_twoeinv<Value_t>()) + else if_const(fp_const_pi<Value_t>()) + else if_const(fp_const_pihalf<Value_t>()) + else if_const(fp_const_twopi<Value_t>()) + else if_const(fp_const_log2<Value_t>()) + else if_const(fp_const_log2inv<Value_t>()) + else if_const(fp_const_log10<Value_t>()) + else if_const(fp_const_log10inv<Value_t>()) + else if_const(fp_const_rad_to_deg<Value_t>()) + else if_const(fp_const_deg_to_rad<Value_t>()) + #undef if_const + #undef Value_t + else + { + NotAnyKnownConstant: + result << "Value_t(" << value.real() << ")"; + if(value.imag() != 0.0) + result << " + fp_make_imag(Value_t(" << value.imag() << "))"; + } + return result.str(); + } + + struct ParamCollection + { + std::vector<ParamSpec_ParamHolder> plist_p; + std::vector<ParamSpec_NumConstant<stdcomplex> > plist_n; + std::vector<ParamSpec_SubFunction> plist_s; + + void Populate(const ParamSpec& param) + { + #define set(when, type, list, code) \ + case when: \ + { for(size_t a=0; a<list.size(); ++a) \ + if(ParamSpec_Compare<stdcomplex>(param.second, (const void*) &list[a], when)) \ + return; \ + list.push_back( *(type*) param.second ); \ + code; \ + break; } + switch(param.first) + { + set(ParamHolder, ParamSpec_ParamHolder, plist_p, {} ); + set(NumConstant, ParamSpec_NumConstant<stdcomplex>, plist_n, {} ); + set(SubFunction, ParamSpec_SubFunction, plist_s, + ParamSpec_SubFunction* p = (ParamSpec_SubFunction*)param.second; + for(size_t a=0; a<p->data.param_count; ++a) + Populate( ParamSpec_Extract<stdcomplex>( p->data.param_list, a) ); + ); + } + #undef set + } + + struct p_compare { int kind( + const ParamSpec_ParamHolder& a, + const ParamSpec_ParamHolder& b) const + { + if((a.index^2) != (b.index^2)) return (a.index^2) < (b.index^2) ? -1 : 1; + // xor-2 is here to tweak the sorting order such that + // the most used parameters (x,y) are first in the list, + // resulting in smaller numbers for the parameter indexes, + // and thus a smaller source code size for grammar data. + return 0; + } }; + struct n_compare { int kind( + const ParamSpec_NumConstant<stdcomplex>& a, + const ParamSpec_NumConstant<stdcomplex>& b) const + { + if(a.modulo != b.modulo) return a.modulo < b.modulo ? -1 : 1; + double av = std::norm(a.constvalue), bv = std::norm(b.constvalue); + if(a.constvalue.real() < 0) av = -av; + if(b.constvalue.real() < 0) bv = -bv; + if(av != bv) return av < bv ? -1 : 1; + return 0; + } }; + struct s_compare { int kind( + const ParamSpec_SubFunction& a, + const ParamSpec_SubFunction& b) const + { + unsigned a_opcode = a.data.subfunc_opcode; + unsigned b_opcode = b.data.subfunc_opcode; + + if(a_opcode == FUNCTIONPARSERTYPES::cAdd) a_opcode = 2; + else if(a_opcode == FUNCTIONPARSERTYPES::cMul) a_opcode = 3; + else if(a_opcode == FUNCTIONPARSERTYPES::cPow) a_opcode = 4; + else if(a_opcode == FUNCTIONPARSERTYPES::cNeg) a_opcode = 0; + else if(a_opcode == FUNCTIONPARSERTYPES::cInv) a_opcode = 1; + else a_opcode += 5; + if(b_opcode == FUNCTIONPARSERTYPES::cAdd) b_opcode = 2; + else if(b_opcode == FUNCTIONPARSERTYPES::cMul) b_opcode = 3; + else if(b_opcode == FUNCTIONPARSERTYPES::cPow) b_opcode = 4; + else if(b_opcode == FUNCTIONPARSERTYPES::cNeg) b_opcode = 0; + else if(b_opcode == FUNCTIONPARSERTYPES::cInv) b_opcode = 1; + else b_opcode += 5; + + if(a_opcode != b_opcode) + return a_opcode < b_opcode ? -1 : 1; + if(a.constraints != b.constraints) + return a.constraints < b.constraints ? -1 : 1; + if(a.data.match_type != b.data.match_type) + return a.data.match_type < b.data.match_type ? -1 : 1; + + size_t min_param_count = std::min(a.data.param_count, b.data.param_count); + + for(size_t c=0; c< min_param_count; ++c) + { + ParamSpec aa = ParamSpec_Extract<stdcomplex>(a.data.param_list, (unsigned)c); + ParamSpec bb = ParamSpec_Extract<stdcomplex>(b.data.param_list, (unsigned)c); + if(aa.first != bb.first) + return aa.first < bb.first; + switch(aa.first) + { + case ParamHolder: { + int k = p_compare().kind + (*(const ParamSpec_ParamHolder*)aa.second, + *(const ParamSpec_ParamHolder*)bb.second); + if(k) return k; + break; + }case NumConstant: { + int k = n_compare().kind + (*(const ParamSpec_NumConstant<stdcomplex>*)aa.second, + *(const ParamSpec_NumConstant<stdcomplex>*)bb.second); + if(k) return k; + break; + }case SubFunction:{ + int k = s_compare().kind + (*(const ParamSpec_SubFunction*)aa.second, + *(const ParamSpec_SubFunction*)bb.second); + if(k) return k; + break; + } } + } + if(a.data.param_count != b.data.param_count) + return a.data.param_count < b.data.param_count ? -1 : 1; + return 0; + } }; + template<typename T> + struct kind_compare + { + template<typename K> + bool operator() (const K& a, const K& b) const + { + return T().kind(a,b) < 0; + } + }; + + void Sort() + { + std::stable_sort(plist_p.begin(), plist_p.end(), kind_compare<p_compare>()); + std::stable_sort(plist_n.begin(), plist_n.end(), kind_compare<n_compare>()); + std::stable_sort(plist_s.begin(), plist_s.end(), kind_compare<s_compare>()); + } + + unsigned ParamPtrToParamIndex(unsigned paramlist, unsigned index) const + { + const ParamSpec& p = ParamSpec_Extract<stdcomplex> (paramlist, index); + if(p.second) + { + #define set(when, list, c) \ + case when: \ + for(size_t a=0; a<list.size(); ++a) \ + if(ParamSpec_Compare<stdcomplex> (p.second, (const void*)&list[a], when)) \ + return (a + c##offset); \ + break; + unsigned Poffset = 0; + unsigned Noffset = plist_p.size(); + unsigned Soffset = plist_n.size() + Noffset; + switch(p.first) + { + set(ParamHolder, plist_p, P); + set(NumConstant, plist_n, N); + set(SubFunction, plist_s, S); + } + #undef set + } + return (1 << 10)-1; + } + + std::string ParamListToString(unsigned paramlist, unsigned paramcount) const + { + std::ostringstream result, comment; + unsigned value = 0; + for(unsigned p=0; p<paramcount; ++p) + { + unsigned index = ParamPtrToParamIndex(paramlist, p); + if(p) comment << ','; + comment << index; + value += index << (p*PARAM_INDEX_BITS); + } + std::string commentstr = comment.str(); + commentstr.resize(3*3+2, ' '); + result << "/*" << commentstr << "*/" << value; + + std::string res = result.str(); + if(res.size() < 25) res.resize(25, ' '); + /* 999*x+999*x+999 = 15 characters */ + /* (*999,999,999*)1048551399 = 25 characters */ + return res; + } + std::string ParamHolderToString(const ParamSpec_ParamHolder& i) const + { + std::ostringstream result; + result << "{" << i.index + << ", " << ConstraintsToString(i.constraints) + << ", 0x" << i.depcode + << "}"; + return result.str(); + } + + std::string NumConstantToString(const ParamSpec_NumConstant<stdcomplex>& i) const + { + std::ostringstream result; + result << "{" << ConstValueToString(i.constvalue) + << ", " << ModuloToString(i.modulo) + << "}"; + return result.str(); + } + + std::string SubFunctionDataToString(const ParamSpec_SubFunctionData& i) const + { + std::ostringstream result; + result << "{" << i.param_count + << "," << ParamListToString(i.param_list, i.param_count) + << ", " << FP_GetOpcodeName(i.subfunc_opcode, true) + << "," << (i.match_type == PositionalParams ? "PositionalParams" + : i.match_type == SelectedParams ? "SelectedParams " + : i.match_type == AnyParams ? "AnyParams " + :/*i.match_type == GroupFunction ?*/ "GroupFunction " + ) + << "," << i.restholder_index + << "}"; + return result.str(); + } + + std::string SubFunctionToString(const ParamSpec_SubFunction& i) const + { + std::ostringstream result; + result << "{" << SubFunctionDataToString(i.data) + << ", " << ConstraintsToString(i.constraints) + << ", 0x" << i.depcode + << "}"; + return result.str(); + } + }; + + ParamCollection collection; + + void Flush() + { + for(size_t a=0; a<rlist.size(); ++a) + { + for(unsigned b=0; b < rlist[a].match_tree.param_count; ++b) + collection.Populate( ParamSpec_Extract<stdcomplex>(rlist[a].match_tree.param_list, b) ); + for(unsigned b=0; b < rlist[a].repl_param_count; ++b) + collection.Populate( ParamSpec_Extract<stdcomplex>(rlist[a].repl_param_list, b) ); + } + collection.Sort(); + + std::cout << "/* BEGIN_EXPLICIT_INSTANTATIONS */\n"; + for(std::map<std::string, Grammar>::const_iterator + i = glist.begin(); i != glist.end(); ++i) + std::cout << "#define grammar_" << i->first << " grammar_" << i->first << "_tweak\n"; + std::cout << + "#include \"../fpoptimizer/grammar.hh\"\n"; + for(std::map<std::string, Grammar>::const_iterator + i = glist.begin(); i != glist.end(); ++i) + std::cout << "#undef grammar_" << i->first << "\n"; + std::cout << "/* END_EXPLICIT_INSTANTATIONS */\n"; + + std::cout << + "\n" + "using namespace FPoptimizer_Grammar;\n" + "using namespace FUNCTIONPARSERTYPES;\n" + "\n" + "namespace\n" + "{\n"; + + { + + #define set(type, listprefix, list, c) \ + std::cout << \ + " const ParamSpec_" #type " " listprefix #list "[" << collection.list.size() << "] =\n" \ + " {\n"; \ + for(size_t a=0; a<collection.list.size(); ++a) \ + { \ + std::cout << " /* " << offset++ << "\t*/ " \ + << collection.type##ToString(collection.list[a]) \ + << ", /* "; \ + FPoptimizer_Grammar::DumpParam<stdcomplex>( ParamSpec(type, (const void*) &collection.list[a]), std::cout); \ + std::cout << " */\n"; \ + } \ + std::cout << \ + " };\n" \ + "\n"; + + unsigned offset = 0; + set(ParamHolder, "", plist_p, P) // Must be first one + std::cout << + " template<typename Value_t>\n" + " struct plist_n_container\n" + " {\n" + " static const ParamSpec_NumConstant<Value_t> plist_n[" << collection.plist_n.size() << "];\n" + " };\n" + " template<typename Value_t>\n"; + set(NumConstant, "<Value_t> plist_n_container<Value_t>::", plist_n, N) + set(SubFunction, "", plist_s, S) + + std::cout << + "}\n"; + } + + #undef set + + std::cout << + "namespace FPoptimizer_Grammar\n" + "{\n"; + std::cout << + " const Rule grammar_rules[" << rlist.size() << "] =\n" + " {\n"; + for(size_t a=0; a<rlist.size(); ++a) + { + std::cout << + " /* " << a << ":\t"; + ParamSpec_SubFunction tmp = {rlist[a].match_tree,0,0}; + if(rlist[a].situation_flags & OnlyForComplex) + std::cout << "@C "; + if(rlist[a].situation_flags & NotForComplex) + std::cout << "@R "; + if(rlist[a].situation_flags & LogicalContextOnly) + std::cout << "@L "; + if(rlist[a].situation_flags & NotForIntegers) + std::cout << "@F "; + if(rlist[a].situation_flags & OnlyForIntegers) + std::cout << "@I "; + FPoptimizer_Grammar::DumpParam<stdcomplex> + ( ParamSpec(SubFunction, (const void*) &tmp) ); + switch(rlist[a].ruletype) + { + case ProduceNewTree: + std::cout << + "\n" + " *\t->\t"; + FPoptimizer_Grammar::DumpParam<stdcomplex>( + ParamSpec_Extract<stdcomplex>(rlist[a].repl_param_list, 0) ); + break; + case ReplaceParams: default: + std::cout << + "\n" + " *\t:\t"; + FPoptimizer_Grammar::DumpParams<stdcomplex> + ( rlist[a].repl_param_list, rlist[a].repl_param_count); + break; + } + std::cout << + "\n" + " */\t\t " + "{" + << (rlist[a].ruletype == ProduceNewTree ? "ProduceNewTree" + :/*rlist[a].ruletype == ReplaceParams ?*/ "ReplaceParams " + ) + << ", " << rlist[a].situation_flags + << ", " << rlist[a].repl_param_count + << "," << collection.ParamListToString(rlist[a].repl_param_list, rlist[a].repl_param_count) + << ", " << collection.SubFunctionDataToString(rlist[a].match_tree) + << "},\n"; + } + std::cout << + " };\n" + << + "\n"; + for(std::map<std::string, Grammar>::const_iterator + i = glist.begin(); i != glist.end(); ++i) + { + std::cout << " struct grammar_" << i->first << "_type\n" + " {\n" + " unsigned c;\n" + " unsigned short l[" << i->second.rule_count << "];\n" + " };\n" + " extern \"C\"\n" + " {\n" + " grammar_" << i->first << "_type grammar_" << i->first << " =\n" + " {\n" + " " << i->second.rule_count << ",\n" + " { "; + for(size_t p=0; p<i->second.rule_count; ++p) + { + std::cout << (unsigned) i->second.rule_list[p]; + if(p+1 == i->second.rule_count) std::cout << "\n"; + else + { + std::cout << ','; + if(p%10 == 9) + std::cout << "\n "; + } + } + std::cout << " } }; }\n"; + } + std::cout << + "}\n"; + } +private: +}; + +static GrammarDumper dumper; + + +/* Line 371 of yacc.c */ +#line 1281 "util/tree_grammar_parser.cc" + +# ifndef YY_NULL +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULL nullptr +# else +# define YY_NULL 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + NUMERIC_CONSTANT = 258, + NAMEDHOLDER_TOKEN = 259, + RESTHOLDER_TOKEN = 260, + IMMEDHOLDER_TOKEN = 261, + BUILTIN_FUNC_NAME = 262, + OPCODE_TOKEN = 263, + UNARY_TRANSFORMATION = 264, + PARAM_CONSTRAINT = 265, + CONST_CONSTRAINT = 266, + NEWLINE = 267, + SUBST_OP_COLON = 268, + SUBST_OP_ARROW = 269 + }; +#endif + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ +/* Line 387 of yacc.c */ +#line 1216 "util/tree_grammar_parser.y" + + /* Note: Because bison's token type is an union or a simple type, + * anything that has constructors and destructors must be + * carried behind pointers here. + */ + GrammarData::Rule* r; + GrammarData::FunctionType* f; + GrammarData::MatchedParams* p; + GrammarData::ParamSpec* a; + + mycomplex num; + unsigned index; + FUNCTIONPARSERTYPES::OPCODE opcode; + + +/* Line 387 of yacc.c */ +#line 1351 "util/tree_grammar_parser.cc" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* Copy the second part of user declarations. */ + +/* Line 390 of yacc.c */ +#line 1378 "util/tree_grammar_parser.cc" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(N) (N) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 86 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 21 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 10 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 28 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 47 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 269 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 19, 20, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 15, 2, 16, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 17, 2, 18, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 6, 10, 13, 14, 17, 20, 21, + 26, 31, 36, 38, 43, 48, 51, 54, 57, 58, + 61, 64, 69, 72, 77, 80, 83, 84, 87 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 22, 0, -1, 22, 24, -1, 22, 23, 24, -1, + 22, 12, -1, -1, 23, 10, -1, 23, 11, -1, + -1, 25, 14, 28, 12, -1, 25, 14, 26, 12, + -1, 25, 13, 27, 12, -1, 26, -1, 8, 15, + 27, 16, -1, 8, 17, 27, 18, -1, 8, 27, + -1, 27, 28, -1, 27, 5, -1, -1, 3, 30, + -1, 6, 29, -1, 7, 19, 27, 20, -1, 4, + 29, -1, 19, 26, 20, 29, -1, 9, 28, -1, + 29, 10, -1, -1, 30, 11, -1, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 1254, 1254, 1259, 1265, 1266, 1270, 1289, 1300, 1306, + 1315, 1333, 1355, 1367, 1375, 1383, 1393, 1397, 1408, 1414, + 1418, 1423, 1434, 1439, 1444, 1459, 1464, 1470, 1475 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "NUMERIC_CONSTANT", "NAMEDHOLDER_TOKEN", + "RESTHOLDER_TOKEN", "IMMEDHOLDER_TOKEN", "BUILTIN_FUNC_NAME", + "OPCODE_TOKEN", "UNARY_TRANSFORMATION", "PARAM_CONSTRAINT", + "CONST_CONSTRAINT", "NEWLINE", "SUBST_OP_COLON", "SUBST_OP_ARROW", "'['", + "']'", "'{'", "'}'", "'('", "')'", "$accept", "grammar", + "rule_constraints", "substitution", "function_match", "function", + "paramlist", "param", "param_constraints", "const_constraints", YY_NULL +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 91, 93, 123, 125, 40, + 41 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 21, 22, 22, 22, 22, 23, 23, 23, 24, + 24, 24, 25, 26, 26, 26, 27, 27, 27, 28, + 28, 28, 28, 28, 28, 29, 29, 30, 30 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 3, 2, 0, 2, 2, 0, 4, + 4, 4, 1, 4, 4, 2, 2, 2, 0, 2, + 2, 4, 2, 4, 2, 2, 0, 2, 0 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 5, 8, 1, 18, 4, 0, 2, 0, 12, 18, + 18, 15, 6, 7, 3, 18, 0, 0, 0, 28, + 26, 17, 26, 0, 0, 0, 16, 0, 0, 0, + 13, 14, 19, 22, 20, 18, 24, 0, 11, 10, + 9, 27, 25, 0, 26, 21, 23 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 1, 5, 6, 7, 8, 11, 26, 33, 32 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -21 +static const yytype_int8 yypact[] = +{ + -21, 74, -21, -12, -21, 23, -21, 63, -21, -21, + -21, 52, -21, -21, -21, -21, 59, 16, 33, -21, + -21, -21, -21, -15, 66, -1, -21, 41, -2, 17, + -21, -21, 19, 31, 31, -21, -21, 29, -21, -21, + -21, -21, -21, 8, -21, -21, 31 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -21, -21, -21, 38, -21, -7, -9, -8, -20, -21 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 17, 18, 34, 9, 35, 10, 27, 3, 29, 28, + 39, 19, 20, 21, 22, 23, 36, 24, 37, 19, + 20, 21, 22, 23, 46, 24, 43, 25, 45, 40, + 41, 3, 30, 12, 13, 25, 19, 20, 21, 22, + 23, 42, 24, 14, 19, 20, 21, 22, 23, 44, + 24, 31, 25, 38, 0, 19, 20, 21, 22, 23, + 25, 24, 19, 20, 0, 22, 23, 3, 24, 19, + 20, 25, 22, 23, 2, 24, 15, 16, 25, 0, + 0, 0, 3, 0, 0, 25, 4 +}; + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-21))) + +#define yytable_value_is_error(Yytable_value) \ + YYID (0) + +static const yytype_int8 yycheck[] = +{ + 9, 10, 22, 15, 19, 17, 15, 8, 16, 16, + 12, 3, 4, 5, 6, 7, 24, 9, 25, 3, + 4, 5, 6, 7, 44, 9, 35, 19, 20, 12, + 11, 8, 16, 10, 11, 19, 3, 4, 5, 6, + 7, 10, 9, 5, 3, 4, 5, 6, 7, 20, + 9, 18, 19, 12, -1, 3, 4, 5, 6, 7, + 19, 9, 3, 4, -1, 6, 7, 8, 9, 3, + 4, 19, 6, 7, 0, 9, 13, 14, 19, -1, + -1, -1, 8, -1, -1, 19, 12 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 22, 0, 8, 12, 23, 24, 25, 26, 15, + 17, 27, 10, 11, 24, 13, 14, 27, 27, 3, + 4, 5, 6, 7, 9, 19, 28, 27, 26, 28, + 16, 18, 30, 29, 29, 19, 28, 26, 12, 12, + 12, 11, 10, 27, 20, 20, 29 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULL; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html> + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +static YYSTYPE yyval_default; +# define YY_INITIAL_VALUE(Value) = Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval YY_INITIAL_VALUE(yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +/* Line 1792 of yacc.c */ +#line 1255 "util/tree_grammar_parser.y" + { + grammar.AddRule(*(yyvsp[(2) - (2)].r)); + delete (yyvsp[(2) - (2)].r); + } + break; + + case 3: +/* Line 1792 of yacc.c */ +#line 1260 "util/tree_grammar_parser.y" + { + (yyvsp[(3) - (3)].r)->SetSituationFlags((yyvsp[(2) - (3)].index)); + grammar.AddRule(*(yyvsp[(3) - (3)].r)); + delete (yyvsp[(3) - (3)].r); + } + break; + + case 6: +/* Line 1792 of yacc.c */ +#line 1271 "util/tree_grammar_parser.y" + { + // Translate constraint flags to Rule Constraints. + // They were lexed as param constraints, which + // is why they have a different value. + if((yyvsp[(2) - (2)].index) == Value_Logical) // @L + (yyval.index) = (yyvsp[(1) - (2)].index) | LogicalContextOnly; + else if((yyvsp[(2) - (2)].index) == Value_NonInteger) // @F + (yyval.index) = (yyvsp[(1) - (2)].index) | NotForIntegers; + else if((yyvsp[(2) - (2)].index) == Value_IsInteger) // @I + (yyval.index) = (yyvsp[(1) - (2)].index) | OnlyForIntegers; + else if((yyvsp[(2) - (2)].index) == Constness_Const) + (yyval.index) = (yyvsp[(1) - (2)].index) | OnlyForComplex; + else + { + char msg[] = "Only @L, @F, @I, @C and @R rule constraints are allowed for now"; + yyerror(msg); YYERROR; + } + } + break; + + case 7: +/* Line 1792 of yacc.c */ +#line 1290 "util/tree_grammar_parser.y" + { + if((yyvsp[(2) - (2)].index) == Modulo_Radians) + (yyval.index) = (yyvsp[(1) - (2)].index) | NotForComplex; + else + { + char msg[] = "Only @L, @F, @I, @C and @R rule constraints are allowed for now"; + yyerror(msg); YYERROR; + } + } + break; + + case 8: +/* Line 1792 of yacc.c */ +#line 1300 "util/tree_grammar_parser.y" + { + (yyval.index) = 0; + } + break; + + case 9: +/* Line 1792 of yacc.c */ +#line 1308 "util/tree_grammar_parser.y" + { + (yyvsp[(3) - (4)].a)->RecursivelySetDefaultParamMatchingType(); + + (yyval.r) = new GrammarData::Rule(ProduceNewTree, *(yyvsp[(1) - (4)].f), (yyvsp[(3) - (4)].a)); + delete (yyvsp[(1) - (4)].f); + } + break; + + case 10: +/* Line 1792 of yacc.c */ +#line 1318 "util/tree_grammar_parser.y" + { + GrammarData::ParamSpec* p = new GrammarData::ParamSpec((yyvsp[(3) - (4)].f)); + p->RecursivelySetDefaultParamMatchingType(); + /*if(!$3->Params.EnsureNoRepeatedNamedHolders()) + { + char msg[] = "The replacement function may not specify the same variable twice"; + yyerror(msg); YYERROR; + }*/ + + (yyval.r) = new GrammarData::Rule(ProduceNewTree, *(yyvsp[(1) - (4)].f), p); + + //std::cout << GrammarDumper().Dump(*new GrammarData::ParamSpec($3)) << "\n"; + delete (yyvsp[(1) - (4)].f); + } + break; + + case 11: +/* Line 1792 of yacc.c */ +#line 1335 "util/tree_grammar_parser.y" + { + /*if($1->Params.RestHolderIndex != 0) + { + char msg[] = "Restholder is not valid in the outermost function when ReplaceParams is used"; + yyerror(msg); YYERROR; + }*/ + (yyvsp[(3) - (4)].p)->RecursivelySetDefaultParamMatchingType(); + /*if(!$3->EnsureNoRepeatedNamedHolders()) + { + char msg[] = "The replacement function may not specify the same variable twice"; + yyerror(msg); YYERROR; + }*/ + + (yyval.r) = new GrammarData::Rule(ReplaceParams, *(yyvsp[(1) - (4)].f), *(yyvsp[(3) - (4)].p)); + delete (yyvsp[(1) - (4)].f); + delete (yyvsp[(3) - (4)].p); + } + break; + + case 12: +/* Line 1792 of yacc.c */ +#line 1356 "util/tree_grammar_parser.y" + { + if(!(yyvsp[(1) - (1)].f)->Params.EnsureNoVariableCoverageParams_InPositionalParamLists()) + { + char msg[] = "Restholders such as <1>, must not occur in bracketed param lists on the matching side"; + yyerror(msg); YYERROR; + } + (yyval.f) = (yyvsp[(1) - (1)].f); + } + break; + + case 13: +/* Line 1792 of yacc.c */ +#line 1371 "util/tree_grammar_parser.y" + { + (yyval.f) = new GrammarData::FunctionType((yyvsp[(1) - (4)].opcode), *(yyvsp[(3) - (4)].p)); + delete (yyvsp[(3) - (4)].p); + } + break; + + case 14: +/* Line 1792 of yacc.c */ +#line 1379 "util/tree_grammar_parser.y" + { + (yyval.f) = new GrammarData::FunctionType((yyvsp[(1) - (4)].opcode), *(yyvsp[(3) - (4)].p)->SetType(SelectedParams)); + delete (yyvsp[(3) - (4)].p); + } + break; + + case 15: +/* Line 1792 of yacc.c */ +#line 1386 "util/tree_grammar_parser.y" + { + (yyval.f) = new GrammarData::FunctionType((yyvsp[(1) - (2)].opcode), *(yyvsp[(2) - (2)].p)->SetType(AnyParams)); + delete (yyvsp[(2) - (2)].p); + } + break; + + case 16: +/* Line 1792 of yacc.c */ +#line 1394 "util/tree_grammar_parser.y" + { + (yyval.p) = (yyvsp[(1) - (2)].p)->AddParam((yyvsp[(2) - (2)].a)); + } + break; + + case 17: +/* Line 1792 of yacc.c */ +#line 1398 "util/tree_grammar_parser.y" + { + if((yyvsp[(1) - (2)].p)->RestHolderIndex != 0) + { + char msg[] = "Illegal attempt to specify two restholders for the same param list"; + yyerror(msg); YYERROR; + } + (yyvsp[(1) - (2)].p)->RestHolderIndex = (yyvsp[(2) - (2)].index); + (yyval.p) = (yyvsp[(1) - (2)].p); + } + break; + + case 18: +/* Line 1792 of yacc.c */ +#line 1408 "util/tree_grammar_parser.y" + { + (yyval.p) = new GrammarData::MatchedParams; + } + break; + + case 19: +/* Line 1792 of yacc.c */ +#line 1415 "util/tree_grammar_parser.y" + { + (yyval.a) = new GrammarData::ParamSpec((yyvsp[(1) - (2)].num), (yyvsp[(2) - (2)].index)); + } + break; + + case 20: +/* Line 1792 of yacc.c */ +#line 1419 "util/tree_grammar_parser.y" + { + (yyval.a) = new GrammarData::ParamSpec((yyvsp[(1) - (2)].index), GrammarData::ParamSpec::ParamHolderTag()); + (yyval.a)->SetConstraint((yyvsp[(2) - (2)].index) | Constness_Const); + } + break; + + case 21: +/* Line 1792 of yacc.c */ +#line 1424 "util/tree_grammar_parser.y" + { + /* Verify that $3 consists of constants */ + (yyval.a) = new GrammarData::ParamSpec((yyvsp[(1) - (4)].opcode), (yyvsp[(3) - (4)].p)->GetParams() ); + if(!(yyval.a)->VerifyIsConstant()) + { + char msg[] = "Not constant"; + yyerror(msg); YYERROR; + } + delete (yyvsp[(3) - (4)].p); + } + break; + + case 22: +/* Line 1792 of yacc.c */ +#line 1435 "util/tree_grammar_parser.y" + { + (yyval.a) = new GrammarData::ParamSpec((yyvsp[(1) - (2)].index) + 2, GrammarData::ParamSpec::ParamHolderTag()); + (yyval.a)->SetConstraint((yyvsp[(2) - (2)].index)); + } + break; + + case 23: +/* Line 1792 of yacc.c */ +#line 1440 "util/tree_grammar_parser.y" + { + (yyval.a) = new GrammarData::ParamSpec((yyvsp[(2) - (4)].f)); + (yyval.a)->SetConstraint((yyvsp[(4) - (4)].index)); + } + break; + + case 24: +/* Line 1792 of yacc.c */ +#line 1445 "util/tree_grammar_parser.y" + { + /* Verify that $2 is constant */ + if(!(yyvsp[(2) - (2)].a)->VerifyIsConstant()) + { + char msg[] = "Not constant"; + yyerror(msg); YYERROR; + } + std::vector<GrammarData::ParamSpec*> tmp; + tmp.push_back((yyvsp[(2) - (2)].a)); + (yyval.a) = new GrammarData::ParamSpec((yyvsp[(1) - (2)].opcode), tmp); + } + break; + + case 25: +/* Line 1792 of yacc.c */ +#line 1460 "util/tree_grammar_parser.y" + { + (yyval.index) = (yyvsp[(1) - (2)].index) | (yyvsp[(2) - (2)].index); + } + break; + + case 26: +/* Line 1792 of yacc.c */ +#line 1464 "util/tree_grammar_parser.y" + { + (yyval.index) = 0; + } + break; + + case 27: +/* Line 1792 of yacc.c */ +#line 1471 "util/tree_grammar_parser.y" + { + (yyval.index) = (yyvsp[(1) - (2)].index) | (yyvsp[(2) - (2)].index); + } + break; + + case 28: +/* Line 1792 of yacc.c */ +#line 1475 "util/tree_grammar_parser.y" + { + (yyval.index) = 0; + } + break; + + +/* Line 1792 of yacc.c */ +#line 2902 "util/tree_grammar_parser.cc" + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +/* Line 2055 of yacc.c */ +#line 1479 "util/tree_grammar_parser.y" + + +#ifndef FP_SUPPORT_OPTIMIZER +enum { cVar,cFetch,cPopNMov }; +#endif + +static void yyerror(const char* msg) +{ + std::cerr << msg << std::endl; + for(;;) + { + int c = std::fgetc(stdin); + if(c == EOF) break; + std::fputc(c, stderr); + } + exit(1); +} + +static int yylex(YYSTYPE* lval) +{ + int c = std::fgetc(stdin); + switch(c) + { + case EOF: break; + case '#': + while(c != EOF && c != '\n') c = std::fgetc(stdin); + return NEWLINE; + case '\n': + { + c = std::fgetc(stdin); + std::ungetc(c, stdin); + if(c == '[' + || c == '$') + return EOF; + return NEWLINE; + } + case '+': + { + c = std::fgetc(stdin); + std::ungetc(c, stdin); + if(c == '(') { lval->opcode = FUNCTIONPARSERTYPES::cAdd; return BUILTIN_FUNC_NAME; } + return '+'; + } + case '*': + { + c = std::fgetc(stdin); + std::ungetc(c, stdin); + if(c == '(') { lval->opcode = FUNCTIONPARSERTYPES::cMul; return BUILTIN_FUNC_NAME; } + return '*'; + } + case '-': + { + int c2 = std::fgetc(stdin); + if(c2 == '>') return SUBST_OP_ARROW; + std::ungetc(c2, stdin); + if(c2 >= '0' && c2 <= '9') + { + goto GotNumeric; + } + lval->opcode = FUNCTIONPARSERTYPES::cNeg; + return UNARY_TRANSFORMATION; + } + case '/': + lval->opcode = FUNCTIONPARSERTYPES::cInv; + return UNARY_TRANSFORMATION; + + case '=': + { + int c2 = std::fgetc(stdin); + std::ungetc(c2, stdin); + return '='; + } + case '[': case '{': + case ']': case '}': + case '(': + case ')': + return c; + case ' ': + case '\t': + case '\v': + case '\r': + return yylex(lval); // Counts as tail recursion, I hope + case ':': + return SUBST_OP_COLON; + case '%': { lval->index = 0; return IMMEDHOLDER_TOKEN; } + case '&': { lval->index = 1; return IMMEDHOLDER_TOKEN; } + + case '@': + { + int c2 = std::fgetc(stdin); + switch(c2) + { + case 'E': { lval->index = Value_EvenInt; return PARAM_CONSTRAINT; } + case 'O': { lval->index = Value_OddInt; return PARAM_CONSTRAINT; } + case 'I': { lval->index = Value_IsInteger; return PARAM_CONSTRAINT; } + case 'F': { lval->index = Value_NonInteger; return PARAM_CONSTRAINT; } + case 'L': { lval->index = Value_Logical; return PARAM_CONSTRAINT; } + case 'P': { lval->index = Sign_Positive; return PARAM_CONSTRAINT; } + case 'N': { lval->index = Sign_Negative; return PARAM_CONSTRAINT; } + case 'Q': { lval->index = Sign_NoIdea; return PARAM_CONSTRAINT; } + case '1': { lval->index = Oneness_One; return PARAM_CONSTRAINT; } + case 'M': { lval->index = Oneness_NotOne; return PARAM_CONSTRAINT; } + case 'C': { lval->index = Constness_Const; return PARAM_CONSTRAINT; } + case 'V': { lval->index = Constness_NotConst; return PARAM_CONSTRAINT; } + case 'R': { lval->index = Modulo_Radians; return CONST_CONSTRAINT; } + } + std::ungetc(c2, stdin); + return '@'; + } + case '<': + { + lval->index = 0; + for(;;) + { + c = std::fgetc(stdin); + if(c < '0' || c > '9') { std::ungetc(c, stdin); break; } + lval->index = lval->index * 10 + (c-'0'); + } + c = std::fgetc(stdin); + if(c != '>') std::ungetc(c, stdin); + return RESTHOLDER_TOKEN; + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + GotNumeric:; + std::string NumBuf; + NumBuf += (char)c; + bool had_comma = false; + for(;;) + { + c = std::fgetc(stdin); + if(c >= '0' && c <= '9') { NumBuf += (char)c; continue; } + if(c == '.' && !had_comma){ had_comma = true; NumBuf += (char)c; continue; } + std::ungetc(c, stdin); + break; + } + lval->num.real = std::strtod(NumBuf.c_str(), 0); + lval->num.imag = 0.0; + if(c == 'i') + { + std::fgetc(stdin); + lval->num.imag = lval->num.real; + lval->num.real = 0.0; + } + else if(c == '-' || c == '+') + { + NumBuf.clear(); + NumBuf += (char)c; + bool had_comma = false; + for(;;) + { + c = std::fgetc(stdin); + if(c >= '0' && c <= '9') { NumBuf += (char)c; continue; } + if(c == '.' && !had_comma){ had_comma = true; NumBuf += (char)c; continue; } + std::ungetc(c, stdin); + break; + } + if(c == 'i') + { + lval->num.imag = std::strtod(NumBuf.c_str(), 0); + std::fgetc(stdin); + } + } + return NUMERIC_CONSTANT; + } + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + { + std::string IdBuf; + IdBuf += (char)c; + for(;;) + { + c = std::fgetc(stdin); + if((c >= '0' && c <= '9') + || c == '_' + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) { IdBuf += (char)c; continue; } + std::ungetc(c, stdin); + break; + } + lval->num.real = 0; + lval->num.imag = 0; + + /* This code figures out if this is a named constant, + an opcode, or a parse-time function name, + or just an identifier + */ + + /* Detect named constants */ + if(IdBuf == "i") { lval->num.imag = 1.0; return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_E") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_e<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_EI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_einv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_2E") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twoe<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_2EI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twoeinv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_RD") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_rad_to_deg<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_DR") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_deg_to_rad<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_PI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_pi<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_PIHALF") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_pihalf<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_TWOPI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twopi<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L2I") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log2inv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L10I") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log10inv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L2") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log2<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L10") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log10<double>(); return NUMERIC_CONSTANT; } + + /* Detect opcodes */ + if(IdBuf == "cAdd") { lval->opcode = FUNCTIONPARSERTYPES::cAdd; return OPCODE_TOKEN; } + if(IdBuf == "cAnd") { lval->opcode = FUNCTIONPARSERTYPES::cAnd; return OPCODE_TOKEN; } + if(IdBuf == "cMul") { lval->opcode = FUNCTIONPARSERTYPES::cMul; return OPCODE_TOKEN; } + if(IdBuf == "cOr") { lval->opcode = FUNCTIONPARSERTYPES::cOr; return OPCODE_TOKEN; } + + if(IdBuf == "cNeg") { lval->opcode = FUNCTIONPARSERTYPES::cNeg; return OPCODE_TOKEN; } + if(IdBuf == "cSub") { lval->opcode = FUNCTIONPARSERTYPES::cSub; return OPCODE_TOKEN; } + if(IdBuf == "cDiv") { lval->opcode = FUNCTIONPARSERTYPES::cDiv; return OPCODE_TOKEN; } + if(IdBuf == "cMod") { lval->opcode = FUNCTIONPARSERTYPES::cMod; return OPCODE_TOKEN; } + if(IdBuf == "cEqual") { lval->opcode = FUNCTIONPARSERTYPES::cEqual; return OPCODE_TOKEN; } + if(IdBuf == "cNEqual") { lval->opcode = FUNCTIONPARSERTYPES::cNEqual; return OPCODE_TOKEN; } + if(IdBuf == "cLess") { lval->opcode = FUNCTIONPARSERTYPES::cLess; return OPCODE_TOKEN; } + if(IdBuf == "cLessOrEq") { lval->opcode = FUNCTIONPARSERTYPES::cLessOrEq; return OPCODE_TOKEN; } + if(IdBuf == "cGreater") { lval->opcode = FUNCTIONPARSERTYPES::cGreater; return OPCODE_TOKEN; } + if(IdBuf == "cGreaterOrEq") { lval->opcode = FUNCTIONPARSERTYPES::cGreaterOrEq; return OPCODE_TOKEN; } + if(IdBuf == "cNot") { lval->opcode = FUNCTIONPARSERTYPES::cNot; return OPCODE_TOKEN; } + if(IdBuf == "cNotNot") { lval->opcode = FUNCTIONPARSERTYPES::cNotNot; return OPCODE_TOKEN; } + if(IdBuf == "cAbsNot") { lval->opcode = FUNCTIONPARSERTYPES::cAbsNot; return OPCODE_TOKEN; } + if(IdBuf == "cAbsNotNot") { lval->opcode = FUNCTIONPARSERTYPES::cAbsNotNot; return OPCODE_TOKEN; } + if(IdBuf == "cAbsAnd") { lval->opcode = FUNCTIONPARSERTYPES::cAbsAnd; return OPCODE_TOKEN; } + if(IdBuf == "cAbsOr") { lval->opcode = FUNCTIONPARSERTYPES::cAbsOr; return OPCODE_TOKEN; } + if(IdBuf == "cAbsIf") { lval->opcode = FUNCTIONPARSERTYPES::cAbsIf; return OPCODE_TOKEN; } + if(IdBuf == "cDeg") { lval->opcode = FUNCTIONPARSERTYPES::cDeg; return OPCODE_TOKEN; } + if(IdBuf == "cRad") { lval->opcode = FUNCTIONPARSERTYPES::cRad; return OPCODE_TOKEN; } + if(IdBuf == "cInv") { lval->opcode = FUNCTIONPARSERTYPES::cInv; return OPCODE_TOKEN; } + if(IdBuf == "cSqr") { lval->opcode = FUNCTIONPARSERTYPES::cSqr; return OPCODE_TOKEN; } + if(IdBuf == "cRDiv") { lval->opcode = FUNCTIONPARSERTYPES::cRDiv; return OPCODE_TOKEN; } + if(IdBuf == "cRSub") { lval->opcode = FUNCTIONPARSERTYPES::cRSub; return OPCODE_TOKEN; } + if(IdBuf == "cRSqrt") { lval->opcode = FUNCTIONPARSERTYPES::cRSqrt; return OPCODE_TOKEN; } +#ifdef FP_SUPPORT_OPTIMIZER + if(IdBuf == "cLog2by") { lval->opcode = FUNCTIONPARSERTYPES::cLog2by; return OPCODE_TOKEN; } +#else + if(IdBuf == "cLog2by") { lval->opcode = FUNCTIONPARSERTYPES::cNop; return OPCODE_TOKEN; } +#endif + + /* Detect other function opcodes */ + if(IdBuf[0] == 'c' && std::isupper(IdBuf[1])) + { + // This has a chance of being an opcode token + std::string opcodetoken = IdBuf.substr(1); + opcodetoken[0] = (char) std::tolower( opcodetoken[0] ); + + unsigned nameLength = readOpcode(opcodetoken.c_str()); + if(nameLength & 0x80000000U) + { + lval->opcode = FUNCTIONPARSERTYPES::OPCODE( + (nameLength >> 16) & 0x7FFF ); + return OPCODE_TOKEN; + } + std::cerr << + "Warning: Unrecognized opcode '" << IdBuf << "' interpreted as cNop\n"; + lval->opcode = FUNCTIONPARSERTYPES::cNop; + return OPCODE_TOKEN; + } + + // If it is typed entirely in capitals, it has a chance of being + // a group token + if(true) + { + std::string grouptoken = IdBuf; + for(size_t a=0; a<grouptoken.size(); ++a) + { + if(std::islower(grouptoken[a])) goto NotAGroupToken; + grouptoken[a] = (char) std::tolower(grouptoken[a]); + } + if(1) // scope + { + unsigned nameLength = readOpcode(grouptoken.c_str()); + if(nameLength & 0x80000000U) + { + lval->opcode = FUNCTIONPARSERTYPES::OPCODE( + (nameLength >> 16) & 0x7FFF ); + return BUILTIN_FUNC_NAME; + } + if(IdBuf == "MOD") + { + lval->opcode = FUNCTIONPARSERTYPES::cMod; + return BUILTIN_FUNC_NAME; + } + if(IdBuf == "DIV") + { + lval->opcode = FUNCTIONPARSERTYPES::cDiv; + return BUILTIN_FUNC_NAME; + } + if(IdBuf == "SUB") + { + lval->opcode = FUNCTIONPARSERTYPES::cSub; + return BUILTIN_FUNC_NAME; + } + + std::cerr << "Warning: Unrecognized constant function '" << IdBuf + << "' interpreted as cNop\n"; + lval->opcode = FUNCTIONPARSERTYPES::cNop; + return BUILTIN_FUNC_NAME; + } + NotAGroupToken:; + } + // Anything else is an identifier + lval->index = dumper.ConvertNamedHolderNameIntoIndex(IdBuf); + // std::cerr << "'" << IdBuf << "'' interpreted as PARAM\n"; + + return NAMEDHOLDER_TOKEN; + } + default: + { + std::cerr << "Ignoring unidentifier character '" << char(c) << "'\n"; + return yylex(lval); // tail recursion + } + } + return EOF; +} + +unsigned GrammarData::ParamSpec::BuildDepMask() +{ + DepMask = 0; + switch(Opcode) + { + case ParamHolder: + DepMask |= 1 << Index; + break; + case SubFunction: + DepMask = Func->Params.BuildDepMask(); + break; + default: break; + } + return DepMask; +} + +namespace FPoptimizer_Grammar +{ + template<typename Value_t> + ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index) + { + unsigned plist_index = (paramlist >> (index*PARAM_INDEX_BITS)) + % (1 << PARAM_INDEX_BITS); + return plist[plist_index]; + } + template ParamSpec ParamSpec_Extract<stdcomplex>(unsigned paramlist, unsigned index); +} + +int main() +{ + std::map<std::string, GrammarData::Grammar> sections; + + std::string sectionname; + + for(;;) + { + grammar = GrammarData::Grammar(); + + yyparse(); + + grammar.BuildFinalDepMask(); + sections[sectionname] = grammar; + + int c = std::fgetc(stdin); + if(c != '[') + { + std::ungetc(c, stdin); + break; + } + + sectionname.clear(); + for(;;) + { + c = std::fgetc(stdin); + if(c == ']' || c == EOF) break; + sectionname += (char)c; + } + std::cerr << "Parsing [" << sectionname << "]\n"; + } + + std::map<std::string, std::vector<std::string> > grammar_components; + sectionname = ""; + for(;;) + { + int c = std::fgetc(stdin); + if(c == ' ' || c == '\t' || c == '\r' || c == '\n') continue; + if(c == '#') + { do { c = std::fgetc(stdin); } while(!(c == '\n' || c == EOF)); + continue; } + if(c == '$') + { + sectionname = ""; + for(;;) + { + c = std::fgetc(stdin); + if(c == EOF) break; + if(c == ' ' || c == '\t' || c == '\r' || c == '\n') break; + if(c == ':') break; + sectionname += char(c); + } + std::cerr << "Parsing $" << sectionname << "\n"; + continue; + } + if((c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9')) + { + std::string componentname; + for(;;) + { + if(c == EOF) break; + if(c == ' ' || c == '\t' || c == '\r' || c == '\n') break; + componentname += char(c); + c = std::fgetc(stdin); + } + std::cerr << "- Has [" << componentname << "]\n"; + grammar_components[sectionname].push_back(componentname); + //dumper.AddRulesFrom(sections[componentname]); + } + else break; + } + + std::cout << + "/* This file is automatically generated. Do not edit... */\n" + "#include \"../fpoptimizer/consts.hh\"\n" + "#include \"fpconfig.hh\"\n" + "#include \"extrasrc/fptypes.hh\"\n" + "#include <algorithm>\n" + "\n"; + + std::vector<GrammarData::Grammar> components; + for(std::map<std::string, std::vector<std::string> >::const_iterator + i = grammar_components.begin(); + i != grammar_components.end(); + ++i) + { + for(size_t a=0; a<i->second.size(); ++a) + components.push_back(sections[ i->second[a] ]); + } + dumper.RegisterGrammar(components); + + for(std::map<std::string, std::vector<std::string> >::const_iterator + i = grammar_components.begin(); + i != grammar_components.end(); + ++i) + { + components.clear(); + for(size_t a=0; a<i->second.size(); ++a) + components.push_back(sections[ i->second[a] ]); + dumper.DumpGrammar(i->first, components); + } + dumper.Flush(); + + unsigned mask = (1 << PARAM_INDEX_BITS)-1; + const unsigned p_begin = 0; + const unsigned n_begin = p_begin + dumper.collection.plist_p.size(); + const unsigned s_begin = n_begin + dumper.collection.plist_n.size(); + std::cout << + "namespace FPoptimizer_Grammar\n" + "{\n" + " template<typename Value_t>\n" + " ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index)\n" + " {\n" + " index = (paramlist >> (index * " << PARAM_INDEX_BITS << ")) & " << mask << " /* % (1 << " << PARAM_INDEX_BITS << ") */;\n" + " if(index >= " << s_begin << ")\n" + " return ParamSpec(SubFunction,(const void*)&plist_s[index-" << s_begin << "]);\n" + " if(index >= " << n_begin << ")\n" + " return ParamSpec(NumConstant,(const void*)&plist_n_container<Value_t>::plist_n[index-" << n_begin << "]);\n" + " return ParamSpec(ParamHolder,(const void*)&plist_p[index"/*"-" << p_begin << */"]);\n" + " }\n" + "}\n" + "/* BEGIN_EXPLICIT_INSTANTATION */\n" + "#include \"instantiate.hh\"\n" + "namespace FPoptimizer_Grammar\n" + "{\n" + "#define FP_INSTANTIATE(type) \\\n" + " template ParamSpec ParamSpec_Extract<type>(unsigned paramlist, unsigned index);\n" + " FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE)\n" + "#undef FP_INSTANTIATE\n" + "}\n" + "/* END_EXPLICIT_INSTANTATION */\n"; + + return 0; +} diff --git a/util/tree_grammar_parser.y b/util/tree_grammar_parser.y new file mode 100644 index 0000000..2383695 --- /dev/null +++ b/util/tree_grammar_parser.y @@ -0,0 +1,1966 @@ +%{ +#define YYDEBUG 1 +#define YYERROR_VERBOSE 1 +#include <string.h> // for error reporting + +#include "fpconfig.hh" +#include "fparser.hh" +#include "extrasrc/fptypes.hh" + +#include "../fpoptimizer/grammar.hh" +#include "../fpoptimizer/consts.hh" + +#include "../fpoptimizer/grammar.cc" +/* ^Note: including .cc file here in order to be able + * to instantiate DumpParam and DumpParams for complex types. + */ + +#include <cstdio> +#include <cctype> +#include <cstdlib> +#include <iostream> +#include <sstream> +#include <complex> +#include <map> +#include <set> +#include <algorithm> +#include <assert.h> + +#include "../lib/crc32.hh" + +#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 + +static const unsigned PARAM_INDEX_BITS = 10; + +/*********/ +using namespace FPoptimizer_Grammar; + +class GrammarDumper; + +static void yyerror(const char* msg); +static int yylex(union YYSTYPE* lval); + +namespace +{ + /* This function generated with make_identifier_parser.cc */ + unsigned readOpcode(const char* input) + { + using namespace FUNCTIONPARSERTYPES; +#include "extrasrc/fp_identifier_parser.inc" + return 0; + } +} + +//namespace +//{ + struct mycomplex + { + double real, imag; + }; + mycomplex operator -(const mycomplex& v) + { mycomplex res = {-v.real, -v.imag }; return res; } + + typedef std::complex<double> stdcomplex; +//} + +namespace GrammarData +{ + class ParamSpec; + + class MatchedParams + { + public: + ParamMatchingType Type; + std::vector<ParamSpec*> Params; + unsigned RestHolderIndex; + + public: + MatchedParams() : Type(PositionalParams), Params(), RestHolderIndex(0) { } + MatchedParams(ParamMatchingType t) : Type(t), Params(), RestHolderIndex(0) { } + MatchedParams(ParamSpec* p) : Type(PositionalParams), Params(), RestHolderIndex(0) { Params.push_back(p); } + + MatchedParams* SetType(ParamMatchingType t) { Type=t; return this; } + MatchedParams* AddParam(ParamSpec* p) { Params.push_back(p); return this; } + + const std::vector<ParamSpec*>& GetParams() const { return Params; } + + void RecursivelySetDefaultParamMatchingType(); + bool EnsureNoRepeatedNamedHolders(std::set<unsigned>& used) const; + bool EnsureNoRepeatedNamedHolders() const; + bool EnsureNoVariableCoverageParams_InPositionalParamLists(); + + unsigned CalcRequiredParamsCount() const; + + unsigned BuildDepMask(); + void BuildFinalDepMask(); + }; + + class FunctionType + { + public: + FUNCTIONPARSERTYPES::OPCODE Opcode; + MatchedParams Params; + public: + FunctionType(FUNCTIONPARSERTYPES::OPCODE o, const MatchedParams& p) + : Opcode(o), Params(p) { } + + void RecursivelySetDefaultParamMatchingType() + { + using namespace FUNCTIONPARSERTYPES; + Params.RecursivelySetDefaultParamMatchingType(); + if((Opcode == cAdd || Opcode == cMul + || Opcode == cAnd || Opcode == cOr + || Opcode == cAbsAnd || Opcode == cAbsOr) + && Params.Type == PositionalParams) + Params.Type = SelectedParams; + } + + bool EnsureNoRepeatedNamedHolders() const + { return Params.EnsureNoRepeatedNamedHolders(); } + }; + + class ParamSpec + { + public: + unsigned DepMask; + + SpecialOpcode Opcode; // specifies the type of the function + union + { + mycomplex ConstantValue;// for NumConstant + unsigned Index; // for ParamHolder + FunctionType* Func; // for SubFunction + }; + unsigned ImmedConstraint; + bool IsConst; // when SubFunction + + public: + struct ParamHolderTag{}; + + ParamSpec(FunctionType* f) + : DepMask(), + Opcode(SubFunction), + Func(f), + ImmedConstraint(0), + IsConst(false) + { + } + + ParamSpec(mycomplex d, unsigned constraints) + : DepMask(), + Opcode(NumConstant), + ConstantValue(d), + ImmedConstraint(constraints), + IsConst(true) + { + } + + ParamSpec(FUNCTIONPARSERTYPES::OPCODE o, const std::vector<ParamSpec*>& p) + : DepMask(), + Opcode(SubFunction), + Func(new FunctionType(o, MatchedParams(PositionalParams))), + ImmedConstraint(0), + IsConst(true) + { + if(o == FUNCTIONPARSERTYPES::cNeg && p[0]->Opcode == NumConstant) + { + delete Func; + Opcode = NumConstant; + ConstantValue = -p[0]->ConstantValue; + ImmedConstraint = p[0]->ImmedConstraint; + } + else + { + Func->Params.Params = p; + /* + if(o == cAdd && p[1]->Opcode == SubFunction + && p[1]->Func->Opcode == cNeg + && p.size() == 2) + { + Func->Opcode = cSub; + Func->Params.Params[1] = p[1]->Func->Params.Params[0]; + } -- not done because ConstantFolding() cannot handle cSub + */ + } + } + + ParamSpec(unsigned i, ParamHolderTag) + : DepMask(), + Opcode(ParamHolder), Index(i), + ImmedConstraint(0), + IsConst(true) + { + } + +/* + // Order: + // NumConstant { ConstantValue } + // ParamHolder { Index } + // SubFunction { Opcode, IsConst } + bool operator< (const ParamSpec& b) const + { + if(Opcode == NumConstant) + return (b.Opcode == NumConstant) + ? ConstantValue < b.ConstantValue + : true; + if(Opcode == ParamHolder) + return (b.Opcode == ParamHolder) + ? Index < b.Index + : (b.Opcode == SubFunction) + ? true + : false; + if(Opcode == SubFunction) + return (b.Opcode == SubFunction) + ? (Func->Opcode != b.Func->Opcode + ? Func->Opcode < b.Func->Opcode + : IsConst < b.IsConst + ) + : false; + return false; + } + bool operator!= (const ParamSpec& b) const { return !operator==(b); } + bool operator== (const ParamSpec& b) const + { + switch(Opcode) + { + case NumConstant: + return b.Opcode == Opcode && fp_equal(ConstantValue, b.ConstantValue); + case ParamHolder: + return b.Opcode == Opcode && ImmedConstraint == b.ImmedConstraint + && b.DepMask == DepMask && Index == b.Index; + case SubFunction: + if(b.Opcode != SubFunction) return false; + if(Func->Opcode != b.Func->Opcode) return false; + if(ImmedConstraint != b.ImmedConstraint) return false; + if(DepMask != b.DepMask) return false; + if(IsConst != b.IsConst) return false; + if(Func->Params.Type != b.Func->Params.Type + || Func->Params.RestHolderIndex != b.Func->Params.RestHolderIndex + || Func->Params.Params.size() != b.Func->Params.Params.size()) + return false; + for(size_t a=0; a<Func->Params.Params.size(); ++a) + if(*Func->Params.Params[a] != *b.Func->Params.Params[a]) + return false; + } + return true; + } +*/ + ParamSpec* SetConstraint(unsigned mask) + { ImmedConstraint |= mask; return this; } + + unsigned BuildDepMask(); + + void RecursivelySetDefaultParamMatchingType() + { + if(Opcode == SubFunction) + Func->RecursivelySetDefaultParamMatchingType(); + } + bool VerifyIsConstant() + { + switch(Opcode) + { + case NumConstant: return true; + case ParamHolder: return + (ImmedConstraint & ConstnessMask) == Constness_Const; + case SubFunction: + if(!IsConst) return false; // subfunctions are not constant + } + // For const-subfunctions, all params must be const. + for(size_t a=0; a<Func->Params.Params.size(); ++a) + if(!Func->Params.Params[a]->VerifyIsConstant()) return false; + return true; + } + + bool EnsureNoRepeatedNamedHolders() const + { + if(Opcode != SubFunction) return true; + MatchedParams tmp; + tmp.Params = Func->Params.Params; + return tmp.EnsureNoRepeatedNamedHolders(); + } + + private: + ParamSpec(const ParamSpec&); + ParamSpec& operator= (const ParamSpec&); + }; + + class Rule + { + public: + friend class GrammarDumper; + RuleType Type; + + FunctionType Input; + MatchedParams Replacement; // length should be 1 if ProduceNewTree is used + unsigned SituationFlags; + public: + Rule(RuleType t, const FunctionType& f, const MatchedParams& r) + : Type(t), Input(f), Replacement(r), SituationFlags(0) + { } + + Rule(RuleType t, const FunctionType& f, ParamSpec* p) + : Type(t), Input(f), Replacement(), SituationFlags(0) + { Replacement.AddParam(p); } + + void BuildFinalDepMask() + { + Input.Params.BuildFinalDepMask(); + //Replacement.BuildFinalDepMask(); -- not needed, though not wrong either. + } + void SetSituationFlags(unsigned flags) + { + SituationFlags = flags; + } + }; + + class Grammar + { + public: + std::vector<Rule> rules; + public: + Grammar(): rules() { } + + void AddRule(const Rule& r) { rules.push_back(r); } + void BuildFinalDepMask() + { + for(size_t a=0; a<rules.size(); ++a) + rules[a].BuildFinalDepMask(); + } + }; + + //////////////////// + + void MatchedParams::RecursivelySetDefaultParamMatchingType() + { + Type = PositionalParams; + if(RestHolderIndex != 0) + Type = AnyParams; + + for(size_t a=0; a<Params.size(); ++a) + Params[a]->RecursivelySetDefaultParamMatchingType(); + } + + bool MatchedParams::EnsureNoRepeatedNamedHolders(std::set<unsigned>& used) const + { + for(size_t a=0; a<Params.size(); ++a) + { + if(Params[a]->Opcode == ParamHolder) + { + unsigned index = Params[a]->Index; + std::set<unsigned>::iterator i = used.lower_bound(index); + if(i != used.end() && *i == index) + return false; + used.insert(i, index); + } + if(Params[a]->Opcode == SubFunction) + if(!Params[a]->Func->Params.EnsureNoRepeatedNamedHolders(used)) + return false; + } + return true; + } + + bool MatchedParams::EnsureNoRepeatedNamedHolders() const + { + std::set<unsigned> used; + return EnsureNoRepeatedNamedHolders(used); + } + + bool MatchedParams::EnsureNoVariableCoverageParams_InPositionalParamLists() + { + if(Type != PositionalParams + && Type != SelectedParams) return true; + + if(RestHolderIndex != 0) return false; + + for(size_t a=0; a<Params.size(); ++a) + { + if(Params[a]->Opcode == SubFunction) + if(!Params[a]->Func->Params.EnsureNoVariableCoverageParams_InPositionalParamLists()) + return false; + } + return true; + } + unsigned MatchedParams::CalcRequiredParamsCount() const + { + return (unsigned)Params.size(); + } + + unsigned MatchedParams::BuildDepMask() + { + unsigned result = 0; + for(size_t a=0; a<Params.size(); ++a) + result |= Params[a]->BuildDepMask(); + return result; + } + + void MatchedParams::BuildFinalDepMask() + { + unsigned all_bits = BuildDepMask(); + + // For each bit that is set in all_bits, unset + // all of them that are only set in one of the parameters. + for(unsigned bit=1; all_bits >= bit; bit <<= 1) + if(all_bits & bit) + { + unsigned count_found = 0; + for(size_t a=0; a<Params.size(); ++a) + { + unsigned param_bitmask = Params[a]->DepMask; + if(param_bitmask & bit) ++count_found; + } + if(count_found <= 1) + { + for(size_t a=0; a<Params.size(); ++a) + Params[a]->DepMask &= ~bit; + } + } + + // Recurse + for(size_t a=0; a<Params.size(); ++a) + if(Params[a]->Opcode == SubFunction) + Params[a]->Func->Params.BuildFinalDepMask(); + } +} + +namespace FPoptimizer_Grammar +{ + template<typename Value_t> // Used only by tree_grammar_parser.y + bool ParamSpec_Compare(const void* aa, const void* bb, SpecialOpcode type) + { + switch(type) + { + case ParamHolder: + { + ParamSpec_ParamHolder& a = *(ParamSpec_ParamHolder*) aa; + ParamSpec_ParamHolder& b = *(ParamSpec_ParamHolder*) bb; + return a.constraints == b.constraints + && a.index == b.index + && a.depcode == b.depcode; + } + case NumConstant: + { + ParamSpec_NumConstant<Value_t>& a = *(ParamSpec_NumConstant<Value_t>*) aa; + ParamSpec_NumConstant<Value_t>& b = *(ParamSpec_NumConstant<Value_t>*) bb; + return a.constvalue == b.constvalue + && a.modulo == b.modulo; + } + case SubFunction: + { + ParamSpec_SubFunction& a = *(ParamSpec_SubFunction*) aa; + ParamSpec_SubFunction& b = *(ParamSpec_SubFunction*) bb; + return a.constraints == b.constraints + && a.data.subfunc_opcode == b.data.subfunc_opcode + && a.data.match_type == b.data.match_type + && a.data.param_count == b.data.param_count + && a.data.param_list == b.data.param_list + && a.data.restholder_index == b.data.restholder_index + && a.depcode == b.depcode; + } + } + return true; + } +} + +GrammarData::Grammar grammar; +std::vector<ParamSpec> plist; +std::vector<Rule> rlist; + +struct RuleComparer +{ + bool operator() (const Rule& a, const Rule& b) const + { + if(a.match_tree.subfunc_opcode != b.match_tree.subfunc_opcode) + return a.match_tree.subfunc_opcode < b.match_tree.subfunc_opcode; + + // Other rules to break ties + if(a.situation_flags != b.situation_flags) + return a.situation_flags < b.situation_flags; + + if(a.ruletype != b.ruletype) + return a.ruletype < b.ruletype; + + if(a.match_tree.match_type != b.match_tree.match_type) + return a.match_tree.match_type < b.match_tree.match_type; + + if(a.match_tree.param_count != b.match_tree.param_count) + return a.match_tree.param_count < b.match_tree.param_count; + + if(a.repl_param_count != b.repl_param_count) + return a.repl_param_count < b.repl_param_count; + + if(a.match_tree.param_list != b.match_tree.param_list) + return a.match_tree.param_list < b.match_tree.param_list; + + if(a.repl_param_list != b.repl_param_list) + return a.repl_param_list < b.repl_param_list; + + return false; + } + + bool operator() (unsigned a, unsigned b) const + { + return this->operator() ( rlist[a], rlist[b] ); + } +}; + +class GrammarDumper +{ +private: + std::string GenName(const char* prefix) + { + static unsigned counter = 0; + std::ostringstream tmp; + tmp << prefix << ++counter; + return tmp.str(); + } +private: + std::map<std::string, size_t> n_index; + + std::vector<std::string> nlist; + std::map<std::string, Grammar> glist; +public: + GrammarDumper(): + n_index(), + nlist(),glist() + { + plist.reserve(16384); + nlist.reserve(16); + rlist.reserve(16384); + } + + unsigned ConvertNamedHolderNameIntoIndex(const std::string& n) + { + std::map<std::string, size_t>::const_iterator i = n_index.find(n); + if(i != n_index.end()) return i->second; + nlist.push_back(n); + return n_index[n] = (unsigned)(nlist.size()-1); + } + size_t GetNumNamedHolderNames() const { return nlist.size(); } + + void DumpParamList(const std::vector<GrammarData::ParamSpec*>& Params, + unsigned& param_count, + unsigned& param_list) + { + param_count = (unsigned)Params.size(); + param_list = 0; + for(unsigned a=0; a<param_count; ++a) + { + ParamSpec p = CreateParam(*Params[a]); + + unsigned paramno = (unsigned)plist.size(); + + for(size_t b = 0; b < plist.size(); ++b) + if(plist[b].first == p.first + && ParamSpec_Compare<stdcomplex>(plist[b].second, p.second, p.first)) + { + paramno = (unsigned)b; + break; + } + + if(paramno == plist.size()) plist.push_back(p); + + param_list |= paramno << (a * PARAM_INDEX_BITS); + } + } + + ParamSpec CreateParam(const GrammarData::ParamSpec& p) + { + unsigned pcount; + unsigned plist; + switch(p.Opcode) + { + case SubFunction: + { + ParamSpec_SubFunction* result = new ParamSpec_SubFunction; + result->constraints = p.ImmedConstraint; + result->data.subfunc_opcode = p.Func->Opcode; + result->data.match_type = p.Func->Params.Type; + DumpParamList(p.Func->Params.Params, pcount, plist); + result->data.param_count = pcount; + result->data.param_list = plist; + result->depcode = p.DepMask; + result->data.restholder_index = p.Func->Params.RestHolderIndex; + if(p.IsConst) + { + result->data.match_type = GroupFunction; + result->constraints |= Constness_Const; + } + return std::make_pair(SubFunction, (void*)result); + } + case NumConstant: + { + typedef stdcomplex v; + ParamSpec_NumConstant<v>* result = new ParamSpec_NumConstant<v>; + result->constvalue = v(p.ConstantValue.real, p.ConstantValue.imag); + result->modulo = p.ImmedConstraint; + return std::make_pair(NumConstant, (void*)result); + } + case ParamHolder: + { + ParamSpec_ParamHolder* result = new ParamSpec_ParamHolder; + result->constraints = p.ImmedConstraint; + result->index = p.Index; + result->depcode = p.DepMask; + return std::make_pair(ParamHolder, (void*)result); + } + } + std::cout << "???\n"; + return std::make_pair(SubFunction, (void*) 0); + } + + Rule CreateRule(const GrammarData::Rule& r) + { + //unsigned min_params = r.Input.Params.CalcRequiredParamsCount(); + + Rule ritem; + memset(&ritem, 0, sizeof(ritem)); + //ritem.n_minimum_params = min_params; + ritem.ruletype = r.Type; + ritem.situation_flags = r.SituationFlags; + ritem.match_tree.subfunc_opcode = r.Input.Opcode; + ritem.match_tree.match_type = r.Input.Params.Type; + ritem.match_tree.restholder_index = r.Input.Params.RestHolderIndex; + unsigned pcount; + unsigned plist; + DumpParamList(r.Input.Params.Params, pcount, plist); + ritem.match_tree.param_count = pcount; + ritem.match_tree.param_list = plist; + + DumpParamList(r.Replacement.Params, pcount, plist); + ritem.repl_param_count = pcount; + ritem.repl_param_list = plist; + return ritem; + } + + void RegisterGrammar(const std::vector<GrammarData::Grammar>& gset) + { + using namespace FUNCTIONPARSERTYPES; + std::vector<Rule> this_rules; + + for(size_t a=0; a<gset.size(); ++a) + { + const GrammarData::Grammar& g = gset[a]; + + for(size_t a=0; a<g.rules.size(); ++a) + { + if(g.rules[a].Input.Opcode == cNop) continue; + this_rules.push_back( CreateRule(g.rules[a]) ); + } + } + + std::sort(this_rules.begin(), this_rules.end(), + RuleComparer()); + + for(size_t a=0; a<this_rules.size(); ++a) + { + const Rule& r = this_rules[a]; + + // Add to global rule list, unless it's already there + bool dup=false; + for(size_t c=0; c<rlist.size(); ++c) + if(memcmp(&r, &rlist[c], sizeof(r)) == 0) + { + // Already in global rule list... + dup = true; + break; + } + if(!dup) + rlist.push_back(r); + } + } + + void DumpGrammar(const std::string& grammarname, + const std::vector<GrammarData::Grammar>& gset) + { + using namespace FUNCTIONPARSERTYPES; + std::vector<unsigned> rule_list; + + std::vector<Rule> this_rules; + + for(size_t a=0; a<gset.size(); ++a) + { + const GrammarData::Grammar& g = gset[a]; + + for(size_t a=0; a<g.rules.size(); ++a) + { + if(g.rules[a].Input.Opcode == cNop) continue; + this_rules.push_back( CreateRule(g.rules[a]) ); + } + } + + std::sort(this_rules.begin(), this_rules.end(), + RuleComparer()); + + for(size_t a=0; a<this_rules.size(); ++a) + { + const Rule& r = this_rules[a]; + + // Add to global rule list, unless it's already there + bool dup=false; + for(size_t c=0; c<rlist.size(); ++c) + if(memcmp(&r, &rlist[c], sizeof(r)) == 0) + { + // Already in global rule list... + // Add to grammar's rule list unless it's already there + dup = false; + for(size_t b=0; b<rule_list.size(); ++b) + if(c == rule_list[b]) + { + dup = true; + break; + } + if(!dup) + { + // Global duplicate, but not yet in grammar. + rule_list.push_back(c); + } + dup = true; + break; + } + if(!dup) + { + // Not in global rule list. Add there and in grammar. + rule_list.push_back( (unsigned) rlist.size() ); + rlist.push_back(r); + } + } + + Grammar& gitem = glist[grammarname]; + + gitem.rule_count = (unsigned) rule_list.size(); + + std::sort(rule_list.begin(), rule_list.end(), + RuleComparer()); + + for(size_t a=0; a<rule_list.size(); ++a) + gitem.rule_list[a] = rule_list[a]; + } + + static std::string ConstraintsToString(unsigned constraints) + { + std::ostringstream result; + const char* sep = ""; + static const char s[] = " | "; + switch( ImmedConstraint_Value( constraints & ValueMask ) ) + { + case ValueMask: case Value_AnyNum: break; + case Value_EvenInt: result << sep << "Value_EvenInt"; sep=s; break; + case Value_OddInt: result << sep << "Value_OddInt"; sep=s; break; + case Value_IsInteger: result << sep << "Value_IsInteger"; sep=s; break; + case Value_NonInteger: result << sep << "Value_NonInteger"; sep=s; break; + case Value_Logical: result << sep << "Value_Logical"; sep=s; break; + } + switch( ImmedConstraint_Sign( constraints & SignMask ) ) + { + /*case SignMask:*/ case Sign_AnySign: break; + case Sign_Positive: result << sep << "Sign_Positive"; sep=s; break; + case Sign_Negative: result << sep << "Sign_Negative"; sep=s; break; + case Sign_NoIdea: result << sep << "Sign_NoIdea"; sep=s; break; + } + switch( ImmedConstraint_Oneness( constraints & OnenessMask ) ) + { + case OnenessMask: case Oneness_Any: break; + case Oneness_One: result << sep << "Oneness_One"; sep=s; break; + case Oneness_NotOne: result << sep << "Oneness_NotOne"; sep=s; break; + } + switch( ImmedConstraint_Constness( constraints & ConstnessMask ) ) + { + case ConstnessMask: case Oneness_Any: break; + case Constness_Const: result << sep << "Constness_Const"; sep=s; break; + case Constness_NotConst: result << sep << "Constness_NotConst"; sep=s; break; + } + if(!*sep) result << "0"; + return result.str(); + } + static std::string ModuloToString(unsigned constraints) + { + std::ostringstream result; + const char* sep = ""; + static const char s[] = " | "; + switch( Modulo_Mode(constraints) ) + { + case Modulo_None: break; + case Modulo_Radians: result << sep << "Modulo_Radians"; sep=s; break; + } + if(!*sep) result << "0"; + return result.str(); + } + + static std::string ConstValueToString(const stdcomplex& value) + { + using namespace FUNCTIONPARSERTYPES; + std::ostringstream result; + result.precision(50); + double dvalue = value.real(); + if(value.imag() != 0.0) goto NotAnyKnownConstant; + #define Value_t double + #define if_const(n) \ + if((dvalue)==(n)) result << #n; \ + else if((dvalue)==(-n)) result << "-" #n; + if_const(fp_const_e<Value_t>()) + else if_const(fp_const_einv<Value_t>()) + else if_const(fp_const_twoe<Value_t>()) + else if_const(fp_const_twoeinv<Value_t>()) + else if_const(fp_const_pi<Value_t>()) + else if_const(fp_const_pihalf<Value_t>()) + else if_const(fp_const_twopi<Value_t>()) + else if_const(fp_const_log2<Value_t>()) + else if_const(fp_const_log2inv<Value_t>()) + else if_const(fp_const_log10<Value_t>()) + else if_const(fp_const_log10inv<Value_t>()) + else if_const(fp_const_rad_to_deg<Value_t>()) + else if_const(fp_const_deg_to_rad<Value_t>()) + #undef if_const + #undef Value_t + else + { + NotAnyKnownConstant: + result << "Value_t(" << value.real() << ")"; + if(value.imag() != 0.0) + result << " + fp_make_imag(Value_t(" << value.imag() << "))"; + } + return result.str(); + } + + struct ParamCollection + { + std::vector<ParamSpec_ParamHolder> plist_p; + std::vector<ParamSpec_NumConstant<stdcomplex> > plist_n; + std::vector<ParamSpec_SubFunction> plist_s; + + void Populate(const ParamSpec& param) + { + #define set(when, type, list, code) \ + case when: \ + { for(size_t a=0; a<list.size(); ++a) \ + if(ParamSpec_Compare<stdcomplex>(param.second, (const void*) &list[a], when)) \ + return; \ + list.push_back( *(type*) param.second ); \ + code; \ + break; } + switch(param.first) + { + set(ParamHolder, ParamSpec_ParamHolder, plist_p, {} ); + set(NumConstant, ParamSpec_NumConstant<stdcomplex>, plist_n, {} ); + set(SubFunction, ParamSpec_SubFunction, plist_s, + ParamSpec_SubFunction* p = (ParamSpec_SubFunction*)param.second; + for(size_t a=0; a<p->data.param_count; ++a) + Populate( ParamSpec_Extract<stdcomplex>( p->data.param_list, a) ); + ); + } + #undef set + } + + struct p_compare { int kind( + const ParamSpec_ParamHolder& a, + const ParamSpec_ParamHolder& b) const + { + if((a.index^2) != (b.index^2)) return (a.index^2) < (b.index^2) ? -1 : 1; + // xor-2 is here to tweak the sorting order such that + // the most used parameters (x,y) are first in the list, + // resulting in smaller numbers for the parameter indexes, + // and thus a smaller source code size for grammar data. + return 0; + } }; + struct n_compare { int kind( + const ParamSpec_NumConstant<stdcomplex>& a, + const ParamSpec_NumConstant<stdcomplex>& b) const + { + if(a.modulo != b.modulo) return a.modulo < b.modulo ? -1 : 1; + double av = std::norm(a.constvalue), bv = std::norm(b.constvalue); + if(a.constvalue.real() < 0) av = -av; + if(b.constvalue.real() < 0) bv = -bv; + if(av != bv) return av < bv ? -1 : 1; + return 0; + } }; + struct s_compare { int kind( + const ParamSpec_SubFunction& a, + const ParamSpec_SubFunction& b) const + { + unsigned a_opcode = a.data.subfunc_opcode; + unsigned b_opcode = b.data.subfunc_opcode; + + if(a_opcode == FUNCTIONPARSERTYPES::cAdd) a_opcode = 2; + else if(a_opcode == FUNCTIONPARSERTYPES::cMul) a_opcode = 3; + else if(a_opcode == FUNCTIONPARSERTYPES::cPow) a_opcode = 4; + else if(a_opcode == FUNCTIONPARSERTYPES::cNeg) a_opcode = 0; + else if(a_opcode == FUNCTIONPARSERTYPES::cInv) a_opcode = 1; + else a_opcode += 5; + if(b_opcode == FUNCTIONPARSERTYPES::cAdd) b_opcode = 2; + else if(b_opcode == FUNCTIONPARSERTYPES::cMul) b_opcode = 3; + else if(b_opcode == FUNCTIONPARSERTYPES::cPow) b_opcode = 4; + else if(b_opcode == FUNCTIONPARSERTYPES::cNeg) b_opcode = 0; + else if(b_opcode == FUNCTIONPARSERTYPES::cInv) b_opcode = 1; + else b_opcode += 5; + + if(a_opcode != b_opcode) + return a_opcode < b_opcode ? -1 : 1; + if(a.constraints != b.constraints) + return a.constraints < b.constraints ? -1 : 1; + if(a.data.match_type != b.data.match_type) + return a.data.match_type < b.data.match_type ? -1 : 1; + + size_t min_param_count = std::min(a.data.param_count, b.data.param_count); + + for(size_t c=0; c< min_param_count; ++c) + { + ParamSpec aa = ParamSpec_Extract<stdcomplex>(a.data.param_list, (unsigned)c); + ParamSpec bb = ParamSpec_Extract<stdcomplex>(b.data.param_list, (unsigned)c); + if(aa.first != bb.first) + return aa.first < bb.first; + switch(aa.first) + { + case ParamHolder: { + int k = p_compare().kind + (*(const ParamSpec_ParamHolder*)aa.second, + *(const ParamSpec_ParamHolder*)bb.second); + if(k) return k; + break; + }case NumConstant: { + int k = n_compare().kind + (*(const ParamSpec_NumConstant<stdcomplex>*)aa.second, + *(const ParamSpec_NumConstant<stdcomplex>*)bb.second); + if(k) return k; + break; + }case SubFunction:{ + int k = s_compare().kind + (*(const ParamSpec_SubFunction*)aa.second, + *(const ParamSpec_SubFunction*)bb.second); + if(k) return k; + break; + } } + } + if(a.data.param_count != b.data.param_count) + return a.data.param_count < b.data.param_count ? -1 : 1; + return 0; + } }; + template<typename T> + struct kind_compare + { + template<typename K> + bool operator() (const K& a, const K& b) const + { + return T().kind(a,b) < 0; + } + }; + + void Sort() + { + std::stable_sort(plist_p.begin(), plist_p.end(), kind_compare<p_compare>()); + std::stable_sort(plist_n.begin(), plist_n.end(), kind_compare<n_compare>()); + std::stable_sort(plist_s.begin(), plist_s.end(), kind_compare<s_compare>()); + } + + unsigned ParamPtrToParamIndex(unsigned paramlist, unsigned index) const + { + const ParamSpec& p = ParamSpec_Extract<stdcomplex> (paramlist, index); + if(p.second) + { + #define set(when, list, c) \ + case when: \ + for(size_t a=0; a<list.size(); ++a) \ + if(ParamSpec_Compare<stdcomplex> (p.second, (const void*)&list[a], when)) \ + return (a + c##offset); \ + break; + unsigned Poffset = 0; + unsigned Noffset = plist_p.size(); + unsigned Soffset = plist_n.size() + Noffset; + switch(p.first) + { + set(ParamHolder, plist_p, P); + set(NumConstant, plist_n, N); + set(SubFunction, plist_s, S); + } + #undef set + } + return (1 << 10)-1; + } + + std::string ParamListToString(unsigned paramlist, unsigned paramcount) const + { + std::ostringstream result, comment; + unsigned value = 0; + for(unsigned p=0; p<paramcount; ++p) + { + unsigned index = ParamPtrToParamIndex(paramlist, p); + if(p) comment << ','; + comment << index; + value += index << (p*PARAM_INDEX_BITS); + } + std::string commentstr = comment.str(); + commentstr.resize(3*3+2, ' '); + result << "/*" << commentstr << "*/" << value; + + std::string res = result.str(); + if(res.size() < 25) res.resize(25, ' '); + /* 999*x+999*x+999 = 15 characters */ + /* (*999,999,999*)1048551399 = 25 characters */ + return res; + } + std::string ParamHolderToString(const ParamSpec_ParamHolder& i) const + { + std::ostringstream result; + result << "{" << i.index + << ", " << ConstraintsToString(i.constraints) + << ", 0x" << i.depcode + << "}"; + return result.str(); + } + + std::string NumConstantToString(const ParamSpec_NumConstant<stdcomplex>& i) const + { + std::ostringstream result; + result << "{" << ConstValueToString(i.constvalue) + << ", " << ModuloToString(i.modulo) + << "}"; + return result.str(); + } + + std::string SubFunctionDataToString(const ParamSpec_SubFunctionData& i) const + { + std::ostringstream result; + result << "{" << i.param_count + << "," << ParamListToString(i.param_list, i.param_count) + << ", " << FP_GetOpcodeName(i.subfunc_opcode, true) + << "," << (i.match_type == PositionalParams ? "PositionalParams" + : i.match_type == SelectedParams ? "SelectedParams " + : i.match_type == AnyParams ? "AnyParams " + :/*i.match_type == GroupFunction ?*/ "GroupFunction " + ) + << "," << i.restholder_index + << "}"; + return result.str(); + } + + std::string SubFunctionToString(const ParamSpec_SubFunction& i) const + { + std::ostringstream result; + result << "{" << SubFunctionDataToString(i.data) + << ", " << ConstraintsToString(i.constraints) + << ", 0x" << i.depcode + << "}"; + return result.str(); + } + }; + + ParamCollection collection; + + void Flush() + { + for(size_t a=0; a<rlist.size(); ++a) + { + for(unsigned b=0; b < rlist[a].match_tree.param_count; ++b) + collection.Populate( ParamSpec_Extract<stdcomplex>(rlist[a].match_tree.param_list, b) ); + for(unsigned b=0; b < rlist[a].repl_param_count; ++b) + collection.Populate( ParamSpec_Extract<stdcomplex>(rlist[a].repl_param_list, b) ); + } + collection.Sort(); + + std::cout << "/* BEGIN_EXPLICIT_INSTANTATIONS */\n"; + for(std::map<std::string, Grammar>::const_iterator + i = glist.begin(); i != glist.end(); ++i) + std::cout << "#define grammar_" << i->first << " grammar_" << i->first << "_tweak\n"; + std::cout << + "#include \"../fpoptimizer/grammar.hh\"\n"; + for(std::map<std::string, Grammar>::const_iterator + i = glist.begin(); i != glist.end(); ++i) + std::cout << "#undef grammar_" << i->first << "\n"; + std::cout << "/* END_EXPLICIT_INSTANTATIONS */\n"; + + std::cout << + "\n" + "using namespace FPoptimizer_Grammar;\n" + "using namespace FUNCTIONPARSERTYPES;\n" + "\n" + "namespace\n" + "{\n"; + + { + + #define set(type, listprefix, list, c) \ + std::cout << \ + " const ParamSpec_" #type " " listprefix #list "[" << collection.list.size() << "] =\n" \ + " {\n"; \ + for(size_t a=0; a<collection.list.size(); ++a) \ + { \ + std::cout << " /* " << offset++ << "\t*/ " \ + << collection.type##ToString(collection.list[a]) \ + << ", /* "; \ + FPoptimizer_Grammar::DumpParam<stdcomplex>( ParamSpec(type, (const void*) &collection.list[a]), std::cout); \ + std::cout << " */\n"; \ + } \ + std::cout << \ + " };\n" \ + "\n"; + + unsigned offset = 0; + set(ParamHolder, "", plist_p, P) // Must be first one + std::cout << + " template<typename Value_t>\n" + " struct plist_n_container\n" + " {\n" + " static const ParamSpec_NumConstant<Value_t> plist_n[" << collection.plist_n.size() << "];\n" + " };\n" + " template<typename Value_t>\n"; + set(NumConstant, "<Value_t> plist_n_container<Value_t>::", plist_n, N) + set(SubFunction, "", plist_s, S) + + std::cout << + "}\n"; + } + + #undef set + + std::cout << + "namespace FPoptimizer_Grammar\n" + "{\n"; + std::cout << + " const Rule grammar_rules[" << rlist.size() << "] =\n" + " {\n"; + for(size_t a=0; a<rlist.size(); ++a) + { + std::cout << + " /* " << a << ":\t"; + ParamSpec_SubFunction tmp = {rlist[a].match_tree,0,0}; + if(rlist[a].situation_flags & OnlyForComplex) + std::cout << "@C "; + if(rlist[a].situation_flags & NotForComplex) + std::cout << "@R "; + if(rlist[a].situation_flags & LogicalContextOnly) + std::cout << "@L "; + if(rlist[a].situation_flags & NotForIntegers) + std::cout << "@F "; + if(rlist[a].situation_flags & OnlyForIntegers) + std::cout << "@I "; + FPoptimizer_Grammar::DumpParam<stdcomplex> + ( ParamSpec(SubFunction, (const void*) &tmp) ); + switch(rlist[a].ruletype) + { + case ProduceNewTree: + std::cout << + "\n" + " *\t->\t"; + FPoptimizer_Grammar::DumpParam<stdcomplex>( + ParamSpec_Extract<stdcomplex>(rlist[a].repl_param_list, 0) ); + break; + case ReplaceParams: default: + std::cout << + "\n" + " *\t:\t"; + FPoptimizer_Grammar::DumpParams<stdcomplex> + ( rlist[a].repl_param_list, rlist[a].repl_param_count); + break; + } + std::cout << + "\n" + " */\t\t " + "{" + << (rlist[a].ruletype == ProduceNewTree ? "ProduceNewTree" + :/*rlist[a].ruletype == ReplaceParams ?*/ "ReplaceParams " + ) + << ", " << rlist[a].situation_flags + << ", " << rlist[a].repl_param_count + << "," << collection.ParamListToString(rlist[a].repl_param_list, rlist[a].repl_param_count) + << ", " << collection.SubFunctionDataToString(rlist[a].match_tree) + << "},\n"; + } + std::cout << + " };\n" + << + "\n"; + for(std::map<std::string, Grammar>::const_iterator + i = glist.begin(); i != glist.end(); ++i) + { + std::cout << " struct grammar_" << i->first << "_type\n" + " {\n" + " unsigned c;\n" + " unsigned short l[" << i->second.rule_count << "];\n" + " };\n" + " extern \"C\"\n" + " {\n" + " grammar_" << i->first << "_type grammar_" << i->first << " =\n" + " {\n" + " " << i->second.rule_count << ",\n" + " { "; + for(size_t p=0; p<i->second.rule_count; ++p) + { + std::cout << (unsigned) i->second.rule_list[p]; + if(p+1 == i->second.rule_count) std::cout << "\n"; + else + { + std::cout << ','; + if(p%10 == 9) + std::cout << "\n "; + } + } + std::cout << " } }; }\n"; + } + std::cout << + "}\n"; + } +private: +}; + +static GrammarDumper dumper; + +%} + +%pure-parser + +%union { + /* Note: Because bison's token type is an union or a simple type, + * anything that has constructors and destructors must be + * carried behind pointers here. + */ + GrammarData::Rule* r; + GrammarData::FunctionType* f; + GrammarData::MatchedParams* p; + GrammarData::ParamSpec* a; + + mycomplex num; + unsigned index; + FUNCTIONPARSERTYPES::OPCODE opcode; +} + +/* See documentation about syntax and token meanings in fpoptimizer.dat */ +%token <num> NUMERIC_CONSTANT +%token <index> NAMEDHOLDER_TOKEN +%token <index> RESTHOLDER_TOKEN +%token <index> IMMEDHOLDER_TOKEN +%token <opcode> BUILTIN_FUNC_NAME +%token <opcode> OPCODE_TOKEN +%token <opcode> UNARY_TRANSFORMATION +%token <index> PARAM_CONSTRAINT +%token <index> CONST_CONSTRAINT +%token NEWLINE + +%token SUBST_OP_COLON /* ':' */ +%token SUBST_OP_ARROW /* '->' */ + +%type <r> substitution +%type <f> function function_match +%type <p> paramlist +%type <a> param +%type <index> param_constraints const_constraints rule_constraints + +%% + grammar: + grammar substitution + { + grammar.AddRule(*$2); + delete $2; + } + | grammar rule_constraints substitution + { + $3->SetSituationFlags($2); + grammar.AddRule(*$3); + delete $3; + } + | grammar NEWLINE + | /* empty */ + ; + + rule_constraints: + rule_constraints PARAM_CONSTRAINT + { + // Translate constraint flags to Rule Constraints. + // They were lexed as param constraints, which + // is why they have a different value. + if($2 == Value_Logical) // @L + $$ = $1 | LogicalContextOnly; + else if($2 == Value_NonInteger) // @F + $$ = $1 | NotForIntegers; + else if($2 == Value_IsInteger) // @I + $$ = $1 | OnlyForIntegers; + else if($2 == Constness_Const) + $$ = $1 | OnlyForComplex; + else + { + char msg[] = "Only @L, @F, @I, @C and @R rule constraints are allowed for now"; + yyerror(msg); YYERROR; + } + } + | rule_constraints CONST_CONSTRAINT + { + if($2 == Modulo_Radians) + $$ = $1 | NotForComplex; + else + { + char msg[] = "Only @L, @F, @I, @C and @R rule constraints are allowed for now"; + yyerror(msg); YYERROR; + } + } + | /* empty */ + { + $$ = 0; + } + ; + + substitution: + function_match SUBST_OP_ARROW param NEWLINE + /* Entire function is changed into the particular param */ + { + $3->RecursivelySetDefaultParamMatchingType(); + + $$ = new GrammarData::Rule(ProduceNewTree, *$1, $3); + delete $1; + } + + | function_match SUBST_OP_ARROW function NEWLINE + /* Entire function changes, the param_notinv_list is rewritten */ + /* NOTE: "p x -> o y" is a shortcut for "p x -> (o y)" */ + { + GrammarData::ParamSpec* p = new GrammarData::ParamSpec($3); + p->RecursivelySetDefaultParamMatchingType(); + /*if(!$3->Params.EnsureNoRepeatedNamedHolders()) + { + char msg[] = "The replacement function may not specify the same variable twice"; + yyerror(msg); YYERROR; + }*/ + + $$ = new GrammarData::Rule(ProduceNewTree, *$1, p); + + //std::cout << GrammarDumper().Dump(*new GrammarData::ParamSpec($3)) << "\n"; + delete $1; + } + + | function_match SUBST_OP_COLON paramlist NEWLINE + /* The params provided are replaced with the new param_maybeinv_list */ + { + /*if($1->Params.RestHolderIndex != 0) + { + char msg[] = "Restholder is not valid in the outermost function when ReplaceParams is used"; + yyerror(msg); YYERROR; + }*/ + $3->RecursivelySetDefaultParamMatchingType(); + /*if(!$3->EnsureNoRepeatedNamedHolders()) + { + char msg[] = "The replacement function may not specify the same variable twice"; + yyerror(msg); YYERROR; + }*/ + + $$ = new GrammarData::Rule(ReplaceParams, *$1, *$3); + delete $1; + delete $3; + } + ; + + function_match: + function + { + if(!$1->Params.EnsureNoVariableCoverageParams_InPositionalParamLists()) + { + char msg[] = "Restholders such as <1>, must not occur in bracketed param lists on the matching side"; + yyerror(msg); YYERROR; + } + $$ = $1; + } + ; + + function: + OPCODE_TOKEN '[' paramlist ']' + /* Match a function with opcode=opcode, + * and the exact parameter list as specified + */ + { + $$ = new GrammarData::FunctionType($1, *$3); + delete $3; + } + | OPCODE_TOKEN '{' paramlist '}' + /* Match a function with opcode=opcode, + * and the exact parameter list in any order + */ + { + $$ = new GrammarData::FunctionType($1, *$3->SetType(SelectedParams)); + delete $3; + } + | OPCODE_TOKEN paramlist + /* Match a function with opcode=opcode and the given way of matching params */ + /* There may be more parameters, don't care about them */ + { + $$ = new GrammarData::FunctionType($1, *$2->SetType(AnyParams)); + delete $2; + } + ; + + paramlist: /* left-recursive list of 0-n params with no delimiter */ + paramlist param /* param */ + { + $$ = $1->AddParam($2); + } + | paramlist RESTHOLDER_TOKEN /* a placeholder for all remaining params */ + { + if($1->RestHolderIndex != 0) + { + char msg[] = "Illegal attempt to specify two restholders for the same param list"; + yyerror(msg); YYERROR; + } + $1->RestHolderIndex = $2; + $$ = $1; + } + | /* empty */ + { + $$ = new GrammarData::MatchedParams; + } + ; + + param: + NUMERIC_CONSTANT const_constraints /* particular immed */ + { + $$ = new GrammarData::ParamSpec($1, $2); + } + | IMMEDHOLDER_TOKEN param_constraints /* a placeholder for some immed */ + { + $$ = new GrammarData::ParamSpec($1, GrammarData::ParamSpec::ParamHolderTag()); + $$->SetConstraint($2 | Constness_Const); + } + | BUILTIN_FUNC_NAME '(' paramlist ')' /* literal logarithm/sin/etc. of the provided immed-type params -- also sum/product/minimum/maximum */ + { + /* Verify that $3 consists of constants */ + $$ = new GrammarData::ParamSpec($1, $3->GetParams() ); + if(!$$->VerifyIsConstant()) + { + char msg[] = "Not constant"; + yyerror(msg); YYERROR; + } + delete $3; + } + | NAMEDHOLDER_TOKEN param_constraints /* any expression, indicated by "x", "a" etc. */ + { + $$ = new GrammarData::ParamSpec($1 + 2, GrammarData::ParamSpec::ParamHolderTag()); + $$->SetConstraint($2); + } + | '(' function ')' param_constraints /* a subtree */ + { + $$ = new GrammarData::ParamSpec($2); + $$->SetConstraint($4); + } + | UNARY_TRANSFORMATION param /* the negated/inverted literal value of the param */ + { + /* Verify that $2 is constant */ + if(!$2->VerifyIsConstant()) + { + char msg[] = "Not constant"; + yyerror(msg); YYERROR; + } + std::vector<GrammarData::ParamSpec*> tmp; + tmp.push_back($2); + $$ = new GrammarData::ParamSpec($1, tmp); + } + ; + + param_constraints: /* List of possible constraints to the given param, eg. odd,int,etc */ + param_constraints PARAM_CONSTRAINT + { + $$ = $1 | $2; + } + | /* empty */ + { + $$ = 0; + } + ; + + const_constraints: /* List of possible constraints to the given param */ + const_constraints CONST_CONSTRAINT + { + $$ = $1 | $2; + } + | /* empty */ + { + $$ = 0; + } + ; +%% + +#ifndef FP_SUPPORT_OPTIMIZER +enum { cVar,cFetch,cPopNMov }; +#endif + +static void yyerror(const char* msg) +{ + std::cerr << msg << std::endl; + for(;;) + { + int c = std::fgetc(stdin); + if(c == EOF) break; + std::fputc(c, stderr); + } + exit(1); +} + +static int yylex(YYSTYPE* lval) +{ + int c = std::fgetc(stdin); + switch(c) + { + case EOF: break; + case '#': + while(c != EOF && c != '\n') c = std::fgetc(stdin); + return NEWLINE; + case '\n': + { + c = std::fgetc(stdin); + std::ungetc(c, stdin); + if(c == '[' + || c == '$') + return EOF; + return NEWLINE; + } + case '+': + { + c = std::fgetc(stdin); + std::ungetc(c, stdin); + if(c == '(') { lval->opcode = FUNCTIONPARSERTYPES::cAdd; return BUILTIN_FUNC_NAME; } + return '+'; + } + case '*': + { + c = std::fgetc(stdin); + std::ungetc(c, stdin); + if(c == '(') { lval->opcode = FUNCTIONPARSERTYPES::cMul; return BUILTIN_FUNC_NAME; } + return '*'; + } + case '-': + { + int c2 = std::fgetc(stdin); + if(c2 == '>') return SUBST_OP_ARROW; + std::ungetc(c2, stdin); + if(c2 >= '0' && c2 <= '9') + { + goto GotNumeric; + } + lval->opcode = FUNCTIONPARSERTYPES::cNeg; + return UNARY_TRANSFORMATION; + } + case '/': + lval->opcode = FUNCTIONPARSERTYPES::cInv; + return UNARY_TRANSFORMATION; + + case '=': + { + int c2 = std::fgetc(stdin); + std::ungetc(c2, stdin); + return '='; + } + case '[': case '{': + case ']': case '}': + case '(': + case ')': + return c; + case ' ': + case '\t': + case '\v': + case '\r': + return yylex(lval); // Counts as tail recursion, I hope + case ':': + return SUBST_OP_COLON; + case '%': { lval->index = 0; return IMMEDHOLDER_TOKEN; } + case '&': { lval->index = 1; return IMMEDHOLDER_TOKEN; } + + case '@': + { + int c2 = std::fgetc(stdin); + switch(c2) + { + case 'E': { lval->index = Value_EvenInt; return PARAM_CONSTRAINT; } + case 'O': { lval->index = Value_OddInt; return PARAM_CONSTRAINT; } + case 'I': { lval->index = Value_IsInteger; return PARAM_CONSTRAINT; } + case 'F': { lval->index = Value_NonInteger; return PARAM_CONSTRAINT; } + case 'L': { lval->index = Value_Logical; return PARAM_CONSTRAINT; } + case 'P': { lval->index = Sign_Positive; return PARAM_CONSTRAINT; } + case 'N': { lval->index = Sign_Negative; return PARAM_CONSTRAINT; } + case 'Q': { lval->index = Sign_NoIdea; return PARAM_CONSTRAINT; } + case '1': { lval->index = Oneness_One; return PARAM_CONSTRAINT; } + case 'M': { lval->index = Oneness_NotOne; return PARAM_CONSTRAINT; } + case 'C': { lval->index = Constness_Const; return PARAM_CONSTRAINT; } + case 'V': { lval->index = Constness_NotConst; return PARAM_CONSTRAINT; } + case 'R': { lval->index = Modulo_Radians; return CONST_CONSTRAINT; } + } + std::ungetc(c2, stdin); + return '@'; + } + case '<': + { + lval->index = 0; + for(;;) + { + c = std::fgetc(stdin); + if(c < '0' || c > '9') { std::ungetc(c, stdin); break; } + lval->index = lval->index * 10 + (c-'0'); + } + c = std::fgetc(stdin); + if(c != '>') std::ungetc(c, stdin); + return RESTHOLDER_TOKEN; + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + GotNumeric:; + std::string NumBuf; + NumBuf += (char)c; + bool had_comma = false; + for(;;) + { + c = std::fgetc(stdin); + if(c >= '0' && c <= '9') { NumBuf += (char)c; continue; } + if(c == '.' && !had_comma){ had_comma = true; NumBuf += (char)c; continue; } + std::ungetc(c, stdin); + break; + } + lval->num.real = std::strtod(NumBuf.c_str(), 0); + lval->num.imag = 0.0; + if(c == 'i') + { + std::fgetc(stdin); + lval->num.imag = lval->num.real; + lval->num.real = 0.0; + } + else if(c == '-' || c == '+') + { + NumBuf.clear(); + NumBuf += (char)c; + bool had_comma = false; + for(;;) + { + c = std::fgetc(stdin); + if(c >= '0' && c <= '9') { NumBuf += (char)c; continue; } + if(c == '.' && !had_comma){ had_comma = true; NumBuf += (char)c; continue; } + std::ungetc(c, stdin); + break; + } + if(c == 'i') + { + lval->num.imag = std::strtod(NumBuf.c_str(), 0); + std::fgetc(stdin); + } + } + return NUMERIC_CONSTANT; + } + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': + case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': + case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': + case 'Y': case 'Z': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': + case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': + case 's': case 't': case 'u': case 'v': case 'w': case 'x': + case 'y': case 'z': + { + std::string IdBuf; + IdBuf += (char)c; + for(;;) + { + c = std::fgetc(stdin); + if((c >= '0' && c <= '9') + || c == '_' + || (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z')) { IdBuf += (char)c; continue; } + std::ungetc(c, stdin); + break; + } + lval->num.real = 0; + lval->num.imag = 0; + + /* This code figures out if this is a named constant, + an opcode, or a parse-time function name, + or just an identifier + */ + + /* Detect named constants */ + if(IdBuf == "i") { lval->num.imag = 1.0; return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_E") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_e<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_EI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_einv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_2E") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twoe<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_2EI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twoeinv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_RD") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_rad_to_deg<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_DR") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_deg_to_rad<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_PI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_pi<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_PIHALF") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_pihalf<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_TWOPI") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_twopi<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L2I") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log2inv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L10I") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log10inv<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L2") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log2<double>(); return NUMERIC_CONSTANT; } + if(IdBuf == "CONSTANT_L10") { lval->num.real = FUNCTIONPARSERTYPES::fp_const_log10<double>(); return NUMERIC_CONSTANT; } + + /* Detect opcodes */ + if(IdBuf == "cAdd") { lval->opcode = FUNCTIONPARSERTYPES::cAdd; return OPCODE_TOKEN; } + if(IdBuf == "cAnd") { lval->opcode = FUNCTIONPARSERTYPES::cAnd; return OPCODE_TOKEN; } + if(IdBuf == "cMul") { lval->opcode = FUNCTIONPARSERTYPES::cMul; return OPCODE_TOKEN; } + if(IdBuf == "cOr") { lval->opcode = FUNCTIONPARSERTYPES::cOr; return OPCODE_TOKEN; } + + if(IdBuf == "cNeg") { lval->opcode = FUNCTIONPARSERTYPES::cNeg; return OPCODE_TOKEN; } + if(IdBuf == "cSub") { lval->opcode = FUNCTIONPARSERTYPES::cSub; return OPCODE_TOKEN; } + if(IdBuf == "cDiv") { lval->opcode = FUNCTIONPARSERTYPES::cDiv; return OPCODE_TOKEN; } + if(IdBuf == "cMod") { lval->opcode = FUNCTIONPARSERTYPES::cMod; return OPCODE_TOKEN; } + if(IdBuf == "cEqual") { lval->opcode = FUNCTIONPARSERTYPES::cEqual; return OPCODE_TOKEN; } + if(IdBuf == "cNEqual") { lval->opcode = FUNCTIONPARSERTYPES::cNEqual; return OPCODE_TOKEN; } + if(IdBuf == "cLess") { lval->opcode = FUNCTIONPARSERTYPES::cLess; return OPCODE_TOKEN; } + if(IdBuf == "cLessOrEq") { lval->opcode = FUNCTIONPARSERTYPES::cLessOrEq; return OPCODE_TOKEN; } + if(IdBuf == "cGreater") { lval->opcode = FUNCTIONPARSERTYPES::cGreater; return OPCODE_TOKEN; } + if(IdBuf == "cGreaterOrEq") { lval->opcode = FUNCTIONPARSERTYPES::cGreaterOrEq; return OPCODE_TOKEN; } + if(IdBuf == "cNot") { lval->opcode = FUNCTIONPARSERTYPES::cNot; return OPCODE_TOKEN; } + if(IdBuf == "cNotNot") { lval->opcode = FUNCTIONPARSERTYPES::cNotNot; return OPCODE_TOKEN; } + if(IdBuf == "cAbsNot") { lval->opcode = FUNCTIONPARSERTYPES::cAbsNot; return OPCODE_TOKEN; } + if(IdBuf == "cAbsNotNot") { lval->opcode = FUNCTIONPARSERTYPES::cAbsNotNot; return OPCODE_TOKEN; } + if(IdBuf == "cAbsAnd") { lval->opcode = FUNCTIONPARSERTYPES::cAbsAnd; return OPCODE_TOKEN; } + if(IdBuf == "cAbsOr") { lval->opcode = FUNCTIONPARSERTYPES::cAbsOr; return OPCODE_TOKEN; } + if(IdBuf == "cAbsIf") { lval->opcode = FUNCTIONPARSERTYPES::cAbsIf; return OPCODE_TOKEN; } + if(IdBuf == "cDeg") { lval->opcode = FUNCTIONPARSERTYPES::cDeg; return OPCODE_TOKEN; } + if(IdBuf == "cRad") { lval->opcode = FUNCTIONPARSERTYPES::cRad; return OPCODE_TOKEN; } + if(IdBuf == "cInv") { lval->opcode = FUNCTIONPARSERTYPES::cInv; return OPCODE_TOKEN; } + if(IdBuf == "cSqr") { lval->opcode = FUNCTIONPARSERTYPES::cSqr; return OPCODE_TOKEN; } + if(IdBuf == "cRDiv") { lval->opcode = FUNCTIONPARSERTYPES::cRDiv; return OPCODE_TOKEN; } + if(IdBuf == "cRSub") { lval->opcode = FUNCTIONPARSERTYPES::cRSub; return OPCODE_TOKEN; } + if(IdBuf == "cRSqrt") { lval->opcode = FUNCTIONPARSERTYPES::cRSqrt; return OPCODE_TOKEN; } +#ifdef FP_SUPPORT_OPTIMIZER + if(IdBuf == "cLog2by") { lval->opcode = FUNCTIONPARSERTYPES::cLog2by; return OPCODE_TOKEN; } +#else + if(IdBuf == "cLog2by") { lval->opcode = FUNCTIONPARSERTYPES::cNop; return OPCODE_TOKEN; } +#endif + + /* Detect other function opcodes */ + if(IdBuf[0] == 'c' && std::isupper(IdBuf[1])) + { + // This has a chance of being an opcode token + std::string opcodetoken = IdBuf.substr(1); + opcodetoken[0] = (char) std::tolower( opcodetoken[0] ); + + unsigned nameLength = readOpcode(opcodetoken.c_str()); + if(nameLength & 0x80000000U) + { + lval->opcode = FUNCTIONPARSERTYPES::OPCODE( + (nameLength >> 16) & 0x7FFF ); + return OPCODE_TOKEN; + } + std::cerr << + "Warning: Unrecognized opcode '" << IdBuf << "' interpreted as cNop\n"; + lval->opcode = FUNCTIONPARSERTYPES::cNop; + return OPCODE_TOKEN; + } + + // If it is typed entirely in capitals, it has a chance of being + // a group token + if(true) + { + std::string grouptoken = IdBuf; + for(size_t a=0; a<grouptoken.size(); ++a) + { + if(std::islower(grouptoken[a])) goto NotAGroupToken; + grouptoken[a] = (char) std::tolower(grouptoken[a]); + } + if(1) // scope + { + unsigned nameLength = readOpcode(grouptoken.c_str()); + if(nameLength & 0x80000000U) + { + lval->opcode = FUNCTIONPARSERTYPES::OPCODE( + (nameLength >> 16) & 0x7FFF ); + return BUILTIN_FUNC_NAME; + } + if(IdBuf == "MOD") + { + lval->opcode = FUNCTIONPARSERTYPES::cMod; + return BUILTIN_FUNC_NAME; + } + if(IdBuf == "DIV") + { + lval->opcode = FUNCTIONPARSERTYPES::cDiv; + return BUILTIN_FUNC_NAME; + } + if(IdBuf == "SUB") + { + lval->opcode = FUNCTIONPARSERTYPES::cSub; + return BUILTIN_FUNC_NAME; + } + + std::cerr << "Warning: Unrecognized constant function '" << IdBuf + << "' interpreted as cNop\n"; + lval->opcode = FUNCTIONPARSERTYPES::cNop; + return BUILTIN_FUNC_NAME; + } + NotAGroupToken:; + } + // Anything else is an identifier + lval->index = dumper.ConvertNamedHolderNameIntoIndex(IdBuf); + // std::cerr << "'" << IdBuf << "'' interpreted as PARAM\n"; + + return NAMEDHOLDER_TOKEN; + } + default: + { + std::cerr << "Ignoring unidentifier character '" << char(c) << "'\n"; + return yylex(lval); // tail recursion + } + } + return EOF; +} + +unsigned GrammarData::ParamSpec::BuildDepMask() +{ + DepMask = 0; + switch(Opcode) + { + case ParamHolder: + DepMask |= 1 << Index; + break; + case SubFunction: + DepMask = Func->Params.BuildDepMask(); + break; + default: break; + } + return DepMask; +} + +namespace FPoptimizer_Grammar +{ + template<typename Value_t> + ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index) + { + unsigned plist_index = (paramlist >> (index*PARAM_INDEX_BITS)) + % (1 << PARAM_INDEX_BITS); + return plist[plist_index]; + } + template ParamSpec ParamSpec_Extract<stdcomplex>(unsigned paramlist, unsigned index); +} + +int main() +{ + std::map<std::string, GrammarData::Grammar> sections; + + std::string sectionname; + + for(;;) + { + grammar = GrammarData::Grammar(); + + yyparse(); + + grammar.BuildFinalDepMask(); + sections[sectionname] = grammar; + + int c = std::fgetc(stdin); + if(c != '[') + { + std::ungetc(c, stdin); + break; + } + + sectionname.clear(); + for(;;) + { + c = std::fgetc(stdin); + if(c == ']' || c == EOF) break; + sectionname += (char)c; + } + std::cerr << "Parsing [" << sectionname << "]\n"; + } + + std::map<std::string, std::vector<std::string> > grammar_components; + sectionname = ""; + for(;;) + { + int c = std::fgetc(stdin); + if(c == ' ' || c == '\t' || c == '\r' || c == '\n') continue; + if(c == '#') + { do { c = std::fgetc(stdin); } while(!(c == '\n' || c == EOF)); + continue; } + if(c == '$') + { + sectionname = ""; + for(;;) + { + c = std::fgetc(stdin); + if(c == EOF) break; + if(c == ' ' || c == '\t' || c == '\r' || c == '\n') break; + if(c == ':') break; + sectionname += char(c); + } + std::cerr << "Parsing $" << sectionname << "\n"; + continue; + } + if((c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9')) + { + std::string componentname; + for(;;) + { + if(c == EOF) break; + if(c == ' ' || c == '\t' || c == '\r' || c == '\n') break; + componentname += char(c); + c = std::fgetc(stdin); + } + std::cerr << "- Has [" << componentname << "]\n"; + grammar_components[sectionname].push_back(componentname); + //dumper.AddRulesFrom(sections[componentname]); + } + else break; + } + + std::cout << + "/* This file is automatically generated. Do not edit... */\n" + "#include \"../fpoptimizer/consts.hh\"\n" + "#include \"fpconfig.hh\"\n" + "#include \"extrasrc/fptypes.hh\"\n" + "#include <algorithm>\n" + "\n"; + + std::vector<GrammarData::Grammar> components; + for(std::map<std::string, std::vector<std::string> >::const_iterator + i = grammar_components.begin(); + i != grammar_components.end(); + ++i) + { + for(size_t a=0; a<i->second.size(); ++a) + components.push_back(sections[ i->second[a] ]); + } + dumper.RegisterGrammar(components); + + for(std::map<std::string, std::vector<std::string> >::const_iterator + i = grammar_components.begin(); + i != grammar_components.end(); + ++i) + { + components.clear(); + for(size_t a=0; a<i->second.size(); ++a) + components.push_back(sections[ i->second[a] ]); + dumper.DumpGrammar(i->first, components); + } + dumper.Flush(); + + unsigned mask = (1 << PARAM_INDEX_BITS)-1; + const unsigned p_begin = 0; + const unsigned n_begin = p_begin + dumper.collection.plist_p.size(); + const unsigned s_begin = n_begin + dumper.collection.plist_n.size(); + std::cout << + "namespace FPoptimizer_Grammar\n" + "{\n" + " template<typename Value_t>\n" + " ParamSpec ParamSpec_Extract(unsigned paramlist, unsigned index)\n" + " {\n" + " index = (paramlist >> (index * " << PARAM_INDEX_BITS << ")) & " << mask << " /* % (1 << " << PARAM_INDEX_BITS << ") */;\n" + " if(index >= " << s_begin << ")\n" + " return ParamSpec(SubFunction,(const void*)&plist_s[index-" << s_begin << "]);\n" + " if(index >= " << n_begin << ")\n" + " return ParamSpec(NumConstant,(const void*)&plist_n_container<Value_t>::plist_n[index-" << n_begin << "]);\n" + " return ParamSpec(ParamHolder,(const void*)&plist_p[index"/*"-" << p_begin << */"]);\n" + " }\n" + "}\n" + "/* BEGIN_EXPLICIT_INSTANTATION */\n" + "#include \"instantiate.hh\"\n" + "namespace FPoptimizer_Grammar\n" + "{\n" + "#define FP_INSTANTIATE(type) \\\n" + " template ParamSpec ParamSpec_Extract<type>(unsigned paramlist, unsigned index);\n" + " FPOPTIMIZER_EXPLICITLY_INSTANTIATE(FP_INSTANTIATE)\n" + "#undef FP_INSTANTIATE\n" + "}\n" + "/* END_EXPLICIT_INSTANTATION */\n"; + + return 0; +} diff --git a/util/version_changer.cc b/util/version_changer.cc new file mode 100644 index 0000000..fbf8a7b --- /dev/null +++ b/util/version_changer.cc @@ -0,0 +1,52 @@ +#include <iostream> +#include <fstream> +#include <string> +#include <cstdio> +#include <cstring> + +namespace +{ + const std::string versionString = "Function Parser for C++ v"; +} + +void writeVersion(std::fstream& is, const std::string& version) +{ + std::string line; + while(std::getline(is, line)) + { + const size_t ind = line.find(versionString); + if(ind != line.npos) + { + is.seekp(size_t(is.tellg()) - line.length() + + ind + versionString.length() - 1); + is.write(version.c_str(), version.length()); + is.seekg(is.tellp()); + } + } +} + +int main(int argc, char* argv[]) +{ + if(argc < 3) + { + std::cerr << "Usage: " << argv[0] << " <version string> <files>\n"; + return 1; + } + + std::string version(argv[1]); + if(version.length() < 6) version.resize(6, ' '); + + for(int i = 2; i < argc; ++i) + { + std::fstream is(argv[i]); + if(!is) + { + std::perror(argv[i]); + return 1; + } + + writeVersion(is, version); + } + + return 0; +} |