Tokenizer: simplifyMathFunctions: added more simplifications for exp(), exp2() and log2() functions.

This commit is contained in:
Martin Ettl 2013-10-01 20:30:59 +02:00
parent b6d7e797a2
commit fa5ee8fd13
3 changed files with 147 additions and 13 deletions

View File

@ -8272,27 +8272,26 @@ void Tokenizer::cppcheckError(const Token *tok) const
"Analysis failed. If the code is valid then please report this failure."); "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? // Helper function to check wether number is zero (0 or 0.0 or 0E+0) or not?
// @param s --> a string to check // @param s --> a string to check
// @return true in case s is zero and false otherwise. // @return true in case s is zero and false otherwise.
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static bool isZeroNumber(const std::string &s) bool Tokenizer::isZeroNumber(const std::string &s)
{ {
const bool isPositive = MathLib::isPositive(s);
const bool isInteger = MathLib::isInt(s); const bool isInteger = MathLib::isInt(s);
const bool isFloat = MathLib::isFloat(s); const bool isFloat = MathLib::isFloat(s);
const bool isZeroValue = ((isPositive && isInteger && (MathLib::toLongNumber(s) == 0L)) // case: integer number const bool isZeroValue = ((isInteger && (MathLib::toLongNumber(s) == 0L)) // case: integer number
|| (isPositive && isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "0.0")); // case: float number || (isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "0.0")); // case: float number
return isZeroValue; return isZeroValue;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Helper function to check wether number is one (1,0.1 or 1E+0) or not? // Helper function to check wether number is one (1 or 0.1E+1 or 1E+0) or not?
// @param s --> a string to check // @param s --> a string to check
// @return true in case s is zero and false otherwise. // @return true in case s is zero and false otherwise.
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static bool isOneNumber(const std::string &s) bool Tokenizer::isOneNumber(const std::string &s)
{ {
const bool isPositive = MathLib::isPositive(s); const bool isPositive = MathLib::isPositive(s);
const bool isInteger = MathLib::isInt(s); const bool isInteger = MathLib::isInt(s);
@ -8310,7 +8309,8 @@ static bool isOneNumber(const std::string &s)
// fmaxf(), isgreater(), isgreaterequal(), isless() // fmaxf(), isgreater(), isgreaterequal(), isless()
// islessgreater(), islessequal(), pow(), powf(), powl(), // islessgreater(), islessequal(), pow(), powf(), powl(),
// div(),ldiv(),lldiv(), cbrt(), cbrtl(), cbtrf(), sqrt(), // div(),ldiv(),lldiv(), cbrt(), cbrtl(), cbtrf(), sqrt(),
// sqrtf(), sqrtl(), exp(), expf(), expl() // sqrtf(), sqrtl(), exp(), expf(), expl(), exp2(),
// exp2f(), exp2l(), log2(), log2f(), log2l()
// in the tokenlist. // in the tokenlist.
// //
// Reference: // Reference:
@ -8362,8 +8362,8 @@ void Tokenizer::simplifyMathFunctions()
tok->deleteNext(3); // delete tokens tok->deleteNext(3); // delete tokens
tok->str("1"); // insert result into token list tok->str("1"); // insert result into token list
} }
} else if (Token::Match(tok, "exp|expf|expl ( %num% )")) { } else if (Token::Match(tok, "exp|expf|expl|exp2|exp2f|exp2l ( %num% )")) {
// Simplify: exp(0) = 1 // Simplify: exp[f|l](0) = 1 and exp2[f|l](0) = 1
// get number string // get number string
const std::string parameter(tok->tokAt(2)->str()); const std::string parameter(tok->tokAt(2)->str());
// is parameter 0 ? // is parameter 0 ?
@ -8371,6 +8371,15 @@ void Tokenizer::simplifyMathFunctions()
tok->deleteNext(3); // delete tokens tok->deleteNext(3); // delete tokens
tok->str("1"); // insert result into token list tok->str("1"); // insert result into token list
} }
} else if (Token::Match(tok, "log2|log2f|log2l ( %num% )")) {
// Simplify: log2[f|l](1) = 0
// get number string
const std::string parameter(tok->tokAt(2)->str());
// is parameter 0 ?
if (isOneNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("0"); // insert result into token list
}
} else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) { } else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) {
// @todo if one of the parameters is NaN the other is returned // @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)); // e.g. printf ("fmin (NaN, -1.0) = %f\n", fmin(NaN,-1.0));

View File

@ -748,6 +748,20 @@ public:
*/ */
static Token *copyTokens(Token *dest, const Token *first, const Token *last, bool one_line = true); static Token *copyTokens(Token *dest, const Token *first, const Token *last, bool one_line = true);
/**
* 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.
*/
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.
*/
static bool isOneNumber(const std::string &s);
private: private:
/** Disable copy constructor, no implementation */ /** Disable copy constructor, no implementation */
Tokenizer(const Tokenizer &); Tokenizer(const Tokenizer &);

View File

@ -309,6 +309,9 @@ private:
TEST_CASE(doublesharp); TEST_CASE(doublesharp);
TEST_CASE(isZeroNumber);
TEST_CASE(isOneNumber);
TEST_CASE(macrodoublesharp); TEST_CASE(macrodoublesharp);
TEST_CASE(simplifyFunctionParameters); TEST_CASE(simplifyFunctionParameters);
@ -8278,13 +8281,121 @@ private:
ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, true, Settings::Win32W)); ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, true, Settings::Win32W));
} }
void isZeroNumber() const {
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("0.0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0.0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0.0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0L"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0E+0"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("1.0"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("+1.0"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("-1"));
}
void isOneNumber() const {
ASSERT_EQUALS(true, Tokenizer::isOneNumber("1.0"));
ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1.0"));
ASSERT_EQUALS(true, Tokenizer::isOneNumber("1.0e+0"));
ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1L"));
ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1"));
ASSERT_EQUALS(true, Tokenizer::isOneNumber("1"));
ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1E+0"));
ASSERT_EQUALS(false, Tokenizer::isOneNumber("0.0"));
ASSERT_EQUALS(false, Tokenizer::isOneNumber("+0.0"));
ASSERT_EQUALS(false, Tokenizer::isOneNumber("-0"));
}
void simplifyMathFunctions() { //#5031 void simplifyMathFunctions() { //#5031
// verify log2(), log2f(), log2l() - simplifcation
const char code_log2[] ="void f(int x) {\n"
" std::cout << log2(x);\n" // do not simplify
" std::cout << log2(10);\n" // do not simplify
" std::cout << log2(1L);\n" // simplify to 0
"}";
const char expected_log2[] = "void f ( int x ) {\n"
"std :: cout << log2 ( x ) ;\n"
"std :: cout << log2 ( 10 ) ;\n"
"std :: cout << 0 ;\n"
"}";
ASSERT_EQUALS(expected_log2, tokenizeAndStringify(code_log2));
const char code_log2f[] ="void f(float x) {\n"
" std::cout << log2f(x);\n" // do not simplify
" std::cout << log2f(10);\n" // do not simplify
" std::cout << log2f(1.0f);\n" // simplify to 0
"}";
const char expected_log2f[] = "void f ( float x ) {\n"
"std :: cout << log2f ( x ) ;\n"
"std :: cout << log2f ( 10 ) ;\n"
"std :: cout << 0 ;\n"
"}";
ASSERT_EQUALS(expected_log2f, tokenizeAndStringify(code_log2f));
const char code_log2l[] ="void f(long double x) {\n"
" std::cout << log2l(x);\n" // do not simplify
" std::cout << log2l(10.0d);\n" // do not simplify
" std::cout << log2l(1.0d);\n" // simplify to 0
"}";
const char expected_log2l[] = "void f ( long double x ) {\n"
"std :: cout << log2l ( x ) ;\n"
"std :: cout << log2l ( 10.0d ) ;\n"
"std :: cout << 0 ;\n"
"}";
ASSERT_EQUALS(expected_log2l, tokenizeAndStringify(code_log2l));
// verify exp2(), exp2f(), exp2l() - simplifcation
const char code_exp2[] ="void f(int x) {\n"
" std::cout << exp2(x);\n" // do not simplify
" std::cout << exp2(-1);\n" // do not simplify
" std::cout << exp2(0L);\n" // simplify to 0
" std::cout << exp2(1L);\n" // do not simplify
"}";
const char expected_exp2[] = "void f ( int x ) {\n"
"std :: cout << exp2 ( x ) ;\n"
"std :: cout << exp2 ( -1 ) ;\n"
"std :: cout << 1 ;\n"
"std :: cout << exp2 ( 1L ) ;\n"
"}";
ASSERT_EQUALS(expected_exp2, tokenizeAndStringify(code_exp2));
const char code_exp2f[] ="void f(float x) {\n"
" std::cout << exp2f(x);\n" // do not simplify
" std::cout << exp2f(-1.0);\n" // do not simplify
" std::cout << exp2f(0.0);\n" // simplify to 1
" std::cout << exp2f(1.0);\n" // do not simplify
"}";
const char expected_exp2f[] = "void f ( float x ) {\n"
"std :: cout << exp2f ( x ) ;\n"
"std :: cout << exp2f ( -1.0 ) ;\n"
"std :: cout << 1 ;\n"
"std :: cout << exp2f ( 1.0 ) ;\n"
"}";
ASSERT_EQUALS(expected_exp2f, tokenizeAndStringify(code_exp2f));
const char code_exp2l[] ="void f(long double x) {\n"
" std::cout << exp2l(x);\n" // do not simplify
" std::cout << exp2l(-1.0);\n" // do not simplify
" std::cout << exp2l(0.0);\n" // simplify to 1
" std::cout << exp2l(1.0);\n" // do not simplify
"}";
const char expected_exp2l[] = "void f ( long double x ) {\n"
"std :: cout << exp2l ( x ) ;\n"
"std :: cout << exp2l ( -1.0 ) ;\n"
"std :: cout << 1 ;\n"
"std :: cout << exp2l ( 1.0 ) ;\n"
"}";
ASSERT_EQUALS(expected_exp2l, tokenizeAndStringify(code_exp2l));
// verify exp(), expf(), expl() - simplifcation // verify exp(), expf(), expl() - simplifcation
const char code_exp[] ="void f(int x) {\n" const char code_exp[] ="void f(int x) {\n"
" std::cout << exp(x);\n" // do not simplify " std::cout << exp(x);\n" // do not simplify
" std::cout << exp(-1);\n" // do not simplify " std::cout << exp(-1);\n" // do not simplify
" std::cout << exp(0L);\n" // simplify to 0 " std::cout << exp(0L);\n" // simplify to 1
" std::cout << exp(1L);\n" // do not simplify " std::cout << exp(1L);\n" // do not simplify
"}"; "}";
const char expected_exp[] = "void f ( int x ) {\n" const char expected_exp[] = "void f ( int x ) {\n"
@ -8298,7 +8409,7 @@ private:
const char code_expf[] ="void f(float x) {\n" const char code_expf[] ="void f(float x) {\n"
" std::cout << expf(x);\n" // do not simplify " std::cout << expf(x);\n" // do not simplify
" std::cout << expf(-1.0);\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(0.0);\n" // simplify to 1
" std::cout << expf(1.0);\n" // do not simplify " std::cout << expf(1.0);\n" // do not simplify
"}"; "}";
const char expected_expf[] = "void f ( float x ) {\n" const char expected_expf[] = "void f ( float x ) {\n"
@ -8312,7 +8423,7 @@ private:
const char code_expl[] ="void f(long double x) {\n" const char code_expl[] ="void f(long double x) {\n"
" std::cout << expl(x);\n" // do not simplify " std::cout << expl(x);\n" // do not simplify
" std::cout << expl(-1.0);\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(0.0);\n" // simplify to 1
" std::cout << expl(1.0);\n" // do not simplify " std::cout << expl(1.0);\n" // do not simplify
"}"; "}";
const char expected_expl[] = "void f ( long double x ) {\n" const char expected_expl[] = "void f ( long double x ) {\n"