From f0cbeb523380bf9d20e196386f3096ef4ef6d2dc Mon Sep 17 00:00:00 2001 From: Martin Ettl Date: Sun, 29 Sep 2013 18:11:17 +0200 Subject: [PATCH] simplifyMathFunctions: added support for exp(),sqrt(),cbrt() functions. --- lib/tokenize.cpp | 106 +++++++++++++++++++------------ test/testmathlib.cpp | 13 ++++ test/testtokenize.cpp | 141 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 212 insertions(+), 48 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 6facd1728..729128096 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8268,13 +8268,46 @@ void Tokenizer::cppcheckError(const Token *tok) const reportError(tok, Severity::error, "cppcheckError", "Analysis failed. If the code is valid then please report this failure."); } +// ------------------------------------------------------------------------ +// Helper function to check wether number is zero (0,0.0 or 0E+0) or not? +// @param s --> a string to check +// @return true in case s is zero and false otherwise. +// ------------------------------------------------------------------------ +static bool isZeroNumber(const std::string &s) +{ + const bool isPositive = MathLib::isPositive(s); + const bool isInteger = MathLib::isInt(s); + const bool isFloat = MathLib::isFloat(s); + const bool isZeroValue = ((isPositive && isInteger && (MathLib::toLongNumber(s) == 0L)) // case: integer number + || (isPositive && isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "0.0")); // case: float number + + return isZeroValue; +} + +// ------------------------------------------------------------------------ +// Helper function to check wether number is one (1,0.1 or 1E+0) or not? +// @param s --> a string to check +// @return true in case s is zero and false otherwise. +// ------------------------------------------------------------------------ +static bool isOneNumber(const std::string &s) +{ + const bool isPositive = MathLib::isPositive(s); + const bool isInteger = MathLib::isInt(s); + const bool isFloat = MathLib::isFloat(s); + const bool isZeroValue = ((isPositive && isInteger && (MathLib::toLongNumber(s) == 1L)) // case: integer number + || (isPositive && isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "1.0")); // case: float number + + return isZeroValue; +} // ------------------------------------------------------ // Simplify math functions. // It simplifies following functions: atol(), abs(), fabs() // labs(), llabs(), fmin(), fminl(), fminf(), fmax(), fmaxl() // fmaxf(), isgreater(), isgreaterequal(), isless() -// islessgreater(), islessequal(), pow(), powf(), powl() +// islessgreater(), islessequal(), pow(), powf(), powl(), +// div(),ldiv(),lldiv(), cbrt(), cbrtl(), cbtrf(), sqrt(), +// sqrtf(), sqrtl(), exp(), expf(), expl() // in the tokenlist. // // Reference: @@ -8313,6 +8346,28 @@ void Tokenizer::simplifyMathFunctions() } tok->deleteNext(3); // delete e.g. abs ( 1 ) tok->str(strNumber); // insert result into token list + } else if (Token::Match(tok, "sqrt|sqrtf|sqrtl|cbrt|cbrtf|cbrtl ( %num% )")) { + // Simplify: sqrt(0) = 0 and cbrt(0) == 0 + // sqrt(1) = 1 and cbrt(1) == 1 + // get number string + const std::string parameter(tok->tokAt(2)->str()); + // is parameter 0 ? + if (isZeroNumber(parameter)) { + tok->deleteNext(3); // delete tokens + tok->str("0"); // insert result into token list + } else if (isOneNumber(parameter)) { + tok->deleteNext(3); // delete tokens + tok->str("1"); // insert result into token list + } + } else if (Token::Match(tok, "exp|expf|expl ( %num% )")) { + // Simplify: exp(0) = 1 + // get number string + const std::string parameter(tok->tokAt(2)->str()); + // is parameter 0 ? + if (isZeroNumber(parameter)) { + tok->deleteNext(3); // delete tokens + tok->str("1"); // insert result into token list + } } else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) { // @todo if one of the parameters is NaN the other is returned // e.g. printf ("fmin (NaN, -1.0) = %f\n", fmin(NaN,-1.0)); @@ -8404,12 +8459,7 @@ void Tokenizer::simplifyMathFunctions() const std::string leftParameter(tok->tokAt(2)->str()); // get the left parameter const std::string rightNumber(tok->tokAt(4)->str()); // get right number if (!rightNumber.empty() && !leftParameter.empty()) { - const bool isNegative = MathLib::isNegative(rightNumber); - const bool isInteger = MathLib::isInt(rightNumber); - const bool isFloat = MathLib::isFloat(rightNumber); - const bool allowToSimplify = ((!isNegative && isInteger && (MathLib::toLongNumber(rightNumber) == 1L)) // case: integer numbers - || (!isNegative && isFloat && (MathLib::toDoubleNumber(rightNumber)-1.0) >= 0.)); // case: float numbers - if (allowToSimplify == true) { + if (isOneNumber(rightNumber)) { tok->deleteNext(5); // delete tokens tok->str(leftParameter); // insert simplified result } @@ -8420,51 +8470,31 @@ void Tokenizer::simplifyMathFunctions() const std::string leftParameter(tok->tokAt(2)->str()); // get the left parameter const std::string rightNumber(tok->tokAt(4)->str()); // get right number if (!rightNumber.empty() && !leftParameter.empty()) { - const bool isNegative = MathLib::isNegative(rightNumber); - const bool isInteger = MathLib::isInt(rightNumber); - const bool isFloat = MathLib::isFloat(rightNumber); - const bool rightParameterIsOne = ((!isNegative && isInteger && (MathLib::toLongNumber(rightNumber) == 1L)) // case: integer numbers - || (!isNegative && isFloat && (MathLib::toDoubleNumber(rightNumber)-1.0) >= 0.)); // case: float numbers - const bool rightParameterIsZero = ((!isNegative && isInteger && (MathLib::toLongNumber(rightNumber) == 0L)) // case: integer numbers - || (!isNegative && isFloat && (MathLib::toDoubleNumber(rightNumber)) >= 0.)); // case: float numbers - if (rightParameterIsOne) { // case: x^(1) = x + if (isOneNumber(rightNumber)) { // case: x^(1) = x tok->deleteNext(5); // delete tokens tok->str(leftParameter); // insert simplified result - } else if (rightParameterIsZero) { // case: x^(0) = 1 + } else if (isZeroNumber(rightNumber)) { // case: x^(0) = 1 tok->deleteNext(5); // delete tokens tok->str("1"); // insert simplified result } } - } - if (tok && Token::Match(tok->tokAt(2), " %num% , %num% )")) { + } else if (tok && Token::Match(tok->tokAt(2), " %num% , %num% )")) { // In case of pow ( 0 , anyNumber > 0): It can be simplified to 0 // In case of pow ( 0 , 0 ): It simplified to 1 // In case of pow ( 1 , anyNumber ): It simplified to 1 const std::string leftNumber(tok->tokAt(2)->str()); // get the left parameter const std::string rightNumber(tok->tokAt(4)->str()); // get the right parameter - if (!leftNumber.empty()) { - const bool isLeftNumberNegative = MathLib::isNegative(leftNumber); - const bool isLeftNumberInteger = MathLib::isInt(leftNumber); - const bool isLeftNumberFloat = MathLib::isFloat(leftNumber); - const bool isRightNumberNegative = MathLib::isNegative(rightNumber); - const bool isRightNumberInteger = MathLib::isInt(rightNumber); - const bool isRightNumberFloat = MathLib::isFloat(rightNumber); - const bool isLeftNumberZero = ((!isLeftNumberNegative && isLeftNumberInteger && (MathLib::toLongNumber(leftNumber) == 0L)) // case: integer numbers - || (!isLeftNumberNegative && isLeftNumberFloat && (MathLib::toDoubleNumber(leftNumber)) >= 0.)); // case: float numbers - const bool isLeftNumberOne = ((isLeftNumberNegative && isLeftNumberInteger && (MathLib::toLongNumber(leftNumber) == 1L)) // case: integer numbers - || (!isLeftNumberNegative && isLeftNumberFloat && (MathLib::toDoubleNumber(leftNumber)) >= 1.)); // case: float numbers - const bool isRightNumberZero = ((!isRightNumberNegative && isRightNumberInteger && (MathLib::toLongNumber(rightNumber) == 0L)) // case: integer numbers - || (!isRightNumberNegative && isRightNumberFloat && (MathLib::toDoubleNumber(rightNumber)) >= 0.)); // case: float numbers - + if (!leftNumber.empty() && !rightNumber.empty()) { + const bool isLeftNumberZero = isZeroNumber(leftNumber); + const bool isLeftNumberOne = isOneNumber(leftNumber); + const bool isRightNumberZero = isZeroNumber(rightNumber); if (isLeftNumberZero && !isRightNumberZero && MathLib::isPositive(rightNumber)) { // case: 0^(y) = 0 and y > 0 tok->deleteNext(5); // delete tokens tok->str("0"); // insert simplified result - } - if (isLeftNumberZero && isRightNumberZero) { // case: 0^0 = 1 + } else if (isLeftNumberZero && isRightNumberZero) { // case: 0^0 = 1 tok->deleteNext(5); // delete tokens tok->str("1"); // insert simplified result - } - if (isLeftNumberOne) { // case 1^(y) = 1 + } else if (isLeftNumberOne) { // case 1^(y) = 1 tok->deleteNext(5); // delete tokens tok->str("1"); // insert simplified result } @@ -10154,12 +10184,12 @@ void Tokenizer::simplifyMathExpressions() { for (Token *tok = list.front(); tok; tok = tok->next()) { - if (Token::Match(tok,"exp|cosh|cos ( 0 )") || Token::simpleMatch(tok,"sqrt ( 1 )")) { + if (Token::Match(tok,"cosh|cos ( 0 )")) { tok->deleteNext(3); tok->str("1"); } - if (Token::Match(tok,"sin|sinh|sqrt ( 0 )") || Token::simpleMatch(tok,"ln ( 1 )")) { + if (Token::Match(tok,"sin|sinh ( 0 )") || Token::simpleMatch(tok,"ln ( 1 )")) { tok->deleteNext(3); tok->str("0"); } diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index c9dc10cc9..1066b6deb 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -220,6 +220,19 @@ private: ASSERT_EQUALS_DOUBLE(0.0 , MathLib::toDoubleNumber("-0.0")); ASSERT_EQUALS_DOUBLE(0.0 , MathLib::toDoubleNumber("+0.0")); + // verify: string --> double --> string conversion + ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("1.0f"))); + ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("1.0"))); + ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("0.0f"))); + ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("0.0"))); + ASSERT_EQUALS("-1.0" , MathLib::toString(MathLib::toDoubleNumber("-1.0f"))); + ASSERT_EQUALS("-1.0" , MathLib::toString(MathLib::toDoubleNumber("-1.0"))); + ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("-0.0f"))); + ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("-0.0"))); + ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("+1.0f"))); + ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("+1.0"))); + ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("+0.0f"))); + ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("+0.0"))); } void isint() const { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 49ea80ffc..c43f43313 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8280,6 +8280,137 @@ private: void simplifyMathFunctions() { //#5031 + // verify exp(), expf(), expl() - simplifcation + const char code_exp[] ="void f(int x) {\n" + " std::cout << exp(x);\n" // do not simplify + " std::cout << exp(-1);\n" // do not simplify + " std::cout << exp(0L);\n" // simplify to 0 + " std::cout << exp(1L);\n" // do not simplify + "}"; + const char expected_exp[] = "void f ( int x ) {\n" + "std :: cout << exp ( x ) ;\n" + "std :: cout << exp ( -1 ) ;\n" + "std :: cout << 1 ;\n" + "std :: cout << exp ( 1L ) ;\n" + "}"; + ASSERT_EQUALS(expected_exp, tokenizeAndStringify(code_exp)); + + const char code_expf[] ="void f(float x) {\n" + " std::cout << expf(x);\n" // do not simplify + " std::cout << expf(-1.0);\n" // do not simplify + " std::cout << expf(0.0);\n" // simplify to 0 + " std::cout << expf(1.0);\n" // do not simplify + "}"; + const char expected_expf[] = "void f ( float x ) {\n" + "std :: cout << expf ( x ) ;\n" + "std :: cout << expf ( -1.0 ) ;\n" + "std :: cout << 1 ;\n" + "std :: cout << expf ( 1.0 ) ;\n" + "}"; + ASSERT_EQUALS(expected_expf, tokenizeAndStringify(code_expf)); + + const char code_expl[] ="void f(long double x) {\n" + " std::cout << expl(x);\n" // do not simplify + " std::cout << expl(-1.0);\n" // do not simplify + " std::cout << expl(0.0);\n" // simplify to 0 + " std::cout << expl(1.0);\n" // do not simplify + "}"; + const char expected_expl[] = "void f ( long double x ) {\n" + "std :: cout << expl ( x ) ;\n" + "std :: cout << expl ( -1.0 ) ;\n" + "std :: cout << 1 ;\n" + "std :: cout << expl ( 1.0 ) ;\n" + "}"; + ASSERT_EQUALS(expected_expl, tokenizeAndStringify(code_expl)); + + // verify cbrt(), cbrtf(), cbrtl() - simplifcation + const char code_cbrt[] ="void f(int x) {\n" + " std::cout << cbrt(x);\n" // do not simplify + " std::cout << cbrt(-1);\n" // do not simplify + " std::cout << cbrt(0L);\n" // simplify to 0 + " std::cout << cbrt(1L);\n" // simplify to 1 + "}"; + const char expected_cbrt[] = "void f ( int x ) {\n" + "std :: cout << cbrt ( x ) ;\n" + "std :: cout << cbrt ( -1 ) ;\n" + "std :: cout << 0 ;\n" + "std :: cout << 1 ;\n" + "}"; + ASSERT_EQUALS(expected_cbrt, tokenizeAndStringify(code_cbrt)); + + const char code_cbrtf[] ="void f(float x) {\n" + " std::cout << cbrtf(x);\n" // do not simplify + " std::cout << cbrtf(-1.0f);\n" // do not simplify + " std::cout << cbrtf(0.0f);\n" // simplify to 0 + " std::cout << cbrtf(1.0);\n" // simplify to 1 + "}"; + const char expected_cbrtf[] = "void f ( float x ) {\n" + "std :: cout << cbrtf ( x ) ;\n" + "std :: cout << cbrtf ( -1.0f ) ;\n" + "std :: cout << 0 ;\n" + "std :: cout << 1 ;\n" + "}"; + ASSERT_EQUALS(expected_cbrtf, tokenizeAndStringify(code_cbrtf)); + + const char code_cbrtl[] ="void f(long double x) {\n" + " std::cout << cbrtl(x);\n" // do not simplify + " std::cout << cbrtl(-1.0);\n" // do not simplify + " std::cout << cbrtl(0.0);\n" // simplify to 0 + " std::cout << cbrtl(1.0);\n" // simplify to 1 + "}"; + const char expected_cbrtl[] = "void f ( long double x ) {\n" + "std :: cout << cbrtl ( x ) ;\n" + "std :: cout << cbrtl ( -1.0 ) ;\n" + "std :: cout << 0 ;\n" + "std :: cout << 1 ;\n" + "}"; + ASSERT_EQUALS(expected_cbrtl, tokenizeAndStringify(code_cbrtl)); + + + // verify sqrt(), sqrtf(), sqrtl() - simplifcation + const char code_sqrt[] ="void f(int x) {\n" + " std::cout << sqrt(x);\n" // do not simplify + " std::cout << sqrt(-1);\n" // do not simplify + " std::cout << sqrt(0L);\n" // simplify to 0 + " std::cout << sqrt(1L);\n" // simplify to 1 + "}"; + const char expected_sqrt[] = "void f ( int x ) {\n" + "std :: cout << sqrt ( x ) ;\n" + "std :: cout << sqrt ( -1 ) ;\n" + "std :: cout << 0 ;\n" + "std :: cout << 1 ;\n" + "}"; + ASSERT_EQUALS(expected_sqrt, tokenizeAndStringify(code_sqrt)); + + const char code_sqrtf[] ="void f(float x) {\n" + " std::cout << sqrtf(x);\n" // do not simplify + " std::cout << sqrtf(-1.0f);\n" // do not simplify + " std::cout << sqrtf(0.0f);\n" // simplify to 0 + " std::cout << sqrtf(1.0);\n" // simplify to 1 + "}"; + const char expected_sqrtf[] = "void f ( float x ) {\n" + "std :: cout << sqrtf ( x ) ;\n" + "std :: cout << sqrtf ( -1.0f ) ;\n" + "std :: cout << 0 ;\n" + "std :: cout << 1 ;\n" + "}"; + ASSERT_EQUALS(expected_sqrtf, tokenizeAndStringify(code_sqrtf)); + + const char code_sqrtl[] ="void f(long double x) {\n" + " std::cout << sqrtf(x);\n" // do not simplify + " std::cout << sqrtf(-1.0);\n" // do not simplify + " std::cout << sqrtf(0.0);\n" // simplify to 0 + " std::cout << sqrtf(1.0);\n" // simplify to 1 + "}"; + const char expected_sqrtl[] = "void f ( long double x ) {\n" + "std :: cout << sqrtf ( x ) ;\n" + "std :: cout << sqrtf ( -1.0 ) ;\n" + "std :: cout << 0 ;\n" + "std :: cout << 1 ;\n" + "}"; + ASSERT_EQUALS(expected_sqrtl, tokenizeAndStringify(code_sqrtl)); + + // verify div(), ldiv(), lldiv() - simplifcation const char code_div[] ="void f(int x) {\n" " std::cout << div(x,1);\n" //simplify @@ -8594,9 +8725,6 @@ private: " std::cout<