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