Add checks of log2 and log1p range (#1324)

* Add tests for log10{,f,l} valid arguments

* Add log2{,f,l} to checkfunctions

* Add log1p{,f,l} to checkfunctions

* checkfunctions: Simplify check for log function limit out of range

The conditions for negative and non-negative int and float were
identical so the call to isNegative can be removed and the if-statements
be simplified.
This commit is contained in:
rikardfalkeborn 2018-08-03 12:14:39 +02:00 committed by Daniel Marjamäki
parent c9b91c24dc
commit 710d7ce015
2 changed files with 154 additions and 31 deletions

View File

@ -226,20 +226,17 @@ void CheckFunctions::checkMathFunctions()
continue;
if (printWarnings && Token::Match(tok, "%name% ( !!)")) {
if (tok->strAt(-1) != "."
&& Token::Match(tok, "log|logf|logl|log10|log10f|log10l ( %num% )")) {
&& Token::Match(tok, "log|logf|logl|log10|log10f|log10l|log2|log2f|log2l ( %num% )")) {
const std::string& number = tok->strAt(2);
const bool isNegative = MathLib::isNegative(number);
const bool isInt = MathLib::isInt(number);
const bool isFloat = MathLib::isFloat(number);
if (isNegative && isInt && MathLib::toLongNumber(number) <= 0) {
mathfunctionCallWarning(tok); // case log(-2)
} else if (isNegative && isFloat && MathLib::toDoubleNumber(number) <= 0.) {
mathfunctionCallWarning(tok); // case log(-2.0)
} else if (!isNegative && isFloat && MathLib::toDoubleNumber(number) <= 0.) {
mathfunctionCallWarning(tok); // case log(0.0)
} else if (!isNegative && isInt && MathLib::toLongNumber(number) <= 0) {
mathfunctionCallWarning(tok); // case log(0)
}
if ((MathLib::isInt(number) && MathLib::toLongNumber(number) <= 0) ||
(MathLib::isFloat(number) && MathLib::toDoubleNumber(number) <= 0.))
mathfunctionCallWarning(tok);
}
else if (Token::Match(tok, "log1p|log1pf|log1pl ( %num% )")) {
const std::string& number = tok->strAt(2);
if ((MathLib::isInt(number) && MathLib::toLongNumber(number) <= -1) ||
(MathLib::isFloat(number) && MathLib::toDoubleNumber(number) <= -1.))
mathfunctionCallWarning(tok);
}
// atan2 ( x , y): x and y can not be zero, because this is mathematically not defined
else if (Token::Match(tok, "atan2|atan2f|atan2l ( %num% , %num% )")) {

View File

@ -478,71 +478,197 @@ private:
}
void mathfunctionCall_log() {
// log,log10,logf,logl,log10f,log10l
// log,log10,logf,logl,log10f,log10l,log2,log2f,log2l,log1p,log1pf,log1pl
check("void foo()\n"
"{\n"
" std::cout << log(-2) << std::endl;\n"
" std::cout << logf(-2) << std::endl;\n"
" std::cout << logl(-2) << std::endl;\n"
" std::cout << log10(-2) << std::endl;\n"
" std::cout << log10f(-2) << std::endl;\n"
" std::cout << log10l(-2) << std::endl;\n"
" std::cout << log2(-2) << std::endl;\n"
" std::cout << log2f(-2) << std::endl;\n"
" std::cout << log2l(-2) << std::endl;\n"
" std::cout << log1p(-3) << std::endl;\n"
" std::cout << log1pf(-3) << std::endl;\n"
" std::cout << log1pl(-3) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -2 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (warning) Passing value -2 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (warning) Passing value -2 to logl() leads to implementation-defined result.\n", errout.str());
"[test.cpp:5]: (warning) Passing value -2 to logl() leads to implementation-defined result.\n"
"[test.cpp:6]: (warning) Passing value -2 to log10() leads to implementation-defined result.\n"
"[test.cpp:7]: (warning) Passing value -2 to log10f() leads to implementation-defined result.\n"
"[test.cpp:8]: (warning) Passing value -2 to log10l() leads to implementation-defined result.\n"
"[test.cpp:9]: (warning) Passing value -2 to log2() leads to implementation-defined result.\n"
"[test.cpp:10]: (warning) Passing value -2 to log2f() leads to implementation-defined result.\n"
"[test.cpp:11]: (warning) Passing value -2 to log2l() leads to implementation-defined result.\n"
"[test.cpp:12]: (warning) Passing value -3 to log1p() leads to implementation-defined result.\n"
"[test.cpp:13]: (warning) Passing value -3 to log1pf() leads to implementation-defined result.\n"
"[test.cpp:14]: (warning) Passing value -3 to log1pl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(-1) << std::endl;\n"
" std::cout << logf(-1) << std::endl;\n"
" std::cout << logl(-1) << std::endl;\n"
" std::cout << log10(-1) << std::endl;\n"
" std::cout << log10f(-1) << std::endl;\n"
" std::cout << log10l(-1) << std::endl;\n"
" std::cout << log2(-1) << std::endl;\n"
" std::cout << log2f(-1) << std::endl;\n"
" std::cout << log2l(-1) << std::endl;\n"
" std::cout << log1p(-2) << std::endl;\n"
" std::cout << log1pf(-2) << std::endl;\n"
" std::cout << log1pl(-2) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (warning) Passing value -1 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (warning) Passing value -1 to logl() leads to implementation-defined result.\n", errout.str());
"[test.cpp:5]: (warning) Passing value -1 to logl() leads to implementation-defined result.\n"
"[test.cpp:6]: (warning) Passing value -1 to log10() leads to implementation-defined result.\n"
"[test.cpp:7]: (warning) Passing value -1 to log10f() leads to implementation-defined result.\n"
"[test.cpp:8]: (warning) Passing value -1 to log10l() leads to implementation-defined result.\n"
"[test.cpp:9]: (warning) Passing value -1 to log2() leads to implementation-defined result.\n"
"[test.cpp:10]: (warning) Passing value -1 to log2f() leads to implementation-defined result.\n"
"[test.cpp:11]: (warning) Passing value -1 to log2l() leads to implementation-defined result.\n"
"[test.cpp:12]: (warning) Passing value -2 to log1p() leads to implementation-defined result.\n"
"[test.cpp:13]: (warning) Passing value -2 to log1pf() leads to implementation-defined result.\n"
"[test.cpp:14]: (warning) Passing value -2 to log1pl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(-1.0) << std::endl;\n"
" std::cout << logf(-1.0) << std::endl;\n"
" std::cout << logl(-1.0) << std::endl;\n"
" std::cout << log10(-1.0) << std::endl;\n"
" std::cout << log10f(-1.0) << std::endl;\n"
" std::cout << log10l(-1.0) << std::endl;\n"
" std::cout << log2(-1.0) << std::endl;\n"
" std::cout << log2f(-1.0) << std::endl;\n"
" std::cout << log2l(-1.0) << std::endl;\n"
" std::cout << log1p(-2.0) << std::endl;\n"
" std::cout << log1pf(-2.0) << std::endl;\n"
" std::cout << log1pl(-2.0) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -1.0 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (warning) Passing value -1.0 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (warning) Passing value -1.0 to logl() leads to implementation-defined result.\n", errout.str());
"[test.cpp:5]: (warning) Passing value -1.0 to logl() leads to implementation-defined result.\n"
"[test.cpp:6]: (warning) Passing value -1.0 to log10() leads to implementation-defined result.\n"
"[test.cpp:7]: (warning) Passing value -1.0 to log10f() leads to implementation-defined result.\n"
"[test.cpp:8]: (warning) Passing value -1.0 to log10l() leads to implementation-defined result.\n"
"[test.cpp:9]: (warning) Passing value -1.0 to log2() leads to implementation-defined result.\n"
"[test.cpp:10]: (warning) Passing value -1.0 to log2f() leads to implementation-defined result.\n"
"[test.cpp:11]: (warning) Passing value -1.0 to log2l() leads to implementation-defined result.\n"
"[test.cpp:12]: (warning) Passing value -2.0 to log1p() leads to implementation-defined result.\n"
"[test.cpp:13]: (warning) Passing value -2.0 to log1pf() leads to implementation-defined result.\n"
"[test.cpp:14]: (warning) Passing value -2.0 to log1pl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(-0.1) << std::endl;\n"
" std::cout << logf(-0.1) << std::endl;\n"
" std::cout << logl(-0.1) << std::endl;\n"
" std::cout << log10(-0.1) << std::endl;\n"
" std::cout << log10f(-0.1) << std::endl;\n"
" std::cout << log10l(-0.1) << std::endl;\n"
" std::cout << log2(-0.1) << std::endl;\n"
" std::cout << log2f(-0.1) << std::endl;\n"
" std::cout << log2l(-0.1) << std::endl;\n"
" std::cout << log1p(-1.1) << std::endl;\n"
" std::cout << log1pf(-1.1) << std::endl;\n"
" std::cout << log1pl(-1.1) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value -0.1 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (warning) Passing value -0.1 to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (warning) Passing value -0.1 to logl() leads to implementation-defined result.\n", errout.str());
"[test.cpp:5]: (warning) Passing value -0.1 to logl() leads to implementation-defined result.\n"
"[test.cpp:6]: (warning) Passing value -0.1 to log10() leads to implementation-defined result.\n"
"[test.cpp:7]: (warning) Passing value -0.1 to log10f() leads to implementation-defined result.\n"
"[test.cpp:8]: (warning) Passing value -0.1 to log10l() leads to implementation-defined result.\n"
"[test.cpp:9]: (warning) Passing value -0.1 to log2() leads to implementation-defined result.\n"
"[test.cpp:10]: (warning) Passing value -0.1 to log2f() leads to implementation-defined result.\n"
"[test.cpp:11]: (warning) Passing value -0.1 to log2l() leads to implementation-defined result.\n"
"[test.cpp:12]: (warning) Passing value -1.1 to log1p() leads to implementation-defined result.\n"
"[test.cpp:13]: (warning) Passing value -1.1 to log1pf() leads to implementation-defined result.\n"
"[test.cpp:14]: (warning) Passing value -1.1 to log1pl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(0) << std::endl;\n"
" std::cout << logf(0.) << std::endl;\n"
" std::cout << logl(0.0) << std::endl;\n"
" std::cout << log10(0.0) << std::endl;\n"
" std::cout << log10f(0) << std::endl;\n"
" std::cout << log10l(0.) << std::endl;\n"
" std::cout << log2(0.) << std::endl;\n"
" std::cout << log2f(0.0) << std::endl;\n"
" std::cout << log2l(0) << std::endl;\n"
" std::cout << log1p(-1.) << std::endl;\n"
" std::cout << log1pf(-1.0) << std::endl;\n"
" std::cout << log1pl(-1) << std::endl;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (warning) Passing value 0 to log() leads to implementation-defined result.\n"
"[test.cpp:4]: (warning) Passing value 0. to logf() leads to implementation-defined result.\n"
"[test.cpp:5]: (warning) Passing value 0.0 to logl() leads to implementation-defined result.\n", errout.str());
"[test.cpp:5]: (warning) Passing value 0.0 to logl() leads to implementation-defined result.\n"
"[test.cpp:6]: (warning) Passing value 0.0 to log10() leads to implementation-defined result.\n"
"[test.cpp:7]: (warning) Passing value 0 to log10f() leads to implementation-defined result.\n"
"[test.cpp:8]: (warning) Passing value 0. to log10l() leads to implementation-defined result.\n"
"[test.cpp:9]: (warning) Passing value 0. to log2() leads to implementation-defined result.\n"
"[test.cpp:10]: (warning) Passing value 0.0 to log2f() leads to implementation-defined result.\n"
"[test.cpp:11]: (warning) Passing value 0 to log2l() leads to implementation-defined result.\n"
"[test.cpp:12]: (warning) Passing value -1. to log1p() leads to implementation-defined result.\n"
"[test.cpp:13]: (warning) Passing value -1.0 to log1pf() leads to implementation-defined result.\n"
"[test.cpp:14]: (warning) Passing value -1 to log1pl() leads to implementation-defined result.\n", errout.str());
check("void foo()\n"
"{\n"
" std::cout << log(1E-3) << std::endl;\n"
" std::cout << logf(1E-3) << std::endl;\n"
" std::cout << logl(1E-3) << std::endl;\n"
" std::cout << log(1.0E-3) << std::endl;\n"
" std::cout << logf(1.0E-3) << std::endl;\n"
" std::cout << logl(1.0E-3) << std::endl;\n"
" std::cout << log(1.0E+3) << std::endl;\n"
" std::cout << logf(1.0E+3) << std::endl;\n"
" std::cout << logl(1.0E+3) << std::endl;\n"
" std::cout << log(2.0) << std::endl;\n"
" std::cout << logf(2.0) << std::endl;\n"
" std::cout << logf(2.0f) << std::endl;\n"
" std::cout << log(1E-3) << std::endl;\n"
" std::cout << logf(1E-3) << std::endl;\n"
" std::cout << logl(1E-3) << std::endl;\n"
" std::cout << log10(1E-3) << std::endl;\n"
" std::cout << log10f(1E-3) << std::endl;\n"
" std::cout << log10l(1E-3) << std::endl;\n"
" std::cout << log2(1E-3) << std::endl;\n"
" std::cout << log2f(1E-3) << std::endl;\n"
" std::cout << log2l(1E-3) << std::endl;\n"
" std::cout << log1p(-1+1E-3) << std::endl;\n"
" std::cout << log1pf(-1+1E-3) << std::endl;\n"
" std::cout << log1pl(-1+1E-3) << std::endl;\n"
" std::cout << log(1.0E-3) << std::endl;\n"
" std::cout << logf(1.0E-3) << std::endl;\n"
" std::cout << logl(1.0E-3) << std::endl;\n"
" std::cout << log10(1.0E-3) << std::endl;\n"
" std::cout << log10f(1.0E-3) << std::endl;\n"
" std::cout << log10l(1.0E-3) << std::endl;\n"
" std::cout << log2(1.0E-3) << std::endl;\n"
" std::cout << log2f(1.0E-3) << std::endl;\n"
" std::cout << log2l(1.0E-3) << std::endl;\n"
" std::cout << log1p(-1+1.0E-3) << std::endl;\n"
" std::cout << log1pf(-1+1.0E-3) << std::endl;\n"
" std::cout << log1pl(-1+1.0E-3) << std::endl;\n"
" std::cout << log(1.0E+3) << std::endl;\n"
" std::cout << logf(1.0E+3) << std::endl;\n"
" std::cout << logl(1.0E+3) << std::endl;\n"
" std::cout << log10(1.0E+3) << std::endl;\n"
" std::cout << log10f(1.0E+3) << std::endl;\n"
" std::cout << log10l(1.0E+3) << std::endl;\n"
" std::cout << log2(1.0E+3) << std::endl;\n"
" std::cout << log2f(1.0E+3) << std::endl;\n"
" std::cout << log2l(1.0E+3) << std::endl;\n"
" std::cout << log1p(1.0E+3) << std::endl;\n"
" std::cout << log1pf(1.0E+3) << std::endl;\n"
" std::cout << log1pl(1.0E+3) << std::endl;\n"
" std::cout << log(2.0) << std::endl;\n"
" std::cout << logf(2.0) << std::endl;\n"
" std::cout << logf(2.0f) << std::endl;\n"
" std::cout << log10(2.0) << std::endl;\n"
" std::cout << log10f(2.0) << std::endl;\n"
" std::cout << log10f(2.0f) << std::endl;\n"
" std::cout << log2(2.0) << std::endl;\n"
" std::cout << log2f(2.0) << std::endl;\n"
" std::cout << log2f(2.0f) << std::endl;\n"
" std::cout << log1p(2.0) << std::endl;\n"
" std::cout << log1pf(2.0) << std::endl;\n"
" std::cout << log1pf(2.0f) << std::endl;\n"
"}");
ASSERT_EQUALS("", errout.str());