simplifyMathFunctions: added support for exp(),sqrt(),cbrt() functions.

This commit is contained in:
Martin Ettl 2013-09-29 18:11:17 +02:00
parent c37c6617d3
commit f0cbeb5233
3 changed files with 212 additions and 48 deletions

View File

@ -8268,13 +8268,46 @@ void Tokenizer::cppcheckError(const Token *tok) const
reportError(tok, Severity::error, "cppcheckError",
"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?
// @param s --> a string to check
// @return true in case s is zero and false otherwise.
// ------------------------------------------------------------------------
static bool isZeroNumber(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) == 0L)) // case: integer number
|| (isPositive && isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "0.0")); // case: float number
return isZeroValue;
}
// ------------------------------------------------------------------------
// Helper function to check wether number is one (1,0.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)
{
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) == 1L)) // case: integer number
|| (isPositive && isFloat && MathLib::toString(MathLib::toDoubleNumber(s)) == "1.0")); // case: float number
return isZeroValue;
}
// ------------------------------------------------------
// Simplify math functions.
// It simplifies following functions: atol(), abs(), fabs()
// labs(), llabs(), fmin(), fminl(), fminf(), fmax(), fmaxl()
// fmaxf(), isgreater(), isgreaterequal(), isless()
// islessgreater(), islessequal(), pow(), powf(), powl()
// islessgreater(), islessequal(), pow(), powf(), powl(),
// div(),ldiv(),lldiv(), cbrt(), cbrtl(), cbtrf(), sqrt(),
// sqrtf(), sqrtl(), exp(), expf(), expl()
// in the tokenlist.
//
// Reference:
@ -8313,6 +8346,28 @@ void Tokenizer::simplifyMathFunctions()
}
tok->deleteNext(3); // delete e.g. abs ( 1 )
tok->str(strNumber); // insert result into token list
} else if (Token::Match(tok, "sqrt|sqrtf|sqrtl|cbrt|cbrtf|cbrtl ( %num% )")) {
// Simplify: sqrt(0) = 0 and cbrt(0) == 0
// sqrt(1) = 1 and cbrt(1) == 1
// get number string
const std::string parameter(tok->tokAt(2)->str());
// is parameter 0 ?
if (isZeroNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("0"); // insert result into token list
} else if (isOneNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("1"); // insert result into token list
}
} else if (Token::Match(tok, "exp|expf|expl ( %num% )")) {
// Simplify: exp(0) = 1
// get number string
const std::string parameter(tok->tokAt(2)->str());
// is parameter 0 ?
if (isZeroNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("1"); // insert result into token list
}
} else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) {
// @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));
@ -8404,12 +8459,7 @@ void Tokenizer::simplifyMathFunctions()
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 allowToSimplify = ((!isNegative && isInteger && (MathLib::toLongNumber(rightNumber) == 1L)) // case: integer numbers
|| (!isNegative && isFloat && (MathLib::toDoubleNumber(rightNumber)-1.0) >= 0.)); // case: float numbers
if (allowToSimplify == true) {
if (isOneNumber(rightNumber)) {
tok->deleteNext(5); // delete tokens
tok->str(leftParameter); // insert simplified result
}
@ -8420,51 +8470,31 @@ void Tokenizer::simplifyMathFunctions()
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
if (isOneNumber(rightNumber)) { // case: x^(1) = x
tok->deleteNext(5); // delete tokens
tok->str(leftParameter); // insert simplified result
} else if (rightParameterIsZero) { // case: x^(0) = 1
} else if (isZeroNumber(rightNumber)) { // case: x^(0) = 1
tok->deleteNext(5); // delete tokens
tok->str("1"); // insert simplified result
}
}
}
if (tok && Token::Match(tok->tokAt(2), " %num% , %num% )")) {
} else 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 (!leftNumber.empty() && !rightNumber.empty()) {
const bool isLeftNumberZero = isZeroNumber(leftNumber);
const bool isLeftNumberOne = isOneNumber(leftNumber);
const bool isRightNumberZero = isZeroNumber(rightNumber);
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
} else if (isLeftNumberZero && isRightNumberZero) { // case: 0^0 = 1
tok->deleteNext(5); // delete tokens
tok->str("1"); // insert simplified result
}
if (isLeftNumberOne) { // case 1^(y) = 1
} else if (isLeftNumberOne) { // case 1^(y) = 1
tok->deleteNext(5); // delete tokens
tok->str("1"); // insert simplified result
}
@ -10154,12 +10184,12 @@ void Tokenizer::simplifyMathExpressions()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (Token::Match(tok,"exp|cosh|cos ( 0 )") || Token::simpleMatch(tok,"sqrt ( 1 )")) {
if (Token::Match(tok,"cosh|cos ( 0 )")) {
tok->deleteNext(3);
tok->str("1");
}
if (Token::Match(tok,"sin|sinh|sqrt ( 0 )") || Token::simpleMatch(tok,"ln ( 1 )")) {
if (Token::Match(tok,"sin|sinh ( 0 )") || Token::simpleMatch(tok,"ln ( 1 )")) {
tok->deleteNext(3);
tok->str("0");
}

View File

@ -220,6 +220,19 @@ private:
ASSERT_EQUALS_DOUBLE(0.0 , MathLib::toDoubleNumber("-0.0"));
ASSERT_EQUALS_DOUBLE(0.0 , MathLib::toDoubleNumber("+0.0"));
// verify: string --> double --> string conversion
ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("1.0f")));
ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("1.0")));
ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("0.0f")));
ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("0.0")));
ASSERT_EQUALS("-1.0" , MathLib::toString(MathLib::toDoubleNumber("-1.0f")));
ASSERT_EQUALS("-1.0" , MathLib::toString(MathLib::toDoubleNumber("-1.0")));
ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("-0.0f")));
ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("-0.0")));
ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("+1.0f")));
ASSERT_EQUALS("1.0" , MathLib::toString(MathLib::toDoubleNumber("+1.0")));
ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("+0.0f")));
ASSERT_EQUALS("0.0" , MathLib::toString(MathLib::toDoubleNumber("+0.0")));
}
void isint() const {

View File

@ -8280,6 +8280,137 @@ private:
void simplifyMathFunctions() { //#5031
// verify exp(), expf(), expl() - simplifcation
const char code_exp[] ="void f(int x) {\n"
" std::cout << exp(x);\n" // do not simplify
" std::cout << exp(-1);\n" // do not simplify
" std::cout << exp(0L);\n" // simplify to 0
" std::cout << exp(1L);\n" // do not simplify
"}";
const char expected_exp[] = "void f ( int x ) {\n"
"std :: cout << exp ( x ) ;\n"
"std :: cout << exp ( -1 ) ;\n"
"std :: cout << 1 ;\n"
"std :: cout << exp ( 1L ) ;\n"
"}";
ASSERT_EQUALS(expected_exp, tokenizeAndStringify(code_exp));
const char code_expf[] ="void f(float x) {\n"
" std::cout << expf(x);\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(1.0);\n" // do not simplify
"}";
const char expected_expf[] = "void f ( float x ) {\n"
"std :: cout << expf ( x ) ;\n"
"std :: cout << expf ( -1.0 ) ;\n"
"std :: cout << 1 ;\n"
"std :: cout << expf ( 1.0 ) ;\n"
"}";
ASSERT_EQUALS(expected_expf, tokenizeAndStringify(code_expf));
const char code_expl[] ="void f(long double x) {\n"
" std::cout << expl(x);\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(1.0);\n" // do not simplify
"}";
const char expected_expl[] = "void f ( long double x ) {\n"
"std :: cout << expl ( x ) ;\n"
"std :: cout << expl ( -1.0 ) ;\n"
"std :: cout << 1 ;\n"
"std :: cout << expl ( 1.0 ) ;\n"
"}";
ASSERT_EQUALS(expected_expl, tokenizeAndStringify(code_expl));
// verify cbrt(), cbrtf(), cbrtl() - simplifcation
const char code_cbrt[] ="void f(int x) {\n"
" std::cout << cbrt(x);\n" // do not simplify
" std::cout << cbrt(-1);\n" // do not simplify
" std::cout << cbrt(0L);\n" // simplify to 0
" std::cout << cbrt(1L);\n" // simplify to 1
"}";
const char expected_cbrt[] = "void f ( int x ) {\n"
"std :: cout << cbrt ( x ) ;\n"
"std :: cout << cbrt ( -1 ) ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"}";
ASSERT_EQUALS(expected_cbrt, tokenizeAndStringify(code_cbrt));
const char code_cbrtf[] ="void f(float x) {\n"
" std::cout << cbrtf(x);\n" // do not simplify
" std::cout << cbrtf(-1.0f);\n" // do not simplify
" std::cout << cbrtf(0.0f);\n" // simplify to 0
" std::cout << cbrtf(1.0);\n" // simplify to 1
"}";
const char expected_cbrtf[] = "void f ( float x ) {\n"
"std :: cout << cbrtf ( x ) ;\n"
"std :: cout << cbrtf ( -1.0f ) ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"}";
ASSERT_EQUALS(expected_cbrtf, tokenizeAndStringify(code_cbrtf));
const char code_cbrtl[] ="void f(long double x) {\n"
" std::cout << cbrtl(x);\n" // do not simplify
" std::cout << cbrtl(-1.0);\n" // do not simplify
" std::cout << cbrtl(0.0);\n" // simplify to 0
" std::cout << cbrtl(1.0);\n" // simplify to 1
"}";
const char expected_cbrtl[] = "void f ( long double x ) {\n"
"std :: cout << cbrtl ( x ) ;\n"
"std :: cout << cbrtl ( -1.0 ) ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"}";
ASSERT_EQUALS(expected_cbrtl, tokenizeAndStringify(code_cbrtl));
// verify sqrt(), sqrtf(), sqrtl() - simplifcation
const char code_sqrt[] ="void f(int x) {\n"
" std::cout << sqrt(x);\n" // do not simplify
" std::cout << sqrt(-1);\n" // do not simplify
" std::cout << sqrt(0L);\n" // simplify to 0
" std::cout << sqrt(1L);\n" // simplify to 1
"}";
const char expected_sqrt[] = "void f ( int x ) {\n"
"std :: cout << sqrt ( x ) ;\n"
"std :: cout << sqrt ( -1 ) ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"}";
ASSERT_EQUALS(expected_sqrt, tokenizeAndStringify(code_sqrt));
const char code_sqrtf[] ="void f(float x) {\n"
" std::cout << sqrtf(x);\n" // do not simplify
" std::cout << sqrtf(-1.0f);\n" // do not simplify
" std::cout << sqrtf(0.0f);\n" // simplify to 0
" std::cout << sqrtf(1.0);\n" // simplify to 1
"}";
const char expected_sqrtf[] = "void f ( float x ) {\n"
"std :: cout << sqrtf ( x ) ;\n"
"std :: cout << sqrtf ( -1.0f ) ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"}";
ASSERT_EQUALS(expected_sqrtf, tokenizeAndStringify(code_sqrtf));
const char code_sqrtl[] ="void f(long double x) {\n"
" std::cout << sqrtf(x);\n" // do not simplify
" std::cout << sqrtf(-1.0);\n" // do not simplify
" std::cout << sqrtf(0.0);\n" // simplify to 0
" std::cout << sqrtf(1.0);\n" // simplify to 1
"}";
const char expected_sqrtl[] = "void f ( long double x ) {\n"
"std :: cout << sqrtf ( x ) ;\n"
"std :: cout << sqrtf ( -1.0 ) ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"}";
ASSERT_EQUALS(expected_sqrtl, tokenizeAndStringify(code_sqrtl));
// verify div(), ldiv(), lldiv() - simplifcation
const char code_div[] ="void f(int x) {\n"
" std::cout << div(x,1);\n" //simplify
@ -8594,9 +8725,6 @@ private:
" std::cout<<cos(0);\n"
" std::cout<<sinh(0);\n"
" std::cout<<cosh(0);\n"
" std::cout<<exp(0);\n"
" std::cout<<sqrt(0);\n"
" std::cout<<sqrt(1);\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"
@ -8609,9 +8737,6 @@ private:
"std :: cout << 1 ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << 0 ;\n"
"std :: cout << 1 ;\n"
"std :: cout << -1 ;\n"
@ -8627,10 +8752,6 @@ private:
ASSERT_EQUALS(code2, tokenizeAndStringify(code2));
}
static std::string testAst(const char code[]) {
// tokenize given code..
TokenList tokenList(NULL);