summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2018-08-25 21:08:35 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2018-08-25 21:08:35 +0200
commit8f8b19149d0136d58f0ebc6928fe7cbd376ef8bc (patch)
tree587ac9c23581f81a9bc8e21a7ba8019fa0c4c696
Import fparserc++_4.5.2.orig.tar.gz
[dgit import orig fparserc++_4.5.2.orig.tar.gz]
-rw-r--r--Makefile403
-rw-r--r--docs/fparser.html1841
-rw-r--r--docs/gpl.txt674
-rw-r--r--docs/lgpl.txt165
-rw-r--r--docs/style.css80
-rw-r--r--examples/example.cc55
-rw-r--r--examples/example2.cc85
-rw-r--r--extrasrc/fp_identifier_parser.inc379
-rw-r--r--extrasrc/fp_opcode_add.inc7696
-rw-r--r--extrasrc/fpaux.hh1249
-rw-r--r--extrasrc/fptypes.hh286
-rw-r--r--fparser.cc3800
-rw-r--r--fparser.hh223
-rw-r--r--fparser_gmpint.hh15
-rw-r--r--fparser_mpfr.hh15
-rw-r--r--fpconfig.hh88
-rw-r--r--fpoptimizer/bytecodesynth.cc638
-rw-r--r--fpoptimizer/bytecodesynth.hh323
-rw-r--r--fpoptimizer/codetree.cc456
-rw-r--r--fpoptimizer/codetree.hh242
-rw-r--r--fpoptimizer/constantfolding.cc941
-rw-r--r--fpoptimizer/constantfolding.hh12
-rw-r--r--fpoptimizer/consts.hh52
-rw-r--r--fpoptimizer/cse.cc501
-rw-r--r--fpoptimizer/debug.cc153
-rw-r--r--fpoptimizer/explicit_instantations.txt37
-rw-r--r--fpoptimizer/fpoptimizer.txt357
-rw-r--r--fpoptimizer/fpoptimizer_footer.txt2
-rw-r--r--fpoptimizer/fpoptimizer_header.txt24
-rw-r--r--fpoptimizer/grammar.cc154
-rw-r--r--fpoptimizer/grammar.hh254
-rw-r--r--fpoptimizer/grammar_data.cc1597
-rw-r--r--fpoptimizer/hash.cc254
-rw-r--r--fpoptimizer/hash.hh38
-rw-r--r--fpoptimizer/instantiate.hh39
-rw-r--r--fpoptimizer/logic_boolgroups.hh382
-rw-r--r--fpoptimizer/logic_collections.hh712
-rw-r--r--fpoptimizer/logic_comparisons.hh282
-rw-r--r--fpoptimizer/logic_ifoperations.hh381
-rw-r--r--fpoptimizer/logic_powoperations.hh222
-rw-r--r--fpoptimizer/makebytecode.cc484
-rw-r--r--fpoptimizer/opcodename.cc143
-rw-r--r--fpoptimizer/opcodename.hh5
-rw-r--r--fpoptimizer/optimize.cc448
-rw-r--r--fpoptimizer/optimize.hh215
-rw-r--r--fpoptimizer/optimize_debug.cc95
-rw-r--r--fpoptimizer/optimize_main.cc100
-rw-r--r--fpoptimizer/optimize_match.cc766
-rw-r--r--fpoptimizer/optimize_synth.cc139
-rw-r--r--fpoptimizer/rangeestimation.cc956
-rw-r--r--fpoptimizer/rangeestimation.hh53
-rw-r--r--fpoptimizer/readbytecode.cc767
-rw-r--r--fpoptimizer/transformations.cc970
-rw-r--r--fpoptimizer/treerules.dat1005
-rw-r--r--fpoptimizer/valuerange.cc94
-rw-r--r--fpoptimizer/valuerange.hh142
-rw-r--r--lib/autoptr.hh66
-rw-r--r--lib/crc32.hh56
-rw-r--r--lib/functional.hh32
-rw-r--r--mpfr/GmpInt.cc710
-rw-r--r--mpfr/GmpInt.hh148
-rw-r--r--mpfr/MpfrFloat.cc976
-rw-r--r--mpfr/MpfrFloat.hh206
-rwxr-xr-xrun_full_release_testing.sh32
-rw-r--r--testbed.cc3102
-rw-r--r--testbed_tests.inc11667
-rw-r--r--tests/01unit_operators/add_cd5
-rw-r--r--tests/01unit_operators/add_d5
-rw-r--r--tests/01unit_operators/add_i5
-rw-r--r--tests/01unit_operators/addsub_cd5
-rw-r--r--tests/01unit_operators/addsub_d5
-rw-r--r--tests/01unit_operators/addsub_i5
-rw-r--r--tests/01unit_operators/and_d6
-rw-r--r--tests/01unit_operators/and_i5
-rw-r--r--tests/01unit_operators/cmpeq_cd5
-rw-r--r--tests/01unit_operators/cmpeq_d5
-rw-r--r--tests/01unit_operators/cmpeq_i5
-rw-r--r--tests/01unit_operators/cmpge_d5
-rw-r--r--tests/01unit_operators/cmpge_i5
-rw-r--r--tests/01unit_operators/cmpgt_d5
-rw-r--r--tests/01unit_operators/cmpgt_i5
-rw-r--r--tests/01unit_operators/cmple_d5
-rw-r--r--tests/01unit_operators/cmple_i5
-rw-r--r--tests/01unit_operators/cmplt_d5
-rw-r--r--tests/01unit_operators/cmplt_i5
-rw-r--r--tests/01unit_operators/cmpne_cd5
-rw-r--r--tests/01unit_operators/cmpne_d5
-rw-r--r--tests/01unit_operators/cmpne_i5
-rw-r--r--tests/01unit_operators/div_d5
-rw-r--r--tests/01unit_operators/div_i5
-rw-r--r--tests/01unit_operators/divmul_d5
-rw-r--r--tests/01unit_operators/divmul_i5
-rw-r--r--tests/01unit_operators/inv_d5
-rw-r--r--tests/01unit_operators/inv_i5
-rw-r--r--tests/01unit_operators/mod5
-rw-r--r--tests/01unit_operators/mod_i5
-rw-r--r--tests/01unit_operators/modf5
-rw-r--r--tests/01unit_operators/modl5
-rw-r--r--tests/01unit_operators/modm5
-rw-r--r--tests/01unit_operators/mul_cd5
-rw-r--r--tests/01unit_operators/mul_d5
-rw-r--r--tests/01unit_operators/mul_i5
-rw-r--r--tests/01unit_operators/neg_cd5
-rw-r--r--tests/01unit_operators/neg_d5
-rw-r--r--tests/01unit_operators/neg_i5
-rw-r--r--tests/01unit_operators/not_d5
-rw-r--r--tests/01unit_operators/not_i5
-rw-r--r--tests/01unit_operators/notnot_d5
-rw-r--r--tests/01unit_operators/notnot_i5
-rw-r--r--tests/01unit_operators/or_d5
-rw-r--r--tests/01unit_operators/or_i5
-rw-r--r--tests/01unit_operators/sub_cd5
-rw-r--r--tests/01unit_operators/sub_d5
-rw-r--r--tests/01unit_operators/sub_i5
-rw-r--r--tests/02unit_functions/abs_cd5
-rw-r--r--tests/02unit_functions/abs_d5
-rw-r--r--tests/02unit_functions/abs_i5
-rw-r--r--tests/02unit_functions/acos5
-rw-r--r--tests/02unit_functions/acos_deg6
-rw-r--r--tests/02unit_functions/acosf5
-rw-r--r--tests/02unit_functions/acosf_deg6
-rw-r--r--tests/02unit_functions/acosh5
-rw-r--r--tests/02unit_functions/acosh_deg6
-rw-r--r--tests/02unit_functions/acoshf5
-rw-r--r--tests/02unit_functions/acoshf_deg6
-rw-r--r--tests/02unit_functions/acoshl5
-rw-r--r--tests/02unit_functions/acoshl_deg6
-rw-r--r--tests/02unit_functions/acoshm5
-rw-r--r--tests/02unit_functions/acoshm_deg6
-rw-r--r--tests/02unit_functions/acosl5
-rw-r--r--tests/02unit_functions/acosl_deg6
-rw-r--r--tests/02unit_functions/acosm5
-rw-r--r--tests/02unit_functions/acosm_deg6
-rw-r--r--tests/02unit_functions/arg5
-rw-r--r--tests/02unit_functions/asin5
-rw-r--r--tests/02unit_functions/asin_deg6
-rw-r--r--tests/02unit_functions/asinf5
-rw-r--r--tests/02unit_functions/asinf_deg6
-rw-r--r--tests/02unit_functions/asinh5
-rw-r--r--tests/02unit_functions/asinh_deg6
-rw-r--r--tests/02unit_functions/asinhf5
-rw-r--r--tests/02unit_functions/asinhf_deg6
-rw-r--r--tests/02unit_functions/asinhl5
-rw-r--r--tests/02unit_functions/asinhl_deg6
-rw-r--r--tests/02unit_functions/asinhm5
-rw-r--r--tests/02unit_functions/asinhm_deg6
-rw-r--r--tests/02unit_functions/asinl5
-rw-r--r--tests/02unit_functions/asinl_deg6
-rw-r--r--tests/02unit_functions/asinm5
-rw-r--r--tests/02unit_functions/asinm_deg6
-rw-r--r--tests/02unit_functions/atan5
-rw-r--r--tests/02unit_functions/atan25
-rw-r--r--tests/02unit_functions/atan2_deg6
-rw-r--r--tests/02unit_functions/atan2f5
-rw-r--r--tests/02unit_functions/atan2f_deg6
-rw-r--r--tests/02unit_functions/atan2l5
-rw-r--r--tests/02unit_functions/atan2l_deg6
-rw-r--r--tests/02unit_functions/atan2m5
-rw-r--r--tests/02unit_functions/atan2m_deg6
-rw-r--r--tests/02unit_functions/atan_deg6
-rw-r--r--tests/02unit_functions/atanf5
-rw-r--r--tests/02unit_functions/atanf_deg6
-rw-r--r--tests/02unit_functions/atanh5
-rw-r--r--tests/02unit_functions/atanhf5
-rw-r--r--tests/02unit_functions/atanhl5
-rw-r--r--tests/02unit_functions/atanhm5
-rw-r--r--tests/02unit_functions/atanl5
-rw-r--r--tests/02unit_functions/atanl_deg6
-rw-r--r--tests/02unit_functions/atanm5
-rw-r--r--tests/02unit_functions/atanm_deg6
-rw-r--r--tests/02unit_functions/cbrt5
-rw-r--r--tests/02unit_functions/cbrtf5
-rw-r--r--tests/02unit_functions/cbrtl5
-rw-r--r--tests/02unit_functions/cbrtm5
-rw-r--r--tests/02unit_functions/ceil5
-rw-r--r--tests/02unit_functions/ceilf5
-rw-r--r--tests/02unit_functions/ceill5
-rw-r--r--tests/02unit_functions/ceilm5
-rw-r--r--tests/02unit_functions/conj5
-rw-r--r--tests/02unit_functions/cos5
-rw-r--r--tests/02unit_functions/cos_cd5
-rw-r--r--tests/02unit_functions/cos_cf5
-rw-r--r--tests/02unit_functions/cos_deg6
-rw-r--r--tests/02unit_functions/cosf5
-rw-r--r--tests/02unit_functions/cosf_deg6
-rw-r--r--tests/02unit_functions/cosh5
-rw-r--r--tests/02unit_functions/cosh_deg6
-rw-r--r--tests/02unit_functions/coshf5
-rw-r--r--tests/02unit_functions/coshf_deg6
-rw-r--r--tests/02unit_functions/coshl5
-rw-r--r--tests/02unit_functions/coshl_deg6
-rw-r--r--tests/02unit_functions/coshm5
-rw-r--r--tests/02unit_functions/coshm_deg6
-rw-r--r--tests/02unit_functions/cosl5
-rw-r--r--tests/02unit_functions/cosl_deg6
-rw-r--r--tests/02unit_functions/cosm5
-rw-r--r--tests/02unit_functions/cosm_deg6
-rw-r--r--tests/02unit_functions/exp5
-rw-r--r--tests/02unit_functions/exp25
-rw-r--r--tests/02unit_functions/exp2f5
-rw-r--r--tests/02unit_functions/exp2l5
-rw-r--r--tests/02unit_functions/exp2m5
-rw-r--r--tests/02unit_functions/expf5
-rw-r--r--tests/02unit_functions/expl5
-rw-r--r--tests/02unit_functions/expm5
-rw-r--r--tests/02unit_functions/floor5
-rw-r--r--tests/02unit_functions/floorf5
-rw-r--r--tests/02unit_functions/floorl5
-rw-r--r--tests/02unit_functions/floorm5
-rw-r--r--tests/02unit_functions/hypot5
-rw-r--r--tests/02unit_functions/hypotf5
-rw-r--r--tests/02unit_functions/hypotl5
-rw-r--r--tests/02unit_functions/hypotm5
-rw-r--r--tests/02unit_functions/if_d5
-rw-r--r--tests/02unit_functions/if_i5
-rw-r--r--tests/02unit_functions/imag5
-rw-r--r--tests/02unit_functions/int5
-rw-r--r--tests/02unit_functions/log5
-rw-r--r--tests/02unit_functions/log105
-rw-r--r--tests/02unit_functions/log10f5
-rw-r--r--tests/02unit_functions/log10l5
-rw-r--r--tests/02unit_functions/log10m5
-rw-r--r--tests/02unit_functions/log25
-rw-r--r--tests/02unit_functions/log2f5
-rw-r--r--tests/02unit_functions/log2l5
-rw-r--r--tests/02unit_functions/log2m5
-rw-r--r--tests/02unit_functions/log_cd5
-rw-r--r--tests/02unit_functions/logf5
-rw-r--r--tests/02unit_functions/logl5
-rw-r--r--tests/02unit_functions/logm5
-rw-r--r--tests/02unit_functions/max5
-rw-r--r--tests/02unit_functions/min5
-rw-r--r--tests/02unit_functions/polar5
-rw-r--r--tests/02unit_functions/pow_neg5
-rw-r--r--tests/02unit_functions/pow_negf5
-rw-r--r--tests/02unit_functions/pow_negl5
-rw-r--r--tests/02unit_functions/pow_negm5
-rw-r--r--tests/02unit_functions/pow_pos5
-rw-r--r--tests/02unit_functions/pow_posf5
-rw-r--r--tests/02unit_functions/pow_posl5
-rw-r--r--tests/02unit_functions/pow_posm5
-rw-r--r--tests/02unit_functions/real5
-rw-r--r--tests/02unit_functions/sin5
-rw-r--r--tests/02unit_functions/sin_cd5
-rw-r--r--tests/02unit_functions/sin_cf5
-rw-r--r--tests/02unit_functions/sin_deg6
-rw-r--r--tests/02unit_functions/sinf5
-rw-r--r--tests/02unit_functions/sinf_deg6
-rw-r--r--tests/02unit_functions/sinh5
-rw-r--r--tests/02unit_functions/sinh_deg6
-rw-r--r--tests/02unit_functions/sinhf5
-rw-r--r--tests/02unit_functions/sinhf_deg6
-rw-r--r--tests/02unit_functions/sinhl5
-rw-r--r--tests/02unit_functions/sinhl_deg6
-rw-r--r--tests/02unit_functions/sinhm5
-rw-r--r--tests/02unit_functions/sinhm_deg6
-rw-r--r--tests/02unit_functions/sinl5
-rw-r--r--tests/02unit_functions/sinl_deg6
-rw-r--r--tests/02unit_functions/sinm5
-rw-r--r--tests/02unit_functions/sinm_deg6
-rw-r--r--tests/02unit_functions/sqrt5
-rw-r--r--tests/02unit_functions/sqrt_cd5
-rw-r--r--tests/02unit_functions/sqrtf5
-rw-r--r--tests/02unit_functions/sqrtl5
-rw-r--r--tests/02unit_functions/sqrtm5
-rw-r--r--tests/02unit_functions/tan5
-rw-r--r--tests/02unit_functions/tan_deg6
-rw-r--r--tests/02unit_functions/tanf5
-rw-r--r--tests/02unit_functions/tanf_deg6
-rw-r--r--tests/02unit_functions/tanh5
-rw-r--r--tests/02unit_functions/tanh_deg6
-rw-r--r--tests/02unit_functions/tanhf5
-rw-r--r--tests/02unit_functions/tanhf_deg6
-rw-r--r--tests/02unit_functions/tanhl5
-rw-r--r--tests/02unit_functions/tanhl_deg6
-rw-r--r--tests/02unit_functions/tanhm5
-rw-r--r--tests/02unit_functions/tanhm_deg6
-rw-r--r--tests/02unit_functions/tanl5
-rw-r--r--tests/02unit_functions/tanl_deg6
-rw-r--r--tests/02unit_functions/tanm5
-rw-r--r--tests/02unit_functions/tanm_deg6
-rw-r--r--tests/02unit_functions/trunc5
-rw-r--r--tests/02unit_functions/truncf5
-rw-r--r--tests/02unit_functions/truncl5
-rw-r--r--tests/02unit_functions/truncm5
-rw-r--r--tests/03unit_constants/e_d5
-rw-r--r--tests/03unit_constants/e_f5
-rw-r--r--tests/03unit_constants/e_ld5
-rw-r--r--tests/03unit_constants/e_mpfr5
-rw-r--r--tests/03unit_constants/l10_d5
-rw-r--r--tests/03unit_constants/l10_f5
-rw-r--r--tests/03unit_constants/l10_ld5
-rw-r--r--tests/03unit_constants/l10_mpfr5
-rw-r--r--tests/03unit_constants/l2_d5
-rw-r--r--tests/03unit_constants/l2_f5
-rw-r--r--tests/03unit_constants/l2_ld5
-rw-r--r--tests/03unit_constants/l2_mpfr5
-rw-r--r--tests/03unit_constants/pi_d5
-rw-r--r--tests/03unit_constants/pi_f5
-rw-r--r--tests/03unit_constants/pi_ld5
-rw-r--r--tests/03unit_constants/pi_mpfr5
-rw-r--r--tests/10optimizer_bytecode/abs5
-rw-r--r--tests/10optimizer_bytecode/abscos5
-rw-r--r--tests/10optimizer_bytecode/abscosh5
-rw-r--r--tests/10optimizer_bytecode/abseq05
-rw-r--r--tests/10optimizer_bytecode/absevenconstpow5
-rw-r--r--tests/10optimizer_bytecode/absmulevenconstpow5
-rw-r--r--tests/10optimizer_bytecode/absneq05
-rw-r--r--tests/10optimizer_bytecode/absneverneg5
-rw-r--r--tests/10optimizer_bytecode/absnot5
-rw-r--r--tests/10optimizer_bytecode/absnot25
-rw-r--r--tests/10optimizer_bytecode/absnot35
-rw-r--r--tests/10optimizer_bytecode/absnot45
-rw-r--r--tests/10optimizer_bytecode/absnotnotnot5
-rw-r--r--tests/10optimizer_bytecode/absnzge5
-rw-r--r--tests/10optimizer_bytecode/absnzlt5
-rw-r--r--tests/10optimizer_bytecode/abssqr5
-rw-r--r--tests/10optimizer_bytecode/absyxpow_neg6
-rw-r--r--tests/10optimizer_bytecode/absyxpow_pos6
-rw-r--r--tests/10optimizer_bytecode/acos5
-rw-r--r--tests/10optimizer_bytecode/acos_deg6
-rw-r--r--tests/10optimizer_bytecode/acosf5
-rw-r--r--tests/10optimizer_bytecode/acosf_deg6
-rw-r--r--tests/10optimizer_bytecode/acosh5
-rw-r--r--tests/10optimizer_bytecode/acosh_deg6
-rw-r--r--tests/10optimizer_bytecode/acoshcosh5
-rw-r--r--tests/10optimizer_bytecode/acoshf5
-rw-r--r--tests/10optimizer_bytecode/acoshf_deg6
-rw-r--r--tests/10optimizer_bytecode/acoshl5
-rw-r--r--tests/10optimizer_bytecode/acoshl_deg6
-rw-r--r--tests/10optimizer_bytecode/acoshm5
-rw-r--r--tests/10optimizer_bytecode/acoshm_deg6
-rw-r--r--tests/10optimizer_bytecode/acoshsinh5
-rw-r--r--tests/10optimizer_bytecode/acosl5
-rw-r--r--tests/10optimizer_bytecode/acosl_deg6
-rw-r--r--tests/10optimizer_bytecode/acosm5
-rw-r--r--tests/10optimizer_bytecode/acosm_deg6
-rw-r--r--tests/10optimizer_bytecode/add5
-rw-r--r--tests/10optimizer_bytecode/add05
-rw-r--r--tests/10optimizer_bytecode/addexp5
-rw-r--r--tests/10optimizer_bytecode/addexp25
-rw-r--r--tests/10optimizer_bytecode/and5
-rw-r--r--tests/10optimizer_bytecode/asin5
-rw-r--r--tests/10optimizer_bytecode/asin_deg6
-rw-r--r--tests/10optimizer_bytecode/asinf5
-rw-r--r--tests/10optimizer_bytecode/asinf_deg6
-rw-r--r--tests/10optimizer_bytecode/asinh5
-rw-r--r--tests/10optimizer_bytecode/asinh_deg6
-rw-r--r--tests/10optimizer_bytecode/asinhcosh5
-rw-r--r--tests/10optimizer_bytecode/asinhf5
-rw-r--r--tests/10optimizer_bytecode/asinhf_deg6
-rw-r--r--tests/10optimizer_bytecode/asinhl5
-rw-r--r--tests/10optimizer_bytecode/asinhl_deg6
-rw-r--r--tests/10optimizer_bytecode/asinhm5
-rw-r--r--tests/10optimizer_bytecode/asinhm_deg6
-rw-r--r--tests/10optimizer_bytecode/asinhsinh5
-rw-r--r--tests/10optimizer_bytecode/asinl5
-rw-r--r--tests/10optimizer_bytecode/asinl_deg6
-rw-r--r--tests/10optimizer_bytecode/asinm5
-rw-r--r--tests/10optimizer_bytecode/asinm_deg6
-rw-r--r--tests/10optimizer_bytecode/atan5
-rw-r--r--tests/10optimizer_bytecode/atan25
-rw-r--r--tests/10optimizer_bytecode/atan2_deg6
-rw-r--r--tests/10optimizer_bytecode/atan2f5
-rw-r--r--tests/10optimizer_bytecode/atan2f_deg6
-rw-r--r--tests/10optimizer_bytecode/atan2l5
-rw-r--r--tests/10optimizer_bytecode/atan2l_deg6
-rw-r--r--tests/10optimizer_bytecode/atan2m5
-rw-r--r--tests/10optimizer_bytecode/atan2m_deg6
-rw-r--r--tests/10optimizer_bytecode/atan2tan5
-rw-r--r--tests/10optimizer_bytecode/atan_deg6
-rw-r--r--tests/10optimizer_bytecode/atanf5
-rw-r--r--tests/10optimizer_bytecode/atanf_deg6
-rw-r--r--tests/10optimizer_bytecode/atanh5
-rw-r--r--tests/10optimizer_bytecode/atanhf5
-rw-r--r--tests/10optimizer_bytecode/atanhl5
-rw-r--r--tests/10optimizer_bytecode/atanhm5
-rw-r--r--tests/10optimizer_bytecode/atanl5
-rw-r--r--tests/10optimizer_bytecode/atanl_deg6
-rw-r--r--tests/10optimizer_bytecode/atanm5
-rw-r--r--tests/10optimizer_bytecode/atanm_deg6
-rw-r--r--tests/10optimizer_bytecode/cbrt5
-rw-r--r--tests/10optimizer_bytecode/cbrtf5
-rw-r--r--tests/10optimizer_bytecode/cbrtl5
-rw-r--r--tests/10optimizer_bytecode/cbrtm5
-rw-r--r--tests/10optimizer_bytecode/ceil5
-rw-r--r--tests/10optimizer_bytecode/ceilf5
-rw-r--r--tests/10optimizer_bytecode/ceill5
-rw-r--r--tests/10optimizer_bytecode/ceilm5
-rw-r--r--tests/10optimizer_bytecode/ceilneg5
-rw-r--r--tests/10optimizer_bytecode/cmp_acos15
-rw-r--r--tests/10optimizer_bytecode/cmp_acos_outrange15
-rw-r--r--tests/10optimizer_bytecode/cmp_add15
-rw-r--r--tests/10optimizer_bytecode/cmp_asin15
-rw-r--r--tests/10optimizer_bytecode/cmp_asin_outrange15
-rw-r--r--tests/10optimizer_bytecode/cmp_atan15
-rw-r--r--tests/10optimizer_bytecode/cmp_exp7
-rw-r--r--tests/10optimizer_bytecode/cmp_exp27
-rw-r--r--tests/10optimizer_bytecode/cmp_exp2_neg7
-rw-r--r--tests/10optimizer_bytecode/cmp_exp_neg7
-rw-r--r--tests/10optimizer_bytecode/cmp_log10_nn15
-rw-r--r--tests/10optimizer_bytecode/cmp_log10_np15
-rw-r--r--tests/10optimizer_bytecode/cmp_log10_pn15
-rw-r--r--tests/10optimizer_bytecode/cmp_log10_pp15
-rw-r--r--tests/10optimizer_bytecode/cmp_log2_nn15
-rw-r--r--tests/10optimizer_bytecode/cmp_log2_np15
-rw-r--r--tests/10optimizer_bytecode/cmp_log2_pn15
-rw-r--r--tests/10optimizer_bytecode/cmp_log2_pp15
-rw-r--r--tests/10optimizer_bytecode/cmp_log_nn15
-rw-r--r--tests/10optimizer_bytecode/cmp_log_np15
-rw-r--r--tests/10optimizer_bytecode/cmp_log_pn15
-rw-r--r--tests/10optimizer_bytecode/cmp_log_pp15
-rw-r--r--tests/10optimizer_bytecode/cmp_mulneg15
-rw-r--r--tests/10optimizer_bytecode/cmp_mulpos15
-rw-r--r--tests/10optimizer_bytecode/cmp_neg7
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_n_n15
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_n_p15
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_nn15
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_np15
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_p_n15
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_p_p15
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_pn15
-rw-r--r--tests/10optimizer_bytecode/cmp_powx_pp15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_n_n15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_n_p15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_nn15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_np15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_p_n15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_p_p15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_pn15
-rw-r--r--tests/10optimizer_bytecode/cmp_powy_pp15
-rw-r--r--tests/10optimizer_bytecode/cmp_sinh15
-rw-r--r--tests/10optimizer_bytecode/cmp_sqr7
-rw-r--r--tests/10optimizer_bytecode/cmp_sqr_neg7
-rw-r--r--tests/10optimizer_bytecode/cmp_tanh15
-rw-r--r--tests/10optimizer_bytecode/cmp_tanh_outrange15
-rw-r--r--tests/10optimizer_bytecode/cmpeq5
-rw-r--r--tests/10optimizer_bytecode/cmpge5
-rw-r--r--tests/10optimizer_bytecode/cmpgt5
-rw-r--r--tests/10optimizer_bytecode/cmple5
-rw-r--r--tests/10optimizer_bytecode/cmplt5
-rw-r--r--tests/10optimizer_bytecode/cmpne5
-rw-r--r--tests/10optimizer_bytecode/cos5
-rw-r--r--tests/10optimizer_bytecode/cos_deg6
-rw-r--r--tests/10optimizer_bytecode/cosf5
-rw-r--r--tests/10optimizer_bytecode/cosf_deg6
-rw-r--r--tests/10optimizer_bytecode/cosh5
-rw-r--r--tests/10optimizer_bytecode/cosh_deg6
-rw-r--r--tests/10optimizer_bytecode/coshf5
-rw-r--r--tests/10optimizer_bytecode/coshf_deg6
-rw-r--r--tests/10optimizer_bytecode/coshl5
-rw-r--r--tests/10optimizer_bytecode/coshl_deg6
-rw-r--r--tests/10optimizer_bytecode/coshm5
-rw-r--r--tests/10optimizer_bytecode/coshm_deg6
-rw-r--r--tests/10optimizer_bytecode/cosl5
-rw-r--r--tests/10optimizer_bytecode/cosl_deg6
-rw-r--r--tests/10optimizer_bytecode/cosm5
-rw-r--r--tests/10optimizer_bytecode/cosm_deg6
-rw-r--r--tests/10optimizer_bytecode/deg5
-rw-r--r--tests/10optimizer_bytecode/degxmul6
-rw-r--r--tests/10optimizer_bytecode/div5
-rw-r--r--tests/10optimizer_bytecode/div15
-rw-r--r--tests/10optimizer_bytecode/divxx5
-rw-r--r--tests/10optimizer_bytecode/dupaddmul77
-rw-r--r--tests/10optimizer_bytecode/dupaddmulh7
-rw-r--r--tests/10optimizer_bytecode/dupaddmulmul77
-rw-r--r--tests/10optimizer_bytecode/dupaddmulmulh7
-rw-r--r--tests/10optimizer_bytecode/dupminmax7
-rw-r--r--tests/10optimizer_bytecode/dupminmax27
-rw-r--r--tests/10optimizer_bytecode/dupminmax36
-rw-r--r--tests/10optimizer_bytecode/dupxmuladd5
-rw-r--r--tests/10optimizer_bytecode/dupxpowmul5
-rw-r--r--tests/10optimizer_bytecode/eq06
-rw-r--r--tests/10optimizer_bytecode/eq16
-rw-r--r--tests/10optimizer_bytecode/exp5
-rw-r--r--tests/10optimizer_bytecode/exp25
-rw-r--r--tests/10optimizer_bytecode/exp2div5
-rw-r--r--tests/10optimizer_bytecode/exp2f5
-rw-r--r--tests/10optimizer_bytecode/exp2l5
-rw-r--r--tests/10optimizer_bytecode/exp2log25
-rw-r--r--tests/10optimizer_bytecode/exp2m5
-rw-r--r--tests/10optimizer_bytecode/exp2xpow6
-rw-r--r--tests/10optimizer_bytecode/expdiv5
-rw-r--r--tests/10optimizer_bytecode/expf5
-rw-r--r--tests/10optimizer_bytecode/expl5
-rw-r--r--tests/10optimizer_bytecode/explog5
-rw-r--r--tests/10optimizer_bytecode/explog107
-rw-r--r--tests/10optimizer_bytecode/explog27
-rw-r--r--tests/10optimizer_bytecode/expm5
-rw-r--r--tests/10optimizer_bytecode/expxpow6
-rw-r--r--tests/10optimizer_bytecode/floor5
-rw-r--r--tests/10optimizer_bytecode/floorf5
-rw-r--r--tests/10optimizer_bytecode/floorl5
-rw-r--r--tests/10optimizer_bytecode/floorm5
-rw-r--r--tests/10optimizer_bytecode/floorneg5
-rw-r--r--tests/10optimizer_bytecode/ge0_abs11
-rw-r--r--tests/10optimizer_bytecode/ge0_neg11
-rw-r--r--tests/10optimizer_bytecode/ge0_pos11
-rw-r--r--tests/10optimizer_bytecode/ge1_abs11
-rw-r--r--tests/10optimizer_bytecode/ge1_neg11
-rw-r--r--tests/10optimizer_bytecode/ge1_pos11
-rw-r--r--tests/10optimizer_bytecode/gehalf5
-rw-r--r--tests/10optimizer_bytecode/gt0_abs11
-rw-r--r--tests/10optimizer_bytecode/gt0_neg11
-rw-r--r--tests/10optimizer_bytecode/gt0_pos11
-rw-r--r--tests/10optimizer_bytecode/gt1_abs11
-rw-r--r--tests/10optimizer_bytecode/gt1_neg11
-rw-r--r--tests/10optimizer_bytecode/gt1_pos11
-rw-r--r--tests/10optimizer_bytecode/gtminushalf5
-rw-r--r--tests/10optimizer_bytecode/hypot5
-rw-r--r--tests/10optimizer_bytecode/hypotf5
-rw-r--r--tests/10optimizer_bytecode/hypotl5
-rw-r--r--tests/10optimizer_bytecode/hypotm5
-rw-r--r--tests/10optimizer_bytecode/immsub5
-rw-r--r--tests/10optimizer_bytecode/int5
-rw-r--r--tests/10optimizer_bytecode/intceil5
-rw-r--r--tests/10optimizer_bytecode/intfloor5
-rw-r--r--tests/10optimizer_bytecode/intint5
-rw-r--r--tests/10optimizer_bytecode/inttrunc5
-rw-r--r--tests/10optimizer_bytecode/invdiv5
-rw-r--r--tests/10optimizer_bytecode/invinv5
-rw-r--r--tests/10optimizer_bytecode/invmul5
-rw-r--r--tests/10optimizer_bytecode/invsincostan62
-rw-r--r--tests/10optimizer_bytecode/leminushalf5
-rw-r--r--tests/10optimizer_bytecode/log5
-rw-r--r--tests/10optimizer_bytecode/log105
-rw-r--r--tests/10optimizer_bytecode/log10f5
-rw-r--r--tests/10optimizer_bytecode/log10l5
-rw-r--r--tests/10optimizer_bytecode/log10m5
-rw-r--r--tests/10optimizer_bytecode/log25
-rw-r--r--tests/10optimizer_bytecode/log2exp17
-rw-r--r--tests/10optimizer_bytecode/log2exp27
-rw-r--r--tests/10optimizer_bytecode/log2f5
-rw-r--r--tests/10optimizer_bytecode/log2l5
-rw-r--r--tests/10optimizer_bytecode/log2m5
-rw-r--r--tests/10optimizer_bytecode/logexp17
-rw-r--r--tests/10optimizer_bytecode/logexp27
-rw-r--r--tests/10optimizer_bytecode/logf5
-rw-r--r--tests/10optimizer_bytecode/logl5
-rw-r--r--tests/10optimizer_bytecode/logm5
-rw-r--r--tests/10optimizer_bytecode/logmul5
-rw-r--r--tests/10optimizer_bytecode/logmul105
-rw-r--r--tests/10optimizer_bytecode/logmul25
-rw-r--r--tests/10optimizer_bytecode/lt05
-rw-r--r--tests/10optimizer_bytecode/lthalf5
-rw-r--r--tests/10optimizer_bytecode/max5
-rw-r--r--tests/10optimizer_bytecode/min5
-rw-r--r--tests/10optimizer_bytecode/mod5
-rw-r--r--tests/10optimizer_bytecode/mul5
-rw-r--r--tests/10optimizer_bytecode/mul15
-rw-r--r--tests/10optimizer_bytecode/mul1b5
-rw-r--r--tests/10optimizer_bytecode/mul25
-rw-r--r--tests/10optimizer_bytecode/mul45
-rw-r--r--tests/10optimizer_bytecode/mul_zero6
-rw-r--r--tests/10optimizer_bytecode/mulminus15
-rw-r--r--tests/10optimizer_bytecode/mulneg5
-rw-r--r--tests/10optimizer_bytecode/multodiv5
-rw-r--r--tests/10optimizer_bytecode/neg5
-rw-r--r--tests/10optimizer_bytecode/negabs5
-rw-r--r--tests/10optimizer_bytecode/negadd5
-rw-r--r--tests/10optimizer_bytecode/negceil5
-rw-r--r--tests/10optimizer_bytecode/negcos5
-rw-r--r--tests/10optimizer_bytecode/negcosh5
-rw-r--r--tests/10optimizer_bytecode/negdiv5
-rw-r--r--tests/10optimizer_bytecode/negfloor5
-rw-r--r--tests/10optimizer_bytecode/negmul5
-rw-r--r--tests/10optimizer_bytecode/negneg5
-rw-r--r--tests/10optimizer_bytecode/negnot5
-rw-r--r--tests/10optimizer_bytecode/negsin5
-rw-r--r--tests/10optimizer_bytecode/negsinh5
-rw-r--r--tests/10optimizer_bytecode/negsqr5
-rw-r--r--tests/10optimizer_bytecode/negsub5
-rw-r--r--tests/10optimizer_bytecode/negtan5
-rw-r--r--tests/10optimizer_bytecode/negtanh5
-rw-r--r--tests/10optimizer_bytecode/neq05
-rw-r--r--tests/10optimizer_bytecode/neq16
-rw-r--r--tests/10optimizer_bytecode/not5
-rw-r--r--tests/10optimizer_bytecode/not_eq5
-rw-r--r--tests/10optimizer_bytecode/not_ge5
-rw-r--r--tests/10optimizer_bytecode/not_gt5
-rw-r--r--tests/10optimizer_bytecode/not_le5
-rw-r--r--tests/10optimizer_bytecode/not_lt5
-rw-r--r--tests/10optimizer_bytecode/not_ne5
-rw-r--r--tests/10optimizer_bytecode/notnot5
-rw-r--r--tests/10optimizer_bytecode/notnotnot5
-rw-r--r--tests/10optimizer_bytecode/notnotnot25
-rw-r--r--tests/10optimizer_bytecode/or6
-rw-r--r--tests/10optimizer_bytecode/pow_neg5
-rw-r--r--tests/10optimizer_bytecode/pow_negf5
-rw-r--r--tests/10optimizer_bytecode/pow_negl5
-rw-r--r--tests/10optimizer_bytecode/pow_negm5
-rw-r--r--tests/10optimizer_bytecode/pow_pos5
-rw-r--r--tests/10optimizer_bytecode/pow_posf5
-rw-r--r--tests/10optimizer_bytecode/pow_posl5
-rw-r--r--tests/10optimizer_bytecode/pow_posm5
-rw-r--r--tests/10optimizer_bytecode/powdiv5
-rw-r--r--tests/10optimizer_bytecode/powhalf5
-rw-r--r--tests/10optimizer_bytecode/powinv5
-rw-r--r--tests/10optimizer_bytecode/powminushalf5
-rw-r--r--tests/10optimizer_bytecode/powminusone5
-rw-r--r--tests/10optimizer_bytecode/powminusthird5
-rw-r--r--tests/10optimizer_bytecode/powthird5
-rw-r--r--tests/10optimizer_bytecode/powxpow6
-rw-r--r--tests/10optimizer_bytecode/rad5
-rw-r--r--tests/10optimizer_bytecode/radxmul5
-rw-r--r--tests/10optimizer_bytecode/rsqrt6
-rw-r--r--tests/10optimizer_bytecode/sin5
-rw-r--r--tests/10optimizer_bytecode/sin_deg6
-rw-r--r--tests/10optimizer_bytecode/sincos_cci5
-rw-r--r--tests/10optimizer_bytecode/sincos_cic5
-rw-r--r--tests/10optimizer_bytecode/sincos_sc5
-rw-r--r--tests/10optimizer_bytecode/sincos_sci5
-rw-r--r--tests/10optimizer_bytecode/sincos_sis5
-rw-r--r--tests/10optimizer_bytecode/sincos_ssi5
-rw-r--r--tests/10optimizer_bytecode/sincos_tan5
-rw-r--r--tests/10optimizer_bytecode/sincos_tit5
-rw-r--r--tests/10optimizer_bytecode/sincos_tti5
-rw-r--r--tests/10optimizer_bytecode/sinf5
-rw-r--r--tests/10optimizer_bytecode/sinf_deg6
-rw-r--r--tests/10optimizer_bytecode/sinh5
-rw-r--r--tests/10optimizer_bytecode/sinh_deg6
-rw-r--r--tests/10optimizer_bytecode/sinhf5
-rw-r--r--tests/10optimizer_bytecode/sinhf_deg6
-rw-r--r--tests/10optimizer_bytecode/sinhl5
-rw-r--r--tests/10optimizer_bytecode/sinhl_deg6
-rw-r--r--tests/10optimizer_bytecode/sinhm5
-rw-r--r--tests/10optimizer_bytecode/sinhm_deg6
-rw-r--r--tests/10optimizer_bytecode/sinl5
-rw-r--r--tests/10optimizer_bytecode/sinl_deg6
-rw-r--r--tests/10optimizer_bytecode/sinm5
-rw-r--r--tests/10optimizer_bytecode/sinm_deg6
-rw-r--r--tests/10optimizer_bytecode/sqr_nxx5
-rw-r--r--tests/10optimizer_bytecode/sqr_xnx5
-rw-r--r--tests/10optimizer_bytecode/sqr_xx5
-rw-r--r--tests/10optimizer_bytecode/sqr_ynxx5
-rw-r--r--tests/10optimizer_bytecode/sqr_yxnx5
-rw-r--r--tests/10optimizer_bytecode/sqr_yxx5
-rw-r--r--tests/10optimizer_bytecode/sqreq05
-rw-r--r--tests/10optimizer_bytecode/sqrlog6
-rw-r--r--tests/10optimizer_bytecode/sqrlog106
-rw-r--r--tests/10optimizer_bytecode/sqrlog26
-rw-r--r--tests/10optimizer_bytecode/sqrneq05
-rw-r--r--tests/10optimizer_bytecode/sqrsqrt6
-rw-r--r--tests/10optimizer_bytecode/sqrt5
-rw-r--r--tests/10optimizer_bytecode/sqrtf5
-rw-r--r--tests/10optimizer_bytecode/sqrtl5
-rw-r--r--tests/10optimizer_bytecode/sqrtm5
-rw-r--r--tests/10optimizer_bytecode/sqrtsqr17
-rw-r--r--tests/10optimizer_bytecode/sqrtsqr27
-rw-r--r--tests/10optimizer_bytecode/sqrxpow6
-rw-r--r--tests/10optimizer_bytecode/sqrxpow_nonint6
-rw-r--r--tests/10optimizer_bytecode/sub5
-rw-r--r--tests/10optimizer_bytecode/sub05
-rw-r--r--tests/10optimizer_bytecode/subxx5
-rw-r--r--tests/10optimizer_bytecode/tan5
-rw-r--r--tests/10optimizer_bytecode/tan_deg6
-rw-r--r--tests/10optimizer_bytecode/tanf5
-rw-r--r--tests/10optimizer_bytecode/tanf_deg6
-rw-r--r--tests/10optimizer_bytecode/tanh5
-rw-r--r--tests/10optimizer_bytecode/tanh_deg6
-rw-r--r--tests/10optimizer_bytecode/tanhf5
-rw-r--r--tests/10optimizer_bytecode/tanhf_deg6
-rw-r--r--tests/10optimizer_bytecode/tanhl5
-rw-r--r--tests/10optimizer_bytecode/tanhl_deg6
-rw-r--r--tests/10optimizer_bytecode/tanhm5
-rw-r--r--tests/10optimizer_bytecode/tanhm_deg6
-rw-r--r--tests/10optimizer_bytecode/tanl5
-rw-r--r--tests/10optimizer_bytecode/tanl_deg6
-rw-r--r--tests/10optimizer_bytecode/tanm5
-rw-r--r--tests/10optimizer_bytecode/tanm_deg6
-rw-r--r--tests/10optimizer_bytecode/trunc5
-rw-r--r--tests/10optimizer_bytecode/truncf5
-rw-r--r--tests/10optimizer_bytecode/truncl5
-rw-r--r--tests/10optimizer_bytecode/truncm5
-rw-r--r--tests/10optimizer_bytecode/xaddnot5
-rw-r--r--tests/10optimizer_bytecode/xaddnotnot5
-rw-r--r--tests/10optimizer_bytecode/xmulrad6
-rw-r--r--tests/10optimizer_bytecode/xmulsinhneg5
-rw-r--r--tests/10optimizer_bytecode/xmulsinneg5
-rw-r--r--tests/10optimizer_bytecode/xmultanhneg5
-rw-r--r--tests/10optimizer_bytecode/xmultanneg5
-rw-r--r--tests/10optimizer_bytecode/xsqryfsqrhypot5
-rw-r--r--tests/10optimizer_bytecode/xsqrysqrhypot5
-rw-r--r--tests/10optimizer_bytecode/xxdup5
-rw-r--r--tests/10optimizer_bytecode/xxfdup5
-rw-r--r--tests/10optimizer_bytecode/xxsqrdup5
-rw-r--r--tests/10optimizer_bytecode/ypowxpow6
-rw-r--r--tests/11optimizer_constaddmul/15
-rw-r--r--tests/11optimizer_constaddmul/105
-rw-r--r--tests/11optimizer_constaddmul/116
-rw-r--r--tests/11optimizer_constaddmul/125
-rw-r--r--tests/11optimizer_constaddmul/135
-rw-r--r--tests/11optimizer_constaddmul/145
-rw-r--r--tests/11optimizer_constaddmul/155
-rw-r--r--tests/11optimizer_constaddmul/165
-rw-r--r--tests/11optimizer_constaddmul/175
-rw-r--r--tests/11optimizer_constaddmul/185
-rw-r--r--tests/11optimizer_constaddmul/195
-rw-r--r--tests/11optimizer_constaddmul/25
-rw-r--r--tests/11optimizer_constaddmul/205
-rw-r--r--tests/11optimizer_constaddmul/215
-rw-r--r--tests/11optimizer_constaddmul/225
-rw-r--r--tests/11optimizer_constaddmul/235
-rw-r--r--tests/11optimizer_constaddmul/245
-rw-r--r--tests/11optimizer_constaddmul/255
-rw-r--r--tests/11optimizer_constaddmul/265
-rw-r--r--tests/11optimizer_constaddmul/275
-rw-r--r--tests/11optimizer_constaddmul/285
-rw-r--r--tests/11optimizer_constaddmul/295
-rw-r--r--tests/11optimizer_constaddmul/35
-rw-r--r--tests/11optimizer_constaddmul/305
-rw-r--r--tests/11optimizer_constaddmul/315
-rw-r--r--tests/11optimizer_constaddmul/325
-rw-r--r--tests/11optimizer_constaddmul/335
-rw-r--r--tests/11optimizer_constaddmul/345
-rw-r--r--tests/11optimizer_constaddmul/355
-rw-r--r--tests/11optimizer_constaddmul/365
-rw-r--r--tests/11optimizer_constaddmul/375
-rw-r--r--tests/11optimizer_constaddmul/385
-rw-r--r--tests/11optimizer_constaddmul/395
-rw-r--r--tests/11optimizer_constaddmul/45
-rw-r--r--tests/11optimizer_constaddmul/405
-rw-r--r--tests/11optimizer_constaddmul/415
-rw-r--r--tests/11optimizer_constaddmul/425
-rw-r--r--tests/11optimizer_constaddmul/435
-rw-r--r--tests/11optimizer_constaddmul/55
-rw-r--r--tests/11optimizer_constaddmul/65
-rw-r--r--tests/11optimizer_constaddmul/75
-rw-r--r--tests/11optimizer_constaddmul/85
-rw-r--r--tests/11optimizer_constaddmul/95
-rw-r--r--tests/11optimizer_constaddmul/README69
-rw-r--r--tests/20optimizer_optimizations/abscos9
-rw-r--r--tests/20optimizer_optimizations/abscosh9
-rw-r--r--tests/20optimizer_optimizations/abseq05
-rw-r--r--tests/20optimizer_optimizations/absneq05
-rw-r--r--tests/20optimizer_optimizations/absnzge5
-rw-r--r--tests/20optimizer_optimizations/absnzlt5
-rw-r--r--tests/20optimizer_optimizations/acoscos5
-rw-r--r--tests/20optimizer_optimizations/acoshsinh5
-rw-r--r--tests/20optimizer_optimizations/addconstmul5
-rw-r--r--tests/20optimizer_optimizations/addlog7
-rw-r--r--tests/20optimizer_optimizations/addmulconstmul5
-rw-r--r--tests/20optimizer_optimizations/addnegmulneg7
-rw-r--r--tests/20optimizer_optimizations/addnegmulpos7
-rw-r--r--tests/20optimizer_optimizations/addsin2cos27
-rw-r--r--tests/20optimizer_optimizations/asinhcosh5
-rw-r--r--tests/20optimizer_optimizations/asinsin5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_add_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_add_reduce5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_addadd_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_minmax5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_minmax_rev5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_mul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_mul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_mulmul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_mulmul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_pow_imm_negneg5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_pow_imm_negpos5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_pow_imm_posneg5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_pow_imm_pospos5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_pow_imm_pospos_base5
-rw-r--r--tests/20optimizer_optimizations/cmpeq_powpow_imm_base5
-rw-r--r--tests/20optimizer_optimizations/cmpge_add_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpge_add_reduce5
-rw-r--r--tests/20optimizer_optimizations/cmpge_addadd_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpge_minmax5
-rw-r--r--tests/20optimizer_optimizations/cmpge_minmax_rev5
-rw-r--r--tests/20optimizer_optimizations/cmpge_mul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpge_mul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpge_mulmul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpge_mulmul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpge_pow_imm_negneg5
-rw-r--r--tests/20optimizer_optimizations/cmpge_pow_imm_negpos5
-rw-r--r--tests/20optimizer_optimizations/cmpge_pow_imm_posneg5
-rw-r--r--tests/20optimizer_optimizations/cmpge_pow_imm_pospos5
-rw-r--r--tests/20optimizer_optimizations/cmpge_pow_imm_pospos_base5
-rw-r--r--tests/20optimizer_optimizations/cmpge_powpow_imm_base5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_add_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_add_reduce5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_addadd_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_minmax5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_minmax_rev5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_mul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_mul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_mulmul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_mulmul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_pow_imm_negneg5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_pow_imm_negpos5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_pow_imm_posneg5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_pow_imm_pospos5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_pow_imm_pospos_base5
-rw-r--r--tests/20optimizer_optimizations/cmpgt_powpow_imm_base5
-rw-r--r--tests/20optimizer_optimizations/cmple_add_imm5
-rw-r--r--tests/20optimizer_optimizations/cmple_add_reduce5
-rw-r--r--tests/20optimizer_optimizations/cmple_addadd_imm5
-rw-r--r--tests/20optimizer_optimizations/cmple_minmax5
-rw-r--r--tests/20optimizer_optimizations/cmple_minmax_rev5
-rw-r--r--tests/20optimizer_optimizations/cmple_mul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmple_mul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmple_mulmul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmple_mulmul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmple_pow_imm_negneg5
-rw-r--r--tests/20optimizer_optimizations/cmple_pow_imm_negpos5
-rw-r--r--tests/20optimizer_optimizations/cmple_pow_imm_posneg5
-rw-r--r--tests/20optimizer_optimizations/cmple_pow_imm_pospos5
-rw-r--r--tests/20optimizer_optimizations/cmple_pow_imm_pospos_base5
-rw-r--r--tests/20optimizer_optimizations/cmple_powpow_imm_base5
-rw-r--r--tests/20optimizer_optimizations/cmplt_add_imm5
-rw-r--r--tests/20optimizer_optimizations/cmplt_add_reduce5
-rw-r--r--tests/20optimizer_optimizations/cmplt_addadd_imm5
-rw-r--r--tests/20optimizer_optimizations/cmplt_minmax5
-rw-r--r--tests/20optimizer_optimizations/cmplt_minmax_rev5
-rw-r--r--tests/20optimizer_optimizations/cmplt_mul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmplt_mul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmplt_mulmul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmplt_mulmul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmplt_pow_imm_negneg5
-rw-r--r--tests/20optimizer_optimizations/cmplt_pow_imm_negpos5
-rw-r--r--tests/20optimizer_optimizations/cmplt_pow_imm_posneg5
-rw-r--r--tests/20optimizer_optimizations/cmplt_pow_imm_pospos5
-rw-r--r--tests/20optimizer_optimizations/cmplt_pow_imm_pospos_base5
-rw-r--r--tests/20optimizer_optimizations/cmplt_powpow_imm_base5
-rw-r--r--tests/20optimizer_optimizations/cmpne_add_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpne_add_reduce5
-rw-r--r--tests/20optimizer_optimizations/cmpne_addadd_imm5
-rw-r--r--tests/20optimizer_optimizations/cmpne_minmax5
-rw-r--r--tests/20optimizer_optimizations/cmpne_minmax_rev5
-rw-r--r--tests/20optimizer_optimizations/cmpne_mul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpne_mul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpne_mulmul_imm_neg5
-rw-r--r--tests/20optimizer_optimizations/cmpne_mulmul_imm_pos5
-rw-r--r--tests/20optimizer_optimizations/cmpne_pow_imm_negneg5
-rw-r--r--tests/20optimizer_optimizations/cmpne_pow_imm_negpos5
-rw-r--r--tests/20optimizer_optimizations/cmpne_pow_imm_posneg5
-rw-r--r--tests/20optimizer_optimizations/cmpne_pow_imm_pospos5
-rw-r--r--tests/20optimizer_optimizations/cmpne_pow_imm_pospos_base5
-rw-r--r--tests/20optimizer_optimizations/cmpne_powpow_imm_base5
-rw-r--r--tests/20optimizer_optimizations/cmpzz_add_imm24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_add_reduce24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_addadd_imm24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_minmax24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_minmax_rev24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_mul_imm_neg24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_mul_imm_pos24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_mulmul_imm_neg24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_mulmul_imm_pos24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_pow_imm_negneg24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_pow_imm_negpos24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_pow_imm_posneg24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_pow_imm_pospos24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_pow_imm_pospos_base24
-rw-r--r--tests/20optimizer_optimizations/cmpzz_powpow_imm_base24
-rw-r--r--tests/20optimizer_optimizations/eq06
-rw-r--r--tests/20optimizer_optimizations/eq16
-rw-r--r--tests/20optimizer_optimizations/expexp_a5
-rw-r--r--tests/20optimizer_optimizations/expexp_b5
-rw-r--r--tests/20optimizer_optimizations/expexp_c5
-rw-r--r--tests/20optimizer_optimizations/ge0_abs11
-rw-r--r--tests/20optimizer_optimizations/ge1_abs11
-rw-r--r--tests/20optimizer_optimizations/ge_and_eq5
-rw-r--r--tests/20optimizer_optimizations/ge_and_le5
-rw-r--r--tests/20optimizer_optimizations/ge_and_ne5
-rw-r--r--tests/20optimizer_optimizations/ge_or_eq5
-rw-r--r--tests/20optimizer_optimizations/ge_or_le5
-rw-r--r--tests/20optimizer_optimizations/ge_or_ne5
-rw-r--r--tests/20optimizer_optimizations/gehalf5
-rw-r--r--tests/20optimizer_optimizations/gt0_abs11
-rw-r--r--tests/20optimizer_optimizations/gt1_abs11
-rw-r--r--tests/20optimizer_optimizations/gt_and_eq5
-rw-r--r--tests/20optimizer_optimizations/gt_and_ge5
-rw-r--r--tests/20optimizer_optimizations/gt_and_le5
-rw-r--r--tests/20optimizer_optimizations/gt_and_ne5
-rw-r--r--tests/20optimizer_optimizations/gt_or_eq5
-rw-r--r--tests/20optimizer_optimizations/gt_or_ge5
-rw-r--r--tests/20optimizer_optimizations/gt_or_le5
-rw-r--r--tests/20optimizer_optimizations/gt_or_ne5
-rw-r--r--tests/20optimizer_optimizations/if105
-rw-r--r--tests/20optimizer_optimizations/if_extract_abs5
-rw-r--r--tests/20optimizer_optimizations/if_extract_add5
-rw-r--r--tests/20optimizer_optimizations/if_extract_add15
-rw-r--r--tests/20optimizer_optimizations/if_extract_add25
-rw-r--r--tests/20optimizer_optimizations/if_extract_and1_l5
-rw-r--r--tests/20optimizer_optimizations/if_extract_and1_nl5
-rw-r--r--tests/20optimizer_optimizations/if_extract_and2_l5
-rw-r--r--tests/20optimizer_optimizations/if_extract_and2_nl5
-rw-r--r--tests/20optimizer_optimizations/if_extract_div5
-rw-r--r--tests/20optimizer_optimizations/if_extract_min5
-rw-r--r--tests/20optimizer_optimizations/if_extract_mul5
-rw-r--r--tests/20optimizer_optimizations/if_extract_mul15
-rw-r--r--tests/20optimizer_optimizations/if_extract_mul25
-rw-r--r--tests/20optimizer_optimizations/if_extract_or1_l5
-rw-r--r--tests/20optimizer_optimizations/if_extract_or1_nl5
-rw-r--r--tests/20optimizer_optimizations/if_extract_or2_l5
-rw-r--r--tests/20optimizer_optimizations/if_extract_or2_nl5
-rw-r--r--tests/20optimizer_optimizations/if_extract_sin5
-rw-r--r--tests/20optimizer_optimizations/if_join_add5
-rw-r--r--tests/20optimizer_optimizations/if_join_add25
-rw-r--r--tests/20optimizer_optimizations/if_join_and5
-rw-r--r--tests/20optimizer_optimizations/if_join_max5
-rw-r--r--tests/20optimizer_optimizations/if_join_min5
-rw-r--r--tests/20optimizer_optimizations/if_join_mul5
-rw-r--r--tests/20optimizer_optimizations/if_join_mul25
-rw-r--r--tests/20optimizer_optimizations/if_join_or5
-rw-r--r--tests/20optimizer_optimizations/ifabs21
-rw-r--r--tests/20optimizer_optimizations/ifabsnot5
-rw-r--r--tests/20optimizer_optimizations/ifconst5
-rw-r--r--tests/20optimizer_optimizations/ififconst5
-rw-r--r--tests/20optimizer_optimizations/ifmerge7
-rw-r--r--tests/20optimizer_optimizations/ifmerge25
-rw-r--r--tests/20optimizer_optimizations/ifmerge2b5
-rw-r--r--tests/20optimizer_optimizations/ifnop5
-rw-r--r--tests/20optimizer_optimizations/ifnot5
-rw-r--r--tests/20optimizer_optimizations/l_abs5
-rw-r--r--tests/20optimizer_optimizations/l_mulabs5
-rw-r--r--tests/20optimizer_optimizations/l_mulneg5
-rw-r--r--tests/20optimizer_optimizations/l_notnot5
-rw-r--r--tests/20optimizer_optimizations/le_and_eq5
-rw-r--r--tests/20optimizer_optimizations/le_and_ne5
-rw-r--r--tests/20optimizer_optimizations/le_or_eq5
-rw-r--r--tests/20optimizer_optimizations/le_or_ne5
-rw-r--r--tests/20optimizer_optimizations/lt_and_eq5
-rw-r--r--tests/20optimizer_optimizations/lt_and_ge5
-rw-r--r--tests/20optimizer_optimizations/lt_and_gt5
-rw-r--r--tests/20optimizer_optimizations/lt_and_le5
-rw-r--r--tests/20optimizer_optimizations/lt_and_ne5
-rw-r--r--tests/20optimizer_optimizations/lt_or_eq5
-rw-r--r--tests/20optimizer_optimizations/lt_or_ge5
-rw-r--r--tests/20optimizer_optimizations/lt_or_gt5
-rw-r--r--tests/20optimizer_optimizations/lt_or_le5
-rw-r--r--tests/20optimizer_optimizations/lt_or_ne5
-rw-r--r--tests/20optimizer_optimizations/lthalf5
-rw-r--r--tests/20optimizer_optimizations/mergemulabs5
-rw-r--r--tests/20optimizer_optimizations/mixedminmax13
-rw-r--r--tests/20optimizer_optimizations/muland25
-rw-r--r--tests/20optimizer_optimizations/muland2plus5
-rw-r--r--tests/20optimizer_optimizations/muland35
-rw-r--r--tests/20optimizer_optimizations/mulandlt5
-rw-r--r--tests/20optimizer_optimizations/mulimmlog11
-rw-r--r--tests/20optimizer_optimizations/mulnor27
-rw-r--r--tests/20optimizer_optimizations/mulnor2plus7
-rw-r--r--tests/20optimizer_optimizations/mulnor37
-rw-r--r--tests/20optimizer_optimizations/nand27
-rw-r--r--tests/20optimizer_optimizations/nand2plus7
-rw-r--r--tests/20optimizer_optimizations/nand37
-rw-r--r--tests/20optimizer_optimizations/negceil9
-rw-r--r--tests/20optimizer_optimizations/negcos5
-rw-r--r--tests/20optimizer_optimizations/negcosh5
-rw-r--r--tests/20optimizer_optimizations/negfloor9
-rw-r--r--tests/20optimizer_optimizations/negsin5
-rw-r--r--tests/20optimizer_optimizations/negsinh5
-rw-r--r--tests/20optimizer_optimizations/neq05
-rw-r--r--tests/20optimizer_optimizations/neq16
-rw-r--r--tests/20optimizer_optimizations/nor27
-rw-r--r--tests/20optimizer_optimizations/nor2plus7
-rw-r--r--tests/20optimizer_optimizations/nor37
-rw-r--r--tests/20optimizer_optimizations/not_eq5
-rw-r--r--tests/20optimizer_optimizations/not_ge5
-rw-r--r--tests/20optimizer_optimizations/not_gt5
-rw-r--r--tests/20optimizer_optimizations/not_le5
-rw-r--r--tests/20optimizer_optimizations/not_lt5
-rw-r--r--tests/20optimizer_optimizations/not_ne5
-rw-r--r--tests/20optimizer_optimizations/notnot5
-rw-r--r--tests/20optimizer_optimizations/posnot7
-rw-r--r--tests/20optimizer_optimizations/posnotnot7
-rw-r--r--tests/20optimizer_optimizations/powimmaddimmlog7
-rw-r--r--tests/20optimizer_optimizations/powimmlog7
-rw-r--r--tests/20optimizer_optimizations/powmulimm_fnen5
-rw-r--r--tests/20optimizer_optimizations/powmulimm_fnep5
-rw-r--r--tests/20optimizer_optimizations/powmulimm_fnfn5
-rw-r--r--tests/20optimizer_optimizations/powmulimm_fnfp5
-rw-r--r--tests/20optimizer_optimizations/powmulimm_fpfp7
-rw-r--r--tests/20optimizer_optimizations/sub1cos27
-rw-r--r--tests/20optimizer_optimizations/sub1sin27
-rw-r--r--tests/20optimizer_optimizations/trig_modulo35
-rw-r--r--tests/20optimizer_optimizations/trunc_from_if12
-rw-r--r--tests/20optimizer_optimizations/xaddnot5
-rw-r--r--tests/20optimizer_optimizations/xaddnotnot5
-rw-r--r--tests/21optimizer_trigcombinations/README1
-rw-r--r--tests/21optimizer_trigcombinations/make.php80
-rw-r--r--tests/50regressions/17
-rw-r--r--tests/50regressions/106
-rw-r--r--tests/50regressions/116
-rw-r--r--tests/50regressions/27
-rw-r--r--tests/50regressions/39
-rw-r--r--tests/50regressions/367
-rw-r--r--tests/50regressions/49
-rw-r--r--tests/50regressions/427
-rw-r--r--tests/50regressions/59
-rw-r--r--tests/50regressions/517
-rw-r--r--tests/50regressions/577
-rw-r--r--tests/50regressions/597
-rw-r--r--tests/50regressions/68
-rw-r--r--tests/50regressions/607
-rw-r--r--tests/50regressions/6111
-rw-r--r--tests/50regressions/79
-rw-r--r--tests/50regressions/88
-rw-r--r--tests/50regressions/9a8
-rw-r--r--tests/50regressions/9b8
-rw-r--r--tests/50regressions/9c8
-rw-r--r--tests/50regressions/9d8
-rw-r--r--tests/99misc/15
-rw-r--r--tests/99misc/105
-rw-r--r--tests/99misc/115
-rw-r--r--tests/99misc/125
-rw-r--r--tests/99misc/135
-rw-r--r--tests/99misc/145
-rw-r--r--tests/99misc/155
-rw-r--r--tests/99misc/165
-rw-r--r--tests/99misc/175
-rw-r--r--tests/99misc/185
-rw-r--r--tests/99misc/1917
-rw-r--r--tests/99misc/25
-rw-r--r--tests/99misc/205
-rw-r--r--tests/99misc/215
-rw-r--r--tests/99misc/2211
-rw-r--r--tests/99misc/235
-rw-r--r--tests/99misc/247
-rw-r--r--tests/99misc/255
-rw-r--r--tests/99misc/26_deg6
-rw-r--r--tests/99misc/275
-rw-r--r--tests/99misc/286
-rw-r--r--tests/99misc/295
-rw-r--r--tests/99misc/35
-rw-r--r--tests/99misc/306
-rw-r--r--tests/99misc/3115
-rw-r--r--tests/99misc/3243
-rw-r--r--tests/99misc/338
-rw-r--r--tests/99misc/345
-rw-r--r--tests/99misc/357
-rw-r--r--tests/99misc/375
-rw-r--r--tests/99misc/385
-rw-r--r--tests/99misc/3912
-rw-r--r--tests/99misc/45
-rw-r--r--tests/99misc/4016
-rw-r--r--tests/99misc/4116
-rw-r--r--tests/99misc/438
-rw-r--r--tests/99misc/4421
-rw-r--r--tests/99misc/455
-rw-r--r--tests/99misc/4610
-rw-r--r--tests/99misc/477
-rw-r--r--tests/99misc/486
-rw-r--r--tests/99misc/495
-rw-r--r--tests/99misc/55
-rw-r--r--tests/99misc/5023
-rw-r--r--tests/99misc/529
-rw-r--r--tests/99misc/538
-rw-r--r--tests/99misc/5420
-rw-r--r--tests/99misc/559
-rw-r--r--tests/99misc/5610
-rw-r--r--tests/99misc/5815
-rw-r--r--tests/99misc/5911
-rw-r--r--tests/99misc/75
-rw-r--r--tests/99misc/85
-rw-r--r--tests/99misc/95
-rw-r--r--tests/99misc/i15
-rw-r--r--tests/99misc/i27
-rw-r--r--tests/99misc/i39
-rw-r--r--tests/make_tests.cc1099
-rw-r--r--tests/test_file_syntax.txt176
-rw-r--r--util/bytecoderules.dat513
-rw-r--r--util/bytecoderules_header.txt27
-rw-r--r--util/bytecoderules_parser.cc1480
-rw-r--r--util/cpp_compress.cc832
-rw-r--r--util/cpp_compress.hh10
-rw-r--r--util/cpp_compress_main.cc20
-rw-r--r--util/create_testrules_for_optimization_rules.cc358
-rw-r--r--util/ftest.cc213
-rw-r--r--util/functioninfo.cc1422
-rw-r--r--util/make_function_name_parser.cc177
-rw-r--r--util/powi_opt.cc208
-rw-r--r--util/powi_speedtest.cc63
-rw-r--r--util/speedtest.cc344
-rw-r--r--util/tree_grammar_parser.cc3621
-rw-r--r--util/tree_grammar_parser.y1966
-rw-r--r--util/version_changer.cc52
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&nbsp;double</code> as its numerical type.
+ <p>The <code>FP_SUPPORT_LONG_DOUBLE_TYPE</code> preprocessor macro needs
+ to be defined for this class to be enabled.
+ <p>Note that the <code>FP_USE_STRTOLD</code> preprocessor macro should
+ also be defined when using this version of the parser if the compiler
+ supports the (C99) function <code>strtold()</code>. (See
+ <a href="#configuring">documentation</a> below.)
+ </dd>
+
+ <dt><p><code>FunctionParser_li</code></dt>
+ <dd>
+ <p>This parser uses <code>long&nbsp;int</code> as its numerical type.
+ <p>The <code>FP_SUPPORT_LONG_INT_TYPE</code> preprocessor macro needs
+ to be defined for this class to be enabled.
+ <p>Note that this version of the class uses a reduced function syntax
+ with support only for functions which are feasible to be used with
+ integral types (namely <code>abs()</code>, <code>eval()</code>,
+ <code>if()</code>, <code>min()</code> and <code>max()</code>, besides
+ basic arithmetic operators, except for the power operator).
+ </dd>
+
+ <dt><p><code>FunctionParser_cd</code>, <code>FunctionParser_cf</code>,
+ <code>FunctionParser_cld</code></dt>
+ <dd>
+ <p>These parsers use <code>std::complex&lt;double&gt;</code>,
+ <code>std::complex&lt;float&gt;</code> and
+ <code>std::complex&lt;long&nbsp;double&gt;</code> as their numerical type,
+ respectively.
+ <p>The preprocessor macros to enable them are
+ <code>FP_SUPPORT_COMPLEX_DOUBLE_TYPE</code>,
+ <code>FP_SUPPORT_COMPLEX_FLOAT_TYPE</code> and
+ <code>FP_SUPPORT_COMPLEX_LONG_DOUBLE_TYPE</code>.
+ <p>If <code>FunctionParser_cld</code> is used, the
+ <code>FP_USE_STRTOLD</code> macro should also be defined if the compiler
+ supports the <code>strtold()</code> function.
+ </dd>
+
+ <dt><p><code>FunctionParser_mpfr</code></dt>
+ <dd>
+ <p>This parser uses <code>MpfrFloat</code> as its numerical type.
+ <p>The <code>FP_SUPPORT_MPFR_FLOAT_TYPE</code> preprocessor macro needs
+ to be defined for this class to be enabled.
+ <p>Note that to use this version of the parser,
+ <code>"fparser_mpfr.hh"</code> needs to be included.
+ <p><code>MpfrFloat</code> is an auxiliary class which uses the MPFR
+ library for multiple-precision floating point numbers. The class
+ behaves largely like a floating point type, and is declared in the
+ <code>mpfr/MpfrFloat.hh</code> file (see that file for info about
+ the public interface of the class).
+ <p>If this class is enabled, <code>mpfr/MpfrFloat.cc</code>
+ needs to be compiled into the project, as well as the GMP and MPFR
+ libraries. (With the gcc compiler this means using the linker options
+ "<code>-lgmp -lmpfr</code>".)
+ </dd>
+
+ <dt><p><code>FunctionParser_gmpint</code></dt>
+ <dd>
+ <p>This parser uses <code>GmpInt</code> as its numerical type.
+ <p>The <code>FP_SUPPORT_GMP_INT_TYPE</code> preprocessor macro needs
+ to be defined for this class to be enabled.
+ <p>Note that to use this version of the parser,
+ <code>"fparser_gmpint.hh"</code> needs to be included.
+ <p><code>GmpInt</code> is an auxiliary class which uses the GMP
+ library for arbitrary-precision integer numbers. The class
+ behaves largely like an integer type, and is declared in the
+ <code>mpfr/GmpInt.hh</code> file (see that file for info about
+ the public interface of the class).
+ <p>If this class is enabled, <code>mpfr/GmpInt.cc</code>
+ needs to be compiled into the project, as well as the GMP library.
+ <p>This version of the class also uses a reduced version of the syntax,
+ like the <code>long int</code> version.
+ <p><b>Note:</b> Since there's no upper limit to the size of GMP
+ integers, this version of the class should be used with care in
+ situations where malicious users might be able to exploit it to
+ make the program run out of memory. An example of this would be
+ a server-side application usable through the WWW.
+ </dd>
+</dl>
+
+<p>Note that these different classes are completely independent and
+ instances of different classes cannot be given to each other using the
+ <code>AddFunction()</code> method. Only objects of the same type can
+ be given to that method.
+
+<p>The rest of the documentation assumes that <code>FunctionParser</code>
+ (which uses the <code>double</code> type) is used. The usage of the other
+ classes is identical except that <code>double</code> is replaced with the
+ correspondent type used by that class. (In other words, whenever the
+ rest of this documentation uses the type keyword '<code>double</code>',
+ the correspondent type should be used instead, when using another version
+ of the class.)
+
+<!-- -------------------------------------------------------------------- -->
+<a name="configuring"></a>
+<h3>Configuring the compilation</h3>
+
+<p>There is a set of precompiler options in the <code>fpconfig.hh</code> file
+which can be used for setting certain features on or off. All of these options
+can also be specified from the outside, using precompiler settings (eg. the
+<code>-D</code> option in gcc), and thus it's not necessary to modify this
+file.
+
+<dl>
+ <dt><p><code>FP_USE_STRTOLD</code> : (Default off)</dt>
+ <dd><p>If <code>FunctionParser_ld</code> or <code>FunctionParser_cld</code>
+ are used, this preprocessor macro should be defined if the compiler
+ supports the (C99) function <code>strtold()</code>. If not, then numeric
+ literals will be parsed with double precision only, which in most
+ systems is less accurate than long double precision, which will cause
+ small rounding errors. (This setting has no effect on the other parser
+ types.) Note that <code>strtold()</code> will also be automatically used
+ if <code>__cplusplus</code> indicates that C++11 is in use.
+ </dd>
+
+ <dt><p><code>FP_SUPPORT_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&amp; Function, const std::string&amp; Vars,
+ bool useDegrees = false);
+
+int Parse(const char* Function, const std::string&amp; Vars,
+ bool useDegrees = false);
+</pre>
+
+<p>Parses the given function and compiles it to internal format.
+ Return value is -1 if successful, else the index value to the location
+ of the error.
+
+<hr>
+<pre>
+void setDelimiterChar(char);
+</pre>
+
+<p>Sets an ending delimiter character for the function string. (See the
+ long description for more details.)
+
+<hr>
+<pre>
+static double epsilon();
+static void setEpsilon(double);
+</pre>
+
+<p>Setter and getter for the epsilon value used with comparison operators.
+
+<hr>
+<pre>
+const char* ErrorMsg(void) const;
+</pre>
+
+<p>Returns an error message corresponding to the error in
+<code>Parse()</code>, or an empty string if no such error occurred.
+
+<hr>
+<pre>
+ParseErrorType GetParseErrorType() const;
+</pre>
+
+<p>Returns the type of parsing error which occurred. Possible return types
+ are described in the long description.
+
+<hr>
+<pre>
+double Eval(const double* Vars);
+</pre>
+
+<p>Evaluates the function given to <code>Parse()</code>.
+
+<hr>
+<pre>
+int EvalError(void) const;
+</pre>
+
+<p>Returns <code>0</code> if no error happened in the previous call to
+<code>Eval()</code>, else an error code <code>&gt;0</code>.
+
+<hr>
+<pre>
+void Optimize();
+</pre>
+
+<p>Tries to optimize the bytecode for faster evaluation.
+
+<hr>
+<pre>
+bool AddConstant(const std::string&amp; name, double value);
+</pre>
+
+<p>Add a constant to the parser. Returns <code>false</code> if the name of
+the constant is invalid, else <code>true</code>.
+
+<hr>
+<pre>
+bool AddUnit(const std::string&amp; name, double value);
+</pre>
+
+<p>Add a new unit to the parser. Returns <code>false</code> if the name of
+the unit is invalid, else <code>true</code>.
+
+<hr>
+<pre>
+bool AddFunction(const std::string&amp; name,
+ double (*functionPtr)(const double*),
+ unsigned paramsAmount);
+</pre>
+
+<p>Add a user-defined function to the parser (as a function pointer).
+Returns <code>false</code> if the name of the function is invalid, else
+<code>true</code>.
+
+<hr>
+<pre>
+bool AddFunction(const std::string&amp; name, FunctionParser&amp;);
+</pre>
+
+<p>Add a user-defined function to the parser (as a <code>FunctionParser</code>
+instance). Returns <code>false</code> if the name of the function is invalid,
+else <code>true</code>.
+
+<hr>
+<pre>
+bool RemoveIdentifier(const std::string&amp; name);
+</pre>
+
+<p>Removes the constant, unit or user-defined function with the specified
+name from the parser.
+
+<hr>
+<pre>
+int ParseAndDeduceVariables(const std::string&amp; function,
+ int* amountOfVariablesFound = 0,
+ bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+ std::string&amp; resultVarString,
+ int* amountOfVariablesFound = 0,
+ bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+ std::vector&lt;std::string&gt;&amp; resultVars,
+ bool useDegrees = false);
+</pre>
+
+<p>Like <code>Parse()</code>, but the variables in the function are deduced
+automatically. The amount of found variables and the variable names themselves
+are returned by the different versions of the function.
+
+<!-- -------------------------------------------------------------------- -->
+<a name="longdesc"></a>
+<h3>Long descriptions of FunctionParser methods</h3>
+
+<hr>
+<a name="longdesc_Parse"></a>
+<pre>
+int Parse(const std::string&amp; Function, const std::string&amp; Vars,
+ bool useDegrees = false);
+
+int Parse(const char* Function, const std::string&amp; Vars,
+ bool useDegrees = false);
+</pre>
+
+<p>Parses the given function (and compiles it to internal format).
+Destroys previous function. Following calls to <code>Eval()</code> will evaluate
+the given function.
+
+<p>The strings given as parameters are not needed anymore after parsing.
+
+<p>Parameters:
+
+<table border=2>
+ <tr>
+ <td><code>Function</code></td>
+ <td>String containing the function to parse.</td>
+ </tr><tr>
+ <td><code>Vars</code></td>
+ <td>String containing the variable names, separated by commas.<br>
+ Eg. <code>"x,y"</code>, <code>"VarX,VarY,VarZ,n"</code> or
+ <code>"x1,x2,x3,x4,__VAR__"</code>.
+ </tr><tr>
+ <td><code>useDegrees</code></td>
+ <td>(Optional.) Whether to use degrees or radians in
+ trigonometric functions. (Default: radians)</td>
+ </tr>
+</table>
+
+<p>If a <code>char*</code> is given as the <code>Function</code> parameter,
+it must be a null-terminated string.
+
+<p>Variables can have any size and they are case sensitive (ie.
+<code>"var"</code>, <code>"VAR"</code> and <code>"Var"</code> are
+<em>different</em> variable names). Letters, digits, underscores and
+UTF8-encoded characters can be used in variable names, but the name of
+a variable can't begin with a digit. Each variable name can appear only
+once in the '<code>Vars</code>' string. Function names are not legal
+variable names.
+
+<p>Using longer variable names causes no overhead whatsoever to the
+<code>Eval()</code> method, so it's completely safe to use variable names
+of any size.
+
+<p>The third, optional parameter specifies whether angles should be
+ interpreted as radians or degrees in trigonometrical functions.
+ If not specified, the default value is radians.
+
+<p>Return values:
+
+<ul>
+ <li>On success the function returns <code>-1</code>.
+ <li>On error the function returns an index to where the error was found
+ (<code>0</code> is the first character, <code>1</code> the second, etc).
+ If the error was not a parsing error returns an index to the end of the
+ string.
+</ul>
+
+<p>Example: <code>parser.Parse("3*x+y", "x,y");</code>
+
+
+<hr>
+<a name="longdesc_setDelimiterChar"></a>
+<pre>
+void setDelimiterChar(char);
+</pre>
+
+<p>By default the parser expects the entire function string to be valid
+(ie. the entire contents of the given <code>std::string</code>, or a C string
+ending in the null character <code>'\0'</code>).
+
+<p>If a delimiter character is specified with this function, then if it's
+encountered at the outermost parsing level by the <code>Parse()</code>
+function, and the input function has been valid so far, <code>Parse()</code>
+will return an index to this character inside the input string, but rather
+than set an error code, <code>FP_NO_ERROR</code> will be set.
+
+<p>The idea is that this can be used to more easily parse functions which
+are embedded inside larger strings, containing surrounding data, without
+having to explicitly extract the function to a separate string.
+
+<p>For example, suppose you are writing an interpreter for a scripting
+ language, which can have commands like this:
+
+<p><code>let MyFunction(x,y) = { sin(x*x+y*y) } // A 2-dimensional function</code>
+
+<p>Normally when parsing such a line you would have to extract the part
+inside the curly brackets into a separate string and parse it that way.
+With this feature what you can do instead is to set <code>'}'</code> as
+the delimiter character and then simply give a pointer to the character
+which comes after the <code>'{'</code>. If all goes well, the
+<code>Parse()</code> function will return an index to the <code>'}'</code>
+character (from the given starting point) and <code>GetParseErrorType()</code>
+will return <code>FP_NO_ERROR</code>. You can use the return
+value (if it's not <code>-1</code>) to jump forward in the string to the
+delimiter character.
+
+<p>Note that a null character (<code>'\0'</code>) or the end of the
+<code>std::string</code> (if one was given) will still be a valid end of
+the function string even if a delimiter character was specified. (In this
+case <code>Parse()</code> will return <code>-1</code> if there was no error,
+as usual.)
+
+<p>Also note that the delimiter character cannot be any valid operator
+or alphanumeric (including the underscore) character, nor the other
+characters defined in the function syntax. It must be a character not
+supported by the function parser (such as <code>'}'</code>,
+<code>'&quot;'</code>, <code>']'</code>, etc).
+
+
+<hr>
+<a name="longdesc_Epsilon"></a>
+<pre>
+static double epsilon();
+static void setEpsilon(double);
+</pre>
+
+<p>Comparison operators (for the non-integral versions of the parser) use an
+epsilon value to account for floating point calculation rounding errors.
+This epsilon value can be set and read with these functions. (Note that the
+specified value will be used by all instances of FunctionParser.) If not
+specified, the default values are:
+
+<ul>
+ <li>double: 1e-12
+ <li>float: 1e-5
+ <li>long double: 1e-14
+ <li>MpfrFloat: The value of MpfrFloat::someEpsilon()
+</ul>
+
+
+<hr>
+<a name="longdesc_ErrorMsg"></a>
+<pre>
+const char* ErrorMsg(void) const;
+</pre>
+
+<p>Returns a pointer to an error message string corresponding to the error
+caused by <code>Parse()</code> (you can use this to print the proper error
+message to the user). If no such error has occurred, returns an empty string.
+
+
+<hr>
+<a name="longdesc_GetParseErrorType"></a>
+<pre>
+ParseErrorType GetParseErrorType() const;
+</pre>
+
+<p>Returns the type of parse error which occurred.
+
+<p>This method can be used to get the error type if <code>ErrorMsg()</code>
+is not enough for printing the error message. In other words, this can be
+used for printing customized error messages (eg. in another language).
+If the default error messages suffice, then this method doesn't need
+to be called.
+
+<code>FunctionParser::ParseErrorType</code> is an enumerated type inside
+the class (ie. its values are accessed like
+"<code>FunctionParser::SYNTAX_ERROR</code>").
+
+<p>The possible values for FunctionParser::ParseErrorType are listed below,
+along with their equivalent error message returned by the
+<code>ErrorMsg()</code> method:
+
+<p><table border=2>
+<tr>
+ <td><code>FP_NO_ERROR</code></td>
+ <td>If no error occurred in the previous call to <code>Parse()</code>.</td>
+</tr><tr>
+ <td><code>SYNTAX_ERROR</code></td>
+ <td>"Syntax error"</td>
+</tr><tr>
+ <td><code>MISM_PARENTH</code></td>
+ <td>"Mismatched parenthesis"</td>
+</tr><tr>
+ <td><code>MISSING_PARENTH</code></td>
+ <td>"Missing ')'"</td>
+</tr><tr>
+ <td><code>EMPTY_PARENTH</code></td>
+ <td>"Empty parentheses"</td>
+</tr><tr>
+ <td><code>EXPECT_OPERATOR</code></td>
+ <td>"Syntax error: Operator expected"</td>
+</tr><tr>
+ <td><code>OUT_OF_MEMORY</code></td>
+ <td>"Not enough memory"</td>
+</tr><tr>
+ <td><code>UNEXPECTED_ERROR</code></td>
+ <td>"An unexpected error occurred. Please make a full bug report to the
+ author"</td>
+</tr><tr>
+ <td><code>INVALID_VARS</code></td>
+ <td>"Syntax error in parameter 'Vars' given to FunctionParser::Parse()"</td>
+</tr><tr>
+ <td><code>ILL_PARAMS_AMOUNT</code></td>
+ <td>"Illegal number of parameters to function"</td>
+</tr><tr>
+ <td><code>PREMATURE_EOS</code></td>
+ <td>"Syntax error: Premature end of string"</td>
+</tr><tr>
+ <td><code>EXPECT_PARENTH_FUNC</code></td>
+ <td>"Syntax error: Expecting ( after function"</td>
+</tr><tr>
+ <td><code>UNKNOWN_IDENTIFIER</code></td>
+ <td>"Syntax error: Unknown identifier"</td>
+</tr><tr>
+ <td><code>NO_FUNCTION_PARSED_YET</code></td>
+ <td>"(No function has been parsed yet)"</td>
+</tr>
+</table>
+
+
+<hr>
+<a name="longdesc_Eval"></a>
+<pre>
+double Eval(const double* Vars);
+</pre>
+
+<p>Evaluates the function given to <code>Parse()</code>.
+The array given as parameter must contain the same amount of values as
+the amount of variables given to <code>Parse()</code>. Each value corresponds
+to each variable, in the same order.
+
+<p>Return values:
+<ul>
+ <li>On success returns the evaluated value of the function given to
+ <code>Parse()</code>.
+ <li>On error (such as division by 0) the return value is unspecified,
+ probably 0.
+</ul>
+
+<p>Example:
+
+<p><code>double Vars[] = {1, -2.5};</code><br>
+<code>double result = parser.Eval(Vars);</code>
+
+
+<hr>
+<a name="longdesc_EvalError"></a>
+<pre>
+int EvalError(void) const;
+</pre>
+
+<p>Used to test if the call to <code>Eval()</code> succeeded.
+
+<p>Return values:
+
+<p>If there was no error in the previous call to <code>Eval()</code>,
+returns <code>0</code>, else returns a positive value as follows:
+<ul>
+ <li>1: division by zero
+ <li>2: sqrt error (sqrt of a negative value)
+ <li>3: log error (logarithm of a negative value)
+ <li>4: trigonometric error (asin or acos of illegal value)
+ <li>5: maximum recursion level in <code>eval()</code> reached
+</ul>
+
+
+<hr>
+<a name="longdesc_Optimize"></a>
+<pre>
+void Optimize();
+</pre>
+
+<p>This method can be called after calling the <code>Parse()</code> method.
+It will try to simplify the internal bytecode so that it will evaluate faster
+(it tries to reduce the amount of opcodes in the bytecode).
+
+<p>For example, the bytecode for the function <code>"5+x*y-25*4/8"</code> will
+be reduced to a bytecode equivalent to the function <code>"x*y-7.5"</code> (the
+original 11 opcodes will be reduced to 5). Besides calculating constant
+expressions (like in the example), it also performs other types of
+simplifications with variable and function expressions.
+
+<p>This method is quite slow and the decision of whether to use it or
+not should depend on the type of application. If a function is parsed
+once and evaluated millions of times, then calling <code>Optimize()</code>
+may speed-up noticeably. However, if there are tons of functions to parse
+and each one is evaluated once or just a few times, then calling
+<code>Optimize()</code> will only slow down the program.
+
+<p>Also, if the original function is expected to be optimal, then calling
+<code>Optimize()</code> would be useless.
+
+<p>Note: Currently this method does not make any checks (like
+<code>Eval()</code> does) and thus things like <code>"1/0"</code> will cause
+undefined behaviour. (On the other hand, if such expression is given to the
+parser, <code>Eval()</code> will always give an error code, no matter what
+the parameters.) If caching this type of errors is important, a work-around
+is to call <code>Eval()</code> once before calling <code>Optimize()</code>
+and checking <code>EvalError()</code>.
+
+<p>If the destination application is not going to use this method,
+the compiler constant <code>FP_SUPPORT_OPTIMIZER</code> can be undefined in
+<code>fpconfig.hh</code> to make the library smaller (<code>Optimize()</code>
+can still be called, but it will not do anything).
+
+<p>(If you are interested in seeing how this method optimizes the opcode,
+you can call the <code>PrintByteCode()</code> method before and after the
+call to <code>Optimize()</code> to see the difference.)
+
+
+<hr>
+<a name="longdesc_AddConstant"></a>
+<pre>
+bool AddConstant(const std::string&amp; name, double value);
+</pre>
+
+<p>This method can be used to add constants to the parser. Syntactically
+ constants are identical to variables (ie. they follow the same naming
+ rules and they can be used in the function string in the same way as
+ variables), but internally constants are directly replaced with their
+ value at parse time.
+
+<p>Constants used by a function must be added before calling
+<code>Parse()</code> for that function. Constants are preserved between
+<code>Parse()</code> calls in the current FunctionParser instance, so
+they don't need to be added but once. (If you use the same constant in
+several instances of FunctionParser, you will need to add it to all the
+instances separately.)
+
+<p>Constants can be added at any time and the value of old constants can
+be changed, but new additions and changes will only have effect the next
+time <code>Parse()</code> is called. (That is, changing the value of a constant
+after calling <code>Parse()</code> and before calling <code>Eval()</code>
+will have no effect.)
+
+<p>The return value will be <code>false</code> if the '<code>name</code>' of
+the constant was illegal, else <code>true</code>. If the name was illegal,
+the method does nothing.
+
+<p>Example: <code>parser.AddConstant("pi", 3.1415926535897932);</code>
+
+<p>Now for example <code>parser.Parse("x*pi", "x");</code> will be identical
+to the call <code>parser.Parse("x*3.1415926535897932", "x");</code>
+
+
+<hr>
+<a name="longdesc_AddUnit"></a>
+<pre>
+bool AddUnit(const std::string&amp; name, double value);
+</pre>
+
+<p>In some applications it is desirable to have units of measurement.
+A typical example is an application which creates a page layout to be
+printed. When printing, distances are usually measured in points
+(defined by the resolution of the printer). However, it is often more
+useful for the user to be able to specify measurements in other units
+such as centimeters or inches.
+
+<p>A unit is simply a value by which the preceding element is multiplied.
+For example, if the printing has been set up to 300 DPI, one inch is
+then 300 points (dots). Thus saying eg. <code>"5in"</code> is the same as saying
+<code>"5*300"</code> or <code>"1500"</code> (assuming <code>"in"</code> has
+been added as a unit with the value 300).
+
+<p>Note that units are slightly different from a multiplication in
+that they have a higher precedence than any other operator (except
+parentheses). Thus for example <code>"5/2in"</code> is parsed as
+<code>"5/(2*300)"</code>.
+(If 5/2 inches is what one wants, it has to be written <code>"(5/2)in"</code>.)
+
+<p>You can use the <code>AddUnit()</code> method to add a new unit. The
+unit can then be used after any element in the function (and will work as
+a multiplier for that element). An element is a float literal, a constant,
+a variable, a function or any expression in parentheses. When the element
+is not a float literal nor an expression in parentheses, there has to naturally
+be at least one whitespace between the element and the unit (eg.
+<code>"x in"</code>). To change the value of a unit, call
+<code>AddUnit()</code> again with the same unit name and the new value.
+
+<p>Unit names share the same namespace as constants, functions and
+ variables, and thus should be distinct from those.
+
+<p>Example: <code>parser.AddUnit("in", 300);</code>
+
+<p>Now for example the function <code>"5in"</code> will be identical to
+<code>"(5*300)"</code>. Other usage examples include <code>"x in"</code>,
+<code>"3in+2"</code>, <code>"pow(x,2)in"</code>, <code>"(x+2)in"</code>.
+
+
+<hr>
+<a name="longdesc_AddFunction1"></a>
+<pre>
+bool AddFunction(const std::string&amp; name,
+ double (*functionPtr)(const double*),
+ unsigned paramsAmount);
+</pre>
+
+This method can be used to add new functions to the parser. For example,
+if you would like to add a function "<code>sqr(A)</code>" which squares the
+value of <code>A</code>, you can do it with this method (so that you don't
+need to touch the source code of the parser).
+
+<p>The method takes three parameters:
+
+<ul>
+ <li>The name of the function. The name follows the same naming conventions
+ as variable names.
+
+ <li>A C++ function, which will be called when evaluating the function
+ string (if the user-given function is called there). The C++ function
+ must have the form:
+ <p><code>double functionName(const double* params);</code>
+
+ <li>The number of parameters the function takes. 0 is a valid value
+ in which case the function takes no parameters (such function
+ should simply ignore the <code>double*</code> it gets as a parameter).
+</ul>
+
+<p>The return value will be <code>false</code> if the given name was invalid
+(either it did not follow the variable naming conventions, or the name was
+already reserved), else <code>true</code>. If the return value is
+<code>false</code>, nothing is added.
+
+<p>Example: Suppose we have a C++ function like this:
+
+<p><code>double Square(const double* p)</code><br>
+<code>{</code><br>
+<code>&nbsp;&nbsp;&nbsp;&nbsp;return p[0]*p[0];</code><br>
+<code>}</code>
+
+<p>Now we can add this function to the parser like this:
+
+<p><code>parser.AddFunction("sqr", Square, 1);</code><br>
+<code>parser.Parse("2*sqr(x)", "x");</code>
+
+<p>An example of a useful function taking no parameters is a function
+ returning a random value. For example:
+
+<p><code>double Rand(const double*)</code><br>
+<code>{</code><br>
+<code>&nbsp;&nbsp;&nbsp;&nbsp;return drand48();</code><br
+<code>}</code>
+
+<p><code>parser.AddFunction("rand", Rand, 0);</code>
+
+<p><em>Important note</em>: If you use the <code>Optimize()</code> method,
+it will assume that the user-given function has no side-effects, that is,
+it always returns the same value for the same parameters. The optimizer will
+optimize the function call away in some cases, making this assumption.
+(The <code>Rand()</code> function given as example above is one such
+problematic case.)
+
+
+<hr>
+<a name="longdesc_AddFunction2"></a>
+<pre>
+bool AddFunction(const std::string&amp; name, FunctionParser&amp;);
+</pre>
+
+<p>This method is almost identical to the previous <code>AddFunction()</code>,
+but instead of taking a C++ function, it takes another FunctionParser
+instance.
+
+<p>There are some important restrictions on making a FunctionParser instance
+ call another:
+
+<ul>
+ <li>The FunctionParser instance given as parameter must be initialized
+ with a <code>Parse()</code> call before giving it as parameter. That
+ is, if you want to use the parser <code>A</code> in the parser
+ <code>B</code>, you must call <code>A.Parse()</code> before you can
+ call <code>B.AddFunction("name", A)</code>.
+
+ <li>The amount of variables in the FunctionParser instance given as
+ parameter must not change after it has been given to the
+ <code>AddFunction()</code>
+ of another instance. Changing the number of variables will result in
+ malfunction.
+
+ <li><code>AddFunction()</code> will fail (ie. return <code>false</code>)
+ if a recursive loop is
+ formed. The method specifically checks that no such loop is built.
+
+ <li>The FunctionParser instance given as parameter will <em>not</em> be
+ copied internally, only referenced. Thus the FunctionParser instance
+ given as parameter must exist for as long as the other FunctionParser
+ instance uses it.
+</ul>
+
+<p>Example:
+
+<p><code>FunctionParser f1, f2;</code><br>
+<p><code>f1.Parse("x*x", "x");</code><br>
+<p><code>f2.AddFunction("sqr", f1);</code>
+
+<p>This version of the <code>AddFunction()</code> method can be useful to
+eg. chain user-given functions. For example, ask the user for a function F1,
+ and then ask the user another function F2, but now the user can
+ call F1 in this second function if he wants (and so on with a third
+ function F3, where he can call F1 and F2, etc).
+
+<hr>
+<a name="longdesc_AddFunction3"></a>
+<pre>
+template&lt;typename DerivedWrapper&gt;
+bool AddFunctionWrapper(const std::string& name, const DerivedWrapper&,
+ unsigned paramsAmount);
+</pre>
+
+<p>See section on <a href="#functionobjects">specialized function objects</a>.
+
+<hr>
+<a name="longdesc_RemoveIdentifier"></a>
+<pre>
+bool RemoveIdentifier(const std::string&amp; name);
+</pre>
+
+<p>If a constant, unit or user-defined function with the specified name
+exists in the parser, it will be removed and the return value will be
+<code>true</code>, else nothing will be done and the return value will be
+<code>false</code>.
+
+<p>(Note: If you want to remove <em>everything</em> from an existing
+FunctionParser instance, simply assign a fresh instance to it, ie. like
+"<code>parser&nbsp;=&nbsp;FunctionParser();</code>")
+
+<hr>
+<a name="longdesc_ParseAndDeduceVariables"></a>
+<pre>
+int ParseAndDeduceVariables(const std::string&amp; function,
+ int* amountOfVariablesFound = 0,
+ bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+ std::string&amp; resultVarString,
+ int* amountOfVariablesFound = 0,
+ bool useDegrees = false);
+int ParseAndDeduceVariables(const std::string&amp; function,
+ std::vector&lt;std::string&gt;&amp; resultVars,
+ bool useDegrees = false);
+</pre>
+
+<p>These functions work in the same way as the <code>Parse()</code> function,
+but the variables in the input function string are deduced automatically. The
+parameters are:
+
+<ul>
+ <li><code>function</code>: The input function string, as with
+ <code>Parse()</code>.
+ <li><code>amountOfVariablesFound</code>: If non-null, the amount of found
+ variables will be assigned here.
+ <li><code>resultVarString</code>: The found variables will be written to
+ this string, in the same format as accepted by the <code>Parse()</code>
+ function. The variable names will be sorted using the <code>&lt;</code>
+ operator of <code>std::string</code>.
+ <li><code>resultVars</code>: The found variables will be written to this
+ vector, each element being one variable name. They will be sorted using
+ the <code>&lt;</code> operator of <code>std::string</code>. (The amount
+ of found variables can be retrieved, rather obviously, with the
+ <code>size()</code> method of the vector.)
+ <li><code>useDegrees</code>: As with <code>Parse()</code>.
+</ul>
+
+<p>As with <code>Parse()</code>, the return value will be <code>-1</code> if
+the parsing succeeded, else an index to the location of the error. None of
+the specified return values will be modified in case of error.
+
+<!-- -------------------------------------------------------------------- -->
+<a name="functionobjects"></a>
+<h3>Specialized function objects</h3>
+
+<p>The <code>AddFunction()</code> method can be used to add a new user-defined
+function to the parser, its implementation being called through a C++ function
+pointer. Sometimes this might not be enough, though. For example, one might
+want to use <code>boost::function</code> or other similar specialized stateful
+function objects instead of raw function pointers. This library provides a
+mechanism to achieve this.
+
+<h4>Creating and adding a specialized function object</h4>
+
+<p>In order to create a specialized function object, create a class derived
+from the <code>FunctionParser::FunctionWrapper</code> class. This class
+declares a virtual function named <code>callFunction</code> that the derived
+class must implement. For example:
+
+<pre>
+class MyFunctionWrapper:
+ public FunctionParser::FunctionWrapper
+{
+ public:
+ virtual double callFunction(const double* values)
+ {
+ // Perform the actual function call here, like:
+ return someFunctionSomewhere(values);
+
+ // In principle the result could also be
+ // calculated here, like for example:
+ return values[0] * values[0];
+ }
+};
+</pre>
+
+<p>You can then add an instance of this class to <code>FunctionParser</code>
+using the <code>AddFunctionWrapper()</code> method, which works like
+<code>AddFunction()</code>, but takes a wrapper object instead of a function
+pointer as parameter. For example:
+
+<pre>
+MyFunctionWrapper wrapper;
+parser.AddFunctionWrapper("funcName", wrapper, 1);
+</pre>
+
+<p>Note that <code>FunctionParser</code> will internally create a copy of
+the wrapper object, managing the lifetime of this copy, and thus the object
+given as parameter does not need to exist for as long as the
+<code>FunctionParser</code> instance. Hence the above could also be written as:
+
+<pre>
+parser.AddFunctionWrapper("funcName", MyFunctionWrapper(), 1);
+</pre>
+
+<p>Note that this also means that the wrapper class must have a working
+copy constructor.
+
+<p>Also note that if the <code>FunctionParser</code> instance is copied, all
+the copies will share the same function wrapper objects given to the original.
+
+<h4>Retrieving specialized function objects</h4>
+
+<p>As noted, the library will internally make a copy of the wrapper object,
+and thus it will be separate from the one which was given as parameter to
+<code>AddFunctionWrapper()</code>. In some cases it may be necessary to
+retrieve this wrapper object (for example to read or change its state).
+This can be done with the <code>GetFunctionWrapper()</code> method, which
+takes the name of the function and returns a pointer to the wrapper object,
+or null if no such object exists with that name.
+
+<p>Note that the returned pointer will be of type
+<code>FunctionParser::FunctionWrapper</code>. In order to get a pointer to
+the actual derived type, the calling code should perform a
+<code>dynamic_cast</code>, for example like this:
+
+<pre>
+MyFunctionWrapper* wrapper =
+ dynamic_cast&lt;MyFunctionWrapper*&gt;
+ (parser.GetFunctionWrapper("funcName"));
+
+if(!wrapper) { /* oops, the retrieval failed */ }
+else ...
+</pre>
+
+<p>(Using dynamic cast rather than a static cast adds safety because if you
+accidentally try to downcast to the wrong type, the pointer will become null.)
+
+<p>The calling code is free to modify the object in any way it wants, but it
+must not delete it (because <code>FunctionParser</code> itself handles this).
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="base"></a>
+<h3>FunctionParserBase</h3>
+
+<p>All the different parser types are derived from a templated base class
+named <code>FunctionParserBase</code>. In normal use it's not necessary to
+directly refer to this base class in the calling code. However, if the calling
+code also needs to be templated (with respect to the numerical type), then
+using <code>FunctionParserBase</code> directly is the easiest way to achieve
+this.
+
+<p>For example, if you want to make a function that handles more than one
+type of parser, it can be done like this:
+
+<pre>
+template&lt;typename Value_t&gt;
+void someFunction(FunctionParserBase&lt;Value_t&gt& parser)
+{
+ // do something with 'parser' here
+}
+</pre>
+
+<p>Now it's convenient to call that function with more than one type of
+parser, for example:
+
+<pre>
+FunctionParser realParser;
+FunctionParser_cd complexParser;
+
+someFunction(realParser);
+someFunction(complexParser);
+</pre>
+
+<p>Another example is a class that inherits from <code>FunctionParser</code>
+which also wants to support different numerical types. Such class can be
+declared as:
+
+<pre>
+template&lt;typename Value_t&gt;
+class SpecializedParser: public FunctionParserBase&lt;Value_t&gt;
+{
+ ...
+};
+</pre>
+
+
+<!-- -------------------------------------------------------------------- -->
+<h2>Syntax</h2>
+
+<a name="literals"></a>
+<h3>Numeric literals</h3>
+
+<p>A numeric literal is a fixed numerical value in the input function string
+ (either a floating point value or an integer value, depending on the parser
+ type).
+
+<p>An integer literal can consist solely of numerical digits (possibly with
+ a preceding unary minus). For example, "<code>12345</code>".
+
+<p>If the literal is preceded by the characters "<code>0x</code>", it
+ will be interpreted as a hexadecimal literal, where digits can also include
+ the letters from '<code>A</code>' to '<code>F</code>' (in either uppercase
+ or lowercase). For example, "<code>0x89ABC</code>" (which corresponds to the
+ value 563900).
+
+<p>A floating point literal (only supported by the floating point type parsers)
+ may additionally include a decimal point followed by the decimal part of the
+ value, such as for example "<code>12.34</code>", optionally followed by a
+ decimal exponent.
+
+<p>A decimal exponent consists of an '<code>E</code>' or '<code>e</code>',
+ followed by an optional plus or minus sign, followed by decimal digits, and
+ indicates multiplication by a power of 10. For example, "<code>1.2e5</code>"
+ (which is equivalent to the value 120000).
+
+<p>If a floating point literal is preceded by the characters "<code>0x</code>"
+ it will be interpreted in hexadecimal. A hexadecimal floating point
+ literal consists of a hexadecimal value, with an optional decimal point,
+ followed optionally by a binary exponent in base 10 (in other words, the
+ exponent is not in hexadecimal).
+
+<p>A binary exponent has the same format as a decimal exponent, except that
+ '<code>P</code>' or '<code>p</code>' is used. A binary exponent indicates
+ multiplication by a power of 2. For example, "<code>0xA.Bp10</code>"
+ (which is equivalent to the value 10944).
+
+<p>With the complex versions of the library, the imaginary part of a numeric
+ literal is written as a regular numeric literal with an '<code>i</code>'
+ appended, for example "<code>5i</code>". Note that when also specifying
+ the real part of a complex literal, parentheses should be used to avoid
+ precedence problems. (For example, "<code>(2+5i)&nbsp;*&nbsp;x</code>"
+ is not the same thing as "<code>2+5i&nbsp;*&nbsp;x</code>". The latter
+ would be equivalent to "<code>2 + (5i&nbsp;*&nbsp;x)</code>".)
+
+<a name="identifiers"></a>
+<h3>Identifier names</h3>
+
+<p>An identifier is the name of a function (internal or user-defined),
+ variable, constant or unit. New identifiers can be specified with the
+ functions described in the earlier subsections in this document.
+
+<p>The name of an identifier can use any alphanumeric characters, the
+ underscore character and any UTF8-encoded unicode character, excluding
+ those denoting whitespace.
+ The first character of the name cannot be a numeric digit, though.
+
+<p>All functions, variables, constants and units must use unique names.
+ It's not possible to add two different identifiers with the same name.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="functionsyntax"></a>
+<h3>The function string syntax</h3>
+
+<p>The function string understood by the class is very similar (but not
+completely identical in all aspects) to mathematical expressions in the
+C/C++ languages.
+Arithmetic float expressions can be created from float literals, variables
+or functions using the following operators in this order of precedence:
+
+<p><table border=2>
+ <tr>
+ <td><code>()</code></td>
+ <td>expressions in parentheses first</td>
+ </tr><tr>
+ <td><code>A unit</code></td>
+ <td>a unit multiplier (if one has been added)</td>
+ </tr><tr>
+ <td><code>A^B</code></td>
+ <td>exponentiation (A raised to the power B)</td>
+ </tr><tr>
+ <td><code>-A</code></td>
+ <td>unary minus</td>
+ </tr><tr>
+ <td><code>!A</code></td>
+ <td>unary logical not (result is 1 if <code>int(A)</code> is 0, else 0)</td>
+ </tr><tr>
+ <td><code>A*B A/B A%B</code></td>
+ <td>multiplication, division and modulo</td>
+ </tr><tr>
+ <td><code>A+B A-B</code></td>
+ <td>addition and subtraction</td>
+ </tr><tr>
+ <td><code>A=B A&lt;B A&lt;=B<br>A!=B A&gt;B A&gt;=B</code></td>
+ <td>comparison between A and B (result is either 0 or 1)</td>
+ </tr><tr>
+ <td><code>A&amp;B</code></td>
+ <td>result is 1 if <code>int(A)</code> and <code>int(B)</code> differ from
+ 0, else 0.<br>
+ Note: Regardless of the values, both operands are always
+ evaluated. However, if the expression is optimized, it may
+ be changed such that only one of the operands is evaluated,
+ according to standard shortcut logical operation semantics.</td>
+ </tr><tr>
+ <td><code>A|B</code></td>
+ <td>result is 1 if <code>int(A)</code> or <code>int(B)</code> differ from 0,
+ else 0.<br>
+ Note: Regardless of the values, both operands are always
+ evaluated. However, if the expression is optimized, it may
+ be changed such that only one of the operands is evaluated,
+ according to standard shortcut logical operation semantics.</td>
+ </tr>
+</table>
+
+<p>(Note that currently the exponentiation operator is not supported for
+ <code>FunctionParser_li</code> nor <code>FunctionParser_gmpint</code>.
+ With the former the result would very easily overflow, making its
+ usefulness questionable. With the latter it could be easily abused to
+ make the program run out of memory; think of a function like
+ "10^10^10^100000".)
+
+<p>Since the unary minus has higher precedence than any other operator, for
+ example the following expression is valid: <code>x*-y</code>
+
+<p>The comparison operators use an epsilon value, so expressions which may
+differ in very least-significant digits should work correctly. For example,
+<code>"0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 1"</code> should always
+return 1, and the same comparison done with "<code>&gt;</code>" or
+"<code>&lt;</code>" should always return 0. (The epsilon value can be
+configured in the <code>fpconfig.hh</code> file.)
+Without epsilon this comparison probably returns the wrong value.
+
+<p>The class supports these functions:
+
+<p><table border=2>
+<tr>
+ <td><code>abs(A)</code></td>
+ <td>Absolute value (magnitude) of A.
+ With real numbers, if A is negative, returns -A otherwise returns A.
+ With complex numbers, equivalent to <code>hypot(real(x),imag(x))</code>.</td>
+</tr><tr>
+ <td><code>acos(A)</code></td>
+ <td>Arc-cosine of A. Returns the angle, measured in radians, whose cosine is A.</td>
+</tr><tr>
+ <td><code>acosh(A)</code></td>
+ <td>Same as acos() but for hyperbolic cosine.</td>
+</tr><tr>
+ <td><code>arg(A)</code></td>
+ <td>Phase angle of complex number A. Equivalent to <code>atan2(imag(x),real(x))</code>.</td>
+</tr><tr>
+ <td><code>asin(A)</code></td>
+ <td>Arc-sine of A. Returns the angle, measured in radians, whose sine is A.</td>
+</tr><tr>
+ <td><code>asinh(A)</code></td>
+ <td>Same as asin() but for hyperbolic sine.</td>
+</tr><tr>
+ <td><code>atan(A)</code></td>
+ <td>Arc-tangent of (A). Returns the angle, measured in radians,
+ whose tangent is A.</td>
+</tr><tr>
+ <td><code>atan2(A,B)</code></td>
+ <td>Principal arc-tangent of A/B, using the signs of the
+ two arguments to determine the quadrant of the result.
+ Returns the solution to the two expressions
+ hypot(A,B)*sin(x)=A, hypot(A,B)*cos(x)=B.
+ The return value is in range -pi to pi, inclusive.</td>
+</tr><tr>
+ <td><code>atanh(A)</code></td>
+ <td>Same as atan() but for hyperbolic tangent.</td>
+</tr><tr>
+ <td><code>cbrt(A)</code></td>
+ <td>Cube root of A. Returns a solution to expression pow(x,3)=A.</td>
+</tr><tr>
+ <td><code>conj(A)</code></td>
+ <td>Complex conjugate of A. Equivalent to <code>real(x) - 1i*imag(x)</code> or <code>polar(abs(x),-arg(x))</code>.</td>
+</tr><tr>
+ <td><code>ceil(A)</code></td>
+ <td>Ceiling of A. Returns the smallest integer not smaller than A.
+ Rounds up to the next higher integer. E.g. -2.9, -2.5 and -2.1 are
+ rounded to -2.0, and 2.9, 2.5 and 2.1 are rounded to 3.0.</td>
+</tr><tr>
+ <td><code>cos(A)</code></td>
+ <td>Cosine of A. Returns the cosine of the angle A, where A is
+ measured in radians.</td>
+</tr><tr>
+ <td><code>cosh(A)</code></td>
+ <td>Same as cos() but for hyperbolic cosine.</td>
+</tr><tr>
+ <td><code>cot(A)</code></td>
+ <td>Cotangent of A. Equivalent to <code>1/tan(A)</code>.</td>
+</tr><tr>
+ <td><code>csc(A)</code></td>
+ <td>Cosecant of A. Equivalent to <code>1/sin(A)</code>.</td>
+</tr><tr>
+ <td><code>eval(...)</code></td>
+ <td>This a recursive call to the function to be evaluated. The
+ number of parameters must be the same as the number of parameters
+ taken by the function. Must be called inside <code>if()</code> to avoid
+ infinite recursion.</td>
+</tr><tr>
+ <td><code>exp(A)</code></td>
+ <td>Exponential of A. Returns the value of e raised to the power
+ A where e is the base of the natural logarithm, i.e. the
+ non-repeating value approximately equal to 2.71828182846.</td>
+</tr><tr>
+ <td><code>exp2(A)</code></td>
+ <td>Base 2 exponential of A. Equivalent to <code>pow(2,A)</code>.</td>
+</tr><tr>
+ <td><code>floor(A)</code></td>
+ <td>Floor of A. Returns the largest integer not greater than A. Rounds
+ down to the next lower integer.
+ E.g. -2.9, -2.5 and -2.1 are rounded to -3.0,
+ and 2.9, 2.5 and 2.1 are rounded to 2.0.</td>
+</tr><tr>
+ <td><code>hypot(A,B)</code></td>
+ <td>Euclidean distance function. Equivalent to <code>sqrt(A^2+B^2)</code>.</td>
+</tr><tr>
+ <td><code>if(A,B,C)</code></td>
+ <td>If int(A) differs from 0, the return value of this function is B,
+ else C. Only the parameter which needs to be evaluated is
+ evaluated, the other parameter is skipped; this makes it safe to
+ use <code>eval()</code> in them.</td>
+</tr><tr>
+ <td><code>imag(A)</code></td>
+ <td>Return the imaginary part of complex number A. Equivalent to <code>abs(A)*sin(arg(A))</code>.</td>
+</tr><tr>
+ <td><code>int(A)</code></td>
+ <td>Rounds A to the closest integer. Equidistant values are rounded away from
+ zero. E.g. -2.9 and -2.5 are rounded to -3.0; -2.1 is rounded to -2.0,
+ and 2.9 and 2.5 are rounded to 3.0; 2.1 is rounded to 2.0.</td>
+</tr><tr>
+ <td><code>log(A)</code></td>
+ <td>Natural (base e) logarithm of A. Returns the solution to expression exp(x)=A.</td>
+</tr><tr>
+ <td><code>log2(A)</code></td>
+ <td>Base 2 logarithm of A. Equivalent to <code>log(A)/log(2)</code>.</td>
+</tr><tr>
+ <td><code>log10(A)</code></td>
+ <td>Base 10 logarithm of A.</td>
+</tr><tr>
+ <td><code>max(A,B)</code></td>
+ <td>If A&gt;B, the result is A, else B.</td>
+</tr><tr>
+ <td><code>min(A,B)</code></td>
+ <td>If A&lt;B, the result is A, else B.</td>
+</tr><tr>
+ <td><code>polar(A,B)</code></td>
+ <td>Returns a complex number from magnitude A, phase angle B (in radians).
+ Equivalent to <code>real(A)*(cos(real(B))+1i*sin(real(B)))</code>.</td>
+</tr><tr>
+ <td><code>pow(A,B)</code></td>
+ <td>Exponentiation (A raised to the power B).</td>
+</tr><tr>
+ <td><code>real(A)</code></td>
+ <td>Return the real part of complex number A. Equivalent to <code>abs(A)*cos(arg(A))</code>.</td>
+</tr><tr>
+ <td><code>sec(A)</code></td>
+ <td>Secant of A. Equivalent to <code>1/cos(A)</code>.</td>
+</tr><tr>
+ <td><code>sin(A)</code></td>
+ <td>Sine of A. Returns the sine of the angle A, where A is
+ measured in radians.</td>
+</tr><tr>
+ <td><code>sinh(A)</code></td>
+ <td>Same as sin() but for hyperbolic sine.</td>
+</tr><tr>
+ <td><code>sqrt(A)</code></td>
+ <td>Square root of A. Returns a solution to expression pow(x,2)=A.</td>
+</tr><tr>
+ <td><code>tan(A)</code></td>
+ <td>Tangent of A. Returns the tangent of the angle A, where A
+ is measured in radians.</td>
+</tr><tr>
+ <td><code>tanh(A)</code></td>
+ <td>Same as tan() but for hyperbolic tangent.</td>
+</tr><tr>
+ <td><code>trunc(A)</code></td>
+ <td>Truncated value of A. Returns an integer corresponding to the value
+ of A without its fractional part.
+ E.g. -2.9, -2.5 and -2.1 are rounded to -2.0,
+ and 2.9, 2.5 and 2.1 are rounded to 2.0.</td>
+</tr>
+</table>
+
+<p>(Note that for <code>FunctionParser_li</code> and
+ <code>FunctionParser_gmpint</code> only the functions
+ <code>abs()</code>, <code>eval()</code>, <code>if()</code>,
+ <code>min()</code> and <code>max()</code> are supported.)
+
+<p>Examples of function string understood by the class:
+
+<p><code>"1+2"</code><br>
+<code>"x-1"</code><br>
+<code>"-sin(sqrt(x^2+y^2))"</code><br>
+<code>"sqrt(XCoord*XCoord + YCoord*YCoord)"</code><br>
+
+<p>An example of a recursive function is the factorial function:
+
+<code>"if(n>1, n*eval(n-1), 1)"</code>
+
+<p>Note that a recursive call has some overhead, which makes it a bit slower
+ than any other operation. It may be a good idea to avoid recursive functions
+ in very time-critical applications. Recursion also takes some memory, so
+ extremely deep recursions should be avoided (eg. millions of nested recursive
+ calls).
+
+<p>Also note that even though the maximum recursion level of
+<code>eval()</code> is limited, it is possible to write functions which
+never reach that level but still take enormous amounts of time to evaluate.
+This can sometimes be undesirable because it is prone to exploitation,
+which is why <code>eval()</code> is disabled by default. It can be enabled
+in the <code>fpconfig.hh</code> file.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="inlinevars"></a>
+<h3>Inline variables</h3>
+
+<p>The function syntax supports defining new variables inside the function
+string itself. This can be done with the following syntax:
+
+<p><code>"&lt;variable name&gt; := &lt;expression&gt;; &lt;function&gt;"</code>
+
+<p>For example:
+
+<p><code>"length := sqrt(x*x+y*y); 2*length*sin(length)"</code>
+
+<p>(Spaces around the '<code>:=</code>' operator are optional.)
+
+<p>The obvious benefit of this is that if a long expression needs to be
+used in the function several times, this allows writing it only once and
+using a named variable from that point forward.
+
+<p>The variable name must be an unused identifier (in other words, not an
+existing function, variable or unit name).
+
+<p>The <code>&lt;function&gt;</code> part can have further inline variable
+definitions, and thus it's possible to have any amount of them, for example:
+
+<p><code>"A := x^2; B := y^2; C := z^2; sqrt(A+B+C)"</code>
+
+<p>The expressions in subsequent inline variable definitions can use any
+of the previous inline variables. It is also possible to redefine an inline
+variable. For example:
+
+<p><code>"A := x^2; A := 2*A; sqrt(A)"</code>
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="whitespace"></a>
+<h3>Whitespace</h3>
+
+<p>Arbitrary amounts of whitespace can optionally be included between
+ elements in the function string.
+ The following unicode characters are interpreted as whitespace:
+<table>
+ <tr>
+ <th>Character number</th>
+ <th>Character name</th>
+ <th>UTF-8 byte sequence</th>
+ </tr>
+ <tr><td>U+0009</td><td>HORIZONTAL TABULATION </td><td>09</td></tr>
+ <tr><td>U+000A</td><td>LINE FEED </td><td>0A</td></tr>
+ <tr><td>U+000B</td><td>VERTICAL TABULATION </td><td>0B</td></tr>
+ <tr><td>U+000D</td><td>CARRIAGE RETURN </td><td>0D</td></tr>
+ <tr><td>U+0020</td><td>SPACE </td><td>20</td></tr>
+ <tr><td>U+00A0</td><td>NO-BREAK SPACE </td><td>C2 A0</td></tr>
+ <tr><td>U+2000</td><td>EN QUAD </td><td>E2 80 80</td></tr>
+ <tr><td>U+2001</td><td>EM QUAD </td><td>E2 80 81</td></tr>
+ <tr><td>U+2002</td><td>EN SPACE </td><td>E2 80 82</td></tr>
+ <tr><td>U+2003</td><td>EM SPACE </td><td>E2 80 83</td></tr>
+ <tr><td>U+2004</td><td>THREE-PER-EM SPACE </td><td>E2 80 84</td></tr>
+ <tr><td>U+2005</td><td>FOUR-PER-EM SPACE </td><td>E2 80 85</td></tr>
+ <tr><td>U+2006</td><td>SIX-PER-EM SPACE </td><td>E2 80 86</td></tr>
+ <tr><td>U+2007</td><td>FIGURE SPACE </td><td>E2 80 87</td></tr>
+ <tr><td>U+2008</td><td>PUNCTUATION SPACE </td><td>E2 80 88</td></tr>
+ <tr><td>U+2009</td><td>THIN SPACE </td><td>E2 80 89</td></tr>
+ <tr><td>U+200A</td><td>HAIR SPACE </td><td>E2 80 8A</td></tr>
+ <tr><td>U+200B</td><td>ZERO WIDTH SPACE </td><td>E2 80 8B</td></tr>
+ <tr><td>U+202F</td><td>NARROW NO-BREAK SPACE </td><td>E2 80 AF</td></tr>
+ <tr><td>U+205F</td><td>MEDIUM MATHEMATICAL SPACE</td><td>E2 81 9F</td></tr>
+ <tr><td>U+3000</td><td>IDEOGRAPHIC SPACE </td><td>E3 80 80</td></tr>
+</table>
+
+<!-- -------------------------------------------------------------------- -->
+<h2>Miscellaneous</h2>
+
+<a name="fpaccuracy"></a>
+<h3>About floating point accuracy</h3>
+
+<p>Note that if you are using <code>FunctionParser_ld</code> or
+<code>FunctionParser_cld</code> and you want calculations to be as accurate
+as the <code>long double</code> type allows, you should pay special attention
+to floating point literals in your own code. For example, this is a very
+typical mistake:
+
+<pre>FunctionParser_ld parser;
+parser.AddConstant("pi", 3.14159265358979323846);</pre>
+
+<p>The mistake might not be immediately apparent. The mistake is that a
+literal of type <code>double</code> is passed to the <code>AddConstant()</code>
+function even though it expects a value of type <code>long&nbsp;double</code>.
+In most systems the latter has more bits of precision than the former, which
+means that the value will have its least-significant bits clipped,
+introducing a rounding error. The proper way of making the above calls is:
+
+<pre>FunctionParser_ld parser;
+parser.AddConstant("pi", 3.14159265358979323846L);</pre>
+
+<p>The same principle should be used everywhere in your own code, if you are
+using the <code>long&nbsp;double</code> type.
+
+<p>This is especially important if you are using the <code>MpfrFloat</code>
+type (in which case its string-parsing constructor or its
+<code>ParseValue()</code> or <code>parseString()</code> member functions
+should be used instead of using numerical literals).
+
+<a name="evaluationchecks"></a>
+<h3>About evaluation-time checks</h3>
+
+<p><code>FunctionParser::Eval()</code> will perform certain sanity
+checks before performing certain operations. For example, before calling the
+<code>sqrt</code> function, it will check if the parameter is negative, and
+if so, it will set the proper error code instead of calling the function.
+These checks include:
+
+<ul>
+ <li>Division by (the exact value of) zero.
+ <li>Square root of a negative value.
+ <li>Logarithm of a non-positive value.
+ <li>Arcsine or arccosine of a value not in the range [-1, 1]. (This includes
+ hyperbolic versions of the functions.)
+</ul>
+
+<p>However, the library <em>can not</em> guarantee that it will catch all
+possible floating point errors before performing them, because this is
+impossible to do with standard C++. For example, dividing a very large
+value by a value which is very close to zero, or calculating the logarithm
+of a very small value may overflow the result, as well as multiplying two
+very large values. Raising a negative number to a non-integral power may
+cause a <em>NaN</em> result, etc.
+
+<p>As a rule of thumb, the library will (by default) detect invalid operations
+if they are invalid for a range of values. For example, square root is undefined
+for all negative values, and arc sine is undefined only values outside the range
+[-1, 1]. In general, operations which are invalid for only one single value
+(rather than a contiguous range of values) will not be detected (division by
+the exact value of zero is an exception to this rule) nor will
+overflow/underflow situations.
+
+<p>The library cannot guarantee that floating point
+errors will never happen during evaluation. This can make the library to
+return the floating point values <em>inf</em> and <em>NaN</em>. Moreover,
+if floating point errors cause an interrupt in the target computer
+architecture and/or when using certain compiler settings, this library
+cannot guarantee that it will never happen.
+
+<p>Note that the optimizer never performs any sanity checks.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="threadsafety"></a>
+<h3>About thread safety</h3>
+
+<p>None of the member functions of the FunctionParser class are thread-safe.
+Most prominently, the <code>Eval()</code> function is not thread-safe.
+(In other words, the <code>Eval()</code> function of a single FunctionParser
+instance cannot be safely called simultaneously by two threads.)
+
+<p>There are ways to use this library in a thread-safe way, though. If each
+thread uses its own FunctionParser instance, no problems will obviously
+happen. Note, however, that if these instances need to be a copy of a given
+FunctionParser instance (eg. one where the user has entered a function),
+a deep copy of this instance has to be performed for each thread. By
+default FunctionParser uses shallow-copying (copy-on-write), which means
+that a simple assignment of copy construction will not copy the data itself.
+To force a deep copy you can all the <code>ForceDeepCopy()</code> function on
+each of the instances of each thread after the assignment or copying has been
+done.
+
+<p>Another possibility is to compile the FunctionParser library so that
+its <code>Eval()</code> function will be thread-safe. (This can be done by
+defining the <code>FP_USE_THREAD_SAFE_EVAL</code> or the
+<code>FP_USE_THREAD_SAFE_EVAL_WITH_ALLOCA</code>
+precompiler constant.) As long as only one thread calls the other functions
+of FunctionParser, the other threads can safely call the <code>Eval()</code>
+of this one instance.
+
+<p>Note, however, that compiling the library like this can make
+<code>Eval()</code> slightly slower. (The <code>alloca</code> version, if
+supported by the compiler, will not be as slow.)
+
+<p>Also note that the MPFR and GMP versions of the library cannot be
+ made thread-safe, and thus this setting has no effect on them.
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="tipsandtricks"></a>
+<h3>Tips and tricks</h3>
+
+<h4>Add constants automatically to all parser objects</h4>
+
+<p>Often the same constants (such as <em>pi</em> and <em>e</em>) and other
+user-defined identifiers (such as units) are always used in all the
+<code>FunctionParser</code> objects throughout the program. It would be
+troublesome to always have to manually add these constants every time a
+new parser object is created.
+
+<p>There is, however, a simple way to always add these user-defined identifiers
+to all instances. Write a class like this:
+
+<pre>
+ class ParserWithConsts: public FunctionParser
+ {
+ public:
+ ParserWithConsts()
+ {
+ AddConstant("pi", 3.14159265358979323846);
+ AddConstant("e", 2.71828182845904523536);
+ }
+ };
+</pre>
+
+<p>Now instead of using <code>FunctionParser</code>, always use
+<code>ParserWithConsts</code>. It will behave identically except that the
+constants (and possibly other user-defined identifiers) will always be
+automatically defined. (Objects of this type even survive
+<a href="http://en.wikipedia.org/wiki/Object_slicing">slicing</a>, so
+they are completely safe to use anywhere.)
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="contact"></a>
+<h3>Contacting the author</h3>
+
+<p>Any comments, bug reports, etc. should be sent to warp@iki.fi
+
+
+<!-- -------------------------------------------------------------------- -->
+<!--
+<a name="algorithm"></a>
+<h2>The algorithm used in the library</h2>
+
+<p>The whole idea behind the algorithm is to convert the regular infix
+format (the regular syntax for mathematical operations in most languages,
+like C and the input of the library) to postfix format. The postfix format
+is also called stack arithmetic since an expression in postfix format
+can be evaluated using a stack and operating with the top of the stack.
+
+<p>For example:
+
+<p><table border=2>
+<tr><th>infix</th> <th>postfix</th></tr>
+<tr><td><code>2+3</code></td><td><code>2 3 +</code></td></tr>
+<tr><td><code>1+2+3</code></td><td><code>1 2 + 3 +</code></td></tr>
+<tr><td><code>5*2+8/2</code></td><td><code>5 2 * 8 2 / +</code></td></tr>
+<tr><td><code>(5+9)*3</code></td><td><code>5 9 + 3 *</code></td></tr>
+</table>
+
+<p>The postfix notation should be read in this way:
+
+<p>Let's take for example the expression: <code>5 2 * 8 2 / +</code>
+<ul>
+ <li>Put 5 on the stack
+ <li>Put 2 on the stack
+ <li>Multiply the two values on the top of the stack and put the result on
+ the stack (removing the two old values)
+ <li>Put 8 on the stack
+ <li>Put 2 on the stack
+ <li>Divide the two values on the top of the stack
+ <li>Add the two values on the top of the stack (which are in this case
+ the result of 5*2 and 8/2, that is, 10 and 4).
+</ul>
+
+<p>At the end there's only one value in the stack, and that value is the
+result of the expression.
+
+<p>Why stack arithmetic?
+
+<p>The last example above can give you a hint.
+ In infix format operators have precedence and we have to use parentheses to
+group operations with lower precedence to be calculated before operations
+with higher precedence.
+ This causes a problem when evaluating an infix expression, specially
+when converting it to byte code. For example in this kind of expression:
+ <code>(x+1)/(y+2)</code>
+we have to calculate first the two additions before we can calculate the
+division. We have to also keep counting parentheses, since there can be
+a countless amount of nested parentheses. This usually means that you
+have to do some type of recursion.
+
+<p>The simplest and mostefficient way of calculating this is to convert it
+to postfix notation.
+ The postfix notation has the advantage that you can make all operations
+in a straightforward way. You just evaluate the expression from left to
+right, applying each operation directly and that's it. There are no
+parentheses to worry about. You don't need recursion anywhere.
+ You have to keep a stack, of course, but that's extremely easily done.
+Also you just operate with the top of the stack, which makes it very easy.
+You never have to go deeper than 2 items in the stack.
+ And even better: Evaluating an expression in postfix format is never
+slower than in infix format. All the contrary, in many cases it's a lot
+faster (eg. because all parentheses are optimized away).
+ The above example could be expressed in postfix format:
+ <code>x 1 + y 2 + /</code>
+
+<p>The good thing about the postfix notation is also the fact that it can
+be extremely easily expressed in bytecode form.
+ You only need a byte value for each operation, for each variable and
+to push a constant to the stack.
+ Then you can interpret this bytecode straightforwardly. You just interpret
+it byte by byte, from the beginning to the end. You never have to go back,
+make loops or anything.
+
+<p>This is what makes byte-coded stack arithmetic so fast.
+-->
+
+
+<!-- -------------------------------------------------------------------- -->
+<a name="license"></a>
+<h2>Usage license</h2>
+
+<p>Copyright © 2003-2011 Juha Nieminen, Joel Yliluoma
+
+<p>This Library is distributed under the
+ <a href="http://www.gnu.org/copyleft/lesser.html">Lesser General Public
+ License</a> (LGPL) version 3.
+
+</body>
+</html>
diff --git a/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(&params);
+ if(i != needlist_cached.end() && i->first == &params)
+ return i->second;
+
+ return
+ needlist_cached.insert(i,
+ std::make_pair(&params, 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 ? "&nbsp;" : " ");
+ 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 ? " &micro;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;
+}