From 7f2d02bc998c0cc9a16de503f4801644759568b0 Mon Sep 17 00:00:00 2001 From: hjw Date: Mon, 21 Nov 2022 07:28:39 +0800 Subject: [PATCH 1/2] Implemented error detecting (3 parameters) random parallel version --- detectErrorThreeRandomParallel.sh | 44 +++++ src/exprAuto.cpp | 7 +- test3paramFPEDParallel.c | 1 - test3paramRandomParallel.c | 294 ++++++++++++++++++++++++++++++ 4 files changed, 343 insertions(+), 3 deletions(-) create mode 100755 detectErrorThreeRandomParallel.sh create mode 100644 test3paramRandomParallel.c diff --git a/detectErrorThreeRandomParallel.sh b/detectErrorThreeRandomParallel.sh new file mode 100755 index 0000000..01e0d23 --- /dev/null +++ b/detectErrorThreeRandomParallel.sh @@ -0,0 +1,44 @@ +# Usage: ./detectErrorThreeParallel.sh ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x2Start} ${x2End} ${x0Size} ${x1Size} ${x2Size} ${prefix} ${middle} ${suffix} +# set -x + +path=`pwd` +cd ${path} +CC=mpicc + +uniqueLabel=${1} # unique number +x0Start=${2} +x0End=${3} +x1Start=${4} +x1End=${5} +x2Start=${6} +x2End=${7} +if [ $# -eq 13 ]; then + x0Size=${8} + x1Size=${9} + x2Size=${10} + prefix=${11} # expr_${uniqueLabel}. Eg: expr_20221030155958 + middle=${12} # intervalsInfo_sizes. Eg: 3.8_7.8_-4.5_-0.3_0.4_0.9_256_256_256 + suffix=${13} # different version. Eg: herbie daisy origin temp_0_3 final +elif [ $# -eq 10 ]; then + x0Size=256 + x1Size=256 + x2Size=256 + prefix=${8} + middle=${9} + suffix=${10} +else + echo "detectErrorThreeParallel: Invalid input parameters" + exit +fi +testFileName=test3paramRandomParallel +numProcs=32 + +echo "Detecting error: ${uniqueLabel} ${x0Start} ${x0End} ${x1Start} ${x1End} ${x2Start} ${x2End} ${x0Size} ${x1Size} ${x2Size} ${prefix} ${middle} ${suffix}" + +# echo "${CC} ${testFileName}.c ${prefix}_${suffix}.c ${prefix}_mpfr.c computeULP.c -IincludeTEST -DEXPRESSION=${prefix}_ -DSUFFIX=${suffix} -lmpfr -lm -O3 -o ${testFileName}.exe" +${CC} ${testFileName}.c ${prefix}_${suffix}.c ${prefix}_mpfr.c computeULP.c -IincludeTEST -DEXPRESSION=${prefix}_ -DSUFFIX=${suffix} -lmpfr -lm -o ${testFileName}.exe +# echo "mpirun -n ${numProcs} ./${testFileName}.exe ${x0Start} ${x0End} ${x1Start} ${x1End} ${x2Start} ${x2End} ${x0Size} ${x1Size} ${x2Size} ${prefix}__${middle}_${suffix}" +mpirun -n ${numProcs} ./${testFileName}.exe ${x0Start} ${x0End} ${x1Start} ${x1End} ${x2Start} ${x2End} ${x0Size} ${x1Size} ${x2Size} ${prefix}__${middle}_${suffix} +rm ${testFileName}.exe +echo "end detecting ${uniqueLabel}" +echo diff --git a/src/exprAuto.cpp b/src/exprAuto.cpp index a8e14bf..a67f726 100644 --- a/src/exprAuto.cpp +++ b/src/exprAuto.cpp @@ -1060,9 +1060,12 @@ vector exprAutoWrapper(ast_ptr &expr) auto funcNameMpfr = geneMpfrCode(exprStr, uniqueLabel, vars); int scale = 256; + // turbine1 + auto info = testError(uniqueLabel, "origin", 3.8, 7.8, -4.5, -0.3, 0.4, 0.9, scale, scale, scale); + auto info1 = testError(uniqueLabel, "sympy", 3.8, 7.8, -4.5, -0.3, 0.4, 0.9, scale, scale, scale); // doppler1 - auto info = testError(uniqueLabel, "origin", -30, 50, -100, 100, 20, 20000, scale, scale, scale); - auto info1 = testError(uniqueLabel, "sympy", -30, 50, -100, 100, 20, 20000, scale, scale, scale); + // auto info = testError(uniqueLabel, "origin", -30, 50, -100, 100, 20, 20000, scale, scale, scale); + // auto info1 = testError(uniqueLabel, "sympy", -30, 50, -100, 100, 20, 20000, scale, scale, scale); // int scale = 500000; // sine // auto info = testError(uniqueLabel, "origin", -1.57079632679, 1.57079632679, scale); diff --git a/test3paramFPEDParallel.c b/test3paramFPEDParallel.c index 2c92bdc..a95b9c1 100644 --- a/test3paramFPEDParallel.c +++ b/test3paramFPEDParallel.c @@ -185,7 +185,6 @@ int main(int argc, char **argv) { printf("Usage: if no correct input:\n"); printf("Usage: \tthe fixed inputs [%g %g %g %g %g %g %lu %lu %lu] will be used\n", x0Start.d, x0End.d, x1Start.d, x1End.d, x2Start.d, x2End.d, testNumX0, testNumX1, testNumX2); } - if(myid == 0) { printf("\n---------------------------------------------------start test3paramFPEDParallel\n"); printf("Parameters: x0Start: %lg, x0End: %lg, x1Start: %lg, x1End: %lg, x2Start: %lg, x2End: %lg, testNumX0 = %lu, testNumX1 = %lu, testNumX2 = %lu, fileNameKernel: %s\n", x0Start.d, x0End.d, x1Start.d, x1End.d, x2Start.d, x2End.d, testNumX0, testNumX1, testNumX2, fileNameKernel); diff --git a/test3paramRandomParallel.c b/test3paramRandomParallel.c new file mode 100644 index 0000000..91646b0 --- /dev/null +++ b/test3paramRandomParallel.c @@ -0,0 +1,294 @@ +#include +#include +#include "common.h" +#include "mpi.h" + +struct errorInfo { + double sumError; + double maxError; + double maxInputX0; + double maxInputX1; + double maxInputX2; +}; + +#ifndef SUFFIX +#define SUFFIX orgin +#endif +#ifndef EXPRESSION +#define EXPRESSION sum +#endif + +#define EXPRESSIONMINE ADDSUFFIX(EXPRESSION, SUFFIX) +#define SUFFIX1 mpfr +#define EXPRESSIONMPFR ADDSUFFIX(EXPRESSION, SUFFIX1) + +#define TESTNUMX0 256 +#define TESTNUMX1 256 +#define TESTNUMX2 256 + +#define RANDOMCOUNT 10 +// #define FP +// #define DEBUG +double EXPRESSIONMPFR(double, double, double, mpfr_t); +double EXPRESSIONMINE(double, double, double); + +int computeOrcle3param(double x0, double x1, double x2, mpfr_t orcle) { + return EXPRESSIONMPFR(x0, x1, x2, orcle); +} + +int computeResult3param(double x0, double x1, double x2, mpfr_t mpfrResult) { + int status = 1; + + double result = EXPRESSIONMINE(x0, x1, x2); + mpfr_set_d(mpfrResult, result, MPFR_RNDN); + + return status; +} + +struct errorInfo test3paramParallel(DL x0Start, DL x0End, DL x1Start, DL x1End, DL x2StartLocal, DL x2EndLocal, int lenX0, int lenX1, int lenX2Local, const char* fileNameKernel, int myid) +{ + srand(time(0)); + // printf("myid = %d: x0Start: %lg, x0End: %lg, x1Start: %lg, x1End: %lg, x2StartLocal: %lg, x2EndLocal: %lg, lenX0Local = %d, lenX1Local = %d, lenX2Local = %d\n", myid, x0Start.d, x0End.d, x1Start.d, x1End.d, x2StartLocal.d, x2EndLocal.d, lenX0Local, lenX1Local, lenX2Local); + DL x0, x1, x2, maxInputX0, maxInputX1, maxInputX2; + #ifdef DEBUG + DL orcle, result; + #endif + int i0, i1, i2, flag; + double reUlp, sumError, aveReUlp, maxReUlp; + + // mpfr + mpfr_t mpfrOrcle, mpfrResult; + mpfr_inits2(PRECISION, mpfrOrcle, mpfrResult, (mpfr_ptr) 0); + + // file + // char *suffix = "sample.txt"; + // char *fileNameSample; + // FILE *f; + // fileNameSample = (char *) calloc(strlen(fileNameKernel) + strlen(suffix) + 128, sizeof(char)); + // sprintf(fileNameSample, "./outputs/%s_%s_%d", fileNameKernel, suffix, myid); + // // printf("%s\n", fileNameSample); + // if ((f = fopen(fileNameSample, "w")) == NULL) { + // printf("Error opening file %s.\n", fileNameSample); + // exit(0); + // } + + // Real number average + maxReUlp = 0; + flag = 1; + size_t testCount = 0; + sumError = 0; + for(size_t i = 0; i < lenX2Local; i++) { + // x2.d = random(x2StartLocal, x2EndLocal); + x2.d = x2StartLocal.d + ((double)rand() / (double)RAND_MAX) * (x2EndLocal.d - x2StartLocal.d); + for(size_t j = 0; j < lenX1; j++) { + x1.d = x1Start.d + ((double)rand() / (double)RAND_MAX) * (x1End.d - x1Start.d); + for(size_t k = 0; k < lenX0; k++) { + x0.d = x0Start.d + ((double)rand() / (double)RAND_MAX) * (x0End.d - x0Start.d); + testCount++; + computeResult3param(x0.d, x1.d, x2.d, mpfrResult); + computeOrcle3param(x0.d, x1.d, x2.d, mpfrOrcle); + #ifdef SINGLE + reUlp = computeUlpDiffF(mpfrOrcle, mpfrResult); + #else // compute Double ULP as default + reUlp = computeUlpDiff(mpfrOrcle, mpfrResult); + #endif + // if(reUlp <= 0.5) { + // reUlp = 0; + // } + // if(isfinite(reUlp) == 0) { + // printf("happen to NaN or inf\n"); + // exit(1); + // } + // fprintf(f, "%.16le\n", reUlp); + sumError += reUlp; + if (reUlp > maxReUlp) { + flag = 0; + maxInputX2 = x2; + maxInputX1 = x1; + maxInputX0 = x0; + maxReUlp = reUlp; + } + } + } + } + // fprintf(f, "\n"); + // aveReUlp = sumError / testCount; + // if(flag == 1) { + // printf("all error are 0!!\n"); + // } + // 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); + + // clear + // fclose(f); + // free(fileNameSample); + mpfr_clears(mpfrOrcle, mpfrResult, (mpfr_ptr) 0); + struct errorInfo err; + err.sumError = sumError; + err.maxError = maxReUlp; + err.maxInputX0 = maxInputX0.d; + err.maxInputX1 = maxInputX1.d; + err.maxInputX2 = maxInputX2.d; + return err; +} + +int main(int argc, char **argv) { + // parallel + int myid, numProcs; + MPI_Init(&argc, &argv); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + MPI_Comm_size(MPI_COMM_WORLD, &numProcs); + MPI_Datatype MPI_errorInfo; + MPI_Type_contiguous(5, MPI_DOUBLE, &MPI_errorInfo); + MPI_Type_commit(&MPI_errorInfo); + + // parameters init + DL x0Start, x0End, x1Start, x1End, x2Start, x2End; + unsigned long int testNumX0, testNumX1, testNumX2; + x0Start.d = 1; + x0End.d = 2; + x1Start.d = 1; + x1End.d = 2; + x2Start.d = 1; + x2End.d = 2; + testNumX0 = TESTNUMX0; + testNumX1 = TESTNUMX1; + testNumX2 = TESTNUMX2; + char *fileNameKernel; + fileNameKernel = calloc(256, sizeof(char)); + if(argc == 11) { + x0Start.d = strtod(argv[1], NULL); + x0End.d = strtod(argv[2], NULL); + x1Start.d = strtod(argv[3], NULL); + x1End.d = strtod(argv[4], NULL); + x2Start.d = strtod(argv[5], NULL); + x2End.d = strtod(argv[6], NULL); + testNumX0 = strtod(argv[7], NULL); + testNumX1 = strtod(argv[8], NULL); + testNumX2 = strtod(argv[9], NULL); + strcpy(fileNameKernel, argv[10]); + } else if(argc == 8) { + x0Start.d = strtod(argv[1], NULL); + x0End.d = strtod(argv[2], NULL); + x1Start.d = strtod(argv[3], NULL); + x1End.d = strtod(argv[4], NULL); + x2Start.d = strtod(argv[5], NULL); + x2End.d = strtod(argv[6], NULL); + strcpy(fileNameKernel, argv[7]); + } else if(argc == 5) { + testNumX0 = strtod(argv[1], NULL); + testNumX1 = strtod(argv[2], NULL); + testNumX2 = strtod(argv[3], NULL); + strcpy(fileNameKernel, argv[4]); + } else { + printf("Usage: ./test3paramParallel.exe [x0Start x0End x1Start x1End x2Start x2End testNumX0 testNumX1 testNumX2 fileNameKernel]\n"); + printf("Usage: if no correct input:\n"); + printf("Usage: \tthe fixed inputs [%g %g %g %g %g %g %lu %lu %lu] will be used\n", x0Start.d, x0End.d, x1Start.d, x1End.d, x2Start.d, x2End.d, testNumX0, testNumX1, testNumX2); + } + if(myid == 0) { + printf("\n---------------------------------------------------start test3paramParallel\n"); + printf("Parameters: x0Start: %lg, x0End: %lg, x1Start: %lg, x1End: %lg, x2Start: %lg, x2End: %lg, testNumX0 = %lu, testNumX1 = %lu, testNumX2 = %lu, fileNameKernel: %s\n", x0Start.d, x0End.d, x1Start.d, x1End.d, x2Start.d, x2End.d, testNumX0, testNumX1, testNumX2, fileNameKernel); + } + // global + double lenX2 = x2End.d - x2Start.d; + double lenX2Unit = lenX2 / testNumX2; + + // local parameters init + int testNumX2Local; + DL x2StartLocal; + DL x2EndLocal; + if(myid < (testNumX2 % numProcs)) { + testNumX2Local = testNumX2 / numProcs + 1; + x2StartLocal.d = x2Start.d + myid * testNumX2Local * lenX2Unit; + x2EndLocal.d = x2Start.d + (myid + 1) * testNumX2Local * lenX2Unit; + } + else + { + testNumX2Local = testNumX2 / numProcs; + x2StartLocal.d = x2End.d - (numProcs - myid - 1) * testNumX2Local * lenX2Unit; + x2EndLocal.d = x2End.d - (numProcs - myid) * testNumX2Local * lenX2Unit; + } + + struct errorInfo *errs; + errs = (struct errorInfo *)calloc(numProcs, sizeof(struct errorInfo)); + double maxErrorFinal = -1; + double aveErrorFinal = 0; + DL maxInputX0Final, maxInputX1Final, maxInputX2Final; + + for(size_t runCount = 0; runCount < RANDOMCOUNT; runCount++){ + // call the error test function + struct errorInfo err = test3paramParallel(x0Start, x0End, x1Start, x1End, x2StartLocal, x2EndLocal, testNumX0, testNumX1, testNumX2Local, fileNameKernel, myid); + + // gather errors and find the max + MPI_Gather(&err, 1, MPI_errorInfo, errs, 1, MPI_errorInfo, 0, MPI_COMM_WORLD); + if(myid == 0) + { + double maxError = -1; + double aveError = 0; + double errTmp = -1; + int maxErrorIdx = -1; + for(int i = 0; i < numProcs; i++) + { + errTmp = errs[i].maxError; + if(errTmp > maxError) + { + maxError = errTmp; + maxErrorIdx = i; + } + aveError += errs[i].sumError; + } + aveError = aveError / (testNumX0 * testNumX1 * testNumX2); + DL maxInputX0, maxInputX1, maxInputX2; + maxInputX0.d = errs[maxErrorIdx].maxInputX0; + maxInputX1.d = errs[maxErrorIdx].maxInputX1; + maxInputX2.d = errs[maxErrorIdx].maxInputX2; + + printf("\n\n----------NO.%lu\n", runCount); + printf("average ulp\tmax ulp\n"); + printf("%lg\t%lg\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); + + if(maxError > maxErrorFinal) + { + maxErrorFinal = maxError; + maxInputX0Final.d = maxInputX0.d; + maxInputX1Final.d = maxInputX1.d; + maxInputX2Final.d = maxInputX2.d; + } + aveErrorFinal += aveError; + } + } + if(myid == 0) { + aveErrorFinal = aveErrorFinal / RANDOMCOUNT; + + printf("\n\n----------FINAL\n"); + printf("average ulp\tmax ulp\n"); + printf("%lg\t%lg\n", aveErrorFinal, maxErrorFinal); + printf("\naveReUlp = %lg\nmaxInputX0Final = 0x%016lx %lg, maxInputX1Final = 0x%016lx %lg, maxInputX2Final = 0x%016lx %lg, maxReUlp = %lg\n", aveErrorFinal, maxInputX0Final.l, maxInputX0Final.d, maxInputX1Final.l, maxInputX1Final.d, maxInputX2Final.l, maxInputX2Final.d, maxErrorFinal); + + FILE *fErr; + char *directory = "./outputs"; + char *suffixErr = "error.txt"; + char *fileNameErr; + fileNameErr = (char *) calloc(strlen(directory) + strlen(fileNameKernel) + strlen(suffixErr) + 128, sizeof(char)); + sprintf(fileNameErr, "%s/%s_%s", directory, fileNameKernel, suffixErr); + if ((fErr = fopen(fileNameErr, "w")) == NULL) + { + printf("Error opening file %s.\n", fileNameErr); + exit(0); + } + fprintf(fErr, "average ulp\tmax ulp\n"); + fprintf(fErr, "%lg\t%lg\n", aveErrorFinal, maxErrorFinal); + fprintf(fErr, "\naveReUlp = %lg\nmaxInputX0Final = 0x%016lx %lg, maxInputX1Final = 0x%016lx %lg, maxInputX2Final = 0x%016lx %lg, maxReUlp = %lg\n", aveErrorFinal, maxInputX0Final.l, maxInputX0Final.d, maxInputX1Final.l, maxInputX1Final.d, maxInputX2Final.l, maxInputX2Final.d, maxErrorFinal); + + free(fileNameErr); + fclose(fErr); + } + // clear + free(fileNameKernel); + free(errs); + MPI_Type_free(&MPI_errorInfo); + MPI_Finalize(); + return 0; +} \ No newline at end of file -- Gitee From 4139e93e0973e35a8b9797fab26345d0a39728db Mon Sep 17 00:00:00 2001 From: hjw Date: Mon, 21 Nov 2022 15:47:59 +0800 Subject: [PATCH 2/2] Add parameters intervals and scales to exprAutoWrapper --- include/exprAuto.hpp | 4 ++-- include/tools.hpp | 2 +- src/exprAuto.cpp | 15 ++++++++------- src/main.cpp | 2 +- src/tools.cpp | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/exprAuto.hpp b/include/exprAuto.hpp index e32015d..701369d 100644 --- a/include/exprAuto.hpp +++ b/include/exprAuto.hpp @@ -48,8 +48,8 @@ vector createAll(vector &numerators, vector &denomina vector exprAutoNew(const ast_ptr &expr); -vector exprAutoWrapper(ast_ptr &expr); +vector exprAutoWrapper(ast_ptr &expr, const std::vector &intervals = {0, 1}, const std::vector &scales = {100}); -vector exprAutoWrapper(const string &inputStr); +vector exprAutoWrapper(const string &inputStr, const std::vector &intervals = {0, 1}, const std::vector &scales = {100}); #endif diff --git a/include/tools.hpp b/include/tools.hpp index a6f5b8d..d08e471 100644 --- a/include/tools.hpp +++ b/include/tools.hpp @@ -27,7 +27,7 @@ vector getIntervals(string interval, const char *split); vector getScales(string scale, const char *split); -exprInfo testError(string uniqueLabel, string suffix, vector &intervals, vector &scales); +exprInfo testError(string uniqueLabel, string suffix, const vector &intervals, const vector &scales); exprInfo testError(string uniqueLabel, string suffix, double x0Start, double x0End, int scale); diff --git a/src/exprAuto.cpp b/src/exprAuto.cpp index a67f726..f851f1f 100644 --- a/src/exprAuto.cpp +++ b/src/exprAuto.cpp @@ -1025,7 +1025,7 @@ vector exprAutoNew(const ast_ptr &expr) return results; } -vector exprAutoWrapper(ast_ptr &expr) +vector exprAutoWrapper(ast_ptr &expr, const std::vector &intervals, const std::vector &scales) { cout << "\n>exprAutoWrapper: start-----------" << endl; @@ -1059,10 +1059,10 @@ vector exprAutoWrapper(ast_ptr &expr) auto funcNameSympy = geneOriginCodeKernel(expr1Str, vars, uniqueLabel, "sympy"); auto funcNameMpfr = geneMpfrCode(exprStr, uniqueLabel, vars); - int scale = 256; + // int scale = 256; // turbine1 - auto info = testError(uniqueLabel, "origin", 3.8, 7.8, -4.5, -0.3, 0.4, 0.9, scale, scale, scale); - auto info1 = testError(uniqueLabel, "sympy", 3.8, 7.8, -4.5, -0.3, 0.4, 0.9, scale, scale, scale); + // auto info = testError(uniqueLabel, "origin", 3.8, 7.8, -4.5, -0.3, 0.4, 0.9, scale, scale, scale); + // auto info1 = testError(uniqueLabel, "sympy", 3.8, 7.8, -4.5, -0.3, 0.4, 0.9, scale, scale, scale); // doppler1 // auto info = testError(uniqueLabel, "origin", -30, 50, -100, 100, 20, 20000, scale, scale, scale); // auto info1 = testError(uniqueLabel, "sympy", -30, 50, -100, 100, 20, 20000, scale, scale, scale); @@ -1074,7 +1074,8 @@ vector exprAutoWrapper(ast_ptr &expr) // auto info = testError(uniqueLabel, "origin", 0, 1, scale); // auto info1 = testError(uniqueLabel, "sympy", 0, 1, scale); - + auto info = testError(uniqueLabel, "origin", intervals, scales); + auto info1 = testError(uniqueLabel, "sympy", intervals, scales); auto maxError = info.maxError; auto maxError1 = info1.maxError; @@ -1111,8 +1112,8 @@ vector exprAutoWrapper(ast_ptr &expr) return results; } -vector exprAutoWrapper(const string &inputStr) +vector exprAutoWrapper(const string &inputStr, const std::vector &intervals, const std::vector &scales) { auto expr = ParseExpressionFromString(inputStr); - return exprAutoWrapper(expr); + return exprAutoWrapper(expr, intervals, scales); } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 30eee14..aebfcb1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -188,7 +188,7 @@ int main() else { // only rewrite // auto timeTmp1 = std::chrono::high_resolution_clock::now(); - auto results = exprAutoWrapper(inputStr); + auto results = exprAutoWrapper(inputStr, intervals, scales); // auto timeTmp2 = std::chrono::high_resolution_clock::now(); // std::chrono::duration exprAutoWrapper_seconds = timeTmp2 - timeTmp1; // cout << BLUE << "exprAutoWrapper time: " << exprAutoWrapper_seconds.count() << " s" << RESET << endl; diff --git a/src/tools.cpp b/src/tools.cpp index d6b74a7..51569f1 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -296,7 +296,7 @@ exprInfo testError(string uniqueLabel, string suffix, double x0Start, double x0E return tempError; } -exprInfo testError(string uniqueLabel, string suffix, vector &intervals, vector &scales) +exprInfo testError(string uniqueLabel, string suffix, const vector &intervals, const vector &scales) { exprInfo tempError; size_t size = scales.size(); -- Gitee