for (auto i = 1; i < 1000; i++)
{ /*A*/ if (i%19)
m_pDoc->SetValue(0, i, 0, i/10 + 1000); else
m_pDoc->SetValue(0, i, 0, 123456); /*B*/ m_pDoc->SetValue(1, i, 0, i%10); /*C*/ m_pDoc->SetValue(2, i, 0, i%5);
/*F*/ m_pDoc->SetValue(5, i, 0, i%17 + i%13);
/*L*/ m_pDoc->SetValue(11, i, 0, i%10); /*M*/ m_pDoc->SetValue(12, i, 0, i%5);
}
for (auto i = 1; i < 1000; i++)
{ // For instance P389 will contain the formula: // =SUMIFS($F$2:$F$1000; $A$2:$A$1000; A$1; $B$2:$B$1000; $L389; $C$2:$C$1000; $M389)
// In other words, it will sum those values in F2:1000 where the A value matches A1 (1001), // the B value matches L389 and the C value matches M389. (There should be just one such // value, so the formula is actually simply used to pick out that single value from the F // column where A,B,C match. Silly, but that is how SUMIFS is used in some corners of the // real world, apparently.)
for (auto i = 1; i < 2000; i++)
{ if (i == 1042)
m_pDoc->SetValue(0, i, 0, 1042.42); elseif (i%5)
m_pDoc->SetValue(0, i, 0, i); else
m_pDoc->SetValue(0, i, 0, i+0.1);
if (i%2)
m_pDoc->SetValue(1, i, 0, i*10); else
m_pDoc->SetString(1, i, 0, "N" + OUString::number(i*10));
if (i < 1000)
{
m_pDoc->SetFormula(ScAddress(2, i, 0), "=VLOOKUP(" + OUString::number(i) + "; " "A$2:B$2000; 2; 0)",
formula::FormulaGrammar::GRAM_NATIVE_UI);
}
else
{ if (i == 1042)
m_pDoc->SetFormula(ScAddress(2, i, 0),
u"=VLOOKUP(1042.42; " "A$2:B$2000; 2; 0)"_ustr,
formula::FormulaGrammar::GRAM_NATIVE_UI); else
m_pDoc->SetFormula(ScAddress(2, i, 0),
u"=VLOOKUP(1.234; " "A$2:B$2000; 2; 0)"_ustr,
formula::FormulaGrammar::GRAM_NATIVE_UI);
}
}
m_xDocShell->DoHardRecalc();
for (auto i = 1; i < 2000; i++)
{
OString sMessage = "At row " + OString::number(i+1); if (i < 1000)
{ if (i%5)
{ if (i%2)
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(sMessage.getStr(), static_cast<double>(i*10), m_pDoc->GetValue(2, i, 0), 1e-10); else
CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), OUString("N" + OUString::number(i*10)), m_pDoc->GetString(2, i, 0));
} else
{ // The corresponding value in A is i+0.1
CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), u"#N/A"_ustr, m_pDoc->GetString(2, i, 0));
}
} else
{ if (i == 1042)
CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), OUString("N" + OUString::number(i*10)), m_pDoc->GetString(2, i, 0)); else
CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), u"#N/A"_ustr, m_pDoc->GetString(2, i, 0));
}
}
OUString aFormula; const size_t nNumRows = 500; for (size_t i = 0; i < nNumRows; ++i)
{
m_pDoc->SetString(0, i, 0, u"AAAAAAAA"_ustr);
aFormula = "=PROPER($A" + OUString::number(i+1) + ")";
m_pDoc->SetFormula(ScAddress(1, i, 0),
aFormula,
formula::FormulaGrammar::GRAM_NATIVE_UI);
}
m_xDocShell->DoHardRecalc();
for (size_t i = 0; i < nNumRows; ++i)
{
OString aMsg = "At row " + OString::number(i);
CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), u"AAAAAAAA"_ustr, m_pDoc->GetString(0, i, 0));
// Without the fix in place, this test would have failed here
CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), u"Aaaaaaaa"_ustr, m_pDoc->GetString(1, i, 0));
}
m_pDoc->DeleteTab(0);
}
// Common test setup steps for testSUMIFImplicitRange*() staticvoid lcl_setupCommon(ScDocument* pDoc, size_t nNumRows, size_t nConstCellValue)
{
pDoc->SetValue(3, 0, 0, static_cast<double>(nConstCellValue)); // D1 for (size_t i = 0; i <= (nNumRows*2); ++i)
{
pDoc->SetValue(0, i, 0, static_cast<double>(i));
pDoc->SetFormula(ScAddress(1, i, 0), "=A" + OUString::number(i+1),
formula::FormulaGrammar::GRAM_NATIVE_UI);
}
}
ScFormulaCell* pCell = m_pDoc->GetFormulaCell(ScAddress(2, 0, 0));
sc::AutoCalcSwitch aACSwitch2(*m_pDoc, true);
pCell->InterpretFormulaGroup(); // Start calculation on the F.G at C1
for (size_t i = 0; i < nNumRows; ++i)
{
OString aMsg = "At row " + OString::number(i);
CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), nConstCellValue, static_cast<size_t>(m_pDoc->GetValue(2, i, 0)));
}
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(ScParallelismTest, testFGCycleWithPlainFormulaCell1)
{
sc::AutoCalcSwitch aACSwitch(*m_pDoc, false);
m_pDoc->InsertTab(0, u"1"_ustr); const size_t nNumRows = 1048; // Column A contains no formula-group // A1 = 100
m_pDoc->SetValue(0, 0, 0, 100.0); // A500 = B499 + 1
m_pDoc->SetFormula(ScAddress(0, 499, 0),
u"=$B499 + 1"_ustr,
formula::FormulaGrammar::GRAM_NATIVE_UI); // Column B has a formula-group referencing column A.
OUString aFormula; for (size_t i = 0; i < nNumRows; ++i)
{
aFormula = "=$A" + OUString::number(i+1) + " + 100";
m_pDoc->SetFormula(ScAddress(1, i, 0),
aFormula,
formula::FormulaGrammar::GRAM_NATIVE_UI);
}
m_xDocShell->DoHardRecalc(); // Value at A500 must be 101 const size_t nVal = 100;
CPPUNIT_ASSERT_EQUAL_MESSAGE("Value at A500", nVal + 1, static_cast<size_t>(m_pDoc->GetValue(0, 499, 0))); for (size_t i = 0; i < nNumRows; ++i)
{
OString aMsg = "Value at cell B" + OString::number(i+1);
size_t nExpected = nVal; if (i == 0)
nExpected = 200; elseif (i == 499)
nExpected = 201;
CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), nExpected, static_cast<size_t>(m_pDoc->GetValue(1, i, 0)));
}
m_pDoc->DeleteTab(0);
}
CPPUNIT_TEST_FIXTURE(ScParallelismTest, testFGCycleWithPlainFormulaCell2)
{
sc::AutoCalcSwitch aACSwitch(*m_pDoc, false);
m_pDoc->InsertTab(0, u"1"_ustr); const size_t nNumRows = 1048; // Column A
OUString aFormula; for (size_t i = 0; i < nNumRows; ++i)
{
aFormula = "=$B" + OUString::number(i+1) + " + 1";
m_pDoc->SetFormula(ScAddress(0, i, 0),
aFormula,
formula::FormulaGrammar::GRAM_NATIVE_UI);
} // Column B for (size_t i = 0; i < nNumRows; ++i)
{
aFormula = "=$C" + OUString::number(i+1) + " + 1";
m_pDoc->SetFormula(ScAddress(1, i, 0),
aFormula,
formula::FormulaGrammar::GRAM_NATIVE_UI);
}
// Column C has no FG but a cell at C500 that references A499
m_pDoc->SetFormula(ScAddress(2, 499, 0), // C500
u"=$A499 + 1"_ustr,
formula::FormulaGrammar::GRAM_NATIVE_UI);
m_xDocShell->DoHardRecalc();
size_t nExpected = 0; for (size_t i = 0; i < nNumRows; ++i)
{
OString aMsg = "Value at cell A" + OString::number(i+1);
nExpected = 2; if (i == 499) // A500 must have value = 5
nExpected = 5;
CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), nExpected, static_cast<size_t>(m_pDoc->GetValue(0, i, 0)));
aMsg = "Value at cell B" + OString::number(i+1);
nExpected = 1; if (i == 499) // B500 must have value = 4
nExpected = 4;
CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), nExpected, static_cast<size_t>(m_pDoc->GetValue(1, i, 0)));
}
// C500 must have value = 3
nExpected = 3;
CPPUNIT_ASSERT_EQUAL_MESSAGE("Value at cell C500", nExpected, static_cast<size_t>(m_pDoc->GetValue(2, 499, 0)));
m_pDoc->DeleteTab(0);
}
OString aMsg; // First cell in the FG in col A references nColAStartOffset cells in second formula-group of column B each having value 1.
size_t nExpected = nColAStartOffset;
size_t nIn = 0, nOut = 0; for (size_t nRow = nColAStartOffset; nRow < nColAFGLen; ++nRow)
{
aMsg = "Value at Cell A" + OString::number(nRow+1);
CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), nExpected, static_cast<size_t>(m_pDoc->GetValue(0, nRow, 0)));
nIn = static_cast<size_t>(m_pDoc->GetValue(2, nRow+nNumRowsInRef, 0));
nOut = static_cast<size_t>(m_pDoc->GetValue(2, nRow, 0));
nExpected = nExpected + nIn - nOut;
}
// EnsureFormulaCellResults should only calculate the specified range along with the dependent spans recursively and nothing more. // The specified range is A99:A1124, and the dependent range is B99:B1125 (since A99 = SUM(B99:B100) and A1124 = SUM(B1124:B1125) ) bool bAnyDirty = m_pDoc->EnsureFormulaCellResults(ScRange(0, nSpanStart, 0, 0, nSpanEnd, 0));
CPPUNIT_ASSERT(bAnyDirty);
m_pDoc->SetAutoCalc(false);
OString aMsg; for (size_t nRow = 0; nRow < nFGLen; ++nRow)
{
size_t nExpectedA = 0, nExpectedB = 0; // For nRow from 100(nSpanStart) to 1123(nSpanEnd) column A must have the value of 2 and // column B should have value 1.
// For nRow == 1124, column A should have value 0 and column B should have value 1.
// For all other rows both column A and B must have value 0. if (nRow >= nSpanStart)
{ if (nRow <= nSpanEnd)
{
nExpectedA = 2;
nExpectedB = 1;
} elseif (nRow == nSpanEnd + 1)
nExpectedB = 1;
}
m_pDoc->SetValue(1, 1, 0, 2.0); // B2 <== 2 for (size_t nRow = 1; nRow < 105; ++nRow)
{ // Formula-group in B3:B104 with first cell "=D2+0.001" if( nRow != 1 )
m_pDoc->SetFormula(ScAddress(1, nRow, 0), "=D" + OUString::number(nRow) + "+0.001",
formula::FormulaGrammar::GRAM_NATIVE_UI); // Formula-group in C2:C104 with first cell "=B2*1.01011"
m_pDoc->SetFormula(ScAddress(2, nRow, 0), "=B" + OUString::number(nRow + 1) + "*1.01011",
formula::FormulaGrammar::GRAM_NATIVE_UI); // Formula-group in D2:C104 with first cell "=C2*1.02"
m_pDoc->SetFormula(ScAddress(3, nRow, 0), "=C" + OUString::number(nRow + 1) + "*1.02",
formula::FormulaGrammar::GRAM_NATIVE_UI);
}
m_xDocShell->DoHardRecalc();
// What happens with tdf#132451 is that the copy&paste C6->C5 really just sets the dirty flag // for C5 and all the cells that depend on it (D5,B6,C6,D6,B7,...), and it also resets // flags marking the C formula group as disabled for parallel calculation because of the cycle.
m_pDoc->SetFormula(ScAddress(2, 4, 0), u"=B5*1.01011"_ustr, formula::FormulaGrammar::GRAM_NATIVE_UI);
m_pDoc->GetFormulaCell(ScAddress(2,4,0))->GetCellGroup()->mbPartOfCycle = false;
m_pDoc->GetFormulaCell(ScAddress(2,4,0))->GetCellGroup()->meCalcState = sc::GroupCalcEnabled;
m_pDoc->SetAutoCalc(true); // Without the fix, getting value of C5 would try to parallel-interpret formula group in B // from its first dirty cell (B6), which depends on D5, which depends on C5, where the cycle // would be detected and dependency check would bail out. But the result from Interpret()-ing // D5 would be used and D5's dirty flag reset, with D5 value incorrect.
m_pDoc->GetValue(2,4,0);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.