simplifyMathFunctions: added support for exp(),sqrt(),cbrt() functions.
This commit is contained in:
parent
c37c6617d3
commit
f0cbeb5233
106
lib/tokenize.cpp
106
lib/tokenize.cpp
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue