LibreOffice Module sc (master) 1
interpr5.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <rtl/math.hxx>
21#include <string.h>
22#include <math.h>
23
24#ifdef DEBUG_SC_LUP_DECOMPOSITION
25#include <stdio.h>
26#endif
27
29#include <svl/zforlist.hxx>
30
31#include <interpre.hxx>
32#include <global.hxx>
33#include <formulacell.hxx>
34#include <document.hxx>
35#include <dociter.hxx>
36#include <scmatrix.hxx>
37#include <globstr.hrc>
38#include <scresid.hxx>
39#include <cellkeytranslator.hxx>
40#include <formulagroup.hxx>
41#include <vcl/svapp.hxx> //Application::
42
43#include <vector>
44
45using ::std::vector;
46using namespace formula;
47
48namespace {
49
50double MatrixAdd(const double& lhs, const double& rhs)
51{
52 return ::rtl::math::approxAdd( lhs,rhs);
53}
54
55double MatrixSub(const double& lhs, const double& rhs)
56{
57 return ::rtl::math::approxSub( lhs,rhs);
58}
59
60double MatrixMul(const double& lhs, const double& rhs)
61{
62 return lhs * rhs;
63}
64
65double MatrixDiv(const double& lhs, const double& rhs)
66{
67 return ScInterpreter::div( lhs,rhs);
68}
69
70double MatrixPow(const double& lhs, const double& rhs)
71{
72 return ::pow( lhs,rhs);
73}
74
75// Multiply n x m Mat A with m x l Mat B to n x l Mat R
76void lcl_MFastMult(const ScMatrixRef& pA, const ScMatrixRef& pB, const ScMatrixRef& pR,
77 SCSIZE n, SCSIZE m, SCSIZE l)
78{
79 for (SCSIZE row = 0; row < n; row++)
80 {
81 for (SCSIZE col = 0; col < l; col++)
82 { // result element(col, row) =sum[ (row of A) * (column of B)]
83 KahanSum fSum = 0.0;
84 for (SCSIZE k = 0; k < m; k++)
85 fSum += pA->GetDouble(k,row) * pB->GetDouble(col,k);
86 pR->PutDouble(fSum.get(), col, row);
87 }
88 }
89}
90
91}
92
93double ScInterpreter::ScGetGCD(double fx, double fy)
94{
95 // By ODFF definition GCD(0,a) => a. This is also vital for the code in
96 // ScGCD() to work correctly with a preset fy=0.0
97 if (fy == 0.0)
98 return fx;
99 else if (fx == 0.0)
100 return fy;
101 else
102 {
103 double fz = fmod(fx, fy);
104 while (fz > 0.0)
105 {
106 fx = fy;
107 fy = fz;
108 fz = fmod(fx, fy);
109 }
110 return fy;
111 }
112}
113
115{
116 short nParamCount = GetByte();
117 if ( !MustHaveParamCountMin( nParamCount, 1 ) )
118 return;
119
120 double fx, fy = 0.0;
121 ScRange aRange;
122 size_t nRefInList = 0;
123 while (nGlobalError == FormulaError::NONE && nParamCount-- > 0)
124 {
125 switch (GetStackType())
126 {
127 case svDouble :
128 case svString:
129 case svSingleRef:
130 {
131 fx = ::rtl::math::approxFloor( GetDouble());
132 if (fx < 0.0)
133 {
135 return;
136 }
137 fy = ScGetGCD(fx, fy);
138 }
139 break;
140 case svDoubleRef :
141 case svRefList :
142 {
143 FormulaError nErr = FormulaError::NONE;
144 PopDoubleRef( aRange, nParamCount, nRefInList);
145 double nCellVal;
146 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
147 if (aValIter.GetFirst(nCellVal, nErr))
148 {
149 do
150 {
151 fx = ::rtl::math::approxFloor( nCellVal);
152 if (fx < 0.0)
153 {
155 return;
156 }
157 fy = ScGetGCD(fx, fy);
158 } while (nErr == FormulaError::NONE && aValIter.GetNext(nCellVal, nErr));
159 }
160 SetError(nErr);
161 }
162 break;
163 case svMatrix :
166 {
167 ScMatrixRef pMat = GetMatrix();
168 if (pMat)
169 {
170 SCSIZE nC, nR;
171 pMat->GetDimensions(nC, nR);
172 if (nC == 0 || nR == 0)
173 SetError(FormulaError::IllegalArgument);
174 else
175 {
176 double nVal = pMat->GetGcd();
177 fy = ScGetGCD(nVal,fy);
178 }
179 }
180 }
181 break;
182 default : SetError(FormulaError::IllegalParameter); break;
183 }
184 }
185 PushDouble(fy);
186}
187
189{
190 short nParamCount = GetByte();
191 if ( !MustHaveParamCountMin( nParamCount, 1 ) )
192 return;
193
194 double fx, fy = 1.0;
195 ScRange aRange;
196 size_t nRefInList = 0;
197 while (nGlobalError == FormulaError::NONE && nParamCount-- > 0)
198 {
199 switch (GetStackType())
200 {
201 case svDouble :
202 case svString:
203 case svSingleRef:
204 {
205 fx = ::rtl::math::approxFloor( GetDouble());
206 if (fx < 0.0)
207 {
209 return;
210 }
211 if (fx == 0.0 || fy == 0.0)
212 fy = 0.0;
213 else
214 fy = fx * fy / ScGetGCD(fx, fy);
215 }
216 break;
217 case svDoubleRef :
218 case svRefList :
219 {
220 FormulaError nErr = FormulaError::NONE;
221 PopDoubleRef( aRange, nParamCount, nRefInList);
222 double nCellVal;
223 ScValueIterator aValIter( mrContext, aRange, mnSubTotalFlags );
224 if (aValIter.GetFirst(nCellVal, nErr))
225 {
226 do
227 {
228 fx = ::rtl::math::approxFloor( nCellVal);
229 if (fx < 0.0)
230 {
232 return;
233 }
234 if (fx == 0.0 || fy == 0.0)
235 fy = 0.0;
236 else
237 fy = fx * fy / ScGetGCD(fx, fy);
238 } while (nErr == FormulaError::NONE && aValIter.GetNext(nCellVal, nErr));
239 }
240 SetError(nErr);
241 }
242 break;
243 case svMatrix :
246 {
247 ScMatrixRef pMat = GetMatrix();
248 if (pMat)
249 {
250 SCSIZE nC, nR;
251 pMat->GetDimensions(nC, nR);
252 if (nC == 0 || nR == 0)
253 SetError(FormulaError::IllegalArgument);
254 else
255 {
256 double nVal = pMat->GetLcm();
257 fy = (nVal * fy ) / ScGetGCD(nVal, fy);
258 }
259 }
260 }
261 break;
262 default : SetError(FormulaError::IllegalParameter); break;
263 }
264 }
265 PushDouble(fy);
266}
267
269{
270 rMat->SetErrorInterpreter( this);
271 // A temporary matrix is mutable and ScMatrix::CloneIfConst() returns the
272 // very matrix.
273 rMat->SetMutable();
274 SCSIZE nCols, nRows;
275 rMat->GetDimensions( nCols, nRows);
276 if ( nCols != nC || nRows != nR )
277 { // arbitrary limit of elements exceeded
278 SetError( FormulaError::MatrixSize);
279 rMat.reset();
280 }
281}
282
284{
285 ScMatrixRef pMat;
286 if (bEmpty)
287 pMat = new ScMatrix(nC, nR);
288 else
289 pMat = new ScMatrix(nC, nR, 0.0);
290 MakeMatNew(pMat, nC, nR);
291 return pMat;
292}
293
294ScMatrixRef ScInterpreter::GetNewMat(SCSIZE nC, SCSIZE nR, const std::vector<double>& rValues)
295{
296 ScMatrixRef pMat(new ScMatrix(nC, nR, rValues));
297 MakeMatNew(pMat, nC, nR);
298 return pMat;
299}
300
302 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
303 SCCOL nCol2, SCROW nRow2, SCTAB nTab2 )
304{
305 if (nTab1 != nTab2 || nGlobalError != FormulaError::NONE)
306 {
307 // Not a 2D matrix.
308 SetError(FormulaError::IllegalParameter);
309 return nullptr;
310 }
311
312 if (nTab1 == nTab2 && pToken)
313 {
314 const ScComplexRefData& rCRef = *pToken->GetDoubleRef();
315 if (rCRef.IsTrimToData())
316 {
317 // Clamp the size of the matrix area to rows which actually contain data.
318 // For e.g. SUM(IF over an entire column, this can make a big difference,
319 // But lets not trim the empty space from the top or left as this matters
320 // at least in matrix formulas involving IF().
321 // Refer ScCompiler::AnnotateTrimOnDoubleRefs() where double-refs are
322 // flagged for trimming.
323 SCCOL nTempCol = nCol1;
324 SCROW nTempRow = nRow1;
325 mrDoc.ShrinkToDataArea(nTab1, nTempCol, nTempRow, nCol2, nRow2);
326 }
327 }
328
329 SCSIZE nMatCols = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
330 SCSIZE nMatRows = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
331
332 if (!ScMatrix::IsSizeAllocatable( nMatCols, nMatRows))
333 {
334 SetError(FormulaError::MatrixSize);
335 return nullptr;
336 }
337
338 ScTokenMatrixMap::const_iterator aIter;
339 if (pToken && ((aIter = maTokenMatrixMap.find( pToken)) != maTokenMatrixMap.end()))
340 {
341 /* XXX casting const away here is ugly; ScMatrixToken (to which the
342 * result of this function usually is assigned) should not be forced to
343 * carry a ScConstMatrixRef though.
344 * TODO: a matrix already stored in pTokenMatrixMap should be
345 * read-only and have a copy-on-write mechanism. Previously all tokens
346 * were modifiable so we're already better than before ... */
347 return const_cast<FormulaToken*>((*aIter).second.get())->GetMatrix();
348 }
349
350 ScMatrixRef pMat = GetNewMat( nMatCols, nMatRows, true);
351 if (!pMat || nGlobalError != FormulaError::NONE)
352 return nullptr;
353
354 if (!bCalcAsShown)
355 {
356 // Use fast array fill.
357 mrDoc.FillMatrix(*pMat, nTab1, nCol1, nRow1, nCol2, nRow2);
358 }
359 else
360 {
361 // Use slower ScCellIterator to round values.
362
363 // TODO: this probably could use CellBucket for faster storage, see
364 // sc/source/core/data/column2.cxx and FillMatrixHandler, and then be
365 // moved to a function on its own, and/or squeeze the rounding into a
366 // similar FillMatrixHandler that would need to keep track of the cell
367 // position then.
368
369 // Set position where the next entry is expected.
370 SCROW nNextRow = nRow1;
371 SCCOL nNextCol = nCol1;
372 // Set last position as if there was a previous entry.
373 SCROW nThisRow = nRow2;
374 SCCOL nThisCol = nCol1 - 1;
375
376 ScCellIterator aCellIter( mrDoc, ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
377 for (bool bHas = aCellIter.first(); bHas; bHas = aCellIter.next())
378 {
379 nThisCol = aCellIter.GetPos().Col();
380 nThisRow = aCellIter.GetPos().Row();
381 if (nThisCol != nNextCol || nThisRow != nNextRow)
382 {
383 // Fill empty between iterator's positions.
384 for ( ; nNextCol <= nThisCol; ++nNextCol)
385 {
386 const SCSIZE nC = nNextCol - nCol1;
387 const SCSIZE nMatStopRow = ((nNextCol < nThisCol) ? nMatRows : nThisRow - nRow1);
388 for (SCSIZE nR = nNextRow - nRow1; nR < nMatStopRow; ++nR)
389 {
390 pMat->PutEmpty( nC, nR);
391 }
392 nNextRow = nRow1;
393 }
394 }
395 if (nThisRow == nRow2)
396 {
397 nNextCol = nThisCol + 1;
398 nNextRow = nRow1;
399 }
400 else
401 {
402 nNextCol = nThisCol;
403 nNextRow = nThisRow + 1;
404 }
405
406 const SCSIZE nMatCol = static_cast<SCSIZE>(nThisCol - nCol1);
407 const SCSIZE nMatRow = static_cast<SCSIZE>(nThisRow - nRow1);
408 ScRefCellValue aCell( aCellIter.getRefCellValue());
409 if (aCellIter.isEmpty() || aCell.hasEmptyValue())
410 {
411 pMat->PutEmpty( nMatCol, nMatRow);
412 }
413 else if (aCell.hasError())
414 {
415 pMat->PutError( aCell.getFormula()->GetErrCode(), nMatCol, nMatRow);
416 }
417 else if (aCell.hasNumeric())
418 {
419 double fVal = aCell.getValue();
420 // CELLTYPE_FORMULA already stores the rounded value.
421 if (aCell.getType() == CELLTYPE_VALUE)
422 {
423 // TODO: this could be moved to ScCellIterator to take
424 // advantage of the faster ScAttrArray_IterGetNumberFormat.
425 const ScAddress aAdr( nThisCol, nThisRow, nTab1);
426 const sal_uInt32 nNumFormat = mrDoc.GetNumberFormat( mrContext, aAdr);
427 fVal = mrDoc.RoundValueAsShown( fVal, nNumFormat, &mrContext);
428 }
429 pMat->PutDouble( fVal, nMatCol, nMatRow);
430 }
431 else if (aCell.hasString())
432 {
433 pMat->PutString( mrStrPool.intern( aCell.getString(&mrDoc)), nMatCol, nMatRow);
434 }
435 else
436 {
437 assert(!"aCell.what?");
438 pMat->PutEmpty( nMatCol, nMatRow);
439 }
440 }
441
442 // Fill empty if iterator's last position wasn't the end.
443 if (nThisCol != nCol2 || nThisRow != nRow2)
444 {
445 for ( ; nNextCol <= nCol2; ++nNextCol)
446 {
447 SCSIZE nC = nNextCol - nCol1;
448 for (SCSIZE nR = nNextRow - nRow1; nR < nMatRows; ++nR)
449 {
450 pMat->PutEmpty( nC, nR);
451 }
452 nNextRow = nRow1;
453 }
454 }
455 }
456
457 if (pToken)
458 maTokenMatrixMap.emplace(pToken, new ScMatrixToken( pMat));
459
460 return pMat;
461}
462
464{
465 ScMatrixRef pMat = nullptr;
466 switch (GetRawStackType())
467 {
468 case svSingleRef :
469 {
470 ScAddress aAdr;
471 PopSingleRef( aAdr );
472 pMat = GetNewMat(1, 1);
473 if (pMat)
474 {
475 ScRefCellValue aCell(mrDoc, aAdr);
476 if (aCell.hasEmptyValue())
477 pMat->PutEmpty(0, 0);
478 else if (aCell.hasNumeric())
479 pMat->PutDouble(GetCellValue(aAdr, aCell), 0);
480 else
481 {
483 GetCellString(aStr, aCell);
484 pMat->PutString(aStr, 0);
485 }
486 }
487 }
488 break;
489 case svDoubleRef:
490 {
491 SCCOL nCol1, nCol2;
492 SCROW nRow1, nRow2;
493 SCTAB nTab1, nTab2;
494 const formula::FormulaToken* p = sp ? pStack[sp-1] : nullptr;
495 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
496 pMat = CreateMatrixFromDoubleRef( p, nCol1, nRow1, nTab1,
497 nCol2, nRow2, nTab2);
498 }
499 break;
500 case svMatrix:
501 pMat = PopMatrix();
502 break;
503 case svError :
504 case svMissing :
505 case svDouble :
506 {
507 double fVal = GetDouble();
508 pMat = GetNewMat( 1, 1);
509 if ( pMat )
510 {
511 if ( nGlobalError != FormulaError::NONE )
512 {
514 nGlobalError = FormulaError::NONE;
515 }
516 pMat->PutDouble( fVal, 0);
517 }
518 }
519 break;
520 case svString :
521 {
523 pMat = GetNewMat( 1, 1);
524 if ( pMat )
525 {
526 if ( nGlobalError != FormulaError::NONE )
527 {
528 double fVal = CreateDoubleError( nGlobalError);
529 pMat->PutDouble( fVal, 0);
530 nGlobalError = FormulaError::NONE;
531 }
532 else
533 pMat->PutString(aStr, 0);
534 }
535 }
536 break;
538 {
540 PopExternalSingleRef(pToken);
541 pMat = GetNewMat( 1, 1, true);
542 if (!pMat)
543 break;
544 if (nGlobalError != FormulaError::NONE)
545 {
546 pMat->PutError( nGlobalError, 0, 0);
547 nGlobalError = FormulaError::NONE;
548 break;
549 }
550 switch (pToken->GetType())
551 {
552 case svError:
553 pMat->PutError( pToken->GetError(), 0, 0);
554 break;
555 case svDouble:
556 pMat->PutDouble( pToken->GetDouble(), 0, 0);
557 break;
558 case svString:
559 pMat->PutString( pToken->GetString(), 0, 0);
560 break;
561 default:
562 ; // nothing, empty element matrix
563 }
564 }
565 break;
568 break;
569 default:
570 PopError();
571 SetError( FormulaError::IllegalArgument);
572 break;
573 }
574 return pMat;
575}
576
577ScMatrixRef ScInterpreter::GetMatrix( short & rParam, size_t & rRefInList )
578{
579 switch (GetRawStackType())
580 {
581 case svRefList:
582 {
584 PopDoubleRef( aRange, rParam, rRefInList);
585 if (nGlobalError != FormulaError::NONE)
586 return nullptr;
587
588 SCCOL nCol1, nCol2;
589 SCROW nRow1, nRow2;
590 SCTAB nTab1, nTab2;
591 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
592 return CreateMatrixFromDoubleRef( nullptr, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
593 }
594 break;
595 default:
596 return GetMatrix();
597 }
598}
599
601{
602 sc::RangeMatrix aRet;
603 switch (GetRawStackType())
604 {
605 case svMatrix:
606 aRet = PopRangeMatrix();
607 break;
608 default:
609 aRet.mpMat = GetMatrix();
610 }
611 return aRet;
612}
613
615{
616 if ( !MustHaveParamCount( GetByte(), 3 ) )
617 return;
618
619 // 0 to count-1
620 // Theoretically we could have GetSize() instead of GetUInt32(), but
621 // really, practically ...
622 SCSIZE nR = static_cast<SCSIZE>(GetUInt32());
623 SCSIZE nC = static_cast<SCSIZE>(GetUInt32());
624 if (nGlobalError != FormulaError::NONE)
625 {
627 return;
628 }
629 switch (GetStackType())
630 {
631 case svSingleRef :
632 {
633 ScAddress aAdr;
634 PopSingleRef( aAdr );
635 ScRefCellValue aCell(mrDoc, aAdr);
636 if (aCell.getType() == CELLTYPE_FORMULA)
637 {
638 FormulaError nErrCode = aCell.getFormula()->GetErrCode();
639 if (nErrCode != FormulaError::NONE)
640 PushError( nErrCode);
641 else
642 {
643 const ScMatrix* pMat = aCell.getFormula()->GetMatrix();
644 CalculateMatrixValue(pMat,nC,nR);
645 }
646 }
647 else
649 }
650 break;
651 case svDoubleRef :
652 {
653 SCCOL nCol1;
654 SCROW nRow1;
655 SCTAB nTab1;
656 SCCOL nCol2;
657 SCROW nRow2;
658 SCTAB nTab2;
659 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
660 if (nCol2 - nCol1 >= static_cast<SCCOL>(nR) &&
661 nRow2 - nRow1 >= static_cast<SCROW>(nC) &&
662 nTab1 == nTab2)
663 {
664 ScAddress aAdr( sal::static_int_cast<SCCOL>( nCol1 + nR ),
665 sal::static_int_cast<SCROW>( nRow1 + nC ), nTab1 );
666 ScRefCellValue aCell(mrDoc, aAdr);
667 if (aCell.hasNumeric())
668 PushDouble(GetCellValue(aAdr, aCell));
669 else
670 {
672 GetCellString(aStr, aCell);
674 }
675 }
676 else
677 PushNoValue();
678 }
679 break;
680 case svMatrix:
681 {
682 ScMatrixRef pMat = PopMatrix();
683 CalculateMatrixValue(pMat.get(),nC,nR);
684 }
685 break;
686 default:
687 PopError();
689 break;
690 }
691}
693{
694 if (pMat)
695 {
696 SCSIZE nCl, nRw;
697 pMat->GetDimensions(nCl, nRw);
698 if (nC < nCl && nR < nRw)
699 {
700 const ScMatrixValue nMatVal = pMat->Get( nC, nR);
701 ScMatValType nMatValType = nMatVal.nType;
702 if (ScMatrix::IsNonValueType( nMatValType))
703 PushString( nMatVal.GetString() );
704 else
705 PushDouble(nMatVal.fVal);
706 // also handles DoubleError
707 }
708 else
709 PushNoValue();
710 }
711 else
712 PushNoValue();
713}
714
716{
717 if ( !MustHaveParamCount( GetByte(), 1 ) )
718 return;
719
720 SCSIZE nDim = static_cast<SCSIZE>(GetUInt32());
721 if (nGlobalError != FormulaError::NONE || nDim == 0)
723 else if (!ScMatrix::IsSizeAllocatable( nDim, nDim))
724 PushError( FormulaError::MatrixSize);
725 else
726 {
727 ScMatrixRef pRMat = GetNewMat(nDim, nDim, /*bEmpty*/true);
728 if (pRMat)
729 {
730 MEMat(pRMat, nDim);
731 PushMatrix(pRMat);
732 }
733 else
735 }
736}
737
739{
740 mM->FillDouble(0.0, 0, 0, n-1, n-1);
741 for (SCSIZE i = 0; i < n; i++)
742 mM->PutDouble(1.0, i, i);
743}
744
745/* Matrix LUP decomposition according to the pseudocode of "Introduction to
746 * Algorithms" by Cormen, Leiserson, Rivest, Stein.
747 *
748 * Added scaling for numeric stability.
749 *
750 * Given an n x n nonsingular matrix A, find a permutation matrix P, a unit
751 * lower-triangular matrix L, and an upper-triangular matrix U such that PA=LU.
752 * Compute L and U "in place" in the matrix A, the original content is
753 * destroyed. Note that the diagonal elements of the U triangular matrix
754 * replace the diagonal elements of the L-unit matrix (that are each ==1). The
755 * permutation matrix P is an array, where P[i]=j means that the i-th row of P
756 * contains a 1 in column j. Additionally keep track of the number of
757 * permutations (row exchanges).
758 *
759 * Returns 0 if a singular matrix is encountered, else +1 if an even number of
760 * permutations occurred, or -1 if odd, which is the sign of the determinant.
761 * This may be used to calculate the determinant by multiplying the sign with
762 * the product of the diagonal elements of the LU matrix.
763 */
764static int lcl_LUP_decompose( ScMatrix* mA, const SCSIZE n,
765 ::std::vector< SCSIZE> & P )
766{
767 int nSign = 1;
768 // Find scale of each row.
769 ::std::vector< double> aScale(n);
770 for (SCSIZE i=0; i < n; ++i)
771 {
772 double fMax = 0.0;
773 for (SCSIZE j=0; j < n; ++j)
774 {
775 double fTmp = fabs( mA->GetDouble( j, i));
776 if (fMax < fTmp)
777 fMax = fTmp;
778 }
779 if (fMax == 0.0)
780 return 0; // singular matrix
781 aScale[i] = 1.0 / fMax;
782 }
783 // Represent identity permutation, P[i]=i
784 for (SCSIZE i=0; i < n; ++i)
785 P[i] = i;
786 // "Recursion" on the diagonal.
787 SCSIZE l = n - 1;
788 for (SCSIZE k=0; k < l; ++k)
789 {
790 // Implicit pivoting. With the scale found for a row, compare values of
791 // a column and pick largest.
792 double fMax = 0.0;
793 double fScale = aScale[k];
794 SCSIZE kp = k;
795 for (SCSIZE i = k; i < n; ++i)
796 {
797 double fTmp = fScale * fabs( mA->GetDouble( k, i));
798 if (fMax < fTmp)
799 {
800 fMax = fTmp;
801 kp = i;
802 }
803 }
804 if (fMax == 0.0)
805 return 0; // singular matrix
806 // Swap rows. The pivot element will be at mA[k,kp] (row,col notation)
807 if (k != kp)
808 {
809 // permutations
810 SCSIZE nTmp = P[k];
811 P[k] = P[kp];
812 P[kp] = nTmp;
813 nSign = -nSign;
814 // scales
815 double fTmp = aScale[k];
816 aScale[k] = aScale[kp];
817 aScale[kp] = fTmp;
818 // elements
819 for (SCSIZE i=0; i < n; ++i)
820 {
821 double fMatTmp = mA->GetDouble( i, k);
822 mA->PutDouble( mA->GetDouble( i, kp), i, k);
823 mA->PutDouble( fMatTmp, i, kp);
824 }
825 }
826 // Compute Schur complement.
827 for (SCSIZE i = k+1; i < n; ++i)
828 {
829 double fNum = mA->GetDouble( k, i);
830 double fDen = mA->GetDouble( k, k);
831 mA->PutDouble( fNum/fDen, k, i);
832 for (SCSIZE j = k+1; j < n; ++j)
833 mA->PutDouble( ( mA->GetDouble( j, i) * fDen -
834 fNum * mA->GetDouble( j, k) ) / fDen, j, i);
835 }
836 }
837#ifdef DEBUG_SC_LUP_DECOMPOSITION
838 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): LU");
839 for (SCSIZE i=0; i < n; ++i)
840 {
841 for (SCSIZE j=0; j < n; ++j)
842 fprintf( stderr, "%8.2g ", mA->GetDouble( j, i));
843 fprintf( stderr, "\n%s\n", "");
844 }
845 fprintf( stderr, "\n%s\n", "lcl_LUP_decompose(): P");
846 for (SCSIZE j=0; j < n; ++j)
847 fprintf( stderr, "%5u ", (unsigned)P[j]);
848 fprintf( stderr, "\n%s\n", "");
849#endif
850
851 bool bSingular=false;
852 for (SCSIZE i=0; i<n && !bSingular; i++)
853 bSingular = (mA->GetDouble(i,i)) == 0.0;
854 if (bSingular)
855 nSign = 0;
856
857 return nSign;
858}
859
860/* Solve a LUP decomposed equation Ax=b. LU is a combined matrix of L and U
861 * triangulars and P the permutation vector as obtained from
862 * lcl_LUP_decompose(). B is the right-hand side input vector, X is used to
863 * return the solution vector.
864 */
865static void lcl_LUP_solve( const ScMatrix* mLU, const SCSIZE n,
866 const ::std::vector< SCSIZE> & P, const ::std::vector< double> & B,
867 ::std::vector< double> & X )
868{
869 SCSIZE nFirst = SCSIZE_MAX;
870 // Ax=b => PAx=Pb, with decomposition LUx=Pb.
871 // Define y=Ux and solve for y in Ly=Pb using forward substitution.
872 for (SCSIZE i=0; i < n; ++i)
873 {
874 KahanSum fSum = B[P[i]];
875 // Matrix inversion comes with a lot of zeros in the B vectors, we
876 // don't have to do all the computing with results multiplied by zero.
877 // Until then, simply lookout for the position of the first nonzero
878 // value.
879 if (nFirst != SCSIZE_MAX)
880 {
881 for (SCSIZE j = nFirst; j < i; ++j)
882 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === y[j]
883 }
884 else if (fSum != 0)
885 nFirst = i;
886 X[i] = fSum.get(); // X[i] === y[i]
887 }
888 // Solve for x in Ux=y using back substitution.
889 for (SCSIZE i = n; i--; )
890 {
891 KahanSum fSum = X[i]; // X[i] === y[i]
892 for (SCSIZE j = i+1; j < n; ++j)
893 fSum -= mLU->GetDouble( j, i) * X[j]; // X[j] === x[j]
894 X[i] = fSum.get() / mLU->GetDouble( i, i); // X[i] === x[i]
895 }
896#ifdef DEBUG_SC_LUP_DECOMPOSITION
897 fprintf( stderr, "\n%s\n", "lcl_LUP_solve():");
898 for (SCSIZE i=0; i < n; ++i)
899 fprintf( stderr, "%8.2g ", X[i]);
900 fprintf( stderr, "%s\n", "");
901#endif
902}
903
905{
906 if ( !MustHaveParamCount( GetByte(), 1 ) )
907 return;
908
909 ScMatrixRef pMat = GetMatrix();
910 if (!pMat)
911 {
913 return;
914 }
915 if ( !pMat->IsNumeric() )
916 {
917 PushNoValue();
918 return;
919 }
920 SCSIZE nC, nR;
921 pMat->GetDimensions(nC, nR);
922 if ( nC != nR || nC == 0 )
924 else if (!ScMatrix::IsSizeAllocatable( nC, nR))
925 PushError( FormulaError::MatrixSize);
926 else
927 {
928 // LUP decomposition is done inplace, use copy.
929 ScMatrixRef xLU = pMat->Clone();
930 if (!xLU)
931 PushError( FormulaError::CodeOverflow);
932 else
933 {
934 ::std::vector< SCSIZE> P(nR);
935 int nDetSign = lcl_LUP_decompose( xLU.get(), nR, P);
936 if (!nDetSign)
937 PushInt(0); // singular matrix
938 else
939 {
940 // In an LU matrix the determinant is simply the product of
941 // all diagonal elements.
942 double fDet = nDetSign;
943 for (SCSIZE i=0; i < nR; ++i)
944 fDet *= xLU->GetDouble( i, i);
945 PushDouble( fDet);
946 }
947 }
948 }
949}
950
952{
953 if ( !MustHaveParamCount( GetByte(), 1 ) )
954 return;
955
956 ScMatrixRef pMat = GetMatrix();
957 if (!pMat)
958 {
960 return;
961 }
962 if ( !pMat->IsNumeric() )
963 {
964 PushNoValue();
965 return;
966 }
967 SCSIZE nC, nR;
968 pMat->GetDimensions(nC, nR);
969
971 {
973 if (pInterpreter != nullptr)
974 {
975 ScMatrixRef xResMat = pInterpreter->inverseMatrix(*pMat);
976 if (xResMat)
977 {
978 PushMatrix(xResMat);
979 return;
980 }
981 }
982 }
983
984 if ( nC != nR || nC == 0 )
986 else if (!ScMatrix::IsSizeAllocatable( nC, nR))
987 PushError( FormulaError::MatrixSize);
988 else
989 {
990 // LUP decomposition is done inplace, use copy.
991 ScMatrixRef xLU = pMat->Clone();
992 // The result matrix.
993 ScMatrixRef xY = GetNewMat( nR, nR, /*bEmpty*/true );
994 if (!xLU || !xY)
995 PushError( FormulaError::CodeOverflow);
996 else
997 {
998 ::std::vector< SCSIZE> P(nR);
999 int nDetSign = lcl_LUP_decompose( xLU.get(), nR, P);
1000 if (!nDetSign)
1002 else
1003 {
1004 // Solve equation for each column.
1005 ::std::vector< double> B(nR);
1006 ::std::vector< double> X(nR);
1007 for (SCSIZE j=0; j < nR; ++j)
1008 {
1009 for (SCSIZE i=0; i < nR; ++i)
1010 B[i] = 0.0;
1011 B[j] = 1.0;
1012 lcl_LUP_solve( xLU.get(), nR, P, B, X);
1013 for (SCSIZE i=0; i < nR; ++i)
1014 xY->PutDouble( X[i], j, i);
1015 }
1016#ifdef DEBUG_SC_LUP_DECOMPOSITION
1017 /* Possible checks for ill-condition:
1018 * 1. Scale matrix, invert scaled matrix. If there are
1019 * elements of the inverted matrix that are several
1020 * orders of magnitude greater than 1 =>
1021 * ill-conditioned.
1022 * Just how much is "several orders"?
1023 * 2. Invert the inverted matrix and assess whether the
1024 * result is sufficiently close to the original matrix.
1025 * If not => ill-conditioned.
1026 * Just what is sufficient?
1027 * 3. Multiplying the inverse by the original matrix should
1028 * produce a result sufficiently close to the identity
1029 * matrix.
1030 * Just what is sufficient?
1031 *
1032 * The following is #3.
1033 */
1034 const double fInvEpsilon = 1.0E-7;
1035 ScMatrixRef xR = GetNewMat( nR, nR);
1036 if (xR)
1037 {
1038 ScMatrix* pR = xR.get();
1039 lcl_MFastMult( pMat, xY.get(), pR, nR, nR, nR);
1040 fprintf( stderr, "\n%s\n", "ScMatInv(): mult-identity");
1041 for (SCSIZE i=0; i < nR; ++i)
1042 {
1043 for (SCSIZE j=0; j < nR; ++j)
1044 {
1045 double fTmp = pR->GetDouble( j, i);
1046 fprintf( stderr, "%8.2g ", fTmp);
1047 if (fabs( fTmp - (i == j)) > fInvEpsilon)
1048 SetError( FormulaError::IllegalArgument);
1049 }
1050 fprintf( stderr, "\n%s\n", "");
1051 }
1052 }
1053#endif
1054 if (nGlobalError != FormulaError::NONE)
1056 else
1057 PushMatrix( xY);
1058 }
1059 }
1060 }
1061}
1062
1064{
1065 if ( !MustHaveParamCount( GetByte(), 2 ) )
1066 return;
1067
1068 ScMatrixRef pMat2 = GetMatrix();
1069 ScMatrixRef pMat1 = GetMatrix();
1070 ScMatrixRef pRMat;
1071 if (pMat1 && pMat2)
1072 {
1073 if ( pMat1->IsNumeric() && pMat2->IsNumeric() )
1074 {
1075 SCSIZE nC1, nC2;
1076 SCSIZE nR1, nR2;
1077 pMat1->GetDimensions(nC1, nR1);
1078 pMat2->GetDimensions(nC2, nR2);
1079 if (nC1 != nR2)
1081 else
1082 {
1083 pRMat = GetNewMat(nC2, nR1, /*bEmpty*/true);
1084 if (pRMat)
1085 {
1086 KahanSum fSum;
1087 for (SCSIZE i = 0; i < nR1; i++)
1088 {
1089 for (SCSIZE j = 0; j < nC2; j++)
1090 {
1091 fSum = 0.0;
1092 for (SCSIZE k = 0; k < nC1; k++)
1093 {
1094 fSum += pMat1->GetDouble(k,i)*pMat2->GetDouble(j,k);
1095 }
1096 pRMat->PutDouble(fSum.get(), j, i);
1097 }
1098 }
1099 PushMatrix(pRMat);
1100 }
1101 else
1103 }
1104 }
1105 else
1106 PushNoValue();
1107 }
1108 else
1110}
1111
1113{
1114 if ( !MustHaveParamCount( GetByte(), 1 ) )
1115 return;
1116
1117 ScMatrixRef pMat = GetMatrix();
1118 ScMatrixRef pRMat;
1119 if (pMat)
1120 {
1121 SCSIZE nC, nR;
1122 pMat->GetDimensions(nC, nR);
1123 pRMat = GetNewMat(nR, nC, /*bEmpty*/true);
1124 if ( pRMat )
1125 {
1126 pMat->MatTrans(*pRMat);
1127 PushMatrix(pRMat);
1128 }
1129 else
1131 }
1132 else
1134}
1135
1141{
1142 if (n1 == 1)
1143 return n2;
1144 else if (n2 == 1)
1145 return n1;
1146 else if (n1 < n2)
1147 return n1;
1148 else
1149 return n2;
1150}
1151
1153 const ScMatrix& rMat1, const ScMatrix& rMat2, ScInterpreter* pInterpreter, ScMatrix::CalculateOpFunction Op)
1154{
1155 SCSIZE nC1, nC2, nMinC;
1156 SCSIZE nR1, nR2, nMinR;
1157 rMat1.GetDimensions(nC1, nR1);
1158 rMat2.GetDimensions(nC2, nR2);
1159 nMinC = lcl_GetMinExtent( nC1, nC2);
1160 nMinR = lcl_GetMinExtent( nR1, nR2);
1161 ScMatrixRef xResMat = pInterpreter->GetNewMat(nMinC, nMinR, /*bEmpty*/true);
1162 if (xResMat)
1163 xResMat->ExecuteBinaryOp(nMinC, nMinR, rMat1, rMat2, pInterpreter, Op);
1164 return xResMat;
1165}
1166
1168{
1169 SCSIZE nC1, nC2, nMinC;
1170 SCSIZE nR1, nR2, nMinR;
1171 pMat1->GetDimensions(nC1, nR1);
1172 pMat2->GetDimensions(nC2, nR2);
1173 nMinC = lcl_GetMinExtent( nC1, nC2);
1174 nMinR = lcl_GetMinExtent( nR1, nR2);
1175 ScMatrixRef xResMat = GetNewMat(nMinC, nMinR, /*bEmpty*/true);
1176 if (xResMat)
1177 {
1178 xResMat->MatConcat(nMinC, nMinR, pMat1, pMat2, *pFormatter, mrDoc.GetSharedStringPool());
1179 }
1180 return xResMat;
1181}
1182
1183// for DATE, TIME, DATETIME, DURATION
1185{
1186 if ( nFmt1 == SvNumFormatType::UNDEFINED && nFmt2 == SvNumFormatType::UNDEFINED )
1187 return;
1188
1189 if ( nFmt1 == nFmt2 )
1190 {
1191 if ( nFmt1 == SvNumFormatType::TIME || nFmt1 == SvNumFormatType::DATETIME
1192 || nFmt1 == SvNumFormatType::DURATION )
1193 nFuncFmt = SvNumFormatType::DURATION; // times result in time duration
1194 // else: nothing special, number (date - date := days)
1195 }
1196 else if ( nFmt1 == SvNumFormatType::UNDEFINED )
1197 nFuncFmt = nFmt2; // e.g. date + days := date
1198 else if ( nFmt2 == SvNumFormatType::UNDEFINED )
1199 nFuncFmt = nFmt1;
1200 else
1201 {
1202 if ( nFmt1 == SvNumFormatType::DATE || nFmt2 == SvNumFormatType::DATE ||
1203 nFmt1 == SvNumFormatType::DATETIME || nFmt2 == SvNumFormatType::DATETIME )
1204 {
1205 if ( nFmt1 == SvNumFormatType::TIME || nFmt2 == SvNumFormatType::TIME )
1206 nFuncFmt = SvNumFormatType::DATETIME; // date + time
1207 }
1208 }
1209}
1210
1212{
1213 CalculateAddSub(false);
1214}
1215
1217{
1218 ScMatrixRef pMat1 = nullptr;
1219 ScMatrixRef pMat2 = nullptr;
1220 double fVal1 = 0.0, fVal2 = 0.0;
1221 SvNumFormatType nFmt1, nFmt2;
1222 nFmt1 = nFmt2 = SvNumFormatType::UNDEFINED;
1223 SvNumFormatType nFmtCurrencyType = nCurFmtType;
1224 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1225 SvNumFormatType nFmtPercentType = nCurFmtType;
1226 if ( GetStackType() == svMatrix )
1227 pMat2 = GetMatrix();
1228 else
1229 {
1230 fVal2 = GetDouble();
1231 switch ( nCurFmtType )
1232 {
1233 case SvNumFormatType::DATE :
1234 case SvNumFormatType::TIME :
1235 case SvNumFormatType::DATETIME :
1236 case SvNumFormatType::DURATION :
1237 nFmt2 = nCurFmtType;
1238 break;
1239 case SvNumFormatType::CURRENCY :
1240 nFmtCurrencyType = nCurFmtType;
1241 nFmtCurrencyIndex = nCurFmtIndex;
1242 break;
1243 case SvNumFormatType::PERCENT :
1244 nFmtPercentType = SvNumFormatType::PERCENT;
1245 break;
1246 default: break;
1247 }
1248 }
1249 if ( GetStackType() == svMatrix )
1250 pMat1 = GetMatrix();
1251 else
1252 {
1253 fVal1 = GetDouble();
1254 switch ( nCurFmtType )
1255 {
1256 case SvNumFormatType::DATE :
1257 case SvNumFormatType::TIME :
1258 case SvNumFormatType::DATETIME :
1259 case SvNumFormatType::DURATION :
1260 nFmt1 = nCurFmtType;
1261 break;
1262 case SvNumFormatType::CURRENCY :
1263 nFmtCurrencyType = nCurFmtType;
1264 nFmtCurrencyIndex = nCurFmtIndex;
1265 break;
1266 case SvNumFormatType::PERCENT :
1267 nFmtPercentType = SvNumFormatType::PERCENT;
1268 break;
1269 default: break;
1270 }
1271 }
1272 if (pMat1 && pMat2)
1273 {
1274 ScMatrixRef pResMat;
1275 if ( _bSub )
1276 {
1277 pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixSub);
1278 }
1279 else
1280 {
1281 pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixAdd);
1282 }
1283
1284 if (!pResMat)
1285 PushNoValue();
1286 else
1287 PushMatrix(pResMat);
1288 }
1289 else if (pMat1 || pMat2)
1290 {
1291 double fVal;
1292 bool bFlag;
1293 ScMatrixRef pMat = pMat1;
1294 if (!pMat)
1295 {
1296 fVal = fVal1;
1297 pMat = pMat2;
1298 bFlag = true; // double - Matrix
1299 }
1300 else
1301 {
1302 fVal = fVal2;
1303 bFlag = false; // Matrix - double
1304 }
1305 SCSIZE nC, nR;
1306 pMat->GetDimensions(nC, nR);
1307 ScMatrixRef pResMat = GetNewMat(nC, nR, true);
1308 if (pResMat)
1309 {
1310 if (_bSub)
1311 {
1312 pMat->SubOp( bFlag, fVal, *pResMat);
1313 }
1314 else
1315 {
1316 pMat->AddOp( fVal, *pResMat);
1317 }
1318 PushMatrix(pResMat);
1319 }
1320 else
1322 }
1323 else
1324 {
1325 // Determine nFuncFmtType type before PushDouble().
1326 if ( nFmtCurrencyType == SvNumFormatType::CURRENCY )
1327 {
1328 nFuncFmtType = nFmtCurrencyType;
1329 nFuncFmtIndex = nFmtCurrencyIndex;
1330 }
1331 else
1332 {
1334 if (nFmtPercentType == SvNumFormatType::PERCENT && nFuncFmtType == SvNumFormatType::NUMBER)
1335 nFuncFmtType = SvNumFormatType::PERCENT;
1336 }
1337 if ( _bSub )
1338 PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) );
1339 else
1340 PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) );
1341 }
1342}
1343
1345{
1346 ScMatrixRef pMat1 = nullptr;
1347 ScMatrixRef pMat2 = nullptr;
1348 OUString sStr1, sStr2;
1349 if ( GetStackType() == svMatrix )
1350 pMat2 = GetMatrix();
1351 else
1352 sStr2 = GetString().getString();
1353 if ( GetStackType() == svMatrix )
1354 pMat1 = GetMatrix();
1355 else
1356 sStr1 = GetString().getString();
1357 if (pMat1 && pMat2)
1358 {
1359 ScMatrixRef pResMat = MatConcat(pMat1, pMat2);
1360 if (!pResMat)
1361 PushNoValue();
1362 else
1363 PushMatrix(pResMat);
1364 }
1365 else if (pMat1 || pMat2)
1366 {
1367 OUString sStr;
1368 bool bFlag;
1369 ScMatrixRef pMat = pMat1;
1370 if (!pMat)
1371 {
1372 sStr = sStr1;
1373 pMat = pMat2;
1374 bFlag = true; // double - Matrix
1375 }
1376 else
1377 {
1378 sStr = sStr2;
1379 bFlag = false; // Matrix - double
1380 }
1381 SCSIZE nC, nR;
1382 pMat->GetDimensions(nC, nR);
1383 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1384 if (pResMat)
1385 {
1386 if (nGlobalError != FormulaError::NONE)
1387 {
1388 for (SCSIZE i = 0; i < nC; ++i)
1389 for (SCSIZE j = 0; j < nR; ++j)
1390 pResMat->PutError( nGlobalError, i, j);
1391 }
1392 else if (bFlag)
1393 {
1394 for (SCSIZE i = 0; i < nC; ++i)
1395 for (SCSIZE j = 0; j < nR; ++j)
1396 {
1397 FormulaError nErr = pMat->GetErrorIfNotString( i, j);
1398 if (nErr != FormulaError::NONE)
1399 pResMat->PutError( nErr, i, j);
1400 else
1401 {
1402 OUString aTmp = sStr + pMat->GetString(*pFormatter, i, j).getString();
1403 pResMat->PutString(mrStrPool.intern(aTmp), i, j);
1404 }
1405 }
1406 }
1407 else
1408 {
1409 for (SCSIZE i = 0; i < nC; ++i)
1410 for (SCSIZE j = 0; j < nR; ++j)
1411 {
1412 FormulaError nErr = pMat->GetErrorIfNotString( i, j);
1413 if (nErr != FormulaError::NONE)
1414 pResMat->PutError( nErr, i, j);
1415 else
1416 {
1417 OUString aTmp = pMat->GetString(*pFormatter, i, j).getString() + sStr;
1418 pResMat->PutString(mrStrPool.intern(aTmp), i, j);
1419 }
1420 }
1421 }
1422 PushMatrix(pResMat);
1423 }
1424 else
1426 }
1427 else
1428 {
1429 if ( CheckStringResultLen( sStr1, sStr2.getLength() ) )
1430 sStr1 += sStr2;
1431 PushString(sStr1);
1432 }
1433}
1434
1436{
1437 CalculateAddSub(true);
1438}
1439
1441{
1442 ScMatrixRef pMat1 = nullptr;
1443 ScMatrixRef pMat2 = nullptr;
1444 double fVal1 = 0.0, fVal2 = 0.0;
1445 SvNumFormatType nFmtCurrencyType = nCurFmtType;
1446 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1447 if ( GetStackType() == svMatrix )
1448 pMat2 = GetMatrix();
1449 else
1450 {
1451 fVal2 = GetDouble();
1452 switch ( nCurFmtType )
1453 {
1454 case SvNumFormatType::CURRENCY :
1455 nFmtCurrencyType = nCurFmtType;
1456 nFmtCurrencyIndex = nCurFmtIndex;
1457 break;
1458 default: break;
1459 }
1460 }
1461 if ( GetStackType() == svMatrix )
1462 pMat1 = GetMatrix();
1463 else
1464 {
1465 fVal1 = GetDouble();
1466 switch ( nCurFmtType )
1467 {
1468 case SvNumFormatType::CURRENCY :
1469 nFmtCurrencyType = nCurFmtType;
1470 nFmtCurrencyIndex = nCurFmtIndex;
1471 break;
1472 default: break;
1473 }
1474 }
1475 if (pMat1 && pMat2)
1476 {
1477 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixMul);
1478 if (!pResMat)
1479 PushNoValue();
1480 else
1481 PushMatrix(pResMat);
1482 }
1483 else if (pMat1 || pMat2)
1484 {
1485 double fVal;
1486 ScMatrixRef pMat = pMat1;
1487 if (!pMat)
1488 {
1489 fVal = fVal1;
1490 pMat = pMat2;
1491 }
1492 else
1493 fVal = fVal2;
1494 SCSIZE nC, nR;
1495 pMat->GetDimensions(nC, nR);
1496 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1497 if (pResMat)
1498 {
1499 pMat->MulOp( fVal, *pResMat);
1500 PushMatrix(pResMat);
1501 }
1502 else
1504 }
1505 else
1506 {
1507 // Determine nFuncFmtType type before PushDouble().
1508 if ( nFmtCurrencyType == SvNumFormatType::CURRENCY )
1509 {
1510 nFuncFmtType = nFmtCurrencyType;
1511 nFuncFmtIndex = nFmtCurrencyIndex;
1512 }
1513 PushDouble(fVal1 * fVal2);
1514 }
1515}
1516
1518{
1519 ScMatrixRef pMat1 = nullptr;
1520 ScMatrixRef pMat2 = nullptr;
1521 double fVal1 = 0.0, fVal2 = 0.0;
1522 SvNumFormatType nFmtCurrencyType = nCurFmtType;
1523 sal_uLong nFmtCurrencyIndex = nCurFmtIndex;
1524 SvNumFormatType nFmtCurrencyType2 = SvNumFormatType::UNDEFINED;
1525 if ( GetStackType() == svMatrix )
1526 pMat2 = GetMatrix();
1527 else
1528 {
1529 fVal2 = GetDouble();
1530 // do not take over currency, 123kg/456USD is not USD
1531 nFmtCurrencyType2 = nCurFmtType;
1532 }
1533 if ( GetStackType() == svMatrix )
1534 pMat1 = GetMatrix();
1535 else
1536 {
1537 fVal1 = GetDouble();
1538 switch ( nCurFmtType )
1539 {
1540 case SvNumFormatType::CURRENCY :
1541 nFmtCurrencyType = nCurFmtType;
1542 nFmtCurrencyIndex = nCurFmtIndex;
1543 break;
1544 default: break;
1545 }
1546 }
1547 if (pMat1 && pMat2)
1548 {
1549 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixDiv);
1550 if (!pResMat)
1551 PushNoValue();
1552 else
1553 PushMatrix(pResMat);
1554 }
1555 else if (pMat1 || pMat2)
1556 {
1557 double fVal;
1558 bool bFlag;
1559 ScMatrixRef pMat = pMat1;
1560 if (!pMat)
1561 {
1562 fVal = fVal1;
1563 pMat = pMat2;
1564 bFlag = true; // double - Matrix
1565 }
1566 else
1567 {
1568 fVal = fVal2;
1569 bFlag = false; // Matrix - double
1570 }
1571 SCSIZE nC, nR;
1572 pMat->GetDimensions(nC, nR);
1573 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1574 if (pResMat)
1575 {
1576 pMat->DivOp( bFlag, fVal, *pResMat);
1577 PushMatrix(pResMat);
1578 }
1579 else
1581 }
1582 else
1583 {
1584 // Determine nFuncFmtType type before PushDouble().
1585 if ( nFmtCurrencyType == SvNumFormatType::CURRENCY &&
1586 nFmtCurrencyType2 != SvNumFormatType::CURRENCY)
1587 { // even USD/USD is not USD
1588 nFuncFmtType = nFmtCurrencyType;
1589 nFuncFmtIndex = nFmtCurrencyIndex;
1590 }
1591 PushDouble( div( fVal1, fVal2) );
1592 }
1593}
1594
1596{
1597 if ( MustHaveParamCount( GetByte(), 2 ) )
1598 ScPow();
1599}
1600
1602{
1603 ScMatrixRef pMat1 = nullptr;
1604 ScMatrixRef pMat2 = nullptr;
1605 double fVal1 = 0.0, fVal2 = 0.0;
1606 if ( GetStackType() == svMatrix )
1607 pMat2 = GetMatrix();
1608 else
1609 fVal2 = GetDouble();
1610 if ( GetStackType() == svMatrix )
1611 pMat1 = GetMatrix();
1612 else
1613 fVal1 = GetDouble();
1614 if (pMat1 && pMat2)
1615 {
1616 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixPow);
1617 if (!pResMat)
1618 PushNoValue();
1619 else
1620 PushMatrix(pResMat);
1621 }
1622 else if (pMat1 || pMat2)
1623 {
1624 double fVal;
1625 bool bFlag;
1626 ScMatrixRef pMat = pMat1;
1627 if (!pMat)
1628 {
1629 fVal = fVal1;
1630 pMat = pMat2;
1631 bFlag = true; // double - Matrix
1632 }
1633 else
1634 {
1635 fVal = fVal2;
1636 bFlag = false; // Matrix - double
1637 }
1638 SCSIZE nC, nR;
1639 pMat->GetDimensions(nC, nR);
1640 ScMatrixRef pResMat = GetNewMat(nC, nR, /*bEmpty*/true);
1641 if (pResMat)
1642 {
1643 pMat->PowOp( bFlag, fVal, *pResMat);
1644 PushMatrix(pResMat);
1645 }
1646 else
1648 }
1649 else
1650 {
1651 PushDouble( sc::power( fVal1, fVal2));
1652 }
1653}
1654
1656{
1657 short nParamCount = GetByte();
1658 if ( !MustHaveParamCountMin( nParamCount, 1) )
1659 return;
1660
1661 // XXX NOTE: Excel returns #VALUE! for reference list and 0 (why?) for
1662 // array of references. We calculate the proper individual arrays if sizes
1663 // match.
1664
1665 size_t nInRefList = 0;
1666 ScMatrixRef pMatLast;
1667 ScMatrixRef pMat;
1668
1669 pMatLast = GetMatrix( --nParamCount, nInRefList);
1670 if (!pMatLast)
1671 {
1673 return;
1674 }
1675
1676 SCSIZE nC, nCLast, nR, nRLast;
1677 pMatLast->GetDimensions(nCLast, nRLast);
1678 std::vector<double> aResArray;
1679 pMatLast->GetDoubleArray(aResArray);
1680
1681 while (nParamCount--)
1682 {
1683 pMat = GetMatrix( nParamCount, nInRefList);
1684 if (!pMat)
1685 {
1687 return;
1688 }
1689 pMat->GetDimensions(nC, nR);
1690 if (nC != nCLast || nR != nRLast)
1691 {
1692 PushNoValue();
1693 return;
1694 }
1695
1696 pMat->MergeDoubleArrayMultiply(aResArray);
1697 }
1698
1699 KahanSum fSum = 0.0;
1700 for( double fPosArray : aResArray )
1701 {
1702 FormulaError nErr = GetDoubleErrorValue(fPosArray);
1703 if (nErr == FormulaError::NONE)
1704 fSum += fPosArray;
1705 else if (nErr != FormulaError::ElementNaN)
1706 {
1707 // Propagate the first error encountered, ignore "this is not a number" elements.
1708 PushError(nErr);
1709 return;
1710 }
1711 }
1712
1713 PushDouble(fSum.get());
1714}
1715
1717{
1719}
1721{
1722 if ( !MustHaveParamCount( GetByte(), 2 ) )
1723 return;
1724
1725 ScMatrixRef pMat1 = nullptr;
1726 ScMatrixRef pMat2 = nullptr;
1727 SCSIZE i, j;
1728 pMat2 = GetMatrix();
1729 pMat1 = GetMatrix();
1730 if (!pMat2 || !pMat1)
1731 {
1733 return;
1734 }
1735 SCSIZE nC1, nC2;
1736 SCSIZE nR1, nR2;
1737 pMat2->GetDimensions(nC2, nR2);
1738 pMat1->GetDimensions(nC1, nR1);
1739 if (nC1 != nC2 || nR1 != nR2)
1740 {
1741 PushNoValue();
1742 return;
1743 }
1744 double fVal;
1745 KahanSum fSum = 0.0;
1746 for (i = 0; i < nC1; i++)
1747 for (j = 0; j < nR1; j++)
1748 if (!pMat1->IsStringOrEmpty(i,j) && !pMat2->IsStringOrEmpty(i,j))
1749 {
1750 fVal = pMat1->GetDouble(i,j);
1751 fSum += fVal * fVal;
1752 fVal = pMat2->GetDouble(i,j);
1753 if ( _bSumX2DY2 )
1754 fSum += fVal * fVal;
1755 else
1756 fSum -= fVal * fVal;
1757 }
1758 PushDouble(fSum.get());
1759}
1760
1762{
1764}
1765
1767{
1768 if ( !MustHaveParamCount( GetByte(), 2 ) )
1769 return;
1770
1771 ScMatrixRef pMat2 = GetMatrix();
1772 ScMatrixRef pMat1 = GetMatrix();
1773 if (!pMat2 || !pMat1)
1774 {
1776 return;
1777 }
1778 SCSIZE nC1, nC2;
1779 SCSIZE nR1, nR2;
1780 pMat2->GetDimensions(nC2, nR2);
1781 pMat1->GetDimensions(nC1, nR1);
1782 if (nC1 != nC2 || nR1 != nR2)
1783 {
1784 PushNoValue();
1785 return;
1786 } // if (nC1 != nC2 || nR1 != nR2)
1787 ScMatrixRef pResMat = lcl_MatrixCalculation( *pMat1, *pMat2, this, MatrixSub);
1788 if (!pResMat)
1789 {
1790 PushNoValue();
1791 }
1792 else
1793 {
1794 PushDouble(pResMat->SumSquare(false).maAccumulator.get());
1795 }
1796}
1797
1799{
1800 if ( !MustHaveParamCount( GetByte(), 2 ) )
1801 return;
1802
1803 vector<double> aBinArray;
1804 vector<tools::Long> aBinIndexOrder;
1805
1806 GetSortArray( 1, aBinArray, &aBinIndexOrder, false, false );
1807 SCSIZE nBinSize = aBinArray.size();
1808 if (nGlobalError != FormulaError::NONE)
1809 {
1810 PushNoValue();
1811 return;
1812 }
1813
1814 vector<double> aDataArray;
1815 GetSortArray( 1, aDataArray, nullptr, false, false );
1816 SCSIZE nDataSize = aDataArray.size();
1817
1818 if (aDataArray.empty() || nGlobalError != FormulaError::NONE)
1819 {
1820 PushNoValue();
1821 return;
1822 }
1823 ScMatrixRef pResMat = GetNewMat(1, nBinSize+1, /*bEmpty*/true);
1824 if (!pResMat)
1825 {
1827 return;
1828 }
1829
1830 if (nBinSize != aBinIndexOrder.size())
1831 {
1833 return;
1834 }
1835
1836 SCSIZE j;
1837 SCSIZE i = 0;
1838 for (j = 0; j < nBinSize; ++j)
1839 {
1840 SCSIZE nCount = 0;
1841 while (i < nDataSize && aDataArray[i] <= aBinArray[j])
1842 {
1843 ++nCount;
1844 ++i;
1845 }
1846 pResMat->PutDouble(static_cast<double>(nCount), aBinIndexOrder[j]);
1847 }
1848 pResMat->PutDouble(static_cast<double>(nDataSize-i), j);
1849 PushMatrix(pResMat);
1850}
1851
1852namespace {
1853
1854// Helper methods for LINEST/LOGEST and TREND/GROWTH
1855// All matrices must already exist and have the needed size, no control tests
1856// done. Those methods, which names start with lcl_T, are adapted to case 3,
1857// where Y (=observed values) is given as row.
1858// Remember, ScMatrix matrices are zero based, index access (column,row).
1859
1860// <A;B> over all elements; uses the matrices as vectors of length M
1861double lcl_GetSumProduct(const ScMatrixRef& pMatA, const ScMatrixRef& pMatB, SCSIZE nM)
1862{
1863 KahanSum fSum = 0.0;
1864 for (SCSIZE i=0; i<nM; i++)
1865 fSum += pMatA->GetDouble(i) * pMatB->GetDouble(i);
1866 return fSum.get();
1867}
1868
1869// Special version for use within QR decomposition.
1870// Euclidean norm of column index C starting in row index R;
1871// matrix A has count N rows.
1872double lcl_GetColumnEuclideanNorm(const ScMatrixRef& pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN)
1873{
1874 KahanSum fNorm = 0.0;
1875 for (SCSIZE row=nR; row<nN; row++)
1876 fNorm += (pMatA->GetDouble(nC,row)) * (pMatA->GetDouble(nC,row));
1877 return sqrt(fNorm.get());
1878}
1879
1880// Euclidean norm of row index R starting in column index C;
1881// matrix A has count N columns.
1882double lcl_TGetColumnEuclideanNorm(const ScMatrixRef& pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN)
1883{
1884 KahanSum fNorm = 0.0;
1885 for (SCSIZE col=nC; col<nN; col++)
1886 fNorm += (pMatA->GetDouble(col,nR)) * (pMatA->GetDouble(col,nR));
1887 return sqrt(fNorm.get());
1888}
1889
1890// Special version for use within QR decomposition.
1891// Maximum norm of column index C starting in row index R;
1892// matrix A has count N rows.
1893double lcl_GetColumnMaximumNorm(const ScMatrixRef& pMatA, SCSIZE nC, SCSIZE nR, SCSIZE nN)
1894{
1895 double fNorm = 0.0;
1896 for (SCSIZE row=nR; row<nN; row++)
1897 {
1898 double fVal = fabs(pMatA->GetDouble(nC,row));
1899 if (fNorm < fVal)
1900 fNorm = fVal;
1901 }
1902 return fNorm;
1903}
1904
1905// Maximum norm of row index R starting in col index C;
1906// matrix A has count N columns.
1907double lcl_TGetColumnMaximumNorm(const ScMatrixRef& pMatA, SCSIZE nR, SCSIZE nC, SCSIZE nN)
1908{
1909 double fNorm = 0.0;
1910 for (SCSIZE col=nC; col<nN; col++)
1911 {
1912 double fVal = fabs(pMatA->GetDouble(col,nR));
1913 if (fNorm < fVal)
1914 fNorm = fVal;
1915 }
1916 return fNorm;
1917}
1918
1919// Special version for use within QR decomposition.
1920// <A(Ca);B(Cb)> starting in row index R;
1921// Ca and Cb are indices of columns, matrices A and B have count N rows.
1922double lcl_GetColumnSumProduct(const ScMatrixRef& pMatA, SCSIZE nCa,
1923 const ScMatrixRef& pMatB, SCSIZE nCb, SCSIZE nR, SCSIZE nN)
1924{
1925 KahanSum fResult = 0.0;
1926 for (SCSIZE row=nR; row<nN; row++)
1927 fResult += pMatA->GetDouble(nCa,row) * pMatB->GetDouble(nCb,row);
1928 return fResult.get();
1929}
1930
1931// <A(Ra);B(Rb)> starting in column index C;
1932// Ra and Rb are indices of rows, matrices A and B have count N columns.
1933double lcl_TGetColumnSumProduct(const ScMatrixRef& pMatA, SCSIZE nRa,
1934 const ScMatrixRef& pMatB, SCSIZE nRb, SCSIZE nC, SCSIZE nN)
1935{
1936 KahanSum fResult = 0.0;
1937 for (SCSIZE col=nC; col<nN; col++)
1938 fResult += pMatA->GetDouble(col,nRa) * pMatB->GetDouble(col,nRb);
1939 return fResult.get();
1940}
1941
1942// no mathematical signum, but used to switch between adding and subtracting
1943double lcl_GetSign(double fValue)
1944{
1945 return (fValue >= 0.0 ? 1.0 : -1.0 );
1946}
1947
1948/* Calculates a QR decomposition with Householder reflection.
1949 * For each NxK matrix A exists a decomposition A=Q*R with an orthogonal
1950 * NxN matrix Q and a NxK matrix R.
1951 * Q=H1*H2*...*Hk with Householder matrices H. Such a householder matrix can
1952 * be build from a vector u by H=I-(2/u'u)*(u u'). This vectors u are returned
1953 * in the columns of matrix A, overwriting the old content.
1954 * The matrix R has a quadric upper part KxK with values in the upper right
1955 * triangle and zeros in all other elements. Here the diagonal elements of R
1956 * are stored in the vector R and the other upper right elements in the upper
1957 * right of the matrix A.
1958 * The function returns false, if calculation breaks. But because of round-off
1959 * errors singularity is often not detected.
1960 */
1961bool lcl_CalculateQRdecomposition(const ScMatrixRef& pMatA,
1962 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN)
1963{
1964 // ScMatrix matrices are zero based, index access (column,row)
1965 for (SCSIZE col = 0; col <nK; col++)
1966 {
1967 // calculate vector u of the householder transformation
1968 const double fScale = lcl_GetColumnMaximumNorm(pMatA, col, col, nN);
1969 if (fScale == 0.0)
1970 {
1971 // A is singular
1972 return false;
1973 }
1974 for (SCSIZE row = col; row <nN; row++)
1975 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row);
1976
1977 const double fEuclid = lcl_GetColumnEuclideanNorm(pMatA, col, col, nN);
1978 const double fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(col,col)));
1979 const double fSignum = lcl_GetSign(pMatA->GetDouble(col,col));
1980 pMatA->PutDouble( pMatA->GetDouble(col,col) + fSignum*fEuclid, col,col);
1981 pVecR[col] = -fSignum * fScale * fEuclid;
1982
1983 // apply Householder transformation to A
1984 for (SCSIZE c=col+1; c<nK; c++)
1985 {
1986 const double fSum =lcl_GetColumnSumProduct(pMatA, col, pMatA, c, col, nN);
1987 for (SCSIZE row = col; row <nN; row++)
1988 pMatA->PutDouble( pMatA->GetDouble(c,row) - fSum * fFactor * pMatA->GetDouble(col,row), c, row);
1989 }
1990 }
1991 return true;
1992}
1993
1994// same with transposed matrix A, N is count of columns, K count of rows
1995bool lcl_TCalculateQRdecomposition(const ScMatrixRef& pMatA,
1996 ::std::vector< double>& pVecR, SCSIZE nK, SCSIZE nN)
1997{
1998 double fSum ;
1999 // ScMatrix matrices are zero based, index access (column,row)
2000 for (SCSIZE row = 0; row <nK; row++)
2001 {
2002 // calculate vector u of the householder transformation
2003 const double fScale = lcl_TGetColumnMaximumNorm(pMatA, row, row, nN);
2004 if (fScale == 0.0)
2005 {
2006 // A is singular
2007 return false;
2008 }
2009 for (SCSIZE col = row; col <nN; col++)
2010 pMatA->PutDouble( pMatA->GetDouble(col,row)/fScale, col, row);
2011
2012 const double fEuclid = lcl_TGetColumnEuclideanNorm(pMatA, row, row, nN);
2013 const double fFactor = 1.0/fEuclid/(fEuclid + fabs(pMatA->GetDouble(row,row)));
2014 const double fSignum = lcl_GetSign(pMatA->GetDouble(row,row));
2015 pMatA->PutDouble( pMatA->GetDouble(row,row) + fSignum*fEuclid, row,row);
2016 pVecR[row] = -fSignum * fScale * fEuclid;
2017
2018 // apply Householder transformation to A
2019 for (SCSIZE r=row+1; r<nK; r++)
2020 {
2021 fSum =lcl_TGetColumnSumProduct(pMatA, row, pMatA, r, row, nN);
2022 for (SCSIZE col = row; col <nN; col++)
2023 pMatA->PutDouble(
2024 pMatA->GetDouble(col,r) - fSum * fFactor * pMatA->GetDouble(col,row), col, r);
2025 }
2026 }
2027 return true;
2028}
2029
2030/* Applies a Householder transformation to a column vector Y with is given as
2031 * Nx1 Matrix. The vector u, from which the Householder transformation is built,
2032 * is the column part in matrix A, with column index C, starting with row
2033 * index C. A is the result of the QR decomposition as obtained from
2034 * lcl_CalculateQRdecomposition.
2035 */
2036void lcl_ApplyHouseholderTransformation(const ScMatrixRef& pMatA, SCSIZE nC,
2037 const ScMatrixRef& pMatY, SCSIZE nN)
2038{
2039 // ScMatrix matrices are zero based, index access (column,row)
2040 double fDenominator = lcl_GetColumnSumProduct(pMatA, nC, pMatA, nC, nC, nN);
2041 double fNumerator = lcl_GetColumnSumProduct(pMatA, nC, pMatY, 0, nC, nN);
2042 double fFactor = 2.0 * (fNumerator/fDenominator);
2043 for (SCSIZE row = nC; row < nN; row++)
2044 pMatY->PutDouble(
2045 pMatY->GetDouble(row) - fFactor * pMatA->GetDouble(nC,row), row);
2046}
2047
2048// Same with transposed matrices A and Y.
2049void lcl_TApplyHouseholderTransformation(const ScMatrixRef& pMatA, SCSIZE nR,
2050 const ScMatrixRef& pMatY, SCSIZE nN)
2051{
2052 // ScMatrix matrices are zero based, index access (column,row)
2053 double fDenominator = lcl_TGetColumnSumProduct(pMatA, nR, pMatA, nR, nR, nN);
2054 double fNumerator = lcl_TGetColumnSumProduct(pMatA, nR, pMatY, 0, nR, nN);
2055 double fFactor = 2.0 * (fNumerator/fDenominator);
2056 for (SCSIZE col = nR; col < nN; col++)
2057 pMatY->PutDouble(
2058 pMatY->GetDouble(col) - fFactor * pMatA->GetDouble(col,nR), col);
2059}
2060
2061/* Solve for X in R*X=S using back substitution. The solution X overwrites S.
2062 * Uses R from the result of the QR decomposition of a NxK matrix A.
2063 * S is a column vector given as matrix, with at least elements on index
2064 * 0 to K-1; elements on index>=K are ignored. Vector R must not have zero
2065 * elements, no check is done.
2066 */
2067void lcl_SolveWithUpperRightTriangle(const ScMatrixRef& pMatA,
2068 ::std::vector< double>& pVecR, const ScMatrixRef& pMatS,
2069 SCSIZE nK, bool bIsTransposed)
2070{
2071 // ScMatrix matrices are zero based, index access (column,row)
2072 SCSIZE row;
2073 // SCSIZE is never negative, therefore test with rowp1=row+1
2074 for (SCSIZE rowp1 = nK; rowp1>0; rowp1--)
2075 {
2076 row = rowp1-1;
2077 KahanSum fSum = pMatS->GetDouble(row);
2078 for (SCSIZE col = rowp1; col<nK ; col++)
2079 if (bIsTransposed)
2080 fSum -= pMatA->GetDouble(row,col) * pMatS->GetDouble(col);
2081 else
2082 fSum -= pMatA->GetDouble(col,row) * pMatS->GetDouble(col);
2083 pMatS->PutDouble( fSum.get() / pVecR[row] , row);
2084 }
2085}
2086
2087/* Solve for X in R' * X= T using forward substitution. The solution X
2088 * overwrites T. Uses R from the result of the QR decomposition of a NxK
2089 * matrix A. T is a column vectors given as matrix, with at least elements on
2090 * index 0 to K-1; elements on index>=K are ignored. Vector R must not have
2091 * zero elements, no check is done.
2092 */
2093void lcl_SolveWithLowerLeftTriangle(const ScMatrixRef& pMatA,
2094 ::std::vector< double>& pVecR, const ScMatrixRef& pMatT,
2095 SCSIZE nK, bool bIsTransposed)
2096{
2097 // ScMatrix matrices are zero based, index access (column,row)
2098 for (SCSIZE row = 0; row < nK; row++)
2099 {
2100 KahanSum fSum = pMatT -> GetDouble(row);
2101 for (SCSIZE col=0; col < row; col++)
2102 {
2103 if (bIsTransposed)
2104 fSum -= pMatA->GetDouble(col,row) * pMatT->GetDouble(col);
2105 else
2106 fSum -= pMatA->GetDouble(row,col) * pMatT->GetDouble(col);
2107 }
2108 pMatT->PutDouble( fSum.get() / pVecR[row] , row);
2109 }
2110}
2111
2112/* Calculates Z = R * B
2113 * R is given in matrix A and vector VecR as obtained from the QR
2114 * decomposition in lcl_CalculateQRdecomposition. B and Z are column vectors
2115 * given as matrix with at least index 0 to K-1; elements on index>=K are
2116 * not used.
2117 */
2118void lcl_ApplyUpperRightTriangle(const ScMatrixRef& pMatA,
2119 ::std::vector< double>& pVecR, const ScMatrixRef& pMatB,
2120 const ScMatrixRef& pMatZ, SCSIZE nK, bool bIsTransposed)
2121{
2122 // ScMatrix matrices are zero based, index access (column,row)
2123 for (SCSIZE row = 0; row < nK; row++)
2124 {
2125 KahanSum fSum = pVecR[row] * pMatB->GetDouble(row);
2126 for (SCSIZE col = row+1; col < nK; col++)
2127 if (bIsTransposed)
2128 fSum += pMatA->GetDouble(row,col) * pMatB->GetDouble(col);
2129 else
2130 fSum += pMatA->GetDouble(col,row) * pMatB->GetDouble(col);
2131 pMatZ->PutDouble( fSum.get(), row);
2132 }
2133}
2134
2135double lcl_GetMeanOverAll(const ScMatrixRef& pMat, SCSIZE nN)
2136{
2137 KahanSum fSum = 0.0;
2138 for (SCSIZE i=0 ; i<nN; i++)
2139 fSum += pMat->GetDouble(i);
2140 return fSum.get()/static_cast<double>(nN);
2141}
2142
2143// Calculates means of the columns of matrix X. X is a RxC matrix;
2144// ResMat is a 1xC matrix (=row).
2145void lcl_CalculateColumnMeans(const ScMatrixRef& pX, const ScMatrixRef& pResMat,
2146 SCSIZE nC, SCSIZE nR)
2147{
2148 for (SCSIZE i=0; i < nC; i++)
2149 {
2150 KahanSum fSum =0.0;
2151 for (SCSIZE k=0; k < nR; k++)
2152 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row)
2153 pResMat ->PutDouble( fSum.get()/static_cast<double>(nR),i);
2154 }
2155}
2156
2157// Calculates means of the rows of matrix X. X is a RxC matrix;
2158// ResMat is a Rx1 matrix (=column).
2159void lcl_CalculateRowMeans(const ScMatrixRef& pX, const ScMatrixRef& pResMat,
2160 SCSIZE nC, SCSIZE nR)
2161{
2162 for (SCSIZE k=0; k < nR; k++)
2163 {
2164 KahanSum fSum = 0.0;
2165 for (SCSIZE i=0; i < nC; i++)
2166 fSum += pX->GetDouble(i,k); // GetDouble(Column,Row)
2167 pResMat ->PutDouble( fSum.get()/static_cast<double>(nC),k);
2168 }
2169}
2170
2171void lcl_CalculateColumnsDelta(const ScMatrixRef& pMat, const ScMatrixRef& pColumnMeans,
2172 SCSIZE nC, SCSIZE nR)
2173{
2174 for (SCSIZE i = 0; i < nC; i++)
2175 for (SCSIZE k = 0; k < nR; k++)
2176 pMat->PutDouble( ::rtl::math::approxSub
2177 (pMat->GetDouble(i,k) , pColumnMeans->GetDouble(i) ) , i, k);
2178}
2179
2180void lcl_CalculateRowsDelta(const ScMatrixRef& pMat, const ScMatrixRef& pRowMeans,
2181 SCSIZE nC, SCSIZE nR)
2182{
2183 for (SCSIZE k = 0; k < nR; k++)
2184 for (SCSIZE i = 0; i < nC; i++)
2185 pMat->PutDouble( ::rtl::math::approxSub
2186 ( pMat->GetDouble(i,k) , pRowMeans->GetDouble(k) ) , i, k);
2187}
2188
2189// Case1 = simple regression
2190// MatX = X - MeanX, MatY = Y - MeanY, y - haty = (y - MeanY) - (haty - MeanY)
2191// = (y-MeanY)-((slope*x+a)-(slope*MeanX+a)) = (y-MeanY)-slope*(x-MeanX)
2192double lcl_GetSSresid(const ScMatrixRef& pMatX, const ScMatrixRef& pMatY, double fSlope,
2193 SCSIZE nN)
2194{
2195 KahanSum fSum = 0.0;
2196 for (SCSIZE i=0; i<nN; i++)
2197 {
2198 const double fTemp = pMatY->GetDouble(i) - fSlope * pMatX->GetDouble(i);
2199 fSum += fTemp * fTemp;
2200 }
2201 return fSum.get();
2202}
2203
2204}
2205
2206// Fill default values in matrix X, transform Y to log(Y) in case LOGEST|GROWTH,
2207// determine sizes of matrices X and Y, determine kind of regression, clone
2208// Y in case LOGEST|GROWTH, if constant.
2209bool ScInterpreter::CheckMatrix(bool _bLOG, sal_uInt8& nCase, SCSIZE& nCX,
2210 SCSIZE& nCY, SCSIZE& nRX, SCSIZE& nRY, SCSIZE& M,
2211 SCSIZE& N, ScMatrixRef& pMatX, ScMatrixRef& pMatY)
2212{
2213
2214 nCX = 0;
2215 nCY = 0;
2216 nRX = 0;
2217 nRY = 0;
2218 M = 0;
2219 N = 0;
2220 pMatY->GetDimensions(nCY, nRY);
2221 const SCSIZE nCountY = nCY * nRY;
2222 for ( SCSIZE i = 0; i < nCountY; i++ )
2223 {
2224 if (!pMatY->IsValue(i))
2225 {
2227 return false;
2228 }
2229 }
2230
2231 if ( _bLOG )
2232 {
2233 ScMatrixRef pNewY = pMatY->CloneIfConst();
2234 for (SCSIZE nElem = 0; nElem < nCountY; nElem++)
2235 {
2236 const double fVal = pNewY->GetDouble(nElem);
2237 if (fVal <= 0.0)
2238 {
2240 return false;
2241 }
2242 else
2243 pNewY->PutDouble(log(fVal), nElem);
2244 }
2245 pMatY = pNewY;
2246 }
2247
2248 if (pMatX)
2249 {
2250 pMatX->GetDimensions(nCX, nRX);
2251 const SCSIZE nCountX = nCX * nRX;
2252 for ( SCSIZE i = 0; i < nCountX; i++ )
2253 if (!pMatX->IsValue(i))
2254 {
2256 return false;
2257 }
2258 if (nCX == nCY && nRX == nRY)
2259 {
2260 nCase = 1; // simple regression
2261 M = 1;
2262 N = nCountY;
2263 }
2264 else if (nCY != 1 && nRY != 1)
2265 {
2267 return false;
2268 }
2269 else if (nCY == 1)
2270 {
2271 if (nRX != nRY)
2272 {
2274 return false;
2275 }
2276 else
2277 {
2278 nCase = 2; // Y is column
2279 N = nRY;
2280 M = nCX;
2281 }
2282 }
2283 else if (nCX != nCY)
2284 {
2286 return false;
2287 }
2288 else
2289 {
2290 nCase = 3; // Y is row
2291 N = nCY;
2292 M = nRX;
2293 }
2294 }
2295 else
2296 {
2297 pMatX = GetNewMat(nCY, nRY, /*bEmpty*/true);
2298 nCX = nCY;
2299 nRX = nRY;
2300 if (!pMatX)
2301 {
2303 return false;
2304 }
2305 for ( SCSIZE i = 1; i <= nCountY; i++ )
2306 pMatX->PutDouble(static_cast<double>(i), i-1);
2307 nCase = 1;
2308 N = nCountY;
2309 M = 1;
2310 }
2311 return true;
2312}
2313
2314// LINEST
2316{
2317 CalculateRGPRKP(false);
2318}
2319
2320// LOGEST
2322{
2323 CalculateRGPRKP(true);
2324}
2325
2327{
2328 sal_uInt8 nParamCount = GetByte();
2329 if (!MustHaveParamCount( nParamCount, 1, 4 ))
2330 return;
2331 bool bConstant, bStats;
2332
2333 // optional forth parameter
2334 if (nParamCount == 4)
2335 bStats = GetBool();
2336 else
2337 bStats = false;
2338
2339 // The third parameter may not be missing in ODF, if the forth parameter
2340 // is present. But Excel allows it with default true, we too.
2341 if (nParamCount >= 3)
2342 {
2343 if (IsMissing())
2344 {
2345 Pop();
2346 bConstant = true;
2347// PushIllegalParameter(); if ODF behavior is desired
2348// return;
2349 }
2350 else
2351 bConstant = GetBool();
2352 }
2353 else
2354 bConstant = true;
2355
2356 ScMatrixRef pMatX;
2357 if (nParamCount >= 2)
2358 {
2359 if (IsMissing())
2360 { //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2361 Pop();
2362 pMatX = nullptr;
2363 }
2364 else
2365 {
2366 pMatX = GetMatrix();
2367 }
2368 }
2369 else
2370 pMatX = nullptr;
2371
2372 ScMatrixRef pMatY = GetMatrix();
2373 if (!pMatY)
2374 {
2376 return;
2377 }
2378
2379 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2380 sal_uInt8 nCase;
2381
2382 SCSIZE nCX, nCY; // number of columns
2383 SCSIZE nRX, nRY; //number of rows
2384 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples
2385 if (!CheckMatrix(_bRKP,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY))
2386 {
2388 return;
2389 }
2390
2391 // Enough data samples?
2392 if ((bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1))
2393 {
2395 return;
2396 }
2397
2398 ScMatrixRef pResMat;
2399 if (bStats)
2400 pResMat = GetNewMat(K+1,5, /*bEmpty*/true);
2401 else
2402 pResMat = GetNewMat(K+1,1, /*bEmpty*/true);
2403 if (!pResMat)
2404 {
2405 PushError(FormulaError::CodeOverflow);
2406 return;
2407 }
2408 // Fill unused cells in pResMat; order (column,row)
2409 if (bStats)
2410 {
2411 for (SCSIZE i=2; i<K+1; i++)
2412 {
2413 pResMat->PutError( FormulaError::NotAvailable, i, 2);
2414 pResMat->PutError( FormulaError::NotAvailable, i, 3);
2415 pResMat->PutError( FormulaError::NotAvailable, i, 4);
2416 }
2417 }
2418
2419 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
2420 // Clone constant matrices, so that Mat = Mat - Mean is possible.
2421 double fMeanY = 0.0;
2422 if (bConstant)
2423 {
2424 ScMatrixRef pNewX = pMatX->CloneIfConst();
2425 ScMatrixRef pNewY = pMatY->CloneIfConst();
2426 if (!pNewX || !pNewY)
2427 {
2428 PushError(FormulaError::CodeOverflow);
2429 return;
2430 }
2431 pMatX = pNewX;
2432 pMatY = pNewY;
2433 // DeltaY is possible here; DeltaX depends on nCase, so later
2434 fMeanY = lcl_GetMeanOverAll(pMatY, N);
2435 for (SCSIZE i=0; i<N; i++)
2436 {
2437 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i );
2438 }
2439 }
2440
2441 if (nCase==1)
2442 {
2443 // calculate simple regression
2444 double fMeanX = 0.0;
2445 if (bConstant)
2446 { // Mat = Mat - Mean
2447 fMeanX = lcl_GetMeanOverAll(pMatX, N);
2448 for (SCSIZE i=0; i<N; i++)
2449 {
2450 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i );
2451 }
2452 }
2453 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N);
2454 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N);
2455 if (fSumX2==0.0)
2456 {
2457 PushNoValue(); // all x-values are identical
2458 return;
2459 }
2460 double fSlope = fSumXY / fSumX2;
2461 double fIntercept = 0.0;
2462 if (bConstant)
2463 fIntercept = fMeanY - fSlope * fMeanX;
2464 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, 1, 0); //order (column,row)
2465 pResMat->PutDouble(_bRKP ? exp(fSlope) : fSlope, 0, 0);
2466
2467 if (bStats)
2468 {
2469 double fSSreg = fSlope * fSlope * fSumX2;
2470 pResMat->PutDouble(fSSreg, 0, 4);
2471
2472 double fDegreesFreedom =static_cast<double>( bConstant ? N-2 : N-1 );
2473 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2474
2475 double fSSresid = lcl_GetSSresid(pMatX,pMatY,fSlope,N);
2476 pResMat->PutDouble(fSSresid, 1, 4);
2477
2478 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2479 { // exact fit; test SSreg too, because SSresid might be
2480 // unequal zero due to round of errors
2481 pResMat->PutDouble(0.0, 1, 4); // SSresid
2482 pResMat->PutError( FormulaError::NotAvailable, 0, 3); // F
2483 pResMat->PutDouble(0.0, 1, 2); // RMSE
2484 pResMat->PutDouble(0.0, 0, 1); // SigmaSlope
2485 if (bConstant)
2486 pResMat->PutDouble(0.0, 1, 1); //SigmaIntercept
2487 else
2488 pResMat->PutError( FormulaError::NotAvailable, 1, 1);
2489 pResMat->PutDouble(1.0, 0, 2); // R^2
2490 }
2491 else
2492 {
2493 double fFstatistic = (fSSreg / static_cast<double>(K))
2494 / (fSSresid / fDegreesFreedom);
2495 pResMat->PutDouble(fFstatistic, 0, 3);
2496
2497 // standard error of estimate
2498 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2499 pResMat->PutDouble(fRMSE, 1, 2);
2500
2501 double fSigmaSlope = fRMSE / sqrt(fSumX2);
2502 pResMat->PutDouble(fSigmaSlope, 0, 1);
2503
2504 if (bConstant)
2505 {
2506 double fSigmaIntercept = fRMSE
2507 * sqrt(fMeanX*fMeanX/fSumX2 + 1.0/static_cast<double>(N));
2508 pResMat->PutDouble(fSigmaIntercept, 1, 1);
2509 }
2510 else
2511 {
2512 pResMat->PutError( FormulaError::NotAvailable, 1, 1);
2513 }
2514
2515 double fR2 = fSSreg / (fSSreg + fSSresid);
2516 pResMat->PutDouble(fR2, 0, 2);
2517 }
2518 }
2519 PushMatrix(pResMat);
2520 }
2521 else // calculate multiple regression;
2522 {
2523 // Uses a QR decomposition X = QR. The solution B = (X'X)^(-1) * X' * Y
2524 // becomes B = R^(-1) * Q' * Y
2525 if (nCase ==2) // Y is column
2526 {
2527 ::std::vector< double> aVecR(N); // for QR decomposition
2528 // Enough memory for needed matrices?
2529 ScMatrixRef pMeans = GetNewMat(K, 1, /*bEmpty*/true); // mean of each column
2530 ScMatrixRef pMatZ; // for Q' * Y , inter alia
2531 if (bStats)
2532 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it
2533 else
2534 pMatZ = pMatY; // Y can be overwritten
2535 ScMatrixRef pSlopes = GetNewMat(1,K, /*bEmpty*/true); // from b1 to bK
2536 if (!pMeans || !pMatZ || !pSlopes)
2537 {
2538 PushError(FormulaError::CodeOverflow);
2539 return;
2540 }
2541 if (bConstant)
2542 {
2543 lcl_CalculateColumnMeans(pMatX, pMeans, K, N);
2544 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N);
2545 }
2546 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N))
2547 {
2548 PushNoValue();
2549 return;
2550 }
2551 // Later on we will divide by elements of aVecR, so make sure
2552 // that they aren't zero.
2553 bool bIsSingular=false;
2554 for (SCSIZE row=0; row < K && !bIsSingular; row++)
2555 bIsSingular = aVecR[row] == 0.0;
2556 if (bIsSingular)
2557 {
2558 PushNoValue();
2559 return;
2560 }
2561 // Z = Q' Y;
2562 for (SCSIZE col = 0; col < K; col++)
2563 {
2564 lcl_ApplyHouseholderTransformation(pMatX, col, pMatZ, N);
2565 }
2566 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2567 // result Z should have zeros for index>=K; if not, ignore values
2568 for (SCSIZE col = 0; col < K ; col++)
2569 {
2570 pSlopes->PutDouble( pMatZ->GetDouble(col), col);
2571 }
2572 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false);
2573 double fIntercept = 0.0;
2574 if (bConstant)
2575 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
2576 // Fill first line in result matrix
2577 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 );
2578 for (SCSIZE i = 0; i < K; i++)
2579 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i))
2580 : pSlopes->GetDouble(i) , K-1-i, 0);
2581
2582 if (bStats)
2583 {
2584 double fSSreg = 0.0;
2585 double fSSresid = 0.0;
2586 // re-use memory of Z;
2587 pMatZ->FillDouble(0.0, 0, 0, 0, N-1);
2588 // Z = R * Slopes
2589 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, false);
2590 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2591 for (SCSIZE colp1 = K; colp1 > 0; colp1--)
2592 {
2593 lcl_ApplyHouseholderTransformation(pMatX, colp1-1, pMatZ,N);
2594 }
2595 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N);
2596 // re-use Y for residuals, Y = Y-Z
2597 for (SCSIZE row = 0; row < N; row++)
2598 pMatY->PutDouble(pMatY->GetDouble(row) - pMatZ->GetDouble(row), row);
2599 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N);
2600 pResMat->PutDouble(fSSreg, 0, 4);
2601 pResMat->PutDouble(fSSresid, 1, 4);
2602
2603 double fDegreesFreedom =static_cast<double>( bConstant ? N-K-1 : N-K );
2604 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2605
2606 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2607 { // exact fit; incl. observed values Y are identical
2608 pResMat->PutDouble(0.0, 1, 4); // SSresid
2609 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2610 pResMat->PutError( FormulaError::NotAvailable, 0, 3); // F
2611 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2612 pResMat->PutDouble(0.0, 1, 2); // RMSE
2613 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2614 for (SCSIZE i=0; i<K; i++)
2615 pResMat->PutDouble(0.0, K-1-i, 1);
2616
2617 // SigmaIntercept = RMSE * sqrt(...) = 0
2618 if (bConstant)
2619 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept
2620 else
2621 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2622
2623 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2624 pResMat->PutDouble(1.0, 0, 2); // R^2
2625 }
2626 else
2627 {
2628 double fFstatistic = (fSSreg / static_cast<double>(K))
2629 / (fSSresid / fDegreesFreedom);
2630 pResMat->PutDouble(fFstatistic, 0, 3);
2631
2632 // standard error of estimate = root mean SSE
2633 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2634 pResMat->PutDouble(fRMSE, 1, 2);
2635
2636 // standard error of slopes
2637 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2638 // standard error of intercept
2639 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2640 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2641 // a whole matrix, but iterate over unit vectors.
2642 KahanSum aSigmaIntercept = 0.0;
2643 double fPart; // for Xmean * single column of (R' R)^(-1)
2644 for (SCSIZE col = 0; col < K; col++)
2645 {
2646 //re-use memory of MatZ
2647 pMatZ->FillDouble(0.0,0,0,0,K-1); // Z = unit vector e
2648 pMatZ->PutDouble(1.0, col);
2649 //Solve R' * Z = e
2650 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, false);
2651 // Solve R * Znew = Zold
2652 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, false);
2653 // now Z is column col in (R' R)^(-1)
2654 double fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(col));
2655 pResMat->PutDouble(fSigmaSlope, K-1-col, 1);
2656 // (R' R) ^(-1) is symmetric
2657 if (bConstant)
2658 {
2659 fPart = lcl_GetSumProduct(pMeans, pMatZ, K);
2660 aSigmaIntercept += fPart * pMeans->GetDouble(col);
2661 }
2662 }
2663 if (bConstant)
2664 {
2665 double fSigmaIntercept = fRMSE
2666 * sqrt( (aSigmaIntercept + 1.0 / static_cast<double>(N) ).get() );
2667 pResMat->PutDouble(fSigmaIntercept, K, 1);
2668 }
2669 else
2670 {
2671 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2672 }
2673
2674 double fR2 = fSSreg / (fSSreg + fSSresid);
2675 pResMat->PutDouble(fR2, 0, 2);
2676 }
2677 }
2678 PushMatrix(pResMat);
2679 }
2680 else // nCase == 3, Y is row, all matrices are transposed
2681 {
2682 ::std::vector< double> aVecR(N); // for QR decomposition
2683 // Enough memory for needed matrices?
2684 ScMatrixRef pMeans = GetNewMat(1, K, /*bEmpty*/true); // mean of each row
2685 ScMatrixRef pMatZ; // for Q' * Y , inter alia
2686 if (bStats)
2687 pMatZ = pMatY->Clone(); // Y is used in statistic, keep it
2688 else
2689 pMatZ = pMatY; // Y can be overwritten
2690 ScMatrixRef pSlopes = GetNewMat(K,1, /*bEmpty*/true); // from b1 to bK
2691 if (!pMeans || !pMatZ || !pSlopes)
2692 {
2693 PushError(FormulaError::CodeOverflow);
2694 return;
2695 }
2696 if (bConstant)
2697 {
2698 lcl_CalculateRowMeans(pMatX, pMeans, N, K);
2699 lcl_CalculateRowsDelta(pMatX, pMeans, N, K);
2700 }
2701
2702 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N))
2703 {
2704 PushNoValue();
2705 return;
2706 }
2707
2708 // Later on we will divide by elements of aVecR, so make sure
2709 // that they aren't zero.
2710 bool bIsSingular=false;
2711 for (SCSIZE row=0; row < K && !bIsSingular; row++)
2712 bIsSingular = aVecR[row] == 0.0;
2713 if (bIsSingular)
2714 {
2715 PushNoValue();
2716 return;
2717 }
2718 // Z = Q' Y
2719 for (SCSIZE row = 0; row < K; row++)
2720 {
2721 lcl_TApplyHouseholderTransformation(pMatX, row, pMatZ, N);
2722 }
2723 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
2724 // result Z should have zeros for index>=K; if not, ignore values
2725 for (SCSIZE col = 0; col < K ; col++)
2726 {
2727 pSlopes->PutDouble( pMatZ->GetDouble(col), col);
2728 }
2729 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true);
2730 double fIntercept = 0.0;
2731 if (bConstant)
2732 fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
2733 // Fill first line in result matrix
2734 pResMat->PutDouble(_bRKP ? exp(fIntercept) : fIntercept, K, 0 );
2735 for (SCSIZE i = 0; i < K; i++)
2736 pResMat->PutDouble(_bRKP ? exp(pSlopes->GetDouble(i))
2737 : pSlopes->GetDouble(i) , K-1-i, 0);
2738
2739 if (bStats)
2740 {
2741 double fSSreg = 0.0;
2742 double fSSresid = 0.0;
2743 // re-use memory of Z;
2744 pMatZ->FillDouble(0.0, 0, 0, N-1, 0);
2745 // Z = R * Slopes
2746 lcl_ApplyUpperRightTriangle(pMatX, aVecR, pSlopes, pMatZ, K, true);
2747 // Z = Q * Z, that is Q * R * Slopes = X * Slopes
2748 for (SCSIZE rowp1 = K; rowp1 > 0; rowp1--)
2749 {
2750 lcl_TApplyHouseholderTransformation(pMatX, rowp1-1, pMatZ,N);
2751 }
2752 fSSreg =lcl_GetSumProduct(pMatZ, pMatZ, N);
2753 // re-use Y for residuals, Y = Y-Z
2754 for (SCSIZE col = 0; col < N; col++)
2755 pMatY->PutDouble(pMatY->GetDouble(col) - pMatZ->GetDouble(col), col);
2756 fSSresid = lcl_GetSumProduct(pMatY, pMatY, N);
2757 pResMat->PutDouble(fSSreg, 0, 4);
2758 pResMat->PutDouble(fSSresid, 1, 4);
2759
2760 double fDegreesFreedom =static_cast<double>( bConstant ? N-K-1 : N-K );
2761 pResMat->PutDouble(fDegreesFreedom, 1, 3);
2762
2763 if (fDegreesFreedom == 0.0 || fSSresid == 0.0 || fSSreg == 0.0)
2764 { // exact fit; incl. case observed values Y are identical
2765 pResMat->PutDouble(0.0, 1, 4); // SSresid
2766 // F = (SSreg/K) / (SSresid/df) = #DIV/0!
2767 pResMat->PutError( FormulaError::NotAvailable, 0, 3); // F
2768 // RMSE = sqrt(SSresid / df) = sqrt(0 / df) = 0
2769 pResMat->PutDouble(0.0, 1, 2); // RMSE
2770 // SigmaSlope[i] = RMSE * sqrt(matrix[i,i]) = 0 * sqrt(...) = 0
2771 for (SCSIZE i=0; i<K; i++)
2772 pResMat->PutDouble(0.0, K-1-i, 1);
2773
2774 // SigmaIntercept = RMSE * sqrt(...) = 0
2775 if (bConstant)
2776 pResMat->PutDouble(0.0, K, 1); //SigmaIntercept
2777 else
2778 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2779
2780 // R^2 = SSreg / (SSreg + SSresid) = 1.0
2781 pResMat->PutDouble(1.0, 0, 2); // R^2
2782 }
2783 else
2784 {
2785 double fFstatistic = (fSSreg / static_cast<double>(K))
2786 / (fSSresid / fDegreesFreedom);
2787 pResMat->PutDouble(fFstatistic, 0, 3);
2788
2789 // standard error of estimate = root mean SSE
2790 double fRMSE = sqrt(fSSresid / fDegreesFreedom);
2791 pResMat->PutDouble(fRMSE, 1, 2);
2792
2793 // standard error of slopes
2794 // = RMSE * sqrt(diagonal element of (R' R)^(-1) )
2795 // standard error of intercept
2796 // = RMSE * sqrt( Xmean * (R' R)^(-1) * Xmean' + 1/N)
2797 // (R' R)^(-1) = R^(-1) * (R')^(-1). Do not calculate it as
2798 // a whole matrix, but iterate over unit vectors.
2799 // (R' R) ^(-1) is symmetric
2800 KahanSum aSigmaIntercept = 0.0;
2801 double fPart; // for Xmean * single col of (R' R)^(-1)
2802 for (SCSIZE row = 0; row < K; row++)
2803 {
2804 //re-use memory of MatZ
2805 pMatZ->FillDouble(0.0,0,0,K-1,0); // Z = unit vector e
2806 pMatZ->PutDouble(1.0, row);
2807 //Solve R' * Z = e
2808 lcl_SolveWithLowerLeftTriangle(pMatX, aVecR, pMatZ, K, true);
2809 // Solve R * Znew = Zold
2810 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pMatZ, K, true);
2811 // now Z is column col in (R' R)^(-1)
2812 double fSigmaSlope = fRMSE * sqrt(pMatZ->GetDouble(row));
2813 pResMat->PutDouble(fSigmaSlope, K-1-row, 1);
2814 if (bConstant)
2815 {
2816 fPart = lcl_GetSumProduct(pMeans, pMatZ, K);
2817 aSigmaIntercept += fPart * pMeans->GetDouble(row);
2818 }
2819 }
2820 if (bConstant)
2821 {
2822 double fSigmaIntercept = fRMSE
2823 * sqrt( (aSigmaIntercept + 1.0 / static_cast<double>(N) ).get() );
2824 pResMat->PutDouble(fSigmaIntercept, K, 1);
2825 }
2826 else
2827 {
2828 pResMat->PutError( FormulaError::NotAvailable, K, 1);
2829 }
2830
2831 double fR2 = fSSreg / (fSSreg + fSSresid);
2832 pResMat->PutDouble(fR2, 0, 2);
2833 }
2834 }
2835 PushMatrix(pResMat);
2836 }
2837 }
2838}
2839
2841{
2842 CalculateTrendGrowth(false);
2843}
2844
2846{
2848}
2849
2851{
2852 sal_uInt8 nParamCount = GetByte();
2853 if (!MustHaveParamCount( nParamCount, 1, 4 ))
2854 return;
2855
2856 // optional forth parameter
2857 bool bConstant;
2858 if (nParamCount == 4)
2859 bConstant = GetBool();
2860 else
2861 bConstant = true;
2862
2863 // The third parameter may be missing in ODF, although the forth parameter
2864 // is present. Default values depend on data not yet read.
2865 ScMatrixRef pMatNewX;
2866 if (nParamCount >= 3)
2867 {
2868 if (IsMissing())
2869 {
2870 Pop();
2871 pMatNewX = nullptr;
2872 }
2873 else
2874 pMatNewX = GetMatrix();
2875 }
2876 else
2877 pMatNewX = nullptr;
2878
2879 //In ODF1.2 empty second parameter (which is two ;; ) is allowed
2880 //Defaults will be set in CheckMatrix
2881 ScMatrixRef pMatX;
2882 if (nParamCount >= 2)
2883 {
2884 if (IsMissing())
2885 {
2886 Pop();
2887 pMatX = nullptr;
2888 }
2889 else
2890 {
2891 pMatX = GetMatrix();
2892 }
2893 }
2894 else
2895 pMatX = nullptr;
2896
2897 ScMatrixRef pMatY = GetMatrix();
2898 if (!pMatY)
2899 {
2901 return;
2902 }
2903
2904 // 1 = simple; 2 = multiple with Y as column; 3 = multiple with Y as row
2905 sal_uInt8 nCase;
2906
2907 SCSIZE nCX, nCY; // number of columns
2908 SCSIZE nRX, nRY; //number of rows
2909 SCSIZE K = 0, N = 0; // K=number of variables X, N=number of data samples
2910 if (!CheckMatrix(_bGrowth,nCase,nCX,nCY,nRX,nRY,K,N,pMatX,pMatY))
2911 {
2913 return;
2914 }
2915
2916 // Enough data samples?
2917 if ((bConstant && (N<K+1)) || (!bConstant && (N<K)) || (N<1) || (K<1))
2918 {
2920 return;
2921 }
2922
2923 // Set default pMatNewX if necessary
2924 SCSIZE nCXN, nRXN;
2925 SCSIZE nCountXN;
2926 if (!pMatNewX)
2927 {
2928 nCXN = nCX;
2929 nRXN = nRX;
2930 nCountXN = nCXN * nRXN;
2931 pMatNewX = pMatX->Clone(); // pMatX will be changed to X-meanX
2932 }
2933 else
2934 {
2935 pMatNewX->GetDimensions(nCXN, nRXN);
2936 if ((nCase == 2 && K != nCXN) || (nCase == 3 && K != nRXN))
2937 {
2939 return;
2940 }
2941 nCountXN = nCXN * nRXN;
2942 for (SCSIZE i = 0; i < nCountXN; i++)
2943 if (!pMatNewX->IsValue(i))
2944 {
2946 return;
2947 }
2948 }
2949 ScMatrixRef pResMat; // size depends on nCase
2950 if (nCase == 1)
2951 pResMat = GetNewMat(nCXN,nRXN, /*bEmpty*/true);
2952 else
2953 {
2954 if (nCase==2)
2955 pResMat = GetNewMat(1,nRXN, /*bEmpty*/true);
2956 else
2957 pResMat = GetNewMat(nCXN,1, /*bEmpty*/true);
2958 }
2959 if (!pResMat)
2960 {
2961 PushError(FormulaError::CodeOverflow);
2962 return;
2963 }
2964 // Uses sum(x-MeanX)^2 and not [sum x^2]-N * MeanX^2 in case bConstant.
2965 // Clone constant matrices, so that Mat = Mat - Mean is possible.
2966 double fMeanY = 0.0;
2967 if (bConstant)
2968 {
2969 ScMatrixRef pCopyX = pMatX->CloneIfConst();
2970 ScMatrixRef pCopyY = pMatY->CloneIfConst();
2971 if (!pCopyX || !pCopyY)
2972 {
2973 PushError(FormulaError::MatrixSize);
2974 return;
2975 }
2976 pMatX = pCopyX;
2977 pMatY = pCopyY;
2978 // DeltaY is possible here; DeltaX depends on nCase, so later
2979 fMeanY = lcl_GetMeanOverAll(pMatY, N);
2980 for (SCSIZE i=0; i<N; i++)
2981 {
2982 pMatY->PutDouble( ::rtl::math::approxSub(pMatY->GetDouble(i),fMeanY), i );
2983 }
2984 }
2985
2986 if (nCase==1)
2987 {
2988 // calculate simple regression
2989 double fMeanX = 0.0;
2990 if (bConstant)
2991 { // Mat = Mat - Mean
2992 fMeanX = lcl_GetMeanOverAll(pMatX, N);
2993 for (SCSIZE i=0; i<N; i++)
2994 {
2995 pMatX->PutDouble( ::rtl::math::approxSub(pMatX->GetDouble(i),fMeanX), i );
2996 }
2997 }
2998 double fSumXY = lcl_GetSumProduct(pMatX,pMatY,N);
2999 double fSumX2 = lcl_GetSumProduct(pMatX,pMatX,N);
3000 if (fSumX2==0.0)
3001 {
3002 PushNoValue(); // all x-values are identical
3003 return;
3004 }
3005 double fSlope = fSumXY / fSumX2;
3006 double fHelp;
3007 if (bConstant)
3008 {
3009 double fIntercept = fMeanY - fSlope * fMeanX;
3010 for (SCSIZE i = 0; i < nCountXN; i++)
3011 {
3012 fHelp = pMatNewX->GetDouble(i)*fSlope + fIntercept;
3013 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i);
3014 }
3015 }
3016 else
3017 {
3018 for (SCSIZE i = 0; i < nCountXN; i++)
3019 {
3020 fHelp = pMatNewX->GetDouble(i)*fSlope;
3021 pResMat->PutDouble(_bGrowth ? exp(fHelp) : fHelp, i);
3022 }
3023 }
3024 }
3025 else // calculate multiple regression;
3026 {
3027 if (nCase ==2) // Y is column
3028 {
3029 ::std::vector< double> aVecR(N); // for QR decomposition
3030 // Enough memory for needed matrices?
3031 ScMatrixRef pMeans = GetNewMat(K, 1, /*bEmpty*/true); // mean of each column
3032 ScMatrixRef pSlopes = GetNewMat(1,K, /*bEmpty*/true); // from b1 to bK
3033 if (!pMeans || !pSlopes)
3034 {
3035 PushError(FormulaError::CodeOverflow);
3036 return;
3037 }
3038 if (bConstant)
3039 {
3040 lcl_CalculateColumnMeans(pMatX, pMeans, K, N);
3041 lcl_CalculateColumnsDelta(pMatX, pMeans, K, N);
3042 }
3043 if (!lcl_CalculateQRdecomposition(pMatX, aVecR, K, N))
3044 {
3045 PushNoValue();
3046 return;
3047 }
3048 // Later on we will divide by elements of aVecR, so make sure
3049 // that they aren't zero.
3050 bool bIsSingular=false;
3051 for (SCSIZE row=0; row < K && !bIsSingular; row++)
3052 bIsSingular = aVecR[row] == 0.0;
3053 if (bIsSingular)
3054 {
3055 PushNoValue();
3056 return;
3057 }
3058 // Z := Q' Y; Y is overwritten with result Z
3059 for (SCSIZE col = 0; col < K; col++)
3060 {
3061 lcl_ApplyHouseholderTransformation(pMatX, col, pMatY, N);
3062 }
3063 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3064 // result Z should have zeros for index>=K; if not, ignore values
3065 for (SCSIZE col = 0; col < K ; col++)
3066 {
3067 pSlopes->PutDouble( pMatY->GetDouble(col), col);
3068 }
3069 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, false);
3070
3071 // Fill result matrix
3072 lcl_MFastMult(pMatNewX,pSlopes,pResMat,nRXN,K,1);
3073 if (bConstant)
3074 {
3075 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
3076 for (SCSIZE row = 0; row < nRXN; row++)
3077 pResMat->PutDouble(pResMat->GetDouble(row)+fIntercept, row);
3078 }
3079 if (_bGrowth)
3080 {
3081 for (SCSIZE i = 0; i < nRXN; i++)
3082 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i);
3083 }
3084 }
3085 else
3086 { // nCase == 3, Y is row, all matrices are transposed
3087
3088 ::std::vector< double> aVecR(N); // for QR decomposition
3089 // Enough memory for needed matrices?
3090 ScMatrixRef pMeans = GetNewMat(1, K, /*bEmpty*/true); // mean of each row
3091 ScMatrixRef pSlopes = GetNewMat(K,1, /*bEmpty*/true); // row from b1 to bK
3092 if (!pMeans || !pSlopes)
3093 {
3094 PushError(FormulaError::CodeOverflow);
3095 return;
3096 }
3097 if (bConstant)
3098 {
3099 lcl_CalculateRowMeans(pMatX, pMeans, N, K);
3100 lcl_CalculateRowsDelta(pMatX, pMeans, N, K);
3101 }
3102 if (!lcl_TCalculateQRdecomposition(pMatX, aVecR, K, N))
3103 {
3104 PushNoValue();
3105 return;
3106 }
3107 // Later on we will divide by elements of aVecR, so make sure
3108 // that they aren't zero.
3109 bool bIsSingular=false;
3110 for (SCSIZE row=0; row < K && !bIsSingular; row++)
3111 bIsSingular = aVecR[row] == 0.0;
3112 if (bIsSingular)
3113 {
3114 PushNoValue();
3115 return;
3116 }
3117 // Z := Q' Y; Y is overwritten with result Z
3118 for (SCSIZE row = 0; row < K; row++)
3119 {
3120 lcl_TApplyHouseholderTransformation(pMatX, row, pMatY, N);
3121 }
3122 // B = R^(-1) * Q' * Y <=> B = R^(-1) * Z <=> R * B = Z
3123 // result Z should have zeros for index>=K; if not, ignore values
3124 for (SCSIZE col = 0; col < K ; col++)
3125 {
3126 pSlopes->PutDouble( pMatY->GetDouble(col), col);
3127 }
3128 lcl_SolveWithUpperRightTriangle(pMatX, aVecR, pSlopes, K, true);
3129
3130 // Fill result matrix
3131 lcl_MFastMult(pSlopes,pMatNewX,pResMat,1,K,nCXN);
3132 if (bConstant)
3133 {
3134 double fIntercept = fMeanY - lcl_GetSumProduct(pMeans,pSlopes,K);
3135 for (SCSIZE col = 0; col < nCXN; col++)
3136 pResMat->PutDouble(pResMat->GetDouble(col)+fIntercept, col);
3137 }
3138 if (_bGrowth)
3139 {
3140 for (SCSIZE i = 0; i < nCXN; i++)
3141 pResMat->PutDouble(exp(pResMat->GetDouble(i)), i);
3142 }
3143 }
3144 }
3145 PushMatrix(pResMat);
3146}
3147
3149{
3150 // In case it contains relative references resolve them as usual.
3151 Push( *pCur );
3152 ScAddress aAdr;
3153 PopSingleRef( aAdr );
3154
3155 ScRefCellValue aCell(mrDoc, aAdr);
3156
3157 if (aCell.getType() != CELLTYPE_FORMULA)
3158 {
3159 PushError( FormulaError::NoRef );
3160 return;
3161 }
3162
3163 if (aCell.getFormula()->IsRunning())
3164 {
3165 // Twisted odd corner case where an array element's cell tries to
3166 // access the top left matrix while it is still running, see tdf#88737
3167 // This is a hackish workaround, not a general solution, the matrix
3168 // isn't available anyway and FormulaError::CircularReference would be set.
3169 PushError( FormulaError::RetryCircular );
3170 return;
3171 }
3172
3173 const ScMatrix* pMat = aCell.getFormula()->GetMatrix();
3174 if (pMat)
3175 {
3176 SCSIZE nCols, nRows;
3177 pMat->GetDimensions( nCols, nRows );
3178 SCSIZE nC = static_cast<SCSIZE>(aPos.Col() - aAdr.Col());
3179 SCSIZE nR = static_cast<SCSIZE>(aPos.Row() - aAdr.Row());
3180#if 0
3181 // XXX: this could be an additional change for tdf#145085 to not
3182 // display the URL in a voluntary entered 2-rows array context.
3183 // However, that might as well be used on purpose to implement a check
3184 // on the URL, which existing documents may have done, the more that
3185 // before the accompanying change of
3186 // ScFormulaCell::GetResultDimensions() the cell array was forced to
3187 // two rows. Do not change without compelling reason. Note that this
3188 // repeating top cell is what Excel implements, but it has no
3189 // additional value so probably isn't used there. Exporting to and
3190 // using in Excel though will lose this capability.
3191 if (aCell.mpFormula->GetCode()->IsHyperLink())
3192 {
3193 // Row 2 element is the URL that is not to be displayed, fake a
3194 // 1-row cell-text-only matrix that is repeated.
3195 assert(nRows == 2);
3196 nR = 0;
3197 }
3198#endif
3199 if ((nCols <= nC && nCols != 1) || (nRows <= nR && nRows != 1))
3200 PushNA();
3201 else
3202 {
3203 const ScMatrixValue nMatVal = pMat->Get( nC, nR);
3204 ScMatValType nMatValType = nMatVal.nType;
3205
3206 if (ScMatrix::IsNonValueType( nMatValType))
3207 {
3208 if (ScMatrix::IsEmptyPathType( nMatValType))
3209 { // result of empty false jump path
3210 nFuncFmtType = SvNumFormatType::LOGICAL;
3211 PushInt(0);
3212 }
3213 else if (ScMatrix::IsEmptyType( nMatValType))
3214 {
3215 // Not inherited (really?) and display as empty string, not 0.
3216 PushTempToken( new ScEmptyCellToken( false, true));
3217 }
3218 else
3219 PushString( nMatVal.GetString() );
3220 }
3221 else
3222 {
3223 // Determine nFuncFmtType type before PushDouble().
3227 PushDouble(nMatVal.fVal); // handles DoubleError
3228 }
3229 }
3230 }
3231 else
3232 {
3233 // Determine nFuncFmtType type before PushDouble().
3237 // If not a result matrix, obtain the cell value.
3238 FormulaError nErr = aCell.getFormula()->GetErrCode();
3239 if (nErr != FormulaError::NONE)
3240 PushError( nErr );
3241 else if (aCell.getFormula()->IsValue())
3242 PushDouble(aCell.getFormula()->GetValue());
3243 else
3244 {
3245 svl::SharedString aVal = aCell.getFormula()->GetString();
3246 PushString( aVal );
3247 }
3248 }
3249}
3250
3252{
3253 if( !MustHaveParamCount( GetByte(), 1 ) )
3254 return;
3255
3256 OUString aStr = GetString().getString();
3258 if( aStr == "SYSTEM" )
3259 PushString( SC_INFO_OSVERSION );
3260 else if( aStr == "OSVERSION" )
3261#if (defined LINUX || defined __FreeBSD__)
3263#elif defined MACOSX
3264 // TODO tdf#140286 handle MACOSX version to get result compatible to Excel
3265 PushString("Windows (32-bit) NT 5.01");
3266#else // handle Windows (WNT, WIN_NT, WIN32, _WIN32)
3267 // TODO tdf#140286 handle Windows version to get a result compatible to Excel
3268 PushString( "Windows (32-bit) NT 5.01" );
3269#endif
3270 else if( aStr == "RELEASE" )
3272 else if( aStr == "NUMFILE" )
3273 PushDouble( 1 );
3274 else if( aStr == "RECALC" )
3275 PushString( ScResId( mrDoc.GetAutoCalc() ? STR_RECALC_AUTO : STR_RECALC_MANUAL ) );
3276 else if (aStr == "DIRECTORY" || aStr == "MEMAVAIL" || aStr == "MEMUSED" || aStr == "ORIGIN" || aStr == "TOTMEM")
3277 PushNA();
3278 else
3280}
3281
3282/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SCSIZE SCSIZE_MAX
Definition: address.hxx:59
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
static OUString GetOSVersion()
This class provides LO with Kahan summation algorithm About this algorithm: https://en....
Definition: kahan.hxx:26
double get() const
Returns the final sum.
Definition: kahan.hxx:211
SCROW Row() const
Definition: address.hxx:274
@ INITIALIZE_INVALID
Definition: address.hxx:221
SCCOL Col() const
Definition: address.hxx:279
Walk through all cells in an area.
Definition: dociter.hxx:206
const ScAddress & GetPos() const
Definition: dociter.hxx:231
const ScRefCellValue & getRefCellValue() const
Definition: dociter.hxx:239
bool isEmpty() const
Definition: dociter.cxx:999
static void transKeyword(OUString &rName, const css::lang::Locale *pLocale, OpCode eOpCode)
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3686
bool ShrinkToDataArea(SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow) const
Shrink a range to only include data area.
Definition: document.cxx:1044
SC_DLLPUBLIC double RoundValueAsShown(double fVal, sal_uInt32 nFormat, const ScInterpreterContext *pContext=nullptr) const
Definition: documen4.cxx:634
SC_DLLPUBLIC bool GetAutoCalc() const
Definition: document.hxx:1411
void GetNumberFormatInfo(const ScInterpreterContext &rContext, SvNumFormatType &nType, sal_uInt32 &nIndex, const ScAddress &rPos) const
Definition: document.cxx:3742
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:603
void FillMatrix(ScMatrix &rMat, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, svl::SharedStringPool *pPool=nullptr) const
Definition: documen8.cxx:384
::formula::FormulaTokenRef TokenRef
bool IsRunning() const
double GetValue()
const svl::SharedString & GetString()
FormulaError GetErrCode()
const ScMatrix * GetMatrix()
ScTokenArray * GetCode()
static css::lang::Locale & GetLocale()
Definition: global.cxx:1119
void ScSumX2MY2()
Definition: interpr5.cxx:1716
sal_uInt32 nCurFmtIndex
Definition: interpre.hxx:202
void ScSumXMY2()
Definition: interpr5.cxx:1766
void SetError(FormulaError nError)
Definition: interpre.hxx:1007
void ScMatDet()
Definition: interpr5.cxx:904
svl::SharedString GetString()
Definition: interpr4.cxx:2322
void ScLCM()
Definition: interpr5.cxx:188
bool CheckMatrix(bool _bLOG, sal_uInt8 &nCase, SCSIZE &nCX, SCSIZE &nCY, SCSIZE &nRX, SCSIZE &nRY, SCSIZE &M, SCSIZE &N, ScMatrixRef &pMatX, ScMatrixRef &pMatY)
Definition: interpr5.cxx:2209
bool MustHaveParamCount(short nAct, short nMust)
Definition: interpre.hxx:1047
ScMatrixRef PopMatrix()
Definition: interpr4.cxx:1630
void PopExternalSingleRef(sal_uInt16 &rFileId, OUString &rTabName, ScSingleRefData &rRef)
Definition: interpr4.cxx:1140
bool MustHaveParamCountMin(short nAct, short nMin)
Definition: interpre.hxx:1069
ScAddress aPos
Definition: interpre.hxx:183
ScDocument & mrDoc
Definition: interpre.hxx:186
SubtotalFlags mnSubTotalFlags
Definition: interpre.hxx:208
bool GetBool()
Definition: interpre.hxx:433
void PushIllegalParameter()
Definition: interpr4.cxx:1926
FormulaError nGlobalError
Definition: interpre.hxx:198
void PushIllegalArgument()
Definition: interpr4.cxx:1931
void Push(const formula::FormulaToken &r)
Does substitute with formula::FormulaErrorToken in case nGlobalError is set and the token passed is n...
Definition: interpr4.cxx:599
void CalculateMatrixValue(const ScMatrix *pMat, SCSIZE nC, SCSIZE nR)
Definition: interpr5.cxx:692
void CalculateRGPRKP(bool _bRKP)
Definition: interpr5.cxx:2326
formula::StackVar GetRawStackType()
Raw stack type without default replacements.
Definition: interpr4.cxx:1951
const formula::FormulaToken * pCur
Definition: interpre.hxx:195
ScInterpreterContext & mrContext
Definition: interpre.hxx:185
SvNumFormatType nFuncFmtType
Definition: interpre.hxx:204
void ScGrowth()
Definition: interpr5.cxx:2845
void ScMatValue()
Definition: interpr5.cxx:614
sal_uInt32 GetUInt32()
if GetDouble() not within uint32 limits sets nGlobalError and returns SAL_MAX_UINT32
Definition: interpr4.cxx:2246
void ScPower()
Definition: interpr5.cxx:1595
void GetCellString(svl::SharedString &rStr, ScRefCellValue &rCell)
Definition: interpr4.cxx:244
void ScTrend()
Definition: interpr5.cxx:2840
void PushError(FormulaError nError)
Definition: interpr4.cxx:1915
sal_uInt8 GetByte() const
Definition: interpre.hxx:415
void ScGCD()
Definition: interpr5.cxx:114
bool CheckStringResultLen(OUString &rResult, sal_Int32 nIncrease)
Definition: interpre.hxx:1108
ScMatrixRef GetNewMat(SCSIZE nC, SCSIZE nR, bool bEmpty=false)
Definition: interpr5.cxx:283
static void MEMat(const ScMatrixRef &mM, SCSIZE n)
Definition: interpr5.cxx:738
double GetDouble()
Definition: interpr4.cxx:2085
void ScSumX2DY2()
Definition: interpr5.cxx:1761
void PushDouble(double nVal)
Definition: interpr4.cxx:1789
void ScMatInv()
Definition: interpr5.cxx:951
void ScLinest()
Definition: interpr5.cxx:2315
void ScFrequency()
Definition: interpr5.cxx:1798
sc::RangeMatrix PopRangeMatrix()
Definition: interpr4.cxx:1662
const formula::FormulaToken ** pStack
Definition: interpre.hxx:197
void ScMatTrans()
Definition: interpr5.cxx:1112
void PopSingleRef(ScAddress &)
Definition: interpr4.cxx:906
ScTokenMatrixMap maTokenMatrixMap
Definition: interpre.hxx:191
SvNumberFormatter * pFormatter
Definition: interpre.hxx:193
void ScEMat()
Definition: interpr5.cxx:715
static double div(const double &fNumerator, const double &fDenominator)
Fail safe division, returning a FormulaError::DivisionByZero coded into a double if denominator is 0....
Definition: interpre.hxx:1143
ScMatrixRef GetMatrix()
Definition: interpr5.cxx:463
void MakeMatNew(ScMatrixRef &rMat, SCSIZE nC, SCSIZE nR)
Definition: interpr5.cxx:268
void CalculateTrendGrowth(bool _bGrowth)
Definition: interpr5.cxx:2850
void CalculateAddSub(bool _bSub)
Definition: interpr5.cxx:1216
void ScMatRef()
Definition: interpr5.cxx:3148
sal_uInt32 nFuncFmtIndex
Definition: interpre.hxx:201
void PopDoubleRef(ScRange &rRange, short &rParam, size_t &rRefInList)
If formula::StackVar formula::svDoubleRef pop ScDoubleRefToken and return values of ScComplexRefData.
Definition: interpr4.cxx:1043
void ScLogest()
Definition: interpr5.cxx:2321
void PushMatrix(const sc::RangeMatrix &rMat)
Definition: interpr4.cxx:1890
void PopError()
Definition: interpr4.cxx:753
void PopExternalDoubleRef(sal_uInt16 &rFileId, OUString &rTabName, ScComplexRefData &rRef)
Definition: interpr4.cxx:1219
double GetCellValue(const ScAddress &, ScRefCellValue &rCell)
Definition: interpr4.cxx:177
void PushTempToken(formula::FormulaToken *)
Does substitute with formula::FormulaErrorToken in case nGlobalError is set and the token passed is n...
Definition: interpr4.cxx:617
void ScSumProduct()
Definition: interpr5.cxx:1655
sc::RangeMatrix GetRangeMatrix()
Definition: interpr5.cxx:600
void PushNoValue()
Definition: interpr4.cxx:1941
void GetSortArray(sal_uInt8 nParamCount, ::std::vector< double > &rSortArray, ::std::vector< tools::Long > *pIndexOrder, bool bConvertTextInArray, bool bAllowEmptyArray)
Definition: interpr3.cxx:4112
bool IsMissing() const
Definition: interpr4.cxx:1946
ScMatrixRef MatConcat(const ScMatrixRef &pMat1, const ScMatrixRef &pMat2)
Definition: interpr5.cxx:1167
formula::StackVar GetStackType()
Stack type with replacement of defaults, e.g. svMissing and formula::svEmptyCell will result in formu...
Definition: interpr4.cxx:1966
void ScAmpersand()
Definition: interpr5.cxx:1344
svl::SharedStringPool & mrStrPool
Definition: interpre.hxx:188
static double ScGetGCD(double fx, double fy)
Definition: interpr5.cxx:93
bool bCalcAsShown
Definition: interpre.hxx:210
void PushInt(int nVal)
Definition: interpr4.cxx:1796
SvNumFormatType nCurFmtType
Definition: interpre.hxx:205
void CalculateSumX2MY2SumX2DY2(bool _bSumX2DY2)
Definition: interpr5.cxx:1720
void PushString(const OUString &rStr)
Definition: interpr4.cxx:1813
ScMatrixRef CreateMatrixFromDoubleRef(const formula::FormulaToken *pToken, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2)
Definition: interpr5.cxx:301
sal_uInt16 sp
Definition: interpre.hxx:199
void ScMatMult()
Definition: interpr5.cxx:1063
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:101
ScMatrixValue Get(SCSIZE nC, SCSIZE nR) const
@ATTENTION: If bString the ScMatrixValue->pS may still be NULL to indicate an empty string!
Definition: scmatrix.cxx:3238
static bool IsEmptyPathType(ScMatValType nType)
Empty path, but not empty or any other type.
Definition: scmatrix.hxx:199
std::function< double(double, double)> CalculateOpFunction
Definition: scmatrix.hxx:121
static bool IsEmptyType(ScMatValType nType)
Empty, but not empty path or any other type.
Definition: scmatrix.hxx:193
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3208
static bool IsSizeAllocatable(SCSIZE nC, SCSIZE nR)
Checks nC or nR for zero and uses GetElementsMax() whether a matrix of the size of nC*nR could be all...
Definition: scmatrix.cxx:3000
static bool IsNonValueType(ScMatValType nType)
String, empty or empty path, but not value nor boolean.
Definition: scmatrix.hxx:179
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3153
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:3128
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:690
bool GetFirst(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:270
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:294
virtual const ScComplexRefData * GetDoubleRef() const
Abstract base class for vectorised formula group interpreters, plus a global instance factory.
static FormulaGroupInterpreter * getStatic()
load and/or configure the correct formula group interpreter
virtual ScMatrixRef inverseMatrix(const ScMatrix &rMat)=0
SharedString intern(const OUString &rStr)
const OUString & getString() const
static OUString getBuildIdData(OUString const &_sDefault)
int nCount
FormulaError
double CreateDoubleError(FormulaError nErr)
FormulaError GetDoubleErrorValue(double fVal)
@ CELLTYPE_FORMULA
Definition: global.hxx:275
@ CELLTYPE_VALUE
Definition: global.hxx:273
static void lcl_GetDiffDateTimeFmtType(SvNumFormatType &nFuncFmt, SvNumFormatType nFmt1, SvNumFormatType nFmt2)
Definition: interpr5.cxx:1184
static SCSIZE lcl_GetMinExtent(SCSIZE n1, SCSIZE n2)
Minimum extent of one result matrix dimension.
Definition: interpr5.cxx:1140
static int lcl_LUP_decompose(ScMatrix *mA, const SCSIZE n, ::std::vector< SCSIZE > &P)
Definition: interpr5.cxx:764
static void lcl_LUP_solve(const ScMatrix *mLU, const SCSIZE n, const ::std::vector< SCSIZE > &P, const ::std::vector< double > &B, ::std::vector< double > &X)
Definition: interpr5.cxx:865
static ScMatrixRef lcl_MatrixCalculation(const ScMatrix &rMat1, const ScMatrix &rMat2, ScInterpreter *pInterpreter, ScMatrix::CalculateOpFunction Op)
Definition: interpr5.cxx:1152
void * p
sal_Int64 n
aStr
int n2
int n1
RttiCompleteObjectLocator col
svMissing
svExternalDoubleRef
svDouble
svError
svDoubleRef
svExternalSingleRef
svString
svRefList
svMatrix
svSingleRef
int i
m
log
Op_< std::function< void(double &, double)>, double > Op
double power(const double &fVal1, const double &fVal2)
Return pow(fVal1,fVal2) with error handling.
Definition: math.cxx:30
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
M
ocInfo
#define N
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
sal_uIntPtr sal_uLong
static bool isOpenCLEnabled()
Definition: calcconfig.cxx:69
Complex reference (a range) into the sheet.
Definition: refdata.hxx:123
bool IsTrimToData() const
Definition: refdata.hxx:193
Try NOT to use this struct.
Definition: scmatrix.hxx:53
ScMatValType nType
Definition: scmatrix.hxx:56
double fVal
Definition: scmatrix.hxx:54
const svl::SharedString & GetString() const
Only valid if ScMatrix methods indicate so!
Definition: scmatrix.hxx:59
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:137
bool hasError() const
Definition: cellvalue.cxx:624
bool hasEmptyValue()
Definition: cellvalue.cxx:672
OUString getString(const ScDocument *pDoc) const
Retrieve string value.
Definition: cellvalue.cxx:657
bool hasNumeric() const
Definition: cellvalue.cxx:619
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:115
double getValue()
Definition: cellvalue.cxx:629
bool hasString() const
Definition: cellvalue.cxx:614
CellType getType() const
Definition: cellvalue.hxx:133
ScMatrixRef mpMat
Definition: types.hxx:84
unsigned char sal_uInt8
sal_Int16 SCTAB
Definition: types.hxx:22
ScMatValType
Definition: types.hxx:31
sal_Int16 SCCOL
Definition: types.hxx:21
::boost::intrusive_ptr< ScMatrix > ScMatrixRef
Definition: types.hxx:25
sal_Int32 SCROW
Definition: types.hxx:17
SvNumFormatType