diff --git a/.gitignore b/.gitignore index 3b424da3e8521636c8f1bc2df18c3738ed9469b6..71b7138a99c770322f010b33d92d1697173eaf19 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ expr_*.c run.log includeTEST/mine.h *.csv +*.log +srcTest/*/*_gen.c +srcTest/*/myhead.h \ No newline at end of file diff --git a/Makefile b/Makefile index 291ac1ead82e5a63e404e1ce81cbc65c65d90851..70ee34c323fea78e818a5e15df7ad0e83ca78718 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CC = gcc CPP = g++ INCLUDE = -Iinclude -I/usr/include/python3.8 # LIBS= -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -lpython3.8 # may need -L to assign the Python lobrary path -LIBS = -lm -lpython3.8 -lfmt +LIBS = -lm -lpython3.8 -lfmt -lmpfr -lqd ECHO = printf # $(info $(CFLAGS) ) diff --git a/benchMark.txt b/benchMark.txt index 3e2ea63a86dbda939aa9cf0bd1193efb7f3e9c64..3111c7fcd22134aa17b7fdf83d47c5255e9bccb9 100644 --- a/benchMark.txt +++ b/benchMark.txt @@ -31,9 +31,9 @@ test05_nonlin1_test2 1.0/(1+x) verhulst (4*x)/(1+x/1.11) ComplexSinCos 1.0/2.0*sin(r)*(exp(-i) - exp(i)) ComplexSquareRoot 1.0/2.0*sqrt(2.0*(sqrt(x1*x1+x2*x2)+x1)) -doppler1 ((-(1657.0/5.0+3.0/5.0*T))*v)/(((1657.0/5.0+3.0/5.0*T)+u)*((1657.0/5.0+3.0/5.0*T)+u)) -doppler2 ((-(1657.0/5.0+3.0/5.0*T))*v)/(((1657.0/5.0+3.0/5.0*T)+u)*((1657.0/5.0+3.0/5.0*T)+u)) -doppler3 ((-(1657.0/5.0+3.0/5.0*T))*v)/(((1657.0/5.0+3.0/5.0*T)+u)*((1657.0/5.0+3.0/5.0*T)+u)) +doppler1 (-(331.4 + (0.6 * T)) * v) / (((331.4 + (0.6 * T)) + u) * ((331.4 + (0.6 * T)) + u)) +doppler2 (-(331.4 + (0.6 * T)) * v) / (((331.4 + (0.6 * T)) + u) * ((331.4 + (0.6 * T)) + u)) +doppler3 (-(331.4 + (0.6 * T)) * v) / (((331.4 + (0.6 * T)) + u) * ((331.4 + (0.6 * T)) + u)) hypot32 sqrt(x1*x1+x2*x2) i4 sqrtf(x+y*y) i6 sinf(x*y) @@ -42,11 +42,11 @@ NMSEproblem332 tan(x+eps) - tan(x) NMSEproblem335 cos(x+eps) - cos(x) NMSEproblem346 pow((x+1),1/n) - pow(x,1/n) NMSEsection35 exp(a*x) - 1 -polarToCarthesianX radius*cos(3.14159265359/180*theta) -polarToCarthesianY radius*sin(3.14159265359/180*theta) +polarToCarthesianX radius*cos(0.01745329251994444444444444444444*theta) +polarToCarthesianY radius*sin(0.01745329251994444444444444444444*theta) sec4example ((x1*x2) - 1)/((x1*x2)*(x1*x2) - 1) test03_nonlin2 (x+y)/(x - y) -theta atan(x2/x1)*180/3.14159265359 +theta atan(x2/x1)*57.29577951307855 turbine1 (2.0/(r*r)+3.0) - ((3.0 - 2.0*v)*(1.0/8.0)*((w*w)*r*r))/(1.0 - v) - 9.0/2.0 nonlin1 z/(z+1) carbonGas 35000000+(401.0/v)*(1000/v)*(v - 0.0427) - 0.0000000000000000041419509 diff --git a/detectErrorOneFPEDParallel.sh b/detectErrorOneFPEDParallel.sh index 140564f60bb9f4c74ee150c8a31d3565c566ad72..dd535a3b9e7e405413127d82143693e50e292975 100755 --- a/detectErrorOneFPEDParallel.sh +++ b/detectErrorOneFPEDParallel.sh @@ -4,6 +4,7 @@ path=`pwd` cd ${path} CC=mpicc +ERRORMODEL=ULP uniqueLabel=${1} # unique number x0Start=${2} @@ -49,7 +50,7 @@ sourceFile=${prefix}_${suffix} fileNameKernel=${prefix}__${middle}_${suffix} # echo "${CC} ${testFileName}.c ${sourceFile}.c ${prefix}_mpfr.c computeULP.c -IincludeTEST -DEXPRESSION=${prefix}_ -DSUFFIX=${suffix} -lmpfr -lm -O3 -o ${testFileName}.exe" -${CC} ./srcTest/${testFileName}.c ${directory}/${sourceFile}.c ${directory}/${prefix}_mpfr.c ./srcTest/computeULP.c -IincludeTEST -IincludeDD -DEXPRESSION=${prefix}_ -DSUFFIX=${suffix} -DERRFILE=${errfile} -Llibs -lTGen -lmpfr -lm -lqd -o ${testFileName}.exe +${CC} ./srcTest/${testFileName}.c ${directory}/${sourceFile}.c ${directory}/${prefix}_mpfr.c ./srcTest/computeULP.c -IincludeTEST -IincludeDD -DEXPRESSION=${prefix}_ -DSUFFIX=${suffix} -DERRFILE=${errfile} -D${ERRORMODEL} -Llibs -lTGen -lmpfr -lm -lqd -mfma -o ${testFileName}.exe # echo "mpirun -n ${numProcs} ./${testFileName}.exe ${x0Start} ${x0End} ${x0Size} ${fileNameKernel}" mpirun -n ${numProcs} ./${testFileName}.exe ${x0Start} ${x0End} ${x0Size} ${x0startNowIdx} ${x0startOriginInterval} ${stepX0} ${fileNameKernel} ${uniqueLabel} # mv outputs/${fileNameKernel}_error.txt ./outputs/${uniqueLabel}/${fileNameKernel}_error.txt @@ -66,5 +67,5 @@ if [ ${errfile} -eq 1 ]; then cd - > /dev/null fi -echo "end detecting error ${uniqueLabel}" -echo +# echo "end detecting error ${uniqueLabel}" +# echo diff --git a/detectErrorOneSingle.sh b/detectErrorOneSingle.sh new file mode 100755 index 0000000000000000000000000000000000000000..6a3795dc402c66713583b750192ce97675126067 --- /dev/null +++ b/detectErrorOneSingle.sh @@ -0,0 +1,26 @@ +# Usage: ./detectErrorOneFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x0Size} ${prefix} ${middle} ${suffix} ${errfile} +# set -x + +path=`pwd` +cd ${path} +CC=gcc + +uniqueLabel=${1} # unique number +if [ $# -eq 3 ]; then + suffix=${2} # different version. Eg: herbie daisy origin temp_0_3 final + x0=${3} +else + echo "detectErrorOneSingle.sh: Invalid input parameters" + exit +fi +prefix=expr_${uniqueLabel} # expr_${uniqueLabel}. Eg: expr_20221030155958 + +testFileName=test1paramSingle +numProcs=32 + +directory="./srcTest"/${uniqueLabel} +sourceFile=${prefix}_${suffix} + +${CC} ./srcTest/${testFileName}.c ${directory}/${sourceFile}.c ${directory}/${prefix}_mpfr.c ./srcTest/computeULP.c -IincludeTEST -IincludeDD -DEXPRESSION=${prefix}_ -DSUFFIX=${suffix} -Llibs -lTGen -lmpfr -lm -lqd -o ${testFileName}.exe +./${testFileName}.exe ${x0} +rm ${testFileName}.exe diff --git a/detectErrorThreeFPEDParallel.sh b/detectErrorThreeFPEDParallel.sh index 84957689675d7302a8423778f4f2cd7636729cd4..128d51dca9d0be9a6614a410048cdd7c4a40646d 100755 --- a/detectErrorThreeFPEDParallel.sh +++ b/detectErrorThreeFPEDParallel.sh @@ -70,7 +70,7 @@ fi testFileName=test3paramFPEDParallel numProcs=32 -echo "Detecting error: ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x2Start} ${x2End} ${x0Size} ${x1Size} ${x2Size} ${prefix} ${middle} ${suffix} ${errfile}" +# echo "Detecting error: ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x2Start} ${x2End} ${x0Size} ${x1Size} ${x2Size} ${prefix} ${middle} ${suffix} ${errfile}" directory="./srcTest"/${uniqueLabel} sourceFile=${prefix}_${suffix} fileNameKernel=${prefix}__${middle}_${suffix} @@ -92,5 +92,5 @@ if [ ${errfile} -eq 1 ]; then cd - > /dev/null fi -echo "end detecting ${uniqueLabel}" +# echo "end detecting ${uniqueLabel}" echo diff --git a/detectErrorTwoFPEDParallel.sh b/detectErrorTwoFPEDParallel.sh index e78b686d802c2460fc4dbf49288020a55fc2fe33..e55f60a40d64a548b1956920783b788bfaa8140f 100755 --- a/detectErrorTwoFPEDParallel.sh +++ b/detectErrorTwoFPEDParallel.sh @@ -58,7 +58,7 @@ fi testFileName=test2paramFPEDParallel numProcs=32 -echo "Detecting error: ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x0Size} ${x1Size} ${prefix} ${middle} ${suffix} ${errfile}" +# echo "Detecting error: ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x0Size} ${x1Size} ${prefix} ${middle} ${suffix} ${errfile}" directory="./srcTest"/${uniqueLabel} suffixClean=`echo ${suffix} | sed 's@_x\|_y\|_z@@g'` sourceFile=${prefix}_${suffixClean} @@ -82,5 +82,5 @@ if [ ${errfile} -eq 1 ]; then cd - > /dev/null fi -echo "end detecting ${uniqueLabel}" +# echo "end detecting ${uniqueLabel}" echo diff --git a/detectErrorTwoSingle.sh b/detectErrorTwoSingle.sh new file mode 100755 index 0000000000000000000000000000000000000000..7b64aa458f3e13d9d2b9363a0f347de72102d050 --- /dev/null +++ b/detectErrorTwoSingle.sh @@ -0,0 +1,26 @@ +# Usage: ./detectErrorOneFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x0Size} ${prefix} ${middle} ${suffix} ${errfile} +# set -x + +path=`pwd` +cd ${path} +CC=gcc + +uniqueLabel=${1} # unique number +if [ $# -eq 4 ]; then + suffix=${2} # different version. Eg: herbie daisy origin temp_0_3 final + x0=${3} + x1=${4} +else + echo "detectErrorTwoSingle.sh: Invalid input parameters" + exit +fi +prefix=expr_${uniqueLabel} # expr_${uniqueLabel}. Eg: expr_20221030155958 + +testFileName=test2paramSingle + +directory="./srcTest"/${uniqueLabel} +sourceFile=${prefix}_${suffix} + +${CC} ./srcTest/${testFileName}.c ${directory}/${sourceFile}.c ${directory}/${prefix}_mpfr.c ./srcTest/computeULP.c -IincludeTEST -IincludeDD -DEXPRESSION=${prefix}_ -DSUFFIX=${suffix} -Llibs -lTGen -lmpfr -lm -lqd -o ${testFileName}.exe +./${testFileName}.exe ${x0} ${x1} +rm ${testFileName}.exe diff --git a/include/basic.hpp b/include/basic.hpp index ec01f591b20dc7dc43e71d5992c6d46aec6d0b7f..318784517d2aeb1096a3e27bb60f73cdbabaf003 100644 --- a/include/basic.hpp +++ b/include/basic.hpp @@ -12,6 +12,9 @@ #include #include #include +#include +#include "mpreal.h" +#include "funclist.hpp" using std::string; using std::vector; @@ -41,6 +44,33 @@ public: size_t rewriteID; }; +typedef std::function singleCall; +typedef std::function doubleCall; +typedef std::function tribleCall; +typedef std::function quadCall; +typedef std::function)> commonCall; +typedef std::function doubleRealCall; +typedef std::function)> commonRealCall; + +extern std::map singleCall_map; +extern std::map doubleCall_map; +extern std::map tribleCall_map; +extern std::map quadCall_map; +extern std::map commonCall_map; +extern std::map doubleRealCall_map; +extern std::map commonRealCall_map; + +typedef std::function singleCall_dd; +typedef std::function doubleCall_d_d; +typedef std::function doubleCall_d_dd; +typedef std::function doubleCall_dd_d; +typedef std::function doubleCall_dd_dd; +extern std::map singleCall_dd_map; +extern std::map doubleCall_d_d_map; +extern std::map doubleCall_d_dd_map; +extern std::map doubleCall_dd_d_map; +extern std::map doubleCall_dd_dd_map; + //===----------------------------------------------------------------------===// // Abstract Syntax Tree (aka Parse Tree) //===----------------------------------------------------------------------===// @@ -110,9 +140,14 @@ class BinaryExprAST : public ExprAST { char Op; std::unique_ptr LHS, RHS; - + doubleCall func; + doubleRealCall realFunc; public: - BinaryExprAST(char Op, std::unique_ptr LHS, std::unique_ptr RHS) : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + BinaryExprAST(char Op, std::unique_ptr LHS, std::unique_ptr RHS) : Op(Op), LHS(std::move(LHS)), RHS(std::move(RHS)) { + string Opstr(1,Op); + func = doubleCall_map.find(Opstr)->second; + realFunc = doubleRealCall_map.find(Opstr)->second; + } void printExpr() { @@ -124,10 +159,12 @@ public: string type() { return "Binary"; } char getOp() { return Op; } - void setOp(char opNew) { Op = opNew; } std::unique_ptr &getLHS() { return LHS; } std::unique_ptr &getRHS() { return RHS; } + doubleCall getCallback() { return func; } + doubleRealCall getRealCallback() { return realFunc; } + void setOp(char opNew) { Op = opNew; } void setLHS(std::unique_ptr &newLHS) { LHS = newLHS->Clone(); } void setRHS(std::unique_ptr &newRHS) { RHS = newRHS->Clone(); } @@ -144,11 +181,19 @@ class CallExprAST : public ExprAST { string Callee; vector> Args; + commonCall call; + commonRealCall realCall; public: - CallExprAST(const string &Callee, vector> Args) : Callee(Callee), Args(std::move(Args)) {} + CallExprAST(const string &Callee, vector> Args) : Callee(Callee), Args(std::move(Args)) { + call = commonCall_map.find(Callee)->second; + realCall = commonRealCall_map.find(Callee)->second; + } - CallExprAST(std::unique_ptr &func) : Callee(func->Callee), Args(std::move(func->Args)) {} + CallExprAST(std::unique_ptr &func) : Callee(func->Callee), Args(std::move(func->Args)) { + call = commonCall_map.find(Callee)->second; + realCall = commonRealCall_map.find(Callee)->second; + } void printExpr() { @@ -164,6 +209,8 @@ public: string getCallee() { return Callee; } vector> &getArgs() { return Args; } + commonCall getCallback() { return call; } + commonRealCall getRealCallback() { return realCall; } std::unique_ptr Clone() { @@ -257,6 +304,8 @@ std::vector geneRandom(size_t start, size_t end); vector> combination(const int num, const vector& indexs); +vector> combinationNew(const int num, const vector& indexs); + size_t combination(size_t k, size_t n); void write_to_file(const string &uniqueLabel, const string &exprOriginBest, const vector &numIntervalsSoloBefore, const vector &numIntervalsSoloAfter, const std::vector thresholds, const std::vector &data, const std::string &filename); @@ -264,4 +313,9 @@ void write_to_file(const string &uniqueLabel, const string &exprOriginBest, cons void write_to_file_wrapper(string uniqueLabel, string exprOriginBest, int dimension, int numIntervalsBefore, double numOfIntervals, const vector &numIntervalsSoloBefore, const vector &numIntervalsSoloAfter, int numOfExprs, vector thresholds, const exprInfo &originExprInfo, const exprInfo &herbieExprInfo, const exprInfo &finalInfo, double originPerformance, double elapsed_seconds, double init_seconds, double matlab_seconds, double regime_seconds, double rewrite_seconds, double final_seconds, double matlabKernelTime); // } // end anonymous namespace +template +std::map setVarsValue(const vector &vars, const vector &values); + +void setDataTypes(vector &dataTypes); + #endif \ No newline at end of file diff --git a/include/color.hpp b/include/color.hpp index 74b91f82db39ff2ed96119582fdbd4808b6a052c..3f202d82855c1f9e2d827e3800e68f70c8e70ef7 100644 --- a/include/color.hpp +++ b/include/color.hpp @@ -11,6 +11,9 @@ #define CYAN "\033[36m" // Cyan #define WHITE "\033[37m" // White +#define BRIGHTRED "\033[91m" // Bright Red +#define BOLDBRIGHTRED "\033[1m\033[91m" // Bold Bright Red + #define BOLDBLACK "\033[1m\033[30m" // Bold Black #define BOLDRED "\033[1m\033[31m" // Bold Red #define BOLDGREEN "\033[1m\033[32m" // Bold Green diff --git a/include/errorDetect.hpp b/include/errorDetect.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9d0ce56dd8e8289eda637ca8b42a3a905af404fc --- /dev/null +++ b/include/errorDetect.hpp @@ -0,0 +1,26 @@ +#ifndef _ERRORDETECT +#define _ERRORDETECT + +#include "mpreal.h" + +typedef union { + double d; + unsigned long int l; +} DL; + +typedef union { + float f; + unsigned int l; +} FS; + +double computeUlpUnit(double x); + +double computeUlpUnit(mpfr::mpreal oracle); + +double computeError(mpfr::mpreal oracle, double x); + +double computeError(mpfr::mpreal oracle, mpfr::mpreal x); + +double computeError(mpfr::mpreal funcRealValue, mpfr::mpreal funcValue, double unitUlp); + +#endif \ No newline at end of file diff --git a/include/funclist.hpp b/include/funclist.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1b3e09cc99c7d530f734c4c125a1f3271094185e --- /dev/null +++ b/include/funclist.hpp @@ -0,0 +1,179 @@ +#ifndef _FUNCLIST +#define _FUNCLIST +#include +#include "mpreal.h" + +using std::vector; + +double mineadd(double x, double y); + +double minesub(double x, double y); + +double minemul(double x, double y); + +double minediv(double x, double y); + +double minesin(double x); + +double minecos(double x); + +double minetan(double x); + +double mineexp(double x); + +double minelog(double x); + +double mineasin(double x); + +double mineacos(double x); + +double mineatan(double x); + +double common_sin(vector args); + +double common_cos(vector args); + +double common_tan(vector args); + +double common_pow(vector args); + +double common_exp(vector args); + +double common_log(vector args); + +double common_asin(vector args); + +double common_acos(vector args); + +double common_atan(vector args); + +double common_expm1(vector args); + +double common_fma(vector args); + +double common_log1p(vector args); + +double common_sqrt(vector args); + +double common_hypot(vector args); + +double common_cbrt(vector args); + +double common_atan2(vector args); + +mpfr::mpreal realadd(mpfr::mpreal x, mpfr::mpreal y); + +mpfr::mpreal realsub(mpfr::mpreal x, mpfr::mpreal y); + +mpfr::mpreal realmul(mpfr::mpreal x, mpfr::mpreal y); + +mpfr::mpreal realdiv(mpfr::mpreal x, mpfr::mpreal y); + +mpfr::mpreal real_sin(vector args); + +mpfr::mpreal real_cos(vector args); + +mpfr::mpreal real_tan(vector args); + +mpfr::mpreal real_pow(vector args); + +mpfr::mpreal real_exp(vector args); + +mpfr::mpreal real_log(vector args); + +mpfr::mpreal real_asin(vector args); + +mpfr::mpreal real_acos(vector args); + +mpfr::mpreal real_atan(vector args); + +mpfr::mpreal real_expm1(vector args); + +mpfr::mpreal real_fma(vector args); + +mpfr::mpreal real_log1p(vector args); + +mpfr::mpreal real_sqrt(vector args); + +mpfr::mpreal real_hypot(vector args); + +mpfr::mpreal real_cbrt(vector args); + +mpfr::mpreal real_atan2(vector args); + +template +mpfr::mpreal mineadd_d_d(double x, double y); + +template +mpfr::mpreal mineadd_d_dd(double x, double *y); + +template +mpfr::mpreal mineadd_dd_d(double *x, double y); + +template +mpfr::mpreal mineadd_dd_dd(double *x, double *y); + +template +mpfr::mpreal minesub_d_d(double x, double y); + +template +mpfr::mpreal minesub_d_dd(double x, double *y); + +template +mpfr::mpreal minesub_dd_d(double *x, double y); + +template +mpfr::mpreal minesub_dd_dd(double *x, double *y); + +template +mpfr::mpreal minemul_d_d(double x, double y); + +template +mpfr::mpreal minemul_d_dd(double x, double *y); + +template +mpfr::mpreal minemul_dd_d(double *x, double y); + +template +mpfr::mpreal minemul_dd_dd(double *x, double *y); + +template +mpfr::mpreal minediv_d_d(double x, double y); + +template +mpfr::mpreal minediv_d_dd(double x, double *y); + +template +mpfr::mpreal minediv_dd_d(double *x, double y); + +template +mpfr::mpreal minediv_dd_dd(double *x, double *y); + +template +mpfr::mpreal minepow_d_d(double x, double y); + +template +mpfr::mpreal minepow_d_dd(double x, double *y); + +template +mpfr::mpreal minepow_dd_d(double *x, double y); + +template +mpfr::mpreal minepow_dd_dd(double *x, double *y); + +template +mpfr::mpreal minesin_dd(double *x); + +template +mpfr::mpreal minecos_dd(double *x); + +template +mpfr::mpreal minetan_dd(double *x); + +template +mpfr::mpreal mineexp_dd(double *x); + +template +mpfr::mpreal minelog_dd(double *x); + +#endif \ No newline at end of file diff --git a/include/geneCode.hpp b/include/geneCode.hpp index 66dfb90e9deed3fb3c82e4367687fad597a926a0..41e5da30507d4e36c2d5551bf24b0b5695b466c2 100644 --- a/include/geneCode.hpp +++ b/include/geneCode.hpp @@ -41,6 +41,12 @@ string geneFinalCode(string exprStr, string uniqueLabel, vector exprIn void getDepth(ast_ptr &expr, int &depth); -int codegenWrapper(ast_ptr &expr, vector &vars, const string uniqueLabel, string tail); +void getOrders(const ast_ptr &expr, vector &opOrder); + +vector setOrder(ast_ptr &expr); + +int showOrder(ast_ptr &expr); + +int codegenWrapper(ast_ptr &expr, vector &vars, const string uniqueLabel, string tail, std::map values, size_t inputNum, vector &outputStr, vector dataTypes = {"DD", "double"}); #endif \ No newline at end of file diff --git a/include/mpreal.h b/include/mpreal.h new file mode 100644 index 0000000000000000000000000000000000000000..426da2f5873311a6bb04fb129e05f49bbfc57b42 --- /dev/null +++ b/include/mpreal.h @@ -0,0 +1,3337 @@ +/* + MPFR C++: Multi-precision floating point number class for C++. + Based on MPFR library: http://mpfr.org + + Project homepage: http://www.holoborodko.com/pavel/mpfr + Contact e-mail: pavel@holoborodko.com + + Copyright (c) 2008-2022 Pavel Holoborodko + + Contributors: + Dmitriy Gubanov, Konstantin Holoborodko, Brian Gladman, + Helmut Jarausch, Fokko Beekhof, Ulrich Mutze, Heinz van Saanen, + Pere Constans, Peter van Hoof, Gael Guennebaud, Tsai Chia Cheng, + Alexei Zubanov, Jauhien Piatlicki, Victor Berger, John Westwood, + Petr Aleksandrov, Orion Poplawski, Charles Karney, Arash Partow, + Rodney James, Jorge Leitao, Jerome Benoit, Michal Maly. + + Licensing: + (A) MPFR C++ is under GNU General Public License ("GPL"). + + (B) Non-free licenses may also be purchased from the author, for users who + do not want their programs protected by the GPL. + + The non-free licenses are for users that wish to use MPFR C++ in + their products but are unwilling to release their software + under the GPL (which would require them to release source code + and allow free redistribution). + + Such users can purchase an unlimited-use license from the author. + Contact us for more details. + + GNU General Public License ("GPL") copyright permissions statement: + ************************************************************************** + 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 . +*/ + +#ifndef __MPREAL_H__ +#define __MPREAL_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Options +#define MPREAL_HAVE_MSVC_DEBUGVIEW // Enable Debugger Visualizer for "Debug" builds in MSVC. +#define MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS // Enable extended std::numeric_limits specialization. + // Meaning that "digits", "round_style" and similar members are defined as functions, not constants. + // See std::numeric_limits at the end of the file for more information. + +// Library version +#define MPREAL_VERSION_MAJOR 3 +#define MPREAL_VERSION_MINOR 6 +#define MPREAL_VERSION_PATCHLEVEL 9 +#define MPREAL_VERSION_STRING "3.6.9" + +// Detect compiler using signatures from http://predef.sourceforge.net/ +#if defined(__GNUC__) && defined(__INTEL_COMPILER) + #define IsInf(x) isinf(x) // Intel ICC compiler on Linux + +#elif defined(_MSC_VER) // Microsoft Visual C++ + #define IsInf(x) (!_finite(x)) + +#else + #define IsInf(x) std::isinf(x) // GNU C/C++ (and/or other compilers), just hope for C99 conformance +#endif + +// A Clang feature extension to determine compiler features. +#ifndef __has_feature + #define __has_feature(x) 0 +#endif + +// Detect support for r-value references (move semantic). +// Move semantic should be enabled with great care in multi-threading environments, +// especially if MPFR uses custom memory allocators. +// Everything should be thread-safe and support passing ownership over thread boundary. +#if (__has_feature(cxx_rvalue_references) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1600) && !defined(MPREAL_DISABLE_MOVE_SEMANTIC)) + + #define MPREAL_HAVE_MOVE_SUPPORT + + // Use fields in mpfr_t structure to check if it was initialized / set dummy initialization + #define mpfr_is_initialized(x) (0 != (x)->_mpfr_d) + #define mpfr_set_uninitialized(x) ((x)->_mpfr_d = 0 ) +#endif + +// Detect support for explicit converters. +#if (__has_feature(cxx_explicit_conversions) || \ + (defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC_MINOR >= 5) || __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1800) || \ + (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1300)) + + #define MPREAL_HAVE_EXPLICIT_CONVERTERS +#endif + +#define MPFR_USE_INTMAX_T // Enable 64-bit integer types - should be defined before mpfr.h + +#if defined(MPREAL_HAVE_MSVC_DEBUGVIEW) && defined(_MSC_VER) && defined(_DEBUG) + #define MPREAL_MSVC_DEBUGVIEW_CODE DebugView = toString(); + #define MPREAL_MSVC_DEBUGVIEW_DATA std::string DebugView; +#else + #define MPREAL_MSVC_DEBUGVIEW_CODE + #define MPREAL_MSVC_DEBUGVIEW_DATA +#endif + +#define MPFR_USE_NO_MACRO +#include + +#if (MPFR_VERSION < MPFR_VERSION_NUM(3,0,0)) + #include // Needed for random() +#endif + +// Less important options +#define MPREAL_DOUBLE_BITS_OVERFLOW -1 // Triggers overflow exception during conversion to double if mpreal + // cannot fit in MPREAL_DOUBLE_BITS_OVERFLOW bits + // = -1 disables overflow checks (default) + +// Fast replacement for mpfr_set_zero(x, +1): +// (a) uses low-level data members, might not be forward compatible +// (b) sign is not set, add (x)->_mpfr_sign = 1; +#define mpfr_set_zero_fast(x) ((x)->_mpfr_exp = __MPFR_EXP_ZERO) + +#if defined(__GNUC__) + #define MPREAL_PERMISSIVE_EXPR __extension__ +#else + #define MPREAL_PERMISSIVE_EXPR +#endif + +namespace mpfr { + +class mpreal { +private: + mpfr_t mp; + +public: + + // Get default rounding mode & precision + inline static mp_rnd_t get_default_rnd() { return (mp_rnd_t)(mpfr_get_default_rounding_mode()); } + inline static mp_prec_t get_default_prec() { return (mpfr_get_default_prec)(); } + + // Constructors && type conversions + mpreal(); + mpreal(const mpreal& u); + mpreal(const mpf_t u); + mpreal(const mpz_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const mpq_t u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const long double u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const unsigned long long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const long long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const unsigned long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const unsigned int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const long int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const int u, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t mode = mpreal::get_default_rnd()); + + // Construct mpreal from mpfr_t structure. + // shared = true allows to avoid deep copy, so that mpreal and 'u' share the same data & pointers. + mpreal(const mpfr_t u, bool shared = false); + + mpreal(const char* s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); + mpreal(const std::string& s, mp_prec_t prec = mpreal::get_default_prec(), int base = 10, mp_rnd_t mode = mpreal::get_default_rnd()); + + ~mpreal(); + +#ifdef MPREAL_HAVE_MOVE_SUPPORT + mpreal& operator=(mpreal&& v); + mpreal(mpreal&& u); +#endif + + // Operations + // = + // +, -, *, /, ++, --, <<, >> + // *=, +=, -=, /=, + // <, >, ==, <=, >= + + // = + mpreal& operator=(const mpreal& v); + mpreal& operator=(const mpf_t v); + mpreal& operator=(const mpz_t v); + mpreal& operator=(const mpq_t v); + mpreal& operator=(const long double v); + mpreal& operator=(const double v); + mpreal& operator=(const unsigned long int v); + mpreal& operator=(const unsigned long long int v); + mpreal& operator=(const long long int v); + mpreal& operator=(const unsigned int v); + mpreal& operator=(const long int v); + mpreal& operator=(const int v); + mpreal& operator=(const char* s); + mpreal& operator=(const std::string& s); + template mpreal& operator= (const std::complex& z); + + // + + mpreal& operator+=(const mpreal& v); + mpreal& operator+=(const mpf_t v); + mpreal& operator+=(const mpz_t v); + mpreal& operator+=(const mpq_t v); + mpreal& operator+=(const long double u); + mpreal& operator+=(const double u); + mpreal& operator+=(const unsigned long int u); + mpreal& operator+=(const unsigned int u); + mpreal& operator+=(const long int u); + mpreal& operator+=(const int u); + + mpreal& operator+=(const long long int u); + mpreal& operator+=(const unsigned long long int u); + mpreal& operator-=(const long long int u); + mpreal& operator-=(const unsigned long long int u); + mpreal& operator*=(const long long int u); + mpreal& operator*=(const unsigned long long int u); + mpreal& operator/=(const long long int u); + mpreal& operator/=(const unsigned long long int u); + + const mpreal operator+() const; + mpreal& operator++ (); + const mpreal operator++ (int); + + // - + mpreal& operator-=(const mpreal& v); + mpreal& operator-=(const mpz_t v); + mpreal& operator-=(const mpq_t v); + mpreal& operator-=(const long double u); + mpreal& operator-=(const double u); + mpreal& operator-=(const unsigned long int u); + mpreal& operator-=(const unsigned int u); + mpreal& operator-=(const long int u); + mpreal& operator-=(const int u); + const mpreal operator-() const; + friend const mpreal operator-(const unsigned long int b, const mpreal& a); + friend const mpreal operator-(const unsigned int b, const mpreal& a); + friend const mpreal operator-(const long int b, const mpreal& a); + friend const mpreal operator-(const int b, const mpreal& a); + friend const mpreal operator-(const double b, const mpreal& a); + mpreal& operator-- (); + const mpreal operator-- (int); + + // * + mpreal& operator*=(const mpreal& v); + mpreal& operator*=(const mpz_t v); + mpreal& operator*=(const mpq_t v); + mpreal& operator*=(const long double v); + mpreal& operator*=(const double v); + mpreal& operator*=(const unsigned long int v); + mpreal& operator*=(const unsigned int v); + mpreal& operator*=(const long int v); + mpreal& operator*=(const int v); + + // / + mpreal& operator/=(const mpreal& v); + mpreal& operator/=(const mpz_t v); + mpreal& operator/=(const mpq_t v); + mpreal& operator/=(const long double v); + mpreal& operator/=(const double v); + mpreal& operator/=(const unsigned long int v); + mpreal& operator/=(const unsigned int v); + mpreal& operator/=(const long int v); + mpreal& operator/=(const int v); + friend const mpreal operator/(const unsigned long int b, const mpreal& a); + friend const mpreal operator/(const unsigned int b, const mpreal& a); + friend const mpreal operator/(const long int b, const mpreal& a); + friend const mpreal operator/(const int b, const mpreal& a); + friend const mpreal operator/(const double b, const mpreal& a); + + //<<= Fast Multiplication by 2^u + mpreal& operator<<=(const unsigned long int u); + mpreal& operator<<=(const unsigned int u); + mpreal& operator<<=(const long int u); + mpreal& operator<<=(const int u); + + //>>= Fast Division by 2^u + mpreal& operator>>=(const unsigned long int u); + mpreal& operator>>=(const unsigned int u); + mpreal& operator>>=(const long int u); + mpreal& operator>>=(const int u); + + // Type Conversion operators + bool toBool ( ) const; + long toLong (mp_rnd_t mode = GMP_RNDZ) const; + unsigned long toULong (mp_rnd_t mode = GMP_RNDZ) const; + long long toLLong (mp_rnd_t mode = GMP_RNDZ) const; + unsigned long long toULLong (mp_rnd_t mode = GMP_RNDZ) const; + float toFloat (mp_rnd_t mode = GMP_RNDN) const; + double toDouble (mp_rnd_t mode = GMP_RNDN) const; + long double toLDouble (mp_rnd_t mode = GMP_RNDN) const; + +#if defined (MPREAL_HAVE_EXPLICIT_CONVERTERS) + explicit operator bool () const { return toBool(); } + explicit operator signed char () const { return (signed char)toLong(); } + explicit operator unsigned char () const { return (unsigned char)toULong(); } + explicit operator short () const { return (short)toLong(); } + explicit operator unsigned short () const { return (unsigned short)toULong();} + explicit operator int () const { return (int)toLong(); } + explicit operator unsigned int () const { return (unsigned int)toULong(); } + explicit operator long () const { return toLong(); } + explicit operator unsigned long () const { return toULong(); } + explicit operator long long () const { return toLLong(); } + explicit operator unsigned long long () const { return toULLong(); } + explicit operator float () const { return toFloat(); } + explicit operator double () const { return toDouble(); } + explicit operator long double () const { return toLDouble(); } +#endif + + // Get raw pointers so that mpreal can be directly used in raw mpfr_* functions + ::mpfr_ptr mpfr_ptr(); + ::mpfr_srcptr mpfr_ptr() const; + ::mpfr_srcptr mpfr_srcptr() const; + + // Convert mpreal to string with n significant digits in base b + // n = -1 -> convert with the maximum available digits + std::string toString(int n = -1, int b = 10, mp_rnd_t mode = mpreal::get_default_rnd()) const; + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + std::string toString(const std::string& format) const; +#endif + + std::ostream& output(std::ostream& os) const; + + // Math Functions + friend const mpreal sqr (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sqrt(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sqrt(const unsigned long int v, mp_rnd_t rnd_mode); + friend const mpreal cbrt(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal root(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode); + friend const mpreal pow (const mpreal& a, const long int b, mp_rnd_t rnd_mode); + friend const mpreal pow (const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode); + friend const mpreal pow (const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode); + friend const mpreal fabs(const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal abs(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode); + friend inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); + friend inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); + friend inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode); + friend inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode); + friend int cmpabs(const mpreal& a,const mpreal& b); + + friend const mpreal log (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal log2 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal logb (const mpreal& v, mp_rnd_t rnd_mode); + friend mp_exp_t ilogb(const mpreal& v); + friend const mpreal log10(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal exp (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal exp2 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal exp10(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal log1p(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal expm1(const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal nextpow2(const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal cos(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sin(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal tan(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sec(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal csc(const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal cot(const mpreal& v, mp_rnd_t rnd_mode); + friend int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal acos (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asin (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal atan (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode); + friend const mpreal acot (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asec (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acsc (const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal cosh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sinh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal tanh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal sech (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal csch (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal coth (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acosh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asinh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal atanh (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acoth (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal asech (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal acsch (const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + + friend const mpreal fac_ui (unsigned long int v, mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal eint (const mpreal& v, mp_rnd_t rnd_mode); + + friend const mpreal gamma (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal tgamma (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal lngamma (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal lgamma (const mpreal& v, int *signp, mp_rnd_t rnd_mode); + friend const mpreal zeta (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal erf (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal erfc (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besselj0 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besselj1 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besseljn (long n, const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal bessely0 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal bessely1 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal besselyn (long n, const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); + friend const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode); + friend const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode); + friend const mpreal sum (const mpreal tab[], const unsigned long int n, int& status, mp_rnd_t rnd_mode); + friend int sgn (const mpreal& v); + +// MPFR 2.4.0 Specifics +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + friend int sinh_cosh (mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal li2 (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + friend const mpreal rec_sqrt (const mpreal& v, mp_rnd_t rnd_mode); + + // MATLAB's semantic equivalents + friend const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Remainder after division + friend const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); // Modulus after division +#endif + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + friend const mpreal digamma (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal ai (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear +#endif + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,1,0)) + friend const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode); // use gmp_randinit_default() to init state, gmp_randclear() to clear + friend const mpreal grandom (unsigned int seed); +#endif + + // Uniformly distributed random number generation in [0,1] using + // Mersenne-Twister algorithm by default. + // Use parameter to setup seed, e.g.: random((unsigned)time(NULL)) + // Check urandom() for more precise control. + friend const mpreal random(unsigned int seed); + + // Splits mpreal value into fractional and integer parts. + // Returns fractional part and stores integer part in n. + friend const mpreal modf(const mpreal& v, mpreal& n); + + // Constants + // don't forget to call mpfr_free_cache() for every thread where you are using const-functions + friend const mpreal const_log2 (mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal const_pi (mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal const_euler (mp_prec_t prec, mp_rnd_t rnd_mode); + friend const mpreal const_catalan (mp_prec_t prec, mp_rnd_t rnd_mode); + + // returns +inf iff sign>=0 otherwise -inf + friend const mpreal const_infinity(int sign, mp_prec_t prec); + + // Output/ Input + friend std::ostream& operator<<(std::ostream& os, const mpreal& v); + friend std::istream& operator>>(std::istream& is, mpreal& v); + + // Integer Related Functions + friend const mpreal rint (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal ceil (const mpreal& v); + friend const mpreal floor(const mpreal& v); + friend const mpreal round(const mpreal& v); + friend long lround(const mpreal& v); + friend long long llround(const mpreal& v); + friend const mpreal trunc(const mpreal& v); + friend const mpreal rint_ceil (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal rint_floor (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal rint_round (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal rint_trunc (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal frac (const mpreal& v, mp_rnd_t rnd_mode); + friend const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + friend const mpreal remquo (const mpreal& x, const mpreal& y, int* q, mp_rnd_t rnd_mode); + + // Miscellaneous Functions + friend const mpreal nexttoward (const mpreal& x, const mpreal& y); + friend const mpreal nextabove (const mpreal& x); + friend const mpreal nextbelow (const mpreal& x); + + // use gmp_randinit_default() to init state, gmp_randclear() to clear + friend const mpreal urandomb (gmp_randstate_t& state); + +// MPFR < 2.4.2 Specifics +#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) + friend const mpreal random2 (mp_size_t size, mp_exp_t exp); +#endif + + // Instance Checkers + friend bool isnan (const mpreal& v); + friend bool isinf (const mpreal& v); + friend bool isfinite (const mpreal& v); + + friend bool isnum (const mpreal& v); + friend bool iszero (const mpreal& v); + friend bool isint (const mpreal& v); + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + friend bool isregular(const mpreal& v); +#endif + + // Set/Get instance properties + inline mp_prec_t get_prec() const; + inline void set_prec(mp_prec_t prec, mp_rnd_t rnd_mode = get_default_rnd()); // Change precision with rounding mode + + // Aliases for get_prec(), set_prec() - needed for compatibility with std::complex interface + inline mpreal& setPrecision(int Precision, mp_rnd_t RoundingMode = get_default_rnd()); + inline int getPrecision() const; + + // Set mpreal to +/- inf, NaN, +/-0 + mpreal& setInf (int Sign = +1); + mpreal& setNan (); + mpreal& setZero (int Sign = +1); + mpreal& setSign (int Sign, mp_rnd_t RoundingMode = get_default_rnd()); + + //Exponent + mp_exp_t get_exp() const; + int set_exp(mp_exp_t e); + int check_range (int t, mp_rnd_t rnd_mode = get_default_rnd()); + int subnormalize (int t, mp_rnd_t rnd_mode = get_default_rnd()); + + // Inexact conversion from float + inline bool fits_in_bits(double x, int n); + + // Set/Get global properties + static void set_default_prec(mp_prec_t prec); + static void set_default_rnd(mp_rnd_t rnd_mode); + + static mp_exp_t get_emin (void); + static mp_exp_t get_emax (void); + static mp_exp_t get_emin_min (void); + static mp_exp_t get_emin_max (void); + static mp_exp_t get_emax_min (void); + static mp_exp_t get_emax_max (void); + static int set_emin (mp_exp_t exp); + static int set_emax (mp_exp_t exp); + + // Efficient swapping of two mpreal values - needed for std algorithms + friend void swap(mpreal& x, mpreal& y); + + friend const mpreal fmax(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + friend const mpreal fmin(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode); + +private: + // Human friendly Debug Preview in Visual Studio. + // Put one of these lines: + // + // mpfr::mpreal= ; Show value only + // mpfr::mpreal=, bits ; Show value & precision + // + // at the beginning of + // [Visual Studio Installation Folder]\Common7\Packages\Debugger\autoexp.dat + MPREAL_MSVC_DEBUGVIEW_DATA + + // "Smart" resources deallocation. Checks if instance initialized before deletion. + void clear(::mpfr_ptr); +}; + +////////////////////////////////////////////////////////////////////////// +// Exceptions +class conversion_overflow : public std::exception { +public: + std::string why() { return "inexact conversion from floating point"; } +}; + +////////////////////////////////////////////////////////////////////////// +// Constructors & converters +// Default constructor: creates mp number and initializes it to 0. +inline mpreal::mpreal() +{ + mpfr_init2(mpfr_ptr(), mpreal::get_default_prec()); + mpfr_set_zero_fast(mpfr_ptr()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpreal& u) +{ + mpfr_init2(mpfr_ptr(),mpfr_get_prec(u.mpfr_srcptr())); + mpfr_set (mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +#ifdef MPREAL_HAVE_MOVE_SUPPORT +inline mpreal::mpreal(mpreal&& other) +{ + mpfr_set_uninitialized(mpfr_ptr()); // make sure "other" holds null-pointer (in uninitialized state) + mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal& mpreal::operator=(mpreal&& other) +{ + if (this != &other) + { + mpfr_swap(mpfr_ptr(), other.mpfr_ptr()); // destructor for "other" will be called just afterwards + MPREAL_MSVC_DEBUGVIEW_CODE; + } + return *this; +} +#endif + +inline mpreal::mpreal(const mpfr_t u, bool shared) +{ + if(shared) + { + std::memcpy(mpfr_ptr(), u, sizeof(mpfr_t)); + } + else + { + mpfr_init2(mpfr_ptr(), mpfr_get_prec(u)); + mpfr_set (mpfr_ptr(), u, mpreal::get_default_rnd()); + } + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpf_t u) +{ + mpfr_init2(mpfr_ptr(),(mp_prec_t) mpf_get_prec(u)); // (gmp: mp_bitcnt_t) unsigned long -> long (mpfr: mp_prec_t) + mpfr_set_f(mpfr_ptr(),u,mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpz_t u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2(mpfr_ptr(), prec); + mpfr_set_z(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const mpq_t u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2(mpfr_ptr(), prec); + mpfr_set_q(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const double u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2(mpfr_ptr(), prec); + +#if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) + if(fits_in_bits(u, MPREAL_DOUBLE_BITS_OVERFLOW)) + { + mpfr_set_d(mpfr_ptr(), u, mode); + }else + throw conversion_overflow(); +#else + mpfr_set_d(mpfr_ptr(), u, mode); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const long double u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_ld(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const unsigned long long int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_uj(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const long long int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_sj(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const unsigned long int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_ui(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const unsigned int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_ui(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const long int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_si(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const int u, mp_prec_t prec, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_si(mpfr_ptr(), u, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_str(mpfr_ptr(), s, base, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mpreal::mpreal(const std::string& s, mp_prec_t prec, int base, mp_rnd_t mode) +{ + mpfr_init2 (mpfr_ptr(), prec); + mpfr_set_str(mpfr_ptr(), s.c_str(), base, mode); + + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline void mpreal::clear(::mpfr_ptr x) +{ +#ifdef MPREAL_HAVE_MOVE_SUPPORT + if(mpfr_is_initialized(x)) +#endif + mpfr_clear(x); +} + +inline mpreal::~mpreal() +{ + clear(mpfr_ptr()); +} + +// internal namespace needed for template magic +namespace internal{ + + // Use SFINAE to restrict arithmetic operations instantiation only for numeric types + // This is needed for smooth integration with libraries based on expression templates, like Eigen. + // TODO: Do the same for boolean operators. + template struct result_type {}; + + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; + template <> struct result_type {typedef mpreal type;}; +} + +// + Addition +template +inline const typename internal::result_type::type + operator+(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) += rhs; } + +template +inline const typename internal::result_type::type + operator+(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) += lhs; } + +// - Subtraction +template +inline const typename internal::result_type::type + operator-(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) -= rhs; } + +template +inline const typename internal::result_type::type + operator-(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) -= rhs; } + +// * Multiplication +template +inline const typename internal::result_type::type + operator*(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) *= rhs; } + +template +inline const typename internal::result_type::type + operator*(const Lhs& lhs, const mpreal& rhs){ return mpreal(rhs) *= lhs; } + +// / Division +template +inline const typename internal::result_type::type + operator/(const mpreal& lhs, const Rhs& rhs){ return mpreal(lhs) /= rhs; } + +template +inline const typename internal::result_type::type + operator/(const Lhs& lhs, const mpreal& rhs){ return mpreal(lhs) /= rhs; } + +////////////////////////////////////////////////////////////////////////// +// sqrt +const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const long int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const int v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const long double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal sqrt(const double v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +// abs +inline const mpreal abs(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()); + +////////////////////////////////////////////////////////////////////////// +// pow +const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); +inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode = mpreal::get_default_rnd()); + +////////////////////////////////////////////////////////////////////////// +// Estimate machine epsilon for the given precision +// Returns smallest eps such that 1.0 + eps != 1.0 +inline mpreal machine_epsilon(mp_prec_t prec = mpreal::get_default_prec()); + +// Returns smallest eps such that x + eps != x (relative machine epsilon) +inline mpreal machine_epsilon(const mpreal& x); + +// Gives max & min values for the required precision, +// minval is 'safe' meaning 1 / minval does not overflow +// maxval is 'safe' meaning 1 / maxval does not underflow +inline mpreal minval(mp_prec_t prec = mpreal::get_default_prec()); +inline mpreal maxval(mp_prec_t prec = mpreal::get_default_prec()); + +// 'Dirty' equality check 1: |a-b| < min{|a|,|b|} * eps +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps); + +// 'Dirty' equality check 2: |a-b| < min{|a|,|b|} * eps( min{|a|,|b|} ) +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b); + +// 'Bitwise' equality check +// maxUlps - a and b can be apart by maxUlps binary numbers. +inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps); + +////////////////////////////////////////////////////////////////////////// +// Convert precision in 'bits' to decimal digits and vice versa. +// bits = ceil(digits*log[2](10)) +// digits = floor(bits*log[10](2)) + +inline mp_prec_t digits2bits(int d); +inline int bits2digits(mp_prec_t b); + +////////////////////////////////////////////////////////////////////////// +// min, max +const mpreal (max)(const mpreal& x, const mpreal& y); +const mpreal (min)(const mpreal& x, const mpreal& y); + +////////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// +// Operators - Assignment +inline mpreal& mpreal::operator=(const mpreal& v) +{ + if (this != &v) + { + mp_prec_t tp = mpfr_get_prec( mpfr_srcptr()); + mp_prec_t vp = mpfr_get_prec(v.mpfr_srcptr()); + + if(tp != vp){ + clear(mpfr_ptr()); + mpfr_init2(mpfr_ptr(), vp); + } + + mpfr_set(mpfr_ptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + } + return *this; +} + +inline mpreal& mpreal::operator=(const mpf_t v) +{ + mpfr_set_f(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const mpz_t v) +{ + mpfr_set_z(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const mpq_t v) +{ + mpfr_set_q(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const long double v) +{ + mpfr_set_ld(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const double v) +{ +#if (MPREAL_DOUBLE_BITS_OVERFLOW > -1) + if(fits_in_bits(v, MPREAL_DOUBLE_BITS_OVERFLOW)) + { + mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); + }else + throw conversion_overflow(); +#else + mpfr_set_d(mpfr_ptr(),v,mpreal::get_default_rnd()); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const unsigned long int v) +{ + mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const unsigned int v) +{ + mpfr_set_ui(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const unsigned long long int v) +{ + mpfr_set_uj(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const long long int v) +{ + mpfr_set_sj(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const long int v) +{ + mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const int v) +{ + mpfr_set_si(mpfr_ptr(), v, mpreal::get_default_rnd()); + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator=(const char* s) +{ + // Use other converters for more precise control on base & precision & rounding: + // + // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) + // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) + // + // Here we assume base = 10 and we use precision of target variable. + + mpfr_t t; + + mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); + + if(0 == mpfr_set_str(t, s, 10, mpreal::get_default_rnd())) + { + mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + } + + clear(t); + return *this; +} + +inline mpreal& mpreal::operator=(const std::string& s) +{ + // Use other converters for more precise control on base & precision & rounding: + // + // mpreal(const char* s, mp_prec_t prec, int base, mp_rnd_t mode) + // mpreal(const std::string& s,mp_prec_t prec, int base, mp_rnd_t mode) + // + // Here we assume base = 10 and we use precision of target variable. + + mpfr_t t; + + mpfr_init2(t, mpfr_get_prec(mpfr_srcptr())); + + if(0 == mpfr_set_str(t, s.c_str(), 10, mpreal::get_default_rnd())) + { + mpfr_set(mpfr_ptr(), t, mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + } + + clear(t); + return *this; +} + +template +inline mpreal& mpreal::operator= (const std::complex& z) +{ + return *this = z.real(); +} + +////////////////////////////////////////////////////////////////////////// +// + Addition +inline mpreal& mpreal::operator+=(const mpreal& v) +{ + mpfr_add(mpfr_ptr(), mpfr_srcptr(), v.mpfr_srcptr(), mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const mpf_t u) +{ + *this += mpreal(u); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const mpz_t u) +{ + mpfr_add_z(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const mpq_t u) +{ + mpfr_add_q(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+= (const long double u) +{ + *this += mpreal(u); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+= (const double u) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_add_d(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); +#else + *this += mpreal(u); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const unsigned long int u) +{ + mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const unsigned int u) +{ + mpfr_add_ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const long int u) +{ + mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const int u) +{ + mpfr_add_si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator+=(const long long int u) { *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator+=(const unsigned long long int u){ *this += mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator-=(const long long int u) { *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator-=(const unsigned long long int u){ *this -= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator*=(const long long int u) { *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator*=(const unsigned long long int u){ *this *= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator/=(const long long int u) { *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } +inline mpreal& mpreal::operator/=(const unsigned long long int u){ *this /= mpreal(u); MPREAL_MSVC_DEBUGVIEW_CODE; return *this; } + +inline const mpreal mpreal::operator+()const { return mpreal(*this); } + +inline const mpreal operator+(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); + mpfr_add(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +inline mpreal& mpreal::operator++() +{ + return *this += 1; +} + +inline const mpreal mpreal::operator++ (int) +{ + mpreal x(*this); + *this += 1; + return x; +} + +inline mpreal& mpreal::operator--() +{ + return *this -= 1; +} + +inline const mpreal mpreal::operator-- (int) +{ + mpreal x(*this); + *this -= 1; + return x; +} + +////////////////////////////////////////////////////////////////////////// +// - Subtraction +inline mpreal& mpreal::operator-=(const mpreal& v) +{ + mpfr_sub(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const mpz_t v) +{ + mpfr_sub_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const mpq_t v) +{ + mpfr_sub_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const long double v) +{ + *this -= mpreal(v); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const double v) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_sub_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); +#else + *this -= mpreal(v); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const unsigned long int v) +{ + mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const unsigned int v) +{ + mpfr_sub_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const long int v) +{ + mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator-=(const int v) +{ + mpfr_sub_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal mpreal::operator-()const +{ + mpreal u(*this); + mpfr_neg(u.mpfr_ptr(),u.mpfr_srcptr(),mpreal::get_default_rnd()); + return u; +} + +inline const mpreal operator-(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); + mpfr_sub(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +inline const mpreal operator-(const double b, const mpreal& a) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_d_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +#else + mpreal x(b, mpfr_get_prec(a.mpfr_ptr())); + x -= a; + return x; +#endif +} + +inline const mpreal operator-(const unsigned long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator-(const unsigned int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_ui_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator-(const long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator-(const int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_ptr())); + mpfr_si_sub(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +////////////////////////////////////////////////////////////////////////// +// * Multiplication +inline mpreal& mpreal::operator*= (const mpreal& v) +{ + mpfr_mul(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const mpz_t v) +{ + mpfr_mul_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const mpq_t v) +{ + mpfr_mul_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const long double v) +{ + *this *= mpreal(v); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const double v) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_mul_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); +#else + *this *= mpreal(v); +#endif + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const unsigned long int v) +{ + mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const unsigned int v) +{ + mpfr_mul_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const long int v) +{ + mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator*=(const int v) +{ + mpfr_mul_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal operator*(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_ptr()), mpfr_get_prec(b.mpfr_ptr()))); + mpfr_mul(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +////////////////////////////////////////////////////////////////////////// +// / Division +inline mpreal& mpreal::operator/=(const mpreal& v) +{ + mpfr_div(mpfr_ptr(),mpfr_srcptr(),v.mpfr_srcptr(),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const mpz_t v) +{ + mpfr_div_z(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const mpq_t v) +{ + mpfr_div_q(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const long double v) +{ + *this /= mpreal(v); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const double v) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpfr_div_d(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); +#else + *this /= mpreal(v); +#endif + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const unsigned long int v) +{ + mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const unsigned int v) +{ + mpfr_div_ui(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const long int v) +{ + mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator/=(const int v) +{ + mpfr_div_si(mpfr_ptr(),mpfr_srcptr(),v,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal operator/(const mpreal& a, const mpreal& b) +{ + mpreal c(0, (std::max)(mpfr_get_prec(a.mpfr_srcptr()), mpfr_get_prec(b.mpfr_srcptr()))); + mpfr_div(c.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), mpreal::get_default_rnd()); + return c; +} + +inline const mpreal operator/(const unsigned long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const unsigned int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_ui_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const long int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const int b, const mpreal& a) +{ + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_si_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +} + +inline const mpreal operator/(const double b, const mpreal& a) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + mpreal x(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_d_div(x.mpfr_ptr(), b, a.mpfr_srcptr(), mpreal::get_default_rnd()); + return x; +#else + mpreal x(b, mpfr_get_prec(a.mpfr_ptr())); + x /= a; + return x; +#endif +} + +////////////////////////////////////////////////////////////////////////// +// Shifts operators - Multiplication/Division by power of 2 +inline mpreal& mpreal::operator<<=(const unsigned long int u) +{ + mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator<<=(const unsigned int u) +{ + mpfr_mul_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator<<=(const long int u) +{ + mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator<<=(const int u) +{ + mpfr_mul_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const unsigned long int u) +{ + mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const unsigned int u) +{ + mpfr_div_2ui(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const long int u) +{ + mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),u,mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::operator>>=(const int u) +{ + mpfr_div_2si(mpfr_ptr(),mpfr_srcptr(),static_cast(u),mpreal::get_default_rnd()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline const mpreal operator<<(const mpreal& v, const unsigned long int k) +{ + return mul_2ui(v,k); +} + +inline const mpreal operator<<(const mpreal& v, const unsigned int k) +{ + return mul_2ui(v,static_cast(k)); +} + +inline const mpreal operator<<(const mpreal& v, const long int k) +{ + return mul_2si(v,k); +} + +inline const mpreal operator<<(const mpreal& v, const int k) +{ + return mul_2si(v,static_cast(k)); +} + +inline const mpreal operator>>(const mpreal& v, const unsigned long int k) +{ + return div_2ui(v,k); +} + +inline const mpreal operator>>(const mpreal& v, const long int k) +{ + return div_2si(v,k); +} + +inline const mpreal operator>>(const mpreal& v, const unsigned int k) +{ + return div_2ui(v,static_cast(k)); +} + +inline const mpreal operator>>(const mpreal& v, const int k) +{ + return div_2si(v,static_cast(k)); +} + +// mul_2ui +inline const mpreal mul_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_mul_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +// mul_2si +inline const mpreal mul_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_mul_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +inline const mpreal div_2ui(const mpreal& v, unsigned long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_div_2ui(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +inline const mpreal div_2si(const mpreal& v, long int k, mp_rnd_t rnd_mode) +{ + mpreal x(v); + mpfr_div_2si(x.mpfr_ptr(),v.mpfr_srcptr(),k,rnd_mode); + return x; +} + +////////////////////////////////////////////////////////////////////////// +//Relational operators + +// WARNING: +// +// Please note that following checks for double-NaN are guaranteed to work only in IEEE math mode: +// +// isnan(b) = (b != b) +// isnan(b) = !(b == b) (we use in code below) +// +// Be cautions if you use compiler options which break strict IEEE compliance (e.g. -ffast-math in GCC). +// Use std::isnan instead (C++11). + +inline bool operator > (const mpreal& a, const mpreal& b ){ return (mpfr_greater_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } +inline bool operator > (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) > 0 ); } +inline bool operator > (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) > 0 ); } +inline bool operator > (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) > 0 ); } +inline bool operator > (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) > 0 ); } +inline bool operator > (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) > 0 ); } +inline bool operator > (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) > 0 ); } + +inline bool operator >= (const mpreal& a, const mpreal& b ){ return (mpfr_greaterequal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } +inline bool operator >= (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) >= 0 ); } +inline bool operator >= (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) >= 0 ); } +inline bool operator >= (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) >= 0 ); } +inline bool operator >= (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) >= 0 ); } +inline bool operator >= (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) >= 0 ); } +inline bool operator >= (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) >= 0 ); } + +inline bool operator < (const mpreal& a, const mpreal& b ){ return (mpfr_less_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } +inline bool operator < (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) < 0 ); } +inline bool operator < (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) < 0 ); } +inline bool operator < (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) < 0 ); } +inline bool operator < (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) < 0 ); } +inline bool operator < (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) < 0 ); } +inline bool operator < (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) < 0 ); } + +inline bool operator <= (const mpreal& a, const mpreal& b ){ return (mpfr_lessequal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } +inline bool operator <= (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) <= 0 ); } +inline bool operator <= (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) <= 0 ); } +inline bool operator <= (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) <= 0 ); } +inline bool operator <= (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) <= 0 ); } +inline bool operator <= (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) <= 0 ); } +inline bool operator <= (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) <= 0 ); } + +inline bool operator == (const mpreal& a, const mpreal& b ){ return (mpfr_equal_p(a.mpfr_srcptr(),b.mpfr_srcptr()) != 0 ); } +inline bool operator == (const mpreal& a, const unsigned long int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const unsigned int b ){ return !isnan(a) && (mpfr_cmp_ui(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const long int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const int b ){ return !isnan(a) && (mpfr_cmp_si(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const long double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_ld(a.mpfr_srcptr(),b) == 0 ); } +inline bool operator == (const mpreal& a, const double b ){ return !isnan(a) && (b == b) && (mpfr_cmp_d (a.mpfr_srcptr(),b) == 0 ); } + +inline bool operator != (const mpreal& a, const mpreal& b ){ return !(a == b); } +inline bool operator != (const mpreal& a, const unsigned long int b ){ return !(a == b); } +inline bool operator != (const mpreal& a, const unsigned int b ){ return !(a == b); } +inline bool operator != (const mpreal& a, const long int b ){ return !(a == b); } +inline bool operator != (const mpreal& a, const int b ){ return !(a == b); } +inline bool operator != (const mpreal& a, const long double b ){ return !(a == b); } +inline bool operator != (const mpreal& a, const double b ){ return !(a == b); } + +inline bool isnan (const mpreal& op){ return (mpfr_nan_p (op.mpfr_srcptr()) != 0 ); } +inline bool isinf (const mpreal& op){ return (mpfr_inf_p (op.mpfr_srcptr()) != 0 ); } +inline bool isfinite (const mpreal& op){ return (mpfr_number_p (op.mpfr_srcptr()) != 0 ); } +inline bool iszero (const mpreal& op){ return (mpfr_zero_p (op.mpfr_srcptr()) != 0 ); } +inline bool isint (const mpreal& op){ return (mpfr_integer_p(op.mpfr_srcptr()) != 0 ); } + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) +inline bool isregular(const mpreal& op){ return (mpfr_regular_p(op.mpfr_srcptr()));} +#endif + +////////////////////////////////////////////////////////////////////////// +// Type Converters +inline bool mpreal::toBool ( ) const { return mpfr_zero_p (mpfr_srcptr()) == 0; } +inline long mpreal::toLong (mp_rnd_t mode) const { return mpfr_get_si (mpfr_srcptr(), mode); } +inline unsigned long mpreal::toULong (mp_rnd_t mode) const { return mpfr_get_ui (mpfr_srcptr(), mode); } +inline float mpreal::toFloat (mp_rnd_t mode) const { return mpfr_get_flt(mpfr_srcptr(), mode); } +inline double mpreal::toDouble (mp_rnd_t mode) const { return mpfr_get_d (mpfr_srcptr(), mode); } +inline long double mpreal::toLDouble(mp_rnd_t mode) const { return mpfr_get_ld (mpfr_srcptr(), mode); } +inline long long mpreal::toLLong (mp_rnd_t mode) const { return mpfr_get_sj (mpfr_srcptr(), mode); } +inline unsigned long long mpreal::toULLong (mp_rnd_t mode) const { return mpfr_get_uj (mpfr_srcptr(), mode); } + +inline ::mpfr_ptr mpreal::mpfr_ptr() { return mp; } +inline ::mpfr_srcptr mpreal::mpfr_ptr() const { return mp; } +inline ::mpfr_srcptr mpreal::mpfr_srcptr() const { return mp; } + +template +inline std::string toString(T t, std::ios_base & (*f)(std::ios_base&)) +{ + std::ostringstream oss; + oss << f << t; + return oss.str(); +} + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + +inline std::string mpreal::toString(const std::string& format) const +{ + char *s = NULL; + std::string out; + + if( !format.empty() ) + { + if(!(mpfr_asprintf(&s, format.c_str(), mpfr_srcptr()) < 0)) + { + out = std::string(s); + + mpfr_free_str(s); + } + } + + return out; +} + +#endif + +inline std::string mpreal::toString(int n, int b, mp_rnd_t mode) const +{ + // TODO: Add extended format specification (f, e, rounding mode) as it done in output operator + (void)b; + (void)mode; + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + + std::ostringstream format; + + int digits = (n >= 0) ? n : 2 + bits2digits(mpfr_get_prec(mpfr_srcptr())); + + format << "%." << digits << "RNg"; + + return toString(format.str()); + +#else + + char *s, *ns = NULL; + size_t slen, nslen; + mp_exp_t exp; + std::string out; + + if(mpfr_inf_p(mp)) + { + if(mpfr_sgn(mp)>0) return "+Inf"; + else return "-Inf"; + } + + if(mpfr_zero_p(mp)) return "0"; + if(mpfr_nan_p(mp)) return "NaN"; + + s = mpfr_get_str(NULL, &exp, b, 0, mp, mode); + ns = mpfr_get_str(NULL, &exp, b, (std::max)(0,n), mp, mode); + + if(s!=NULL && ns!=NULL) + { + slen = strlen(s); + nslen = strlen(ns); + if(nslen<=slen) + { + mpfr_free_str(s); + s = ns; + slen = nslen; + } + else { + mpfr_free_str(ns); + } + + // Make human eye-friendly formatting if possible + if (exp>0 && static_cast(exp)s+exp) ptr--; + + if(ptr==s+exp) out = std::string(s,exp+1); + else out = std::string(s,exp+1)+'.'+std::string(s+exp+1,ptr-(s+exp+1)+1); + + //out = string(s,exp+1)+'.'+string(s+exp+1); + } + else + { + // Remove zeros starting from right end + char* ptr = s+slen-1; + while (*ptr=='0' && ptr>s+exp-1) ptr--; + + if(ptr==s+exp-1) out = std::string(s,exp); + else out = std::string(s,exp)+'.'+std::string(s+exp,ptr-(s+exp)+1); + + //out = string(s,exp)+'.'+string(s+exp); + } + + }else{ // exp<0 || exp>slen + if(s[0]=='-') + { + // Remove zeros starting from right end + char* ptr = s+slen-1; + while (*ptr=='0' && ptr>s+1) ptr--; + + if(ptr==s+1) out = std::string(s,2); + else out = std::string(s,2)+'.'+std::string(s+2,ptr-(s+2)+1); + + //out = string(s,2)+'.'+string(s+2); + } + else + { + // Remove zeros starting from right end + char* ptr = s+slen-1; + while (*ptr=='0' && ptr>s) ptr--; + + if(ptr==s) out = std::string(s,1); + else out = std::string(s,1)+'.'+std::string(s+1,ptr-(s+1)+1); + + //out = string(s,1)+'.'+string(s+1); + } + + // Make final string + if(--exp) + { + if(exp>0) out += "e+"+mpfr::toString(exp,std::dec); + else out += "e"+mpfr::toString(exp,std::dec); + } + } + + mpfr_free_str(s); + return out; + }else{ + return "conversion error!"; + } +#endif +} + + +////////////////////////////////////////////////////////////////////////// +// I/O +inline std::ostream& mpreal::output(std::ostream& os) const +{ + std::ostringstream format; + const std::ios::fmtflags flags = os.flags(); + + format << ((flags & std::ios::showpos) ? "%+" : "%"); + if (os.precision() >= 0) + format << '.' << os.precision() << "R*" + << ((flags & std::ios::floatfield) == std::ios::fixed ? 'f' : + (flags & std::ios::floatfield) == std::ios::scientific ? 'e' : + 'g'); + else + format << "R*e"; + + char *s = NULL; + if(!(mpfr_asprintf(&s, format.str().c_str(), + mpfr::mpreal::get_default_rnd(), + mpfr_srcptr()) + < 0)) + { + os << std::string(s); + mpfr_free_str(s); + } + return os; +} + +inline std::ostream& operator<<(std::ostream& os, const mpreal& v) +{ + return v.output(os); +} + +inline std::istream& operator>>(std::istream &is, mpreal& v) +{ + // TODO: use cout::hexfloat and other flags to setup base + std::string tmp; + is >> tmp; + mpfr_set_str(v.mpfr_ptr(), tmp.c_str(), 10, mpreal::get_default_rnd()); + return is; +} + +////////////////////////////////////////////////////////////////////////// +// Bits - decimal digits relation +// bits = ceil(digits*log[2](10)) +// digits = floor(bits*log[10](2)) + +inline mp_prec_t digits2bits(int d) +{ + const double LOG2_10 = 3.3219280948873624; + + return mp_prec_t(std::ceil( d * LOG2_10 )); +} + +inline int bits2digits(mp_prec_t b) +{ + const double LOG10_2 = 0.30102999566398119; + + return int(std::floor( b * LOG10_2 )); +} + +////////////////////////////////////////////////////////////////////////// +// Set/Get number properties +inline mpreal& mpreal::setSign(int sign, mp_rnd_t RoundingMode) +{ + mpfr_setsign(mpfr_ptr(), mpfr_srcptr(), sign < 0, RoundingMode); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline int mpreal::getPrecision() const +{ + return int(mpfr_get_prec(mpfr_srcptr())); +} + +inline mpreal& mpreal::setPrecision(int Precision, mp_rnd_t RoundingMode) +{ + mpfr_prec_round(mpfr_ptr(), Precision, RoundingMode); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::setInf(int sign) +{ + mpfr_set_inf(mpfr_ptr(), sign); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::setNan() +{ + mpfr_set_nan(mpfr_ptr()); + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mpreal& mpreal::setZero(int sign) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + mpfr_set_zero(mpfr_ptr(), sign); +#else + mpfr_set_si(mpfr_ptr(), 0, (mpfr_get_default_rounding_mode)()); + setSign(sign); +#endif + + MPREAL_MSVC_DEBUGVIEW_CODE; + return *this; +} + +inline mp_prec_t mpreal::get_prec() const +{ + return mpfr_get_prec(mpfr_srcptr()); +} + +inline void mpreal::set_prec(mp_prec_t prec, mp_rnd_t rnd_mode) +{ + mpfr_prec_round(mpfr_ptr(),prec,rnd_mode); + MPREAL_MSVC_DEBUGVIEW_CODE; +} + +inline mp_exp_t mpreal::get_exp () const +{ + return mpfr_get_exp(mpfr_srcptr()); +} + +inline int mpreal::set_exp (mp_exp_t e) +{ + int x = mpfr_set_exp(mpfr_ptr(), e); + MPREAL_MSVC_DEBUGVIEW_CODE; + return x; +} + +inline mpreal& negate(mpreal& x) // -x in place +{ + mpfr_neg(x.mpfr_ptr(),x.mpfr_srcptr(),mpreal::get_default_rnd()); + return x; +} + +inline const mpreal frexp(const mpreal& x, mp_exp_t* exp, mp_rnd_t mode = mpreal::get_default_rnd()) +{ + mpreal y(x); +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,1,0)) + mpfr_frexp(exp,y.mpfr_ptr(),x.mpfr_srcptr(),mode); +#else + *exp = mpfr_get_exp(y.mpfr_srcptr()); + mpfr_set_exp(y.mpfr_ptr(),0); +#endif + return y; +} + +inline const mpreal frexp(const mpreal& x, int* exp, mp_rnd_t mode = mpreal::get_default_rnd()) +{ + mp_exp_t expl; + mpreal y = frexp(x, &expl, mode); + *exp = int(expl); + return y; +} + +inline const mpreal ldexp(const mpreal& v, mp_exp_t exp) +{ + mpreal x(v); + + // rounding is not important since we are just increasing the exponent (= exact operation) + mpfr_mul_2si(x.mpfr_ptr(), x.mpfr_srcptr(), exp, mpreal::get_default_rnd()); + return x; +} + +inline const mpreal scalbn(const mpreal& v, mp_exp_t exp) +{ + return ldexp(v, exp); +} + +inline mpreal machine_epsilon(mp_prec_t prec) +{ + /* the smallest eps such that 1 + eps != 1 */ + return machine_epsilon(mpreal(1, prec)); +} + +inline mpreal machine_epsilon(const mpreal& x) +{ + /* the smallest eps such that x + eps != x */ + if( x < 0) + { + return nextabove(-x) + x; + }else{ + return nextabove( x) - x; + } +} + +// minval is 'safe' meaning 1 / minval does not overflow +inline mpreal minval(mp_prec_t prec) +{ + /* min = 1/2 * 2^emin = 2^(emin - 1) */ + return mpreal(1, prec) << mpreal::get_emin()-1; +} + +// maxval is 'safe' meaning 1 / maxval does not underflow +inline mpreal maxval(mp_prec_t prec) +{ + /* max = (1 - eps) * 2^emax, eps is machine epsilon */ + return (mpreal(1, prec) - machine_epsilon(prec)) << mpreal::get_emax(); +} + +inline bool isEqualUlps(const mpreal& a, const mpreal& b, int maxUlps) +{ + return abs(a - b) <= machine_epsilon((max)(abs(a), abs(b))) * maxUlps; +} + +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b, const mpreal& eps) +{ + return abs(a - b) <= eps; +} + +inline bool isEqualFuzzy(const mpreal& a, const mpreal& b) +{ + return isEqualFuzzy(a, b, machine_epsilon((max)(1, (min)(abs(a), abs(b))))); +} + +////////////////////////////////////////////////////////////////////////// +// C++11 sign functions. +inline mpreal copysign(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal rop(0, mpfr_get_prec(x.mpfr_ptr())); + mpfr_setsign(rop.mpfr_ptr(), x.mpfr_srcptr(), mpfr_signbit(y.mpfr_srcptr()), rnd_mode); + return rop; +} + +inline bool signbit(const mpreal& x) +{ + return mpfr_signbit(x.mpfr_srcptr()); +} + +inline mpreal& setsignbit(mpreal& x, bool minus, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpfr_setsign(x.mpfr_ptr(), x.mpfr_srcptr(), minus, rnd_mode); + return x; +} + +inline const mpreal modf(const mpreal& v, mpreal& n) +{ + mpreal f(v); + + // rounding is not important since we are using the same number + mpfr_frac (f.mpfr_ptr(),f.mpfr_srcptr(),mpreal::get_default_rnd()); + mpfr_trunc(n.mpfr_ptr(),v.mpfr_srcptr()); + return f; +} + +inline int mpreal::check_range (int t, mp_rnd_t rnd_mode) +{ + return mpfr_check_range(mpfr_ptr(),t,rnd_mode); +} + +inline int mpreal::subnormalize (int t,mp_rnd_t rnd_mode) +{ + int r = mpfr_subnormalize(mpfr_ptr(),t,rnd_mode); + MPREAL_MSVC_DEBUGVIEW_CODE; + return r; +} + +inline mp_exp_t mpreal::get_emin (void) +{ + return mpfr_get_emin(); +} + +inline int mpreal::set_emin (mp_exp_t exp) +{ + return mpfr_set_emin(exp); +} + +inline mp_exp_t mpreal::get_emax (void) +{ + return mpfr_get_emax(); +} + +inline int mpreal::set_emax (mp_exp_t exp) +{ + return mpfr_set_emax(exp); +} + +inline mp_exp_t mpreal::get_emin_min (void) +{ + return mpfr_get_emin_min(); +} + +inline mp_exp_t mpreal::get_emin_max (void) +{ + return mpfr_get_emin_max(); +} + +inline mp_exp_t mpreal::get_emax_min (void) +{ + return mpfr_get_emax_min(); +} + +inline mp_exp_t mpreal::get_emax_max (void) +{ + return mpfr_get_emax_max(); +} + +////////////////////////////////////////////////////////////////////////// +// Mathematical Functions +////////////////////////////////////////////////////////////////////////// + +// Unary function template with single 'mpreal' argument +#define MPREAL_UNARY_MATH_FUNCTION_BODY(f) \ + mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); \ + mpfr_##f(y.mpfr_ptr(), x.mpfr_srcptr(), r); \ + return y; + +// Binary function template with 'mpreal' and 'unsigned long' arguments +#define MPREAL_BINARY_MATH_FUNCTION_UI_BODY(f, u) \ + mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); \ + mpfr_##f(y.mpfr_ptr(), x.mpfr_srcptr(), u, r); \ + return y; + +inline const mpreal sqr (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ MPREAL_UNARY_MATH_FUNCTION_BODY(sqr ); } + +inline const mpreal sqrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ MPREAL_UNARY_MATH_FUNCTION_BODY(sqrt); } + +inline const mpreal sqrt(const unsigned long int x, mp_rnd_t r) +{ + mpreal y; + mpfr_sqrt_ui(y.mpfr_ptr(), x, r); + return y; +} + +inline const mpreal sqrt(const unsigned int v, mp_rnd_t rnd_mode) +{ + return sqrt(static_cast(v),rnd_mode); +} + +inline const mpreal sqrt(const long int v, mp_rnd_t rnd_mode) +{ + if (v>=0) return sqrt(static_cast(v),rnd_mode); + else return mpreal().setNan(); // NaN +} + +inline const mpreal sqrt(const int v, mp_rnd_t rnd_mode) +{ + if (v>=0) return sqrt(static_cast(v),rnd_mode); + else return mpreal().setNan(); // NaN +} + +inline const mpreal root(const mpreal& x, unsigned long int k, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, mpfr_get_prec(x.mpfr_srcptr())); +#if (MPFR_VERSION >= MPFR_VERSION_NUM(4,0,0)) + mpfr_rootn_ui(y.mpfr_ptr(), x.mpfr_srcptr(), k, r); +#else + mpfr_root(y.mpfr_ptr(), x.mpfr_srcptr(), k, r); +#endif + return y; +} + +inline const mpreal dim(const mpreal& a, const mpreal& b, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, mpfr_get_prec(a.mpfr_srcptr())); + mpfr_dim(y.mpfr_ptr(), a.mpfr_srcptr(), b.mpfr_srcptr(), r); + return y; +} + +inline int cmpabs(const mpreal& a,const mpreal& b) +{ + return mpfr_cmpabs(a.mpfr_ptr(), b.mpfr_srcptr()); +} + +inline int sin_cos(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + return mpfr_sin_cos(s.mpfr_ptr(), c.mpfr_ptr(), v.mpfr_srcptr(), rnd_mode); +} + +inline const mpreal sqrt (const long double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } +inline const mpreal sqrt (const double v, mp_rnd_t rnd_mode) { return sqrt(mpreal(v),rnd_mode); } + +inline const mpreal cbrt (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cbrt ); } +inline const mpreal fabs (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } +inline const mpreal abs (const mpreal& x, mp_rnd_t r) { MPREAL_UNARY_MATH_FUNCTION_BODY(abs ); } +inline const mpreal log (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log ); } +inline const mpreal log2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log2 ); } +inline const mpreal log10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log10); } +inline const mpreal exp (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp ); } +inline const mpreal exp2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp2 ); } +inline const mpreal exp10 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp10); } +inline const mpreal cos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cos ); } +inline const mpreal sin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sin ); } +inline const mpreal tan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tan ); } +inline const mpreal sec (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sec ); } +inline const mpreal csc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csc ); } +inline const mpreal cot (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cot ); } +inline const mpreal acos (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acos ); } +inline const mpreal asin (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asin ); } +inline const mpreal atan (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atan ); } + +inline const mpreal logb (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { return log2 (abs(x),r); } +inline mp_exp_t ilogb (const mpreal& x) { return x.get_exp(); } + +inline const mpreal acot (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atan (1/v, r); } +inline const mpreal asec (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acos (1/v, r); } +inline const mpreal acsc (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asin (1/v, r); } +inline const mpreal acoth (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return atanh(1/v, r); } +inline const mpreal asech (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return acosh(1/v, r); } +inline const mpreal acsch (const mpreal& v, mp_rnd_t r = mpreal::get_default_rnd()) { return asinh(1/v, r); } + +inline const mpreal cosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cosh ); } +inline const mpreal sinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sinh ); } +inline const mpreal tanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tanh ); } +inline const mpreal sech (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sech ); } +inline const mpreal csch (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(csch ); } +inline const mpreal coth (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(coth ); } +inline const mpreal acosh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acosh); } +inline const mpreal asinh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asinh); } +inline const mpreal atanh (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atanh); } + +inline const mpreal log1p (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log1p ); } +inline const mpreal expm1 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(expm1 ); } +inline const mpreal eint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(eint ); } +inline const mpreal gamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(gamma ); } +inline const mpreal tgamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(gamma ); } +inline const mpreal lngamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(lngamma); } +inline const mpreal zeta (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(zeta ); } +inline const mpreal erf (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erf ); } +inline const mpreal erfc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(erfc ); } +inline const mpreal besselj0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j0 ); } +inline const mpreal besselj1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(j1 ); } +inline const mpreal bessely0(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y0 ); } +inline const mpreal bessely1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(y1 ); } + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(4,0,0)) +inline const mpreal gammainc (const mpreal& a, const mpreal& x, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* + The non-normalized (upper) incomplete gamma function of a and x: + gammainc(a,x) := Gamma(a,x) = int(t^(a-1) * exp(-t), t=x..infinity) + */ + mpreal y(0,(std::max)(a.getPrecision(), x.getPrecision())); + mpfr_gamma_inc(y.mpfr_ptr(), a.mpfr_srcptr(), x.mpfr_srcptr(), rnd_mode); + return y; +} + +inline const mpreal beta (const mpreal& z, const mpreal& w, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* + Beta function, uses formula (6.2.2) from Abramowitz & Stegun: + beta(z,w) = gamma(z)*gamma(w)/gamma(z+w) + */ + mpreal y(0,(std::max)(z.getPrecision(), w.getPrecision())); + mpfr_beta(y.mpfr_ptr(), z.mpfr_srcptr(), w.mpfr_srcptr(), rnd_mode); + return y; +} + +inline const mpreal log_ui (unsigned long int n, mp_prec_t prec = mpreal::get_default_prec(), mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* Computes natural logarithm of an unsigned long */ + mpreal y(0, prec); + mpfr_log_ui(y.mpfr_ptr(),n,rnd_mode); + return y; +} +#endif + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)) + +/* f(x,u) = f(2*pi*x/u) */ +inline const mpreal cosu (const mpreal& x, unsigned long u, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_BINARY_MATH_FUNCTION_UI_BODY(cosu, u); } +inline const mpreal sinu (const mpreal& x, unsigned long u, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_BINARY_MATH_FUNCTION_UI_BODY(sinu, u); } +inline const mpreal tanu (const mpreal& x, unsigned long u, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_BINARY_MATH_FUNCTION_UI_BODY(tanu, u); } +inline const mpreal acosu (const mpreal& x, unsigned long u, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_BINARY_MATH_FUNCTION_UI_BODY(acosu, u); } +inline const mpreal asinu (const mpreal& x, unsigned long u, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_BINARY_MATH_FUNCTION_UI_BODY(asinu, u); } +inline const mpreal atanu (const mpreal& x, unsigned long u, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_BINARY_MATH_FUNCTION_UI_BODY(atanu, u); } + +/* f(x) = f(pi*x) */ +inline const mpreal cospi (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(cospi ); } +inline const mpreal sinpi (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(sinpi ); } +inline const mpreal tanpi (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(tanpi ); } +inline const mpreal acospi (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(acospi); } +inline const mpreal asinpi (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(asinpi); } +inline const mpreal atanpi (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(atanpi); } + +inline const mpreal log2p1 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log2p1 ); } /* log2 (1+x) */ +inline const mpreal log10p1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(log10p1); } /* log10(1+x) */ +inline const mpreal exp2m1 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp2m1 ); } /* 2^x-1 */ +inline const mpreal exp10m1(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(exp10m1); } /* 10^x-1 */ + +inline const mpreal atan2u(const mpreal& y, const mpreal& x, unsigned long u, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* + atan2u(y,x,u) = atan(|y/x|)*u/(2*pi) for x > 0 + atan2u(y,x,u) = 1-atan(|y/x|)*u/(2*pi) for x < 0 + */ + mpreal a(0, (std::max)(y.getPrecision(), x.getPrecision())); + mpfr_atan2u(a.mpfr_ptr(), y.mpfr_srcptr(), x.mpfr_srcptr(), u, rnd_mode); + return a; +} + +inline const mpreal atan2pi(const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* atan2pi(x) = atan2u(u=2) */ + mpreal a(0, (std::max)(y.getPrecision(), x.getPrecision())); + mpfr_atan2pi(a.mpfr_ptr(), y.mpfr_srcptr(), x.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal powr(const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* powr(x,y) = exp(y*log(x)) */ + mpreal a(0, (std::max)(x.getPrecision(), y.getPrecision())); + mpfr_powr(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal compound(const mpreal& x, long n, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* compound(x,n) = (1+x)^n */ + mpreal y(0, x.getPrecision()); + mpfr_compound_si(y.mpfr_ptr(),x.mpfr_srcptr(),n,rnd_mode); + return y; +} + +inline const mpreal fmod(const mpreal& x, unsigned long u, mp_rnd_t r = mpreal::get_default_rnd()) +{ + /* x modulo a machine integer u */ + MPREAL_BINARY_MATH_FUNCTION_UI_BODY(fmod_ui, u); +} +#endif + +inline const mpreal nextpow2(const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, x.getPrecision()); + + if(!iszero(x)) + y = ceil(log2(abs(x,r),r)); + + return y; +} + +inline const mpreal atan2 (const mpreal& y, const mpreal& x, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_atan2(a.mpfr_ptr(), y.mpfr_srcptr(), x.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal hypot (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_hypot(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal hypot(const mpreal& a, const mpreal& b, const mpreal& c) +{ + if(isnan(a) || isnan(b) || isnan(c)) return mpreal().setNan(); + else + { + mpreal absa = abs(a), absb = abs(b), absc = abs(c); + mpreal w = (std::max)(absa, (std::max)(absb, absc)); + mpreal r; + + if (!iszero(w)) + { + mpreal iw = 1/w; + r = w * sqrt(sqr(absa*iw) + sqr(absb*iw) + sqr(absc*iw)); + } + + return r; + } +} + +inline const mpreal hypot(const mpreal& a, const mpreal& b, const mpreal& c, const mpreal& d) +{ + if(isnan(a) || isnan(b) || isnan(c) || isnan(d)) return mpreal().setNan(); + else + { + mpreal absa = abs(a), absb = abs(b), absc = abs(c), absd = abs(d); + mpreal w = (std::max)(absa, (std::max)(absb, (std::max)(absc, absd))); + mpreal r; + + if (!iszero(w)) + { + mpreal iw = 1/w; + r = w * sqrt(sqr(absa*iw) + sqr(absb*iw) + sqr(absc*iw) + sqr(absd*iw)); + } + + return r; + } +} + +inline const mpreal remainder (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_remainder(a.mpfr_ptr(), x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); + return a; +} + +inline const mpreal remquo (const mpreal& x, const mpreal& y, int* q, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + long lq; + mpreal a(0,(std::max)(y.getPrecision(), x.getPrecision())); + mpfr_remquo(a.mpfr_ptr(), &lq, x.mpfr_srcptr(), y.mpfr_srcptr(), rnd_mode); + if (q) *q = int(lq); + return a; +} + +inline const mpreal fac_ui (unsigned long int v, mp_prec_t prec = mpreal::get_default_prec(), + mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(0, prec); + mpfr_fac_ui(x.mpfr_ptr(),v,rnd_mode); + return x; +} + + +inline const mpreal lgamma (const mpreal& v, int *signp = 0, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(v); + int tsignp; + + if(signp) mpfr_lgamma(x.mpfr_ptr(), signp,v.mpfr_srcptr(),rnd_mode); + else mpfr_lgamma(x.mpfr_ptr(),&tsignp,v.mpfr_srcptr(),rnd_mode); + + return x; +} + + +inline const mpreal besseljn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, x.getPrecision()); + mpfr_jn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); + return y; +} + +inline const mpreal besselyn (long n, const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal y(0, x.getPrecision()); + mpfr_yn(y.mpfr_ptr(), n, x.mpfr_srcptr(), r); + return y; +} + +inline const mpreal fma (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t p1, p2, p3; + + p1 = v1.get_prec(); + p2 = v2.get_prec(); + p3 = v3.get_prec(); + + a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); + + mpfr_fma(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); + return a; +} + +inline const mpreal fms (const mpreal& v1, const mpreal& v2, const mpreal& v3, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t p1, p2, p3; + + p1 = v1.get_prec(); + p2 = v2.get_prec(); + p3 = v3.get_prec(); + + a.set_prec(p3>p2?(p3>p1?p3:p1):(p2>p1?p2:p1)); + + mpfr_fms(a.mp,v1.mp,v2.mp,v3.mp,rnd_mode); + return a; +} + +inline const mpreal agm (const mpreal& v1, const mpreal& v2, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t p1, p2; + + p1 = v1.get_prec(); + p2 = v2.get_prec(); + + a.set_prec(p1>p2?p1:p2); + + mpfr_agm(a.mp, v1.mp, v2.mp, rnd_mode); + + return a; +} + +inline const mpreal sum (const mpreal tab[], const unsigned long int n, int& status, mp_rnd_t mode = mpreal::get_default_rnd()) +{ + mpfr_srcptr *p = new mpfr_srcptr[n]; + + for (unsigned long int i = 0; i < n; i++) + p[i] = tab[i].mpfr_srcptr(); + + mpreal x; + status = mpfr_sum(x.mpfr_ptr(), (mpfr_ptr*)p, n, mode); + + delete [] p; + return x; +} + +////////////////////////////////////////////////////////////////////////// +// MPFR 2.4.0 Specifics +#if (MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)) + +inline int sinh_cosh(mpreal& s, mpreal& c, const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + return mpfr_sinh_cosh(s.mp,c.mp,v.mp,rnd_mode); +} + +inline const mpreal li2 (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) +{ + MPREAL_UNARY_MATH_FUNCTION_BODY(li2); +} + +inline const mpreal rem (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + /* R = rem(X,Y) if Y != 0, returns X - n * Y where n = trunc(X/Y). */ + return fmod(x, y, rnd_mode); +} + +inline const mpreal mod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + (void)rnd_mode; + + /* + + m = mod(x,y) if y != 0, returns x - n*y where n = floor(x/y) + + The following are true by convention: + - mod(x,0) is x + - mod(x,x) is 0 + - mod(x,y) for x != y and y != 0 has the same sign as y. + + */ + + if(iszero(y)) return x; + if(x == y) return 0; + + mpreal m = x - floor(x / y) * y; + + return copysign(abs(m),y); // make sure result has the same sign as Y +} + +inline const mpreal fmod (const mpreal& x, const mpreal& y, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal a; + mp_prec_t yp, xp; + + yp = y.get_prec(); + xp = x.get_prec(); + + a.set_prec(yp>xp?yp:xp); + + mpfr_fmod(a.mp, x.mp, y.mp, rnd_mode); + + return a; +} + +inline const mpreal rec_sqrt(const mpreal& v, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(v); + mpfr_rec_sqrt(x.mp,v.mp,rnd_mode); + return x; +} +#endif // MPFR 2.4.0 Specifics + +////////////////////////////////////////////////////////////////////////// +// MPFR 3.0.0 Specifics +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) +inline const mpreal digamma (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(digamma); } +inline const mpreal ai (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(ai); } +#endif // MPFR 3.0.0 Specifics + +////////////////////////////////////////////////////////////////////////// +// Constants +inline const mpreal const_log2 (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_log2(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_pi (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_pi(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_euler (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_euler(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_catalan (mp_prec_t p = mpreal::get_default_prec(), mp_rnd_t r = mpreal::get_default_rnd()) +{ + mpreal x(0, p); + mpfr_const_catalan(x.mpfr_ptr(), r); + return x; +} + +inline const mpreal const_infinity (int sign = 1, mp_prec_t p = mpreal::get_default_prec()) +{ + mpreal x(0, p); + mpfr_set_inf(x.mpfr_ptr(), sign); + return x; +} + +////////////////////////////////////////////////////////////////////////// +// Integer Related Functions +inline const mpreal ceil(const mpreal& v) +{ + mpreal x(v); + mpfr_ceil(x.mp,v.mp); + return x; +} + +inline const mpreal floor(const mpreal& v) +{ + mpreal x(v); + mpfr_floor(x.mp,v.mp); + return x; +} + +inline const mpreal round(const mpreal& v) +{ + mpreal x(v); + mpfr_round(x.mp,v.mp); + return x; +} + +inline long lround(const mpreal& v) +{ + long r = std::numeric_limits::min(); + mpreal x = round(v); + if (abs(x) < -mpreal(r)) // Assume mpreal(LONG_MIN) is exact + r = x.toLong(); + return r; +} + +inline long long llround(const mpreal& v) +{ + long long r = std::numeric_limits::min(); + mpreal x = round(v); + if (abs(x) < -mpreal(r)) // Assume mpreal(LLONG_MIN) is exact + r = x.toLLong(); + return r; +} + +inline const mpreal trunc(const mpreal& v) +{ + mpreal x(v); + mpfr_trunc(x.mp,v.mp); + return x; +} + +inline const mpreal rint (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint ); } +inline const mpreal rint_ceil (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_ceil ); } +inline const mpreal rint_floor (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_floor); } +inline const mpreal rint_round (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_round); } +inline const mpreal rint_trunc (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(rint_trunc); } +inline const mpreal frac (const mpreal& x, mp_rnd_t r = mpreal::get_default_rnd()) { MPREAL_UNARY_MATH_FUNCTION_BODY(frac ); } + +////////////////////////////////////////////////////////////////////////// +// Miscellaneous Functions +inline int sgn(const mpreal& op) +{ + // Please note, this is classic signum function which ignores sign of zero. + // Use signbit if you need sign of zero. + return mpfr_sgn(op.mpfr_srcptr()); +} + +////////////////////////////////////////////////////////////////////////// +// Miscellaneous Functions +inline void swap (mpreal& a, mpreal& b) { mpfr_swap(a.mpfr_ptr(),b.mpfr_ptr()); } +inline const mpreal (max)(const mpreal& x, const mpreal& y){ return (x= MPFR_VERSION_NUM(3,0,0)) +inline const mpreal urandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x; + mpfr_urandom(x.mpfr_ptr(), state, rnd_mode); + return x; +} +#endif + +#if (MPFR_VERSION <= MPFR_VERSION_NUM(2,4,2)) +inline const mpreal random2 (mp_size_t size, mp_exp_t exp) +{ + mpreal x; + mpfr_random2(x.mpfr_ptr(),size,exp); + return x; +} +#endif + +// Uniformly distributed random number generation +// a = random(seed); <- initialization & first random number generation +// a = random(); <- next random numbers generation +// seed != 0 +inline const mpreal random(unsigned int seed = 0) +{ +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,0,0)) + static gmp_randstate_t state; + static bool initialize = true; + + if(initialize) + { + gmp_randinit_default(state); + gmp_randseed_ui(state,0); + initialize = false; + } + + if(seed != 0) gmp_randseed_ui(state,seed); + + return mpfr::urandom(state); +#else + if(seed != 0) std::srand(seed); + return mpfr::mpreal(std::rand()/(double)RAND_MAX); +#endif +} + +#if (MPFR_VERSION >= MPFR_VERSION_NUM(3,1,0)) +inline const mpreal grandom (gmp_randstate_t& state, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x; +#if (MPFR_VERSION >= MPFR_VERSION_NUM(4,0,0)) + mpfr_nrandom(x.mpfr_ptr(), state, rnd_mode); +#else + mpfr_grandom(x.mpfr_ptr(), NULL, state, rnd_mode); +#endif + return x; +} + +inline const mpreal grandom(unsigned int seed = 0) +{ + static gmp_randstate_t state; + static bool initialize = true; + + if(initialize) + { + gmp_randinit_default(state); + gmp_randseed_ui(state,0); + initialize = false; + } + + if(seed != 0) gmp_randseed_ui(state,seed); + + return mpfr::grandom(state); +} +#endif + +////////////////////////////////////////////////////////////////////////// +// Set/Get global properties +inline void mpreal::set_default_prec(mp_prec_t prec) +{ + mpfr_set_default_prec(prec); +} + +inline void mpreal::set_default_rnd(mp_rnd_t rnd_mode) +{ + mpfr_set_default_rounding_mode(rnd_mode); +} + +inline bool mpreal::fits_in_bits(double x, int n) +{ + int i; + double t; + return IsInf(x) || (std::modf ( std::ldexp ( std::frexp ( x, &i ), n ), &t ) == 0.0); +} + +inline const mpreal pow(const mpreal& a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow(x.mp,x.mp,b.mp,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const mpz_t b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow_z(x.mp,x.mp,b,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const long long b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + (void)rnd_mode; + return pow(a,mpreal(b)); +} + +inline const mpreal pow(const mpreal& a, const unsigned long long b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + (void)rnd_mode; + return pow(a,mpreal(b)); +} + +inline const mpreal pow(const mpreal& a, const unsigned long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow_ui(x.mp,x.mp,b,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(a,static_cast(b),rnd_mode); +} + +inline const mpreal pow(const mpreal& a, const long int b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_pow_si(x.mp,x.mp,b,rnd_mode); + return x; +} + +inline const mpreal pow(const mpreal& a, const int b, mp_rnd_t rnd_mode) +{ + return pow(a,static_cast(b),rnd_mode); +} + +inline const mpreal pow(const mpreal& a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); +} + +inline const mpreal pow(const mpreal& a, const double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); +} + +inline const mpreal pow(const unsigned long int a, const mpreal& b, mp_rnd_t rnd_mode = mpreal::get_default_rnd()) +{ + mpreal x(a); + mpfr_ui_pow(x.mp,a,b.mp,rnd_mode); + return x; +} + +inline const mpreal pow(const unsigned int a, const mpreal& b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),b,rnd_mode); +} + +inline const mpreal pow(const long int a, const mpreal& b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),b,rnd_mode); + else return pow(mpreal(a),b,rnd_mode); +} + +inline const mpreal pow(const int a, const mpreal& b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),b,rnd_mode); + else return pow(mpreal(a),b,rnd_mode); +} + +inline const mpreal pow(const long double a, const mpreal& b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); +} + +inline const mpreal pow(const double a, const mpreal& b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); +} + +// pow unsigned long int +inline const mpreal pow(const unsigned long int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + mpreal x(a); + mpfr_ui_pow_ui(x.mp,a,b,rnd_mode); + return x; +} + +inline const mpreal pow(const unsigned long int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui +} + +inline const mpreal pow(const unsigned long int a, const long int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned long int a, const int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(a,static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned long int a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned long int a, const double b, mp_rnd_t rnd_mode) +{ + return pow(a,mpreal(b),rnd_mode); //mpfr_ui_pow +} + +// pow unsigned int +inline const mpreal pow(const unsigned int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui +} + +inline const mpreal pow(const unsigned int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui +} + +inline const mpreal pow(const unsigned int a, const long int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned int a, const int b, mp_rnd_t rnd_mode) +{ + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned int a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +inline const mpreal pow(const unsigned int a, const double b, mp_rnd_t rnd_mode) +{ + return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow +} + +// pow long int +inline const mpreal pow(const long int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long int a, const long int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const long int a, const int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const long int a, const long double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +inline const mpreal pow(const long int a, const double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +// pow int +inline const mpreal pow(const int a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),b,rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const int a, const unsigned int b, mp_rnd_t rnd_mode) +{ + if (a>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const int a, const long int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const int a, const int b, mp_rnd_t rnd_mode) +{ + if (a>0) + { + if(b>0) return pow(static_cast(a),static_cast(b),rnd_mode); //mpfr_ui_pow_ui + else return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + }else{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si + } +} + +inline const mpreal pow(const int a, const long double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +inline const mpreal pow(const int a, const double b, mp_rnd_t rnd_mode) +{ + if (a>=0) return pow(static_cast(a),mpreal(b),rnd_mode); //mpfr_ui_pow + else return pow(mpreal(a),mpreal(b),rnd_mode); //mpfr_pow +} + +// pow long double +inline const mpreal pow(const long double a, const long double b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),mpreal(b),rnd_mode); +} + +inline const mpreal pow(const long double a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long double a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); //mpfr_pow_ui +} + +inline const mpreal pow(const long double a, const long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si +} + +inline const mpreal pow(const long double a, const int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si +} + +inline const mpreal pow(const double a, const double b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),mpreal(b),rnd_mode); +} + +inline const mpreal pow(const double a, const unsigned long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_ui +} + +inline const mpreal pow(const double a, const unsigned int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_ui +} + +inline const mpreal pow(const double a, const long int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),b,rnd_mode); // mpfr_pow_si +} + +inline const mpreal pow(const double a, const int b, mp_rnd_t rnd_mode) +{ + return pow(mpreal(a),static_cast(b),rnd_mode); // mpfr_pow_si +} +} // End of mpfr namespace + +// Explicit specialization of std::swap for mpreal numbers +// Thus standard algorithms will use efficient version of swap (due to Koenig lookup) +// Non-throwing swap C++ idiom: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-throwing_swap +namespace std +{ + + template <> + inline void swap(mpfr::mpreal& x, mpfr::mpreal& y) + { + return mpfr::swap(x, y); + } + + template<> + class numeric_limits + { + public: + static const bool is_specialized = true; + static const bool is_signed = true; + static const bool is_integer = false; + static const bool is_exact = false; + static const int radix = 2; + + static const bool has_infinity = true; + static const bool has_quiet_NaN = true; + static const bool has_signaling_NaN = true; + + static const bool is_iec559 = true; // = IEEE 754 + static const bool is_bounded = true; + static const bool is_modulo = false; + static const bool traps = true; + static const bool tinyness_before = true; + + static const float_denorm_style has_denorm = denorm_absent; + + inline static mpfr::mpreal (min) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::minval(precision); } + inline static mpfr::mpreal (max) (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::maxval(precision); } + inline static mpfr::mpreal lowest (mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return -mpfr::maxval(precision); } + + // Returns smallest eps such that 1 + eps != 1 (classic machine epsilon) + inline static mpfr::mpreal epsilon(mp_prec_t precision = mpfr::mpreal::get_default_prec()) { return mpfr::machine_epsilon(precision); } + + // Returns smallest eps such that x + eps != x (relative machine epsilon) + inline static mpfr::mpreal epsilon(const mpfr::mpreal& x) { return mpfr::machine_epsilon(x); } + + inline static mpfr::mpreal round_error(mp_prec_t precision = mpfr::mpreal::get_default_prec()) + { + mp_rnd_t r = mpfr::mpreal::get_default_rnd(); + + if(r == GMP_RNDN) return mpfr::mpreal(0.5, precision); + else return mpfr::mpreal(1.0, precision); + } + + inline static const mpfr::mpreal infinity() { return mpfr::const_infinity(); } + inline static const mpfr::mpreal quiet_NaN() { return mpfr::mpreal().setNan(); } + inline static const mpfr::mpreal signaling_NaN() { return mpfr::mpreal().setNan(); } + inline static const mpfr::mpreal denorm_min() { return (min)(); } + + // Please note, exponent range is not fixed in MPFR + static const int min_exponent = MPFR_EMIN_DEFAULT; + static const int max_exponent = MPFR_EMAX_DEFAULT; + MPREAL_PERMISSIVE_EXPR static const int min_exponent10 = (int) (MPFR_EMIN_DEFAULT * 0.3010299956639811); + MPREAL_PERMISSIVE_EXPR static const int max_exponent10 = (int) (MPFR_EMAX_DEFAULT * 0.3010299956639811); + +#ifdef MPREAL_HAVE_DYNAMIC_STD_NUMERIC_LIMITS + + // Following members should be constant according to standard, but they can be variable in MPFR + // So we define them as functions here. + // + // This is preferable way for std::numeric_limits specialization. + // But it is incompatible with standard std::numeric_limits and might not work with other libraries, e.g. boost. + // See below for compatible implementation. + inline static float_round_style round_style() + { + mp_rnd_t r = mpfr::mpreal::get_default_rnd(); + + switch (r) + { + case GMP_RNDN: return round_to_nearest; + case GMP_RNDZ: return round_toward_zero; + case GMP_RNDU: return round_toward_infinity; + case GMP_RNDD: return round_toward_neg_infinity; + default: return round_indeterminate; + } + } + + inline static int digits() { return int(mpfr::mpreal::get_default_prec()); } + inline static int digits(const mpfr::mpreal& x) { return x.getPrecision(); } + + inline static int digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) + { + return mpfr::bits2digits(precision); + } + + inline static int digits10(const mpfr::mpreal& x) + { + return mpfr::bits2digits(x.getPrecision()); + } + + inline static int max_digits10(mp_prec_t precision = mpfr::mpreal::get_default_prec()) + { + return digits10(precision); + } +#else + // Digits and round_style are NOT constants when it comes to mpreal. + // If possible, please use functions digits() and round_style() defined above. + // + // These (default) values are preserved for compatibility with existing libraries, e.g. boost. + // Change them accordingly to your application. + // + // For example, if you use 256 bits of precision uniformly in your program, then: + // digits = 256 + // digits10 = 77 + // max_digits10 = 78 + // + // Approximate formula for decimal digits is: digits10 = floor(log10(2) * digits). See bits2digits() for more details. + + static const std::float_round_style round_style = round_to_nearest; + static const int digits = 53; + static const int digits10 = 15; + static const int max_digits10 = 16; +#endif + }; + +} + +#endif /* __MPREAL_H__ */ diff --git a/include/shadowValue.hpp b/include/shadowValue.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a3da000e7fb372f4b1c54c54e9a1a5b53956ebed --- /dev/null +++ b/include/shadowValue.hpp @@ -0,0 +1,11 @@ +#ifndef _SHADOWVALUE +#define _SHADOWVALUE + +#include "basic.hpp" +namespace Shadow { + +template +vector shadowValue(const ast_ptr &expr, const std::map &varsValue, int length = 1, bool ifUnique = false, string uniqueLabel = "", string funcName = ""); + +} +#endif \ No newline at end of file diff --git a/includeDD/dd.h b/includeDD/dd.h index 91a1c94be9e1941f4abc0c882de6ba01bdfbed1c..72427f67247ab13343e99b1cb968fc145ca46db4 100644 --- a/includeDD/dd.h +++ b/includeDD/dd.h @@ -3,13 +3,19 @@ #define xTmp(x) x##Tmp +// TODO: 操作的实现精度取决于操作结果的类型以及变量类型。如果结果是dd类型,那实现必须按照dd的方法来。如果结果是double,那要看变量类型有无dd。如果有的话,就得使用dd算法,只不过最后要将结果舍入到double。 +// 解释:这么做的原因在于,避免上一步的精度优化白做。如果上步采用的是dd,那其精度提升效果主要体现在新增的精度位。如果当前步骤舍去新增的精度位,那就相当于舍弃了上一步的精度优化效果。 +// 解释:虽然这么做,感觉是存在一些性能上的牵连,但如果不这么做的话,那精度优化的意义就不大了。而且从优化的角度,也鼓励一条龙式的优化,这样可以尽量避免精度、性能浪费。 +// 我的疑问就是:dd+double的话,究竟算是dd实现,还是double实现?dd+dd和ld+dd的精度实现有差异吗 + // =========================================== ADD ======================================= +// 先只改dd、double #define add_d_d_d(a, b, c) double c = (a) + (b); #define add_ld_d_d(a, b, c) long double xTmp(c) = (a) + (b); double c = xTmp(c); -#define add_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_add_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0]; -#define add_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_add_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0]; +#define add_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_add_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; +#define add_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_add_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; #define add_ld_dd_d(a, b, c) double xTmp(a)[2]; xTmp(a)[0] = a; xTmp(a)[1] = a - xTmp(a)[0]; double xTmp(c)[2]; c_dd_add(xTmp(a), b, xTmp(c)); c = xTmp(c)[0]; // check c = ((a) + (b[0])) + b[1]; -#define add_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_add(a, b, xTmp(c)); double c; c = xTmp(c)[0]; +#define add_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_add(a, b, xTmp(c)); double c; c = xTmp(c)[0] + xTmp(c)[1]; #define add_d_ld_d(a, b, c) double c = (a) + (b); #define add_ld_ld_d(a, b, c) double c = (a) + (b); #define add_dd_ld_d(a, b, c) double xTmp(b)[2]; xTmp(b)[0] = b; xTmp(b)[1] = b - xTmp(b)[0]; double xTmp(c)[2]; c_dd_add(a, xTmp(b), xTmp(c)); c = xTmp(c)[0]; // check double c = ((a[0]) + (b[0])) + a[1]; @@ -37,10 +43,10 @@ // =========================================== SUB ======================================= #define sub_d_d_d(a, b, c) double c = (a) - (b); #define sub_ld_d_d(a, b, c) long double xTmp(c) = (a) - (b); double c = xTmp(c); -#define sub_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_sub_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0]; -#define sub_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_sub_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0]; +#define sub_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_sub_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; +#define sub_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_sub_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; #define sub_ld_dd_d(a, b, c) double xTmp(a)[2]; xTmp(a)[0] = a; xTmp(a)[1] = a - xTmp(a)[0]; double xTmp(c)[2]; c_dd_sub(xTmp(a), b, xTmp(c)); c = xTmp(c)[0]; // check c = ((a) - (b[0])) - b[1]; -#define sub_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_sub(a, b, xTmp(c)); double c; c = xTmp(c)[0]; +#define sub_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_sub(a, b, xTmp(c)); double c; c = xTmp(c)[0] + xTmp(c)[1]; #define sub_d_ld_d(a, b, c) double c = (a) - (b); #define sub_ld_ld_d(a, b, c) double c = (a) - (b); #define sub_dd_ld_d(a, b, c) double xTmp(b)[2]; xTmp(b)[0] = b; xTmp(b)[1] = b - xTmp(b)[0]; double xTmp(c)[2]; c_dd_sub(a, xTmp(b), xTmp(c)); c = xTmp(c)[0]; // check double c = ((a[0]) - (b[0])) - a[1]; @@ -68,10 +74,10 @@ // =========================================== MUL ======================================= #define mul_d_d_d(a, b, c) double c = (a) * (b); #define mul_ld_d_d(a, b, c) long double xTmp(c) = (a) * (b); double c = xTmp(c); -#define mul_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_mul_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0]; -#define mul_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_mul_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0]; +#define mul_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_mul_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; +#define mul_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_mul_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; #define mul_ld_dd_d(a, b, c) double xTmp(a)[2]; xTmp(a)[0] = a; xTmp(a)[1] = a - xTmp(a)[0]; double xTmp(c)[2]; c_dd_mul(xTmp(a), b, xTmp(c)); c = xTmp(c)[0]; // TODO: check c = ((a) + (b[0])) + b[1]; -#define mul_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_mul(a, b, xTmp(c)); double c; c = xTmp(c)[0]; +#define mul_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_mul(a, b, xTmp(c)); double c; c = xTmp(c)[0] + xTmp(c)[1]; #define mul_d_ld_d(a, b, c) double c = (a) * (b); #define mul_ld_ld_d(a, b, c) double c = (a) * (b); #define mul_dd_ld_d(a, b, c) double xTmp(b)[2]; xTmp(b)[0] = b; xTmp(b)[1] = b - xTmp(b)[0]; double xTmp(c)[2]; c_dd_mul(a, xTmp(b), xTmp(c)); c = xTmp(c)[0]; // TODO: check double c = ((a[0]) + (b)) + a[1]; @@ -99,10 +105,10 @@ // =========================================== DIV ======================================= #define div_d_d_d(a, b, c) double c = (a) / (b); #define div_ld_d_d(a, b, c) long double xTmp(c) = (a) / (b); double c = xTmp(c); -#define div_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_div_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0]; -#define div_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_div_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0]; +#define div_dd_d_d(a, b, c) double xTmp(c)[2]; c_dd_div_dd_d(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; +#define div_d_dd_d(a, b, c) double xTmp(c)[2]; c_dd_div_d_dd(a, b, xTmp(c)); double c = xTmp(c)[0] + xTmp(c)[1]; #define div_ld_dd_d(a, b, c) double xTmp(a)[2]; xTmp(a)[0] = a; xTmp(a)[1] = a - xTmp(a)[0]; double xTmp(c)[2]; c_dd_div(xTmp(a), b, xTmp(c)); c = xTmp(c)[0]; // TODO: check c = ((a) + (b[0])) + b[1]; -#define div_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_div(a, b, xTmp(c)); double c; c = xTmp(c)[0]; +#define div_dd_dd_d(a, b, c) double xTmp(c)[2]; c_dd_div(a, b, xTmp(c)); double c; c = xTmp(c)[0] + xTmp(c)[1]; #define div_d_ld_d(a, b, c) double c = (a) / (b); #define div_ld_ld_d(a, b, c) double c = (a) / (b); #define div_dd_ld_d(a, b, c) double xTmp(b)[2]; xTmp(b)[0] = b; xTmp(b)[1] = b - xTmp(b)[0]; double xTmp(c)[2]; c_dd_div(a, xTmp(b), xTmp(c)); c = xTmp(c)[0]; // TODO: check double c = ((a[0]) + (b)) + a[1]; diff --git a/includeTEST/common.h b/includeTEST/common.h index d1f852e627b0326897e9a5b90c93886108028cbd..e5051a729754f67166df9ee3dd22746ac2c35834 100644 --- a/includeTEST/common.h +++ b/includeTEST/common.h @@ -33,6 +33,10 @@ double computeUlpDiff(mpfr_t correctValue, mpfr_t myValue); double computeUlpDiffF(mpfr_t correctValue, mpfr_t myValue); +double computeAbs(mpfr_t correctValue, mpfr_t myValue, mpfr_t mpfrDiff); + +double computeRel(mpfr_t correctValue, mpfr_t myValue); + #define _EXP_BITS 11 #define SIGN_BIT 0x8000000000000000 #define EXP_BIT 0x7FF0000000000000 diff --git a/src/basic.cpp b/src/basic.cpp index 9483ebc1949431b4206afdefdba7c80b30f8af21..8b23e08a53527b614a15a1315de646a0fd147313 100644 --- a/src/basic.cpp +++ b/src/basic.cpp @@ -7,8 +7,10 @@ #include #include #include +#include "mpreal.h" using std::cerr; +using std::cin; using std::cout; using std::endl; using std::string; @@ -18,6 +20,135 @@ using std::endl; using std::to_string; using std::ofstream; using std::ios; + +std::map singleCall_map = { + {"sin", minesin}, + {"cos", minecos}, + {"tan", minetan}, + {"exp", mineexp}, + {"log", minelog}, + {"asin", mineasin}, + {"acos", mineacos}, + {"atan", mineatan}, +}; + +std::map doubleCall_map = { + {"+", mineadd}, + {"-", minesub}, + {"*", minemul}, + {"/", minediv}, +}; + +std::map commonCall_map = { + {"sin", common_sin}, + {"cos", common_cos}, + {"tan", common_tan}, + {"pow", common_pow}, + {"exp", common_exp}, + {"log", common_log}, + {"asin", common_asin}, + {"acos", common_acos}, + {"atan", common_atan}, + {"expm1", common_expm1}, + {"fma", common_fma}, + {"log1p", common_log1p}, + {"sqrt", common_sqrt}, + {"hypot", common_hypot}, + {"cbrt", common_cbrt}, + {"atan2", common_atan2}, +}; + +std::map doubleRealCall_map = { + {"+", realadd}, + {"-", realsub}, + {"*", realmul}, + {"/", realdiv}, +}; + +std::map commonRealCall_map = { + {"sin", real_sin}, + {"cos", real_cos}, + {"tan", real_tan}, + {"pow", real_pow}, + {"exp", real_exp}, + {"log", real_log}, + {"asin", real_asin}, + {"acos", real_acos}, + {"atan", real_atan}, + {"expm1", real_expm1}, + {"fma", real_fma}, + {"log1p", real_log1p}, + {"sqrt", real_sqrt}, + {"hypot", real_hypot}, + {"cbrt", real_cbrt}, + {"atan2", real_atan2}, +}; + +std::map singleCall_dd_map = { + {"sin_d", minesin_dd}, + {"sin_dd", minesin_dd}, + {"cos_d", minecos_dd}, + {"cos_dd", minecos_dd}, + {"tan_d", minetan_dd}, + {"tan_dd", minetan_dd}, + {"exp_d", mineexp_dd}, + {"exp_dd", mineexp_dd}, + {"log_d", minelog_dd}, + {"log_dd", minelog_dd}, +}; + +std::map doubleCall_d_d_map = { + {"add_d", mineadd_d_d}, + {"add_dd", mineadd_d_d}, + {"sub_d", minesub_d_d}, + {"sub_dd", minesub_d_d}, + {"mul_d", minemul_d_d}, + {"mul_dd", minemul_d_d}, + {"div_d", minediv_d_d}, + {"div_dd", minediv_d_d}, + {"pow_dd", minepow_d_d}, + {"pow_dd", minepow_d_d}, +}; + +std::map doubleCall_d_dd_map = { + {"add_d", mineadd_d_dd}, + {"add_dd", mineadd_d_dd}, + {"sub_d", minesub_d_dd}, + {"sub_dd", minesub_d_dd}, + {"mul_d", minemul_d_dd}, + {"mul_dd", minemul_d_dd}, + {"div_d", minediv_d_dd}, + {"div_dd", minediv_d_dd}, + {"pow_dd", minepow_d_dd}, + {"pow_dd", minepow_d_dd}, +}; + +std::map doubleCall_dd_d_map = { + {"add_d", mineadd_dd_d}, + {"add_dd", mineadd_dd_d}, + {"sub_d", minesub_dd_d}, + {"sub_dd", minesub_dd_d}, + {"mul_d", minemul_dd_d}, + {"mul_dd", minemul_dd_d}, + {"div_d", minediv_dd_d}, + {"div_dd", minediv_dd_d}, + {"pow_dd", minepow_dd_d}, + {"pow_dd", minepow_dd_d}, +}; + +std::map doubleCall_dd_dd_map = { + {"add_d", mineadd_dd_dd}, + {"add_dd", mineadd_dd_dd}, + {"sub_d", minesub_dd_dd}, + {"sub_dd", minesub_dd_dd}, + {"mul_d", minemul_dd_dd}, + {"mul_dd", minemul_dd_dd}, + {"div_d", minediv_dd_dd}, + {"div_dd", minediv_dd_dd}, + {"pow_dd", minepow_dd_dd}, + {"pow_dd", minepow_dd_dd}, +}; + //===----------------------------------------------------------------------===// // basic operation //===----------------------------------------------------------------------===// @@ -723,9 +854,39 @@ vector> combination(const int num, const vector &indexs) return set; } -inline unsigned int factorial(unsigned int value) +// add at 20230709, update from the origin combination +vector> combinationNew(const int num, const vector &indexs) +{ + vector> set; + if(num > (int)indexs.size()) + return set; + + vector elements; + elements.resize(indexs.size()); + for(int i = 0; i < num; i++) + { + elements.at(i) = 1; + } + + do + { + vector currentCombination; + for(size_t i = 0; i < elements.size(); ++i) + { + if(elements[i]) + { + currentCombination.push_back(indexs[i]); + } + } + set.push_back(currentCombination); + } while(prev_permutation(elements.begin(), elements.end())); + + return set; +} + +inline double factorial(unsigned int value) { - unsigned int local_value = value; + double local_value = value; while(value-- > 1) { local_value *= value; @@ -836,3 +997,64 @@ void write_to_file_wrapper(string uniqueLabel, string exprOriginBest, int dimens summaryData.push_back(matlabKernelTime); write_to_file(uniqueLabel, exprOriginBest, numIntervalsSoloBefore, numIntervalsSoloAfter, thresholds, summaryData, "runlog.csv"); } + +template +std::map setVarsValue(const vector &vars, const vector &values) +{ + if (values.size() != vars.size()) + { + fprintf(stderr, "ERROR: %s : line %d: values.size() should be equal to vars.size(). But values.size() = %ld, vars.size() = %ld\n", __func__, __LINE__, values.size(), vars.size()); + exit(EXIT_FAILURE); + } + std::map results; + for (size_t i = 0; i < vars.size(); i++) + { + auto &var = vars.at(i); + auto &value = values.at(i); + results[var] = value; + } + return results; +} + +template std::map setVarsValue(const vector &vars, const vector &values); +template std::map setVarsValue(const vector &vars, const vector &values); + +void setDataTypes(vector &dataTypes) +{ + cout << "please input the mixed-precision types. if input Enter, then set DD & double by default.\n"; + string tmpDataTypes; + cin >> tmpDataTypes; // TODO: improve the input method + cin.clear(); // clear the error signal + cin.ignore(std::numeric_limits::max(),'\n'); // clear the current line in input buffer + if (tmpDataTypes != "") + { + dataTypes.clear(); + if(tmpDataTypes == "0") + { + dataTypes.push_back("ld"); + dataTypes.push_back("double"); + } + else if(tmpDataTypes == "1") + { + dataTypes.push_back("DD"); + dataTypes.push_back("double"); + } + else if(tmpDataTypes == "2") + { + dataTypes.push_back("DD"); + dataTypes.push_back("ld"); + } + else if(tmpDataTypes == "3") + { + dataTypes.push_back("DD"); + dataTypes.push_back("ld"); + dataTypes.push_back("double"); + } + else + { + cout << "ERROR: Unknown input. please enter 0~4 to to indicate a mixed-precision configuration"; + exit(EXIT_FAILURE); + } + } + fmt::print("mix precision dataTypes: {}", dataTypes); +} \ No newline at end of file diff --git a/src/errorDetect.cpp b/src/errorDetect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54f20d4973508e6012eacc0a9020c31e4a5a8124 --- /dev/null +++ b/src/errorDetect.cpp @@ -0,0 +1,69 @@ +#include +#include "errorDetect.hpp" + +double computeUlpUnit(double x) { + DL x0; + x0.d = fabs(x); + // printf("x0 = %le\n", x0.d); + // printf("x0 = %016lx\n", x0.l); + if(x0.d < pow(2, -1021)) { + x0.d = pow(2, -1074); + } else if(x0.d > (1 - pow(2, -53)) * pow(2, 1024)) { + x0.d = pow(2,971); + } else { + x0.l = x0.l >> 52; + // printf("1x0 = %016lx\n", x0.l); + // x0.l = x0.l - 52; // for these FP numbers whose exponent is lower than 52, the result will be zero wrongly. + // printf("2x0 = %016lx\n", x0.l); + x0.l = x0.l << 52; + // printf("3x0 = %016lx\n", x0.l); + x0.d = x0.d * pow(2, -52); + // printf("4x0 = %016lx\n", x0.l); + // printf("else: x0 = %le\n", x0.d); + } + return x0.d; +} + +double computeUlpUnit(mpfr::mpreal oracle) { + double x = oracle.toDouble(); + return computeUlpUnit(x); +} + +double computeError(mpfr::mpreal oracle, double x) +{ + // absolute error + // double errorValue = fabs((oracle - x).toDouble()); + + // relative error + // double errorValue = fabs(((oracle - x) / oracle).toDouble()); + + // ulp error + auto unitUlp = computeUlpUnit(oracle.toDouble()); + auto errorValue = fabs((oracle - x).toDouble() / unitUlp); + + return errorValue; +} + +double computeError(mpfr::mpreal oracle, mpfr::mpreal x) +{ + // absolute error + // double errorValue = fabs((oracle - x).toDouble()); + + // relative error + // double errorValue = fabs(((oracle - x) / oracle).toDouble()); + + // ulp error + auto unitUlp = computeUlpUnit(oracle.toDouble()); + auto errorValue = fabs((oracle - x).toDouble() / unitUlp); + + return errorValue; +} + +double computeError(mpfr::mpreal funcRealValue, mpfr::mpreal funcValue, double unitUlp) +{ + // ulp error + auto errorValue = fabs((funcRealValue - funcValue).toDouble() / unitUlp); + // auto errorValue = (funcRealValue - funcValue).toDouble() / unitUlp; + + return errorValue; +} \ No newline at end of file diff --git a/src/funclist.cpp b/src/funclist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..313a1b58bb9bf52c4c0598269f48ee97ce2b34b5 --- /dev/null +++ b/src/funclist.cpp @@ -0,0 +1,570 @@ +#include +#include "basic.hpp" +#include "funclist.hpp" +#include "includeDD/inline.h" + +double mineadd(double x, double y) { + return x + y; +} + +double minesub(double x, double y) { + return x - y; +} + +double minemul(double x, double y) { + return x * y; +} + +double minediv(double x, double y) { + return x / y; +} + +double minesin(double x) { + return sin(x); +} + +double minecos(double x) { + return cos(x); +} + +double minetan(double x) { + return tan(x); +} + +double mineexp(double x) { + return exp(x); +} + +double minelog(double x) { + return log(x); +} + +double mineasin(double x) { + return asin(x); +} + +double mineacos(double x) { + return acos(x); +} + +double mineatan(double x) { + return atan(x); +} + +double common_sin(vector args) { + return sin(args.at(0)); +} + +double common_cos(vector args) { + return cos(args.at(0)); +} + +double common_tan(vector args) { + return tan(args.at(0)); +} + +double common_pow(vector args) { + return pow(args.at(0), args.at(1)); +} + +double common_exp(vector args) { + return exp(args.at(0)); +} + +double common_log(vector args) { + return log(args.at(0)); +} + +double common_asin(vector args) { + return asin(args.at(0)); +} + +double common_acos(vector args) { + return acos(args.at(0)); +} + +double common_atan(vector args) { + return atan(args.at(0)); +} + +double common_expm1(vector args) { + return expm1(args.at(0)); +} + +double common_fma(vector args) { + return fma(args.at(0), args.at(1), args.at(2)); +} + +double common_log1p(vector args) { + return log1p(args.at(0)); +} + +double common_sqrt(vector args) { + return sqrt(args.at(0)); +} + +double common_hypot(vector args) { + return hypot(args.at(0), args.at(1)); +} + +double common_cbrt(vector args) { + return cbrt(args.at(0)); +} + +double common_atan2(vector args) { + return atan2(args.at(0), args.at(1)); +} + +mpfr::mpreal realadd(mpfr::mpreal x, mpfr::mpreal y) +{ + return x + y; +} + +mpfr::mpreal realsub(mpfr::mpreal x, mpfr::mpreal y) +{ + return x - y; +} + +mpfr::mpreal realmul(mpfr::mpreal x, mpfr::mpreal y) +{ + return x * y; +} + +mpfr::mpreal realdiv(mpfr::mpreal x, mpfr::mpreal y) +{ + return x / y; +} + +mpfr::mpreal real_sin(vector args) { + return sin(args.at(0)); +} + +mpfr::mpreal real_cos(vector args) { + return cos(args.at(0)); +} + +mpfr::mpreal real_tan(vector args) { + return tan(args.at(0)); +} + +mpfr::mpreal real_pow(vector args) { + return pow(args.at(0), args.at(1)); +} + +mpfr::mpreal real_exp(vector args) { + return exp(args.at(0)); +} + +mpfr::mpreal real_log(vector args) { + return log(args.at(0)); +} + +mpfr::mpreal real_asin(vector args) { + return asin(args.at(0)); +} + +mpfr::mpreal real_acos(vector args) { + return acos(args.at(0)); +} + +mpfr::mpreal real_atan(vector args) { + return atan(args.at(0)); +} + +mpfr::mpreal real_expm1(vector args) { + return expm1(args.at(0)); +} + +mpfr::mpreal real_fma(vector args) { + return fma(args.at(0), args.at(1), args.at(2)); +} + +mpfr::mpreal real_log1p(vector args) { + return log1p(args.at(0)); +} + +mpfr::mpreal real_sqrt(vector args) { + return sqrt(args.at(0)); +} + +mpfr::mpreal real_hypot(vector args) { + return hypot(args.at(0), args.at(1)); +} + +mpfr::mpreal real_cbrt(vector args) { + return cbrt(args.at(0)); +} + +mpfr::mpreal real_atan2(vector args) { + return atan2(args.at(0), args.at(1)); +} + +template +mpfr::mpreal mineadd_d_d(double x1, double x2) +{ + double y[2]; + y[0] = two_add_mine(x1, x2, &(y[1])); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal mineadd_d_dd(double x1, double *x2Ptr) +{ + double y[2]; + c_dd_add_d_dd(x1, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal mineadd_dd_d(double *x1Ptr, double x2) +{ + double y[2]; + c_dd_add_dd_d(x1Ptr, x2, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal mineadd_dd_dd(double *x1Ptr, double *x2Ptr) +{ + double y[2]; + c_dd_add(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minesub_d_d(double x1, double x2) +{ + double y[2]; + y[0] = two_sub_mine(x1, x2, &(y[1])); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minesub_d_dd(double x1, double *x2Ptr) +{ + double y[2]; + c_dd_sub_d_dd(x1, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minesub_dd_d(double *x1Ptr, double x2) +{ + double y[2]; + c_dd_sub_dd_d(x1Ptr, x2, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minesub_dd_dd(double *x1Ptr, double *x2Ptr) +{ + double y[2]; + c_dd_sub(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minemul_d_d(double x1, double x2) +{ + double y[2]; + y[0] = two_mul_mine(x1, x2, &(y[1])); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minemul_d_dd(double x1, double *x2Ptr) +{ + double y[2]; + c_dd_mul_d_dd(x1, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minemul_dd_d(double *x1Ptr, double x2) +{ + double y[2]; + c_dd_mul_dd_d(x1Ptr, x2, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minemul_dd_dd(double *x1Ptr, double *x2Ptr) +{ + double y[2]; + c_dd_mul(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minediv_d_d(double x1, double x2) +{ + double y[2]; + y[0] = div_mine(x1, x2, &(y[1])); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minediv_d_dd(double x1, double *x2Ptr) +{ + double y[2]; + c_dd_div_d_dd(x1, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minediv_dd_d(double *x1Ptr, double x2) +{ + double y[2]; + c_dd_div_dd_d(x1Ptr, x2, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minediv_dd_dd(double *x1Ptr, double *x2Ptr) +{ + double y[2]; + c_dd_div(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minepow_d_d(double x1, double x2) +{ + double x1Ptr[2]; + x1Ptr[0] = x1; + double x2Ptr[2]; + x2Ptr[0] = x2; + double y[2]; + c_dd_pow_mine(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minepow_d_dd(double x1, double *x2Ptr) +{ + double x1Ptr[2]; + x1Ptr[0] = x1; + double y[2]; + c_dd_pow_mine(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minepow_dd_d(double *x1Ptr, double x2) +{ + double x2Ptr[2]; + x2Ptr[0] = x2; + double y[2]; + c_dd_pow_mine(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minepow_dd_dd(double *x1Ptr, double *x2Ptr) +{ + double y[2]; + c_dd_pow_mine(x1Ptr, x2Ptr, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minesin_dd(double *x) +{ + double y[2]; + c_dd_sin(x, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minecos_dd(double *x) +{ + double y[2]; + c_dd_cos(x, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minetan_dd(double *x) +{ + double y[2]; + c_dd_tan(x, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal mineexp_dd(double *x) +{ + double y[2]; + c_dd_exp(x, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +template +mpfr::mpreal minelog_dd(double *x) +{ + double y[2]; + c_dd_log(x, y); + T tmp; + mpfr::mpreal result; + tmp = y[0]; + result = tmp + y[1]; + return result; +} + +// add +template mpfr::mpreal mineadd_d_d(double x, double y); +template mpfr::mpreal mineadd_d_d(double x, double y); +template mpfr::mpreal mineadd_d_dd(double x, double *y); +template mpfr::mpreal mineadd_d_dd(double x, double *y); +template mpfr::mpreal mineadd_dd_d(double *x, double y); +template mpfr::mpreal mineadd_dd_d(double *x, double y); +template mpfr::mpreal mineadd_dd_dd(double *x, double *y); +template mpfr::mpreal mineadd_dd_dd(double *x, double *y); + +// sub +template mpfr::mpreal minesub_d_d(double x, double y); +template mpfr::mpreal minesub_d_d(double x, double y); +template mpfr::mpreal minesub_d_dd(double x, double *y); +template mpfr::mpreal minesub_d_dd(double x, double *y); +template mpfr::mpreal minesub_dd_d(double *x, double y); +template mpfr::mpreal minesub_dd_d(double *x, double y); +template mpfr::mpreal minesub_dd_dd(double *x, double *y); +template mpfr::mpreal minesub_dd_dd(double *x, double *y); + +// mul +template mpfr::mpreal minemul_d_d(double x, double y); +template mpfr::mpreal minemul_d_d(double x, double y); +template mpfr::mpreal minemul_d_dd(double x, double *y); +template mpfr::mpreal minemul_d_dd(double x, double *y); +template mpfr::mpreal minemul_dd_d(double *x, double y); +template mpfr::mpreal minemul_dd_d(double *x, double y); +template mpfr::mpreal minemul_dd_dd(double *x, double *y); +template mpfr::mpreal minemul_dd_dd(double *x, double *y); + +// div +template mpfr::mpreal minediv_d_d(double x, double y); +template mpfr::mpreal minediv_d_d(double x, double y); +template mpfr::mpreal minediv_d_dd(double x, double *y); +template mpfr::mpreal minediv_d_dd(double x, double *y); +template mpfr::mpreal minediv_dd_d(double *x, double y); +template mpfr::mpreal minediv_dd_d(double *x, double y); +template mpfr::mpreal minediv_dd_dd(double *x, double *y); +template mpfr::mpreal minediv_dd_dd(double *x, double *y); + +// pow +template mpfr::mpreal minepow_d_d(double x, double y); +template mpfr::mpreal minepow_d_d(double x, double y); +template mpfr::mpreal minepow_d_dd(double x, double *y); +template mpfr::mpreal minepow_d_dd(double x, double *y); +template mpfr::mpreal minepow_dd_d(double *x, double y); +template mpfr::mpreal minepow_dd_d(double *x, double y); +template mpfr::mpreal minepow_dd_dd(double *x, double *y); +template mpfr::mpreal minepow_dd_dd(double *x, double *y); + +// single math function +template mpfr::mpreal minesin_dd(double *x); +template mpfr::mpreal minesin_dd(double *x); +template mpfr::mpreal minecos_dd(double *x); +template mpfr::mpreal minecos_dd(double *x); +template mpfr::mpreal minetan_dd(double *x); +template mpfr::mpreal minetan_dd(double *x); +template mpfr::mpreal mineexp_dd(double *x); +template mpfr::mpreal mineexp_dd(double *x); +template mpfr::mpreal minelog_dd(double *x); +template mpfr::mpreal minelog_dd(double *x); \ No newline at end of file diff --git a/src/geneCode.cpp b/src/geneCode.cpp index d19338e5a9a3f461b93cba63ba84c23357f0354f..35b1b5095440d8a64794afd7ac2415af52930cf5 100644 --- a/src/geneCode.cpp +++ b/src/geneCode.cpp @@ -1,6 +1,8 @@ #include "basic.hpp" #include "geneCode.hpp" #include "parserASTLY.hpp" +#include "shadowValue.hpp" +#include "color.hpp" #include #include @@ -324,7 +326,8 @@ string geneHerbieCode(string uniqueLabel) return herbieExpr; } fprintf(stderr, "ERROR: geneHerbieCode: we can not support %s now\n", uniqueLabel.c_str()); - exit(EXIT_FAILURE); + return ""; + // exit(EXIT_FAILURE); } string geneDaisyCode(string uniqueLabel) @@ -416,7 +419,8 @@ string geneDaisyCode(string uniqueLabel) return daisyExpr; } fprintf(stderr, "ERROR: geneDaisyCode: we can not support %s now\n", uniqueLabel.c_str()); - exit(EXIT_FAILURE); + return ""; + // exit(EXIT_FAILURE); } string geneMpfrCode(const ast_ptr &exprAst, const string uniqueLabel, vector vars) @@ -820,6 +824,46 @@ void setType(ast_ptr &expr, map opTypes) } } +void getOrders(const ast_ptr &expr, vector &opOrder) +{ + auto type = expr->type(); + if(type == "Number") + { + ; + } + else if(type == "Variable") + { + ; + } + else if(type == "Call") + { + CallExprAST *callPtr = dynamic_cast(expr.get()); + auto &args = callPtr->getArgs(); + vector paramOrders; + for(auto& arg : args) + { + getOrders(arg, opOrder); + } + auto orderNow = expr->getOrder(); + opOrder.push_back(orderNow); + } + else if(type == "Binary") + { + BinaryExprAST *binPtr = dynamic_cast(expr.get()); + ast_ptr &lhs = binPtr->getLHS(); + ast_ptr &rhs = binPtr->getRHS(); + getOrders(lhs, opOrder); + getOrders(rhs, opOrder); + auto orderNow = expr->getOrder(); + opOrder.push_back(orderNow); + } + else + { + fprintf(stderr, "ERROR: %s : line %d: unknown type %s\n", __func__, __LINE__, type.c_str()); + exit(EXIT_FAILURE); + } +} + void setOrdersKernel(ast_ptr &expr, int &orderNow, vector &opOrder) { auto type = expr->type(); @@ -873,6 +917,60 @@ vector setOrder(ast_ptr &expr) return opOrder; } +void showOrdersKernel(ast_ptr &expr, int &orderNow) +{ + auto type = expr->type(); + // string prompt = ""; + if(type == "Number") + { + // string tmp = prompt + std::to_string(orderNow) + ": "; + printExpr(expr, to_string(orderNow) + " "); + orderNow++; + } + else if(type == "Variable") + { + // string tmp = prompt + std::to_string(orderNow) + ": "; + printExpr(expr, to_string(orderNow) + " "); + orderNow++; + } + else if(type == "Call") + { + CallExprAST *callPtr = dynamic_cast(expr.get()); + auto &args = callPtr->getArgs(); + vector paramOrders; + for(auto& arg : args) + { + showOrdersKernel(arg, orderNow); + } + // string tmp = prompt + std::to_string(orderNow) + ": "; + printExpr(expr, to_string(orderNow) + " "); + orderNow++; + } + else if(type == "Binary") + { + BinaryExprAST *binPtr = dynamic_cast(expr.get()); + ast_ptr &lhs = binPtr->getLHS(); + ast_ptr &rhs = binPtr->getRHS(); + showOrdersKernel(lhs, orderNow); + showOrdersKernel(rhs, orderNow); + // string tmp = prompt + std::to_string(orderNow) + ": "; + printExpr(expr, to_string(orderNow) + " "); + orderNow++; + } + else + { + fprintf(stderr, "ERROR: unknowntype %s\n", type.c_str()); + exit(EXIT_FAILURE); + } +} + +int showOrder(ast_ptr &expr) +{ + int order = 0; + showOrdersKernel(expr, order); + return order; +} + static std::map opMap = { {'+', "add"}, {'-', "sub"}, @@ -911,18 +1009,19 @@ int codegenKernel(ofstream &ofs, const ast_ptr &expr) { NumberExprAST *numPtr = dynamic_cast(expr.get()); auto num = numPtr->getNumber(); + auto numStr = fmt::format("{}", num); if(opType == "double") { - ofs << "\t" << "double tmp" << order << " = " << num << ";\n"; + ofs << "\t" << "double tmp" << order << " = " << numStr << ";\n"; } else if(opType == "ld") { - ofs << "\t" << "long double tmp" << order << " = " << num << ";\n"; + ofs << "\t" << "long double tmp" << order << " = " << numStr << ";\n"; } else if(opType == "DD") { ofs << "\t" << "double tmp" << order << "[2];\n"; - ofs << "\t" << "tmp" << order << "[0] = " << num << ";\n"; + ofs << "\t" << "tmp" << order << "[0] = " << numStr << ";\n"; ofs << "\t" << "tmp" << order << "[1] = 0.0;\n"; } else @@ -972,6 +1071,231 @@ int codegenKernel(ofstream &ofs, const ast_ptr &expr) paramOrders.push_back(paramOrder); } + // to find the highest type of the parameters + bool hasDDparam = false; + bool hasLDparam = false; + for(const auto& paramOpType : paramOpTypes) + { + if(paramOpType == "DD") + { + hasDDparam = true; + break; + } + } + if(hasDDparam == false) + { + for(const auto& paramOpType : paramOpTypes) + { + if(paramOpType == "ld") + { + hasLDparam = true; + break; + } + else if(paramOpType != "double") // the type of param's op is not in {double, ld, DD} + { + fprintf(stderr, "ERROR: Unknown paramOpType %s\n", paramOpType.c_str()); + exit(EXIT_FAILURE); + } + } + } + + // set all the parameters to the highest type + // set the callee according to the highest type and opType + // set the return value type according to the opType + if(hasDDparam == true) + { + // paramOpType must be DD or ld or double + for(size_t i = 0; i < paramOpTypes.size(); i++) + { + auto ¶mOpType = paramOpTypes.at(i); + ofs << "\t" << "double p" << paramOrders.at(i) << "[2];\n"; + if(paramOpType == "DD") + { + ofs << "\t" << "p" << paramOrders.at(i) << "[0] = tmp" << paramOrders.at(i) << "[0];\n"; + ofs << "\t" << "p" << paramOrders.at(i) << "[1] = tmp" << paramOrders.at(i) << "[1];\n"; + } + else if(paramOpType == "ld") + { + ofs << "\t" << "p" << paramOrders.at(i) << "[0] = tmp" << paramOrders.at(i) << ";\n"; + ofs << "\t" << "p" << paramOrders.at(i) << "[1] = tmp" << paramOrders.at(i) << " - p" << paramOrders.at(i) << "[0];\n"; + } + else // must be double + { + ofs << "\t" << "p" << paramOrders.at(i) << "[0] = tmp" << paramOrders.at(i) << ";\n"; + ofs << "\t" << "p" << paramOrders.at(i) << "[1] = 0;\n"; + } + } + + ofs << "\t" << "double tmpCallResult" << order << "[2];\n"; + auto it = callMap.find(callee); + auto callStr = it->second; + ofs << "\t" << callStr << "("; + for(size_t i = 0; i < paramOrders.size(); i++) + { + ofs << "p" << paramOrders.at(i) << ", "; + } + ofs << "tmpCallResult" << order; + ofs << ");\n"; + + if(opType == "DD") + { + ofs << "\t" << "double tmp" << order << "[2];\n"; + ofs << "\t" << "tmp" << order << "[0] = tmpCallResult" << order << "[0];\n"; + ofs << "\t" << "tmp" << order << "[1] = tmpCallResult" << order << "[1];\n"; + } + else if(opType == "ld") + { + ofs << "\t" << "long double tmp" << order << ";\n"; + ofs << "\t" << "tmp" << order << " = tmpCallResult" << order << "[0];\n"; + ofs << "\t" << "tmp" << order << "+= tmpCallResult" << order << "[1];\n"; + + } + else + { + ofs << "\t" << "double tmp" << order << ";\n"; + ofs << "\t" << "tmp" << order << " = tmpCallResult" << order << "[0];\n"; + ofs << "\t" << "tmp" << order << " += tmpCallResult" << order << "[1];\n"; + } + } + else if(hasLDparam == true) + { + if(opType == "DD") + { + for(size_t i = 0; i < paramOpTypes.size(); i++) + { + auto ¶mOpType = paramOpTypes.at(i); + ofs << "\t" << "double p" << paramOrders.at(i) << "[2];\n"; + if(paramOpType == "ld") + { + ofs << "\t" << "p" << paramOrders.at(i) << "[0] = tmp" << paramOrders.at(i) << ";\n"; + ofs << "\t" << "p" << paramOrders.at(i) << "[1] = tmp" << paramOrders.at(i) << " - p" << paramOrders.at(i) << "[0];\n"; + } + else // must be double + { + ofs << "\t" << "p" << paramOrders.at(i) << "[0] = tmp" << paramOrders.at(i) << ";\n"; + ofs << "\t" << "p" << paramOrders.at(i) << "[1] = 0;\n"; + } + } + + ofs << "\t" << "double tmpCallResult" << order << "[2];\n"; + auto it = callMap.find(callee); + auto callStr = it->second; + ofs << "\t" << callStr << "("; + for(size_t i = 0; i < paramOrders.size(); i++) + { + ofs << "p" << paramOrders.at(i) << ", "; + } + ofs << "tmpCallResult" << order; + ofs << ");\n"; + + ofs << "\t" << "double tmp" << order << "[2];\n"; + ofs << "\t" << "tmp" << order << "[0] = tmpCallResult" << order << "[0];\n"; + ofs << "\t" << "tmp" << order << "[1] = tmpCallResult" << order << "[1];\n"; + } + else if(opType == "ld") + { + // paramOpType must be ld or double + for(size_t i = 0; i < paramOpTypes.size(); i++) + { + ofs << "\t" << "long double p" << paramOrders.at(i) << " = tmp" << paramOrders.at(i) << ";\n"; + } + + ofs << "\t" << "long double tmpCallResult" << order << " = " << callee << "("; + for(size_t i = 0; i < paramOrders.size() - 1; i++) + { + ofs << "p" << paramOrders.at(i) << ", "; + } + ofs << "p" << paramOrders.back(); + ofs << ");\n"; + + ofs << "\t" << "long double tmp" << order << " = tmpCallResult" << order << ";\n"; + } + else + { + // paramOpType must be ld or double + for(size_t i = 0; i < paramOpTypes.size(); i++) + { + ofs << "\t" << "long double p" << paramOrders.at(i) << " = tmp" << paramOrders.at(i) << ";\n"; + } + + ofs << "\t" << "long double tmpCallResult" << order << " = " << callee << "("; + for(size_t i = 0; i < paramOrders.size() - 1; i++) + { + ofs << "p" << paramOrders.at(i) << ", "; + } + ofs << "p" << paramOrders.back(); + ofs << ");\n"; + + ofs << "\t" << "double tmp" << order << " = tmpCallResult" << order << ";\n"; + } + } + else + { + if(opType == "DD") + { + for(size_t i = 0; i < paramOpTypes.size(); i++) + { + auto ¶mOpType = paramOpTypes.at(i); + ofs << "\t" << "double p" << paramOrders.at(i) << "[2];\n"; + ofs << "\t" << "p" << paramOrders.at(i) << "[0] = tmp" << paramOrders.at(i) << ";\n"; + ofs << "\t" << "p" << paramOrders.at(i) << "[1] = 0;\n"; + } + + ofs << "\t" << "double tmpCallResult" << order << "[2];\n"; + auto it = callMap.find(callee); + auto callStr = it->second; + ofs << "\t" << callStr << "("; + for(size_t i = 0; i < paramOrders.size(); i++) + { + ofs << "p" << paramOrders.at(i) << ", "; + } + ofs << "tmpCallResult" << order; + ofs << ");\n"; + + ofs << "\t" << "double tmp" << order << "[2];\n"; + ofs << "\t" << "tmp" << order << "[0] = tmpCallResult" << order << "[0];\n"; + ofs << "\t" << "tmp" << order << "[1] = tmpCallResult" << order << "[1];\n"; + } + else if(opType == "ld") + { + // paramOpType must be double + for(size_t i = 0; i < paramOpTypes.size(); i++) + { + ofs << "\t" << "long double p" << paramOrders.at(i) << " = tmp" << paramOrders.at(i) << ";\n"; + } + + ofs << "\t" << "long double tmpCallResult" << order << " = " << callee << "("; // 应该可以根据函数参数类型,直接调用到ld版本吧 + for(size_t i = 0; i < paramOrders.size() - 1; i++) + { + ofs << "p" << paramOrders.at(i) << ", "; + } + ofs << "p" << paramOrders.back(); + ofs << ");\n"; + + ofs << "\t" << "long double tmp" << order << " = tmpCallResult" << order << ";\n"; + } + else + { + // paramOpType must be ld or double + for(size_t i = 0; i < paramOpTypes.size(); i++) + { + ofs << "\t" << "double p" << paramOrders.at(i) << " = tmp" << paramOrders.at(i) << ";\n"; + } + + ofs << "\t" << "double tmpCallResult" << order << " = " << callee << "("; + for(size_t i = 0; i < paramOrders.size() - 1; i++) + { + ofs << "p" << paramOrders.at(i) << ", "; + } + ofs << "p" << paramOrders.back(); + ofs << ");\n"; + + ofs << "\t" << "double tmp" << order << " = tmpCallResult" << order << ";\n"; + } + } + + + /* if(opType == "double") { for(size_t i = 0; i < paramOpTypes.size(); i++) @@ -1080,7 +1404,7 @@ int codegenKernel(ofstream &ofs, const ast_ptr &expr) fprintf(stderr, "ERROR: Unknown opType %s\n", opType.c_str()); exit(EXIT_FAILURE); } - + */ return order; } else if(type == "Binary") @@ -1149,12 +1473,20 @@ void codegen(ast_ptr &expr, vector &vars, const string funcName, ofstrea // Note: Each operator node has two states, double or double-double. if there are n node in that expression, there are 2^n states. // Generate double-double implementations in all states and return the number of generated codes -int codegenWrapper(ast_ptr &expr, vector &vars, const string uniqueLabel, string tail) +int codegenWrapper(ast_ptr &expr, vector &vars, const string uniqueLabel, string tail, std::map varsValue, size_t inputNum, vector &outputStr, vector dataTypes) { - // AST init - auto opOrder = setOrder(expr); - auto lenOp = opOrder.size(); - + // init + auto opSequence = setOrder(expr); + auto lenOp = opSequence.size(); + typedef std::map mapOpType; + vector opTypesAll; + + // for these expressions winth huge number mix-precision versions. + // 1st: set the opTypes vector + // 2nd: loop the vector to generate code and do other things + + //// 1st: set opTypesAll. There can be many methods about setting opTypes. + // set opTypes: method NO.1 // int depth = 0; // getDepth(expr, depth); @@ -1162,6 +1494,7 @@ int codegenWrapper(ast_ptr &expr, vector &vars, const string uniqueLabel // int middle = (depth - 3) > 1 ? (depth - 3) : 1; // !!! // int middle = depth - 1; // setType(expr, depth, middle); + // set opTypes: method NO.2 // auto order = expr->getOrder(); // vector opTypes; @@ -1178,40 +1511,126 @@ int codegenWrapper(ast_ptr &expr, vector &vars, const string uniqueLabel // } // currentNum = currentNum >> 1; // } - - vector dataTypes = {"DD", "ld", "double"}; - int lenDataTypes = dataTypes.size(); - int maxNum = pow(lenDataTypes, lenOp); // for dataTypes = {"ld", "double"}, maxNum = 1 << lenOp; - for(int num = 0; num < maxNum; num++) - { - // set opTypes: method NO.3 - auto currentNum = num; - std::map opTypes; - for(size_t i = 0; i < lenOp; i++) + + // set opTypes: method NO.3 + // int lenDataTypes = dataTypes.size(); + // int maxNum = pow(lenDataTypes, lenOp); // for dataTypes = {"ld", "double"}, maxNum = 1 << lenOp; + // for(int num = 0; num < maxNum; num++) + // { + // auto currentNum = num; + // std::map opTypes; + // for(size_t i = 0; i < lenOp; i++) + // { + // auto id = opSequence[i]; + // auto tmp = currentNum % lenDataTypes; + // opTypes[id] = dataTypes[tmp]; + // currentNum = currentNum / lenDataTypes; + // } + // opTypesAll.push_back(opTypes); + // } + + // set opTypes: method NO.4 + // for (size_t i = 0; i < lenOp; i++) + // { + // mapOpType opTypes; + // for(size_t j = 0; j < lenOp; j++) + // { + // auto id = opSequence[j]; + // opTypes[id] = dataTypes.at(1); // double + // } + // auto id = opSequence[i]; + // opTypes[id] = dataTypes.at(0); // DD + // opTypesAll.push_back(opTypes); + // } + + // set opTypes: method NO.5 + opSequence.pop_back(); + for(size_t numStep = 1; numStep < opSequence.size(); numStep++) + { + // judge if too many combination number + auto combNum = combination(numStep, opSequence.size()); + if(combNum > 200) { - auto id = opOrder[i]; - auto tmp = currentNum % lenDataTypes; - opTypes[id] = dataTypes[tmp]; - currentNum = currentNum / lenDataTypes; + cout << "ATTENTION: combination number " << combNum << " is too big to run!!!\n"; + continue; } + auto combResults = combinationNew(numStep, opSequence); + for(const auto &combResult : combResults) + { + mapOpType opTypes; + for(size_t j = 0; j < lenOp; j++) + { + auto id = opSequence[j]; + opTypes[id] = dataTypes.at(1); // double + } + for(size_t j = 0; j < combResult.size(); j++) + { + auto id = combResult.at(j); + opTypes[id] = dataTypes.at(0); // DD + } + opTypesAll.push_back(opTypes); + } + } + + //// 2nd: loop the vector to generate code and do other things + int currentNum = 0; + for(const auto &opTypes : opTypesAll) + { setType(expr, opTypes); // init to generate code string directory = "srcTest/" + uniqueLabel + "/"; - string funcName = "expr_" + uniqueLabel + "_" + tail + "_" + to_string(num); + string funcName = "expr_" + uniqueLabel + "_" + tail + "_" + to_string(currentNum); string fileName = directory + funcName + ".c"; - cout << "fileName: " << fileName << "\topTypes: "; - for(map::iterator it = opTypes.begin(); it != opTypes.end(); it++) + // cout << "\n\nfileName: " << fileName << "\topTypes: "; + ofstream file_clean(fileName, ios_base::out); + ofstream ofs(fileName, ios::app); + // call codegen to generate code + codegen(expr, vars, funcName, ofs); + + std::stringstream ss; + for(auto it = opTypes.begin(); it != opTypes.end(); it++) { - cout << it->first << " " << it->second << ", "; + // cout << it->first << " " << it->second << ", "; + ss << it->first << " " << it->second << " "; } - cout << "\n"; - ofstream file_clean(fileName, ios_base::out); - ofstream ofs(fileName, ios::app); + outputStr.push_back(ss.str()); - // call codegen to generate code - codegen(expr, vars, funcName, ofs); - } + /// call shadowValue to generate each step's values of expr. (Many points) + // varsValue is input values + // inputNum is the number of input data + // auto epsilonEStr = Shadow::shadowValue(expr, varsValue, inputNum, true, uniqueLabel, funcName); + // auto it = opSequence.begin(); + // for(int i = 0; i < (int)epsilonEStr.size(); i++) + // { + // auto &epsilonEStrNow = epsilonEStr.at(i); + // if(*it == i) + // { + // if(opTypes.at(i) == "DD") + // { + // cout << BOLDBRIGHTRED << epsilonEStrNow << "\n" << RESET; + // } + // else + // { + // cout << RED << epsilonEStrNow << "\n" << RESET; + // } + // it++; + // } + // else + // { + // cout << epsilonEStrNow << "\n"; + // } + // } + + /// call shadowValue to generate each step's values of expr. (Single point) + // unsigned long int pointHEX = 0x3fe6e4f765fd8adaul; + // double point = *((double *)(&pointHEX)); + // vector values(1, point); + // auto varsValue = setVarsValue(vars, values); + // fmt::print("varsValue = {}\n", varsValue); + // Shadow::shadowValue(expr, varsValue); - return maxNum; + currentNum++; + } + return opTypesAll.size(); } diff --git a/src/main.cpp b/src/main.cpp index f192b85cbda76ed7bf0d28bf9607363dea79c629..e0c34617d90dcfa0bcc02940d0ff9d5fce376394 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include "geneCode.hpp" #include "tools.hpp" #include "benchMark.hpp" +#include "shadowValue.hpp" #include #include @@ -279,6 +280,154 @@ int main() auto exprHerbie = geneHerbieCode(uniqueLabel); auto exprDaisy = geneDaisyCode(uniqueLabel); auto funcNameMpfr = geneMpfrCode(inputStr, uniqueLabel, vars); + printExpr(originExpr, "the origin expr: "); + std::cout << "NO. step\n"; + showOrder(originExpr); + + // set calculation order for originExpr + auto opSequence = setOrder(originExpr); + fmt::print("\noperation's Sequence: {}\nthe number of sequence: {}, the max number of mix-prec version: {}\n", opSequence, opSequence.size(), 1 << opSequence.size()); + + //// generate input data for shadow value + vector values1; + size_t inputNum = 100000; + size_t inputAllNum = 100000; + if (dimension == 1) + { + inputNum = 100000; + } + else if (dimension == 2) + { + inputNum = 316; // 316*316=99,856 + } + else if (dimension == 3) + { + inputNum = 100; + } + else if (dimension == 4) + { + inputNum = 18; // 18*18*18*18=104,976 + } + else + { + inputNum = 10; + } + inputAllNum = pow(inputNum, dimension); + for(int i = 0; i < dimension; i++) + { + auto &startOriginInterval = intervals.at(i * 2); + auto &endOriginInterval = intervals.at(i * 2 + 1); + double width = endOriginInterval - startOriginInterval; + double step = width / inputNum; + + double *tmp = new double[inputAllNum]; + for(size_t j = 0; j < inputAllNum; j++) + { + tmp[j] = startOriginInterval + (j % inputNum) * step; + } + values1.push_back(tmp); + } + auto varsValue1 = setVarsValue(vars, values1); + //// call the shadowValue function to generate the shadow values of the expression. The shadow values are stored into files partly. + // unsigned long int hjw = 0x3fe6e4f765fd8adaul; + // double hhh = *((double *)(&hjw)); + // vector values(2, hhh); + // auto varsValue = setVarsValue(vars, values); + // fmt::print("varsValue = {}\n", varsValue); + // Shadow::shadowValue(originExpr, varsValue); + + auto epsilonEStr = Shadow::shadowValue(originExpr, varsValue1, inputNum); + string tmpStr; + // tmpStr = fmt::format("expr: {}\n", exprOrigin); + // epsilonEStr.insert(epsilonEStr.begin(), tmpStr); + // tmpStr = fmt::format("# uniqueLabel: {}\n", uniqueLabel); + // epsilonEStr.insert(epsilonEStr.begin(), tmpStr); + std::ofstream outputFile; + outputFile.open("mixPrecNew.log", std::ios::out | std::ios::app); + if (outputFile.is_open() == false) + { + exit(EXIT_FAILURE); + } + for(int i = 0; i < (int)epsilonEStr.size(); i++) + { + auto &epsilonEStrNow = epsilonEStr.at(i); + cout << epsilonEStrNow << "\n"; + outputFile << epsilonEStrNow; + } + outputFile << "\n"; + outputFile.close(); + // fprintf(stderr, GREEN "ready> " RESET); + // continue; + //// TODO: free values1 + + //// support DD + vector outputStr; + vector dataTypes = {"DD", "double"}; + // setDataTypes(dataTypes); + auto maxNum = codegenWrapper(originExpr, vars, uniqueLabel, "dd", varsValue1, inputNum, outputStr, dataTypes); + //// test DD's error + vector startNowIdxs(dimension, 0); + vector startOriginIntervals; + vector steps; + for (int i = 0; i < dimension; i++) + { + auto &startOriginInterval = intervals.at(i * 2); + auto &endOriginInterval = intervals.at(i * 2 + 1); + startOriginIntervals.push_back(startOriginInterval); + double width = endOriginInterval - startOriginInterval; + double step = width / (double)scales.at(i); + steps.push_back(step); + } + testError(uniqueLabel, "origin", intervals, scales, startNowIdxs, startOriginIntervals, steps, false); + vector infos; + vector perfValues; + // for(int i = 0; i < maxNum; i++) { + // cout << "\n\n-test error-" << i << "\n"; + // string tmp = "dd_" + std::to_string(i); + // auto infoTmp = testError(uniqueLabel, tmp, intervals, scales, startNowIdxs, startOriginIntervals, steps, false); + // auto tmpPerformance = testPerformance(uniqueLabel, tmp, intervals); + // cout << tmp << " performance: " << tmpPerformance << "\n\n"; + // infos.push_back(infoTmp); + // perfValues.push_back(tmpPerformance); + // } + fprintf(stderr, GREEN "ready> " RESET); + continue; + // cout << std::left << setw(4) << "No"; + // cout << "\n\n" << std::left << setw(6) << "No" << std::left << setw(15) << "average_Err" << std::left << setw(15) << "max_Err"; + cout << "\n## Actual data\n\n" << std::left << setw(6) << "No" << std::left << setw(15) << "performamce" << std::left << setw(15) << "average_Err" << std::left << setw(15) << "max_Err"; + outputFile << "\n## Actual data\n\n" << std::left << setw(6) << "No" << std::left << setw(15) << "performamce" << std::left << setw(15) << "average_Err" << std::left << setw(15) << "max_Err"; + for(size_t i = 0; i < opSequence.size(); i++) { + cout << "step Type "; + outputFile << "step Type "; + } + cout << "\n"; + outputFile << "\n"; + for(int i = 0; i < maxNum; i++) + { + auto &info = infos.at(i); + auto &opTypeStr = outputStr.at(i); + // cout << std::left << setw(4) << i << opTypeStr << "\n"; + // cout << std::left << setw(6) << i << std::left << setw(15) << perfValues.at(i) << "\n"; + cout << std::left << setw(6) << i << std::left << setw(15) << perfValues.at(i) << std::left << setw(15) << info.aveError << std::left << setw(15) << info.maxError << opTypeStr << "\n"; + outputFile << std::left << setw(6) << i << std::left << setw(15) << perfValues.at(i) << std::left << setw(15) << info.aveError << std::left << setw(15) << info.maxError << opTypeStr << "\n"; + } + outputFile << "\n\n"; + + outputFile << "## Final data\n\n"; + cout << "\n\n## Final data\n\n"; + cout << std::left << setw(6) << "No" << std::left << setw(15) << "step log" << std::left << setw(15) << "average_Err" << std::left << setw(15) << "max_Err" << "performamce\n"; + outputFile << std::left << setw(6) << "No" << std::left << setw(15) << "step log" << std::left << setw(15) << "average_Err" << std::left << setw(15) << "max_Err" << "performamce\n"; + for(int i = 0; i < maxNum; i++) + { + auto &info = infos.at(i); + auto &opTypeStr = outputStr.at(i); + cout << std::left << setw(6) << i << std::left << setw(15) << epsilonEStr.at(i + 2) << " " << std::left << setw(15) << info.aveError << std::left << setw(15) << info.maxError << std::left << setw(15) << perfValues.at(i) << "\n"; + outputFile << std::left << setw(6) << i << std::left << setw(15) << epsilonEStr.at(i + 2) << " " << std::left << setw(15) << info.aveError << std::left << setw(15) << info.maxError << std::left << setw(15) << perfValues.at(i) << "\n"; + } + outputFile << "\n\n"; + outputFile.close(); + fprintf(stderr, GREEN "ready> " RESET); + continue; // if(exprOrigin != "") // { @@ -455,9 +604,6 @@ int main() auto funcNameFinal = geneFinalCodeKernel(inputStr, uniqueLabel, exprInfoVector, vars); cout << "=-=-=-=-=-=-=-=-=-=-=-=-= test final code's error and performance start =-=-=-=-=-=-=-=-=-=-=-=-=\n"; - vector startNowIdxs(dimension, 0); - vector startOriginIntervals; - vector steps; for (int i = 0; i < dimension; i++) { auto &startOriginInterval = intervals.at(i * 2); diff --git a/src/shadowValue.cpp b/src/shadowValue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54ada2658683c4c978dd40b99d5742d092ad7dc4 --- /dev/null +++ b/src/shadowValue.cpp @@ -0,0 +1,1582 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpreal.h" +#include "shadowValue.hpp" +#include "funclist.hpp" +#include "errorDetect.hpp" +#include "geneCode.hpp" + + +using std::string; +using std::vector; +using std::ofstream; +using std::ios; + +namespace Shadow { + +static const unsigned long int hugeNumINT = 0x7FC0000000000000ul; +static const double hugeNum = *(double *)(&hugeNumINT); // 1/8 * inf + +std::map> fDrvMapOne = { + {"sqrt", [](double x) { return 0.5 / sqrt(x); }}, + {"cbrt", [](double x) { return 1 / (3.0 * cbrt(x*x)); }}, + {"exp", [](double x) { return exp(x); }}, + {"exp2", [](double x) { return exp2(x) * log(2); }}, + {"exp10", [](double x) { return exp10(x) * log(10); }}, + {"log", [](double x) { return (1 / x); }}, + {"log2", [](double x) { return (1 / (x * log(2))); }}, + {"log10", [](double x) { return (1 / (x * log(10))); }}, + {"sin", [](double x) { return cos(x); }}, + {"cos", [](double x) { return -sin(x); }}, + {"tan", [](double x) { return 1 / (cos(x) * cos(x)); }}, + {"asin", [](double x) { return 1 / sqrt(1 - x * x); }}, + {"acos", [](double x) { return -1 / sqrt(1 - x * x); }}, + {"atan", [](double x) { return 1 / (1 + x * x); }}, +}; + +std::map> fDrvMapTwo = { + {"addL", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return 1; }}, + {"addR", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return 1; }}, + {"subL", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return 1; }}, + {"subR", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return -1; }}, + {"mulL", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return y; }}, + {"mulR", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return x; }}, + {"divL", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return 1 / y; }}, + {"divR", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return -x / (y * y); }}, + {"powL", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return y * pow(x, y - 1); }}, + {"powR", []([[maybe_unused]] double x, [[maybe_unused]] double y) { return log(x) * pow(x, y); }}, +}; + +std::map binaryOp = { + {'+', "add"}, + {'-', "sub"}, + {'*', "mul"}, + {'/', "div"}, +}; + +std::map opTypeMap = { + {"double", "d"}, + {"DD", "dd"}, + {"ld", "ld"}, +}; + +template +struct ParamTypeMapper +{ + using ParamType = T; +}; + +template <> +struct ParamTypeMapper +{ + using ParamType = mpfr::mpreal; +}; + +template <> +struct ParamTypeMapper +{ + using ParamType = mpfr::mpreal *; +}; + +template +using ParamType = typename ParamTypeMapper::ParamType; + +template +struct valueThree { + ParamType funcValue; + ParamType realValue; + T ulpValue; +}; + +template +void computeConditionNumberKernel(vector &conditionNumbers, vector &conditionNumbersOp, const int IDfather, int &IDnow, const int length = 1) +{ + constexpr bool TisDouble = (std::is_same::value); + constexpr bool TisDoublePointer = (std::is_same::value); + if constexpr (TisDouble) + { + conditionNumbersOp.at(IDnow) = conditionNumbersOp.at(IDfather) * conditionNumbers.at(IDnow); + } + else if constexpr (TisDoublePointer) + { + for(int i = 0; i < length; i++) + { + conditionNumbersOp.at(IDnow)[i] = conditionNumbersOp.at(IDfather)[i] * conditionNumbers.at(IDnow)[i]; + } + } + else + { + fprintf(stderr, "ERROR: %s: the type of T %s is not supported\n", __func__, typeid(T).name()); + exit(EXIT_FAILURE); + } +} + +template +void computeConditionNumber(const ast_ptr &expr, vector &conditionNumbers, vector &conditionNumbersOp, const int IDfather, int &IDnow, const int length = 1) +{ + auto type = expr->type(); + if(type == "Number") + { + return ; // do nothing + } + else if (type == "Variable") + { + return ; // do nothing + } + else if (type == "Call") + { + CallExprAST *callPtr = dynamic_cast(expr.get()); + auto &args = callPtr->getArgs(); + auto IDparam = new int[args.size()]; + + for (int i = args.size() - 1; i >= 0; i--) + { + computeConditionNumberKernel(conditionNumbers, conditionNumbersOp, IDfather, IDnow, length); + IDparam[i] = IDnow; + IDnow--; + } + for (int i = args.size() - 1; i >= 0; i--) + { + const auto &arg = args.at(i); + computeConditionNumber(arg, conditionNumbers, conditionNumbersOp, IDparam[i], IDnow, length); + } + delete []IDparam; + } + else if (type == "Binary") + { + BinaryExprAST *binPtr = dynamic_cast(expr.get()); + ast_ptr &lhs = binPtr->getLHS(); + ast_ptr &rhs = binPtr->getRHS(); + + computeConditionNumberKernel(conditionNumbers, conditionNumbersOp, IDfather, IDnow, length); + auto IDrhs = IDnow; + IDnow--; + computeConditionNumberKernel(conditionNumbers, conditionNumbersOp, IDfather, IDnow, length); + auto IDlhs = IDnow; + IDnow--; + + computeConditionNumber(rhs, conditionNumbers, conditionNumbersOp, IDrhs, IDnow, length); + computeConditionNumber(lhs, conditionNumbers, conditionNumbersOp, IDlhs, IDnow, length); + } + else + { + fprintf(stderr, "ERROR: %s : line %d: unknowntype %s\n", __func__, __LINE__, type.c_str()); + exit(EXIT_FAILURE); + } +} + +// The function takes in vecotor v as input, and returns vecotor res, where res[i] represents the rank of the v[i] by descending order." +vector getRanks(const vector &v, bool descending = true) +{ + vector sorted = v; + if(descending) + { + std::sort(sorted.begin(), sorted.end(), std::greater()); + } + else + { + std::sort(sorted.begin(), sorted.end(), std::less()); + } + auto last = std::unique(sorted.begin(), sorted.end()); // Remove duplicates + sorted.erase(last, sorted.end()); // Delete excess elements + vector res(v.size()); + for (size_t i = 0; i < v.size(); i++) + { + auto it = std::find(sorted.begin(), sorted.end(), v[i]); // Find the first occurrence of v[i] in sorted + res[i] = std::distance(sorted.begin(), it) + 1; // Record the position, which is the ranking of v[i] in the sorted order + } + + return res; +} + +template +vector computeEpsilonE(vector &benefit, vector &epsilonE, const vector &errorValues, const vector &conditionNumbersOp, const vector &condNumOrder, const vector &opSequence, const int length = 1) +{ + constexpr bool TisDouble = (std::is_same::value); + constexpr bool TisDoublePointer = (std::is_same::value); + if constexpr (TisDouble) + { + vector epsilonEStr; + for(size_t i = 0; i < errorValues.size(); i++) + { + epsilonE.at(i) = errorValues.at(i) * conditionNumbersOp.at(condNumOrder.at(i)); + epsilonEStr.push_back(std::to_string(epsilonE.at(i))); + } + auto sum = std::accumulate(epsilonE.begin(), epsilonE.end(), 0.0); + fmt::print("the average of epsilonE are: {}\n", epsilonE); + std::cout << "The sum of the elements in the vector is: " << sum << std::endl; + + // compute benefit + double minBenefit = std::numeric_limits::infinity(); + int minBenefitIdx = std::numeric_limits::infinity(); + for(size_t i = 0; i < errorValues.size(); i++) + { + benefit.at(i) = fabs(sum - epsilonE.at(i)); + if(benefit.at(i) < minBenefit) + { + minBenefit = benefit.at(i); + minBenefitIdx = i; + } + } + fmt::print("the benefit of steps are: {}\n", benefit); + std::cout << "minBenefitIdx: " << minBenefitIdx << ", minBenefit: " << minBenefit << std::endl; + + return epsilonEStr; + } + else if constexpr (TisDoublePointer) + { + vector epsilonEAverage(errorValues.size(), 0.0); + vector errorValuesAverage(errorValues.size(), 0.0); + vector conditionNumbersOpAverage(errorValues.size(), 0.0); + vector sumOfAll(length, 0.0); + + // compute epsilonE and its sum. These 3 average values are not useful + for(size_t i = 0; i < errorValues.size(); i++) + { + for(int j = 0; j < length; j++) + { + epsilonE.at(i)[j] = errorValues.at(i)[j] * conditionNumbersOp.at(condNumOrder.at(i))[j]; + epsilonEAverage.at(i) += epsilonE.at(i)[j]; + errorValuesAverage.at(i) += errorValues.at(i)[j]; + conditionNumbersOpAverage.at(i) += fabs(conditionNumbersOp.at(i)[j]); + sumOfAll.at(j) += epsilonE.at(i)[j]; + } + epsilonEAverage.at(i) /= length; + errorValuesAverage.at(i) /= length; + conditionNumbersOpAverage.at(i) /= length; + } + // auto sum = std::accumulate(epsilonEAverage.begin(), epsilonEAverage.end(), 0.0); + auto sum = std::accumulate(sumOfAll.begin(), sumOfAll.end(), 0.0); + auto sumAverage = fabs(sum / length); + + // compute benefit for 1-step + // notes: benefit is the predicted error value after mixed-precision tuning. + vector minBenefit(length, std::numeric_limits::infinity()); + vector minBenefitIdx(length, std::numeric_limits::infinity()); + vector benefitAverage(errorValues.size(), 0.0); + for(size_t i = 0; i < errorValues.size(); i++) + { + for(int j = 0; j < length; j++) + { + benefit.at(i)[j] = fabs(sumOfAll.at(j) - epsilonE.at(i)[j]); + if(benefit.at(i)[j] < minBenefit.at(j)) + { + minBenefit.at(j) = benefit.at(i)[j]; + minBenefitIdx.at(j) = i; + } + benefitAverage.at(i) += benefit.at(i)[j]; + } + benefitAverage.at(i) /= length; + } + // for(size_t i = 0; i < errorValues.size(); i++) + // { + // benefitAverage.at(i) = fabs((sum / length) - epsilonEAverage.at(i)); + // } + + // old print + // auto ranks1 = getRanks(benefitAverage, false); + // std::cout << "epsilonE rank\n"; + // vector epsilonEStr; + // for(size_t i = 0; i < epsilonEAverage.size(); i++) + // { + // // fmt::print("{} {}\n", epsilonEAverage.at(i), ranks.at(i)); + // // fmt::print("rank {}: errorValuesAverage = {} conditionNumbersOpAverage = {} epsilonEAverage = {}\n", ranks.at(i), errorValuesAverage.at(i), conditionNumbersOpAverage.at(i), epsilonEAverage.at(i)); + // // fmt::print("{}: {:<15e} {:<15e} {:<15e}\n", ranks.at(i), errorValuesAverage.at(i), conditionNumbersOpAverage.at(i), epsilonEAverage.at(i)); + // // auto epsilonEStrNow = fmt::format("{}: {:<15e} {:<15e} {:<15e}", ranks.at(i), errorValuesAverage.at(i), conditionNumbersOpAverage.at(i), epsilonEAverage.at(i)); + // auto epsilonEStrNow = fmt::format("{}: {:<15e}", ranks1.at(i), epsilonEAverage.at(i)); + // epsilonEStr.push_back(epsilonEStrNow); + // } + // auto sumEpsilon = std::accumulate(epsilonEAverage.begin(), epsilonEAverage.end(), 0.0); + // string sumEpsilonStr = fmt::format("The sum of the epsilon is {:g}\n", sumEpsilon); + // epsilonEStr.push_back(sumEpsilonStr); + // return epsilonEStr; + + // print + // fmt::print("the average of benefit are: {}", benefitAverage); + auto ranks = getRanks(benefitAverage, false); + // fmt::print("{:^4} {:<15}\n", "rank", "benefit"); + // fmt::print("{:<3} {:^4} {:<15}\n", "NO.", "rank", "benefit"); + fmt::print("{:<3} {:<4} {:<15} {:<15} {:<15} {:<15}\n", "No.", "rank", "errValAver", "condNumOpAver", "epsilonEAver", "benefit"); + vector benefitStr; + for(size_t i = 0; i < benefitAverage.size(); i++) + { + // fmt::print("{} {} {}\n", benefitAverage.at(i), ranks.at(i)); + // fmt::print("rank {}: errorValuesAverage = {} conditionNumbersOpAverage = {} benefitAverage = {}\n", ranks.at(i), errorValuesAverage.at(i), conditionNumbersOpAverage.at(i), benefitAverage.at(i)); + // fmt::print("{}: {:<15e} {:<15e} {:<15e}\n", ranks.at(i), errorValuesAverage.at(i), conditionNumbersOpAverage.at(i), benefitAverage.at(i)); + auto benefitStrNow = fmt::format("{:<3} {:<4} {:<15e} {:<15e} {:<15e} {:<15e}", i, ranks.at(i), errorValuesAverage.at(i), conditionNumbersOpAverage.at(i), epsilonEAverage.at(i), benefitAverage.at(i)); + // auto benefitStrNow = fmt::format("{:^4} {:<15e}", ranks.at(i), benefitAverage.at(i)); + // auto benefitStrNow = fmt::format("{:<3} {:^4} {:<15e}", i, ranks.at(i), benefitAverage.at(i)); + benefitStr.push_back(benefitStrNow); + } + string sumStr = fmt::format("The average sum of the epsilon is {:g}\n", sumAverage); + benefitStr.push_back(sumStr); + return benefitStr; + // compute n-step mixed-precision + // benefitStr.clear(); + // fmt::print("opSequence (remove the last step) for n-step: {}\n", opSequence); + string tmpStr = fmt::format("## mixed-precision predict\nopSequence (remove the last step) for n-step: {}\n", opSequence); + benefitStr.push_back(tmpStr); + for(size_t numStep = 1; numStep < opSequence.size(); numStep++) + // for(size_t numStep = 1; numStep < 2; numStep++) + { + // judge if too many combination number + auto combNum = combination(numStep, opSequence.size()); + if(combNum > 200) + { + cout << "ATTENTION: combination number " << combNum << " is too big to run!!!\n"; + continue; + } + auto combResults = combinationNew(numStep, opSequence); + // fmt::print("for {}-step, combResult = {}\n", numStep, combResults); + tmpStr = fmt::format("### for {}-step\n\tcombResult = {}\n", numStep, combResults); + benefitStr.push_back(tmpStr); + vector benefitAverage; + vector tmp(length, 1); + for(const auto &combResult : combResults) + { + double benefitTmp = 0.0; + for(int j = 0; j < length; j++) + { + tmp.at(j) = sumOfAll.at(j); + for(size_t i = 0; i < combResult.size(); i++) + { + auto stepIdx = combResult.at(i); + tmp.at(j) = tmp.at(j) - epsilonE.at(stepIdx)[j]; + } + tmp.at(j) = fabs(tmp.at(j)); + benefitTmp += tmp.at(j); + } + benefitTmp /= length; + benefitAverage.push_back(benefitTmp); + } + auto ranks = getRanks(benefitAverage, false); + // fmt::print("\tbenefitAverage = {}\n", benefitAverage); + // fmt::print("\tranks = {}\n", ranks); + tmpStr = fmt::format("\tbenefitAverage = {}\n", benefitAverage);; + benefitStr.push_back(tmpStr); + tmpStr = fmt::format("\tranks = {}\n", ranks); + benefitStr.push_back(tmpStr); + + benefitStr.push_back("step log\n"); + cout << "step log\n"; + for(size_t i = 0; i < benefitAverage.size(); i++) + { + // tmpStr = fmt::format("{}", combResults.at(i)); + auto &combResult = combResults.at(i); + tmpStr = std::to_string(combResult.at(0)); + for(size_t j = 1; j < combResult.size(); j++) + { + tmpStr = tmpStr + "," + std::to_string(combResult.at(j)); + } + tmpStr = tmpStr + " " + std::to_string(ranks.at(i)) + "\n"; + cout << tmpStr; + benefitStr.push_back(tmpStr); + } + } + return benefitStr; + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } +} + +template +vector computeEpsilonENew(vector &benefit, vector &epsilonE, const vector &errorValues, const vector &conditionNumbersOp, const vector &condNumOrder, const vector &opSequence, const int length = 1) +{ + constexpr bool TisDouble = (std::is_same::value); + constexpr bool TisDoublePointer = (std::is_same::value); + if constexpr (TisDouble) + { + vector epsilonEStr; + for(size_t i = 0; i < errorValues.size(); i++) + { + epsilonE.at(i) = errorValues.at(i) * conditionNumbersOp.at(condNumOrder.at(i)); + epsilonEStr.push_back(std::to_string(epsilonE.at(i))); + } + auto sum = std::accumulate(epsilonE.begin(), epsilonE.end(), 0.0); + fmt::print("the average of epsilonE are: {}\n", epsilonE); + std::cout << "The sum of the elements in the vector is: " << sum << std::endl; + + // compute benefit + double minBenefit = std::numeric_limits::infinity(); + int minBenefitIdx = std::numeric_limits::infinity(); + for(size_t i = 0; i < errorValues.size(); i++) + { + benefit.at(i) = fabs(sum - epsilonE.at(i)); + if(benefit.at(i) < minBenefit) + { + minBenefit = benefit.at(i); + minBenefitIdx = i; + } + } + fmt::print("the benefit of steps are: {}\n", benefit); + std::cout << "minBenefitIdx: " << minBenefitIdx << ", minBenefit: " << minBenefit << std::endl; + + return epsilonEStr; + } + else if constexpr (TisDoublePointer) + { + vector epsilonEAverage(errorValues.size(), 0.0); + vector errorValuesAverage(errorValues.size(), 0.0); + vector conditionNumbersOpAverage(errorValues.size(), 0.0); + vector sumOfAll(length, 0.0); + + // compute epsilonE and its sum. These 3 average values are not useful + for(size_t i = 0; i < errorValues.size(); i++) + { + for(int j = 0; j < length; j++) + { + epsilonE.at(i)[j] = errorValues.at(i)[j] * conditionNumbersOp.at(condNumOrder.at(i))[j]; + epsilonEAverage.at(i) += epsilonE.at(i)[j]; + errorValuesAverage.at(i) += errorValues.at(i)[j]; + conditionNumbersOpAverage.at(i) += conditionNumbersOp.at(i)[j]; + sumOfAll.at(j) += epsilonE.at(i)[j]; + } + epsilonEAverage.at(i) /= length; + errorValuesAverage.at(i) /= length; + conditionNumbersOpAverage.at(i) /= length; + } + // auto sum = std::accumulate(epsilonEAverage.begin(), epsilonEAverage.end(), 0.0); + auto sum = std::accumulate(sumOfAll.begin(), sumOfAll.end(), 0.0); + auto sumAverage = fabs(sum / length); + + // compute benefit for 1-step + // notes: benefit is the predicted error value after mixed-precision tuning. + vector minBenefit(length, std::numeric_limits::infinity()); + vector minBenefitIdx(length, std::numeric_limits::infinity()); + vector benefitAverage(errorValues.size(), 0.0); + for(size_t i = 0; i < errorValues.size(); i++) + { + for(int j = 0; j < length; j++) + { + benefit.at(i)[j] = fabs(sumOfAll.at(j) - epsilonE.at(i)[j]); + if(benefit.at(i)[j] < minBenefit.at(j)) + { + minBenefit.at(j) = benefit.at(i)[j]; + minBenefitIdx.at(j) = i; + } + benefitAverage.at(i) += benefit.at(i)[j]; + } + benefitAverage.at(i) /= length; + } + + // print + vector benefitStr; + // compute n-step mixed-precision + // string tmpStr = fmt::format("## mixed-precision predict\nopSequence (remove the last step) for n-step: {}\n", opSequence); + // benefitStr.push_back(tmpStr); + string tmpStr; + for(size_t numStep = 1; numStep < opSequence.size(); numStep++) + { + // judge if too many combination number + auto combNum = combination(numStep, opSequence.size()); + if(combNum > 200) + { + cout << "ATTENTION: combination number " << combNum << " is too big to run!!!\n"; + continue; + } + auto combResults = combinationNew(numStep, opSequence); + fmt::print("for {}-step, combResult = {}\n", numStep, combResults); + // tmpStr = fmt::format("### for {}-step\n\tcombResult = {}\n", numStep, combResults); + // benefitStr.push_back(tmpStr); + vector benefitAverage; + vector tmp(length, 1); + for(const auto &combResult : combResults) + { + double benefitTmp = 0.0; + for(int j = 0; j < length; j++) + { + tmp.at(j) = sumOfAll.at(j); + for(size_t i = 0; i < combResult.size(); i++) + { + auto stepIdx = combResult.at(i); + tmp.at(j) = tmp.at(j) - epsilonE.at(stepIdx)[j]; + } + tmp.at(j) = fabs(tmp.at(j)); + benefitTmp += tmp.at(j); + } + benefitTmp /= length; + benefitAverage.push_back(benefitTmp); + } + auto ranks = getRanks(benefitAverage, false); + fmt::print("\tbenefitAverage = {}\n", benefitAverage); + fmt::print("\tranks = {}\n", ranks); + // tmpStr = fmt::format("\tbenefitAverage = {}\n", benefitAverage);; + // benefitStr.push_back(tmpStr); + // tmpStr = fmt::format("\tranks = {}\n", ranks); + // benefitStr.push_back(tmpStr); + + // benefitStr.push_back("step log\n"); + cout << "step log\n"; + for(size_t i = 0; i < benefitAverage.size(); i++) + { + // tmpStr = fmt::format("{}", combResults.at(i)); + auto &combResult = combResults.at(i); + tmpStr = std::to_string(combResult.at(0)); + for(size_t j = 1; j < combResult.size(); j++) + { + tmpStr = tmpStr + "," + std::to_string(combResult.at(j)); + } + tmpStr = tmpStr + " " + std::to_string(ranks.at(i)); + cout << tmpStr << "\n"; + benefitStr.push_back(tmpStr); + } + } + return benefitStr; + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } +} + +template +valueThree shadowValueKernel(const ast_ptr &expr, const std::map &varsValue, vector> &funcValues, vector> &funcRealValues, vector> &mathRealValues, vector &errorValues, vector &conditionNumbers, vector &errorValueOrder, int length = 1) +{ + auto type = expr->type(); + constexpr bool TisDouble = (std::is_same::value); + constexpr bool TisDoublePointer = (std::is_same::value); + valueThree result; + if(type == "Number") + { + NumberExprAST *numberExpr = dynamic_cast(expr.get()); + auto funcValue = (numberExpr->getNumber()); + if constexpr (TisDouble) + { + result.funcValue = funcValue; + result.realValue = result.funcValue; + result.ulpValue = computeUlpUnit(funcValue); // may set to ZERO! + funcValues.push_back(result.funcValue); + funcRealValues.push_back(result.realValue); + mathRealValues.push_back(result.realValue); + errorValues.push_back(0); + // conditionNumber : do nothing + } + else if constexpr (TisDoublePointer) + { + auto tmpfuncValues = new mpfr::mpreal[length]; + auto tmpRealValues = new mpfr::mpreal[length]; + auto tmperrorValues = new double[length](); + auto tmpUlpValues = new double[length](); + for(int i = 0; i < length; i++) + { + tmpfuncValues[i] = funcValue; + tmpRealValues[i] = funcValue; + tmpUlpValues[i] = computeUlpUnit(funcValue); // may set to ZERO! + } + result.funcValue = tmpfuncValues; + result.realValue = tmpRealValues; + result.ulpValue = tmpUlpValues; + funcValues.push_back(tmpfuncValues); + funcRealValues.push_back(tmpRealValues); + mathRealValues.push_back(tmpRealValues); + errorValues.push_back(tmperrorValues); + // conditionNumber : do nothing + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + return result; + } + else if(type == "Variable") + { + VariableExprAST *variableExpr = dynamic_cast(expr.get()); + string variable = (variableExpr->getVariable()); + auto varValue = varsValue.find(variable)->second; + // if(std::is_same::type, T>::value) + if constexpr (TisDouble) + { + result.funcValue = varValue; + result.realValue = result.funcValue; + result.ulpValue = computeUlpUnit(varValue); + funcValues.push_back(result.funcValue); + funcRealValues.push_back(result.realValue); + mathRealValues.push_back(result.realValue); + errorValues.push_back(0); + // conditionNumber : do nothing + } + else if constexpr (TisDoublePointer) + { + auto tmpfuncValues = new mpfr::mpreal[length]; + auto tmpRealValues = new mpfr::mpreal[length]; + auto tmperrorValues = new double[length](); + auto tmpUlpValues = new double[length](); + for(int i = 0; i < length; i++) + { + auto &tmpfuncValue = varValue[i]; + tmpfuncValues[i] = tmpfuncValue; + tmpRealValues[i] = tmpfuncValue; + tmpUlpValues[i] = computeUlpUnit(tmpfuncValue); + } + result.funcValue = tmpfuncValues; + result.realValue = tmpRealValues; + result.ulpValue = tmpUlpValues; + funcValues.push_back(tmpfuncValues); + funcRealValues.push_back(tmpRealValues); + mathRealValues.push_back(tmpRealValues); + errorValues.push_back(tmperrorValues); + // conditionNumber : do nothing + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + + return result; + } + else if(type == "Call") + { + CallExprAST *callPtr = dynamic_cast(expr.get()); + auto &args = callPtr->getArgs(); + vector> paramResults; + vector paramResultsDouble; + vector> paramFuncRealResults; + vector> parammathRealResults; + vector paramUlpResults; + + for(auto& arg : args) + { + auto tmp = shadowValueKernel(arg, varsValue, funcValues, funcRealValues, mathRealValues, errorValues, conditionNumbers, errorValueOrder, length); + paramResults.push_back(tmp.funcValue); + if constexpr (TisDouble) + { + paramFuncRealResults.push_back(tmp.funcValue); + paramResultsDouble.push_back((tmp.funcValue).toDouble()); + } + parammathRealResults.push_back(tmp.realValue); + paramUlpResults.push_back(tmp.ulpValue); + // condition number vector's op order + errorValueOrder.push_back(arg->getOrder()); + } + + // func + auto tmpCall = callPtr->getCallback(); + auto callee = callPtr->getCallee(); + auto calleeType = callPtr->getOpType(); + auto callTypeStr = opTypeMap.find(calleeType)->second; + string mapType; + for(const auto& arg : args) + { + auto opType = arg->getOpType(); + auto opTypeStr = opTypeMap.find(opType)->second; + mapType += "_" + opTypeStr; + } + + // func value + if constexpr (TisDouble) + { + if(mapType == "_d_dd") + { + double x0[2]{0}; + double x1[2]{0}; + auto tmpDoubleCall = doubleCall_d_dd_map.find(callee + "_" + callTypeStr)->second; + x0[0] = (paramResults.at(0)).toDouble(); + x1[0] = (paramResults.at(1)).toDouble(); + x1[1] = (paramResults.at(1) - x1[0]).toDouble(); + mpfr::mpreal tmp = tmpDoubleCall(x0[0], x1); + result.funcValue = tmp; + } + else if(mapType == "_dd_d") + { + double x0[2]{0}; + double x1[2]{0}; + auto tmpDoubleCall = doubleCall_dd_d_map.find(callee + "_" + callTypeStr)->second; + x0[0] = (paramResults.at(0)).toDouble(); + x0[1] = (paramResults.at(0) - x0[0]).toDouble(); + x1[0] = (paramResults.at(1)).toDouble(); + mpfr::mpreal tmp = tmpDoubleCall(x0, x1[0]); + result.funcValue = tmp; + } + else if(mapType == "_dd_dd") + { + double x0[2]{0}; + double x1[2]{0}; + auto tmpDoubleCall = doubleCall_dd_dd_map.find(callee + "_" + callTypeStr)->second; + x0[0] = (paramResults.at(0)).toDouble(); + x0[1] = (paramResults.at(0) - x0[0]).toDouble(); + x1[0] = (paramResults.at(1)).toDouble(); + x1[1] = (paramResults.at(1) - x1[0]).toDouble(); + mpfr::mpreal tmp = tmpDoubleCall(x0, x1); + result.funcValue = tmp; + } + else if(mapType == "_d_d") + { + double x0[2]{0}; + double x1[2]{0}; + if(callTypeStr == "dd") + { + auto tmpDoubleCall = doubleCall_d_d_map.find(callee + "_" + callTypeStr)->second; + x0[0] = (paramResults.at(0)).toDouble(); + x1[0] = (paramResults.at(1)).toDouble(); + mpfr::mpreal tmp = tmpDoubleCall(x0[0], x1[0]); + result.funcValue = tmp; + } + else + { + double tmp = tmpCall(paramResultsDouble); + result.funcValue = tmp; + } + } + else if(mapType == "_dd") + { + double x1[2]{0}; + x1[0] = paramResults.at(0).toDouble(); + x1[1] = (paramResults.at(0) - x1[0]).toDouble(); + auto tmpSingleCall = singleCall_dd_map.find(callee + "_" + callTypeStr)->second; + mpfr::mpreal tmp = tmpSingleCall(x1); + result.funcValue = tmp; + } + else if(mapType == "_d") + { + if(callTypeStr == "dd") + { + double x1[2]{0}; + x1[0] = paramResults.at(0).toDouble(); + auto tmpSingleCall = singleCall_dd_map.find(callee + "_" + callTypeStr)->second; + mpfr::mpreal tmp = tmpSingleCall(x1); + result.funcValue = tmp; + } + else + { + double tmp = tmpCall(paramResultsDouble); + result.funcValue = tmp; + } + } + else + { + fprintf(stderr, "ERROR: %s : line %d: Invalid map type: %s\n", __func__, __LINE__, mapType.c_str()); + exit(EXIT_FAILURE); + } + // std::cout << "callee = " << callPtr->getCallee() << " result = " << result.funcValue << std::endl; + funcValues.push_back(result.funcValue); + } + else if constexpr (TisDoublePointer) + { + auto tmpfuncValues = new mpfr::mpreal[length]; + if(mapType == "_d_dd") + { + double x0[2]{0}; + double x1[2]{0}; + auto tmpDoubleCall = doubleCall_d_dd_map.find(callee + "_" + callTypeStr)->second; + for(int i = 0; i < length; i++) + { + x0[0] = ((paramResults.at(0))[i]).toDouble(); + x1[0] = ((paramResults.at(1))[i]).toDouble(); + x1[1] = ((paramResults.at(1))[i] - x1[0]).toDouble(); + tmpfuncValues[i] = tmpDoubleCall(x0[0], x1); + } + } + else if(mapType == "_dd_d") + { + double x0[2]{0}; + double x1[2]{0}; + auto tmpDoubleCall = doubleCall_dd_d_map.find(callee + "_" + callTypeStr)->second; + for(int i = 0; i < length; i++) + { + x0[0] = ((paramResults.at(0))[i]).toDouble(); + x0[1] = ((paramResults.at(0))[i] - x0[0]).toDouble(); + x1[0] = ((paramResults.at(1))[i]).toDouble(); + tmpfuncValues[i] = tmpDoubleCall(x0, x1[0]); + } + } + else if(mapType == "_dd_dd") + { + double x0[2]{0}; + double x1[2]{0}; + auto tmpDoubleCall = doubleCall_dd_dd_map.find(callee + "_" + callTypeStr)->second; + for(int i = 0; i < length; i++) + { + x0[0] = ((paramResults.at(0))[i]).toDouble(); + x0[1] = ((paramResults.at(0))[i] - x0[0]).toDouble(); + x1[0] = ((paramResults.at(1))[i]).toDouble(); + x1[1] = ((paramResults.at(1))[i] - x1[0]).toDouble(); + tmpfuncValues[i] = tmpDoubleCall(x0, x1); + } + } + else if(mapType == "_d_d") + { + double x0[2]{0}; + double x1[2]{0}; + if(callTypeStr == "dd") + { + auto tmpDoubleCall = doubleCall_d_d_map.find(callee + "_" + callTypeStr)->second; + for(int i = 0; i < length; i++) + { + x0[0] = ((paramResults.at(0))[i]).toDouble(); + x1[0] = ((paramResults.at(1))[i]).toDouble(); + tmpfuncValues[i] = tmpDoubleCall(x0[0], x1[0]); + } + } + else + { + for(int i = 0; i < length; i++) + { + vector tmpParam; + for(auto ¶m : paramResults) + { + tmpParam.push_back((param[i]).toDouble()); + } + tmpfuncValues[i] = tmpCall(tmpParam); + } + } + } + else if(mapType == "_dd") + { + double x1[2]{0}; + mpfr::mpreal tmp; + auto tmpSingleCall = singleCall_dd_map.find(callee + "_" + callTypeStr)->second; + for(int i = 0; i < length; i++) + { + x1[0] = ((paramResults.at(0))[i]).toDouble(); + x1[1] = ((paramResults.at(0))[i] - x1[0]).toDouble(); + tmpfuncValues[i] = tmpSingleCall(x1); + } + } + else if(mapType == "_d") + { + if(callTypeStr == "dd") + { + auto tmpSingleCall = singleCall_dd_map.find(callee + "_" + callTypeStr)->second; + double x1[2]{0}; + for(int i = 0; i < length; i++) + { + x1[0] = ((paramResults.at(0))[i]).toDouble(); + mpfr::mpreal funcValue = tmpSingleCall(x1); + tmpfuncValues[i] = funcValue; + } + } + else + { + for(int i = 0; i < length; i++) + { + vector tmpParam; + for(auto ¶m : paramResults) + { + tmpParam.push_back((param[i]).toDouble()); + } + double funcValue = tmpCall(tmpParam); + tmpfuncValues[i] = funcValue; + } + } + } + else + { + fprintf(stderr, "ERROR: %s : line %d: Invalid map type: %s\n", __func__, __LINE__, mapType.c_str()); + exit(EXIT_FAILURE); + } + + result.funcValue = tmpfuncValues; + funcValues.push_back(tmpfuncValues); + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + + // real func + auto tmpRealCall = callPtr->getRealCallback(); + + // func real value & math real value & ulp unit value & error value + if constexpr (TisDouble) + { + // func real value + mpfr::mpreal funcRealValue = tmpRealCall(paramFuncRealResults); + // std::cout << "callee = " << callPtr->getCallee() << " funcRealValue = " << funcRealValue.toString() << std::endl; + funcRealValues.push_back(funcRealValue); + + // math real value + result.realValue = tmpRealCall(parammathRealResults); + // std::cout << "callee = " << callPtr->getCallee() << " mathRealResult = " << result.realValue.toString() << std::endl; + mathRealValues.push_back(result.realValue); + + // math real value's ulp unit Value + result.ulpValue = computeUlpUnit(result.realValue); + + // error value according funcReal & func & mathReal values + auto errorValue = computeError(funcRealValue, result.funcValue, result.ulpValue); + errorValues.push_back(errorValue); + } + else if constexpr (TisDoublePointer) + { + auto tmpfuncRealValues = new mpfr::mpreal[length]; + auto tmpmathRealValues = new mpfr::mpreal[length]; + auto tmpUlpValues = new double[length]; + auto tmpErrorValues = new double[length]; + for(int i = 0; i < length; i++) + { + // func real value + vector tmpParam; + for(auto ¶m : paramResults) + { + tmpParam.push_back(param[i]); + } + auto funcRealValue = tmpRealCall(tmpParam); + tmpfuncRealValues[i] = funcRealValue; + + // math real value + vector tmpParam1; + for(auto ¶m : parammathRealResults) + { + tmpParam1.push_back(param[i]); + } + auto mathRealValue = tmpRealCall(tmpParam1); + tmpmathRealValues[i] = mathRealValue; + + // math real value's ulp unit Value + tmpUlpValues[i] = computeUlpUnit(mathRealValue); + + // error value according funcReal & func & mathReal values + tmpErrorValues[i] = computeError(funcRealValue, ((result.funcValue)[i]), tmpUlpValues[i]); + } + funcRealValues.push_back(tmpfuncRealValues); + mathRealValues.push_back(tmpmathRealValues); + errorValues.push_back(tmpErrorValues); + result.realValue = tmpmathRealValues; + result.ulpValue = tmpUlpValues; + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + + // condition number value + if constexpr (TisDouble) + { + auto &ulpY = result.ulpValue; + // std::function funcDrv = [](double x){ return exp(x); }; + // std::function funcDrv = &exp; // wrong! + // std::function funcDrv = exp; // wrong! + const size_t &lenParam = args.size(); + if (lenParam == 1) + { + std::function funcDrv = fDrvMapOne.find(callee)->second; + auto &ulpX = paramUlpResults.at(0); + auto input = parammathRealResults.at(0).toDouble(); + auto derivativeFuncValue = funcDrv(input); + auto conditionNumber = ulpX * derivativeFuncValue / ulpY; + if(!finite(conditionNumber)) + { + conditionNumber = hugeNum; + } + conditionNumbers.push_back(conditionNumber); + } + else if (lenParam == 2) + { + std::function funcDrv; + auto inputX1 = parammathRealResults.at(0).toDouble(); + auto inputX2 = parammathRealResults.at(1).toDouble(); + + funcDrv = fDrvMapTwo.find(callee + "L")->second; + auto derivativeFuncValue = funcDrv(inputX1, inputX2); + auto &ulpX1 = paramUlpResults.at(0); + auto conditionNumber = ulpX1 * derivativeFuncValue / ulpY; + if(!finite(conditionNumber)) + { + conditionNumber = hugeNum; + } + conditionNumbers.push_back(conditionNumber); + + funcDrv = fDrvMapTwo.find(callee + "R")->second; + derivativeFuncValue = funcDrv(inputX1, inputX2); + auto &ulpX2 = paramUlpResults.at(1); + conditionNumber = ulpX2 * derivativeFuncValue / ulpY; + if(!finite(conditionNumber)) + { + conditionNumber = hugeNum; + } + conditionNumbers.push_back(conditionNumber); + } + else + { + fprintf(stderr, "ERROR: %s : line %d: we can not support %ld parameters' function call\n", __func__, __LINE__, lenParam); + exit(EXIT_FAILURE); + } + // for(size_t i = 0; i < parammathRealResults.size(); i++) + // { + // auto &ulpX = paramUlpResults.at(i); + // auto input = parammathRealResults.at(i).toDouble(); + // auto derivativeFuncValue = funcDrv(input); + // auto conditionNumber = (ulpX * derivativeFuncValue / ulpY).toDouble(); + // conditionNumbers.push_back(conditionNumber); + // } + } + else if constexpr (TisDoublePointer) + { + auto &ulpYs = result.ulpValue; + // std::function funcDrv = [](double x){ return exp(x); }; + // std::function funcDrv = &exp; // wrong! + // std::function funcDrv = exp; // wrong! + const size_t &lenParam = args.size(); + if (lenParam == 1) + { + std::function funcDrv = fDrvMapOne.find(callee)->second; + auto tmpConditionNumbers = new double[length]; + for(int i = 0; i < length; i++) + { + auto ulpX = paramUlpResults.at(0)[i]; + auto input = parammathRealResults.at(0)[i].toDouble(); + auto derivativeFuncValue = funcDrv(input); + tmpConditionNumbers[i] = ulpX * derivativeFuncValue / ulpYs[i]; + if(!finite(tmpConditionNumbers[i])) + { + tmpConditionNumbers[i] = hugeNum; + } + } + conditionNumbers.push_back(tmpConditionNumbers); + } + else if (lenParam == 2) + { + std::function funcDrvL, funcDrvR; + auto tmpConditionNumbers1 = new double[length]; + auto tmpConditionNumbers2 = new double[length]; + funcDrvL = fDrvMapTwo.find(callee + "L")->second; + funcDrvR = fDrvMapTwo.find(callee + "R")->second; + for(int i = 0; i < length; i++) + { + auto inputX1 = parammathRealResults.at(0)[i].toDouble(); + auto inputX2 = parammathRealResults.at(1)[i].toDouble(); + + auto derivativeFuncValue = funcDrvL(inputX1, inputX2); + auto &ulpX1 = paramUlpResults.at(0)[i]; + tmpConditionNumbers1[i] = ulpX1 * derivativeFuncValue / ulpYs[i]; + + derivativeFuncValue = funcDrvR(inputX1, inputX2); + auto &ulpX2 = paramUlpResults.at(1)[i]; + tmpConditionNumbers2[i] = ulpX2 * derivativeFuncValue / ulpYs[i]; + + if(!finite(tmpConditionNumbers1[i])) + { + tmpConditionNumbers1[i] = hugeNum; + } + if(!finite(tmpConditionNumbers2[i])) + { + tmpConditionNumbers2[i] = hugeNum; + } + } + conditionNumbers.push_back(tmpConditionNumbers1); + conditionNumbers.push_back(tmpConditionNumbers2); + } + else + { + fprintf(stderr, "ERROR: %s : line %d: we can not support %ld parameters' function call\n", __func__, __LINE__, lenParam); + exit(EXIT_FAILURE); + } + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + + return result; + } + else if(type == "Binary") + { + BinaryExprAST *binPtr = dynamic_cast(expr.get()); + ast_ptr &lhs = binPtr->getLHS(); + ast_ptr &rhs = binPtr->getRHS(); + auto lhsValue = shadowValueKernel(lhs, varsValue, funcValues, funcRealValues, mathRealValues, errorValues, conditionNumbers, errorValueOrder, length); + auto rhsValue = shadowValueKernel(rhs, varsValue, funcValues, funcRealValues, mathRealValues, errorValues, conditionNumbers, errorValueOrder, length); + + // func + auto tmpCall = binPtr->getCallback(); + auto op = binPtr->getOp(); + auto opType = binPtr->getOpType(); + auto opTypeStr = opTypeMap.find(opType)->second; + auto opTypeLHS = lhs->getOpType(); + auto opTypeRHS = rhs->getOpType(); + auto opStr = binaryOp.find(op)->second; + auto opTypeLhsStr = opTypeMap.find(opTypeLHS)->second; + auto opTypeRhsStr = opTypeMap.find(opTypeRHS)->second; + auto mapType = opTypeLhsStr + "_" + opTypeRhsStr; + + // condition number vector's op order + errorValueOrder.push_back(lhs->getOrder()); + errorValueOrder.push_back(rhs->getOrder()); + + // func value + if constexpr (TisDouble) + { + double x1[2]{0}; + double x2[2]{0}; + x1[0] = lhsValue.funcValue.toDouble(); + x2[0] = rhsValue.funcValue.toDouble(); + if(mapType == "d_dd") + { + auto tmpDoubleCall = doubleCall_d_dd_map.find(opStr + "_" + opTypeStr)->second; + x2[1] = (rhsValue.funcValue - x2[0]).toDouble(); + result.funcValue = tmpDoubleCall(x1[0], x2); + } + else if(mapType == "dd_d") + { + auto tmpDoubleCall = doubleCall_dd_d_map.find(opStr + "_" + opTypeStr)->second; + x1[1] = (lhsValue.funcValue - x1[0]).toDouble(); + result.funcValue = tmpDoubleCall(x1, x2[0]); + } + else if(mapType == "dd_dd") + { + auto tmpDoubleCall = doubleCall_dd_dd_map.find(opStr + "_" + opTypeStr)->second; + x1[1] = (lhsValue.funcValue - x1[0]).toDouble(); + x2[1] = (rhsValue.funcValue - x2[0]).toDouble(); + result.funcValue = tmpDoubleCall(x1, x2); + } + else if(mapType == "d_d") + { + if(opTypeStr == "dd") + { + auto tmpDoubleCall = doubleCall_d_d_map.find(opStr + "_" + opTypeStr)->second; + result.funcValue = tmpDoubleCall(x1[0], x2[0]); + } + else + { + result.funcValue = tmpCall(x1[0], x2[0]); + } + } + else + { + fprintf(stderr, "ERROR: %s : line %d: Invalid map type: %s\n", __func__, __LINE__, mapType.c_str()); + exit(EXIT_FAILURE); + } + // std::cout << "op = " << binPtr->getOp() << " result = " << result.funcValue << std::endl; + funcValues.push_back(result.funcValue); + + } + // TODO: (DONE) 按照double的方法,需要考虑输入为d_d的情况。目前这样可以解决模型不唯一的问题。 + // TODO: 下一步就是怎么把代码实现对应到模型上。可能需要重新考虑把当前步骤更改为dd带来的影响。 + else if constexpr (TisDoublePointer) + { + auto tmpfuncValues = new mpfr::mpreal[length]; + double x1[2]{0}; + double x2[2]{0}; + if(mapType == "d_dd") + { + auto tmpDoubleCall = doubleCall_d_dd_map.find(opStr + "_" + opTypeStr)->second; + for(int i = 0; i < length; i++) + { + auto &tmpLhsValue = (lhsValue.funcValue)[i]; + auto &tmpRhsValue = (rhsValue.funcValue)[i]; + x2[0] = tmpRhsValue.toDouble(); + x2[1] = (tmpRhsValue - x2[0]).toDouble(); + tmpfuncValues[i] = tmpDoubleCall(tmpLhsValue.toDouble(), x2); + } + } + else if(mapType == "dd_d") + { + auto tmpDoubleCall = doubleCall_dd_d_map.find(opStr + "_" + opTypeStr)->second; + for(int i = 0; i < length; i++) + { + auto &tmpLhsValue = (lhsValue.funcValue)[i]; + auto &tmpRhsValue = (rhsValue.funcValue)[i]; + x1[0] = tmpLhsValue.toDouble(); + x1[1] = (tmpLhsValue - x1[0]).toDouble(); + tmpfuncValues[i] = tmpDoubleCall(x1, tmpRhsValue.toDouble()); + } + } + else if(mapType == "dd_dd") + { + auto tmpDoubleCall = doubleCall_dd_dd_map.find(opStr + "_" + opTypeStr)->second; + for(int i = 0; i < length; i++) + { + auto &tmpLhsValue = (lhsValue.funcValue)[i]; + auto &tmpRhsValue = (rhsValue.funcValue)[i]; + x1[0] = tmpLhsValue.toDouble(); + x1[1] = (tmpLhsValue - x1[0]).toDouble(); + x2[0] = tmpRhsValue.toDouble(); + x2[1] = (tmpRhsValue - x2[0]).toDouble(); + tmpfuncValues[i] = tmpDoubleCall(x1, x2); + } + } + else if(mapType == "d_d") + { + if(opTypeStr == "dd") + { + auto tmpDoubleCall = doubleCall_d_d_map.find(opStr + "_" + opTypeStr)->second; + for(int i = 0; i < length; i++) + { + auto &tmpLhsValue = (lhsValue.funcValue)[i]; + auto &tmpRhsValue = (rhsValue.funcValue)[i]; + tmpfuncValues[i] = tmpDoubleCall(tmpLhsValue.toDouble(), tmpRhsValue.toDouble()); + } + } + else + { + for(int i = 0; i < length; i++) + { + auto &tmpLhsValue = (lhsValue.funcValue)[i]; + auto &tmpRhsValue = (rhsValue.funcValue)[i]; + tmpfuncValues[i] = tmpCall(tmpLhsValue.toDouble(), tmpRhsValue.toDouble()); + } + } + } + else + { + fprintf(stderr, "ERROR: %s : line %d: Invalid map type: %s\n", __func__, __LINE__, mapType.c_str()); + exit(EXIT_FAILURE); + } + result.funcValue = tmpfuncValues; + funcValues.push_back(tmpfuncValues); + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + + // real func + auto tmpRealCall = binPtr->getRealCallback(); + + // func real value & math real value & ulp unit value & error value + if constexpr (TisDouble) + { + // func Real Value + mpfr::mpreal funcRealValue = tmpRealCall(lhsValue.funcValue, rhsValue.funcValue); + // std::cout << "op = " << binPtr->getOp() << " funcRealValue = " << funcRealValue.toString() << std::endl; + funcRealValues.push_back(funcRealValue); + + // math real value + result.realValue = tmpRealCall(lhsValue.realValue, rhsValue.realValue); + // std::cout << "op = " << binPtr->getOp() << " mathRealValue = " << result.realValue.toString() << std::endl; + mathRealValues.push_back(result.realValue); + + // math real value's ulp unit Value + result.ulpValue = computeUlpUnit(result.realValue); + + // error value according funcReal & func & mathReal values + // absolute error + // double absErrorValue = fabs((funcRealValue - result.funcValue).toDouble()); + // errorValues.push_back(absErrorValue); + // relative error + // double relErrorValue = fabs(((funcRealValue - result.funcValue) / funcRealValue).toDouble()); + // errorValues.push_back(relErrorValue); + // ulp error + auto errorValue = computeError(funcRealValue, result.funcValue, result.ulpValue); + errorValues.push_back(errorValue); + } + else if constexpr (TisDoublePointer) + { + auto tmpfuncRealValues = new mpfr::mpreal[length]; + auto tmpmathRealValues = new mpfr::mpreal[length]; + auto tmpUlpValues = new double[length]; + auto tmpErrorValues = new double[length]; + for(int i = 0; i < length; i++) + { + // func real value + mpfr::mpreal tmpLhsValue = (lhsValue.funcValue)[i]; + mpfr::mpreal tmpRhsValue = (rhsValue.funcValue)[i]; + auto funcRealValue = tmpRealCall(tmpLhsValue, tmpRhsValue); + tmpfuncRealValues[i] = funcRealValue; + + // math real value + tmpLhsValue = (lhsValue.realValue)[i]; + tmpRhsValue = (rhsValue.realValue)[i]; + auto mathRealValue = tmpRealCall(tmpLhsValue, tmpRhsValue); + tmpmathRealValues[i] = mathRealValue; + + // math real value's ulp unit value + tmpUlpValues[i] = computeUlpUnit(mathRealValue); + + // error value + tmpErrorValues[i] = computeError(funcRealValue, (result.funcValue)[i], tmpUlpValues[i]); + } + funcRealValues.push_back(tmpfuncRealValues); + mathRealValues.push_back(tmpmathRealValues); + errorValues.push_back(tmpErrorValues); // error between funcRealValue and funcValue + result.realValue = tmpmathRealValues; + result.ulpValue = tmpUlpValues; + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + + // condition number value + if constexpr (TisDouble) + { + auto &ulpY = result.ulpValue; + std::function funcDrv; + + auto inputLhs = lhsValue.realValue.toDouble(); + auto inputRhs = rhsValue.realValue.toDouble(); + + funcDrv = fDrvMapTwo.find(opStr + "L")->second; + auto derivativeFuncValue = funcDrv(inputLhs, inputRhs); + auto &ulpXLhs = lhsValue.ulpValue; + auto conditionNumber = ulpXLhs * derivativeFuncValue / ulpY; + if(!finite(conditionNumber)) + { + conditionNumber = hugeNum; + } + conditionNumbers.push_back(conditionNumber); + + funcDrv = fDrvMapTwo.find(opStr + "R")->second; + derivativeFuncValue = funcDrv(inputLhs, inputRhs); + auto &ulpXRhs = rhsValue.ulpValue; + conditionNumber = ulpXRhs * derivativeFuncValue / ulpY; + if(!finite(conditionNumber)) + { + conditionNumber = hugeNum; + } + conditionNumbers.push_back(conditionNumber); + } + else if constexpr (TisDoublePointer) + { + auto &ulpYs = result.ulpValue; + + std::function funcDrvL, funcDrvR; + auto tmpConditionNumbers1 = new double[length]; + auto tmpConditionNumbers2 = new double[length]; + funcDrvL = fDrvMapTwo.find(opStr + "L")->second; + funcDrvR = fDrvMapTwo.find(opStr + "R")->second; + for(int i = 0; i < length; i++) + { + auto inputLhs = lhsValue.realValue[i].toDouble(); + auto inputRhs = rhsValue.realValue[i].toDouble(); + + auto derivativeFuncValue = funcDrvL(inputLhs, inputRhs); + auto &ulpX1 = lhsValue.ulpValue[i]; + tmpConditionNumbers1[i] = ulpX1 * derivativeFuncValue / ulpYs[i]; + + derivativeFuncValue = funcDrvR(inputLhs, inputRhs); + auto &ulpX2 = rhsValue.ulpValue[i]; + tmpConditionNumbers2[i] = ulpX2 * derivativeFuncValue / ulpYs[i]; + + if(!finite(tmpConditionNumbers1[i])) + { + tmpConditionNumbers1[i] = hugeNum; + } + if(!finite(tmpConditionNumbers2[i])) + { + tmpConditionNumbers2[i] = hugeNum; + } + } + conditionNumbers.push_back(tmpConditionNumbers1); + conditionNumbers.push_back(tmpConditionNumbers2); + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } + + return result; + } + else + { + fprintf(stderr, "ERROR: %s : line %d: unknown type %s\n", __func__, __LINE__, type.c_str()); + exit(EXIT_FAILURE); + } +} + +template +void shadowValueInit(vector &conditionNumbersOp, vector &benefit, vector &epsilonE, const size_t condNumOpSize, const int length) +{ + constexpr bool TisDouble = (std::is_same::value); + constexpr bool TisDoublePointer = (std::is_same::value); + if constexpr (TisDouble) + { + for(size_t i = 0; i < condNumOpSize; i++) + { + conditionNumbersOp.push_back(1); + benefit.push_back(0); + epsilonE.push_back(0); + } + } + else if constexpr (TisDoublePointer) + { + for(size_t i = 0; i < condNumOpSize; i++) + { + auto tmp = new double[length]; + conditionNumbersOp.push_back(tmp); + } + for(int i = 0; i < length; i++) + { + conditionNumbersOp.back()[i] = 1; + } + for(size_t i = 0; i < condNumOpSize; i++) + { + auto tmp = new double[length]; + benefit.push_back(tmp); + } + for(size_t i = 0; i < condNumOpSize; i++) + { + auto tmp = new double[length]; + epsilonE.push_back(tmp); + } + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } +} + +template +void shadowValuePrint(const vector> &funcValues, const vector> &funcRealValues, const vector> &mathRealValues, const vector &errorValues, const vector &conditionNumbers, const vector &conditionNumbersOp, [[maybe_unused]] const vector &epsilonE, const std::map &varsValue, const int length, const bool ifUnique, const string uniqueLabel, const string funcName) +{ + constexpr bool TisDouble = (std::is_same::value); + constexpr bool TisDoublePointer = (std::is_same::value); + if constexpr (TisDouble) + { + // fmt::print("funcValues := {}\n", funcValues); + for(auto &funcValue : funcValues) + { + std::cout << "func value: " << funcValue.toString() << std::endl; + } + for(auto &funRealValue : funcRealValues) + { + std::cout << "func real value: " << funRealValue.toString() << std::endl; + } + for(auto &mathRealValue : mathRealValues) + { + std::cout << "math real value: " << mathRealValue.toString() << std::endl; + } + fmt::print("errorValues := {}\n", errorValues); + fmt::print("conditionNumbers := {}\n", conditionNumbers); + fmt::print("conditionNumbersOp := {}\n", conditionNumbersOp); + fmt::print("epsilonE := {}\n", epsilonE); + } + else if constexpr (TisDoublePointer) + { + // TODO: free funcValues, funcRealValues, mathRealValues, errorValues + // print to the screen + for(int i = 0; i < length; i++) + { + for(size_t j = 0; j < funcValues.size(); j++) + { + fprintf(stderr, "input NO.%d step NO.%ld: funcValue = %s\n", i, j, (funcValues.at(j))[i].toString().c_str()); + fprintf(stderr, "input NO.%d step NO.%ld: funcRealValue = %s\n", i, j, (funcRealValues.at(j))[i].toString().c_str()); + fprintf(stderr, "input NO.%d step NO.%ld: mathRealValue = %s\n", i, j, (mathRealValues.at(j))[i].toString().c_str()); + fprintf(stderr, "input NO.%d step NO.%ld: errorValue = %g\n", i, j, (errorValues.at(j))[i]); + if (j != funcValues.size() - 1) + fprintf(stderr, "input NO.%d step NO.%ld: conditionNumbers = %g\n", i, j, (conditionNumbers.at(j))[i]); + fprintf(stderr, "input NO.%d step NO.%ld: conditionNumbersOp = %g\n\n", i, j, (conditionNumbersOp.at(j))[i]); + } + fprintf(stderr, "================================\n\n"); + } + // print to the file + double **inputsPtr = new double *[varsValue.size()]; + int ptrIdx = 0; + for(auto &value : varsValue){ + inputsPtr[ptrIdx] = value.second; + ptrIdx++; + } + for(size_t i = 0; i < funcValues.size(); i++) // i is represent the step of expression + { + std::ofstream fout; + + string filename = "./outputs/"; + if(ifUnique) + { + filename += uniqueLabel + "/errorFunc_" + funcName + "_" + std::to_string(i) + ".txt"; + } + else + { + filename += "errorFunc_" + std::to_string(i) + ".txt"; + } + fout.open(filename, ios::out); + if (!fout.is_open()) + { + fprintf(stderr, "ERROR: %s : line %d: open %s failed\n", __func__, __LINE__, filename.c_str()); + exit(EXIT_FAILURE); + } + for(int j = 0; j < length; j++) + { + for(size_t ptrIdx = 0; ptrIdx < varsValue.size(); ptrIdx++) // print all the input variables' value + { + fout << inputsPtr[ptrIdx][j] << " "; + } + fout << (errorValues.at(i))[j] << "\n"; + } + } + // std::ofstream fout; + // fout.open("./shadowValueResult.txt", ios::out); + // if (!fout.is_open()) + // { + // std::cout << "open shadowValueResult.txt failed"; + // exit(EXIT_FAILURE); + // } + // fout << "inputIdx stepIdx funcValue funcRealValue mathRealValue errorValue\n"; + // for(int i = 0; i < length; i++) + // { + // for(size_t j = 0; j < funcValues.size(); j++) + // { + // fout << i << " " << j << " " << (funcValues.at(j))[i] << " " << (funcRealValues.at(j))[i].toString() << " " << (mathRealValues.at(j))[i].toString() << " " << (errorValues.at(j))[i] << "\n"; + // } + // } + // fout << "input NO." << i << " step NO." << j << ": funcValue = " << (funcValues.at(j))[i] << "\n"; + // fout << "input NO." << i << " step NO." << j << ": funcRealValue = " << (funcRealValues.at(j))[i].toString() << "\n"; + // fout << "input NO." << i << " step NO." << j << ": mathRealValue = " << (mathRealValues.at(j))[i].toString() << "\n"; + // fout << "input NO." << i << " step NO." << j << ": errorValue = " << (errorValues.at(j))[i] << "\n"; + // fout << "================================\n\n"; + } + else + { + fprintf(stderr, "ERROR: %s : line %d: the type of T %s is not supported\n", __func__, __LINE__, typeid(T).name()); + exit(EXIT_FAILURE); + } +} + +template +vector shadowValue(const ast_ptr &expr, const std::map &varsValue, int length, bool ifUnique, string uniqueLabel, string funcName) +{ + mpfr::mpreal::set_default_prec(128); + vector> funcValues; + vector errorValues; // this error is f(x+\delta x) between F(x + \delta x) + vector conditionNumbers; + std::vector> funcRealValues; + std::vector> mathRealValues; + vector errorValueOrder; // for conditionNumbers vector, store the corresponding errorValue order + shadowValueKernel(expr, varsValue, funcValues, funcRealValues, mathRealValues, errorValues, conditionNumbers, errorValueOrder, length); // compute condition numbers of each operation in expr for varsValue. This condition number is only for the corresponding opeation. + errorValueOrder.push_back(conditionNumbers.size()); // 令condNumber最后一个元素指向conditionNumber的最后一个元素,同时保证其长度同errorValues、conditionNumberOp一致 + // fmt::print("errorValueOrder: {}\n", errorValueOrder); + vector condNumOrder; // for errorValue vector, store the corresponding conditionNumbers order + for(int i = 0; i < (int)errorValueOrder.size(); i++) + { + vector::iterator iter = std::find(errorValueOrder.begin(), errorValueOrder.end(), i); + if (iter == errorValueOrder.end()) + { + fprintf(stderr, "ERROR: %s : line %d: %d can not be found in errorValueOrder\n", __func__, __LINE__, i); + exit(EXIT_FAILURE); + } + else + { + auto tmp = std::distance(errorValueOrder.begin(), iter); + condNumOrder.push_back(tmp); + } + } + // fmt::print("condNumOrder: {}\n", condNumOrder); + vector conditionNumbersOp; + vector benefit, epsilonE; + shadowValueInit(conditionNumbersOp, benefit, epsilonE, conditionNumbers.size() + 1, length); + int IDfather = conditionNumbersOp.size() - 1; + int IDnow = conditionNumbers.size() - 1; + computeConditionNumber(expr, conditionNumbers, conditionNumbersOp, IDfather, IDnow, length); // compute the segma condition number for operations. + vector opSequence; + getOrders(expr, opSequence); + opSequence.pop_back(); + auto epsilonEStr = computeEpsilonE(benefit, epsilonE, errorValues, conditionNumbersOp, condNumOrder, opSequence, length); + // auto epsilonEStr = computeEpsilonENew(benefit, epsilonE, errorValues, conditionNumbersOp, condNumOrder, opSequence, length); + + // shadowValuePrint(funcValues, funcRealValues, mathRealValues, errorValues, conditionNumbers, conditionNumbersOp, epsilonE, varsValue, length, ifUnique, uniqueLabel, funcName); + return epsilonEStr; +} + +template vector shadowValue(const ast_ptr &expr, const std::map &varsValue, int length, bool ifUnique, std::string uniqueLabel, std::string funcName); +template vector shadowValue(const ast_ptr &expr, const std::map &varsValue, int length, bool ifUnique, std::string uniqueLabel, std::string funcName); + +} \ No newline at end of file diff --git a/srcTest/MPMF_1.sh b/srcTest/MPMF_1.sh new file mode 100755 index 0000000000000000000000000000000000000000..2c74099a7b786aba80acad080e46dbd0750d7dde --- /dev/null +++ b/srcTest/MPMF_1.sh @@ -0,0 +1,62 @@ +#!/bin/bash +# set -x +# 多精度版本函数的路径是TGen的路径,特定于北京服务器的固定路径。 +# NMSEproblem345的单参特供版,仅能修改其中的sin函数,用来测试使用不同函数的表达式的性能和精度 +#init for mix-precision +source funcMap.sh +func1=sin +path_TGen=/home/xyy/helloBro/TGen +path_func1=${path_TGen}/${func1}_gen +path_current=`pwd` +temp_file=${path_current}/temp.log # 临时文件,在循环中被刷新 +log_file=${path_current}/hjw.log # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 + +if [ -f "${log_file}" ]; then + rm "${log_file}" +fi + +# init for error detection and performance detection +uniqueLabel=NMSEproblem345 +x0Start=0.01 +x0End=100 +x0Size=500000 +x0startNowIdx=0 +x0startOriginInterval=0.01 +stepX0=0.00019998 +prefix=expr_${uniqueLabel} +middle=${x0Start}_${x0End}_${x0Size} +suffix=origin +errfile=0 + +# init for the expression code file +expr_file=${uniqueLabel}/${prefix}_${suffix}.c +expr_bkp_file=${uniqueLabel}/${prefix}_${suffix}_bkp.c +if [ -f "${expr_bkp_file}" ]; then + cp ${expr_bkp_file} ${expr_file} +else + echo "ERROR" + exit +fi +sed -i "1a\#include \"${func1}_gen.c\"" ${expr_file} +sed -i "s@${func1}(@${func1}_gen(@g" ${expr_file} + +# loop to generate different version + +# loop1,2 for func1 +# for ((bit1=0; bit1<=1; bit1++)) +for ((bit1=0; bit1<=${bit_range[$func1]}; bit1++)) +do + # for ((degree1=0; degree1<1; degree1++)) + for ((degree1=0; degree1<${degree_range[$func1]}; degree1++)) + do + cp ${path_func1}/${func1}_gen_${bit1}_1_${degree1}.c ${uniqueLabel}/${func1}_gen.c + echo "${func1}: bit = ${bit1} degree = ${degree1}" + echo -e "${func1}\t${bit1}\t${degree1}:" > ${temp_file} + cd .. + ./detectErrorOneFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x0Size} ${x0startNowIdx} ${x0startOriginInterval} ${stepX0} ${prefix} ${middle} ${suffix} ${errfile} | tee -a ${temp_file} + cd - >/dev/null + taskset -c 8 ./testPerformanceOneManual.sh ${uniqueLabel} ${suffix} ${x0Start} ${x0End} | tee -a ${temp_file} + awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $0 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + echo + done +done \ No newline at end of file diff --git a/srcTest/MPMF_2.sh b/srcTest/MPMF_2.sh new file mode 100755 index 0000000000000000000000000000000000000000..d006a707b0141984ea8a434453ed2ea2e1d5026b --- /dev/null +++ b/srcTest/MPMF_2.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# set -x +# 多精度版本函数的路径是TGen的路径,特定于北京服务器的固定路径。 +# NMSEproblem345的双参特供版,能修改其中的tan, sin函数的精度版本,用来测试使用不同函数的表达式的性能和精度 + +# init for multi-precision func +source funcMap.sh +source init.sh + +# init for current path +path_current=`pwd` +temp_file=${path_current}/temp.log # 临时文件,在循环中被刷新 +log_file=${path_current}/hjw.log # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 + +if [ -f "${log_file}" ]; then + rm "${log_file}" +fi + +# loop to generate different version + +# loop1,2 for func1 +# for ((bit1=0; bit1<=1; bit1++)) +for ((bit1=0; bit1<=${bit_range[$func1]}; bit1++)) +do + # for ((degree1=0; degree1<1; degree1++)) + for ((degree1=0; degree1<${degree_range[$func1]}; degree1++)) + do + cp ${path_func1}/${func1}_gen_${bit1}_1_${degree1}.c ${uniqueLabel}/${func1}_gen.c + + # loop3,4 for func2 + # for ((bit2=0; bit2<=1; bit2++)) + for ((bit2=0; bit2<=${bit_range[$func2]}; bit2++)) + do + # for ((degree2=0; degree2<1; degree2++)) + for ((degree2=0; degree2<${degree_range[$func2]}; degree2++)) + do + cp ${path_func2}/${func2}_gen_${bit2}_1_${degree2}.c ${uniqueLabel}/${func2}_gen.c + echo "${func1}: bit = ${bit1} degree = ${degree1}; ${func2}: bit2 = ${bit2} degree = ${degree2}" + echo -e "${func1}\t${bit1}\t${degree1}\t${func2}\t${bit2}\t${degree2}:" > ${temp_file} + cd .. + ./detectErrorOneFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x0Size} ${x0startNowIdx} ${x0startOriginInterval} ${stepX0} ${prefix} ${middle} ${suffix} ${errfile} | tee -a ${temp_file} + cd - >/dev/null + taskset -c 8 ./testPerformanceOneManual.sh ${uniqueLabel} ${suffix} ${x0Start} ${x0End} | tee -a ${temp_file} + awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $0 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + echo + done + done + done +done \ No newline at end of file diff --git a/srcTest/combine_2.py b/srcTest/combine_2.py new file mode 100644 index 0000000000000000000000000000000000000000..fcacc0484050d18c9e4aada90a7383407cfdd778 --- /dev/null +++ b/srcTest/combine_2.py @@ -0,0 +1,105 @@ +import pandas as pd +import sys +import itertools +import math + +condNumSin = 8.943225 +condNumTan = 1.07E+00 + +# 读取2个文件,对应表达式中的两个函数。每个文件有2列,对应函数的误差和性能。 +def geneData(file1, file2): + # 读取文件并将数据存储在 DataFrame 中 + func1 = pd.read_csv(file1, sep='\t') # sin + func2 = pd.read_csv(file2, sep='\t') # tan + + # regime + regime1 = func1["regime"] + regime2 = func2["regime"] + + # degree + degree1 = func1["degree"] + degree2 = func2["degree"] + + # 平均误差 + error1 = func1["averageErr"] + error2 = func2["averageErr"] + + # 将平均误差的字符串数据转换为浮点数 + error1 = [float(x) for x in error1] + error2 = [float(x) for x in error2] + + # 性能节拍 + perf1 = func1["performance"] + perf2 = func2["performance"] + + # 两两组合 + result = [] + for i in range(len(error1)): + for j in range(len(error2)): + # errorSum = error1[i] + error2[j] # !!! 这里是关键,关键在于要不要从error变成epsilon。 + errorSum = error1[i] * condNumSin + error2[j] * condNumTan # !!! 这里是关键,关键在于要不要从error变成epsilon。 + perfSum = perf1[i] + perf2[j] + pair = (regime1[i], degree1[i], regime2[j], degree2[j], errorSum, perfSum) + result.append(pair) + return result + +def pareto_optimal(points): + pareto_points = [] + is_pareto = [True] * len(points) + for i in range(len(points)): + # if is_pareto[i] == False: + # continue + + regime1, degree1, regime2, degree2, err, cost = points[i] + + for j in range(len(points)): + # if is_pareto[j] == False: + # continue + if j == i: + continue + err2 = points[j][4] + cost2 = points[j][5] + if (err2 < err) and (cost2 <= cost): + is_pareto[i] = False + break + + for i in range(len(points)): + if is_pareto[i]: + pareto_points.append(points[i]) + + return pareto_points + +def writeToFile(data, file_path): + # file_path = 'output.csv' + + with open(file_path, 'w') as file: + file.write(f"regime1\tdegree1\tregime2\tdegree2\tepsilon\tcost\n") + for item in data: + # file.write(f"{item[2]} {item[0]:.6e} {item[1]}\n") + file.write(f"{item[0]}\t{item[1]}\t{item[2]}\t{item[3]}\t{item[4]:.6e}\t{item[5]}\n") + print("output file is %s"%(str(file_path))) + +# 默认读取2个文件:func1.csv func2.csv,分别存储的是两个函数的误差-开销信息 +if __name__ == '__main__': + func1 = "sin" + func1OutputFile = func1 + "Output.csv" + func2 = "tan" + func2OutputFile = func2 + "Output.csv" + uniqueLabel = "NMSEproblem345" + outputFile = uniqueLabel + "Output.csv" + # 读取命令行参数 + arguments = sys.argv + # 检查是否传递了参数 + if len(arguments) > 4: + print("please input only 2 paremeters or none paremeter!") + sys.exit(1) + elif len(arguments) == 4: + uniqueLabel = arguments[1] + func1 = arguments[2] # arguments[2] 为 sin, 即优化函数 + func2 = arguments[3] # arguments[3] 为 cos, 即优化函数 + func1OutputFile = func1 + "Output.csv" + func2OutputFile = func2 + "Output.csv" + outputFile = uniqueLabel + "Output.csv" + + input_points = geneData(func1OutputFile, func2OutputFile) + writeToFile(input_points, outputFile) \ No newline at end of file diff --git a/srcTest/computeULP.c b/srcTest/computeULP.c index febfa08b68c02f55d6b77938959c9228a704e12a..5bb3c0467d59825b60f3521cac2381ae974492df 100644 --- a/srcTest/computeULP.c +++ b/srcTest/computeULP.c @@ -96,3 +96,30 @@ double computeUlpDiffF(mpfr_t correctValue, mpfr_t myValue) { mpfr_clears(mpfrDiff, mpfrReUlp, (mpfr_ptr) 0); return reUlp; } + +double computeAbs(mpfr_t correctValue, mpfr_t myValue, mpfr_t mpfrDiff) { + double result; + + mpfr_sub(mpfrDiff, correctValue, myValue, MPFR_RNDN); + result = mpfr_get_d(mpfrDiff, MPFR_RNDN); + result = fabs(result); + + return result; +} + +double computeRel(mpfr_t correctValue, mpfr_t myValue) +{ + double result; + mpfr_t mpfrDiff; + + mpfr_inits2(PRECISION, mpfrDiff, (mpfr_ptr)0); + + mpfr_sub(mpfrDiff, correctValue, myValue, MPFR_RNDN); + mpfr_div(mpfrDiff, mpfrDiff, correctValue, MPFR_RNDN); + result = mpfr_get_d(mpfrDiff, MPFR_RNDN); + result = fabs(result); + + // mpfr clear + mpfr_clears(mpfrDiff, (mpfr_ptr)0); + return result; +} \ No newline at end of file diff --git a/srcTest/convertCSV_TO_EXCEL.py b/srcTest/convertCSV_TO_EXCEL.py new file mode 100644 index 0000000000000000000000000000000000000000..f7b214e0c1902c9b38d1837bd2f266241d854638 --- /dev/null +++ b/srcTest/convertCSV_TO_EXCEL.py @@ -0,0 +1,47 @@ +import pandas as pd +import glob + +# 查找所有带有 "Sorted.csv" 后缀的文件 +csv_files = glob.glob('*Sorted.csv') + +# 创建一个 Excel Writer 对象,用于写入 Excel 文件 +excel_writer = pd.ExcelWriter('output.xlsx', engine='openpyxl') + +# 定义空白行数和起始列数 +num_blank_rows = 3 +start_rows = num_blank_rows +start_col = 3 + + +# 遍历 CSV 文件列表 +for csv_file in csv_files: + # 读取 CSV 文件 + df = pd.read_csv(csv_file, sep='\t') + + # 提取文件名作为工作表名称 + sheet_name = csv_file[:-24] # 去除文件扩展名和后缀 + + # 在左侧的一个单元格内写入文件名 + df.insert(0, sheet_name, '') + + # 将当前文件的数据写入 Excel 表格,追加到同一个工作表中,并添加空白行和起始列 + df.to_excel(excel_writer, sheet_name='Combined', startrow=start_rows, startcol=start_col, index=False, header=True) + + # 计算下一个文件的起始行数 + start_rows += df.shape[0] + 4 # 添加间隔行 + + +# 遍历 CSV 文件列表 +for csv_file in csv_files: + # 读取 CSV 文件 + df = pd.read_csv(csv_file, sep='\t') + + # 提取文件名作为工作表名称 + sheet_name = csv_file[:-24] # 去除文件扩展名和后缀 + + # 将当前文件的数据写入 Excel 表格,每个文件写入一个新的工作表 + df.to_excel(excel_writer, sheet_name=sheet_name, startrow=num_blank_rows, startcol=start_col, index=False, header=True) + + +# 关闭 Excel Writer 对象 +excel_writer.save() diff --git a/srcTest/exprMap.sh b/srcTest/exprMap.sh new file mode 100644 index 0000000000000000000000000000000000000000..ce0c294e540d83631fe716ddd5ecdcd2d9712fbb --- /dev/null +++ b/srcTest/exprMap.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +# 定义关联数组,模拟map +declare -A x0Starts=( + ["NMSEproblem345"]=0.01 + ["NMSEexample34"]=0.01 + ["logexp"]=-8 + ["exp1x_log"]=0.01 + ["NMSEproblem343"]=-0.5 # -1 + ["exp1x"]=0.01 + ["NMSEexample37"]=0.01 + ["NMSEexample39"]=0.01 + ["NMSEproblem341"]=0.01 + ["NMSEexample310"]=-0.5 # -1 + ["NMSEexample35"]=0.01 + ["NMSEexample38"]=0.01 + ["NMSEproblem336"]=0.01 + ["NMSEproblem337"]=0.01 + ["NMSEproblem344"]=0.01 + ["NMSEsection311"]=0.01 + ["theta"]=1 + ["ComplexSinCos"]=0 + ["NMSEexample33"]=0.01 + ["NMSEproblem332"]=0.01 + ["NMSEproblem335"]=0.01 + ["NMSEsection35"]=0 + ["polarToCarthesianX"]=1 + ["polarToCarthesianY"]=1 + ["i6"]=0.1 +) + +declare -A x0Ends=( + ["NMSEproblem345"]=100 + ["NMSEexample34"]=3 + ["logexp"]=8 + ["exp1x_log"]=0.5 + ["NMSEproblem343"]=0.5 # 1 + ["exp1x"]=0.5 + ["NMSEexample37"]=100 + ["NMSEexample39"]=1 + ["NMSEproblem341"]=100 + ["NMSEexample310"]=0.5 # 1 + ["NMSEexample35"]=100 + ["NMSEexample38"]=100 + ["NMSEproblem336"]=100 + ["NMSEproblem337"]=100 + ["NMSEproblem344"]=100 + ["NMSEsection311"]=100 + ["theta"]=100 + ["ComplexSinCos"]=1 + ["NMSEexample33"]=1 + ["NMSEproblem332"]=1 + ["NMSEproblem335"]=1 + ["NMSEsection35"]=1 + ["polarToCarthesianX"]=10 + ["polarToCarthesianY"]=10 + ["i6"]=10 +) + +declare -A stepX0s=( + ["NMSEproblem345"]=0.00019998 + ["NMSEexample34"]=5.98e-06 + ["logexp"]=3.2e-05 + ["exp1x_log"]=9.8e-07 + ["NMSEproblem343"]=2e-06 # 4e-06 + ["exp1x"]=9.8e-07 + ["NMSEexample37"]=0.00019998 + ["NMSEexample39"]=1.98e-06 + ["NMSEproblem341"]=0.00019998 + ["NMSEexample310"]=2e-06 # 4e-06 + ["NMSEexample35"]=0.00019998 + ["NMSEexample38"]=0.00019998 + ["NMSEproblem336"]=0.00019998 + ["NMSEproblem337"]=0.00019998 + ["NMSEproblem344"]=0.00019998 + ["NMSEsection311"]=0.00019998 + ["theta"]=0.0966796875 + ["ComplexSinCos"]=0.0009765625 + ["NMSEexample33"]=0.000966796875 + ["NMSEproblem332"]=0.000966796875 + ["NMSEproblem335"]=0.000966796875 + ["NMSEsection35"]=0.0009765625 + ["polarToCarthesianX"]=0.0087890625 + ["polarToCarthesianY"]=0.0087890625 + ["i6"]=0.00966796875 +) + +declare -A x1Starts=( + ["theta"]=1 + ["ComplexSinCos"]=0 + ["NMSEexample33"]=0 + ["NMSEproblem332"]=0 + ["NMSEproblem335"]=0 + ["NMSEsection35"]=0 + ["polarToCarthesianX"]=0 + ["polarToCarthesianY"]=0 + ["i6"]=-5 +) + +declare -A x1Ends=( + ["theta"]=100 + ["ComplexSinCos"]=1 + ["NMSEexample33"]=100 + ["NMSEproblem332"]=100 + ["NMSEproblem335"]=100 + ["NMSEsection35"]=1 + ["polarToCarthesianX"]=360 + ["polarToCarthesianY"]=360 + ["i6"]=5 +) + +declare -A stepX1s=( + ["theta"]=0.0966796875 + ["ComplexSinCos"]=0.0009765625 + ["NMSEexample33"]=0.0009765625 + ["NMSEproblem332"]=0.0009765625 + ["NMSEproblem335"]=0.0009765625 + ["NMSEsection35"]=0.0009765625 + ["polarToCarthesianX"]=0.3515625 + ["polarToCarthesianY"]=0.3515625 + ["i6"]=0.009765625 +) + +declare -A func1s=( + ["NMSEproblem345"]=sin + ["NMSEexample34"]=cos + ["logexp"]=exp + ["exp1x_log"]=exp + ["NMSEproblem343"]=log + ["exp1x"]=exp + ["NMSEexample37"]=exp + ["NMSEexample39"]=tan + ["NMSEproblem341"]=cos + ["NMSEexample310"]=log + ["NMSEexample35"]=atan + ["NMSEexample38"]=log + ["NMSEproblem336"]=log + ["NMSEproblem337"]=exp + ["NMSEproblem344"]=exp + ["NMSEsection311"]=exp + ["theta"]=atan + ["ComplexSinCos"]=exp + ["NMSEexample33"]=sin + ["NMSEproblem332"]=tan + ["NMSEproblem335"]=cos + ["NMSEsection35"]=exp + ["polarToCarthesianX"]=cos + ["polarToCarthesianY"]=sin + ["i6"]=sin +) + +declare -A func2s=( + ["NMSEproblem345"]=tan + ["NMSEexample34"]=sin + ["logexp"]=log + ["exp1x_log"]=log + ["ComplexSinCos"]=sin +) \ No newline at end of file diff --git a/srcTest/funcMap.sh b/srcTest/funcMap.sh new file mode 100755 index 0000000000000000000000000000000000000000..8e59d2571b1d73fc5c2b2f627369060e71c8ded5 --- /dev/null +++ b/srcTest/funcMap.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# 定义关联数组,模拟map +declare -A bit_range=( + ["sin"]=7 + ["cos"]=7 + ["tan"]=7 + ["exp"]=7 + ["exp2"]=7 + ["exp10"]=7 + ["log"]=7 + ["log2"]=7 + ["log10"]=7 + ["asinh"]=7 + ["acosh"]=7 + ["atanh"]=7 + ["asin"]=7 + ["acos"]=7 + ["atan"]=7 + ["sinh"]=7 + ["cosh"]=7 + ["tanh"]=7 +) +declare -A fnum_range=( + ["sin"]=1 + ["cos"]=1 + ["tan"]=1 + ["exp"]=1 + ["exp2"]=1 + ["exp10"]=1 + ["log"]=1 + ["log2"]=1 + ["log10"]=1 + ["asinh"]=1 + ["acosh"]=1 + ["atanh"]=1 + ["asin"]=1 + ["acos"]=1 + ["atan"]=1 + ["sinh"]=1 + ["cosh"]=1 + ["tanh"]=1 +) +declare -A degree_range=( + ["sin"]=7 + ["cos"]=7 + ["tan"]=7 + ["exp"]=8 + ["exp2"]=8 + ["exp10"]=8 + ["log"]=8 + ["log2"]=8 + ["log10"]=8 + ["asinh"]=8 + ["acosh"]=8 + ["atanh"]=8 + ["asin"]=8 + ["acos"]=8 + ["atan"]=8 + ["sinh"]=8 + ["cosh"]=8 + ["tanh"]=8 +) + +# 打印map中的值 +# echo "bit_range:" +# for key in "${!bit_range[@]}"; do +# echo "$key: ${bit_range[$key]}" +# done + +# echo "fnum_range:" +# for key in "${!fnum_range[@]}"; do +# echo "$key: ${fnum_range[$key]}" +# done + +# echo "degree_range:" +# for key in "${!degree_range[@]}"; do +# echo "$key: ${degree_range[$key]}" +# done \ No newline at end of file diff --git a/srcTest/getOriginErrCost.sh b/srcTest/getOriginErrCost.sh new file mode 100755 index 0000000000000000000000000000000000000000..bc4a6b854fcfb03ce45a9082a3f374e8a0f15099 --- /dev/null +++ b/srcTest/getOriginErrCost.sh @@ -0,0 +1,288 @@ +#!/bin/bash +# init for current path +path_current=`pwd` +temp_file=${path_current}/temp.log # 临时文件,在循环中被刷新 +suffix=errPerfParetoSorted +bit1=-1 +degree1=-1 +bit2=-1 +degree2=-1 + +echo +uniqueLabel=NMSEproblem345 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}\t${bit2}\t${degree2}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEproblem345 0.01 100 500000 0 0.01 0.00019998 expr_NMSEproblem345 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEproblem345 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEexample34 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}\t${bit2}\t${degree2}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEexample34 0.01 3 500000 0 0.01 5.98e-06 expr_NMSEexample34 0.01_3_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEexample34 origin 0.01 3 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=logexp +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}\t${bit2}\t${degree2}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh logexp -8 8 500000 0 -8 3.2e-05 expr_logexp -8_8_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh logexp origin -8 8 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=exp1x_log +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}\t${bit2}\t${degree2}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh exp1x_log 0.01 0.5 500000 0 0.01 9.8e-07 expr_exp1x_log 0.01_0.5_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh exp1x_log origin 0.01 0.5 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEproblem343 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +# ./detectErrorOneFPEDParallel.sh NMSEproblem343 -1 1 500000 0 -1 4e-06 expr_NMSEproblem343 -1_1_500000 origin 0 | tee -a ${temp_file} +./detectErrorOneFPEDParallel.sh NMSEproblem343 -0.5 0.5 500000 0 -0.5 2e-06 expr_NMSEproblem343 -0.5_0.5_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +# taskset -c 0 ./testPerformanceOneManual.sh NMSEproblem343 origin -1 1 +taskset -c 0 ./testPerformanceOneManual.sh NMSEproblem343 origin -0.5 0.5 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=exp1x +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh exp1x 0.01 0.5 500000 0 0.01 9.8e-07 expr_exp1x 0.01_0.5_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh exp1x origin 0.01 0.5 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEexample37 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEexample37 0.01 100 500000 0 0.01 0.00019998 expr_NMSEexample37 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEexample37 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEexample39 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEexample39 0.01 1 500000 0 0.01 1.98e-06 expr_NMSEexample39 0.01_1_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEexample39 origin 0.01 1 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEproblem341 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEproblem341 0.01 100 500000 0 0.01 0.00019998 expr_NMSEproblem341 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEproblem341 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEexample310 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +# ./detectErrorOneFPEDParallel.sh NMSEexample310 -1 1 500000 0 -1 4e-06 expr_NMSEexample310 -1_1_500000 origin 0 | tee -a ${temp_file} +./detectErrorOneFPEDParallel.sh NMSEexample310 -0.5 0.5 500000 0 -0.5 2e-06 expr_NMSEexample310 -0.5_0.5_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +# taskset -c 0 ./testPerformanceOneManual.sh NMSEexample310 -1 1 +taskset -c 0 ./testPerformanceOneManual.sh NMSEexample310 origin -0.5 0.5 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEexample35 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEexample35 0.01 100 500000 0 0.01 0.00019998 expr_NMSEexample35 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEexample35 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEexample38 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEexample38 0.01 100 500000 0 0.01 0.00019998 expr_NMSEexample38 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEexample38 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEproblem336 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEproblem336 0.01 100 500000 0 0.01 0.00019998 expr_NMSEproblem336 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEproblem336 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEproblem337 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEproblem337 0.01 100 500000 0 0.01 0.00019998 expr_NMSEproblem337 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEproblem337 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEproblem344 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEproblem344 0.01 100 500000 0 0.01 0.00019998 expr_NMSEproblem344 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEproblem344 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEsection311 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorOneFPEDParallel.sh NMSEsection311 0.01 100 500000 0 0.01 0.00019998 expr_NMSEsection311 0.01_100_500000 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceOneManual.sh NMSEsection311 origin 0.01 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=theta +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh theta 1 100 1 100 1024 1024 0 0 1 1 0.0966796875 0.0966796875 expr_theta 1_100_1_100_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh theta origin 1 100 1 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=ComplexSinCos +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}\t${bit2}\t${degree2}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh ComplexSinCos 0 1 0 1 1024 1024 0 0 0 0 0.0009765625 0.0009765625 expr_ComplexSinCos 0_1_0_1_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh ComplexSinCos origin 0 1 0 1 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEexample33 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh NMSEexample33 0.01 1 0 100 1024 1024 0 0 0.01 0 0.000966796875 0.09765625 expr_NMSEexample33 0.01_1_0_100_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh NMSEexample33 origin 0.01 1 0 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEproblem332 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh NMSEproblem332 0.01 1 0 100 1024 1024 0 0 0.01 0 0.000966796875 0.09765625 expr_NMSEproblem332 0.01_1_0_100_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh NMSEproblem332 origin 0.01 1 0 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEproblem335 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh NMSEproblem335 0.01 1 0 100 1024 1024 0 0 0.01 0 0.000966796875 0.09765625 expr_NMSEproblem335 0.01_1_0_100_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh NMSEproblem335 origin 0.01 1 0 100 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=NMSEsection35 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh NMSEsection35 0 1 0 1 1024 1024 0 0 0 0 0.0009765625 0.0009765625 expr_NMSEsection35 0_1_0_1_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh NMSEsection35 origin 0 1 0 1 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=polarToCarthesianX +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh polarToCarthesianX 1 10 0 360 1024 1024 0 0 1 0 0.0087890625 0.3515625 expr_polarToCarthesianX 1_10_0_360_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh polarToCarthesianX origin 1 10 0 360 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=polarToCarthesianY +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh polarToCarthesianY 1 10 0 360 1024 1024 0 0 1 0 0.0087890625 0.3515625 expr_polarToCarthesianY 1_10_0_360_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh polarToCarthesianY origin 1 10 0 360 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + +echo +uniqueLabel=i6 +echo ${uniqueLabel} +log_file=${path_current}/${uniqueLabel}_${suffix}.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 +echo -e "${bit1}\t${degree1}" > ${temp_file} +cd .. +./detectErrorTwoFPEDParallel.sh i6 0.1 10 -5 5 1024 1024 0 0 0.1 -5 0.00966796875 0.009765625 expr_i6 0.1_10_-5_5_1024_1024 origin 0 | tee -a ${temp_file} +cd - >/dev/null +taskset -c 0 ./testPerformanceTwoManual.sh i6 origin 0.1 10 -5 5 | tee -a ${temp_file} +awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} \ No newline at end of file diff --git a/srcTest/getRealErrCost.sh b/srcTest/getRealErrCost.sh new file mode 100755 index 0000000000000000000000000000000000000000..1381ed581411b9767464ddc149a86c4b81c39cdd --- /dev/null +++ b/srcTest/getRealErrCost.sh @@ -0,0 +1,151 @@ +#!/bin/bash +# set -x + +# !!!仅有两个函数 +# 多精度版本函数的路径是TGen的路径,特定于北京服务器的固定路径。 +# NMSEproblem345的双参特供版,能修改其中的tan, sin函数的精度版本,用来测试使用不同函数的表达式的性能和精度 +# getRealErrCost脚本的测试对象是帕累托优化得到的所有混合精度方案,用来验证帕累托优化效果 +# getRealErrCost脚本从output.csv中读取数据。该数据是利用pareto_2.py生成的。 +# pareto_2.py是根据函数的测试信息,生成帕累托优化结果。 +# pareto_2.py中的数据是从func1.csv、func2.csv中获取得来的,即直接复制自TGen的结果。 +# !!!func1.csv、func2.csv中的数据不能直接复制自TGen,还需要对其乘以“条件数”!!! + +# 与getRealErrCost脚本功能类似的是MPMF_2.sh。 +# MPMF_2.sh脚本是直接测试所有不同的混合精度组合下的表达式“误差-性能”信息。 + +# init for mix-precision +source funcMap.sh +source exprMap.sh + +# init for error detection and performance detection +inputNum="One" +if [ $# == 3 ]; then + uniqueLabel=${1} + x0Start=${x0Starts[${uniqueLabel}]} + x0End=${x0Ends[${uniqueLabel}]} + stepX0=${stepX0s[${uniqueLabel}]} + x1Start=${x1Starts[${uniqueLabel}]} + if [ -n "${x1Start}" ]; then + inputNum="Two" + x1End=${x1Ends[${uniqueLabel}]} + stepX1=${stepX1s[${uniqueLabel}]} + fi + func1=${2} + func2=${3} +elif [ $# == 1 ]; then + uniqueLabel=${1} + x0Start=${x0Starts[${uniqueLabel}]} + x0End=${x0Ends[${uniqueLabel}]} + stepX0=${stepX0s[${uniqueLabel}]} + x1Start=${x1Starts[${uniqueLabel}]} + if [ -n "${x1Start}" ]; then + inputNum="Two" + x1End=${x1Ends[${uniqueLabel}]} + stepX1=${stepX1s[${uniqueLabel}]} + fi + func1=sin + func2=tan +else + uniqueLabel="NMSEproblem345" + x0Start=0.01 + x0End=100 + stepX0=0.00019998 + + func1=sin + func2=tan +fi + +x0Size=500000 +x0startNowIdx=0 +x0startOriginInterval=${x0Start} + +if [ ${inputNum} == "Two" ]; then + x0Size=1024 + x1Size=1024 + x1startNowIdx=0 + x1startOriginInterval=${x1Start} + echo "x1Start is ${x1Start}, not empty" + echo "x1End is ${x1End}, not empty" + echo "stepX1 is ${stepX1}, not empty" + echo "x1startOriginInterval is ${x1startOriginInterval}, not empty" +fi + +prefix=expr_${uniqueLabel} +middle=${x0Start} +suffix=origin +errfile=0 + +# init for TGen +path_TGen=/home/xyy/helloBro/TGen +path_func1=${path_TGen}/${func1}_gen +path_func2=${path_TGen}/${func2}_gen + +# init for the expression code file +expr_file=${uniqueLabel}/${prefix}_${suffix}.c +expr_bkp_file=${uniqueLabel}/${prefix}_${suffix}_bkp.c +if [ -f "${expr_bkp_file}" ]; then + cp ${expr_bkp_file} ${expr_file} +else + echo "ERROR: no ${expr_bkp_file}" + exit +fi +sed -i "1a\#include \"${func1}_gen.c\"" ${expr_file} +sed -i "2a\#include \"${func2}_gen.c\"" ${expr_file} +sed -i "s@${func1}(@${func1}_gen(@g" ${expr_file} +sed -i "s@${func2}(@${func2}_gen(@g" ${expr_file} + +# 读取CSV文件,保存到数组 +csv_file="${uniqueLabel}Output.csv" +data_array=() + +# init for current path +path_current=`pwd` +temp_file=${path_current}/temp.log # 临时文件,在循环中被刷新 +log_file=${path_current}/${uniqueLabel}_errPerf.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 + +while IFS=$'\t' read -r -a cols +do + data=() + for ((i=0; i<${#cols[@]}; i++)) + do + if [ $i -lt 4 ]; then # 只保存前4列数据 + data+=("${cols[i]}") + fi + done + data_array+=("${data[@]}") +done < <(tail -n +2 "$csv_file") # 从第二行开始读取文件,跳过标题行 + +# loop to generate different version +echo -e "${func1}_regime1\tdegree1\t${func2}_regime2\tdegree2\terror\tperformance" > ${log_file} +step=4 +for ((i=0; i<${#data_array[@]}; i+=step)) +do + # echo "Batch $((i/step+1)): ${data_array[@]:i:step}" + bit1=${data_array[i]} + degree1=${data_array[i+1]} + bit2=${data_array[i+2]} + degree2=${data_array[i+3]} + + # echo "当前参数:$bit1 $degree1 $bit2 $degree2" + cp ${path_func1}/${func1}_gen_${bit1}_1_${degree1}.c ${uniqueLabel}/${func1}_gen.c + cp ${path_func2}/${func2}_gen_${bit2}_1_${degree2}.c ${uniqueLabel}/${func2}_gen.c + echo "${func1}: bit = ${bit1} degree = ${degree1}; ${func2}: bit2 = ${bit2} degree = ${degree2}" + echo -e "${bit1}\t${degree1}\t${bit2}\t${degree2}" > ${temp_file} + cd .. + if [ ${inputNum} = "One" ]; then + ./detectErrorOneFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x0Size} ${x0startNowIdx} ${x0startOriginInterval} ${stepX0} ${prefix} ${middle} ${suffix} ${errfile} | tee -a ${temp_file} + elif [ ${inputNum} = "Two" ]; then + ./detectErrorTwoFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x0Size} ${x1Size} ${x0startNowIdx} ${x1startNowIdx} ${x0startOriginInterval} ${x1startOriginInterval} ${stepX0} ${stepX1} ${prefix} ${middle} ${suffix} ${errfile} | tee -a ${temp_file} + fi + cd - >/dev/null + if [ ${inputNum} = "One" ]; then + taskset -c 0 ./testPerformanceOneManual.sh ${uniqueLabel} ${suffix} ${x0Start} ${x0End} | tee -a ${temp_file} + elif [ ${inputNum} = "Two" ]; then + taskset -c 0 ./testPerformanceTwoManual.sh ${uniqueLabel} ${suffix} ${x0Start} ${x0End} ${x1Start} ${x1End} | tee -a ${temp_file} + fi + awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + echo +done + +cp ${expr_bkp_file} ${expr_file} +echo "The data is logged into ${log_file}" \ No newline at end of file diff --git a/srcTest/getRealErrCost_1.sh b/srcTest/getRealErrCost_1.sh new file mode 100755 index 0000000000000000000000000000000000000000..ccc92b577b88601f98328a571a243aeac327fd7c --- /dev/null +++ b/srcTest/getRealErrCost_1.sh @@ -0,0 +1,142 @@ +#!/bin/bash +# set -x + +# !!!仅有一个函数 +# 多精度版本函数的路径是TGen的路径,特定于北京服务器的固定路径。 +# getRealErrCost_1 脚本的测试对象是帕累托优化得到的所有混合精度方案,用来验证帕累托优化效果 +# getRealErrCost_1 脚本从 funcOutput.csv 中读取数据。该数据是利用 pareto_singleFunc.py 生成的。 +# pareto_singleFunc.py 是根据函数的测试信息,生成帕累托优化结果。 +# pareto_singleFunc.py 中的数据是从 funcInput.csv 中获取得来的 + +# 与 getRealErrCost_1 脚本功能类似的是 MPMF_1.sh。 +# MPMF_1.sh 脚本是直接测试所有不同的混合精度组合下的表达式“误差-性能”信息。 + +# init for mix-precision +source funcMap.sh +source exprMap.sh + +# init for error detection and performance detection +inputNum="One" +if [ $# == 2 ]; then + uniqueLabel=${1} + x0Start=${x0Starts[${uniqueLabel}]} + x0End=${x0Ends[${uniqueLabel}]} + stepX0=${stepX0s[${uniqueLabel}]} + x1Start=${x1Starts[${uniqueLabel}]} + if [ -n "${x1Start}" ]; then + inputNum="Two" + x1End=${x1Ends[${uniqueLabel}]} + stepX1=${stepX1s[${uniqueLabel}]} + fi + func1=${2} +elif [ $# == 1 ]; then + uniqueLabel=${1} + x0Start=${x0Starts[${uniqueLabel}]} + x0End=${x0Ends[${uniqueLabel}]} + stepX0=${stepX0s[${uniqueLabel}]} + x1Start=${x1Starts[${uniqueLabel}]} + if [ -n "${x1Start}" ]; then + inputNum="Two" + x1End=${x1Ends[${uniqueLabel}]} + stepX1=${stepX1s[${uniqueLabel}]} + fi + func1=sin +else + uniqueLabel="NMSEproblem345" + x0Start=0.01 + x0End=100 + stepX0=0.00019998 + + func1=sin +fi + +x0Size=500000 +x0startNowIdx=0 +x0startOriginInterval=${x0Start} + +if [ ${inputNum} == "Two" ]; then + x0Size=1024 + x1Size=1024 + x1startNowIdx=0 + x1startOriginInterval=${x1Start} + echo "x1Start is ${x1Start}, not empty" + echo "x1End is ${x1End}, not empty" + echo "stepX1 is ${stepX1}, not empty" + echo "x1startOriginInterval is ${x1startOriginInterval}, not empty" +fi + +prefix=expr_${uniqueLabel} +middle=${x0Start} +suffix=origin +errfile=0 + +# init for TGen +path_TGen=/home/xyy/helloBro/TGen +path_func1=${path_TGen}/${func1}_gen + +# init for the expression code file +expr_file=${uniqueLabel}/${prefix}_${suffix}.c +expr_bkp_file=${uniqueLabel}/${prefix}_${suffix}_bkp.c +if [ -f "${expr_bkp_file}" ]; then + cp ${expr_bkp_file} ${expr_file} +else + echo "ERROR: fail to open ${expr_bkp_file}" + exit +fi +sed -i "1a\#include \"${func1}_gen.c\"" ${expr_file} +sed -i "s@${func1}(@${func1}_gen(@g" ${expr_file} + +# 读取CSV文件,保存到数组 +csv_file="${uniqueLabel}Output.csv" +data_array=() + +# init for current path +path_current=`pwd` +temp_file=${path_current}/temp.log # 临时文件,在循环中被刷新 +log_file=${path_current}/${uniqueLabel}_errPerf.csv # 其中依次记录的是: 函数名, bit, degree, 平均误差, 最大误差, 性能节拍 + +# 解析 csv 文件,保存到数组 data_array +while IFS=$'\t' read -r -a cols +do + data=() + for ((i=0; i<${#cols[@]}; i++)) + do + if [ $i -lt 4 ]; then # 只保存前4列数据 + data+=("${cols[i]}") + fi + done + data_array+=("${data[@]}") +done < <(tail -n +2 "$csv_file") # 从第二行开始读取文件,跳过标题行 + +# loop to generate different version +echo -e "${func1}_regime\tdegree\taverageErr\tperformance" > ${log_file} +step=4 +for ((i=0; i<${#data_array[@]}; i+=step)) +do + # echo "Batch $((i/step+1)): ${data_array[@]:i:step}" + bit1=${data_array[i]} + degree1=${data_array[i+1]} + + # echo "当前参数:$bit1 $degree1 $bit2 $degree2" + cp ${path_func1}/${func1}_gen_${bit1}_1_${degree1}.c ${uniqueLabel}/${func1}_gen.c + echo "${func1}: bit = ${bit1} degree = ${degree1}" + echo -e "${bit1}\t${degree1}" > ${temp_file} + cd .. + if [ ${inputNum} = "One" ]; then + ./detectErrorOneFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x0Size} ${x0startNowIdx} ${x0startOriginInterval} ${stepX0} ${prefix} ${middle} ${suffix} ${errfile} | tee -a ${temp_file} + elif [ ${inputNum} = "Two" ]; then + ./detectErrorTwoFPEDParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x0Size} ${x1Size} ${x0startNowIdx} ${x1startNowIdx} ${x0startOriginInterval} ${x1startOriginInterval} ${stepX0} ${stepX1} ${prefix} ${middle} ${suffix} ${errfile} | tee -a ${temp_file} + fi + cd - >/dev/null + if [ ${inputNum} = "One" ]; then + taskset -c 0 ./testPerformanceOneManual.sh ${uniqueLabel} ${suffix} ${x0Start} ${x0End} | tee -a ${temp_file} + elif [ ${inputNum} = "Two" ]; then + taskset -c 0 ./testPerformanceTwoManual.sh ${uniqueLabel} ${suffix} ${x0Start} ${x0End} ${x1Start} ${x1End} | tee -a ${temp_file} + fi + awk 'NR == 1 { printf "%s\t", $0 }; NR == 3 { printf "%s\t", $1 }; NR == 5 { print $0 }' ${temp_file} >> ${log_file} + echo +done + +cp ${expr_bkp_file} ${expr_file} +echo "Input file: ${csv_file}" +echo "Output file: ${uniqueLabel}_errPerf.csv" \ No newline at end of file diff --git a/srcTest/init.sh b/srcTest/init.sh new file mode 100644 index 0000000000000000000000000000000000000000..070a3de7397ea01013ea7253f4bcdbbbb2683ffc --- /dev/null +++ b/srcTest/init.sh @@ -0,0 +1,32 @@ +func1=sin +func2=tan +path_TGen=/home/xyy/helloBro/TGen +path_func1=${path_TGen}/${func1}_gen +path_func2=${path_TGen}/${func2}_gen + +# init for error detection and performance detection +uniqueLabel=NMSEproblem345 +x0Start=0.01 +x0End=100 +x0Size=500000 +x0startNowIdx=0 +x0startOriginInterval=0.01 +stepX0=0.00019998 +prefix=expr_${uniqueLabel} +middle=${x0Start} +suffix=origin +errfile=0 + +# init for the expression code file +expr_file=${uniqueLabel}/${prefix}_${suffix}.c +expr_bkp_file=${uniqueLabel}/${prefix}_${suffix}_bkp.c +if [ -f "${expr_bkp_file}" ]; then + cp ${expr_bkp_file} ${expr_file} +else + echo "ERROR" + exit +fi +sed -i "1a\#include \"${func1}_gen.c\"" ${expr_file} +sed -i "2a\#include \"${func2}_gen.c\"" ${expr_file} +sed -i "s@${func1}(@${func1}_gen(@g" ${expr_file} +sed -i "s@${func2}(@${func2}_gen(@g" ${expr_file} \ No newline at end of file diff --git a/srcTest/pareto_2Files.py b/srcTest/pareto_2Files.py new file mode 100644 index 0000000000000000000000000000000000000000..1c822948b6aa3f5ca8747a0cdfbc00d0048c0f8a --- /dev/null +++ b/srcTest/pareto_2Files.py @@ -0,0 +1,87 @@ +import pandas as pd +import itertools +import math + +condNumSin = 8.943225 +condNumTan = 1.07E+00 + +# 读取2个文件,对应表达式中的两个函数。每个文件有2列,对应函数的误差和性能。 +def geneData(file1, file2): + # 读取文件并将数据存储在 DataFrame 中 + func1 = pd.read_csv(file1, sep='\t') # sin + func2 = pd.read_csv(file2, sep='\t') # tan + + # regime + regime1 = func1["regime"] + regime2 = func2["regime"] + + # degree + degree1 = func1["degree"] + degree2 = func2["degree"] + + # 平均误差 + error1 = func1["averageErr"] + error2 = func2["averageErr"] + + # 将平均误差的字符串数据转换为浮点数 + error1 = [float(x) for x in error1] + error2 = [float(x) for x in error2] + + # 性能节拍 + perf1 = func1["performance"] + perf2 = func2["performance"] + + # 两两组合 + result = [] + for i in range(len(error1)): + for j in range(len(error2)): + # errorSum = error1[i] + error2[j] # !!! 这里是关键,关键在于要不要从error变成epsilon。 + errorSum = error1[i] * condNumSin + error2[j] * condNumTan # !!! 这里是关键,关键在于要不要从error变成epsilon。 + perfSum = perf1[i] + perf2[j] + pair = (regime1[i], degree1[i], degree1[j], degree2[j], errorSum, perfSum) + result.append(pair) + return result + +def pareto_optimal(points): + pareto_points = [] + is_pareto = [True] * len(points) + for i in range(len(points)): + # if is_pareto[i] == False: + # continue + + regime1, degree1, regime2, degree2, err, cost = points[i] + + for j in range(len(points)): + # if is_pareto[j] == False: + # continue + if j == i: + continue + err2 = points[j][4] + cost2 = points[j][5] + if (err2 < err) and (cost2 <= cost): + is_pareto[i] = False + break + + for i in range(len(points)): + if is_pareto[i]: + pareto_points.append(points[i]) + + return pareto_points + +def writeToFile(data, file_path): + # file_path = 'output.csv' + + with open(file_path, 'w') as file: + file.write(f"regime1\tdegree1\tregime2\tdegree2\tepsilon\tcost\n") + for item in data: + # file.write(f"{item[2]} {item[0]:.6e} {item[1]}\n") + file.write(f"{item[0]}\t{item[1]}\t{item[2]}\t{item[3]}\t{item[4]:.6e}\t{item[5]}\n") + print("output file is %s"%(str(file_path))) + +# 默认读取2个文件:func1.csv func2.csv,分别存储的是两个函数的误差-开销信息 +if __name__ == '__main__': + input_points = geneData("sinInput.csv", "tanInput.csv") + + pareto_result = pareto_optimal(input_points) + print(f"\nLength of 'pareto_optimal points': {len(pareto_result)}") + writeToFile(pareto_result, "NMSEproblem345ParetoOutput.csv") \ No newline at end of file diff --git a/srcTest/pareto_all.sh b/srcTest/pareto_all.sh new file mode 100755 index 0000000000000000000000000000000000000000..bd8edcdde9ca3a46e574a66182760265146f06a9 --- /dev/null +++ b/srcTest/pareto_all.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# !!! 缺少对函数input.csv 的预处理,即去除低精度代码 +# set -x +source exprMap.sh + +# init for error detection and performance detection +if [ $# == 5 ]; then + uniqueLabel=${1} + x0Start=${2} + x0End=${3} + x0Start_2=${4} + x0End_2=${5} + func1=${func1s[${uniqueLabel}]} + func2=${func2s[${uniqueLabel}]} + f1=${func1}_gen_${x0Start}-${x0End} + f2=${func2}_gen_${x0Start_2}-${x0End_2} +elif [ $# == 3 ]; then + uniqueLabel=${1} + x0Start=${2} + x0End=${3} + func1=${func1s[${uniqueLabel}]} + func2=${func2s[${uniqueLabel}]} + f1=${func1}_gen_${x0Start}-${x0End} + f2=${func2}_gen_${x0Start}-${x0End} +elif [ $# == 1 ]; then + uniqueLabel=${1} + x0Start=${x0Starts[${uniqueLabel}]} + x0End=${x0Ends[${uniqueLabel}]} + func1=${func1s[${uniqueLabel}]} + func2=${func2s[${uniqueLabel}]} + f1=${func1}_gen_${x0Start}-${x0End} + f2=${func2}_gen_${x0Start}-${x0End} +else + uniqueLabel=NMSEexample34 + x0Start=0.01 + x0End=3 + func1=sin + func2=cos + f1=${func1}_gen_${x0Start}-${x0End} + f2=${func2}_gen_${x0Start}-${x0End} +fi + +# NMSEexample34 +python3 pareto_singleFunc.py ${f1} +python3 pareto_singleFunc.py ${f2} +python3 combine_2.py ${uniqueLabel} ${f1} ${f2} +./getRealErrCost.sh ${uniqueLabel} ${func1} ${func2} +python3 pareto_twoFunc.py ${uniqueLabel} ${func1} ${func2} +python3 sortData.py ${uniqueLabel} ${func1} ${func2} \ No newline at end of file diff --git a/srcTest/pareto_all_1.sh b/srcTest/pareto_all_1.sh new file mode 100755 index 0000000000000000000000000000000000000000..ad4d5ae636054052700dd686a6065349db4df0d7 --- /dev/null +++ b/srcTest/pareto_all_1.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# set -x +# !!! 缺少对函数input.csv 的预处理,即去除低精度代码 +source exprMap.sh + +# init for error detection and performance detection +if [ $# == 3 ]; then + uniqueLabel=${1} + x0Start=${2} + x0End=${3} + func1=${func1s[${uniqueLabel}]} +elif [ $# == 1 ]; then + uniqueLabel=${1} + x0Start=${x0Starts[${uniqueLabel}]} + x0End=${x0Ends[${uniqueLabel}]} + func1=${func1s[${uniqueLabel}]} +else + uniqueLabel="exp1x" + x0Start=0.01 + x0End=0.5 + func1=exp +fi +f1=${func1}_gen_${x0Start}-${x0End} + +python3 pareto_singleFunc.py ${f1} +cp ${f1}Output.csv ${uniqueLabel}Output.csv +./getRealErrCost_1.sh ${uniqueLabel} ${func1} +python3 pareto_singleFunc.py ${uniqueLabel} ${func1} +python3 sortData.py ${uniqueLabel} ${func1} \ No newline at end of file diff --git a/srcTest/pareto_all_list.sh b/srcTest/pareto_all_list.sh new file mode 100755 index 0000000000000000000000000000000000000000..75579f19f3f2d4755720400da37ad7a3b93433d9 --- /dev/null +++ b/srcTest/pareto_all_list.sh @@ -0,0 +1,318 @@ +#!/bin/bash +# NMSEproblem345 := (/ (- x (sin x)) (- x (tan x))) +# sin: [0.01, 100] +# tan: [0.01, 100] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all.sh NMSEproblem345 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem345 time is ${duration} s." +echo "NMSEproblem345 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py sin 0.01 100 +# taskset -c 0 python3 per_allversion.py tan 0.01 100 + +# NMSEexample34: (/ (- 1 (cos x)) (sin x)) +# sin: [0.01, 3] +# cos: [0.01, 3] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all.sh NMSEexample34 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEexample34 time is ${duration} s." +echo "NMSEexample34 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py sin 0.01 3 +# taskset -c 0 python3 per_allversion.py cos 0.01 3 + +# logexp := log (+ 1 (exp x)) +# exp: [-8, 8] +# log: [1 + exp(-8), 1 + exp(8)] = [1.000335, 2,981.957987] \approx [1, 2982] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all.sh logexp -8 8 1 2982 +end_time=$(date +%s.%n) +duration=$(echo "$end_time - $start_time" | bc) +echo "logexp time is ${duration} s." +echo "logexp time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp -8 8 +# taskset -c 0 python3 per_allversion.py log 1 2982 + +# exp1x_log := ((exp(x) - 1.0) / log(exp(x))) +# exp: [0.01, 0.5] +# log: [e^0.01, e^0.5] \approx [1, 1.65] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all.sh exp1x_log 0.01 0.5 1 1.65 +end_time=$(date +%s.%n) +duration=$(echo "$end_time - $start_time" | bc) +echo "exp1x_log time is ${duration} s." +echo "exp1x_log time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp 0.01 0.5 +# taskset -c 0 python3 per_allversion.py log 1 1.65 + +# !!!!!! +# NMSEproblem343 := (log (/ (- 1 eps) (+ 1 eps))) +# eps: [-1, 1] +# log: (0, +infty) +# taskset -c 0 ./pareto_all_1.sh NMSEproblem343 0.5 1 +# eps: [-1/2, 1/2] +# log: (1/3, 3) +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEproblem343 0.3 3 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem343 time is ${duration} s." +echo "NMSEproblem343 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py log 0.3 3 + +# exp1x := (exp(x) - 1) / x +# exp: [0.01, 0.5] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh exp1x +end_time=$(date +%s.%n) +duration=$(echo "$end_time - $start_time" | bc) +echo "exp1x time is ${duration} s." +echo "exp1x time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp 0.01 0.5 + +# NMSEexample37 := exp(x) - 1 +# exp: [0.01, 100] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEexample37 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEexample37 time is ${duration} s." +echo "NMSEexample37 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp 0.01 100 + +# NMSEexample39 := (- (/ 1 x) (/ 1 (tan x))) +# tan: [0.01, 1] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEexample39 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEexample39 time is ${duration} s." +echo "NMSEexample39 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py tan 0.01 1 + +# NMSEproblem341 := (/ (- 1 (cos x)) (* x x)) +# cos: [0.01, 100] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEproblem341 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem341 time is ${duration} s." +echo "NMSEproblem341 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py cos 0.01 100 + +# NMSEexample310 := (log((1.0 - x)) / log((1.0 + x))) +# x: -1, 1 +# log: (0, 2) +# taskset -c 0 ./pareto_all_1.sh NMSEexample310 0 2 +# x: -1/2, 1/2 +# log: [1/2, 3/2] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEexample310 0.5 1.5 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEexample310 time is ${duration} s." +echo "NMSEexample310 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py log 0.5 1.5 + +# NMSEexample35 := (atan((x + 1.0)) - atan(x)) +# x: [0.01, 100] +# atan: [0.01, 101] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEexample35 0.01 101 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEexample35 time is ${duration} s." +echo "NMSEexample35 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py atan 0.01 101 + +# NMSEexample38 := ((((x + 1.0) * log((x + 1.0))) - (x * log(x))) - 1.0) +# x: [0.01, 100] +# log: [0.01, 101] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEexample38 0.01 101 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEexample38 time is ${duration} s." +echo "NMSEexample38 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py log 0.01 101 + +# NMSEproblem336 := (log((x + 1.0)) - log(x)) +# x: [0.01, 100] +# log: [0.01, 101] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEproblem336 0.01 101 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem336 time is ${duration} s." +echo "NMSEproblem336 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py log 0.01 101 + +# NMSEproblem337 := ((exp(x) + (-1.0 * 2.0)) + exp((-1.0 * x))) +# x: [0.01, 100] +# exp: [-100, -0.01] & [0.01, 100] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEproblem337 -100 100 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem337 time is ${duration} s." +echo "NMSEproblem337 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp -100 100 + +# NMSEproblem344 := (exp(x) / (exp(x) - 1.0)) +# x: [0.01, 100] +# exp: [0.01, 100] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEproblem344 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem344 time is ${duration} s." +echo "NMSEproblem344 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp 0.01 100 + +# NMSEsection311 := sqrt(((exp((2.0 * x)) - 1.0) / (exp(x) - 1.0))) +# x: [0.01, 100] +# exp: [0.01, 200] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEsection311 0.01 200 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEsection311 time is ${duration} s." +echo "NMSEsection311 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp 0 200 + +# theta := (atan((x2 / x1)) * 57.29577951307855) +# x: [1, 100] +# y: [1, 100] +# atan: [0.01, 100] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh theta 0.01 100 +end_time=$(date +%s.%n) +duration=$(echo "$end_time - $start_time" | bc) +echo "theta time is ${duration} s." +echo "theta time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py atan 0.01 100 + +# ComplexSinCos := (((1.0 / 2.0) * sin(r)) * (exp((-1.0 * i)) - exp(i))) +# x: [0, 1] +# y: [0, 1] +# sin: [0, 1] +# exp: [-1, 1] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all.sh ComplexSinCos -1 1 0 1 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "ComplexSinCos time is ${duration} s." +echo "ComplexSinCos time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp -1 1 +# taskset -c 0 python3 per_allversion.py sin 0 1 + +# NMSEexample33 := (sin((x + eps)) - sin(x)) +# eps: [0.01, 1] +# x: [0, 100] +# sin: [0, 101] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEexample33 0 101 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEexample33 time is ${duration} s." +echo "NMSEexample33 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py sin 0 101 + +# NMSEproblem332 := (tan((x + eps)) - tan(x)) +# eps: [0.01, 1] +# x: [0, 100] +# tan: [0, 101] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEproblem332 0 101 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem332 time is ${duration} s." +echo "NMSEproblem332 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py tan 0 101 + +# NMSEproblem335 := (cos((x + eps)) - cos(x)) +# eps: [0.01, 1] +# x: [0, 100] +# cos: [0, 101] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEproblem335 0 101 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEproblem335 time is ${duration} s." +echo "NMSEproblem335 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py cos 0 101 + +# NMSEsection35 := (exp((a * x)) - 1.0) +# a: [0, 1] +# x: [0, 1] +# exp: [0, 1] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh NMSEsection35 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "NMSEsection35 time is ${duration} s." +echo "NMSEsection35 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py exp 0 1 + +# polarToCarthesianX := (radius * cos((0.017453292519944444 * theta))) +# radius: [1, 10] +# theta: [0, 360] +# cos: [0, 2pi] \approx [0, 6.2832] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh polarToCarthesianX 0 6.2832 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "polarToCarthesianX time is ${duration} s." +echo "polarToCarthesianX time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py cos 0 6.2832 + +# polarToCarthesianY := (radius * sin((0.017453292519944444 * theta))) +# radius: [1, 10] +# theta: [0, 360] +# sin: [0, 2pi] \approx [0, 6.2832] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh polarToCarthesianY 0 6.2832 +end_time=$(date +%s.%N) +duration=$(echo "$end_time - $start_time" | bc) +echo "polarToCarthesianY time is ${duration} s." +echo "polarToCarthesianY time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py sin 0 6.2832 + +# i6 := sin((x * y)) +# x: [0.1, 10] +# y: [-5, 5] +# sin: [-50, 50] +start_time=$(date +%s.%n) +taskset -c 0 ./pareto_all_1.sh i6 -50 50 +end_time=$(date +%s.%n) +duration=$(echo "$end_time - $start_time" | bc) +echo "i6 time is ${duration} s." +echo "i6 time is ${duration} s." >> hjwTime.log +## TGen +# taskset -c 0 python3 per_allversion.py sin -50 50 \ No newline at end of file diff --git a/srcTest/pareto_singleFunc.py b/srcTest/pareto_singleFunc.py new file mode 100644 index 0000000000000000000000000000000000000000..3d15a5a5c38c8ce38f80cc78f1a0f0cc8c04c789 --- /dev/null +++ b/srcTest/pareto_singleFunc.py @@ -0,0 +1,103 @@ +import pandas as pd +import sys + +condNumSin = 8.943225 +condNumTan = 1.07E+00 + +# 读取1个文件,对应表达式中的函数。每个文件有若干列,但只需要 regime 和 degree 这2列,对应函数的误差和性能。 +def geneData(file1, regimeStr): + # 读取文件并将数据存储在 DataFrame 中 + csvReader = pd.read_csv(file1, sep='\t') # sin + + # regime + regime1 = csvReader[regimeStr] + + # degree + degree1 = csvReader["degree"] + + # 平均误差 + error1 = csvReader["averageErr"] + + # 将平均误差的字符串数据转换为浮点数 + error1 = [float(x) for x in error1] + + # 性能节拍 + perf1 = csvReader["performance"] + + # 两两组合 + result = [] + for i in range(len(error1)): + # errorSum = error1[i] + error2[j] # !!! 这里是关键,关键在于要不要从error变成epsilon。 + errorSum = error1[i] + perfSum = perf1[i] + pair = (regime1[i], degree1[i], errorSum, perfSum) + result.append(pair) + return result + +def pareto_optimal(points): + pareto_points = [] + is_pareto = [True] * len(points) + for i in range(len(points)): + # if is_pareto[i] == False: + # continue + + err1 = points[i][2] + cost1 = points[i][3] + + for j in range(len(points)): + # if is_pareto[j] == False: + # continue + if j == i: + continue + err2 = points[j][2] + cost2 = points[j][3] + if (err2 < err1) and (cost2 <= cost1): + is_pareto[i] = False + break + + for i in range(len(points)): + if is_pareto[i]: + pareto_points.append(points[i]) + + return pareto_points + +def writeToFile(data, file_path): + # file_path = 'output.csv' + + with open(file_path, 'w') as file: + file.write(f"regime\tdegree\taverageErr\tperformance\n") + for item in data: + file.write(f"{item[0]}\t{item[1]}\t{item[2]:.6e}\t{item[3]}\n") + +# 默认读取1个文件:func1.csv,存储的是函数的误差-开销信息 +if __name__ == '__main__': + # 读取命令行参数 + arguments = sys.argv + + func = "tan" + funcInputFile = func + "Input.csv" + funcOutputFile = func + "Output.csv" + regimeStr="regime" + # 检查是否传递了参数 + if len(arguments) > 3: + print("please input only one paremeter!") + sys.exit(1) + elif len(arguments) == 3: # 表达式中只有一个函数。用于实测性能误差后的对表达式的帕累托优化 + funcInputFile = arguments[1] + "_errPerf.csv" # arguments[1] 为 exp1x, 即优化表达式 + funcOutputFile = arguments[1] + "_errPerfPareto.csv" + func = arguments[2] # arguments[1] 为 exp, 即优化函数 + regimeStr = func + "_regime" + elif len(arguments) == 2: # 用于一开始针对单个函数的帕累托优化 + func = arguments[1] # arguments[1] 为 exp, 即优化函数 + funcInputFile = func + "Input.csv" + funcOutputFile = func + "Output.csv" + + input_points = geneData(funcInputFile, regimeStr) + + pareto_result = pareto_optimal(input_points) + + # 输出符合帕累托最优化的点集 + print(f"\nLength of 'pareto_optimal points': {len(pareto_result)}") + writeToFile(pareto_result, funcOutputFile) + print("Input file is %s"%(str(funcInputFile))) + print("Output file is %s"%(str(funcOutputFile))) \ No newline at end of file diff --git a/srcTest/pareto_twoFunc.py b/srcTest/pareto_twoFunc.py new file mode 100644 index 0000000000000000000000000000000000000000..7ba06dbc4a354e7ebb9bfd04b22a2c38dff7f940 --- /dev/null +++ b/srcTest/pareto_twoFunc.py @@ -0,0 +1,66 @@ +import pandas as pd +import sys + +def geneData(file1): + data = pd.read_csv(file1, sep='\t') + return data.values.tolist() + +def pareto_optimal(points): + pareto_points = [] + is_pareto = [True] * len(points) + for i in range(len(points)): + # if is_pareto[i] == False: + # continue + + err1 = points[i][4] + cost1 = points[i][5] + + for j in range(len(points)): + # if is_pareto[j] == False: + # continue + if j == i: + continue + err2 = points[j][4] + cost2 = points[j][5] + if (err2 <= err1) and (cost2 <= cost1): + is_pareto[i] = False + break + + for i in range(len(points)): + if is_pareto[i]: + pareto_points.append(points[i]) + + return pareto_points + +def writeToFile(data, file_path, func1, func2): + with open(file_path, 'w') as file: + file.write(f"{func1}_regime1\tdegree1\t{func2}_regime2\tdegree2\terror\tperformance\n") + for item in data: + file.write(f"{int(item[0])}\t{int(item[1])}\t{int(item[2])}\t{int(item[3])}\t{item[4]:.7e}\t{int(item[5])}\n") + print("output file is %s"%(str(file_path))) + +# 默认读取1个文件:func1.csv,存储的是函数的误差-开销信息 +if __name__ == '__main__': + uniqueLabel = "NMSEproblem345" + func1 = "sin" + func2 = "tan" + # 读取命令行参数, 并检查是否传递了参数 + arguments = sys.argv + if len(arguments) > 4: + print("please input only 2 or 3 paremeters or none paremeter!") + sys.exit(1) + elif len(arguments) == 4: # 表达式中只有一个函数。用于实测性能误差后的对表达式的帕累托优化 + uniqueLabel = arguments[1] # arguments[2] 为 NMSEexample34, 即优化表达式 + + func1 = arguments[2] # arguments[1] 为 sin, 即优化函数 + func2 = arguments[3] # arguments[2] 为 cos, 即优化函数 + + inputFile = uniqueLabel + "_errPerf.csv" + outputFile = uniqueLabel + "_errPerfPareto.csv" + + input_points = geneData(inputFile) + pareto_result = pareto_optimal(input_points) + + # 输出符合帕累托最优化的点集 + print(f"\nLength of 'pareto_optimal points': {len(pareto_result)}") + writeToFile(pareto_result, outputFile, func1, func2) \ No newline at end of file diff --git a/srcTest/prepare.sh b/srcTest/prepare.sh new file mode 100755 index 0000000000000000000000000000000000000000..48d0ccd3ea6e8b435c15676c5a81aa8901d2d0e1 --- /dev/null +++ b/srcTest/prepare.sh @@ -0,0 +1,5 @@ +#/bin/bash +set -x +uniqueLabel=${1} +cp ${uniqueLabel}/expr_${uniqueLabel}_origin.c ${uniqueLabel}/expr_${uniqueLabel}_origin_bkp.c +cp exp1x/myhead.h ${uniqueLabel}/ \ No newline at end of file diff --git a/srcTest/readmePareto.md b/srcTest/readmePareto.md new file mode 100644 index 0000000000000000000000000000000000000000..367131f6885722b084cfb6871ecd3631751e3ad7 --- /dev/null +++ b/srcTest/readmePareto.md @@ -0,0 +1,63 @@ +# 函数级混合精度优化思路 + +## 旧思路 + +第一步: +先用MP脚本生成不同混合精度配置的实际性能-精度二元组信息。 +使用上述数据,构建数据表,即func1.csv,func2.csv +然后调用pareto_2.py脚本,构建混合精度方案的误差-开销二元组。并从中生成帕累托最优集合(帕累托前沿) +第一步得到的信息就是纯作为对比。这是理想情况下能找到的最优组合。 + +第二步(与第一步并行): +执行TGen,生成函数的性能-精度数据 +使用上述数据,构建数据表,即func1.csv,func2.csv +然后调用pareto_2.py脚本,构建混合精度方案的误差-开销二元组。并从中生成帕累托最优集合(帕累托前沿) +这是初步通过估算得到的预测的最优组合。当然此时的组合因为没有实测,其性能-精度数据并不一定对 + +第三步(承接第二步): +把第二步最后得到的帕累托最优集合,再重新用MP脚本测一下表达式的性能-精度二元组数据。 +然后再对实测的二元组信息执行帕累托优化。 + + +## 新思路 + +双函数的步骤: + +0. 预处理:把误差低于float32的都删除 +1. 先用 pareto_singleFunc.py 生成各函数的帕累托优化结果 (NMSEproblem345 sin tan) +2. 再用 combine_2.py 将其两两组合,生成所有可能的混合精度方案 +3. 再用 getRealErrCost.sh 对所有的混合精度方案进行测试,生成表达式的实际值构成的误差-开销二元组集合 +4. 再用 pareto_twoFunc.py 对该集合执行帕累托优化,缩小数量 +5. 最后用 sortData.py 对混合精度方案按照误差升序排序 + +双函数执行脚本: + +shell script name: pareto_all.sh + +```shell +python3 pareto_singleFunc.py sin +python3 pareto_singleFunc.py tan +python3 combine_2.py +./getRealErrCost.sh +python3 pareto_twoFunc.py +python3 sortData.py +``` + +单函数的步骤: + +0. 预处理:把误差低于float32的都删除 +1. 先用 pareto_singleFunc.py 生成函数的帕累托优化结果 (exp1x exp) +2. 再用 getRealErrCost_1.sh 对所有的混合精度方案进行测试,生成表达式的实际值构成的误差-开销二元组集合 +3. 再用 pareto_singleFunc.py 对该集合执行帕累托优化,缩小数量 +4. 最后用 sortData.py 对混合精度方案按照误差升序排序 + +单函数执行脚本: + +shell script name: pareto_all_1.sh + +```shell +python3 pareto_singleFunc.py exp_gen_0.01-0.5 +./getRealErrCost_1.sh exp1x exp +python3 pareto_singleFunc.py exp1x exp +python3 sortData.py exp1x exp +``` \ No newline at end of file diff --git a/srcTest/sortData.py b/srcTest/sortData.py new file mode 100644 index 0000000000000000000000000000000000000000..0c9d758538fa450bf7ec3f0be75a596e646ddc6f --- /dev/null +++ b/srcTest/sortData.py @@ -0,0 +1,91 @@ +import csv +import sys + +def sort_csv_by_column(csv_file, output_file, sort_column, func1, func2): + # 读取CSV文件数据 + data = [] + with open(csv_file, 'r') as file: + lines = file.readlines() + + # 跳过第一行 + lines = lines[1:] + + for line in lines: + row = line.strip().split('\t') + data.append(row) + + # 按照指定列进行排序 + sorted_data = sorted(data, key=lambda row: float(row[sort_column])) + + # 将排序后的结果写入新文件 + with open(output_file, 'w', newline='') as file: + csv_writer = csv.writer(file, delimiter = "\t") + header = [f"{func1}_regime1", "degree1", f"{func2}_regime2", "degree2", "averageErr", "performance", ] + csv_writer.writerow(header) + csv_writer.writerows(sorted_data) + print("Input file: %s"%(csv_file)) + print("Output file: %s"%(output_file)) + + +def sort_csv_by_column_1(csv_file, output_file, sort_column, func1): + # 读取CSV文件数据 + data = [] + with open(csv_file, 'r') as file: + lines = file.readlines() + + # 跳过第一行 + lines = lines[1:] + + for line in lines: + row = line.strip().split('\t') + data.append(row) + + # 按照指定列进行排序 + sorted_data = sorted(data, key=lambda row: float(row[sort_column])) + + # 将排序后的结果写入新文件 + with open(output_file, 'w', newline='') as file: + csv_writer = csv.writer(file, delimiter = "\t") + header = [f"{func1}_regime", "degree", "averageErr", "performance", ] + csv_writer.writerow(header) + csv_writer.writerows(sorted_data) + print("Input file: %s"%(csv_file)) + print("Output file: %s"%(output_file)) + + +# 按照第 sort_column 列数据对 inputFile 文件进行排序,结果写入 outputFile 文件 +if __name__ == '__main__': + # 读取命令行参数, 并检查是否传递了参数 + arguments = sys.argv + if len(arguments) > 4: + print("please input only 2 or 3 paremeters or none paremeter!") + sys.exit(1) + elif len(arguments) == 4: # 表达式中有 2 个函数。 + uniqueLabel = arguments[1] # arguments[2] 为 NMSEexample34, 即优化表达式 + + inputFile = uniqueLabel + "_errPerfPareto.csv" + outputFile = uniqueLabel + "_errPerfParetoSorted.csv" + sort_column = int(4) # 说明表达式中有2个函数,故第5列才是平均误差 + func1 = arguments[2] + func2 = arguments[3] + + sort_csv_by_column(inputFile, outputFile, sort_column, func1, func2) + elif len(arguments) == 3: # 表达式中只有 1 个函数。 + uniqueLabel = arguments[1] # arguments[2] 为 exp1x, 即优化表达式 + + inputFile = uniqueLabel + "_errPerfPareto.csv" + outputFile = uniqueLabel + "_errPerfParetoSorted.csv" + sort_column = int(2) # 说明表达式中有1个函数,故第3列才是平均误差 + func1 = arguments[2] + + sort_csv_by_column_1(inputFile, outputFile, sort_column, func1) + elif len(arguments) == 1: # 没有输入,对应的是之前的默认情况,即 NMSEproblem345 + uniqueLabel = "NMSEproblem345" + + inputFile = uniqueLabel + "_errPerfPareto.csv" + outputFile = uniqueLabel + "_errPerfParetoSorted.csv" + sort_column = int(4) # 说明表达式中有2个函数,故第5列才是平均误差 + func1 = "sin" + func2 = "tan" + + sort_csv_by_column(inputFile, outputFile, sort_column, func1, func2) \ No newline at end of file diff --git a/srcTest/test1paramFPEDParallel.c b/srcTest/test1paramFPEDParallel.c index 8e9f5a2156133dd739c87c0da4a251d0e8e54faa..450f4cc8318ddb0822979ba18a73a105a2de96ce 100644 --- a/srcTest/test1paramFPEDParallel.c +++ b/srcTest/test1paramFPEDParallel.c @@ -46,11 +46,11 @@ struct errorInfo test1FPEDparamParallel(DL x0Start, DL x0End, unsigned long int DL maxInputX0; int i0; // int flag; - double x0, reUlp, sumError, aveReUlp, maxReUlp, lenX0; + double x0, error, sumError, aveReUlp, maxReUlp, lenX0; // mpfr - mpfr_t mpfrOrcle, mpfrResult; - mpfr_inits2(PRECISION, mpfrOrcle, mpfrResult, (mpfr_ptr) 0); + mpfr_t mpfrOrcle, mpfrResult, mpfrDiff; + mpfr_inits2(PRECISION, mpfrOrcle, mpfrResult, mpfrDiff, (mpfr_ptr) 0); // write error data to file #if ERRFILE @@ -85,29 +85,35 @@ struct errorInfo test1FPEDparamParallel(DL x0Start, DL x0End, unsigned long int x0 = x0startOriginInterval + stepX0 * i0; computeResult1param(x0, mpfrResult); computeOrcle1param(x0, mpfrOrcle); - #ifdef SINGLE - reUlp = computeUlpDiffF(mpfrOrcle, mpfrResult); - #else // compute Double ULP as default - reUlp = computeUlpDiff(mpfrOrcle, mpfrResult); + #if (defined ABSOLUTE) + error = computeAbs(mpfrOrcle, mpfrResult, mpfrDiff); + #elif (defined RELATIVE) + error = computeRel(mpfrOrcle, mpfrResult); + #else + #if (defined SINGLE) + error = computeUlpDiffF(mpfrOrcle, mpfrResult); + #else // compute Double ULP as default + error = computeUlpDiff(mpfrOrcle, mpfrResult); + #endif #endif - // if(reUlp <= 0.5) { - // reUlp = 0; + // if(error <= 0.5) { + // error = 0; // } - // if(isfinite(reUlp) == 0) { + // if(isfinite(error) == 0) { // printf("happen to NaN or inf\n"); // exit(1); // } - if (isnormal(reUlp) != 0) + if (isnormal(error) != 0) { #if ERRFILE - fprintf(f, "%le\t%le\n", x0, reUlp); + fprintf(f, "%le\t%le\n", x0, error); #endif - sumError += reUlp; - if (reUlp > maxReUlp) { + sumError += error; + if (error > maxReUlp) { // flag = 0; maxInputX0.d = x0; - maxReUlp = reUlp; + maxReUlp = error; } } @@ -127,7 +133,7 @@ struct errorInfo test1FPEDparamParallel(DL x0Start, DL x0End, unsigned long int fclose(f); free(fileNameSample); #endif - mpfr_clears(mpfrOrcle, mpfrResult, (mpfr_ptr) 0); + mpfr_clears(mpfrOrcle, mpfrResult, mpfrDiff, (mpfr_ptr) 0); struct errorInfo err; err.sumError = sumError; err.maxError = maxReUlp; diff --git a/srcTest/test1paramSingle.c b/srcTest/test1paramSingle.c new file mode 100644 index 0000000000000000000000000000000000000000..51017e96d2e3a12315ab801750e526db034c27e3 --- /dev/null +++ b/srcTest/test1paramSingle.c @@ -0,0 +1,66 @@ +#include "common.h" + +#ifndef SUFFIX +#define SUFFIX orgin +#endif +#ifndef EXPRESSION +#define EXPRESSION NMSEproblem334 +#endif + +#define EXPRESSIONMINE ADDSUFFIX(EXPRESSION, SUFFIX) +#define SUFFIX1 mpfr +#define EXPRESSIONMPFR ADDSUFFIX(EXPRESSION, SUFFIX1) + +double EXPRESSIONMPFR(double, mpfr_t); +double EXPRESSIONMINE(double); + +int computeOrcle1param(double x0, mpfr_t orcle) +{ + return EXPRESSIONMPFR(x0, orcle); +} + +int computeResult1param(double x0, mpfr_t mpfrResult) +{ + int status = 1; + + double result = EXPRESSIONMINE(x0); + mpfr_set_d(mpfrResult, result, MPFR_RNDN); + + return status; +} + +void test1param(double x0) +{ + mpfr_t mpfrOrcle, mpfrResult; + mpfr_inits2(PRECISION, mpfrOrcle, mpfrResult, (mpfr_ptr) 0); + + computeResult1param(x0, mpfrResult); + computeOrcle1param(x0, mpfrOrcle); + + double reUlp = computeUlpDiff(mpfrOrcle, mpfrResult); + DL orcle, result; + orcle.d = mpfr_get_d(mpfrOrcle, MPFR_RNDN); + result.d = mpfr_get_d(mpfrResult, MPFR_RNDN); + printf("%8lg %8lg %8lg %8lg\n", x0, result.d, orcle.d, reUlp); + + // clear + mpfr_clears(mpfrOrcle, mpfrResult, (mpfr_ptr) 0); +} + +int main(int argc, char **argv) +{ + DL x0; + + if (argc == 2) + { + x0.l = strtoul(argv[1], NULL, 16); + printf("Value = 0x%016lx\n", x0.l); + } + else + { + printf("Wrong number of arguments.\n"); + exit(EXIT_FAILURE); + } + test1param(x0.d); + return 0; +} diff --git a/srcTest/test2paramFPEDParallel.c b/srcTest/test2paramFPEDParallel.c index c868375f42afc2dbefc39e9ac11bc64cd6d147e9..c3d57b37681a8fd4b1a7dafd0135a1c66387819d 100644 --- a/srcTest/test2paramFPEDParallel.c +++ b/srcTest/test2paramFPEDParallel.c @@ -3,7 +3,7 @@ struct errorInfo { - double sumError; + long double sumError; double maxError; double maxInputX0; double maxInputX1; @@ -51,7 +51,9 @@ struct errorInfo test2paramFPEDParallel(DL x0Start, DL x0End, DL x1Start, DL x1E DL maxInputX0, maxInputX1; int i0, i1; // int flag; - double x0, x1, reUlp, sumError, aveReUlp, maxReUlp, lenX0, lenX1; + double x0, x1, reUlp, aveReUlp, maxReUlp, lenX0, lenX1; + // double x0, x1, reUlp, sumError, aveReUlp, maxReUlp, lenX0, lenX1; + long double sumError; // mpfr mpfr_t mpfrOrcle, mpfrResult; @@ -122,6 +124,7 @@ struct errorInfo test2paramFPEDParallel(DL x0Start, DL x0End, DL x1Start, DL x1E // printf("average ulp\tmax ulp\n"); // printf("%lg\t%lg\n", aveReUlp, maxReUlp); // printf("\naveReUlp = %lg\nmaxInputX0 = 0x%016lx %lg, maxInputX1 = 0x%016lx %lg, maxInputX2 = 0x%016lx %lg, maxReUlp = %lg\n", aveReUlp, maxInputX0.l, maxInputX0.d, maxInputX1.l, maxInputX1.d, maxInputX2.l, maxInputX2.d, maxReUlp); + // printf("myid = %d, maxReUlp = %g, sumError = %Lg\n", myid, maxReUlp, sumError); #if ERRFILE // fprintf(f, "\n"); @@ -146,7 +149,11 @@ int main(int argc, char **argv) MPI_Comm_rank(MPI_COMM_WORLD, &myid); MPI_Comm_size(MPI_COMM_WORLD, &numProcs); MPI_Datatype MPI_errorInfo; - MPI_Type_contiguous(4, MPI_DOUBLE, &MPI_errorInfo); + // MPI_Type_contiguous(4, MPI_DOUBLE, &MPI_errorInfo); + const int blocklens[4] = {2, 1, 1, 1}; + MPI_Aint blockIndices[4] = {0, 16, 24, 32}; + MPI_Datatype blockType[4] = {MPI_LONG_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE}; + MPI_Type_create_struct(4, blocklens, blockIndices, blockType, &MPI_errorInfo); MPI_Type_commit(&MPI_errorInfo); // parameters init @@ -251,7 +258,7 @@ int main(int argc, char **argv) if (myid == 0) { double maxError = -1; - double aveError = 0; + long double aveError = 0; double errTmp = -1; int maxErrorIdx = -1; for (int i = 0; i < numProcs; i++) @@ -281,11 +288,11 @@ int main(int argc, char **argv) exit(0); } printf("average ulp\tmax ulp\n"); - printf("%.16le\t%.16le\n", aveError, maxError); - // printf("\naveReUlp = %lg\nmaxInputX0 = 0x%016lx %lg, maxInputX1 = 0x%016lx %lg, maxReUlp = %lg\n", aveError, maxInputX0.l, maxInputX0.d, maxInputX1.l, maxInputX1.d, maxError); + printf("%.16Le\t%.16le\n", aveError, maxError); + // printf("\naveReUlp = %Lg\nmaxInputX0 = 0x%016lx %lg, maxInputX1 = 0x%016lx %lg, maxReUlp = %lg\n", aveError, maxInputX0.l, maxInputX0.d, maxInputX1.l, maxInputX1.d, maxError); fprintf(fErr, "average ulp\tmax ulp\n"); - fprintf(fErr, "%.16le\t%.16le\n", aveError, maxError); - fprintf(fErr, "\naveReUlp = %lg\nmaxInputX0 = 0x%016lx %lg, maxInputX1 = 0x%016lx %lg, maxReUlp = %lg\n", aveError, maxInputX0.l, maxInputX0.d, maxInputX1.l, maxInputX1.d, maxError); + fprintf(fErr, "%.16Le\t%.16le\n", aveError, maxError); + fprintf(fErr, "\naveReUlp = %Lg\nmaxInputX0 = 0x%016lx %lg, maxInputX1 = 0x%016lx %lg, maxReUlp = %lg\n", aveError, maxInputX0.l, maxInputX0.d, maxInputX1.l, maxInputX1.d, maxError); free(fileNameErr); free(uniqueLabel); diff --git a/srcTest/test2paramSingle.c b/srcTest/test2paramSingle.c new file mode 100644 index 0000000000000000000000000000000000000000..8b9072fd665ac59b273d5689729154e4088fff25 --- /dev/null +++ b/srcTest/test2paramSingle.c @@ -0,0 +1,69 @@ +#include "common.h" + +#ifndef SUFFIX +#define SUFFIX orgin +#endif +#ifndef EXPRESSION +#define EXPRESSION NMSEproblem334 +#endif + +#define EXPRESSIONMINE ADDSUFFIX(EXPRESSION, SUFFIX) +#define SUFFIX1 mpfr +#define EXPRESSIONMPFR ADDSUFFIX(EXPRESSION, SUFFIX1) + +double EXPRESSIONMPFR(double, double, mpfr_t); +double EXPRESSIONMINE(double, double); + +int computeOrcle2param(double x0, double x1, mpfr_t orcle) +{ + return EXPRESSIONMPFR(x0, x1, orcle); +} + +int computeResult2param(double x0, double x1, mpfr_t mpfrResult) +{ + int status = 1; + + double result = EXPRESSIONMINE(x0, x1); + mpfr_set_d(mpfrResult, result, MPFR_RNDN); + + return status; +} + +void test2param(double x0, double x1) +{ + mpfr_t mpfrOrcle, mpfrResult; + mpfr_inits2(PRECISION, mpfrOrcle, mpfrResult, (mpfr_ptr) 0); + + computeResult2param(x0, x1, mpfrResult); + computeOrcle2param(x0, x1, mpfrOrcle); + + double reUlp = computeUlpDiff(mpfrOrcle, mpfrResult); + DL orcle, result; + orcle.d = mpfr_get_d(mpfrOrcle, MPFR_RNDN); + result.d = mpfr_get_d(mpfrResult, MPFR_RNDN); + printf("%8lg %8lg %8lg\n", result.d, orcle.d, reUlp); + printf("0x%016lx 0x%016lx %8lg\n", result.l, orcle.l, reUlp); + + // clear + mpfr_clears(mpfrOrcle, mpfrResult, (mpfr_ptr) 0); +} + +int main(int argc, char **argv) +{ + DL x0, x1; + + if (argc == 3) + { + x0.l = strtoul(argv[1], NULL, 16); + x1.l = strtoul(argv[2], NULL, 16); + printf("x0 = 0x%016lx\t", x0.l); + printf("x1 = 0x%016lx\n", x1.l); + } + else + { + printf("Wrong number of arguments.\n"); + exit(EXIT_FAILURE); + } + test2param(x0.d, x1.d); + return 0; +} diff --git a/srcTest/test3paramFPEDParallel.c b/srcTest/test3paramFPEDParallel.c index 80f58e5ccf2a290c9ca88cdbde2f4cc823e3d457..13b859db88a77a009e7cd37835a1ae48c1acdc91 100644 --- a/srcTest/test3paramFPEDParallel.c +++ b/srcTest/test3paramFPEDParallel.c @@ -288,8 +288,8 @@ int main(int argc, char **argv) { printf("Error opening file %s.\n", fileNameErr); exit(0); } - printf("average ulp\tmax ulp\n"); - printf("%.16le\t%.16le\n", aveError, maxError); + // printf("average ulp\tmax ulp\n"); + // printf("%.16le\t%.16le\n", aveError, maxError); // printf("\naveReUlp = %lg\nmaxInputX0 = 0x%016lx %lg, maxInputX1 = 0x%016lx %lg, maxInputX2 = 0x%016lx %lg, maxReUlp = %lg\n", aveError, maxInputX0.l, maxInputX0.d, maxInputX1.l, maxInputX1.d, maxInputX2.l, maxInputX2.d, maxError); fprintf(fErr, "average ulp\tmax ulp\n"); fprintf(fErr, "%.16le\t%.16le\n", aveError, maxError); diff --git a/srcTest/testPerformanceOneManual.sh b/srcTest/testPerformanceOneManual.sh index ff23c00b8a0de661684cf0cf05418a482ef75f8d..56adc75f5f1b3bbbeb7981b529d0cee1c327c766 100755 --- a/srcTest/testPerformanceOneManual.sh +++ b/srcTest/testPerformanceOneManual.sh @@ -26,15 +26,15 @@ fi resultFileName=result_${uniqueLabel}_${start}_${end}.txt funcName=expr_${uniqueLabel}_${suffix} -# gcc gccPerformanceTest.c binary.c ${uniqueLabel}/${funcName}.c -DFUNCNAME=${funcName} -DRUNTIME=${runtime} -I../includeTEST -lm -o gccPerformanceTest_${uniqueLabel}.exe -O3 +# gcc testPerformanceOne.c binary.c ${uniqueLabel}/${funcName}.c -DFUNCNAME=${funcName} -DRUNTIME=${runtime} -I../includeTEST -lm -o testPerformanceOne_${uniqueLabel}.exe -O3 -# make gccPerformanceTest.o -s CFLAGS="-DFUNCNAME=${funcName} -DRUNTIME=${runtime}" -gcc gccPerformanceTest.c -DFUNCNAME=${funcName} -DRUNTIME=${runtime} -I../includeTEST -c -O3 +# make testPerformanceOne.o -s CFLAGS="-DFUNCNAME=${funcName} -DRUNTIME=${runtime}" +gcc testPerformanceOne.c -DFUNCNAME=${funcName} -DRUNTIME=${runtime} -I../includeTEST -c -O3 make binary.o -s # gcc binary.c -I../includeTEST -c -O3 -gcc ${uniqueLabel}/${funcName}.c -I../includeDD -c -O3 -gcc gccPerformanceTest.o binary.o ${funcName}.o -lmpfr -lm -lqd -o gccPerformanceTest_${uniqueLabel}.exe -O3 -./gccPerformanceTest_${uniqueLabel}.exe ${resultFileName} ${start} ${end} -# rm -rf gccPerformanceTest_${uniqueLabel}.exe +gcc ${uniqueLabel}/${funcName}.c -I../includeDD -c -O3 -mfma +gcc testPerformanceOne.o binary.o ${funcName}.o ../libs/libTGen.so -lmpfr -lm -lqd -o testPerformanceOne_${uniqueLabel}.exe -O3 +./testPerformanceOne_${uniqueLabel}.exe ${resultFileName} ${start} ${end} +# rm -rf testPerformanceOne_${uniqueLabel}.exe ### compute the cycles of the function ${uniqueLabel} make dataClean.exe -s CFLAGS="-DRUNTIME=${runtime}" # gcc dataClean.c -DRUNTIME=${runtime} -o dataClean.exe diff --git a/srcTest/testPerformanceTwo.c b/srcTest/testPerformanceTwo.c index 6c4ce2e2fef8914188985c045b873be2e397cc50..1981848336d69a512ed20b2ac21c874b329ccc60 100644 --- a/srcTest/testPerformanceTwo.c +++ b/srcTest/testPerformanceTwo.c @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) sumResult = sumResult + result[i]; } sum = sum / RUNTIME; - printf("sumResult is %f\n", sumResult); + // printf("sumResult is %f\n", sumResult); // printf("the performance result to be clean: %lu\n", sum); if(fclose(stream_time) == EOF) { diff --git a/srcTest/testPerformanceTwoManual.sh b/srcTest/testPerformanceTwoManual.sh new file mode 100755 index 0000000000000000000000000000000000000000..a569cb173c932d1ff298bab37384677d9b8a4b73 --- /dev/null +++ b/srcTest/testPerformanceTwoManual.sh @@ -0,0 +1,52 @@ +#!/bin/bash +#example: cd path/to/srcTest; taskset -c 0 ./testPerformanceTwoManual.sh i6 origin 0 100 0 100 + +if [ $# == 1 ]; then + uniqueLabel=${1} + suffix=origin + x0Start=0.01 + x0End=100 + x1Start=0.01 + x1End=100 + runtime=10000 +elif [ $# == 6 ]; then + uniqueLabel=${1} + suffix=${2} + x0Start=${3} + x0End=${4} + x1Start=${5} + x1End=${6} + runtime=10000 +elif [ $# == 7 ]; then + uniqueLabel=${1} + suffix=${2} + x0Start=${3} + x0End=${4} + x1Start=${5} + x1End=${6} + runtime=${7} +else + echo "please input 1, 6 or 7 parameters" + exit +fi + +resultFileName=result_${uniqueLabel}_${x0Start}_${x0End}_${x1Start}_${x1End}.txt +funcName=expr_${uniqueLabel}_${suffix} + +# gcc testPerformanceTwo.c binary.c ${uniqueLabel}/${funcName}.c -DFUNCNAME=${funcName} -DRUNTIME=${runtime} -I../includeTEST -lm -o testPerformanceTwo_${uniqueLabel}.exe -O3 + +# make testPerformanceTwo.o -s CFLAGS="-DFUNCNAME=${funcName} -DRUNTIME=${runtime}" +gcc testPerformanceTwo.c -DFUNCNAME=${funcName} -DRUNTIME=${runtime} -I../includeTEST -c -O3 +# gcc ${uniqueLabel}/expr_${uniqueLabel}_mpfr.c -c +make binary.o -s # gcc binary.c -I../includeTEST -c -O3 +gcc ${uniqueLabel}/${funcName}.c -I../includeTEST -I../includeDD -c -O3 -mfma +gcc testPerformanceTwo.o binary.o ${funcName}.o -lm -lqd -lmpfr -o testPerformanceTwo_${uniqueLabel}.exe -O3 +./testPerformanceTwo_${uniqueLabel}.exe ${resultFileName} ${x0Start} ${x0End} ${x1Start} ${x1End} +# rm -rf testPerformanceTwo_${uniqueLabel}.exe + +### compute the cycles of the function ${uniqueLabel} +make dataClean.exe -s CFLAGS="-DRUNTIME=${runtime}" # gcc dataClean.c -DRUNTIME=${runtime} -o dataClean.exe +sort -n ${resultFileName} > ${resultFileName}.sort +./dataClean.exe ${resultFileName}.sort +rm -rf ${resultFileName} ${resultFileName}.sort +# rm dataClean.exe