diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e6aa35d17..a63f6609d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8291,7 +8291,7 @@ bool Tokenizer::isZeroNumber(const std::string &s) // ------------------------------------------------------------------------ // Helper function to check wether number is one (1 or 0.1E+1 or 1E+0) or not? // @param s --> a string to check -// @return true in case s is zero and false otherwise. +// @return true in case s is one and false otherwise. // ------------------------------------------------------------------------ bool Tokenizer::isOneNumber(const std::string &s) { @@ -8304,6 +8304,22 @@ bool Tokenizer::isOneNumber(const std::string &s) return isZeroValue; } +// ------------------------------------------------------------------------ +// Helper function to check wether number is one (2 or 0.2E+1 or 2E+0) or not? +// @param s --> a string to check +// @return true in case s is two and false otherwise. +// ------------------------------------------------------------------------ +bool Tokenizer::isTwoNumber(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) == 2L)) // case: integer number + || (isPositive && isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "2.0")); // case: float number + + return isZeroValue; +} + // ------------------------------------------------------ // Simplify math functions. // It simplifies following functions: atol(), abs(), fabs() @@ -10232,27 +10248,83 @@ void Tokenizer::simplifyMathExpressions() tok->str("0"); } - //Pythagorean trigonometric identity: pow(sin(x),2)+pow(cos(x),2) = 1 - //Hyperbolic identity: pow(sinh(x),2)-pow(cosh(x),2) = -1 + //simplify Pythagorean trigonometric identity: pow(sin(x),2)+pow(cos(x),2) = 1 + // pow(cos(x),2)+pow(sin(x),2) = 1 + // @todo: sin(x) * sin(x) + cos(x) * cos(x) = 1 + // cos(x) * cos(x) + sin(x) * sin(x) = 1 + //simplify Hyperbolic identity: pow(sinh(x),2)-pow(cosh(x),2) = -1 + // pow(cosh(x),2)-pow(sinh(x),2) = -1 + // @todo: sinh(x) * sinh(x) - cosh(x) * cosh(x) = -1 + // cosh(x) * cosh(x) - sinh(x) * sinh(x) = -1 if (Token::simpleMatch(tok, "pow (")) { if (Token::simpleMatch(tok->tokAt(2), "sin (")) { - Token *tok2 = tok->linkAt(3); - if (!Token::simpleMatch(tok2, ") , 2 ) + pow ( cos (")) + Token * const tok2 = tok->linkAt(3); + if (!Token::Match(tok2, ") , %num% ) + pow ( cos (")) continue; - Token *tok3 = tok2->tokAt(8); - if (!Token::simpleMatch(tok3->link(), ") , 2 )")) + const std::string leftExponent = tok2->tokAt(2)->str(); + if (!isTwoNumber(leftExponent)) + continue; // left exponent is not 2 + Token * const tok3 = tok2->tokAt(8); + if (!Token::Match(tok3->link(), ") , %num% )")) continue; + Token * const tok4 = tok3->link(); + const std::string rightExponent = tok4->tokAt(2)->str(); + if (!isTwoNumber(rightExponent)) + continue; // right exponent is not 2 + if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok3->link()->next())) { + Token::eraseTokens(tok, tok3->link()->tokAt(4)); + tok->str("1"); + } + } else if (Token::simpleMatch(tok->tokAt(2), "cos (")) { + Token * const tok2 = tok->linkAt(3); + if (!Token::Match(tok2, ") , %num% ) + pow ( sin (")) + continue; + const std::string leftExponent = tok2->tokAt(2)->str(); + if (!isTwoNumber(leftExponent)) + continue; // left exponent is not 2 + Token * const tok3 = tok2->tokAt(8); + if (!Token::Match(tok3->link(), ") , %num% )")) + continue; + Token * const tok4 = tok3->link(); + const std::string rightExponent = tok4->tokAt(2)->str(); + if (!isTwoNumber(rightExponent)) + continue; // right exponent is not 2 if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok3->link()->next())) { Token::eraseTokens(tok, tok3->link()->tokAt(4)); tok->str("1"); } } else if (Token::simpleMatch(tok->tokAt(2), "sinh (")) { - Token *tok2 = tok->linkAt(3); - if (!Token::simpleMatch(tok2, ") , 2 ) - pow ( cosh (")) + Token * const tok2 = tok->linkAt(3); + if (!Token::Match(tok2, ") , %num% ) - pow ( cosh (")) continue; - Token *tok3 = tok2->tokAt(8); - if (!Token::simpleMatch(tok3->link(), ") , 2 )")) + const std::string leftExponent = tok2->tokAt(2)->str(); + if (!isTwoNumber(leftExponent)) + continue; // left exponent is not 2 + Token * const tok3 = tok2->tokAt(8); + if (!Token::Match(tok3->link(), ") , %num% )")) continue; + Token * const tok4 = tok3->link(); + const std::string rightExponent = tok4->tokAt(2)->str(); + if (!isTwoNumber(rightExponent)) + continue; // right exponent is not 2 + if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok3->link()->next())) { + Token::eraseTokens(tok, tok3->link()->tokAt(4)); + tok->str("-1"); + } + } else if (Token::simpleMatch(tok->tokAt(2), "cosh (")) { + Token * const tok2 = tok->linkAt(3); + if (!Token::Match(tok2, ") , %num% ) - pow ( sinh (")) + continue; + const std::string leftExponent = tok2->tokAt(2)->str(); + if (!isTwoNumber(leftExponent)) + continue; // left exponent is not 2 + Token * const tok3 = tok2->tokAt(8); + if (!Token::Match(tok3->link(), ") , %num% )")) + continue; + Token * const tok4 = tok3->link(); + const std::string rightExponent = tok4->tokAt(2)->str(); + if (!isTwoNumber(rightExponent)) + continue; // right exponent is not 2 if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok3->link()->next())) { Token::eraseTokens(tok, tok3->link()->tokAt(4)); tok->str("-1"); diff --git a/lib/tokenize.h b/lib/tokenize.h index a59efccd3..af5fe10dd 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -751,17 +751,24 @@ public: /** * Helper function to check wether number is zero (0 or 0.0 or 0E+0) or not? * @param s --> a string to check - * @return true in case s is zero and false otherwise. + * @return true in case is is zero and false otherwise. */ static bool isZeroNumber(const std::string &s); /** * Helper function to check wether number is one (1 or 0.1E+1 or 1E+0) or not? * @param s --> a string to check - * @return true in case s is zero and false otherwise. + * @return true in case is is one and false otherwise. */ static bool isOneNumber(const std::string &s); + /** + * Helper function to check wether number is one (2 or 0.2E+1 or 2E+0) or not? + * @param s --> a string to check + * @return true in case is is two and false otherwise. + */ + static bool isTwoNumber(const std::string &s); + private: /** Disable copy constructor, no implementation */ Tokenizer(const Tokenizer &); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index fb68cd983..2e354b6fb 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -311,6 +311,7 @@ private: TEST_CASE(isZeroNumber); TEST_CASE(isOneNumber); + TEST_CASE(isTwoNumber); TEST_CASE(macrodoublesharp); @@ -8309,6 +8310,20 @@ private: ASSERT_EQUALS(false, Tokenizer::isOneNumber("-0")); } + void isTwoNumber() const { + ASSERT_EQUALS(true, Tokenizer::isTwoNumber("2.0")); + ASSERT_EQUALS(true, Tokenizer::isTwoNumber("+2.0")); + ASSERT_EQUALS(true, Tokenizer::isTwoNumber("2.0e+0")); + ASSERT_EQUALS(true, Tokenizer::isTwoNumber("+2L")); + ASSERT_EQUALS(true, Tokenizer::isTwoNumber("+2")); + ASSERT_EQUALS(true, Tokenizer::isTwoNumber("2")); + ASSERT_EQUALS(true, Tokenizer::isTwoNumber("+2E+0")); + + ASSERT_EQUALS(false, Tokenizer::isTwoNumber("0.0")); + ASSERT_EQUALS(false, Tokenizer::isTwoNumber("+0.0")); + ASSERT_EQUALS(false, Tokenizer::isTwoNumber("-0")); + } + void simplifyMathFunctions() { //#5031 // verify log2(), log2f(), log2l() - simplifcation @@ -8838,9 +8853,21 @@ private: " std::cout<