tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / sc / source / core / tool / interpr5.cxx
blobf282d5fe71696deb5650943c530d23776125f25c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <rtl/math.hxx>
21 #include <string.h>
22 #include <math.h>
24 #ifdef DEBUG_SC_LUP_DECOMPOSITION
25 #include <stdio.h>
26 #endif
28 #include <unotools/bootstrap.hxx>
29 #include <svl/zforlist.hxx>
30 #include <tools/duration.hxx>
32 #include <interpre.hxx>
33 #include <global.hxx>
34 #include <formulacell.hxx>
35 #include <document.hxx>
36 #include <dociter.hxx>
37 #include <scmatrix.hxx>
38 #include <globstr.hrc>
39 #include <scresid.hxx>
40 #include <cellkeytranslator.hxx>
41 #include <formulagroup.hxx>
42 #include <vcl/svapp.hxx> //Application::
44 #include <vector>
46 using ::std::vector;
47 using namespace formula;
49 namespace {
51 double MatrixAdd(const double& lhs, const double& rhs)
53 return ::rtl::math::approxAdd( lhs,rhs);
56 double MatrixSub(const double& lhs, const double& rhs)
58 return ::rtl::math::approxSub( lhs,rhs);
61 double MatrixMul(const double& lhs, const double& rhs)
63 return lhs * rhs;
66 double MatrixDiv(const double& lhs, const double& rhs)
68 return ScInterpreter::div( lhs,rhs);
71 double MatrixPow(const double& lhs, const double& rhs)
73 return ::pow( lhs,rhs);
76 // Multiply n x m Mat A with m x l Mat B to n x l Mat R
77 void lcl_MFastMult(const ScMatrixRef& pA, const ScMatrixRef& pB, const ScMatrixRef& pR,
78 SCSIZE n, SCSIZE m, SCSIZE l)
80 for (SCSIZE row = 0; row < n; row++)
82 for (SCSIZE col = 0; col < l; col++)
83 { // result element(col, row) =sum[ (row of A) * (column of B)]
84 KahanSum fSum = 0.0;
85 for (SCSIZE k = 0; k < m; k++)
86 fSum += pA->GetDouble(k,row) * pB->GetDouble(col,k);
87 pR->PutDouble(fSum.get(), col, row);
94 double ScInterpreter::ScGetGCD(double fx, double fy)
96 // By ODFF definition GCD(0,a) => a. This is also vital for the code in
97 // ScGCD() to work correctly with a preset fy=0.0
98 if (fy == 0.0)
99 return fx;
100 else if (fx == 0.0)
101 return fy;
102 else
104 double fz = fmod(fx, fy);
105 while (fz > 0.0)
107 fx = fy;
108 fy = fz;
109 fz = fmod(fx, fy);
111 return fy;
115 void ScInterpreter::ScGCD()
117 short nParamCount = GetByte();
118 if ( !MustHaveParamCountMin( nParamCount, 1 ) )
119 return;
121 double fx, fy = 0.0;
122 ScRange aRange;
123 size_t nRefInList = 0;
124 while (nGlobalError == FormulaError::NONE && nParamCount-- > 0)
126 switch (GetStackType())
128 case svDouble :
129 case svString:
130 case svSingleRef:
132 fx = ::rtl::math::approxFloor( GetDouble());
133 if (fx < 0.0)
135 PushIllegalArgument();
136 return;
138 fy = ScGetGCD(fx, fy);
140 break;
141 case svDoubleRef :
142 case svRefList :
144 FormulaError nErr = FormulaError::NONE;
145 PopDoubleRef( aRange, nParamCount, nRefInList);
146 double nCellVal;
147 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
148 if (aValIter.GetFirst(nCellVal, nErr))
152 fx = ::rtl::math::approxFloor( nCellVal);
153 if (fx < 0.0)
155 PushIllegalArgument();
156 return;
158 fy = ScGetGCD(fx, fy);
159 } while (nErr == FormulaError::NONE && aValIter.GetNext(nCellVal, nErr));
161 SetError(nErr);
163 break;
164 case svMatrix :
165 case svExternalSingleRef:
166 case svExternalDoubleRef:
168 ScMatrixRef pMat = GetMatrix();
169 if (pMat)
171 SCSIZE nC, nR;
172 pMat->GetDimensions(nC, nR);
173 if (nC == 0 || nR == 0)
174 SetError(FormulaError::IllegalArgument);
175 else
177 double nVal = pMat->GetGcd();
178 fy = ScGetGCD(nVal,fy);
182 break;
183 default : SetError(FormulaError::IllegalParameter); break;
186 PushDouble(fy);
189 void ScInterpreter:: ScLCM()
191 short nParamCount = GetByte();
192 if ( !MustHaveParamCountMin( nParamCount, 1 ) )
193 return;
195 double fx, fy = 1.0;
196 ScRange aRange;
197 size_t nRefInList = 0;
198 while (nGlobalError == FormulaError::NONE && nParamCount-- > 0)
200 switch (GetStackType())
202 case svDouble :
203 case svString:
204 case svSingleRef:
206 fx = ::rtl::math::approxFloor( GetDouble());
207 if (fx < 0.0)
209 PushIllegalArgument();
210 return;
212 if (fx == 0.0 || fy == 0.0)
213 fy = 0.0;
214 else
215 fy = fx * fy / ScGetGCD(fx, fy);
217 break;
218 case svDoubleRef :
219 case svRefList :
221 FormulaError nErr = FormulaError::NONE;
222 PopDoubleRef( aRange, nParamCount, nRefInList);
223 double nCellVal;
224 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
225 if (aValIter.GetFirst(nCellVal, nErr))
229 fx = ::rtl::math::approxFloor( nCellVal);
230 if (fx < 0.0)
232 PushIllegalArgument();
233 return;
235 if (fx == 0.0 || fy == 0.0)
236 fy = 0.0;
237 else
238 fy = fx * fy / ScGetGCD(fx, fy);
239 } while (nErr == FormulaError::NONE && aValIter.GetNext(nCellVal, nErr));
241 SetError(nErr);
243 break;
244 case svMatrix :
245 case svExternalSingleRef:
246 case svExternalDoubleRef:
248 ScMatrixRef pMat = GetMatrix();
249 if (pMat)
251 SCSIZE nC, nR;
252 pMat->GetDimensions(nC, nR);
253 if (nC == 0 || nR == 0)
254 SetError(FormulaError::IllegalArgument);
255 else
257 double nVal = pMat->GetLcm();
258 fy = (nVal * fy ) / ScGetGCD(nVal, fy);
262 break;
263 default : SetError(FormulaError::IllegalParameter); break;
266 PushDouble(fy);
269 void ScInterpreter::MakeMatNew(ScMatrixRef& rMat, SCSIZE nC, SCSIZE nR)
271 rMat->SetErrorInterpreter( this);
272 // A temporary matrix is mutable and ScMatrix::CloneIfConst() returns the
273 // very matrix.
274 rMat->SetMutable();
275 SCSIZE nCols, nRows;
276 rMat->GetDimensions( nCols, nRows);
277 if ( nCols != nC || nRows != nR )
278 { // arbitrary limit of elements exceeded
279 SetError( FormulaError::MatrixSize);
280 rMat.reset();
284 ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR, bool bEmpty)
286 ScMatrixRef pMat;
287 if (bEmpty)
288 pMat = new ScMatrix(nC, nR);
289 else
290 pMat = new ScMatrix(nC, nR, 0.0);
291 MakeMatNew(pMat, nC, nR);
292 return pMat;
295 ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR, const std::vector<double>& rValues)
297 ScMatrixRef pMat(new ScMatrix(nC, nR, rValues));
298 MakeMatNew(pMat, nC, nR);
299 return pMat;
302 ScMatrixRef ScInterpreter::CreateMatrixFromDoubleRef( const FormulaToken* pToken,
303 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
304 SCCOL nCol2, SCROW nRow2, SCTAB nTab2 )
306 if (nTab1 != nTab2 || nGlobalError != FormulaError::NONE)
308 // Not a 2D matrix.
309 SetError(FormulaError::IllegalParameter);
310 return nullptr;
313 if (nTab1 == nTab2 && pToken)
315 const ScComplexRefData& rCRef = *pToken->GetDoubleRef();
316 if (rCRef.IsTrimToData())
318 // Clamp the size of the matrix area to rows which actually contain data.
319 // For e.g. SUM(IF over an entire column, this can make a big difference,
320 // But let's not trim the empty space from the top or left as this matters
321 // at least in matrix formulas involving IF().
322 // Refer ScCompiler::AnnotateTrimOnDoubleRefs() where double-refs are
323 // flagged for trimming.
324 SCCOL nTempCol = nCol1;
325 SCROW nTempRow = nRow1;
326 mrDoc.ShrinkToDataArea(nTab1, nTempCol, nTempRow, nCol2, nRow2);
330 SCSIZE nMatCols = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
331 SCSIZE nMatRows = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
333 if (!ScMatrix::IsSizeAllocatable( nMatCols, nMatRows))
335 SetError(FormulaError::MatrixSize);
336 return nullptr;
339 ScTokenMatrixMap::const_iterator aIter;
340 if (pToken && ((aIter = maTokenMatrixMap.find( pToken)) != maTokenMatrixMap.end()))
342 /* XXX casting const away here is ugly; ScMatrixToken (to which the
343 * result of this function usually is assigned) should not be forced to
344 * carry a ScConstMatrixRef though.
345 * TODO: a matrix already stored in pTokenMatrixMap should be
346 * read-only and have a copy-on-write mechanism. Previously all tokens
347 * were modifiable so we're already better than before ... */
348 return const_cast<FormulaToken*>((*aIter).second.get())->GetMatrix();
351 ScMatrixRef pMat = GetNewMat( nMatCols, nMatRows, true);
352 if (!pMat || nGlobalError != FormulaError::NONE)
353 return nullptr;
355 if (!bCalcAsShown)
357 // Use fast array fill.
358 mrDoc.FillMatrix(*pMat, nTab1, nCol1, nRow1, nCol2, nRow2);
360 else
362 // Use slower ScCellIterator to round values.
364 // TODO: this probably could use CellBucket for faster storage, see
365 // sc/source/core/data/column2.cxx and FillMatrixHandler, and then be
366 // moved to a function on its own, and/or squeeze the rounding into a
367 // similar FillMatrixHandler that would need to keep track of the cell
368 // position then.
370 // Set position where the next entry is expected.
371 SCROW nNextRow = nRow1;
372 SCCOL nNextCol = nCol1;
373 // Set last position as if there was a previous entry.
374 SCROW nThisRow = nRow2;
375 SCCOL nThisCol = nCol1 - 1;
377 ScCellIterator aCellIter( mrDoc, ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
378 for (bool bHas = aCellIter.first(); bHas; bHas = aCellIter.next())
380 nThisCol = aCellIter.GetPos().Col();
381 nThisRow = aCellIter.GetPos().Row();
382 if (nThisCol != nNextCol || nThisRow != nNextRow)
384 // Fill empty between iterator's positions.
385 for ( ; nNextCol <= nThisCol; ++nNextCol)
387 const SCSIZE nC = nNextCol - nCol1;
388 const SCSIZE nMatStopRow = ((nNextCol < nThisCol) ? nMatRows : nThisRow - nRow1);
389 for (SCSIZE nR = nNextRow - nRow1; nR < nMatStopRow; ++nR)
391 pMat->PutEmpty( nC, nR);
393 nNextRow = nRow1;
396 if (nThisRow == nRow2)
398 nNextCol = nThisCol + 1;
399 nNextRow = nRow1;
401 else
403 nNextCol = nThisCol;
404 nNextRow = nThisRow + 1;
407 const SCSIZE nMatCol = static_cast<SCSIZE>(nThisCol - nCol1);
408 const SCSIZE nMatRow = static_cast<SCSIZE>(nThisRow - nRow1);
409 ScRefCellValue aCell( aCellIter.getRefCellValue());
410 if (aCellIter.isEmpty() || aCell.hasEmptyValue())
412 pMat->PutEmpty( nMatCol, nMatRow);
414 else if (aCell.hasError())
416 pMat->PutError( aCell.getFormula()->GetErrCode(), nMatCol, nMatRow);
418 else if (aCell.hasNumeric())
420 double fVal = aCell.getValue();
421 // CELLTYPE_FORMULA already stores the rounded value.
422 if (aCell.getType() == CELLTYPE_VALUE)
424 // TODO: this could be moved to ScCellIterator to take
425 // advantage of the faster ScAttrArray_IterGetNumberFormat.
426 const ScAddress aAdr( nThisCol, nThisRow, nTab1);
427 const sal_uInt32 nNumFormat = mrDoc.GetNumberFormat( mrContext, aAdr);
428 fVal = mrDoc.RoundValueAsShown( fVal, nNumFormat, &mrContext);
430 pMat->PutDouble( fVal, nMatCol, nMatRow);
432 else if (aCell.hasString())
434 pMat->PutString( mrStrPool.intern( aCell.getString(&mrDoc)), nMatCol, nMatRow);
436 else
438 assert(!"aCell.what?");
439 pMat->PutEmpty( nMatCol, nMatRow);
443 // Fill empty if iterator's last position wasn't the end.
444 if (nThisCol != nCol2 || nThisRow != nRow2)
446 for ( ; nNextCol <= nCol2; ++nNextCol)
448 SCSIZE nC = nNextCol - nCol1;
449 for (SCSIZE nR = nNextRow - nRow1; nR < nMatRows; ++nR)
451 pMat->PutEmpty( nC, nR);
453 nNextRow = nRow1;
458 if (pToken)
459 maTokenMatrixMap.emplace(pToken, new ScMatrixToken( pMat));
461 return pMat;
464 ScMatrixRef ScInterpreter::GetMatrix()
466 ScMatrixRef pMat = nullptr;
467 switch (GetRawStackType())
469 case svSingleRef :
471 ScAddress aAdr;
472 PopSingleRef( aAdr );
473 pMat = GetNewMat(1, 1);
474 if (pMat)
476 ScRefCellValue aCell(mrDoc, aAdr);
477 if (aCell.hasEmptyValue())
478 pMat->PutEmpty(0, 0);
479 else if (aCell.hasNumeric())
480 pMat->PutDouble(GetCellValue(aAdr, aCell), 0);
481 else
483 svl::SharedString aStr;
484 GetCellString(aStr, aCell);
485 pMat->PutString(aStr, 0);
489 break;
490 case svDoubleRef:
492 SCCOL nCol1, nCol2;
493 SCROW nRow1, nRow2;
494 SCTAB nTab1, nTab2;
495 const formula::FormulaToken* p = sp ? pStack[sp-1] : nullptr;
496 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
497 pMat = CreateMatrixFromDoubleRef( p, nCol1, nRow1, nTab1,
498 nCol2, nRow2, nTab2);
500 break;
501 case svMatrix:
502 pMat = PopMatrix();
503 break;
504 case svError :
505 case svMissing :
506 case svDouble :
508 double fVal = GetDouble();
509 pMat = GetNewMat( 1, 1);
510 if ( pMat )
512 if ( nGlobalError != FormulaError::NONE )
514 fVal = CreateDoubleError( nGlobalError);
515 nGlobalError = FormulaError::NONE;
517 pMat->PutDouble( fVal, 0);
520 break;
521 case svString :
523 svl::SharedString aStr = GetString();
524 pMat = GetNewMat( 1, 1);
525 if ( pMat )
527 if ( nGlobalError != FormulaError::NONE )
529 double fVal = CreateDoubleError( nGlobalError);
530 pMat->PutDouble( fVal, 0);
531 nGlobalError = FormulaError::NONE;
533 else
534 pMat->PutString(aStr, 0);
537 break;
538 case svExternalSingleRef:
540 ScExternalRefCache::TokenRef pToken;
541 PopExternalSingleRef(pToken);
542 pMat = GetNewMat( 1, 1, true);
543 if (!pMat)
544 break;
545 if (nGlobalError != FormulaError::NONE)
547 pMat->PutError( nGlobalError, 0, 0);
548 nGlobalError = FormulaError::NONE;
549 break;
551 switch (pToken->GetType())
553 case svError:
554 pMat->PutError( pToken->GetError(), 0, 0);
555 break;
556 case svDouble:
557 pMat->PutDouble( pToken->GetDouble(), 0, 0);
558 break;
559 case svString:
560 pMat->PutString( pToken->GetString(), 0, 0);
561 break;
562 default:
563 ; // nothing, empty element matrix
566 break;
567 case svExternalDoubleRef:
568 PopExternalDoubleRef(pMat);
569 break;
570 default:
571 PopError();
572 SetError( FormulaError::IllegalArgument);
573 break;
575 return pMat;
578 ScMatrixRef ScInterpreter::GetMatrix( short & rParam, size_t & rRefInList )
580 switch (GetRawStackType())
582 case svRefList:
584 ScRange aRange( ScAddress::INITIALIZE_INVALID );
585 PopDoubleRef( aRange, rParam, rRefInList);
586 if (nGlobalError != FormulaError::NONE)
587 return nullptr;
589 SCCOL nCol1, nCol2;
590 SCROW nRow1, nRow2;
591 SCTAB nTab1, nTab2;
592 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
593 return CreateMatrixFromDoubleRef( nullptr, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
595 break;
596 default:
597 return GetMatrix();
601 sc::RangeMatrix ScInterpreter::GetRangeMatrix()
603 sc::RangeMatrix aRet;
604 switch (GetRawStackType())
606 case svMatrix:
607 aRet = PopRangeMatrix();
608 break;
609 default:
610 aRet.mpMat = GetMatrix();
612 return aRet;
615 void ScInterpreter::ScMatValue()
617 if ( !MustHaveParamCount( GetByte(), 3 ) )
618 return;
620 // 0 to count-1
621 // Theoretically we could have GetSize() instead of GetUInt32(), but
622 // really, practically ...
623 SCSIZE nR = static_cast<SCSIZE>(GetUInt32());
624 SCSIZE nC = static_cast<SCSIZE>(GetUInt32());
625 if (nGlobalError != FormulaError::NONE)
627 PushError( nGlobalError);
628 return;
630 switch (GetStackType())
632 case svSingleRef :
634 ScAddress aAdr;
635 PopSingleRef( aAdr );
636 ScRefCellValue aCell(mrDoc, aAdr);
637 if (aCell.getType() == CELLTYPE_FORMULA)
639 FormulaError nErrCode = aCell.getFormula()->GetErrCode();
640 if (nErrCode != FormulaError::NONE)
641 PushError( nErrCode);
642 else
644 const ScMatrix* pMat = aCell.getFormula()->GetMatrix();
645 CalculateMatrixValue(pMat,nC,nR);
648 else
649 PushIllegalParameter();
651 break;
652 case svDoubleRef :
654 SCCOL nCol1;
655 SCROW nRow1;
656 SCTAB nTab1;
657 SCCOL nCol2;
658 SCROW nRow2;
659 SCTAB nTab2;
660 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
661 if (nCol2 - nCol1 >= static_cast<SCCOL>(nR) &&
662 nRow2 - nRow1 >= static_cast<SCROW>(nC) &&
663 nTab1 == nTab2)
665 ScAddress aAdr( sal::static_int_cast<SCCOL>( nCol1 + nR ),
666 sal::static_int_cast<SCROW>( nRow1 + nC ), nTab1 );
667 ScRefCellValue aCell(mrDoc, aAdr);
668 if (aCell.hasNumeric())
669 PushDouble(GetCellValue(aAdr, aCell));
670 else
672 svl::SharedString aStr;
673 GetCellString(aStr, aCell);
674 PushString(aStr);
677 else
678 PushNoValue();
680 break;
681 case svMatrix:
683 ScMatrixRef pMat = PopMatrix();
684 CalculateMatrixValue(pMat.get(),nC,nR);
686 break;
687 default:
688 PopError();
689 PushIllegalParameter();
690 break;
693 void ScInterpreter::CalculateMatrixValue(const ScMatrix* pMat,SCSIZE nC,SCSIZE nR)
695 if (pMat)
697 SCSIZE nCl, nRw;
698 pMat->GetDimensions(nCl, nRw);
699 if (nC < nCl && nR < nRw)
701 const ScMatrixValue nMatVal = pMat->Get( nC, nR);
702 ScMatValType nMatValType = nMatVal.nType;
703 if (ScMatrix::IsNonValueType( nMatValType))
704 PushString( nMatVal.GetString() );
705 else
706 PushDouble(nMatVal.fVal);
707 // also handles DoubleError
709 else
710 PushNoValue();
712 else
713 PushNoValue();
716 void ScInterpreter::ScEMat()
718 if ( !MustHaveParamCount( GetByte(), 1 ) )
719 return;
721 SCSIZE nDim = static_cast<SCSIZE>(GetUInt32());
722 if (nGlobalError != FormulaError::NONE || nDim == 0)
723 PushIllegalArgument();
724 else if (!ScMatrix::IsSizeAllocatable( nDim, nDim))
725 PushError( FormulaError::MatrixSize);
726 else
728 ScMatrixRef pRMat = GetNewMat(nDim, nDim, /*bEmpty*/true);
729 if (pRMat)
731 MEMat(pRMat, nDim);
732 PushMatrix(pRMat);
734 else
735 PushIllegalArgument();
739 void ScInterpreter::MEMat(const ScMatrixRef& mM, SCSIZE n)
741 mM->FillDouble(0.0, 0, 0, n-1, n-1);
742 for (SCSIZE i = 0; i < n; i++)
743 mM->PutDouble(1.0, i, i);
746 /* Matrix LUP decomposition according to the pseudocode of "Introduction to
747 * Algorithms" by Cormen, Leiserson, Rivest, Stein.
749 * Added scaling for numeric stability.
751 * Given an n x n nonsingular matrix A, find a permutation matrix P, a unit
752 * lower-triangular matrix L, and an upper-triangular matrix U such that PA=LU.
753 * Compute L and U "in place" in the matrix A, the original content is
754 * destroyed. Note that the diagonal elements of the U triangular matrix
755 * replace the diagonal elements of the L-unit matrix (that are each ==1). The
756 * permutation matrix P is an array, where P[i]=j means that the i-th row of P
757 * contains a 1 in column j. Additionally keep track of the number of
758 * permutations (row exchanges).
760 * Returns 0 if a singular matrix is encountered, else +1 if an even number of
761 * permutations occurred, or -1 if odd, which is the sign of the determinant.
762 * This may be used to calculate the determinant by multiplying the sign with
763 * the product of the diagonal elements of the LU matrix.
765 static int lcl_LUP_decompose( ScMatrix* mA, const SCSIZE n,
766 ::std::vector< SCSIZE> & P )
768 int nSign = 1;
769 // Find scale of each row.
770 ::std::vector< double> aScale(n);
771 for (SCSIZE i=0; i < n; ++i)
773 double fMax = 0.0;
774 for (SCSIZE j=0; j < n; ++j)
776 double fTmp = fabs( mA->GetDouble( j, i));
777 if (fMax < fTmp)
778 fMax = fTmp;
780 if (fMax == 0.0)
781 return 0; // singular matrix
782 aScale[i] = 1.0 / fMax;
784 // Represent identity permutation, P[i]=i
785 for (SCSIZE i=0; i < n; ++i)
786 P[i] = i;
787 // "Recursion" on the diagonal.
788 SCSIZE l = n - 1;
789 for (SCSIZE k=0; k < l; ++k)
791 // Implicit pivoting. With the scale found for a row, compare values of
792 // a column and pick largest.
793 double fMax = 0.0;
794 double fScale = aScale[k];
795 SCSIZE kp = k;
796 for (SCSIZE i = k; i < n; ++i)
798 double fTmp = fScale * fabs( mA->GetDouble( k, i));
799 if (fMax < fTmp)
801 fMax = fTmp;
802 kp = i;
805 if (fMax == 0.0)
806 return 0; // singular matrix
807 // Swap rows. The pivot element will be at mA[k,kp] (row,col notation)
808 if (k != kp)
810 // permutations
811 SCSIZE nTmp = P[k];
812 P[k] = P[kp];
813 P[kp] = nTmp;
814 nSign = -nSign;
815 // scales
816 double fTmp = aScale[k];
817 aScale[k] = aScale[kp];
818 aScale[kp] = fTmp;
819 // elements
820 for (SCSIZE i=0; i < n; ++i)
822 double fMatTmp = mA->GetDouble( i, k);
823 mA->PutDouble( mA->GetDouble( i, kp), i, k);
824 mA->PutDouble( fMatTmp, i, kp);
827 // Compute Schur complement.
828 for (SCSIZE i = k+1; i < n; ++i)
830 double fNum = mA->GetDouble( k, i);
831 double fDen = mA->GetDouble( k, k);
832 mA->PutDouble( fNum/fDen, k, i);
833 for (SCSIZE j = k+1; j < n; ++j)
834 mA->PutDouble( ( mA->GetDouble( j, i) * fDen -
835 fNum * mA->GetDouble( j, k) ) / fDen, j, i);
838 #ifdef DEBUG_SC_LUP_DECOMPOSITION
839 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): LU");
840 for (SCSIZE i=0; i < n; ++i)
842 for (SCSIZE j=0; j < n; ++j)
843 fprintf( stderr, "%8.2g ", mA->GetDouble( j, i));
844 fprintf( stderr, "\n%s\n", "");
846 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): P");
847 for (SCSIZE j=0; j < n; ++j)
848 fprintf( stderr, "%5u ", (unsigned)P[j]);
849 fprintf( stderr, "\n%s\n", "");
850 #endif
852 bool bSingular=false;
853 for (SCSIZE i=0; i<n && !bSingular; i++)
854 bSingular = (mA->GetDouble(i,i)) == 0.0;
855 if (bSingular)
856 nSign = 0;
858 return nSign;
861 /* Solve a LUP decomposed equation Ax=b. LU is a combined matrix of L and U
862 * triangulars and P the permutation vector as obtained from
863 * lcl_LUP_decompose(). B is the right-hand side input vector, X is used to
864 * return the solution vector.
866 static void lcl_LUP_solve( const ScMatrix* mLU, const SCSIZE n,
867 const ::std::vector< SCSIZE> & P, const ::std::vector< double> & B,
868 ::std::vector< double> & X )
870 SCSIZE nFirst = SCSIZE_MAX;
871 // Ax=b => PAx=Pb, with decomposition LUx=Pb.
872 // Define y=Ux and solve for y in Ly=Pb using forward substitution.
873 for (SCSIZE i=0; i < n; ++i)
875 KahanSum fSum = B[P[i]];
876 // Matrix inversion comes with a lot of zeros in the B vectors, we
877 // don't have to do all the computing with results multiplied by zero.
878 // Until then, simply lookout for the position of the first nonzero
879 // value.
880 if (nFirst != SCSIZE_MAX)
882 for (SCSIZE j = nFirst; j < i; ++j)
883 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === y[j]
885 else if (fSum != 0)
886 nFirst = i;
887 X[i] = fSum.get(); // X[i] === y[i]
889 // Solve for x in Ux=y using back substitution.
890 for (SCSIZE i = n; i--; )
892 KahanSum fSum = X[i]; // X[i] === y[i]
893 for (SCSIZE j = i+1; j < n; ++j)
894 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === x[j]
895 X[i] = fSum.get() / mLU->GetDouble( i, i); // X[i] === x[i]
897 #ifdef DEBUG_SC_LUP_DECOMPOSITION
898 fprintf( stderr, "\n%s\n", "lcl_LUP_solve():");
899 for (SCSIZE i=0; i < n; ++i)
900 fprintf( stderr, "%8.2g ", X[i]);
901 fprintf( stderr, "%s\n", "");
902 #endif
905 void ScInterpreter::ScMatDet()
907 if ( !MustHaveParamCount( GetByte(), 1 ) )
908 return;
910 ScMatrixRef pMat = GetMatrix();
911 if (!pMat)
913 PushIllegalParameter();
914 return;
916 if ( !pMat->IsNumeric() )
918 PushNoValue();
919 return;
921 SCSIZE nC, nR;
922 pMat->GetDimensions(nC, nR);
923 if ( nC != nR || nC == 0 )
924 PushIllegalArgument();
925 else if (!ScMatrix::IsSizeAllocatable( nC, nR))
926 PushError( FormulaError::MatrixSize);
927 else
929 // LUP decomposition is done inplace, use copy.
930 ScMatrixRef xLU = pMat->Clone();
931 if (!xLU)
932 PushError( FormulaError::CodeOverflow);
933 else
935 ::std::vector< SCSIZE> P(nR);
936 int nDetSign = lcl_LUP_decompose( xLU.get(), nR, P);
937 if (!nDetSign)
938 PushInt(0); // singular matrix
939 else
941 // In an LU matrix the determinant is simply the product of
942 // all diagonal elements.
943 double fDet = nDetSign;
944 for (SCSIZE i=0; i < nR; ++i)
945 fDet *= xLU->GetDouble( i, i);
946 PushDouble( fDet);
952 void ScInterpreter::ScMatInv()
954 if ( !MustHaveParamCount( GetByte(), 1 ) )
955 return;
957 ScMatrixRef pMat = GetMatrix();
958 if (!pMat)
960 PushIllegalParameter();
961 return;
963 if ( !pMat->IsNumeric() )
965 PushNoValue();
966 return;
968 SCSIZE nC, nR;
969 pMat->GetDimensions(nC, nR);
971 if (ScCalcConfig::isOpenCLEnabled())
973 sc::FormulaGroupInterpreter *pInterpreter = sc::FormulaGroupInterpreter::getStatic();
974 if (pInterpreter != nullptr)
976 ScMatrixRef xResMat = pInterpreter->inverseMatrix(*pMat);
977 if (xResMat)
979 PushMatrix(xResMat);
980 return;
985 if ( nC != nR || nC == 0 )
986 PushIllegalArgument();
987 else if (!ScMatrix::IsSizeAllocatable( nC, nR))
988 PushError( FormulaError::MatrixSize);
989 else
991 // LUP decomposition is done inplace, use copy.
992 ScMatrixRef xLU = pMat->Clone();
993 // The result matrix.
994 ScMatrixRef xY = GetNewMat( nR, nR, /*bEmpty*/true );
995 if (!xLU || !xY)
996 PushError( FormulaError::CodeOverflow);
997 else
999 ::std::vector< SCSIZE> P(nR);
1000 int nDetSign = lcl_LUP_decompose( xLU.get(), nR, P);
1001 if (!nDetSign)
1002 PushIllegalArgument();
1003 else
1005 // Solve equation for each column.
1006 ::std::vector< double> B(nR);
1007 ::std::vector< double> X(nR);
1008 for (SCSIZE j=0; j < nR; ++j)
1010 for (SCSIZE i=0; i < nR; ++i)
1011 B[i] = 0.0;
1012 B[j] = 1.0;
1013 lcl_LUP_solve( xLU.get(), nR, P, B, X);
1014 for (SCSIZE i=0; i < nR; ++i)
1015 xY->PutDouble( X[i], j, i);
1017 #ifdef DEBUG_SC_LUP_DECOMPOSITION
1018 /* Possible checks for ill-condition:
1019 * 1. Scale matrix, invert scaled matrix. If there are
1020 * elements of the inverted matrix that are several
1021 * orders of magnitude greater than 1 =>
1022 * ill-conditioned.
1023 * Just how much is "several orders"?
1024 * 2. Invert the inverted matrix and assess whether the
1025 * result is sufficiently close to the original matrix.
1026 * If not => ill-conditioned.
1027 * Just what is sufficient?
1028 * 3. Multiplying the inverse by the original matrix should
1029 * produce a result sufficiently close to the identity
1030 * matrix.
1031 * Just what is sufficient?
1033 * The following is #3.
1035 const double fInvEpsilon = 1.0E-7;
1036 ScMatrixRef xR = GetNewMat( nR, nR);
1037 if (xR)
1039 ScMatrix* pR = xR.get();
1040 lcl_MFastMult( pMat, xY.get(), pR, nR, nR, nR);
1041 fprintf( stderr, "\n%s\n", "ScMatInv(): mult-identity");
1042 for (SCSIZE i=0; i < nR; ++i)
1044 for (SCSIZE j=0; j < nR; ++j)
1046 double fTmp = pR->GetDouble( j, i);
1047 fprintf( stderr, "%8.2g ", fTmp);
1048 if (fabs( fTmp - (i == j)) > fInvEpsilon)
1049 SetError( FormulaError::IllegalArgument);
1051 fprintf( stderr, "\n%s\n", "");
1054 #endif
1055 if (nGlobalError != FormulaError::NONE)
1056 PushError( nGlobalError);
1057 else
1058 PushMatrix( xY);
1064 void ScInterpreter::ScMatMult()
1066 if ( !MustHaveParamCount( GetByte(), 2 ) )
1067 return;
1069 ScMatrixRef pMat2 = GetMatrix();
1070 ScMatrixRef pMat1 = GetMatrix();
1071 ScMatrixRef pRMat;
1072 if (pMat1 && pMat2)
1074 if ( pMat1->IsNumeric() && pMat2->IsNumeric() )
1076 SCSIZE nC1, nC2;
1077 SCSIZE nR1, nR2;
1078 pMat1->GetDimensions(nC1, nR1);
1079 pMat2->GetDimensions(nC2, nR2);
1080 if (nC1 != nR2)
1081 PushIllegalArgument();
1082 else
1084 pRMat = GetNewMat(nC2, nR1, /*bEmpty*/true);
1085 if (pRMat)
1087 KahanSum fSum;
1088 for (SCSIZE i = 0; i < nR1; i++)
1090 for (SCSIZE j = 0; j < nC2; j++)
1092 fSum = 0.0;
1093 for (SCSIZE k = 0; k < nC1; k++)
1095 fSum += pMat1->GetDouble(k,i)*pMat2->GetDouble(j,k);
1097 pRMat->PutDouble(fSum.get(), j, i);
1100 PushMatrix(pRMat);
1102 else
1103 PushIllegalArgument();
1106 else
1107 PushNoValue();
1109 else
1110 PushIllegalParameter();
1113 void ScInterpreter::ScMatSequence()
1115 sal_uInt8 nParamCount = GetByte();
1116 if (!MustHaveParamCount(nParamCount, 1, 4))
1117 return;
1119 // 4th argument is the step number (optional)
1120 double nSteps = 1.0;
1121 if (nParamCount == 4)
1122 nSteps = GetDoubleWithDefault(nSteps);
1124 // 3d argument is the start number (optional)
1125 double nStart = 1.0;
1126 if (nParamCount >= 3)
1127 nStart = GetDoubleWithDefault(nStart);
1129 // 2nd argument is the col number (optional)
1130 sal_Int32 nColumns = 1;
1131 if (nParamCount >= 2)
1133 nColumns = GetInt32WithDefault(nColumns);
1134 if (nColumns < 1)
1136 PushIllegalArgument();
1137 return;
1141 // 1st argument is the row number (required)
1142 sal_Int32 nRows = GetInt32WithDefault(1);
1143 if (nRows < 1)
1145 PushIllegalArgument();
1146 return;
1149 if (nGlobalError != FormulaError::NONE)
1151 PushError(nGlobalError);
1152 return;
1155 size_t nMatrixSize = nColumns * nRows;
1156 ScMatrixRef pResMat = GetNewMat(nColumns, nRows, /*bEmpty*/true);
1157 for (size_t iPos = 0; iPos < nMatrixSize; iPos++)
1159 pResMat->PutDoubleTrans(nStart, iPos);
1160 nStart = nStart + nSteps;
1163 if (pResMat)
1165 PushMatrix(pResMat);
1167 else
1169 PushIllegalParameter();
1170 return;
1174 void ScInterpreter::ScMatTrans()
1176 if ( !MustHaveParamCount( GetByte(), 1 ) )
1177 return;
1179 ScMatrixRef pMat = GetMatrix();
1180 ScMatrixRef pRMat;
1181 if (pMat)
1183 SCSIZE nC, nR;
1184 pMat->GetDimensions(nC, nR);
1185 pRMat = GetNewMat(nR, nC, /*bEmpty*/true);
1186 if ( pRMat )
1188 pMat->MatTrans(*pRMat);
1189 PushMatrix(pRMat);
1191 else
1192 PushIllegalArgument();
1194 else
1195 PushIllegalParameter();
1198 /** Minimum extent of one result matrix dimension.
1199 For a row or column vector to be replicated the larger matrix dimension is
1200 returned, else the smaller dimension.
1202 static SCSIZE lcl_GetMinExtent( SCSIZE n1, SCSIZE n2 )
1204 if (n1 == 1)
1205 return n2;
1206 else if (n2 == 1)
1207 return n1;
1208 else if (n1 < n2)
1209 return n1;
1210 else
1211 return n2;
1214 static ScMatrixRef lcl_MatrixCalculation(
1215 const ScMatrix& rMat1, const ScMatrix& rMat2, ScInterpreter* pInterpreter, const ScMatrix::CalculateOpFunction& Op)
1217 SCSIZE nC1, nC2, nMinC;
1218 SCSIZE nR1, nR2, nMinR;
1219 rMat1.GetDimensions(nC1, nR1);
1220 rMat2.GetDimensions(nC2, nR2);
1221 nMinC = lcl_GetMinExtent( nC1, nC2);
1222 nMinR = lcl_GetMinExtent( nR1, nR2);
1223 ScMatrixRef xResMat = pInterpreter->GetNewMat(nMinC, nMinR, /*bEmpty*/true);
1224 if (xResMat)
1225 xResMat->ExecuteBinaryOp(nMinC, nMinR, rMat1, rMat2, pInterpreter, Op);
1226 return xResMat;
1229 ScMatrixRef ScInterpreter::MatConcat(const ScMatrixRef& pMat1, const ScMatrixRef& pMat2)
1231 SCSIZE nC1, nC2, nMinC;
1232 SCSIZE nR1, nR2, nMinR;
1233 pMat1->GetDimensions(nC1, nR1);
1234 pMat2->GetDimensions(nC2, nR2);
1235 nMinC = lcl_GetMinExtent( nC1, nC2);
1236 nMinR = lcl_GetMinExtent( nR1, nR2);
1237 ScMatrixRef xResMat = GetNewMat(nMinC, nMinR, /*bEmpty*/true);
1238 if (xResMat)
1240 xResMat->MatConcat(nMinC, nMinR, pMat1, pMat2, mrContext, mrDoc.GetSharedStringPool());
1242 return xResMat;
1245 // for DATE, TIME, DATETIME, DURATION
1246 static void lcl_GetDiffDateTimeFmtType( SvNumFormatType& nFuncFmt, SvNumFormatType nFmt1, SvNumFormatType nFmt2 )
1248 if ( nFmt1 == SvNumFormatType::UNDEFINED && nFmt2 == SvNumFormatType::UNDEFINED )
1249 return;
1251 if ( nFmt1 == nFmt2 )
1253 if ( nFmt1 == SvNumFormatType::TIME || nFmt1 == SvNumFormatType::DATETIME
1254 || nFmt1 == SvNumFormatType::DURATION )
1255 nFuncFmt = SvNumFormatType::DURATION; // times result in time duration
1256 // else: nothing special, number (date - date := days)
1258 else if ( nFmt1 == SvNumFormatType::UNDEFINED )
1259 nFuncFmt = nFmt2; // e.g. date + days := date
1260 else if ( nFmt2 == SvNumFormatType::UNDEFINED )
1261 nFuncFmt = nFmt1;
1262 else
1264 if ( nFmt1 == SvNumFormatType::DATE || nFmt2 == SvNumFormatType::DATE ||
1265 nFmt1 == SvNumFormatType::DATETIME || nFmt2 == SvNumFormatType::DATETIME )
1267 if ( nFmt1 == SvNumFormatType::TIME || nFmt2 == SvNumFormatType::TIME )
1268 nFuncFmt = SvNumFormatType::DATETIME; // date + time
1273 void ScInterpreter::ScAdd()
1275 CalculateAddSub(false);
1278 void ScInterpreter::CalculateAddSub(bool _bSub)
1280 ScMatrixRef pMat1 = nullptr;
1281 ScMatrixRef pMat2 = nullptr;
1282 double fVal1 = 0.0, fVal2 = 0.0;
1283 SvNumFormatType nFmt1, nFmt2;
1284 nFmt1 = nFmt2 = SvNumFormatType::UNDEFINED;
1285 bool bDuration = false;
1286 SvNumFormatType nFmtCurrencyType = nCurFmtType;
1287 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1288 SvNumFormatType nFmtPercentType = nCurFmtType;
1289 if ( GetStackType() == svMatrix )
1290 pMat2 = GetMatrix();
1291 else
1293 fVal2 = GetDouble();
1294 switch ( nCurFmtType )
1296 case SvNumFormatType::DATE :
1297 case SvNumFormatType::TIME :
1298 case SvNumFormatType::DATETIME :
1299 case SvNumFormatType::DURATION :
1300 nFmt2 = nCurFmtType;
1301 bDuration = true;
1302 break;
1303 case SvNumFormatType::CURRENCY :
1304 nFmtCurrencyType = nCurFmtType;
1305 nFmtCurrencyIndex = nCurFmtIndex;
1306 break;
1307 case SvNumFormatType::PERCENT :
1308 nFmtPercentType = SvNumFormatType::PERCENT;
1309 break;
1310 default: break;
1313 if ( GetStackType() == svMatrix )
1314 pMat1 = GetMatrix();
1315 else
1317 fVal1 = GetDouble();
1318 switch ( nCurFmtType )
1320 case SvNumFormatType::DATE :
1321 case SvNumFormatType::TIME :
1322 case SvNumFormatType::DATETIME :
1323 case SvNumFormatType::DURATION :
1324 nFmt1 = nCurFmtType;
1325 bDuration = true;
1326 break;
1327 case SvNumFormatType::CURRENCY :
1328 nFmtCurrencyType = nCurFmtType;
1329 nFmtCurrencyIndex = nCurFmtIndex;
1330 break;
1331 case SvNumFormatType::PERCENT :
1332 nFmtPercentType = SvNumFormatType::PERCENT;
1333 break;
1334 default: break;
1337 if (pMat1 && pMat2)
1339 ScMatrixRef pResMat;
1340 if ( _bSub )
1342 pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixSub);
1344 else
1346 pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixAdd);
1349 if (!pResMat)
1350 PushNoValue();
1351 else
1352 PushMatrix(pResMat);
1354 else if (pMat1 || pMat2)
1356 double fVal;
1357 bool bFlag;
1358 ScMatrixRef pMat = std::move(pMat1);
1359 if (!pMat)
1361 fVal = fVal1;
1362 pMat = std::move(pMat2);
1363 bFlag = true; // double - Matrix
1365 else
1367 fVal = fVal2;
1368 bFlag = false; // Matrix - double
1370 SCSIZE nC, nR;
1371 pMat->GetDimensions(nC, nR);
1372 ScMatrixRef pResMat = GetNewMat(nC, nR, true);
1373 if (pResMat)
1375 if (_bSub)
1377 pMat->SubOp( bFlag, fVal, *pResMat);
1379 else
1381 pMat->AddOp( fVal, *pResMat);
1383 PushMatrix(pResMat);
1385 else
1386 PushIllegalArgument();
1388 else
1390 // Determine nFuncFmtType type before PushDouble().
1391 if ( nFmtCurrencyType == SvNumFormatType::CURRENCY )
1393 nFuncFmtType = nFmtCurrencyType;
1394 nFuncFmtIndex = nFmtCurrencyIndex;
1396 else
1398 lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 );
1399 if (nFmtPercentType == SvNumFormatType::PERCENT && nFuncFmtType == SvNumFormatType::NUMBER)
1400 nFuncFmtType = SvNumFormatType::PERCENT;
1402 if ((nFuncFmtType == SvNumFormatType::DURATION || bDuration)
1403 && ((_bSub && std::fabs(fVal1 - fVal2) <= SAL_MAX_INT32)
1404 || (!_bSub && std::fabs(fVal1 + fVal2) <= SAL_MAX_INT32)))
1406 // Limit to microseconds resolution on date inflicted or duration
1407 // values of 24 hours or more.
1408 const sal_uInt64 nEpsilon = ((std::fabs(fVal1) >= 1.0 || std::fabs(fVal2) >= 1.0) ?
1409 ::tools::Duration::kAccuracyEpsilonNanosecondsMicroseconds :
1410 ::tools::Duration::kAccuracyEpsilonNanoseconds);
1411 if (_bSub)
1412 PushDouble( ::tools::Duration( fVal1 - fVal2, nEpsilon).GetInDays());
1413 else
1414 PushDouble( ::tools::Duration( fVal1 + fVal2, nEpsilon).GetInDays());
1416 else
1418 if (_bSub)
1419 PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) );
1420 else
1421 PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) );
1426 void ScInterpreter::ScAmpersand()
1428 ScMatrixRef pMat1 = nullptr;
1429 ScMatrixRef pMat2 = nullptr;
1430 OUString sStr1, sStr2;
1431 if ( GetStackType() == svMatrix )
1432 pMat2 = GetMatrix();
1433 else
1434 sStr2 = GetString().getString();
1435 if ( GetStackType() == svMatrix )
1436 pMat1 = GetMatrix();
1437 else
1438 sStr1 = GetString().getString();
1439 if (pMat1 && pMat2)
1441 ScMatrixRef pResMat = MatConcat(pMat1, pMat2);
1442 if (!pResMat)
1443 PushNoValue();
1444 else
1445 PushMatrix(pResMat);
1447 else if (pMat1 || pMat2)
1449 OUString sStr;
1450 bool bFlag;
1451 ScMatrixRef pMat = std::move(pMat1);
1452 if (!pMat)
1454 sStr = sStr1;
1455 pMat = std::move(pMat2);
1456 bFlag = true; // double - Matrix
1458 else
1460 sStr = sStr2;
1461 bFlag = false; // Matrix - double
1463 SCSIZE nC, nR;
1464 pMat->GetDimensions(nC, nR);
1465 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1466 if (pResMat)
1468 if (nGlobalError != FormulaError::NONE)
1470 for (SCSIZE i = 0; i < nC; ++i)
1471 for (SCSIZE j = 0; j < nR; ++j)
1472 pResMat->PutError( nGlobalError, i, j);
1474 else if (bFlag)
1476 for (SCSIZE i = 0; i < nC; ++i)
1477 for (SCSIZE j = 0; j < nR; ++j)
1479 FormulaError nErr = pMat->GetErrorIfNotString( i, j);
1480 if (nErr != FormulaError::NONE)
1481 pResMat->PutError( nErr, i, j);
1482 else
1484 OUString aTmp = sStr + pMat->GetString(mrContext, i, j).getString();
1485 pResMat->PutString(mrStrPool.intern(aTmp), i, j);
1489 else
1491 for (SCSIZE i = 0; i < nC; ++i)
1492 for (SCSIZE j = 0; j < nR; ++j)
1494 FormulaError nErr = pMat->GetErrorIfNotString( i, j);
1495 if (nErr != FormulaError::NONE)
1496 pResMat->PutError( nErr, i, j);
1497 else
1499 OUString aTmp = pMat->GetString(mrContext, i, j).getString() + sStr;
1500 pResMat->PutString(mrStrPool.intern(aTmp), i, j);
1504 PushMatrix(pResMat);
1506 else
1507 PushIllegalArgument();
1509 else
1511 if ( CheckStringResultLen( sStr1, sStr2.getLength() ) )
1512 sStr1 += sStr2;
1513 PushString(sStr1);
1517 void ScInterpreter::ScSub()
1519 CalculateAddSub(true);
1522 void ScInterpreter::ScMul()
1524 ScMatrixRef pMat1 = nullptr;
1525 ScMatrixRef pMat2 = nullptr;
1526 double fVal1 = 0.0, fVal2 = 0.0;
1527 SvNumFormatType nFmtCurrencyType = nCurFmtType;
1528 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1529 if ( GetStackType() == svMatrix )
1530 pMat2 = GetMatrix();
1531 else
1533 fVal2 = GetDouble();
1534 switch ( nCurFmtType )
1536 case SvNumFormatType::CURRENCY :
1537 nFmtCurrencyType = nCurFmtType;
1538 nFmtCurrencyIndex = nCurFmtIndex;
1539 break;
1540 default: break;
1543 if ( GetStackType() == svMatrix )
1544 pMat1 = GetMatrix();
1545 else
1547 fVal1 = GetDouble();
1548 switch ( nCurFmtType )
1550 case SvNumFormatType::CURRENCY :
1551 nFmtCurrencyType = nCurFmtType;
1552 nFmtCurrencyIndex = nCurFmtIndex;
1553 break;
1554 default: break;
1557 if (pMat1 && pMat2)
1559 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixMul);
1560 if (!pResMat)
1561 PushNoValue();
1562 else
1563 PushMatrix(pResMat);
1565 else if (pMat1 || pMat2)
1567 double fVal;
1568 ScMatrixRef pMat = std::move(pMat1);
1569 if (!pMat)
1571 fVal = fVal1;
1572 pMat = std::move(pMat2);
1574 else
1575 fVal = fVal2;
1576 SCSIZE nC, nR;
1577 pMat->GetDimensions(nC, nR);
1578 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1579 if (pResMat)
1581 pMat->MulOp( fVal, *pResMat);
1582 PushMatrix(pResMat);
1584 else
1585 PushIllegalArgument();
1587 else
1589 // Determine nFuncFmtType type before PushDouble().
1590 if ( nFmtCurrencyType == SvNumFormatType::CURRENCY )
1592 nFuncFmtType = nFmtCurrencyType;
1593 nFuncFmtIndex = nFmtCurrencyIndex;
1595 PushDouble(fVal1 * fVal2);
1599 void ScInterpreter::ScDiv()
1601 ScMatrixRef pMat1 = nullptr;
1602 ScMatrixRef pMat2 = nullptr;
1603 double fVal1 = 0.0, fVal2 = 0.0;
1604 SvNumFormatType nFmtCurrencyType = nCurFmtType;
1605 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1606 SvNumFormatType nFmtCurrencyType2 = SvNumFormatType::UNDEFINED;
1607 if ( GetStackType() == svMatrix )
1608 pMat2 = GetMatrix();
1609 else
1611 fVal2 = GetDouble();
1612 // do not take over currency, 123kg/456USD is not USD
1613 nFmtCurrencyType2 = nCurFmtType;
1615 if ( GetStackType() == svMatrix )
1616 pMat1 = GetMatrix();
1617 else
1619 fVal1 = GetDouble();
1620 switch ( nCurFmtType )
1622 case SvNumFormatType::CURRENCY :
1623 nFmtCurrencyType = nCurFmtType;
1624 nFmtCurrencyIndex = nCurFmtIndex;
1625 break;
1626 default: break;
1629 if (pMat1 && pMat2)
1631 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixDiv);
1632 if (!pResMat)
1633 PushNoValue();
1634 else
1635 PushMatrix(pResMat);
1637 else if (pMat1 || pMat2)
1639 double fVal;
1640 bool bFlag;
1641 ScMatrixRef pMat = std::move(pMat1);
1642 if (!pMat)
1644 fVal = fVal1;
1645 pMat = std::move(pMat2);
1646 bFlag = true; // double - Matrix
1648 else
1650 fVal = fVal2;
1651 bFlag = false; // Matrix - double
1653 SCSIZE nC, nR;
1654 pMat->GetDimensions(nC, nR);
1655 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1656 if (pResMat)
1658 pMat->DivOp( bFlag, fVal, *pResMat);
1659 PushMatrix(pResMat);
1661 else
1662 PushIllegalArgument();
1664 else
1666 // Determine nFuncFmtType type before PushDouble().
1667 if ( nFmtCurrencyType == SvNumFormatType::CURRENCY &&
1668 nFmtCurrencyType2 != SvNumFormatType::CURRENCY)
1669 { // even USD/USD is not USD
1670 nFuncFmtType = nFmtCurrencyType;
1671 nFuncFmtIndex = nFmtCurrencyIndex;
1673 PushDouble( div( fVal1, fVal2) );
1677 void ScInterpreter::ScPower()
1679 if ( MustHaveParamCount( GetByte(), 2 ) )
1680 ScPow();
1683 void ScInterpreter::ScPow()
1685 ScMatrixRef pMat1 = nullptr;
1686 ScMatrixRef pMat2 = nullptr;
1687 double fVal1 = 0.0, fVal2 = 0.0;
1688 if ( GetStackType() == svMatrix )
1689 pMat2 = GetMatrix();
1690 else
1691 fVal2 = GetDouble();
1692 if ( GetStackType() == svMatrix )
1693 pMat1 = GetMatrix();
1694 else
1695 fVal1 = GetDouble();
1696 if (pMat1 && pMat2)
1698 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixPow);
1699 if (!pResMat)
1700 PushNoValue();
1701 else
1702 PushMatrix(pResMat);
1704 else if (pMat1 || pMat2)
1706 double fVal;
1707 bool bFlag;
1708 ScMatrixRef pMat = std::move(pMat1);
1709 if (!pMat)
1711 fVal = fVal1;
1712 pMat = std::move(pMat2);
1713 bFlag = true; // double - Matrix
1715 else
1717 fVal = fVal2;
1718 bFlag = false; // Matrix - double
1720 SCSIZE nC, nR;
1721 pMat->GetDimensions(nC, nR);
1722 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1723 if (pResMat)
1725 pMat->PowOp( bFlag, fVal, *pResMat);
1726 PushMatrix(pResMat);
1728 else
1729 PushIllegalArgument();
1731 else
1733 PushDouble( sc::power( fVal1, fVal2));
1737 void ScInterpreter::ScSumProduct()
1739 short nParamCount = GetByte();
1740 if ( !MustHaveParamCountMin( nParamCount, 1) )
1741 return;
1743 // XXX NOTE: Excel returns #VALUE! for reference list and 0 (why?) for
1744 // array of references. We calculate the proper individual arrays if sizes
1745 // match.
1747 size_t nInRefList = 0;
1748 ScMatrixRef pMatLast;
1749 ScMatrixRef pMat;
1751 pMatLast = GetMatrix( --nParamCount, nInRefList);
1752 if (!pMatLast)
1754 PushIllegalParameter();
1755 return;
1758 SCSIZE nC, nCLast, nR, nRLast;
1759 pMatLast->GetDimensions(nCLast, nRLast);
1760 std::vector<double> aResArray;
1761 pMatLast->GetDoubleArray(aResArray);
1763 while (nParamCount--)
1765 pMat = GetMatrix( nParamCount, nInRefList);
1766 if (!pMat)
1768 PushIllegalParameter();
1769 return;
1771 pMat->GetDimensions(nC, nR);
1772 if (nC != nCLast || nR != nRLast)
1774 PushNoValue();
1775 return;
1778 pMat->MergeDoubleArrayMultiply(aResArray);
1781 KahanSum fSum = 0.0;
1782 for( double fPosArray : aResArray )
1784 FormulaError nErr = GetDoubleErrorValue(fPosArray);
1785 if (nErr == FormulaError::NONE)
1786 fSum += fPosArray;
1787 else if (nErr != FormulaError::ElementNaN)
1789 // Propagate the first error encountered, ignore "this is not a number" elements.
1790 PushError(nErr);
1791 return;
1795 PushDouble(fSum.get());
1798 void ScInterpreter::ScSumX2MY2()
1800 CalculateSumX2MY2SumX2DY2(false);
1802 void ScInterpreter::CalculateSumX2MY2SumX2DY2(bool _bSumX2DY2)
1804 if ( !MustHaveParamCount( GetByte(), 2 ) )
1805 return;
1807 ScMatrixRef pMat1 = nullptr;
1808 ScMatrixRef pMat2 = nullptr;
1809 SCSIZE i, j;
1810 pMat2 = GetMatrix();
1811 pMat1 = GetMatrix();
1812 if (!pMat2 || !pMat1)
1814 PushIllegalParameter();
1815 return;
1817 SCSIZE nC1, nC2;
1818 SCSIZE nR1, nR2;
1819 pMat2->GetDimensions(nC2, nR2);
1820 pMat1->GetDimensions(nC1, nR1);
1821 if (nC1 != nC2 || nR1 != nR2)
1823 PushNoValue();
1824 return;
1826 double fVal;
1827 KahanSum fSum = 0.0;
1828 for (i = 0; i < nC1; i++)
1829 for (j = 0; j < nR1; j++)
1830 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
1832 fVal = pMat1->GetDouble(i,j);
1833 fSum += fVal * fVal;
1834 fVal = pMat2->GetDouble(i,j);
1835 if ( _bSumX2DY2 )
1836 fSum += fVal * fVal;
1837 else
1838 fSum -= fVal * fVal;
1840 PushDouble(fSum.get());
1843 void ScInterpreter::ScSumX2DY2()
1845 CalculateSumX2MY2SumX2DY2(true);
1848 void ScInterpreter::ScSumXMY2()
1850 if ( !MustHaveParamCount( GetByte(), 2 ) )
1851 return;
1853 ScMatrixRef pMat2 = GetMatrix();
1854 ScMatrixRef pMat1 = GetMatrix();
1855 if (!pMat2 || !pMat1)
1857 PushIllegalParameter();
1858 return;
1860 SCSIZE nC1, nC2;
1861 SCSIZE nR1, nR2;
1862 pMat2->GetDimensions(nC2, nR2);
1863 pMat1->GetDimensions(nC1, nR1);
1864 if (nC1 != nC2 || nR1 != nR2)
1866 PushNoValue();
1867 return;
1868 } // if (nC1 != nC2 || nR1 != nR2)
1869 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixSub);
1870 if (!pResMat)
1872 PushNoValue();
1874 else
1876 PushDouble(pResMat->SumSquare(false).maAccumulator.get());
1880 void ScInterpreter::ScFrequency()
1882 if ( !MustHaveParamCount( GetByte(), 2 ) )
1883 return;
1885 vector<double> aBinArray;
1886 vector<tools::Long> aBinIndexOrder;
1888 GetSortArray( 1, aBinArray, &aBinIndexOrder, false, false );
1889 SCSIZE nBinSize = aBinArray.size();
1890 if (nGlobalError != FormulaError::NONE)
1892 PushNoValue();
1893 return;
1896 vector<double> aDataArray;
1897 GetSortArray( 1, aDataArray, nullptr, false, false );
1898 SCSIZE nDataSize = aDataArray.size();
1900 if (aDataArray.empty() || nGlobalError != FormulaError::NONE)
1902 PushNoValue();
1903 return;
1905 ScMatrixRef pResMat = GetNewMat(1, nBinSize+1, /*bEmpty*/true);
1906 if (!pResMat)
1908 PushIllegalArgument();
1909 return;
1912 if (nBinSize != aBinIndexOrder.size())
1914 PushIllegalArgument();
1915 return;
1918 SCSIZE j;
1919 SCSIZE i = 0;
1920 for (j = 0; j < nBinSize; ++j)
1922 SCSIZE nCount = 0;
1923 while (i < nDataSize && aDataArray[i] <= aBinArray[j])
1925 ++nCount;
1926 ++i;
1928 pResMat->PutDouble(static_cast<double>(nCount), aBinIndexOrder[j]);
1930 pResMat->PutDouble(static_cast<double>(nDataSize-i), j);
1931 PushMatrix(pResMat);
1934 namespace {
1936 // Helper methods for LINEST/LOGEST and TREND/GROWTH
1937 // All matrices must already exist and have the needed size, no control tests
1938 // done. Those methods, which names start with lcl_T, are adapted to case 3,
1939 // where Y (=observed values) is given as row.
1940 // Remember, ScMatrix matrices are zero based, index access (column,row).
1942 // <A;B> over all elements; uses the matrices as vectors of length M
1943 double lcl_GetSumProduct(const ScMatrixRef& pMatA, const ScMatrixRef& pMatB, SCSIZE nM)
1945 KahanSum fSum = 0.0;
1946 for (SCSIZE i=0; i<nM; i++)
1947 fSum += pMatA->GetDouble(i) * pMatB->GetDouble(i);
1948 return fSum.get();
1951 // Special version for use within QR decomposition.
1952 // Euclidean norm of column index C starting in row index R;
1953 // matrix A has count N rows.
1954 double lcl_GetColumnEuclideanNorm(const ScMatrixRef& pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN)
1956 KahanSum fNorm = 0.0;
1957 for (SCSIZE row=nR; row<nN; row++)
1958 fNorm += (pMatA->GetDouble(nC,row)) * (pMatA->GetDouble(nC,row));
1959 return sqrt(fNorm.get());
1962 // Euclidean norm of row index R starting in column index C;
1963 // matrix A has count N columns.
1964 double lcl_TGetColumnEuclideanNorm(const ScMatrixRef& pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN)
1966 KahanSum fNorm = 0.0;
1967 for (SCSIZE col=nC; col<nN; col++)
1968 fNorm += (pMatA->GetDouble(col,nR)) * (pMatA->GetDouble(col,nR));
1969 return sqrt(fNorm.get());
1972 // Special version for use within QR decomposition.
1973 // Maximum norm of column index C starting in row index R;
1974 // matrix A has count N rows.
1975 double lcl_GetColumnMaximumNorm(const ScMatrixRef& pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN)
1977 double fNorm = 0.0;
1978 for (SCSIZE row=nR; row<nN; row++)
1980 double fVal = fabs(pMatA->GetDouble(nC,row));
1981 if (fNorm < fVal)
1982 fNorm = fVal;
1984 return fNorm;
1987 // Maximum norm of row index R starting in col index C;
1988 // matrix A has count N columns.
1989 double lcl_TGetColumnMaximumNorm(const ScMatrixRef& pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN)
1991 double fNorm = 0.0;
1992 for (SCSIZE col=nC; col<nN; col++)
1994 double fVal = fabs(pMatA->GetDouble(col,nR));
1995 if (fNorm < fVal)
1996 fNorm = fVal;
1998 return fNorm;
2001 // Special version for use within QR decomposition.
2002 // <A(Ca);B(Cb)> starting in row index R;
2003 // Ca and Cb are indices of columns, matrices A and B have count N rows.
2004 double lcl_GetColumnSumProduct(const ScMatrixRef& pMatA, SCSIZE nCa,
2005 const ScMatrixRef& pMatB, SCSIZE nCb, SCSIZE nR, SCSIZE nN)
2007 KahanSum fResult = 0.0;
2008 for (SCSIZE row=nR; row<nN; row++)
2009 fResult += pMatA->GetDouble(nCa,row) * pMatB->GetDouble(nCb,row);
2010 return fResult.get();
2013 // <A(Ra);B(Rb)> starting in column index C;
2014 // Ra and Rb are indices of rows, matrices A and B have count N columns.
2015 double lcl_TGetColumnSumProduct(const ScMatrixRef& pMatA, SCSIZE nRa,
2016 const ScMatrixRef& pMatB, SCSIZE nRb, SCSIZE nC, SCSIZE nN)
2018 KahanSum fResult = 0.0;
2019 for (SCSIZE col=nC; col<nN; col++)
2020 fResult += pMatA->GetDouble(col,nRa) * pMatB->GetDouble(col,nRb);
2021 return fResult.get();
2024 // no mathematical signum, but used to switch between adding and subtracting
2025 double lcl_GetSign(double fValue)
2027 return (fValue >= 0.0 ? 1.0 : -1.0 );
2030 /* Calculates a QR decomposition with Householder reflection.
2031 * For each NxK matrix A exists a decomposition A=Q*R with an orthogonal
2032 * NxN matrix Q and a NxK matrix R.
2033 * Q=H1*H2*...*Hk with Householder matrices H. Such a householder matrix can
2034 * be build from a vector u by H=I-(2/u'u)*(u u'). This vectors u are returned
2035 * in the columns of matrix A, overwriting the old content.
2036 * The matrix R has a quadric upper part KxK with values in the upper right
2037 * triangle and zeros in all other elements. Here the diagonal elements of R
2038 * are stored in the vector R and the other upper right elements in the upper
2039 * right of the matrix A.
2040 * The function returns false, if calculation breaks. But because of round-off
2041 * errors singularity is often not detected.
2043 bool lcl_CalculateQRdecomposition(const ScMatrixRef& pMatA,
2044 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN)
2046 // ScMatrix matrices are zero based, index access (column,row)
2047 for (SCSIZE col = 0; col <nK; col++)
2049 // calculate vector u of the householder transformation
2050 const double fScale = lcl_GetColumnMaximumNorm(pMatA, col, col, nN);
2051 if (fScale == 0.0)
2053 // A is singular
2054 return false;
2056 for (SCSIZE row = col; row <nN; row++)
2057 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row);
2059 const double fEuclid = lcl_GetColumnEuclideanNorm(pMatA, col, col, nN);
2060 const double fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(col,col)));
2061 const double fSignum = lcl_GetSign(pMatA->GetDouble(col,col));
2062 pMatA->PutDouble( pMatA->GetDouble(col,col) + fSignum*fEuclid, col,col);
2063 pVecR[col] = -fSignum * fScale * fEuclid;
2065 // apply Householder transformation to A
2066 for (SCSIZE c=col+1; c<nK; c++)
2068 const double fSum =lcl_GetColumnSumProduct(pMatA, col, pMatA, c, col, nN);
2069 for (SCSIZE row = col; row <nN; row++)
2070 pMatA->PutDouble( pMatA->GetDouble(c,row) - fSum * fFactor * pMatA->GetDouble(col,row), c, row);
2073 return true;
2076 // same with transposed matrix A, N is count of columns, K count of rows
2077 bool lcl_TCalculateQRdecomposition(const ScMatrixRef& pMatA,
2078 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN)
2080 double fSum ;
2081 // ScMatrix matrices are zero based, index access (column,row)
2082 for (SCSIZE row = 0; row <nK; row++)
2084 // calculate vector u of the householder transformation
2085 const double fScale = lcl_TGetColumnMaximumNorm(pMatA, row, row, nN);
2086 if (fScale == 0.0)
2088 // A is singular
2089 return false;
2091 for (SCSIZE col = row; col <nN; col++)
2092 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row);
2094 const double fEuclid = lcl_TGetColumnEuclideanNorm(pMatA, row, row, nN);
2095 const double fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(row,row)));
2096 const double fSignum = lcl_GetSign(pMatA->GetDouble(row,row));
2097 pMatA->PutDouble( pMatA->GetDouble(row,row) + fSignum*fEuclid, row,row);
2098 pVecR[row] = -fSignum * fScale * fEuclid;
2100 // apply Householder transformation to A
2101 for (SCSIZE r=row+1; r<nK; r++)
2103 fSum =lcl_TGetColumnSumProduct(pMatA, row, pMatA, r, row, nN);
2104 for (SCSIZE col = row; col <nN; col++)
2105 pMatA->PutDouble(
2106 pMatA->GetDouble(col,r) - fSum * fFactor * pMatA->GetDouble(col,row), col, r);
2109 return true;
2112 /* Applies a Householder transformation to a column vector Y with is given as
2113 * Nx1 Matrix. The vector u, from which the Householder transformation is built,
2114 * is the column part in matrix A, with column index C, starting with row
2115 * index C. A is the result of the QR decomposition as obtained from
2116 * lcl_CalculateQRdecomposition.
2118 void lcl_ApplyHouseholderTransformation(const ScMatrixRef& pMatA, SCSIZE nC,
2119 const ScMatrixRef& pMatY, SCSIZE nN)
2121 // ScMatrix matrices are zero based, index access (column,row)
2122 double fDenominator = lcl_GetColumnSumProduct(pMatA, nC, pMatA, nC, nC, nN);
2123 double fNumerator = lcl_GetColumnSumProduct(pMatA, nC, pMatY, 0, nC, nN);
2124 double fFactor = 2.0 * (fNumerator/fDenominator);
2125 for (SCSIZE row = nC; row < nN; row++)
2126 pMatY->PutDouble(
2127 pMatY->GetDouble(row) - fFactor * pMatA->GetDouble(nC,row), row);
2130 // Same with transposed matrices A and Y.
2131 void lcl_TApplyHouseholderTransformation(const ScMatrixRef& pMatA, SCSIZE nR,
2132 const ScMatrixRef& pMatY, SCSIZE nN)
2134 // ScMatrix matrices are zero based, index access (column,row)
2135 double fDenominator = lcl_TGetColumnSumProduct(pMatA, nR, pMatA, nR, nR, nN);
2136 double fNumerator = lcl_TGetColumnSumProduct(pMatA, nR, pMatY, 0, nR, nN);
2137 double fFactor = 2.0 * (fNumerator/fDenominator);
2138 for (SCSIZE col = nR; col < nN; col++)
2139 pMatY->PutDouble(
2140 pMatY->GetDouble(col) - fFactor * pMatA->GetDouble(col,nR), col);
2143 /* Solve for X in R*X=S using back substitution. The solution X overwrites S.
2144 * Uses R from the result of the QR decomposition of a NxK matrix A.
2145 * S is a column vector given as matrix, with at least elements on index
2146 * 0 to K-1; elements on index>=K are ignored. Vector R must not have zero
2147 * elements, no check is done.
2149 void lcl_SolveWithUpperRightTriangle(const ScMatrixRef& pMatA,
2150 ::std::vector< double>& pVecR, const ScMatrixRef& pMatS,
2151 SCSIZE nK, bool bIsTransposed)
2153 // ScMatrix matrices are zero based, index access (column,row)
2154 SCSIZE row;
2155 // SCSIZE is never negative, therefore test with rowp1=row+1
2156 for (SCSIZE rowp1 = nK; rowp1>0; rowp1--)
2158 row = rowp1-1;
2159 KahanSum fSum = pMatS->GetDouble(row);
2160 for (SCSIZE col = rowp1; col<nK ; col++)
2161 if (bIsTransposed)
2162 fSum -= pMatA->GetDouble(row,col) * pMatS->GetDouble(col);
2163 else
2164 fSum -= pMatA->GetDouble(col,row) * pMatS->GetDouble(col);
2165 pMatS->PutDouble( fSum.get() / pVecR[row] , row);
2169 /* Solve for X in R' * X= T using forward substitution. The solution X
2170 * overwrites T. Uses R from the result of the QR decomposition of a NxK
2171 * matrix A. T is a column vectors given as matrix, with at least elements on
2172 * index 0 to K-1; elements on index>=K are ignored. Vector R must not have
2173 * zero elements, no check is done.
2175 void lcl_SolveWithLowerLeftTriangle(const ScMatrixRef& pMatA,
2176 ::std::vector< double>& pVecR, const ScMatrixRef& pMatT,
2177 SCSIZE nK, bool bIsTransposed)
2179 // ScMatrix matrices are zero based, index access (column,row)
2180 for (SCSIZE row = 0; row < nK; row++)
2182 KahanSum fSum = pMatT -> GetDouble(row);
2183 for (SCSIZE col=0; col < row; col++)
2185 if (bIsTransposed)
2186 fSum -= pMatA->GetDouble(col,row) * pMatT->GetDouble(col);
2187 else
2188 fSum -= pMatA->GetDouble(row,col) * pMatT->GetDouble(col);
2190 pMatT->PutDouble( fSum.get() / pVecR[row] , row);
2194 /* Calculates Z = R * B
2195 * R is given in matrix A and vector VecR as obtained from the QR
2196 * decomposition in lcl_CalculateQRdecomposition. B and Z are column vectors
2197 * given as matrix with at least index 0 to K-1; elements on index>=K are
2198 * not used.
2200 void lcl_ApplyUpperRightTriangle(const ScMatrixRef& pMatA,
2201 ::std::vector< double>& pVecR, const ScMatrixRef& pMatB,
2202 const ScMatrixRef& pMatZ, SCSIZE nK, bool bIsTransposed)
2204 // ScMatrix matrices are zero based, index access (column,row)
2205 for (SCSIZE row = 0; row < nK; row++)
2207 KahanSum fSum = pVecR[row] * pMatB->GetDouble(row);
2208 for (SCSIZE col = row+1; col < nK; col++)
2209 if (bIsTransposed)
2210 fSum += pMatA->GetDouble(row,col) * pMatB->GetDouble(col);
2211 else
2212 fSum += pMatA->GetDouble(col,row) * pMatB->GetDouble(col);
2213 pMatZ->PutDouble( fSum.get(), row);
2217 double lcl_GetMeanOverAll(const ScMatrixRef& pMat, SCSIZE nN)
2219 KahanSum fSum = 0.0;
2220 for (SCSIZE i=0 ; i<nN; i++)
2221 fSum += pMat->GetDouble(i);
2222 return fSum.get()/static_cast<double>(nN);
2225 // Calculates means of the columns of matrix X. X is a RxC matrix;
2226 // ResMat is a 1xC matrix (=row).
2227 void lcl_CalculateColumnMeans(const ScMatrixRef& pX, const ScMatrixRef& pResMat,
2228 SCSIZE nC, SCSIZE nR)
2230 for (SCSIZE i=0; i < nC; i++)
2232 KahanSum fSum =0.0;
2233 for (SCSIZE k=0; k < nR; k++)
2234 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row)
2235 pResMat ->PutDouble( fSum.get()/static_cast<double>(nR),i);
2239 // Calculates means of the rows of matrix X. X is a RxC matrix;
2240 // ResMat is a Rx1 matrix (=column).
2241 void lcl_CalculateRowMeans(const ScMatrixRef& pX, const ScMatrixRef& pResMat,
2242 SCSIZE nC, SCSIZE nR)
2244 for (SCSIZE k=0; k < nR; k++)
2246 KahanSum fSum = 0.0;
2247 for (SCSIZE i=0; i < nC; i++)
2248 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row)
2249 pResMat ->PutDouble( fSum.get()/static_cast<double>(nC),k);
2253 void lcl_CalculateColumnsDelta(const ScMatrixRef& pMat, const ScMatrixRef& pColumnMeans,
2254 SCSIZE nC, SCSIZE nR)
2256 for (SCSIZE i = 0; i < nC; i++)
2257 for (SCSIZE k = 0; k < nR; k++)
2258 pMat->PutDouble( ::rtl::math::approxSub
2259 (pMat->GetDouble(i,k) , pColumnMeans->GetDouble(i) ) , i, k);
2262 void lcl_CalculateRowsDelta(const ScMatrixRef& pMat, const ScMatrixRef& pRowMeans,
2263 SCSIZE nC, SCSIZE nR)
2265 for (SCSIZE k = 0; k < nR; k++)
2266 for (SCSIZE i = 0; i < nC; i++)
2267 pMat->PutDouble( ::rtl::math::approxSub
2268 ( pMat->GetDouble(i,k) , pRowMeans->GetDouble(k) ) , i, k);
2271 // Case1 = simple regression
2272 // MatX = X - MeanX, MatY = Y - MeanY, y - haty = (y - MeanY) - (haty - MeanY)
2273 // = (y-MeanY)-((slope*x+a)-(slope*MeanX+a)) = (y-MeanY)-slope*(x-MeanX)
2274 double lcl_GetSSresid(const ScMatrixRef& pMatX, const ScMatrixRef& pMatY, double fSlope,
2275 SCSIZE nN)
2277 KahanSum fSum = 0.0;
2278 for (SCSIZE i=0; i<nN; i++)
2280 const double fTemp = pMatY->GetDouble(i) - fSlope * pMatX->GetDouble(i);
2281 fSum += fTemp * fTemp;
2283 return fSum.get();
2288 // Fill default values in matrix X, transform Y to log(Y) in case LOGEST|GROWTH,
2289 // determine sizes of matrices X and Y, determine kind of regression, clone
2290 // Y in case LOGEST|GROWTH, if constant.
2291 bool ScInterpreter::CheckMatrix(bool _bLOG, sal_uInt8& nCase, SCSIZE& nCX,
2292 SCSIZE& nCY, SCSIZE& nRX, SCSIZE& nRY, SCSIZE& M,
2293 SCSIZE& N, ScMatrixRef& pMatX, ScMatrixRef& pMatY)
2296 nCX = 0;
2297 nCY = 0;
2298 nRX = 0;
2299 nRY = 0;
2300 M = 0;
2301 N = 0;
2302 pMatY->GetDimensions(nCY, nRY);
2303 const SCSIZE nCountY = nCY * nRY;
2304 for ( SCSIZE i = 0; i < nCountY; i++ )
2306 if (!pMatY->IsValue(i))
2308 PushIllegalArgument();
2309 return false;
2313 if ( _bLOG )
2315 ScMatrixRef pNewY = pMatY->CloneIfConst();
2316 for (SCSIZE nElem = 0; nElem < nCountY; nElem++)
2318 const double fVal = pNewY->GetDouble(nElem);
2319 if (fVal <= 0.0)
2321 PushIllegalArgument();
2322 return false;
2324 else
2325 pNewY->PutDouble(log(fVal), nElem);
2327 pMatY = std::move(pNewY);
2330 if (pMatX)
2332 pMatX->GetDimensions(nCX, nRX);
2333 const SCSIZE nCountX = nCX * nRX;
2334 for ( SCSIZE i = 0; i < nCountX; i++ )
2335 if (!pMatX->IsValue(i))
2337 PushIllegalArgument();
2338 return false;
2340 if (nCX == nCY && nRX == nRY)
2342 nCase = 1; // simple regression
2343 M = 1;
2344 N = nCountY;
2346 else if (nCY != 1 && nRY != 1)
2348 PushIllegalArgument();
2349 return false;
2351 else if (nCY == 1)
2353 if (nRX != nRY)
2355 PushIllegalArgument();
2356 return false;
2358 else
2360 nCase = 2; // Y is column
2361 N = nRY;
2362 M = nCX;
2365 else if (nCX != nCY)
2367 PushIllegalArgument();
2368 return false;
2370 else
2372 nCase = 3; // Y is row
2373 N = nCY;
2374 M = nRX;
2377 else
2379 pMatX = GetNewMat(nCY, nRY, /*bEmpty*/true);
2380 nCX = nCY;
2381 nRX = nRY;
2382 if (!pMatX)
2384 PushIllegalArgument();
2385 return false;
2387 for ( SCSIZE i = 1; i <= nCountY; i++ )
2388 pMatX->PutDouble(static_cast<double>(i), i-1);
2389 nCase = 1;
2390 N = nCountY;
2391 M = 1;
2393 return true;
2396 // LINEST
2397 void ScInterpreter::ScLinest()
2399 CalculateRGPRKP(false);
2402 // LOGEST
2403 void ScInterpreter::ScLogest()
2405 CalculateRGPRKP(true);
2408 void ScInterpreter::CalculateRGPRKP(bool _bRKP)
2410 sal_uInt8 nParamCount = GetByte();
2411 if (!MustHaveParamCount( nParamCount, 1, 4 ))
2412 return;
2413 bool bConstant, bStats;
2415 // optional forth parameter
2416 if (nParamCount == 4)
2417 bStats = GetBool();
2418 else
2419 bStats = false;
2421 // The third parameter may not be missing in ODF, if the forth parameter
2422 // is present. But Excel allows it with default true, we too.
2423 if (nParamCount >= 3)
2425 if (IsMissing())
2427 Pop();
2428 bConstant = true;
2429 // PushIllegalParameter(); if ODF behavior is desired
2430 // return;
2432 else
2433 bConstant = GetBool();
2435 else
2436 bConstant = true;
2438 ScMatrixRef pMatX;
2439 if (nParamCount >= 2)
2441 if (IsMissing())
2442 { //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2443 Pop();
2444 pMatX = nullptr;
2446 else
2448 pMatX = GetMatrix();
2451 else
2452 pMatX = nullptr;
2454 ScMatrixRef pMatY = GetMatrix();
2455 if (!pMatY)
2457 PushIllegalParameter();
2458 return;
2461 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2462 sal_uInt8 nCase;
2464 SCSIZE nCX, nCY; // number of columns
2465 SCSIZE nRX, nRY; //number of rows
2466 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples
2467 if (!CheckMatrix(_bRKP,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY))
2469 PushIllegalParameter();
2470 return;
2473 // Enough data samples?
2474 if ((bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1))
2476 PushIllegalParameter();
2477 return;
2480 ScMatrixRef pResMat;
2481 if (bStats)
2482 pResMat = GetNewMat(K+1,5, /*bEmpty*/true);
2483 else
2484 pResMat = GetNewMat(K+1,1, /*bEmpty*/true);
2485 if (!pResMat)
2487 PushError(FormulaError::CodeOverflow);
2488 return;
2490 // Fill unused cells in pResMat; order (column,row)
2491 if (bStats)
2493 for (SCSIZE i=2; i<K+1; i++)
2495 pResMat->PutError( FormulaError::NotAvailable, i, 2);
2496 pResMat->PutError( FormulaError::NotAvailable, i, 3);
2497 pResMat->PutError( FormulaError::NotAvailable, i, 4);
2501 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
2502 // Clone constant matrices, so that Mat = Mat - Mean is possible.
2503 double fMeanY = 0.0;
2504 if (bConstant)
2506 ScMatrixRef pNewX = pMatX->CloneIfConst();
2507 ScMatrixRef pNewY = pMatY->CloneIfConst();
2508 if (!pNewX || !pNewY)
2510 PushError(FormulaError::CodeOverflow);
2511 return;
2513 pMatX = std::move(pNewX);
2514 pMatY = std::move(pNewY);
2515 // DeltaY is possible here; DeltaX depends on nCase, so later
2516 fMeanY = lcl_GetMeanOverAll(pMatY, N);
2517 for (SCSIZE i=0; i<N; i++)
2519 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i );
2523 if (nCase==1)
2525 // calculate simple regression
2526 double fMeanX = 0.0;
2527 if (bConstant)
2528 { // Mat = Mat - Mean
2529 fMeanX = lcl_GetMeanOverAll(pMatX, N);
2530 for (SCSIZE i=0; i<N; i++)
2532 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i );
2535 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N);
2536 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N);
2537 if (fSumX2==0.0)
2539 PushNoValue(); // all x-values are identical
2540 return;
2542 double fSlope = fSumXY / fSumX2;
2543 double fIntercept = 0.0;
2544 if (bConstant)
2545 fIntercept = fMeanY - fSlope * fMeanX;
2546 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, 1, 0); //order (column,row)
2547 pResMat->PutDouble(_bRKP ? exp(fSlope) : fSlope, 0, 0);
2549 if (bStats)
2551 double fSSreg = fSlope * fSlope * fSumX2;
2552 pResMat->PutDouble(fSSreg, 0, 4);
2554 double fDegreesFreedom =static_cast<double>( bConstant ? N-2 : N-1 );
2555 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2557 double fSSresid = lcl_GetSSresid(pMatX,pMatY,fSlope,N);
2558 pResMat->PutDouble(fSSresid, 1, 4);
2560 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2561 { // exact fit; test SSreg too, because SSresid might be
2562 // unequal zero due to round of errors
2563 pResMat->PutDouble(0.0, 1, 4); // SSresid
2564 pResMat->PutError( FormulaError::NotAvailable, 0, 3); // F
2565 pResMat->PutDouble(0.0, 1, 2); // RMSE
2566 pResMat->PutDouble(0.0, 0, 1); // SigmaSlope
2567 if (bConstant)
2568 pResMat->PutDouble(0.0, 1, 1); //SigmaIntercept
2569 else
2570 pResMat->PutError( FormulaError::NotAvailable, 1, 1);
2571 pResMat->PutDouble(1.0, 0, 2); // R^2
2573 else
2575 double fFstatistic = (fSSreg / static_cast<double>(K))
2576 / (fSSresid / fDegreesFreedom);
2577 pResMat->PutDouble(fFstatistic, 0, 3);
2579 // standard error of estimate
2580 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2581 pResMat->PutDouble(fRMSE, 1, 2);
2583 double fSigmaSlope = fRMSE / sqrt(fSumX2);
2584 pResMat->PutDouble(fSigmaSlope, 0, 1);
2586 if (bConstant)
2588 double fSigmaIntercept = fRMSE
2589 * sqrt(fMeanX*fMeanX/fSumX2 + 1.0/static_cast<double>(N));
2590 pResMat->PutDouble(fSigmaIntercept, 1, 1);
2592 else
2594 pResMat->PutError( FormulaError::NotAvailable, 1, 1);
2597 double fR2 = fSSreg / (fSSreg + fSSresid);
2598 pResMat->PutDouble(fR2, 0, 2);
2601 PushMatrix(pResMat);
2603 else // calculate multiple regression;
2605 // Uses a QR decomposition X = QR. The solution B = (X'X)^(-1) * X' * Y
2606 // becomes B = R^(-1) * Q' * Y
2607 if (nCase ==2) // Y is column
2609 ::std::vector< double> aVecR(N); // for QR decomposition
2610 // Enough memory for needed matrices?
2611 ScMatrixRef pMeans = GetNewMat(K, 1, /*bEmpty*/true); // mean of each column
2612 ScMatrixRef pMatZ; // for Q' * Y , inter alia
2613 if (bStats)
2614 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it
2615 else
2616 pMatZ = pMatY; // Y can be overwritten
2617 ScMatrixRef pSlopes = GetNewMat(1,K, /*bEmpty*/true); // from b1 to bK
2618 if (!pMeans || !pMatZ || !pSlopes)
2620 PushError(FormulaError::CodeOverflow);
2621 return;
2623 if (bConstant)
2625 lcl_CalculateColumnMeans(pMatX, pMeans, K, N);
2626 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N);
2628 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N))
2630 PushNoValue();
2631 return;
2633 // Later on we will divide by elements of aVecR, so make sure
2634 // that they aren't zero.
2635 bool bIsSingular=false;
2636 for (SCSIZE row=0; row < K && !bIsSingular; row++)
2637 bIsSingular = aVecR[row] == 0.0;
2638 if (bIsSingular)
2640 PushNoValue();
2641 return;
2643 // Z = Q' Y;
2644 for (SCSIZE col = 0; col < K; col++)
2646 lcl_ApplyHouseholderTransformation(pMatX, col, pMatZ, N);
2648 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2649 // result Z should have zeros for index>=K; if not, ignore values
2650 for (SCSIZE col = 0; col < K ; col++)
2652 pSlopes->PutDouble( pMatZ->GetDouble(col), col);
2654 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false);
2655 double fIntercept = 0.0;
2656 if (bConstant)
2657 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
2658 // Fill first line in result matrix
2659 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 );
2660 for (SCSIZE i = 0; i < K; i++)
2661 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i))
2662 : pSlopes->GetDouble(i) , K-1-i, 0);
2664 if (bStats)
2666 double fSSreg = 0.0;
2667 double fSSresid = 0.0;
2668 // re-use memory of Z;
2669 pMatZ->FillDouble(0.0, 0, 0, 0, N-1);
2670 // Z = R * Slopes
2671 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, false);
2672 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2673 for (SCSIZE colp1 = K; colp1 > 0; colp1--)
2675 lcl_ApplyHouseholderTransformation(pMatX, colp1-1, pMatZ,N);
2677 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N);
2678 // re-use Y for residuals, Y = Y-Z
2679 for (SCSIZE row = 0; row < N; row++)
2680 pMatY->PutDouble(pMatY->GetDouble(row) - pMatZ->GetDouble(row), row);
2681 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N);
2682 pResMat->PutDouble(fSSreg, 0, 4);
2683 pResMat->PutDouble(fSSresid, 1, 4);
2685 double fDegreesFreedom =static_cast<double>( bConstant ? N-K-1 : N-K );
2686 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2688 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2689 { // exact fit; incl. observed values Y are identical
2690 pResMat->PutDouble(0.0, 1, 4); // SSresid
2691 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2692 pResMat->PutError( FormulaError::NotAvailable, 0, 3); // F
2693 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2694 pResMat->PutDouble(0.0, 1, 2); // RMSE
2695 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2696 for (SCSIZE i=0; i<K; i++)
2697 pResMat->PutDouble(0.0, K-1-i, 1);
2699 // SigmaIntercept = RMSE * sqrt(...) = 0
2700 if (bConstant)
2701 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept
2702 else
2703 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2705 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2706 pResMat->PutDouble(1.0, 0, 2); // R^2
2708 else
2710 double fFstatistic = (fSSreg / static_cast<double>(K))
2711 / (fSSresid / fDegreesFreedom);
2712 pResMat->PutDouble(fFstatistic, 0, 3);
2714 // standard error of estimate = root mean SSE
2715 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2716 pResMat->PutDouble(fRMSE, 1, 2);
2718 // standard error of slopes
2719 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2720 // standard error of intercept
2721 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2722 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2723 // a whole matrix, but iterate over unit vectors.
2724 KahanSum aSigmaIntercept = 0.0;
2725 double fPart; // for Xmean * single column of (R' R)^(-1)
2726 for (SCSIZE col = 0; col < K; col++)
2728 //re-use memory of MatZ
2729 pMatZ->FillDouble(0.0,0,0,0,K-1); // Z = unit vector e
2730 pMatZ->PutDouble(1.0, col);
2731 //Solve R' * Z = e
2732 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, false);
2733 // Solve R * Znew = Zold
2734 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, false);
2735 // now Z is column col in (R' R)^(-1)
2736 double fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(col));
2737 pResMat->PutDouble(fSigmaSlope, K-1-col, 1);
2738 // (R' R) ^(-1) is symmetric
2739 if (bConstant)
2741 fPart = lcl_GetSumProduct(pMeans, pMatZ, K);
2742 aSigmaIntercept += fPart * pMeans->GetDouble(col);
2745 if (bConstant)
2747 double fSigmaIntercept = fRMSE
2748 * sqrt( (aSigmaIntercept + 1.0 / static_cast<double>(N) ).get() );
2749 pResMat->PutDouble(fSigmaIntercept, K, 1);
2751 else
2753 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2756 double fR2 = fSSreg / (fSSreg + fSSresid);
2757 pResMat->PutDouble(fR2, 0, 2);
2760 PushMatrix(pResMat);
2762 else // nCase == 3, Y is row, all matrices are transposed
2764 ::std::vector< double> aVecR(N); // for QR decomposition
2765 // Enough memory for needed matrices?
2766 ScMatrixRef pMeans = GetNewMat(1, K, /*bEmpty*/true); // mean of each row
2767 ScMatrixRef pMatZ; // for Q' * Y , inter alia
2768 if (bStats)
2769 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it
2770 else
2771 pMatZ = pMatY; // Y can be overwritten
2772 ScMatrixRef pSlopes = GetNewMat(K,1, /*bEmpty*/true); // from b1 to bK
2773 if (!pMeans || !pMatZ || !pSlopes)
2775 PushError(FormulaError::CodeOverflow);
2776 return;
2778 if (bConstant)
2780 lcl_CalculateRowMeans(pMatX, pMeans, N, K);
2781 lcl_CalculateRowsDelta(pMatX, pMeans, N, K);
2784 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N))
2786 PushNoValue();
2787 return;
2790 // Later on we will divide by elements of aVecR, so make sure
2791 // that they aren't zero.
2792 bool bIsSingular=false;
2793 for (SCSIZE row=0; row < K && !bIsSingular; row++)
2794 bIsSingular = aVecR[row] == 0.0;
2795 if (bIsSingular)
2797 PushNoValue();
2798 return;
2800 // Z = Q' Y
2801 for (SCSIZE row = 0; row < K; row++)
2803 lcl_TApplyHouseholderTransformation(pMatX, row, pMatZ, N);
2805 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2806 // result Z should have zeros for index>=K; if not, ignore values
2807 for (SCSIZE col = 0; col < K ; col++)
2809 pSlopes->PutDouble( pMatZ->GetDouble(col), col);
2811 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true);
2812 double fIntercept = 0.0;
2813 if (bConstant)
2814 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
2815 // Fill first line in result matrix
2816 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 );
2817 for (SCSIZE i = 0; i < K; i++)
2818 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i))
2819 : pSlopes->GetDouble(i) , K-1-i, 0);
2821 if (bStats)
2823 double fSSreg = 0.0;
2824 double fSSresid = 0.0;
2825 // re-use memory of Z;
2826 pMatZ->FillDouble(0.0, 0, 0, N-1, 0);
2827 // Z = R * Slopes
2828 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, true);
2829 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2830 for (SCSIZE rowp1 = K; rowp1 > 0; rowp1--)
2832 lcl_TApplyHouseholderTransformation(pMatX, rowp1-1, pMatZ,N);
2834 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N);
2835 // re-use Y for residuals, Y = Y-Z
2836 for (SCSIZE col = 0; col < N; col++)
2837 pMatY->PutDouble(pMatY->GetDouble(col) - pMatZ->GetDouble(col), col);
2838 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N);
2839 pResMat->PutDouble(fSSreg, 0, 4);
2840 pResMat->PutDouble(fSSresid, 1, 4);
2842 double fDegreesFreedom =static_cast<double>( bConstant ? N-K-1 : N-K );
2843 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2845 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2846 { // exact fit; incl. case observed values Y are identical
2847 pResMat->PutDouble(0.0, 1, 4); // SSresid
2848 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2849 pResMat->PutError( FormulaError::NotAvailable, 0, 3); // F
2850 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2851 pResMat->PutDouble(0.0, 1, 2); // RMSE
2852 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2853 for (SCSIZE i=0; i<K; i++)
2854 pResMat->PutDouble(0.0, K-1-i, 1);
2856 // SigmaIntercept = RMSE * sqrt(...) = 0
2857 if (bConstant)
2858 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept
2859 else
2860 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2862 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2863 pResMat->PutDouble(1.0, 0, 2); // R^2
2865 else
2867 double fFstatistic = (fSSreg / static_cast<double>(K))
2868 / (fSSresid / fDegreesFreedom);
2869 pResMat->PutDouble(fFstatistic, 0, 3);
2871 // standard error of estimate = root mean SSE
2872 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2873 pResMat->PutDouble(fRMSE, 1, 2);
2875 // standard error of slopes
2876 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2877 // standard error of intercept
2878 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2879 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2880 // a whole matrix, but iterate over unit vectors.
2881 // (R' R) ^(-1) is symmetric
2882 KahanSum aSigmaIntercept = 0.0;
2883 double fPart; // for Xmean * single col of (R' R)^(-1)
2884 for (SCSIZE row = 0; row < K; row++)
2886 //re-use memory of MatZ
2887 pMatZ->FillDouble(0.0,0,0,K-1,0); // Z = unit vector e
2888 pMatZ->PutDouble(1.0, row);
2889 //Solve R' * Z = e
2890 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, true);
2891 // Solve R * Znew = Zold
2892 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, true);
2893 // now Z is column col in (R' R)^(-1)
2894 double fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(row));
2895 pResMat->PutDouble(fSigmaSlope, K-1-row, 1);
2896 if (bConstant)
2898 fPart = lcl_GetSumProduct(pMeans, pMatZ, K);
2899 aSigmaIntercept += fPart * pMeans->GetDouble(row);
2902 if (bConstant)
2904 double fSigmaIntercept = fRMSE
2905 * sqrt( (aSigmaIntercept + 1.0 / static_cast<double>(N) ).get() );
2906 pResMat->PutDouble(fSigmaIntercept, K, 1);
2908 else
2910 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2913 double fR2 = fSSreg / (fSSreg + fSSresid);
2914 pResMat->PutDouble(fR2, 0, 2);
2917 PushMatrix(pResMat);
2922 void ScInterpreter::ScTrend()
2924 CalculateTrendGrowth(false);
2927 void ScInterpreter::ScGrowth()
2929 CalculateTrendGrowth(true);
2932 void ScInterpreter::CalculateTrendGrowth(bool _bGrowth)
2934 sal_uInt8 nParamCount = GetByte();
2935 if (!MustHaveParamCount( nParamCount, 1, 4 ))
2936 return;
2938 // optional forth parameter
2939 bool bConstant;
2940 if (nParamCount == 4)
2941 bConstant = GetBool();
2942 else
2943 bConstant = true;
2945 // The third parameter may be missing in ODF, although the forth parameter
2946 // is present. Default values depend on data not yet read.
2947 ScMatrixRef pMatNewX;
2948 if (nParamCount >= 3)
2950 if (IsMissing())
2952 Pop();
2953 pMatNewX = nullptr;
2955 else
2956 pMatNewX = GetMatrix();
2958 else
2959 pMatNewX = nullptr;
2961 //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2962 //Defaults will be set in CheckMatrix
2963 ScMatrixRef pMatX;
2964 if (nParamCount >= 2)
2966 if (IsMissing())
2968 Pop();
2969 pMatX = nullptr;
2971 else
2973 pMatX = GetMatrix();
2976 else
2977 pMatX = nullptr;
2979 ScMatrixRef pMatY = GetMatrix();
2980 if (!pMatY)
2982 PushIllegalParameter();
2983 return;
2986 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2987 sal_uInt8 nCase;
2989 SCSIZE nCX, nCY; // number of columns
2990 SCSIZE nRX, nRY; //number of rows
2991 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples
2992 if (!CheckMatrix(_bGrowth,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY))
2994 PushIllegalParameter();
2995 return;
2998 // Enough data samples?
2999 if ((bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1))
3001 PushIllegalParameter();
3002 return;
3005 // Set default pMatNewX if necessary
3006 SCSIZE nCXN, nRXN;
3007 SCSIZE nCountXN;
3008 if (!pMatNewX)
3010 nCXN = nCX;
3011 nRXN = nRX;
3012 nCountXN = nCXN * nRXN;
3013 pMatNewX = pMatX->Clone(); // pMatX will be changed to X-meanX
3015 else
3017 pMatNewX->GetDimensions(nCXN, nRXN);
3018 if ((nCase == 2 && K != nCXN) || (nCase == 3 && K != nRXN))
3020 PushIllegalArgument();
3021 return;
3023 nCountXN = nCXN * nRXN;
3024 for (SCSIZE i = 0; i < nCountXN; i++)
3025 if (!pMatNewX->IsValue(i))
3027 PushIllegalArgument();
3028 return;
3031 ScMatrixRef pResMat; // size depends on nCase
3032 if (nCase == 1)
3033 pResMat = GetNewMat(nCXN,nRXN, /*bEmpty*/true);
3034 else
3036 if (nCase==2)
3037 pResMat = GetNewMat(1,nRXN, /*bEmpty*/true);
3038 else
3039 pResMat = GetNewMat(nCXN,1, /*bEmpty*/true);
3041 if (!pResMat)
3043 PushError(FormulaError::CodeOverflow);
3044 return;
3046 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
3047 // Clone constant matrices, so that Mat = Mat - Mean is possible.
3048 double fMeanY = 0.0;
3049 if (bConstant)
3051 ScMatrixRef pCopyX = pMatX->CloneIfConst();
3052 ScMatrixRef pCopyY = pMatY->CloneIfConst();
3053 if (!pCopyX || !pCopyY)
3055 PushError(FormulaError::MatrixSize);
3056 return;
3058 pMatX = std::move(pCopyX);
3059 pMatY = std::move(pCopyY);
3060 // DeltaY is possible here; DeltaX depends on nCase, so later
3061 fMeanY = lcl_GetMeanOverAll(pMatY, N);
3062 for (SCSIZE i=0; i<N; i++)
3064 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i );
3068 if (nCase==1)
3070 // calculate simple regression
3071 double fMeanX = 0.0;
3072 if (bConstant)
3073 { // Mat = Mat - Mean
3074 fMeanX = lcl_GetMeanOverAll(pMatX, N);
3075 for (SCSIZE i=0; i<N; i++)
3077 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i );
3080 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N);
3081 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N);
3082 if (fSumX2==0.0)
3084 PushNoValue(); // all x-values are identical
3085 return;
3087 double fSlope = fSumXY / fSumX2;
3088 double fHelp;
3089 if (bConstant)
3091 double fIntercept = fMeanY - fSlope * fMeanX;
3092 for (SCSIZE i = 0; i < nCountXN; i++)
3094 fHelp = pMatNewX->GetDouble(i)*fSlope + fIntercept;
3095 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i);
3098 else
3100 for (SCSIZE i = 0; i < nCountXN; i++)
3102 fHelp = pMatNewX->GetDouble(i)*fSlope;
3103 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i);
3107 else // calculate multiple regression;
3109 if (nCase ==2) // Y is column
3111 ::std::vector< double> aVecR(N); // for QR decomposition
3112 // Enough memory for needed matrices?
3113 ScMatrixRef pMeans = GetNewMat(K, 1, /*bEmpty*/true); // mean of each column
3114 ScMatrixRef pSlopes = GetNewMat(1,K, /*bEmpty*/true); // from b1 to bK
3115 if (!pMeans || !pSlopes)
3117 PushError(FormulaError::CodeOverflow);
3118 return;
3120 if (bConstant)
3122 lcl_CalculateColumnMeans(pMatX, pMeans, K, N);
3123 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N);
3125 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N))
3127 PushNoValue();
3128 return;
3130 // Later on we will divide by elements of aVecR, so make sure
3131 // that they aren't zero.
3132 bool bIsSingular=false;
3133 for (SCSIZE row=0; row < K && !bIsSingular; row++)
3134 bIsSingular = aVecR[row] == 0.0;
3135 if (bIsSingular)
3137 PushNoValue();
3138 return;
3140 // Z := Q' Y; Y is overwritten with result Z
3141 for (SCSIZE col = 0; col < K; col++)
3143 lcl_ApplyHouseholderTransformation(pMatX, col, pMatY, N);
3145 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3146 // result Z should have zeros for index>=K; if not, ignore values
3147 for (SCSIZE col = 0; col < K ; col++)
3149 pSlopes->PutDouble( pMatY->GetDouble(col), col);
3151 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false);
3153 // Fill result matrix
3154 lcl_MFastMult(pMatNewX,pSlopes,pResMat,nRXN,K,1);
3155 if (bConstant)
3157 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
3158 for (SCSIZE row = 0; row < nRXN; row++)
3159 pResMat->PutDouble(pResMat->GetDouble(row)+fIntercept, row);
3161 if (_bGrowth)
3163 for (SCSIZE i = 0; i < nRXN; i++)
3164 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i);
3167 else
3168 { // nCase == 3, Y is row, all matrices are transposed
3170 ::std::vector< double> aVecR(N); // for QR decomposition
3171 // Enough memory for needed matrices?
3172 ScMatrixRef pMeans = GetNewMat(1, K, /*bEmpty*/true); // mean of each row
3173 ScMatrixRef pSlopes = GetNewMat(K,1, /*bEmpty*/true); // row from b1 to bK
3174 if (!pMeans || !pSlopes)
3176 PushError(FormulaError::CodeOverflow);
3177 return;
3179 if (bConstant)
3181 lcl_CalculateRowMeans(pMatX, pMeans, N, K);
3182 lcl_CalculateRowsDelta(pMatX, pMeans, N, K);
3184 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N))
3186 PushNoValue();
3187 return;
3189 // Later on we will divide by elements of aVecR, so make sure
3190 // that they aren't zero.
3191 bool bIsSingular=false;
3192 for (SCSIZE row=0; row < K && !bIsSingular; row++)
3193 bIsSingular = aVecR[row] == 0.0;
3194 if (bIsSingular)
3196 PushNoValue();
3197 return;
3199 // Z := Q' Y; Y is overwritten with result Z
3200 for (SCSIZE row = 0; row < K; row++)
3202 lcl_TApplyHouseholderTransformation(pMatX, row, pMatY, N);
3204 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3205 // result Z should have zeros for index>=K; if not, ignore values
3206 for (SCSIZE col = 0; col < K ; col++)
3208 pSlopes->PutDouble( pMatY->GetDouble(col), col);
3210 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true);
3212 // Fill result matrix
3213 lcl_MFastMult(pSlopes,pMatNewX,pResMat,1,K,nCXN);
3214 if (bConstant)
3216 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
3217 for (SCSIZE col = 0; col < nCXN; col++)
3218 pResMat->PutDouble(pResMat->GetDouble(col)+fIntercept, col);
3220 if (_bGrowth)
3222 for (SCSIZE i = 0; i < nCXN; i++)
3223 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i);
3227 PushMatrix(pResMat);
3230 void ScInterpreter::ScMatRef()
3232 // In case it contains relative references resolve them as usual.
3233 Push( *pCur );
3234 ScAddress aAdr;
3235 PopSingleRef( aAdr );
3237 ScRefCellValue aCell(mrDoc, aAdr);
3239 if (aCell.getType() != CELLTYPE_FORMULA)
3241 PushError( FormulaError::NoRef );
3242 return;
3245 if (aCell.getFormula()->IsRunning())
3247 // Twisted odd corner case where an array element's cell tries to
3248 // access the top left matrix while it is still running, see tdf#88737
3249 // This is a hackish workaround, not a general solution, the matrix
3250 // isn't available anyway and FormulaError::CircularReference would be set.
3251 PushError( FormulaError::RetryCircular );
3252 return;
3255 const ScMatrix* pMat = aCell.getFormula()->GetMatrix();
3256 if (pMat)
3258 SCSIZE nCols, nRows;
3259 pMat->GetDimensions( nCols, nRows );
3260 SCSIZE nC = static_cast<SCSIZE>(aPos.Col() - aAdr.Col());
3261 SCSIZE nR = static_cast<SCSIZE>(aPos.Row() - aAdr.Row());
3262 #if 0
3263 // XXX: this could be an additional change for tdf#145085 to not
3264 // display the URL in a voluntary entered 2-rows array context.
3265 // However, that might as well be used on purpose to implement a check
3266 // on the URL, which existing documents may have done, the more that
3267 // before the accompanying change of
3268 // ScFormulaCell::GetResultDimensions() the cell array was forced to
3269 // two rows. Do not change without compelling reason. Note that this
3270 // repeating top cell is what Excel implements, but it has no
3271 // additional value so probably isn't used there. Exporting to and
3272 // using in Excel though will lose this capability.
3273 if (aCell.mpFormula->GetCode()->IsHyperLink())
3275 // Row 2 element is the URL that is not to be displayed, fake a
3276 // 1-row cell-text-only matrix that is repeated.
3277 assert(nRows == 2);
3278 nR = 0;
3280 #endif
3281 if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1))
3282 PushNA();
3283 else
3285 const ScMatrixValue nMatVal = pMat->Get( nC, nR);
3286 ScMatValType nMatValType = nMatVal.nType;
3288 if (ScMatrix::IsNonValueType( nMatValType))
3290 if (ScMatrix::IsEmptyPathType( nMatValType))
3291 { // result of empty false jump path
3292 nFuncFmtType = SvNumFormatType::LOGICAL;
3293 PushInt(0);
3295 else if (ScMatrix::IsEmptyType( nMatValType))
3297 // Not inherited (really?) and display as empty string, not 0.
3298 PushTempToken( new ScEmptyCellToken( false, true));
3300 else
3301 PushString( nMatVal.GetString() );
3303 else
3305 // Determine nFuncFmtType type before PushDouble().
3306 mrDoc.GetNumberFormatInfo(mrContext, nCurFmtType, nCurFmtIndex, aAdr);
3307 nFuncFmtType = nCurFmtType;
3308 nFuncFmtIndex = nCurFmtIndex;
3309 PushDouble(nMatVal.fVal); // handles DoubleError
3313 else
3315 // Determine nFuncFmtType type before PushDouble().
3316 mrDoc.GetNumberFormatInfo(mrContext, nCurFmtType, nCurFmtIndex, aAdr);
3317 nFuncFmtType = nCurFmtType;
3318 nFuncFmtIndex = nCurFmtIndex;
3319 // If not a result matrix, obtain the cell value.
3320 FormulaError nErr = aCell.getFormula()->GetErrCode();
3321 if (nErr != FormulaError::NONE)
3322 PushError( nErr );
3323 else if (aCell.getFormula()->IsValue())
3324 PushDouble(aCell.getFormula()->GetValue());
3325 else
3327 svl::SharedString aVal = aCell.getFormula()->GetString();
3328 PushString( aVal );
3333 void ScInterpreter::ScInfo()
3335 if( !MustHaveParamCount( GetByte(), 1 ) )
3336 return;
3338 OUString aStr = GetString().getString();
3339 ScCellKeywordTranslator::transKeyword(aStr, &ScGlobal::GetLocale(), ocInfo);
3340 if( aStr == "SYSTEM" )
3341 PushString( u"" SC_INFO_OSVERSION ""_ustr );
3342 else if( aStr == "OSVERSION" )
3343 #if (defined LINUX || defined __FreeBSD__)
3344 PushString(Application::GetOSVersion());
3345 #elif defined MACOSX
3346 // TODO tdf#140286 handle MACOSX version to get result compatible to Excel
3347 PushString("Windows (32-bit) NT 5.01");
3348 #else // handle Windows (WNT, WIN_NT, WIN32, _WIN32)
3349 // TODO tdf#140286 handle Windows version to get a result compatible to Excel
3350 PushString( "Windows (32-bit) NT 5.01" );
3351 #endif
3352 else if( aStr == "RELEASE" )
3353 PushString( ::utl::Bootstrap::getBuildIdData( OUString() ) );
3354 else if( aStr == "NUMFILE" )
3355 PushDouble( 1 );
3356 else if( aStr == "RECALC" )
3357 PushString( ScResId( mrDoc.GetAutoCalc() ? STR_RECALC_AUTO : STR_RECALC_MANUAL ) );
3358 else if (aStr == "DIRECTORY" || aStr == "MEMAVAIL" || aStr == "MEMUSED" || aStr == "ORIGIN" || aStr == "TOTMEM")
3359 PushNA();
3360 else
3361 PushIllegalArgument();
3364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */