diff --git a/preprocessor/DataTree.cc b/preprocessor/DataTree.cc index ba94916556c505edab8956f60f3320d9c4c56e50..e748e7598b94e3fd66483e7d4568e5e154cda5a9 100644 --- a/preprocessor/DataTree.cc +++ b/preprocessor/DataTree.cc @@ -707,3 +707,48 @@ DataTree::writePowerDeriv(ostream &output) const << " }" << endl << "}" << endl; } + +void +DataTree::writeNormcdfCHeader(ostream &output) const +{ +#if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) + if (isTrinaryOpUsed(oNormcdf)) + output << "#ifdef _MSC_VER" << endl + << "double normcdf(double);" << endl + << "#endif" << endl; +#endif +} + +void +DataTree::writeNormcdf(ostream &output) const +{ +#if defined(_WIN32) || defined(__CYGWIN32__) || defined(__MINGW32__) + if (isTrinaryOpUsed(oNormcdf)) + output << endl + << "#ifdef _MSC_VER" << endl + << "/*" << endl + << " * Define normcdf for MSVC compiler" << endl + << " */" << endl + << "double normcdf(double x)" << endl + << "{" << endl + << "#if _MSC_VER >= 1700" << endl + << " return 0.5 * erfc(-x * M_SQRT1_2);" << endl + << "#else" << endl + << " // From http://www.johndcook.com/blog/cpp_phi" << endl + << " double a1 = 0.254829592;" << endl + << " double a2 = -0.284496736;" << endl + << " double a3 = 1.421413741;" << endl + << " double a4 = -1.453152027;" << endl + << " double a5 = 1.061405429;" << endl + << " double p = 0.3275911;" << endl + << " int sign = (x < 0) ? -1 : 1;" << endl + << " x = fabs(x)/sqrt(2.0);" << endl + << " // From the Handbook of Mathematical Functions by Abramowitz and Stegun, formula 7.1.26" << endl + << " double t = 1.0/(1.0 + p*x);" << endl + << " double y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);" << endl + << " return 0.5*(1.0 + sign*y);" << endl + << "#endif" << endl + << "}" << endl + << "#endif" << endl; +#endif +} diff --git a/preprocessor/DataTree.hh b/preprocessor/DataTree.hh index ce908408acaddb22680bfcde055450d287630c5a..83e59471cb76ce29bd016a0d46c3bf3076c668ed 100644 --- a/preprocessor/DataTree.hh +++ b/preprocessor/DataTree.hh @@ -239,6 +239,10 @@ public: void writePowerDerivCHeader(ostream &output) const; //! Write getPowerDeriv in C void writePowerDeriv(ostream &output) const; + //! Write the C Header for normcdf when use_dll is used + void writeNormcdfCHeader(ostream &output) const; + //! Write normcdf in C + void writeNormcdf(ostream &output) const; //! Thrown when trying to access an unknown variable by deriv_id class UnknownDerivIDException { diff --git a/preprocessor/DynamicModel.cc b/preprocessor/DynamicModel.cc index f9720fa1c569564d96ffcd5330beafeca8da7258..cc16f5aaed7693c85c15681d2f7827ad58cec34e 100644 --- a/preprocessor/DynamicModel.cc +++ b/preprocessor/DynamicModel.cc @@ -1620,11 +1620,13 @@ DynamicModel::writeDynamicCFile(const string &dynamic_basename, const int order) // Write function definition if oPowerDeriv is used writePowerDerivCHeader(mDynamicModelFile); + writeNormcdfCHeader(mDynamicModelFile); // Writing the function body writeDynamicModel(mDynamicModelFile, true, false); writePowerDeriv(mDynamicModelFile); + writeNormcdf(mDynamicModelFile); mDynamicModelFile.close(); mDynamicMexFile.open(filename_mex.c_str(), ios::out | ios::binary); @@ -4883,6 +4885,7 @@ DynamicModel::writeResidualsC(const string &basename, bool cuda) const // Write function definition if oPowerDeriv is used // even for residuals if doing Ramsey writePowerDerivCHeader(mDynamicModelFile); + writeNormcdfCHeader(mDynamicModelFile); mDynamicModelFile << "void Residuals(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual)" << endl << "{" << endl; @@ -4900,6 +4903,7 @@ DynamicModel::writeResidualsC(const string &basename, bool cuda) const << "}" << endl; writePowerDeriv(mDynamicModelFile); + writeNormcdf(mDynamicModelFile); mDynamicModelFile.close(); } @@ -4931,6 +4935,7 @@ DynamicModel::writeFirstDerivativesC(const string &basename, bool cuda) const // Write function definition if oPowerDeriv is used writePowerDerivCHeader(mDynamicModelFile); + writeNormcdfCHeader(mDynamicModelFile); mDynamicModelFile << "void FirstDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, double *g1, double *v2, double *v3)" << endl << "{" << endl; @@ -4988,6 +4993,7 @@ DynamicModel::writeFirstDerivativesC_csr(const string &basename, bool cuda) cons // Write function definition if oPowerDeriv is used writePowerDerivCHeader(mDynamicModelFile); + writeNormcdfCHeader(mDynamicModelFile); mDynamicModelFile << "void FirstDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, int *row_ptr, int *col_ptr, double *value)" << endl << "{" << endl; @@ -5089,6 +5095,7 @@ DynamicModel::writeSecondDerivativesC_csr(const string &basename, bool cuda) con // write function definition if oPowerDeriv is used writePowerDerivCHeader(mDynamicModelFile); + writeNormcdfCHeader(mDynamicModelFile); mDynamicModelFile << "void SecondDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, int *row_ptr, int *col_ptr, double *value)" << endl << "{" << endl; @@ -5151,8 +5158,8 @@ DynamicModel::writeSecondDerivativesC_csr(const string &basename, bool cuda) con mDynamicModelFile << "}" << endl; writePowerDeriv(mDynamicModelFile); + writeNormcdf(mDynamicModelFile); mDynamicModelFile.close(); - } void @@ -5182,6 +5189,7 @@ DynamicModel::writeThirdDerivativesC_csr(const string &basename, bool cuda) cons // Write function definition if oPowerDeriv is used writePowerDerivCHeader(mDynamicModelFile); + writeNormcdfCHeader(mDynamicModelFile); mDynamicModelFile << "void ThirdDerivatives(const double *y, double *x, int nb_row_x, double *params, double *steady_state, int it_, double *residual, double *g1, double *v2, double *v3)" << endl << "{" << endl; @@ -5277,6 +5285,7 @@ DynamicModel::writeThirdDerivativesC_csr(const string &basename, bool cuda) cons mDynamicModelFile << "}" << endl; writePowerDeriv(mDynamicModelFile); + writeNormcdf(mDynamicModelFile); mDynamicModelFile.close(); } diff --git a/preprocessor/ModFile.cc b/preprocessor/ModFile.cc index 3ee5612f9b35986b68bac0a2134ac960df70a0d6..173f9b669c36046e347b9116b608aafc189975af 100644 --- a/preprocessor/ModFile.cc +++ b/preprocessor/ModFile.cc @@ -739,12 +739,6 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo } } #endif - if (use_dll && msvc) - if (dynamic_model.isTrinaryOpUsed(oNormcdf)) - { - cerr << "ERROR: normcdf() function is not supported with USE_DLL option and older MSVC compilers; use Cygwin, MinGW or upgrade your MSVC compiler to 11.0 (2012) or later." << endl; - exit(EXIT_FAILURE); - } #endif // Compile the dynamic MEX file for use_dll option diff --git a/preprocessor/StaticModel.cc b/preprocessor/StaticModel.cc index 23e5e1f4d6b96d4a7310d65e114022c1d374f6e9..251cbe1e044dd284592bb866989cbe929a337e3a 100644 --- a/preprocessor/StaticModel.cc +++ b/preprocessor/StaticModel.cc @@ -1611,12 +1611,14 @@ StaticModel::writeStaticCFile(const string &func_name) const // Write function definition if oPowerDeriv is used writePowerDerivCHeader(output); + writeNormcdfCHeader(output); // Writing the function body writeStaticModel(output, true, false); output << "}" << endl << endl; writePowerDeriv(output); + writeNormcdf(output); output.close(); output.open(filename_mex.c_str(), ios::out | ios::binary);