Tokenizer:simplifyMathExpression: fixed false negatives in simplifying Pythagorean and Hyperbolic identities.

This commit is contained in:
Martin Ettl 2013-10-03 15:41:12 +02:00
parent 59de30823e
commit 548e2f3fbf
3 changed files with 141 additions and 17 deletions

View File

@ -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");

View File

@ -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 &);

View File

@ -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));
}