Bugfix for Bulkmode: Expressions with like "a=b, b*10" did not compute properly.
--HG-- branch : develop
This commit is contained in:
parent
99bb3f8962
commit
aef39533c8
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user