diff options
author | Eike Rathke <erack@redhat.com> | 2018-06-20 20:00:23 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2018-06-20 23:28:47 +0200 |
commit | eb678c01d35a485b9f79009c126e296d9e811d36 (patch) | |
tree | f60dbb7113470dd6a63958d436200bf71fb3e68c | |
parent | 00b3007976f60bdf65fbe69e3f4f1613b477a059 (diff) |
Prepare for Excel's dirty circular references iteration behaviour
In which either convergence is detected or N iterations are
executed and the result is displayed no matter what. Which would
"do N iteration steps" but never detect non-convergence.
Enable that only with an additional option where the user
specifies s/he doesn't want to be informed of non-convergence
errors.
Change-Id: I3caba0c200e16514e39ea46d7f899afc05a5a2cc
Reviewed-on: https://gerrit.libreoffice.org/56183
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Eike Rathke <erack@redhat.com>
-rw-r--r-- | sc/source/core/data/formulacell.cxx | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 661b0940eaf6..2fd26955891c 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1622,12 +1622,15 @@ void ScFormulaCell::Interpret() } // Start at 1, init things. rRecursionHelper.StartIteration(); - // Mark all cells being in iteration. + // Mark all cells being in iteration. Reset results to + // original values, formula cells have been interpreted + // already, discard that step. for (ScFormulaRecursionList::const_iterator aIter( rRecursionHelper.GetIterationStart()); aIter != rRecursionHelper.GetIterationEnd(); ++aIter) { ScFormulaCell* pIterCell = (*aIter).pCell; + pIterCell->aResult = (*aIter).aPreviousResult; pIterCell->bIsIterCell = true; } } @@ -1636,7 +1639,8 @@ void ScFormulaCell::Interpret() for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone; rRecursionHelper.IncIteration()) { - rDone = true; + rDone = false; + bool bFirst = true; for ( ScFormulaRecursionList::iterator aIter( rRecursionHelper.GetIterationStart()); aIter != rRecursionHelper.GetIterationEnd() && @@ -1652,7 +1656,15 @@ void ScFormulaCell::Interpret() pIterCell->InterpretTail( pDocument->GetNonThreadedContext(), SCITP_FROM_ITERATION); pDocument->DecInterpretLevel(); } - rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty(); + if (bFirst) + { + rDone = !pIterCell->IsDirtyOrInTableOpDirty(); + bFirst = false; + } + else if (rDone) + { + rDone = !pIterCell->IsDirtyOrInTableOpDirty(); + } } if (rRecursionHelper.IsInReturn()) { @@ -1687,12 +1699,26 @@ void ScFormulaCell::Interpret() pIterCell->bIsIterCell = false; pIterCell->nSeenInIteration = 0; pIterCell->bRunning = (*aIter).bOldRunning; + pIterCell->ResetDirty(); + // The difference to Excel is that Excel does not + // produce an error for non-convergence thus a + // delta of 0.001 still works to execute the + // maximum number of iterations and display the + // results no matter if the result anywhere reached + // near delta, but also never indicates whether the + // result actually makes sense in case of + // non-counter context. Calc does check the delta + // in every case. If we wanted to support what + // Excel does then add another option "indicate + // non-convergence error" (default on) and execute + // the following block only if set. +#if 1 // If one cell didn't converge, all cells of this // circular dependency don't, no matter whether // single cells did. - pIterCell->ResetDirty(); pIterCell->aResult.SetResultError( FormulaError::NoConvergence); pIterCell->bChanged = true; +#endif } } // End this iteration and remove entries. |