diff --git a/mex/sources/bytecode/ErrorHandling.hh b/mex/sources/bytecode/ErrorHandling.hh index 0af66aee3453e2b0c3b5426802bd96fb4e6810c5..00e6c8cdb8569b0194cde357020c7bc80211663b 100644 --- a/mex/sources/bytecode/ErrorHandling.hh +++ b/mex/sources/bytecode/ErrorHandling.hh @@ -33,57 +33,59 @@ struct GeneralException struct FloatingPointException : public GeneralException { - FloatingPointException(const string &details) : - GeneralException {"Floating point error: " + details} + const string location; + FloatingPointException(const string &details, string location_arg) : + GeneralException {"Floating point error: " + details}, + location {move(location_arg)} { } }; struct LogException : public FloatingPointException { - LogException(double value) : + LogException(double value, string location_arg) : FloatingPointException { [=] { // We don’t use std::to_string(), because it uses fixed formatting ostringstream s; s << "log(X) with X=" << defaultfloat << value; return s.str(); - }() } + }(), move(location_arg) } { } }; struct Log10Exception : public FloatingPointException { - Log10Exception(double value) : + Log10Exception(double value, string location_arg) : FloatingPointException { [=] { // We don’t use std::to_string(), because it uses fixed formatting ostringstream s; s << "log10(X) with X=" << defaultfloat << value; return s.str(); - }() } + }(), move(location_arg) } { } }; struct DivideException : public FloatingPointException { - DivideException(double divisor) : + DivideException(double v1, double v2, string location_arg) : FloatingPointException { [=] { // We don’t use std::to_string(), because it uses fixed formatting ostringstream s; - s << "a/X with X=" << defaultfloat << divisor; + s << "a/X with a=" << defaultfloat << v1 << " and X= " << v2; return s.str(); - }() } + }(), move(location_arg) } { } }; struct PowException : public FloatingPointException { - PowException(double base, double exponent) : + PowException(double base, double exponent, string location_arg) : FloatingPointException { [=] { // We don’t use std::to_string(), because it uses fixed formatting @@ -92,7 +94,7 @@ struct PowException : public FloatingPointException if (fabs(base) <= 1e-10) s << " and a=" << exponent; return s.str(); - }() } + }(), move(location_arg) } { } }; diff --git a/mex/sources/bytecode/Evaluate.cc b/mex/sources/bytecode/Evaluate.cc index 0772fe2c999dc020db025429456c247ed1472d49..05ba368a36d9bf2983a3c732334361231a715d08 100644 --- a/mex/sources/bytecode/Evaluate.cc +++ b/mex/sources/bytecode/Evaluate.cc @@ -21,6 +21,7 @@ #include <cmath> #include <limits> #include <stack> +#include <cfenv> #include <dynmex.h> @@ -987,64 +988,8 @@ Evaluate::print_expression(const Evaluate::it_code_type &expr_begin, const optio return { get<0>(Stack.top()), it_code }; } -double -Evaluate::pow1(double a, double b) -{ - double r = pow(a, b); - if (isnan(r) || isinf(r)) - { - res1 = std::numeric_limits<double>::quiet_NaN(); - r = 0.0000000000000000000000001; - if (print_error) - throw PowException{a, b}; - } - return r; -} - -double -Evaluate::divide(double a, double b) -{ - double r = a / b; - if (isnan(r) || isinf(r)) - { - res1 = std::numeric_limits<double>::quiet_NaN(); - r = 1e70; - if (print_error) - throw DivideException{b}; - } - return r; -} - -double -Evaluate::log1(double a) -{ - double r = log(a); - if (isnan(r) || isinf(r)) - { - res1 = std::numeric_limits<double>::quiet_NaN(); - r = -1e70; - if (print_error) - throw LogException{a}; - } - return r; -} - -double -Evaluate::log10_1(double a) -{ - double r = log(a); - if (isnan(r) || isinf(r)) - { - res1 = std::numeric_limits<double>::quiet_NaN(); - r = -1e70; - if (print_error) - throw Log10Exception{a}; - } - return r; -} - void -Evaluate::compute_block_time(int Per_u_, bool evaluate, bool no_derivative) +Evaluate::evaluateBlock(int Per_u_, bool evaluate, bool no_derivative) { auto it_code { currentBlockBeginning() }; int var{0}, lag{0}; @@ -1619,20 +1564,13 @@ Evaluate::compute_block_time(int Per_u_, bool evaluate, bool no_derivative) #endif break; case BinaryOpcode::divide: - double tmp; -#ifdef DEBUG - mexPrintf("v1=%f / v2=%f\n", v1, v2); -#endif - try - { - tmp = divide(v1, v2); - } - catch (FloatingPointException &fpeh) - { - mexPrintf("%s\n %s\n", fpeh.message.c_str(), error_location(it_code_expr, it_code, steady_state, it_).c_str()); - go_on = false; - } - Stack.push(tmp); + { + feclearexcept(FE_ALL_EXCEPT); + double tmp {v1 / v2}; + if (fetestexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW)) + throw DivideException{v1, v2, error_location(it_code_expr, it_code, steady_state, it_)}; + Stack.push(tmp); + } #ifdef DEBUG tmp_out << " |" << v1 << "/" << v2 << "|"; #endif @@ -1674,20 +1612,13 @@ Evaluate::compute_block_time(int Per_u_, bool evaluate, bool no_derivative) #endif break; case BinaryOpcode::power: -#ifdef DEBUG - mexPrintf("pow\n"); -#endif - try - { - tmp = pow1(v1, v2); - } - catch (FloatingPointException &fpeh) - { - mexPrintf("%s\n %s\n", fpeh.message.c_str(), error_location(it_code_expr, it_code, steady_state, it_).c_str()); - go_on = false; - } - Stack.push(tmp); - + { + feclearexcept(FE_ALL_EXCEPT); + double tmp {pow(v1, v2)}; + if (fetestexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW)) + throw PowException{v1, v2, error_location(it_code_expr, it_code, steady_state, it_)}; + Stack.push(tmp); + } #ifdef DEBUG tmp_out << " |" << v1 << "^" << v2 << "|"; #endif @@ -1704,7 +1635,10 @@ Evaluate::compute_block_time(int Per_u_, bool evaluate, bool no_derivative) Stack.push(0.0); else { - double dxp = pow1(v1, v2-derivOrder); + feclearexcept(FE_ALL_EXCEPT); + double dxp {pow(v1, v2-derivOrder)}; + if (fetestexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW)) + throw PowException{v1, v2-derivOrder, error_location(it_code_expr, it_code, steady_state, it_)}; for (int i = 0; i < derivOrder; i++) dxp *= v2--; Stack.push(dxp); @@ -1767,33 +1701,25 @@ Evaluate::compute_block_time(int Per_u_, bool evaluate, bool no_derivative) #endif break; case UnaryOpcode::log: - double tmp; - try - { - tmp = log1(v1); - } - catch (FloatingPointException &fpeh) - { - mexPrintf("%s\n %s\n", fpeh.message.c_str(), error_location(it_code_expr, it_code, steady_state, it_).c_str()); - go_on = false; - } - Stack.push(tmp); - + { + feclearexcept(FE_ALL_EXCEPT); + double tmp {log(v1)}; + if (fetestexcept(FE_DIVBYZERO | FE_INVALID)) + throw LogException{v1, error_location(it_code_expr, it_code, steady_state, it_)}; + Stack.push(tmp); + } #ifdef DEBUG tmp_out << " |log(" << v1 << ")|"; #endif break; case UnaryOpcode::log10: - try - { - tmp = log10_1(v1); - } - catch (FloatingPointException &fpeh) - { - mexPrintf("%s\n %s\n", fpeh.message.c_str(), error_location(it_code_expr, it_code, steady_state, it_).c_str()); - go_on = false; - } - Stack.push(tmp); + { + feclearexcept(FE_ALL_EXCEPT); + double tmp {log10(v1)}; + if (fetestexcept(FE_DIVBYZERO | FE_INVALID)) + throw Log10Exception{v1, error_location(it_code_expr, it_code, steady_state, it_)}; + Stack.push(tmp); + } #ifdef DEBUG tmp_out << " |log10(" << v1 << ")|"; #endif diff --git a/mex/sources/bytecode/Evaluate.hh b/mex/sources/bytecode/Evaluate.hh index 16b22aa326218daa8c6543ee9dd44b411f915052..d6a37e673e08cacce9cdba022dea8dd91e1ff370 100644 --- a/mex/sources/bytecode/Evaluate.hh +++ b/mex/sources/bytecode/Evaluate.hh @@ -89,14 +89,8 @@ protected: double *g1, *r, *res; vector<mxArray *> jacobian_block, jacobian_exo_block, jacobian_det_exo_block; mxArray *GlobalTemporaryTerms; - double pow1(double a, double b); - double divide(double a, double b); - double log1(double a); - double log10_1(double a); - void compute_block_time(int Per_u_, bool evaluate, bool no_derivatives); + void evaluateBlock(int Per_u_, bool evaluate, bool no_derivatives); int it_; - bool print_error; - double res1; int block_num; // Index of the current block int size; // Size of the current block diff --git a/mex/sources/bytecode/Interpreter.cc b/mex/sources/bytecode/Interpreter.cc index 8f4e069710dcdeda96f90fefbe381db7d2bbe5f1..cba6fecd04d7915ee57b4a524dba2dfb90d42caf 100644 --- a/mex/sources/bytecode/Interpreter.cc +++ b/mex/sources/bytecode/Interpreter.cc @@ -22,6 +22,7 @@ #include <cstring> #include <filesystem> #include <numeric> +#include <cfenv> #include "Interpreter.hh" @@ -34,7 +35,7 @@ Interpreter::Interpreter(double *params_arg, double *y_arg, double *ya_arg, doub string &filename_arg, int minimal_solving_periods_arg, int stack_solve_algo_arg, int solve_algo_arg, bool global_temporary_terms_arg, bool print_arg, bool print_error_arg, mxArray *GlobalTemporaryTerms_arg, bool steady_state_arg, bool block_decomposed_arg, bool print_it_arg, int col_x_arg, int col_y_arg, BasicSymbolTable &symbol_table_arg) -: dynSparseMatrix {y_size_arg, y_kmin_arg, y_kmax_arg, print_it_arg, steady_state_arg, block_decomposed_arg, periods_arg, minimal_solving_periods_arg, symbol_table_arg} +: dynSparseMatrix {y_size_arg, y_kmin_arg, y_kmax_arg, print_it_arg, steady_state_arg, block_decomposed_arg, periods_arg, minimal_solving_periods_arg, symbol_table_arg, print_error_arg} { params = params_arg; y = y_arg; @@ -61,7 +62,6 @@ Interpreter::Interpreter(double *params_arg, double *y_arg, double *ya_arg, doub col_x = col_x_arg; col_y = col_y_arg; GlobalTemporaryTerms = GlobalTemporaryTerms_arg; - print_error = print_error_arg; print_it = print_it_arg; } @@ -110,7 +110,14 @@ Interpreter::solve_simple_one_periods() { slowc /= 1.5; mexPrintf("Reducing the path length in Newton step slowc=%f\n", slowc); - y[Block_Contain[0].Variable + Per_y_] = ya - slowc * divide(r[0], g1[0]); + feclearexcept(FE_ALL_EXCEPT); + y[Block_Contain[0].Variable + Per_y_] = ya - slowc * (r[0] / g1[0]); + if (fetestexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW)) + { + res1 = numeric_limits<double>::quiet_NaN(); + if (print_error) + mexPrintf(" Singularity in block %d", block_num+1); + } } } } @@ -119,14 +126,13 @@ Interpreter::solve_simple_one_periods() cvg = (fabs(rr) < solve_tolf); if (cvg) continue; - try + feclearexcept(FE_ALL_EXCEPT); + y[Block_Contain[0].Variable + Per_y_] += -slowc * (rr / g1[0]); + if (fetestexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW)) { - y[Block_Contain[0].Variable + Per_y_] += -slowc *divide(rr, g1[0]); - } - catch (FloatingPointException &fpeh) - { - mexPrintf("%s\n \n", fpeh.message.c_str()); - mexPrintf(" Singularity in block %d", block_num+1); + res1 = numeric_limits<double>::quiet_NaN(); + if (print_error) + mexPrintf(" Singularity in block %d", block_num+1); } iter++; } diff --git a/mex/sources/bytecode/SparseMatrix.cc b/mex/sources/bytecode/SparseMatrix.cc index 303124ccc9c6b4885c1c23cdd7226a816140742b..1b10ac0766966ea6469ed2dc11f7c8dd0b71b945 100644 --- a/mex/sources/bytecode/SparseMatrix.cc +++ b/mex/sources/bytecode/SparseMatrix.cc @@ -25,11 +25,13 @@ #include "SparseMatrix.hh" dynSparseMatrix::dynSparseMatrix(int y_size_arg, int y_kmin_arg, int y_kmax_arg, bool print_it_arg, bool steady_state_arg, bool block_decomposed_arg, int periods_arg, - int minimal_solving_periods_arg, BasicSymbolTable &symbol_table_arg) : + int minimal_solving_periods_arg, BasicSymbolTable &symbol_table_arg, + bool print_error_arg) : Evaluate {y_size_arg, y_kmin_arg, y_kmax_arg, steady_state_arg, periods_arg, symbol_table_arg}, block_decomposed {block_decomposed_arg}, minimal_solving_periods {minimal_solving_periods_arg}, - print_it {print_it_arg} + print_it {print_it_arg}, + print_error {print_error_arg} { pivotva = nullptr; g_save_op = nullptr; @@ -1818,6 +1820,21 @@ dynSparseMatrix::Sparse_transpose(const mxArray *A_m) return C_m; } +void +dynSparseMatrix::compute_block_time(int Per_u_, bool evaluate, bool no_derivatives) +{ + try + { + evaluateBlock(Per_u_, evaluate, no_derivatives); + } + catch (FloatingPointException &e) + { + res1 = numeric_limits<double>::quiet_NaN(); + if (print_error) + mexPrintf("%s\n %s\n", e.message.c_str(), e.location.c_str()); + } +} + bool dynSparseMatrix::compute_complete(bool no_derivatives, double &_res1, double &_res2, double &_max_res, int &_max_res_idx) { diff --git a/mex/sources/bytecode/SparseMatrix.hh b/mex/sources/bytecode/SparseMatrix.hh index 12c5c76d141f33768808dcb5aac112eef3c19108..0f018e702b5227458df5d8251d571e194364af85 100644 --- a/mex/sources/bytecode/SparseMatrix.hh +++ b/mex/sources/bytecode/SparseMatrix.hh @@ -68,7 +68,7 @@ constexpr double mem_increasing_factor = 1.1; class dynSparseMatrix : public Evaluate { public: - dynSparseMatrix(int y_size_arg, int y_kmin_arg, int y_kmax_arg, bool print_it_arg, bool steady_state_arg, bool block_decomposed_arg, int periods_arg, int minimal_solving_periods_arg, BasicSymbolTable &symbol_table_arg); + dynSparseMatrix(int y_size_arg, int y_kmin_arg, int y_kmax_arg, bool print_it_arg, bool steady_state_arg, bool block_decomposed_arg, int periods_arg, int minimal_solving_periods_arg, BasicSymbolTable &symbol_table_arg, bool print_error_arg); void Simulate_Newton_Two_Boundaries(int blck, int y_size, int y_kmin, int y_kmax, int Size, int periods, bool cvg, int minimal_solving_periods, int stack_solve_algo, const vector_table_conditional_local_type &vector_table_conditional_local); void Simulate_Newton_One_Boundary(bool forward); void fixe_u(double **u, int u_count_int, int max_lag_plus_max_lead_plus_1); @@ -198,13 +198,16 @@ protected: int maxit_; double *direction; double solve_tolf; - double res2, max_res; + double res1, res2, max_res; int max_res_idx; int *index_vara; + void compute_block_time(int Per_u_, bool evaluate, bool no_derivatives); bool compute_complete(bool no_derivatives, double &res1, double &res2, double &max_res, int &max_res_idx); bool compute_complete(double lambda, double *crit); + + bool print_error; // Whether to stop processing on floating point exceptions }; #endif // _SPARSEMATRIX_HH