Tokenizer:simplifyMathExpression: fixed false negatives in simplifying Pythagorean and Hyperbolic identities.
This commit is contained in:
parent
59de30823e
commit
548e2f3fbf
|
@ -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");
|
||||
|
|
|
@ -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 &);
|
||||
|
|
|
@ -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<<cosh(0);\n"
|
||||
" std::cout<<ln(1);\n"
|
||||
" std::cout<<pow(sin(x),2)+pow(cos(x),2);\n"
|
||||
" std::cout<<pow(sinh(x),2)-pow(cosh(x),2);\n"
|
||||
" std::cout<<pow(sin(x),2.0)+pow(cos(x),2.0);\n"
|
||||
" std::cout<<pow(sin(x*y+z),2.0)+pow(cos(x*y+z),2.0);\n"
|
||||
" std::cout<<pow(sin(x*y+z),2)+pow(cos(x*y+z),2);\n"
|
||||
" std::cout<<pow(cos(x),2)+pow(sin(x),2);\n"
|
||||
" std::cout<<pow(cos(x),2.0)+pow(sin(x),2.0);\n"
|
||||
" std::cout<<pow(cos(x*y+z),2.0)+pow(sin(x*y+z),2.0);\n"
|
||||
" std::cout<<pow(cos(x*y+z),2)+pow(sin(x*y+z),2);\n"
|
||||
" std::cout<<pow(sinh(x*y+z),2)-pow(cosh(x*y+z),2);\n"
|
||||
" std::cout<<pow(sinh(x),2)-pow(cosh(x),2);\n"
|
||||
" std::cout<<pow(sinh(x*y+z),2.0)-pow(cosh(x*y+z),2.0);\n"
|
||||
" std::cout<<pow(sinh(x),2.0)-pow(cosh(x),2.0);\n"
|
||||
" std::cout<<pow(cosh(x*y+z),2)-pow(sinh(x*y+z),2);\n"
|
||||
" std::cout<<pow(cosh(x),2)-pow(sinh(x),2);\n"
|
||||
" std::cout<<pow(cosh(x*y+z),2.0)-pow(sinh(x*y+z),2.0);\n"
|
||||
" std::cout<<pow(cosh(x),2.0)-pow(sinh(x),2.0);\n"
|
||||
"}";
|
||||
|
||||
const char expected1[] = "void foo ( ) {\n"
|
||||
|
@ -8850,15 +8877,33 @@ private:
|
|||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << 0 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << 1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"std :: cout << -1 ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected1, tokenizeAndStringify(code1));
|
||||
|
||||
const char code2[] = "void f ( ) {\n"
|
||||
"z = pow ( sin ( x ) , 2 ) + pow ( cos ( y ) , 2 ) ;\n"
|
||||
"t = pow ( sinh ( x ) , 2 ) - pow ( cosh ( y ) , 2 ) ;\n"
|
||||
"a = pow ( sin ( x ) , 2 ) + pow ( cos ( y ) , 2 ) ;\n"
|
||||
"b = pow ( sinh ( x ) , 2 ) - pow ( cosh ( y ) , 2 ) ;\n"
|
||||
"c = pow ( sin ( x ) , 2.0 ) + pow ( cos ( y ) , 2.0 ) ;\n"
|
||||
"d = pow ( sinh ( x ) , 2.0 ) - pow ( cosh ( y ) , 2.0 ) ;\n"
|
||||
"e = pow ( cos ( x ) , 2 ) + pow ( sin ( y ) , 2 ) ;\n"
|
||||
"f = pow ( cosh ( x ) , 2 ) - pow ( sinh ( y ) , 2 ) ;\n"
|
||||
"g = pow ( cos ( x ) , 2.0 ) + pow ( sin ( y ) , 2.0 ) ;\n"
|
||||
"h = pow ( cosh ( x ) , 2.0 ) - pow ( sinh ( y ) , 2.0 ) ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(code2, tokenizeAndStringify(code2));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue