From 175f0aa944534bf19a2807e776861b54eac501c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Fri, 7 Apr 2023 15:45:44 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20sign(0)=20was=20returning=201=20?= =?UTF-8?q?instead=20of=200=20with=20use=5Fdll?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The C99 copysign() function was used in the generated C output, but that function does not correctly handle zero. Replace it by a custom sign() function. (manually cherry picked from commit b1e4884237376fdce06265b7f96fb63e0bd8b224) --- src/DataTree.cc | 12 ++++++++++-- src/DataTree.hh | 8 ++++---- src/DynamicModel.cc | 6 +++--- src/ExprNode.cc | 10 ++++------ src/StaticModel.cc | 6 +++--- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/DataTree.cc b/src/DataTree.cc index f24c3030..b315eb75 100644 --- a/src/DataTree.cc +++ b/src/DataTree.cc @@ -873,7 +873,7 @@ DataTree::minLagForSymbol(int symb_id) const } void -DataTree::writePowerDeriv(ostream &output) const +DataTree::writeCHelpersDefinition(ostream &output) const { if (isBinaryOpUsed(BinaryOpcode::powerDeriv)) output << "/*" << endl @@ -892,6 +892,12 @@ DataTree::writePowerDeriv(ostream &output) const << " return dxp;" << endl << " }" << endl << "}" << endl; + + if (isUnaryOpUsed(UnaryOpcode::sign)) + output << "double sign(double x)" << endl + << "{" << endl + << " return (x > 0) ? 1 : ((x < 0) ? -1 : 0);" << endl + << "}" << endl; } void @@ -915,10 +921,12 @@ DataTree::writePowerDerivJulia(ostream &output) const } void -DataTree::writePowerDerivHeader(ostream &output) const +DataTree::writeCHelpersDeclaration(ostream &output) const { if (isBinaryOpUsed(BinaryOpcode::powerDeriv)) output << "double getPowerDeriv(double x, double p, int k);" << endl; + if (isUnaryOpUsed(UnaryOpcode::sign)) + output << "double sign(double x);" << endl; } string diff --git a/src/DataTree.hh b/src/DataTree.hh index 6e9f818d..61dfcfbf 100644 --- a/src/DataTree.hh +++ b/src/DataTree.hh @@ -280,12 +280,12 @@ public: //! Returns the minimum lag (as a negative number) of the given symbol in the whole data tree (and not only in the equations !!) /*! Returns 0 if the symbol is not used */ int minLagForSymbol(int symb_id) const; - //! Write getPowerDeriv in C (function body) - void writePowerDeriv(ostream &output) const; - //! Write getPowerDeriv in C (prototype) - void writePowerDerivHeader(ostream &output) const; //! Write getPowerDeriv in Julia void writePowerDerivJulia(ostream &output) const; + //! Writes definitions of C function helpers (getPowerDeriv(), sign()) + void writeCHelpersDefinition(ostream &output) const; + //! Writes declarations of C function helpers (getPowerDeriv(), sign()) + void writeCHelpersDeclaration(ostream &output) const; //! Thrown when trying to access an unknown variable by deriv_id class UnknownDerivIDException { diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index ea98032b..f1968626 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -631,7 +631,7 @@ DynamicModel::writeDynamicPerBlockCFiles(const string &basename) const << endl; // Write function definition if BinaryOpcode::powerDeriv is used - writePowerDerivHeader(output); + writeCHelpersDeclaration(output); output << endl; @@ -1447,7 +1447,7 @@ DynamicModel::writeDynamicCFile(const string &basename) const << endl; // Write function definition if BinaryOpcode::powerDeriv is used - writePowerDeriv(output); + writeCHelpersDefinition(output); output << endl; @@ -1671,7 +1671,7 @@ DynamicModel::writeDynamicBlockCFile(const string &basename) const output << R"(#include "dynamic_)" << blk+1 << R"(.h")" << endl; output << endl; - writePowerDeriv(output); + writeCHelpersDefinition(output); output << endl << "void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])" << endl diff --git a/src/ExprNode.cc b/src/ExprNode.cc index d1ab8690..7c512ab8 100644 --- a/src/ExprNode.cc +++ b/src/ExprNode.cc @@ -2693,10 +2693,10 @@ UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type, output << "abs"; break; case UnaryOpcode::sign: - if (output_type == ExprNodeOutputType::CDynamicModel || output_type == ExprNodeOutputType::CStaticModel) - output << "copysign"; - else - output << "sign"; + /* C does not have a sign() function, and copysign() is not suitable + because it does not handle zero correctly, so we define our own sign() + helper function, see DataTree::writeCHelpersDefinition() */ + output << "sign"; break; case UnaryOpcode::steadyState: ExprNodeOutputType new_output_type; @@ -2787,8 +2787,6 @@ UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type, && arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms))) { output << LEFT_PAR(output_type); - if (op_code == UnaryOpcode::sign && (output_type == ExprNodeOutputType::CDynamicModel || output_type == ExprNodeOutputType::CStaticModel)) - output << "1.0,"; close_parenthesis = true; } diff --git a/src/StaticModel.cc b/src/StaticModel.cc index ba9d28f6..37cae8b1 100644 --- a/src/StaticModel.cc +++ b/src/StaticModel.cc @@ -311,7 +311,7 @@ StaticModel::writeStaticPerBlockCFiles(const string &basename) const << endl; // Write function definition if BinaryOpcode::powerDeriv is used - writePowerDerivHeader(output); + writeCHelpersDeclaration(output); output << endl; @@ -1730,7 +1730,7 @@ StaticModel::writeStaticCFile(const string &basename) const << endl; // Write function definition if BinaryOpcode::powerDeriv is used - writePowerDeriv(output); + writeCHelpersDefinition(output); output << endl; @@ -1914,7 +1914,7 @@ StaticModel::writeStaticBlockCFile(const string &basename) const output << R"(#include "static_)" << blk+1 << R"(.h")" << endl; output << endl; - writePowerDeriv(output); + writeCHelpersDefinition(output); output << endl << "void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])" << endl -- GitLab