Bugfix for Bulkmode: Expressions with like "a=b, b*10" did not compute properly.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2015-03-31 16:08:44 +03:00
parent 99bb3f8962
commit aef39533c8
4 changed files with 114 additions and 12 deletions

View File

@ -1044,9 +1044,18 @@ qreal QmuParserBase::ParseCmdCodeBulk(int nOffset, int nThreadID) const
#endif #endif
continue; continue;
case cmASSIGN: case cmASSIGN:
// Bugfix for Bulkmode:
// for details see:
// https://groups.google.com/forum/embed/?place=forum/muparser-dev&showsearch=true&showpopout=true&
// showtabs=false&parenturl=http://muparser.beltoforion.de/mup_forum.html&afterlogin&pli=1#!topic/
// muparser-dev/szgatgoHTws
--sidx; --sidx;
Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1]; Stack[sidx] = *(pTok->Oprt.ptr + nOffset) = Stack[sidx + 1];
continue; continue;
// original code:
//--sidx;
//Stack[sidx] = *pTok->Oprt.ptr = Stack[sidx+1];
//continue;
case cmIF: case cmIF:
if (qFuzzyCompare(Stack[sidx--]+1, 1+0)) if (qFuzzyCompare(Stack[sidx--]+1, 1+0))
{ {

View File

@ -392,7 +392,7 @@ void QmuParserByteCode::AddAssignOp(qreal *a_pVar)
SToken tok; SToken tok;
tok.Cmd = cmASSIGN; tok.Cmd = cmASSIGN;
tok.Val.ptr = a_pVar; tok.Oprt.ptr = a_pVar;
m_vRPN.push_back(tok); m_vRPN.push_back(tok);
} }

View File

@ -56,6 +56,7 @@ QmuParserTester::QmuParserTester()
AddTest ( &QmuParserTester::TestBinOprt ); AddTest ( &QmuParserTester::TestBinOprt );
AddTest ( &QmuParserTester::TestException ); AddTest ( &QmuParserTester::TestException );
AddTest ( &QmuParserTester::TestStrArg ); AddTest ( &QmuParserTester::TestStrArg );
AddTest ( &QmuParserTester::TestBulkMode );
QmuParserTester::c_iCount = 0; QmuParserTester::c_iCount = 0;
} }
@ -164,6 +165,44 @@ int QmuParserTester::TestStrArg()
return iStat; return iStat;
} }
//---------------------------------------------------------------------------------------------------------------------
int QmuParserTester::TestBulkMode()
{
int iStat = 0;
qWarning() << "testing bulkmode...";
#define EQN_TEST_BULK(EXPR, R1, R2, R3, R4, PASS) \
{ \
double res[] = { R1, R2, R3, R4 }; \
iStat += EqnTestBulk(EXPR, res, (PASS)); \
}
// Bulk Variables for the test:
// a: 1,2,3,4
// b: 2,2,2,2
// c: 3,3,3,3
// d: 5,4,3,2
EQN_TEST_BULK("a", 1, 1, 1, 1, false)
EQN_TEST_BULK("a", 1, 2, 3, 4, true)
EQN_TEST_BULK("b=a", 1, 2, 3, 4, true)
EQN_TEST_BULK("b=a, b*10", 10, 20, 30, 40, true)
EQN_TEST_BULK("b=a, b*10, a", 1, 2, 3, 4, true)
EQN_TEST_BULK("a+b", 3, 4, 5, 6, true)
EQN_TEST_BULK("c*(a+b)", 9, 12, 15, 18, true)
#undef EQN_TEST_BULK
if (iStat == 0)
{
qWarning() << "passed";
}
else
{
qWarning() << "\n failed with " << iStat << " errors";
}
return iStat;
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
int QmuParserTester::TestBinOprt() int QmuParserTester::TestBinOprt()
{ {
@ -172,16 +211,7 @@ int QmuParserTester::TestBinOprt()
// built in operators // built in operators
// xor operator // xor operator
//iStat += EqnTest("1 xor 2", 3, true);
//iStat += EqnTest("a xor b", 3, true); // with a=1 and b=2
//iStat += EqnTest("1 xor 2 xor 3", 0, true);
//iStat += EqnTest("a xor b xor 3", 0, true); // with a=1 and b=2
//iStat += EqnTest("a xor b xor c", 0, true); // with a=1 and b=2
//iStat += EqnTest("(1 xor 2) xor 3", 0, true);
//iStat += EqnTest("(a xor b) xor c", 0, true); // with a=1 and b=2
//iStat += EqnTest("(a) xor (b) xor c", 0, true); // with a=1 and b=2
//iStat += EqnTest("1 or 2"), 3, true;
//iStat += EqnTest("a or b"), 3, true; // with a=1 and b=2
iStat += EqnTest ( "a++b", 3, true ); iStat += EqnTest ( "a++b", 3, true );
iStat += EqnTest ( "a ++ b", 3, true ); iStat += EqnTest ( "a ++ b", 3, true );
iStat += EqnTest ( "1++2", 3, true ); iStat += EqnTest ( "1++2", 3, true );
@ -220,6 +250,7 @@ int QmuParserTester::TestBinOprt()
iStat += EqnTest ( "2*(a=b)", 4, true ); iStat += EqnTest ( "2*(a=b)", 4, true );
iStat += EqnTest ( "2*(a=b+1)", 6, true ); iStat += EqnTest ( "2*(a=b+1)", 6, true );
iStat += EqnTest ( "(a=b+1)*2", 6, true ); iStat += EqnTest ( "(a=b+1)*2", 6, true );
iStat += EqnTest ( "a=c, a*10", 30, true);
iStat += EqnTest ( "2^2^3", 256, true ); iStat += EqnTest ( "2^2^3", 256, true );
iStat += EqnTest ( "1/2/3", 1.0 / 6.0, true ); iStat += EqnTest ( "1/2/3", 1.0 / 6.0, true );
@ -1406,6 +1437,63 @@ int QmuParserTester::EqnTest ( const QString &a_str, double a_fRes, bool a_fPass
return iRet; return iRet;
} }
//---------------------------------------------------------------------------------------------------------------------
/** \brief Test an expression in Bulk Mode. */
int QmuParserTester::EqnTestBulk(const QString &a_str, double a_fRes[4], bool a_fPass)
{
QmuParserTester::c_iCount++;
// Define Bulk Variables
int nBulkSize = 4;
double vVariableA[] = { 1, 2, 3, 4 }; // variable values
double vVariableB[] = { 2, 2, 2, 2 }; // variable values
double vVariableC[] = { 3, 3, 3, 3 }; // variable values
double vResults[] = { 0, 0, 0, 0 }; // variable values
int iRet(0);
try
{
QmuParser p;
p.DefineConst("const1", 1);
p.DefineConst("const2", 2);
p.DefineVar("a", vVariableA);
p.DefineVar("b", vVariableB);
p.DefineVar("c", vVariableC);
p.SetExpr(a_str);
p.Eval(vResults, nBulkSize);
bool bCloseEnough(true);
for (int i = 0; i < nBulkSize; ++i)
{
bCloseEnough &= (fabs(a_fRes[i] - vResults[i]) <= fabs(a_fRes[i] * 0.00001));
}
iRet = ((bCloseEnough && a_fPass) || (!bCloseEnough && !a_fPass)) ? 0 : 1;
if (iRet == 1)
{
qWarning() << "\n fail: " << a_str << " (incorrect result; expected: {" << a_fRes[0] << ","
<< a_fRes[1] << "," << a_fRes[2] << "," << a_fRes[3] << "}" << " ;calculated: " << vResults[0]
<< "," << vResults[1] << "," << vResults[2] << "," << vResults[3] << "}";
}
}
catch (QmuParserError &e)
{
if (a_fPass)
{
qWarning() << "\n fail: " << e.GetExpr() << " : " << e.GetMsg();
iRet = 1;
}
}
catch (...)
{
qWarning() << "\n fail: " << a_str << " (unexpected exception)";
iRet = 1; // exceptions other than ParserException are not allowed
}
return iRet;
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
* @brief Internal error in test class Test is going to be aborted. * @brief Internal error in test class Test is going to be aborted.

View File

@ -63,6 +63,9 @@ private:
double a_fVar2 ); double a_fVar2 );
static int ThrowTest ( const QString &a_str, int a_iErrc, bool a_bFail = true ); static int ThrowTest ( const QString &a_str, int a_iErrc, bool a_bFail = true );
// Test Bulkmode
int EqnTestBulk(const QString &a_str, double a_fRes[4], bool a_fPass);
// Multiarg callbacks // Multiarg callbacks
static qreal f1of1 ( qreal v ) static qreal f1of1 ( qreal v )
{ {
@ -301,6 +304,8 @@ private:
int TestStrArg(); int TestStrArg();
// cppcheck-suppress functionStatic // cppcheck-suppress functionStatic
int TestIfThenElse(); int TestIfThenElse();
// cppcheck-suppress functionStatic
int TestBulkMode();
static void Q_NORETURN Abort(); static void Q_NORETURN Abort();
}; };