diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index b38df6923..7352b7b63 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -121,6 +121,11 @@ bool MathLib::isNegative(const std::string &s) return (s[n] == '-'); } +bool MathLib::isPositive(const std::string &s) +{ + return !MathLib::isNegative(s); +} + bool MathLib::isOct(const std::string& str) { bool sign = str[0]=='-' || str[0]=='+'; diff --git a/lib/mathlib.h b/lib/mathlib.h index 6e75ebaff..465605954 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -45,6 +45,7 @@ public: static bool isInt(const std::string & str); static bool isFloat(const std::string &str); static bool isNegative(const std::string &str); + static bool isPositive(const std::string &str); static bool isHex(const std::string& str); static bool isOct(const std::string& str); static bool isBin(const std::string& str); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e1051a61c..83d83c948 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8377,10 +8377,9 @@ void Tokenizer::simplifyMathFunctions() tok->deleteNext(5); // delete tokens tok->str((isLessOrGreater == true) ? "true": "false"); // insert results } - } else if (Token::Match(tok, "div|ldiv|lldiv|pow|powf|powl ( %any% , %num% )")) { + } else if (Token::Match(tok, "div|ldiv|lldiv ( %any% , %num% )")) { // Calling the function 'div(x,y)' is the same as calculating (x)/(y). In case y has the value 1 // (the identity element), the call can be simplified to (x). - // In case of pow( anyNumber,1 ): It can be simplified to anynumber. 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()) { @@ -8388,12 +8387,68 @@ void Tokenizer::simplifyMathFunctions() 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 + || (!isNegative && isFloat && (MathLib::toDoubleNumber(rightNumber)-1.0) >= 0.)); // case: float numbers if (allowToSimplify == true) { tok->deleteNext(5); // delete tokens tok->str(leftParameter); // insert simplified result } } + } else if (Token::Match(tok, "pow|powf|powl (")) { + if (tok && Token::Match(tok->tokAt(2), " %any% , %num% )")) { + // In case of pow( x , 1 ): It can be simplified to x. + 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 + tok->deleteNext(5); // delete tokens + tok->str(leftParameter); // insert simplified result + } else if (rightParameterIsZero) { // case: x^(0) = 1 + tok->deleteNext(5); // delete tokens + tok->str("1"); // insert simplified result + } + } + } + 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 (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 + tok->deleteNext(5); // delete tokens + tok->str("1"); // insert simplified result + } + if (isLeftNumberOne) { // case 1^(y) = 1 + tok->deleteNext(5); // delete tokens + tok->str("1"); // insert simplified result + } + } + } } } } diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index 958d394bf..c9dc10cc9 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -34,6 +34,7 @@ private: TEST_CASE(convert); TEST_CASE(isint); TEST_CASE(isnegative); + TEST_CASE(ispositive); TEST_CASE(isfloat); TEST_CASE(isGreater) TEST_CASE(isGreaterEqual) @@ -312,6 +313,20 @@ private: ASSERT_EQUALS(false, MathLib::isNegative("+1.0E-2")); } + void ispositive() const { + ASSERT_EQUALS(false, MathLib::isPositive("-1")); + ASSERT_EQUALS(false, MathLib::isPositive("-1.")); + ASSERT_EQUALS(false, MathLib::isPositive("-1.0")); + ASSERT_EQUALS(false, MathLib::isPositive("-1.0E+2")); + ASSERT_EQUALS(false, MathLib::isPositive("-1.0E-2")); + + ASSERT_EQUALS(true , MathLib::isPositive("+1")); + ASSERT_EQUALS(true , MathLib::isPositive("+1.")); + ASSERT_EQUALS(true , MathLib::isPositive("+1.0")); + ASSERT_EQUALS(true , MathLib::isPositive("+1.0E+2")); + ASSERT_EQUALS(true , MathLib::isPositive("+1.0E-2")); + } + void isfloat() const { ASSERT_EQUALS(false, MathLib::isFloat("0")); ASSERT_EQUALS(true , MathLib::isFloat("0.")); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index a4e916b20..49ea80ffc 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -8346,6 +8346,18 @@ private: const char expected_pow1[] = "int f ( const Fred & fred ) { return fred . pow ( 12 , 3 ) ; }"; ASSERT_EQUALS(expected_pow1, tokenizeAndStringify(code_pow1)); + const char code_pow2[] = "int f() {return pow(0,0);}"; + const char expected_pow2[] = "int f ( ) { return 1 ; }"; + ASSERT_EQUALS(expected_pow2, tokenizeAndStringify(code_pow2)); + + const char code_pow3[] = "int f() {return pow(0,1);}"; + const char expected_pow3[] = "int f ( ) { return 0 ; }"; + ASSERT_EQUALS(expected_pow3, tokenizeAndStringify(code_pow3)); + + const char code_pow4[] = "int f() {return pow(1,0);}"; + const char expected_pow4[] = "int f ( ) { return 1 ; }"; + ASSERT_EQUALS(expected_pow4, tokenizeAndStringify(code_pow4)); + // verify islessgreater() simplification const char code_islessgreater[] = "bool f(){\n" "return islessgreater(1,0);\n" // (1 < 0) or (1 > 0) --> true